runit

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

svlogd.c (25555B)


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