blob: 25799f6be556a3208135a448df9b67f3c9f4ae8b [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{
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000148 bb_perror_msg(PAUSE"can't %s", m0);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000149 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{
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000153 bb_perror_msg(PAUSE"can't %s %s", m0, m1);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000154 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 Vlasenko4ee7cd42008-03-17 09:13:22 +0000209static void processorstart(struct logdir *ld)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000210{
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000211 char sv_ch;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000212 int pid;
213
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000214 if (!ld->processor) return;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000215 if (ld->ppid) {
216 warnx("processor already running", ld->name);
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000217 return;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000218 }
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000219
220 /* vfork'ed child trashes this byte, save... */
221 sv_ch = ld->fnsave[26];
222
223 while ((pid = vfork()) == -1)
224 pause2cannot("vfork for processor", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000225 if (!pid) {
226 char *prog[4];
227 int fd;
228
229 /* child */
Denis Vlasenko3fa36e22008-11-09 00:15:11 +0000230 /* Non-ignored signals revert to SIG_DFL on exec anyway */
231 /*bb_signals(0
Denis Vlasenko25591c32008-02-16 22:58:56 +0000232 + (1 << SIGTERM)
233 + (1 << SIGALRM)
234 + (1 << SIGHUP)
Denis Vlasenko3fa36e22008-11-09 00:15:11 +0000235 , SIG_DFL);*/
Denis Vlasenko8c783952007-01-27 22:21:52 +0000236 sig_unblock(SIGTERM);
237 sig_unblock(SIGALRM);
238 sig_unblock(SIGHUP);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000239
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000240 if (verbose)
241 bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
242 fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000243 xmove_fd(fd, 0);
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000244 ld->fnsave[26] = 't'; /* <- that's why we need sv_ch! */
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000245 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000246 xmove_fd(fd, 1);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000247 fd = open_read("state");
248 if (fd == -1) {
249 if (errno != ENOENT)
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000250 bb_perror_msg_and_die(FATAL"can't %s processor %s", "open state for", ld->name);
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000251 close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000252 fd = xopen("state", O_RDONLY|O_NDELAY);
253 }
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000254 xmove_fd(fd, 4);
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000255 fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000256 xmove_fd(fd, 5);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000257
Denis Vlasenko8c783952007-01-27 22:21:52 +0000258// getenv("SHELL")?
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000259 prog[0] = (char*)"sh";
260 prog[1] = (char*)"-c";
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000261 prog[2] = ld->processor;
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000262 prog[3] = NULL;
Denis Vlasenko847fa772008-01-28 22:45:43 +0000263 execv("/bin/sh", prog);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000264 bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000265 }
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000266 ld->fnsave[26] = sv_ch; /* ...restore */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000267 ld->ppid = pid;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000268}
269
270static unsigned processorstop(struct logdir *ld)
271{
272 char f[28];
273
274 if (ld->ppid) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000275 sig_unblock(SIGHUP);
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000276 while (safe_waitpid(ld->ppid, &wstat, 0) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000277 pause2cannot("wait for processor", ld->name);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000278 sig_block(SIGHUP);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000279 ld->ppid = 0;
280 }
281 if (ld->fddir == -1) return 1;
282 while (fchdir(ld->fddir) == -1)
283 pause2cannot("change directory, want processor", ld->name);
Denys Vlasenko8f24f982009-06-07 16:02:00 +0200284 if (WEXITSTATUS(wstat) != 0) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000285 warnx("processor failed, restart", ld->name);
286 ld->fnsave[26] = 't';
287 unlink(ld->fnsave);
288 ld->fnsave[26] = 'u';
289 processorstart(ld);
290 while (fchdir(fdwdir) == -1)
291 pause1cannot("change to initial working directory");
292 return ld->processor ? 0 : 1;
293 }
294 ld->fnsave[26] = 't';
295 memcpy(f, ld->fnsave, 26);
296 f[26] = 's';
297 f[27] = '\0';
298 while (rename(ld->fnsave, f) == -1)
299 pause2cannot("rename processed", ld->name);
300 while (chmod(f, 0744) == -1)
301 pause2cannot("set mode of processed", ld->name);
302 ld->fnsave[26] = 'u';
303 if (unlink(ld->fnsave) == -1)
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000304 bb_error_msg(WARNING"can't unlink: %s/%s", ld->name, ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000305 while (rename("newstate", "state") == -1)
306 pause2cannot("rename state", ld->name);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000307 if (verbose)
308 bb_error_msg(INFO"processed: %s/%s", ld->name, f);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000309 while (fchdir(fdwdir) == -1)
310 pause1cannot("change to initial working directory");
311 return 1;
312}
313
314static void rmoldest(struct logdir *ld)
315{
316 DIR *d;
317 struct dirent *f;
318 char oldest[FMT_PTIME];
319 int n = 0;
320
321 oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
322 while (!(d = opendir(".")))
323 pause2cannot("open directory, want rotate", ld->name);
324 errno = 0;
325 while ((f = readdir(d))) {
326 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
327 if (f->d_name[26] == 't') {
328 if (unlink(f->d_name) == -1)
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000329 warn2("can't unlink processor leftover", f->d_name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000330 } else {
331 ++n;
332 if (strcmp(f->d_name, oldest) < 0)
333 memcpy(oldest, f->d_name, 27);
334 }
335 errno = 0;
336 }
337 }
Denis Vlasenko8c783952007-01-27 22:21:52 +0000338 if (errno)
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000339 warn2("can't read directory", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000340 closedir(d);
341
342 if (ld->nmax && (n > ld->nmax)) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000343 if (verbose)
344 bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000345 if ((*oldest == '@') && (unlink(oldest) == -1))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000346 warn2("can't unlink oldest logfile", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000347 }
348}
349
350static unsigned rotate(struct logdir *ld)
351{
352 struct stat st;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000353 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000354
355 if (ld->fddir == -1) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000356 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000357 return 0;
358 }
359 if (ld->ppid)
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000360 while (!processorstop(ld))
Denis Vlasenko45946f82007-08-20 17:27:40 +0000361 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000362
363 while (fchdir(ld->fddir) == -1)
364 pause2cannot("change directory, want rotate", ld->name);
365
366 /* create new filename */
367 ld->fnsave[25] = '.';
368 ld->fnsave[26] = 's';
369 if (ld->processor)
370 ld->fnsave[26] = 'u';
371 ld->fnsave[27] = '\0';
372 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000373 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000374 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000375 stat(ld->fnsave, &st);
376 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000377
Denis Vlasenko45946f82007-08-20 17:27:40 +0000378 now = monotonic_sec();
379 if (ld->rotate_period && LESS(ld->next_rotate, now)) {
380 ld->next_rotate = now + ld->rotate_period;
381 if (LESS(ld->next_rotate, nearest_rotate))
382 nearest_rotate = ld->next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000383 }
384
385 if (ld->size > 0) {
Denis Vlasenko64392902007-02-03 00:53:43 +0000386 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000387 pause2cannot("fsync current logfile", ld->name);
388 while (fchmod(ld->fdcur, 0744) == -1)
389 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000390 ////close(ld->fdcur);
391 fclose(ld->filecur);
392
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000393 if (verbose) {
394 bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
395 ld->fnsave, ld->size);
396 }
397 while (rename("current", ld->fnsave) == -1)
398 pause2cannot("rename current", ld->name);
399 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
400 pause2cannot("create new current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000401 /* we presume this cannot fail */
402 ld->filecur = fdopen(ld->fdcur, "a"); ////
403 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000404 close_on_exec_on(ld->fdcur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000405 ld->size = 0;
406 while (fchmod(ld->fdcur, 0644) == -1)
407 pause2cannot("set mode of current", ld->name);
408 rmoldest(ld);
409 processorstart(ld);
410 }
411
412 while (fchdir(fdwdir) == -1)
413 pause1cannot("change to initial working directory");
414 return 1;
415}
416
417static int buffer_pwrite(int n, char *s, unsigned len)
418{
419 int i;
420 struct logdir *ld = &dir[n];
421
422 if (ld->sizemax) {
423 if (ld->size >= ld->sizemax)
424 rotate(ld);
425 if (len > (ld->sizemax - ld->size))
426 len = ld->sizemax - ld->size;
427 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000428 while (1) {
429 ////i = full_write(ld->fdcur, s, len);
430 ////if (i != -1) break;
431 i = fwrite(s, 1, len, ld->filecur);
432 if (i == len) break;
433
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000434 if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
435 DIR *d;
436 struct dirent *f;
437 char oldest[FMT_PTIME];
438 int j = 0;
439
440 while (fchdir(ld->fddir) == -1)
441 pause2cannot("change directory, want remove old logfile",
442 ld->name);
443 oldest[0] = 'A';
444 oldest[1] = oldest[27] = '\0';
445 while (!(d = opendir(".")))
446 pause2cannot("open directory, want remove old logfile",
447 ld->name);
448 errno = 0;
449 while ((f = readdir(d)))
450 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
451 ++j;
452 if (strcmp(f->d_name, oldest) < 0)
453 memcpy(oldest, f->d_name, 27);
454 }
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000455 if (errno) warn2("can't read directory, want remove old logfile",
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000456 ld->name);
457 closedir(d);
458 errno = ENOSPC;
459 if (j > ld->nmin) {
460 if (*oldest == '@') {
461 bb_error_msg(WARNING"out of disk space, delete: %s/%s",
462 ld->name, oldest);
463 errno = 0;
464 if (unlink(oldest) == -1) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000465 warn2("can't unlink oldest logfile", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000466 errno = ENOSPC;
467 }
468 while (fchdir(fdwdir) == -1)
469 pause1cannot("change to initial working directory");
470 }
471 }
472 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000473 if (errno)
474 pause2cannot("write to current", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000475 }
476
477 ld->size += i;
478 if (ld->sizemax)
479 if (s[i-1] == '\n')
480 if (ld->size >= (ld->sizemax - linemax))
481 rotate(ld);
482 return i;
483}
484
485static void logdir_close(struct logdir *ld)
486{
487 if (ld->fddir == -1)
488 return;
489 if (verbose)
490 bb_error_msg(INFO"close: %s", ld->name);
491 close(ld->fddir);
492 ld->fddir = -1;
493 if (ld->fdcur == -1)
494 return; /* impossible */
Denis Vlasenko64392902007-02-03 00:53:43 +0000495 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000496 pause2cannot("fsync current logfile", ld->name);
497 while (fchmod(ld->fdcur, 0744) == -1)
498 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000499 ////close(ld->fdcur);
500 fclose(ld->filecur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000501 ld->fdcur = -1;
502 if (ld->fdlock == -1)
503 return; /* impossible */
504 close(ld->fdlock);
505 ld->fdlock = -1;
506 free(ld->processor);
507 ld->processor = NULL;
508}
509
510static unsigned logdir_open(struct logdir *ld, const char *fn)
511{
512 char buf[128];
Denis Vlasenko45946f82007-08-20 17:27:40 +0000513 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000514 char *new, *s, *np;
515 int i;
516 struct stat st;
517
Denis Vlasenko45946f82007-08-20 17:27:40 +0000518 now = monotonic_sec();
519
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000520 ld->fddir = open(fn, O_RDONLY|O_NDELAY);
521 if (ld->fddir == -1) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000522 warn2("can't open log directory", (char*)fn);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000523 return 0;
524 }
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000525 close_on_exec_on(ld->fddir);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000526 if (fchdir(ld->fddir) == -1) {
527 logdir_close(ld);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000528 warn2("can't change directory", (char*)fn);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000529 return 0;
530 }
531 ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
532 if ((ld->fdlock == -1)
533 || (lock_exnb(ld->fdlock) == -1)
534 ) {
535 logdir_close(ld);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000536 warn2("can't lock directory", (char*)fn);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000537 while (fchdir(fdwdir) == -1)
538 pause1cannot("change to initial working directory");
539 return 0;
540 }
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000541 close_on_exec_on(ld->fdlock);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000542
543 ld->size = 0;
544 ld->sizemax = 1000000;
545 ld->nmax = ld->nmin = 10;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000546 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000547 ld->name = (char*)fn;
548 ld->ppid = 0;
549 ld->match = '+';
550 free(ld->inst); ld->inst = NULL;
551 free(ld->processor); ld->processor = NULL;
552
553 /* read config */
554 i = open_read_close("config", buf, sizeof(buf));
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000555 if (i < 0 && errno != ENOENT)
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000556 bb_perror_msg(WARNING"%s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000557 if (i > 0) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000558 if (verbose)
559 bb_error_msg(INFO"read: %s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000560 s = buf;
561 while (s) {
562 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000563 if (np)
564 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000565 switch (s[0]) {
566 case '+':
567 case '-':
568 case 'e':
569 case 'E':
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000570 /* Add '\n'-terminated line to ld->inst */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000571 while (1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000572 int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);
573 if (l >= 0 && new)
574 break;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000575 pause_nomem();
576 }
577 free(ld->inst);
578 ld->inst = new;
579 break;
580 case 's': {
581 static const struct suffix_mult km_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000582 { "k", 1024 },
583 { "m", 1024*1024 },
584 { }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000585 };
586 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
587 break;
588 }
589 case 'n':
590 ld->nmax = xatoi_u(&s[1]);
591 break;
592 case 'N':
593 ld->nmin = xatoi_u(&s[1]);
594 break;
595 case 't': {
596 static const struct suffix_mult mh_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000597 { "m", 60 },
598 { "h", 60*60 },
599 /*{ "d", 24*60*60 },*/
600 { }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000601 };
Denis Vlasenko45946f82007-08-20 17:27:40 +0000602 ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
603 if (ld->rotate_period) {
604 ld->next_rotate = now + ld->rotate_period;
605 if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate))
606 nearest_rotate = ld->next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000607 tmaxflag = 1;
608 }
609 break;
610 }
611 case '!':
612 if (s[1]) {
613 free(ld->processor);
614 ld->processor = wstrdup(s);
615 }
616 break;
617 }
618 s = np;
619 }
620 /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
621 s = ld->inst;
622 while (s) {
623 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000624 if (np)
625 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000626 s = np;
627 }
628 }
629
630 /* open current */
631 i = stat("current", &st);
632 if (i != -1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000633 if (st.st_size && !(st.st_mode & S_IXUSR)) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000634 ld->fnsave[25] = '.';
635 ld->fnsave[26] = 'u';
636 ld->fnsave[27] = '\0';
637 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000638 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000639 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000640 stat(ld->fnsave, &st);
641 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000642 while (rename("current", ld->fnsave) == -1)
643 pause2cannot("rename current", ld->name);
644 rmoldest(ld);
645 i = -1;
646 } else {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000647 /* st.st_size can be not just bigger, but WIDER!
648 * This code is safe: if st.st_size > 4GB, we select
649 * ld->sizemax (because it's "unsigned") */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000650 ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
651 }
652 } else {
653 if (errno != ENOENT) {
654 logdir_close(ld);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000655 warn2("can't stat current", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000656 while (fchdir(fdwdir) == -1)
657 pause1cannot("change to initial working directory");
658 return 0;
659 }
660 }
661 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
662 pause2cannot("open current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000663 /* we presume this cannot fail */
664 ld->filecur = fdopen(ld->fdcur, "a"); ////
665 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
666
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000667 close_on_exec_on(ld->fdcur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000668 while (fchmod(ld->fdcur, 0644) == -1)
669 pause2cannot("set mode of current", ld->name);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000670
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000671 if (verbose) {
672 if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
673 else bb_error_msg(INFO"new: %s/current", ld->name);
674 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000675
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000676 while (fchdir(fdwdir) == -1)
677 pause1cannot("change to initial working directory");
678 return 1;
679}
680
681static void logdirs_reopen(void)
682{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000683 int l;
684 int ok = 0;
685
686 tmaxflag = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000687 for (l = 0; l < dirn; ++l) {
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000688 logdir_close(&dir[l]);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000689 if (logdir_open(&dir[l], fndir[l]))
690 ok = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000691 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000692 if (!ok)
693 fatalx("no functional log directories");
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000694}
695
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000696/* Will look good in libbb one day */
697static ssize_t ndelay_read(int fd, void *buf, size_t count)
698{
699 if (!(fl_flag_0 & O_NONBLOCK))
700 fcntl(fd, F_SETFL, fl_flag_0 | O_NONBLOCK);
701 count = safe_read(fd, buf, count);
702 if (!(fl_flag_0 & O_NONBLOCK))
703 fcntl(fd, F_SETFL, fl_flag_0);
704 return count;
705}
706
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000707/* Used for reading stdin */
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000708static int buffer_pread(/*int fd, */char *s, unsigned len)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000709{
Denis Vlasenko45946f82007-08-20 17:27:40 +0000710 unsigned now;
711 struct pollfd input;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000712 int i;
713
Denis Vlasenko45946f82007-08-20 17:27:40 +0000714 input.fd = 0;
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000715 input.events = POLLIN;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000716
Denis Vlasenkob9528352007-05-06 01:37:21 +0000717 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000718 if (rotateasap) {
719 for (i = 0; i < dirn; ++i)
720 rotate(dir + i);
721 rotateasap = 0;
722 }
723 if (exitasap) {
724 if (linecomplete)
725 return 0;
726 len = 1;
727 }
728 if (reopenasap) {
729 logdirs_reopen();
730 reopenasap = 0;
731 }
732 now = monotonic_sec();
733 nearest_rotate = now + (45 * 60 + 45);
734 for (i = 0; i < dirn; ++i) {
735 if (dir[i].rotate_period) {
736 if (LESS(dir[i].next_rotate, now))
737 rotate(dir + i);
738 if (LESS(dir[i].next_rotate, nearest_rotate))
739 nearest_rotate = dir[i].next_rotate;
740 }
741 }
742
Denis Vlasenko339936b2007-10-05 22:11:06 +0000743 sigprocmask(SIG_UNBLOCK, &blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000744 i = nearest_rotate - now;
745 if (i > 1000000)
746 i = 1000000;
747 if (i <= 0)
748 i = 1;
749 poll(&input, 1, i * 1000);
Denis Vlasenko339936b2007-10-05 22:11:06 +0000750 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000751
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +0000752 i = ndelay_read(STDIN_FILENO, s, len);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000753 if (i >= 0)
754 break;
755 if (errno == EINTR)
756 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000757 if (errno != EAGAIN) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000758 warn("can't read standard input");
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000759 break;
760 }
761 /* else: EAGAIN - normal, repeat silently */
Denis Vlasenkob9528352007-05-06 01:37:21 +0000762 } while (!exitasap);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000763
764 if (i > 0) {
765 int cnt;
766 linecomplete = (s[i-1] == '\n');
Denis Vlasenko45946f82007-08-20 17:27:40 +0000767 if (!repl)
768 return i;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000769
770 cnt = i;
771 while (--cnt >= 0) {
772 char ch = *s;
773 if (ch != '\n') {
774 if (ch < 32 || ch > 126)
775 *s = repl;
776 else {
777 int j;
778 for (j = 0; replace[j]; ++j) {
779 if (ch == replace[j]) {
780 *s = repl;
781 break;
782 }
783 }
784 }
785 }
786 s++;
787 }
788 }
789 return i;
790}
791
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000792static void sig_term_handler(int sig_no UNUSED_PARAM)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000793{
794 if (verbose)
795 bb_error_msg(INFO"sig%s received", "term");
796 exitasap = 1;
797}
798
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000799static void sig_child_handler(int sig_no UNUSED_PARAM)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000800{
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000801 pid_t pid;
802 int l;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000803
804 if (verbose)
805 bb_error_msg(INFO"sig%s received", "child");
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000806 while ((pid = wait_any_nohang(&wstat)) > 0) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000807 for (l = 0; l < dirn; ++l) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000808 if (dir[l].ppid == pid) {
809 dir[l].ppid = 0;
810 processorstop(&dir[l]);
811 break;
812 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000813 }
814 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000815}
816
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000817static void sig_alarm_handler(int sig_no UNUSED_PARAM)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000818{
819 if (verbose)
820 bb_error_msg(INFO"sig%s received", "alarm");
821 rotateasap = 1;
822}
823
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000824static void sig_hangup_handler(int sig_no UNUSED_PARAM)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000825{
826 if (verbose)
827 bb_error_msg(INFO"sig%s received", "hangup");
828 reopenasap = 1;
829}
830
831static void logmatch(struct logdir *ld)
832{
833 char *s;
834
835 ld->match = '+';
836 ld->matcherr = 'E';
837 s = ld->inst;
838 while (s && s[0]) {
839 switch (s[0]) {
840 case '+':
841 case '-':
842 if (pmatch(s+1, line, linelen))
843 ld->match = s[0];
844 break;
845 case 'e':
846 case 'E':
847 if (pmatch(s+1, line, linelen))
848 ld->matcherr = s[0];
849 break;
850 }
851 s += strlen(s) + 1;
852 }
853}
854
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000855int svlogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000856int svlogd_main(int argc, char **argv)
857{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000858 char *r,*l,*b;
859 ssize_t stdin_cnt = 0;
860 int i;
861 unsigned opt;
862 unsigned timestamp = 0;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000863 void* (*memRchr)(const void *, int, size_t) = memchr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000864
Denis Vlasenko339936b2007-10-05 22:11:06 +0000865 INIT_G();
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000866
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000867 opt_complementary = "tt:vv";
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000868 opt = getopt32(argv, "r:R:l:b:tv",
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000869 &r, &replace, &l, &b, &timestamp, &verbose);
870 if (opt & 1) { // -r
871 repl = r[0];
872 if (!repl || r[1]) usage();
873 }
874 if (opt & 2) if (!repl) repl = '_'; // -R
875 if (opt & 4) { // -l
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000876 linemax = xatou_range(l, 0, BUFSIZ-26);
877 if (linemax == 0) linemax = BUFSIZ-26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000878 if (linemax < 256) linemax = 256;
879 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000880 ////if (opt & 8) { // -b
881 //// buflen = xatoi_u(b);
882 //// if (buflen == 0) buflen = 1024;
883 ////}
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000884 //if (opt & 0x10) timestamp++; // -t
885 //if (opt & 0x20) verbose++; // -v
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000886 //if (timestamp > 2) timestamp = 2;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000887 argv += optind;
888 argc -= optind;
889
890 dirn = argc;
891 if (dirn <= 0) usage();
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000892 ////if (buflen <= linemax) usage();
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000893 fdwdir = xopen(".", O_RDONLY|O_NDELAY);
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000894 close_on_exec_on(fdwdir);
Denis Vlasenkob9528352007-05-06 01:37:21 +0000895 dir = xzalloc(dirn * sizeof(struct logdir));
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000896 for (i = 0; i < dirn; ++i) {
897 dir[i].fddir = -1;
898 dir[i].fdcur = -1;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000899 ////dir[i].btmp = xmalloc(buflen);
Denis Vlasenkob9528352007-05-06 01:37:21 +0000900 /*dir[i].ppid = 0;*/
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000901 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000902 /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000903 fndir = argv;
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000904 /* We cannot set NONBLOCK on fd #0 permanently - this setting
905 * _isn't_ per-process! It is shared among all other processes
906 * with the same stdin */
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000907 fl_flag_0 = fcntl(0, F_GETFL);
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000908
Denis Vlasenko339936b2007-10-05 22:11:06 +0000909 sigemptyset(&blocked_sigset);
910 sigaddset(&blocked_sigset, SIGTERM);
911 sigaddset(&blocked_sigset, SIGCHLD);
912 sigaddset(&blocked_sigset, SIGALRM);
913 sigaddset(&blocked_sigset, SIGHUP);
914 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
Denis Vlasenkocab28aa2009-01-31 01:02:07 +0000915 bb_signals_recursive_norestart(1 << SIGTERM, sig_term_handler);
916 bb_signals_recursive_norestart(1 << SIGCHLD, sig_child_handler);
917 bb_signals_recursive_norestart(1 << SIGALRM, sig_alarm_handler);
918 bb_signals_recursive_norestart(1 << SIGHUP, sig_hangup_handler);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000919
920 logdirs_reopen();
921
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000922 /* Without timestamps, we don't have to print each line
923 * separately, so we can look for _last_ newline, not first,
924 * thus batching writes */
925 if (!timestamp)
926 memRchr = memrchr;
927
Denis Vlasenko64392902007-02-03 00:53:43 +0000928 setvbuf(stderr, NULL, _IOFBF, linelen);
929
Denis Vlasenko4e1715f2007-01-28 14:51:32 +0000930 /* Each iteration processes one or more lines */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000931 while (1) {
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000932 char stamp[FMT_PTIME];
933 char *lineptr;
934 char *printptr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000935 char *np;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000936 int printlen;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000937 char ch;
938
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000939 lineptr = line;
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000940 if (timestamp)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000941 lineptr += 26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000942
943 /* lineptr[0..linemax-1] - buffer for stdin */
944 /* (possibly has some unprocessed data from prev loop) */
945
946 /* Refill the buffer if needed */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000947 np = memRchr(lineptr, '\n', stdin_cnt);
948 if (!np && !exitasap) {
949 i = linemax - stdin_cnt; /* avail. bytes at tail */
950 if (i >= 128) {
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000951 i = buffer_pread(/*0, */lineptr + stdin_cnt, i);
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000952 if (i <= 0) /* EOF or error on stdin */
953 exitasap = 1;
954 else {
955 np = memRchr(lineptr + stdin_cnt, '\n', i);
956 stdin_cnt += i;
957 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000958 }
959 }
960 if (stdin_cnt <= 0 && exitasap)
961 break;
962
963 /* Search for '\n' (in fact, np already holds the result) */
964 linelen = stdin_cnt;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000965 if (np) {
966 print_to_nl: /* NB: starting from here lineptr may point
967 * farther out into line[] */
968 linelen = np - lineptr + 1;
969 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000970 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
971 ch = lineptr[linelen-1];
972
Denis Vlasenko64392902007-02-03 00:53:43 +0000973 /* Biggest performance hit was coming from the fact
974 * that we did not buffer writes. We were reading many lines
975 * in one read() above, but wrote one line per write().
976 * We are using stdio to fix that */
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000977
978 /* write out lineptr[0..linelen-1] to each log destination
979 * (or lineptr[-26..linelen-1] if timestamping) */
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000980 printlen = linelen;
981 printptr = lineptr;
982 if (timestamp) {
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000983 if (timestamp == 1)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000984 fmt_time_bernstein_25(stamp);
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000985 else /* 2: */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000986 fmt_time_human_30nul(stamp);
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000987 printlen += 26;
988 printptr -= 26;
989 memcpy(printptr, stamp, 25);
990 printptr[25] = ' ';
991 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000992 for (i = 0; i < dirn; ++i) {
993 struct logdir *ld = &dir[i];
994 if (ld->fddir == -1) continue;
995 if (ld->inst)
996 logmatch(ld);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +0000997 if (ld->matcherr == 'e') {
998 /* runit-1.8.0 compat: if timestamping, do it on stderr too */
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +0000999 ////full_write(STDERR_FILENO, printptr, printlen);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001000 fwrite(printptr, 1, printlen, stderr);
1001 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001002 if (ld->match != '+') continue;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001003 buffer_pwrite(i, printptr, printlen);
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001004 }
1005
1006 /* If we didn't see '\n' (long input line), */
1007 /* read/write repeatedly until we see it */
1008 while (ch != '\n') {
1009 /* lineptr is emptied now, safe to use as buffer */
Denis Vlasenko5d61e712007-09-27 10:09:59 +00001010 stdin_cnt = exitasap ? -1 : buffer_pread(/*0, */lineptr, linemax);
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001011 if (stdin_cnt <= 0) { /* EOF or error on stdin */
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001012 exitasap = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001013 lineptr[0] = ch = '\n';
1014 linelen = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001015 stdin_cnt = 1;
1016 } else {
1017 linelen = stdin_cnt;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001018 np = memRchr(lineptr, '\n', stdin_cnt);
1019 if (np)
1020 linelen = np - lineptr + 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001021 ch = lineptr[linelen-1];
1022 }
1023 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
1024 for (i = 0; i < dirn; ++i) {
1025 if (dir[i].fddir == -1) continue;
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001026 if (dir[i].matcherr == 'e') {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001027 ////full_write(STDERR_FILENO, lineptr, linelen);
Denis Vlasenko64392902007-02-03 00:53:43 +00001028 fwrite(lineptr, 1, linelen, stderr);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001029 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001030 if (dir[i].match != '+') continue;
1031 buffer_pwrite(i, lineptr, linelen);
1032 }
1033 }
1034
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001035 stdin_cnt -= linelen;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001036 if (stdin_cnt > 0) {
1037 lineptr += linelen;
1038 /* If we see another '\n', we don't need to read
1039 * next piece of input: can print what we have */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001040 np = memRchr(lineptr, '\n', stdin_cnt);
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001041 if (np)
1042 goto print_to_nl;
1043 /* Move unprocessed data to the front of line */
1044 memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1045 }
Denis Vlasenko64392902007-02-03 00:53:43 +00001046 fflush(NULL);////
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001047 }
1048
1049 for (i = 0; i < dirn; ++i) {
1050 if (dir[i].ppid)
1051 while (!processorstop(&dir[i]))
1052 /* repeat */;
1053 logdir_close(&dir[i]);
1054 }
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001055 return 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001056}