1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <sys/param.h>
4 #include <sys/socket.h>
5 #include <netinet/in.h>
6 #include <time.h>
7 #include <sys/time.h>
8 #include <dirent.h>
9 #include <unistd.h>
10 #include <stdio.h>
11 #include "pmatch.h"
12 #include "fmt_ptime.h"
13 #include "alloc.h"
14 #include "stralloc.h"
15 #include "strerr.h"
16 #include "buffer.h"
17 #include "sig.h"
18 #include "env.h"
19 #include "fd.h"
20 #include "wait.h"
21 #include "error.h"
22 #include "sgetopt.h"
23 #include "open.h"
24 #include "openreadclose.h"
25 #include "coe.h"
26 #include "lock.h"
27 #include "str.h"
28 #include "byte.h"
29 #include "scan.h"
30 #include "direntry.h"
31 #include "taia.h"
32 #include "fmt.h"
33 #include "ndelay.h"
34 #include "iopause.h"
35
36 #define USAGE " [-ttv] [-r c] [-R abc] [-l len] [-b buflen] dir ..."
37
38 #define FATAL "svlogd: fatal: "
39 #define WARNING "svlogd: warning: "
40 #define PAUSE "svlogd: pausing: "
41 #define INFO "svlogd: info: "
42
43 const char *progname;
44
45 unsigned int verbose =0;
46 unsigned int timestamp =0;
47 unsigned long linemax =1000;
48 unsigned long buflen =1024;
49 unsigned long linelen;
50
51 const char *replace ="";
52 char repl =0;
53
54 const char **fndir;
55 int fdwdir;
56 struct stat st;
57 stralloc sa;
58 int wstat;
59 struct taia now;
60 struct taia trotate;
61
62 char *databuf;
63 buffer data;
64 char *line;
65 char stamp[FMT_PTIME];
66 unsigned int exitasap =0;
67 unsigned int rotateasap =0;
68 unsigned int reopenasap =0;
69 unsigned int linecomplete =1;
70 unsigned int tmaxflag =0;
71 int fdudp =-1;
72 iopause_fd in;
73
74 struct logdir {
75 int fddir;
76 char *btmp;
77 buffer b;
78 stralloc inst;
79 unsigned long size;
80 unsigned long sizemax;
81 unsigned long nmax;
82 unsigned long nmin;
83 unsigned long tmax;
84 struct taia trotate;
85 stralloc processor;
86 int ppid;
87 char fnsave[FMT_PTIME];
88 char *name;
89 int fdcur;
90 int fdlock;
91 char match;
92 char matcherr;
93 struct sockaddr_in udpaddr;
94 unsigned int udponly;
95 stralloc prefix;
96 } *dir;
97 unsigned int dirn =0;
98
usage()99 void usage() { strerr_die4x(111, "usage: ", progname, USAGE, "\n"); }
die_nomem()100 void die_nomem() { strerr_die2x(111, FATAL, "out of memory."); }
fatal(char * m0)101 void fatal(char *m0) { strerr_die3sys(111, FATAL, m0, ": "); }
fatalx(char * m0)102 void fatalx(char *m0) { strerr_die2x(111, FATAL, m0); }
fatal2(char * m0,char * m1)103 void fatal2(char *m0, char *m1) {
104 strerr_die5sys(111, FATAL, m0, ": ", m1, ": ");
105 }
warn(char * m0)106 void warn(char *m0) { strerr_warn3(WARNING, m0, ": ", &strerr_sys); }
warn2(char * m0,char * m1)107 void warn2(char *m0, char *m1) {
108 strerr_warn5(WARNING, m0, ": ", m1, ": ", &strerr_sys);
109 }
warnx(char * m0,char * m1)110 void warnx(char *m0, char *m1) { strerr_warn4(WARNING, m0, ": ", m1, 0); }
pause_nomem()111 void pause_nomem() { strerr_warn2(PAUSE, "out of memory.", 0); sleep(3); }
pause1(char * m0)112 void pause1(char *m0) { strerr_warn3(PAUSE, m0, ": ", &strerr_sys); sleep(3); }
pause2(char * m0,char * m1)113 void pause2(char *m0, char *m1) {
114 strerr_warn5(PAUSE, m0, ": ", m1, ": ", &strerr_sys);
115 sleep(3);
116 }
117
processorstart(struct logdir * ld)118 unsigned int processorstart(struct logdir *ld) {
119 int pid;
120
121 if (! ld->processor.len) return(0);
122 if (ld->ppid) {
123 warnx("processor already running", ld->name);
124 return(0);
125 }
126 while ((pid =fork()) == -1)
127 pause2("unable to fork for processor", ld->name);
128 if (! pid) {
129 char *prog[4];
130 int fd;
131
132 /* child */
133 sig_uncatch(sig_term);
134 sig_uncatch(sig_alarm);
135 sig_uncatch(sig_hangup);
136 sig_unblock(sig_term);
137 sig_unblock(sig_alarm);
138 sig_unblock(sig_hangup);
139
140 if (verbose)
141 strerr_warn5(INFO, "processing: ", ld->name, "/", ld->fnsave, 0);
142 if ((fd =open_read(ld->fnsave)) == -1)
143 fatal2("unable to open input for processor", ld->name);
144 if (fd_move(0, fd) == -1)
145 fatal2("unable to move filedescriptor for processor", ld->name);
146 ld->fnsave[26] ='t';
147 if ((fd =open_trunc(ld->fnsave)) == -1)
148 fatal2("unable to open output for processor", ld->name);
149 if (fd_move(1, fd) == -1)
150 fatal2("unable to move filedescriptor for processor", ld->name);
151 if ((fd =open_read("state")) == -1) {
152 if (errno == error_noent) {
153 if ((fd =open_trunc("state")) == -1)
154 fatal2("unable to create empty state for processor", ld->name);
155 close(fd);
156 if ((fd =open_read("state")) == -1)
157 fatal2("unable to open state for processor", ld->name);
158 }
159 else
160 fatal2("unable to open state for processor", ld->name);
161 }
162 if (fd_move(4, fd) == -1)
163 fatal2("unable to move filedescriptor for processor", ld->name);
164 if ((fd =open_trunc("newstate")) == -1)
165 fatal2("unable to open newstate for processor", ld->name);
166 if (fd_move(5, fd) == -1)
167 fatal2("unable to move filedescriptor for processor", ld->name);
168
169 prog[0] = "sh";
170 prog[1] = "-c";
171 prog[2] = ld->processor.s;
172 prog[3] = 0;
173 execve("/bin/sh", prog, environ);
174 fatal2("unable to run processor", ld->name);
175 }
176 ld->ppid =pid;
177 return(1);
178 }
processorstop(struct logdir * ld)179 unsigned int processorstop(struct logdir *ld) {
180 char f[28];
181
182 if (ld->ppid) {
183 sig_unblock(sig_hangup);
184 while (wait_pid(&wstat, ld->ppid) == -1)
185 pause2("error waiting for processor", ld->name);
186 sig_block(sig_hangup);
187 ld->ppid =0;
188 }
189 if (ld->fddir == -1) return(1);
190 while (fchdir(ld->fddir) == -1)
191 pause2("unable to change directory, want processor", ld->name);
192 if (wait_exitcode(wstat) != 0) {
193 warnx("processor failed, restart", ld->name);
194 ld->fnsave[26] ='t';
195 unlink(ld->fnsave);
196 ld->fnsave[26] ='u';
197 processorstart(ld);
198 while (fchdir(fdwdir) == -1)
199 pause1("unable to change to initial working directory");
200 return(ld->processor.len ? 0 : 1);
201 }
202 ld->fnsave[26] ='t';
203 byte_copy(f, 26, ld->fnsave);
204 f[26] ='s'; f[27] =0;
205 while (rename(ld->fnsave, f) == -1)
206 pause2("unable to rename processed", ld->name);
207 while (chmod(f, 0744) == -1)
208 pause2("unable to set mode of processed", ld->name);
209 ld->fnsave[26] ='u';
210 if (unlink(ld->fnsave) == -1)
211 strerr_warn5(WARNING, "unable to unlink: ", ld->name, "/", ld->fnsave, 0);
212 while (rename("newstate", "state") == -1)
213 pause2("unable to rename state", ld->name);
214 if (verbose) strerr_warn5(INFO, "processed: ", ld->name, "/", f, 0);
215 while (fchdir(fdwdir) == -1)
216 pause1("unable to change to initial working directory");
217 return(1);
218 }
219
rmoldest(struct logdir * ld)220 void rmoldest(struct logdir *ld) {
221 DIR *d;
222 direntry *f;
223 char oldest[FMT_PTIME];
224 int n =0;
225
226 oldest[0] ='A'; oldest[1] =oldest[27] =0;
227 while (! (d =opendir(".")))
228 pause2("unable to open directory, want rotate", ld->name);
229 errno =0;
230 while ((f =readdir(d)))
231 if ((f->d_name[0] == '@') && (str_len(f->d_name) == 27)) {
232 if (f->d_name[26] == 't') {
233 if (unlink(f->d_name) == -1)
234 warn2("unable to unlink processor leftover", f->d_name);
235 }
236 else {
237 ++n;
238 if (str_diff(f->d_name, oldest) < 0) byte_copy(oldest, 27, f->d_name);
239 }
240 errno =0;
241 }
242 if (errno) warn2("unable to read directory", ld->name);
243 closedir(d);
244
245 if (ld->nmax && (n > ld->nmax)) {
246 if (verbose) strerr_warn5(INFO, "delete: ", ld->name, "/", oldest, 0);
247 if ((*oldest == '@') && (unlink(oldest) == -1))
248 warn2("unable to unlink oldest logfile", ld->name);
249 }
250 }
251
rotate(struct logdir * ld)252 unsigned int rotate(struct logdir *ld) {
253 char tmp[FMT_ULONG +1];
254
255 if (ld->fddir == -1) { ld->tmax =0; return(0); }
256 if (ld->ppid) while(! processorstop(ld));
257
258 while (fchdir(ld->fddir) == -1)
259 pause2("unable to change directory, want rotate", ld->name);
260
261 /* create new filename */
262 ld->fnsave[25] ='.';
263 if (ld->processor.len)
264 ld->fnsave[26] ='u';
265 else
266 ld->fnsave[26] ='s';
267 ld->fnsave[27] =0;
268 do {
269 taia_now(&now);
270 fmt_taia(ld->fnsave, &now);
271 errno =0;
272 } while ((stat(ld->fnsave, &st) != -1) || (errno != error_noent));
273
274 if (ld->tmax && taia_less(&ld->trotate, &now)) {
275 taia_uint(&ld->trotate, ld->tmax);
276 taia_add(&ld->trotate, &now, &ld->trotate);
277 if (taia_less(&ld->trotate, &trotate)) trotate =ld->trotate;
278 }
279
280 if (ld->size > 0) {
281 buffer_flush(&ld->b);
282 while (fsync(ld->fdcur) == -1)
283 pause2("unable to fsync current logfile", ld->name);
284 while (fchmod(ld->fdcur, 0744) == -1)
285 pause2("unable to set mode of current", ld->name);
286 close(ld->fdcur);
287 if (verbose) {
288 tmp[0] =' '; tmp[fmt_ulong(tmp +1, ld->size) +1] =0;
289 strerr_warn6(INFO, "rename: ", ld->name, "/current ",
290 ld->fnsave, tmp, 0);
291 }
292 while (rename("current", ld->fnsave) == -1)
293 pause2("unable to rename current", ld->name);
294 while ((ld->fdcur =open_append("current")) == -1)
295 pause2("unable to create new current", ld->name);
296 coe(ld->fdcur);
297 ld->size =0;
298 while (fchmod(ld->fdcur, 0644) == -1)
299 pause2("unable to set mode of current", ld->name);
300 rmoldest(ld);
301 processorstart(ld);
302 }
303
304 while (fchdir(fdwdir) == -1)
305 pause1("unable to change to initial working directory");
306 return(1);
307 }
308
buffer_pwrite(int n,char * s,unsigned int len)309 int buffer_pwrite(int n, char *s, unsigned int len) {
310 int i;
311
312 if ((dir +n)->sizemax) {
313 if ((dir +n)->size >= (dir +n)->sizemax) rotate(dir +n);
314 if (len > ((dir +n)->sizemax -(dir +n)->size))
315 len =(dir +n)->sizemax -(dir +n)->size;
316 }
317 while ((i =write((dir +n)->fdcur, s, len)) == -1) {
318 if ((errno == ENOSPC) && ((dir +n)->nmin < (dir +n)->nmax)) {
319 DIR *d;
320 direntry *f;
321 char oldest[FMT_PTIME];
322 int j =0;
323
324 while (fchdir((dir +n)->fddir) == -1)
325 pause2("unable to change directory, want remove old logfile",
326 (dir +n)->name);
327 oldest[0] ='A'; oldest[1] =oldest[27] =0;
328 while (! (d =opendir(".")))
329 pause2("unable to open directory, want remove old logfile",
330 (dir +n)->name);
331 errno =0;
332 while ((f =readdir(d)))
333 if ((f->d_name[0] == '@') && (str_len(f->d_name) == 27)) {
334 ++j;
335 if (str_diff(f->d_name, oldest) < 0)
336 byte_copy(oldest, 27, f->d_name);
337 }
338 if (errno) warn2("unable to read directory, want remove old logfile",
339 (dir +n)->name);
340 closedir(d);
341 errno =ENOSPC;
342 if (j > (dir +n)->nmin)
343 if (*oldest == '@') {
344 strerr_warn5(WARNING, "out of disk space, delete: ", (dir +n)->name,
345 "/", oldest, 0);
346 errno =0;
347 if (unlink(oldest) == -1) {
348 warn2("unable to unlink oldest logfile", (dir +n)->name);
349 errno =ENOSPC;
350 }
351 while (fchdir(fdwdir) == -1)
352 pause1("unable to change to initial working directory");
353 }
354 }
355 if (errno) pause2("unable to write to current", (dir +n)->name);
356 }
357
358 (dir +n)->size +=i;
359 if ((dir +n)->sizemax)
360 if (s[i -1] == '\n')
361 if ((dir +n)->size >= ((dir +n)->sizemax -linemax)) rotate(dir +n);
362 return(i);
363 }
364
logdir_close(struct logdir * ld)365 void logdir_close(struct logdir *ld) {
366 if (ld->fddir == -1) return;
367 if (verbose) strerr_warn3(INFO, "close: ", ld->name, 0);
368 close(ld->fddir);
369 ld->fddir =-1;
370 if (ld->fdcur == -1) return; /* impossible */
371 buffer_flush(&ld->b);
372 while (fsync(ld->fdcur) == -1)
373 pause2("unable to fsync current logfile", ld->name);
374 while (fchmod(ld->fdcur, 0744) == -1)
375 pause2("unable to set mode of current", ld->name);
376 close(ld->fdcur);
377 ld->fdcur =-1;
378 if (ld->fdlock == -1) return; /* impossible */
379 close(ld->fdlock);
380 ld->fdlock =-1;
381 while (! stralloc_copys(&ld->processor, "")) pause_nomem();
382 }
383
384 /* taken from libdjbdns */
ip4_scan(const char * s,char ip[4])385 unsigned int ip4_scan(const char *s,char ip[4])
386 {
387 unsigned int i;
388 unsigned int len;
389 unsigned long u;
390
391 len = 0;
392 i = scan_ulong(s,&u); if (!i) return 0; ip[0] = u; s += i; len += i;
393 if (*s != '.') return 0; ++s; ++len;
394 i = scan_ulong(s,&u); if (!i) return 0; ip[1] = u; s += i; len += i;
395 if (*s != '.') return 0; ++s; ++len;
396 i = scan_ulong(s,&u); if (!i) return 0; ip[2] = u; s += i; len += i;
397 if (*s != '.') return 0; ++s; ++len;
398 i = scan_ulong(s,&u); if (!i) return 0; ip[3] = u; s += i; len += i;
399 return len;
400 }
401
logdir_open(struct logdir * ld,const char * fn)402 unsigned int logdir_open(struct logdir *ld, const char *fn) {
403 int i;
404
405 if ((ld->fddir =open_read(fn)) == -1) {
406 warn2("unable to open log directory", (char*)fn);
407 return(0);
408 }
409 coe(ld->fddir);
410 if (fchdir(ld->fddir) == -1) {
411 logdir_close(ld);
412 warn2("unable to change directory", (char*)fn);
413 return(0);
414 }
415 ld->fdlock =open_append("lock");
416 if ((ld->fdlock == -1) || (lock_exnb(ld->fdlock) == -1)) {
417 logdir_close(ld);
418 warn2("unable to lock directory", (char*)fn);
419 while (fchdir(fdwdir) == -1)
420 pause1("unable to change to initial working directory");
421 return(0);
422 }
423 coe(ld->fdlock);
424
425 ld->size =0;
426 ld->sizemax =1000000;
427 ld->nmax =ld->nmin =10;
428 ld->tmax =0;
429 ld->name =(char*)fn;
430 ld->ppid =0;
431 ld->match ='+';
432 ld->udpaddr.sin_family =AF_INET;
433 ld->udpaddr.sin_port =0;
434 ld->udponly =0;
435 while (! stralloc_copys(&ld->prefix, "")) pause_nomem();
436 while (! stralloc_copys(&ld->inst, "")) pause_nomem();
437 while (! stralloc_copys(&ld->processor, "")) pause_nomem();
438
439 /* read config */
440 if ((i =openreadclose("config", &sa, 128)) == -1)
441 warn2("unable to read config", ld->name);
442 if (i != 0) {
443 int len, c;
444 unsigned long port;
445
446 if (verbose) strerr_warn4(INFO, "read: ", ld->name, "/config", 0);
447 for (i =0; i +1 < sa.len; ++i) {
448 len =byte_chr(&sa.s[i], sa.len -i, '\n');
449 sa.s[len +i] =0;
450 switch(sa.s[i]) {
451 case '\n':
452 case '#':
453 break;
454 case '+':
455 case '-':
456 case 'e':
457 case 'E':
458 while (! stralloc_catb(&ld->inst, &sa.s[i], len)) pause_nomem();
459 while (! stralloc_0(&ld->inst)) pause_nomem();
460 break;
461 case 's':
462 switch (sa.s[scan_ulong(&sa.s[i +1], &ld->sizemax) +i +1]) {
463 case 'm': ld->sizemax *=1024;
464 case 'k': ld->sizemax *=1024;
465 }
466 break;
467 case 'n':
468 scan_ulong(&sa.s[i +1], &ld->nmax);
469 break;
470 case 'N':
471 scan_ulong(&sa.s[i +1], &ld->nmin);
472 break;
473 case 't':
474 switch (sa.s[scan_ulong(&sa.s[i +1], &ld->tmax) +i +1]) {
475 /* case 'd': ld->tmax *=24; */
476 case 'h': ld->tmax *=60;
477 case 'm': ld->tmax *=60;
478 }
479 if (ld->tmax) {
480 taia_uint(&ld->trotate, ld->tmax);
481 taia_add(&ld->trotate, &now, &ld->trotate);
482 if (! tmaxflag || taia_less(&ld->trotate, &trotate))
483 trotate =ld->trotate;
484 tmaxflag =1;
485 }
486 break;
487 case '!':
488 if (len > 1) {
489 while (! stralloc_copys(&ld->processor, &sa.s[i +1])) pause_nomem();
490 while (! stralloc_0(&ld->processor)) pause_nomem();
491 }
492 break;
493 case 'U':
494 ld->udponly =1;
495 case 'u':
496 if (! (c =ip4_scan(sa.s +i +1, (char *)&ld->udpaddr.sin_addr))) {
497 warnx("unable to scan ip address", sa.s +i +1);
498 break;
499 }
500 if (sa.s[i +1 +c] == ':') {
501 scan_ulong(sa.s +i +c +2, &port);
502 if (port == 0) {
503 warnx("unable to scan port number", sa.s +i +c +2);
504 break;
505 }
506 }
507 else
508 port =514;
509 ld->udpaddr.sin_port =htons(port);
510 break;
511 case 'p':
512 if (len > 1) {
513 while (! stralloc_copys(&ld->prefix, &sa.s[i +1])) pause_nomem();
514 while (! stralloc_0(&ld->prefix)) pause_nomem();
515 }
516 break;
517 }
518 i +=len;
519 }
520 }
521
522 /* open current */
523 if ((i =stat("current", &st)) != -1) {
524 if (st.st_size && ! (st.st_mode & S_IXUSR)) {
525 ld->fnsave[25] ='.'; ld->fnsave[26] ='u'; ld->fnsave[27] =0;
526 do {
527 taia_now(&now);
528 fmt_taia(ld->fnsave, &now);
529 errno =0;
530 } while ((stat(ld->fnsave, &st) != -1) || (errno != error_noent));
531 while (rename("current", ld->fnsave) == -1)
532 pause2("unable to rename current", ld->name);
533 rmoldest(ld);
534 i =-1;
535 }
536 else
537 ld->size =st.st_size;
538 }
539 else
540 if (errno != error_noent) {
541 logdir_close(ld);
542 warn2("unable to stat current", ld->name);
543 while (fchdir(fdwdir) == -1)
544 pause1("unable to change to initial working directory");
545 return(0);
546 }
547 while ((ld->fdcur =open_append("current")) == -1)
548 pause2("unable to open current", ld->name);
549 coe(ld->fdcur);
550 while (fchmod(ld->fdcur, 0644) == -1)
551 pause2("unable to set mode of current", ld->name);
552 buffer_init(&ld->b, buffer_pwrite, ld -dir, ld->btmp, buflen);
553
554 if (verbose) {
555 if (i == 0) strerr_warn4(INFO, "append: ", ld->name, "/current", 0);
556 else strerr_warn4(INFO, "new: ", ld->name, "/current", 0);
557 }
558
559 while (fchdir(fdwdir) == -1)
560 pause1("unable to change to initial working directory");
561 return(1);
562 }
563
logdirs_reopen(void)564 void logdirs_reopen(void) {
565 int l;
566 int ok =0;
567
568 tmaxflag =0;
569 taia_now(&now);
570 for (l =0; l < dirn; ++l) {
571 logdir_close(&dir[l]);
572 if (logdir_open(&dir[l], fndir[l])) ok =1;
573 }
574 if (! ok) fatalx("no functional log directories.");
575 }
576
buffer_pread(int fd,char * s,unsigned int len)577 int buffer_pread(int fd, char *s, unsigned int len) {
578 int i;
579
580 for (i =0; i < dirn; ++i) buffer_flush(&dir[i].b);
581 if (rotateasap) {
582 for (i =0; i < dirn; ++i) rotate(dir +i);
583 rotateasap =0;
584 }
585 if (exitasap) {
586 if (linecomplete) return(0);
587 len =1;
588 }
589 if (reopenasap) {
590 logdirs_reopen();
591 reopenasap =0;
592 }
593 taia_now(&now);
594 taia_uint(&trotate, 2744);
595 taia_add(&trotate, &now, &trotate);
596 for (i =0; i < dirn; ++i)
597 if ((dir +i)->tmax) {
598 if (taia_less(&dir[i].trotate, &now)) rotate(dir +i);
599 if (taia_less(&dir[i].trotate, &trotate)) trotate =dir[i].trotate;
600 }
601 sig_unblock(sig_term);
602 sig_unblock(sig_child);
603 sig_unblock(sig_alarm);
604 sig_unblock(sig_hangup);
605 iopause(&in, 1, &trotate, &now);
606 sig_block(sig_term);
607 sig_block(sig_child);
608 sig_block(sig_alarm);
609 sig_block(sig_hangup);
610 i =read(fd, s, len);
611 if (i == -1) {
612 if (errno == error_again) errno =error_intr;
613 if (errno != error_intr) warn("unable to read standard input");
614 }
615 if (i > 0) linecomplete =(s[i -1] == '\n');
616 return(i);
617 }
sig_term_handler(void)618 void sig_term_handler(void) {
619 if (verbose) strerr_warn2(INFO, "sigterm received.", 0);
620 exitasap =1;
621 }
sig_child_handler(void)622 void sig_child_handler(void) {
623 int pid, l;
624
625 if (verbose) strerr_warn2(INFO, "sigchild received.", 0);
626 while ((pid =wait_nohang(&wstat)) > 0)
627 for (l =0; l < dirn; ++l)
628 if (dir[l].ppid == pid) {
629 dir[l].ppid =0;
630 processorstop(&dir[l]);
631 break;
632 }
633 }
sig_alarm_handler(void)634 void sig_alarm_handler(void) {
635 if (verbose) strerr_warn2(INFO, "sigalarm received.", 0);
636 rotateasap =1;
637 }
sig_hangup_handler(void)638 void sig_hangup_handler(void) {
639 if (verbose) strerr_warn2(INFO, "sighangup received.", 0);
640 reopenasap =1;
641 }
642
logmatch(struct logdir * ld)643 void logmatch(struct logdir *ld) {
644 int i;
645
646 ld->match ='+';
647 ld->matcherr ='E';
648 for (i =0; i < ld->inst.len; ++i) {
649 switch(ld->inst.s[i]) {
650 case '+':
651 case '-':
652 if (pmatch(&ld->inst.s[i +1], line, linelen))
653 ld->match =ld->inst.s[i];
654 break;
655 case 'e':
656 case 'E':
657 if (pmatch(&ld->inst.s[i +1], line, linelen))
658 ld->matcherr =ld->inst.s[i];
659 break;
660 }
661 i +=byte_chr(&ld->inst.s[i], ld->inst.len -i, 0);
662 }
663 }
main(int argc,const char ** argv)664 int main(int argc, const char **argv) {
665 int i;
666 int opt;
667
668 progname =*argv;
669
670 while ((opt =getopt(argc, argv, "R:r:l:b:tv")) != opteof) {
671 switch(opt) {
672 case 'R':
673 replace =optarg;
674 if (! repl) repl ='_';
675 break;
676 case 'r':
677 repl =*optarg;
678 if (! repl || *(optarg +1)) usage();
679 break;
680 case 'l':
681 scan_ulong(optarg, &linemax);
682 if (linemax == 0) linemax =1000;
683 break;
684 case 'b':
685 scan_ulong(optarg, &buflen);
686 if (buflen == 0) buflen =1024;
687 break;
688 case 't':
689 if (++timestamp > 3) timestamp =3;
690 break;
691 case 'v':
692 ++verbose;
693 break;
694 case '?': usage();
695 }
696 }
697 argv +=optind;
698
699 dirn =argc -optind;
700 if (dirn <= 0) usage();
701 if (buflen <= linemax) usage();
702 if ((fdwdir =open_read(".")) == -1)
703 fatal("unable to open current working directory");
704 coe(fdwdir);
705 dir =(struct logdir*)alloc(dirn *sizeof(struct logdir));
706 if (! dir) die_nomem();
707 for (i =0; i < dirn; ++i) {
708 dir[i].fddir =-1; dir[i].fdcur =-1;
709 dir[i].btmp =(char*)alloc(buflen *sizeof(char));
710 if (! dir[i].btmp) die_nomem();
711 dir[i].ppid =0;
712 }
713 databuf =(char*)alloc(buflen *sizeof(char));
714 if (! databuf) die_nomem();
715 buffer_init(&data, buffer_pread, 0, databuf, buflen);
716 line =(char*)alloc(linemax *sizeof(char));
717 if (! line) die_nomem();
718 fndir =argv;
719 in.fd =0;
720 in.events =IOPAUSE_READ;
721 ndelay_on(in.fd);
722
723 sig_block(sig_term);
724 sig_block(sig_child);
725 sig_block(sig_alarm);
726 sig_block(sig_hangup);
727 sig_catch(sig_term, sig_term_handler);
728 sig_catch(sig_child, sig_child_handler);
729 sig_catch(sig_alarm, sig_alarm_handler);
730 sig_catch(sig_hangup, sig_hangup_handler);
731
732 logdirs_reopen();
733
734 for(;;) {
735 char ch;
736
737 linelen =0;
738 for (linelen =0; linelen < linemax; ++linelen) {
739 if (buffer_GETC(&data, &ch) <= 0) {
740 exitasap =1;
741 break;
742 }
743 if (! linelen && timestamp) {
744 taia_now(&now);
745 switch (timestamp) {
746 case 1: fmt_taia(stamp, &now); break;
747 case 2: fmt_ptime(stamp, &now); break;
748 case 3: fmt_ptime_iso8601(stamp, &now); break;
749 }
750 stamp[25] =' '; stamp[26] =0;
751 }
752 if (ch == '\n') break;
753 if (repl) {
754 if ((ch < 32) || (ch > 126))
755 ch =repl;
756 else
757 for (i =0; replace[i]; ++i)
758 if (ch == replace[i]) {
759 ch =repl;
760 break;
761 }
762 }
763 line[linelen] =ch;
764 }
765 if (exitasap && ! data.p) break; /* data buffer is empty */
766 for (i =0; i < dirn; ++i)
767 if (dir[i].fddir != -1) {
768 if (dir[i].inst.len) logmatch(&dir[i]);
769 if (dir[i].matcherr == 'e') {
770 if (timestamp) buffer_puts(buffer_2, stamp);
771 if (dir[i].prefix.len) buffer_puts(buffer_2, dir[i].prefix.s);
772 buffer_put(buffer_2, line, linelen);
773 if (linelen == linemax) buffer_puts(buffer_2, "...");
774 buffer_put(buffer_2, "\n", 1); buffer_flush(buffer_2);
775 }
776 if (dir[i].match != '+') continue;
777 if (dir[i].udpaddr.sin_port != 0) {
778 fdudp =socket(AF_INET, SOCK_DGRAM, 0);
779 if (fdudp)
780 if (ndelay_on(fdudp) == -1) {
781 close(fdudp);
782 fdudp =-1;
783 }
784 if (fdudp == -1) {
785 buffer_puts(&dir[i].b, "warning: no udp socket available: ");
786 if (timestamp) buffer_puts(&dir[i].b, stamp);
787 if (dir[i].prefix.len) buffer_puts(&dir[i].b, dir[i].prefix.s);
788 buffer_put(&dir[i].b, line, linelen);
789 buffer_put(&dir[i].b, "\n", 1);
790 buffer_flush(&dir[i].b);
791 }
792 else {
793 while (! stralloc_copys(&sa, "")) pause_nomem();
794 if (timestamp)
795 while (! stralloc_cats(&sa, stamp)) pause_nomem();
796 if (dir[i].prefix.len)
797 while (! stralloc_cats(&sa, dir[i].prefix.s)) pause_nomem();
798 while (! stralloc_catb(&sa, line, linelen)) pause_nomem();
799 if (linelen == linemax)
800 while (! stralloc_cats(&sa, "...")) pause_nomem();
801 while (! stralloc_append(&sa, "\n")) pause_nomem();
802 if (sendto(fdudp, sa.s, sa.len, 0,
803 (struct sockaddr *)&dir[i].udpaddr,
804 sizeof(dir[i].udpaddr)) != sa.len) {
805 buffer_puts(&dir[i].b, "warning: failure sending through udp: ");
806 buffer_put(&dir[i].b, sa.s, sa.len);
807 buffer_flush(&dir[i].b);
808 }
809 close(fdudp);
810 }
811 }
812 if (! dir[i].udponly) {
813 if (timestamp) buffer_puts(&dir[i].b, stamp);
814 if (dir[i].prefix.len) buffer_puts(&dir[i].b, dir[i].prefix.s);
815 buffer_put(&dir[i].b, line, linelen);
816 }
817 }
818 if (linelen == linemax)
819 for (;;) {
820 if (buffer_GETC(&data, &ch) <= 0) {
821 exitasap =1;
822 break;
823 }
824 if (ch == '\n') break;
825 for (i =0; i < dirn; ++i)
826 if (dir[i].fddir != -1) {
827 if (dir[i].match != '+') continue;
828 if (! dir[i].udponly) buffer_PUTC(&dir[i].b, ch);
829 }
830 }
831 for (i =0; i < dirn; ++i)
832 if (dir[i].fddir != -1) {
833 if (dir[i].match != '+') continue;
834 if (! dir[i].udponly) {
835 ch ='\n';
836 buffer_PUTC(&dir[i].b, ch);
837 buffer_flush(&dir[i].b);
838 }
839 }
840 }
841
842 for (i =0; i < dirn; ++i) {
843 if (dir[i].ppid) while (! processorstop(&dir[i]));
844 logdir_close(&dir[i]);
845 }
846 _exit(0);
847 }
848