runit

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

commit dfe4f9d2469f5404817543bbaf7619b500ff0cbe
parent 3a4427a8d0bc34970b905a8c8723805ba29056d8
Author: Gerrit Pape <pape@smarden.org>
Date:   Sat,  6 Nov 2004 15:38:33 +0000

  * 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:
MMakefile | 2+-
Mdoc/install.html | 12++++++------
Mdoc/replaceinit.html | 4++--
Metc/2 | 2+-
Mman/chpst.8 | 13+++++++++++++
Mman/runsv.8 | 4++--
Mman/svlogd.8 | 52+++++++++++++++++++++++++++++++++++++++++++---------
Mpackage/CHANGES | 12++++++++++++
Mpackage/upgrade | 4++--
Mpackage/versions | 1+
Msrc/chpst.c | 37+++++++++++++++++++++++++++----------
Msrc/runsv.c | 113++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/svlogd.c | 438+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/svlogd.check | 6++++++
14 files changed, 433 insertions(+), 267 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,6 +1,6 @@ DESTDIR= -PACKAGE=runit-1.0.5 +PACKAGE=runit-1.1.0 DIRS=doc man etc package src MANPAGES=runit.8 runit-init.8 runsvdir.8 runsv.8 svwaitdown.8 svwaitup.8 \ utmpset.8 runsvchdir.8 runsvstat.8 runsvctrl.8 svlogd.8 chpst.8 diff --git a/doc/install.html b/doc/install.html @@ -17,14 +17,14 @@ If you don't have a <tt>/package</tt> directory, create it now: # chmod 1755 /package </pre> Download -<a href="runit-1.0.5.tar.gz">runit-1.0.5.tar.gz</a> into <tt>/package</tt> +<a href="runit-1.1.0.tar.gz">runit-1.1.0.tar.gz</a> into <tt>/package</tt> and unpack the archive <pre> # cd /package - # gunzip runit-1.0.5.tar - # tar -xpf runit-1.0.5.tar - # rm runit-1.0.5.tar - # cd admin/runit-1.0.5 + # gunzip runit-1.1.0.tar + # tar -xpf runit-1.1.0.tar + # rm runit-1.1.0.tar + # cd admin/runit-1.1.0 </pre> On MacOSX, do <pre> @@ -43,7 +43,7 @@ hierarchy, do: </pre> To report success: <pre> - # mail pape-runit-1.0.5@smarden.org &lt;compile/sysdeps + # mail pape-runit-1.1.0@smarden.org &lt;compile/sysdeps </pre> If you use <i>runit</i> regularly, please <a href="http://smarden.org/pape/#contribution">contribute</a> to the project. diff --git a/doc/replaceinit.html b/doc/replaceinit.html @@ -117,7 +117,7 @@ default Unix process no 1 <i>runit</i>. </pre> To report success: <pre> - # ( uname -a ; cat /etc/runit/[123] ) |mail pape-runit-1.0.5@smarden.org + # ( uname -a ; cat /etc/runit/[123] ) |mail pape-runit-1.1.0@smarden.org </pre> <hr> @@ -206,7 +206,7 @@ This will cause <i>runit</i> to enter stage 3 which runs <p> To report success: <pre> - # ( uname -a ; cat /etc/runit/[123] ) |mail pape-runit-1.0.5@smarden.org + # ( uname -a ; cat /etc/runit/[123] ) |mail pape-runit-1.1.0@smarden.org </pre> <h3>Step 5: Service migration</h3> The goal is to migrate all services from <i>/etc/rc.*</i> scheme to the diff --git a/etc/2 b/etc/2 @@ -3,4 +3,4 @@ PATH=/command:/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin exec env - PATH=$PATH \ -runsvdir /var/service 'log: ...........................................................................................................................................................................................................................................................................................................................................................................................................' +runsvdir -P /var/service 'log: ...........................................................................................................................................................................................................................................................................................................................................................................................................' diff --git a/man/chpst.8 b/man/chpst.8 @@ -12,6 +12,8 @@ chpst \- runs a program with a changed process state .IR dir ] [\-/ .IR root ] +[\-n +.IR inc ] [-l|-L .IR lock ] [-m @@ -105,6 +107,17 @@ Change the root directory to before starting .IR prog . .TP +.B \-n \fIinc +nice. +Add +.I inc +to the +.BR nice (2) +value before starting +.IR prog . +.I inc +must be an integer, and may start with a minus or plus. +.TP .B \-l \fIlock lock. Open the file diff --git a/man/runsv.8 b/man/runsv.8 @@ -79,7 +79,7 @@ If the service stops, restart it. .TP .B d Down. -If the service is running, send it a TERM signal. +If the service is running, send it a TERM signal, and then a CONT signal. If ./run exits, start ./finish if it exists. After it stops, do not restart service. .TP @@ -129,7 +129,7 @@ If the service is running, send it a KILL signal. .TP .B x \fRor \fBe Exit. -If the service is running, send it a TERM signal. +If the service is running, send it a TERM signal, and then a CONT signal. Do not restart the service. If the service is down, and no log service exists, .B runsv diff --git a/man/svlogd.8 b/man/svlogd.8 @@ -73,7 +73,8 @@ bytes or more (or there is a new-line within the last .I len of .I size -bytes) +bytes), or is older than a specified amount of +.IR time , .I current is rotated: .P @@ -192,6 +193,40 @@ old log files in after log file rotation, it deletes the oldest one. Default is 10. .TP +.RI N min +sets the minimum number of old log files +.B svlogd +should maintain to +.IR min . +.I min +must be less than +.IR num . +If +.I min +is set, and +.B svlogd +cannot write to +.I current +because the filesystem is full, and it sees more than +.I min +old log files, it deletes the oldest one. +.TP +.RI t timeout +sets the maximum age of the +.I current +log file when +.B svlogd +should rotate the current log file to +.I timeout +seconds. +If +.I current +is +.I timeout +seconds old, and is not empty, +.B svlogd +forces log file rotation. +.TP .RI ! processor tells .B svlogd @@ -248,21 +283,20 @@ and acts accordingly: the log message is deselected. .TP .RI + pattern -the log message is selected +the log message is selected. .TP .RI e pattern -log messages matching -.I pattern -are printed to standard error. +the log message is selected to be printed to standard error. .TP .RI E pattern -log messages not matching -.I pattern -are printed to standard error. +the log message is deselected to be printed to standard error. .P -Initially each line is selected. +Initially each line is selected to be written to +.IR log/current . Deselected log messages are discarded from .IR log . +Initially each line is deselected to be written to standard err. +Log messages selected for standard error are written to standard error. .SH PATTERN MATCHING .B svlogd matches a log message against the string diff --git a/package/CHANGES b/package/CHANGES @@ -1,3 +1,15 @@ +runit 1.1.0 +Sat, 06 Nov 2004 15:38:54 +0000 + * 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. + runit 1.0.5 Tue, 21 Sep 2004 18:18:14 +0000 * svlogd.c: fix line buffer handling for pattern matching (thx Enrico diff --git a/package/upgrade b/package/upgrade @@ -8,9 +8,9 @@ test -d src || sh -cx '! : Wrong working directory.' here=`env - PATH=$PATH pwd` parent=`dirname $here` -echo 'Creating symlink runit -> runit-1.0.5...' +echo 'Creating symlink runit -> runit-1.1.0...' rm -f runit -ln -s runit-1.0.5 runit +ln -s runit-1.1.0 runit mv -f runit .. echo 'Making command links in /command...' diff --git a/package/versions b/package/versions @@ -29,3 +29,4 @@ 1.0.3 1.0.4 1.0.5 +1.1.0 diff --git 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 @@ -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 @@ -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 @@ -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}"