summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorGerrit Pape <pape@smarden.org>2004-11-06 15:38:33 +0000
committerGerrit Pape <pape@smarden.org>2004-11-06 15:38:33 +0000
commit71af2a32da251505d02769a32c979d5ccd1e49fa (patch)
tree8a1eb1b91e2801036fad734777dc9cae340fb552 /src
parent267ae0374a33530cd6641d69ae6c115db23f30b6 (diff)
downloadrunit-71af2a32da251505d02769a32c979d5ccd1e49fa.tar.gz
runit-71af2a32da251505d02769a32c979d5ccd1e49fa.tar.xz
runit-71af2a32da251505d02769a32c979d5ccd1e49fa.zip
* svlogd.c: new config option t timeout; config options e and E select and
    deselect lines for stderr respectively; new config option N.
  * man/svlogd.8: adapt.
  * runsv.c: on commands down and exit send CONT after TERM.
  * man/runsv.8: adapt.
  * etc/2: use -P option to runsvdir.
  * src/svlogd.check: end check for t config option.
  * chpst.c: new option -n: adjust nice level.
  * man/chpst.8: adapt.
Diffstat (limited to 'src')
-rw-r--r--src/chpst.c37
-rw-r--r--src/runsv.c113
-rw-r--r--src/svlogd.c438
-rwxr-xr-xsrc/svlogd.check6
4 files changed, 350 insertions, 244 deletions
diff --git a/src/chpst.c b/src/chpst.c
index 1b0e33e..5ab405a 100644
--- a/src/chpst.c
+++ b/src/chpst.c
@@ -20,7 +20,7 @@
 #include "openreadclose.h"
 #include "direntry.h"
 
-#define USAGE_MAIN " [-vP012] [-u user[:group]] [-U user[:group]] [-e dir] [-/ root] [-l|-L lock] [-m n] [-o n] [-p n] [-f n] [-c n] prog"
+#define USAGE_MAIN " [-vP012] [-u user[:group]] [-U user[:group]] [-e dir] [-/ root] [-n nice] [-l|-L lock] [-m n] [-o n] [-p n] [-f n] [-c n] prog"
 #define FATAL "chpst: fatal: "
 #define WARNING "chpst: warning: "
 
@@ -56,6 +56,7 @@ long limitf =-2;
 long limitc =-2;
 long limitr =-2;
 long limitt =-2;
+long nicelvl =0;
 const char *lock =0;
 const char *root =0;
 unsigned int lockdelay;
@@ -109,19 +110,19 @@ void edir(const char *dirname) {
     if (d->d_name[0] == '.') continue;
     if (openreadclose(d->d_name, &sa, 256) == -1) {
       if ((errno == error_isdir) && env_dir) {
-	if (verbose)
-	  strerr_warn6(WARNING, "unable to read ", dirname, "/",
-	               d->d_name, ": ", &strerr_sys);
-	continue;
+        if (verbose)
+          strerr_warn6(WARNING, "unable to read ", dirname, "/",
+                       d->d_name, ": ", &strerr_sys);
+        continue;
       }
       else
         strerr_die6sys(111, FATAL, "unable to read ", dirname, "/",
-	      	       d->d_name, ": ");
+                             d->d_name, ": ");
     }
     if (sa.len) {
       sa.len =byte_chr(sa.s, sa.len, '\n');
       while (sa.len && (sa.s[sa.len -1] == ' ' || sa.s[sa.len -1] == '\t'))
-	--sa.len;
+        --sa.len;
       for (i =0; i < sa.len; ++i) if (! sa.s[i]) sa.s[i] ='\n';
       if (! stralloc_0(&sa)) die_nomem();
       if (! pathexec_env(d->d_name, sa.s)) die_nomem();
@@ -271,8 +272,8 @@ int main(int argc, const char *const *argv) {
   if (str_equal(progname, "setlock")) setlock(argc, argv);
   if (str_equal(progname, "softlimit")) softlimit(argc, argv);
 
-  while ((opt =getopt(argc, argv, "u:U:e:m:o:p:f:c:r:t:/:l:L:vP012V"))
-	 != opteof)
+  while ((opt =getopt(argc, argv, "u:U:e:m:o:p:f:c:r:t:/:n:l:L:vP012V"))
+         != opteof)
     switch(opt) {
     case 'u': set_user =(char*)optarg; break;
     case 'U': env_user =(char*)optarg; break;
@@ -288,6 +289,18 @@ int main(int argc, const char *const *argv) {
     case 'r': if (optarg[scan_ulong(optarg, &limitr)]) usage(); break;
     case 't': if (optarg[scan_ulong(optarg, &limitt)]) usage(); break;
     case '/': root =optarg; break;
+    case 'n':
+      switch (*optarg) {
+        case '-':
+          if (optarg[scan_ulong(++optarg, &nicelvl)]) usage();
+          nicelvl *=-1;
+          break;
+        case '+': ++optarg;
+        default:
+          if (optarg[scan_ulong(optarg, &nicelvl)]) usage();
+          break;
+      }
+      break;
     case 'l': if (lock) usage(); lock =optarg; lockdelay =1; break;
     case 'L': if (lock) usage(); lock =optarg; lockdelay =0; break;
     case 'v': verbose =1; break;
@@ -314,7 +327,11 @@ int main(int argc, const char *const *argv) {
   if (nostdin) if (close(0) == -1) fatal("unable to close stdin");
   if (nostdout) if (close(1) == -1) fatal("unable to close stdout");
   if (nostderr) if (close(2) == -1) fatal("unable to close stderr");
-
+  if (nicelvl) {
+    errno =0;
+    if (nice(nicelvl) == -1)
+      if (errno) fatal("unable to set nice level");
+  }
   pathexec(argv);
   fatal2("unable to run", *argv);
   return(0);
diff --git a/src/runsv.c b/src/runsv.c
index 6072664..3e826aa 100644
--- a/src/runsv.c
+++ b/src/runsv.c
@@ -105,14 +105,14 @@ void update_status(struct svdir *s) {
     close(fd);
     if (s->islog) {
       if (rename("supervise/pid.new", "log/supervise/pid") == -1) {
-	warn("unable to rename supervise/pid.new to log/supervise/pid");
-	return;
+        warn("unable to rename supervise/pid.new to log/supervise/pid");
+        return;
       }
     }
     else {
       if (rename("supervise/pid.new", "supervise/pid") == -1) {
-	warn("unable to rename supervise/pid.new to supervise/pid");
-	return;
+        warn("unable to rename supervise/pid.new to supervise/pid");
+        return;
       }
     }
     pidchanged =0;
@@ -205,6 +205,7 @@ void stopservice(struct svdir *s) {
   if (s->pid) kill(s->pid, SIGTERM);
   s->ctrl |=C_TERM;
   update_status(s);
+  if ((s->want == W_DOWN) || (s->want == W_EXIT)) kill(s->pid, SIGCONT);
 }
 
 void startservice(struct svdir *s) {
@@ -226,16 +227,16 @@ void startservice(struct svdir *s) {
     /* child */
     if (haslog) {
       if (s->islog) {
-	if (fd_copy(0, logpipe[0]) == -1)
-	  fatal("unable to setup filedescriptor for ./log/run");
-	close(logpipe[1]);
-	if (chdir("./log") == -1)
-	  fatal("unable to change directory to ./log");	
+        if (fd_copy(0, logpipe[0]) == -1)
+          fatal("unable to setup filedescriptor for ./log/run");
+        close(logpipe[1]);
+        if (chdir("./log") == -1)
+          fatal("unable to change directory to ./log");        
       }
       else {
-	if (fd_copy(1, logpipe[1]) == -1)
-	  fatal("unable to setup filedescriptor for ./run");
-	close(logpipe[0]);
+        if (fd_copy(1, logpipe[1]) == -1)
+          fatal("unable to setup filedescriptor for ./run");
+        close(logpipe[0]);
       }
     }
     sig_uncatch(sig_child);
@@ -367,9 +368,9 @@ int main(int argc, char **argv) {
       svd[1].islog =1;
       taia_now(&svd[1].start);
       if (stat("log/down", &s) != -1)
-	svd[1].want =W_DOWN;
+        svd[1].want =W_DOWN;
       if (pipe(logpipe) == -1)
-	fatal("unable to create log pipe");
+        fatal("unable to create log pipe");
       coe(logpipe[0]);
       coe(logpipe[1]);
     }
@@ -378,13 +379,13 @@ int main(int argc, char **argv) {
   if (mkdir("supervise", 0700) == -1) {
     if ((r =readlink("supervise", buf, 256)) != -1) {
       if (r == 256)
-	fatalx("unable to readlink ./supervise: ", "name too long");
+        fatalx("unable to readlink ./supervise: ", "name too long");
       buf[r] =0;
       mkdir(buf, 0700);
     }
     else {
       if ((errno != ENOENT) && (errno != EINVAL))
-	fatal("unable to readlink ./supervise");
+        fatal("unable to readlink ./supervise");
     }
   }
   if ((svd[0].fdlock =open_append("supervise/lock")) == -1)
@@ -394,21 +395,21 @@ int main(int argc, char **argv) {
   if (haslog) {
     if (mkdir("log/supervise", 0700) == -1) {
       if ((r =readlink("log/supervise", buf, 256)) != -1) {
-	if (r == 256)
-	  fatalx("unable to readlink ./log/supervise: ", "name too long");
-	buf[r] =0;
-	if ((fd =open_read(".")) == -1)
-	  fatal("unable to open current directory");
-	if (chdir("./log") == -1)
-	  fatal("unable to change directory to ./log"); 
-	mkdir(buf, 0700);
-	if (fchdir(fd) == -1)
-	  fatal("unable to change back to service directory");
-	close(fd);
+        if (r == 256)
+          fatalx("unable to readlink ./log/supervise: ", "name too long");
+        buf[r] =0;
+        if ((fd =open_read(".")) == -1)
+          fatal("unable to open current directory");
+        if (chdir("./log") == -1)
+          fatal("unable to change directory to ./log"); 
+        mkdir(buf, 0700);
+        if (fchdir(fd) == -1)
+          fatal("unable to change back to service directory");
+        close(fd);
       }
       else {
-	if ((errno != ENOENT) && (errno != EINVAL))
-	  fatal("unable to readlink ./log/supervise");
+        if ((errno != ENOENT) && (errno != EINVAL))
+          fatal("unable to readlink ./log/supervise");
       }
     }
     if ((svd[1].fdlock =open_append("log/supervise/lock")) == -1)
@@ -456,7 +457,7 @@ int main(int argc, char **argv) {
       if (! svd[1].pid && (svd[1].want == W_UP)) startservice(&svd[1]);
     if (! svd[0].pid)
       if ((svd[0].want == W_UP) || (svd[0].state == S_FINISH))
-	startservice(&svd[0]);
+        startservice(&svd[0]);
 
     x[0].fd =selfpipe[0];
     x[0].events =IOPAUSE_READ;
@@ -486,29 +487,29 @@ int main(int argc, char **argv) {
       if (!child) break;
       if ((child == -1) && (errno != error_intr)) break;
       if (child == svd[0].pid) {
-	svd[0].pid =0;
-	pidchanged =1;
-	svd[0].ctrl &=~C_TERM;
-	taia_now(&svd[0].start);
-	if (svd[0].state != S_FINISH)
-	  if ((fd =open_read("finish")) != -1) {
-	    close(fd);
-	    svd[0].state =S_FINISH;
-	    update_status(&svd[0]);
-	    break;
-	  }
-	svd[0].state =S_DOWN;
-	update_status(&svd[0]);
+        svd[0].pid =0;
+        pidchanged =1;
+        svd[0].ctrl &=~C_TERM;
+        taia_now(&svd[0].start);
+        if (svd[0].state != S_FINISH)
+          if ((fd =open_read("finish")) != -1) {
+            close(fd);
+            svd[0].state =S_FINISH;
+            update_status(&svd[0]);
+            break;
+          }
+        svd[0].state =S_DOWN;
+        update_status(&svd[0]);
       }
       if (haslog) {
-	if (child == svd[1].pid) {
-	  svd[1].pid =0;
-	  pidchanged =1;
-	  svd[1].state =S_DOWN;
-	  svd[1].ctrl &=~C_TERM;
-	  taia_now(&svd[1].start);
-	  update_status(&svd[1]);
-	}
+        if (child == svd[1].pid) {
+          svd[1].pid =0;
+          pidchanged =1;
+          svd[1].state =S_DOWN;
+          svd[1].ctrl &=~C_TERM;
+          taia_now(&svd[1].start);
+          update_status(&svd[1]);
+        }
       }
     }
     if (read(svd[0].fdcontrol, &ch, 1) == 1) ctrl(&svd[0], ch);
@@ -518,11 +519,11 @@ int main(int argc, char **argv) {
     if (svd[0].want == W_EXIT && svd[0].state == S_DOWN) {
       if (svd[1].pid == 0) _exit(0);
       if (svd[1].want != W_EXIT) {
-	svd[1].want =W_EXIT;
-	/* stopservice(&svd[1]); */
-	update_status(&svd[1]);
-	if (close(logpipe[1]) == -1) warn("unable to close logpipe[1]");
-	if (close(logpipe[0]) == -1) warn("unable to close logpipe[0]");
+        svd[1].want =W_EXIT;
+        /* stopservice(&svd[1]); */
+        update_status(&svd[1]);
+        if (close(logpipe[1]) == -1) warn("unable to close logpipe[1]");
+        if (close(logpipe[0]) == -1) warn("unable to close logpipe[0]");
       }
     }
   }
diff --git a/src/svlogd.c b/src/svlogd.c
index 7b9275a..f6cf68b 100644
--- a/src/svlogd.c
+++ b/src/svlogd.c
@@ -31,8 +31,9 @@
 #include "taia.h"
 #include "fmt.h"
 #include "ndelay.h"
+#include "iopause.h"
 
-#define USAGE " [-tv] [-r c] [-R abc] [-l n ] [-b n] dir ..."
+#define USAGE " [-ttv] [-r c] [-R abc] [-l len] [-b buflen] dir ..."
 #define VERSION "$Id$"
 
 #define FATAL "svlogd: fatal: "
@@ -57,6 +58,7 @@ struct stat st;
 stralloc sa;
 int wstat;
 struct taia now;
+struct taia trotate;
 
 char *databuf;
 buffer data;
@@ -66,7 +68,9 @@ unsigned int exitasap =0;
 unsigned int rotateasap =0;
 unsigned int reopenasap =0;
 unsigned int linecomplete =1;
+unsigned int tmaxflag =0;
 int fdudp =-1;
+iopause_fd in;
 
 struct logdir {
   int fddir;
@@ -76,6 +80,9 @@ struct logdir {
   unsigned long size;
   unsigned long sizemax;
   unsigned long nmax;
+  unsigned long nmin;
+  unsigned long tmax;
+  struct taia trotate;
   stralloc processor;
   int ppid;
   char fnsave[FMT_PTIME];
@@ -83,6 +90,7 @@ struct logdir {
   int fdcur;
   int fdlock;
   char match;
+  char matcherr;
   struct sockaddr_in udpaddr;
   unsigned int udponly;
 } *dir;
@@ -142,14 +150,14 @@ unsigned int processorstart(struct logdir *ld) {
       fatal2("unable to move filedescriptor for processor", ld->name);
     if ((fd =open_read("state")) == -1) {
       if (errno == error_noent) {
-	if ((fd =open_trunc("state")) == -1)
-	  fatal2("unable to create empty state for processor", ld->name);
-	close(fd);
-	if ((fd =open_read("state")) == -1)
-	  fatal2("unable to open state for processor", ld->name);
+        if ((fd =open_trunc("state")) == -1)
+          fatal2("unable to create empty state for processor", ld->name);
+        close(fd);
+        if ((fd =open_read("state")) == -1)
+          fatal2("unable to open state for processor", ld->name);
       }
       else
-	fatal2("unable to open state for processor", ld->name);
+        fatal2("unable to open state for processor", ld->name);
     }
     if (fd_move(4, fd) == -1)
       fatal2("unable to move filedescriptor for processor", ld->name);
@@ -215,8 +223,7 @@ unsigned int rotate(struct logdir *ld) {
   char tmp[FMT_ULONG +1];
   char oldest[FMT_PTIME];
 
-  if (ld->fddir == -1) return(0);
-  if (ld->size <= 0) return(1);
+  if (ld->fddir == -1) { ld->tmax =0; return(0); }
   if (ld->ppid) while(! processorstop(ld));
 
   while (fchdir(ld->fddir) == -1)
@@ -235,45 +242,53 @@ unsigned int rotate(struct logdir *ld) {
     errno =0;
   } while ((stat(ld->fnsave, &st) != -1) || (errno != error_noent));
 
-  buffer_flush(&ld->b);
-  while (fsync(ld->fdcur) == -1)
-    pause2("unable to fsync current logfile", ld->name);
-  while (fchmod(ld->fdcur, 0744) == -1)
-    pause2("unable to set mode of current", ld->name);
-  close(ld->fdcur);
-  if (verbose) {
-    tmp[0] =' '; tmp[fmt_ulong(tmp +1, ld->size) +1] =0;
-    strerr_warn6(INFO, "rename: ", ld->name, "/current ",
-		 ld->fnsave, tmp, 0);
+  if (ld->tmax && taia_less(&ld->trotate, &now)) {
+    taia_uint(&ld->trotate, ld->tmax);
+    taia_add(&ld->trotate, &now, &ld->trotate);
+    if (taia_less(&ld->trotate, &trotate)) trotate =ld->trotate;
   }
-  while (rename("current", ld->fnsave) == -1)
-    pause2("unable to rename current", ld->name);
-  while ((ld->fdcur =open_append("current")) == -1)
-    pause2("unable to create new current", ld->name);
-  coe(ld->fdcur);
-  ld->size =0;
-  while (fchmod(ld->fdcur, 0644) == -1)
-    pause2("unable to set mode of current", ld->name);
 
-  oldest[0] ='A'; oldest[1] =oldest[27] =0;
-  while (! (d =opendir(".")))
-    pause2("unable to open directory, want rotate", ld->name);
-  errno =0;
-  while ((f =readdir(d)))
-    if ((f->d_name[0] == '@') && (str_len(f->d_name) == 27)) {
-      ++n;
-      if (str_diff(f->d_name, oldest) < 0) byte_copy(oldest, 27, f->d_name);
+  if (ld->size > 0) {
+    buffer_flush(&ld->b);
+    while (fsync(ld->fdcur) == -1)
+      pause2("unable to fsync current logfile", ld->name);
+    while (fchmod(ld->fdcur, 0744) == -1)
+      pause2("unable to set mode of current", ld->name);
+    close(ld->fdcur);
+    if (verbose) {
+      tmp[0] =' '; tmp[fmt_ulong(tmp +1, ld->size) +1] =0;
+      strerr_warn6(INFO, "rename: ", ld->name, "/current ",
+                   ld->fnsave, tmp, 0);
     }
-  if (errno) warn2("unable to read directory", ld->name);
-  closedir(d);
-  
-  if (ld->nmax && (n >= ld->nmax)) {
-    if (verbose) strerr_warn5(INFO, "delete: ", ld->name, "/", oldest, 0);
-    if ((*oldest == '@') && (unlink(oldest) == -1))
-      warn2("unable to unlink oldest logfile", ld->name);
+    while (rename("current", ld->fnsave) == -1)
+      pause2("unable to rename current", ld->name);
+    while ((ld->fdcur =open_append("current")) == -1)
+      pause2("unable to create new current", ld->name);
+    coe(ld->fdcur);
+    ld->size =0;
+    while (fchmod(ld->fdcur, 0644) == -1)
+      pause2("unable to set mode of current", ld->name);
+    
+    oldest[0] ='A'; oldest[1] =oldest[27] =0;
+    while (! (d =opendir(".")))
+      pause2("unable to open directory, want rotate", ld->name);
+    errno =0;
+    while ((f =readdir(d)))
+      if ((f->d_name[0] == '@') && (str_len(f->d_name) == 27)) {
+        ++n;
+        if (str_diff(f->d_name, oldest) < 0) byte_copy(oldest, 27, f->d_name);
+      }
+    if (errno) warn2("unable to read directory", ld->name);
+    closedir(d);
+    
+    if (ld->nmax && (n >= ld->nmax)) {
+      if (verbose) strerr_warn5(INFO, "delete: ", ld->name, "/", oldest, 0);
+      if ((*oldest == '@') && (unlink(oldest) == -1))
+        warn2("unable to unlink oldest logfile", ld->name);
+    }
+    processorstart(ld);
   }
 
-  processorstart(ld);
   while (fchdir(fdwdir) == -1)
     pause1("unable to change to initial working directory");
   return(1);
@@ -287,8 +302,47 @@ int buffer_pwrite(int n, char *s, unsigned int len) {
     if (len > ((dir +n)->sizemax -(dir +n)->size))
       len =(dir +n)->sizemax -(dir +n)->size;
   }
-  while ((i =write((dir +n)->fdcur, s, len)) == -1)
-    pause2("unable to write to current", (dir +n)->name);
+  while ((i =write((dir +n)->fdcur, s, len)) == -1) {
+    if ((errno == ENOSPC) && ((dir +n)->nmin < (dir +n)->nmax)) {
+      DIR *d;
+      direntry *f;
+      char oldest[FMT_PTIME];
+      int j =0;
+
+      while (fchdir((dir +n)->fddir) == -1)
+        pause2("unable to change directory, want remove old logfile",
+               (dir +n)->name);
+      oldest[0] ='A'; oldest[1] =oldest[27] =0;
+      while (! (d =opendir(".")))
+        pause2("unable to open directory, want remove old logfile",
+               (dir +n)->name);
+      errno =0;
+      while ((f =readdir(d)))
+        if ((f->d_name[0] == '@') && (str_len(f->d_name) == 27)) {
+          ++j;
+          if (str_diff(f->d_name, oldest) < 0)
+            byte_copy(oldest, 27, f->d_name);
+        }
+      if (errno) warn2("unable to read directory, want remove old logfile",
+                       (dir +n)->name);
+      closedir(d);
+      errno =ENOSPC;
+      if (j > (dir +n)->nmin)
+        if (*oldest == '@') {
+          strerr_warn5(WARNING, "out of disk space, delete: ", (dir +n)->name,
+                       "/", oldest, 0);
+          errno =0;
+          if (unlink(oldest) == -1) {
+            warn2("unable to unlink oldest logfile", (dir +n)->name);
+            errno =ENOSPC;
+          }
+          while (fchdir(fdwdir) == -1)
+            pause1("unable to change to initial working directory");
+        }
+    }
+    if (errno) pause2("unable to write to current", (dir +n)->name);
+  }
+
   (dir +n)->size +=i;
   if ((dir +n)->sizemax)
     if (s[i -1] == '\n')
@@ -358,7 +412,8 @@ unsigned int logdir_open(struct logdir *ld, const char *fn) {
 
   ld->size =0;
   ld->sizemax =1000000;
-  ld->nmax =10;
+  ld->nmax =ld->nmin =10;
+  ld->tmax =0;
   ld->name =(char*)fn;
   ld->ppid =0;
   ld->match ='+';
@@ -377,57 +432,76 @@ unsigned int logdir_open(struct logdir *ld, const char *fn) {
     if (verbose) strerr_warn4(INFO, "read: ", ld->name, "/config", 0);
     for (i =0; i +1 < sa.len; ++i) {
       if ((len =byte_chr(&sa.s[i], sa.len -i, '\n')) == 1) {
-	++i; continue;
+        ++i; continue;
       }
       sa.s[len +i] =0;
       switch(sa.s[i]) {
       case '\n':
       case '#':
-	 break;
+         break;
       case '+':
       case '-':
       case 'e':
       case 'E':
-	while (! stralloc_catb(&ld->inst, &sa.s[i], len)) pause_nomem();
-	while (! stralloc_0(&ld->inst)) pause_nomem();
-	break;
+        while (! stralloc_catb(&ld->inst, &sa.s[i], len)) pause_nomem();
+        while (! stralloc_0(&ld->inst)) pause_nomem();
+        break;
       case 's':
-	scan_ulong(&sa.s[i +1], &ld->sizemax);
-	break;
+        switch (sa.s[scan_ulong(&sa.s[i +1], &ld->sizemax) +i +1]) {
+        case 'm': ld->sizemax *=1024;
+        case 'k': ld->sizemax *=1024;
+        }
+        break;
       case 'n':
-	scan_ulong(&sa.s[i +1], &ld->nmax);
-	if (ld->nmax == 1) ld->nmax =2;
-	break;
+        scan_ulong(&sa.s[i +1], &ld->nmax);
+        break;
+      case 'N':
+        scan_ulong(&sa.s[i +1], &ld->nmin);
+        break;
+      case 't':
+        switch (sa.s[scan_ulong(&sa.s[i +1], &ld->tmax) +i +1]) {
+        /* case 'd': ld->tmax *=24; */
+        case 'h': ld->tmax *=60;
+        case 'm': ld->tmax *=60;
+        }
+        if (ld->tmax) {
+          taia_uint(&ld->trotate, ld->tmax);
+          taia_add(&ld->trotate, &now, &ld->trotate);
+          if (! tmaxflag || taia_less(&ld->trotate, &trotate))
+            trotate =ld->trotate;
+          tmaxflag =1;
+        }
+        break;
       case '!':
-	while (! stralloc_copys(&ld->processor, &sa.s[i +1])) pause_nomem();
-	while (! stralloc_0(&ld->processor)) pause_nomem();
-	break;
+        while (! stralloc_copys(&ld->processor, &sa.s[i +1])) pause_nomem();
+        while (! stralloc_0(&ld->processor)) pause_nomem();
+        break;
       case 'U':
-	ld->udponly =1;
+        ld->udponly =1;
       case 'u':
-	if (! (c =ip4_scan(sa.s +i +1, (char *)&ld->udpaddr.sin_addr))) {
-	  warnx("unable to scan ip address", sa.s +i +1);
-	  break;
-	}
-	if (sa.s[i +1 +c] == ':') {
-	  scan_ulong(sa.s +i +c +2, &port);
-	  if (port == 0) {
-	    warnx("unable to scan port number", sa.s +i +c +2);
-	    break;
-	  }
-	}
-	else
-	  port =514;
-	ld->udpaddr.sin_port =htons(port);
-	if (fdudp == -1) {
-       	  fdudp =socket(AF_INET, SOCK_DGRAM, 0);
-	  if (fdudp)
-	    if (ndelay_on(fdudp) == -1) {
-	      close(fdudp);
-	      fdudp =-1;
-	    }
-	}
-	break;
+        if (! (c =ip4_scan(sa.s +i +1, (char *)&ld->udpaddr.sin_addr))) {
+          warnx("unable to scan ip address", sa.s +i +1);
+          break;
+        }
+        if (sa.s[i +1 +c] == ':') {
+          scan_ulong(sa.s +i +c +2, &port);
+          if (port == 0) {
+            warnx("unable to scan port number", sa.s +i +c +2);
+            break;
+          }
+        }
+        else
+          port =514;
+        ld->udpaddr.sin_port =htons(port);
+        if (fdudp == -1) {
+                 fdudp =socket(AF_INET, SOCK_DGRAM, 0);
+          if (fdudp)
+            if (ndelay_on(fdudp) == -1) {
+              close(fdudp);
+              fdudp =-1;
+            }
+        }
+        break;
       }
       i +=len;
     }
@@ -438,12 +512,12 @@ unsigned int logdir_open(struct logdir *ld, const char *fn) {
     if (st.st_size && ! (st.st_mode & S_IXUSR)) {
       ld->fnsave[25] ='.'; ld->fnsave[26] ='u'; ld->fnsave[27] =0;
       do {
-	taia_now(&now);
-	fmt_taia(ld->fnsave, &now);
-	errno =0;
+        taia_now(&now);
+        fmt_taia(ld->fnsave, &now);
+        errno =0;
       } while ((stat(ld->fnsave, &st) != -1) || (errno != error_noent));
       while (rename("current", ld->fnsave) == -1)
-	pause2("unable to rename current", ld->name);
+        pause2("unable to rename current", ld->name);
       i =-1;
     }
     else
@@ -454,7 +528,7 @@ unsigned int logdir_open(struct logdir *ld, const char *fn) {
       logdir_close(ld);
       warn2("unable to stat current", ld->name);
       while (fchdir(fdwdir) == -1)
-	pause1("unable to change to initial working directory");
+        pause1("unable to change to initial working directory");
       return(0);
     }
   while ((ld->fdcur =open_append("current")) == -1)
@@ -478,6 +552,8 @@ void logdirs_reopen(void) {
   int l;
   int ok =0;
 
+  tmaxflag =0;
+  taia_now(&now);
   for (l =0; l < dirn; ++l) {
     logdir_close(&dir[l]);    
     if (logdir_open(&dir[l], fndir[l])) ok =1;
@@ -501,16 +577,28 @@ int buffer_pread(int fd, char *s, unsigned int len) {
     logdirs_reopen();
     reopenasap =0;
   }
+  taia_now(&now);
+  taia_uint(&trotate, 2744);
+  taia_add(&trotate, &now, &trotate);
+  for (i =0; i < dirn; ++i)
+    if ((dir +i)->tmax) {
+      if (taia_less(&dir[i].trotate, &now)) rotate(dir +i);
+      if (taia_less(&dir[i].trotate, &trotate)) trotate =dir[i].trotate;
+    }
   sig_unblock(sig_term);
   sig_unblock(sig_child);
   sig_unblock(sig_alarm);
   sig_unblock(sig_hangup);
-  i =read(fd, s, len);
+  iopause(&in, 1, &trotate, &now);
   sig_block(sig_term);
   sig_block(sig_child);
   sig_block(sig_alarm);
   sig_block(sig_hangup);
-  if (i == -1) if (errno != error_intr) warn("unable to read standard input");
+  i =read(fd, s, len);
+  if (i == -1) {
+    if (errno == error_again) errno =error_intr;
+    if (errno != error_intr) warn("unable to read standard input");
+  }
   if (i > 0) linecomplete =(s[i -1] == '\n');
   return(i);
 }
@@ -525,9 +613,9 @@ void sig_child_handler(void) {
   while ((pid =wait_nohang(&wstat)) > 0)
     for (l =0; l < dirn; ++l)
       if (dir[l].ppid == pid) {
-	dir[l].ppid =0;
-	processorstop(&dir[l]);
-	break;
+        dir[l].ppid =0;
+        processorstop(&dir[l]);
+        break;
       }
 }
 void sig_alarm_handler(void) {
@@ -543,28 +631,18 @@ void logmatch(struct logdir *ld) {
   int i;
 
   ld->match ='+';
+  ld->matcherr ='E';
   for (i =0; i < ld->inst.len; ++i) {
     switch(ld->inst.s[i]) {
     case '+':
     case '-':
       if (pmatch(&ld->inst.s[i +1], line, linelen))
-	ld->match =ld->inst.s[i];
+        ld->match =ld->inst.s[i];
       break;
     case 'e':
-      if (pmatch(&ld->inst.s[i +1], line, linelen)) {
-	if (timestamp) buffer_puts(buffer_2, stamp);
-	buffer_put(buffer_2, line, linelen);
-	if (linelen == linemax) buffer_puts(buffer_2, "...");
-	buffer_put(buffer_2, "\n", 1); buffer_flush(buffer_2);
-      }
-      break;
     case 'E':
-      if (! pmatch(&ld->inst.s[i +1], line, linelen)) {
-	if (timestamp) buffer_puts(buffer_2, stamp);
-	buffer_put(buffer_2, line, linelen);
-	if (linelen == linemax) buffer_puts(buffer_2, "...");
-	buffer_put(buffer_2, "\n", 1); buffer_flush(buffer_2);
-      }
+      if (pmatch(&ld->inst.s[i +1], line, linelen))
+        ld->matcherr =ld->inst.s[i];
       break;
     }
     i +=byte_chr(&ld->inst.s[i], ld->inst.len -i, 0);
@@ -595,7 +673,7 @@ int main(int argc, const char **argv) {
       if (buflen == 0) buflen =1024;
       break;
     case 't':
-      ++timestamp;
+      if (++timestamp > 2) timestamp =2;
       break;
     case 'v':
       ++verbose;
@@ -626,6 +704,9 @@ int main(int argc, const char **argv) {
   line =(char*)alloc(linemax *sizeof(char));
   if (! line) die_nomem();
   fndir =argv;
+  in.fd =0;
+  in.events =IOPAUSE_READ;
+  ndelay_on(in.fd);
 
   sig_block(sig_term);
   sig_block(sig_child);
@@ -645,93 +726,94 @@ int main(int argc, const char **argv) {
     if (exitasap && ! data.p) break; /* data buffer is empty */
     for (linelen =0; linelen < linemax; ++linelen) {
       if (buffer_GETC(&data, &ch) <= 0) {
-	exitasap =1;
-	break;
+        exitasap =1;
+        break;
       }
       if (! linelen && timestamp) {
-	taia_now(&now);
-	switch (timestamp) {
-	case 1:
-	  stamp[fmt_taia(stamp, &now)] =' ';
-	  stamp[26] =0;
-	  break;
-	case 2:
-	  stamp[fmt_ptime(stamp, &now)] =' ';
-	  stamp[26] =0;
-	  break;
-	case 3:
-	  stamp[fmt_ptime(stamp, &now)] =0;
-	  stamp[19] =' '; stamp[20] =0;
-	  break;
-	}
+        taia_now(&now);
+        switch (timestamp) {
+        case 1:
+          stamp[fmt_taia(stamp, &now)] =' ';
+          stamp[26] =0;
+          break;
+        case 2:
+          stamp[fmt_ptime(stamp, &now)] =' ';
+          stamp[26] =0;
+          break;
+        }
       }
       if (ch == '\n') break;
       if (repl) {
-	if ((ch < 32) || (ch > 126))
-	  ch =repl;
-	else
-	  for (i =0; replace[i]; ++i)
-	    if (ch == replace[i]) {
-	      ch =repl;
-	      break;
-	    }
+        if ((ch < 32) || (ch > 126))
+          ch =repl;
+        else
+          for (i =0; replace[i]; ++i)
+            if (ch == replace[i]) {
+              ch =repl;
+              break;
+            }
       }
       line[linelen] =ch;
     }
     if (! linelen) continue;
     for (i =0; i < dirn; ++i)
       if (dir[i].fddir != -1) {
-	if (dir[i].inst.len) logmatch(&dir[i]);
-	if (dir[i].match != '+') continue;
-	if (! dir[i].udponly) {
-	  if (timestamp) buffer_puts(&dir[i].b, stamp);
-	  buffer_put(&dir[i].b, line, linelen);
-	}
-	if (dir[i].udpaddr.sin_port != 0) {
-	  if (fdudp == -1) {
-	    buffer_puts(&dir[i].b, "warning: no udp socket available: ");
-	    buffer_put(&dir[i].b, line, linelen);
-	    buffer_put(&dir[i].b, "\n", 1);
-	    buffer_flush(&dir[i].b);
-	  }
-	  else {
-	    if (linelen >= linemax -1) {
-	      line[linemax -4] =line[linemax -3] =line[linemax -2] ='.';
-	      linelen =linemax -1;
-	    }
-	    if (line[linelen -1] != '\n') line[linelen++] ='\n';
-	    if (sendto(fdudp, line, linelen, 0,
-		       (struct sockaddr *)&dir[i].udpaddr,
-		       sizeof(dir[i].udpaddr)) != linelen) {
-	      buffer_puts(&dir[i].b, "warning: failure sending through udp: ");
-	      buffer_put(&dir[i].b, line, linelen);
-	      buffer_put(&dir[i].b, "\n", 1);
-	      buffer_flush(&dir[i].b);
-	    }
-	  }
-	}
+        if (dir[i].inst.len) logmatch(&dir[i]);
+        if (dir[i].matcherr == 'e') {
+          buffer_put(buffer_2, line, linelen);
+          if (linelen == linemax) buffer_puts(buffer_2, "...");
+          buffer_put(buffer_2, "\n", 1); buffer_flush(buffer_2);
+        }
+        if (dir[i].match != '+') continue;
+        if (! dir[i].udponly) {
+          if (timestamp) buffer_puts(&dir[i].b, stamp);
+          buffer_put(&dir[i].b, line, linelen);
+        }
+        if (dir[i].udpaddr.sin_port != 0) {
+          if (fdudp == -1) {
+            buffer_puts(&dir[i].b, "warning: no udp socket available: ");
+            buffer_put(&dir[i].b, line, linelen);
+            buffer_put(&dir[i].b, "\n", 1);
+            buffer_flush(&dir[i].b);
+          }
+          else {
+            if (linelen >= linemax -1) {
+              line[linemax -4] =line[linemax -3] =line[linemax -2] ='.';
+              linelen =linemax -1;
+            }
+            if (line[linelen -1] != '\n') line[linelen++] ='\n';
+            if (sendto(fdudp, line, linelen, 0,
+                       (struct sockaddr *)&dir[i].udpaddr,
+                       sizeof(dir[i].udpaddr)) != linelen) {
+              buffer_puts(&dir[i].b, "warning: failure sending through udp: ");
+              buffer_put(&dir[i].b, line, linelen);
+              buffer_put(&dir[i].b, "\n", 1);
+              buffer_flush(&dir[i].b);
+            }
+          }
+        }
       }
     if (linelen == linemax)
       for (;;) {
-	if (buffer_GETC(&data, &ch) <= 0) {
-	  exitasap =1;
-	  break;
-	}
-	if (ch == '\n') break;
-	for (i =0; i < dirn; ++i)
-	  if (dir[i].fddir != -1) {
-	    if (dir[i].match != '+') continue;
-	    if (! dir[i].udponly) buffer_PUTC(&dir[i].b, ch);
-	  }
+        if (buffer_GETC(&data, &ch) <= 0) {
+          exitasap =1;
+          break;
+        }
+        if (ch == '\n') break;
+        for (i =0; i < dirn; ++i)
+          if (dir[i].fddir != -1) {
+            if (dir[i].match != '+') continue;
+            if (! dir[i].udponly) buffer_PUTC(&dir[i].b, ch);
+          }
       }
     for (i =0; i < dirn; ++i)
       if (dir[i].fddir != -1) {
-	if (dir[i].match != '+') continue;
-	if (! dir[i].udponly) {
-	  ch ='\n';
-	  buffer_PUTC(&dir[i].b, ch);
-	  buffer_flush(&dir[i].b);
-	}
+        if (dir[i].match != '+') continue;
+        if (! dir[i].udponly) {
+          ch ='\n';
+          buffer_PUTC(&dir[i].b, ch);
+          buffer_flush(&dir[i].b);
+        }
       }
   }
   
diff --git a/src/svlogd.check b/src/svlogd.check
index ea8e3f2..7d926ef 100755
--- a/src/svlogd.check
+++ b/src/svlogd.check
@@ -18,4 +18,10 @@ cat "${ctmp}"/current
 ( echo foo; echo bar; echo baz ) |svlogd -r: -R fb "${ctmp}"
 echo $?
 cat "${ctmp}"/current
+
+echo t2 >"${ctmp}"/config
+( echo foo; sleep 3 ) |svlogd "${ctmp}"
+echo $?
+cat "${ctmp}"/current
+
 rm -rf "${ctmp}"