s6

Mirror/fork of https://skarnet.org/software/s6/
git clone https://ccx.te2000.cz/git/s6
Log | Files | Refs | README | LICENSE

commit 678508409a92f80cacd94a70e1e51ca4a389435a
parent 0fbc13bdc5bf68c6ff44bca7d0f6db02ae045ba5
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date:   Wed, 18 Aug 2021 18:46:40 +0000

 Add s6-socklog

Signed-off-by: Laurent Bercot <ska@appnovation.com>

Diffstat:
Mdoc/index.html | 1+
Adoc/s6-socklog.html | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mexamples/klogd-linux/log/run | 2+-
Mexamples/klogd-linux/run | 2+-
Mexamples/s6-svscanboot | 16++++++++--------
Dexamples/syslogd-linux/README | 9---------
Dexamples/syslogd-linux/log/env/LOGSCRIPT | 6------
Dexamples/syslogd-linux/log/run | 8--------
Dexamples/syslogd-linux/run | 8--------
Aexamples/syslogd/README | 4++++
Rexamples/syslogd-linux/log/README -> examples/syslogd/log/README | 0
Aexamples/syslogd/log/env/LOGSCRIPT | 6++++++
Rexamples/syslogd-linux/log/notification-fd -> examples/syslogd/log/notification-fd | 0
Aexamples/syslogd/log/run | 8++++++++
Rexamples/syslogd-linux/notification-fd -> examples/syslogd/notification-fd | 0
Aexamples/syslogd/run | 4++++
Mpackage/deps.mak | 8++++++--
Mpackage/modes | 1+
Mpackage/targets.mak | 1+
Asrc/daemontools-extras/deps-exe/s6-socklog | 4++++
Msrc/daemontools-extras/deps-exe/ucspilogd | 1+
Asrc/daemontools-extras/lolsyslog.c | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/daemontools-extras/lolsyslog.h | 10++++++++++
Asrc/daemontools-extras/s6-socklog.c | 220+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/daemontools-extras/ucspilogd.c | 144+++++++++++--------------------------------------------------------------------
25 files changed, 525 insertions(+), 167 deletions(-)

diff --git a/doc/index.html b/doc/index.html @@ -259,6 +259,7 @@ synchronization</a>. <ul> <li><a href="s6-log.html">The <tt>s6-log</tt> program</a></li> +<li><a href="s6-socklog.html">The <tt>s6-socklog</tt> program</a></li> <li><a href="ucspilogd.html">The <tt>ucspilogd</tt> program</a></li> </ul> diff --git a/doc/s6-socklog.html b/doc/s6-socklog.html @@ -0,0 +1,139 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>s6: the s6-socklog program</title> + <meta name="Description" content="s6: the s6-socklog program" /> + <meta name="Keywords" content="s6 syslog syslogd log logging daemon root utilities socket unix inet udp datagram protocol" /> + <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="index.html">s6</a><br /> +<a href="//skarnet.org/software/">Software</a><br /> +<a href="//skarnet.org/">skarnet.org</a> +</p> + +<h1> The <tt>s6-socklog</tt> program </h1> + +<p> +<tt>s6-socklog</tt> is a minimal syslog daemon. It reads datagrams +from the <tt>/dev/log</tt> Unix domain socket, or from a Unix domain +or Internet domain socket of the user's choice, converts the encoded +syslog facility and priority names to their human-readable equivalents, +and prints the logs to its stdout. +</p> + +<p> +<tt>s6-socklog</tt> is a reimplementation of the +<a href="http://smarden.org/socklog/socklog.8.html">socklog</a> program +with a few more features. +</p> + +<h2> Interface </h2> + +<pre> + s6-socklog [ -d <em>notif</em> ] [ -r ] [ -U | -u <em>uid</em> -g <em>gid</em> -G <em>gidlist</em> ] [ -l <em>linelen</em> ] [ -t <em>lameducktimeout</em> ] [ -x <em>unixsocket</em> | -i <em>ipport</em> ] +</pre> + +<ul> + <li> <tt>s6-socklog</tt> binds to <tt>/dev/log</tt>. </li> + <li> It drops its root privileges. </li> + <li> For every datagram it reads, it turns its content into a log line: + <ul> + <li> Messages are truncated to 1024 characters </li> + <li> Trailing nulls or newlines are removed </li> + <li> Embedded nulls or newlines are converted to <tt>~</tt> characters (tildas) </li> + <li> A <tt>&lt;syslogcode&gt;</tt> at the beginning of the line is converted to <tt>facility.priority: </tt> </li> + </ul> +and prints the log line to its stdout, terminated by a newline. </li> + <li> It exits 0 on a SIGTERM. </li> +</ul> + +<h2> Exit codes </h2> + +<ul> + <li> 0: SIGTERM received, clean exit </li> + <li> 99: SIGTERM received but the buffer could not be flushed in time, some logs may be lost </li> + <li> 100: wrong usage </li> + <li> 111: system call failed </li> +</ul> + +<h2> Signals </h2> + +<p> + <tt>s6-socklog</tt> reacts to the following signals: +</p> + +<ul> + <li> SIGTERM: exit as soon as possible </li> +</ul> + +<h2> Options </h2> + +<ul> + <li> <tt>-r</tt>&nbsp;: raw logging. <tt>&lt;syslogcode&gt;</tt> codes +will not be converted to facility/priority names. </li> + <li> <tt>-d</tt>&nbsp;<em>notif</em>&nbsp;: when ready +(actually bound to its socket), +write a newline to file descriptor <em>notif</em> then close it. +This allows <tt>s6-socklog</tt> to use the <a href="notifywhenup.html">s6 +mechanism to notify readiness</a>. <em>notif</em> cannot be lesser than 3. +If this option is not given, no readiness notification is sent. </li> + <li> <tt>-u&nbsp;<em>uid</em></tt>&nbsp;: set the process' user ID to <em>uid</em> </li> + <li> <tt>-g&nbsp;<em>gid</em></tt>&nbsp;: set the process' group ID to <em>gid</em> </li> + <li> <tt>-G&nbsp;<em>gidlist</em></tt>&nbsp;: set the process' supplementary group list +to <em>gidlist</em>, which must be given as a comma-separated list of numeric GIDs, +without spaces. </li> + <li> <tt>-U</tt>&nbsp;: set the process' user ID, group ID and supplementary group list +to the values of the UID, GID and GIDLIST environment variables. If a <tt>-u</tt>, +<tt>-g</tt> or <tt>-G</tt> option is given after <tt>-U</tt>, the command line +value overrides the environment variable. </li> + <li> <tt>-l</tt>&nbsp;<em>linelen</em>&nbsp;: Set the maximum datagram size to +<em>linelen</em>. Default is 1024. It cannot be set to less than 80 or more than +1048576. If a datagram is bigger than <em>linelen</em>, it will be truncated to +<em>linelen</em> characters, and the logged line will end with a <tt>...</tt> ellipsis +to show the truncation. </li> + <li> <tt>-t</tt>&nbsp;<em>lameducktimeout</em>&nbsp;: on receipt of a SIGTERM, give +<tt>s6-socklog</tt> a grace period of <em>lameducktimeout</em> milliseconds to +flush any log lines that are still in its buffer. Default is 0, which means +infinite: the program will only exit when its buffer is empty, and may wait +forever. If <em>lameducktimeout</em> is nonzero and the timeout expires, the +program will exit 99. </li> + <li> <tt>-x</tt>&nbsp;<em>unixsocket</em>&nbsp;: bind to a Unix domain socket +at <em>unixsocket</em>. Default is <tt>/dev/log</tt>. </li> + <li> <tt>-i</tt>&nbsp;<em>ipport</em>&nbsp;: bind to a UDP socket. <em>ipport</em> +is a combination of <em>ip</em>, which must be an IPv4 or IPv6 address, and +<em>port</em>, which must be an integer. <em>port</em> may be omitted, in which +case it defaults to 514. If <em>port</em> is given, <em>ip</em> and <em>port</em> +must be separated by a <tt>_</tt> character (an underscore). If <em>ip</em> is +IPv4, a <tt>:</tt> (colon) can be used instead of an underscore. </li> +</ul> + +<h2> Typical use </h2> + +<p> + <tt>s6-socklog</tt> can be paired with <a href="s6-log.html">s6-log</a> to +implement <em>syslogd</em> functionality. <tt>s6-socklog</tt> acts as the +<em>frontend</em>: it reads the log lines and processes them, then pipes them +to an <a href="s6-log.html">s6-log</a> instance that acts as the <em>backend</em>, +i.e. sorts the log lines depending on regular expressions that typically involve +the facility and priority names, then stores them into the filesystem. +</p> + +<p> + The pipe between <tt>s6-socklog</tt> and <a href="s6-log.html">s6-log</a> is +typically a <em>logging pipe</em> automatically provided by +<a href="s6-svscan.html">s6-svscan</a> when the <tt>s6-log</tt> instance is declared as +a logger service for the <tt>s6-socklog</tt> instance. +</p> + +<p> + The <tt>examples/</tt> subdirectory of the s6 package contains a turnkey +<tt>syslogd</tt> service that implements this pattern. +</p> + +</body> +</html> diff --git a/examples/klogd-linux/log/run b/examples/klogd-linux/log/run @@ -1,4 +1,4 @@ -#!/command/execlineb -P +#!/bin/execlineb -P s6-setuidgid klog exec -c s6-log -d3 t s1000000 n20 /var/log/klogd diff --git a/examples/klogd-linux/run b/examples/klogd-linux/run @@ -1,4 +1,4 @@ -#!/command/execlineb -P +#!/bin/execlineb -P fdmove -c 2 1 redirfd -r 0 /proc/kmsg exec -c diff --git a/examples/s6-svscanboot b/examples/s6-svscanboot @@ -1,9 +1,9 @@ -#!/command/execlineb -P +#!/bin/execlineb -P -/command/exec -c -/command/s6-setsid -qb -/command/redirfd -r 0 /dev/null -/command/redirfd -wnb 1 /service/s6-svscan-log/fifo -/command/fdmove -c 2 1 -/command/exec -a s6-svscan -/command/s6-svscan -t0 /service +/bin/exec -c +/bin/s6-setsid -qb +/bin/redirfd -r 0 /dev/null +/bin/redirfd -wnb 1 /service/s6-svscan-log/fifo +/bin/fdmove -c 2 1 +/bin/exec -a s6-svscan +/bin/s6-svscan -t0 /service diff --git a/examples/syslogd-linux/README b/examples/syslogd-linux/README @@ -1,9 +0,0 @@ -This is an example of a service directory for process supervision by s6. - -This syslogd emulation works on any Unix where syslog() is -implemented via a connection on the /dev/log Unix-domain socket. -It needs a Unix superserver (see s6-networking, ucspi-unix or -ucspi-ipc) and ucspilogd. -A ucspilogd process is spawned for every syslog() client. It -processes logs and sends them to stderr, i.e. the service's -logger. diff --git a/examples/syslogd-linux/log/env/LOGSCRIPT b/examples/syslogd-linux/log/env/LOGSCRIPT @@ -1,6 +0,0 @@ -- +^[0-9]+:\s[0-9]+:\serror\. t /var/log/syslogd/error -- +^[0-9]+:\s[0-9]+:\sauthpriv\. t /var/log/syslogd/auth -- +^[0-9]+:\s[0-9]+:\suser\. t /var/log/syslogd/user -- +^[0-9]+:\s[0-9]+:\smessages\. t /var/log/syslogd/messages -- +^[0-9]+:\s[0-9]+:\sdaemon\. t /var/log/syslogd/daemon -f t /var/log/syslogd/misc diff --git a/examples/syslogd-linux/log/run b/examples/syslogd-linux/log/run @@ -1,8 +0,0 @@ -#!/command/execlineb -P -s6-setuidgid syslog -s6-envdir -f env -importas -Cs LOGSCRIPT LOGSCRIPT -exec -c -s6-log -d3 -- $LOGSCRIPT - -# Change env/LOGSCRIPT to alter s6-log's behaviour diff --git a/examples/syslogd-linux/run b/examples/syslogd-linux/run @@ -1,8 +0,0 @@ -#!/command/execlineb -P -fdmove -c 2 1 -exec -c -s6-envuidgid nobody -fdmove 1 3 -s6-ipcserver -U -1 -- /dev/log -fdmove -c 1 2 -ucspilogd IPCREMOTEEUID IPCREMOTEEGID diff --git a/examples/syslogd/README b/examples/syslogd/README @@ -0,0 +1,4 @@ +This is an example of a service directory for process supervision by s6. + +This syslogd emulation works on any Unix where syslog() is +implemented via a connection on the /dev/log Unix-domain socket. diff --git a/examples/syslogd-linux/log/README b/examples/syslogd/log/README diff --git a/examples/syslogd/log/env/LOGSCRIPT b/examples/syslogd/log/env/LOGSCRIPT @@ -0,0 +1,6 @@ +- +^\\serror\\. t /var/log/syslogd/error +- +^\\sauthpriv\\. t /var/log/syslogd/auth +- +^\\suser\\. t /var/log/syslogd/user +- +^\\smessages\\. t /var/log/syslogd/messages +- +^\\sdaemon\\. t /var/log/syslogd/daemon +f t /var/log/syslogd/misc diff --git a/examples/syslogd-linux/log/notification-fd b/examples/syslogd/log/notification-fd diff --git a/examples/syslogd/log/run b/examples/syslogd/log/run @@ -0,0 +1,8 @@ +#!/bun/execlineb -P +s6-setuidgid syslog +s6-envdir -f env +importas -Cs LOGSCRIPT LOGSCRIPT +exec -c +s6-log -d3 -- $LOGSCRIPT + +# Change env/LOGSCRIPT to alter s6-log's behaviour diff --git a/examples/syslogd-linux/notification-fd b/examples/syslogd/notification-fd diff --git a/examples/syslogd/run b/examples/syslogd/run @@ -0,0 +1,4 @@ +#!/bin/execlineb -P +fdmove -c 2 1 +s6-envuidgid nobody +s6-socklog -d3 -U -t3000 diff --git a/package/deps.mak b/package/deps.mak @@ -19,6 +19,7 @@ src/conn-tools/s6-ipcserverd.o src/conn-tools/s6-ipcserverd.lo: src/conn-tools/s src/conn-tools/s6-sudo.o src/conn-tools/s6-sudo.lo: src/conn-tools/s6-sudo.c src/include/s6/config.h src/conn-tools/s6-sudoc.o src/conn-tools/s6-sudoc.lo: src/conn-tools/s6-sudoc.c src/conn-tools/s6-sudo.h src/conn-tools/s6-sudod.o src/conn-tools/s6-sudod.lo: src/conn-tools/s6-sudod.c src/conn-tools/s6-sudo.h +src/daemontools-extras/lolsyslog.o src/daemontools-extras/lolsyslog.lo: src/daemontools-extras/lolsyslog.c src/daemontools-extras/lolsyslog.h src/daemontools-extras/s6-applyuidgid.o src/daemontools-extras/s6-applyuidgid.lo: src/daemontools-extras/s6-applyuidgid.c src/daemontools-extras/s6-envdir.o src/daemontools-extras/s6-envdir.lo: src/daemontools-extras/s6-envdir.c src/daemontools-extras/s6-envuidgid.o src/daemontools-extras/s6-envuidgid.lo: src/daemontools-extras/s6-envuidgid.c @@ -27,10 +28,11 @@ src/daemontools-extras/s6-log.o src/daemontools-extras/s6-log.lo: src/daemontool src/daemontools-extras/s6-setlock.o src/daemontools-extras/s6-setlock.lo: src/daemontools-extras/s6-setlock.c src/include/s6/config.h src/include-local/s6lockd.h src/daemontools-extras/s6-setsid.o src/daemontools-extras/s6-setsid.lo: src/daemontools-extras/s6-setsid.c src/daemontools-extras/s6-setuidgid.o src/daemontools-extras/s6-setuidgid.lo: src/daemontools-extras/s6-setuidgid.c src/include/s6/config.h +src/daemontools-extras/s6-socklog.o src/daemontools-extras/s6-socklog.lo: src/daemontools-extras/s6-socklog.c src/daemontools-extras/lolsyslog.h src/daemontools-extras/s6-softlimit.o src/daemontools-extras/s6-softlimit.lo: src/daemontools-extras/s6-softlimit.c src/daemontools-extras/s6-tai64n.o src/daemontools-extras/s6-tai64n.lo: src/daemontools-extras/s6-tai64n.c src/daemontools-extras/s6-tai64nlocal.o src/daemontools-extras/s6-tai64nlocal.lo: src/daemontools-extras/s6-tai64nlocal.c -src/daemontools-extras/ucspilogd.o src/daemontools-extras/ucspilogd.lo: src/daemontools-extras/ucspilogd.c +src/daemontools-extras/ucspilogd.o src/daemontools-extras/ucspilogd.lo: src/daemontools-extras/ucspilogd.c src/daemontools-extras/lolsyslog.h src/fdholder/s6-fdholder-daemon.o src/fdholder/s6-fdholder-daemon.lo: src/fdholder/s6-fdholder-daemon.c src/include/s6/config.h src/fdholder/s6-fdholder-delete.o src/fdholder/s6-fdholder-delete.lo: src/fdholder/s6-fdholder-delete.c src/include/s6/s6-fdholder.h src/fdholder/s6-fdholder-getdump.o src/fdholder/s6-fdholder-getdump.lo: src/fdholder/s6-fdholder-getdump.c src/include/s6/s6-fdholder.h @@ -176,6 +178,8 @@ s6-setsid: EXTRA_LIBS := -lskarnet s6-setsid: src/daemontools-extras/s6-setsid.o s6-setuidgid: EXTRA_LIBS := -lskarnet s6-setuidgid: src/daemontools-extras/s6-setuidgid.o +s6-socklog: EXTRA_LIBS := -lskarnet ${SOCKET_LIB} ${SYSCLOCK_LIB} +s6-socklog: src/daemontools-extras/s6-socklog.o src/daemontools-extras/lolsyslog.o s6-softlimit: EXTRA_LIBS := -lskarnet s6-softlimit: src/daemontools-extras/s6-softlimit.o s6-tai64n: EXTRA_LIBS := -lskarnet ${SYSCLOCK_LIB} @@ -183,7 +187,7 @@ s6-tai64n: src/daemontools-extras/s6-tai64n.o s6-tai64nlocal: EXTRA_LIBS := -lskarnet s6-tai64nlocal: src/daemontools-extras/s6-tai64nlocal.o ucspilogd: EXTRA_LIBS := -lskarnet -ucspilogd: src/daemontools-extras/ucspilogd.o +ucspilogd: src/daemontools-extras/ucspilogd.o src/daemontools-extras/lolsyslog.o s6-fdholder-daemon: EXTRA_LIBS := -lskarnet ${SOCKET_LIB} ${SYSCLOCK_LIB} s6-fdholder-daemon: src/fdholder/s6-fdholder-daemon.o ${LIBS6} s6-fdholder-delete: EXTRA_LIBS := -lskarnet ${SOCKET_LIB} ${SYSCLOCK_LIB} diff --git a/package/modes b/package/modes @@ -31,6 +31,7 @@ s6-setlock 0755 s6-setsid 0755 s6-setuidgid 0700 s6-softlimit 0755 +s6-socklog 0755 s6-tai64n 0755 s6-tai64nlocal 0755 s6-accessrules-cdb-from-fs 0755 diff --git a/package/targets.mak b/package/targets.mak @@ -29,6 +29,7 @@ s6-log \ s6-setlock \ s6-setsid \ s6-softlimit \ +s6-socklog \ s6-tai64n \ s6-tai64nlocal \ s6-accessrules-cdb-from-fs \ diff --git a/src/daemontools-extras/deps-exe/s6-socklog b/src/daemontools-extras/deps-exe/s6-socklog @@ -0,0 +1,4 @@ +lolsyslog.o +-lskarnet +${SOCKET_LIB} +${SYSCLOCK_LIB} diff --git a/src/daemontools-extras/deps-exe/ucspilogd b/src/daemontools-extras/deps-exe/ucspilogd @@ -1 +1,2 @@ +lolsyslog.o -lskarnet diff --git a/src/daemontools-extras/lolsyslog.c b/src/daemontools-extras/lolsyslog.c @@ -0,0 +1,90 @@ +/* ISC license. */ + +#undef INTERNAL_MARK +#ifndef SYSLOG_NAMES +#define SYSLOG_NAMES +#endif + +#include <skalibs/nonposix.h> + +#include <string.h> +#include <syslog.h> + +#include <skalibs/types.h> + +#include "lolsyslog.h" + +#ifndef INTERNAL_MARK + +typedef struct CODE_s CODE, *CODE_ref ; +struct CODE_s +{ + char *c_name ; + unsigned int c_val ; +} ; + +#define LOG_PRI(p) ((p) & LOG_PRIMASK) +#define LOG_FAC(p) (((p) & LOG_FACMASK) / (LOG_PRIMASK + 1)) + +static CODE const facilitynames[] = +{ + { "kern", LOG_KERN }, + { "user", LOG_USER }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "uucp", LOG_UUCP }, + { "daemon", LOG_DAEMON }, + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "lpr", LOG_LPR }, +#ifdef LOG_SYSLOG + { "syslog", LOG_SYSLOG }, +#endif +#ifdef LOG_AUDIT + { "audit", LOG_AUDIT }, +#endif + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, + { 0, -1 } +} ; + +static CODE const prioritynames[] = +{ + { "emerg", LOG_EMERG }, + { "alert", LOG_ALERT }, + { "crit", LOG_CRIT }, + { "err", LOG_ERR }, + { "warning", LOG_WARNING }, + { "notice", LOG_NOTICE }, + { "info", LOG_INFO }, + { "debug", LOG_DEBUG }, + { 0, -1 } +} ; + +#endif + +size_t lolsyslog_string (char *out, char const *in) +{ + size_t i ; + unsigned int fpr ; + int fp ; + CODE const *p = facilitynames ; + + if (in[0] != '<' || !(i = uint_scan(in+1, &fpr)) || in[1+i] != '>') return 0 ; + fp = LOG_FAC(fpr) << 3 ; + for (; p->c_name ; p++) if (p->c_val == fp) break ; + out = stpcpy(out, p->c_name ? p->c_name : "unknown") ; + *out++ = '.' ; + + fp = LOG_PRI(fpr) ; + for (p = prioritynames ; p->c_name ; p++) if (p->c_val == fp) break ; + out = stpcpy(out, p->c_name ? p->c_name : "unknown") ; + *out++ = ':' ; *out++ = ' ' ; *out++ = 0 ; + return i+2 ; +} diff --git a/src/daemontools-extras/lolsyslog.h b/src/daemontools-extras/lolsyslog.h @@ -0,0 +1,10 @@ +/* ISC license. */ + +#ifndef LOLSYSLOG_H +#define LOLSYSLOG_H + +#define LOLSYSLOG_STRING 32 + +extern size_t lolsyslog_string (char *, char const *) ; + +#endif diff --git a/src/daemontools-extras/s6-socklog.c b/src/daemontools-extras/s6-socklog.c @@ -0,0 +1,220 @@ +/* ISC license. */ + +#include <stdint.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <signal.h> +#include <errno.h> +#include <limits.h> + +#include <skalibs/types.h> +#include <skalibs/sgetopt.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/buffer.h> +#include <skalibs/error.h> +#include <skalibs/strerr2.h> +#include <skalibs/tai.h> +#include <skalibs/iopause.h> +#include <skalibs/djbunix.h> +#include <skalibs/socket.h> +#include <skalibs/ip46.h> +#include <skalibs/setgroups.h> +#include <skalibs/sig.h> +#include <skalibs/selfpipe.h> + +#include "lolsyslog.h" + +#define USAGE "s6-socklog [ -d notif ] [ -r ] [ -U | -u uid -g gid -G gidlist ] [ -l linelen ] [ -t lameducktimeout ] [ -x socket | -i ip_port ]" +#define dieusage() strerr_dieusage(100, USAGE) + +static tain lameducktto = TAIN_INFINITE_RELATIVE ; +static int cont = 1 ; + +static inline void handle_signals (void) +{ + for (;;) switch (selfpipe_read()) + { + case -1 : strerr_diefu1sys(111, "selfpipe_read()") ; + case 0 : return ; + case SIGTERM : cont = 0 ; break ; + default : break ; + } +} + +int main (int argc, char const *const *argv) +{ + iopause_fd x[3] = { { .events = IOPAUSE_READ }, { .fd = 1 } } ; + int flagraw = 0 ; + char const *usock = "/dev/log" ; + unsigned int linelen = 1024 ; + PROG = "s6-socklog" ; + { + subgetopt l = SUBGETOPT_ZERO ; + unsigned int notif = 0 ; + unsigned int t = 0 ; + uid_t uid = 0 ; + gid_t gid = 0 ; + gid_t gids[NGROUPS_MAX + 1] ; + size_t gidn = (size_t)-1 ; + ip46 ip ; + uint16_t port = 514 ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "rd:l:t:u:g:G:Ux:i:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'r' : flagraw = 1 ; break ; + case 'd' : if (!uint0_scan(l.arg, &notif)) dieusage() ; break ; + case 'l' : if (!uint0_scan(l.arg, &linelen)) dieusage() ; break ; + case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; + case 'u' : if (!uid0_scan(l.arg, &uid)) dieusage() ; break ; + case 'g' : if (!gid0_scan(l.arg, &gid)) dieusage() ; break ; + case 'G' : if (!gid_scanlist(gids, NGROUPS_MAX, l.arg, &gidn) && *l.arg) dieusage() ; break ; + case 'U' : + { + char const *x = getenv("UID") ; + if (!x) strerr_dienotset(100, "UID") ; + if (!uid0_scan(x, &uid)) strerr_dieinvalid(100, "UID") ; + x = getenv("GID") ; + if (!x) strerr_dienotset(100, "GID") ; + if (!gid0_scan(x, &gid)) strerr_dieinvalid(100, "GID") ; + x = getenv("GIDLIST") ; + if (!x) strerr_dienotset(100, "GIDLIST") ; + if (!gid_scanlist(gids, NGROUPS_MAX+1, x, &gidn) && *x) + strerr_dieinvalid(100, "GIDLIST") ; + break ; + } + case 'x' : usock = l.arg ; break ; + case 'i' : + { + size_t pos = ip46_scan(l.arg, &ip) ; + if (!pos) dieusage() ; + if (l.arg[pos] == '_' || (!ip46_is6(&ip) && l.arg[pos] == ':')) + if (!uint160_scan(l.arg + pos + 1, &port)) dieusage() ; + usock = 0 ; + break ; + } + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + + if (linelen < 80) linelen = 80 ; + if (linelen > 1048576) linelen = 1048576 ; + if (t) tain_from_millisecs(&lameducktto, t) ; + else lameducktto = tain_infinite_relative ; + if (notif) + { + if (notif < 3) strerr_dief1x(100, "notification fd must be 3 or more") ; + if (fcntl(notif, F_GETFD) < 0) strerr_dief1sys(100, "invalid notification fd") ; + } + + close(0) ; + if (fcntl(1, F_GETFD) < 0) strerr_dief1sys(100, "invalid stdout") ; + if (usock) + { + x[2].fd = ipc_datagram_nbcoe() ; + if (x[2].fd == -1) strerr_diefu1sys(111, "create socket") ; + if (ipc_bind_reuse_perms(x[2].fd, usock, 0777) == -1) + strerr_diefu2sys(111, "bind socket to ", usock) ; + } + else + { + x[2].fd = socket_udp46_nbcoe(ip46_is6(&ip)) ; + if (x[2].fd == -1) strerr_diefu1sys(111, "create socket") ; + if (socket_bind46_reuse(x[2].fd, &ip, port) == -1) + { + char fmti[IP46_FMT] ; + char fmtp[UINT16_FMT] ; + fmti[ip46_fmt(fmti, &ip)] = 0 ; + fmtp[uint16_fmt(fmtp, port)] = 0 ; + strerr_diefu5sys(111, "bind socket to ", "ip ", fmti, " port ", fmtp) ; + } + } + + if (gidn != (size_t)-1 && setgroups_and_gid(gid ? gid : getegid(), gidn, gids) < 0) + strerr_diefu1sys(111, "set supplementary group list") ; + if (gid && setgid(gid) < 0) + strerr_diefu1sys(111, "setgid") ; + if (uid && setuid(uid) < 0) + strerr_diefu1sys(111, "setuid") ; + + x[0].fd = selfpipe_init() ; + if (x[0].fd == -1) strerr_diefu1sys(111, "init selfpipe") ; + if (!sig_altignore(SIGPIPE)) strerr_diefu1sys(111, "ignore SIGPIPE") ; + if (!selfpipe_trap(SIGTERM)) strerr_diefu1sys(111, "trap signals") ; + + tain_now_set_stopwatch_g() ; + + if (notif) + { + fd_write(notif, "\n", 1) ; + fd_close(notif) ; + } + } + + { + char outbuf[linelen << 2] ; + buffer b1 = BUFFER_INIT(&buffer_write, 1, outbuf, linelen << 2) ; + char line[linelen + 1] ; + while (cont || buffer_len(&b1)) + { + tain deadline = TAIN_INFINITE ; + ssize_t r ; + if (!cont) tain_add_g(&deadline, &lameducktto) ; + x[1].events = buffer_len(&b1) ? IOPAUSE_WRITE : 0 ; + x[2].events = cont && buffer_available(&b1) >= linelen + 80 ? IOPAUSE_READ : 0 ; + r = iopause_g(x, 3, &deadline) ; + if (r == -1) strerr_diefu1sys(111, "iopause") ; + if (!r) return 99 ; + if (x[0].revents & IOPAUSE_READ) handle_signals() ; + if (x[1].events & x[1].revents & IOPAUSE_WRITE) + if (!buffer_flush(&b1) && !error_isagain(errno)) + strerr_diefu1sys(111, "write to stdout") ; + if (x[2].events & x[2].revents & IOPAUSE_READ) + { + if (usock) + { + r = sanitize_read(fd_recv(x[2].fd, line, linelen + 1, 0)) ; + if (r == -1) strerr_diefu1sys(111, "recv") ; + } + else + { + ip46 ip ; + uint16 port ; + r = sanitize_read(socket_recv46(x[2].fd, line, linelen + 1, &ip, &port)) ; + if (r == -1) strerr_diefu1sys(111, "recv") ; + if (r) + { + char fmt[IP46_FMT + UINT16_FMT + 3] ; + size_t m = ip46_fmt(fmt, &ip) ; + fmt[m++] = '_' ; + m += uint16_fmt(fmt, port) ; + fmt[m++] = ':' ; fmt[m++] = ' ' ; + buffer_putnoflush(&b1, fmt, m) ; + } + } + if (r) + { + size_t len = r ; + size_t pos = 0 ; + while (r && (!line[r-1] || line[r-1] == '\n')) r-- ; + for (size_t i = 0 ; i < r ; i++) + if (!line[i] || line[i] == '\n') line[i] = '~' ; + if (!flagraw) + { + char sbuf[LOLSYSLOG_STRING] ; + pos = lolsyslog_string(sbuf, line) ; + if (pos) buffer_putsnoflush(&b1, sbuf) ; + } + buffer_putnoflush(&b1, line + pos, r - pos) ; + if (len == linelen+1) buffer_putnoflush(&b1, "...", 3) ; + buffer_putnoflush(&b1, "\n", 1) ; + } + } + } + } + return 0 ; +} diff --git a/src/daemontools-extras/ucspilogd.c b/src/daemontools-extras/ucspilogd.c @@ -1,24 +1,18 @@ /* ISC license. */ -#undef INTERNAL_MARK -#ifndef SYSLOG_NAMES -#define SYSLOG_NAMES -#endif - -#include <skalibs/nonposix.h> #include <sys/types.h> #include <errno.h> #include <stdlib.h> -#include <syslog.h> -#include <skalibs/types.h> + #include <skalibs/sgetopt.h> #include <skalibs/bytestr.h> #include <skalibs/buffer.h> #include <skalibs/strerr2.h> #include <skalibs/stralloc.h> -#include <skalibs/env.h> #include <skalibs/skamisc.h> +#include "lolsyslog.h" + #define USAGE "ucspilogd [ -D default ] [ var... ]" #define dieusage() strerr_dieusage(100, USAGE) @@ -27,110 +21,7 @@ static inline void die (void) strerr_diefu1sys(111, "write to stdout") ; } - - /* - Hack: INTERNAL_MARK is defined by all systems that - use the CODE stuff, and not by others (Solaris). -*/ - -#ifndef INTERNAL_MARK - -typedef struct CODE_s CODE, *CODE_ref ; -struct CODE_s -{ - char *c_name ; - unsigned int c_val ; -} ; - -static CODE const prioritynames[] = -{ - { "emerg", LOG_EMERG }, - { "alert", LOG_ALERT }, - { "crit", LOG_CRIT }, - { "err", LOG_ERR }, - { "warning", LOG_WARNING }, - { "notice", LOG_NOTICE }, - { "info", LOG_INFO }, - { "debug", LOG_DEBUG }, - { 0, -1 } -} ; - -static CODE const facilitynames[] = -{ - { "kern", LOG_KERN }, - { "user", LOG_USER }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "uucp", LOG_UUCP }, - { "daemon", LOG_DAEMON }, - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "lpr", LOG_LPR }, -#ifdef LOG_SYSLOG - { "syslog", LOG_SYSLOG }, -#endif -#ifdef LOG_AUDIT - { "audit", LOG_AUDIT }, -#endif - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { 0, -1 } -} ; - -#define LOG_PRI(p) ((p) & LOG_PRIMASK) -#define LOG_FAC(p) (((p) & LOG_FACMASK) / (LOG_PRIMASK + 1)) - -#endif - - -static size_t syslog_names (char const *line) -{ - size_t i ; - unsigned int fpr ; - int fp ; - CODE const *p = facilitynames ; - - if (line[0] != '<') return 0 ; - i = uint_scan(line+1, &fpr) ; - if (!i || (line[i+1] != '>')) return 0 ; - i += 2 ; - - fp = LOG_FAC(fpr) << 3 ; - for (; p->c_name ; p++) if (p->c_val == fp) break ; - if (p->c_name) - { - if ((buffer_puts(buffer_1, p->c_name) < 0) - || (buffer_put(buffer_1, ".", 1) < 1)) die() ; - } - else - { - if (buffer_put(buffer_1, "unknown.", 8) < 8) die() ; - i = 0 ; - } - - fp = LOG_PRI(fpr) ; - for (p = prioritynames ; p->c_name ; p++) if (p->c_val == fp) break ; - if (p->c_name) - { - if ((buffer_puts(buffer_1, p->c_name) < 0) - || (buffer_put(buffer_1, ": ", 2) < 2)) die() ; - } - else - { - if (buffer_put(buffer_1, "unknown: ", 9) < 9) die() ; - i = 0 ; - } - return i ; -} - - -int main (int argc, char const *const *argv, char const *const *envp) +int main (int argc, char const *const *argv) { char const *d = "<undefined>" ; PROG = "ucspilogd" ; @@ -150,38 +41,43 @@ int main (int argc, char const *const *argv, char const *const *envp) } { - char const *envs[argc] ; unsigned int i = 0 ; + stralloc sa = STRALLOC_ZERO ; + char buf[LOLSYSLOG_STRING] ; + char const *envs[argc] ; for (; i < (unsigned int)argc ; i++) { - envs[i] = env_get2(envp, argv[i]) ; + envs[i] = getenv(argv[i]) ; if (!envs[i]) envs[i] = d ; } for (;;) { size_t pos = 0 ; - satmp.len = 0 ; + size_t j ; + sa.len = 0 ; { - int r = skagetlnsep(buffer_0f1, &satmp, "\n", 2) ; + int r = skagetlnsep(buffer_0f1, &sa, "\n", 2) ; if (r < 0) { - if (errno != EPIPE || !stralloc_0(&satmp)) + if (errno != EPIPE || !stralloc_0(&sa)) strerr_diefu1sys(111, "read from stdin") ; } if (!r) break ; } - if (!satmp.len) continue ; - satmp.s[satmp.len-1] = '\n' ; - if ((satmp.s[0] == '@') && (satmp.len > 26) && (byte_chr(satmp.s, 26, ' ') == 25)) + if (!sa.len) continue ; + sa.s[sa.len-1] = 0 ; + if ((sa.s[0] == '@') && (sa.len > 26) && (byte_chr(sa.s, 26, ' ') == 25)) { - if (buffer_put(buffer_1, satmp.s, 26) < 26) die() ; + if (buffer_put(buffer_1, sa.s, 26) < 26) die() ; pos += 26 ; } for (i = 0 ; i < (unsigned int)argc ; i++) if ((buffer_puts(buffer_1, envs[i]) < 0) || (buffer_put(buffer_1, ": ", 2) < 2)) die() ; - pos += syslog_names(satmp.s + pos) ; - if (buffer_put(buffer_1, satmp.s + pos, satmp.len - pos) < (ssize_t)(satmp.len - pos)) die() ; + j = lolsyslog_string(buf, sa.s + pos) ; pos += j ; + if (j && buffer_puts(buffer_1, buf) < 0) die() ; + sa.s[sa.len-1] = '\n' ; + if (buffer_put(buffer_1, sa.s + pos, sa.len - pos) < 0) die() ; } } return 0 ;