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