123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014 |
- /*
- Copyright (c) 2001-2006, Gerrit Pape
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of the author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
- /* TODO: depends on runit_lib.c - review and reduce/eliminate */
- #include <sys/poll.h>
- #include <sys/file.h>
- #include "libbb.h"
- #include "runit_lib.h"
- #define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0)
- #define FMT_PTIME 30
- static unsigned verbose;
- static int linemax = 1000;
- ////static int buflen = 1024;
- static int linelen;
- static char **fndir;
- static int fdwdir;
- static int wstat;
- static unsigned nearest_rotate;
- static char *line;
- static smallint exitasap;
- static smallint rotateasap;
- static smallint reopenasap;
- static smallint linecomplete = 1;
- static smallint tmaxflag;
- static char repl;
- static const char *replace = "";
- static sigset_t *blocked_sigset;
- static int fl_flag_0;
- static struct logdir {
- ////char *btmp;
- /* pattern list to match, in "aa\0bb\0\cc\0\0" form */
- char *inst;
- char *processor;
- char *name;
- unsigned size;
- unsigned sizemax;
- unsigned nmax;
- unsigned nmin;
- unsigned rotate_period;
- int ppid;
- int fddir;
- int fdcur;
- FILE* filecur; ////
- int fdlock;
- unsigned next_rotate;
- char fnsave[FMT_PTIME];
- char match;
- char matcherr;
- } *dir;
- static unsigned dirn;
- #define FATAL "fatal: "
- #define WARNING "warning: "
- #define PAUSE "pausing: "
- #define INFO "info: "
- #define usage() bb_show_usage()
- static void fatalx(const char *m0)
- {
- bb_error_msg_and_die(FATAL"%s", m0);
- }
- static void warn(const char *m0)
- {
- bb_perror_msg(WARNING"%s", m0);
- }
- static void warn2(const char *m0, const char *m1)
- {
- bb_perror_msg(WARNING"%s: %s", m0, m1);
- }
- static void warnx(const char *m0, const char *m1)
- {
- bb_error_msg(WARNING"%s: %s", m0, m1);
- }
- static void pause_nomem(void)
- {
- bb_error_msg(PAUSE"out of memory");
- sleep(3);
- }
- static void pause1cannot(const char *m0)
- {
- bb_perror_msg(PAUSE"cannot %s", m0);
- sleep(3);
- }
- static void pause2cannot(const char *m0, const char *m1)
- {
- bb_perror_msg(PAUSE"cannot %s %s", m0, m1);
- sleep(3);
- }
- static char* wstrdup(const char *str)
- {
- char *s;
- while (!(s = strdup(str)))
- pause_nomem();
- return s;
- }
- /*** ex fmt_ptime.[ch] ***/
- /* NUL terminated */
- static void fmt_time_human_30nul(char *s)
- {
- struct tm *t;
- struct timeval tv;
- gettimeofday(&tv, NULL);
- t = gmtime(&(tv.tv_sec));
- sprintf(s, "%04u-%02u-%02u_%02u:%02u:%02u.%06u000",
- (unsigned)(1900 + t->tm_year),
- (unsigned)(t->tm_mon + 1),
- (unsigned)(t->tm_mday),
- (unsigned)(t->tm_hour),
- (unsigned)(t->tm_min),
- (unsigned)(t->tm_sec),
- (unsigned)(tv.tv_usec)
- );
- /* 4+1 + 2+1 + 2+1 + 2+1 + 2+1 + 2+1 + 9 = */
- /* 5 + 3 + 3 + 3 + 3 + 3 + 9 = */
- /* 20 (up to '.' inclusive) + 9 (not including '\0') */
- }
- /* NOT terminated! */
- static void fmt_time_bernstein_25(char *s)
- {
- uint32_t pack[3];
- struct timeval tv;
- unsigned sec_hi;
- gettimeofday(&tv, NULL);
- sec_hi = (0x400000000000000aULL + tv.tv_sec) >> 32;
- tv.tv_sec = (time_t)(0x400000000000000aULL) + tv.tv_sec;
- tv.tv_usec *= 1000;
- /* Network order is big-endian: most significant byte first.
- * This is exactly what we want here */
- pack[0] = htonl(sec_hi);
- pack[1] = htonl(tv.tv_sec);
- pack[2] = htonl(tv.tv_usec);
- *s++ = '@';
- bin2hex(s, (char*)pack, 12);
- }
- static unsigned processorstart(struct logdir *ld)
- {
- int pid;
- if (!ld->processor) return 0;
- if (ld->ppid) {
- warnx("processor already running", ld->name);
- return 0;
- }
- while ((pid = fork()) == -1)
- pause2cannot("fork for processor", ld->name);
- if (!pid) {
- char *prog[4];
- int fd;
- /* child */
- signal(SIGTERM, SIG_DFL);
- signal(SIGALRM, SIG_DFL);
- signal(SIGHUP, SIG_DFL);
- sig_unblock(SIGTERM);
- sig_unblock(SIGALRM);
- sig_unblock(SIGHUP);
- if (verbose)
- bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
- fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
- xmove_fd(fd, 0);
- ld->fnsave[26] = 't';
- fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
- xmove_fd(fd, 1);
- fd = open_read("state");
- if (fd == -1) {
- if (errno != ENOENT)
- bb_perror_msg_and_die(FATAL"cannot %s processor %s", "open state for", ld->name);
- close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
- fd = xopen("state", O_RDONLY|O_NDELAY);
- }
- xmove_fd(fd, 4);
- fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
- xmove_fd(fd, 5);
- // getenv("SHELL")?
- prog[0] = (char*)"sh";
- prog[1] = (char*)"-c";
- prog[2] = ld->processor;
- prog[3] = NULL;
- execve("/bin/sh", prog, environ);
- bb_perror_msg_and_die(FATAL"cannot %s processor %s", "run", ld->name);
- }
- ld->ppid = pid;
- return 1;
- }
- static unsigned processorstop(struct logdir *ld)
- {
- char f[28];
- if (ld->ppid) {
- sig_unblock(SIGHUP);
- while (wait_pid(&wstat, ld->ppid) == -1)
- pause2cannot("wait for processor", ld->name);
- sig_block(SIGHUP);
- ld->ppid = 0;
- }
- if (ld->fddir == -1) return 1;
- while (fchdir(ld->fddir) == -1)
- pause2cannot("change directory, want processor", ld->name);
- if (wait_exitcode(wstat) != 0) {
- warnx("processor failed, restart", ld->name);
- ld->fnsave[26] = 't';
- unlink(ld->fnsave);
- ld->fnsave[26] = 'u';
- processorstart(ld);
- while (fchdir(fdwdir) == -1)
- pause1cannot("change to initial working directory");
- return ld->processor ? 0 : 1;
- }
- ld->fnsave[26] = 't';
- memcpy(f, ld->fnsave, 26);
- f[26] = 's';
- f[27] = '\0';
- while (rename(ld->fnsave, f) == -1)
- pause2cannot("rename processed", ld->name);
- while (chmod(f, 0744) == -1)
- pause2cannot("set mode of processed", ld->name);
- ld->fnsave[26] = 'u';
- if (unlink(ld->fnsave) == -1)
- bb_error_msg(WARNING"cannot unlink: %s/%s", ld->name, ld->fnsave);
- while (rename("newstate", "state") == -1)
- pause2cannot("rename state", ld->name);
- if (verbose)
- bb_error_msg(INFO"processed: %s/%s", ld->name, f);
- while (fchdir(fdwdir) == -1)
- pause1cannot("change to initial working directory");
- return 1;
- }
- static void rmoldest(struct logdir *ld)
- {
- DIR *d;
- struct dirent *f;
- char oldest[FMT_PTIME];
- int n = 0;
- oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
- while (!(d = opendir(".")))
- pause2cannot("open directory, want rotate", ld->name);
- errno = 0;
- while ((f = readdir(d))) {
- if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
- if (f->d_name[26] == 't') {
- if (unlink(f->d_name) == -1)
- warn2("cannot unlink processor leftover", f->d_name);
- } else {
- ++n;
- if (strcmp(f->d_name, oldest) < 0)
- memcpy(oldest, f->d_name, 27);
- }
- errno = 0;
- }
- }
- if (errno)
- warn2("cannot read directory", ld->name);
- closedir(d);
- if (ld->nmax && (n > ld->nmax)) {
- if (verbose)
- bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
- if ((*oldest == '@') && (unlink(oldest) == -1))
- warn2("cannot unlink oldest logfile", ld->name);
- }
- }
- static unsigned rotate(struct logdir *ld)
- {
- struct stat st;
- unsigned now;
- if (ld->fddir == -1) {
- ld->rotate_period = 0;
- return 0;
- }
- if (ld->ppid)
- while (!processorstop(ld))
- continue;
- while (fchdir(ld->fddir) == -1)
- pause2cannot("change directory, want rotate", ld->name);
- /* create new filename */
- ld->fnsave[25] = '.';
- ld->fnsave[26] = 's';
- if (ld->processor)
- ld->fnsave[26] = 'u';
- ld->fnsave[27] = '\0';
- do {
- fmt_time_bernstein_25(ld->fnsave);
- errno = 0;
- stat(ld->fnsave, &st);
- } while (errno != ENOENT);
- now = monotonic_sec();
- if (ld->rotate_period && LESS(ld->next_rotate, now)) {
- ld->next_rotate = now + ld->rotate_period;
- if (LESS(ld->next_rotate, nearest_rotate))
- nearest_rotate = ld->next_rotate;
- }
- if (ld->size > 0) {
- while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
- pause2cannot("fsync current logfile", ld->name);
- while (fchmod(ld->fdcur, 0744) == -1)
- pause2cannot("set mode of current", ld->name);
- ////close(ld->fdcur);
- fclose(ld->filecur);
- if (verbose) {
- bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
- ld->fnsave, ld->size);
- }
- while (rename("current", ld->fnsave) == -1)
- pause2cannot("rename current", ld->name);
- while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
- pause2cannot("create new current", ld->name);
- /* we presume this cannot fail */
- ld->filecur = fdopen(ld->fdcur, "a"); ////
- setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
- coe(ld->fdcur);
- ld->size = 0;
- while (fchmod(ld->fdcur, 0644) == -1)
- pause2cannot("set mode of current", ld->name);
- rmoldest(ld);
- processorstart(ld);
- }
- while (fchdir(fdwdir) == -1)
- pause1cannot("change to initial working directory");
- return 1;
- }
- static int buffer_pwrite(int n, char *s, unsigned len)
- {
- int i;
- struct logdir *ld = &dir[n];
- if (ld->sizemax) {
- if (ld->size >= ld->sizemax)
- rotate(ld);
- if (len > (ld->sizemax - ld->size))
- len = ld->sizemax - ld->size;
- }
- while (1) {
- ////i = full_write(ld->fdcur, s, len);
- ////if (i != -1) break;
- i = fwrite(s, 1, len, ld->filecur);
- if (i == len) break;
- if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
- DIR *d;
- struct dirent *f;
- char oldest[FMT_PTIME];
- int j = 0;
- while (fchdir(ld->fddir) == -1)
- pause2cannot("change directory, want remove old logfile",
- ld->name);
- oldest[0] = 'A';
- oldest[1] = oldest[27] = '\0';
- while (!(d = opendir(".")))
- pause2cannot("open directory, want remove old logfile",
- ld->name);
- errno = 0;
- while ((f = readdir(d)))
- if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
- ++j;
- if (strcmp(f->d_name, oldest) < 0)
- memcpy(oldest, f->d_name, 27);
- }
- if (errno) warn2("cannot read directory, want remove old logfile",
- ld->name);
- closedir(d);
- errno = ENOSPC;
- if (j > ld->nmin) {
- if (*oldest == '@') {
- bb_error_msg(WARNING"out of disk space, delete: %s/%s",
- ld->name, oldest);
- errno = 0;
- if (unlink(oldest) == -1) {
- warn2("cannot unlink oldest logfile", ld->name);
- errno = ENOSPC;
- }
- while (fchdir(fdwdir) == -1)
- pause1cannot("change to initial working directory");
- }
- }
- }
- if (errno)
- pause2cannot("write to current", ld->name);
- }
- ld->size += i;
- if (ld->sizemax)
- if (s[i-1] == '\n')
- if (ld->size >= (ld->sizemax - linemax))
- rotate(ld);
- return i;
- }
- static void logdir_close(struct logdir *ld)
- {
- if (ld->fddir == -1)
- return;
- if (verbose)
- bb_error_msg(INFO"close: %s", ld->name);
- close(ld->fddir);
- ld->fddir = -1;
- if (ld->fdcur == -1)
- return; /* impossible */
- while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
- pause2cannot("fsync current logfile", ld->name);
- while (fchmod(ld->fdcur, 0744) == -1)
- pause2cannot("set mode of current", ld->name);
- ////close(ld->fdcur);
- fclose(ld->filecur);
- ld->fdcur = -1;
- if (ld->fdlock == -1)
- return; /* impossible */
- close(ld->fdlock);
- ld->fdlock = -1;
- free(ld->processor);
- ld->processor = NULL;
- }
- static unsigned logdir_open(struct logdir *ld, const char *fn)
- {
- char buf[128];
- unsigned now;
- char *new, *s, *np;
- int i;
- struct stat st;
- now = monotonic_sec();
- ld->fddir = open(fn, O_RDONLY|O_NDELAY);
- if (ld->fddir == -1) {
- warn2("cannot open log directory", (char*)fn);
- return 0;
- }
- coe(ld->fddir);
- if (fchdir(ld->fddir) == -1) {
- logdir_close(ld);
- warn2("cannot change directory", (char*)fn);
- return 0;
- }
- ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
- if ((ld->fdlock == -1)
- || (lock_exnb(ld->fdlock) == -1)
- ) {
- logdir_close(ld);
- warn2("cannot lock directory", (char*)fn);
- while (fchdir(fdwdir) == -1)
- pause1cannot("change to initial working directory");
- return 0;
- }
- coe(ld->fdlock);
- ld->size = 0;
- ld->sizemax = 1000000;
- ld->nmax = ld->nmin = 10;
- ld->rotate_period = 0;
- ld->name = (char*)fn;
- ld->ppid = 0;
- ld->match = '+';
- free(ld->inst); ld->inst = NULL;
- free(ld->processor); ld->processor = NULL;
- /* read config */
- i = open_read_close("config", buf, sizeof(buf));
- if (i < 0 && errno != ENOENT)
- bb_perror_msg(WARNING"%s/config", ld->name);
- if (i > 0) {
- if (verbose)
- bb_error_msg(INFO"read: %s/config", ld->name);
- s = buf;
- while (s) {
- np = strchr(s, '\n');
- if (np)
- *np++ = '\0';
- switch (s[0]) {
- case '+':
- case '-':
- case 'e':
- case 'E':
- /* Add '\n'-terminated line to ld->inst */
- while (1) {
- int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);
- if (l >= 0 && new)
- break;
- pause_nomem();
- }
- free(ld->inst);
- ld->inst = new;
- break;
- case 's': {
- static const struct suffix_mult km_suffixes[] = {
- { "k", 1024 },
- { "m", 1024*1024 },
- { }
- };
- ld->sizemax = xatou_sfx(&s[1], km_suffixes);
- break;
- }
- case 'n':
- ld->nmax = xatoi_u(&s[1]);
- break;
- case 'N':
- ld->nmin = xatoi_u(&s[1]);
- break;
- case 't': {
- static const struct suffix_mult mh_suffixes[] = {
- { "m", 60 },
- { "h", 60*60 },
- /*{ "d", 24*60*60 },*/
- { }
- };
- ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
- if (ld->rotate_period) {
- ld->next_rotate = now + ld->rotate_period;
- if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate))
- nearest_rotate = ld->next_rotate;
- tmaxflag = 1;
- }
- break;
- }
- case '!':
- if (s[1]) {
- free(ld->processor);
- ld->processor = wstrdup(s);
- }
- break;
- }
- s = np;
- }
- /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
- s = ld->inst;
- while (s) {
- np = strchr(s, '\n');
- if (np)
- *np++ = '\0';
- s = np;
- }
- }
- /* open current */
- i = stat("current", &st);
- if (i != -1) {
- if (st.st_size && !(st.st_mode & S_IXUSR)) {
- ld->fnsave[25] = '.';
- ld->fnsave[26] = 'u';
- ld->fnsave[27] = '\0';
- do {
- fmt_time_bernstein_25(ld->fnsave);
- errno = 0;
- stat(ld->fnsave, &st);
- } while (errno != ENOENT);
- while (rename("current", ld->fnsave) == -1)
- pause2cannot("rename current", ld->name);
- rmoldest(ld);
- i = -1;
- } else {
- /* st.st_size can be not just bigger, but WIDER!
- * This code is safe: if st.st_size > 4GB, we select
- * ld->sizemax (because it's "unsigned") */
- ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
- }
- } else {
- if (errno != ENOENT) {
- logdir_close(ld);
- warn2("cannot stat current", ld->name);
- while (fchdir(fdwdir) == -1)
- pause1cannot("change to initial working directory");
- return 0;
- }
- }
- while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
- pause2cannot("open current", ld->name);
- /* we presume this cannot fail */
- ld->filecur = fdopen(ld->fdcur, "a"); ////
- setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
- coe(ld->fdcur);
- while (fchmod(ld->fdcur, 0644) == -1)
- pause2cannot("set mode of current", ld->name);
- if (verbose) {
- if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
- else bb_error_msg(INFO"new: %s/current", ld->name);
- }
- while (fchdir(fdwdir) == -1)
- pause1cannot("change to initial working directory");
- return 1;
- }
- static void logdirs_reopen(void)
- {
- int l;
- int ok = 0;
- tmaxflag = 0;
- for (l = 0; l < dirn; ++l) {
- logdir_close(&dir[l]);
- if (logdir_open(&dir[l], fndir[l]))
- ok = 1;
- }
- if (!ok)
- fatalx("no functional log directories");
- }
- /* Will look good in libbb one day */
- static ssize_t ndelay_read(int fd, void *buf, size_t count)
- {
- if (!(fl_flag_0 & O_NONBLOCK))
- fcntl(fd, F_SETFL, fl_flag_0 | O_NONBLOCK);
- count = safe_read(fd, buf, count);
- if (!(fl_flag_0 & O_NONBLOCK))
- fcntl(fd, F_SETFL, fl_flag_0);
- return count;
- }
- /* Used for reading stdin */
- static int buffer_pread(int fd, char *s, unsigned len)
- {
- unsigned now;
- struct pollfd input;
- int i;
- input.fd = 0;
- input.events = POLLIN;
- do {
- if (rotateasap) {
- for (i = 0; i < dirn; ++i)
- rotate(dir + i);
- rotateasap = 0;
- }
- if (exitasap) {
- if (linecomplete)
- return 0;
- len = 1;
- }
- if (reopenasap) {
- logdirs_reopen();
- reopenasap = 0;
- }
- now = monotonic_sec();
- nearest_rotate = now + (45 * 60 + 45);
- for (i = 0; i < dirn; ++i) {
- if (dir[i].rotate_period) {
- if (LESS(dir[i].next_rotate, now))
- rotate(dir + i);
- if (LESS(dir[i].next_rotate, nearest_rotate))
- nearest_rotate = dir[i].next_rotate;
- }
- }
- sigprocmask(SIG_UNBLOCK, blocked_sigset, NULL);
- i = nearest_rotate - now;
- if (i > 1000000)
- i = 1000000;
- if (i <= 0)
- i = 1;
- poll(&input, 1, i * 1000);
- sigprocmask(SIG_BLOCK, blocked_sigset, NULL);
- i = ndelay_read(fd, s, len);
- if (i >= 0)
- break;
- if (errno == EINTR)
- continue;
- if (errno != EAGAIN) {
- warn("cannot read standard input");
- break;
- }
- /* else: EAGAIN - normal, repeat silently */
- } while (!exitasap);
- if (i > 0) {
- int cnt;
- linecomplete = (s[i-1] == '\n');
- if (!repl)
- return i;
- cnt = i;
- while (--cnt >= 0) {
- char ch = *s;
- if (ch != '\n') {
- if (ch < 32 || ch > 126)
- *s = repl;
- else {
- int j;
- for (j = 0; replace[j]; ++j) {
- if (ch == replace[j]) {
- *s = repl;
- break;
- }
- }
- }
- }
- s++;
- }
- }
- return i;
- }
- static void sig_term_handler(int sig_no)
- {
- if (verbose)
- bb_error_msg(INFO"sig%s received", "term");
- exitasap = 1;
- }
- static void sig_child_handler(int sig_no)
- {
- int pid, l;
- if (verbose)
- bb_error_msg(INFO"sig%s received", "child");
- while ((pid = wait_nohang(&wstat)) > 0) {
- for (l = 0; l < dirn; ++l) {
- if (dir[l].ppid == pid) {
- dir[l].ppid = 0;
- processorstop(&dir[l]);
- break;
- }
- }
- }
- }
- static void sig_alarm_handler(int sig_no)
- {
- if (verbose)
- bb_error_msg(INFO"sig%s received", "alarm");
- rotateasap = 1;
- }
- static void sig_hangup_handler(int sig_no)
- {
- if (verbose)
- bb_error_msg(INFO"sig%s received", "hangup");
- reopenasap = 1;
- }
- static void logmatch(struct logdir *ld)
- {
- char *s;
- ld->match = '+';
- ld->matcherr = 'E';
- s = ld->inst;
- while (s && s[0]) {
- switch (s[0]) {
- case '+':
- case '-':
- if (pmatch(s+1, line, linelen))
- ld->match = s[0];
- break;
- case 'e':
- case 'E':
- if (pmatch(s+1, line, linelen))
- ld->matcherr = s[0];
- break;
- }
- s += strlen(s) + 1;
- }
- }
- int svlogd_main(int argc, char **argv);
- int svlogd_main(int argc, char **argv)
- {
- sigset_t ss;
- char *r,*l,*b;
- ssize_t stdin_cnt = 0;
- int i;
- unsigned opt;
- unsigned timestamp = 0;
- void* (*memRchr)(const void *, int, size_t) = memchr;
- #define line bb_common_bufsiz1
- opt_complementary = "tt:vv";
- opt = getopt32(argv, "r:R:l:b:tv",
- &r, &replace, &l, &b, ×tamp, &verbose);
- if (opt & 1) { // -r
- repl = r[0];
- if (!repl || r[1]) usage();
- }
- if (opt & 2) if (!repl) repl = '_'; // -R
- if (opt & 4) { // -l
- linemax = xatou_range(l, 0, BUFSIZ-26);
- if (linemax == 0) linemax = BUFSIZ-26;
- if (linemax < 256) linemax = 256;
- }
- ////if (opt & 8) { // -b
- //// buflen = xatoi_u(b);
- //// if (buflen == 0) buflen = 1024;
- ////}
- //if (opt & 0x10) timestamp++; // -t
- //if (opt & 0x20) verbose++; // -v
- //if (timestamp > 2) timestamp = 2;
- argv += optind;
- argc -= optind;
- dirn = argc;
- if (dirn <= 0) usage();
- ////if (buflen <= linemax) usage();
- fdwdir = xopen(".", O_RDONLY|O_NDELAY);
- coe(fdwdir);
- dir = xzalloc(dirn * sizeof(struct logdir));
- for (i = 0; i < dirn; ++i) {
- dir[i].fddir = -1;
- dir[i].fdcur = -1;
- ////dir[i].btmp = xmalloc(buflen);
- /*dir[i].ppid = 0;*/
- }
- /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
- fndir = argv;
- /* We cannot set NONBLOCK on fd #0 permanently - this setting
- * _isn't_ per-process! It is shared among all other processes
- * with the same stdin */
- fl_flag_0 = fcntl(0, F_GETFL);
- blocked_sigset = &ss;
- sigemptyset(&ss);
- sigaddset(&ss, SIGTERM);
- sigaddset(&ss, SIGCHLD);
- sigaddset(&ss, SIGALRM);
- sigaddset(&ss, SIGHUP);
- sigprocmask(SIG_BLOCK, &ss, NULL);
- sig_catch(SIGTERM, sig_term_handler);
- sig_catch(SIGCHLD, sig_child_handler);
- sig_catch(SIGALRM, sig_alarm_handler);
- sig_catch(SIGHUP, sig_hangup_handler);
- logdirs_reopen();
- /* Without timestamps, we don't have to print each line
- * separately, so we can look for _last_ newline, not first,
- * thus batching writes */
- if (!timestamp)
- memRchr = memrchr;
- setvbuf(stderr, NULL, _IOFBF, linelen);
- /* Each iteration processes one or more lines */
- while (1) {
- char stamp[FMT_PTIME];
- char *lineptr;
- char *printptr;
- char *np;
- int printlen;
- char ch;
- lineptr = line;
- if (timestamp)
- lineptr += 26;
- /* lineptr[0..linemax-1] - buffer for stdin */
- /* (possibly has some unprocessed data from prev loop) */
- /* Refill the buffer if needed */
- np = memRchr(lineptr, '\n', stdin_cnt);
- if (!np && !exitasap) {
- i = linemax - stdin_cnt; /* avail. bytes at tail */
- if (i >= 128) {
- i = buffer_pread(0, lineptr + stdin_cnt, i);
- if (i <= 0) /* EOF or error on stdin */
- exitasap = 1;
- else {
- np = memRchr(lineptr + stdin_cnt, '\n', i);
- stdin_cnt += i;
- }
- }
- }
- if (stdin_cnt <= 0 && exitasap)
- break;
- /* Search for '\n' (in fact, np already holds the result) */
- linelen = stdin_cnt;
- if (np) {
- print_to_nl: /* NB: starting from here lineptr may point
- * farther out into line[] */
- linelen = np - lineptr + 1;
- }
- /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
- ch = lineptr[linelen-1];
- /* Biggest performance hit was coming from the fact
- * that we did not buffer writes. We were reading many lines
- * in one read() above, but wrote one line per write().
- * We are using stdio to fix that */
- /* write out lineptr[0..linelen-1] to each log destination
- * (or lineptr[-26..linelen-1] if timestamping) */
- printlen = linelen;
- printptr = lineptr;
- if (timestamp) {
- if (timestamp == 1)
- fmt_time_bernstein_25(stamp);
- else /* 2: */
- fmt_time_human_30nul(stamp);
- printlen += 26;
- printptr -= 26;
- memcpy(printptr, stamp, 25);
- printptr[25] = ' ';
- }
- for (i = 0; i < dirn; ++i) {
- struct logdir *ld = &dir[i];
- if (ld->fddir == -1) continue;
- if (ld->inst)
- logmatch(ld);
- if (ld->matcherr == 'e')
- ////full_write(2, printptr, printlen);
- fwrite(lineptr, 1, linelen, stderr);
- if (ld->match != '+') continue;
- buffer_pwrite(i, printptr, printlen);
- }
- /* If we didn't see '\n' (long input line), */
- /* read/write repeatedly until we see it */
- while (ch != '\n') {
- /* lineptr is emptied now, safe to use as buffer */
- stdin_cnt = exitasap ? -1 : buffer_pread(0, lineptr, linemax);
- if (stdin_cnt <= 0) { /* EOF or error on stdin */
- exitasap = 1;
- lineptr[0] = ch = '\n';
- linelen = 1;
- stdin_cnt = 1;
- } else {
- linelen = stdin_cnt;
- np = memRchr(lineptr, '\n', stdin_cnt);
- if (np)
- linelen = np - lineptr + 1;
- ch = lineptr[linelen-1];
- }
- /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
- for (i = 0; i < dirn; ++i) {
- if (dir[i].fddir == -1) continue;
- if (dir[i].matcherr == 'e')
- ////full_write(2, lineptr, linelen);
- fwrite(lineptr, 1, linelen, stderr);
- if (dir[i].match != '+') continue;
- buffer_pwrite(i, lineptr, linelen);
- }
- }
- stdin_cnt -= linelen;
- if (stdin_cnt > 0) {
- lineptr += linelen;
- /* If we see another '\n', we don't need to read
- * next piece of input: can print what we have */
- np = memRchr(lineptr, '\n', stdin_cnt);
- if (np)
- goto print_to_nl;
- /* Move unprocessed data to the front of line */
- memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
- }
- fflush(NULL);////
- }
- for (i = 0; i < dirn; ++i) {
- if (dir[i].ppid)
- while (!processorstop(&dir[i]))
- /* repeat */;
- logdir_close(&dir[i]);
- }
- return 0;
- }
|