blob: c3ff4e9c1832aef439b4ebdd0348217e190ccd20 [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
Denys Vlasenkoaebb7422009-08-02 00:55:49 +020031/*
32Config files
33
34On startup, and after receiving a HUP signal, svlogd checks for each
35log directory log if the configuration file log/config exists,
36and if so, reads the file line by line and adjusts configuration
37for log as follows:
38
39If the line is empty, or starts with a #, it is ignored. A line
40of the form
41
42ssize
43 sets the maximum file size of current when svlogd should rotate
44 the current log file to size bytes. Default is 1000000.
45 If size is zero, svlogd doesnt rotate log files
46 You should set size to at least (2 * len).
47nnum
48 sets the number of old log files svlogd should maintain to num.
49 If svlogd sees more that num old log files in log after log file
50 rotation, it deletes the oldest one. Default is 10.
51 If num is zero, svlogd doesnt remove old log files.
52Nmin
53 sets the minimum number of old log files svlogd should maintain
54 to min. min must be less than num. If min is set, and svlogd
55 cannot write to current because the filesystem is full,
56 and it sees more than min old log files, it deletes the oldest one.
57ttimeout
58 sets the maximum age of the current log file when svlogd should
59 rotate the current log file to timeout seconds. If current
60 is timeout seconds old, and is not empty, svlogd forces log file rotation.
61!processor
62 tells svlogd to feed each recent log file through processor
63 (see above) on log file rotation. By default log files are not processed.
64ua.b.c.d[:port]
65 tells svlogd to transmit the first len characters of selected
66 log messages to the IP address a.b.c.d, port number port.
67 If port isnt set, the default port for syslog is used (514).
68 len can be set through the -l option, see below. If svlogd
69 has trouble sending udp packets, it writes error messages
70 to the log directory. Attention: logging through udp is unreliable,
71 and should be used in private networks only.
72Ua.b.c.d[:port]
73 is the same as the u line above, but the log messages are no longer
74 written to the log directory, but transmitted through udp only.
75 Error messages from svlogd concerning sending udp packages still go
76 to the log directory.
77pprefix
78 tells svlogd to prefix each line to be written to the log directory,
79 to standard error, or through UDP, with prefix.
80
81If a line starts with a -, +, e, or E, svlogd matches the first len characters
82of each log message against pattern and acts accordingly:
83
84-pattern
85 the log message is deselected.
86+pattern
87 the log message is selected.
88epattern
89 the log message is selected to be printed to standard error.
90Epattern
91 the log message is deselected to be printed to standard error.
92
93Initially each line is selected to be written to log/current. Deselected
94log messages are discarded from log. Initially each line is deselected
95to be written to standard err. Log messages selected for standard error
96are written to standard error.
97
98Pattern Matching
99
100svlogd matches a log message against the string pattern as follows:
101
102pattern is applied to the log message one character by one, starting
103with the first. A character not a star (*) and not a plus (+) matches itself.
104A plus matches the next character in pattern in the log message one
105or more times. A star before the end of pattern matches any string
106in the log message that does not include the next character in pattern.
107A star at the end of pattern matches any string.
108
109Timestamps optionally added by svlogd are not considered part
110of the log message.
111
112An svlogd pattern is not a regular expression. For example consider
113a log message like this
114
1152005-12-18_09:13:50.97618 tcpsvd: info: pid 1977 from 10.4.1.14
116
117The following pattern doesnt match
118
119-*pid*
120
121because the first star matches up to the first p in tcpsvd,
122and then the match fails because i is not s. To match this
123log message, you can use a pattern like this instead
124
125-*: *: pid *
126*/
127
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000128#include <sys/poll.h>
129#include <sys/file.h>
Denis Vlasenkob6adbf12007-05-26 19:00:18 +0000130#include "libbb.h"
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000131#include "runit_lib.h"
132
Denis Vlasenko45946f82007-08-20 17:27:40 +0000133#define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0)
134
135#define FMT_PTIME 30
136
Denis Vlasenko339936b2007-10-05 22:11:06 +0000137struct logdir {
Denis Vlasenko64392902007-02-03 00:53:43 +0000138 ////char *btmp;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000139 /* pattern list to match, in "aa\0bb\0\cc\0\0" form */
140 char *inst;
141 char *processor;
142 char *name;
143 unsigned size;
144 unsigned sizemax;
145 unsigned nmax;
146 unsigned nmin;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000147 unsigned rotate_period;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000148 int ppid;
149 int fddir;
150 int fdcur;
Denis Vlasenko64392902007-02-03 00:53:43 +0000151 FILE* filecur; ////
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000152 int fdlock;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000153 unsigned next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000154 char fnsave[FMT_PTIME];
155 char match;
156 char matcherr;
Denis Vlasenko339936b2007-10-05 22:11:06 +0000157};
158
159
160struct globals {
161 struct logdir *dir;
162 unsigned verbose;
163 int linemax;
164 ////int buflen;
165 int linelen;
166
167 int fdwdir;
168 char **fndir;
169 int wstat;
170 unsigned nearest_rotate;
171
Denys Vlasenkoaebb7422009-08-02 00:55:49 +0200172 void* (*memRchr)(const void *, int, size_t);
173
Denis Vlasenko339936b2007-10-05 22:11:06 +0000174 smallint exitasap;
175 smallint rotateasap;
176 smallint reopenasap;
177 smallint linecomplete;
178 smallint tmaxflag;
179
180 char repl;
181 const char *replace;
182 int fl_flag_0;
183 unsigned dirn;
184
185 sigset_t blocked_sigset;
186};
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100187#define G (*ptr_to_globals)
Denis Vlasenko339936b2007-10-05 22:11:06 +0000188#define dir (G.dir )
189#define verbose (G.verbose )
190#define linemax (G.linemax )
191#define buflen (G.buflen )
192#define linelen (G.linelen )
193#define fndir (G.fndir )
194#define fdwdir (G.fdwdir )
195#define wstat (G.wstat )
Denys Vlasenkoaebb7422009-08-02 00:55:49 +0200196#define memRchr (G.memRchr )
Denis Vlasenko339936b2007-10-05 22:11:06 +0000197#define nearest_rotate (G.nearest_rotate)
198#define exitasap (G.exitasap )
199#define rotateasap (G.rotateasap )
200#define reopenasap (G.reopenasap )
201#define linecomplete (G.linecomplete )
202#define tmaxflag (G.tmaxflag )
203#define repl (G.repl )
204#define replace (G.replace )
205#define blocked_sigset (G.blocked_sigset)
206#define fl_flag_0 (G.fl_flag_0 )
207#define dirn (G.dirn )
208#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000209 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenko339936b2007-10-05 22:11:06 +0000210 linemax = 1000; \
211 /*buflen = 1024;*/ \
212 linecomplete = 1; \
213 replace = ""; \
214} while (0)
215
216#define line bb_common_bufsiz1
217
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000218
219#define FATAL "fatal: "
220#define WARNING "warning: "
221#define PAUSE "pausing: "
222#define INFO "info: "
223
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000224static void fatalx(const char *m0)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000225{
226 bb_error_msg_and_die(FATAL"%s", m0);
227}
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000228static void warn(const char *m0)
229{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000230 bb_perror_msg(WARNING"%s", m0);
231}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000232static void warn2(const char *m0, const char *m1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000233{
234 bb_perror_msg(WARNING"%s: %s", m0, m1);
235}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000236static void warnx(const char *m0, const char *m1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000237{
238 bb_error_msg(WARNING"%s: %s", m0, m1);
239}
240static void pause_nomem(void)
241{
Denis Vlasenko8c783952007-01-27 22:21:52 +0000242 bb_error_msg(PAUSE"out of memory");
243 sleep(3);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000244}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000245static void pause1cannot(const char *m0)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000246{
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000247 bb_perror_msg(PAUSE"can't %s", m0);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000248 sleep(3);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000249}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000250static void pause2cannot(const char *m0, const char *m1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000251{
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000252 bb_perror_msg(PAUSE"can't %s %s", m0, m1);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000253 sleep(3);
254}
255
256static char* wstrdup(const char *str)
257{
258 char *s;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000259 while (!(s = strdup(str)))
260 pause_nomem();
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000261 return s;
262}
263
Denys Vlasenko05e86052010-10-13 12:53:27 +0200264static unsigned pmatch(const char *p, const char *s, unsigned len)
265{
266 for (;;) {
267 char c = *p++;
268 if (!c) return !len;
269 switch (c) {
270 case '*':
271 c = *p;
272 if (!c) return 1;
273 for (;;) {
274 if (!len) return 0;
275 if (*s == c) break;
276 ++s;
277 --len;
278 }
279 continue;
280 case '+':
281 c = *p++;
282 if (c != *s) return 0;
283 for (;;) {
284 if (!len) return 1;
285 if (*s != c) break;
286 ++s;
287 --len;
288 }
289 continue;
290 /*
291 case '?':
292 if (*p == '?') {
293 if (*s != '?') return 0;
294 ++p;
295 }
296 ++s; --len;
297 continue;
298 */
299 default:
300 if (!len) return 0;
301 if (*s != c) return 0;
302 ++s;
303 --len;
304 continue;
305 }
306 }
307 return 0;
308}
309
Denis Vlasenko45946f82007-08-20 17:27:40 +0000310/*** ex fmt_ptime.[ch] ***/
311
312/* NUL terminated */
313static void fmt_time_human_30nul(char *s)
314{
Denys Vlasenkodc698bb2010-01-09 19:10:49 +0100315 struct tm *ptm;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000316 struct timeval tv;
317
318 gettimeofday(&tv, NULL);
Denys Vlasenkodc698bb2010-01-09 19:10:49 +0100319 ptm = gmtime(&tv.tv_sec);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000320 sprintf(s, "%04u-%02u-%02u_%02u:%02u:%02u.%06u000",
Denys Vlasenkodc698bb2010-01-09 19:10:49 +0100321 (unsigned)(1900 + ptm->tm_year),
322 (unsigned)(ptm->tm_mon + 1),
323 (unsigned)(ptm->tm_mday),
324 (unsigned)(ptm->tm_hour),
325 (unsigned)(ptm->tm_min),
326 (unsigned)(ptm->tm_sec),
Denis Vlasenko45946f82007-08-20 17:27:40 +0000327 (unsigned)(tv.tv_usec)
328 );
329 /* 4+1 + 2+1 + 2+1 + 2+1 + 2+1 + 2+1 + 9 = */
330 /* 5 + 3 + 3 + 3 + 3 + 3 + 9 = */
331 /* 20 (up to '.' inclusive) + 9 (not including '\0') */
332}
333
334/* NOT terminated! */
335static void fmt_time_bernstein_25(char *s)
336{
337 uint32_t pack[3];
338 struct timeval tv;
339 unsigned sec_hi;
340
341 gettimeofday(&tv, NULL);
342 sec_hi = (0x400000000000000aULL + tv.tv_sec) >> 32;
343 tv.tv_sec = (time_t)(0x400000000000000aULL) + tv.tv_sec;
344 tv.tv_usec *= 1000;
345 /* Network order is big-endian: most significant byte first.
346 * This is exactly what we want here */
347 pack[0] = htonl(sec_hi);
348 pack[1] = htonl(tv.tv_sec);
349 pack[2] = htonl(tv.tv_usec);
350 *s++ = '@';
351 bin2hex(s, (char*)pack, 12);
352}
353
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000354static void processorstart(struct logdir *ld)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000355{
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000356 char sv_ch;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000357 int pid;
358
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000359 if (!ld->processor) return;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000360 if (ld->ppid) {
361 warnx("processor already running", ld->name);
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000362 return;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000363 }
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000364
365 /* vfork'ed child trashes this byte, save... */
366 sv_ch = ld->fnsave[26];
367
368 while ((pid = vfork()) == -1)
369 pause2cannot("vfork for processor", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000370 if (!pid) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000371 int fd;
372
373 /* child */
Denis Vlasenko3fa36e22008-11-09 00:15:11 +0000374 /* Non-ignored signals revert to SIG_DFL on exec anyway */
375 /*bb_signals(0
Denis Vlasenko25591c32008-02-16 22:58:56 +0000376 + (1 << SIGTERM)
377 + (1 << SIGALRM)
378 + (1 << SIGHUP)
Denis Vlasenko3fa36e22008-11-09 00:15:11 +0000379 , SIG_DFL);*/
Denis Vlasenko8c783952007-01-27 22:21:52 +0000380 sig_unblock(SIGTERM);
381 sig_unblock(SIGALRM);
382 sig_unblock(SIGHUP);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000383
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000384 if (verbose)
385 bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
386 fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000387 xmove_fd(fd, 0);
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000388 ld->fnsave[26] = 't'; /* <- that's why we need sv_ch! */
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000389 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000390 xmove_fd(fd, 1);
Denys Vlasenko05e86052010-10-13 12:53:27 +0200391 fd = open("state", O_RDONLY|O_NDELAY);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000392 if (fd == -1) {
393 if (errno != ENOENT)
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000394 bb_perror_msg_and_die(FATAL"can't %s processor %s", "open state for", ld->name);
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000395 close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000396 fd = xopen("state", O_RDONLY|O_NDELAY);
397 }
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000398 xmove_fd(fd, 4);
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000399 fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000400 xmove_fd(fd, 5);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000401
Denis Vlasenko8c783952007-01-27 22:21:52 +0000402// getenv("SHELL")?
Ladislav Michla73b87e2010-06-27 03:23:31 +0200403 execl(DEFAULT_SHELL, DEFAULT_SHELL_SHORT_NAME, "-c", ld->processor, (char*) NULL);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000404 bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000405 }
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000406 ld->fnsave[26] = sv_ch; /* ...restore */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000407 ld->ppid = pid;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000408}
409
410static unsigned processorstop(struct logdir *ld)
411{
412 char f[28];
413
414 if (ld->ppid) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000415 sig_unblock(SIGHUP);
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000416 while (safe_waitpid(ld->ppid, &wstat, 0) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000417 pause2cannot("wait for processor", ld->name);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000418 sig_block(SIGHUP);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000419 ld->ppid = 0;
420 }
Denys Vlasenkoaebb7422009-08-02 00:55:49 +0200421 if (ld->fddir == -1)
422 return 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000423 while (fchdir(ld->fddir) == -1)
424 pause2cannot("change directory, want processor", ld->name);
Denys Vlasenko8f24f982009-06-07 16:02:00 +0200425 if (WEXITSTATUS(wstat) != 0) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000426 warnx("processor failed, restart", ld->name);
427 ld->fnsave[26] = 't';
428 unlink(ld->fnsave);
429 ld->fnsave[26] = 'u';
430 processorstart(ld);
431 while (fchdir(fdwdir) == -1)
432 pause1cannot("change to initial working directory");
433 return ld->processor ? 0 : 1;
434 }
435 ld->fnsave[26] = 't';
436 memcpy(f, ld->fnsave, 26);
437 f[26] = 's';
438 f[27] = '\0';
439 while (rename(ld->fnsave, f) == -1)
440 pause2cannot("rename processed", ld->name);
441 while (chmod(f, 0744) == -1)
442 pause2cannot("set mode of processed", ld->name);
443 ld->fnsave[26] = 'u';
444 if (unlink(ld->fnsave) == -1)
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000445 bb_error_msg(WARNING"can't unlink: %s/%s", ld->name, ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000446 while (rename("newstate", "state") == -1)
447 pause2cannot("rename state", ld->name);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000448 if (verbose)
449 bb_error_msg(INFO"processed: %s/%s", ld->name, f);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000450 while (fchdir(fdwdir) == -1)
451 pause1cannot("change to initial working directory");
452 return 1;
453}
454
455static void rmoldest(struct logdir *ld)
456{
457 DIR *d;
458 struct dirent *f;
459 char oldest[FMT_PTIME];
460 int n = 0;
461
462 oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
463 while (!(d = opendir(".")))
464 pause2cannot("open directory, want rotate", ld->name);
465 errno = 0;
466 while ((f = readdir(d))) {
467 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
468 if (f->d_name[26] == 't') {
469 if (unlink(f->d_name) == -1)
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000470 warn2("can't unlink processor leftover", f->d_name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000471 } else {
472 ++n;
473 if (strcmp(f->d_name, oldest) < 0)
474 memcpy(oldest, f->d_name, 27);
475 }
476 errno = 0;
477 }
478 }
Denis Vlasenko8c783952007-01-27 22:21:52 +0000479 if (errno)
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000480 warn2("can't read directory", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000481 closedir(d);
482
483 if (ld->nmax && (n > ld->nmax)) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000484 if (verbose)
485 bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000486 if ((*oldest == '@') && (unlink(oldest) == -1))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000487 warn2("can't unlink oldest logfile", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000488 }
489}
490
491static unsigned rotate(struct logdir *ld)
492{
493 struct stat st;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000494 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000495
496 if (ld->fddir == -1) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000497 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000498 return 0;
499 }
500 if (ld->ppid)
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000501 while (!processorstop(ld))
Denis Vlasenko45946f82007-08-20 17:27:40 +0000502 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000503
504 while (fchdir(ld->fddir) == -1)
505 pause2cannot("change directory, want rotate", ld->name);
506
507 /* create new filename */
508 ld->fnsave[25] = '.';
509 ld->fnsave[26] = 's';
510 if (ld->processor)
511 ld->fnsave[26] = 'u';
512 ld->fnsave[27] = '\0';
513 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000514 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000515 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000516 stat(ld->fnsave, &st);
517 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000518
Denis Vlasenko45946f82007-08-20 17:27:40 +0000519 now = monotonic_sec();
520 if (ld->rotate_period && LESS(ld->next_rotate, now)) {
521 ld->next_rotate = now + ld->rotate_period;
522 if (LESS(ld->next_rotate, nearest_rotate))
523 nearest_rotate = ld->next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000524 }
525
526 if (ld->size > 0) {
Denis Vlasenko64392902007-02-03 00:53:43 +0000527 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000528 pause2cannot("fsync current logfile", ld->name);
529 while (fchmod(ld->fdcur, 0744) == -1)
530 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000531 ////close(ld->fdcur);
532 fclose(ld->filecur);
533
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000534 if (verbose) {
535 bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
536 ld->fnsave, ld->size);
537 }
538 while (rename("current", ld->fnsave) == -1)
539 pause2cannot("rename current", ld->name);
540 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
541 pause2cannot("create new current", ld->name);
Denys Vlasenkoc5d07fb2009-07-03 18:31:23 +0200542 while ((ld->filecur = fdopen(ld->fdcur, "a")) == NULL) ////
543 pause2cannot("create new current", ld->name); /* very unlikely */
Denis Vlasenko64392902007-02-03 00:53:43 +0000544 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000545 close_on_exec_on(ld->fdcur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000546 ld->size = 0;
547 while (fchmod(ld->fdcur, 0644) == -1)
548 pause2cannot("set mode of current", ld->name);
Denys Vlasenkoc5d07fb2009-07-03 18:31:23 +0200549
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000550 rmoldest(ld);
551 processorstart(ld);
552 }
553
554 while (fchdir(fdwdir) == -1)
555 pause1cannot("change to initial working directory");
556 return 1;
557}
558
559static int buffer_pwrite(int n, char *s, unsigned len)
560{
561 int i;
562 struct logdir *ld = &dir[n];
563
564 if (ld->sizemax) {
565 if (ld->size >= ld->sizemax)
566 rotate(ld);
567 if (len > (ld->sizemax - ld->size))
568 len = ld->sizemax - ld->size;
569 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000570 while (1) {
571 ////i = full_write(ld->fdcur, s, len);
572 ////if (i != -1) break;
573 i = fwrite(s, 1, len, ld->filecur);
574 if (i == len) break;
575
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000576 if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
577 DIR *d;
578 struct dirent *f;
579 char oldest[FMT_PTIME];
580 int j = 0;
581
582 while (fchdir(ld->fddir) == -1)
583 pause2cannot("change directory, want remove old logfile",
584 ld->name);
585 oldest[0] = 'A';
586 oldest[1] = oldest[27] = '\0';
587 while (!(d = opendir(".")))
588 pause2cannot("open directory, want remove old logfile",
589 ld->name);
590 errno = 0;
591 while ((f = readdir(d)))
592 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
593 ++j;
594 if (strcmp(f->d_name, oldest) < 0)
595 memcpy(oldest, f->d_name, 27);
596 }
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000597 if (errno) warn2("can't read directory, want remove old logfile",
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000598 ld->name);
599 closedir(d);
600 errno = ENOSPC;
601 if (j > ld->nmin) {
602 if (*oldest == '@') {
603 bb_error_msg(WARNING"out of disk space, delete: %s/%s",
604 ld->name, oldest);
605 errno = 0;
606 if (unlink(oldest) == -1) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000607 warn2("can't unlink oldest logfile", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000608 errno = ENOSPC;
609 }
610 while (fchdir(fdwdir) == -1)
611 pause1cannot("change to initial working directory");
612 }
613 }
614 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000615 if (errno)
616 pause2cannot("write to current", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000617 }
618
619 ld->size += i;
620 if (ld->sizemax)
621 if (s[i-1] == '\n')
622 if (ld->size >= (ld->sizemax - linemax))
623 rotate(ld);
624 return i;
625}
626
627static void logdir_close(struct logdir *ld)
628{
629 if (ld->fddir == -1)
630 return;
631 if (verbose)
632 bb_error_msg(INFO"close: %s", ld->name);
633 close(ld->fddir);
634 ld->fddir = -1;
635 if (ld->fdcur == -1)
636 return; /* impossible */
Denis Vlasenko64392902007-02-03 00:53:43 +0000637 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000638 pause2cannot("fsync current logfile", ld->name);
639 while (fchmod(ld->fdcur, 0744) == -1)
640 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000641 ////close(ld->fdcur);
642 fclose(ld->filecur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000643 ld->fdcur = -1;
644 if (ld->fdlock == -1)
645 return; /* impossible */
646 close(ld->fdlock);
647 ld->fdlock = -1;
648 free(ld->processor);
649 ld->processor = NULL;
650}
651
Denys Vlasenkoa7bb3c12009-10-08 12:28:08 +0200652static NOINLINE unsigned logdir_open(struct logdir *ld, const char *fn)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000653{
654 char buf[128];
Denis Vlasenko45946f82007-08-20 17:27:40 +0000655 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000656 char *new, *s, *np;
657 int i;
658 struct stat st;
659
Denis Vlasenko45946f82007-08-20 17:27:40 +0000660 now = monotonic_sec();
661
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000662 ld->fddir = open(fn, O_RDONLY|O_NDELAY);
663 if (ld->fddir == -1) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000664 warn2("can't open log directory", (char*)fn);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000665 return 0;
666 }
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000667 close_on_exec_on(ld->fddir);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000668 if (fchdir(ld->fddir) == -1) {
669 logdir_close(ld);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000670 warn2("can't change directory", (char*)fn);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000671 return 0;
672 }
673 ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
674 if ((ld->fdlock == -1)
Denys Vlasenko05e86052010-10-13 12:53:27 +0200675 || (flock(ld->fdlock, LOCK_EX | LOCK_NB) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000676 ) {
677 logdir_close(ld);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000678 warn2("can't lock directory", (char*)fn);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000679 while (fchdir(fdwdir) == -1)
680 pause1cannot("change to initial working directory");
681 return 0;
682 }
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000683 close_on_exec_on(ld->fdlock);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000684
685 ld->size = 0;
686 ld->sizemax = 1000000;
687 ld->nmax = ld->nmin = 10;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000688 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000689 ld->name = (char*)fn;
690 ld->ppid = 0;
691 ld->match = '+';
692 free(ld->inst); ld->inst = NULL;
693 free(ld->processor); ld->processor = NULL;
694
695 /* read config */
Denys Vlasenkoc5d07fb2009-07-03 18:31:23 +0200696 i = open_read_close("config", buf, sizeof(buf) - 1);
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000697 if (i < 0 && errno != ENOENT)
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000698 bb_perror_msg(WARNING"%s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000699 if (i > 0) {
Denys Vlasenkoc5d07fb2009-07-03 18:31:23 +0200700 buf[i] = '\0';
Denis Vlasenko45946f82007-08-20 17:27:40 +0000701 if (verbose)
702 bb_error_msg(INFO"read: %s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000703 s = buf;
704 while (s) {
705 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000706 if (np)
707 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000708 switch (s[0]) {
709 case '+':
710 case '-':
711 case 'e':
712 case 'E':
Denys Vlasenkoaebb7422009-08-02 00:55:49 +0200713 /* Filtering requires one-line buffering,
714 * resetting the "find newline" function
715 * accordingly */
716 memRchr = memchr;
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000717 /* Add '\n'-terminated line to ld->inst */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000718 while (1) {
Denys Vlasenko90a99042009-09-06 02:36:23 +0200719 int l = asprintf(&new, "%s%s\n", ld->inst ? ld->inst : "", s);
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000720 if (l >= 0 && new)
721 break;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000722 pause_nomem();
723 }
724 free(ld->inst);
725 ld->inst = new;
726 break;
727 case 's': {
728 static const struct suffix_mult km_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000729 { "k", 1024 },
730 { "m", 1024*1024 },
Denys Vlasenko043b1e52009-09-06 12:47:55 +0200731 { "", 0 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000732 };
733 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
734 break;
735 }
736 case 'n':
Denys Vlasenko77832482010-08-12 14:14:45 +0200737 ld->nmax = xatoi_positive(&s[1]);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000738 break;
739 case 'N':
Denys Vlasenko77832482010-08-12 14:14:45 +0200740 ld->nmin = xatoi_positive(&s[1]);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000741 break;
742 case 't': {
743 static const struct suffix_mult mh_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000744 { "m", 60 },
745 { "h", 60*60 },
746 /*{ "d", 24*60*60 },*/
Denys Vlasenko043b1e52009-09-06 12:47:55 +0200747 { "", 0 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000748 };
Denis Vlasenko45946f82007-08-20 17:27:40 +0000749 ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
750 if (ld->rotate_period) {
751 ld->next_rotate = now + ld->rotate_period;
752 if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate))
753 nearest_rotate = ld->next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000754 tmaxflag = 1;
755 }
756 break;
757 }
758 case '!':
759 if (s[1]) {
760 free(ld->processor);
761 ld->processor = wstrdup(s);
762 }
763 break;
764 }
765 s = np;
766 }
767 /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
768 s = ld->inst;
769 while (s) {
770 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000771 if (np)
772 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000773 s = np;
774 }
775 }
776
777 /* open current */
778 i = stat("current", &st);
779 if (i != -1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000780 if (st.st_size && !(st.st_mode & S_IXUSR)) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000781 ld->fnsave[25] = '.';
782 ld->fnsave[26] = 'u';
783 ld->fnsave[27] = '\0';
784 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000785 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000786 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000787 stat(ld->fnsave, &st);
788 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000789 while (rename("current", ld->fnsave) == -1)
790 pause2cannot("rename current", ld->name);
791 rmoldest(ld);
792 i = -1;
793 } else {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000794 /* st.st_size can be not just bigger, but WIDER!
795 * This code is safe: if st.st_size > 4GB, we select
796 * ld->sizemax (because it's "unsigned") */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000797 ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
798 }
799 } else {
800 if (errno != ENOENT) {
801 logdir_close(ld);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000802 warn2("can't stat current", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000803 while (fchdir(fdwdir) == -1)
804 pause1cannot("change to initial working directory");
805 return 0;
806 }
807 }
808 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
809 pause2cannot("open current", ld->name);
Denys Vlasenkoa7ccdee2009-11-15 23:28:11 +0100810 while ((ld->filecur = fdopen(ld->fdcur, "a")) == NULL)
811 pause2cannot("open current", ld->name); ////
Denis Vlasenko64392902007-02-03 00:53:43 +0000812 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
813
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000814 close_on_exec_on(ld->fdcur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000815 while (fchmod(ld->fdcur, 0644) == -1)
816 pause2cannot("set mode of current", ld->name);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000817
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000818 if (verbose) {
819 if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
820 else bb_error_msg(INFO"new: %s/current", ld->name);
821 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000822
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000823 while (fchdir(fdwdir) == -1)
824 pause1cannot("change to initial working directory");
825 return 1;
826}
827
828static void logdirs_reopen(void)
829{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000830 int l;
831 int ok = 0;
832
833 tmaxflag = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000834 for (l = 0; l < dirn; ++l) {
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000835 logdir_close(&dir[l]);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000836 if (logdir_open(&dir[l], fndir[l]))
837 ok = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000838 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000839 if (!ok)
840 fatalx("no functional log directories");
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000841}
842
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000843/* Will look good in libbb one day */
844static ssize_t ndelay_read(int fd, void *buf, size_t count)
845{
846 if (!(fl_flag_0 & O_NONBLOCK))
847 fcntl(fd, F_SETFL, fl_flag_0 | O_NONBLOCK);
848 count = safe_read(fd, buf, count);
849 if (!(fl_flag_0 & O_NONBLOCK))
850 fcntl(fd, F_SETFL, fl_flag_0);
851 return count;
852}
853
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000854/* Used for reading stdin */
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000855static int buffer_pread(/*int fd, */char *s, unsigned len)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000856{
Denis Vlasenko45946f82007-08-20 17:27:40 +0000857 unsigned now;
858 struct pollfd input;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000859 int i;
860
Denys Vlasenkoaebb7422009-08-02 00:55:49 +0200861 input.fd = STDIN_FILENO;
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000862 input.events = POLLIN;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000863
Denis Vlasenkob9528352007-05-06 01:37:21 +0000864 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000865 if (rotateasap) {
866 for (i = 0; i < dirn; ++i)
867 rotate(dir + i);
868 rotateasap = 0;
869 }
870 if (exitasap) {
871 if (linecomplete)
872 return 0;
873 len = 1;
874 }
875 if (reopenasap) {
876 logdirs_reopen();
877 reopenasap = 0;
878 }
879 now = monotonic_sec();
880 nearest_rotate = now + (45 * 60 + 45);
881 for (i = 0; i < dirn; ++i) {
882 if (dir[i].rotate_period) {
883 if (LESS(dir[i].next_rotate, now))
884 rotate(dir + i);
885 if (LESS(dir[i].next_rotate, nearest_rotate))
886 nearest_rotate = dir[i].next_rotate;
887 }
888 }
889
Denis Vlasenko339936b2007-10-05 22:11:06 +0000890 sigprocmask(SIG_UNBLOCK, &blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000891 i = nearest_rotate - now;
892 if (i > 1000000)
893 i = 1000000;
894 if (i <= 0)
895 i = 1;
896 poll(&input, 1, i * 1000);
Denis Vlasenko339936b2007-10-05 22:11:06 +0000897 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000898
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +0000899 i = ndelay_read(STDIN_FILENO, s, len);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000900 if (i >= 0)
901 break;
902 if (errno == EINTR)
903 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000904 if (errno != EAGAIN) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000905 warn("can't read standard input");
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000906 break;
907 }
908 /* else: EAGAIN - normal, repeat silently */
Denis Vlasenkob9528352007-05-06 01:37:21 +0000909 } while (!exitasap);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000910
911 if (i > 0) {
912 int cnt;
913 linecomplete = (s[i-1] == '\n');
Denis Vlasenko45946f82007-08-20 17:27:40 +0000914 if (!repl)
915 return i;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000916
917 cnt = i;
918 while (--cnt >= 0) {
919 char ch = *s;
920 if (ch != '\n') {
921 if (ch < 32 || ch > 126)
922 *s = repl;
923 else {
924 int j;
925 for (j = 0; replace[j]; ++j) {
926 if (ch == replace[j]) {
927 *s = repl;
928 break;
929 }
930 }
931 }
932 }
933 s++;
934 }
935 }
936 return i;
937}
938
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000939static void sig_term_handler(int sig_no UNUSED_PARAM)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000940{
941 if (verbose)
942 bb_error_msg(INFO"sig%s received", "term");
943 exitasap = 1;
944}
945
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000946static void sig_child_handler(int sig_no UNUSED_PARAM)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000947{
Denis Vlasenko3854c5d2008-11-06 22:39:57 +0000948 pid_t pid;
949 int l;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000950
951 if (verbose)
952 bb_error_msg(INFO"sig%s received", "child");
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000953 while ((pid = wait_any_nohang(&wstat)) > 0) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000954 for (l = 0; l < dirn; ++l) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000955 if (dir[l].ppid == pid) {
956 dir[l].ppid = 0;
957 processorstop(&dir[l]);
958 break;
959 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000960 }
961 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000962}
963
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000964static void sig_alarm_handler(int sig_no UNUSED_PARAM)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000965{
966 if (verbose)
967 bb_error_msg(INFO"sig%s received", "alarm");
968 rotateasap = 1;
969}
970
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000971static void sig_hangup_handler(int sig_no UNUSED_PARAM)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000972{
973 if (verbose)
974 bb_error_msg(INFO"sig%s received", "hangup");
975 reopenasap = 1;
976}
977
978static void logmatch(struct logdir *ld)
979{
980 char *s;
981
982 ld->match = '+';
983 ld->matcherr = 'E';
984 s = ld->inst;
985 while (s && s[0]) {
986 switch (s[0]) {
987 case '+':
988 case '-':
989 if (pmatch(s+1, line, linelen))
990 ld->match = s[0];
991 break;
992 case 'e':
993 case 'E':
994 if (pmatch(s+1, line, linelen))
995 ld->matcherr = s[0];
996 break;
997 }
998 s += strlen(s) + 1;
999 }
1000}
1001
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001002int svlogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001003int svlogd_main(int argc, char **argv)
1004{
Denys Vlasenkoaebb7422009-08-02 00:55:49 +02001005 char *r, *l, *b;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001006 ssize_t stdin_cnt = 0;
1007 int i;
1008 unsigned opt;
1009 unsigned timestamp = 0;
1010
Denis Vlasenko339936b2007-10-05 22:11:06 +00001011 INIT_G();
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001012
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001013 opt_complementary = "tt:vv";
Denis Vlasenkofe7cd642007-08-18 15:32:12 +00001014 opt = getopt32(argv, "r:R:l:b:tv",
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001015 &r, &replace, &l, &b, &timestamp, &verbose);
1016 if (opt & 1) { // -r
1017 repl = r[0];
Denys Vlasenkoaebb7422009-08-02 00:55:49 +02001018 if (!repl || r[1])
1019 bb_show_usage();
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001020 }
1021 if (opt & 2) if (!repl) repl = '_'; // -R
1022 if (opt & 4) { // -l
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001023 linemax = xatou_range(l, 0, BUFSIZ-26);
Denys Vlasenkoaebb7422009-08-02 00:55:49 +02001024 if (linemax == 0)
1025 linemax = BUFSIZ-26;
1026 if (linemax < 256)
1027 linemax = 256;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001028 }
Denis Vlasenko64392902007-02-03 00:53:43 +00001029 ////if (opt & 8) { // -b
Denys Vlasenko77832482010-08-12 14:14:45 +02001030 //// buflen = xatoi_positive(b);
Denis Vlasenko64392902007-02-03 00:53:43 +00001031 //// if (buflen == 0) buflen = 1024;
1032 ////}
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001033 //if (opt & 0x10) timestamp++; // -t
1034 //if (opt & 0x20) verbose++; // -v
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001035 //if (timestamp > 2) timestamp = 2;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001036 argv += optind;
1037 argc -= optind;
1038
1039 dirn = argc;
Denys Vlasenkoaebb7422009-08-02 00:55:49 +02001040 if (dirn <= 0)
1041 bb_show_usage();
1042 ////if (buflen <= linemax) bb_show_usage();
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001043 fdwdir = xopen(".", O_RDONLY|O_NDELAY);
Denis Vlasenko96e1b382007-09-30 23:50:48 +00001044 close_on_exec_on(fdwdir);
Denys Vlasenkoaebb7422009-08-02 00:55:49 +02001045 dir = xzalloc(dirn * sizeof(dir[0]));
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001046 for (i = 0; i < dirn; ++i) {
1047 dir[i].fddir = -1;
1048 dir[i].fdcur = -1;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001049 ////dir[i].btmp = xmalloc(buflen);
Denis Vlasenkob9528352007-05-06 01:37:21 +00001050 /*dir[i].ppid = 0;*/
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001051 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001052 /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001053 fndir = argv;
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +00001054 /* We cannot set NONBLOCK on fd #0 permanently - this setting
1055 * _isn't_ per-process! It is shared among all other processes
1056 * with the same stdin */
Denis Vlasenkod37f2222007-08-19 13:42:08 +00001057 fl_flag_0 = fcntl(0, F_GETFL);
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +00001058
Denis Vlasenko339936b2007-10-05 22:11:06 +00001059 sigemptyset(&blocked_sigset);
1060 sigaddset(&blocked_sigset, SIGTERM);
1061 sigaddset(&blocked_sigset, SIGCHLD);
1062 sigaddset(&blocked_sigset, SIGALRM);
1063 sigaddset(&blocked_sigset, SIGHUP);
1064 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
Denis Vlasenkocab28aa2009-01-31 01:02:07 +00001065 bb_signals_recursive_norestart(1 << SIGTERM, sig_term_handler);
1066 bb_signals_recursive_norestart(1 << SIGCHLD, sig_child_handler);
1067 bb_signals_recursive_norestart(1 << SIGALRM, sig_alarm_handler);
1068 bb_signals_recursive_norestart(1 << SIGHUP, sig_hangup_handler);
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001069
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001070 /* Without timestamps, we don't have to print each line
1071 * separately, so we can look for _last_ newline, not first,
Denys Vlasenkoaebb7422009-08-02 00:55:49 +02001072 * thus batching writes. If filtering is enabled in config,
1073 * logdirs_reopen resets it to memchr.
1074 */
1075 memRchr = (timestamp ? memchr : memrchr);
1076
1077 logdirs_reopen();
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001078
Denis Vlasenko64392902007-02-03 00:53:43 +00001079 setvbuf(stderr, NULL, _IOFBF, linelen);
1080
Denis Vlasenko4e1715f2007-01-28 14:51:32 +00001081 /* Each iteration processes one or more lines */
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001082 while (1) {
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001083 char stamp[FMT_PTIME];
1084 char *lineptr;
1085 char *printptr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001086 char *np;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001087 int printlen;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001088 char ch;
1089
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001090 lineptr = line;
Denis Vlasenkof223efb2007-08-03 10:58:12 +00001091 if (timestamp)
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001092 lineptr += 26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001093
1094 /* lineptr[0..linemax-1] - buffer for stdin */
1095 /* (possibly has some unprocessed data from prev loop) */
1096
1097 /* Refill the buffer if needed */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001098 np = memRchr(lineptr, '\n', stdin_cnt);
1099 if (!np && !exitasap) {
1100 i = linemax - stdin_cnt; /* avail. bytes at tail */
1101 if (i >= 128) {
Denis Vlasenko5d61e712007-09-27 10:09:59 +00001102 i = buffer_pread(/*0, */lineptr + stdin_cnt, i);
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001103 if (i <= 0) /* EOF or error on stdin */
1104 exitasap = 1;
1105 else {
1106 np = memRchr(lineptr + stdin_cnt, '\n', i);
1107 stdin_cnt += i;
1108 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001109 }
1110 }
1111 if (stdin_cnt <= 0 && exitasap)
1112 break;
1113
1114 /* Search for '\n' (in fact, np already holds the result) */
1115 linelen = stdin_cnt;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001116 if (np) {
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001117 print_to_nl:
1118 /* NB: starting from here lineptr may point
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001119 * farther out into line[] */
1120 linelen = np - lineptr + 1;
1121 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001122 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
1123 ch = lineptr[linelen-1];
1124
Denis Vlasenko64392902007-02-03 00:53:43 +00001125 /* Biggest performance hit was coming from the fact
1126 * that we did not buffer writes. We were reading many lines
1127 * in one read() above, but wrote one line per write().
1128 * We are using stdio to fix that */
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +00001129
1130 /* write out lineptr[0..linelen-1] to each log destination
1131 * (or lineptr[-26..linelen-1] if timestamping) */
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001132 printlen = linelen;
1133 printptr = lineptr;
1134 if (timestamp) {
Denis Vlasenkof223efb2007-08-03 10:58:12 +00001135 if (timestamp == 1)
Denis Vlasenko45946f82007-08-20 17:27:40 +00001136 fmt_time_bernstein_25(stamp);
Denis Vlasenkof223efb2007-08-03 10:58:12 +00001137 else /* 2: */
Denis Vlasenko45946f82007-08-20 17:27:40 +00001138 fmt_time_human_30nul(stamp);
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001139 printlen += 26;
1140 printptr -= 26;
1141 memcpy(printptr, stamp, 25);
1142 printptr[25] = ' ';
1143 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001144 for (i = 0; i < dirn; ++i) {
1145 struct logdir *ld = &dir[i];
Denys Vlasenkoaebb7422009-08-02 00:55:49 +02001146 if (ld->fddir == -1)
1147 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001148 if (ld->inst)
1149 logmatch(ld);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001150 if (ld->matcherr == 'e') {
1151 /* runit-1.8.0 compat: if timestamping, do it on stderr too */
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001152 ////full_write(STDERR_FILENO, printptr, printlen);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001153 fwrite(printptr, 1, printlen, stderr);
1154 }
Denys Vlasenkoaebb7422009-08-02 00:55:49 +02001155 if (ld->match != '+')
1156 continue;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001157 buffer_pwrite(i, printptr, printlen);
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001158 }
1159
1160 /* If we didn't see '\n' (long input line), */
1161 /* read/write repeatedly until we see it */
1162 while (ch != '\n') {
1163 /* lineptr is emptied now, safe to use as buffer */
Denis Vlasenko5d61e712007-09-27 10:09:59 +00001164 stdin_cnt = exitasap ? -1 : buffer_pread(/*0, */lineptr, linemax);
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001165 if (stdin_cnt <= 0) { /* EOF or error on stdin */
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001166 exitasap = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001167 lineptr[0] = ch = '\n';
1168 linelen = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001169 stdin_cnt = 1;
1170 } else {
1171 linelen = stdin_cnt;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001172 np = memRchr(lineptr, '\n', stdin_cnt);
1173 if (np)
1174 linelen = np - lineptr + 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001175 ch = lineptr[linelen-1];
1176 }
1177 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
1178 for (i = 0; i < dirn; ++i) {
Denys Vlasenkoaebb7422009-08-02 00:55:49 +02001179 if (dir[i].fddir == -1)
1180 continue;
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001181 if (dir[i].matcherr == 'e') {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001182 ////full_write(STDERR_FILENO, lineptr, linelen);
Denis Vlasenko64392902007-02-03 00:53:43 +00001183 fwrite(lineptr, 1, linelen, stderr);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001184 }
Denys Vlasenkoaebb7422009-08-02 00:55:49 +02001185 if (dir[i].match != '+')
1186 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001187 buffer_pwrite(i, lineptr, linelen);
1188 }
1189 }
1190
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001191 stdin_cnt -= linelen;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001192 if (stdin_cnt > 0) {
1193 lineptr += linelen;
1194 /* If we see another '\n', we don't need to read
1195 * next piece of input: can print what we have */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001196 np = memRchr(lineptr, '\n', stdin_cnt);
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001197 if (np)
1198 goto print_to_nl;
1199 /* Move unprocessed data to the front of line */
1200 memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1201 }
Denys Vlasenko8131eea2009-11-02 14:19:51 +01001202 fflush_all();////
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001203 }
1204
1205 for (i = 0; i < dirn; ++i) {
1206 if (dir[i].ppid)
1207 while (!processorstop(&dir[i]))
Denys Vlasenkoaebb7422009-08-02 00:55:49 +02001208 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001209 logdir_close(&dir[i]);
1210 }
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001211 return 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001212}