source: MondoRescue/branches/stable/mindi-busybox/runit/svlogd.c@ 1770

Last change on this file since 1770 was 1765, checked in by Bruno Cornec, 16 years ago

Update to busybox 1.7.2

  • Property svn:eol-style set to native
File size: 24.1 KB
Line 
1/*
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>
33#include "libbb.h"
34#include "runit_lib.h"
35
36#define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0)
37
38#define FMT_PTIME 30
39
40static unsigned verbose;
41static int linemax = 1000;
42////static int buflen = 1024;
43static int linelen;
44
45static char **fndir;
46static int fdwdir;
47static int wstat;
48static unsigned nearest_rotate;
49
50static char *line;
51static smallint exitasap;
52static smallint rotateasap;
53static smallint reopenasap;
54static smallint linecomplete = 1;
55
56static smallint tmaxflag;
57
58static char repl;
59static const char *replace = "";
60
61static sigset_t *blocked_sigset;
62static int fl_flag_0;
63
64static struct logdir {
65 ////char *btmp;
66 /* pattern list to match, in "aa\0bb\0\cc\0\0" form */
67 char *inst;
68 char *processor;
69 char *name;
70 unsigned size;
71 unsigned sizemax;
72 unsigned nmax;
73 unsigned nmin;
74 unsigned rotate_period;
75 int ppid;
76 int fddir;
77 int fdcur;
78 FILE* filecur; ////
79 int fdlock;
80 unsigned next_rotate;
81 char fnsave[FMT_PTIME];
82 char match;
83 char matcherr;
84} *dir;
85static unsigned dirn;
86
87#define FATAL "fatal: "
88#define WARNING "warning: "
89#define PAUSE "pausing: "
90#define INFO "info: "
91
92#define usage() bb_show_usage()
93static void fatalx(const char *m0)
94{
95 bb_error_msg_and_die(FATAL"%s", m0);
96}
97static void warn(const char *m0)
98{
99 bb_perror_msg(WARNING"%s", m0);
100}
101static void warn2(const char *m0, const char *m1)
102{
103 bb_perror_msg(WARNING"%s: %s", m0, m1);
104}
105static void warnx(const char *m0, const char *m1)
106{
107 bb_error_msg(WARNING"%s: %s", m0, m1);
108}
109static void pause_nomem(void)
110{
111 bb_error_msg(PAUSE"out of memory");
112 sleep(3);
113}
114static void pause1cannot(const char *m0)
115{
116 bb_perror_msg(PAUSE"cannot %s", m0);
117 sleep(3);
118}
119static void pause2cannot(const char *m0, const char *m1)
120{
121 bb_perror_msg(PAUSE"cannot %s %s", m0, m1);
122 sleep(3);
123}
124
125static char* wstrdup(const char *str)
126{
127 char *s;
128 while (!(s = strdup(str)))
129 pause_nomem();
130 return s;
131}
132
133/*** ex fmt_ptime.[ch] ***/
134
135/* NUL terminated */
136static void fmt_time_human_30nul(char *s)
137{
138 struct tm *t;
139 struct timeval tv;
140
141 gettimeofday(&tv, NULL);
142 t = gmtime(&(tv.tv_sec));
143 sprintf(s, "%04u-%02u-%02u_%02u:%02u:%02u.%06u000",
144 (unsigned)(1900 + t->tm_year),
145 (unsigned)(t->tm_mon + 1),
146 (unsigned)(t->tm_mday),
147 (unsigned)(t->tm_hour),
148 (unsigned)(t->tm_min),
149 (unsigned)(t->tm_sec),
150 (unsigned)(tv.tv_usec)
151 );
152 /* 4+1 + 2+1 + 2+1 + 2+1 + 2+1 + 2+1 + 9 = */
153 /* 5 + 3 + 3 + 3 + 3 + 3 + 9 = */
154 /* 20 (up to '.' inclusive) + 9 (not including '\0') */
155}
156
157/* NOT terminated! */
158static void fmt_time_bernstein_25(char *s)
159{
160 uint32_t pack[3];
161 struct timeval tv;
162 unsigned sec_hi;
163
164 gettimeofday(&tv, NULL);
165 sec_hi = (0x400000000000000aULL + tv.tv_sec) >> 32;
166 tv.tv_sec = (time_t)(0x400000000000000aULL) + tv.tv_sec;
167 tv.tv_usec *= 1000;
168 /* Network order is big-endian: most significant byte first.
169 * This is exactly what we want here */
170 pack[0] = htonl(sec_hi);
171 pack[1] = htonl(tv.tv_sec);
172 pack[2] = htonl(tv.tv_usec);
173 *s++ = '@';
174 bin2hex(s, (char*)pack, 12);
175}
176
177static unsigned processorstart(struct logdir *ld)
178{
179 int pid;
180
181 if (!ld->processor) return 0;
182 if (ld->ppid) {
183 warnx("processor already running", ld->name);
184 return 0;
185 }
186 while ((pid = fork()) == -1)
187 pause2cannot("fork for processor", ld->name);
188 if (!pid) {
189 char *prog[4];
190 int fd;
191
192 /* child */
193 signal(SIGTERM, SIG_DFL);
194 signal(SIGALRM, SIG_DFL);
195 signal(SIGHUP, SIG_DFL);
196 sig_unblock(SIGTERM);
197 sig_unblock(SIGALRM);
198 sig_unblock(SIGHUP);
199
200 if (verbose)
201 bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
202 fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
203 xmove_fd(fd, 0);
204 ld->fnsave[26] = 't';
205 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
206 xmove_fd(fd, 1);
207 fd = open_read("state");
208 if (fd == -1) {
209 if (errno != ENOENT)
210 bb_perror_msg_and_die(FATAL"cannot %s processor %s", "open state for", ld->name);
211 close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
212 fd = xopen("state", O_RDONLY|O_NDELAY);
213 }
214 xmove_fd(fd, 4);
215 fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
216 xmove_fd(fd, 5);
217
218// getenv("SHELL")?
219 prog[0] = (char*)"sh";
220 prog[1] = (char*)"-c";
221 prog[2] = ld->processor;
222 prog[3] = NULL;
223 execve("/bin/sh", prog, environ);
224 bb_perror_msg_and_die(FATAL"cannot %s processor %s", "run", ld->name);
225 }
226 ld->ppid = pid;
227 return 1;
228}
229
230static unsigned processorstop(struct logdir *ld)
231{
232 char f[28];
233
234 if (ld->ppid) {
235 sig_unblock(SIGHUP);
236 while (wait_pid(&wstat, ld->ppid) == -1)
237 pause2cannot("wait for processor", ld->name);
238 sig_block(SIGHUP);
239 ld->ppid = 0;
240 }
241 if (ld->fddir == -1) return 1;
242 while (fchdir(ld->fddir) == -1)
243 pause2cannot("change directory, want processor", ld->name);
244 if (wait_exitcode(wstat) != 0) {
245 warnx("processor failed, restart", ld->name);
246 ld->fnsave[26] = 't';
247 unlink(ld->fnsave);
248 ld->fnsave[26] = 'u';
249 processorstart(ld);
250 while (fchdir(fdwdir) == -1)
251 pause1cannot("change to initial working directory");
252 return ld->processor ? 0 : 1;
253 }
254 ld->fnsave[26] = 't';
255 memcpy(f, ld->fnsave, 26);
256 f[26] = 's';
257 f[27] = '\0';
258 while (rename(ld->fnsave, f) == -1)
259 pause2cannot("rename processed", ld->name);
260 while (chmod(f, 0744) == -1)
261 pause2cannot("set mode of processed", ld->name);
262 ld->fnsave[26] = 'u';
263 if (unlink(ld->fnsave) == -1)
264 bb_error_msg(WARNING"cannot unlink: %s/%s", ld->name, ld->fnsave);
265 while (rename("newstate", "state") == -1)
266 pause2cannot("rename state", ld->name);
267 if (verbose)
268 bb_error_msg(INFO"processed: %s/%s", ld->name, f);
269 while (fchdir(fdwdir) == -1)
270 pause1cannot("change to initial working directory");
271 return 1;
272}
273
274static void rmoldest(struct logdir *ld)
275{
276 DIR *d;
277 struct dirent *f;
278 char oldest[FMT_PTIME];
279 int n = 0;
280
281 oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
282 while (!(d = opendir(".")))
283 pause2cannot("open directory, want rotate", ld->name);
284 errno = 0;
285 while ((f = readdir(d))) {
286 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
287 if (f->d_name[26] == 't') {
288 if (unlink(f->d_name) == -1)
289 warn2("cannot unlink processor leftover", f->d_name);
290 } else {
291 ++n;
292 if (strcmp(f->d_name, oldest) < 0)
293 memcpy(oldest, f->d_name, 27);
294 }
295 errno = 0;
296 }
297 }
298 if (errno)
299 warn2("cannot read directory", ld->name);
300 closedir(d);
301
302 if (ld->nmax && (n > ld->nmax)) {
303 if (verbose)
304 bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
305 if ((*oldest == '@') && (unlink(oldest) == -1))
306 warn2("cannot unlink oldest logfile", ld->name);
307 }
308}
309
310static unsigned rotate(struct logdir *ld)
311{
312 struct stat st;
313 unsigned now;
314
315 if (ld->fddir == -1) {
316 ld->rotate_period = 0;
317 return 0;
318 }
319 if (ld->ppid)
320 while (!processorstop(ld))
321 continue;
322
323 while (fchdir(ld->fddir) == -1)
324 pause2cannot("change directory, want rotate", ld->name);
325
326 /* create new filename */
327 ld->fnsave[25] = '.';
328 ld->fnsave[26] = 's';
329 if (ld->processor)
330 ld->fnsave[26] = 'u';
331 ld->fnsave[27] = '\0';
332 do {
333 fmt_time_bernstein_25(ld->fnsave);
334 errno = 0;
335 stat(ld->fnsave, &st);
336 } while (errno != ENOENT);
337
338 now = monotonic_sec();
339 if (ld->rotate_period && LESS(ld->next_rotate, now)) {
340 ld->next_rotate = now + ld->rotate_period;
341 if (LESS(ld->next_rotate, nearest_rotate))
342 nearest_rotate = ld->next_rotate;
343 }
344
345 if (ld->size > 0) {
346 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
347 pause2cannot("fsync current logfile", ld->name);
348 while (fchmod(ld->fdcur, 0744) == -1)
349 pause2cannot("set mode of current", ld->name);
350 ////close(ld->fdcur);
351 fclose(ld->filecur);
352
353 if (verbose) {
354 bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
355 ld->fnsave, ld->size);
356 }
357 while (rename("current", ld->fnsave) == -1)
358 pause2cannot("rename current", ld->name);
359 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
360 pause2cannot("create new current", ld->name);
361 /* we presume this cannot fail */
362 ld->filecur = fdopen(ld->fdcur, "a"); ////
363 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
364 coe(ld->fdcur);
365 ld->size = 0;
366 while (fchmod(ld->fdcur, 0644) == -1)
367 pause2cannot("set mode of current", ld->name);
368 rmoldest(ld);
369 processorstart(ld);
370 }
371
372 while (fchdir(fdwdir) == -1)
373 pause1cannot("change to initial working directory");
374 return 1;
375}
376
377static int buffer_pwrite(int n, char *s, unsigned len)
378{
379 int i;
380 struct logdir *ld = &dir[n];
381
382 if (ld->sizemax) {
383 if (ld->size >= ld->sizemax)
384 rotate(ld);
385 if (len > (ld->sizemax - ld->size))
386 len = ld->sizemax - ld->size;
387 }
388 while (1) {
389 ////i = full_write(ld->fdcur, s, len);
390 ////if (i != -1) break;
391 i = fwrite(s, 1, len, ld->filecur);
392 if (i == len) break;
393
394 if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
395 DIR *d;
396 struct dirent *f;
397 char oldest[FMT_PTIME];
398 int j = 0;
399
400 while (fchdir(ld->fddir) == -1)
401 pause2cannot("change directory, want remove old logfile",
402 ld->name);
403 oldest[0] = 'A';
404 oldest[1] = oldest[27] = '\0';
405 while (!(d = opendir(".")))
406 pause2cannot("open directory, want remove old logfile",
407 ld->name);
408 errno = 0;
409 while ((f = readdir(d)))
410 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
411 ++j;
412 if (strcmp(f->d_name, oldest) < 0)
413 memcpy(oldest, f->d_name, 27);
414 }
415 if (errno) warn2("cannot read directory, want remove old logfile",
416 ld->name);
417 closedir(d);
418 errno = ENOSPC;
419 if (j > ld->nmin) {
420 if (*oldest == '@') {
421 bb_error_msg(WARNING"out of disk space, delete: %s/%s",
422 ld->name, oldest);
423 errno = 0;
424 if (unlink(oldest) == -1) {
425 warn2("cannot unlink oldest logfile", ld->name);
426 errno = ENOSPC;
427 }
428 while (fchdir(fdwdir) == -1)
429 pause1cannot("change to initial working directory");
430 }
431 }
432 }
433 if (errno)
434 pause2cannot("write to current", ld->name);
435 }
436
437 ld->size += i;
438 if (ld->sizemax)
439 if (s[i-1] == '\n')
440 if (ld->size >= (ld->sizemax - linemax))
441 rotate(ld);
442 return i;
443}
444
445static void logdir_close(struct logdir *ld)
446{
447 if (ld->fddir == -1)
448 return;
449 if (verbose)
450 bb_error_msg(INFO"close: %s", ld->name);
451 close(ld->fddir);
452 ld->fddir = -1;
453 if (ld->fdcur == -1)
454 return; /* impossible */
455 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
456 pause2cannot("fsync current logfile", ld->name);
457 while (fchmod(ld->fdcur, 0744) == -1)
458 pause2cannot("set mode of current", ld->name);
459 ////close(ld->fdcur);
460 fclose(ld->filecur);
461 ld->fdcur = -1;
462 if (ld->fdlock == -1)
463 return; /* impossible */
464 close(ld->fdlock);
465 ld->fdlock = -1;
466 free(ld->processor);
467 ld->processor = NULL;
468}
469
470static unsigned logdir_open(struct logdir *ld, const char *fn)
471{
472 char buf[128];
473 unsigned now;
474 char *new, *s, *np;
475 int i;
476 struct stat st;
477
478 now = monotonic_sec();
479
480 ld->fddir = open(fn, O_RDONLY|O_NDELAY);
481 if (ld->fddir == -1) {
482 warn2("cannot open log directory", (char*)fn);
483 return 0;
484 }
485 coe(ld->fddir);
486 if (fchdir(ld->fddir) == -1) {
487 logdir_close(ld);
488 warn2("cannot change directory", (char*)fn);
489 return 0;
490 }
491 ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
492 if ((ld->fdlock == -1)
493 || (lock_exnb(ld->fdlock) == -1)
494 ) {
495 logdir_close(ld);
496 warn2("cannot lock directory", (char*)fn);
497 while (fchdir(fdwdir) == -1)
498 pause1cannot("change to initial working directory");
499 return 0;
500 }
501 coe(ld->fdlock);
502
503 ld->size = 0;
504 ld->sizemax = 1000000;
505 ld->nmax = ld->nmin = 10;
506 ld->rotate_period = 0;
507 ld->name = (char*)fn;
508 ld->ppid = 0;
509 ld->match = '+';
510 free(ld->inst); ld->inst = NULL;
511 free(ld->processor); ld->processor = NULL;
512
513 /* read config */
514 i = open_read_close("config", buf, sizeof(buf));
515 if (i < 0 && errno != ENOENT)
516 bb_perror_msg(WARNING"%s/config", ld->name);
517 if (i > 0) {
518 if (verbose)
519 bb_error_msg(INFO"read: %s/config", ld->name);
520 s = buf;
521 while (s) {
522 np = strchr(s, '\n');
523 if (np)
524 *np++ = '\0';
525 switch (s[0]) {
526 case '+':
527 case '-':
528 case 'e':
529 case 'E':
530 /* Add '\n'-terminated line to ld->inst */
531 while (1) {
532 int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);
533 if (l >= 0 && new)
534 break;
535 pause_nomem();
536 }
537 free(ld->inst);
538 ld->inst = new;
539 break;
540 case 's': {
541 static const struct suffix_mult km_suffixes[] = {
542 { "k", 1024 },
543 { "m", 1024*1024 },
544 { }
545 };
546 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
547 break;
548 }
549 case 'n':
550 ld->nmax = xatoi_u(&s[1]);
551 break;
552 case 'N':
553 ld->nmin = xatoi_u(&s[1]);
554 break;
555 case 't': {
556 static const struct suffix_mult mh_suffixes[] = {
557 { "m", 60 },
558 { "h", 60*60 },
559 /*{ "d", 24*60*60 },*/
560 { }
561 };
562 ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
563 if (ld->rotate_period) {
564 ld->next_rotate = now + ld->rotate_period;
565 if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate))
566 nearest_rotate = ld->next_rotate;
567 tmaxflag = 1;
568 }
569 break;
570 }
571 case '!':
572 if (s[1]) {
573 free(ld->processor);
574 ld->processor = wstrdup(s);
575 }
576 break;
577 }
578 s = np;
579 }
580 /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
581 s = ld->inst;
582 while (s) {
583 np = strchr(s, '\n');
584 if (np)
585 *np++ = '\0';
586 s = np;
587 }
588 }
589
590 /* open current */
591 i = stat("current", &st);
592 if (i != -1) {
593 if (st.st_size && !(st.st_mode & S_IXUSR)) {
594 ld->fnsave[25] = '.';
595 ld->fnsave[26] = 'u';
596 ld->fnsave[27] = '\0';
597 do {
598 fmt_time_bernstein_25(ld->fnsave);
599 errno = 0;
600 stat(ld->fnsave, &st);
601 } while (errno != ENOENT);
602 while (rename("current", ld->fnsave) == -1)
603 pause2cannot("rename current", ld->name);
604 rmoldest(ld);
605 i = -1;
606 } else {
607 /* st.st_size can be not just bigger, but WIDER!
608 * This code is safe: if st.st_size > 4GB, we select
609 * ld->sizemax (because it's "unsigned") */
610 ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
611 }
612 } else {
613 if (errno != ENOENT) {
614 logdir_close(ld);
615 warn2("cannot stat current", ld->name);
616 while (fchdir(fdwdir) == -1)
617 pause1cannot("change to initial working directory");
618 return 0;
619 }
620 }
621 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
622 pause2cannot("open current", ld->name);
623 /* we presume this cannot fail */
624 ld->filecur = fdopen(ld->fdcur, "a"); ////
625 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
626
627 coe(ld->fdcur);
628 while (fchmod(ld->fdcur, 0644) == -1)
629 pause2cannot("set mode of current", ld->name);
630
631 if (verbose) {
632 if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
633 else bb_error_msg(INFO"new: %s/current", ld->name);
634 }
635
636 while (fchdir(fdwdir) == -1)
637 pause1cannot("change to initial working directory");
638 return 1;
639}
640
641static void logdirs_reopen(void)
642{
643 int l;
644 int ok = 0;
645
646 tmaxflag = 0;
647 for (l = 0; l < dirn; ++l) {
648 logdir_close(&dir[l]);
649 if (logdir_open(&dir[l], fndir[l]))
650 ok = 1;
651 }
652 if (!ok)
653 fatalx("no functional log directories");
654}
655
656/* Will look good in libbb one day */
657static ssize_t ndelay_read(int fd, void *buf, size_t count)
658{
659 if (!(fl_flag_0 & O_NONBLOCK))
660 fcntl(fd, F_SETFL, fl_flag_0 | O_NONBLOCK);
661 count = safe_read(fd, buf, count);
662 if (!(fl_flag_0 & O_NONBLOCK))
663 fcntl(fd, F_SETFL, fl_flag_0);
664 return count;
665}
666
667/* Used for reading stdin */
668static int buffer_pread(int fd, char *s, unsigned len)
669{
670 unsigned now;
671 struct pollfd input;
672 int i;
673
674 input.fd = 0;
675 input.events = POLLIN;
676
677 do {
678 if (rotateasap) {
679 for (i = 0; i < dirn; ++i)
680 rotate(dir + i);
681 rotateasap = 0;
682 }
683 if (exitasap) {
684 if (linecomplete)
685 return 0;
686 len = 1;
687 }
688 if (reopenasap) {
689 logdirs_reopen();
690 reopenasap = 0;
691 }
692 now = monotonic_sec();
693 nearest_rotate = now + (45 * 60 + 45);
694 for (i = 0; i < dirn; ++i) {
695 if (dir[i].rotate_period) {
696 if (LESS(dir[i].next_rotate, now))
697 rotate(dir + i);
698 if (LESS(dir[i].next_rotate, nearest_rotate))
699 nearest_rotate = dir[i].next_rotate;
700 }
701 }
702
703 sigprocmask(SIG_UNBLOCK, blocked_sigset, NULL);
704 i = nearest_rotate - now;
705 if (i > 1000000)
706 i = 1000000;
707 if (i <= 0)
708 i = 1;
709 poll(&input, 1, i * 1000);
710 sigprocmask(SIG_BLOCK, blocked_sigset, NULL);
711
712 i = ndelay_read(fd, s, len);
713 if (i >= 0)
714 break;
715 if (errno == EINTR)
716 continue;
717 if (errno != EAGAIN) {
718 warn("cannot read standard input");
719 break;
720 }
721 /* else: EAGAIN - normal, repeat silently */
722 } while (!exitasap);
723
724 if (i > 0) {
725 int cnt;
726 linecomplete = (s[i-1] == '\n');
727 if (!repl)
728 return i;
729
730 cnt = i;
731 while (--cnt >= 0) {
732 char ch = *s;
733 if (ch != '\n') {
734 if (ch < 32 || ch > 126)
735 *s = repl;
736 else {
737 int j;
738 for (j = 0; replace[j]; ++j) {
739 if (ch == replace[j]) {
740 *s = repl;
741 break;
742 }
743 }
744 }
745 }
746 s++;
747 }
748 }
749 return i;
750}
751
752static void sig_term_handler(int sig_no)
753{
754 if (verbose)
755 bb_error_msg(INFO"sig%s received", "term");
756 exitasap = 1;
757}
758
759static void sig_child_handler(int sig_no)
760{
761 int pid, l;
762
763 if (verbose)
764 bb_error_msg(INFO"sig%s received", "child");
765 while ((pid = wait_nohang(&wstat)) > 0) {
766 for (l = 0; l < dirn; ++l) {
767 if (dir[l].ppid == pid) {
768 dir[l].ppid = 0;
769 processorstop(&dir[l]);
770 break;
771 }
772 }
773 }
774}
775
776static void sig_alarm_handler(int sig_no)
777{
778 if (verbose)
779 bb_error_msg(INFO"sig%s received", "alarm");
780 rotateasap = 1;
781}
782
783static void sig_hangup_handler(int sig_no)
784{
785 if (verbose)
786 bb_error_msg(INFO"sig%s received", "hangup");
787 reopenasap = 1;
788}
789
790static void logmatch(struct logdir *ld)
791{
792 char *s;
793
794 ld->match = '+';
795 ld->matcherr = 'E';
796 s = ld->inst;
797 while (s && s[0]) {
798 switch (s[0]) {
799 case '+':
800 case '-':
801 if (pmatch(s+1, line, linelen))
802 ld->match = s[0];
803 break;
804 case 'e':
805 case 'E':
806 if (pmatch(s+1, line, linelen))
807 ld->matcherr = s[0];
808 break;
809 }
810 s += strlen(s) + 1;
811 }
812}
813
814int svlogd_main(int argc, char **argv);
815int svlogd_main(int argc, char **argv)
816{
817 sigset_t ss;
818 char *r,*l,*b;
819 ssize_t stdin_cnt = 0;
820 int i;
821 unsigned opt;
822 unsigned timestamp = 0;
823 void* (*memRchr)(const void *, int, size_t) = memchr;
824
825#define line bb_common_bufsiz1
826
827 opt_complementary = "tt:vv";
828 opt = getopt32(argv, "r:R:l:b:tv",
829 &r, &replace, &l, &b, &timestamp, &verbose);
830 if (opt & 1) { // -r
831 repl = r[0];
832 if (!repl || r[1]) usage();
833 }
834 if (opt & 2) if (!repl) repl = '_'; // -R
835 if (opt & 4) { // -l
836 linemax = xatou_range(l, 0, BUFSIZ-26);
837 if (linemax == 0) linemax = BUFSIZ-26;
838 if (linemax < 256) linemax = 256;
839 }
840 ////if (opt & 8) { // -b
841 //// buflen = xatoi_u(b);
842 //// if (buflen == 0) buflen = 1024;
843 ////}
844 //if (opt & 0x10) timestamp++; // -t
845 //if (opt & 0x20) verbose++; // -v
846 //if (timestamp > 2) timestamp = 2;
847 argv += optind;
848 argc -= optind;
849
850 dirn = argc;
851 if (dirn <= 0) usage();
852 ////if (buflen <= linemax) usage();
853 fdwdir = xopen(".", O_RDONLY|O_NDELAY);
854 coe(fdwdir);
855 dir = xzalloc(dirn * sizeof(struct logdir));
856 for (i = 0; i < dirn; ++i) {
857 dir[i].fddir = -1;
858 dir[i].fdcur = -1;
859 ////dir[i].btmp = xmalloc(buflen);
860 /*dir[i].ppid = 0;*/
861 }
862 /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
863 fndir = argv;
864 /* We cannot set NONBLOCK on fd #0 permanently - this setting
865 * _isn't_ per-process! It is shared among all other processes
866 * with the same stdin */
867 fl_flag_0 = fcntl(0, F_GETFL);
868
869 blocked_sigset = &ss;
870 sigemptyset(&ss);
871 sigaddset(&ss, SIGTERM);
872 sigaddset(&ss, SIGCHLD);
873 sigaddset(&ss, SIGALRM);
874 sigaddset(&ss, SIGHUP);
875 sigprocmask(SIG_BLOCK, &ss, NULL);
876 sig_catch(SIGTERM, sig_term_handler);
877 sig_catch(SIGCHLD, sig_child_handler);
878 sig_catch(SIGALRM, sig_alarm_handler);
879 sig_catch(SIGHUP, sig_hangup_handler);
880
881 logdirs_reopen();
882
883 /* Without timestamps, we don't have to print each line
884 * separately, so we can look for _last_ newline, not first,
885 * thus batching writes */
886 if (!timestamp)
887 memRchr = memrchr;
888
889 setvbuf(stderr, NULL, _IOFBF, linelen);
890
891 /* Each iteration processes one or more lines */
892 while (1) {
893 char stamp[FMT_PTIME];
894 char *lineptr;
895 char *printptr;
896 char *np;
897 int printlen;
898 char ch;
899
900 lineptr = line;
901 if (timestamp)
902 lineptr += 26;
903
904 /* lineptr[0..linemax-1] - buffer for stdin */
905 /* (possibly has some unprocessed data from prev loop) */
906
907 /* Refill the buffer if needed */
908 np = memRchr(lineptr, '\n', stdin_cnt);
909 if (!np && !exitasap) {
910 i = linemax - stdin_cnt; /* avail. bytes at tail */
911 if (i >= 128) {
912 i = buffer_pread(0, lineptr + stdin_cnt, i);
913 if (i <= 0) /* EOF or error on stdin */
914 exitasap = 1;
915 else {
916 np = memRchr(lineptr + stdin_cnt, '\n', i);
917 stdin_cnt += i;
918 }
919 }
920 }
921 if (stdin_cnt <= 0 && exitasap)
922 break;
923
924 /* Search for '\n' (in fact, np already holds the result) */
925 linelen = stdin_cnt;
926 if (np) {
927 print_to_nl: /* NB: starting from here lineptr may point
928 * farther out into line[] */
929 linelen = np - lineptr + 1;
930 }
931 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
932 ch = lineptr[linelen-1];
933
934 /* Biggest performance hit was coming from the fact
935 * that we did not buffer writes. We were reading many lines
936 * in one read() above, but wrote one line per write().
937 * We are using stdio to fix that */
938
939 /* write out lineptr[0..linelen-1] to each log destination
940 * (or lineptr[-26..linelen-1] if timestamping) */
941 printlen = linelen;
942 printptr = lineptr;
943 if (timestamp) {
944 if (timestamp == 1)
945 fmt_time_bernstein_25(stamp);
946 else /* 2: */
947 fmt_time_human_30nul(stamp);
948 printlen += 26;
949 printptr -= 26;
950 memcpy(printptr, stamp, 25);
951 printptr[25] = ' ';
952 }
953 for (i = 0; i < dirn; ++i) {
954 struct logdir *ld = &dir[i];
955 if (ld->fddir == -1) continue;
956 if (ld->inst)
957 logmatch(ld);
958 if (ld->matcherr == 'e')
959 ////full_write(2, printptr, printlen);
960 fwrite(lineptr, 1, linelen, stderr);
961 if (ld->match != '+') continue;
962 buffer_pwrite(i, printptr, printlen);
963 }
964
965 /* If we didn't see '\n' (long input line), */
966 /* read/write repeatedly until we see it */
967 while (ch != '\n') {
968 /* lineptr is emptied now, safe to use as buffer */
969 stdin_cnt = exitasap ? -1 : buffer_pread(0, lineptr, linemax);
970 if (stdin_cnt <= 0) { /* EOF or error on stdin */
971 exitasap = 1;
972 lineptr[0] = ch = '\n';
973 linelen = 1;
974 stdin_cnt = 1;
975 } else {
976 linelen = stdin_cnt;
977 np = memRchr(lineptr, '\n', stdin_cnt);
978 if (np)
979 linelen = np - lineptr + 1;
980 ch = lineptr[linelen-1];
981 }
982 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
983 for (i = 0; i < dirn; ++i) {
984 if (dir[i].fddir == -1) continue;
985 if (dir[i].matcherr == 'e')
986 ////full_write(2, lineptr, linelen);
987 fwrite(lineptr, 1, linelen, stderr);
988 if (dir[i].match != '+') continue;
989 buffer_pwrite(i, lineptr, linelen);
990 }
991 }
992
993 stdin_cnt -= linelen;
994 if (stdin_cnt > 0) {
995 lineptr += linelen;
996 /* If we see another '\n', we don't need to read
997 * next piece of input: can print what we have */
998 np = memRchr(lineptr, '\n', stdin_cnt);
999 if (np)
1000 goto print_to_nl;
1001 /* Move unprocessed data to the front of line */
1002 memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1003 }
1004 fflush(NULL);////
1005 }
1006
1007 for (i = 0; i < dirn; ++i) {
1008 if (dir[i].ppid)
1009 while (!processorstop(&dir[i]))
1010 /* repeat */;
1011 logdir_close(&dir[i]);
1012 }
1013 return 0;
1014}
Note: See TracBrowser for help on using the repository browser.