runit

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

commit b633c0e3d484184d56c3ab17e2d3bbf1279f9a1e
parent 9b282e5c956ab9511bc07f129c4e32b0345752cc
Author: Gerrit Pape <pape@smarden.org>
Date:   Mon, 20 Sep 2004 19:53:10 +0000

  * svlogd.c: fix line buffer handling for pattern matching (thx Enrico
    Scholz); minor bug fixes.
  * doc/index.html: wording; add link to useinit.html; remove link to runit
    on LinuxFromScratch.
  * doc/runscripts.html: add hint, some getties need to be run in a new
    session/process group (thx Dan Melomedman).
  * man/svlogd.8: minor fixes.
  * man/svwaitdown.8: remove hint about -x option.

Diffstat:
Mdoc/index.html | 16++++++++--------
Mdoc/runscripts.html | 5+++++
Mdoc/svlogd.8.html | 118++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mdoc/svwaitdown.8.html | 28+++++++++++++---------------
Mman/svlogd.8 | 15++++++++-------
Mman/svwaitdown.8 | 5-----
Mpackage/CHANGES | 11+++++++++++
Msrc/svlogd.c | 372+++++++++++++++++++++++++++++++++++++++----------------------------------------
8 files changed, 286 insertions(+), 284 deletions(-)

diff --git a/doc/index.html b/doc/index.html @@ -78,23 +78,23 @@ if this is started by the kernel. terminate. The system's one time initialization tasks are done here. <tt>/etc/runit/1</tt> has full control over <tt>/dev/console</tt> to be - able to start an emergency shell if the one time initialization tasks - fail. + able to start an emergency shell in case the one time initialization + tasks fail. <li><b>Stage 2:</b><br> <i>runit</i> starts <tt>/etc/runit/2</tt> which should not return until the system is going to halt or reboot; if it crashes, it will be restarted. Normally, <tt>/etc/runit/2</tt> runs <a href="runsvdir.8.html">runsvdir</a>. - In Stage 2 <i>runit</i> optionally handles an INT signal (ctrl-alt-del + In Stage 2 <i>runit</i> optionally handles the INT signal (ctrl-alt-del keyboard request on Linux/i386). <li><b>Stage 3:</b><br> - If <i>runit</i> is told to halt or reboot the system, or the Stage 2 - returns without errors, it terminates Stage 2 if it is running and runs + If <i>runit</i> is told to halt or reboot the system, or Stage 2 returns + without errors, it terminates Stage 2 if it is running, and runs <tt>/etc/runit/3</tt>. The systems tasks to shutdown and halt or reboot are done here. </ul> -These are working examples for Debian woody: +These are working examples for Debian sarge: <a href="debian/1">/etc/runit/1</a>, <a href="debian/2">/etc/runit/2</a>, <a href="debian/3">/etc/runit/3</a>. @@ -185,6 +185,8 @@ Of course also the <tt>smarden.org</tt> content server is running with See <a href="install.html">How to install runit</a> for installing <i>runit</i>, and <a href="replaceinit.html">How to replace init</a> for configuring <i>runit</i> to run as process no 1. +See <a href="useinit.html">How to use with current init</a> if you want to +use <i>runit</i> without replacing the current init scheme. <hr> If <i>runit</i> on Linux is compiled and linked with the <a href="http://www.fefe.de/dietlibc/">dietlibc</a>, it yields in a @@ -208,8 +210,6 @@ runit Debian package</a> runit-run Debian package</a> <li><a href="http://www.freshports.org/sysutils/runit/"> runit FreeBSD port</a> -<li><a href="http://www.109bean.org.uk/betterboot/index.html"> -runit on LinuxFromScratch</a> - by Richard A Downing FBCS <li><a href="http://rpmfind.net/linux/rpm2html/search.php?query=runit"> runit RPMs</a> <li><a href="http://www.fefe.de/minit/"> diff --git a/doc/runscripts.html b/doc/runscripts.html @@ -339,6 +339,11 @@ Debian's <tt>mingetty</tt> creates its own utmp record. #!/bin/sh exec chpst -P fgetty tty4 </pre> +The <a href="runsv.8.html">runsv</a> program does not automatically create +a new session and separate process group for run scripts, which can +cause some <i>getties</i> to fail due to limited permissions. +The <a href="chpst.8.html">chpst</a> program can be used to alter the +process state for those <i>getties</i>. <hr> <h3><a name="gpm">A <tt>gpm</tt> run script</a></h3> (<i>LFS</i>) diff --git a/doc/svlogd.8.html b/doc/svlogd.8.html @@ -12,7 +12,7 @@ svlogd - runit&rsquo;s service logging daemon <h2><a name='sect1'>Synopsis</a></h2> <b>svlogd</b> [-ttv] [-r <i>c]</i> [-R -<i>xyz]</i> [-l <i>n]</i> [-b <i>n]</i> <i>logs</i> +<i>xyz]</i> [-l <i>len]</i> [-b <i>buflen]</i> <i>logs</i> <h2><a name='sect2'>Description</a></h2> <i>logs</i> consists of one or more arguments, each specifying a directory. <p> @@ -21,78 +21,78 @@ standard input, optionally filters log messages, and writes the data to one or more automatically rotated <i>logs</i>. <p> Recent log files can automatically be processed by an arbitrary processor program when they are rotated, and -<b>svlogd</b> can be told to alert selected log messages to standard error. <p> -<b>svlogd</b> -runs until it sees end-of-file on standard input or is sent a TERM signal, -see below. +<b>svlogd</b> can be told to alert selected log messages to standard error, and +through udp. <p> +<b>svlogd</b> runs until it sees end-of-file on standard input or is +sent a TERM signal, see below. <h3><a name='sect3'>Log Directory</a></h3> -A log directory <i>log</i> contains some number of old -log files, and the current log file <i>current</i>. Old log files have a file name -starting with <i>@</i> followed by a precise timestamp (see <i><b>tai64n</b>(8)</i>), indicating -when <i>current</i> was rotated and renamed to this file. <p> -A log directory additionally -contains the lock file <i>lock</i>, maybe <i>state</i> and <i>newstate</i>, and optionally the -file <i>config</i>. <b>svlogd</b> creates necessary files if they don&rsquo;t exist. <p> -If <b>svlogd</b> -has trouble opening a log directory, it prints a warning, and ignores this -log directory. If <b>svlogd</b> is unable to open all log directories given at -the command line, it exits with an error. This can happen on start-up or -after receiving a HUP signal. +A log directory <i>log</i> contains +some number of old log files, and the current log file <i>current</i>. Old log +files have a file name starting with <i>@</i> followed by a precise timestamp +(see <i><b>tai64n</b>(8)</i>), indicating when <i>current</i> was rotated and renamed to this +file. <p> +A log directory additionally contains the lock file <i>lock</i>, maybe <i>state</i> +and <i>newstate</i>, and optionally the file <i>config</i>. <b>svlogd</b> creates necessary files +if they don&rsquo;t exist. <p> +If <b>svlogd</b> has trouble opening a log directory, it prints +a warning, and ignores this log directory. If <b>svlogd</b> is unable to open all +log directories given at the command line, it exits with an error. This +can happen on start-up or after receiving a HUP signal. <h3><a name='sect4'>Log File Rotation</a></h3> -<b>svlogd</b> appends selected log -messages to the <i>current</i> log file. If <i>current</i> has <i>size</i> bytes or more size -(or there is a new-line within the last <i>len</i> of <i>size</i> bytes) <i>current</i> is rotated: -<p> -<b>svlogd</b> closes <i>current</i>, changes permission of <i>current</i> to 0755, renames <i>current</i> -to @<i>timestamp.s,</i> and starts with a new empty <i>current</i>. If <b>svlogd</b> sees <i>num</i> -or more old log files in <i>dir</i>, it removes the oldest. +<b>svlogd</b> +appends selected log messages to the <i>current</i> log file. If <i>current</i> has <i>size</i> +bytes or more (or there is a new-line within the last <i>len</i> of <i>size</i> bytes) +<i>current</i> is rotated: <p> +<b>svlogd</b> closes <i>current</i>, changes permission of <i>current</i> +to 0755, renames <i>current</i> to @<i>timestamp.s,</i> and starts with a new empty <i>current</i>. +If <b>svlogd</b> sees <i>num</i> or more old log files in <i>dir</i>, it removes the oldest +one. <h3><a name='sect5'>Processor</a></h3> -If <b>svlogd</b> -is told to process recent log files, it saves <i>current</i> to @<i>timestamp.u,</i> feeds -@<i>timestamp.u</i> through &lsquo;&lsquo;sh -c "<i>processor</i>"&rsquo;&rsquo; and writes the output to @<i>timestamp.t.</i> -If the <i>processor</i> finishes successfully, @<i>timestamp.u</i> is deleted and @<i>timestamp.t</i> -is renamed to @<i>timestamp.s,</i> otherwise @<i>timestamp.t</i> is deleted and the <i>processor</i> -is started again. <b>svlogd</b> also saves any output that the <i>processor</i> writes -to file descriptor 5, and make that output available on file descriptor -4 when it runs <i>processor</i> on the next log file rotation. <p> -A <i>processor</i> is run -in the background. If <b>svlogd</b> sees a previously started <i>processor</i> still running -when trying to start a new one for the same <i>log</i>, it blocks until the currently -running <i>processor</i> has finished successfully. Only the HUP signal works in -that situation. Note that this may block any program feeding its log data -to <b>svlogd.</b> +If <b>svlogd</b> is told to process recent log files, it saves <i>current</i> +to @<i>timestamp.u,</i> feeds @<i>timestamp.u</i> through &lsquo;&lsquo;sh -c "<i>processor</i>"&rsquo;&rsquo; and writes the +output to @<i>timestamp.t.</i> If the <i>processor</i> finishes successfully, @<i>timestamp.u</i> +is deleted and @<i>timestamp.t</i> is renamed to @<i>timestamp.s,</i> otherwise @<i>timestamp.t</i> +is deleted and the <i>processor</i> is started again. <b>svlogd</b> also saves any output +that the <i>processor</i> writes to file descriptor 5, and makes that output available +on file descriptor 4 when running <i>processor</i> on the next log file rotation. +<p> +A <i>processor</i> is run in the background. If <b>svlogd</b> sees a previously started +<i>processor</i> still running when trying to start a new one for the same <i>log</i>, +it blocks until the currently running <i>processor</i> has finished successfully. +Only the HUP signal works in that situation. Note that this may block any +program feeding its log data to <b>svlogd.</b> <p> <h3><a name='sect6'>Config</a></h3> -On startup, and after receiving a HUP signal, <b>svlogd</b> checks -for each <i>log</i> if the configuration file <i>log/config</i> exists, and if so, reads -the file line by line and adjusts configuration for <i>log</i> as follows: <p> -If -the line is empty, less than two characters long, or starts with a &lsquo;&lsquo;#&rsquo;&rsquo;, it -is ignored. A line of the form +On startup, and after receiving +a HUP signal, <b>svlogd</b> checks for each <i>log</i> if the configuration file <i>log/config</i> +exists, and if so, reads the file line by line and adjusts configuration +for <i>log</i> as follows: <p> +If the line is empty, less than two characters long, +or starts with a &lsquo;&lsquo;#&rsquo;&rsquo;, it is ignored. A line of the form <dl> <dt>s<i>size</i> </dt> -<dd>sets the maximum file size of <i>current</i> -when <b>svlogd</b> should rotate the current log file to <i>size</i> bytes. Default is -1000000. If <i>size</i> is zero, <b>svlogd</b> doesn&rsquo;t rotate log files. You should set -<i>size</i> to at least (2 * <i>len</i>). </dd> +<dd>sets the maximum +file size of <i>current</i> when <b>svlogd</b> should rotate the current log file to +<i>size</i> bytes. Default is 1000000. If <i>size</i> is zero, <b>svlogd</b> doesn&rsquo;t rotate log +files. You should set <i>size</i> to at least (2 * <i>len</i>). </dd> <dt>n<i>num</i> </dt> -<dd>sets the maximum number of old log files -<b>svlogd</b> should maintain to <i>num</i>. If <b>svlogd</b> sees more that <i>num</i> old log files -in <i>log</i> after log file rotation, it deletes the oldest one. Default is 10. -</dd> +<dd>sets the maximum number +of old log files <b>svlogd</b> should maintain to <i>num</i>. If <b>svlogd</b> sees more that +<i>num</i> old log files in <i>log</i> after log file rotation, it deletes the oldest +one. Default is 10. </dd> <dt>!<i>processor</i> </dt> -<dd>tells <b>svlogd</b> to feed each recent log file through <i>processor</i> -(see above) on log file rotation. By default log files are not processed. -</dd> +<dd>tells <b>svlogd</b> to feed each recent log file +through <i>processor</i> (see above) on log file rotation. By default log files +are not processed. </dd> <dt>u<i>a.b.c.d[:port]</i> </dt> -<dd>tells <b>svlogd</b> to transmit the first <i>len</i> characters of selected -log messages to the IP address <i>a.b.c.d</i>, port number <i>port</i>. If <i>port</i> isn&rsquo;t set, -the default port for syslog is used (514). <i>len</i> can be set through the -l -option, see below. If <b>svlogd</b> has trouble sending udp packets, it writes +<dd>tells <b>svlogd</b> to transmit the first <i>len</i> characters +of selected log messages to the IP address <i>a.b.c.d</i>, port number <i>port</i>. If <i>port</i> +isn&rsquo;t set, the default port for syslog is used (514). <i>len</i> can be set through +the -l option, see below. If <b>svlogd</b> has trouble sending udp packets, it writes error messages to the log directory. Attention: logging through udp is unreliable, and should be used in private networks only. </dd> diff --git a/doc/svwaitdown.8.html b/doc/svwaitdown.8.html @@ -43,25 +43,23 @@ signal. </dd> <dt><b>-x</b> </dt> <dd>Exit. Send each <i>service</i> the &lsquo;&lsquo;exit&rsquo;&rsquo; command additionally to the &lsquo;&lsquo;down&rsquo;&rsquo; command, and wait for the corresponding <i><b>runsv</b>(8)</i> processes to exit instead -for the <i>services</i> to be down. This option should only be used by <i><b>runit</b>(8)</i> -in stage 3 when <i><b>runsvdir</b>(8)</i> is already stopped. </dd> +for the <i>services</i> to be down. </dd> </dl> <h2><a name='sect4'>Exit Codes</a></h2> -<b>svwaitdown</b> returns -0 as soon as all <i>services</i> are down. <p> -If a <i>service</i> is usually controlled by -<i><b>runsv (8)</b></i> or <i><b>supervise</b>(8)</i>, but no supervisor process is currently running, -<b>svwaitdown</b> treats this <i>service</i> as if it would be down. <p> -For each <i>service</i> -that causes an error while checking, <b>svwaitdown</b> increases the exit code -by one and exits non zero. The maximum is 100. <p> -<b>svwaitdown</b> returns 111 if -the timeout <i>sec</i> was reached. +<b>svwaitdown</b> returns 0 as soon as all +<i>services</i> are down. <p> +If a <i>service</i> is usually controlled by <i><b>runsv (8)</b></i> or <i><b>supervise</b>(8)</i>, +but no supervisor process is currently running, <b>svwaitdown</b> treats this +<i>service</i> as if it would be down. <p> +For each <i>service</i> that causes an error while +checking, <b>svwaitdown</b> increases the exit code by one and exits non zero. +The maximum is 100. <p> +<b>svwaitdown</b> returns 111 if the timeout <i>sec</i> was reached. + <h2><a name='sect5'>See Also</a></h2> -<i>svwaitup(8)</i>, <i>runsv(8)</i>, <i>runsvctrl(8)</i>, -<i>runsvstat(8)</i>, <i>chpst(8)</i>, <i>svlogd(8)</i>, <i>runit(8)</i>, <i>runit-init(8)</i>, <i>runsvdir(8)</i>, -<i>runsvchdir(8)</i>, <i>utmpset(8)</i> <p> +<i>svwaitup(8)</i>, <i>runsv(8)</i>, <i>runsvctrl(8)</i>, <i>runsvstat(8)</i>, <i>chpst(8)</i>, <i>svlogd(8)</i>, +<i>runit(8)</i>, <i>runit-init(8)</i>, <i>runsvdir(8)</i>, <i>runsvchdir(8)</i>, <i>utmpset(8)</i> <p> <i>http://smarden.org/runit/</i><br> <i>http://cr.yp.to/daemontools.html</i><br> diff --git a/man/svlogd.8 b/man/svlogd.8 @@ -6,8 +6,8 @@ svlogd \- runit's service logging daemon [\-ttv] [\-r .I c\fR] [\-R .I xyz\fR] [\-l -.I n\fR] [\-b -.I n\fR] +.I len\fR] [\-b +.I buflen\fR] .I logs .SH DESCRIPTION .I logs @@ -21,7 +21,8 @@ messages, and writes the data to one or more automatically rotated Recent log files can automatically be processed by an arbitrary processor program when they are rotated, and .B svlogd -can be told to alert selected log messages to standard error. +can be told to alert selected log messages to standard error, and through +udp. .P .B svlogd runs until it sees end-of-file on standard input or is sent a TERM signal, @@ -68,7 +69,7 @@ If .I current has .I size -bytes or more size (or there is a new-line within the last +bytes or more (or there is a new-line within the last .I len of .I size @@ -93,7 +94,7 @@ sees .I num or more old log files in .IR dir , -it removes the oldest. +it removes the oldest one. .SS PROCESSOR If .B svlogd @@ -122,8 +123,8 @@ is started again. .B svlogd also saves any output that the .I processor -writes to file descriptor 5, and make that output available on file -descriptor 4 when it runs +writes to file descriptor 5, and makes that output available on file +descriptor 4 when running .I processor on the next log file rotation. .P diff --git a/man/svwaitdown.8 b/man/svwaitdown.8 @@ -68,11 +68,6 @@ corresponding processes to exit instead for the .I services to be down. -This option should only be used by -.BR runit (8) -in stage 3 when -.BR runsvdir (8) -is already stopped. .SH EXIT CODES .B svwaitdown returns 0 as soon as all diff --git a/package/CHANGES b/package/CHANGES @@ -1,3 +1,14 @@ +runit 1.0.5 +Mon, 20 Sep 2004 13:14:42 +0000 + * svlogd.c: fix line buffer handling for pattern matching (thx Enrico + Scholz); minor bug fixes. + * doc/index.html: wording; add link to useinit.html; remove link to runit + on LinuxFromScratch. + * doc/runscripts.html: add hint, some getties need to be run in a new + session/process group (thx Dan Melomedman). + * man/svlogd.8: minor fixes. + * man/svwaitdown.8: remove hint about -x option. + runit 1.0.4 Sun, 01 Aug 2004 18:29:36 +0000 * doc/runlevels.html, doc/upgrade.html, doc/useinit.html, man/runsvdir.8, diff --git a/src/svlogd.c b/src/svlogd.c @@ -7,7 +7,6 @@ #include <sys/time.h> #include <dirent.h> #include <unistd.h> -#include <dirent.h> #include <stdio.h> #include "pmatch.h" #include "fmt_ptime.h" @@ -45,8 +44,10 @@ const char *progname; unsigned int verbose =0; unsigned int timestamp =0; -unsigned long linelen =1000; +unsigned long linemax =1000; unsigned long buflen =1024; +unsigned long linelen; + const char *replace =""; char repl =0; @@ -62,6 +63,9 @@ buffer data; char *line; char stamp[FMT_PTIME]; unsigned int exitasap =0; +unsigned int rotateasap =0; +unsigned int reopenasap =0; +unsigned int linecomplete =1; int fdudp =-1; struct logdir { @@ -78,7 +82,7 @@ struct logdir { char *name; int fdcur; int fdlock; - unsigned int match; + char match; struct sockaddr_in udpaddr; unsigned int udponly; } *dir; @@ -125,6 +129,8 @@ unsigned int processorstart(struct logdir *ld) { sig_unblock(sig_alarm); sig_unblock(sig_hangup); + if (verbose) + strerr_warn5(INFO, "processing: ", ld->name, "/", ld->fnsave, 0); if ((fd =open_read(ld->fnsave)) == -1) fatal2("unable to open input for processor", ld->name); if (fd_move(0, fd) == -1) @@ -160,7 +166,7 @@ unsigned int processorstart(struct logdir *ld) { fatal2("unable to run processor", ld->name); } ld->ppid =pid; - return(1); + return(1); } unsigned int processorstop(struct logdir *ld) { char f[28]; @@ -172,14 +178,15 @@ unsigned int processorstop(struct logdir *ld) { sig_block(sig_hangup); ld->ppid =0; } + if (ld->fddir == -1) return(1); while (fchdir(ld->fddir) == -1) pause2("unable to change directory, want processor", ld->name); if (wait_exitcode(wstat) != 0) { - warnx("processor crashed, restart", ld->name); + warnx("processor failed, restart", ld->name); ld->fnsave[26] ='t'; unlink(ld->fnsave); ld->fnsave[26] ='u'; - if (ld->processor.len) processorstart(ld); + processorstart(ld); while (fchdir(fdwdir) == -1) pause1("unable to change to initial working directory"); return(ld->processor.len ? 0 : 1); @@ -195,6 +202,7 @@ unsigned int processorstop(struct logdir *ld) { pause2("unable to set mode of processed", ld->name); while (rename("newstate", "state") == -1) pause2("unable to rename state", ld->name); + if (verbose) strerr_warn5(INFO, "processed: ", ld->name, "/", f, 0); while (fchdir(fdwdir) == -1) pause1("unable to change to initial working directory"); return(1); @@ -207,6 +215,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->ppid) while(! processorstop(ld)); @@ -245,11 +254,11 @@ unsigned int rotate(struct logdir *ld) { ld->size =0; while (fchmod(ld->fdcur, 0644) == -1) pause2("unable to set mode of current", ld->name); - buffer_init(&ld->b, buffer_unixwrite, ld->fdcur, ld->btmp, sizeof ld->btmp); - oldest[0] ='A'; oldest[1] =oldest[27] =0; errno =0; + 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; @@ -264,14 +273,29 @@ unsigned int rotate(struct logdir *ld) { warn2("unable to unlink oldest logfile", ld->name); } - if (ld->processor.len) { - processorstart(ld); - } + processorstart(ld); while (fchdir(fdwdir) == -1) pause1("unable to change to initial working directory"); return(1); } +int buffer_pwrite(int n, char *s, unsigned int len) { + int i; + + if ((dir +n)->sizemax) { + if ((dir +n)->size >= (dir +n)->sizemax) rotate(dir +n); + 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); + (dir +n)->size +=i; + if ((dir +n)->sizemax) + if (s[i -1] == '\n') + if ((dir +n)->size >= ((dir +n)->sizemax -linemax)) rotate(dir +n); + return(i); +} + void logdir_close(struct logdir *ld) { if (ld->fddir == -1) return; if (verbose) strerr_warn3(INFO, "close: ", ld->name, 0); @@ -288,6 +312,7 @@ void logdir_close(struct logdir *ld) { if (ld->fdlock == -1) return; /* impossible */ close(ld->fdlock); ld->fdlock =-1; + while (! stralloc_copys(&ld->processor, "")) pause_nomem(); } /* taken from libdjbdns */ @@ -335,7 +360,8 @@ unsigned int logdir_open(struct logdir *ld, const char *fn) { ld->sizemax =1000000; ld->nmax =10; ld->name =(char*)fn; - ld->match =0; + ld->ppid =0; + ld->match ='+'; ld->udpaddr.sin_port =0; ld->udponly =0; while (! stralloc_copys(&ld->inst, "")) pause_nomem(); @@ -367,9 +393,6 @@ unsigned int logdir_open(struct logdir *ld, const char *fn) { break; case 's': scan_ulong(&sa.s[i +1], &ld->sizemax); - /* - if (ld->sizemax && (ld->sizemax < linelen)) ld->sizemax =2 *linelen; - */ break; case 'n': scan_ulong(&sa.s[i +1], &ld->nmax); @@ -421,6 +444,7 @@ unsigned int logdir_open(struct logdir *ld, const char *fn) { } while ((stat(ld->fnsave, &st) != -1) || (errno != error_noent)); while (rename("current", ld->fnsave) == -1) pause2("unable to rename current", ld->name); + i =-1; } else ld->size =st.st_size; @@ -438,7 +462,7 @@ unsigned int logdir_open(struct logdir *ld, const char *fn) { coe(ld->fdcur); while (fchmod(ld->fdcur, 0644) == -1) pause2("unable to set mode of current", ld->name); - buffer_init(&ld->b, buffer_unixwrite, ld->fdcur, ld->btmp, sizeof ld->btmp); + buffer_init(&ld->b, buffer_pwrite, ld -dir, ld->btmp, buflen); if (verbose) { if (i == 0) strerr_warn4(INFO, "append: ", ld->name, "/current", 0); @@ -461,121 +485,43 @@ void logdirs_reopen(void) { if (! ok) fatalx("no functional log directories."); } -unsigned int linestart(struct logdir *ld, char *s, int len) { +int buffer_pread(int fd, char *s, unsigned int len) { int i; - /* check inst, set match */ - ld->match ='+'; - if (ld->inst.len) { - for (i =0; i < ld->inst.len; ++i) { - switch(ld->inst.s[i]) { - case '+': - case '-': - if (pmatch(&ld->inst.s[i +1], s, len)) - ld->match =ld->inst.s[i]; - break; - case 'e': - if (pmatch(&ld->inst.s[i +1], s, len)) { - if (timestamp) buffer_puts(buffer_2, stamp); - buffer_put(buffer_2, s, len); - if (len == linelen) buffer_puts(buffer_2, "..."); - buffer_putflush(buffer_2, "\n", 1); - } - break; - case 'E': - if (! pmatch(&ld->inst.s[i +1], s, len)) { - if (timestamp) buffer_puts(buffer_2, stamp); - buffer_put(buffer_2, s, len); - if (len == linelen) buffer_puts(buffer_2, "..."); - buffer_putflush(buffer_2, "\n", 1); - } - break; - } - i +=byte_chr(&ld->inst.s[i], ld->inst.len -i, 0); - } - } - if (ld->match == '-') return(0); - if (! ld->udponly) { - if (timestamp) { - buffer_puts(&ld->b, stamp); - if (timestamp != 3) ld->size +=26; - else ld->size +=20; - } - buffer_put(&ld->b, s, len); - ld->size +=len; - } - if (ld->udpaddr.sin_port != 0) { - if (fdudp == -1) { - buffer_puts(&ld->b, "warning: no udp socket available: "); - buffer_put(&ld->b, s, len); - buffer_putflush(&ld->b, "\n", 1); - } - else { - if (len >= linelen -1) { - s[linelen -4] =s[linelen -3] =s[linelen -2] ='.'; - len =linelen -1; - } - if (s[len -1] != '\n') s[len++] ='\n'; - if (sendto(fdudp, s, len, 0, (struct sockaddr *)&ld->udpaddr, - sizeof(ld->udpaddr)) != len) { - buffer_puts(&ld->b, "warning: failure sending through udp: "); - buffer_put(&ld->b, s, len); - buffer_putflush(&ld->b, "\n", 1); - } - } + for (i =0; i < dirn; ++i) buffer_flush(&dir[i].b); + if (rotateasap) { + for (i =0; i < dirn; ++i) rotate(dir +i); + rotateasap =0; } - return(1); -} -unsigned int lineadd(struct logdir *ld, char *s, int len) { - if ((ld->match != '+') || ld->udponly) return(0); - buffer_put(&ld->b, s, len); - ld->size +=len; - /* if (ld->sizemax && (ld->size >= ld->sizemax)) rotate(ld); */ - return(1); -} -unsigned int lineflush(struct logdir *ld, char *s, int len) { - switch(ld->match) { - case '-': - ld->match =0; - return(0); - case 0: - linestart(ld, s, len); - break; - case '+': - if (ld->udponly) { - ld->match =0; - return(0); - } - buffer_put(&ld->b, s, len); - ld->size +=len; - break; + if (exitasap) { + if (linecomplete) return(0); + len =1; } - if (ld->match == '+') { - buffer_putflush(&ld->b, "\n", 1); - ld->size +=1; - ld->match =0; - if (ld->sizemax) - if ((linelen > ld->sizemax) || (ld->size >= (ld->sizemax -linelen))) - rotate(ld); - return(1); + if (reopenasap) { + logdirs_reopen(); + reopenasap =0; } - ld->match =0; - return(0); -} -int buffer_pread(int fd, char *s, unsigned int len) { - int rc; - - rc =read(fd, s, len); - if ((rc == -1) && (errno == error_intr)) return(0); - return(rc); + sig_unblock(sig_term); + sig_unblock(sig_child); + sig_unblock(sig_alarm); + sig_unblock(sig_hangup); + i =read(fd, s, len); + 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"); + if (i > 0) linecomplete =(s[i -1] == '\n'); + return(i); } void sig_term_handler(void) { - exitasap =1; if (verbose) strerr_warn2(INFO, "sigterm received.", 0); + exitasap =1; } void sig_child_handler(void) { int pid, l; + if (verbose) strerr_warn2(INFO, "sigchild received.", 0); while ((pid =wait_nohang(&wstat)) > 0) for (l =0; l < dirn; ++l) if (dir[l].ppid == pid) { @@ -583,26 +529,50 @@ void sig_child_handler(void) { processorstop(&dir[l]); break; } - if (verbose) strerr_warn2(INFO, "sigchild received.", 0); } void sig_alarm_handler(void) { - int l; - - for (l =0; l < dirn; ++l) - if (dir[l].fddir != -1) - if (dir[l].size > 0) - rotate(&dir[l]); if (verbose) strerr_warn2(INFO, "sigalarm received.", 0); + rotateasap =1; } void sig_hangup_handler(void) { - logdirs_reopen(); if (verbose) strerr_warn2(INFO, "sighangup received.", 0); + reopenasap =1; } +void logmatch(struct logdir *ld) { + int i; + + ld->match ='+'; + 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]; + 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); + } + break; + } + i +=byte_chr(&ld->inst.s[i], ld->inst.len -i, 0); + } +} int main(int argc, const char **argv) { int i; int opt; - unsigned int eol; progname =*argv; @@ -617,8 +587,8 @@ int main(int argc, const char **argv) { if (! repl || *(optarg +1)) usage(); break; case 'l': - scan_ulong(optarg, &linelen); - if (linelen == 0) linelen =1000; + scan_ulong(optarg, &linemax); + if (linemax == 0) linemax =1000; break; case 'b': scan_ulong(optarg, &buflen); @@ -638,7 +608,7 @@ int main(int argc, const char **argv) { dirn =argc -optind; if (dirn <= 0) usage(); - if (buflen <= linelen) usage(); + if (buflen <= linemax) usage(); if ((fdwdir =open_read(".")) == -1) fatal("unable to open current working directory"); coe(fdwdir); @@ -653,7 +623,7 @@ int main(int argc, const char **argv) { databuf =(char*)alloc(buflen *sizeof(char)); if (! databuf) die_nomem(); buffer_init(&data, buffer_pread, 0, databuf, buflen); - line =(char*)alloc(linelen *sizeof(char)); + line =(char*)alloc(linemax *sizeof(char)); if (! line) die_nomem(); fndir =argv; @@ -668,79 +638,101 @@ int main(int argc, const char **argv) { logdirs_reopen(); - for(eol =0;;) { - int r, len; - char *ch; - - if (exitasap && ! data.p) break; /* buffer is empty */ - - sig_unblock(sig_term); - sig_unblock(sig_child); - sig_unblock(sig_alarm); - sig_unblock(sig_hangup); - errno =0; - r =buffer_feed(&data); - sig_block(sig_term); - sig_block(sig_child); - sig_block(sig_alarm); - sig_block(sig_hangup); + for(;;) { + char ch; - if (r == -1) { - warn("unable to read standard input"); - continue; - } - if (r == 0) { - if (errno == error_intr) continue; - break; /* eof */ - } - if (r > linelen) r =linelen; - if (timestamp && (eol == 0)) { - 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; + linelen =0; + if (exitasap && ! data.p) break; /* data buffer is empty */ + for (linelen =0; linelen < linemax; ++linelen) { + if (buffer_GETC(&data, &ch) <= 0) { + exitasap =1; break; } - } - ch =buffer_peek(&data); - for (len =0; len < r; ++len, ++ch) { - if (*ch == '\n') { - eol =2; - 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; + } } - line[len] =*ch; - + if (ch == '\n') break; if (repl) { - if ((line[len] < 33) || (line[len] > 126)) - line[len] =repl; + if ((ch < 32) || (ch > 126)) + ch =repl; else for (i =0; replace[i]; ++i) - if (line[len] == replace[i]) { - line[len] =repl; + if (ch == replace[i]) { + ch =repl; break; } } + line[linelen] =ch; } - buffer_seek(&data, len); + 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 (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); + } + } for (i =0; i < dirn; ++i) if (dir[i].fddir != -1) { - switch(eol) { - case 0: linestart(&dir[i], line, len); break; - case 1: lineadd(&dir[i], line, len); break; - case 2: lineflush(&dir[i], line, len); break; + if (dir[i].match != '+') continue; + if (! dir[i].udponly) { + ch ='\n'; + buffer_PUTC(&dir[i].b, ch); + buffer_flush(&dir[i].b); } } - if (eol == 0) eol =1; - if (eol == 2) { eol =0; buffer_seek(&data, 1); } } for (i =0; i < dirn; ++i) {