diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 |
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 |
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /liblog | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
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); +} |
