blob: 6c8747e964be286c73d1d1b6129f33c600f7ff5f [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
28/* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
29/* TODO: depends on runit_lib.c - review and reduce/eliminate */
30
31#include <sys/poll.h>
32#include <sys/file.h>
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 Vlasenko83ea6432006-11-16 02:27:24 +000040static unsigned verbose;
41static int linemax = 1000;
Denis Vlasenkoca549c52007-01-27 22:24:59 +000042////static int buflen = 1024;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000043static int linelen;
44
45static char **fndir;
46static int fdwdir;
47static int wstat;
Denis Vlasenko45946f82007-08-20 17:27:40 +000048static unsigned nearest_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000049
50static char *line;
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +000051static smallint exitasap;
52static smallint rotateasap;
53static smallint reopenasap;
54static smallint linecomplete = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000055
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +000056static smallint tmaxflag;
57
Denis Vlasenko83ea6432006-11-16 02:27:24 +000058static char repl;
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +000059static const char *replace = "";
60
Denis Vlasenko0aa84902007-02-03 01:47:56 +000061static sigset_t *blocked_sigset;
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +000062static int fl_flag_0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000063
64static struct logdir {
Denis Vlasenko64392902007-02-03 00:53:43 +000065 ////char *btmp;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000066 /* pattern list to match, in "aa\0bb\0\cc\0\0" form */
67 char *inst;
68 char *processor;
69 char *name;
70 unsigned size;
71 unsigned sizemax;
72 unsigned nmax;
73 unsigned nmin;
Denis Vlasenko45946f82007-08-20 17:27:40 +000074 unsigned rotate_period;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000075 int ppid;
76 int fddir;
77 int fdcur;
Denis Vlasenko64392902007-02-03 00:53:43 +000078 FILE* filecur; ////
Denis Vlasenko83ea6432006-11-16 02:27:24 +000079 int fdlock;
Denis Vlasenko45946f82007-08-20 17:27:40 +000080 unsigned next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000081 char fnsave[FMT_PTIME];
82 char match;
83 char matcherr;
84} *dir;
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000085static unsigned dirn;
Denis Vlasenko83ea6432006-11-16 02:27:24 +000086
87#define FATAL "fatal: "
88#define WARNING "warning: "
89#define PAUSE "pausing: "
90#define INFO "info: "
91
92#define usage() bb_show_usage()
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000093static void fatalx(const char *m0)
Denis Vlasenko83ea6432006-11-16 02:27:24 +000094{
95 bb_error_msg_and_die(FATAL"%s", m0);
96}
Denis Vlasenkoac678ec2007-04-16 22:32:04 +000097static void warn(const char *m0)
98{
Denis Vlasenko83ea6432006-11-16 02:27:24 +000099 bb_perror_msg(WARNING"%s", m0);
100}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000101static void warn2(const char *m0, const char *m1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000102{
103 bb_perror_msg(WARNING"%s: %s", m0, m1);
104}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000105static void warnx(const char *m0, const char *m1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000106{
107 bb_error_msg(WARNING"%s: %s", m0, m1);
108}
109static void pause_nomem(void)
110{
Denis Vlasenko8c783952007-01-27 22:21:52 +0000111 bb_error_msg(PAUSE"out of memory");
112 sleep(3);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000113}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000114static void pause1cannot(const char *m0)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000115{
Denis Vlasenko8c783952007-01-27 22:21:52 +0000116 bb_perror_msg(PAUSE"cannot %s", m0);
117 sleep(3);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000118}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000119static void pause2cannot(const char *m0, const char *m1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000120{
121 bb_perror_msg(PAUSE"cannot %s %s", m0, m1);
122 sleep(3);
123}
124
125static char* wstrdup(const char *str)
126{
127 char *s;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000128 while (!(s = strdup(str)))
129 pause_nomem();
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000130 return s;
131}
132
Denis Vlasenko45946f82007-08-20 17:27:40 +0000133/*** ex fmt_ptime.[ch] ***/
134
135/* NUL terminated */
136static void fmt_time_human_30nul(char *s)
137{
138 struct tm *t;
139 struct timeval tv;
140
141 gettimeofday(&tv, NULL);
142 t = gmtime(&(tv.tv_sec));
143 sprintf(s, "%04u-%02u-%02u_%02u:%02u:%02u.%06u000",
144 (unsigned)(1900 + t->tm_year),
145 (unsigned)(t->tm_mon + 1),
146 (unsigned)(t->tm_mday),
147 (unsigned)(t->tm_hour),
148 (unsigned)(t->tm_min),
149 (unsigned)(t->tm_sec),
150 (unsigned)(tv.tv_usec)
151 );
152 /* 4+1 + 2+1 + 2+1 + 2+1 + 2+1 + 2+1 + 9 = */
153 /* 5 + 3 + 3 + 3 + 3 + 3 + 9 = */
154 /* 20 (up to '.' inclusive) + 9 (not including '\0') */
155}
156
157/* NOT terminated! */
158static void fmt_time_bernstein_25(char *s)
159{
160 uint32_t pack[3];
161 struct timeval tv;
162 unsigned sec_hi;
163
164 gettimeofday(&tv, NULL);
165 sec_hi = (0x400000000000000aULL + tv.tv_sec) >> 32;
166 tv.tv_sec = (time_t)(0x400000000000000aULL) + tv.tv_sec;
167 tv.tv_usec *= 1000;
168 /* Network order is big-endian: most significant byte first.
169 * This is exactly what we want here */
170 pack[0] = htonl(sec_hi);
171 pack[1] = htonl(tv.tv_sec);
172 pack[2] = htonl(tv.tv_usec);
173 *s++ = '@';
174 bin2hex(s, (char*)pack, 12);
175}
176
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000177static unsigned processorstart(struct logdir *ld)
178{
179 int pid;
180
181 if (!ld->processor) return 0;
182 if (ld->ppid) {
183 warnx("processor already running", ld->name);
184 return 0;
185 }
186 while ((pid = fork()) == -1)
187 pause2cannot("fork for processor", ld->name);
188 if (!pid) {
189 char *prog[4];
190 int fd;
191
192 /* child */
Denis Vlasenko2856dab2007-04-01 01:18:20 +0000193 signal(SIGTERM, SIG_DFL);
194 signal(SIGALRM, SIG_DFL);
195 signal(SIGHUP, SIG_DFL);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000196 sig_unblock(SIGTERM);
197 sig_unblock(SIGALRM);
198 sig_unblock(SIGHUP);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000199
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000200 if (verbose)
201 bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave);
202 fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000203 xmove_fd(fd, 0);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000204 ld->fnsave[26] = 't';
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000205 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000206 xmove_fd(fd, 1);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000207 fd = open_read("state");
208 if (fd == -1) {
209 if (errno != ENOENT)
210 bb_perror_msg_and_die(FATAL"cannot %s processor %s", "open state for", ld->name);
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000211 close(xopen("state", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT));
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000212 fd = xopen("state", O_RDONLY|O_NDELAY);
213 }
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000214 xmove_fd(fd, 4);
Denis Vlasenkocf749bc2006-11-26 15:45:17 +0000215 fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000216 xmove_fd(fd, 5);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000217
Denis Vlasenko8c783952007-01-27 22:21:52 +0000218// getenv("SHELL")?
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000219 prog[0] = (char*)"sh";
220 prog[1] = (char*)"-c";
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000221 prog[2] = ld->processor;
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000222 prog[3] = NULL;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000223 execve("/bin/sh", prog, environ);
224 bb_perror_msg_and_die(FATAL"cannot %s processor %s", "run", ld->name);
225 }
226 ld->ppid = pid;
227 return 1;
228}
229
230static unsigned processorstop(struct logdir *ld)
231{
232 char f[28];
233
234 if (ld->ppid) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000235 sig_unblock(SIGHUP);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000236 while (wait_pid(&wstat, ld->ppid) == -1)
237 pause2cannot("wait for processor", ld->name);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000238 sig_block(SIGHUP);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000239 ld->ppid = 0;
240 }
241 if (ld->fddir == -1) return 1;
242 while (fchdir(ld->fddir) == -1)
243 pause2cannot("change directory, want processor", ld->name);
244 if (wait_exitcode(wstat) != 0) {
245 warnx("processor failed, restart", ld->name);
246 ld->fnsave[26] = 't';
247 unlink(ld->fnsave);
248 ld->fnsave[26] = 'u';
249 processorstart(ld);
250 while (fchdir(fdwdir) == -1)
251 pause1cannot("change to initial working directory");
252 return ld->processor ? 0 : 1;
253 }
254 ld->fnsave[26] = 't';
255 memcpy(f, ld->fnsave, 26);
256 f[26] = 's';
257 f[27] = '\0';
258 while (rename(ld->fnsave, f) == -1)
259 pause2cannot("rename processed", ld->name);
260 while (chmod(f, 0744) == -1)
261 pause2cannot("set mode of processed", ld->name);
262 ld->fnsave[26] = 'u';
263 if (unlink(ld->fnsave) == -1)
264 bb_error_msg(WARNING"cannot unlink: %s/%s", ld->name, ld->fnsave);
265 while (rename("newstate", "state") == -1)
266 pause2cannot("rename state", ld->name);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000267 if (verbose)
268 bb_error_msg(INFO"processed: %s/%s", ld->name, f);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000269 while (fchdir(fdwdir) == -1)
270 pause1cannot("change to initial working directory");
271 return 1;
272}
273
274static void rmoldest(struct logdir *ld)
275{
276 DIR *d;
277 struct dirent *f;
278 char oldest[FMT_PTIME];
279 int n = 0;
280
281 oldest[0] = 'A'; oldest[1] = oldest[27] = 0;
282 while (!(d = opendir(".")))
283 pause2cannot("open directory, want rotate", ld->name);
284 errno = 0;
285 while ((f = readdir(d))) {
286 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
287 if (f->d_name[26] == 't') {
288 if (unlink(f->d_name) == -1)
289 warn2("cannot unlink processor leftover", f->d_name);
290 } else {
291 ++n;
292 if (strcmp(f->d_name, oldest) < 0)
293 memcpy(oldest, f->d_name, 27);
294 }
295 errno = 0;
296 }
297 }
Denis Vlasenko8c783952007-01-27 22:21:52 +0000298 if (errno)
299 warn2("cannot read directory", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000300 closedir(d);
301
302 if (ld->nmax && (n > ld->nmax)) {
Denis Vlasenko8c783952007-01-27 22:21:52 +0000303 if (verbose)
304 bb_error_msg(INFO"delete: %s/%s", ld->name, oldest);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000305 if ((*oldest == '@') && (unlink(oldest) == -1))
306 warn2("cannot unlink oldest logfile", ld->name);
307 }
308}
309
310static unsigned rotate(struct logdir *ld)
311{
312 struct stat st;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000313 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000314
315 if (ld->fddir == -1) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000316 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000317 return 0;
318 }
319 if (ld->ppid)
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000320 while (!processorstop(ld))
Denis Vlasenko45946f82007-08-20 17:27:40 +0000321 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000322
323 while (fchdir(ld->fddir) == -1)
324 pause2cannot("change directory, want rotate", ld->name);
325
326 /* create new filename */
327 ld->fnsave[25] = '.';
328 ld->fnsave[26] = 's';
329 if (ld->processor)
330 ld->fnsave[26] = 'u';
331 ld->fnsave[27] = '\0';
332 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000333 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000334 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000335 stat(ld->fnsave, &st);
336 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000337
Denis Vlasenko45946f82007-08-20 17:27:40 +0000338 now = monotonic_sec();
339 if (ld->rotate_period && LESS(ld->next_rotate, now)) {
340 ld->next_rotate = now + ld->rotate_period;
341 if (LESS(ld->next_rotate, nearest_rotate))
342 nearest_rotate = ld->next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000343 }
344
345 if (ld->size > 0) {
Denis Vlasenko64392902007-02-03 00:53:43 +0000346 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000347 pause2cannot("fsync current logfile", ld->name);
348 while (fchmod(ld->fdcur, 0744) == -1)
349 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000350 ////close(ld->fdcur);
351 fclose(ld->filecur);
352
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000353 if (verbose) {
354 bb_error_msg(INFO"rename: %s/current %s %u", ld->name,
355 ld->fnsave, ld->size);
356 }
357 while (rename("current", ld->fnsave) == -1)
358 pause2cannot("rename current", ld->name);
359 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
360 pause2cannot("create new current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000361 /* we presume this cannot fail */
362 ld->filecur = fdopen(ld->fdcur, "a"); ////
363 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000364 coe(ld->fdcur);
365 ld->size = 0;
366 while (fchmod(ld->fdcur, 0644) == -1)
367 pause2cannot("set mode of current", ld->name);
368 rmoldest(ld);
369 processorstart(ld);
370 }
371
372 while (fchdir(fdwdir) == -1)
373 pause1cannot("change to initial working directory");
374 return 1;
375}
376
377static int buffer_pwrite(int n, char *s, unsigned len)
378{
379 int i;
380 struct logdir *ld = &dir[n];
381
382 if (ld->sizemax) {
383 if (ld->size >= ld->sizemax)
384 rotate(ld);
385 if (len > (ld->sizemax - ld->size))
386 len = ld->sizemax - ld->size;
387 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000388 while (1) {
389 ////i = full_write(ld->fdcur, s, len);
390 ////if (i != -1) break;
391 i = fwrite(s, 1, len, ld->filecur);
392 if (i == len) break;
393
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000394 if ((errno == ENOSPC) && (ld->nmin < ld->nmax)) {
395 DIR *d;
396 struct dirent *f;
397 char oldest[FMT_PTIME];
398 int j = 0;
399
400 while (fchdir(ld->fddir) == -1)
401 pause2cannot("change directory, want remove old logfile",
402 ld->name);
403 oldest[0] = 'A';
404 oldest[1] = oldest[27] = '\0';
405 while (!(d = opendir(".")))
406 pause2cannot("open directory, want remove old logfile",
407 ld->name);
408 errno = 0;
409 while ((f = readdir(d)))
410 if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) {
411 ++j;
412 if (strcmp(f->d_name, oldest) < 0)
413 memcpy(oldest, f->d_name, 27);
414 }
415 if (errno) warn2("cannot read directory, want remove old logfile",
416 ld->name);
417 closedir(d);
418 errno = ENOSPC;
419 if (j > ld->nmin) {
420 if (*oldest == '@') {
421 bb_error_msg(WARNING"out of disk space, delete: %s/%s",
422 ld->name, oldest);
423 errno = 0;
424 if (unlink(oldest) == -1) {
425 warn2("cannot unlink oldest logfile", ld->name);
426 errno = ENOSPC;
427 }
428 while (fchdir(fdwdir) == -1)
429 pause1cannot("change to initial working directory");
430 }
431 }
432 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000433 if (errno)
434 pause2cannot("write to current", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000435 }
436
437 ld->size += i;
438 if (ld->sizemax)
439 if (s[i-1] == '\n')
440 if (ld->size >= (ld->sizemax - linemax))
441 rotate(ld);
442 return i;
443}
444
445static void logdir_close(struct logdir *ld)
446{
447 if (ld->fddir == -1)
448 return;
449 if (verbose)
450 bb_error_msg(INFO"close: %s", ld->name);
451 close(ld->fddir);
452 ld->fddir = -1;
453 if (ld->fdcur == -1)
454 return; /* impossible */
Denis Vlasenko64392902007-02-03 00:53:43 +0000455 while (fflush(ld->filecur) || fsync(ld->fdcur) == -1)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000456 pause2cannot("fsync current logfile", ld->name);
457 while (fchmod(ld->fdcur, 0744) == -1)
458 pause2cannot("set mode of current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000459 ////close(ld->fdcur);
460 fclose(ld->filecur);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000461 ld->fdcur = -1;
462 if (ld->fdlock == -1)
463 return; /* impossible */
464 close(ld->fdlock);
465 ld->fdlock = -1;
466 free(ld->processor);
467 ld->processor = NULL;
468}
469
470static unsigned logdir_open(struct logdir *ld, const char *fn)
471{
472 char buf[128];
Denis Vlasenko45946f82007-08-20 17:27:40 +0000473 unsigned now;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000474 char *new, *s, *np;
475 int i;
476 struct stat st;
477
Denis Vlasenko45946f82007-08-20 17:27:40 +0000478 now = monotonic_sec();
479
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000480 ld->fddir = open(fn, O_RDONLY|O_NDELAY);
481 if (ld->fddir == -1) {
482 warn2("cannot open log directory", (char*)fn);
483 return 0;
484 }
485 coe(ld->fddir);
486 if (fchdir(ld->fddir) == -1) {
487 logdir_close(ld);
488 warn2("cannot change directory", (char*)fn);
489 return 0;
490 }
491 ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
492 if ((ld->fdlock == -1)
493 || (lock_exnb(ld->fdlock) == -1)
494 ) {
495 logdir_close(ld);
496 warn2("cannot lock directory", (char*)fn);
497 while (fchdir(fdwdir) == -1)
498 pause1cannot("change to initial working directory");
499 return 0;
500 }
501 coe(ld->fdlock);
502
503 ld->size = 0;
504 ld->sizemax = 1000000;
505 ld->nmax = ld->nmin = 10;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000506 ld->rotate_period = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000507 ld->name = (char*)fn;
508 ld->ppid = 0;
509 ld->match = '+';
510 free(ld->inst); ld->inst = NULL;
511 free(ld->processor); ld->processor = NULL;
512
513 /* read config */
514 i = open_read_close("config", buf, sizeof(buf));
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000515 if (i < 0 && errno != ENOENT)
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000516 bb_perror_msg(WARNING"%s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000517 if (i > 0) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000518 if (verbose)
519 bb_error_msg(INFO"read: %s/config", ld->name);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000520 s = buf;
521 while (s) {
522 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000523 if (np)
524 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000525 switch (s[0]) {
526 case '+':
527 case '-':
528 case 'e':
529 case 'E':
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000530 /* Add '\n'-terminated line to ld->inst */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000531 while (1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000532 int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);
533 if (l >= 0 && new)
534 break;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000535 pause_nomem();
536 }
537 free(ld->inst);
538 ld->inst = new;
539 break;
540 case 's': {
541 static const struct suffix_mult km_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000542 { "k", 1024 },
543 { "m", 1024*1024 },
544 { }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000545 };
546 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
547 break;
548 }
549 case 'n':
550 ld->nmax = xatoi_u(&s[1]);
551 break;
552 case 'N':
553 ld->nmin = xatoi_u(&s[1]);
554 break;
555 case 't': {
556 static const struct suffix_mult mh_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000557 { "m", 60 },
558 { "h", 60*60 },
559 /*{ "d", 24*60*60 },*/
560 { }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000561 };
Denis Vlasenko45946f82007-08-20 17:27:40 +0000562 ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
563 if (ld->rotate_period) {
564 ld->next_rotate = now + ld->rotate_period;
565 if (!tmaxflag || LESS(ld->next_rotate, nearest_rotate))
566 nearest_rotate = ld->next_rotate;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000567 tmaxflag = 1;
568 }
569 break;
570 }
571 case '!':
572 if (s[1]) {
573 free(ld->processor);
574 ld->processor = wstrdup(s);
575 }
576 break;
577 }
578 s = np;
579 }
580 /* Convert "aa\nbb\ncc\n\0" to "aa\0bb\0cc\0\0" */
581 s = ld->inst;
582 while (s) {
583 np = strchr(s, '\n');
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000584 if (np)
585 *np++ = '\0';
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000586 s = np;
587 }
588 }
589
590 /* open current */
591 i = stat("current", &st);
592 if (i != -1) {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000593 if (st.st_size && !(st.st_mode & S_IXUSR)) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000594 ld->fnsave[25] = '.';
595 ld->fnsave[26] = 'u';
596 ld->fnsave[27] = '\0';
597 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000598 fmt_time_bernstein_25(ld->fnsave);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000599 errno = 0;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000600 stat(ld->fnsave, &st);
601 } while (errno != ENOENT);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000602 while (rename("current", ld->fnsave) == -1)
603 pause2cannot("rename current", ld->name);
604 rmoldest(ld);
605 i = -1;
606 } else {
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000607 /* st.st_size can be not just bigger, but WIDER!
608 * This code is safe: if st.st_size > 4GB, we select
609 * ld->sizemax (because it's "unsigned") */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000610 ld->size = (st.st_size > ld->sizemax) ? ld->sizemax : st.st_size;
611 }
612 } else {
613 if (errno != ENOENT) {
614 logdir_close(ld);
615 warn2("cannot stat current", ld->name);
616 while (fchdir(fdwdir) == -1)
617 pause1cannot("change to initial working directory");
618 return 0;
619 }
620 }
621 while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
622 pause2cannot("open current", ld->name);
Denis Vlasenko64392902007-02-03 00:53:43 +0000623 /* we presume this cannot fail */
624 ld->filecur = fdopen(ld->fdcur, "a"); ////
625 setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
626
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000627 coe(ld->fdcur);
628 while (fchmod(ld->fdcur, 0644) == -1)
629 pause2cannot("set mode of current", ld->name);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000630
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000631 if (verbose) {
632 if (i == 0) bb_error_msg(INFO"append: %s/current", ld->name);
633 else bb_error_msg(INFO"new: %s/current", ld->name);
634 }
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000635
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000636 while (fchdir(fdwdir) == -1)
637 pause1cannot("change to initial working directory");
638 return 1;
639}
640
641static void logdirs_reopen(void)
642{
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000643 int l;
644 int ok = 0;
645
646 tmaxflag = 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000647 for (l = 0; l < dirn; ++l) {
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000648 logdir_close(&dir[l]);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000649 if (logdir_open(&dir[l], fndir[l]))
650 ok = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000651 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000652 if (!ok)
653 fatalx("no functional log directories");
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000654}
655
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000656/* Will look good in libbb one day */
657static ssize_t ndelay_read(int fd, void *buf, size_t count)
658{
659 if (!(fl_flag_0 & O_NONBLOCK))
660 fcntl(fd, F_SETFL, fl_flag_0 | O_NONBLOCK);
661 count = safe_read(fd, buf, count);
662 if (!(fl_flag_0 & O_NONBLOCK))
663 fcntl(fd, F_SETFL, fl_flag_0);
664 return count;
665}
666
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000667/* Used for reading stdin */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000668static int buffer_pread(int fd, char *s, unsigned len)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000669{
Denis Vlasenko45946f82007-08-20 17:27:40 +0000670 unsigned now;
671 struct pollfd input;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000672 int i;
673
Denis Vlasenko45946f82007-08-20 17:27:40 +0000674 input.fd = 0;
Denis Vlasenko72b6a652007-08-21 11:18:25 +0000675 input.events = POLLIN;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000676
Denis Vlasenkob9528352007-05-06 01:37:21 +0000677 do {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000678 if (rotateasap) {
679 for (i = 0; i < dirn; ++i)
680 rotate(dir + i);
681 rotateasap = 0;
682 }
683 if (exitasap) {
684 if (linecomplete)
685 return 0;
686 len = 1;
687 }
688 if (reopenasap) {
689 logdirs_reopen();
690 reopenasap = 0;
691 }
692 now = monotonic_sec();
693 nearest_rotate = now + (45 * 60 + 45);
694 for (i = 0; i < dirn; ++i) {
695 if (dir[i].rotate_period) {
696 if (LESS(dir[i].next_rotate, now))
697 rotate(dir + i);
698 if (LESS(dir[i].next_rotate, nearest_rotate))
699 nearest_rotate = dir[i].next_rotate;
700 }
701 }
702
Denis Vlasenko0aa84902007-02-03 01:47:56 +0000703 sigprocmask(SIG_UNBLOCK, blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000704 i = nearest_rotate - now;
705 if (i > 1000000)
706 i = 1000000;
707 if (i <= 0)
708 i = 1;
709 poll(&input, 1, i * 1000);
Denis Vlasenko0aa84902007-02-03 01:47:56 +0000710 sigprocmask(SIG_BLOCK, blocked_sigset, NULL);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000711
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000712 i = ndelay_read(fd, s, len);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000713 if (i >= 0)
714 break;
715 if (errno == EINTR)
716 continue;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000717 if (errno != EAGAIN) {
718 warn("cannot read standard input");
719 break;
720 }
721 /* else: EAGAIN - normal, repeat silently */
Denis Vlasenkob9528352007-05-06 01:37:21 +0000722 } while (!exitasap);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000723
724 if (i > 0) {
725 int cnt;
726 linecomplete = (s[i-1] == '\n');
Denis Vlasenko45946f82007-08-20 17:27:40 +0000727 if (!repl)
728 return i;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000729
730 cnt = i;
731 while (--cnt >= 0) {
732 char ch = *s;
733 if (ch != '\n') {
734 if (ch < 32 || ch > 126)
735 *s = repl;
736 else {
737 int j;
738 for (j = 0; replace[j]; ++j) {
739 if (ch == replace[j]) {
740 *s = repl;
741 break;
742 }
743 }
744 }
745 }
746 s++;
747 }
748 }
749 return i;
750}
751
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000752static void sig_term_handler(int sig_no)
753{
754 if (verbose)
755 bb_error_msg(INFO"sig%s received", "term");
756 exitasap = 1;
757}
758
759static void sig_child_handler(int sig_no)
760{
761 int pid, l;
762
763 if (verbose)
764 bb_error_msg(INFO"sig%s received", "child");
Denis Vlasenko45946f82007-08-20 17:27:40 +0000765 while ((pid = wait_nohang(&wstat)) > 0) {
766 for (l = 0; l < dirn; ++l) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000767 if (dir[l].ppid == pid) {
768 dir[l].ppid = 0;
769 processorstop(&dir[l]);
770 break;
771 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000772 }
773 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000774}
775
776static void sig_alarm_handler(int sig_no)
777{
778 if (verbose)
779 bb_error_msg(INFO"sig%s received", "alarm");
780 rotateasap = 1;
781}
782
783static void sig_hangup_handler(int sig_no)
784{
785 if (verbose)
786 bb_error_msg(INFO"sig%s received", "hangup");
787 reopenasap = 1;
788}
789
790static void logmatch(struct logdir *ld)
791{
792 char *s;
793
794 ld->match = '+';
795 ld->matcherr = 'E';
796 s = ld->inst;
797 while (s && s[0]) {
798 switch (s[0]) {
799 case '+':
800 case '-':
801 if (pmatch(s+1, line, linelen))
802 ld->match = s[0];
803 break;
804 case 'e':
805 case 'E':
806 if (pmatch(s+1, line, linelen))
807 ld->matcherr = s[0];
808 break;
809 }
810 s += strlen(s) + 1;
811 }
812}
813
Denis Vlasenko06af2162007-02-03 17:28:39 +0000814int svlogd_main(int argc, char **argv);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000815int svlogd_main(int argc, char **argv)
816{
Denis Vlasenko0aa84902007-02-03 01:47:56 +0000817 sigset_t ss;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000818 char *r,*l,*b;
819 ssize_t stdin_cnt = 0;
820 int i;
821 unsigned opt;
822 unsigned timestamp = 0;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000823 void* (*memRchr)(const void *, int, size_t) = memchr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000824
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000825#define line bb_common_bufsiz1
826
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000827 opt_complementary = "tt:vv";
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000828 opt = getopt32(argv, "r:R:l:b:tv",
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000829 &r, &replace, &l, &b, &timestamp, &verbose);
830 if (opt & 1) { // -r
831 repl = r[0];
832 if (!repl || r[1]) usage();
833 }
834 if (opt & 2) if (!repl) repl = '_'; // -R
835 if (opt & 4) { // -l
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000836 linemax = xatou_range(l, 0, BUFSIZ-26);
837 if (linemax == 0) linemax = BUFSIZ-26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000838 if (linemax < 256) linemax = 256;
839 }
Denis Vlasenko64392902007-02-03 00:53:43 +0000840 ////if (opt & 8) { // -b
841 //// buflen = xatoi_u(b);
842 //// if (buflen == 0) buflen = 1024;
843 ////}
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000844 //if (opt & 0x10) timestamp++; // -t
845 //if (opt & 0x20) verbose++; // -v
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000846 //if (timestamp > 2) timestamp = 2;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000847 argv += optind;
848 argc -= optind;
849
850 dirn = argc;
851 if (dirn <= 0) usage();
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000852 ////if (buflen <= linemax) usage();
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000853 fdwdir = xopen(".", O_RDONLY|O_NDELAY);
854 coe(fdwdir);
Denis Vlasenkob9528352007-05-06 01:37:21 +0000855 dir = xzalloc(dirn * sizeof(struct logdir));
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000856 for (i = 0; i < dirn; ++i) {
857 dir[i].fddir = -1;
858 dir[i].fdcur = -1;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000859 ////dir[i].btmp = xmalloc(buflen);
Denis Vlasenkob9528352007-05-06 01:37:21 +0000860 /*dir[i].ppid = 0;*/
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000861 }
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000862 /* line = xmalloc(linemax + (timestamp ? 26 : 0)); */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000863 fndir = argv;
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000864 /* We cannot set NONBLOCK on fd #0 permanently - this setting
865 * _isn't_ per-process! It is shared among all other processes
866 * with the same stdin */
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000867 fl_flag_0 = fcntl(0, F_GETFL);
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000868
Denis Vlasenko0aa84902007-02-03 01:47:56 +0000869 blocked_sigset = &ss;
870 sigemptyset(&ss);
871 sigaddset(&ss, SIGTERM);
872 sigaddset(&ss, SIGCHLD);
873 sigaddset(&ss, SIGALRM);
874 sigaddset(&ss, SIGHUP);
875 sigprocmask(SIG_BLOCK, &ss, NULL);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000876 sig_catch(SIGTERM, sig_term_handler);
877 sig_catch(SIGCHLD, sig_child_handler);
878 sig_catch(SIGALRM, sig_alarm_handler);
879 sig_catch(SIGHUP, sig_hangup_handler);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000880
881 logdirs_reopen();
882
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000883 /* Without timestamps, we don't have to print each line
884 * separately, so we can look for _last_ newline, not first,
885 * thus batching writes */
886 if (!timestamp)
887 memRchr = memrchr;
888
Denis Vlasenko64392902007-02-03 00:53:43 +0000889 setvbuf(stderr, NULL, _IOFBF, linelen);
890
Denis Vlasenko4e1715f2007-01-28 14:51:32 +0000891 /* Each iteration processes one or more lines */
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000892 while (1) {
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000893 char stamp[FMT_PTIME];
894 char *lineptr;
895 char *printptr;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000896 char *np;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000897 int printlen;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000898 char ch;
899
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000900 lineptr = line;
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000901 if (timestamp)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000902 lineptr += 26;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000903
904 /* lineptr[0..linemax-1] - buffer for stdin */
905 /* (possibly has some unprocessed data from prev loop) */
906
907 /* Refill the buffer if needed */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000908 np = memRchr(lineptr, '\n', stdin_cnt);
909 if (!np && !exitasap) {
910 i = linemax - stdin_cnt; /* avail. bytes at tail */
911 if (i >= 128) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000912 i = buffer_pread(0, lineptr + stdin_cnt, i);
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000913 if (i <= 0) /* EOF or error on stdin */
914 exitasap = 1;
915 else {
916 np = memRchr(lineptr + stdin_cnt, '\n', i);
917 stdin_cnt += i;
918 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000919 }
920 }
921 if (stdin_cnt <= 0 && exitasap)
922 break;
923
924 /* Search for '\n' (in fact, np already holds the result) */
925 linelen = stdin_cnt;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000926 if (np) {
927 print_to_nl: /* NB: starting from here lineptr may point
928 * farther out into line[] */
929 linelen = np - lineptr + 1;
930 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000931 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
932 ch = lineptr[linelen-1];
933
Denis Vlasenko64392902007-02-03 00:53:43 +0000934 /* Biggest performance hit was coming from the fact
935 * that we did not buffer writes. We were reading many lines
936 * in one read() above, but wrote one line per write().
937 * We are using stdio to fix that */
Denis Vlasenko4f8d27f2007-02-03 00:52:17 +0000938
939 /* write out lineptr[0..linelen-1] to each log destination
940 * (or lineptr[-26..linelen-1] if timestamping) */
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000941 printlen = linelen;
942 printptr = lineptr;
943 if (timestamp) {
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000944 if (timestamp == 1)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000945 fmt_time_bernstein_25(stamp);
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000946 else /* 2: */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000947 fmt_time_human_30nul(stamp);
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000948 printlen += 26;
949 printptr -= 26;
950 memcpy(printptr, stamp, 25);
951 printptr[25] = ' ';
952 }
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000953 for (i = 0; i < dirn; ++i) {
954 struct logdir *ld = &dir[i];
955 if (ld->fddir == -1) continue;
956 if (ld->inst)
957 logmatch(ld);
Denis Vlasenko83edaf32006-11-19 17:33:54 +0000958 if (ld->matcherr == 'e')
Denis Vlasenko64392902007-02-03 00:53:43 +0000959 ////full_write(2, printptr, printlen);
960 fwrite(lineptr, 1, linelen, stderr);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000961 if (ld->match != '+') continue;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000962 buffer_pwrite(i, printptr, printlen);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000963 }
964
965 /* If we didn't see '\n' (long input line), */
966 /* read/write repeatedly until we see it */
967 while (ch != '\n') {
968 /* lineptr is emptied now, safe to use as buffer */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000969 stdin_cnt = exitasap ? -1 : buffer_pread(0, lineptr, linemax);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000970 if (stdin_cnt <= 0) { /* EOF or error on stdin */
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000971 exitasap = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000972 lineptr[0] = ch = '\n';
973 linelen = 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000974 stdin_cnt = 1;
975 } else {
976 linelen = stdin_cnt;
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000977 np = memRchr(lineptr, '\n', stdin_cnt);
978 if (np)
979 linelen = np - lineptr + 1;
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000980 ch = lineptr[linelen-1];
981 }
982 /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
983 for (i = 0; i < dirn; ++i) {
984 if (dir[i].fddir == -1) continue;
Denis Vlasenko83edaf32006-11-19 17:33:54 +0000985 if (dir[i].matcherr == 'e')
Denis Vlasenko64392902007-02-03 00:53:43 +0000986 ////full_write(2, lineptr, linelen);
987 fwrite(lineptr, 1, linelen, stderr);
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000988 if (dir[i].match != '+') continue;
989 buffer_pwrite(i, lineptr, linelen);
990 }
991 }
992
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000993 stdin_cnt -= linelen;
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000994 if (stdin_cnt > 0) {
995 lineptr += linelen;
996 /* If we see another '\n', we don't need to read
997 * next piece of input: can print what we have */
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +0000998 np = memRchr(lineptr, '\n', stdin_cnt);
Denis Vlasenkoca549c52007-01-27 22:24:59 +0000999 if (np)
1000 goto print_to_nl;
1001 /* Move unprocessed data to the front of line */
1002 memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1003 }
Denis Vlasenko64392902007-02-03 00:53:43 +00001004 fflush(NULL);////
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001005 }
1006
1007 for (i = 0; i < dirn; ++i) {
1008 if (dir[i].ppid)
1009 while (!processorstop(&dir[i]))
1010 /* repeat */;
1011 logdir_close(&dir[i]);
1012 }
Denis Vlasenkoeeafc1a2007-01-27 23:15:50 +00001013 return 0;
Denis Vlasenko83ea6432006-11-16 02:27:24 +00001014}