X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=sysklogd%2Fsyslogd.c;h=38ea3d7ff2e4177907cc94b0c8b2dca0d167468e;hb=a09a42cd83a0365b5b52dfdcce20b3c9932be801;hp=345bf0e87940ca8f1d3d7b7bb68076b5196b5b35;hpb=4e9ca75281a25dcdbb3e2d2fa79108b02afa43db;p=oweals%2Fbusybox.git diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 345bf0e87..38ea3d7ff 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c @@ -13,15 +13,16 @@ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ +/* + * Done in syslogd_and_logger.c: #include "libbb.h" +#define SYSLOG_NAMES +#define SYSLOG_NAMES_CONST +#include +*/ + #include #include - -/* SYSLOG_NAMES defined to pull prioritynames[] and facilitynames[] - * from syslog.h. Grrrr - glibc puts those in _rwdata_! :( */ -#define SYSLOG_NAMES -#define SYSLOG_NAMES_CONST /* uclibc is saner :) */ -#include #include #if ENABLE_FEATURE_REMOTE_LOG @@ -99,11 +100,11 @@ struct globals { struct shbuf_ds *shbuf; #endif time_t last_log_time; - /* localhost's name */ - char localHostName[64]; + /* localhost's name. We print only first 64 chars */ + char *hostname; /* We recv into recvbuf... */ - char recvbuf[MAX_READ]; + char recvbuf[MAX_READ * (1 + ENABLE_FEATURE_SYSLOGD_DUP)]; /* ...then copy to parsebuf, escaping control chars */ /* (can grow x2 max) */ char parsebuf[MAX_READ*2]; @@ -138,7 +139,7 @@ static const struct init_globals init_data = { #define G (*ptr_to_globals) #define INIT_G() do { \ - PTR_TO_GLOBALS = memcpy(xzalloc(sizeof(G)), &init_data, sizeof(init_data)); \ + SET_PTR_TO_GLOBALS(memcpy(xzalloc(sizeof(G)), &init_data, sizeof(init_data))); \ } while (0) @@ -154,6 +155,7 @@ enum { USE_FEATURE_REMOTE_LOG( OPTBIT_remote ,) // -R USE_FEATURE_REMOTE_LOG( OPTBIT_locallog ,) // -L USE_FEATURE_IPC_SYSLOG( OPTBIT_circularlog,) // -C + USE_FEATURE_SYSLOGD_DUP( OPTBIT_dup ,) // -D OPT_mark = 1 << OPTBIT_mark , OPT_nofork = 1 << OPTBIT_nofork , @@ -165,13 +167,15 @@ enum { OPT_remotelog = USE_FEATURE_REMOTE_LOG( (1 << OPTBIT_remote )) + 0, OPT_locallog = USE_FEATURE_REMOTE_LOG( (1 << OPTBIT_locallog )) + 0, OPT_circularlog = USE_FEATURE_IPC_SYSLOG( (1 << OPTBIT_circularlog)) + 0, + OPT_dup = USE_FEATURE_SYSLOGD_DUP( (1 << OPTBIT_dup )) + 0, }; #define OPTION_STR "m:nO:l:S" \ USE_FEATURE_ROTATE_LOGFILE("s:" ) \ USE_FEATURE_ROTATE_LOGFILE("b:" ) \ USE_FEATURE_REMOTE_LOG( "R:" ) \ USE_FEATURE_REMOTE_LOG( "L" ) \ - USE_FEATURE_IPC_SYSLOG( "C::") + USE_FEATURE_IPC_SYSLOG( "C::") \ + USE_FEATURE_SYSLOGD_DUP( "D" ) #define OPTION_DECL *opt_m, *opt_l \ USE_FEATURE_ROTATE_LOGFILE(,*opt_s) \ USE_FEATURE_ROTATE_LOGFILE(,*opt_b) \ @@ -191,8 +195,8 @@ enum { #error Please check CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE #endif -/* our shared key */ -#define KEY_ID ((long)0x414e4547) /* "GENA" */ +/* our shared key (syslogd.c and logread.c must be in sync) */ +enum { KEY_ID = 0x414e4547 }; /* "GENA" */ static void ipcsyslog_cleanup(void) { @@ -210,7 +214,7 @@ static void ipcsyslog_cleanup(void) static void ipcsyslog_init(void) { if (DEBUG) - printf("shmget(%lx, %d,...)\n", KEY_ID, G.shm_size); + printf("shmget(%x, %d,...)\n", (int)KEY_ID, G.shm_size); G.shmid = shmget(KEY_ID, G.shm_size, IPC_CREAT | 0644); if (G.shmid == -1) { @@ -346,6 +350,7 @@ static void log_locally(time_t now, char *msg) sprintf(newFile, "%s.%d", G.logFilePath, i); if (i == 0) break; sprintf(oldFile, "%s.%d", G.logFilePath, --i); + /* ignore errors - file might be missing */ rename(oldFile, newFile); } /* newFile == "f.0" now */ @@ -359,7 +364,7 @@ static void log_locally(time_t now, char *msg) } G.curFileSize += #endif - full_write(G.logFD, msg, len); + full_write(G.logFD, msg, len); fl.l_type = F_UNLCK; fcntl(G.logFD, F_SETLKW, &fl); } @@ -372,13 +377,15 @@ static void parse_fac_prio_20(int pri, char *res20) c_fac = facilitynames; while (c_fac->c_name) { if (c_fac->c_val != (LOG_FAC(pri) << 3)) { - c_fac++; continue; + c_fac++; + continue; } /* facility is found, look for prio */ c_pri = prioritynames; while (c_pri->c_name) { if (c_pri->c_val != LOG_PRI(pri)) { - c_pri++; continue; + c_pri++; + continue; } snprintf(res20, 20, "%s.%s", c_fac->c_name, c_pri->c_name); @@ -416,7 +423,7 @@ static void timestamp_and_log(int pri, char *msg, int len) else { char res[20]; parse_fac_prio_20(pri, res); - sprintf(G.printbuf, "%s %s %s %s\n", timestamp, G.localHostName, res, msg); + sprintf(G.printbuf, "%s %.64s %s %s\n", timestamp, G.hostname, res, msg); } /* Log message locally (to file or shared mem) */ @@ -430,6 +437,9 @@ static void timestamp_and_log_internal(const char *msg) timestamp_and_log(LOG_SYSLOG | LOG_INFO, (char*)msg, 0); } +/* tmpbuf[len] is a NUL byte (set by caller), but there can be other, + * embedded NULs. Split messages on each of these NULs, parse prio, + * escape control chars and log each locally. */ static void split_escape_and_log(char *tmpbuf, int len) { char *p = tmpbuf; @@ -472,7 +482,7 @@ static void quit_signal(int sig) puts("syslogd exiting"); if (ENABLE_FEATURE_IPC_SYSLOG) ipcsyslog_cleanup(); - exit(1); + kill_myself_with_sig(sig); } #ifdef SYSLOGD_MARK @@ -527,19 +537,28 @@ static int try_to_resolve_remote(void) if (!G.remoteAddr) return -1; } - return socket(G.remoteAddr->sa.sa_family, SOCK_DGRAM, 0); + return socket(G.remoteAddr->u.sa.sa_family, SOCK_DGRAM, 0); } #endif -static void do_syslogd(void) ATTRIBUTE_NORETURN; +static void do_syslogd(void) NORETURN; static void do_syslogd(void) { int sock_fd; +#if ENABLE_FEATURE_SYSLOGD_DUP + int last_sz = -1; + char *last_buf; + char *recvbuf = G.recvbuf; +#else +#define recvbuf (G.recvbuf) +#endif /* Set up signal handlers */ - signal(SIGINT, quit_signal); - signal(SIGTERM, quit_signal); - signal(SIGQUIT, quit_signal); + bb_signals(0 + + (1 << SIGINT) + + (1 << SIGTERM) + + (1 << SIGQUIT) + , quit_signal); signal(SIGHUP, SIG_IGN); /* signal(SIGCHLD, SIG_IGN); - why? */ #ifdef SYSLOGD_MARK @@ -555,34 +574,41 @@ static void do_syslogd(void) timestamp_and_log_internal("syslogd started: BusyBox v" BB_VER); for (;;) { - size_t sz; + ssize_t sz; + +#if ENABLE_FEATURE_SYSLOGD_DUP + last_buf = recvbuf; + if (recvbuf == G.recvbuf) + recvbuf = G.recvbuf + MAX_READ; + else + recvbuf = G.recvbuf; +#endif read_again: - sz = safe_read(sock_fd, G.recvbuf, MAX_READ - 1); - if (sz < 0) { + sz = safe_read(sock_fd, recvbuf, MAX_READ - 1); + if (sz < 0) bb_perror_msg_and_die("read from /dev/log"); - } - /* Drop trailing NULs (typically there is one NUL) */ + /* Drop trailing '\n' and NULs (typically there is one NUL) */ while (1) { if (sz == 0) goto read_again; /* man 3 syslog says: "A trailing newline is added when needed". * However, neither glibc nor uclibc do this: * syslog(prio, "test") sends "test\0" to /dev/log, - * syslog(prio, "test\n") sends "test\n\0", + * syslog(prio, "test\n") sends "test\n\0". * IOW: newline is passed verbatim! * I take it to mean that it's syslogd's job - * to make those look identical in the log files */ - if (G.recvbuf[sz-1] && G.recvbuf[sz-1] != '\n') + * to make those look identical in the log files. */ + if (recvbuf[sz-1] != '\0' && recvbuf[sz-1] != '\n') break; sz--; } - /* Maybe we need to add '\n' here, not later? - * It looks like stock syslogd does send '\n' over network, - * but we do not (see sendto below) */ - G.recvbuf[sz] = '\0'; /* make sure it *is* NUL terminated */ - - /* TODO: maybe suppress duplicates? */ +#if ENABLE_FEATURE_SYSLOGD_DUP + if ((option_mask32 & OPT_dup) && (sz == last_sz)) + if (memcmp(last_buf, recvbuf, sz) == 0) + continue; + last_sz = sz; +#endif #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 */ @@ -592,22 +618,29 @@ static void do_syslogd(void) if (-1 == G.remoteFD) goto no_luck; } + /* Stock syslogd sends it '\n'-terminated + * over network, mimic that */ + recvbuf[sz] = '\n'; /* send message to remote logger, ignore possible error */ - sendto(G.remoteFD, G.recvbuf, sz, MSG_DONTWAIT, - &G.remoteAddr->sa, G.remoteAddr->len); + /* TODO: on some errors, close and set G.remoteFD to -1 + * so that DNS resolution and connect is retried? */ + sendto(G.remoteFD, recvbuf, sz+1, MSG_DONTWAIT, + &G.remoteAddr->u.sa, G.remoteAddr->len); no_luck: ; } #endif - if (!ENABLE_FEATURE_REMOTE_LOG || (option_mask32 & OPT_locallog)) - split_escape_and_log(G.recvbuf, sz); + if (!ENABLE_FEATURE_REMOTE_LOG || (option_mask32 & OPT_locallog)) { + recvbuf[sz] = '\0'; /* ensure it *is* NUL terminated */ + split_escape_and_log(recvbuf, sz); + } } /* for (;;) */ +#undef recvbuf } int syslogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int syslogd_main(int argc, char **argv) +int syslogd_main(int argc UNUSED_PARAM, char **argv) { char OPTION_DECL; - char *p; INIT_G(); #if ENABLE_FEATURE_REMOTE_LOG @@ -642,11 +675,8 @@ int syslogd_main(int argc, char **argv) option_mask32 |= OPT_locallog; /* Store away localhost's name before the fork */ - gethostname(G.localHostName, sizeof(G.localHostName)); - p = strchr(G.localHostName, '.'); - if (p) { - *p = '\0'; - } + G.hostname = safe_gethostname(); + *strchrnul(G.hostname, '.') = '\0'; if (!(option_mask32 & OPT_nofork)) { bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); @@ -656,3 +686,11 @@ int syslogd_main(int argc, char **argv) do_syslogd(); /* return EXIT_SUCCESS; */ } + +/* Clean up. Needed because we are included from syslogd_and_logger.c */ +#undef G +#undef GLOBALS +#undef INIT_G +#undef OPTION_STR +#undef OPTION_DECL +#undef OPTION_PARAM