Stuf
No binary (build failed)
—
(log yok)
| @@ -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 | |
| @@ -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... | |
| @@ -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}, | |
| @@ -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}, | |
| @@ -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 | |
| @@ -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); | |
| @@ -0,0 +1,186 @@ | |
| + | /* |
| + | * Mini logger implementation for busybox |
| + | * |
| + | * Copyright (C) 1999 by Lineo, inc. |
| + | * Written by Erik Andersen <[email protected]>, <[email protected]> |
| + | * |
| + | * 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); |
| + | } |
| + | |
| @@ -0,0 +1,186 @@ | |
| + | /* |
| + | * Mini logger implementation for busybox |
| + | * |
| + | * Copyright (C) 1999 by Lineo, inc. |
| + | * Written by Erik Andersen <[email protected]>, <[email protected]> |
| + | * |
| + | * 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); |
| + | } |
| + | |
| @@ -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 <[email protected]>, <[email protected]> |
| + | * |
| + | * 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); |
| + | } |
| + | |
| @@ -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 <[email protected]>, <[email protected]> |
| + | * |
| + | * 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); |
| + | } |
| + | |