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