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 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
);
225 signal(SIGTERM
, SIG_DFL
);
226 signal(SIGALRM
, SIG_DFL
);
227 signal(SIGHUP
, SIG_DFL
);
228 sig_unblock(SIGTERM
);
229 sig_unblock(SIGALRM
);
233 bb_error_msg(INFO
"processing: %s/%s", ld
->name
, ld
->fnsave
);
234 fd
= xopen(ld
->fnsave
, O_RDONLY
|O_NDELAY
);
236 ld
->fnsave
[26] = 't';
237 fd
= xopen(ld
->fnsave
, O_WRONLY
|O_NDELAY
|O_TRUNC
|O_CREAT
);
239 fd
= open_read("state");
242 bb_perror_msg_and_die(FATAL
"cannot %s processor %s", "open state for", ld
->name
);
243 close(xopen("state", O_WRONLY
|O_NDELAY
|O_TRUNC
|O_CREAT
));
244 fd
= xopen("state", O_RDONLY
|O_NDELAY
);
247 fd
= xopen("newstate", O_WRONLY
|O_NDELAY
|O_TRUNC
|O_CREAT
);
251 prog
[0] = (char*)"sh";
252 prog
[1] = (char*)"-c";
253 prog
[2] = ld
->processor
;
255 execve("/bin/sh", prog
, environ
);
256 bb_perror_msg_and_die(FATAL
"cannot %s processor %s", "run", ld
->name
);
262 static unsigned processorstop(struct logdir
*ld
)
268 while (wait_pid(&wstat
, ld
->ppid
) == -1)
269 pause2cannot("wait for processor", ld
->name
);
273 if (ld
->fddir
== -1) return 1;
274 while (fchdir(ld
->fddir
) == -1)
275 pause2cannot("change directory, want processor", ld
->name
);
276 if (wait_exitcode(wstat
) != 0) {
277 warnx("processor failed, restart", ld
->name
);
278 ld
->fnsave
[26] = 't';
280 ld
->fnsave
[26] = 'u';
282 while (fchdir(fdwdir
) == -1)
283 pause1cannot("change to initial working directory");
284 return ld
->processor
? 0 : 1;
286 ld
->fnsave
[26] = 't';
287 memcpy(f
, ld
->fnsave
, 26);
290 while (rename(ld
->fnsave
, f
) == -1)
291 pause2cannot("rename processed", ld
->name
);
292 while (chmod(f
, 0744) == -1)
293 pause2cannot("set mode of processed", ld
->name
);
294 ld
->fnsave
[26] = 'u';
295 if (unlink(ld
->fnsave
) == -1)
296 bb_error_msg(WARNING
"cannot unlink: %s/%s", ld
->name
, ld
->fnsave
);
297 while (rename("newstate", "state") == -1)
298 pause2cannot("rename state", ld
->name
);
300 bb_error_msg(INFO
"processed: %s/%s", ld
->name
, f
);
301 while (fchdir(fdwdir
) == -1)
302 pause1cannot("change to initial working directory");
306 static void rmoldest(struct logdir
*ld
)
310 char oldest
[FMT_PTIME
];
313 oldest
[0] = 'A'; oldest
[1] = oldest
[27] = 0;
314 while (!(d
= opendir(".")))
315 pause2cannot("open directory, want rotate", ld
->name
);
317 while ((f
= readdir(d
))) {
318 if ((f
->d_name
[0] == '@') && (strlen(f
->d_name
) == 27)) {
319 if (f
->d_name
[26] == 't') {
320 if (unlink(f
->d_name
) == -1)
321 warn2("cannot unlink processor leftover", f
->d_name
);
324 if (strcmp(f
->d_name
, oldest
) < 0)
325 memcpy(oldest
, f
->d_name
, 27);
331 warn2("cannot read directory", ld
->name
);
334 if (ld
->nmax
&& (n
> ld
->nmax
)) {
336 bb_error_msg(INFO
"delete: %s/%s", ld
->name
, oldest
);
337 if ((*oldest
== '@') && (unlink(oldest
) == -1))
338 warn2("cannot unlink oldest logfile", ld
->name
);
342 static unsigned rotate(struct logdir
*ld
)
347 if (ld
->fddir
== -1) {
348 ld
->rotate_period
= 0;
352 while (!processorstop(ld
))
355 while (fchdir(ld
->fddir
) == -1)
356 pause2cannot("change directory, want rotate", ld
->name
);
358 /* create new filename */
359 ld
->fnsave
[25] = '.';
360 ld
->fnsave
[26] = 's';
362 ld
->fnsave
[26] = 'u';
363 ld
->fnsave
[27] = '\0';
365 fmt_time_bernstein_25(ld
->fnsave
);
367 stat(ld
->fnsave
, &st
);
368 } while (errno
!= ENOENT
);
370 now
= monotonic_sec();
371 if (ld
->rotate_period
&& LESS(ld
->next_rotate
, now
)) {
372 ld
->next_rotate
= now
+ ld
->rotate_period
;
373 if (LESS(ld
->next_rotate
, nearest_rotate
))
374 nearest_rotate
= ld
->next_rotate
;
378 while (fflush(ld
->filecur
) || fsync(ld
->fdcur
) == -1)
379 pause2cannot("fsync current logfile", ld
->name
);
380 while (fchmod(ld
->fdcur
, 0744) == -1)
381 pause2cannot("set mode of current", ld
->name
);
382 ////close(ld->fdcur);
386 bb_error_msg(INFO
"rename: %s/current %s %u", ld
->name
,
387 ld
->fnsave
, ld
->size
);
389 while (rename("current", ld
->fnsave
) == -1)
390 pause2cannot("rename current", ld
->name
);
391 while ((ld
->fdcur
= open("current", O_WRONLY
|O_NDELAY
|O_APPEND
|O_CREAT
, 0600)) == -1)
392 pause2cannot("create new current", ld
->name
);
393 /* we presume this cannot fail */
394 ld
->filecur
= fdopen(ld
->fdcur
, "a"); ////
395 setvbuf(ld
->filecur
, NULL
, _IOFBF
, linelen
); ////
396 close_on_exec_on(ld
->fdcur
);
398 while (fchmod(ld
->fdcur
, 0644) == -1)
399 pause2cannot("set mode of current", ld
->name
);
404 while (fchdir(fdwdir
) == -1)
405 pause1cannot("change to initial working directory");
409 static int buffer_pwrite(int n
, char *s
, unsigned len
)
412 struct logdir
*ld
= &dir
[n
];
415 if (ld
->size
>= ld
->sizemax
)
417 if (len
> (ld
->sizemax
- ld
->size
))
418 len
= ld
->sizemax
- ld
->size
;
421 ////i = full_write(ld->fdcur, s, len);
422 ////if (i != -1) break;
423 i
= fwrite(s
, 1, len
, ld
->filecur
);
426 if ((errno
== ENOSPC
) && (ld
->nmin
< ld
->nmax
)) {
429 char oldest
[FMT_PTIME
];
432 while (fchdir(ld
->fddir
) == -1)
433 pause2cannot("change directory, want remove old logfile",
436 oldest
[1] = oldest
[27] = '\0';
437 while (!(d
= opendir(".")))
438 pause2cannot("open directory, want remove old logfile",
441 while ((f
= readdir(d
)))
442 if ((f
->d_name
[0] == '@') && (strlen(f
->d_name
) == 27)) {
444 if (strcmp(f
->d_name
, oldest
) < 0)
445 memcpy(oldest
, f
->d_name
, 27);
447 if (errno
) warn2("cannot read directory, want remove old logfile",
452 if (*oldest
== '@') {
453 bb_error_msg(WARNING
"out of disk space, delete: %s/%s",
456 if (unlink(oldest
) == -1) {
457 warn2("cannot unlink oldest logfile", ld
->name
);
460 while (fchdir(fdwdir
) == -1)
461 pause1cannot("change to initial working directory");
466 pause2cannot("write to current", ld
->name
);
472 if (ld
->size
>= (ld
->sizemax
- linemax
))
477 static void logdir_close(struct logdir
*ld
)
482 bb_error_msg(INFO
"close: %s", ld
->name
);
486 return; /* impossible */
487 while (fflush(ld
->filecur
) || fsync(ld
->fdcur
) == -1)
488 pause2cannot("fsync current logfile", ld
->name
);
489 while (fchmod(ld
->fdcur
, 0744) == -1)
490 pause2cannot("set mode of current", ld
->name
);
491 ////close(ld->fdcur);
494 if (ld
->fdlock
== -1)
495 return; /* impossible */
499 ld
->processor
= NULL
;
502 static unsigned logdir_open(struct logdir
*ld
, const char *fn
)
510 now
= monotonic_sec();
512 ld
->fddir
= open(fn
, O_RDONLY
|O_NDELAY
);
513 if (ld
->fddir
== -1) {
514 warn2("cannot open log directory", (char*)fn
);
517 close_on_exec_on(ld
->fddir
);
518 if (fchdir(ld
->fddir
) == -1) {
520 warn2("cannot change directory", (char*)fn
);
523 ld
->fdlock
= open("lock", O_WRONLY
|O_NDELAY
|O_APPEND
|O_CREAT
, 0600);
524 if ((ld
->fdlock
== -1)
525 || (lock_exnb(ld
->fdlock
) == -1)
528 warn2("cannot lock directory", (char*)fn
);
529 while (fchdir(fdwdir
) == -1)
530 pause1cannot("change to initial working directory");
533 close_on_exec_on(ld
->fdlock
);
536 ld
->sizemax
= 1000000;
537 ld
->nmax
= ld
->nmin
= 10;
538 ld
->rotate_period
= 0;
539 ld
->name
= (char*)fn
;
542 free(ld
->inst
); ld
->inst
= NULL
;
543 free(ld
->processor
); ld
->processor
= NULL
;
546 i
= open_read_close("config", buf
, sizeof(buf
));
547 if (i
< 0 && errno
!= ENOENT
)
548 bb_perror_msg(WARNING
"%s/config", ld
->name
);
551 bb_error_msg(INFO
"read: %s/config", ld
->name
);
554 np
= strchr(s
, '\n');
562 /* Add '\n'-terminated line to ld->inst */
564 int l
= asprintf(&new, "%s%s\n", ld
->inst
? : "", s
);
573 static const struct suffix_mult km_suffixes
[] = {
578 ld
->sizemax
= xatou_sfx(&s
[1], km_suffixes
);
582 ld
->nmax
= xatoi_u(&s
[1]);
585 ld
->nmin
= xatoi_u(&s
[1]);
588 static const struct suffix_mult mh_suffixes
[] = {
591 /*{ "d", 24*60*60 },*/
594 ld
->rotate_period
= xatou_sfx(&s
[1], mh_suffixes
);
595 if (ld
->rotate_period
) {
596 ld
->next_rotate
= now
+ ld
->rotate_period
;
597 if (!tmaxflag
|| LESS(ld
->next_rotate
, nearest_rotate
))
598 nearest_rotate
= ld
->next_rotate
;
606 ld
->processor
= wstrdup(s
);
612 /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
615 np
= strchr(s
, '\n');
623 i
= stat("current", &st
);
625 if (st
.st_size
&& !(st
.st_mode
& S_IXUSR
)) {
626 ld
->fnsave
[25] = '.';
627 ld
->fnsave
[26] = 'u';
628 ld
->fnsave
[27] = '\0';
630 fmt_time_bernstein_25(ld
->fnsave
);
632 stat(ld
->fnsave
, &st
);
633 } while (errno
!= ENOENT
);
634 while (rename("current", ld
->fnsave
) == -1)
635 pause2cannot("rename current", ld
->name
);
639 /* st.st_size can be not just bigger, but WIDER!
640 * This code is safe: if st.st_size > 4GB, we select
641 * ld->sizemax (because it's "unsigned") */
642 ld
->size
= (st
.st_size
> ld
->sizemax
) ? ld
->sizemax
: st
.st_size
;
645 if (errno
!= ENOENT
) {
647 warn2("cannot stat current", ld
->name
);
648 while (fchdir(fdwdir
) == -1)
649 pause1cannot("change to initial working directory");
653 while ((ld
->fdcur
= open("current", O_WRONLY
|O_NDELAY
|O_APPEND
|O_CREAT
, 0600)) == -1)
654 pause2cannot("open current", ld
->name
);
655 /* we presume this cannot fail */
656 ld
->filecur
= fdopen(ld
->fdcur
, "a"); ////
657 setvbuf(ld
->filecur
, NULL
, _IOFBF
, linelen
); ////
659 close_on_exec_on(ld
->fdcur
);
660 while (fchmod(ld
->fdcur
, 0644) == -1)
661 pause2cannot("set mode of current", ld
->name
);
664 if (i
== 0) bb_error_msg(INFO
"append: %s/current", ld
->name
);
665 else bb_error_msg(INFO
"new: %s/current", ld
->name
);
668 while (fchdir(fdwdir
) == -1)
669 pause1cannot("change to initial working directory");
673 static void logdirs_reopen(void)
679 for (l
= 0; l
< dirn
; ++l
) {
680 logdir_close(&dir
[l
]);
681 if (logdir_open(&dir
[l
], fndir
[l
]))
685 fatalx("no functional log directories");
688 /* Will look good in libbb one day */
689 static ssize_t
ndelay_read(int fd
, void *buf
, size_t count
)
691 if (!(fl_flag_0
& O_NONBLOCK
))
692 fcntl(fd
, F_SETFL
, fl_flag_0
| O_NONBLOCK
);
693 count
= safe_read(fd
, buf
, count
);
694 if (!(fl_flag_0
& O_NONBLOCK
))
695 fcntl(fd
, F_SETFL
, fl_flag_0
);
699 /* Used for reading stdin */
700 static int buffer_pread(/*int fd, */char *s
, unsigned len
)
707 input
.events
= POLLIN
;
711 for (i
= 0; i
< dirn
; ++i
)
724 now
= monotonic_sec();
725 nearest_rotate
= now
+ (45 * 60 + 45);
726 for (i
= 0; i
< dirn
; ++i
) {
727 if (dir
[i
].rotate_period
) {
728 if (LESS(dir
[i
].next_rotate
, now
))
730 if (LESS(dir
[i
].next_rotate
, nearest_rotate
))
731 nearest_rotate
= dir
[i
].next_rotate
;
735 sigprocmask(SIG_UNBLOCK
, &blocked_sigset
, NULL
);
736 i
= nearest_rotate
- now
;
741 poll(&input
, 1, i
* 1000);
742 sigprocmask(SIG_BLOCK
, &blocked_sigset
, NULL
);
744 i
= ndelay_read(0, s
, len
);
749 if (errno
!= EAGAIN
) {
750 warn("cannot read standard input");
753 /* else: EAGAIN - normal, repeat silently */
758 linecomplete
= (s
[i
-1] == '\n');
766 if (ch
< 32 || ch
> 126)
770 for (j
= 0; replace
[j
]; ++j
) {
771 if (ch
== replace
[j
]) {
784 static void sig_term_handler(int sig_no
)
787 bb_error_msg(INFO
"sig%s received", "term");
791 static void sig_child_handler(int sig_no
)
796 bb_error_msg(INFO
"sig%s received", "child");
797 while ((pid
= wait_nohang(&wstat
)) > 0) {
798 for (l
= 0; l
< dirn
; ++l
) {
799 if (dir
[l
].ppid
== pid
) {
801 processorstop(&dir
[l
]);
808 static void sig_alarm_handler(int sig_no
)
811 bb_error_msg(INFO
"sig%s received", "alarm");
815 static void sig_hangup_handler(int sig_no
)
818 bb_error_msg(INFO
"sig%s received", "hangup");
822 static void logmatch(struct logdir
*ld
)
833 if (pmatch(s
+1, line
, linelen
))
838 if (pmatch(s
+1, line
, linelen
))
846 int svlogd_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
847 int svlogd_main(int argc
, char **argv
)
850 ssize_t stdin_cnt
= 0;
853 unsigned timestamp
= 0;
854 void* (*memRchr
)(const void *, int, size_t) = memchr
;
858 opt_complementary
= "tt:vv";
859 opt
= getopt32(argv
, "r:R:l:b:tv",
860 &r
, &replace
, &l
, &b
, ×tamp
, &verbose
);
863 if (!repl
|| r
[1]) usage();
865 if (opt
& 2) if (!repl
) repl
= '_'; // -R
867 linemax
= xatou_range(l
, 0, BUFSIZ
-26);
868 if (linemax
== 0) linemax
= BUFSIZ
-26;
869 if (linemax
< 256) linemax
= 256;
871 ////if (opt & 8) { // -b
872 //// buflen = xatoi_u(b);
873 //// if (buflen == 0) buflen = 1024;
875 //if (opt & 0x10) timestamp++; // -t
876 //if (opt & 0x20) verbose++; // -v
877 //if (timestamp > 2) timestamp = 2;
882 if (dirn
<= 0) usage();
883 ////if (buflen <= linemax) usage();
884 fdwdir
= xopen(".", O_RDONLY
|O_NDELAY
);
885 close_on_exec_on(fdwdir
);
886 dir
= xzalloc(dirn
* sizeof(struct logdir
));
887 for (i
= 0; i
< dirn
; ++i
) {
890 ////dir[i].btmp = xmalloc(buflen);
893 /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
895 /* We cannot set NONBLOCK on fd #0 permanently - this setting
896 * _isn't_ per-process! It is shared among all other processes
897 * with the same stdin */
898 fl_flag_0
= fcntl(0, F_GETFL
);
900 sigemptyset(&blocked_sigset
);
901 sigaddset(&blocked_sigset
, SIGTERM
);
902 sigaddset(&blocked_sigset
, SIGCHLD
);
903 sigaddset(&blocked_sigset
, SIGALRM
);
904 sigaddset(&blocked_sigset
, SIGHUP
);
905 sigprocmask(SIG_BLOCK
, &blocked_sigset
, NULL
);
906 sig_catch(SIGTERM
, sig_term_handler
);
907 sig_catch(SIGCHLD
, sig_child_handler
);
908 sig_catch(SIGALRM
, sig_alarm_handler
);
909 sig_catch(SIGHUP
, sig_hangup_handler
);
913 /* Without timestamps, we don't have to print each line
914 * separately, so we can look for _last_ newline, not first,
915 * thus batching writes */
919 setvbuf(stderr
, NULL
, _IOFBF
, linelen
);
921 /* Each iteration processes one or more lines */
923 char stamp
[FMT_PTIME
];
934 /* lineptr[0..linemax-1] - buffer for stdin */
935 /* (possibly has some unprocessed data from prev loop) */
937 /* Refill the buffer if needed */
938 np
= memRchr(lineptr
, '\n', stdin_cnt
);
939 if (!np
&& !exitasap
) {
940 i
= linemax
- stdin_cnt
; /* avail. bytes at tail */
942 i
= buffer_pread(/*0, */lineptr
+ stdin_cnt
, i
);
943 if (i
<= 0) /* EOF or error on stdin */
946 np
= memRchr(lineptr
+ stdin_cnt
, '\n', i
);
951 if (stdin_cnt
<= 0 && exitasap
)
954 /* Search for '\n' (in fact, np already holds the result) */
957 print_to_nl
: /* NB: starting from here lineptr may point
958 * farther out into line[] */
959 linelen
= np
- lineptr
+ 1;
961 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
962 ch
= lineptr
[linelen
-1];
964 /* Biggest performance hit was coming from the fact
965 * that we did not buffer writes. We were reading many lines
966 * in one read() above, but wrote one line per write().
967 * We are using stdio to fix that */
969 /* write out lineptr[0..linelen-1] to each log destination
970 * (or lineptr[-26..linelen-1] if timestamping) */
975 fmt_time_bernstein_25(stamp
);
977 fmt_time_human_30nul(stamp
);
980 memcpy(printptr
, stamp
, 25);
983 for (i
= 0; i
< dirn
; ++i
) {
984 struct logdir
*ld
= &dir
[i
];
985 if (ld
->fddir
== -1) continue;
988 if (ld
->matcherr
== 'e') {
989 /* runit-1.8.0 compat: if timestamping, do it on stderr too */
990 ////full_write(2, printptr, printlen);
991 fwrite(printptr
, 1, printlen
, stderr
);
993 if (ld
->match
!= '+') continue;
994 buffer_pwrite(i
, printptr
, printlen
);
997 /* If we didn't see '\n' (long input line), */
998 /* read/write repeatedly until we see it */
1000 /* lineptr is emptied now, safe to use as buffer */
1001 stdin_cnt
= exitasap
? -1 : buffer_pread(/*0, */lineptr
, linemax
);
1002 if (stdin_cnt
<= 0) { /* EOF or error on stdin */
1004 lineptr
[0] = ch
= '\n';
1008 linelen
= stdin_cnt
;
1009 np
= memRchr(lineptr
, '\n', stdin_cnt
);
1011 linelen
= np
- lineptr
+ 1;
1012 ch
= lineptr
[linelen
-1];
1014 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
1015 for (i
= 0; i
< dirn
; ++i
) {
1016 if (dir
[i
].fddir
== -1) continue;
1017 if (dir
[i
].matcherr
== 'e') {
1018 ////full_write(2, lineptr, linelen);
1019 fwrite(lineptr
, 1, linelen
, stderr
);
1021 if (dir
[i
].match
!= '+') continue;
1022 buffer_pwrite(i
, lineptr
, linelen
);
1026 stdin_cnt
-= linelen
;
1027 if (stdin_cnt
> 0) {
1029 /* If we see another '\n', we don't need to read
1030 * next piece of input: can print what we have */
1031 np
= memRchr(lineptr
, '\n', stdin_cnt
);
1034 /* Move unprocessed data to the front of line */
1035 memmove((timestamp
? line
+26 : line
), lineptr
, stdin_cnt
);
1040 for (i
= 0; i
< dirn
; ++i
) {
1042 while (!processorstop(&dir
[i
]))
1044 logdir_close(&dir
[i
]);