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);
229 /* Non-ignored signals revert to SIG_DFL on exec anyway */
235 sig_unblock(SIGTERM);
236 sig_unblock(SIGALRM);
240 bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
241 fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
243 ld->fnsave[26] = 't'; /* <- that's why we need sv_ch! */
244 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
246 fd = open_read("state");
249 bb_perror_msg_and_die(FATAL"can't %s processor %s", "open state for", ld->name);
250 close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
251 fd = xopen("state", O_RDONLY|O_NDELAY);
254 fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
258 execl("/bin/sh", "/bin/sh" + 5, "-c", ld->processor, (char*) NULL);
259 bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name);
261 ld->fnsave[26] = sv_ch; /* ...restore */
265 static unsigned processorstop(struct logdir *ld)
271 while (safe_waitpid(ld->ppid, &wstat, 0) == -1)
272 pause2cannot("wait for processor", ld->name);
276 if (ld->fddir == -1) return 1;
277 while (fchdir(ld->fddir) == -1)
278 pause2cannot("change directory, want processor", ld->name);
279 if (WEXITSTATUS(wstat) != 0) {
280 warnx("processor failed, restart", ld->name);
281 ld->fnsave[26] = 't';
283 ld->fnsave[26] = 'u';
285 while (fchdir(fdwdir) == -1)
286 pause1cannot("change to initial working directory");
287 return ld->processor ? 0 : 1;
289 ld->fnsave[26] = 't';
290 memcpy(f, ld->fnsave, 26);
293 while (rename(ld->fnsave, f) == -1)
294 pause2cannot("rename processed", ld->name);
295 while (chmod(f, 0744) == -1)
296 pause2cannot("set mode of processed", ld->name);
297 ld->fnsave[26] = 'u';
298 if (unlink(ld->fnsave) == -1)
299 bb_error_msg(WARNING"can't unlink: %s/%s", ld->name, ld->fnsave);
300 while (rename("newstate", "state") == -1)
301 pause2cannot("rename state", ld->name);
303 bb_error_msg(INFO"processed: %s/%s", ld->name, f);
304 while (fchdir(fdwdir) == -1)
305 pause1cannot("change to initial working directory");
309 static void rmoldest(struct logdir *ld)
313 char oldest[FMT_PTIME];
316 oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
317 while (!(d = opendir(".")))
318 pause2cannot("open directory, want rotate", ld->name);
320 while ((f = readdir(d))) {
321 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
322 if (f->d_name[26] == 't') {
323 if (unlink(f->d_name) == -1)
324 warn2("can't unlink processor leftover", f->d_name);
327 if (strcmp(f->d_name, oldest) < 0)
328 memcpy(oldest, f->d_name, 27);
334 warn2("can't read directory", ld->name);
337 if (ld->nmax && (n > ld->nmax)) {
339 bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
340 if ((*oldest == '@') && (unlink(oldest) == -1))
341 warn2("can't unlink oldest logfile", ld->name);
345 static unsigned rotate(struct logdir *ld)
350 if (ld->fddir == -1) {
351 ld->rotate_period = 0;
355 while (!processorstop(ld))
358 while (fchdir(ld->fddir) == -1)
359 pause2cannot("change directory, want rotate", ld->name);
361 /* create new filename */
362 ld->fnsave[25] = '.';
363 ld->fnsave[26] = 's';
365 ld->fnsave[26] = 'u';
366 ld->fnsave[27] = '\0';
368 fmt_time_bernstein_25(ld->fnsave);
370 stat(ld->fnsave, &st);
371 } while (errno != ENOENT);
373 now = monotonic_sec();
374 if (ld->rotate_period && LESS(ld->next_rotate, now)) {
375 ld->next_rotate = now + ld->rotate_period;
376 if (LESS(ld->next_rotate, nearest_rotate))
377 nearest_rotate = ld->next_rotate;
381 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
382 pause2cannot("fsync current logfile", ld->name);
383 while (fchmod(ld->fdcur, 0744) == -1)
384 pause2cannot("set mode of current", ld->name);
385 ////close(ld->fdcur);
389 bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
390 ld->fnsave, ld->size);
392 while (rename("current", ld->fnsave) == -1)
393 pause2cannot("rename current", ld->name);
394 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
395 pause2cannot("create new current", ld->name);
396 while ((ld->filecur = fdopen(ld->fdcur, "a")) == NULL) ////
397 pause2cannot("create new current", ld->name); /* very unlikely */
398 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
399 close_on_exec_on(ld->fdcur);
401 while (fchmod(ld->fdcur, 0644) == -1)
402 pause2cannot("set mode of current", ld->name);
408 while (fchdir(fdwdir) == -1)
409 pause1cannot("change to initial working directory");
413 static int buffer_pwrite(int n, char *s, unsigned len)
416 struct logdir *ld = &dir[n];
419 if (ld->size >= ld->sizemax)
421 if (len > (ld->sizemax - ld->size))
422 len = ld->sizemax - ld->size;
425 ////i = full_write(ld->fdcur, s, len);
426 ////if (i != -1) break;
427 i = fwrite(s, 1, len, ld->filecur);
430 if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
433 char oldest[FMT_PTIME];
436 while (fchdir(ld->fddir) == -1)
437 pause2cannot("change directory, want remove old logfile",
440 oldest[1] = oldest[27] = '\0';
441 while (!(d = opendir(".")))
442 pause2cannot("open directory, want remove old logfile",
445 while ((f = readdir(d)))
446 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
448 if (strcmp(f->d_name, oldest) < 0)
449 memcpy(oldest, f->d_name, 27);
451 if (errno) warn2("can't read directory, want remove old logfile",
456 if (*oldest == '@') {
457 bb_error_msg(WARNING"out of disk space, delete: %s/%s",
460 if (unlink(oldest) == -1) {
461 warn2("can't unlink oldest logfile", ld->name);
464 while (fchdir(fdwdir) == -1)
465 pause1cannot("change to initial working directory");
470 pause2cannot("write to current", ld->name);
476 if (ld->size >= (ld->sizemax - linemax))
481 static void logdir_close(struct logdir *ld)
486 bb_error_msg(INFO"close: %s", ld->name);
490 return; /* impossible */
491 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
492 pause2cannot("fsync current logfile", ld->name);
493 while (fchmod(ld->fdcur, 0744) == -1)
494 pause2cannot("set mode of current", ld->name);
495 ////close(ld->fdcur);
498 if (ld->fdlock == -1)
499 return; /* impossible */
503 ld->processor = NULL;
506 static unsigned logdir_open(struct logdir *ld, const char *fn)
514 now = monotonic_sec();
516 ld->fddir = open(fn, O_RDONLY|O_NDELAY);
517 if (ld->fddir == -1) {
518 warn2("can't open log directory", (char*)fn);
521 close_on_exec_on(ld->fddir);
522 if (fchdir(ld->fddir) == -1) {
524 warn2("can't change directory", (char*)fn);
527 ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
528 if ((ld->fdlock == -1)
529 || (lock_exnb(ld->fdlock) == -1)
532 warn2("can't lock directory", (char*)fn);
533 while (fchdir(fdwdir) == -1)
534 pause1cannot("change to initial working directory");
537 close_on_exec_on(ld->fdlock);
540 ld->sizemax = 1000000;
541 ld->nmax = ld->nmin = 10;
542 ld->rotate_period = 0;
543 ld->name = (char*)fn;
546 free(ld->inst); ld->inst = NULL;
547 free(ld->processor); ld->processor = NULL;
550 i = open_read_close("config", buf, sizeof(buf) - 1);
551 if (i < 0 && errno != ENOENT)
552 bb_perror_msg(WARNING"%s/config", ld->name);
556 bb_error_msg(INFO"read: %s/config", ld->name);
559 np = strchr(s, '\n');
567 /* Add '\n'-terminated line to ld->inst */
569 int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);
578 static const struct suffix_mult km_suffixes[] = {
583 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
587 ld->nmax = xatoi_u(&s[1]);
590 ld->nmin = xatoi_u(&s[1]);
593 static const struct suffix_mult mh_suffixes[] = {
596 /*{ "d", 24*60*60 },*/
599 ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
600 if (ld->rotate_period) {
601 ld->next_rotate = now + ld->rotate_period;
602 if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate))
603 nearest_rotate = ld->next_rotate;
611 ld->processor = wstrdup(s);
617 /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
620 np = strchr(s, '\n');
628 i = stat("current", &st);
630 if (st.st_size && !(st.st_mode & S_IXUSR)) {
631 ld->fnsave[25] = '.';
632 ld->fnsave[26] = 'u';
633 ld->fnsave[27] = '\0';
635 fmt_time_bernstein_25(ld->fnsave);
637 stat(ld->fnsave, &st);
638 } while (errno != ENOENT);
639 while (rename("current", ld->fnsave) == -1)
640 pause2cannot("rename current", ld->name);
644 /* st.st_size can be not just bigger, but WIDER!
645 * This code is safe: if st.st_size > 4GB, we select
646 * ld->sizemax (because it's "unsigned") */
647 ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
650 if (errno != ENOENT) {
652 warn2("can't stat current", ld->name);
653 while (fchdir(fdwdir) == -1)
654 pause1cannot("change to initial working directory");
658 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
659 pause2cannot("open current", ld->name);
660 /* we presume this cannot fail */
661 ld->filecur = fdopen(ld->fdcur, "a"); ////
662 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
664 close_on_exec_on(ld->fdcur);
665 while (fchmod(ld->fdcur, 0644) == -1)
666 pause2cannot("set mode of current", ld->name);
669 if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
670 else bb_error_msg(INFO"new: %s/current", ld->name);
673 while (fchdir(fdwdir) == -1)
674 pause1cannot("change to initial working directory");
678 static void logdirs_reopen(void)
684 for (l = 0; l < dirn; ++l) {
685 logdir_close(&dir[l]);
686 if (logdir_open(&dir[l], fndir[l]))
690 fatalx("no functional log directories");
693 /* Will look good in libbb one day */
694 static ssize_t ndelay_read(int fd, void *buf, size_t count)
696 if (!(fl_flag_0 & O_NONBLOCK))
697 fcntl(fd, F_SETFL, fl_flag_0 | O_NONBLOCK);
698 count = safe_read(fd, buf, count);
699 if (!(fl_flag_0 & O_NONBLOCK))
700 fcntl(fd, F_SETFL, fl_flag_0);
704 /* Used for reading stdin */
705 static int buffer_pread(/*int fd, */char *s, unsigned len)
712 input.events = POLLIN;
716 for (i = 0; i < dirn; ++i)
729 now = monotonic_sec();
730 nearest_rotate = now + (45 * 60 + 45);
731 for (i = 0; i < dirn; ++i) {
732 if (dir[i].rotate_period) {
733 if (LESS(dir[i].next_rotate, now))
735 if (LESS(dir[i].next_rotate, nearest_rotate))
736 nearest_rotate = dir[i].next_rotate;
740 sigprocmask(SIG_UNBLOCK, &blocked_sigset, NULL);
741 i = nearest_rotate - now;
746 poll(&input, 1, i * 1000);
747 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
749 i = ndelay_read(STDIN_FILENO, s, len);
754 if (errno != EAGAIN) {
755 warn("can't read standard input");
758 /* else: EAGAIN - normal, repeat silently */
763 linecomplete = (s[i-1] == '\n');
771 if (ch < 32 || ch > 126)
775 for (j = 0; replace[j]; ++j) {
776 if (ch == replace[j]) {
789 static void sig_term_handler(int sig_no UNUSED_PARAM)
792 bb_error_msg(INFO"sig%s received", "term");
796 static void sig_child_handler(int sig_no UNUSED_PARAM)
802 bb_error_msg(INFO"sig%s received", "child");
803 while ((pid = wait_any_nohang(&wstat)) > 0) {
804 for (l = 0; l < dirn; ++l) {
805 if (dir[l].ppid == pid) {
807 processorstop(&dir[l]);
814 static void sig_alarm_handler(int sig_no UNUSED_PARAM)
817 bb_error_msg(INFO"sig%s received", "alarm");
821 static void sig_hangup_handler(int sig_no UNUSED_PARAM)
824 bb_error_msg(INFO"sig%s received", "hangup");
828 static void logmatch(struct logdir *ld)
839 if (pmatch(s+1, line, linelen))
844 if (pmatch(s+1, line, linelen))
852 int svlogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
853 int svlogd_main(int argc, char **argv)
856 ssize_t stdin_cnt = 0;
859 unsigned timestamp = 0;
860 void* (*memRchr)(const void *, int, size_t) = memchr;
864 opt_complementary = "tt:vv";
865 opt = getopt32(argv, "r:R:l:b:tv",
866 &r, &replace, &l, &b, ×tamp, &verbose);
869 if (!repl || r[1]) usage();
871 if (opt & 2) if (!repl) repl = '_'; // -R
873 linemax = xatou_range(l, 0, BUFSIZ-26);
874 if (linemax == 0) linemax = BUFSIZ-26;
875 if (linemax < 256) linemax = 256;
877 ////if (opt & 8) { // -b
878 //// buflen = xatoi_u(b);
879 //// if (buflen == 0) buflen = 1024;
881 //if (opt & 0x10) timestamp++; // -t
882 //if (opt & 0x20) verbose++; // -v
883 //if (timestamp > 2) timestamp = 2;
888 if (dirn <= 0) usage();
889 ////if (buflen <= linemax) usage();
890 fdwdir = xopen(".", O_RDONLY|O_NDELAY);
891 close_on_exec_on(fdwdir);
892 dir = xzalloc(dirn * sizeof(struct logdir));
893 for (i = 0; i < dirn; ++i) {
896 ////dir[i].btmp = xmalloc(buflen);
899 /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
901 /* We cannot set NONBLOCK on fd #0 permanently - this setting
902 * _isn't_ per-process! It is shared among all other processes
903 * with the same stdin */
904 fl_flag_0 = fcntl(0, F_GETFL);
906 sigemptyset(&blocked_sigset);
907 sigaddset(&blocked_sigset, SIGTERM);
908 sigaddset(&blocked_sigset, SIGCHLD);
909 sigaddset(&blocked_sigset, SIGALRM);
910 sigaddset(&blocked_sigset, SIGHUP);
911 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
912 bb_signals_recursive_norestart(1 << SIGTERM, sig_term_handler);
913 bb_signals_recursive_norestart(1 << SIGCHLD, sig_child_handler);
914 bb_signals_recursive_norestart(1 << SIGALRM, sig_alarm_handler);
915 bb_signals_recursive_norestart(1 << SIGHUP, sig_hangup_handler);
919 /* Without timestamps, we don't have to print each line
920 * separately, so we can look for _last_ newline, not first,
921 * thus batching writes */
925 setvbuf(stderr, NULL, _IOFBF, linelen);
927 /* Each iteration processes one or more lines */
929 char stamp[FMT_PTIME];
940 /* lineptr[0..linemax-1] - buffer for stdin */
941 /* (possibly has some unprocessed data from prev loop) */
943 /* Refill the buffer if needed */
944 np = memRchr(lineptr, '\n', stdin_cnt);
945 if (!np && !exitasap) {
946 i = linemax - stdin_cnt; /* avail. bytes at tail */
948 i = buffer_pread(/*0, */lineptr + stdin_cnt, i);
949 if (i <= 0) /* EOF or error on stdin */
952 np = memRchr(lineptr + stdin_cnt, '\n', i);
957 if (stdin_cnt <= 0 && exitasap)
960 /* Search for '\n' (in fact, np already holds the result) */
963 print_to_nl: /* NB: starting from here lineptr may point
964 * farther out into line[] */
965 linelen = np - lineptr + 1;
967 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
968 ch = lineptr[linelen-1];
970 /* Biggest performance hit was coming from the fact
971 * that we did not buffer writes. We were reading many lines
972 * in one read() above, but wrote one line per write().
973 * We are using stdio to fix that */
975 /* write out lineptr[0..linelen-1] to each log destination
976 * (or lineptr[-26..linelen-1] if timestamping) */
981 fmt_time_bernstein_25(stamp);
983 fmt_time_human_30nul(stamp);
986 memcpy(printptr, stamp, 25);
989 for (i = 0; i < dirn; ++i) {
990 struct logdir *ld = &dir[i];
991 if (ld->fddir == -1) continue;
994 if (ld->matcherr == 'e') {
995 /* runit-1.8.0 compat: if timestamping, do it on stderr too */
996 ////full_write(STDERR_FILENO, printptr, printlen);
997 fwrite(printptr, 1, printlen, stderr);
999 if (ld->match != '+') continue;
1000 buffer_pwrite(i, printptr, printlen);
1003 /* If we didn't see '\n' (long input line), */
1004 /* read/write repeatedly until we see it */
1005 while (ch != '\n') {
1006 /* lineptr is emptied now, safe to use as buffer */
1007 stdin_cnt = exitasap ? -1 : buffer_pread(/*0, */lineptr, linemax);
1008 if (stdin_cnt <= 0) { /* EOF or error on stdin */
1010 lineptr[0] = ch = '\n';
1014 linelen = stdin_cnt;
1015 np = memRchr(lineptr, '\n', stdin_cnt);
1017 linelen = np - lineptr + 1;
1018 ch = lineptr[linelen-1];
1020 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
1021 for (i = 0; i < dirn; ++i) {
1022 if (dir[i].fddir == -1) continue;
1023 if (dir[i].matcherr == 'e') {
1024 ////full_write(STDERR_FILENO, lineptr, linelen);
1025 fwrite(lineptr, 1, linelen, stderr);
1027 if (dir[i].match != '+') continue;
1028 buffer_pwrite(i, lineptr, linelen);
1032 stdin_cnt -= linelen;
1033 if (stdin_cnt > 0) {
1035 /* If we see another '\n', we don't need to read
1036 * next piece of input: can print what we have */
1037 np = memRchr(lineptr, '\n', stdin_cnt);
1040 /* Move unprocessed data to the front of line */
1041 memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1046 for (i = 0; i < dirn; ++i) {
1048 while (!processorstop(&dir[i]))
1050 logdir_close(&dir[i]);