blob: 4458bd787235f41aebbd2edd0e95e590ef519b1e [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
Denis Vlasenkod18f52b2008-03-02 12:53:15 +000028/* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
Denis Vlasenko83ea6432006-11-16 02:27:24 +000029/* 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 { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000109 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenko339936b2007-10-05 22:11:06 +0000110 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 Vlasenko25591c32008-02-16 22:58:56 +0000225 bb_signals(0
226 + (1 << SIGTERM)
227 + (1 << SIGALRM)
228 + (1 << SIGHUP)
229 , SIG_DFL);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000230 sig_unblock(SIGTERM);
231 sig_unblock(SIGALRM);
232 sig_unblock(SIGHUP);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000233
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000234 if (verbose)
235 bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
236 fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000237 xmove_fd(fd, 0);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000238 ld->fnsave[26] = 't';
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000239 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000240 xmove_fd(fd, 1);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000241 fd = open_read("state");
242 if (fd == -1) {
243 if (errno != ENOENT)
244 bb_perror_msg_and_die(FATAL"cannot %s processor %s", "open state for", ld->name);
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000245 close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000246 fd = xopen("state", O_RDONLY|O_NDELAY);
247 }
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000248 xmove_fd(fd, 4);
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000249 fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000250 xmove_fd(fd, 5);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000251
Denis Vlasenko8c783952007-01-27 22:21:52 +0000252// getenv("SHELL")?
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000253 prog[0] = (char*)"sh";
254 prog[1] = (char*)"-c";
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000255 prog[2] = ld->processor;
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000256 prog[3] = NULL;
Denis Vlasenko847fa772008-01-28 22:45:43 +0000257 execv("/bin/sh", prog);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000258 bb_perror_msg_and_die(FATAL"cannot %s processor %s", "run", ld->name);
259 }
260 ld->ppid = pid;
261 return 1;
262}
263
264static unsigned processorstop(struct logdir *ld)
265{
266 char f[28];
267
268 if (ld->ppid) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000269 sig_unblock(SIGHUP);
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000270 while (safe_waitpid(ld->ppid, &wstat, 0) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000271 pause2cannot("wait for processor", ld->name);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000272 sig_block(SIGHUP);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000273 ld->ppid = 0;
274 }
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';
281 unlink(ld->fnsave);
282 ld->fnsave[26] = 'u';
283 processorstart(ld);
284 while (fchdir(fdwdir) == -1)
285 pause1cannot("change to initial working directory");
286 return ld->processor ? 0 : 1;
287 }
288 ld->fnsave[26] = 't';
289 memcpy(f, ld->fnsave, 26);
290 f[26] = 's';
291 f[27] = '\0';
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);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000301 if (verbose)
302 bb_error_msg(INFO"processed: %s/%s", ld->name, f);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000303 while (fchdir(fdwdir) == -1)
304 pause1cannot("change to initial working directory");
305 return 1;
306}
307
308static void rmoldest(struct logdir *ld)
309{
310 DIR *d;
311 struct dirent *f;
312 char oldest[FMT_PTIME];
313 int n = 0;
314
315 oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
316 while (!(d = opendir(".")))
317 pause2cannot("open directory, want rotate", ld->name);
318 errno = 0;
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);
324 } else {
325 ++n;
326 if (strcmp(f->d_name, oldest) < 0)
327 memcpy(oldest, f->d_name, 27);
328 }
329 errno = 0;
330 }
331 }
Denis Vlasenko8c783952007-01-27 22:21:52 +0000332 if (errno)
333 warn2("cannot read directory", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000334 closedir(d);
335
336 if (ld->nmax && (n > ld->nmax)) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000337 if (verbose)
338 bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000339 if ((*oldest == '@') && (unlink(oldest) == -1))
340 warn2("cannot unlink oldest logfile", ld->name);
341 }
342}
343
344static unsigned rotate(struct logdir *ld)
345{
346 struct stat st;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000347 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000348
349 if (ld->fddir == -1) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000350 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000351 return 0;
352 }
353 if (ld->ppid)
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000354 while (!processorstop(ld))
Denis Vlasenko45946f82007-08-20 17:27:40 +0000355 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000356
357 while (fchdir(ld->fddir) == -1)
358 pause2cannot("change directory, want rotate", ld->name);
359
360 /* create new filename */
361 ld->fnsave[25] = '.';
362 ld->fnsave[26] = 's';
363 if (ld->processor)
364 ld->fnsave[26] = 'u';
365 ld->fnsave[27] = '\0';
366 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000367 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000368 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000369 stat(ld->fnsave, &st);
370 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000371
Denis Vlasenko45946f82007-08-20 17:27:40 +0000372 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;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000377 }
378
379 if (ld->size > 0) {
Denis Vlasenko64392902007-02-03 00:53:43 +0000380 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000381 pause2cannot("fsync current logfile", ld->name);
382 while (fchmod(ld->fdcur, 0744) == -1)
383 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000384 ////close(ld->fdcur);
385 fclose(ld->filecur);
386
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000387 if (verbose) {
388 bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
389 ld->fnsave, ld->size);
390 }
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);
Denis Vlasenko64392902007-02-03 00:53:43 +0000395 /* we presume this cannot fail */
396 ld->filecur = fdopen(ld->fdcur, "a"); ////
397 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000398 close_on_exec_on(ld->fdcur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000399 ld->size = 0;
400 while (fchmod(ld->fdcur, 0644) == -1)
401 pause2cannot("set mode of current", ld->name);
402 rmoldest(ld);
403 processorstart(ld);
404 }
405
406 while (fchdir(fdwdir) == -1)
407 pause1cannot("change to initial working directory");
408 return 1;
409}
410
411static int buffer_pwrite(int n, char *s, unsigned len)
412{
413 int i;
414 struct logdir *ld = &dir[n];
415
416 if (ld->sizemax) {
417 if (ld->size >= ld->sizemax)
418 rotate(ld);
419 if (len > (ld->sizemax - ld->size))
420 len = ld->sizemax - ld->size;
421 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000422 while (1) {
423 ////i = full_write(ld->fdcur, s, len);
424 ////if (i != -1) break;
425 i = fwrite(s, 1, len, ld->filecur);
426 if (i == len) break;
427
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000428 if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
429 DIR *d;
430 struct dirent *f;
431 char oldest[FMT_PTIME];
432 int j = 0;
433
434 while (fchdir(ld->fddir) == -1)
435 pause2cannot("change directory, want remove old logfile",
436 ld->name);
437 oldest[0] = 'A';
438 oldest[1] = oldest[27] = '\0';
439 while (!(d = opendir(".")))
440 pause2cannot("open directory, want remove old logfile",
441 ld->name);
442 errno = 0;
443 while ((f = readdir(d)))
444 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
445 ++j;
446 if (strcmp(f->d_name, oldest) < 0)
447 memcpy(oldest, f->d_name, 27);
448 }
449 if (errno) warn2("cannot read directory, want remove old logfile",
450 ld->name);
451 closedir(d);
452 errno = ENOSPC;
453 if (j > ld->nmin) {
454 if (*oldest == '@') {
455 bb_error_msg(WARNING"out of disk space, delete: %s/%s",
456 ld->name, oldest);
457 errno = 0;
458 if (unlink(oldest) == -1) {
459 warn2("cannot unlink oldest logfile", ld->name);
460 errno = ENOSPC;
461 }
462 while (fchdir(fdwdir) == -1)
463 pause1cannot("change to initial working directory");
464 }
465 }
466 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000467 if (errno)
468 pause2cannot("write to current", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000469 }
470
471 ld->size += i;
472 if (ld->sizemax)
473 if (s[i-1] == '\n')
474 if (ld->size >= (ld->sizemax - linemax))
475 rotate(ld);
476 return i;
477}
478
479static void logdir_close(struct logdir *ld)
480{
481 if (ld->fddir == -1)
482 return;
483 if (verbose)
484 bb_error_msg(INFO"close: %s", ld->name);
485 close(ld->fddir);
486 ld->fddir = -1;
487 if (ld->fdcur == -1)
488 return; /* impossible */
Denis Vlasenko64392902007-02-03 00:53:43 +0000489 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000490 pause2cannot("fsync current logfile", ld->name);
491 while (fchmod(ld->fdcur, 0744) == -1)
492 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000493 ////close(ld->fdcur);
494 fclose(ld->filecur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000495 ld->fdcur = -1;
496 if (ld->fdlock == -1)
497 return; /* impossible */
498 close(ld->fdlock);
499 ld->fdlock = -1;
500 free(ld->processor);
501 ld->processor = NULL;
502}
503
504static unsigned logdir_open(struct logdir *ld, const char *fn)
505{
506 char buf[128];
Denis Vlasenko45946f82007-08-20 17:27:40 +0000507 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000508 char *new, *s, *np;
509 int i;
510 struct stat st;
511
Denis Vlasenko45946f82007-08-20 17:27:40 +0000512 now = monotonic_sec();
513
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000514 ld->fddir = open(fn, O_RDONLY|O_NDELAY);
515 if (ld->fddir == -1) {
516 warn2("cannot open log directory", (char*)fn);
517 return 0;
518 }
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000519 close_on_exec_on(ld->fddir);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000520 if (fchdir(ld->fddir) == -1) {
521 logdir_close(ld);
522 warn2("cannot change directory", (char*)fn);
523 return 0;
524 }
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)
528 ) {
529 logdir_close(ld);
530 warn2("cannot lock directory", (char*)fn);
531 while (fchdir(fdwdir) == -1)
532 pause1cannot("change to initial working directory");
533 return 0;
534 }
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000535 close_on_exec_on(ld->fdlock);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000536
537 ld->size = 0;
538 ld->sizemax = 1000000;
539 ld->nmax = ld->nmin = 10;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000540 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000541 ld->name = (char*)fn;
542 ld->ppid = 0;
543 ld->match = '+';
544 free(ld->inst); ld->inst = NULL;
545 free(ld->processor); ld->processor = NULL;
546
547 /* read config */
548 i = open_read_close("config", buf, sizeof(buf));
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000549 if (i < 0 && errno != ENOENT)
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000550 bb_perror_msg(WARNING"%s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000551 if (i > 0) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000552 if (verbose)
553 bb_error_msg(INFO"read: %s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000554 s = buf;
555 while (s) {
556 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000557 if (np)
558 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000559 switch (s[0]) {
560 case '+':
561 case '-':
562 case 'e':
563 case 'E':
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000564 /* Add '\n'-terminated line to ld->inst */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000565 while (1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000566 int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);
567 if (l >= 0 && new)
568 break;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000569 pause_nomem();
570 }
571 free(ld->inst);
572 ld->inst = new;
573 break;
574 case 's': {
575 static const struct suffix_mult km_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000576 { "k", 1024 },
577 { "m", 1024*1024 },
578 { }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000579 };
580 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
581 break;
582 }
583 case 'n':
584 ld->nmax = xatoi_u(&s[1]);
585 break;
586 case 'N':
587 ld->nmin = xatoi_u(&s[1]);
588 break;
589 case 't': {
590 static const struct suffix_mult mh_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000591 { "m", 60 },
592 { "h", 60*60 },
593 /*{ "d", 24*60*60 },*/
594 { }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000595 };
Denis Vlasenko45946f82007-08-20 17:27:40 +0000596 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;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000601 tmaxflag = 1;
602 }
603 break;
604 }
605 case '!':
606 if (s[1]) {
607 free(ld->processor);
608 ld->processor = wstrdup(s);
609 }
610 break;
611 }
612 s = np;
613 }
614 /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
615 s = ld->inst;
616 while (s) {
617 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000618 if (np)
619 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000620 s = np;
621 }
622 }
623
624 /* open current */
625 i = stat("current", &st);
626 if (i != -1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000627 if (st.st_size && !(st.st_mode & S_IXUSR)) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000628 ld->fnsave[25] = '.';
629 ld->fnsave[26] = 'u';
630 ld->fnsave[27] = '\0';
631 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000632 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000633 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000634 stat(ld->fnsave, &st);
635 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000636 while (rename("current", ld->fnsave) == -1)
637 pause2cannot("rename current", ld->name);
638 rmoldest(ld);
639 i = -1;
640 } else {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000641 /* 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") */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000644 ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
645 }
646 } else {
647 if (errno != ENOENT) {
648 logdir_close(ld);
649 warn2("cannot stat current", ld->name);
650 while (fchdir(fdwdir) == -1)
651 pause1cannot("change to initial working directory");
652 return 0;
653 }
654 }
655 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
656 pause2cannot("open current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000657 /* we presume this cannot fail */
658 ld->filecur = fdopen(ld->fdcur, "a"); ////
659 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
660
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000661 close_on_exec_on(ld->fdcur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000662 while (fchmod(ld->fdcur, 0644) == -1)
663 pause2cannot("set mode of current", ld->name);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000664
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000665 if (verbose) {
666 if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
667 else bb_error_msg(INFO"new: %s/current", ld->name);
668 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000669
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000670 while (fchdir(fdwdir) == -1)
671 pause1cannot("change to initial working directory");
672 return 1;
673}
674
675static void logdirs_reopen(void)
676{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000677 int l;
678 int ok = 0;
679
680 tmaxflag = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000681 for (l = 0; l < dirn; ++l) {
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000682 logdir_close(&dir[l]);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000683 if (logdir_open(&dir[l], fndir[l]))
684 ok = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000685 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000686 if (!ok)
687 fatalx("no functional log directories");
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000688}
689
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000690/* Will look good in libbb one day */
691static ssize_t ndelay_read(int fd, void *buf, size_t count)
692{
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);
698 return count;
699}
700
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000701/* Used for reading stdin */
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000702static int buffer_pread(/*int fd, */char *s, unsigned len)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000703{
Denis Vlasenko45946f82007-08-20 17:27:40 +0000704 unsigned now;
705 struct pollfd input;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000706 int i;
707
Denis Vlasenko45946f82007-08-20 17:27:40 +0000708 input.fd = 0;
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000709 input.events = POLLIN;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000710
Denis Vlasenkob9528352007-05-06 01:37:21 +0000711 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000712 if (rotateasap) {
713 for (i = 0; i < dirn; ++i)
714 rotate(dir + i);
715 rotateasap = 0;
716 }
717 if (exitasap) {
718 if (linecomplete)
719 return 0;
720 len = 1;
721 }
722 if (reopenasap) {
723 logdirs_reopen();
724 reopenasap = 0;
725 }
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))
731 rotate(dir + i);
732 if (LESS(dir[i].next_rotate, nearest_rotate))
733 nearest_rotate = dir[i].next_rotate;
734 }
735 }
736
Denis Vlasenko339936b2007-10-05 22:11:06 +0000737 sigprocmask(SIG_UNBLOCK, &blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000738 i = nearest_rotate - now;
739 if (i > 1000000)
740 i = 1000000;
741 if (i <= 0)
742 i = 1;
743 poll(&input, 1, i * 1000);
Denis Vlasenko339936b2007-10-05 22:11:06 +0000744 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000745
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000746 i = ndelay_read(0, s, len);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000747 if (i >= 0)
748 break;
749 if (errno == EINTR)
750 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000751 if (errno != EAGAIN) {
752 warn("cannot read standard input");
753 break;
754 }
755 /* else: EAGAIN - normal, repeat silently */
Denis Vlasenkob9528352007-05-06 01:37:21 +0000756 } while (!exitasap);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000757
758 if (i > 0) {
759 int cnt;
760 linecomplete = (s[i-1] == '\n');
Denis Vlasenko45946f82007-08-20 17:27:40 +0000761 if (!repl)
762 return i;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000763
764 cnt = i;
765 while (--cnt >= 0) {
766 char ch = *s;
767 if (ch != '\n') {
768 if (ch < 32 || ch > 126)
769 *s = repl;
770 else {
771 int j;
772 for (j = 0; replace[j]; ++j) {
773 if (ch == replace[j]) {
774 *s = repl;
775 break;
776 }
777 }
778 }
779 }
780 s++;
781 }
782 }
783 return i;
784}
785
Denis Vlasenko68404f12008-03-17 09:00:54 +0000786static void sig_term_handler(int sig_no ATTRIBUTE_UNUSED)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000787{
788 if (verbose)
789 bb_error_msg(INFO"sig%s received", "term");
790 exitasap = 1;
791}
792
Denis Vlasenko68404f12008-03-17 09:00:54 +0000793static void sig_child_handler(int sig_no ATTRIBUTE_UNUSED)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000794{
795 int pid, l;
796
797 if (verbose)
798 bb_error_msg(INFO"sig%s received", "child");
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000799 while ((pid = wait_any_nohang(&wstat)) > 0) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000800 for (l = 0; l < dirn; ++l) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000801 if (dir[l].ppid == pid) {
802 dir[l].ppid = 0;
803 processorstop(&dir[l]);
804 break;
805 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000806 }
807 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000808}
809
Denis Vlasenko68404f12008-03-17 09:00:54 +0000810static void sig_alarm_handler(int sig_no ATTRIBUTE_UNUSED)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000811{
812 if (verbose)
813 bb_error_msg(INFO"sig%s received", "alarm");
814 rotateasap = 1;
815}
816
Denis Vlasenko68404f12008-03-17 09:00:54 +0000817static void sig_hangup_handler(int sig_no ATTRIBUTE_UNUSED)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000818{
819 if (verbose)
820 bb_error_msg(INFO"sig%s received", "hangup");
821 reopenasap = 1;
822}
823
824static void logmatch(struct logdir *ld)
825{
826 char *s;
827
828 ld->match = '+';
829 ld->matcherr = 'E';
830 s = ld->inst;
831 while (s && s[0]) {
832 switch (s[0]) {
833 case '+':
834 case '-':
835 if (pmatch(s+1, line, linelen))
836 ld->match = s[0];
837 break;
838 case 'e':
839 case 'E':
840 if (pmatch(s+1, line, linelen))
841 ld->matcherr = s[0];
842 break;
843 }
844 s += strlen(s) + 1;
845 }
846}
847
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000848int svlogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000849int svlogd_main(int argc, char **argv)
850{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000851 char *r,*l,*b;
852 ssize_t stdin_cnt = 0;
853 int i;
854 unsigned opt;
855 unsigned timestamp = 0;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000856 void* (*memRchr)(const void *, int, size_t) = memchr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000857
Denis Vlasenko339936b2007-10-05 22:11:06 +0000858 INIT_G();
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000859
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000860 opt_complementary = "tt:vv";
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000861 opt = getopt32(argv, "r:R:l:b:tv",
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000862 &r, &replace, &l, &b, &timestamp, &verbose);
863 if (opt & 1) { // -r
864 repl = r[0];
865 if (!repl || r[1]) usage();
866 }
867 if (opt & 2) if (!repl) repl = '_'; // -R
868 if (opt & 4) { // -l
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000869 linemax = xatou_range(l, 0, BUFSIZ-26);
870 if (linemax == 0) linemax = BUFSIZ-26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000871 if (linemax < 256) linemax = 256;
872 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000873 ////if (opt & 8) { // -b
874 //// buflen = xatoi_u(b);
875 //// if (buflen == 0) buflen = 1024;
876 ////}
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000877 //if (opt & 0x10) timestamp++; // -t
878 //if (opt & 0x20) verbose++; // -v
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000879 //if (timestamp > 2) timestamp = 2;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000880 argv += optind;
881 argc -= optind;
882
883 dirn = argc;
884 if (dirn <= 0) usage();
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000885 ////if (buflen <= linemax) usage();
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000886 fdwdir = xopen(".", O_RDONLY|O_NDELAY);
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000887 close_on_exec_on(fdwdir);
Denis Vlasenkob9528352007-05-06 01:37:21 +0000888 dir = xzalloc(dirn * sizeof(struct logdir));
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000889 for (i = 0; i < dirn; ++i) {
890 dir[i].fddir = -1;
891 dir[i].fdcur = -1;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000892 ////dir[i].btmp = xmalloc(buflen);
Denis Vlasenkob9528352007-05-06 01:37:21 +0000893 /*dir[i].ppid = 0;*/
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000894 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000895 /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000896 fndir = argv;
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000897 /* 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 */
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000900 fl_flag_0 = fcntl(0, F_GETFL);
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000901
Denis Vlasenko339936b2007-10-05 22:11:06 +0000902 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);
Denis Vlasenko25591c32008-02-16 22:58:56 +0000908 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);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000912
913 logdirs_reopen();
914
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000915 /* 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 */
918 if (!timestamp)
919 memRchr = memrchr;
920
Denis Vlasenko64392902007-02-03 00:53:43 +0000921 setvbuf(stderr, NULL, _IOFBF, linelen);
922
Denis Vlasenko4e1715f2007-01-28 14:51:32 +0000923 /* Each iteration processes one or more lines */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000924 while (1) {
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000925 char stamp[FMT_PTIME];
926 char *lineptr;
927 char *printptr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000928 char *np;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000929 int printlen;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000930 char ch;
931
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000932 lineptr = line;
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000933 if (timestamp)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000934 lineptr += 26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000935
936 /* lineptr[0..linemax-1] - buffer for stdin */
937 /* (possibly has some unprocessed data from prev loop) */
938
939 /* Refill the buffer if needed */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000940 np = memRchr(lineptr, '\n', stdin_cnt);
941 if (!np && !exitasap) {
942 i = linemax - stdin_cnt; /* avail. bytes at tail */
943 if (i >= 128) {
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000944 i = buffer_pread(/*0, */lineptr + stdin_cnt, i);
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000945 if (i <= 0) /* EOF or error on stdin */
946 exitasap = 1;
947 else {
948 np = memRchr(lineptr + stdin_cnt, '\n', i);
949 stdin_cnt += i;
950 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000951 }
952 }
953 if (stdin_cnt <= 0 && exitasap)
954 break;
955
956 /* Search for '\n' (in fact, np already holds the result) */
957 linelen = stdin_cnt;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000958 if (np) {
959 print_to_nl: /* NB: starting from here lineptr may point
960 * farther out into line[] */
961 linelen = np - lineptr + 1;
962 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000963 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
964 ch = lineptr[linelen-1];
965
Denis Vlasenko64392902007-02-03 00:53:43 +0000966 /* 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 */
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000970
971 /* write out lineptr[0..linelen-1] to each log destination
972 * (or lineptr[-26..linelen-1] if timestamping) */
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000973 printlen = linelen;
974 printptr = lineptr;
975 if (timestamp) {
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000976 if (timestamp == 1)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000977 fmt_time_bernstein_25(stamp);
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000978 else /* 2: */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000979 fmt_time_human_30nul(stamp);
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000980 printlen += 26;
981 printptr -= 26;
982 memcpy(printptr, stamp, 25);
983 printptr[25] = ' ';
984 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000985 for (i = 0; i < dirn; ++i) {
986 struct logdir *ld = &dir[i];
987 if (ld->fddir == -1) continue;
988 if (ld->inst)
989 logmatch(ld);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +0000990 if (ld->matcherr == 'e') {
991 /* runit-1.8.0 compat: if timestamping, do it on stderr too */
Denis Vlasenko64392902007-02-03 00:53:43 +0000992 ////full_write(2, printptr, printlen);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +0000993 fwrite(printptr, 1, printlen, stderr);
994 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000995 if (ld->match != '+') continue;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000996 buffer_pwrite(i, printptr, printlen);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000997 }
998
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 */
Denis Vlasenko5d61e712007-09-27 10:09:59 +00001003 stdin_cnt = exitasap ? -1 : buffer_pread(/*0, */lineptr, linemax);
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001004 if (stdin_cnt <= 0) { /* EOF or error on stdin */
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001005 exitasap = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001006 lineptr[0] = ch = '\n';
1007 linelen = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001008 stdin_cnt = 1;
1009 } else {
1010 linelen = stdin_cnt;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001011 np = memRchr(lineptr, '\n', stdin_cnt);
1012 if (np)
1013 linelen = np - lineptr + 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001014 ch = lineptr[linelen-1];
1015 }
1016 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
1017 for (i = 0; i < dirn; ++i) {
1018 if (dir[i].fddir == -1) continue;
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001019 if (dir[i].matcherr == 'e') {
Denis Vlasenko64392902007-02-03 00:53:43 +00001020 ////full_write(2, lineptr, linelen);
1021 fwrite(lineptr, 1, linelen, stderr);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001022 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001023 if (dir[i].match != '+') continue;
1024 buffer_pwrite(i, lineptr, linelen);
1025 }
1026 }
1027
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001028 stdin_cnt -= linelen;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001029 if (stdin_cnt > 0) {
1030 lineptr += linelen;
1031 /* If we see another '\n', we don't need to read
1032 * next piece of input: can print what we have */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001033 np = memRchr(lineptr, '\n', stdin_cnt);
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001034 if (np)
1035 goto print_to_nl;
1036 /* Move unprocessed data to the front of line */
1037 memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1038 }
Denis Vlasenko64392902007-02-03 00:53:43 +00001039 fflush(NULL);////
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001040 }
1041
1042 for (i = 0; i < dirn; ++i) {
1043 if (dir[i].ppid)
1044 while (!processorstop(&dir[i]))
1045 /* repeat */;
1046 logdir_close(&dir[i]);
1047 }
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001048 return 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001049}