1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145#include <sys/file.h>
146#include "libbb.h"
147#include "runit_lib.h"
148
149#define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0)
150
151#define FMT_PTIME 30
152
153struct logdir {
154
155
156 char *inst;
157 char *processor;
158 char *name;
159 unsigned size;
160 unsigned sizemax;
161 unsigned nmax;
162 unsigned nmin;
163 unsigned rotate_period;
164 int ppid;
165 int fddir;
166 int fdcur;
167 FILE* filecur;
168 int fdlock;
169 unsigned next_rotate;
170 char fnsave[FMT_PTIME];
171 char match;
172 char matcherr;
173};
174
175
176struct globals {
177 struct logdir *dir;
178 unsigned verbose;
179 int linemax;
180
181 int linelen;
182
183 int fdwdir;
184 char **fndir;
185 int wstat;
186 unsigned nearest_rotate;
187
188 void* (*memRchr)(const void *, int, size_t);
189 char *shell;
190
191 smallint exitasap;
192 smallint rotateasap;
193 smallint reopenasap;
194 smallint linecomplete;
195 smallint tmaxflag;
196
197 char repl;
198 const char *replace;
199 int fl_flag_0;
200 unsigned dirn;
201
202 sigset_t blocked_sigset;
203};
204#define G (*ptr_to_globals)
205#define dir (G.dir )
206#define verbose (G.verbose )
207#define linemax (G.linemax )
208#define buflen (G.buflen )
209#define linelen (G.linelen )
210#define fndir (G.fndir )
211#define fdwdir (G.fdwdir )
212#define wstat (G.wstat )
213#define memRchr (G.memRchr )
214#define nearest_rotate (G.nearest_rotate)
215#define exitasap (G.exitasap )
216#define rotateasap (G.rotateasap )
217#define reopenasap (G.reopenasap )
218#define linecomplete (G.linecomplete )
219#define tmaxflag (G.tmaxflag )
220#define repl (G.repl )
221#define replace (G.replace )
222#define blocked_sigset (G.blocked_sigset)
223#define fl_flag_0 (G.fl_flag_0 )
224#define dirn (G.dirn )
225#define INIT_G() do { \
226 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
227 linemax = 1000; \
228 \
229 linecomplete = 1; \
230 replace = ""; \
231} while (0)
232
233#define line bb_common_bufsiz1
234
235
236#define FATAL "fatal: "
237#define WARNING "warning: "
238#define PAUSE "pausing: "
239#define INFO "info: "
240
241static void fatalx(const char *m0)
242{
243 bb_error_msg_and_die(FATAL"%s", m0);
244}
245static void warn(const char *m0)
246{
247 bb_perror_msg(WARNING"%s", m0);
248}
249static void warn2(const char *m0, const char *m1)
250{
251 bb_perror_msg(WARNING"%s: %s", m0, m1);
252}
253static void warnx(const char *m0, const char *m1)
254{
255 bb_error_msg(WARNING"%s: %s", m0, m1);
256}
257static void pause_nomem(void)
258{
259 bb_error_msg(PAUSE"out of memory");
260 sleep(3);
261}
262static void pause1cannot(const char *m0)
263{
264 bb_perror_msg(PAUSE"can't %s", m0);
265 sleep(3);
266}
267static void pause2cannot(const char *m0, const char *m1)
268{
269 bb_perror_msg(PAUSE"can't %s %s", m0, m1);
270 sleep(3);
271}
272
273static char* wstrdup(const char *str)
274{
275 char *s;
276 while (!(s = strdup(str)))
277 pause_nomem();
278 return s;
279}
280
281static unsigned pmatch(const char *p, const char *s, unsigned len)
282{
283 for (;;) {
284 char c = *p++;
285 if (!c) return !len;
286 switch (c) {
287 case '*':
288 c = *p;
289 if (!c) return 1;
290 for (;;) {
291 if (!len) return 0;
292 if (*s == c) break;
293 ++s;
294 --len;
295 }
296 continue;
297 case '+':
298 c = *p++;
299 if (c != *s) return 0;
300 for (;;) {
301 if (!len) return 1;
302 if (*s != c) break;
303 ++s;
304 --len;
305 }
306 continue;
307
308
309
310
311
312
313
314
315
316 default:
317 if (!len) return 0;
318 if (*s != c) return 0;
319 ++s;
320 --len;
321 continue;
322 }
323 }
324 return 0;
325}
326
327
328
329
330static void fmt_time_human_30nul(char *s)
331{
332 struct tm *ptm;
333 struct timeval tv;
334
335 gettimeofday(&tv, NULL);
336 ptm = gmtime(&tv.tv_sec);
337 sprintf(s, "%04u-%02u-%02u_%02u:%02u:%02u.%06u000",
338 (unsigned)(1900 + ptm->tm_year),
339 (unsigned)(ptm->tm_mon + 1),
340 (unsigned)(ptm->tm_mday),
341 (unsigned)(ptm->tm_hour),
342 (unsigned)(ptm->tm_min),
343 (unsigned)(ptm->tm_sec),
344 (unsigned)(tv.tv_usec)
345 );
346
347
348
349}
350
351
352static void fmt_time_bernstein_25(char *s)
353{
354 uint32_t pack[3];
355 struct timeval tv;
356 unsigned sec_hi;
357
358 gettimeofday(&tv, NULL);
359 sec_hi = (0x400000000000000aULL + tv.tv_sec) >> 32;
360 tv.tv_sec = (time_t)(0x400000000000000aULL) + tv.tv_sec;
361 tv.tv_usec *= 1000;
362
363
364 pack[0] = htonl(sec_hi);
365 pack[1] = htonl(tv.tv_sec);
366 pack[2] = htonl(tv.tv_usec);
367 *s++ = '@';
368 bin2hex(s, (char*)pack, 12);
369}
370
371static void processorstart(struct logdir *ld)
372{
373 char sv_ch;
374 int pid;
375
376 if (!ld->processor) return;
377 if (ld->ppid) {
378 warnx("processor already running", ld->name);
379 return;
380 }
381
382
383 sv_ch = ld->fnsave[26];
384
385 if (!G.shell)
386 G.shell = xstrdup(get_shell_name());
387
388 while ((pid = vfork()) == -1)
389 pause2cannot("vfork for processor", ld->name);
390 if (!pid) {
391 int fd;
392
393
394
395
396
397
398
399
400 sig_unblock(SIGTERM);
401 sig_unblock(SIGALRM);
402 sig_unblock(SIGHUP);
403
404 if (verbose)
405 bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
406 fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
407 xmove_fd(fd, 0);
408 ld->fnsave[26] = 't';
409 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
410 xmove_fd(fd, 1);
411 fd = open("state", O_RDONLY|O_NDELAY);
412 if (fd == -1) {
413 if (errno != ENOENT)
414 bb_perror_msg_and_die(FATAL"can't %s processor %s", "open state for", ld->name);
415 close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
416 fd = xopen("state", O_RDONLY|O_NDELAY);
417 }
418 xmove_fd(fd, 4);
419 fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
420 xmove_fd(fd, 5);
421
422 execl(G.shell, G.shell, "-c", ld->processor, (char*) NULL);
423 bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name);
424 }
425 ld->fnsave[26] = sv_ch;
426 ld->ppid = pid;
427}
428
429static unsigned processorstop(struct logdir *ld)
430{
431 char f[28];
432
433 if (ld->ppid) {
434 sig_unblock(SIGHUP);
435 while (safe_waitpid(ld->ppid, &wstat, 0) == -1)
436 pause2cannot("wait for processor", ld->name);
437 sig_block(SIGHUP);
438 ld->ppid = 0;
439 }
440 if (ld->fddir == -1)
441 return 1;
442 while (fchdir(ld->fddir) == -1)
443 pause2cannot("change directory, want processor", ld->name);
444 if (WEXITSTATUS(wstat) != 0) {
445 warnx("processor failed, restart", ld->name);
446 ld->fnsave[26] = 't';
447 unlink(ld->fnsave);
448 ld->fnsave[26] = 'u';
449 processorstart(ld);
450 while (fchdir(fdwdir) == -1)
451 pause1cannot("change to initial working directory");
452 return ld->processor ? 0 : 1;
453 }
454 ld->fnsave[26] = 't';
455 memcpy(f, ld->fnsave, 26);
456 f[26] = 's';
457 f[27] = '\0';
458 while (rename(ld->fnsave, f) == -1)
459 pause2cannot("rename processed", ld->name);
460 while (chmod(f, 0744) == -1)
461 pause2cannot("set mode of processed", ld->name);
462 ld->fnsave[26] = 'u';
463 if (unlink(ld->fnsave) == -1)
464 bb_error_msg(WARNING"can't unlink: %s/%s", ld->name, ld->fnsave);
465 while (rename("newstate", "state") == -1)
466 pause2cannot("rename state", ld->name);
467 if (verbose)
468 bb_error_msg(INFO"processed: %s/%s", ld->name, f);
469 while (fchdir(fdwdir) == -1)
470 pause1cannot("change to initial working directory");
471 return 1;
472}
473
474static void rmoldest(struct logdir *ld)
475{
476 DIR *d;
477 struct dirent *f;
478 char oldest[FMT_PTIME];
479 int n = 0;
480
481 oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
482 while (!(d = opendir(".")))
483 pause2cannot("open directory, want rotate", ld->name);
484 errno = 0;
485 while ((f = readdir(d))) {
486 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
487 if (f->d_name[26] == 't') {
488 if (unlink(f->d_name) == -1)
489 warn2("can't unlink processor leftover", f->d_name);
490 } else {
491 ++n;
492 if (strcmp(f->d_name, oldest) < 0)
493 memcpy(oldest, f->d_name, 27);
494 }
495 errno = 0;
496 }
497 }
498 if (errno)
499 warn2("can't read directory", ld->name);
500 closedir(d);
501
502 if (ld->nmax && (n > ld->nmax)) {
503 if (verbose)
504 bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
505 if ((*oldest == '@') && (unlink(oldest) == -1))
506 warn2("can't unlink oldest logfile", ld->name);
507 }
508}
509
510static unsigned rotate(struct logdir *ld)
511{
512 struct stat st;
513 unsigned now;
514
515 if (ld->fddir == -1) {
516 ld->rotate_period = 0;
517 return 0;
518 }
519 if (ld->ppid)
520 while (!processorstop(ld))
521 continue;
522
523 while (fchdir(ld->fddir) == -1)
524 pause2cannot("change directory, want rotate", ld->name);
525
526
527 ld->fnsave[25] = '.';
528 ld->fnsave[26] = 's';
529 if (ld->processor)
530 ld->fnsave[26] = 'u';
531 ld->fnsave[27] = '\0';
532 do {
533 fmt_time_bernstein_25(ld->fnsave);
534 errno = 0;
535 stat(ld->fnsave, &st);
536 } while (errno != ENOENT);
537
538 now = monotonic_sec();
539 if (ld->rotate_period && LESS(ld->next_rotate, now)) {
540 ld->next_rotate = now + ld->rotate_period;
541 if (LESS(ld->next_rotate, nearest_rotate))
542 nearest_rotate = ld->next_rotate;
543 }
544
545 if (ld->size > 0) {
546 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
547 pause2cannot("fsync current logfile", ld->name);
548 while (fchmod(ld->fdcur, 0744) == -1)
549 pause2cannot("set mode of current", ld->name);
550
551 fclose(ld->filecur);
552
553 if (verbose) {
554 bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
555 ld->fnsave, ld->size);
556 }
557 while (rename("current", ld->fnsave) == -1)
558 pause2cannot("rename current", ld->name);
559 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
560 pause2cannot("create new current", ld->name);
561 while ((ld->filecur = fdopen(ld->fdcur, "a")) == NULL)
562 pause2cannot("create new current", ld->name);
563 setvbuf(ld->filecur, NULL, _IOFBF, linelen);
564 close_on_exec_on(ld->fdcur);
565 ld->size = 0;
566 while (fchmod(ld->fdcur, 0644) == -1)
567 pause2cannot("set mode of current", ld->name);
568
569 rmoldest(ld);
570 processorstart(ld);
571 }
572
573 while (fchdir(fdwdir) == -1)
574 pause1cannot("change to initial working directory");
575 return 1;
576}
577
578static int buffer_pwrite(int n, char *s, unsigned len)
579{
580 int i;
581 struct logdir *ld = &dir[n];
582
583 if (ld->sizemax) {
584 if (ld->size >= ld->sizemax)
585 rotate(ld);
586 if (len > (ld->sizemax - ld->size))
587 len = ld->sizemax - ld->size;
588 }
589 while (1) {
590
591
592 i = fwrite(s, 1, len, ld->filecur);
593 if (i == len) break;
594
595 if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
596 DIR *d;
597 struct dirent *f;
598 char oldest[FMT_PTIME];
599 int j = 0;
600
601 while (fchdir(ld->fddir) == -1)
602 pause2cannot("change directory, want remove old logfile",
603 ld->name);
604 oldest[0] = 'A';
605 oldest[1] = oldest[27] = '\0';
606 while (!(d = opendir(".")))
607 pause2cannot("open directory, want remove old logfile",
608 ld->name);
609 errno = 0;
610 while ((f = readdir(d)))
611 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
612 ++j;
613 if (strcmp(f->d_name, oldest) < 0)
614 memcpy(oldest, f->d_name, 27);
615 }
616 if (errno) warn2("can't read directory, want remove old logfile",
617 ld->name);
618 closedir(d);
619 errno = ENOSPC;
620 if (j > ld->nmin) {
621 if (*oldest == '@') {
622 bb_error_msg(WARNING"out of disk space, delete: %s/%s",
623 ld->name, oldest);
624 errno = 0;
625 if (unlink(oldest) == -1) {
626 warn2("can't unlink oldest logfile", ld->name);
627 errno = ENOSPC;
628 }
629 while (fchdir(fdwdir) == -1)
630 pause1cannot("change to initial working directory");
631 }
632 }
633 }
634 if (errno)
635 pause2cannot("write to current", ld->name);
636 }
637
638 ld->size += i;
639 if (ld->sizemax)
640 if (s[i-1] == '\n')
641 if (ld->size >= (ld->sizemax - linemax))
642 rotate(ld);
643 return i;
644}
645
646static void logdir_close(struct logdir *ld)
647{
648 if (ld->fddir == -1)
649 return;
650 if (verbose)
651 bb_error_msg(INFO"close: %s", ld->name);
652 close(ld->fddir);
653 ld->fddir = -1;
654 if (ld->fdcur == -1)
655 return;
656 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
657 pause2cannot("fsync current logfile", ld->name);
658 while (fchmod(ld->fdcur, 0744) == -1)
659 pause2cannot("set mode of current", ld->name);
660
661 fclose(ld->filecur);
662 ld->fdcur = -1;
663 if (ld->fdlock == -1)
664 return;
665 close(ld->fdlock);
666 ld->fdlock = -1;
667 free(ld->processor);
668 ld->processor = NULL;
669}
670
671static NOINLINE unsigned logdir_open(struct logdir *ld, const char *fn)
672{
673 char buf[128];
674 unsigned now;
675 char *new, *s, *np;
676 int i;
677 struct stat st;
678
679 now = monotonic_sec();
680
681 ld->fddir = open(fn, O_RDONLY|O_NDELAY);
682 if (ld->fddir == -1) {
683 warn2("can't open log directory", (char*)fn);
684 return 0;
685 }
686 close_on_exec_on(ld->fddir);
687 if (fchdir(ld->fddir) == -1) {
688 logdir_close(ld);
689 warn2("can't change directory", (char*)fn);
690 return 0;
691 }
692 ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
693 if ((ld->fdlock == -1)
694 || (flock(ld->fdlock, LOCK_EX | LOCK_NB) == -1)
695 ) {
696 logdir_close(ld);
697 warn2("can't lock directory", (char*)fn);
698 while (fchdir(fdwdir) == -1)
699 pause1cannot("change to initial working directory");
700 return 0;
701 }
702 close_on_exec_on(ld->fdlock);
703
704 ld->size = 0;
705 ld->sizemax = 1000000;
706 ld->nmax = ld->nmin = 10;
707 ld->rotate_period = 0;
708 ld->name = (char*)fn;
709 ld->ppid = 0;
710 ld->match = '+';
711 free(ld->inst); ld->inst = NULL;
712 free(ld->processor); ld->processor = NULL;
713
714
715 i = open_read_close("config", buf, sizeof(buf) - 1);
716 if (i < 0 && errno != ENOENT)
717 bb_perror_msg(WARNING"%s/config", ld->name);
718 if (i > 0) {
719 buf[i] = '\0';
720 if (verbose)
721 bb_error_msg(INFO"read: %s/config", ld->name);
722 s = buf;
723 while (s) {
724 np = strchr(s, '\n');
725 if (np)
726 *np++ = '\0';
727 switch (s[0]) {
728 case '+':
729 case '-':
730 case 'e':
731 case 'E':
732
733
734
735 memRchr = memchr;
736
737 while (1) {
738 int l = asprintf(&new, "%s%s\n", ld->inst ? ld->inst : "", s);
739 if (l >= 0 && new)
740 break;
741 pause_nomem();
742 }
743 free(ld->inst);
744 ld->inst = new;
745 break;
746 case 's': {
747 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
748 break;
749 }
750 case 'n':
751 ld->nmax = xatoi_positive(&s[1]);
752 break;
753 case 'N':
754 ld->nmin = xatoi_positive(&s[1]);
755 break;
756 case 't': {
757 static const struct suffix_mult mh_suffixes[] = {
758 { "m", 60 },
759 { "h", 60*60 },
760
761 { "", 0 }
762 };
763 ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
764 if (ld->rotate_period) {
765 ld->next_rotate = now + ld->rotate_period;
766 if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate))
767 nearest_rotate = ld->next_rotate;
768 tmaxflag = 1;
769 }
770 break;
771 }
772 case '!':
773 if (s[1]) {
774 free(ld->processor);
775 ld->processor = wstrdup(s);
776 }
777 break;
778 }
779 s = np;
780 }
781
782 s = ld->inst;
783 while (s) {
784 np = strchr(s, '\n');
785 if (np)
786 *np++ = '\0';
787 s = np;
788 }
789 }
790
791
792 i = stat("current", &st);
793 if (i != -1) {
794 if (st.st_size && !(st.st_mode & S_IXUSR)) {
795 ld->fnsave[25] = '.';
796 ld->fnsave[26] = 'u';
797 ld->fnsave[27] = '\0';
798 do {
799 fmt_time_bernstein_25(ld->fnsave);
800 errno = 0;
801 stat(ld->fnsave, &st);
802 } while (errno != ENOENT);
803 while (rename("current", ld->fnsave) == -1)
804 pause2cannot("rename current", ld->name);
805 rmoldest(ld);
806 i = -1;
807 } else {
808
809
810
811 ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
812 }
813 } else {
814 if (errno != ENOENT) {
815 logdir_close(ld);
816 warn2("can't stat current", ld->name);
817 while (fchdir(fdwdir) == -1)
818 pause1cannot("change to initial working directory");
819 return 0;
820 }
821 }
822 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
823 pause2cannot("open current", ld->name);
824 while ((ld->filecur = fdopen(ld->fdcur, "a")) == NULL)
825 pause2cannot("open current", ld->name);
826 setvbuf(ld->filecur, NULL, _IOFBF, linelen);
827
828 close_on_exec_on(ld->fdcur);
829 while (fchmod(ld->fdcur, 0644) == -1)
830 pause2cannot("set mode of current", ld->name);
831
832 if (verbose) {
833 if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
834 else bb_error_msg(INFO"new: %s/current", ld->name);
835 }
836
837 while (fchdir(fdwdir) == -1)
838 pause1cannot("change to initial working directory");
839 return 1;
840}
841
842static void logdirs_reopen(void)
843{
844 int l;
845 int ok = 0;
846
847 tmaxflag = 0;
848 for (l = 0; l < dirn; ++l) {
849 logdir_close(&dir[l]);
850 if (logdir_open(&dir[l], fndir[l]))
851 ok = 1;
852 }
853 if (!ok)
854 fatalx("no functional log directories");
855}
856
857
858static ssize_t ndelay_read(int fd, void *buf, size_t count)
859{
860 if (!(fl_flag_0 & O_NONBLOCK))
861 fcntl(fd, F_SETFL, fl_flag_0 | O_NONBLOCK);
862 count = safe_read(fd, buf, count);
863 if (!(fl_flag_0 & O_NONBLOCK))
864 fcntl(fd, F_SETFL, fl_flag_0);
865 return count;
866}
867
868
869static int buffer_pread(char *s, unsigned len)
870{
871 unsigned now;
872 struct pollfd input;
873 int i;
874
875 input.fd = STDIN_FILENO;
876 input.events = POLLIN;
877
878 do {
879 if (rotateasap) {
880 for (i = 0; i < dirn; ++i)
881 rotate(dir + i);
882 rotateasap = 0;
883 }
884 if (exitasap) {
885 if (linecomplete)
886 return 0;
887 len = 1;
888 }
889 if (reopenasap) {
890 logdirs_reopen();
891 reopenasap = 0;
892 }
893 now = monotonic_sec();
894 nearest_rotate = now + (45 * 60 + 45);
895 for (i = 0; i < dirn; ++i) {
896 if (dir[i].rotate_period) {
897 if (LESS(dir[i].next_rotate, now))
898 rotate(dir + i);
899 if (LESS(dir[i].next_rotate, nearest_rotate))
900 nearest_rotate = dir[i].next_rotate;
901 }
902 }
903
904 sigprocmask(SIG_UNBLOCK, &blocked_sigset, NULL);
905 i = nearest_rotate - now;
906 if (i > 1000000)
907 i = 1000000;
908 if (i <= 0)
909 i = 1;
910 poll(&input, 1, i * 1000);
911 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
912
913 i = ndelay_read(STDIN_FILENO, s, len);
914 if (i >= 0)
915 break;
916 if (errno == EINTR)
917 continue;
918 if (errno != EAGAIN) {
919 warn("can't read standard input");
920 break;
921 }
922
923 } while (!exitasap);
924
925 if (i > 0) {
926 int cnt;
927 linecomplete = (s[i-1] == '\n');
928 if (!repl)
929 return i;
930
931 cnt = i;
932 while (--cnt >= 0) {
933 char ch = *s;
934 if (ch != '\n') {
935 if (ch < 32 || ch > 126)
936 *s = repl;
937 else {
938 int j;
939 for (j = 0; replace[j]; ++j) {
940 if (ch == replace[j]) {
941 *s = repl;
942 break;
943 }
944 }
945 }
946 }
947 s++;
948 }
949 }
950 return i;
951}
952
953static void sig_term_handler(int sig_no UNUSED_PARAM)
954{
955 if (verbose)
956 bb_error_msg(INFO"sig%s received", "term");
957 exitasap = 1;
958}
959
960static void sig_child_handler(int sig_no UNUSED_PARAM)
961{
962 pid_t pid;
963 int l;
964
965 if (verbose)
966 bb_error_msg(INFO"sig%s received", "child");
967 while ((pid = wait_any_nohang(&wstat)) > 0) {
968 for (l = 0; l < dirn; ++l) {
969 if (dir[l].ppid == pid) {
970 dir[l].ppid = 0;
971 processorstop(&dir[l]);
972 break;
973 }
974 }
975 }
976}
977
978static void sig_alarm_handler(int sig_no UNUSED_PARAM)
979{
980 if (verbose)
981 bb_error_msg(INFO"sig%s received", "alarm");
982 rotateasap = 1;
983}
984
985static void sig_hangup_handler(int sig_no UNUSED_PARAM)
986{
987 if (verbose)
988 bb_error_msg(INFO"sig%s received", "hangup");
989 reopenasap = 1;
990}
991
992static void logmatch(struct logdir *ld)
993{
994 char *s;
995
996 ld->match = '+';
997 ld->matcherr = 'E';
998 s = ld->inst;
999 while (s && s[0]) {
1000 switch (s[0]) {
1001 case '+':
1002 case '-':
1003 if (pmatch(s+1, line, linelen))
1004 ld->match = s[0];
1005 break;
1006 case 'e':
1007 case 'E':
1008 if (pmatch(s+1, line, linelen))
1009 ld->matcherr = s[0];
1010 break;
1011 }
1012 s += strlen(s) + 1;
1013 }
1014}
1015
1016int svlogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1017int svlogd_main(int argc, char **argv)
1018{
1019 char *r, *l, *b;
1020 ssize_t stdin_cnt = 0;
1021 int i;
1022 unsigned opt;
1023 unsigned timestamp = 0;
1024
1025 INIT_G();
1026
1027 opt_complementary = "tt:vv";
1028 opt = getopt32(argv, "r:R:l:b:tv",
1029 &r, &replace, &l, &b, ×tamp, &verbose);
1030 if (opt & 1) {
1031 repl = r[0];
1032 if (!repl || r[1])
1033 bb_show_usage();
1034 }
1035 if (opt & 2) if (!repl) repl = '_';
1036 if (opt & 4) {
1037 linemax = xatou_range(l, 0, BUFSIZ-26);
1038 if (linemax == 0)
1039 linemax = BUFSIZ-26;
1040 if (linemax < 256)
1041 linemax = 256;
1042 }
1043
1044
1045
1046
1047
1048
1049
1050 argv += optind;
1051 argc -= optind;
1052
1053 dirn = argc;
1054 if (dirn <= 0)
1055 bb_show_usage();
1056
1057 fdwdir = xopen(".", O_RDONLY|O_NDELAY);
1058 close_on_exec_on(fdwdir);
1059 dir = xzalloc(dirn * sizeof(dir[0]));
1060 for (i = 0; i < dirn; ++i) {
1061 dir[i].fddir = -1;
1062 dir[i].fdcur = -1;
1063
1064
1065 }
1066
1067 fndir = argv;
1068
1069
1070
1071 fl_flag_0 = fcntl(0, F_GETFL);
1072
1073 sigemptyset(&blocked_sigset);
1074 sigaddset(&blocked_sigset, SIGTERM);
1075 sigaddset(&blocked_sigset, SIGCHLD);
1076 sigaddset(&blocked_sigset, SIGALRM);
1077 sigaddset(&blocked_sigset, SIGHUP);
1078 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
1079 bb_signals_recursive_norestart(1 << SIGTERM, sig_term_handler);
1080 bb_signals_recursive_norestart(1 << SIGCHLD, sig_child_handler);
1081 bb_signals_recursive_norestart(1 << SIGALRM, sig_alarm_handler);
1082 bb_signals_recursive_norestart(1 << SIGHUP, sig_hangup_handler);
1083
1084
1085
1086
1087
1088
1089 memRchr = (timestamp ? memchr : memrchr);
1090
1091 logdirs_reopen();
1092
1093 setvbuf(stderr, NULL, _IOFBF, linelen);
1094
1095
1096 while (1) {
1097 char stamp[FMT_PTIME];
1098 char *lineptr;
1099 char *printptr;
1100 char *np;
1101 int printlen;
1102 char ch;
1103
1104 lineptr = line;
1105 if (timestamp)
1106 lineptr += 26;
1107
1108
1109
1110
1111
1112 np = memRchr(lineptr, '\n', stdin_cnt);
1113 if (!np && !exitasap) {
1114 i = linemax - stdin_cnt;
1115 if (i >= 128) {
1116 i = buffer_pread(lineptr + stdin_cnt, i);
1117 if (i <= 0)
1118 exitasap = 1;
1119 else {
1120 np = memRchr(lineptr + stdin_cnt, '\n', i);
1121 stdin_cnt += i;
1122 }
1123 }
1124 }
1125 if (stdin_cnt <= 0 && exitasap)
1126 break;
1127
1128
1129 linelen = stdin_cnt;
1130 if (np) {
1131 print_to_nl:
1132
1133
1134 linelen = np - lineptr + 1;
1135 }
1136
1137 ch = lineptr[linelen-1];
1138
1139
1140
1141
1142
1143
1144
1145
1146 printlen = linelen;
1147 printptr = lineptr;
1148 if (timestamp) {
1149 if (timestamp == 1)
1150 fmt_time_bernstein_25(stamp);
1151 else
1152 fmt_time_human_30nul(stamp);
1153 printlen += 26;
1154 printptr -= 26;
1155 memcpy(printptr, stamp, 25);
1156 printptr[25] = ' ';
1157 }
1158 for (i = 0; i < dirn; ++i) {
1159 struct logdir *ld = &dir[i];
1160 if (ld->fddir == -1)
1161 continue;
1162 if (ld->inst)
1163 logmatch(ld);
1164 if (ld->matcherr == 'e') {
1165
1166
1167 fwrite(printptr, 1, printlen, stderr);
1168 }
1169 if (ld->match != '+')
1170 continue;
1171 buffer_pwrite(i, printptr, printlen);
1172 }
1173
1174
1175
1176 while (ch != '\n') {
1177
1178 stdin_cnt = exitasap ? -1 : buffer_pread(lineptr, linemax);
1179 if (stdin_cnt <= 0) {
1180 exitasap = 1;
1181 lineptr[0] = ch = '\n';
1182 linelen = 1;
1183 stdin_cnt = 1;
1184 } else {
1185 linelen = stdin_cnt;
1186 np = memRchr(lineptr, '\n', stdin_cnt);
1187 if (np)
1188 linelen = np - lineptr + 1;
1189 ch = lineptr[linelen-1];
1190 }
1191
1192 for (i = 0; i < dirn; ++i) {
1193 if (dir[i].fddir == -1)
1194 continue;
1195 if (dir[i].matcherr == 'e') {
1196
1197 fwrite(lineptr, 1, linelen, stderr);
1198 }
1199 if (dir[i].match != '+')
1200 continue;
1201 buffer_pwrite(i, lineptr, linelen);
1202 }
1203 }
1204
1205 stdin_cnt -= linelen;
1206 if (stdin_cnt > 0) {
1207 lineptr += linelen;
1208
1209
1210 np = memRchr(lineptr, '\n', stdin_cnt);
1211 if (np)
1212 goto print_to_nl;
1213
1214 memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1215 }
1216 fflush_all();
1217 }
1218
1219 for (i = 0; i < dirn; ++i) {
1220 if (dir[i].ppid)
1221 while (!processorstop(&dir[i]))
1222 continue;
1223 logdir_close(&dir[i]);
1224 }
1225 return 0;
1226}
1227