syslogd: decrease stack usage, ~50 bytes

function                                             old     new   delta
syslogd_init                                           -    1007   +1007
syslogd_main                                        1619     636    -983
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 0/1 up/down: 1007/-983)          Total: 24 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
master
Denys Vlasenko 2023-06-13 16:16:37 +02:00
parent c1d7507a4d
commit 02378ce20c
1 changed files with 136 additions and 130 deletions

View File

@ -1002,132 +1002,10 @@ static int try_to_resolve_remote(remoteHost_t *rh)
}
#endif
static void do_syslogd(void) NORETURN;
static void do_syslogd(void)
{
#if ENABLE_FEATURE_REMOTE_LOG
llist_t *item;
#endif
#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 (so that they interrupt read()) */
signal_no_SA_RESTART_empty_mask(SIGTERM, record_signo);
signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
//signal_no_SA_RESTART_empty_mask(SIGQUIT, record_signo);
signal(SIGHUP, SIG_IGN);
#ifdef SYSLOGD_MARK
signal(SIGALRM, do_mark);
alarm(G.markInterval);
#endif
xmove_fd(create_socket(), STDIN_FILENO);
if (option_mask32 & OPT_circularlog)
ipcsyslog_init();
if (option_mask32 & OPT_kmsg)
kmsg_init();
timestamp_and_log_internal("syslogd started: BusyBox v" BB_VER);
write_pidfile_std_path_and_ext("syslogd");
while (!bb_got_signal) {
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 = read(STDIN_FILENO, recvbuf, MAX_READ - 1);
if (sz < 0) {
if (!bb_got_signal)
bb_perror_msg("read from %s", _PATH_LOG);
break;
}
/* 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".
* 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 (recvbuf[sz-1] != '\0' && recvbuf[sz-1] != '\n')
break;
sz--;
}
#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
/* Stock syslogd sends it '\n'-terminated
* over network, mimic that */
recvbuf[sz] = '\n';
/* We are not modifying log messages in any way before send */
/* Remote site cannot trust _us_ anyway and need to do validation again */
for (item = G.remoteHosts; item != NULL; item = item->link) {
remoteHost_t *rh = (remoteHost_t *)item->data;
if (rh->remoteFD == -1) {
rh->remoteFD = try_to_resolve_remote(rh);
if (rh->remoteFD == -1)
continue;
}
/* Send message to remote logger.
* On some errors, close and set remoteFD to -1
* so that DNS resolution is retried.
*/
if (sendto(rh->remoteFD, recvbuf, sz+1,
MSG_DONTWAIT | MSG_NOSIGNAL,
&(rh->remoteAddr->u.sa), rh->remoteAddr->len) == -1
) {
switch (errno) {
case ECONNRESET:
case ENOTCONN: /* paranoia */
case EPIPE:
close(rh->remoteFD);
rh->remoteFD = -1;
free(rh->remoteAddr);
rh->remoteAddr = NULL;
}
}
}
#endif
if (!ENABLE_FEATURE_REMOTE_LOG || (option_mask32 & OPT_locallog)) {
recvbuf[sz] = '\0'; /* ensure it *is* NUL terminated */
split_escape_and_log(recvbuf, sz);
}
} /* while (!bb_got_signal) */
timestamp_and_log_internal("syslogd exiting");
remove_pidfile_std_path_and_ext("syslogd");
ipcsyslog_cleanup();
if (option_mask32 & OPT_kmsg)
kmsg_cleanup();
kill_myself_with_sig(bb_got_signal);
#undef recvbuf
}
int syslogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int syslogd_main(int argc UNUSED_PARAM, char **argv)
/* By doing init in a separate function we decrease stack usage
* in main loop.
*/
static int NOINLINE syslogd_init(char **argv)
{
int opts;
char OPTION_DECL;
@ -1135,8 +1013,6 @@ int syslogd_main(int argc UNUSED_PARAM, char **argv)
llist_t *remoteAddrList = NULL;
#endif
INIT_G();
/* No non-option params */
opts = getopt32(argv, "^"OPTION_STR"\0""=0", OPTION_PARAM);
#if ENABLE_FEATURE_REMOTE_LOG
@ -1183,8 +1059,138 @@ int syslogd_main(int argc UNUSED_PARAM, char **argv)
bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
}
do_syslogd();
/* return EXIT_SUCCESS; */
/* Set up signal handlers (so that they interrupt read()) */
signal_no_SA_RESTART_empty_mask(SIGTERM, record_signo);
signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
//signal_no_SA_RESTART_empty_mask(SIGQUIT, record_signo);
signal(SIGHUP, SIG_IGN);
#ifdef SYSLOGD_MARK
signal(SIGALRM, do_mark);
alarm(G.markInterval);
#endif
xmove_fd(create_socket(), STDIN_FILENO);
if (opts & OPT_circularlog)
ipcsyslog_init();
if (opts & OPT_kmsg)
kmsg_init();
return opts;
}
int syslogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int syslogd_main(int argc UNUSED_PARAM, char **argv)
{
int opts;
#if ENABLE_FEATURE_REMOTE_LOG
llist_t *item;
#endif
#if ENABLE_FEATURE_SYSLOGD_DUP
int last_sz = -1;
char *last_buf;
char *recvbuf;
#else
#define recvbuf (G.recvbuf)
#endif
INIT_G();
opts = syslogd_init(argv);
timestamp_and_log_internal("syslogd started: BusyBox v" BB_VER);
write_pidfile_std_path_and_ext("syslogd");
#if ENABLE_FEATURE_SYSLOGD_DUP
recvbuf = G.recvbuf;
#endif
while (!bb_got_signal) {
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 = read(STDIN_FILENO, recvbuf, MAX_READ - 1);
if (sz < 0) {
if (!bb_got_signal)
bb_perror_msg("read from %s", _PATH_LOG);
break;
}
/* 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".
* 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 (recvbuf[sz-1] != '\0' && recvbuf[sz-1] != '\n')
break;
sz--;
}
#if ENABLE_FEATURE_SYSLOGD_DUP
if ((opts & OPT_dup) && (sz == last_sz))
if (memcmp(last_buf, recvbuf, sz) == 0)
continue;
last_sz = sz;
#endif
#if ENABLE_FEATURE_REMOTE_LOG
/* Stock syslogd sends it '\n'-terminated
* over network, mimic that */
recvbuf[sz] = '\n';
/* We are not modifying log messages in any way before send */
/* Remote site cannot trust _us_ anyway and need to do validation again */
for (item = G.remoteHosts; item != NULL; item = item->link) {
remoteHost_t *rh = (remoteHost_t *)item->data;
if (rh->remoteFD == -1) {
rh->remoteFD = try_to_resolve_remote(rh);
if (rh->remoteFD == -1)
continue;
}
/* Send message to remote logger.
* On some errors, close and set remoteFD to -1
* so that DNS resolution is retried.
*/
if (sendto(rh->remoteFD, recvbuf, sz+1,
MSG_DONTWAIT | MSG_NOSIGNAL,
&(rh->remoteAddr->u.sa), rh->remoteAddr->len) == -1
) {
switch (errno) {
case ECONNRESET:
case ENOTCONN: /* paranoia */
case EPIPE:
close(rh->remoteFD);
rh->remoteFD = -1;
free(rh->remoteAddr);
rh->remoteAddr = NULL;
}
}
}
#endif
if (!ENABLE_FEATURE_REMOTE_LOG || (opts & OPT_locallog)) {
recvbuf[sz] = '\0'; /* ensure it *is* NUL terminated */
split_escape_and_log(recvbuf, sz);
}
} /* while (!bb_got_signal) */
timestamp_and_log_internal("syslogd exiting");
remove_pidfile_std_path_and_ext("syslogd");
ipcsyslog_cleanup();
if (opts & OPT_kmsg)
kmsg_cleanup();
kill_myself_with_sig(bb_got_signal);
#undef recvbuf
}
/* Clean up. Needed because we are included from syslogd_and_logger.c */