source: branches/2.2.5/mindi-busybox/runit/svlogd.c @ 1765

Last change on this file since 1765 was 1765, checked in by bruno, 12 years ago

Update to busybox 1.7.2

  • Property svn:eol-style set to native
File size: 24.1 KB
Line 
1/*
2Copyright (c) 2001-2006, Gerrit Pape
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
8   1. Redistributions of source code must retain the above copyright notice,
9      this list of conditions and the following disclaimer.
10   2. Redistributions in binary form must reproduce the above copyright
11      notice, this list of conditions and the following disclaimer in the
12      documentation and/or other materials provided with the distribution.
13   3. The name of the author may not be used to endorse or promote products
14      derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28/* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
29/* TODO: depends on runit_lib.c - review and reduce/eliminate */
30
31#include <sys/poll.h>
32#include <sys/file.h>
33#include "libbb.h"
34#include "runit_lib.h"
35
36#define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0)
37
38#define FMT_PTIME 30
39
40static unsigned verbose;
41static int linemax = 1000;
42////static int buflen = 1024;
43static int linelen;
44
45static char **fndir;
46static int fdwdir;
47static int wstat;
48static unsigned nearest_rotate;
49
50static char *line;
51static smallint exitasap;
52static smallint rotateasap;
53static smallint reopenasap;
54static smallint linecomplete = 1;
55
56static smallint tmaxflag;
57
58static char repl;
59static const char *replace = "";
60
61static sigset_t *blocked_sigset;
62static int fl_flag_0;
63
64static struct logdir {
65    ////char *btmp;
66    /* pattern list to match, in "aa\0bb\0\cc\0\0" form */
67    char *inst;
68    char *processor;
69    char *name;
70    unsigned size;
71    unsigned sizemax;
72    unsigned nmax;
73    unsigned nmin;
74    unsigned rotate_period;
75    int ppid;
76    int fddir;
77    int fdcur;
78    FILE* filecur; ////
79    int fdlock;
80    unsigned next_rotate;
81    char fnsave[FMT_PTIME];
82    char match;
83    char matcherr;
84} *dir;
85static unsigned dirn;
86
87#define FATAL "fatal: "
88#define WARNING "warning: "
89#define PAUSE "pausing: "
90#define INFO "info: "
91
92#define usage() bb_show_usage()
93static void fatalx(const char *m0)
94{
95    bb_error_msg_and_die(FATAL"%s", m0);
96}
97static void warn(const char *m0)
98{
99    bb_perror_msg(WARNING"%s", m0);
100}
101static void warn2(const char *m0, const char *m1)
102{
103    bb_perror_msg(WARNING"%s: %s", m0, m1);
104}
105static void warnx(const char *m0, const char *m1)
106{
107    bb_error_msg(WARNING"%s: %s", m0, m1);
108}
109static void pause_nomem(void)
110{
111    bb_error_msg(PAUSE"out of memory");
112    sleep(3);
113}
114static void pause1cannot(const char *m0)
115{
116    bb_perror_msg(PAUSE"cannot %s", m0);
117    sleep(3);
118}
119static void pause2cannot(const char *m0, const char *m1)
120{
121    bb_perror_msg(PAUSE"cannot %s %s", m0, m1);
122    sleep(3);
123}
124
125static char* wstrdup(const char *str)
126{
127    char *s;
128    while (!(s = strdup(str)))
129        pause_nomem();
130    return s;
131}
132
133/*** ex fmt_ptime.[ch] ***/
134
135/* NUL terminated */
136static void fmt_time_human_30nul(char *s)
137{
138    struct tm *t;
139    struct timeval tv;
140
141    gettimeofday(&tv, NULL);
142    t = gmtime(&(tv.tv_sec));
143    sprintf(s, "%04u-%02u-%02u_%02u:%02u:%02u.%06u000",
144        (unsigned)(1900 + t->tm_year),
145        (unsigned)(t->tm_mon + 1),
146        (unsigned)(t->tm_mday),
147        (unsigned)(t->tm_hour),
148        (unsigned)(t->tm_min),
149        (unsigned)(t->tm_sec),
150        (unsigned)(tv.tv_usec)
151    );
152    /* 4+1 + 2+1 + 2+1 + 2+1 + 2+1 + 2+1 + 9 = */
153    /* 5   + 3   + 3   + 3   + 3   + 3   + 9 = */
154    /* 20 (up to '.' inclusive) + 9 (not including '\0') */
155}
156
157/* NOT terminated! */
158static void fmt_time_bernstein_25(char *s)
159{
160    uint32_t pack[3];
161    struct timeval tv;
162    unsigned sec_hi;
163
164    gettimeofday(&tv, NULL);
165    sec_hi = (0x400000000000000aULL + tv.tv_sec) >> 32;
166    tv.tv_sec = (time_t)(0x400000000000000aULL) + tv.tv_sec;
167    tv.tv_usec *= 1000;
168    /* Network order is big-endian: most significant byte first.
169     * This is exactly what we want here */
170    pack[0] = htonl(sec_hi);
171    pack[1] = htonl(tv.tv_sec);
172    pack[2] = htonl(tv.tv_usec);
173    *s++ = '@';
174    bin2hex(s, (char*)pack, 12);
175}
176
177static unsigned processorstart(struct logdir *ld)
178{
179    int pid;
180
181    if (!ld->processor) return 0;
182    if (ld->ppid) {
183        warnx("processor already running", ld->name);
184        return 0;
185    }
186    while ((pid = fork()) == -1)
187        pause2cannot("fork for processor", ld->name);
188    if (!pid) {
189        char *prog[4];
190        int fd;
191
192        /* child */
193        signal(SIGTERM, SIG_DFL);
194        signal(SIGALRM, SIG_DFL);
195        signal(SIGHUP, SIG_DFL);
196        sig_unblock(SIGTERM);
197        sig_unblock(SIGALRM);
198        sig_unblock(SIGHUP);
199
200        if (verbose)
201            bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
202        fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
203        xmove_fd(fd, 0);
204        ld->fnsave[26] = 't';
205        fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
206        xmove_fd(fd, 1);
207        fd = open_read("state");
208        if (fd == -1) {
209            if (errno != ENOENT)
210                bb_perror_msg_and_die(FATAL"cannot %s processor %s", "open state for", ld->name);
211            close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
212            fd = xopen("state", O_RDONLY|O_NDELAY);
213        }
214        xmove_fd(fd, 4);
215        fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
216        xmove_fd(fd, 5);
217
218// getenv("SHELL")?
219        prog[0] = (char*)"sh";
220        prog[1] = (char*)"-c";
221        prog[2] = ld->processor;
222        prog[3] = NULL;
223        execve("/bin/sh", prog, environ);
224        bb_perror_msg_and_die(FATAL"cannot %s processor %s", "run", ld->name);
225    }
226    ld->ppid = pid;
227    return 1;
228}
229
230static unsigned processorstop(struct logdir *ld)
231{
232    char f[28];
233
234    if (ld->ppid) {
235        sig_unblock(SIGHUP);
236        while (wait_pid(&wstat, ld->ppid) == -1)
237            pause2cannot("wait for processor", ld->name);
238        sig_block(SIGHUP);
239        ld->ppid = 0;
240    }
241    if (ld->fddir == -1) return 1;
242    while (fchdir(ld->fddir) == -1)
243        pause2cannot("change directory, want processor", ld->name);
244    if (wait_exitcode(wstat) != 0) {
245        warnx("processor failed, restart", ld->name);
246        ld->fnsave[26] = 't';
247        unlink(ld->fnsave);
248        ld->fnsave[26] = 'u';
249        processorstart(ld);
250        while (fchdir(fdwdir) == -1)
251            pause1cannot("change to initial working directory");
252        return ld->processor ? 0 : 1;
253    }
254    ld->fnsave[26] = 't';
255    memcpy(f, ld->fnsave, 26);
256    f[26] = 's';
257    f[27] = '\0';
258    while (rename(ld->fnsave, f) == -1)
259        pause2cannot("rename processed", ld->name);
260    while (chmod(f, 0744) == -1)
261        pause2cannot("set mode of processed", ld->name);
262    ld->fnsave[26] = 'u';
263    if (unlink(ld->fnsave) == -1)
264        bb_error_msg(WARNING"cannot unlink: %s/%s", ld->name, ld->fnsave);
265    while (rename("newstate", "state") == -1)
266        pause2cannot("rename state", ld->name);
267    if (verbose)
268        bb_error_msg(INFO"processed: %s/%s", ld->name, f);
269    while (fchdir(fdwdir) == -1)
270        pause1cannot("change to initial working directory");
271    return 1;
272}
273
274static void rmoldest(struct logdir *ld)
275{
276    DIR *d;
277    struct dirent *f;
278    char oldest[FMT_PTIME];
279    int n = 0;
280
281    oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
282    while (!(d = opendir(".")))
283        pause2cannot("open directory, want rotate", ld->name);
284    errno = 0;
285    while ((f = readdir(d))) {
286        if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
287            if (f->d_name[26] == 't') {
288                if (unlink(f->d_name) == -1)
289                    warn2("cannot unlink processor leftover", f->d_name);
290            } else {
291                ++n;
292                if (strcmp(f->d_name, oldest) < 0)
293                    memcpy(oldest, f->d_name, 27);
294            }
295            errno = 0;
296        }
297    }
298    if (errno)
299        warn2("cannot read directory", ld->name);
300    closedir(d);
301
302    if (ld->nmax && (n > ld->nmax)) {
303        if (verbose)
304            bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
305        if ((*oldest == '@') && (unlink(oldest) == -1))
306            warn2("cannot unlink oldest logfile", ld->name);
307    }
308}
309
310static unsigned rotate(struct logdir *ld)
311{
312    struct stat st;
313    unsigned now;
314
315    if (ld->fddir == -1) {
316        ld->rotate_period = 0;
317        return 0;
318    }
319    if (ld->ppid)
320        while (!processorstop(ld))
321            continue;
322
323    while (fchdir(ld->fddir) == -1)
324        pause2cannot("change directory, want rotate", ld->name);
325
326    /* create new filename */
327    ld->fnsave[25] = '.';
328    ld->fnsave[26] = 's';
329    if (ld->processor)
330        ld->fnsave[26] = 'u';
331    ld->fnsave[27] = '\0';
332    do {
333        fmt_time_bernstein_25(ld->fnsave);
334        errno = 0;
335        stat(ld->fnsave, &st);
336    } while (errno != ENOENT);
337
338    now = monotonic_sec();
339    if (ld->rotate_period && LESS(ld->next_rotate, now)) {
340        ld->next_rotate = now + ld->rotate_period;
341        if (LESS(ld->next_rotate, nearest_rotate))
342            nearest_rotate = ld->next_rotate;
343    }
344
345    if (ld->size > 0) {
346        while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
347            pause2cannot("fsync current logfile", ld->name);
348        while (fchmod(ld->fdcur, 0744) == -1)
349            pause2cannot("set mode of current", ld->name);
350        ////close(ld->fdcur);
351        fclose(ld->filecur);
352
353        if (verbose) {
354            bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
355                    ld->fnsave, ld->size);
356        }
357        while (rename("current", ld->fnsave) == -1)
358            pause2cannot("rename current", ld->name);
359        while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
360            pause2cannot("create new current", ld->name);
361        /* we presume this cannot fail */
362        ld->filecur = fdopen(ld->fdcur, "a"); ////
363        setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
364        coe(ld->fdcur);
365        ld->size = 0;
366        while (fchmod(ld->fdcur, 0644) == -1)
367            pause2cannot("set mode of current", ld->name);
368        rmoldest(ld);
369        processorstart(ld);
370    }
371
372    while (fchdir(fdwdir) == -1)
373        pause1cannot("change to initial working directory");
374    return 1;
375}
376
377static int buffer_pwrite(int n, char *s, unsigned len)
378{
379    int i;
380    struct logdir *ld = &dir[n];
381
382    if (ld->sizemax) {
383        if (ld->size >= ld->sizemax)
384            rotate(ld);
385        if (len > (ld->sizemax - ld->size))
386            len = ld->sizemax - ld->size;
387    }
388    while (1) {
389        ////i = full_write(ld->fdcur, s, len);
390        ////if (i != -1) break;
391        i = fwrite(s, 1, len, ld->filecur);
392        if (i == len) break;
393
394        if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
395            DIR *d;
396            struct dirent *f;
397            char oldest[FMT_PTIME];
398            int j = 0;
399
400            while (fchdir(ld->fddir) == -1)
401                pause2cannot("change directory, want remove old logfile",
402                             ld->name);
403            oldest[0] = 'A';
404            oldest[1] = oldest[27] = '\0';
405            while (!(d = opendir(".")))
406                pause2cannot("open directory, want remove old logfile",
407                             ld->name);
408            errno = 0;
409            while ((f = readdir(d)))
410                if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
411                    ++j;
412                    if (strcmp(f->d_name, oldest) < 0)
413                        memcpy(oldest, f->d_name, 27);
414                }
415            if (errno) warn2("cannot read directory, want remove old logfile",
416                    ld->name);
417            closedir(d);
418            errno = ENOSPC;
419            if (j > ld->nmin) {
420                if (*oldest == '@') {
421                    bb_error_msg(WARNING"out of disk space, delete: %s/%s",
422                            ld->name, oldest);
423                    errno = 0;
424                    if (unlink(oldest) == -1) {
425                        warn2("cannot unlink oldest logfile", ld->name);
426                        errno = ENOSPC;
427                    }
428                    while (fchdir(fdwdir) == -1)
429                        pause1cannot("change to initial working directory");
430                }
431            }
432        }
433        if (errno)
434            pause2cannot("write to current", ld->name);
435    }
436
437    ld->size += i;
438    if (ld->sizemax)
439        if (s[i-1] == '\n')
440            if (ld->size >= (ld->sizemax - linemax))
441                rotate(ld);
442    return i;
443}
444
445static void logdir_close(struct logdir *ld)
446{
447    if (ld->fddir == -1)
448        return;
449    if (verbose)
450        bb_error_msg(INFO"close: %s", ld->name);
451    close(ld->fddir);
452    ld->fddir = -1;
453    if (ld->fdcur == -1)
454        return; /* impossible */
455    while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
456        pause2cannot("fsync current logfile", ld->name);
457    while (fchmod(ld->fdcur, 0744) == -1)
458        pause2cannot("set mode of current", ld->name);
459    ////close(ld->fdcur);
460    fclose(ld->filecur);
461    ld->fdcur = -1;
462    if (ld->fdlock == -1)
463        return; /* impossible */
464    close(ld->fdlock);
465    ld->fdlock = -1;
466    free(ld->processor);
467    ld->processor = NULL;
468}
469
470static unsigned logdir_open(struct logdir *ld, const char *fn)
471{
472    char buf[128];
473    unsigned now;
474    char *new, *s, *np;
475    int i;
476    struct stat st;
477
478    now = monotonic_sec();
479
480    ld->fddir = open(fn, O_RDONLY|O_NDELAY);
481    if (ld->fddir == -1) {
482        warn2("cannot open log directory", (char*)fn);
483        return 0;
484    }
485    coe(ld->fddir);
486    if (fchdir(ld->fddir) == -1) {
487        logdir_close(ld);
488        warn2("cannot change directory", (char*)fn);
489        return 0;
490    }
491    ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
492    if ((ld->fdlock == -1)
493     || (lock_exnb(ld->fdlock) == -1)
494    ) {
495        logdir_close(ld);
496        warn2("cannot lock directory", (char*)fn);
497        while (fchdir(fdwdir) == -1)
498            pause1cannot("change to initial working directory");
499        return 0;
500    }
501    coe(ld->fdlock);
502
503    ld->size = 0;
504    ld->sizemax = 1000000;
505    ld->nmax = ld->nmin = 10;
506    ld->rotate_period = 0;
507    ld->name = (char*)fn;
508    ld->ppid = 0;
509    ld->match = '+';
510    free(ld->inst); ld->inst = NULL;
511    free(ld->processor); ld->processor = NULL;
512
513    /* read config */
514    i = open_read_close("config", buf, sizeof(buf));
515    if (i < 0 && errno != ENOENT)
516        bb_perror_msg(WARNING"%s/config", ld->name);
517    if (i > 0) {
518        if (verbose)
519            bb_error_msg(INFO"read: %s/config", ld->name);
520        s = buf;
521        while (s) {
522            np = strchr(s, '\n');
523            if (np)
524                *np++ = '\0';
525            switch (s[0]) {
526            case '+':
527            case '-':
528            case 'e':
529            case 'E':
530                /* Add '\n'-terminated line to ld->inst */
531                while (1) {
532                    int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);
533                    if (l >= 0 && new)
534                        break;
535                    pause_nomem();
536                }
537                free(ld->inst);
538                ld->inst = new;
539                break;
540            case 's': {
541                static const struct suffix_mult km_suffixes[] = {
542                    { "k", 1024 },
543                    { "m", 1024*1024 },
544                    { }
545                };
546                ld->sizemax = xatou_sfx(&s[1], km_suffixes);
547                break;
548            }
549            case 'n':
550                ld->nmax = xatoi_u(&s[1]);
551                break;
552            case 'N':
553                ld->nmin = xatoi_u(&s[1]);
554                break;
555            case 't': {
556                static const struct suffix_mult mh_suffixes[] = {
557                    { "m", 60 },
558                    { "h", 60*60 },
559                    /*{ "d", 24*60*60 },*/
560                    { }
561                };
562                ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
563                if (ld->rotate_period) {
564                    ld->next_rotate = now + ld->rotate_period;
565                    if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate))
566                        nearest_rotate = ld->next_rotate;
567                    tmaxflag = 1;
568                }
569                break;
570            }
571            case '!':
572                if (s[1]) {
573                    free(ld->processor);
574                    ld->processor = wstrdup(s);
575                }
576                break;
577            }
578            s = np;
579        }
580        /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
581        s = ld->inst;
582        while (s) {
583            np = strchr(s, '\n');
584            if (np)
585                *np++ = '\0';
586            s = np;
587        }
588    }
589
590    /* open current */
591    i = stat("current", &st);
592    if (i != -1) {
593        if (st.st_size && !(st.st_mode & S_IXUSR)) {
594            ld->fnsave[25] = '.';
595            ld->fnsave[26] = 'u';
596            ld->fnsave[27] = '\0';
597            do {
598                fmt_time_bernstein_25(ld->fnsave);
599                errno = 0;
600                stat(ld->fnsave, &st);
601            } while (errno != ENOENT);
602            while (rename("current", ld->fnsave) == -1)
603                pause2cannot("rename current", ld->name);
604            rmoldest(ld);
605            i = -1;
606        } else {
607            /* st.st_size can be not just bigger, but WIDER!
608             * This code is safe: if st.st_size > 4GB, we select
609             * ld->sizemax (because it's "unsigned") */
610            ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
611        }
612    } else {
613        if (errno != ENOENT) {
614            logdir_close(ld);
615            warn2("cannot stat current", ld->name);
616            while (fchdir(fdwdir) == -1)
617                pause1cannot("change to initial working directory");
618            return 0;
619        }
620    }
621    while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
622        pause2cannot("open current", ld->name);
623    /* we presume this cannot fail */
624    ld->filecur = fdopen(ld->fdcur, "a"); ////
625    setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
626
627    coe(ld->fdcur);
628    while (fchmod(ld->fdcur, 0644) == -1)
629        pause2cannot("set mode of current", ld->name);
630
631    if (verbose) {
632        if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
633        else bb_error_msg(INFO"new: %s/current", ld->name);
634    }
635
636    while (fchdir(fdwdir) == -1)
637        pause1cannot("change to initial working directory");
638    return 1;
639}
640
641static void logdirs_reopen(void)
642{
643    int l;
644    int ok = 0;
645
646    tmaxflag = 0;
647    for (l = 0; l < dirn; ++l) {
648        logdir_close(&dir[l]);
649        if (logdir_open(&dir[l], fndir[l]))
650            ok = 1;
651    }
652    if (!ok)
653        fatalx("no functional log directories");
654}
655
656/* Will look good in libbb one day */
657static ssize_t ndelay_read(int fd, void *buf, size_t count)
658{
659    if (!(fl_flag_0 & O_NONBLOCK))
660        fcntl(fd, F_SETFL, fl_flag_0 | O_NONBLOCK);
661    count = safe_read(fd, buf, count);
662    if (!(fl_flag_0 & O_NONBLOCK))
663        fcntl(fd, F_SETFL, fl_flag_0);
664    return count;
665}
666
667/* Used for reading stdin */
668static int buffer_pread(int fd, char *s, unsigned len)
669{
670    unsigned now;
671    struct pollfd input;
672    int i;
673
674    input.fd = 0;
675    input.events = POLLIN;
676
677    do {
678        if (rotateasap) {
679            for (i = 0; i < dirn; ++i)
680                rotate(dir + i);
681            rotateasap = 0;
682        }
683        if (exitasap) {
684            if (linecomplete)
685                return 0;
686            len = 1;
687        }
688        if (reopenasap) {
689            logdirs_reopen();
690            reopenasap = 0;
691        }
692        now = monotonic_sec();
693        nearest_rotate = now + (45 * 60 + 45);
694        for (i = 0; i < dirn; ++i) {
695            if (dir[i].rotate_period) {
696                if (LESS(dir[i].next_rotate, now))
697                    rotate(dir + i);
698                if (LESS(dir[i].next_rotate, nearest_rotate))
699                    nearest_rotate = dir[i].next_rotate;
700            }
701        }
702
703        sigprocmask(SIG_UNBLOCK, blocked_sigset, NULL);
704        i = nearest_rotate - now;
705        if (i > 1000000)
706            i = 1000000;
707        if (i <= 0)
708            i = 1;
709        poll(&input, 1, i * 1000);
710        sigprocmask(SIG_BLOCK, blocked_sigset, NULL);
711
712        i = ndelay_read(fd, s, len);
713        if (i >= 0)
714            break;
715        if (errno == EINTR)
716            continue;
717        if (errno != EAGAIN) {
718            warn("cannot read standard input");
719            break;
720        }
721        /* else: EAGAIN - normal, repeat silently */
722    } while (!exitasap);
723
724    if (i > 0) {
725        int cnt;
726        linecomplete = (s[i-1] == '\n');
727        if (!repl)
728            return i;
729
730        cnt = i;
731        while (--cnt >= 0) {
732            char ch = *s;
733            if (ch != '\n') {
734                if (ch < 32 || ch > 126)
735                    *s = repl;
736                else {
737                    int j;
738                    for (j = 0; replace[j]; ++j) {
739                        if (ch == replace[j]) {
740                            *s = repl;
741                            break;
742                        }
743                    }
744                }
745            }
746            s++;
747        }
748    }
749    return i;
750}
751
752static void sig_term_handler(int sig_no)
753{
754    if (verbose)
755        bb_error_msg(INFO"sig%s received", "term");
756    exitasap = 1;
757}
758
759static void sig_child_handler(int sig_no)
760{
761    int pid, l;
762
763    if (verbose)
764        bb_error_msg(INFO"sig%s received", "child");
765    while ((pid = wait_nohang(&wstat)) > 0) {
766        for (l = 0; l < dirn; ++l) {
767            if (dir[l].ppid == pid) {
768                dir[l].ppid = 0;
769                processorstop(&dir[l]);
770                break;
771            }
772        }
773    }
774}
775
776static void sig_alarm_handler(int sig_no)
777{
778    if (verbose)
779        bb_error_msg(INFO"sig%s received", "alarm");
780    rotateasap = 1;
781}
782
783static void sig_hangup_handler(int sig_no)
784{
785    if (verbose)
786        bb_error_msg(INFO"sig%s received", "hangup");
787    reopenasap = 1;
788}
789
790static void logmatch(struct logdir *ld)
791{
792    char *s;
793
794    ld->match = '+';
795    ld->matcherr = 'E';
796    s = ld->inst;
797    while (s && s[0]) {
798        switch (s[0]) {
799        case '+':
800        case '-':
801            if (pmatch(s+1, line, linelen))
802                ld->match = s[0];
803            break;
804        case 'e':
805        case 'E':
806            if (pmatch(s+1, line, linelen))
807                ld->matcherr = s[0];
808            break;
809        }
810        s += strlen(s) + 1;
811    }
812}
813
814int svlogd_main(int argc, char **argv);
815int svlogd_main(int argc, char **argv)
816{
817    sigset_t ss;
818    char *r,*l,*b;
819    ssize_t stdin_cnt = 0;
820    int i;
821    unsigned opt;
822    unsigned timestamp = 0;
823    void* (*memRchr)(const void *, int, size_t) = memchr;
824
825#define line bb_common_bufsiz1
826
827    opt_complementary = "tt:vv";
828    opt = getopt32(argv, "r:R:l:b:tv",
829            &r, &replace, &l, &b, &timestamp, &verbose);
830    if (opt & 1) { // -r
831        repl = r[0];
832        if (!repl || r[1]) usage();
833    }
834    if (opt & 2) if (!repl) repl = '_'; // -R
835    if (opt & 4) { // -l
836        linemax = xatou_range(l, 0, BUFSIZ-26);
837        if (linemax == 0) linemax = BUFSIZ-26;
838        if (linemax < 256) linemax = 256;
839    }
840    ////if (opt & 8) { // -b
841    ////    buflen = xatoi_u(b);
842    ////    if (buflen == 0) buflen = 1024;
843    ////}
844    //if (opt & 0x10) timestamp++; // -t
845    //if (opt & 0x20) verbose++; // -v
846    //if (timestamp > 2) timestamp = 2;
847    argv += optind;
848    argc -= optind;
849
850    dirn = argc;
851    if (dirn <= 0) usage();
852    ////if (buflen <= linemax) usage();
853    fdwdir = xopen(".", O_RDONLY|O_NDELAY);
854    coe(fdwdir);
855    dir = xzalloc(dirn * sizeof(struct logdir));
856    for (i = 0; i < dirn; ++i) {
857        dir[i].fddir = -1;
858        dir[i].fdcur = -1;
859        ////dir[i].btmp = xmalloc(buflen);
860        /*dir[i].ppid = 0;*/
861    }
862    /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
863    fndir = argv;
864    /* We cannot set NONBLOCK on fd #0 permanently - this setting
865     * _isn't_ per-process! It is shared among all other processes
866     * with the same stdin */
867    fl_flag_0 = fcntl(0, F_GETFL);
868
869    blocked_sigset = &ss;
870    sigemptyset(&ss);
871    sigaddset(&ss, SIGTERM);
872    sigaddset(&ss, SIGCHLD);
873    sigaddset(&ss, SIGALRM);
874    sigaddset(&ss, SIGHUP);
875    sigprocmask(SIG_BLOCK, &ss, NULL);
876    sig_catch(SIGTERM, sig_term_handler);
877    sig_catch(SIGCHLD, sig_child_handler);
878    sig_catch(SIGALRM, sig_alarm_handler);
879    sig_catch(SIGHUP, sig_hangup_handler);
880
881    logdirs_reopen();
882
883    /* Without timestamps, we don't have to print each line
884     * separately, so we can look for _last_ newline, not first,
885     * thus batching writes */
886    if (!timestamp)
887        memRchr = memrchr;
888
889    setvbuf(stderr, NULL, _IOFBF, linelen);
890
891    /* Each iteration processes one or more lines */
892    while (1) {
893        char stamp[FMT_PTIME];
894        char *lineptr;
895        char *printptr;
896        char *np;
897        int printlen;
898        char ch;
899
900        lineptr = line;
901        if (timestamp)
902            lineptr += 26;
903
904        /* lineptr[0..linemax-1] - buffer for stdin */
905        /* (possibly has some unprocessed data from prev loop) */
906
907        /* Refill the buffer if needed */
908        np = memRchr(lineptr, '\n', stdin_cnt);
909        if (!np && !exitasap) {
910            i = linemax - stdin_cnt; /* avail. bytes at tail */
911            if (i >= 128) {
912                i = buffer_pread(0, lineptr + stdin_cnt, i);
913                if (i <= 0) /* EOF or error on stdin */
914                    exitasap = 1;
915                else {
916                    np = memRchr(lineptr + stdin_cnt, '\n', i);
917                    stdin_cnt += i;
918                }
919            }
920        }
921        if (stdin_cnt <= 0 && exitasap)
922            break;
923
924        /* Search for '\n' (in fact, np already holds the result) */
925        linelen = stdin_cnt;
926        if (np) {
927 print_to_nl:       /* NB: starting from here lineptr may point
928             * farther out into line[] */
929            linelen = np - lineptr + 1;
930        }
931        /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
932        ch = lineptr[linelen-1];
933
934        /* Biggest performance hit was coming from the fact
935         * that we did not buffer writes. We were reading many lines
936         * in one read() above, but wrote one line per write().
937         * We are using stdio to fix that */
938
939        /* write out lineptr[0..linelen-1] to each log destination
940         * (or lineptr[-26..linelen-1] if timestamping) */
941        printlen = linelen;
942        printptr = lineptr;
943        if (timestamp) {
944            if (timestamp == 1)
945                fmt_time_bernstein_25(stamp);
946            else /* 2: */
947                fmt_time_human_30nul(stamp);
948            printlen += 26;
949            printptr -= 26;
950            memcpy(printptr, stamp, 25);
951            printptr[25] = ' ';
952        }
953        for (i = 0; i < dirn; ++i) {
954            struct logdir *ld = &dir[i];
955            if (ld->fddir == -1) continue;
956            if (ld->inst)
957                logmatch(ld);
958            if (ld->matcherr == 'e')
959                ////full_write(2, printptr, printlen);
960                fwrite(lineptr, 1, linelen, stderr);
961            if (ld->match != '+') continue;
962            buffer_pwrite(i, printptr, printlen);
963        }
964
965        /* If we didn't see '\n' (long input line), */
966        /* read/write repeatedly until we see it */
967        while (ch != '\n') {
968            /* lineptr is emptied now, safe to use as buffer */
969            stdin_cnt = exitasap ? -1 : buffer_pread(0, lineptr, linemax);
970            if (stdin_cnt <= 0) { /* EOF or error on stdin */
971                exitasap = 1;
972                lineptr[0] = ch = '\n';
973                linelen = 1;
974                stdin_cnt = 1;
975            } else {
976                linelen = stdin_cnt;
977                np = memRchr(lineptr, '\n', stdin_cnt);
978                if (np)
979                    linelen = np - lineptr + 1;
980                ch = lineptr[linelen-1];
981            }
982            /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
983            for (i = 0; i < dirn; ++i) {
984                if (dir[i].fddir == -1) continue;
985                if (dir[i].matcherr == 'e')
986                    ////full_write(2, lineptr, linelen);
987                    fwrite(lineptr, 1, linelen, stderr);
988                if (dir[i].match != '+') continue;
989                buffer_pwrite(i, lineptr, linelen);
990            }
991        }
992
993        stdin_cnt -= linelen;
994        if (stdin_cnt > 0) {
995            lineptr += linelen;
996            /* If we see another '\n', we don't need to read
997             * next piece of input: can print what we have */
998            np = memRchr(lineptr, '\n', stdin_cnt);
999            if (np)
1000                goto print_to_nl;
1001            /* Move unprocessed data to the front of line */
1002            memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1003        }
1004        fflush(NULL);////
1005    }
1006
1007    for (i = 0; i < dirn; ++i) {
1008        if (dir[i].ppid)
1009            while (!processorstop(&dir[i]))
1010                /* repeat */;
1011        logdir_close(&dir[i]);
1012    }
1013    return 0;
1014}
Note: See TracBrowser for help on using the repository browser.