diff options
Diffstat (limited to 'runit/svlogd.c')
-rw-r--r-- | runit/svlogd.c | 198 |
1 files changed, 127 insertions, 71 deletions
diff --git a/runit/svlogd.c b/runit/svlogd.c index 8632ba6a5..b8fa5645b 100644 --- a/runit/svlogd.c +++ b/runit/svlogd.c | |||
@@ -33,6 +33,10 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
33 | #include "libbb.h" | 33 | #include "libbb.h" |
34 | #include "runit_lib.h" | 34 | #include "runit_lib.h" |
35 | 35 | ||
36 | #define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0) | ||
37 | |||
38 | #define FMT_PTIME 30 | ||
39 | |||
36 | static unsigned verbose; | 40 | static unsigned verbose; |
37 | static int linemax = 1000; | 41 | static int linemax = 1000; |
38 | ////static int buflen = 1024; | 42 | ////static int buflen = 1024; |
@@ -41,7 +45,7 @@ static int linelen; | |||
41 | static char **fndir; | 45 | static char **fndir; |
42 | static int fdwdir; | 46 | static int fdwdir; |
43 | static int wstat; | 47 | static int wstat; |
44 | static struct taia trotate; | 48 | static unsigned nearest_rotate; |
45 | 49 | ||
46 | static char *line; | 50 | static char *line; |
47 | static smallint exitasap; | 51 | static smallint exitasap; |
@@ -55,7 +59,6 @@ static char repl; | |||
55 | static const char *replace = ""; | 59 | static const char *replace = ""; |
56 | 60 | ||
57 | static sigset_t *blocked_sigset; | 61 | static sigset_t *blocked_sigset; |
58 | static iopause_fd input; | ||
59 | static int fl_flag_0; | 62 | static int fl_flag_0; |
60 | 63 | ||
61 | static struct logdir { | 64 | static struct logdir { |
@@ -68,14 +71,13 @@ static struct logdir { | |||
68 | unsigned sizemax; | 71 | unsigned sizemax; |
69 | unsigned nmax; | 72 | unsigned nmax; |
70 | unsigned nmin; | 73 | unsigned nmin; |
71 | /* int (not long) because of taia_uint() usage: */ | 74 | unsigned rotate_period; |
72 | unsigned tmax; | ||
73 | int ppid; | 75 | int ppid; |
74 | int fddir; | 76 | int fddir; |
75 | int fdcur; | 77 | int fdcur; |
76 | FILE* filecur; //// | 78 | FILE* filecur; //// |
77 | int fdlock; | 79 | int fdlock; |
78 | struct taia trotate; | 80 | unsigned next_rotate; |
79 | char fnsave[FMT_PTIME]; | 81 | char fnsave[FMT_PTIME]; |
80 | char match; | 82 | char match; |
81 | char matcherr; | 83 | char matcherr; |
@@ -128,6 +130,50 @@ static char* wstrdup(const char *str) | |||
128 | return s; | 130 | return s; |
129 | } | 131 | } |
130 | 132 | ||
133 | /*** ex fmt_ptime.[ch] ***/ | ||
134 | |||
135 | /* NUL terminated */ | ||
136 | static 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! */ | ||
158 | static 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 | |||
131 | static unsigned processorstart(struct logdir *ld) | 177 | static unsigned processorstart(struct logdir *ld) |
132 | { | 178 | { |
133 | int pid; | 179 | int pid; |
@@ -264,15 +310,15 @@ static void rmoldest(struct logdir *ld) | |||
264 | static unsigned rotate(struct logdir *ld) | 310 | static unsigned rotate(struct logdir *ld) |
265 | { | 311 | { |
266 | struct stat st; | 312 | struct stat st; |
267 | struct taia now; | 313 | unsigned now; |
268 | 314 | ||
269 | if (ld->fddir == -1) { | 315 | if (ld->fddir == -1) { |
270 | ld->tmax = 0; | 316 | ld->rotate_period = 0; |
271 | return 0; | 317 | return 0; |
272 | } | 318 | } |
273 | if (ld->ppid) | 319 | if (ld->ppid) |
274 | while (!processorstop(ld)) | 320 | while (!processorstop(ld)) |
275 | /* wait */; | 321 | continue; |
276 | 322 | ||
277 | while (fchdir(ld->fddir) == -1) | 323 | while (fchdir(ld->fddir) == -1) |
278 | pause2cannot("change directory, want rotate", ld->name); | 324 | pause2cannot("change directory, want rotate", ld->name); |
@@ -284,17 +330,16 @@ static unsigned rotate(struct logdir *ld) | |||
284 | ld->fnsave[26] = 'u'; | 330 | ld->fnsave[26] = 'u'; |
285 | ld->fnsave[27] = '\0'; | 331 | ld->fnsave[27] = '\0'; |
286 | do { | 332 | do { |
287 | taia_now(&now); | 333 | fmt_time_bernstein_25(ld->fnsave); |
288 | fmt_taia25(ld->fnsave, &now); | ||
289 | errno = 0; | 334 | errno = 0; |
290 | stat(ld->fnsave, &st); | 335 | stat(ld->fnsave, &st); |
291 | } while (errno != ENOENT); | 336 | } while (errno != ENOENT); |
292 | 337 | ||
293 | if (ld->tmax && taia_less(&ld->trotate, &now)) { | 338 | now = monotonic_sec(); |
294 | taia_uint(&ld->trotate, ld->tmax); | 339 | if (ld->rotate_period && LESS(ld->next_rotate, now)) { |
295 | taia_add(&ld->trotate, &now, &ld->trotate); | 340 | ld->next_rotate = now + ld->rotate_period; |
296 | if (taia_less(&ld->trotate, &trotate)) | 341 | if (LESS(ld->next_rotate, nearest_rotate)) |
297 | trotate = ld->trotate; | 342 | nearest_rotate = ld->next_rotate; |
298 | } | 343 | } |
299 | 344 | ||
300 | if (ld->size > 0) { | 345 | if (ld->size > 0) { |
@@ -425,11 +470,13 @@ static void logdir_close(struct logdir *ld) | |||
425 | static unsigned logdir_open(struct logdir *ld, const char *fn) | 470 | static unsigned logdir_open(struct logdir *ld, const char *fn) |
426 | { | 471 | { |
427 | char buf[128]; | 472 | char buf[128]; |
428 | struct taia now; | 473 | unsigned now; |
429 | char *new, *s, *np; | 474 | char *new, *s, *np; |
430 | int i; | 475 | int i; |
431 | struct stat st; | 476 | struct stat st; |
432 | 477 | ||
478 | now = monotonic_sec(); | ||
479 | |||
433 | ld->fddir = open(fn, O_RDONLY|O_NDELAY); | 480 | ld->fddir = open(fn, O_RDONLY|O_NDELAY); |
434 | if (ld->fddir == -1) { | 481 | if (ld->fddir == -1) { |
435 | warn2("cannot open log directory", (char*)fn); | 482 | warn2("cannot open log directory", (char*)fn); |
@@ -456,7 +503,7 @@ static unsigned logdir_open(struct logdir *ld, const char *fn) | |||
456 | ld->size = 0; | 503 | ld->size = 0; |
457 | ld->sizemax = 1000000; | 504 | ld->sizemax = 1000000; |
458 | ld->nmax = ld->nmin = 10; | 505 | ld->nmax = ld->nmin = 10; |
459 | ld->tmax = 0; | 506 | ld->rotate_period = 0; |
460 | ld->name = (char*)fn; | 507 | ld->name = (char*)fn; |
461 | ld->ppid = 0; | 508 | ld->ppid = 0; |
462 | ld->match = '+'; | 509 | ld->match = '+'; |
@@ -468,7 +515,8 @@ static unsigned logdir_open(struct logdir *ld, const char *fn) | |||
468 | if (i < 0 && errno != ENOENT) | 515 | if (i < 0 && errno != ENOENT) |
469 | bb_perror_msg(WARNING": %s/config", ld->name); | 516 | bb_perror_msg(WARNING": %s/config", ld->name); |
470 | if (i > 0) { | 517 | if (i > 0) { |
471 | if (verbose) bb_error_msg(INFO"read: %s/config", ld->name); | 518 | if (verbose) |
519 | bb_error_msg(INFO"read: %s/config", ld->name); | ||
472 | s = buf; | 520 | s = buf; |
473 | while (s) { | 521 | while (s) { |
474 | np = strchr(s, '\n'); | 522 | np = strchr(s, '\n'); |
@@ -508,12 +556,11 @@ static unsigned logdir_open(struct logdir *ld, const char *fn) | |||
508 | /*{ "d", 24*60*60 },*/ | 556 | /*{ "d", 24*60*60 },*/ |
509 | { } | 557 | { } |
510 | }; | 558 | }; |
511 | ld->tmax = xatou_sfx(&s[1], mh_suffixes); | 559 | ld->rotate_period = xatou_sfx(&s[1], mh_suffixes); |
512 | if (ld->tmax) { | 560 | if (ld->rotate_period) { |
513 | taia_uint(&ld->trotate, ld->tmax); | 561 | ld->next_rotate = now + ld->rotate_period; |
514 | taia_add(&ld->trotate, &now, &ld->trotate); | 562 | if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate)) |
515 | if (!tmaxflag || taia_less(&ld->trotate, &trotate)) | 563 | nearest_rotate = ld->next_rotate; |
516 | trotate = ld->trotate; | ||
517 | tmaxflag = 1; | 564 | tmaxflag = 1; |
518 | } | 565 | } |
519 | break; | 566 | break; |
@@ -544,8 +591,7 @@ static unsigned logdir_open(struct logdir *ld, const char *fn) | |||
544 | ld->fnsave[26] = 'u'; | 591 | ld->fnsave[26] = 'u'; |
545 | ld->fnsave[27] = '\0'; | 592 | ld->fnsave[27] = '\0'; |
546 | do { | 593 | do { |
547 | taia_now(&now); | 594 | fmt_time_bernstein_25(ld->fnsave); |
548 | fmt_taia25(ld->fnsave, &now); | ||
549 | errno = 0; | 595 | errno = 0; |
550 | stat(ld->fnsave, &st); | 596 | stat(ld->fnsave, &st); |
551 | } while (errno != ENOENT); | 597 | } while (errno != ENOENT); |
@@ -589,17 +635,17 @@ static unsigned logdir_open(struct logdir *ld, const char *fn) | |||
589 | 635 | ||
590 | static void logdirs_reopen(void) | 636 | static void logdirs_reopen(void) |
591 | { | 637 | { |
592 | struct taia now; | ||
593 | int l; | 638 | int l; |
594 | int ok = 0; | 639 | int ok = 0; |
595 | 640 | ||
596 | tmaxflag = 0; | 641 | tmaxflag = 0; |
597 | taia_now(&now); | ||
598 | for (l = 0; l < dirn; ++l) { | 642 | for (l = 0; l < dirn; ++l) { |
599 | logdir_close(&dir[l]); | 643 | logdir_close(&dir[l]); |
600 | if (logdir_open(&dir[l], fndir[l])) ok = 1; | 644 | if (logdir_open(&dir[l], fndir[l])) |
645 | ok = 1; | ||
601 | } | 646 | } |
602 | if (!ok) fatalx("no functional log directories"); | 647 | if (!ok) |
648 | fatalx("no functional log directories"); | ||
603 | } | 649 | } |
604 | 650 | ||
605 | /* Will look good in libbb one day */ | 651 | /* Will look good in libbb one day */ |
@@ -614,42 +660,55 @@ static ssize_t ndelay_read(int fd, void *buf, size_t count) | |||
614 | } | 660 | } |
615 | 661 | ||
616 | /* Used for reading stdin */ | 662 | /* Used for reading stdin */ |
617 | static int buffer_pread(int fd, char *s, unsigned len, struct taia *now) | 663 | static int buffer_pread(int fd, char *s, unsigned len) |
618 | { | 664 | { |
665 | unsigned now; | ||
666 | struct pollfd input; | ||
619 | int i; | 667 | int i; |
620 | 668 | ||
621 | if (rotateasap) { | 669 | input.fd = 0; |
622 | for (i = 0; i < dirn; ++i) | 670 | input.events = POLLIN|POLLHUP|POLLERR; |
623 | rotate(dir+i); | ||
624 | rotateasap = 0; | ||
625 | } | ||
626 | if (exitasap) { | ||
627 | if (linecomplete) | ||
628 | return 0; | ||
629 | len = 1; | ||
630 | } | ||
631 | if (reopenasap) { | ||
632 | logdirs_reopen(); | ||
633 | reopenasap = 0; | ||
634 | } | ||
635 | taia_uint(&trotate, 2744); | ||
636 | taia_add(&trotate, now, &trotate); | ||
637 | for (i = 0; i < dirn; ++i) | ||
638 | if (dir[i].tmax) { | ||
639 | if (taia_less(&dir[i].trotate, now)) | ||
640 | rotate(dir+i); | ||
641 | if (taia_less(&dir[i].trotate, &trotate)) | ||
642 | trotate = dir[i].trotate; | ||
643 | } | ||
644 | 671 | ||
645 | do { | 672 | do { |
673 | if (rotateasap) { | ||
674 | for (i = 0; i < dirn; ++i) | ||
675 | rotate(dir + i); | ||
676 | rotateasap = 0; | ||
677 | } | ||
678 | if (exitasap) { | ||
679 | if (linecomplete) | ||
680 | return 0; | ||
681 | len = 1; | ||
682 | } | ||
683 | if (reopenasap) { | ||
684 | logdirs_reopen(); | ||
685 | reopenasap = 0; | ||
686 | } | ||
687 | now = monotonic_sec(); | ||
688 | nearest_rotate = now + (45 * 60 + 45); | ||
689 | for (i = 0; i < dirn; ++i) { | ||
690 | if (dir[i].rotate_period) { | ||
691 | if (LESS(dir[i].next_rotate, now)) | ||
692 | rotate(dir + i); | ||
693 | if (LESS(dir[i].next_rotate, nearest_rotate)) | ||
694 | nearest_rotate = dir[i].next_rotate; | ||
695 | } | ||
696 | } | ||
697 | |||
646 | sigprocmask(SIG_UNBLOCK, blocked_sigset, NULL); | 698 | sigprocmask(SIG_UNBLOCK, blocked_sigset, NULL); |
647 | iopause(&input, 1, &trotate, now); | 699 | i = nearest_rotate - now; |
648 | // TODO: do not unblock/block, but use sigpending after iopause | 700 | if (i > 1000000) |
649 | // to see whether there was any sig? (one syscall less...) | 701 | i = 1000000; |
702 | if (i <= 0) | ||
703 | i = 1; | ||
704 | poll(&input, 1, i * 1000); | ||
650 | sigprocmask(SIG_BLOCK, blocked_sigset, NULL); | 705 | sigprocmask(SIG_BLOCK, blocked_sigset, NULL); |
706 | |||
651 | i = ndelay_read(fd, s, len); | 707 | i = ndelay_read(fd, s, len); |
652 | if (i >= 0) break; | 708 | if (i >= 0) |
709 | break; | ||
710 | if (errno == EINTR) | ||
711 | continue; | ||
653 | if (errno != EAGAIN) { | 712 | if (errno != EAGAIN) { |
654 | warn("cannot read standard input"); | 713 | warn("cannot read standard input"); |
655 | break; | 714 | break; |
@@ -660,7 +719,8 @@ static int buffer_pread(int fd, char *s, unsigned len, struct taia *now) | |||
660 | if (i > 0) { | 719 | if (i > 0) { |
661 | int cnt; | 720 | int cnt; |
662 | linecomplete = (s[i-1] == '\n'); | 721 | linecomplete = (s[i-1] == '\n'); |
663 | if (!repl) return i; | 722 | if (!repl) |
723 | return i; | ||
664 | 724 | ||
665 | cnt = i; | 725 | cnt = i; |
666 | while (--cnt >= 0) { | 726 | while (--cnt >= 0) { |
@@ -698,13 +758,15 @@ static void sig_child_handler(int sig_no) | |||
698 | 758 | ||
699 | if (verbose) | 759 | if (verbose) |
700 | bb_error_msg(INFO"sig%s received", "child"); | 760 | bb_error_msg(INFO"sig%s received", "child"); |
701 | while ((pid = wait_nohang(&wstat)) > 0) | 761 | while ((pid = wait_nohang(&wstat)) > 0) { |
702 | for (l = 0; l < dirn; ++l) | 762 | for (l = 0; l < dirn; ++l) { |
703 | if (dir[l].ppid == pid) { | 763 | if (dir[l].ppid == pid) { |
704 | dir[l].ppid = 0; | 764 | dir[l].ppid = 0; |
705 | processorstop(&dir[l]); | 765 | processorstop(&dir[l]); |
706 | break; | 766 | break; |
707 | } | 767 | } |
768 | } | ||
769 | } | ||
708 | } | 770 | } |
709 | 771 | ||
710 | static void sig_alarm_handler(int sig_no) | 772 | static void sig_alarm_handler(int sig_no) |
@@ -795,8 +857,6 @@ int svlogd_main(int argc, char **argv) | |||
795 | } | 857 | } |
796 | /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */ | 858 | /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */ |
797 | fndir = argv; | 859 | fndir = argv; |
798 | input.fd = 0; | ||
799 | input.events = IOPAUSE_READ; | ||
800 | /* We cannot set NONBLOCK on fd #0 permanently - this setting | 860 | /* We cannot set NONBLOCK on fd #0 permanently - this setting |
801 | * _isn't_ per-process! It is shared among all other processes | 861 | * _isn't_ per-process! It is shared among all other processes |
802 | * with the same stdin */ | 862 | * with the same stdin */ |
@@ -826,7 +886,6 @@ int svlogd_main(int argc, char **argv) | |||
826 | 886 | ||
827 | /* Each iteration processes one or more lines */ | 887 | /* Each iteration processes one or more lines */ |
828 | while (1) { | 888 | while (1) { |
829 | struct taia now; | ||
830 | char stamp[FMT_PTIME]; | 889 | char stamp[FMT_PTIME]; |
831 | char *lineptr; | 890 | char *lineptr; |
832 | char *printptr; | 891 | char *printptr; |
@@ -846,8 +905,7 @@ int svlogd_main(int argc, char **argv) | |||
846 | if (!np && !exitasap) { | 905 | if (!np && !exitasap) { |
847 | i = linemax - stdin_cnt; /* avail. bytes at tail */ | 906 | i = linemax - stdin_cnt; /* avail. bytes at tail */ |
848 | if (i >= 128) { | 907 | if (i >= 128) { |
849 | taia_now(&now); | 908 | i = buffer_pread(0, lineptr + stdin_cnt, i); |
850 | i = buffer_pread(0, lineptr + stdin_cnt, i, &now); | ||
851 | if (i <= 0) /* EOF or error on stdin */ | 909 | if (i <= 0) /* EOF or error on stdin */ |
852 | exitasap = 1; | 910 | exitasap = 1; |
853 | else { | 911 | else { |
@@ -879,11 +937,10 @@ int svlogd_main(int argc, char **argv) | |||
879 | printlen = linelen; | 937 | printlen = linelen; |
880 | printptr = lineptr; | 938 | printptr = lineptr; |
881 | if (timestamp) { | 939 | if (timestamp) { |
882 | taia_now(&now); | ||
883 | if (timestamp == 1) | 940 | if (timestamp == 1) |
884 | fmt_taia25(stamp, &now); | 941 | fmt_time_bernstein_25(stamp); |
885 | else /* 2: */ | 942 | else /* 2: */ |
886 | fmt_ptime30nul(stamp, &now); | 943 | fmt_time_human_30nul(stamp); |
887 | printlen += 26; | 944 | printlen += 26; |
888 | printptr -= 26; | 945 | printptr -= 26; |
889 | memcpy(printptr, stamp, 25); | 946 | memcpy(printptr, stamp, 25); |
@@ -905,8 +962,7 @@ int svlogd_main(int argc, char **argv) | |||
905 | /* read/write repeatedly until we see it */ | 962 | /* read/write repeatedly until we see it */ |
906 | while (ch != '\n') { | 963 | while (ch != '\n') { |
907 | /* lineptr is emptied now, safe to use as buffer */ | 964 | /* lineptr is emptied now, safe to use as buffer */ |
908 | taia_now(&now); | 965 | stdin_cnt = exitasap ? -1 : buffer_pread(0, lineptr, linemax); |
909 | stdin_cnt = exitasap ? -1 : buffer_pread(0, lineptr, linemax, &now); | ||
910 | if (stdin_cnt <= 0) { /* EOF or error on stdin */ | 966 | if (stdin_cnt <= 0) { /* EOF or error on stdin */ |
911 | exitasap = 1; | 967 | exitasap = 1; |
912 | lineptr[0] = ch = '\n'; | 968 | lineptr[0] = ch = '\n'; |