blob: 79286a3ee51c57151da2146b9a0179a5e53e141d [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) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000226 int fd;
227
228 /* child */
Denis Vlasenko3fa36e22008-11-09 00:15:11 +0000229 /* Non-ignored signals revert to SIG_DFL on exec anyway */
230 /*bb_signals(0
Denis Vlasenko25591c32008-02-16 22:58:56 +0000231 + (1 << SIGTERM)
232 + (1 << SIGALRM)
233 + (1 << SIGHUP)
Denis Vlasenko3fa36e22008-11-09 00:15:11 +0000234 , SIG_DFL);*/
Denis Vlasenko8c783952007-01-27 22:21:52 +0000235 sig_unblock(SIGTERM);
236 sig_unblock(SIGALRM);
237 sig_unblock(SIGHUP);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000238
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000239 if (verbose)
240 bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
241 fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000242 xmove_fd(fd, 0);
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000243 ld->fnsave[26] = 't'; /* <- that's why we need sv_ch! */
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000244 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000245 xmove_fd(fd, 1);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000246 fd = open_read("state");
247 if (fd == -1) {
248 if (errno != ENOENT)
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000249 bb_perror_msg_and_die(FATAL"can't %s processor %s", "open state for", ld->name);
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000250 close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000251 fd = xopen("state", O_RDONLY|O_NDELAY);
252 }
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000253 xmove_fd(fd, 4);
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000254 fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000255 xmove_fd(fd, 5);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000256
Denis Vlasenko8c783952007-01-27 22:21:52 +0000257// getenv("SHELL")?
Denys Vlasenkoc5d07fb2009-07-03 18:31:23 +0200258 execl("/bin/sh", "/bin/sh" + 5, "-c", ld->processor, (char*) NULL);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000259 bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000260 }
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000261 ld->fnsave[26] = sv_ch; /* ...restore */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000262 ld->ppid = pid;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000263}
264
265static unsigned processorstop(struct logdir *ld)
266{
267 char f[28];
268
269 if (ld->ppid) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000270 sig_unblock(SIGHUP);
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000271 while (safe_waitpid(ld->ppid, &wstat, 0) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000272 pause2cannot("wait for processor", ld->name);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000273 sig_block(SIGHUP);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000274 ld->ppid = 0;
275 }
276 if (ld->fddir == -1) return 1;
277 while (fchdir(ld->fddir) == -1)
278 pause2cannot("change directory, want processor", ld->name);
Denys Vlasenko8f24f982009-06-07 16:02:00 +0200279 if (WEXITSTATUS(wstat) != 0) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000280 warnx("processor failed, restart", ld->name);
281 ld->fnsave[26] = 't';
282 unlink(ld->fnsave);
283 ld->fnsave[26] = 'u';
284 processorstart(ld);
285 while (fchdir(fdwdir) == -1)
286 pause1cannot("change to initial working directory");
287 return ld->processor ? 0 : 1;
288 }
289 ld->fnsave[26] = 't';
290 memcpy(f, ld->fnsave, 26);
291 f[26] = 's';
292 f[27] = '\0';
293 while (rename(ld->fnsave, f) == -1)
294 pause2cannot("rename processed", ld->name);
295 while (chmod(f, 0744) == -1)
296 pause2cannot("set mode of processed", ld->name);
297 ld->fnsave[26] = 'u';
298 if (unlink(ld->fnsave) == -1)
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000299 bb_error_msg(WARNING"can't unlink: %s/%s", ld->name, ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000300 while (rename("newstate", "state") == -1)
301 pause2cannot("rename state", ld->name);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000302 if (verbose)
303 bb_error_msg(INFO"processed: %s/%s", ld->name, f);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000304 while (fchdir(fdwdir) == -1)
305 pause1cannot("change to initial working directory");
306 return 1;
307}
308
309static void rmoldest(struct logdir *ld)
310{
311 DIR *d;
312 struct dirent *f;
313 char oldest[FMT_PTIME];
314 int n = 0;
315
316 oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
317 while (!(d = opendir(".")))
318 pause2cannot("open directory, want rotate", ld->name);
319 errno = 0;
320 while ((f = readdir(d))) {
321 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
322 if (f->d_name[26] == 't') {
323 if (unlink(f->d_name) == -1)
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000324 warn2("can't unlink processor leftover", f->d_name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000325 } else {
326 ++n;
327 if (strcmp(f->d_name, oldest) < 0)
328 memcpy(oldest, f->d_name, 27);
329 }
330 errno = 0;
331 }
332 }
Denis Vlasenko8c783952007-01-27 22:21:52 +0000333 if (errno)
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000334 warn2("can't read directory", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000335 closedir(d);
336
337 if (ld->nmax && (n > ld->nmax)) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000338 if (verbose)
339 bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000340 if ((*oldest == '@') && (unlink(oldest) == -1))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000341 warn2("can't unlink oldest logfile", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000342 }
343}
344
345static unsigned rotate(struct logdir *ld)
346{
347 struct stat st;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000348 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000349
350 if (ld->fddir == -1) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000351 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000352 return 0;
353 }
354 if (ld->ppid)
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000355 while (!processorstop(ld))
Denis Vlasenko45946f82007-08-20 17:27:40 +0000356 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000357
358 while (fchdir(ld->fddir) == -1)
359 pause2cannot("change directory, want rotate", ld->name);
360
361 /* create new filename */
362 ld->fnsave[25] = '.';
363 ld->fnsave[26] = 's';
364 if (ld->processor)
365 ld->fnsave[26] = 'u';
366 ld->fnsave[27] = '\0';
367 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000368 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000369 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000370 stat(ld->fnsave, &st);
371 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000372
Denis Vlasenko45946f82007-08-20 17:27:40 +0000373 now = monotonic_sec();
374 if (ld->rotate_period && LESS(ld->next_rotate, now)) {
375 ld->next_rotate = now + ld->rotate_period;
376 if (LESS(ld->next_rotate, nearest_rotate))
377 nearest_rotate = ld->next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000378 }
379
380 if (ld->size > 0) {
Denis Vlasenko64392902007-02-03 00:53:43 +0000381 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000382 pause2cannot("fsync current logfile", ld->name);
383 while (fchmod(ld->fdcur, 0744) == -1)
384 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000385 ////close(ld->fdcur);
386 fclose(ld->filecur);
387
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000388 if (verbose) {
389 bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
390 ld->fnsave, ld->size);
391 }
392 while (rename("current", ld->fnsave) == -1)
393 pause2cannot("rename current", ld->name);
394 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
395 pause2cannot("create new current", ld->name);
Denys Vlasenkoc5d07fb2009-07-03 18:31:23 +0200396 while ((ld->filecur = fdopen(ld->fdcur, "a")) == NULL) ////
397 pause2cannot("create new current", ld->name); /* very unlikely */
Denis Vlasenko64392902007-02-03 00:53:43 +0000398 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000399 close_on_exec_on(ld->fdcur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000400 ld->size = 0;
401 while (fchmod(ld->fdcur, 0644) == -1)
402 pause2cannot("set mode of current", ld->name);
Denys Vlasenkoc5d07fb2009-07-03 18:31:23 +0200403
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000404 rmoldest(ld);
405 processorstart(ld);
406 }
407
408 while (fchdir(fdwdir) == -1)
409 pause1cannot("change to initial working directory");
410 return 1;
411}
412
413static int buffer_pwrite(int n, char *s, unsigned len)
414{
415 int i;
416 struct logdir *ld = &dir[n];
417
418 if (ld->sizemax) {
419 if (ld->size >= ld->sizemax)
420 rotate(ld);
421 if (len > (ld->sizemax - ld->size))
422 len = ld->sizemax - ld->size;
423 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000424 while (1) {
425 ////i = full_write(ld->fdcur, s, len);
426 ////if (i != -1) break;
427 i = fwrite(s, 1, len, ld->filecur);
428 if (i == len) break;
429
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000430 if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
431 DIR *d;
432 struct dirent *f;
433 char oldest[FMT_PTIME];
434 int j = 0;
435
436 while (fchdir(ld->fddir) == -1)
437 pause2cannot("change directory, want remove old logfile",
438 ld->name);
439 oldest[0] = 'A';
440 oldest[1] = oldest[27] = '\0';
441 while (!(d = opendir(".")))
442 pause2cannot("open directory, want remove old logfile",
443 ld->name);
444 errno = 0;
445 while ((f = readdir(d)))
446 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
447 ++j;
448 if (strcmp(f->d_name, oldest) < 0)
449 memcpy(oldest, f->d_name, 27);
450 }
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000451 if (errno) warn2("can't read directory, want remove old logfile",
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000452 ld->name);
453 closedir(d);
454 errno = ENOSPC;
455 if (j > ld->nmin) {
456 if (*oldest == '@') {
457 bb_error_msg(WARNING"out of disk space, delete: %s/%s",
458 ld->name, oldest);
459 errno = 0;
460 if (unlink(oldest) == -1) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000461 warn2("can't unlink oldest logfile", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000462 errno = ENOSPC;
463 }
464 while (fchdir(fdwdir) == -1)
465 pause1cannot("change to initial working directory");
466 }
467 }
468 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000469 if (errno)
470 pause2cannot("write to current", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000471 }
472
473 ld->size += i;
474 if (ld->sizemax)
475 if (s[i-1] == '\n')
476 if (ld->size >= (ld->sizemax - linemax))
477 rotate(ld);
478 return i;
479}
480
481static void logdir_close(struct logdir *ld)
482{
483 if (ld->fddir == -1)
484 return;
485 if (verbose)
486 bb_error_msg(INFO"close: %s", ld->name);
487 close(ld->fddir);
488 ld->fddir = -1;
489 if (ld->fdcur == -1)
490 return; /* impossible */
Denis Vlasenko64392902007-02-03 00:53:43 +0000491 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000492 pause2cannot("fsync current logfile", ld->name);
493 while (fchmod(ld->fdcur, 0744) == -1)
494 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000495 ////close(ld->fdcur);
496 fclose(ld->filecur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000497 ld->fdcur = -1;
498 if (ld->fdlock == -1)
499 return; /* impossible */
500 close(ld->fdlock);
501 ld->fdlock = -1;
502 free(ld->processor);
503 ld->processor = NULL;
504}
505
506static unsigned logdir_open(struct logdir *ld, const char *fn)
507{
508 char buf[128];
Denis Vlasenko45946f82007-08-20 17:27:40 +0000509 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000510 char *new, *s, *np;
511 int i;
512 struct stat st;
513
Denis Vlasenko45946f82007-08-20 17:27:40 +0000514 now = monotonic_sec();
515
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000516 ld->fddir = open(fn, O_RDONLY|O_NDELAY);
517 if (ld->fddir == -1) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000518 warn2("can't open log directory", (char*)fn);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000519 return 0;
520 }
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000521 close_on_exec_on(ld->fddir);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000522 if (fchdir(ld->fddir) == -1) {
523 logdir_close(ld);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000524 warn2("can't change directory", (char*)fn);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000525 return 0;
526 }
527 ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
528 if ((ld->fdlock == -1)
529 || (lock_exnb(ld->fdlock) == -1)
530 ) {
531 logdir_close(ld);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000532 warn2("can't lock directory", (char*)fn);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000533 while (fchdir(fdwdir) == -1)
534 pause1cannot("change to initial working directory");
535 return 0;
536 }
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000537 close_on_exec_on(ld->fdlock);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000538
539 ld->size = 0;
540 ld->sizemax = 1000000;
541 ld->nmax = ld->nmin = 10;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000542 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000543 ld->name = (char*)fn;
544 ld->ppid = 0;
545 ld->match = '+';
546 free(ld->inst); ld->inst = NULL;
547 free(ld->processor); ld->processor = NULL;
548
549 /* read config */
Denys Vlasenkoc5d07fb2009-07-03 18:31:23 +0200550 i = open_read_close("config", buf, sizeof(buf) - 1);
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000551 if (i < 0 && errno != ENOENT)
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000552 bb_perror_msg(WARNING"%s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000553 if (i > 0) {
Denys Vlasenkoc5d07fb2009-07-03 18:31:23 +0200554 buf[i] = '\0';
Denis Vlasenko45946f82007-08-20 17:27:40 +0000555 if (verbose)
556 bb_error_msg(INFO"read: %s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000557 s = buf;
558 while (s) {
559 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000560 if (np)
561 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000562 switch (s[0]) {
563 case '+':
564 case '-':
565 case 'e':
566 case 'E':
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000567 /* Add '\n'-terminated line to ld->inst */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000568 while (1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000569 int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);
570 if (l >= 0 && new)
571 break;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000572 pause_nomem();
573 }
574 free(ld->inst);
575 ld->inst = new;
576 break;
577 case 's': {
578 static const struct suffix_mult km_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000579 { "k", 1024 },
580 { "m", 1024*1024 },
581 { }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000582 };
583 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
584 break;
585 }
586 case 'n':
587 ld->nmax = xatoi_u(&s[1]);
588 break;
589 case 'N':
590 ld->nmin = xatoi_u(&s[1]);
591 break;
592 case 't': {
593 static const struct suffix_mult mh_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000594 { "m", 60 },
595 { "h", 60*60 },
596 /*{ "d", 24*60*60 },*/
597 { }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000598 };
Denis Vlasenko45946f82007-08-20 17:27:40 +0000599 ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
600 if (ld->rotate_period) {
601 ld->next_rotate = now + ld->rotate_period;
602 if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate))
603 nearest_rotate = ld->next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000604 tmaxflag = 1;
605 }
606 break;
607 }
608 case '!':
609 if (s[1]) {
610 free(ld->processor);
611 ld->processor = wstrdup(s);
612 }
613 break;
614 }
615 s = np;
616 }
617 /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
618 s = ld->inst;
619 while (s) {
620 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000621 if (np)
622 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000623 s = np;
624 }
625 }
626
627 /* open current */
628 i = stat("current", &st);
629 if (i != -1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000630 if (st.st_size && !(st.st_mode & S_IXUSR)) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000631 ld->fnsave[25] = '.';
632 ld->fnsave[26] = 'u';
633 ld->fnsave[27] = '\0';
634 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000635 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000636 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000637 stat(ld->fnsave, &st);
638 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000639 while (rename("current", ld->fnsave) == -1)
640 pause2cannot("rename current", ld->name);
641 rmoldest(ld);
642 i = -1;
643 } else {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000644 /* st.st_size can be not just bigger, but WIDER!
645 * This code is safe: if st.st_size > 4GB, we select
646 * ld->sizemax (because it's "unsigned") */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000647 ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
648 }
649 } else {
650 if (errno != ENOENT) {
651 logdir_close(ld);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000652 warn2("can't stat current", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000653 while (fchdir(fdwdir) == -1)
654 pause1cannot("change to initial working directory");
655 return 0;
656 }
657 }
658 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
659 pause2cannot("open current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000660 /* we presume this cannot fail */
661 ld->filecur = fdopen(ld->fdcur, "a"); ////
662 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
663
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000664 close_on_exec_on(ld->fdcur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000665 while (fchmod(ld->fdcur, 0644) == -1)
666 pause2cannot("set mode of current", ld->name);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000667
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000668 if (verbose) {
669 if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
670 else bb_error_msg(INFO"new: %s/current", ld->name);
671 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000672
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000673 while (fchdir(fdwdir) == -1)
674 pause1cannot("change to initial working directory");
675 return 1;
676}
677
678static void logdirs_reopen(void)
679{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000680 int l;
681 int ok = 0;
682
683 tmaxflag = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000684 for (l = 0; l < dirn; ++l) {
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000685 logdir_close(&dir[l]);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000686 if (logdir_open(&dir[l], fndir[l]))
687 ok = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000688 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000689 if (!ok)
690 fatalx("no functional log directories");
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000691}
692
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000693/* Will look good in libbb one day */
694static ssize_t ndelay_read(int fd, void *buf, size_t count)
695{
696 if (!(fl_flag_0 & O_NONBLOCK))
697 fcntl(fd, F_SETFL, fl_flag_0 | O_NONBLOCK);
698 count = safe_read(fd, buf, count);
699 if (!(fl_flag_0 & O_NONBLOCK))
700 fcntl(fd, F_SETFL, fl_flag_0);
701 return count;
702}
703
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000704/* Used for reading stdin */
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000705static int buffer_pread(/*int fd, */char *s, unsigned len)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000706{
Denis Vlasenko45946f82007-08-20 17:27:40 +0000707 unsigned now;
708 struct pollfd input;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000709 int i;
710
Denis Vlasenko45946f82007-08-20 17:27:40 +0000711 input.fd = 0;
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000712 input.events = POLLIN;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000713
Denis Vlasenkob9528352007-05-06 01:37:21 +0000714 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000715 if (rotateasap) {
716 for (i = 0; i < dirn; ++i)
717 rotate(dir + i);
718 rotateasap = 0;
719 }
720 if (exitasap) {
721 if (linecomplete)
722 return 0;
723 len = 1;
724 }
725 if (reopenasap) {
726 logdirs_reopen();
727 reopenasap = 0;
728 }
729 now = monotonic_sec();
730 nearest_rotate = now + (45 * 60 + 45);
731 for (i = 0; i < dirn; ++i) {
732 if (dir[i].rotate_period) {
733 if (LESS(dir[i].next_rotate, now))
734 rotate(dir + i);
735 if (LESS(dir[i].next_rotate, nearest_rotate))
736 nearest_rotate = dir[i].next_rotate;
737 }
738 }
739
Denis Vlasenko339936b2007-10-05 22:11:06 +0000740 sigprocmask(SIG_UNBLOCK, &blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000741 i = nearest_rotate - now;
742 if (i > 1000000)
743 i = 1000000;
744 if (i <= 0)
745 i = 1;
746 poll(&input, 1, i * 1000);
Denis Vlasenko339936b2007-10-05 22:11:06 +0000747 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000748
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +0000749 i = ndelay_read(STDIN_FILENO, s, len);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000750 if (i >= 0)
751 break;
752 if (errno == EINTR)
753 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000754 if (errno != EAGAIN) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000755 warn("can't read standard input");
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000756 break;
757 }
758 /* else: EAGAIN - normal, repeat silently */
Denis Vlasenkob9528352007-05-06 01:37:21 +0000759 } while (!exitasap);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000760
761 if (i > 0) {
762 int cnt;
763 linecomplete = (s[i-1] == '\n');
Denis Vlasenko45946f82007-08-20 17:27:40 +0000764 if (!repl)
765 return i;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000766
767 cnt = i;
768 while (--cnt >= 0) {
769 char ch = *s;
770 if (ch != '\n') {
771 if (ch < 32 || ch > 126)
772 *s = repl;
773 else {
774 int j;
775 for (j = 0; replace[j]; ++j) {
776 if (ch == replace[j]) {
777 *s = repl;
778 break;
779 }
780 }
781 }
782 }
783 s++;
784 }
785 }
786 return i;
787}
788
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000789static void sig_term_handler(int sig_no UNUSED_PARAM)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000790{
791 if (verbose)
792 bb_error_msg(INFO"sig%s received", "term");
793 exitasap = 1;
794}
795
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000796static void sig_child_handler(int sig_no UNUSED_PARAM)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000797{
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000798 pid_t pid;
799 int l;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000800
801 if (verbose)
802 bb_error_msg(INFO"sig%s received", "child");
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000803 while ((pid = wait_any_nohang(&wstat)) > 0) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000804 for (l = 0; l < dirn; ++l) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000805 if (dir[l].ppid == pid) {
806 dir[l].ppid = 0;
807 processorstop(&dir[l]);
808 break;
809 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000810 }
811 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000812}
813
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000814static void sig_alarm_handler(int sig_no UNUSED_PARAM)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000815{
816 if (verbose)
817 bb_error_msg(INFO"sig%s received", "alarm");
818 rotateasap = 1;
819}
820
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000821static void sig_hangup_handler(int sig_no UNUSED_PARAM)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000822{
823 if (verbose)
824 bb_error_msg(INFO"sig%s received", "hangup");
825 reopenasap = 1;
826}
827
828static void logmatch(struct logdir *ld)
829{
830 char *s;
831
832 ld->match = '+';
833 ld->matcherr = 'E';
834 s = ld->inst;
835 while (s && s[0]) {
836 switch (s[0]) {
837 case '+':
838 case '-':
839 if (pmatch(s+1, line, linelen))
840 ld->match = s[0];
841 break;
842 case 'e':
843 case 'E':
844 if (pmatch(s+1, line, linelen))
845 ld->matcherr = s[0];
846 break;
847 }
848 s += strlen(s) + 1;
849 }
850}
851
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000852int svlogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000853int svlogd_main(int argc, char **argv)
854{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000855 char *r,*l,*b;
856 ssize_t stdin_cnt = 0;
857 int i;
858 unsigned opt;
859 unsigned timestamp = 0;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000860 void* (*memRchr)(const void *, int, size_t) = memchr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000861
Denis Vlasenko339936b2007-10-05 22:11:06 +0000862 INIT_G();
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000863
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000864 opt_complementary = "tt:vv";
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000865 opt = getopt32(argv, "r:R:l:b:tv",
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000866 &r, &replace, &l, &b, &timestamp, &verbose);
867 if (opt & 1) { // -r
868 repl = r[0];
869 if (!repl || r[1]) usage();
870 }
871 if (opt & 2) if (!repl) repl = '_'; // -R
872 if (opt & 4) { // -l
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000873 linemax = xatou_range(l, 0, BUFSIZ-26);
874 if (linemax == 0) linemax = BUFSIZ-26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000875 if (linemax < 256) linemax = 256;
876 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000877 ////if (opt & 8) { // -b
878 //// buflen = xatoi_u(b);
879 //// if (buflen == 0) buflen = 1024;
880 ////}
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000881 //if (opt & 0x10) timestamp++; // -t
882 //if (opt & 0x20) verbose++; // -v
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000883 //if (timestamp > 2) timestamp = 2;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000884 argv += optind;
885 argc -= optind;
886
887 dirn = argc;
888 if (dirn <= 0) usage();
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000889 ////if (buflen <= linemax) usage();
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000890 fdwdir = xopen(".", O_RDONLY|O_NDELAY);
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000891 close_on_exec_on(fdwdir);
Denis Vlasenkob9528352007-05-06 01:37:21 +0000892 dir = xzalloc(dirn * sizeof(struct logdir));
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000893 for (i = 0; i < dirn; ++i) {
894 dir[i].fddir = -1;
895 dir[i].fdcur = -1;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000896 ////dir[i].btmp = xmalloc(buflen);
Denis Vlasenkob9528352007-05-06 01:37:21 +0000897 /*dir[i].ppid = 0;*/
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000898 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000899 /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000900 fndir = argv;
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000901 /* We cannot set NONBLOCK on fd #0 permanently - this setting
902 * _isn't_ per-process! It is shared among all other processes
903 * with the same stdin */
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000904 fl_flag_0 = fcntl(0, F_GETFL);
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000905
Denis Vlasenko339936b2007-10-05 22:11:06 +0000906 sigemptyset(&blocked_sigset);
907 sigaddset(&blocked_sigset, SIGTERM);
908 sigaddset(&blocked_sigset, SIGCHLD);
909 sigaddset(&blocked_sigset, SIGALRM);
910 sigaddset(&blocked_sigset, SIGHUP);
911 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
Denis Vlasenkocab28aa2009-01-31 01:02:07 +0000912 bb_signals_recursive_norestart(1 << SIGTERM, sig_term_handler);
913 bb_signals_recursive_norestart(1 << SIGCHLD, sig_child_handler);
914 bb_signals_recursive_norestart(1 << SIGALRM, sig_alarm_handler);
915 bb_signals_recursive_norestart(1 << SIGHUP, sig_hangup_handler);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000916
917 logdirs_reopen();
918
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000919 /* Without timestamps, we don't have to print each line
920 * separately, so we can look for _last_ newline, not first,
921 * thus batching writes */
922 if (!timestamp)
923 memRchr = memrchr;
924
Denis Vlasenko64392902007-02-03 00:53:43 +0000925 setvbuf(stderr, NULL, _IOFBF, linelen);
926
Denis Vlasenko4e1715f2007-01-28 14:51:32 +0000927 /* Each iteration processes one or more lines */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000928 while (1) {
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000929 char stamp[FMT_PTIME];
930 char *lineptr;
931 char *printptr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000932 char *np;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000933 int printlen;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000934 char ch;
935
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000936 lineptr = line;
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000937 if (timestamp)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000938 lineptr += 26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000939
940 /* lineptr[0..linemax-1] - buffer for stdin */
941 /* (possibly has some unprocessed data from prev loop) */
942
943 /* Refill the buffer if needed */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000944 np = memRchr(lineptr, '\n', stdin_cnt);
945 if (!np && !exitasap) {
946 i = linemax - stdin_cnt; /* avail. bytes at tail */
947 if (i >= 128) {
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000948 i = buffer_pread(/*0, */lineptr + stdin_cnt, i);
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000949 if (i <= 0) /* EOF or error on stdin */
950 exitasap = 1;
951 else {
952 np = memRchr(lineptr + stdin_cnt, '\n', i);
953 stdin_cnt += i;
954 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000955 }
956 }
957 if (stdin_cnt <= 0 && exitasap)
958 break;
959
960 /* Search for '\n' (in fact, np already holds the result) */
961 linelen = stdin_cnt;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000962 if (np) {
963 print_to_nl: /* NB: starting from here lineptr may point
964 * farther out into line[] */
965 linelen = np - lineptr + 1;
966 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000967 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
968 ch = lineptr[linelen-1];
969
Denis Vlasenko64392902007-02-03 00:53:43 +0000970 /* Biggest performance hit was coming from the fact
971 * that we did not buffer writes. We were reading many lines
972 * in one read() above, but wrote one line per write().
973 * We are using stdio to fix that */
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000974
975 /* write out lineptr[0..linelen-1] to each log destination
976 * (or lineptr[-26..linelen-1] if timestamping) */
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000977 printlen = linelen;
978 printptr = lineptr;
979 if (timestamp) {
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000980 if (timestamp == 1)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000981 fmt_time_bernstein_25(stamp);
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000982 else /* 2: */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000983 fmt_time_human_30nul(stamp);
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000984 printlen += 26;
985 printptr -= 26;
986 memcpy(printptr, stamp, 25);
987 printptr[25] = ' ';
988 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000989 for (i = 0; i < dirn; ++i) {
990 struct logdir *ld = &dir[i];
991 if (ld->fddir == -1) continue;
992 if (ld->inst)
993 logmatch(ld);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +0000994 if (ld->matcherr == 'e') {
995 /* runit-1.8.0 compat: if timestamping, do it on stderr too */
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +0000996 ////full_write(STDERR_FILENO, printptr, printlen);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +0000997 fwrite(printptr, 1, printlen, stderr);
998 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000999 if (ld->match != '+') continue;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001000 buffer_pwrite(i, printptr, printlen);
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001001 }
1002
1003 /* If we didn't see '\n' (long input line), */
1004 /* read/write repeatedly until we see it */
1005 while (ch != '\n') {
1006 /* lineptr is emptied now, safe to use as buffer */
Denis Vlasenko5d61e712007-09-27 10:09:59 +00001007 stdin_cnt = exitasap ? -1 : buffer_pread(/*0, */lineptr, linemax);
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001008 if (stdin_cnt <= 0) { /* EOF or error on stdin */
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001009 exitasap = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001010 lineptr[0] = ch = '\n';
1011 linelen = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001012 stdin_cnt = 1;
1013 } else {
1014 linelen = stdin_cnt;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001015 np = memRchr(lineptr, '\n', stdin_cnt);
1016 if (np)
1017 linelen = np - lineptr + 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001018 ch = lineptr[linelen-1];
1019 }
1020 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
1021 for (i = 0; i < dirn; ++i) {
1022 if (dir[i].fddir == -1) continue;
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001023 if (dir[i].matcherr == 'e') {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001024 ////full_write(STDERR_FILENO, lineptr, linelen);
Denis Vlasenko64392902007-02-03 00:53:43 +00001025 fwrite(lineptr, 1, linelen, stderr);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001026 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001027 if (dir[i].match != '+') continue;
1028 buffer_pwrite(i, lineptr, linelen);
1029 }
1030 }
1031
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001032 stdin_cnt -= linelen;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001033 if (stdin_cnt > 0) {
1034 lineptr += linelen;
1035 /* If we see another '\n', we don't need to read
1036 * next piece of input: can print what we have */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001037 np = memRchr(lineptr, '\n', stdin_cnt);
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001038 if (np)
1039 goto print_to_nl;
1040 /* Move unprocessed data to the front of line */
1041 memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1042 }
Denis Vlasenko64392902007-02-03 00:53:43 +00001043 fflush(NULL);////
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001044 }
1045
1046 for (i = 0; i < dirn; ++i) {
1047 if (dir[i].ppid)
1048 while (!processorstop(&dir[i]))
1049 /* repeat */;
1050 logdir_close(&dir[i]);
1051 }
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001052 return 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001053}