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/logger.c | |
| 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/logger.c')
| -rw-r--r-- | liblog/logger.c | 519 |
1 files changed, 519 insertions, 0 deletions
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); +} |
