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