syslogd: start using bb_common_bufsiz1 instead of stack/malloc
authorDenis Vlasenko <vda.linux@googlemail.com>
Thu, 4 Jan 2007 21:22:11 +0000 (21:22 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Thu, 4 Jan 2007 21:22:11 +0000 (21:22 -0000)
logger: optimize, also use bb_common_bufsiz1 (~40 bytes)
tested to eat arbitrarily-sized input at high speed - ok

include/usage.h
sysklogd/logger.c
sysklogd/syslogd.c

index 6202c4afd1171b9425f3d9a03f93de47d474d2e9..ae03d54310679e6aadce8bf2f7c78aa467cb2018 100644 (file)
        "System logging utility.\n" \
        "Note that this version of syslogd ignores /etc/syslog.conf." \
        "\n\nOptions:" \
-       "\n     -m MIN  Minutes between MARK lines (default=20, 0=off)" \
-       "\n     -n      Run as a foreground process" \
-       "\n     -O FILE Use an alternate log file (default=/var/log/messages)" \
-       "\n     -l n    Sets the local log level of messages to n" \
-       "\n     -S      Make logging output smaller" \
+       "\n     -m MIN          Minutes between MARK lines (default=20, 0=off)" \
+       "\n     -n              Run as a foreground process" \
+       "\n     -O FILE         Use an alternate log file (default=/var/log/messages)" \
+       "\n     -l n            Sets the local log level of messages to n" \
+       "\n     -S              Make logging output smaller" \
        USE_FEATURE_ROTATE_LOGFILE( \
-       "\n     -s SIZE Max size (KB) before rotate (default=200KB, 0=off)" \
-       "\n     -b NUM  Number of rotated logs to keep (default=1, max=99, 0=purge)") \
+       "\n     -s SIZE         Max size (KB) before rotate (default=200KB, 0=off)" \
+       "\n     -b NUM          Number of rotated logs to keep (default=1, max=99, 0=purge)") \
        USE_FEATURE_REMOTE_LOG( \
        "\n     -R HOST[:PORT]  Log to IP or hostname on PORT (default PORT=514/UDP)" \
-       "\n     -L      Log locally and via network logging (default is network only)") \
+       "\n     -L              Log locally and via network logging (default is network only)") \
        USE_FEATURE_IPC_SYSLOG( \
-       "\n     -C[size(KiB)]   Log to a circular buffer (read the buffer using logread)")
+       "\n     -C[size(KiB)]   Log to a shared mem buffer (read the buffer using logread)")
        /* NB: -Csize shouldn't have space (because size is optional) */
 #define syslogd_example_usage \
        "$ syslogd -R masterlog:514\n" \
index 8901bd79f6b4cc778190b5da9889332a027b1549..3a4f515755f578f48a4d6f41df46e722dc2381f2 100644 (file)
@@ -8,13 +8,6 @@
  */
 
 #include "busybox.h"
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdlib.h>
 
 #if !defined CONFIG_SYSLOGD
 
@@ -93,49 +86,40 @@ int logger_main(int argc, char **argv)
        char *opt_p, *opt_t;
        int pri = LOG_USER | LOG_NOTICE;
        int option = 0;
-       int c, i;
-       char buf[1024], name[128];
+       char name[80];
 
        /* Fill out the name string early (may be overwritten later) */
        bb_getpwuid(name, geteuid(), sizeof(name));
 
        /* Parse any options */
        opt = getopt32(argc, argv, "p:st:", &opt_p, &opt_t);
+       argc -= optind;
+       argv += optind;
        if (opt & 0x1) pri = pencode(opt_p); // -p
        if (opt & 0x2) option |= LOG_PERROR; // -s
        if (opt & 0x4) safe_strncpy(name, opt_t, sizeof(name)); // -t
 
        openlog(name, option, 0);
-       if (optind == argc) {
-               do {
-                       /* read from stdin */
-                       i = 0;
-                       while ((c = getc(stdin)) != EOF && c != '\n' &&
-                                       i < (sizeof(buf)-1)) {
-                               buf[i++] = c;
-                       }
-                       if (i > 0) {
-                               buf[i++] = '\0';
-                               syslog(pri, "%s", buf);
+       if (!argc) {
+               while (fgets(bb_common_bufsiz1, BUFSIZ, stdin)) {
+                       if (bb_common_bufsiz1[0]
+                        && NOT_LONE_CHAR(bb_common_bufsiz1, '\n')
+                       ) {
+                               /* Neither "" nor "\n" */
+                               syslog(pri, "%s", bb_common_bufsiz1);
                        }
-               } while (c != EOF);
+               }
        } else {
                char *message = NULL;
-               int len = argc - optind; /* for the space between the args
-                                           and  '\0' */
-               opt = len;
-               argv += optind;
-               for (i = 0; i < opt; i++) {
-                       len += strlen(*argv);
+               int len = 1; /* for NUL */
+               int pos = 0;
+               do {
+                       len += strlen(*argv) + 1;
                        message = xrealloc(message, len);
-                       if(!i)
-                               message[0] = '\0';
-                       else
-                               strcat(message, " ");
-                       strcat(message, *argv);
-                       argv++;
-               }
-               syslog(pri, "%s", message);
+                       sprintf(message + pos, " %s", *argv),
+                       pos = len;
+               } while (*++argv);
+               syslog(pri, "%s", message + 1); /* skip leading " " */
        }
 
        closelog();
index 7edce7a0ae347cfda5eaa037f1c58aa40b2332b6..fbb85338abe145339707c087f79e3ed299dbc7ff 100644 (file)
@@ -56,13 +56,23 @@ static int remoteFD = -1;
 static struct sockaddr_in remoteAddr;
 #endif
 
-
-/* NB: we may need 2x this amount on stack... */
-enum { MAX_READ = 1024 };
-
-
-/* options */
-/* Correct regardless of combination of CONFIG_xxx */
+/* We are using bb_common_bufsiz1 for buffering: */
+enum { MAX_READ = (BUFSIZ/6) & ~0xf };
+/* We recv into this... (size: MAX_READ ~== BUFSIZ/6) */
+#define RECVBUF  bb_common_bufsiz1
+/* ...then copy here, escaping control chars */
+/* (can grow x2 + 1 max ~== BUFSIZ/3) */
+#define PARSEBUF (bb_common_bufsiz1 + MAX_READ)
+/* ...then sprintf into this, adding timestamp (15 chars),
+ * host (64), fac.prio (20) to the message */
+/* (growth by: 15 + 64 + 20 + delims = ~110) */
+#define PRINTBUF (bb_common_bufsiz1 + 3*MAX_READ + 0x10)
+/* totals: BUFSIZ/6 + BUFSIZ/3 + BUFSIZ/3 = BUFSIZ - BUFSIZ/6
+ * -- we have BUFSIZ/6 extra at the ent of PRINTBUF
+ * which covers needed ~110 extra bytes (and much more) */
+
+
+/* Options */
 enum {
        OPTBIT_mark = 0, // -m
        OPTBIT_nofork, // -n
@@ -175,11 +185,12 @@ static void ipcsyslog_init(void)
        }
 }
 
-/* write message to buffer */
+/* Write message to shared mem buffer */
 static void log_to_shmem(const char *msg, int len)
 {
-       static /*const*/ struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} };
-       static /*const*/ struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} };
+       /* Why libc insists on these being rw? */
+       static struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} };
+       static struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} };
 
        int old_tail, new_tail;
        char *c;
@@ -362,9 +373,9 @@ static void parse_fac_prio_20(int pri, char *res20)
        }
 }
 
-/* len parameter is used only for "is there a timestamp?" check
+/* len parameter is used only for "is there a timestamp?" check.
  * NB: some callers cheat and supply 0 when they know
- * that there is no timestamp, short-cutting the test */
+ * that there is no timestamp, short-cutting the test. */
 static void timestamp_and_log(int pri, char *msg, int len)
 {
        time_t now;
@@ -385,31 +396,29 @@ static void timestamp_and_log(int pri, char *msg, int len)
        if (!ENABLE_FEATURE_REMOTE_LOG || (option_mask32 & OPT_locallog)) {
                if (LOG_PRI(pri) < logLevel) {
                        if (option_mask32 & OPT_small)
-                               msg = xasprintf("%s %s\n", timestamp, msg);
+                               sprintf(PRINTBUF, "%s %s\n", timestamp, msg);
                        else {
                                char res[20];
                                parse_fac_prio_20(pri, res);
-                               msg = xasprintf("%s %s %s %s\n", timestamp, localHostName, res, msg);
+                               sprintf(PRINTBUF, "%s %s %s %s\n", timestamp, localHostName, res, msg);
                        }
-                       log_locally(msg);
-                       free(msg);
+                       log_locally(PRINTBUF);
                }
        }
 }
 
 static void split_escape_and_log(char *tmpbuf, int len)
 {
-       char line[len * 2 + 1]; /* gcc' cheap alloca */
        char *p = tmpbuf;
 
        tmpbuf += len;
        while (p < tmpbuf) {
                char c;
-               char *q = line;
+               char *q = PARSEBUF;
                int pri = (LOG_USER | LOG_NOTICE);
 
                if (*p == '<') {
-                       /* Parse the magic priority number. */
+                       /* Parse the magic priority number */
                        pri = bb_strtou(p + 1, &p, 10);
                        if (*p == '>') p++;
                        if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) {
@@ -427,8 +436,8 @@ static void split_escape_and_log(char *tmpbuf, int len)
                        *q++ = c;
                }
                *q = '\0';
-               /* now log it */
-               timestamp_and_log(pri, line, q - line);
+               /* Now log it */
+               timestamp_and_log(pri, PARSEBUF, q - PARSEBUF);
        }
 }
 
@@ -509,11 +518,10 @@ static void do_syslogd(void)
 
                if (FD_ISSET(sock_fd, &fds)) {
                        int i;
-#define tmpbuf bb_common_bufsiz1
-                       i = recv(sock_fd, tmpbuf, MAX_READ, 0);
+                       i = recv(sock_fd, RECVBUF, MAX_READ - 1, 0);
                        if (i <= 0)
                                bb_perror_msg_and_die("UNIX socket error");
-                       /* TODO: maybe supress duplicates? */
+                       /* TODO: maybe suppress duplicates? */
 #if ENABLE_FEATURE_REMOTE_LOG
                        /* We are not modifying log messages in any way before send */
                        /* Remote site cannot trust _us_ anyway and need to do validation again */
@@ -523,15 +531,14 @@ static void do_syslogd(void)
                                }
                                if (-1 != remoteFD) {
                                        /* send message to remote logger, ignore possible error */
-                                       sendto(remoteFD, tmpbuf, i, MSG_DONTWAIT,
+                                       sendto(remoteFD, RECVBUF, i, MSG_DONTWAIT,
                                                (struct sockaddr *) &remoteAddr,
                                                sizeof(remoteAddr));
                                }
                        }
 #endif
-                       tmpbuf[i] = '\0';
-                       split_escape_and_log(tmpbuf, i);
-#undef tmpbuf
+                       RECVBUF[i] = '\0';
+                       split_escape_and_log(RECVBUF, i);
                } /* FD_ISSET() */
        } /* for */
 }