blob: db3d4c5406bca394c79b05fe0baea0048c222ba6 [file] [log] [blame]
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001/*
2Copyright (c) 2001-2006, Gerrit Pape
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
Denis Vlasenkod18f52b2008-03-02 12:53:15 +000028/* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
Denis Vlasenko83ea6432006-11-16 02:27:24 +000029/* TODO: depends on runit_lib.c - review and reduce/eliminate */
30
31#include <sys/poll.h>
32#include <sys/file.h>
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000033#include "libbb.h"
Denis Vlasenko83ea6432006-11-16 02:27:24 +000034#include "runit_lib.h"
35
Denis Vlasenko45946f82007-08-20 17:27:40 +000036#define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0)
37
38#define FMT_PTIME 30
39
Denis Vlasenko339936b2007-10-05 22:11:06 +000040struct logdir {
Denis Vlasenko64392902007-02-03 00:53:43 +000041 ////char *btmp;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000042 /* pattern list to match, in "aa\0bb\0\cc\0\0" form */
43 char *inst;
44 char *processor;
45 char *name;
46 unsigned size;
47 unsigned sizemax;
48 unsigned nmax;
49 unsigned nmin;
Denis Vlasenko45946f82007-08-20 17:27:40 +000050 unsigned rotate_period;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000051 int ppid;
52 int fddir;
53 int fdcur;
Denis Vlasenko64392902007-02-03 00:53:43 +000054 FILE* filecur; ////
Denis Vlasenko83ea6432006-11-16 02:27:24 +000055 int fdlock;
Denis Vlasenko45946f82007-08-20 17:27:40 +000056 unsigned next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000057 char fnsave[FMT_PTIME];
58 char match;
59 char matcherr;
Denis Vlasenko339936b2007-10-05 22:11:06 +000060};
61
62
63struct globals {
64 struct logdir *dir;
65 unsigned verbose;
66 int linemax;
67 ////int buflen;
68 int linelen;
69
70 int fdwdir;
71 char **fndir;
72 int wstat;
73 unsigned nearest_rotate;
74
75 smallint exitasap;
76 smallint rotateasap;
77 smallint reopenasap;
78 smallint linecomplete;
79 smallint tmaxflag;
80
81 char repl;
82 const char *replace;
83 int fl_flag_0;
84 unsigned dirn;
85
86 sigset_t blocked_sigset;
87};
88#define G (*(struct globals*)ptr_to_globals)
89#define dir (G.dir )
90#define verbose (G.verbose )
91#define linemax (G.linemax )
92#define buflen (G.buflen )
93#define linelen (G.linelen )
94#define fndir (G.fndir )
95#define fdwdir (G.fdwdir )
96#define wstat (G.wstat )
97#define nearest_rotate (G.nearest_rotate)
98#define exitasap (G.exitasap )
99#define rotateasap (G.rotateasap )
100#define reopenasap (G.reopenasap )
101#define linecomplete (G.linecomplete )
102#define tmaxflag (G.tmaxflag )
103#define repl (G.repl )
104#define replace (G.replace )
105#define blocked_sigset (G.blocked_sigset)
106#define fl_flag_0 (G.fl_flag_0 )
107#define dirn (G.dirn )
108#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000109 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenko339936b2007-10-05 22:11:06 +0000110 linemax = 1000; \
111 /*buflen = 1024;*/ \
112 linecomplete = 1; \
113 replace = ""; \
114} while (0)
115
116#define line bb_common_bufsiz1
117
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000118
119#define FATAL "fatal: "
120#define WARNING "warning: "
121#define PAUSE "pausing: "
122#define INFO "info: "
123
124#define usage() bb_show_usage()
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000125static void fatalx(const char *m0)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000126{
127 bb_error_msg_and_die(FATAL"%s", m0);
128}
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000129static void warn(const char *m0)
130{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000131 bb_perror_msg(WARNING"%s", m0);
132}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000133static void warn2(const char *m0, const char *m1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000134{
135 bb_perror_msg(WARNING"%s: %s", m0, m1);
136}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000137static void warnx(const char *m0, const char *m1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000138{
139 bb_error_msg(WARNING"%s: %s", m0, m1);
140}
141static void pause_nomem(void)
142{
Denis Vlasenko8c783952007-01-27 22:21:52 +0000143 bb_error_msg(PAUSE"out of memory");
144 sleep(3);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000145}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000146static void pause1cannot(const char *m0)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000147{
Denis Vlasenko8c783952007-01-27 22:21:52 +0000148 bb_perror_msg(PAUSE"cannot %s", m0);
149 sleep(3);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000150}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000151static void pause2cannot(const char *m0, const char *m1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000152{
153 bb_perror_msg(PAUSE"cannot %s %s", m0, m1);
154 sleep(3);
155}
156
157static char* wstrdup(const char *str)
158{
159 char *s;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000160 while (!(s = strdup(str)))
161 pause_nomem();
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000162 return s;
163}
164
Denis Vlasenko45946f82007-08-20 17:27:40 +0000165/*** ex fmt_ptime.[ch] ***/
166
167/* NUL terminated */
168static void fmt_time_human_30nul(char *s)
169{
170 struct tm *t;
171 struct timeval tv;
172
173 gettimeofday(&tv, NULL);
174 t = gmtime(&(tv.tv_sec));
175 sprintf(s, "%04u-%02u-%02u_%02u:%02u:%02u.%06u000",
176 (unsigned)(1900 + t->tm_year),
177 (unsigned)(t->tm_mon + 1),
178 (unsigned)(t->tm_mday),
179 (unsigned)(t->tm_hour),
180 (unsigned)(t->tm_min),
181 (unsigned)(t->tm_sec),
182 (unsigned)(tv.tv_usec)
183 );
184 /* 4+1 + 2+1 + 2+1 + 2+1 + 2+1 + 2+1 + 9 = */
185 /* 5 + 3 + 3 + 3 + 3 + 3 + 9 = */
186 /* 20 (up to '.' inclusive) + 9 (not including '\0') */
187}
188
189/* NOT terminated! */
190static void fmt_time_bernstein_25(char *s)
191{
192 uint32_t pack[3];
193 struct timeval tv;
194 unsigned sec_hi;
195
196 gettimeofday(&tv, NULL);
197 sec_hi = (0x400000000000000aULL + tv.tv_sec) >> 32;
198 tv.tv_sec = (time_t)(0x400000000000000aULL) + tv.tv_sec;
199 tv.tv_usec *= 1000;
200 /* Network order is big-endian: most significant byte first.
201 * This is exactly what we want here */
202 pack[0] = htonl(sec_hi);
203 pack[1] = htonl(tv.tv_sec);
204 pack[2] = htonl(tv.tv_usec);
205 *s++ = '@';
206 bin2hex(s, (char*)pack, 12);
207}
208
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000209static void processorstart(struct logdir *ld)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000210{
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000211 char sv_ch;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000212 int pid;
213
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000214 if (!ld->processor) return;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000215 if (ld->ppid) {
216 warnx("processor already running", ld->name);
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000217 return;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000218 }
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000219
220 /* vfork'ed child trashes this byte, save... */
221 sv_ch = ld->fnsave[26];
222
223 while ((pid = vfork()) == -1)
224 pause2cannot("vfork for processor", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000225 if (!pid) {
226 char *prog[4];
227 int fd;
228
229 /* child */
Denis Vlasenko25591c32008-02-16 22:58:56 +0000230 bb_signals(0
231 + (1 << SIGTERM)
232 + (1 << SIGALRM)
233 + (1 << SIGHUP)
234 , 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)
249 bb_perror_msg_and_die(FATAL"cannot %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")?
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000258 prog[0] = (char*)"sh";
259 prog[1] = (char*)"-c";
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000260 prog[2] = ld->processor;
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000261 prog[3] = NULL;
Denis Vlasenko847fa772008-01-28 22:45:43 +0000262 execv("/bin/sh", prog);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000263 bb_perror_msg_and_die(FATAL"cannot %s processor %s", "run", ld->name);
264 }
Denis Vlasenko4ee7cd42008-03-17 09:13:22 +0000265 ld->fnsave[26] = sv_ch; /* ...restore */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000266 ld->ppid = pid;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000267}
268
269static unsigned processorstop(struct logdir *ld)
270{
271 char f[28];
272
273 if (ld->ppid) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000274 sig_unblock(SIGHUP);
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000275 while (safe_waitpid(ld->ppid, &wstat, 0) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000276 pause2cannot("wait for processor", ld->name);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000277 sig_block(SIGHUP);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000278 ld->ppid = 0;
279 }
280 if (ld->fddir == -1) return 1;
281 while (fchdir(ld->fddir) == -1)
282 pause2cannot("change directory, want processor", ld->name);
283 if (wait_exitcode(wstat) != 0) {
284 warnx("processor failed, restart", ld->name);
285 ld->fnsave[26] = 't';
286 unlink(ld->fnsave);
287 ld->fnsave[26] = 'u';
288 processorstart(ld);
289 while (fchdir(fdwdir) == -1)
290 pause1cannot("change to initial working directory");
291 return ld->processor ? 0 : 1;
292 }
293 ld->fnsave[26] = 't';
294 memcpy(f, ld->fnsave, 26);
295 f[26] = 's';
296 f[27] = '\0';
297 while (rename(ld->fnsave, f) == -1)
298 pause2cannot("rename processed", ld->name);
299 while (chmod(f, 0744) == -1)
300 pause2cannot("set mode of processed", ld->name);
301 ld->fnsave[26] = 'u';
302 if (unlink(ld->fnsave) == -1)
303 bb_error_msg(WARNING"cannot unlink: %s/%s", ld->name, ld->fnsave);
304 while (rename("newstate", "state") == -1)
305 pause2cannot("rename state", ld->name);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000306 if (verbose)
307 bb_error_msg(INFO"processed: %s/%s", ld->name, f);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000308 while (fchdir(fdwdir) == -1)
309 pause1cannot("change to initial working directory");
310 return 1;
311}
312
313static void rmoldest(struct logdir *ld)
314{
315 DIR *d;
316 struct dirent *f;
317 char oldest[FMT_PTIME];
318 int n = 0;
319
320 oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
321 while (!(d = opendir(".")))
322 pause2cannot("open directory, want rotate", ld->name);
323 errno = 0;
324 while ((f = readdir(d))) {
325 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
326 if (f->d_name[26] == 't') {
327 if (unlink(f->d_name) == -1)
328 warn2("cannot unlink processor leftover", f->d_name);
329 } else {
330 ++n;
331 if (strcmp(f->d_name, oldest) < 0)
332 memcpy(oldest, f->d_name, 27);
333 }
334 errno = 0;
335 }
336 }
Denis Vlasenko8c783952007-01-27 22:21:52 +0000337 if (errno)
338 warn2("cannot read directory", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000339 closedir(d);
340
341 if (ld->nmax && (n > ld->nmax)) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000342 if (verbose)
343 bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000344 if ((*oldest == '@') && (unlink(oldest) == -1))
345 warn2("cannot unlink oldest logfile", ld->name);
346 }
347}
348
349static unsigned rotate(struct logdir *ld)
350{
351 struct stat st;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000352 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000353
354 if (ld->fddir == -1) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000355 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000356 return 0;
357 }
358 if (ld->ppid)
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000359 while (!processorstop(ld))
Denis Vlasenko45946f82007-08-20 17:27:40 +0000360 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000361
362 while (fchdir(ld->fddir) == -1)
363 pause2cannot("change directory, want rotate", ld->name);
364
365 /* create new filename */
366 ld->fnsave[25] = '.';
367 ld->fnsave[26] = 's';
368 if (ld->processor)
369 ld->fnsave[26] = 'u';
370 ld->fnsave[27] = '\0';
371 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000372 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000373 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000374 stat(ld->fnsave, &st);
375 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000376
Denis Vlasenko45946f82007-08-20 17:27:40 +0000377 now = monotonic_sec();
378 if (ld->rotate_period && LESS(ld->next_rotate, now)) {
379 ld->next_rotate = now + ld->rotate_period;
380 if (LESS(ld->next_rotate, nearest_rotate))
381 nearest_rotate = ld->next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000382 }
383
384 if (ld->size > 0) {
Denis Vlasenko64392902007-02-03 00:53:43 +0000385 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000386 pause2cannot("fsync current logfile", ld->name);
387 while (fchmod(ld->fdcur, 0744) == -1)
388 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000389 ////close(ld->fdcur);
390 fclose(ld->filecur);
391
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000392 if (verbose) {
393 bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
394 ld->fnsave, ld->size);
395 }
396 while (rename("current", ld->fnsave) == -1)
397 pause2cannot("rename current", ld->name);
398 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
399 pause2cannot("create new current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000400 /* we presume this cannot fail */
401 ld->filecur = fdopen(ld->fdcur, "a"); ////
402 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000403 close_on_exec_on(ld->fdcur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000404 ld->size = 0;
405 while (fchmod(ld->fdcur, 0644) == -1)
406 pause2cannot("set mode of current", ld->name);
407 rmoldest(ld);
408 processorstart(ld);
409 }
410
411 while (fchdir(fdwdir) == -1)
412 pause1cannot("change to initial working directory");
413 return 1;
414}
415
416static int buffer_pwrite(int n, char *s, unsigned len)
417{
418 int i;
419 struct logdir *ld = &dir[n];
420
421 if (ld->sizemax) {
422 if (ld->size >= ld->sizemax)
423 rotate(ld);
424 if (len > (ld->sizemax - ld->size))
425 len = ld->sizemax - ld->size;
426 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000427 while (1) {
428 ////i = full_write(ld->fdcur, s, len);
429 ////if (i != -1) break;
430 i = fwrite(s, 1, len, ld->filecur);
431 if (i == len) break;
432
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000433 if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
434 DIR *d;
435 struct dirent *f;
436 char oldest[FMT_PTIME];
437 int j = 0;
438
439 while (fchdir(ld->fddir) == -1)
440 pause2cannot("change directory, want remove old logfile",
441 ld->name);
442 oldest[0] = 'A';
443 oldest[1] = oldest[27] = '\0';
444 while (!(d = opendir(".")))
445 pause2cannot("open directory, want remove old logfile",
446 ld->name);
447 errno = 0;
448 while ((f = readdir(d)))
449 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
450 ++j;
451 if (strcmp(f->d_name, oldest) < 0)
452 memcpy(oldest, f->d_name, 27);
453 }
454 if (errno) warn2("cannot read directory, want remove old logfile",
455 ld->name);
456 closedir(d);
457 errno = ENOSPC;
458 if (j > ld->nmin) {
459 if (*oldest == '@') {
460 bb_error_msg(WARNING"out of disk space, delete: %s/%s",
461 ld->name, oldest);
462 errno = 0;
463 if (unlink(oldest) == -1) {
464 warn2("cannot unlink oldest logfile", ld->name);
465 errno = ENOSPC;
466 }
467 while (fchdir(fdwdir) == -1)
468 pause1cannot("change to initial working directory");
469 }
470 }
471 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000472 if (errno)
473 pause2cannot("write to current", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000474 }
475
476 ld->size += i;
477 if (ld->sizemax)
478 if (s[i-1] == '\n')
479 if (ld->size >= (ld->sizemax - linemax))
480 rotate(ld);
481 return i;
482}
483
484static void logdir_close(struct logdir *ld)
485{
486 if (ld->fddir == -1)
487 return;
488 if (verbose)
489 bb_error_msg(INFO"close: %s", ld->name);
490 close(ld->fddir);
491 ld->fddir = -1;
492 if (ld->fdcur == -1)
493 return; /* impossible */
Denis Vlasenko64392902007-02-03 00:53:43 +0000494 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000495 pause2cannot("fsync current logfile", ld->name);
496 while (fchmod(ld->fdcur, 0744) == -1)
497 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000498 ////close(ld->fdcur);
499 fclose(ld->filecur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000500 ld->fdcur = -1;
501 if (ld->fdlock == -1)
502 return; /* impossible */
503 close(ld->fdlock);
504 ld->fdlock = -1;
505 free(ld->processor);
506 ld->processor = NULL;
507}
508
509static unsigned logdir_open(struct logdir *ld, const char *fn)
510{
511 char buf[128];
Denis Vlasenko45946f82007-08-20 17:27:40 +0000512 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000513 char *new, *s, *np;
514 int i;
515 struct stat st;
516
Denis Vlasenko45946f82007-08-20 17:27:40 +0000517 now = monotonic_sec();
518
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000519 ld->fddir = open(fn, O_RDONLY|O_NDELAY);
520 if (ld->fddir == -1) {
521 warn2("cannot open log directory", (char*)fn);
522 return 0;
523 }
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000524 close_on_exec_on(ld->fddir);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000525 if (fchdir(ld->fddir) == -1) {
526 logdir_close(ld);
527 warn2("cannot change directory", (char*)fn);
528 return 0;
529 }
530 ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
531 if ((ld->fdlock == -1)
532 || (lock_exnb(ld->fdlock) == -1)
533 ) {
534 logdir_close(ld);
535 warn2("cannot lock directory", (char*)fn);
536 while (fchdir(fdwdir) == -1)
537 pause1cannot("change to initial working directory");
538 return 0;
539 }
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000540 close_on_exec_on(ld->fdlock);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000541
542 ld->size = 0;
543 ld->sizemax = 1000000;
544 ld->nmax = ld->nmin = 10;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000545 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000546 ld->name = (char*)fn;
547 ld->ppid = 0;
548 ld->match = '+';
549 free(ld->inst); ld->inst = NULL;
550 free(ld->processor); ld->processor = NULL;
551
552 /* read config */
553 i = open_read_close("config", buf, sizeof(buf));
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000554 if (i < 0 && errno != ENOENT)
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000555 bb_perror_msg(WARNING"%s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000556 if (i > 0) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000557 if (verbose)
558 bb_error_msg(INFO"read: %s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000559 s = buf;
560 while (s) {
561 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000562 if (np)
563 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000564 switch (s[0]) {
565 case '+':
566 case '-':
567 case 'e':
568 case 'E':
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000569 /* Add '\n'-terminated line to ld->inst */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000570 while (1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000571 int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);
572 if (l >= 0 && new)
573 break;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000574 pause_nomem();
575 }
576 free(ld->inst);
577 ld->inst = new;
578 break;
579 case 's': {
580 static const struct suffix_mult km_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000581 { "k", 1024 },
582 { "m", 1024*1024 },
583 { }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000584 };
585 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
586 break;
587 }
588 case 'n':
589 ld->nmax = xatoi_u(&s[1]);
590 break;
591 case 'N':
592 ld->nmin = xatoi_u(&s[1]);
593 break;
594 case 't': {
595 static const struct suffix_mult mh_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000596 { "m", 60 },
597 { "h", 60*60 },
598 /*{ "d", 24*60*60 },*/
599 { }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000600 };
Denis Vlasenko45946f82007-08-20 17:27:40 +0000601 ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
602 if (ld->rotate_period) {
603 ld->next_rotate = now + ld->rotate_period;
604 if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate))
605 nearest_rotate = ld->next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000606 tmaxflag = 1;
607 }
608 break;
609 }
610 case '!':
611 if (s[1]) {
612 free(ld->processor);
613 ld->processor = wstrdup(s);
614 }
615 break;
616 }
617 s = np;
618 }
619 /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
620 s = ld->inst;
621 while (s) {
622 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000623 if (np)
624 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000625 s = np;
626 }
627 }
628
629 /* open current */
630 i = stat("current", &st);
631 if (i != -1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000632 if (st.st_size && !(st.st_mode & S_IXUSR)) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000633 ld->fnsave[25] = '.';
634 ld->fnsave[26] = 'u';
635 ld->fnsave[27] = '\0';
636 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000637 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000638 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000639 stat(ld->fnsave, &st);
640 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000641 while (rename("current", ld->fnsave) == -1)
642 pause2cannot("rename current", ld->name);
643 rmoldest(ld);
644 i = -1;
645 } else {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000646 /* st.st_size can be not just bigger, but WIDER!
647 * This code is safe: if st.st_size > 4GB, we select
648 * ld->sizemax (because it's "unsigned") */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000649 ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
650 }
651 } else {
652 if (errno != ENOENT) {
653 logdir_close(ld);
654 warn2("cannot stat current", ld->name);
655 while (fchdir(fdwdir) == -1)
656 pause1cannot("change to initial working directory");
657 return 0;
658 }
659 }
660 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
661 pause2cannot("open current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000662 /* we presume this cannot fail */
663 ld->filecur = fdopen(ld->fdcur, "a"); ////
664 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
665
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000666 close_on_exec_on(ld->fdcur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000667 while (fchmod(ld->fdcur, 0644) == -1)
668 pause2cannot("set mode of current", ld->name);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000669
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000670 if (verbose) {
671 if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
672 else bb_error_msg(INFO"new: %s/current", ld->name);
673 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000674
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000675 while (fchdir(fdwdir) == -1)
676 pause1cannot("change to initial working directory");
677 return 1;
678}
679
680static void logdirs_reopen(void)
681{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000682 int l;
683 int ok = 0;
684
685 tmaxflag = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000686 for (l = 0; l < dirn; ++l) {
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000687 logdir_close(&dir[l]);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000688 if (logdir_open(&dir[l], fndir[l]))
689 ok = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000690 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000691 if (!ok)
692 fatalx("no functional log directories");
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000693}
694
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000695/* Will look good in libbb one day */
696static ssize_t ndelay_read(int fd, void *buf, size_t count)
697{
698 if (!(fl_flag_0 & O_NONBLOCK))
699 fcntl(fd, F_SETFL, fl_flag_0 | O_NONBLOCK);
700 count = safe_read(fd, buf, count);
701 if (!(fl_flag_0 & O_NONBLOCK))
702 fcntl(fd, F_SETFL, fl_flag_0);
703 return count;
704}
705
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000706/* Used for reading stdin */
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000707static int buffer_pread(/*int fd, */char *s, unsigned len)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000708{
Denis Vlasenko45946f82007-08-20 17:27:40 +0000709 unsigned now;
710 struct pollfd input;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000711 int i;
712
Denis Vlasenko45946f82007-08-20 17:27:40 +0000713 input.fd = 0;
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000714 input.events = POLLIN;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000715
Denis Vlasenkob9528352007-05-06 01:37:21 +0000716 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000717 if (rotateasap) {
718 for (i = 0; i < dirn; ++i)
719 rotate(dir + i);
720 rotateasap = 0;
721 }
722 if (exitasap) {
723 if (linecomplete)
724 return 0;
725 len = 1;
726 }
727 if (reopenasap) {
728 logdirs_reopen();
729 reopenasap = 0;
730 }
731 now = monotonic_sec();
732 nearest_rotate = now + (45 * 60 + 45);
733 for (i = 0; i < dirn; ++i) {
734 if (dir[i].rotate_period) {
735 if (LESS(dir[i].next_rotate, now))
736 rotate(dir + i);
737 if (LESS(dir[i].next_rotate, nearest_rotate))
738 nearest_rotate = dir[i].next_rotate;
739 }
740 }
741
Denis Vlasenko339936b2007-10-05 22:11:06 +0000742 sigprocmask(SIG_UNBLOCK, &blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000743 i = nearest_rotate - now;
744 if (i > 1000000)
745 i = 1000000;
746 if (i <= 0)
747 i = 1;
748 poll(&input, 1, i * 1000);
Denis Vlasenko339936b2007-10-05 22:11:06 +0000749 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000750
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000751 i = ndelay_read(0, s, len);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000752 if (i >= 0)
753 break;
754 if (errno == EINTR)
755 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000756 if (errno != EAGAIN) {
757 warn("cannot read standard input");
758 break;
759 }
760 /* else: EAGAIN - normal, repeat silently */
Denis Vlasenkob9528352007-05-06 01:37:21 +0000761 } while (!exitasap);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000762
763 if (i > 0) {
764 int cnt;
765 linecomplete = (s[i-1] == '\n');
Denis Vlasenko45946f82007-08-20 17:27:40 +0000766 if (!repl)
767 return i;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000768
769 cnt = i;
770 while (--cnt >= 0) {
771 char ch = *s;
772 if (ch != '\n') {
773 if (ch < 32 || ch > 126)
774 *s = repl;
775 else {
776 int j;
777 for (j = 0; replace[j]; ++j) {
778 if (ch == replace[j]) {
779 *s = repl;
780 break;
781 }
782 }
783 }
784 }
785 s++;
786 }
787 }
788 return i;
789}
790
Denis Vlasenko68404f12008-03-17 09:00:54 +0000791static void sig_term_handler(int sig_no ATTRIBUTE_UNUSED)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000792{
793 if (verbose)
794 bb_error_msg(INFO"sig%s received", "term");
795 exitasap = 1;
796}
797
Denis Vlasenko68404f12008-03-17 09:00:54 +0000798static void sig_child_handler(int sig_no ATTRIBUTE_UNUSED)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000799{
800 int pid, l;
801
802 if (verbose)
803 bb_error_msg(INFO"sig%s received", "child");
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000804 while ((pid = wait_any_nohang(&wstat)) > 0) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000805 for (l = 0; l < dirn; ++l) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000806 if (dir[l].ppid == pid) {
807 dir[l].ppid = 0;
808 processorstop(&dir[l]);
809 break;
810 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000811 }
812 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000813}
814
Denis Vlasenko68404f12008-03-17 09:00:54 +0000815static void sig_alarm_handler(int sig_no ATTRIBUTE_UNUSED)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000816{
817 if (verbose)
818 bb_error_msg(INFO"sig%s received", "alarm");
819 rotateasap = 1;
820}
821
Denis Vlasenko68404f12008-03-17 09:00:54 +0000822static void sig_hangup_handler(int sig_no ATTRIBUTE_UNUSED)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000823{
824 if (verbose)
825 bb_error_msg(INFO"sig%s received", "hangup");
826 reopenasap = 1;
827}
828
829static void logmatch(struct logdir *ld)
830{
831 char *s;
832
833 ld->match = '+';
834 ld->matcherr = 'E';
835 s = ld->inst;
836 while (s && s[0]) {
837 switch (s[0]) {
838 case '+':
839 case '-':
840 if (pmatch(s+1, line, linelen))
841 ld->match = s[0];
842 break;
843 case 'e':
844 case 'E':
845 if (pmatch(s+1, line, linelen))
846 ld->matcherr = s[0];
847 break;
848 }
849 s += strlen(s) + 1;
850 }
851}
852
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000853int svlogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000854int svlogd_main(int argc, char **argv)
855{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000856 char *r,*l,*b;
857 ssize_t stdin_cnt = 0;
858 int i;
859 unsigned opt;
860 unsigned timestamp = 0;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000861 void* (*memRchr)(const void *, int, size_t) = memchr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000862
Denis Vlasenko339936b2007-10-05 22:11:06 +0000863 INIT_G();
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000864
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000865 opt_complementary = "tt:vv";
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000866 opt = getopt32(argv, "r:R:l:b:tv",
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000867 &r, &replace, &l, &b, &timestamp, &verbose);
868 if (opt & 1) { // -r
869 repl = r[0];
870 if (!repl || r[1]) usage();
871 }
872 if (opt & 2) if (!repl) repl = '_'; // -R
873 if (opt & 4) { // -l
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000874 linemax = xatou_range(l, 0, BUFSIZ-26);
875 if (linemax == 0) linemax = BUFSIZ-26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000876 if (linemax < 256) linemax = 256;
877 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000878 ////if (opt & 8) { // -b
879 //// buflen = xatoi_u(b);
880 //// if (buflen == 0) buflen = 1024;
881 ////}
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000882 //if (opt & 0x10) timestamp++; // -t
883 //if (opt & 0x20) verbose++; // -v
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000884 //if (timestamp > 2) timestamp = 2;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000885 argv += optind;
886 argc -= optind;
887
888 dirn = argc;
889 if (dirn <= 0) usage();
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000890 ////if (buflen <= linemax) usage();
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000891 fdwdir = xopen(".", O_RDONLY|O_NDELAY);
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000892 close_on_exec_on(fdwdir);
Denis Vlasenkob9528352007-05-06 01:37:21 +0000893 dir = xzalloc(dirn * sizeof(struct logdir));
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000894 for (i = 0; i < dirn; ++i) {
895 dir[i].fddir = -1;
896 dir[i].fdcur = -1;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000897 ////dir[i].btmp = xmalloc(buflen);
Denis Vlasenkob9528352007-05-06 01:37:21 +0000898 /*dir[i].ppid = 0;*/
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000899 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000900 /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000901 fndir = argv;
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000902 /* We cannot set NONBLOCK on fd #0 permanently - this setting
903 * _isn't_ per-process! It is shared among all other processes
904 * with the same stdin */
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000905 fl_flag_0 = fcntl(0, F_GETFL);
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000906
Denis Vlasenko339936b2007-10-05 22:11:06 +0000907 sigemptyset(&blocked_sigset);
908 sigaddset(&blocked_sigset, SIGTERM);
909 sigaddset(&blocked_sigset, SIGCHLD);
910 sigaddset(&blocked_sigset, SIGALRM);
911 sigaddset(&blocked_sigset, SIGHUP);
912 sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
Denis Vlasenko25591c32008-02-16 22:58:56 +0000913 bb_signals_recursive(1 << SIGTERM, sig_term_handler);
914 bb_signals_recursive(1 << SIGCHLD, sig_child_handler);
915 bb_signals_recursive(1 << SIGALRM, sig_alarm_handler);
916 bb_signals_recursive(1 << SIGHUP, sig_hangup_handler);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000917
918 logdirs_reopen();
919
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000920 /* Without timestamps, we don't have to print each line
921 * separately, so we can look for _last_ newline, not first,
922 * thus batching writes */
923 if (!timestamp)
924 memRchr = memrchr;
925
Denis Vlasenko64392902007-02-03 00:53:43 +0000926 setvbuf(stderr, NULL, _IOFBF, linelen);
927
Denis Vlasenko4e1715f2007-01-28 14:51:32 +0000928 /* Each iteration processes one or more lines */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000929 while (1) {
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000930 char stamp[FMT_PTIME];
931 char *lineptr;
932 char *printptr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000933 char *np;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000934 int printlen;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000935 char ch;
936
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000937 lineptr = line;
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000938 if (timestamp)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000939 lineptr += 26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000940
941 /* lineptr[0..linemax-1] - buffer for stdin */
942 /* (possibly has some unprocessed data from prev loop) */
943
944 /* Refill the buffer if needed */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000945 np = memRchr(lineptr, '\n', stdin_cnt);
946 if (!np && !exitasap) {
947 i = linemax - stdin_cnt; /* avail. bytes at tail */
948 if (i >= 128) {
Denis Vlasenko5d61e712007-09-27 10:09:59 +0000949 i = buffer_pread(/*0, */lineptr + stdin_cnt, i);
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000950 if (i <= 0) /* EOF or error on stdin */
951 exitasap = 1;
952 else {
953 np = memRchr(lineptr + stdin_cnt, '\n', i);
954 stdin_cnt += i;
955 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000956 }
957 }
958 if (stdin_cnt <= 0 && exitasap)
959 break;
960
961 /* Search for '\n' (in fact, np already holds the result) */
962 linelen = stdin_cnt;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000963 if (np) {
964 print_to_nl: /* NB: starting from here lineptr may point
965 * farther out into line[] */
966 linelen = np - lineptr + 1;
967 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000968 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
969 ch = lineptr[linelen-1];
970
Denis Vlasenko64392902007-02-03 00:53:43 +0000971 /* Biggest performance hit was coming from the fact
972 * that we did not buffer writes. We were reading many lines
973 * in one read() above, but wrote one line per write().
974 * We are using stdio to fix that */
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000975
976 /* write out lineptr[0..linelen-1] to each log destination
977 * (or lineptr[-26..linelen-1] if timestamping) */
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000978 printlen = linelen;
979 printptr = lineptr;
980 if (timestamp) {
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000981 if (timestamp == 1)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000982 fmt_time_bernstein_25(stamp);
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000983 else /* 2: */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000984 fmt_time_human_30nul(stamp);
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000985 printlen += 26;
986 printptr -= 26;
987 memcpy(printptr, stamp, 25);
988 printptr[25] = ' ';
989 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000990 for (i = 0; i < dirn; ++i) {
991 struct logdir *ld = &dir[i];
992 if (ld->fddir == -1) continue;
993 if (ld->inst)
994 logmatch(ld);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +0000995 if (ld->matcherr == 'e') {
996 /* runit-1.8.0 compat: if timestamping, do it on stderr too */
Denis Vlasenko64392902007-02-03 00:53:43 +0000997 ////full_write(2, printptr, printlen);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +0000998 fwrite(printptr, 1, printlen, stderr);
999 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001000 if (ld->match != '+') continue;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001001 buffer_pwrite(i, printptr, printlen);
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001002 }
1003
1004 /* If we didn't see '\n' (long input line), */
1005 /* read/write repeatedly until we see it */
1006 while (ch != '\n') {
1007 /* lineptr is emptied now, safe to use as buffer */
Denis Vlasenko5d61e712007-09-27 10:09:59 +00001008 stdin_cnt = exitasap ? -1 : buffer_pread(/*0, */lineptr, linemax);
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001009 if (stdin_cnt <= 0) { /* EOF or error on stdin */
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001010 exitasap = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001011 lineptr[0] = ch = '\n';
1012 linelen = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001013 stdin_cnt = 1;
1014 } else {
1015 linelen = stdin_cnt;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001016 np = memRchr(lineptr, '\n', stdin_cnt);
1017 if (np)
1018 linelen = np - lineptr + 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001019 ch = lineptr[linelen-1];
1020 }
1021 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
1022 for (i = 0; i < dirn; ++i) {
1023 if (dir[i].fddir == -1) continue;
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001024 if (dir[i].matcherr == 'e') {
Denis Vlasenko64392902007-02-03 00:53:43 +00001025 ////full_write(2, lineptr, linelen);
1026 fwrite(lineptr, 1, linelen, stderr);
Denis Vlasenko7ab5e3d2007-10-22 15:53:34 +00001027 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001028 if (dir[i].match != '+') continue;
1029 buffer_pwrite(i, lineptr, linelen);
1030 }
1031 }
1032
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001033 stdin_cnt -= linelen;
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001034 if (stdin_cnt > 0) {
1035 lineptr += linelen;
1036 /* If we see another '\n', we don't need to read
1037 * next piece of input: can print what we have */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001038 np = memRchr(lineptr, '\n', stdin_cnt);
Denis Vlasenkoca549c52007-01-27 22:24:59 +00001039 if (np)
1040 goto print_to_nl;
1041 /* Move unprocessed data to the front of line */
1042 memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1043 }
Denis Vlasenko64392902007-02-03 00:53:43 +00001044 fflush(NULL);////
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001045 }
1046
1047 for (i = 0; i < dirn; ++i) {
1048 if (dir[i].ppid)
1049 while (!processorstop(&dir[i]))
1050 /* repeat */;
1051 logdir_close(&dir[i]);
1052 }
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001053 return 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001054}