diff options
Diffstat (limited to 'sysklogd')
-rw-r--r-- | sysklogd/logger.c | 186 | ||||
-rw-r--r-- | sysklogd/syslogd.c | 316 |
2 files changed, 449 insertions, 53 deletions
diff --git a/sysklogd/logger.c b/sysklogd/logger.c new file mode 100644 index 0000000..0683838 --- /dev/null +++ b/sysklogd/logger.c @@ -0,0 +1,186 @@ +/* + * Mini logger implementation for busybox + * + * Copyright (C) 1999 by Lineo, inc. + * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "internal.h" +#include <stdio.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <signal.h> +#include <ctype.h> +#include <netdb.h> + +#if !defined BB_SYSLOGD + +#define SYSLOG_NAMES +#include <sys/syslog.h> + +#else +/* We have to do this since the header file defines static + * structues. Argh.... bad libc, bad, bad... + */ +#include <sys/syslog.h> +typedef struct _code { + char *c_name; + int c_val; +} CODE; +extern CODE prioritynames[]; +extern CODE facilitynames[]; +#endif + +static const char logger_usage[] = + "logger [OPTION]... [MESSAGE]\n\n" + "Write MESSAGE to the system log. If MESSAGE is '-', log stdin.\n\n" + "Options:\n" + "\t-s\tLog to stderr as well as the system log.\n" + "\t-p\tEnter the message with the specified priority.\n" + "\t\tThis may be numerical or a ``facility.level'' pair.\n"; + + +/* Decode a symbolic name to a numeric value + * this function is based on code + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + */ +static int +decode(char* name, CODE* codetab) +{ + CODE *c; + + if (isdigit(*name)) + return (atoi(name)); + for (c = codetab; c->c_name; c++) { + if (!strcasecmp(name, c->c_name)) { + return (c->c_val); + } + } + + return (-1); +} + +/* Decode a symbolic name to a numeric value + * this function is based on code + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + */ +static int +pencode(char* s) +{ + char *save; + int lev, fac=LOG_USER; + + for (save = s; *s && *s != '.'; ++s); + if (*s) { + *s = '\0'; + fac = decode(save, facilitynames); + if (fac < 0) { + fprintf(stderr, "unknown facility name: %s\n", save); + exit( FALSE); + } + *s++ = '.'; + } + else { + s = save; + } + lev = decode(s, prioritynames); + if (lev < 0) { + fprintf(stderr, "unknown priority name: %s\n", save); + exit( FALSE); + } + return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); +} + + +extern int logger_main(int argc, char **argv) +{ + struct sockaddr_un sunx; + int fd, pri = LOG_USER|LOG_NOTICE; + int toStdErrFlag=FALSE; + char *message, buf[1024]; + time_t now; + size_t addrLength; + + /* Parse any options */ + while (--argc > 0 && **(++argv) == '-') { + while (*(++(*argv))) { + switch (**argv) { + case 's': + toStdErrFlag = TRUE; + break; + case 'p': + if (--argc == 0) { + usage(logger_usage); + } + pri = pencode(*(++argv)); + if (--argc == 0) { + usage(logger_usage); + } + ++argv; + break; + default: + usage(logger_usage); + } + } + } + + if (argc>=1) + if (**argv=='-') { + /* read from stdin */ + } else { + message=*argv; + } + else { + fprintf(stderr, "No message\n"); + exit( FALSE); + } + + memset(&sunx, 0, sizeof(sunx)); + sunx.sun_family = AF_UNIX; /* Unix domain socket */ + strncpy(sunx.sun_path, _PATH_LOG, sizeof(sunx.sun_path)); + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0 ) { + perror("Couldn't obtain descriptor for socket " _PATH_LOG); + exit( FALSE); + } + + addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path); + + if (connect(fd, (struct sockaddr *) &sunx, addrLength)) { + perror("Could not connect to socket " _PATH_LOG); + exit( FALSE); + } + + time(&now); + snprintf (buf, sizeof(buf), "<%d>%.15s %s", pri, ctime(&now)+4, message); + + if (toStdErrFlag==TRUE) + fprintf(stderr, "%s\n", buf); + + write( fd, buf, sizeof(buf)); + + close(fd); + exit( TRUE); +} + diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 03fea9c..736adf7 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c @@ -1,86 +1,296 @@ -/* userver.c - simple server for Unix domain sockets */ - -/* Waits for a connection on the ./sample-socket Unix domain - socket. Once a connection has been established, copy data - from the socket to stdout until the other end closes the - connection, and then wait for another connection to the socket. */ +/* + * Mini syslogd implementation for busybox + * + * Copyright (C) 1999 by Lineo, inc. + * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "internal.h" #include <stdio.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <signal.h> +#include <ctype.h> +#include <netdb.h> + + +/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */ +#define SYSLOG_NAMES +#include <sys/syslog.h> + +/* Path for the file where all log messages are written */ +#define __LOG_FILE "/var/log/messages" +/* Path to the current console device */ +#define __DEV_CONSOLE "/dev/console" + + +static char* logFilePath = __LOG_FILE; +/* interval between marks in seconds */ +static int MarkInterval = 20*60; +/* localhost's name */ +static char LocalHostName[32]; -#define _PATH_LOG "/dev/log" +static const char syslogd_usage[] = + "syslogd [OPTION]...\n\n" + "Linux system logging utility.\n\n" + "Options:\n" + "\t-m\tChange the mark timestamp interval. default=20min. 0=off\n" + "\t-n\tDo not fork into the background (for when run by init)\n" + "\t-O\tSpecify an alternate log file. default=/var/log/messages\n"; -/* issue an error message via perror() and terminate the program */ -void die(char * message) { - perror(message); - exit(1); + +/* try to open up the specified device */ +static int device_open(char *device, int mode) +{ + int m, f, fd = -1; + + m = mode | O_NONBLOCK; + + /* Retry up to 5 times */ + for (f = 0; f < 5; f++) + if ((fd = open(device, m)) >= 0) + break; + if (fd < 0) + return fd; + /* Reset original flags. */ + if (m != mode) + fcntl(fd, F_SETFL, mode); + return fd; } -/* Copies data from file descriptor 'from' to file descriptor 'to' - until nothing is left to be copied. Exits if an error occurs. */ -void copyData(int from, int to) { - char buf[1024]; - int amount; - - while ((amount = read(from, buf, sizeof(buf))) > 0) { - if (write(to, buf, amount) != amount) { - die("write"); - return; - } +/* print a message to the log file */ +static void message(char *fmt, ...) +{ + int fd; + va_list arguments; + + if ((fd = device_open(logFilePath, O_WRONLY|O_CREAT|O_NOCTTY|O_APPEND|O_NONBLOCK)) >= 0) { + va_start(arguments, fmt); + vdprintf(fd, fmt, arguments); + va_end(arguments); + close(fd); + } else { + /* Always send console messages to /dev/console so people will see them. */ + if ((fd = device_open(__DEV_CONSOLE, O_WRONLY|O_NOCTTY|O_NONBLOCK)) >= 0) { + va_start(arguments, fmt); + vdprintf(fd, fmt, arguments); + va_end(arguments); + close(fd); + } else { + fprintf(stderr, "Bummer, can't print: "); + va_start(arguments, fmt); + vfprintf(stderr, fmt, arguments); + fflush(stderr); + va_end(arguments); + } + } +} + +static void logMessage( int pri, char* msg) +{ + time_t now; + char *timestamp; + static char res[20]; + CODE *c_pri, *c_fac; + + for (c_fac=facilitynames; c_fac->c_name && !(c_fac->c_val==LOG_FAC(pri)<<3); c_fac++); + for (c_pri=prioritynames; c_pri->c_name && !(c_pri->c_val==LOG_PRI(pri)); c_pri++); + if (*c_fac->c_name=='\0' || *c_pri->c_name=='\0') + snprintf (res, sizeof(res), "<%d>", pri); + else + snprintf (res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name); + + if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' || + msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') + { + time(&now); + timestamp = ctime(&now) + 4; + timestamp[15] = '\0'; + } else { + timestamp = msg; + timestamp[15] = '\0'; + msg += 16; } - if (amount < 0) - die("read"); + + /* todo: supress duplicates */ + + /* now spew out the message to wherever it is supposed to go */ + message( "%s %s %s %s\n", timestamp, LocalHostName, res, msg); } +static void quit_signal(int sig) +{ + logMessage(LOG_SYSLOG|LOG_INFO, "syslogd exiting"); + exit( TRUE); +} -int main(void) { - struct sockaddr_un address; +static void restart_signal(int sig) +{ + /* pretend to restart */ + logMessage(LOG_SYSLOG|LOG_INFO, "syslogd restarting"); +} + +static void domark(int sig) +{ + if (MarkInterval > 0) { + logMessage(LOG_SYSLOG|LOG_INFO, "-- MARK --"); + signal(SIGALRM, domark); + alarm(MarkInterval); + } +} + +static void doSyslogd(void) +{ + struct sockaddr_un sunx; int fd, conn; size_t addrLength; + char buf[1024]; + char *q, *p = buf; + int readSize; - /* Remove any preexisting socket (or other file) */ + /* Remove any preexisting socket/file */ unlink(_PATH_LOG); - memset(&address, 0, sizeof(address)); - address.sun_family = AF_UNIX; /* Unix domain socket */ - strncpy(address.sun_path, _PATH_LOG, sizeof(address.sun_path)); + /* Set up sig handlers */ + signal(SIGINT, quit_signal); + signal(SIGTERM, quit_signal); + signal(SIGQUIT, quit_signal); + signal(SIGHUP, restart_signal); + signal(SIGALRM, domark); + alarm(MarkInterval); - if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) - die("socket"); - - - /* The total length of the address includes the sun_family - element */ - addrLength = sizeof(address.sun_family) + - strlen(address.sun_path); + memset(&sunx, 0, sizeof(sunx)); + sunx.sun_family = AF_UNIX; /* Unix domain socket */ + strncpy(sunx.sun_path, _PATH_LOG, sizeof(sunx.sun_path)); + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0 ) { + perror("Couldn't obtain descriptor for socket " _PATH_LOG); + exit( FALSE); + } - if (bind(fd, (struct sockaddr *) &address, addrLength)) - die("bind"); + addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path); + if ( (bind(fd, (struct sockaddr *) &sunx, addrLength)) || + (chmod(_PATH_LOG, 0666) < 0) || + (listen(fd, 5)) ) + { + perror("Could not connect to socket " _PATH_LOG); + exit( FALSE); + } + + + /* Get localhost's name */ + gethostname(LocalHostName, sizeof(LocalHostName)); + if ( (p = strchr(LocalHostName, '.')) ) { + *p++ = '\0'; + } + + logMessage(LOG_SYSLOG|LOG_INFO, "syslogd started: " + "BusyBox v" BB_VER " (" BB_BT ") multi-call binary"); - if (chmod(_PATH_LOG, 0666) < 0) - die("chmod"); - if (listen(fd, 5)) - die("listen"); + while ((conn = accept(fd, (struct sockaddr *) &sunx, + &addrLength)) >= 0) + { + while ((readSize=read(conn, buf, sizeof(buf))) > 0) + { + char line[1025]; + unsigned char c; + int pri = (LOG_USER|LOG_NOTICE); + memset (line, 0, sizeof(line)); + p = buf; + q = line; + while ( p && (c = *p) && q < &line[sizeof(line) - 1]) { + if (c == '<') { + /* Parse the magic priority number */ + pri = 0; + while (isdigit(*(++p))) { + pri = 10 * pri + (*p - '0'); + } + if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) + pri = (LOG_USER|LOG_NOTICE); + } else if (c == '\n') { + *q++ = ' '; + } else if (iscntrl(c)&&(c<0177)) { + *q++ = '^'; + *q++ = c ^ 0100; + } else { + *q++ = c; + } + p++; + } + *q = '\0'; - while ((conn = accept(fd, (struct sockaddr *) &address, - &addrLength)) >= 0) { - printf("---- getting data\n"); - copyData(conn, fileno(stdout)); - printf("---- done\n"); + /* Now log it */ + logMessage( pri, line); + } close(conn); } - if (conn < 0) - die("accept"); - close(fd); - return 0; } +extern int syslogd_main(int argc, char **argv) +{ + int pid; + int doFork = TRUE; + + while (--argc > 0 && **(++argv) == '-') { + while (*(++(*argv))) { + switch (**argv) { + case 'm': + if (--argc == 0) { + usage(syslogd_usage); + } + MarkInterval = atoi(*(++argv))*60; + break; + case 'n': + doFork = FALSE; + break; + case 'O': + if (--argc == 0) { + usage(syslogd_usage); + } + logFilePath = *(++argv); + break; + default: + usage(syslogd_usage); + } + } + } + + if (doFork == TRUE) { + pid = fork(); + if ( pid < 0 ) + exit( pid); + else if ( pid == 0 ) { + doSyslogd(); + } + } else { + doSyslogd(); + } + exit( TRUE); +} + |