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 Denis 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"cannot %s", m0);
151 static void pause2cannot(const char *m0, const char *m1)
153 bb_perror_msg(PAUSE"cannot %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 unsigned processorstart(struct logdir *ld)
213 if (!ld->processor) return 0;
215 warnx("processor already running", ld->name);
218 while ((pid = fork()) == -1)
219 pause2cannot("fork for processor", ld->name);
230 sig_unblock(SIGTERM);
231 sig_unblock(SIGALRM);
235 bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
236 fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
238 ld->fnsave[26] = 't';
239 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
241 fd = open_read("state");
244 bb_perror_msg_and_die(FATAL"cannot %s processor %s", "open state for", ld->name);
245 close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
246 fd = xopen("state", O_RDONLY|O_NDELAY);
249 fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
253 prog[0] = (char*)"sh";
254 prog[1] = (char*)"-c";
255 prog[2] = ld->processor;
257 execv("/bin/sh", prog);
258 bb_perror_msg_and_die(FATAL"cannot %s processor %s", "run", ld->name);
264 static unsigned processorstop(struct logdir *ld)
270 while (safe_waitpid(ld->ppid, &wstat, 0) == -1)
271 pause2cannot("wait for processor", ld->name);
275 if (ld->fddir == -1) return 1;
276 while (fchdir(ld->fddir) == -1)
277 pause2cannot("change directory, want processor", ld->name);
278 if (wait_exitcode(wstat) != 0) {
279 warnx("processor failed, restart", ld->name);
280 ld->fnsave[26] = 't';
282 ld->fnsave[26] = 'u';
284 while (fchdir(fdwdir) == -1)
285 pause1cannot("change to initial working directory");
286 return ld->processor ? 0 : 1;
288 ld->fnsave[26] = 't';
289 memcpy(f, ld->fnsave, 26);
292 while (rename(ld->fnsave, f) == -1)
293 pause2cannot("rename processed", ld->name);
294 while (chmod(f, 0744) == -1)
295 pause2cannot("set mode of processed", ld->name);
296 ld->fnsave[26] = 'u';
297 if (unlink(ld->fnsave) == -1)
298 bb_error_msg(WARNING"cannot unlink: %s/%s", ld->name, ld->fnsave);
299 while (rename("newstate", "state") == -1)
300 pause2cannot("rename state", ld->name);
302 bb_error_msg(INFO"processed: %s/%s", ld->name, f);
303 while (fchdir(fdwdir) == -1)
304 pause1cannot("change to initial working directory");
308 static void rmoldest(struct logdir *ld)
312 char oldest[FMT_PTIME];
315 oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
316 while (!(d = opendir(".")))
317 pause2cannot("open directory, want rotate", ld->name);
319 while ((f = readdir(d))) {
320 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
321 if (f->d_name[26] == 't') {
322 if (unlink(f->d_name) == -1)
323 warn2("cannot unlink processor leftover", f->d_name);
326 if (strcmp(f->d_name, oldest) < 0)
327 memcpy(oldest, f->d_name, 27);
333 warn2("cannot read directory", ld->name);
336 if (ld->nmax && (n > ld->nmax)) {
338 bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
339 if ((*oldest == '@') && (unlink(oldest) == -1))
340 warn2("cannot unlink oldest logfile", ld->name);
344 static unsigned rotate(struct logdir *ld)
349 if (ld->fddir == -1) {
350 ld->rotate_period = 0;
354 while (!processorstop(ld))
357 while (fchdir(ld->fddir) == -1)
358 pause2cannot("change directory, want rotate", ld->name);
360 /* create new filename */
361 ld->fnsave[25] = '.';
362 ld->fnsave[26] = 's';
364 ld->fnsave[26] = 'u';
365 ld->fnsave[27] = '\0';
367 fmt_time_bernstein_25(ld->fnsave);
369 stat(ld->fnsave, &st);
370 } while (errno != ENOENT);
372 now = monotonic_sec();
373 if (ld->rotate_period && LESS(ld->next_rotate, now)) {
374 ld->next_rotate = now + ld->rotate_period;
375 if (LESS(ld->next_rotate, nearest_rotate))
376 nearest_rotate = ld->next_rotate;
380 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
381 pause2cannot("fsync current logfile", ld->name);
382 while (fchmod(ld->fdcur, 0744) == -1)
383 pause2cannot("set mode of current", ld->name);
384 ////close(ld->fdcur);
388 bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
389 ld->fnsave, ld->size);
391 while (rename("current", ld->fnsave) == -1)
392 pause2cannot("rename current", ld->name);
393 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
394 pause2cannot("create new current", ld->name);
395 /* we presume this cannot fail */
396 ld->filecur = fdopen(ld->fdcur, "a"); ////
397 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
398 close_on_exec_on(ld->fdcur);
400 while (fchmod(ld->fdcur, 0644) == -1)
401 pause2cannot("set mode of current", ld->name);
406 while (fchdir(fdwdir) == -1)
407 pause1cannot("change to initial working directory");
411 static int buffer_pwrite(int n, char *s, unsigned len)
414 struct logdir *ld = &dir[n];
417 if (ld->size >= ld->sizemax)
419 if (len > (ld->sizemax - ld->size))
420 len = ld->sizemax - ld->size;
423 ////i = full_write(ld->fdcur, s, len);
424 ////if (i != -1) break;
425 i = fwrite(s, 1, len, ld->filecur);
428 if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
431 char oldest[FMT_PTIME];
434 while (fchdir(ld->fddir) == -1)
435 pause2cannot("change directory, want remove old logfile",
438 oldest[1] = oldest[27] = '\0';
439 while (!(d = opendir(".")))
440 pause2cannot("open directory, want remove old logfile",
443 while ((f = readdir(d)))
444 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
446 if (strcmp(f->d_name, oldest) < 0)
447 memcpy(oldest, f->d_name, 27);
449 if (errno) warn2("cannot read directory, want remove old logfile",
454 if (*oldest == '@') {
455 bb_error_msg(WARNING"out of disk space, delete: %s/%s",
458 if (unlink(oldest) == -1) {
459 warn2("cannot unlink oldest logfile", ld->name);
462 while (fchdir(fdwdir) == -1)
463 pause1cannot("change to initial working directory");
468 pause2cannot("write to current", ld->name);
474 if (ld->size >= (ld->sizemax - linemax))
479 static void logdir_close(struct logdir *ld)
484 bb_error_msg(INFO"close: %s", ld->name);
488 return; /* impossible */
489 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
490 pause2cannot("fsync current logfile", ld->name);
491 while (fchmod(ld->fdcur, 0744) == -1)
492 pause2cannot("set mode of current", ld->name);
493 ////close(ld->fdcur);
496 if (ld->fdlock == -1)
497 return; /* impossible */
501 ld->processor = NULL;
504 static unsigned logdir_open(struct logdir *ld, const char *fn)
512 now = monotonic_sec();
514 ld->fddir = open(fn, O_RDONLY|O_NDELAY);
515 if (ld->fddir == -1) {
516 warn2("cannot open log directory", (char*)fn);
519 close_on_exec_on(ld->fddir);
520 if (fchdir(ld->fddir) == -1) {
522 warn2("cannot change directory", (char*)fn);
525 ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
526 if ((ld->fdlock == -1)
527 || (lock_exnb(ld->fdlock) == -1)
530 warn2("cannot lock directory", (char*)fn);
531 while (fchdir(fdwdir) == -1)
532 pause1cannot("change to initial working directory");
535 close_on_exec_on(ld->fdlock);
538 ld->sizemax = 1000000;
539 ld->nmax = ld->nmin = 10;
540 ld->rotate_period = 0;
541 ld->name = (char*)fn;
544 free(ld->inst); ld->inst = NULL;
545 free(ld->processor); ld->processor = NULL;
548 i = open_read_close("config", buf, sizeof(buf));
549 if (i < 0 && errno != ENOENT)
550 bb_perror_msg(WARNING"%s/config", ld->name);
553 bb_error_msg(INFO"read: %s/config", ld->name);
556 np = strchr(s, '\n');
564 /* Add '\n'-terminated line to ld->inst */
566 int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);
575 static const struct suffix_mult km_suffixes[] = {
580 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
584 ld->nmax = xatoi_u(&s[1]);
587 ld->nmin = xatoi_u(&s[1]);
590 static const struct suffix_mult mh_suffixes[] = {
593 /*{ "d", 24*60*60 },*/
596 ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
597 if (ld->rotate_period) {
598 ld->next_rotate = now + ld->rotate_period;
599 if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate))
600 nearest_rotate = ld->next_rotate;
608 ld->processor = wstrdup(s);
614 /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
617 np = strchr(s, '\n');
625 i = stat("current", &st);
627 if (st.st_size && !(st.st_mode & S_IXUSR)) {
628 ld->fnsave[25] = '.';
629 ld->fnsave[26] = 'u';
630 ld->fnsave[27] = '\0';
632 fmt_time_bernstein_25(ld->fnsave);
634 stat(ld->fnsave, &st);
635 } while (errno != ENOENT);
636 while (rename("current", ld->fnsave) == -1)
637 pause2cannot("rename current", ld->name);
641 /* st.st_size can be not just bigger, but WIDER!
642 * This code is safe: if st.st_size > 4GB, we select
643 * ld->sizemax (because it's "unsigned") */
644 ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
647 if (errno != ENOENT) {
649 warn2("cannot stat current", ld->name);
650 while (fchdir(fdwdir) == -1)
651 pause1cannot("change to initial working directory");
655 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
656 pause2cannot("open current", ld->name);
657 /* we presume this cannot fail */
658 ld->filecur = fdopen(ld->fdcur, "a"); ////
659 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
661 close_on_exec_on(ld->fdcur);
662 while (fchmod(ld->fdcur, 0644) == -1)
663 pause2cannot("set mode of current", ld->name);
666 if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
667 else bb_error_msg(INFO"new: %s/current", ld->name);
670 while (fchdir(fdwdir) == -1)
671 pause1cannot("change to initial working directory");
675 static void logdirs_reopen(void)
681 for (l = 0; l < dirn; ++l) {
682 logdir_close(&dir[l]);
683 if (logdir_open(&dir[l], fndir[l]))
687 fatalx("no functional log directories");
690 /* Will look good in libbb one day */
691 static ssize_t ndelay_read(int fd, void *buf, size_t count)
693 if (!(fl_flag_0 & O_NONBLOCK))
694 fcntl(fd, F_SETFL, fl_flag_0 | O_NONBLOCK);
695 count = safe_read(fd, buf, count);
696 if (!(fl_flag_0 & O_NONBLOCK))
697 fcntl(fd, F_SETFL, fl_flag_0);
701 /* Used for reading stdin */
702 static int buffer_pread(/*int fd, */char *s, unsigned len)
709 input.events = POLLIN;
713 for (i = 0; i < dirn; ++i)
726 now = monotonic_sec();
727 nearest_rotate = now + (45 * 60 + 45);
728 for (i = 0; i < dirn; ++i) {
729 if (dir[i].rotate_period) {
730 if (LESS(dir[i].next_rotate, now))
732 if (LESS(dir[i].next_rotate, nearest_rotate))
733 nearest_rotate = dir[i].next_rotate;
737 sigprocmask(SIG_UNBLOCK, &blocked_sigset, NULL);
738 i = nearest_rotate - now;
743 poll(&input, 1, i * 1000);
744 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
746 i = ndelay_read(0, s, len);
751 if (errno != EAGAIN) {
752 warn("cannot read standard input");
755 /* else: EAGAIN - normal, repeat silently */
760 linecomplete = (s[i-1] == '\n');
768 if (ch < 32 || ch > 126)
772 for (j = 0; replace[j]; ++j) {
773 if (ch == replace[j]) {
786 static void sig_term_handler(int sig_no)
789 bb_error_msg(INFO"sig%s received", "term");
793 static void sig_child_handler(int sig_no)
798 bb_error_msg(INFO"sig%s received", "child");
799 while ((pid = wait_any_nohang(&wstat)) > 0) {
800 for (l = 0; l < dirn; ++l) {
801 if (dir[l].ppid == pid) {
803 processorstop(&dir[l]);
810 static void sig_alarm_handler(int sig_no)
813 bb_error_msg(INFO"sig%s received", "alarm");
817 static void sig_hangup_handler(int sig_no)
820 bb_error_msg(INFO"sig%s received", "hangup");
824 static void logmatch(struct logdir *ld)
835 if (pmatch(s+1, line, linelen))
840 if (pmatch(s+1, line, linelen))
848 int svlogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
849 int svlogd_main(int argc, char **argv)
852 ssize_t stdin_cnt = 0;
855 unsigned timestamp = 0;
856 void* (*memRchr)(const void *, int, size_t) = memchr;
860 opt_complementary = "tt:vv";
861 opt = getopt32(argv, "r:R:l:b:tv",
862 &r, &replace, &l, &b, ×tamp, &verbose);
865 if (!repl || r[1]) usage();
867 if (opt & 2) if (!repl) repl = '_'; // -R
869 linemax = xatou_range(l, 0, BUFSIZ-26);
870 if (linemax == 0) linemax = BUFSIZ-26;
871 if (linemax < 256) linemax = 256;
873 ////if (opt & 8) { // -b
874 //// buflen = xatoi_u(b);
875 //// if (buflen == 0) buflen = 1024;
877 //if (opt & 0x10) timestamp++; // -t
878 //if (opt & 0x20) verbose++; // -v
879 //if (timestamp > 2) timestamp = 2;
884 if (dirn <= 0) usage();
885 ////if (buflen <= linemax) usage();
886 fdwdir = xopen(".", O_RDONLY|O_NDELAY);
887 close_on_exec_on(fdwdir);
888 dir = xzalloc(dirn * sizeof(struct logdir));
889 for (i = 0; i < dirn; ++i) {
892 ////dir[i].btmp = xmalloc(buflen);
895 /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
897 /* We cannot set NONBLOCK on fd #0 permanently - this setting
898 * _isn't_ per-process! It is shared among all other processes
899 * with the same stdin */
900 fl_flag_0 = fcntl(0, F_GETFL);
902 sigemptyset(&blocked_sigset);
903 sigaddset(&blocked_sigset, SIGTERM);
904 sigaddset(&blocked_sigset, SIGCHLD);
905 sigaddset(&blocked_sigset, SIGALRM);
906 sigaddset(&blocked_sigset, SIGHUP);
907 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
908 bb_signals_recursive(1 << SIGTERM, sig_term_handler);
909 bb_signals_recursive(1 << SIGCHLD, sig_child_handler);
910 bb_signals_recursive(1 << SIGALRM, sig_alarm_handler);
911 bb_signals_recursive(1 << SIGHUP, sig_hangup_handler);
915 /* Without timestamps, we don't have to print each line
916 * separately, so we can look for _last_ newline, not first,
917 * thus batching writes */
921 setvbuf(stderr, NULL, _IOFBF, linelen);
923 /* Each iteration processes one or more lines */
925 char stamp[FMT_PTIME];
936 /* lineptr[0..linemax-1] - buffer for stdin */
937 /* (possibly has some unprocessed data from prev loop) */
939 /* Refill the buffer if needed */
940 np = memRchr(lineptr, '\n', stdin_cnt);
941 if (!np && !exitasap) {
942 i = linemax - stdin_cnt; /* avail. bytes at tail */
944 i = buffer_pread(/*0, */lineptr + stdin_cnt, i);
945 if (i <= 0) /* EOF or error on stdin */
948 np = memRchr(lineptr + stdin_cnt, '\n', i);
953 if (stdin_cnt <= 0 && exitasap)
956 /* Search for '\n' (in fact, np already holds the result) */
959 print_to_nl: /* NB: starting from here lineptr may point
960 * farther out into line[] */
961 linelen = np - lineptr + 1;
963 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
964 ch = lineptr[linelen-1];
966 /* Biggest performance hit was coming from the fact
967 * that we did not buffer writes. We were reading many lines
968 * in one read() above, but wrote one line per write().
969 * We are using stdio to fix that */
971 /* write out lineptr[0..linelen-1] to each log destination
972 * (or lineptr[-26..linelen-1] if timestamping) */
977 fmt_time_bernstein_25(stamp);
979 fmt_time_human_30nul(stamp);
982 memcpy(printptr, stamp, 25);
985 for (i = 0; i < dirn; ++i) {
986 struct logdir *ld = &dir[i];
987 if (ld->fddir == -1) continue;
990 if (ld->matcherr == 'e') {
991 /* runit-1.8.0 compat: if timestamping, do it on stderr too */
992 ////full_write(2, printptr, printlen);
993 fwrite(printptr, 1, printlen, stderr);
995 if (ld->match != '+') continue;
996 buffer_pwrite(i, printptr, printlen);
999 /* If we didn't see '\n' (long input line), */
1000 /* read/write repeatedly until we see it */
1001 while (ch != '\n') {
1002 /* lineptr is emptied now, safe to use as buffer */
1003 stdin_cnt = exitasap ? -1 : buffer_pread(/*0, */lineptr, linemax);
1004 if (stdin_cnt <= 0) { /* EOF or error on stdin */
1006 lineptr[0] = ch = '\n';
1010 linelen = stdin_cnt;
1011 np = memRchr(lineptr, '\n', stdin_cnt);
1013 linelen = np - lineptr + 1;
1014 ch = lineptr[linelen-1];
1016 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
1017 for (i = 0; i < dirn; ++i) {
1018 if (dir[i].fddir == -1) continue;
1019 if (dir[i].matcherr == 'e') {
1020 ////full_write(2, lineptr, linelen);
1021 fwrite(lineptr, 1, linelen, stderr);
1023 if (dir[i].match != '+') continue;
1024 buffer_pwrite(i, lineptr, linelen);
1028 stdin_cnt -= linelen;
1029 if (stdin_cnt > 0) {
1031 /* If we see another '\n', we don't need to read
1032 * next piece of input: can print what we have */
1033 np = memRchr(lineptr, '\n', stdin_cnt);
1036 /* Move unprocessed data to the front of line */
1037 memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1042 for (i = 0; i < dirn; ++i) {
1044 while (!processorstop(&dir[i]))
1046 logdir_close(&dir[i]);