From 3843e96252a823b4fdfc89c61d00342bf011ad88 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Thu, 25 Nov 1999 07:30:46 +0000 Subject: [PATCH] Stuf --- Changelog | 5 + Makefile | 2 +- applets/busybox.c | 14 +- busybox.c | 14 +- busybox.def.h | 2 + internal.h | 2 + logger.c | 186 ++++++++++++++++++++++++++ sysklogd/logger.c | 186 ++++++++++++++++++++++++++ sysklogd/syslogd.c | 316 +++++++++++++++++++++++++++++++++++++-------- syslogd.c | 316 +++++++++++++++++++++++++++++++++++++-------- 10 files changed, 928 insertions(+), 115 deletions(-) create mode 100644 logger.c create mode 100644 sysklogd/logger.c diff --git a/Changelog b/Changelog index 7a7f50ab6..cef86ec66 100644 --- a/Changelog +++ b/Changelog @@ -10,6 +10,11 @@ from createPath into mkdir where it belonged, thereby making tar work properly. * Fixed an off-by-one bug in cat. Given a list of file it wouldn't cat out the last file in the list. + * Fixed 'ls -ln' so numeric group/uid are presented properly, and fixed 'ls -l' + so when uid/gid is not in /etc/{passwd,group} the numeric group/uid are + presented properly. + * Also added a TODO. + -Erik Andrsen diff --git a/Makefile b/Makefile index c715c0bd6..1413ea05d 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ BUILDTIME=$(shell date "+%Y%m%d-%H%M") # Comment out the following to make a debuggable build # Leave this off for production use. -DODEBUG=false +DODEBUG=true # If you want a static binary, turn this on. I can't think # of many situations where anybody would ever want it static, # but... diff --git a/applets/busybox.c b/applets/busybox.c index efa4ec72d..af81ad8a2 100644 --- a/applets/busybox.c +++ b/applets/busybox.c @@ -151,15 +151,21 @@ static const struct Applet applets[] = { #ifdef BB_SLEEP //bin {"sleep", sleep_main}, #endif -#ifdef BB_TAR //bin - {"tar", tar_main}, +#ifdef BB_SYNC //bin + {"sync", sync_main}, +#endif +#ifdef BB_SYSLOGD //sbin + {"syslogd", syslogd_main}, +#endif +#ifdef BB_LOGGER //usr/bin + {"logger", logger_main}, #endif #ifdef BB_SWAPONOFF //sbin {"swapon", swap_on_off_main}, {"swapoff", swap_on_off_main}, #endif -#ifdef BB_SYNC //bin - {"sync", sync_main}, +#ifdef BB_TAR //bin + {"tar", tar_main}, #endif #ifdef BB_TOUCH //usr/bin {"touch", touch_main}, diff --git a/busybox.c b/busybox.c index efa4ec72d..af81ad8a2 100644 --- a/busybox.c +++ b/busybox.c @@ -151,15 +151,21 @@ static const struct Applet applets[] = { #ifdef BB_SLEEP //bin {"sleep", sleep_main}, #endif -#ifdef BB_TAR //bin - {"tar", tar_main}, +#ifdef BB_SYNC //bin + {"sync", sync_main}, +#endif +#ifdef BB_SYSLOGD //sbin + {"syslogd", syslogd_main}, +#endif +#ifdef BB_LOGGER //usr/bin + {"logger", logger_main}, #endif #ifdef BB_SWAPONOFF //sbin {"swapon", swap_on_off_main}, {"swapoff", swap_on_off_main}, #endif -#ifdef BB_SYNC //bin - {"sync", sync_main}, +#ifdef BB_TAR //bin + {"tar", tar_main}, #endif #ifdef BB_TOUCH //usr/bin {"touch", touch_main}, diff --git a/busybox.def.h b/busybox.def.h index 77ab4b567..bf8f54556 100644 --- a/busybox.def.h +++ b/busybox.def.h @@ -28,6 +28,7 @@ #define BB_LN #define BB_LOADFONT #define BB_LOADKMAP +#define BB_LOGGER #define BB_LS //#define BB_MAKEDEVS //#define BB_MATH @@ -53,6 +54,7 @@ #define BB_SLEEP #define BB_SWAPONOFF #define BB_SYNC +#define BB_SYSLOGD #define BB_TAR #define BB_TOUCH #define BB_TRUE_FALSE diff --git a/internal.h b/internal.h index feaea6339..5cca663b4 100644 --- a/internal.h +++ b/internal.h @@ -104,6 +104,8 @@ extern int sed_main(int argc, char** argv); extern int sleep_main(int argc, char** argv); extern int swap_on_off_main(int argc, char** argv); extern int sync_main(int argc, char** argv); +extern int syslogd_main(int argc, char **argv); +extern int logger_main(int argc, char **argv); extern int tar_main(int argc, char** argv); extern int touch_main(int argc, char** argv); extern int tput_main(int argc, char** argv); diff --git a/logger.c b/logger.c new file mode 100644 index 000000000..0683838cc --- /dev/null +++ b/logger.c @@ -0,0 +1,186 @@ +/* + * Mini logger implementation for busybox + * + * Copyright (C) 1999 by Lineo, inc. + * Written by Erik Andersen , + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined BB_SYSLOGD + +#define SYSLOG_NAMES +#include + +#else +/* We have to do this since the header file defines static + * structues. Argh.... bad libc, bad, bad... + */ +#include +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/logger.c b/sysklogd/logger.c new file mode 100644 index 000000000..0683838cc --- /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 , + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined BB_SYSLOGD + +#define SYSLOG_NAMES +#include + +#else +/* We have to do this since the header file defines static + * structues. Argh.... bad libc, bad, bad... + */ +#include +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 03fea9c76..736adf7d1 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 , + * + * 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 #include #include #include +#include +#include +#include +#include +#include +#include +#include + + +/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */ +#define SYSLOG_NAMES +#include + +/* 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); +} + diff --git a/syslogd.c b/syslogd.c index 03fea9c76..736adf7d1 100644 --- a/syslogd.c +++ b/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 , + * + * 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 #include #include #include +#include +#include +#include +#include +#include +#include +#include + + +/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */ +#define SYSLOG_NAMES +#include + +/* 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); +} + -- 2.25.1