diff options
Diffstat (limited to 'liblog')
| -rw-r--r-- | liblog/Makefile.am | 23 | ||||
| -rw-r--r-- | liblog/configure.in | 44 | ||||
| -rw-r--r-- | liblog/courierlogger.sgml | 252 | ||||
| -rw-r--r-- | liblog/logger.c | 519 | 
4 files changed, 838 insertions, 0 deletions
| diff --git a/liblog/Makefile.am b/liblog/Makefile.am new file mode 100644 index 0000000..dfec2c3 --- /dev/null +++ b/liblog/Makefile.am @@ -0,0 +1,23 @@ +# +# Copyright 2004-2007 Double Precision, Inc.  See COPYING for +# distribution information. + +sbin_PROGRAMS=courierlogger + +BUILT_SOURCES=courierlogger.html courierlogger.1 +man_MANS=courierlogger.1 + +EXTRA_DIST=$(BUILT_SOURCES) + +courierlogger_SOURCES=logger.c +courierlogger_DEPENDENCIES=../liblock/liblock.la ../numlib/libnumlib.la +courierlogger_LDADD=../liblock/liblock.la ../numlib/libnumlib.la +courierlogger_LDFLAGS=-static + +if HAVE_SGML +courierlogger.html: courierlogger.sgml ../docbook/sgml2html +	../docbook/sgml2html courierlogger.sgml courierlogger.html + +courierlogger.1: courierlogger.sgml ../docbook/sgml2html +	../docbook/sgml2man courierlogger.sgml courierlogger.1 +endif diff --git a/liblog/configure.in b/liblog/configure.in new file mode 100644 index 0000000..5cfcd20 --- /dev/null +++ b/liblog/configure.in @@ -0,0 +1,44 @@ +dnl Process this file with autoconf to produce a configure script. +dnl +dnl Copyright 2004 Double Precision, Inc.  See COPYING for +dnl distribution information. + +AC_INIT(courierlogger, 0.10, [courier-users@lists.sourceforge.net]) + +>confdefs.h # Kill PACKAGE_ macros. +LPATH="$PATH:/usr/local/bin" +AC_CONFIG_SRCDIR(logger.c) +AC_CONFIG_AUX_DIR(../..) +AM_INIT_AUTOMAKE([foreign no-define]) +AM_CONFIG_HEADER(config.h) + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_LIBTOOL + +if test x$GCC = xyes +then +	CFLAGS="-Wall $CFLAGS" +fi +if test x$GXX = xyes +then +	CXXFLAGS="-Wall $CXXFLAGS" +fi + +AC_C_CONST +AC_HEADER_STDC +AC_CHECK_HEADERS(fcntl.h string.h syslog.h) +AC_TYPE_UID_T +AC_SYS_LARGEFILE +AC_CHECK_FUNCS(strchr) + +AC_ARG_WITH(syslog, +	AC_HELP_STRING([--with-syslog=XXX],[syslog facility [[MAIL]]]), +	logdest="LOG_$withval", logdest="LOG_MAIL") + +AC_DEFINE_UNQUOTED(LOG_DEST, [$logdest], +	[ syslog facility ]) +AM_CONDITIONAL(HAVE_SGML, test -d ${srcdir}/../docbook) +AC_OUTPUT(Makefile) diff --git a/liblog/courierlogger.sgml b/liblog/courierlogger.sgml new file mode 100644 index 0000000..47f7014 --- /dev/null +++ b/liblog/courierlogger.sgml @@ -0,0 +1,252 @@ +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> + +  <!-- Copyright 2004-2007 Double Precision, Inc.  See COPYING for --> +  <!-- distribution information. --> + +<refentry id="courierlogger"> + +  <refmeta> +    <refentrytitle>courierlogger</refentrytitle> +    <manvolnum>1</manvolnum> +    <refmiscinfo>Double Precision, Inc.</refmiscinfo> +  </refmeta> + +  <refnamediv> +    <refname>courierlogger</refname> +    <refpurpose>Courier syslog wrapper</refpurpose> +  </refnamediv> + +  <refsynopsisdiv> +    <cmdsynopsis> +      <command>courierlogger</command> +      <arg>-name=<replaceable>title</replaceable></arg> +      <arg>-facility=<replaceable>subsystem</replaceable></arg> +      <arg>-pid=<replaceable>filename</replaceable></arg> +      <arg>-user=<replaceable>user</replaceable></arg> +      <arg>-group=<replaceable>group</replaceable></arg> +      <arg>-droproot</arg> +      <group> +	<arg><arg choice='opt'>-respawn</arg> <arg choice='opt'>-start</arg> +             <replaceable>program</replaceable> <arg rep='repeat'>argument</arg></arg> +	<arg>-stop</arg> +	<arg>-restart</arg> +      </group> +    </cmdsynopsis> + +  </refsynopsisdiv> + +  <refsect1> +    <title>DESCRIPTION</title> + +    <para> +<command>courierlogger</command> +is a wrapper that captures +another process's error messages, and forwards them +to the system logging facility, +<quote>syslog</quote>.</para> + +    <para> +There are two ways to use courierlogger: +<orderedlist> +	<listitem> +	  <para> +Use the shell to pipe another command's standard error, and/or its standard +output, to +<command>courierlogger</command>'s standard input.</para> +	</listitem> +	<listitem> +	  <para> +Alternatively, +<command>courierlogger</command> +itself can start another process, and arrange to have its standard error +captured.</para> +	</listitem> +      </orderedlist> +    </para> + +    <para> +In either case, each read line of text is sent as a syslog message.</para> +  </refsect1> + +  <refsect1> +    <title>OPTIONS</title> +    <variablelist> +      <varlistentry> +	<term>-name=<replaceable>title</replaceable></term> +	<listitem> +<para> +Use <replaceable>title</replaceable> for sending messages to syslog. +<replaceable>title</replaceable> should be the application's name.</para> +	</listitem> +      </varlistentry> +      <varlistentry> +	<term>-facility=<replaceable>subsystem</replaceable></term> +	<listitem> +	  <para> +Use <replaceable>subsystem</replaceable> for classifying messages. +Your syslog facility uses <replaceable>subsystem</replaceable> to determine +which log messages are recorded in which log files. +The currently defined subsystems are:</para> + +	  <itemizedlist> +	    <listitem><para><literal>auth</literal></para></listitem> +	    <listitem><para><literal>authpriv</literal></para></listitem> +	    <listitem><para><literal>console</literal></para></listitem> +	    <listitem><para><literal>cron</literal></para></listitem> +	    <listitem><para><literal>daemon</literal></para></listitem> +	    <listitem><para><literal>ftp</literal></para></listitem> +	    <listitem><para><literal>kern</literal></para></listitem> +	    <listitem><para><literal>lpr</literal></para></listitem> +	    <listitem><para><literal>mail</literal></para></listitem> +	    <listitem><para><literal>news</literal></para></listitem> +	    <listitem><para><literal>security</literal></para></listitem> +	    <listitem><para><literal>user</literal></para></listitem> +	    <listitem><para><literal>uucp</literal></para></listitem> +	    <listitem><para><literal>local0</literal></para></listitem> +	    <listitem><para><literal>local1</literal></para></listitem> +	    <listitem><para><literal>local2</literal></para></listitem> +	    <listitem><para><literal>local3</literal></para></listitem> +	    <listitem><para><literal>local4</literal></para></listitem> +	    <listitem><para><literal>local5</literal></para></listitem> +	    <listitem><para><literal>local6</literal></para></listitem> +	    <listitem><para><literal>local7</literal></para></listitem> +	  </itemizedlist> + +	  <note> +	    <para> +Not all of the above facility names are implemented on every system. +Check your system's syslog documentation for information on which facility +names are allowed, and which log files record the corresponding messages +for each facility.</para> +	  </note> +	</listitem> +      </varlistentry> +      <varlistentry> +	<term>-pid=<replaceable>filename</replaceable></term> +	<listitem> +<para> +Save <command>courierlogger</command>'s +process ID in <replaceable>filename</replaceable>. +The <parameter>-pid</parameter> option is required when +<parameter>-start</parameter>, +<parameter>-stop</parameter>, +<parameter>-restart</parameter> are given. If <parameter>-pid</parameter> +is given without any of these, <parameter>-start</parameter> is assumed.</para> +	</listitem> +      </varlistentry> + +      <varlistentry> +	<term>-start</term> +	<listitem> +	  <para> +Run as a daemon. The <option>pid</option> option is required. +<command>courierlogger</command> will quietly terminate if another +<command>courierlogger</command> process is already running. +This is used to make sure that only one instance of +<filename>program</filename> is running at the same time. +Specify a different filename with <option>pid</option> to start a second +copy of <filename>program</filename>.</para> +	</listitem> +      </varlistentry> + +      <varlistentry> +	<term>-respawn</term> +	<listitem> +<para> +Restart <filename>program</filename> if it terminates. +Normally +<command>courierlogger</command> itself will terminate when +<filename>program</filename> finishes running. +Use <option>respawn</option> to restart it instead.</para> +	</listitem> +      </varlistentry> + +      <varlistentry> +	<term>-restart</term> +	<listitem> +	  <para> +Send a <literal>SIGHUP</literal> signal to the courierlogger process +(as determined by examining the contents of the file specified by +<option>pid</option>), which will in turn send a <literal>SIGHUP</literal> +to its child <filename>program</filename>. +Does nothing if courierlogger is not running.</para> + +	  <note> +	    <para> +<filename>program</filename> must be originally started with the +<option>respawn</option> option if sending it a <literal>SIGHUP</literal> +causes it to terminate.</para> +	  </note> + +	  <para> +The same thing may be accomplished by sending <literal>SIGHUP</literal> +to <command>courierlogger</command> itself.</para> + +	</listitem> +      </varlistentry> + +      <varlistentry> +	<term>-stop</term> +	<listitem> +<para> +Send a <literal>SIGTERM</literal> signal to courierlogger, which in turn +forwards it on to <filename>program</filename>. +If <filename>program</filename> does not terminate in 8 seconds, kill it +with <literal>SIGKILL</literal>.</para> +	</listitem> +      </varlistentry> + +      <varlistentry> +	<term>-user=<replaceable>user</replaceable>, -group=<replaceable>group</replaceable></term> +	<listitem> +	  <para> +If running as root, change credentials to the given user and/or group, which +may be given as names or numeric ids.</para> +<para>When running a child program, it is started +<emphasis>before</emphasis> privileges are dropped +(unless the <option>-droproot</option> option is also given). +This gives a means of +starting a child as root so it can bind to a privileged port, but still have +courierlogger run as a non-root user. For the <option>-stop</option> and +<option>-restart</option> options to work, you should configure the child +program to drop its privileges to the same userid too.</para> +	</listitem> +      </varlistentry> + +      <varlistentry> +	<term>-droproot</term> +	<listitem> +	  <para> +Drop root privileges before starting the child process. +The <option>-user</option> and <option>-group</option> options specify +the non-privileges userid and groupid. +Without the <option>-droproot</option> option the child process remains +a root process, and only the parent <command>courierlogger</command> +process drops root privileges.</para> +	</listitem> +      </varlistentry> + +      <varlistentry> +        <term><replaceable>program</replaceable> [ argument ] ... </term> +        <listitem> +          <para> +If a program is given <filename>program</filename> +will be started as a child process of +<command>courierlogger</command>, capturing its standard error. +Otherwise, <command>courierlogger</command> +reads message from standard input, and automatically terminates when +standard input is closed.</para> +        </listitem> +      </varlistentry> + +    </variablelist> +  </refsect1> + +  <refsect1> +    <title>SEE ALSO</title> + +    <para> +<ulink url="couriertcpd.html"><citerefentry><refentrytitle>couriertcpd</refentrytitle><manvolnum>1</manvolnum></citerefentry></ulink>, your syslog man page.</para> +  </refsect1> +</refentry> diff --git a/liblog/logger.c b/liblog/logger.c new file mode 100644 index 0000000..2fe40cc --- /dev/null +++ b/liblog/logger.c @@ -0,0 +1,519 @@ +/* +** Copyright 1998 - 2006 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#if	HAVE_CONFIG_H +#include	"config.h" +#endif +#include	<string.h> +#include	<stdio.h> +#include	<stdlib.h> +#include	<sys/types.h> +#include	<sys/wait.h> +#include	<signal.h> +#include	<errno.h> +#include	<fcntl.h> +#include	<pwd.h> +#include	<grp.h> +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif +#if	HAVE_SYSLOG_H +#include	<syslog.h> +#else +#undef	TESTMODE +#define	TESTMODE	1 +#endif +#include	"../liblock/config.h" +#include	"../liblock/liblock.h" +#include	"../numlib/numlib.h" + + +static int do_logger(const char *name, int facility, FILE *f) +{ +char	buf[512]; +char	*p; +int	c; + +#if	TESTMODE + +#else +	openlog(name, 0 + +#ifdef	LOG_NDELAY +			| LOG_NDELAY +#else +			| LOG_NOWAIT +#endif + +			, facility); +#endif +	if (chdir("/") < 0) +	{ +		perror("chdir(\"/\")"); +		exit(1); +	} + +	while (fgets(buf, sizeof(buf), f)) +	{ +		if ((p=strchr(buf, '\n')) != 0)	*p=0; +		else +			while ((c=getchar()) != EOF && c != '\n') +				; + +#if	TESTMODE +		fprintf(stderr, "%s: %s\n", name, buf); +#else +		c=LOG_INFO; +		if (strncmp(buf, "ERR:", 4) == 0) +		{ +			c=LOG_ERR; +			p=buf+4; +		} +		else if (strncmp(buf, "WARN:", 5) == 0) +		{ +			c=LOG_WARNING; +			p=buf+5; +		} +		else if (strncmp(buf, "ALERT:", 6) == 0) +		{ +			c=LOG_ALERT; +			p=buf+6; +		} +		else if (strncmp(buf, "CRIT:", 5) == 0) +		{ +			c=LOG_CRIT; +			p=buf+5; +		} +		else if (strncmp(buf, "DEBUG:", 6) == 0) +		{ +			c=LOG_DEBUG; +			p=buf+6; +		} +		else if (strncmp(buf, "INFO:", 5) == 0) +			p=buf+5; +		else	p=buf; + +		while (*p == ' ') +			++p; + +		syslog(c, "%s", p); +#endif +	} +	return (0); +} + +static const char *namearg=0; +static const char *pidarg=0; +static char *lockfilename=0; + +struct lognames +{ +	char *name; +	int value; +}; + +static struct lognames facilitynames[] = +{ +#ifdef LOG_AUTH +	{ "auth",	LOG_AUTH }, +#endif +#ifdef LOG_AUTHPRIV +	{ "authpriv",	LOG_AUTHPRIV }, +#endif +#ifdef LOG_CONSOLE +	{ "console",	LOG_CONSOLE }, +#endif +#ifdef LOG_CRON +	{ "cron",	LOG_CRON }, +#endif +#ifdef LOG_DAEMON +	{ "daemon",	LOG_DAEMON }, +#endif +#ifdef LOG_FTP +	{ "ftp",	LOG_FTP }, +#endif +#ifdef LOG_KERN +	{ "kern",	LOG_KERN }, +#endif +#ifdef LOG_LPR +	{ "lpr",	LOG_LPR }, +#endif +#ifdef LOG_MAIL +	{ "mail",	LOG_MAIL }, +#endif +#ifdef LOG_AUTHPRIV +	{ "news",	LOG_NEWS }, +#endif +#ifdef LOG_SECURITY +	{ "security",	LOG_SECURITY }, +#endif +#ifdef LOG_USER +	{ "user",	LOG_USER }, +#endif +#ifdef LOG_UUCP +	{ "uucp",	LOG_UUCP }, +#endif +#ifdef LOG_LOCAL0 +	{ "local0",	LOG_LOCAL0 }, +#endif +#ifdef LOG_LOCAL1 +	{ "local1",	LOG_LOCAL1 }, +#endif +#ifdef LOG_LOCAL2 +	{ "local2",	LOG_LOCAL2 }, +#endif +#ifdef LOG_LOCAL3 +	{ "local3",	LOG_LOCAL3 }, +#endif +#ifdef LOG_LOCAL4 +	{ "local4",	LOG_LOCAL4 }, +#endif +#ifdef LOG_LOCAL5 +	{ "local5",	LOG_LOCAL5 }, +#endif +#ifdef LOG_LOCAL6 +	{ "local6",	LOG_LOCAL6 }, +#endif +#ifdef LOG_LOCAL7 +	{ "local7",	LOG_LOCAL7 }, +#endif +	{ 0,		0 } +}; + +static int hup_restart = 0; +static int respawn = 0; +static int child_pid = -1; + +static RETSIGTYPE sighup(int n) +{ +	if (child_pid > 0) +	{ +		/* The child may respond to HUP by dying. If so it will +		   close its stderr and do_logger will terminate; at that +		   point we need to restart it */ +		hup_restart = 1; +		kill (child_pid, SIGHUP); +	} +	signal(SIGHUP, sighup); +#if	RETSIGTYPE != void +	return (1); +#endif +} + +static RETSIGTYPE sigalrm(int n) +{ +	if (child_pid > 0) kill(child_pid, SIGKILL); +#if	RETSIGTYPE != void +	return (1); +#endif +} + +static RETSIGTYPE sigterm(int n) +{ +	if (child_pid > 0) +	{ +		hup_restart = 0; +		respawn = 0; +		kill(child_pid, SIGTERM); +		signal(SIGALRM, sigalrm); /* kill after 8 secs */ +		alarm(8); +	} +	else exit(0); +#if	RETSIGTYPE != void +	return (1); +#endif +} + +static void checkfd(int actual, int exp) +{ +	if (actual == exp) return; +	fprintf(stderr, "Bad fd, got %d, expected %d\n", actual, exp); +	if (actual < 0) perror("error"); +	exit(1); +} + +static int isid(const char *p) +{ +	while (*p) +	{ +		if (*p < '0' || *p > '9')	return (0); +		++p; +	} +	return (1); +} + +static void setuidgid(const char *userarg, +		      const char *grouparg) +{ +	if (grouparg) +	{ +	gid_t gid = 0; +	struct group *gr; +	 +		if (isid(grouparg)) +			gid=atoi(grouparg); +		else if ((gr=getgrnam(grouparg)) == 0) +		{ +			fprintf(stderr, "Group not found: %s\n", grouparg); +			exit(1); +		} +		else	gid=gr->gr_gid; + +		libmail_changegroup(gid); +	} + +	if (userarg) +	{ +	uid_t	uid; + +		if (isid(userarg)) +		{ +			uid=atoi(userarg); +			libmail_changeuidgid(uid, getgid()); +		} +		else +		{ +		gid_t	g=getgid(), *gp=0; + +			if (grouparg)	gp= &g; +			libmail_changeusername(userarg, gp); +		} +	} +} + + +static void startchild(char **argv, const char *userarg, const char *grouparg) +{ +pid_t p; +int pipefd[2]; +int tmp; + +	signal(SIGTERM, sigterm); +	signal(SIGHUP, sighup); + +	/* Make sure the pipefds are at least 3 and 4. If we have an open +	   stderr then keep it around for debugging purposes. */ +	close(0); +	checkfd(open("/dev/null", O_RDWR), 0); +	close(1); +	checkfd(dup(0), 1); +	if ((tmp = dup(0)) > 2) close(tmp); + +	if (pipe(pipefd) < 0) +	{ +		perror("pipe"); +		exit(1); +	} +	p = fork(); +	if (p < 0) +	{ +		perror("fork"); +		exit(1); +	} +	if (p == 0) +	{ + +		close(pipefd[0]); +		close(2); +		checkfd(dup(pipefd[1]), 2); +		close(pipefd[1]); +		setuidgid(userarg, grouparg); +		execvp(argv[0], argv); +		perror("exec"); +		exit(1); +	} + +	// We can close stderr now + +	close(2); +	checkfd(dup(0), 2); + + +	close(pipefd[1]); +	close(0); +	checkfd(dup(pipefd[0]), 0); +	close(pipefd[0]); +	child_pid = p; +} +/* + * Note that we now support several modes of operation: + * + * (1) standalone logger, just collect messages on stdin and feed to syslog + *   courierlogger foo + *   courierlogger -name=foo + * + * (2) run a child process, collect its stderr messages and feed to syslog + *   courierlogger [-name=foo] foo arg1 arg2 + * + * (3) start a detached daemon with a child process + *   courierlogger [-name=foo] -pid=/var/run/foo.pid -start foo arg1 arg2 + * + * (4) stop or restart a detached daemon + *   courierlogger -pid=/var/run/foo.pid -stop      (or receive a SIGTERM) + *   courierlogger -pid=/var/run/foo.pid -restart   (or receive a SIGHUP) + */ +  +int main(int argc, char **argv) +{ +int facility = LOG_DEST; +int daemon = 0; +int lockfd = -1; +const char *userarg = 0; +const char *grouparg = 0; +int droproot=0; + +	if (argc == 2 && argv[1][0] != '-') +	{ +		/* backwards-compatibility mode */ +		close(1); +		close(2); +		checkfd(open("/dev/null", O_WRONLY), 1); +		checkfd(open("/dev/null", O_WRONLY), 2); +		do_logger(argv[1], facility, stdin); +		exit(0); +	} + +	if (argc <= 1) +	{ +		fprintf(stderr, + +			"Usage: courierlogger [-name=name] [-pid=pidfile] [-facility=type]\n" +			"       [-start|-stop|-restart] [cmd [args...]]\n" +		); +		exit(1); +	} + +	argv++, argc--; +	while (argc > 0 && argv[0][0]=='-') +	{ +		if (strncmp(argv[0],"-pid=",5) == 0 && argv[0][5]) +		{ +			pidarg=&argv[0][5]; +			lockfilename=malloc(strlen(pidarg)+sizeof(".lock")); +			if (!lockfilename) +			{ +				perror("malloc"); +				exit(1); +			} +			strcat(strcpy(lockfilename, pidarg), ".lock"); +		} +		else +		if (strncmp(argv[0],"-name=",6) == 0 && argv[0][6]) +			namearg=&argv[0][6]; +		else if (strncmp(argv[0],"-user=",6) == 0) +			userarg=argv[0]+6; +		else if (strncmp(argv[0],"-group=",7) == 0) +			grouparg=argv[0]+7; +		else if (strcmp(argv[0], "-droproot") == 0) +			droproot=1; +		else +		if (strncmp(argv[0],"-facility=",10) == 0) +		{ +		struct lognames *p = facilitynames; + +			while (p->name && strcmp(p->name, &argv[0][10])) +				p++; +			if (p->name == 0) +			{ +				fprintf(stderr, "Unknown facility name '%s'\n", +					&argv[0][10]); +				exit(1); +			} +			facility = p->value; +		} +		else +		if (strcmp(argv[0],"-start") == 0) +			daemon = 1; +		else +		if (strcmp(argv[0],"-stop") == 0) +			daemon = 2; +		else +		if (strcmp(argv[0],"-restart") == 0) +			daemon = 3; +		else +		if (strcmp(argv[0],"-respawn") == 0) +			respawn = 1; +		else +		{ +			fprintf(stderr, "Unknown option '%s'\n", argv[0]); +			exit(1); +		} +		argv++, argc--; +	} + +	if (daemon && !pidarg) +	{ +		fprintf(stderr, "-pid argument required\n"); +		exit(1); +	} + +	if (!daemon && pidarg) +		daemon = 1; /* -start implied */ + +	if (!namearg && daemon != 2 && daemon != 3) +	{ +		/* choose a default name based on the program we're running */ +		if (argc <= 0 || !argv[0] || !argv[0][0]) +		{ +			fprintf(stderr, "-name option required for standalone logger\n"); +			exit(1); +		} +		namearg = strrchr(argv[0],'/'); +		namearg = namearg ? namearg+1 : argv[0]; +	} + +	switch (daemon) +	{ +	case 1: /* start */ +		if (argc <= 0 || !argv[0] || !argv[0][0]) +		{ +			fprintf(stderr, "-start must be followed by a command to execute\n"); +			exit(1); +		} +		lockfd=ll_daemon_start(lockfilename); +		if (lockfd < 0) +		{ +			perror("ll_daemon_start"); +			exit(1); +		} +		startchild(argv, droproot ? userarg:NULL, +			   droproot ? grouparg:NULL); +		ll_daemon_started(pidarg, lockfd); +		break; +	case 2: /* stop */ +		exit(ll_daemon_stop(lockfilename, pidarg)); +	case 3: /* restart */ +		exit(ll_daemon_restart(lockfilename, pidarg)); +	default: /* run in foreground, with or without a child process */ + +		if (argc > 0) +			startchild(argv, droproot ? userarg:NULL, +				   droproot ? grouparg:NULL); +	} + +	setuidgid(userarg, grouparg); + +	while (1) +	{ +	int waitstat; +	pid_t p2; +	FILE *f = fdopen(0, "r"); + +		do_logger(namearg, facility, f); +		fclose(f); +		if (child_pid < 0) break; +		while ((p2=wait(&waitstat)) != child_pid && +			(p2 != -1 || errno != ECHILD)) +			; +		if (hup_restart) +			hup_restart = 0; +		else if (respawn) +			sleep (5); +		else +			break; +		startchild(argv, NULL, NULL); +	} +	exit(0); +} | 
