blob: 9c169da1f3b9c3fe6e5738611a3061b72ea1649a [file] [log] [blame]
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001/*
2Copyright (c) 2001-2006, Gerrit Pape
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
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.
15
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28/* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
29/* TODO: depends on runit_lib.c - review and reduce/eliminate */
30
31#include <sys/poll.h>
32#include <sys/file.h>
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000033#include "libbb.h"
Denis Vlasenko83ea6432006-11-16 02:27:24 +000034#include "runit_lib.h"
35
Denis Vlasenko45946f82007-08-20 17:27:40 +000036#define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0)
37
38#define FMT_PTIME 30
39
Denis Vlasenko339936b2007-10-05 22:11:06 +000040struct logdir {
Denis Vlasenko64392902007-02-03 00:53:43 +000041 ////char *btmp;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000042 /* pattern list to match, in "aa\0bb\0\cc\0\0" form */
43 char *inst;
44 char *processor;
45 char *name;
46 unsigned size;
47 unsigned sizemax;
48 unsigned nmax;
49 unsigned nmin;
Denis Vlasenko45946f82007-08-20 17:27:40 +000050 unsigned rotate_period;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000051 int ppid;
52 int fddir;
53 int fdcur;
Denis Vlasenko64392902007-02-03 00:53:43 +000054 FILE* filecur; ////
Denis Vlasenko83ea6432006-11-16 02:27:24 +000055 int fdlock;
Denis Vlasenko45946f82007-08-20 17:27:40 +000056 unsigned next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000057 char fnsave[FMT_PTIME];
58 char match;
59 char matcherr;
Denis Vlasenko339936b2007-10-05 22:11:06 +000060};
61
62
63struct globals {
64 struct logdir *dir;
65 unsigned verbose;
66 int linemax;
67 ////int buflen;
68 int linelen;
69
70 int fdwdir;
71 char **fndir;
72 int wstat;
73 unsigned nearest_rotate;
74
75 smallint exitasap;
76 smallint rotateasap;
77 smallint reopenasap;
78 smallint linecomplete;
79 smallint tmaxflag;
80
81 char repl;
82 const char *replace;
83 int fl_flag_0;
84 unsigned dirn;
85
86 sigset_t blocked_sigset;
87};
88#define G (*(struct globals*)ptr_to_globals)
89#define dir (G.dir )
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)); \
110 linemax = 1000; \
111 /*buflen = 1024;*/ \
112 linecomplete = 1; \
113 replace = ""; \
114} while (0)
115
116#define line bb_common_bufsiz1
117
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000118
119#define FATAL "fatal: "
120#define WARNING "warning: "
121#define PAUSE "pausing: "
122#define INFO "info: "
123
124#define usage() bb_show_usage()
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000125static void fatalx(const char *m0)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000126{
127 bb_error_msg_and_die(FATAL"%s", m0);
128}
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000129static void warn(const char *m0)
130{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000131 bb_perror_msg(WARNING"%s", m0);
132}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000133static void warn2(const char *m0, const char *m1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000134{
135 bb_perror_msg(WARNING"%s: %s", m0, m1);
136}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000137static void warnx(const char *m0, const char *m1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000138{
139 bb_error_msg(WARNING"%s: %s", m0, m1);
140}
141static void pause_nomem(void)
142{
Denis Vlasenko8c783952007-01-27 22:21:52 +0000143 bb_error_msg(PAUSE"out of memory");
144 sleep(3);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000145}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000146static void pause1cannot(const char *m0)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000147{
Denis Vlasenko8c783952007-01-27 22:21:52 +0000148 bb_perror_msg(PAUSE"cannot %s", m0);
149 sleep(3);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000150}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000151static void pause2cannot(const char *m0, const char *m1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000152{
153 bb_perror_msg(PAUSE"cannot %s %s", m0, m1);
154 sleep(3);
155}
156
157static char* wstrdup(const char *str)
158{
159 char *s;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000160 while (!(s = strdup(str)))
161 pause_nomem();
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000162 return s;
163}
164
Denis Vlasenko45946f82007-08-20 17:27:40 +0000165/*** ex fmt_ptime.[ch] ***/
166
167/* NUL terminated */
168static void fmt_time_human_30nul(char *s)
169{
170 struct tm *t;
171 struct timeval tv;
172
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)
183 );
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') */
187}
188
189/* NOT terminated! */
190static void fmt_time_bernstein_25(char *s)
191{
192 uint32_t pack[3];
193 struct timeval tv;
194 unsigned sec_hi;
195
196 gettimeofday(&tv, NULL);
197 sec_hi = (0x400000000000000aULL + tv.tv_sec) >> 32;
198 tv.tv_sec = (time_t)(0x400000000000000aULL) + tv.tv_sec;
199 tv.tv_usec *= 1000;
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);
205 *s++ = '@';
206 bin2hex(s, (char*)pack, 12);
207}
208
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000209static unsigned processorstart(struct logdir *ld)
210{
211 int pid;
212
213 if (!ld->processor) return 0;
214 if (ld->ppid) {
215 warnx("processor already running", ld->name);
216 return 0;
217 }
218 while ((pid = fork()) == -1)
219 pause2cannot("fork for processor", ld->name);
220 if (!pid) {
221 char *prog[4];
222 int fd;
223
224 /* child */
Denis Vlasenko2856dab2007-04-01 01:18:20 +0000225 signal(SIGTERM, SIG_DFL);
226 signal(SIGALRM, SIG_DFL);
227 signal(SIGHUP, SIG_DFL);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000228 sig_unblock(SIGTERM);
229 sig_unblock(SIGALRM);
230 sig_unblock(SIGHUP);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000231
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000232 if (verbose)
233 bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
234 fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000235 xmove_fd(fd, 0);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000236 ld->fnsave[26] = 't';
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000237 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000238 xmove_fd(fd, 1);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000239 fd = open_read("state");
240 if (fd == -1) {
241 if (errno != ENOENT)
242 bb_perror_msg_and_die(FATAL"cannot %s processor %s", "open state for", ld->name);
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000243 close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000244 fd = xopen("state", O_RDONLY|O_NDELAY);
245 }
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000246 xmove_fd(fd, 4);
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000247 fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000248 xmove_fd(fd, 5);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000249
Denis Vlasenko8c783952007-01-27 22:21:52 +0000250// getenv("SHELL")?
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000251 prog[0] = (char*)"sh";
252 prog[1] = (char*)"-c";
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000253 prog[2] = ld->processor;
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000254 prog[3] = NULL;
Denis Vlasenko847fa772008-01-28 22:45:43 +0000255 execv("/bin/sh", prog);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000256 bb_perror_msg_and_die(FATAL"cannot %s processor %s", "run", ld->name);
257 }
258 ld->ppid = pid;
259 return 1;
260}
261
262static unsigned processorstop(struct logdir *ld)
263{
264 char f[28];
265
266 if (ld->ppid) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000267 sig_unblock(SIGHUP);
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000268 while (safe_waitpid(ld->ppid, &wstat, 0) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000269 pause2cannot("wait for processor", ld->name);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000270 sig_block(SIGHUP);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000271 ld->ppid = 0;
272 }
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';
279 unlink(ld->fnsave);
280 ld->fnsave[26] = 'u';
281 processorstart(ld);
282 while (fchdir(fdwdir) == -1)
283 pause1cannot("change to initial working directory");
284 return ld->processor ? 0 : 1;
285 }
286 ld->fnsave[26] = 't';
287 memcpy(f, ld->fnsave, 26);
288 f[26] = 's';
289 f[27] = '\0';
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);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000299 if (verbose)
300 bb_error_msg(INFO"processed: %s/%s", ld->name, f);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000301 while (fchdir(fdwdir) == -1)
302 pause1cannot("change to initial working directory");
303 return 1;
304}
305
306static void rmoldest(struct logdir *ld)
307{
308 DIR *d;
309 struct dirent *f;
310 char oldest[FMT_PTIME];
311 int n = 0;
312
313 oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
314 while (!(d = opendir(".")))
315 pause2cannot("open directory, want rotate", ld->name);
316 errno = 0;
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);
322 } else {
323 ++n;
324 if (strcmp(f->d_name, oldest) < 0)
325 memcpy(oldest, f->d_name, 27);
326 }
327 errno = 0;
328 }
329 }
Denis Vlasenko8c783952007-01-27 22:21:52 +0000330 if (errno)
331 warn2("cannot read directory", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000332 closedir(d);
333
334 if (ld->nmax && (n > ld->nmax)) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000335 if (verbose)
336 bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000337 if ((*oldest == '@') && (unlink(oldest) == -1))
338 warn2("cannot unlink oldest logfile", ld->name);
339 }
340}
341
342static unsigned rotate(struct logdir *ld)
343{
344 struct stat st;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000345 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000346
347 if (ld->fddir == -1) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000348 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000349 return 0;
350 }
351 if (ld->ppid)
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000352 while (!processorstop(ld))
Denis Vlasenko45946f82007-08-20 17:27:40 +0000353 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000354
355 while (fchdir(ld->fddir) == -1)
356 pause2cannot("change directory, want rotate", ld->name);
357
358 /* create new filename */
359 ld->fnsave[25] = '.';
360 ld->fnsave[26] = 's';
361 if (ld->processor)
362 ld->fnsave[26] = 'u';
363 ld->fnsave[27] = '\0';
364 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000365 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000366 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000367 stat(ld->fnsave, &st);
368 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000369
Denis Vlasenko45946f82007-08-20 17:27:40 +0000370 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;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000375 }
376
377 if (ld->size > 0) {
Denis Vlasenko64392902007-02-03 00:53:43 +0000378 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000379 pause2cannot("fsync current logfile", ld->name);
380 while (fchmod(ld->fdcur, 0744) == -1)
381 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000382 ////close(ld->fdcur);
383 fclose(ld->filecur);
384
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000385 if (verbose) {
386 bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
387 ld->fnsave, ld->size);
388 }
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);
Denis Vlasenko64392902007-02-03 00:53:43 +0000393 /* we presume this cannot fail */
394 ld->filecur = fdopen(ld->fdcur, "a"); ////
395 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000396 close_on_exec_on(ld->fdcur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000397 ld->size = 0;
398 while (fchmod(ld->fdcur, 0644) == -1)
399 pause2cannot("set mode of current", ld->name);
400 rmoldest(ld);
401 processorstart(ld);
402 }
403
404 while (fchdir(fdwdir) == -1)
405 pause1cannot("change to initial working directory");
406 return 1;
407}
408
409static int buffer_pwrite(int n, char *s, unsigned len)
410{
411 int i;
412 struct logdir *ld = &dir[n];
413
414 if (ld->sizemax) {
415 if (ld->size >= ld->sizemax)
416 rotate(ld);
417 if (len > (ld->sizemax - ld->size))
418 len = ld->sizemax - ld->size;
419 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000420 while (1) {
421 ////i = full_write(ld->fdcur, s, len);
422 ////if (i != -1) break;
423 i = fwrite(s, 1, len, ld->filecur);
424 if (i == len) break;
425
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000426 if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
427 DIR *d;
428 struct dirent *f;
429 char oldest[FMT_PTIME];
430 int j = 0;
431
432 while (fchdir(ld->fddir) == -1)
433 pause2cannot("change directory, want remove old logfile",
434 ld->name);
435 oldest[0] = 'A';
436 oldest[1] = oldest[27] = '\0';
437 while (!(d = opendir(".")))
438 pause2cannot("open directory, want remove old logfile",
439 ld->name);
440 errno = 0;
441 while ((f = readdir(d)))
442 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
443 ++j;
444 if (strcmp(f->d_name, oldest) < 0)
445 memcpy(oldest, f->d_name, 27);
446 }
447 if (errno) warn2("cannot read directory, want remove old logfile",
448 ld->name);
449 closedir(d);
450 errno = ENOSPC;
451 if (j > ld->nmin) {
452 if (*oldest == '@') {
453 bb_error_msg(WARNING"out of disk space, delete: %s/%s",
454 ld->name, oldest);
455 errno = 0;
456 if (unlink(oldest) == -1) {
457 warn2("cannot unlink oldest logfile", ld->name);
458 errno = ENOSPC;
459 }
460 while (fchdir(fdwdir) == -1)
461 pause1cannot("change to initial working directory");
462 }
463 }
464 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000465 if (errno)
466 pause2cannot("write to current", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000467 }
468
469 ld->size += i;
470 if (ld->sizemax)
471 if (s[i-1] == '\n')
472 if (ld->size >= (ld->sizemax - linemax))
473 rotate(ld);
474 return i;
475}
476
477static void logdir_close(struct logdir *ld)
478{
479 if (ld->fddir == -1)
480 return;
481 if (verbose)
482 bb_error_msg(INFO"close: %s", ld->name);
483 close(ld->fddir);
484 ld->fddir = -1;
485 if (ld->fdcur == -1)
486 return; /* impossible */
Denis Vlasenko64392902007-02-03 00:53:43 +0000487 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000488 pause2cannot("fsync current logfile", ld->name);
489 while (fchmod(ld->fdcur, 0744) == -1)
490 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000491 ////close(ld->fdcur);
492 fclose(ld->filecur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000493 ld->fdcur = -1;
494 if (ld->fdlock == -1)
495 return; /* impossible */
496 close(ld->fdlock);
497 ld->fdlock = -1;
498 free(ld->processor);
499 ld->processor = NULL;
500}
501
502static unsigned logdir_open(struct logdir *ld, const char *fn)
503{
504 char buf[128];
Denis Vlasenko45946f82007-08-20 17:27:40 +0000505 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000506 char *new, *s, *np;
507 int i;
508 struct stat st;
509
Denis Vlasenko45946f82007-08-20 17:27:40 +0000510 now = monotonic_sec();
511
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000512 ld->fddir = open(fn, O_RDONLY|O_NDELAY);
513 if (ld->fddir == -1) {
514 warn2("cannot open log directory", (char*)fn);
515 return 0;
516 }
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000517 close_on_exec_on(ld->fddir);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000518 if (fchdir(ld->fddir) == -1) {
519 logdir_close(ld);
520 warn2("cannot change directory", (char*)fn);
521 return 0;
522 }
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)
526 ) {
527 logdir_close(ld);
528 warn2("cannot lock directory", (char*)fn);
529 while (fchdir(fdwdir) == -1)
530 pause1cannot("change to initial working directory");
531 return 0;
532 }
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000533 close_on_exec_on(ld->fdlock);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000534
535 ld->size = 0;
536 ld->sizemax = 1000000;
537 ld->nmax = ld->nmin = 10;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000538 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000539 ld->name = (char*)fn;
540 ld->ppid = 0;
541 ld->match = '+';
542 free(ld->inst); ld->inst = NULL;
543 free(ld->processor); ld->processor = NULL;
544
545 /* read config */
546 i = open_read_close("config", buf, sizeof(buf));
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000547 if (i < 0 && errno != ENOENT)
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000548 bb_perror_msg(WARNING"%s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000549 if (i > 0) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000550 if (verbose)
551 bb_error_msg(INFO"read: %s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000552 s = buf;
553 while (s) {
554 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000555 if (np)
556 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000557 switch (s[0]) {
558 case '+':
559 case '-':
560 case 'e':
561 case 'E':
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000562 /* Add '\n'-terminated line to ld->inst */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000563 while (1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000564 int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);
565 if (l >= 0 && new)
566 break;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000567 pause_nomem();
568 }
569 free(ld->inst);
570 ld->inst = new;
571 break;
572 case 's': {
573 static const struct suffix_mult km_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000574 { "k", 1024 },
575 { "m", 1024*1024 },
576 { }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000577 };
578 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
579 break;
580 }
581 case 'n':
582 ld->nmax = xatoi_u(&s[1]);
583 break;
584 case 'N':
585 ld->nmin = xatoi_u(&s[1]);
586 break;
587 case 't': {
588 static const struct suffix_mult mh_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000589 { "m", 60 },
590 { "h", 60*60 },
591 /*{ "d", 24*60*60 },*/
592 { }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000593 };
Denis Vlasenko45946f82007-08-20 17:27:40 +0000594 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;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000599 tmaxflag = 1;
600 }
601 break;
602 }
603 case '!':
604 if (s[1]) {
605 free(ld->processor);
606 ld->processor = wstrdup(s);
607 }
608 break;
609 }
610 s = np;
611 }
612 /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
613 s = ld->inst;
614 while (s) {
615 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000616 if (np)
617 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000618 s = np;
619 }
620 }
621
622 /* open current */
623 i = stat("current", &st);
624 if (i != -1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000625 if (st.st_size && !(st.st_mode & S_IXUSR)) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000626 ld->fnsave[25] = '.';
627 ld->fnsave[26] = 'u';
628 ld->fnsave[27] = '\0';
629 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000630 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000631 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000632 stat(ld->fnsave, &st);
633 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000634 while (rename("current", ld->fnsave) == -1)
635 pause2cannot("rename current", ld->name);
636 rmoldest(ld);
637 i = -1;
638 } else {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000639 /* 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") */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000642 ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
643 }
644 } else {
645 if (errno != ENOENT) {
646 logdir_close(ld);
647 warn2("cannot stat current", ld->name);
648 while (fchdir(fdwdir) == -1)
649 pause1cannot("change to initial working directory");
650 return 0;
651 }
652 }
653 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
654 pause2cannot("open current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000655 /* we presume this cannot fail */
656 ld->filecur = fdopen(ld->fdcur, "a"); ////
657 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
658
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000659 close_on_exec_on(ld->fdcur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000660 while (fchmod(ld->fdcur, 0644) == -1)
661 pause2cannot("set mode of current", ld->name);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000662
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000663 if (verbose) {
664 if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
665 else bb_error_msg(INFO"new: %s/current", ld->name);
666 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000667
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000668 while (fchdir(fdwdir) == -1)
669 pause1cannot("change to initial working directory");
670 return 1;
671}
672
673static void logdirs_reopen(void)
674{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000675 int l;
676 int ok = 0;
677
678 tmaxflag = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000679 for (l = 0; l < dirn; ++l) {
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000680 logdir_close(&dir[l]);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000681 if (logdir_open(&dir[l], fndir[l]))
682 ok = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000683 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000684 if (!ok)
685 fatalx("no functional log directories");
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000686}
687
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000688/* Will look good in libbb one day */
689static ssize_t ndelay_read(int fd, void *buf, size_t count)
690{
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);
696 return count;
697}
698
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000699/* Used for reading stdin */
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000700static int buffer_pread(/*int fd, */char *s, unsigned len)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000701{
Denis Vlasenko45946f82007-08-20 17:27:40 +0000702 unsigned now;
703 struct pollfd input;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000704 int i;
705
Denis Vlasenko45946f82007-08-20 17:27:40 +0000706 input.fd = 0;
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000707 input.events = POLLIN;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000708
Denis Vlasenkob9528352007-05-06 01:37:21 +0000709 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000710 if (rotateasap) {
711 for (i = 0; i < dirn; ++i)
712 rotate(dir + i);
713 rotateasap = 0;
714 }
715 if (exitasap) {
716 if (linecomplete)
717 return 0;
718 len = 1;
719 }
720 if (reopenasap) {
721 logdirs_reopen();
722 reopenasap = 0;
723 }
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))
729 rotate(dir + i);
730 if (LESS(dir[i].next_rotate, nearest_rotate))
731 nearest_rotate = dir[i].next_rotate;
732 }
733 }
734
Denis Vlasenko339936b2007-10-05 22:11:06 +0000735 sigprocmask(SIG_UNBLOCK, &blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000736 i = nearest_rotate - now;
737 if (i > 1000000)
738 i = 1000000;
739 if (i <= 0)
740 i = 1;
741 poll(&input, 1, i * 1000);
Denis Vlasenko339936b2007-10-05 22:11:06 +0000742 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000743
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000744 i = ndelay_read(0, s, len);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000745 if (i >= 0)
746 break;
747 if (errno == EINTR)
748 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000749 if (errno != EAGAIN) {
750 warn("cannot read standard input");
751 break;
752 }
753 /* else: EAGAIN - normal, repeat silently */
Denis Vlasenkob9528352007-05-06 01:37:21 +0000754 } while (!exitasap);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000755
756 if (i > 0) {
757 int cnt;
758 linecomplete = (s[i-1] == '\n');
Denis Vlasenko45946f82007-08-20 17:27:40 +0000759 if (!repl)
760 return i;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000761
762 cnt = i;
763 while (--cnt >= 0) {
764 char ch = *s;
765 if (ch != '\n') {
766 if (ch < 32 || ch > 126)
767 *s = repl;
768 else {
769 int j;
770 for (j = 0; replace[j]; ++j) {
771 if (ch == replace[j]) {
772 *s = repl;
773 break;
774 }
775 }
776 }
777 }
778 s++;
779 }
780 }
781 return i;
782}
783
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000784static void sig_term_handler(int sig_no)
785{
786 if (verbose)
787 bb_error_msg(INFO"sig%s received", "term");
788 exitasap = 1;
789}
790
791static void sig_child_handler(int sig_no)
792{
793 int pid, l;
794
795 if (verbose)
796 bb_error_msg(INFO"sig%s received", "child");
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000797 while ((pid = wait_any_nohang(&wstat)) > 0) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000798 for (l = 0; l < dirn; ++l) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000799 if (dir[l].ppid == pid) {
800 dir[l].ppid = 0;
801 processorstop(&dir[l]);
802 break;
803 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000804 }
805 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000806}
807
808static void sig_alarm_handler(int sig_no)
809{
810 if (verbose)
811 bb_error_msg(INFO"sig%s received", "alarm");
812 rotateasap = 1;
813}
814
815static void sig_hangup_handler(int sig_no)
816{
817 if (verbose)
818 bb_error_msg(INFO"sig%s received", "hangup");
819 reopenasap = 1;
820}
821
822static void logmatch(struct logdir *ld)
823{
824 char *s;
825
826 ld->match = '+';
827 ld->matcherr = 'E';
828 s = ld->inst;
829 while (s && s[0]) {
830 switch (s[0]) {
831 case '+':
832 case '-':
833 if (pmatch(s+1, line, linelen))
834 ld->match = s[0];
835 break;
836 case 'e':
837 case 'E':
838 if (pmatch(s+1, line, linelen))
839 ld->matcherr = s[0];
840 break;
841 }
842 s += strlen(s) + 1;
843 }
844}
845
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000846int svlogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000847int svlogd_main(int argc, char **argv)
848{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000849 char *r,*l,*b;
850 ssize_t stdin_cnt = 0;
851 int i;
852 unsigned opt;
853 unsigned timestamp = 0;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000854 void* (*memRchr)(const void *, int, size_t) = memchr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000855
Denis Vlasenko339936b2007-10-05 22:11:06 +0000856 INIT_G();
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000857
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000858 opt_complementary = "tt:vv";
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000859 opt = getopt32(argv, "r:R:l:b:tv",
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000860 &r, &replace, &l, &b, &timestamp, &verbose);
861 if (opt & 1) { // -r
862 repl = r[0];
863 if (!repl || r[1]) usage();
864 }
865 if (opt & 2) if (!repl) repl = '_'; // -R
866 if (opt & 4) { // -l
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000867 linemax = xatou_range(l, 0, BUFSIZ-26);
868 if (linemax == 0) linemax = BUFSIZ-26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000869 if (linemax < 256) linemax = 256;
870 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000871 ////if (opt & 8) { // -b
872 //// buflen = xatoi_u(b);
873 //// if (buflen == 0) buflen = 1024;
874 ////}
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000875 //if (opt & 0x10) timestamp++; // -t
876 //if (opt & 0x20) verbose++; // -v
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000877 //if (timestamp > 2) timestamp = 2;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000878 argv += optind;
879 argc -= optind;
880
881 dirn = argc;
882 if (dirn <= 0) usage();
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000883 ////if (buflen <= linemax) usage();
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000884 fdwdir = xopen(".", O_RDONLY|O_NDELAY);
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000885 close_on_exec_on(fdwdir);
Denis Vlasenkob9528352007-05-06 01:37:21 +0000886 dir = xzalloc(dirn * sizeof(struct logdir));
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000887 for (i = 0; i < dirn; ++i) {
888 dir[i].fddir = -1;
889 dir[i].fdcur = -1;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000890 ////dir[i].btmp = xmalloc(buflen);
Denis Vlasenkob9528352007-05-06 01:37:21 +0000891 /*dir[i].ppid = 0;*/
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000892 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000893 /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000894 fndir = argv;
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000895 /* 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 */
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000898 fl_flag_0 = fcntl(0, F_GETFL);
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000899
Denis Vlasenko339936b2007-10-05 22:11:06 +0000900 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);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000906 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);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000910
911 logdirs_reopen();
912
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000913 /* 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 */
916 if (!timestamp)
917 memRchr = memrchr;
918
Denis Vlasenko64392902007-02-03 00:53:43 +0000919 setvbuf(stderr, NULL, _IOFBF, linelen);
920
Denis Vlasenko4e1715f2007-01-28 14:51:32 +0000921 /* Each iteration processes one or more lines */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000922 while (1) {
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000923 char stamp[FMT_PTIME];
924 char *lineptr;
925 char *printptr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000926 char *np;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000927 int printlen;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000928 char ch;
929
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000930 lineptr = line;
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000931 if (timestamp)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000932 lineptr += 26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000933
934 /* lineptr[0..linemax-1] - buffer for stdin */
935 /* (possibly has some unprocessed data from prev loop) */
936
937 /* Refill the buffer if needed */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000938 np = memRchr(lineptr, '\n', stdin_cnt);
939 if (!np && !exitasap) {
940 i = linemax - stdin_cnt; /* avail. bytes at tail */
941 if (i >= 128) {
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000942 i = buffer_pread(/*0, */lineptr + stdin_cnt, i);
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000943 if (i <= 0) /* EOF or error on stdin */
944 exitasap = 1;
945 else {
946 np = memRchr(lineptr + stdin_cnt, '\n', i);
947 stdin_cnt += i;
948 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000949 }
950 }
951 if (stdin_cnt <= 0 && exitasap)
952 break;
953
954 /* Search for '\n' (in fact, np already holds the result) */
955 linelen = stdin_cnt;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000956 if (np) {
957 print_to_nl: /* NB: starting from here lineptr may point
958 * farther out into line[] */
959 linelen = np - lineptr + 1;
960 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000961 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
962 ch = lineptr[linelen-1];
963
Denis Vlasenko64392902007-02-03 00:53:43 +0000964 /* 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 */
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000968
969 /* write out lineptr[0..linelen-1] to each log destination
970 * (or lineptr[-26..linelen-1] if timestamping) */
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000971 printlen = linelen;
972 printptr = lineptr;
973 if (timestamp) {
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000974 if (timestamp == 1)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000975 fmt_time_bernstein_25(stamp);
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000976 else /* 2: */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000977 fmt_time_human_30nul(stamp);
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000978 printlen += 26;
979 printptr -= 26;
980 memcpy(printptr, stamp, 25);
981 printptr[25] = ' ';
982 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000983 for (i = 0; i < dirn; ++i) {
984 struct logdir *ld = &dir[i];
985 if (ld->fddir == -1) continue;
986 if (ld->inst)
987 logmatch(ld);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +0000988 if (ld->matcherr == 'e') {
989 /* runit-1.8.0 compat: if timestamping, do it on stderr too */
Denis Vlasenko64392902007-02-03 00:53:43 +0000990 ////full_write(2, printptr, printlen);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +0000991 fwrite(printptr, 1, printlen, stderr);
992 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000993 if (ld->match != '+') continue;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000994 buffer_pwrite(i, printptr, printlen);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000995 }
996
997 /* If we didn't see '\n' (long input line), */
998 /* read/write repeatedly until we see it */
999 while (ch != '\n') {
1000 /* lineptr is emptied now, safe to use as buffer */
Denis Vlasenko5d61e712007-09-27 10:09:59 +00001001 stdin_cnt = exitasap ? -1 : buffer_pread(/*0, */lineptr, linemax);
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001002 if (stdin_cnt <= 0) { /* EOF or error on stdin */
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001003 exitasap = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001004 lineptr[0] = ch = '\n';
1005 linelen = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001006 stdin_cnt = 1;
1007 } else {
1008 linelen = stdin_cnt;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001009 np = memRchr(lineptr, '\n', stdin_cnt);
1010 if (np)
1011 linelen = np - lineptr + 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001012 ch = lineptr[linelen-1];
1013 }
1014 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
1015 for (i = 0; i < dirn; ++i) {
1016 if (dir[i].fddir == -1) continue;
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001017 if (dir[i].matcherr == 'e') {
Denis Vlasenko64392902007-02-03 00:53:43 +00001018 ////full_write(2, lineptr, linelen);
1019 fwrite(lineptr, 1, linelen, stderr);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001020 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001021 if (dir[i].match != '+') continue;
1022 buffer_pwrite(i, lineptr, linelen);
1023 }
1024 }
1025
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001026 stdin_cnt -= linelen;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001027 if (stdin_cnt > 0) {
1028 lineptr += linelen;
1029 /* If we see another '\n', we don't need to read
1030 * next piece of input: can print what we have */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001031 np = memRchr(lineptr, '\n', stdin_cnt);
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001032 if (np)
1033 goto print_to_nl;
1034 /* Move unprocessed data to the front of line */
1035 memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1036 }
Denis Vlasenko64392902007-02-03 00:53:43 +00001037 fflush(NULL);////
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001038 }
1039
1040 for (i = 0; i < dirn; ++i) {
1041 if (dir[i].ppid)
1042 while (!processorstop(&dir[i]))
1043 /* repeat */;
1044 logdir_close(&dir[i]);
1045 }
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001046 return 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001047}