2 Copyright (c) 2001-2006, Gerrit Pape
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
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.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 /* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
29 /* TODO: depends on runit_lib.c - review and reduce/eliminate */
34 #include "runit_lib.h"
36 #define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0)
42 /* pattern list to match, in "aa\0bb\0\cc\0\0" form */
50 unsigned rotate_period;
57 char fnsave[FMT_PTIME];
73 unsigned nearest_rotate;
78 smallint linecomplete;
86 sigset_t blocked_sigset;
88 #define G (*(struct globals*)ptr_to_globals)
90 #define verbose (G.verbose )
91 #define linemax (G.linemax )
92 #define buflen (G.buflen )
93 #define linelen (G.linelen )
94 #define fndir (G.fndir )
95 #define fdwdir (G.fdwdir )
96 #define wstat (G.wstat )
97 #define nearest_rotate (G.nearest_rotate)
98 #define exitasap (G.exitasap )
99 #define rotateasap (G.rotateasap )
100 #define reopenasap (G.reopenasap )
101 #define linecomplete (G.linecomplete )
102 #define tmaxflag (G.tmaxflag )
103 #define repl (G.repl )
104 #define replace (G.replace )
105 #define blocked_sigset (G.blocked_sigset)
106 #define fl_flag_0 (G.fl_flag_0 )
107 #define dirn (G.dirn )
108 #define INIT_G() do { \
109 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
116 #define line bb_common_bufsiz1
119 #define FATAL "fatal: "
120 #define WARNING "warning: "
121 #define PAUSE "pausing: "
122 #define INFO "info: "
124 #define usage() bb_show_usage()
125 static void fatalx(const char *m0)
127 bb_error_msg_and_die(FATAL"%s", m0);
129 static void warn(const char *m0)
131 bb_perror_msg(WARNING"%s", m0);
133 static void warn2(const char *m0, const char *m1)
135 bb_perror_msg(WARNING"%s: %s", m0, m1);
137 static void warnx(const char *m0, const char *m1)
139 bb_error_msg(WARNING"%s: %s", m0, m1);
141 static void pause_nomem(void)
143 bb_error_msg(PAUSE"out of memory");
146 static void pause1cannot(const char *m0)
148 bb_perror_msg(PAUSE"can't %s", m0);
151 static void pause2cannot(const char *m0, const char *m1)
153 bb_perror_msg(PAUSE"can't %s %s", m0, m1);
157 static char* wstrdup(const char *str)
160 while (!(s = strdup(str)))
165 /*** ex fmt_ptime.[ch] ***/
168 static void fmt_time_human_30nul(char *s)
173 gettimeofday(&tv, NULL);
174 t = gmtime(&(tv.tv_sec));
175 sprintf(s, "%04u-%02u-%02u_%02u:%02u:%02u.%06u000",
176 (unsigned)(1900 + t->tm_year),
177 (unsigned)(t->tm_mon + 1),
178 (unsigned)(t->tm_mday),
179 (unsigned)(t->tm_hour),
180 (unsigned)(t->tm_min),
181 (unsigned)(t->tm_sec),
182 (unsigned)(tv.tv_usec)
184 /* 4+1 + 2+1 + 2+1 + 2+1 + 2+1 + 2+1 + 9 = */
185 /* 5 + 3 + 3 + 3 + 3 + 3 + 9 = */
186 /* 20 (up to '.' inclusive) + 9 (not including '\0') */
189 /* NOT terminated! */
190 static void fmt_time_bernstein_25(char *s)
196 gettimeofday(&tv, NULL);
197 sec_hi = (0x400000000000000aULL + tv.tv_sec) >> 32;
198 tv.tv_sec = (time_t)(0x400000000000000aULL) + tv.tv_sec;
200 /* Network order is big-endian: most significant byte first.
201 * This is exactly what we want here */
202 pack[0] = htonl(sec_hi);
203 pack[1] = htonl(tv.tv_sec);
204 pack[2] = htonl(tv.tv_usec);
206 bin2hex(s, (char*)pack, 12);
209 static void processorstart(struct logdir *ld)
214 if (!ld->processor) return;
216 warnx("processor already running", ld->name);
220 /* vfork'ed child trashes this byte, save... */
221 sv_ch = ld->fnsave[26];
223 while ((pid = vfork()) == -1)
224 pause2cannot("vfork for processor", ld->name);
230 /* Non-ignored signals revert to SIG_DFL on exec anyway */
236 sig_unblock(SIGTERM);
237 sig_unblock(SIGALRM);
241 bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
242 fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
244 ld->fnsave[26] = 't'; /* <- that's why we need sv_ch! */
245 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
247 fd = open_read("state");
250 bb_perror_msg_and_die(FATAL"can't %s processor %s", "open state for", ld->name);
251 close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
252 fd = xopen("state", O_RDONLY|O_NDELAY);
255 fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
259 prog[0] = (char*)"sh";
260 prog[1] = (char*)"-c";
261 prog[2] = ld->processor;
263 execv("/bin/sh", prog);
264 bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name);
266 ld->fnsave[26] = sv_ch; /* ...restore */
270 static unsigned processorstop(struct logdir *ld)
276 while (safe_waitpid(ld->ppid, &wstat, 0) == -1)
277 pause2cannot("wait for processor", ld->name);
281 if (ld->fddir == -1) return 1;
282 while (fchdir(ld->fddir) == -1)
283 pause2cannot("change directory, want processor", ld->name);
284 if (wait_exitcode(wstat) != 0) {
285 warnx("processor failed, restart", ld->name);
286 ld->fnsave[26] = 't';
288 ld->fnsave[26] = 'u';
290 while (fchdir(fdwdir) == -1)
291 pause1cannot("change to initial working directory");
292 return ld->processor ? 0 : 1;
294 ld->fnsave[26] = 't';
295 memcpy(f, ld->fnsave, 26);
298 while (rename(ld->fnsave, f) == -1)
299 pause2cannot("rename processed", ld->name);
300 while (chmod(f, 0744) == -1)
301 pause2cannot("set mode of processed", ld->name);
302 ld->fnsave[26] = 'u';
303 if (unlink(ld->fnsave) == -1)
304 bb_error_msg(WARNING"can't unlink: %s/%s", ld->name, ld->fnsave);
305 while (rename("newstate", "state") == -1)
306 pause2cannot("rename state", ld->name);
308 bb_error_msg(INFO"processed: %s/%s", ld->name, f);
309 while (fchdir(fdwdir) == -1)
310 pause1cannot("change to initial working directory");
314 static void rmoldest(struct logdir *ld)
318 char oldest[FMT_PTIME];
321 oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
322 while (!(d = opendir(".")))
323 pause2cannot("open directory, want rotate", ld->name);
325 while ((f = readdir(d))) {
326 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
327 if (f->d_name[26] == 't') {
328 if (unlink(f->d_name) == -1)
329 warn2("can't unlink processor leftover", f->d_name);
332 if (strcmp(f->d_name, oldest) < 0)
333 memcpy(oldest, f->d_name, 27);
339 warn2("can't read directory", ld->name);
342 if (ld->nmax && (n > ld->nmax)) {
344 bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
345 if ((*oldest == '@') && (unlink(oldest) == -1))
346 warn2("can't unlink oldest logfile", ld->name);
350 static unsigned rotate(struct logdir *ld)
355 if (ld->fddir == -1) {
356 ld->rotate_period = 0;
360 while (!processorstop(ld))
363 while (fchdir(ld->fddir) == -1)
364 pause2cannot("change directory, want rotate", ld->name);
366 /* create new filename */
367 ld->fnsave[25] = '.';
368 ld->fnsave[26] = 's';
370 ld->fnsave[26] = 'u';
371 ld->fnsave[27] = '\0';
373 fmt_time_bernstein_25(ld->fnsave);
375 stat(ld->fnsave, &st);
376 } while (errno != ENOENT);
378 now = monotonic_sec();
379 if (ld->rotate_period && LESS(ld->next_rotate, now)) {
380 ld->next_rotate = now + ld->rotate_period;
381 if (LESS(ld->next_rotate, nearest_rotate))
382 nearest_rotate = ld->next_rotate;
386 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
387 pause2cannot("fsync current logfile", ld->name);
388 while (fchmod(ld->fdcur, 0744) == -1)
389 pause2cannot("set mode of current", ld->name);
390 ////close(ld->fdcur);
394 bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
395 ld->fnsave, ld->size);
397 while (rename("current", ld->fnsave) == -1)
398 pause2cannot("rename current", ld->name);
399 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
400 pause2cannot("create new current", ld->name);
401 /* we presume this cannot fail */
402 ld->filecur = fdopen(ld->fdcur, "a"); ////
403 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
404 close_on_exec_on(ld->fdcur);
406 while (fchmod(ld->fdcur, 0644) == -1)
407 pause2cannot("set mode of current", ld->name);
412 while (fchdir(fdwdir) == -1)
413 pause1cannot("change to initial working directory");
417 static int buffer_pwrite(int n, char *s, unsigned len)
420 struct logdir *ld = &dir[n];
423 if (ld->size >= ld->sizemax)
425 if (len > (ld->sizemax - ld->size))
426 len = ld->sizemax - ld->size;
429 ////i = full_write(ld->fdcur, s, len);
430 ////if (i != -1) break;
431 i = fwrite(s, 1, len, ld->filecur);
434 if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
437 char oldest[FMT_PTIME];
440 while (fchdir(ld->fddir) == -1)
441 pause2cannot("change directory, want remove old logfile",
444 oldest[1] = oldest[27] = '\0';
445 while (!(d = opendir(".")))
446 pause2cannot("open directory, want remove old logfile",
449 while ((f = readdir(d)))
450 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
452 if (strcmp(f->d_name, oldest) < 0)
453 memcpy(oldest, f->d_name, 27);
455 if (errno) warn2("can't read directory, want remove old logfile",
460 if (*oldest == '@') {
461 bb_error_msg(WARNING"out of disk space, delete: %s/%s",
464 if (unlink(oldest) == -1) {
465 warn2("can't unlink oldest logfile", ld->name);
468 while (fchdir(fdwdir) == -1)
469 pause1cannot("change to initial working directory");
474 pause2cannot("write to current", ld->name);
480 if (ld->size >= (ld->sizemax - linemax))
485 static void logdir_close(struct logdir *ld)
490 bb_error_msg(INFO"close: %s", ld->name);
494 return; /* impossible */
495 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
496 pause2cannot("fsync current logfile", ld->name);
497 while (fchmod(ld->fdcur, 0744) == -1)
498 pause2cannot("set mode of current", ld->name);
499 ////close(ld->fdcur);
502 if (ld->fdlock == -1)
503 return; /* impossible */
507 ld->processor = NULL;
510 static unsigned logdir_open(struct logdir *ld, const char *fn)
518 now = monotonic_sec();
520 ld->fddir = open(fn, O_RDONLY|O_NDELAY);
521 if (ld->fddir == -1) {
522 warn2("can't open log directory", (char*)fn);
525 close_on_exec_on(ld->fddir);
526 if (fchdir(ld->fddir) == -1) {
528 warn2("can't change directory", (char*)fn);
531 ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
532 if ((ld->fdlock == -1)
533 || (lock_exnb(ld->fdlock) == -1)
536 warn2("can't lock directory", (char*)fn);
537 while (fchdir(fdwdir) == -1)
538 pause1cannot("change to initial working directory");
541 close_on_exec_on(ld->fdlock);
544 ld->sizemax = 1000000;
545 ld->nmax = ld->nmin = 10;
546 ld->rotate_period = 0;
547 ld->name = (char*)fn;
550 free(ld->inst); ld->inst = NULL;
551 free(ld->processor); ld->processor = NULL;
554 i = open_read_close("config", buf, sizeof(buf));
555 if (i < 0 && errno != ENOENT)
556 bb_perror_msg(WARNING"%s/config", ld->name);
559 bb_error_msg(INFO"read: %s/config", ld->name);
562 np = strchr(s, '\n');
570 /* Add '\n'-terminated line to ld->inst */
572 int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);
581 static const struct suffix_mult km_suffixes[] = {
586 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
590 ld->nmax = xatoi_u(&s[1]);
593 ld->nmin = xatoi_u(&s[1]);
596 static const struct suffix_mult mh_suffixes[] = {
599 /*{ "d", 24*60*60 },*/
602 ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
603 if (ld->rotate_period) {
604 ld->next_rotate = now + ld->rotate_period;
605 if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate))
606 nearest_rotate = ld->next_rotate;
614 ld->processor = wstrdup(s);
620 /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
623 np = strchr(s, '\n');
631 i = stat("current", &st);
633 if (st.st_size && !(st.st_mode & S_IXUSR)) {
634 ld->fnsave[25] = '.';
635 ld->fnsave[26] = 'u';
636 ld->fnsave[27] = '\0';
638 fmt_time_bernstein_25(ld->fnsave);
640 stat(ld->fnsave, &st);
641 } while (errno != ENOENT);
642 while (rename("current", ld->fnsave) == -1)
643 pause2cannot("rename current", ld->name);
647 /* st.st_size can be not just bigger, but WIDER!
648 * This code is safe: if st.st_size > 4GB, we select
649 * ld->sizemax (because it's "unsigned") */
650 ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
653 if (errno != ENOENT) {
655 warn2("can't stat current", ld->name);
656 while (fchdir(fdwdir) == -1)
657 pause1cannot("change to initial working directory");
661 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
662 pause2cannot("open current", ld->name);
663 /* we presume this cannot fail */
664 ld->filecur = fdopen(ld->fdcur, "a"); ////
665 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
667 close_on_exec_on(ld->fdcur);
668 while (fchmod(ld->fdcur, 0644) == -1)
669 pause2cannot("set mode of current", ld->name);
672 if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
673 else bb_error_msg(INFO"new: %s/current", ld->name);
676 while (fchdir(fdwdir) == -1)
677 pause1cannot("change to initial working directory");
681 static void logdirs_reopen(void)
687 for (l = 0; l < dirn; ++l) {
688 logdir_close(&dir[l]);
689 if (logdir_open(&dir[l], fndir[l]))
693 fatalx("no functional log directories");
696 /* Will look good in libbb one day */
697 static ssize_t ndelay_read(int fd, void *buf, size_t count)
699 if (!(fl_flag_0 & O_NONBLOCK))
700 fcntl(fd, F_SETFL, fl_flag_0 | O_NONBLOCK);
701 count = safe_read(fd, buf, count);
702 if (!(fl_flag_0 & O_NONBLOCK))
703 fcntl(fd, F_SETFL, fl_flag_0);
707 /* Used for reading stdin */
708 static int buffer_pread(/*int fd, */char *s, unsigned len)
715 input.events = POLLIN;
719 for (i = 0; i < dirn; ++i)
732 now = monotonic_sec();
733 nearest_rotate = now + (45 * 60 + 45);
734 for (i = 0; i < dirn; ++i) {
735 if (dir[i].rotate_period) {
736 if (LESS(dir[i].next_rotate, now))
738 if (LESS(dir[i].next_rotate, nearest_rotate))
739 nearest_rotate = dir[i].next_rotate;
743 sigprocmask(SIG_UNBLOCK, &blocked_sigset, NULL);
744 i = nearest_rotate - now;
749 poll(&input, 1, i * 1000);
750 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
752 i = ndelay_read(STDIN_FILENO, s, len);
757 if (errno != EAGAIN) {
758 warn("can't read standard input");
761 /* else: EAGAIN - normal, repeat silently */
766 linecomplete = (s[i-1] == '\n');
774 if (ch < 32 || ch > 126)
778 for (j = 0; replace[j]; ++j) {
779 if (ch == replace[j]) {
792 static void sig_term_handler(int sig_no UNUSED_PARAM)
795 bb_error_msg(INFO"sig%s received", "term");
799 static void sig_child_handler(int sig_no UNUSED_PARAM)
805 bb_error_msg(INFO"sig%s received", "child");
806 while ((pid = wait_any_nohang(&wstat)) > 0) {
807 for (l = 0; l < dirn; ++l) {
808 if (dir[l].ppid == pid) {
810 processorstop(&dir[l]);
817 static void sig_alarm_handler(int sig_no UNUSED_PARAM)
820 bb_error_msg(INFO"sig%s received", "alarm");
824 static void sig_hangup_handler(int sig_no UNUSED_PARAM)
827 bb_error_msg(INFO"sig%s received", "hangup");
831 static void logmatch(struct logdir *ld)
842 if (pmatch(s+1, line, linelen))
847 if (pmatch(s+1, line, linelen))
855 int svlogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
856 int svlogd_main(int argc, char **argv)
859 ssize_t stdin_cnt = 0;
862 unsigned timestamp = 0;
863 void* (*memRchr)(const void *, int, size_t) = memchr;
867 opt_complementary = "tt:vv";
868 opt = getopt32(argv, "r:R:l:b:tv",
869 &r, &replace, &l, &b, ×tamp, &verbose);
872 if (!repl || r[1]) usage();
874 if (opt & 2) if (!repl) repl = '_'; // -R
876 linemax = xatou_range(l, 0, BUFSIZ-26);
877 if (linemax == 0) linemax = BUFSIZ-26;
878 if (linemax < 256) linemax = 256;
880 ////if (opt & 8) { // -b
881 //// buflen = xatoi_u(b);
882 //// if (buflen == 0) buflen = 1024;
884 //if (opt & 0x10) timestamp++; // -t
885 //if (opt & 0x20) verbose++; // -v
886 //if (timestamp > 2) timestamp = 2;
891 if (dirn <= 0) usage();
892 ////if (buflen <= linemax) usage();
893 fdwdir = xopen(".", O_RDONLY|O_NDELAY);
894 close_on_exec_on(fdwdir);
895 dir = xzalloc(dirn * sizeof(struct logdir));
896 for (i = 0; i < dirn; ++i) {
899 ////dir[i].btmp = xmalloc(buflen);
902 /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
904 /* We cannot set NONBLOCK on fd #0 permanently - this setting
905 * _isn't_ per-process! It is shared among all other processes
906 * with the same stdin */
907 fl_flag_0 = fcntl(0, F_GETFL);
909 sigemptyset(&blocked_sigset);
910 sigaddset(&blocked_sigset, SIGTERM);
911 sigaddset(&blocked_sigset, SIGCHLD);
912 sigaddset(&blocked_sigset, SIGALRM);
913 sigaddset(&blocked_sigset, SIGHUP);
914 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
915 bb_signals_recursive(1 << SIGTERM, sig_term_handler);
916 bb_signals_recursive(1 << SIGCHLD, sig_child_handler);
917 bb_signals_recursive(1 << SIGALRM, sig_alarm_handler);
918 bb_signals_recursive(1 << SIGHUP, sig_hangup_handler);
922 /* Without timestamps, we don't have to print each line
923 * separately, so we can look for _last_ newline, not first,
924 * thus batching writes */
928 setvbuf(stderr, NULL, _IOFBF, linelen);
930 /* Each iteration processes one or more lines */
932 char stamp[FMT_PTIME];
943 /* lineptr[0..linemax-1] - buffer for stdin */
944 /* (possibly has some unprocessed data from prev loop) */
946 /* Refill the buffer if needed */
947 np = memRchr(lineptr, '\n', stdin_cnt);
948 if (!np && !exitasap) {
949 i = linemax - stdin_cnt; /* avail. bytes at tail */
951 i = buffer_pread(/*0, */lineptr + stdin_cnt, i);
952 if (i <= 0) /* EOF or error on stdin */
955 np = memRchr(lineptr + stdin_cnt, '\n', i);
960 if (stdin_cnt <= 0 && exitasap)
963 /* Search for '\n' (in fact, np already holds the result) */
966 print_to_nl: /* NB: starting from here lineptr may point
967 * farther out into line[] */
968 linelen = np - lineptr + 1;
970 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
971 ch = lineptr[linelen-1];
973 /* Biggest performance hit was coming from the fact
974 * that we did not buffer writes. We were reading many lines
975 * in one read() above, but wrote one line per write().
976 * We are using stdio to fix that */
978 /* write out lineptr[0..linelen-1] to each log destination
979 * (or lineptr[-26..linelen-1] if timestamping) */
984 fmt_time_bernstein_25(stamp);
986 fmt_time_human_30nul(stamp);
989 memcpy(printptr, stamp, 25);
992 for (i = 0; i < dirn; ++i) {
993 struct logdir *ld = &dir[i];
994 if (ld->fddir == -1) continue;
997 if (ld->matcherr == 'e') {
998 /* runit-1.8.0 compat: if timestamping, do it on stderr too */
999 ////full_write(STDERR_FILENO, printptr, printlen);
1000 fwrite(printptr, 1, printlen, stderr);
1002 if (ld->match != '+') continue;
1003 buffer_pwrite(i, printptr, printlen);
1006 /* If we didn't see '\n' (long input line), */
1007 /* read/write repeatedly until we see it */
1008 while (ch != '\n') {
1009 /* lineptr is emptied now, safe to use as buffer */
1010 stdin_cnt = exitasap ? -1 : buffer_pread(/*0, */lineptr, linemax);
1011 if (stdin_cnt <= 0) { /* EOF or error on stdin */
1013 lineptr[0] = ch = '\n';
1017 linelen = stdin_cnt;
1018 np = memRchr(lineptr, '\n', stdin_cnt);
1020 linelen = np - lineptr + 1;
1021 ch = lineptr[linelen-1];
1023 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
1024 for (i = 0; i < dirn; ++i) {
1025 if (dir[i].fddir == -1) continue;
1026 if (dir[i].matcherr == 'e') {
1027 ////full_write(STDERR_FILENO, lineptr, linelen);
1028 fwrite(lineptr, 1, linelen, stderr);
1030 if (dir[i].match != '+') continue;
1031 buffer_pwrite(i, lineptr, linelen);
1035 stdin_cnt -= linelen;
1036 if (stdin_cnt > 0) {
1038 /* If we see another '\n', we don't need to read
1039 * next piece of input: can print what we have */
1040 np = memRchr(lineptr, '\n', stdin_cnt);
1043 /* Move unprocessed data to the front of line */
1044 memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1049 for (i = 0; i < dirn; ++i) {
1051 while (!processorstop(&dir[i]))
1053 logdir_close(&dir[i]);