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