Skip to content

Commit

Permalink
bbs: Ignore SIGHUP signal and don't skip logging if daemonized. (#47)
Browse files Browse the repository at this point in the history
When running as a daemon, the BBS receives a SIGHUP whenever a remote
sysop console disconnects. Without handling the signal, this causes
the BBS to get killed by the kernel. To avoid this, install a dummy
signal handler when daemonized to ignore the signal and continue
running.

Additionally, logger.c was using the wrong check to determine whether
to generate a log message for outputting to terminals, which resulted
in no log messages on consoles when the BBS was daemonized. Adjust
this logic so that console messages are generated when needed.

Resolves: #46
  • Loading branch information
InterLinked1 authored Oct 17, 2024
1 parent 693f72b commit 5952cfb
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 4 deletions.
16 changes: 16 additions & 0 deletions bbs/bbs.c
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,13 @@ static void __sigint_handler(int num)
}
}

static void __sighup_handler(int num)
{
UNUSED(num);

bbs_debug(2, "Got SIGHUP, ignoring\n"); /* XXX technically not safe to use in signal handler */
}

/*! \brief Log any SIGWINCHes received */
static void __sigwinch_handler(int num)
{
Expand Down Expand Up @@ -711,6 +718,7 @@ static void __sigwinch_handler(int num)
static void __sigusr1_handler(int num)
{
UNUSED(num);

/* By default, if we use pthread_kill to try to send SIGUSR1 to a thread,
* it will terminate the entire BBS.
* Installing this dummy signal handler that does nothing prevents that,
Expand Down Expand Up @@ -986,6 +994,14 @@ int main(int argc, char *argv[])
}
signal(SIGINT, __sigint_handler);
signal(SIGTERM, __sigint_handler);
if (!option_nofork) {
/* If daemonized, we get a SIGHUP whenever a remote sysop console disconnects... ignore it,
* or the BBS will get killed by the signal.
* Frequently used by daemonized processes to reread their configuration,
* for now we just ignore it.
* If running in the foreground, then allow SIGHUP to terminate as usual. */
signal(SIGHUP, __sighup_handler);
}
signal(SIGWINCH, __sigwinch_handler);
signal(SIGUSR1, __sigusr1_handler);
sigaction(SIGPIPE, &ignore_sig_handler, NULL);
Expand Down
20 changes: 16 additions & 4 deletions bbs/logger.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ static RWLIST_HEAD_STATIC(remote_log_fds, remote_log_fd);

/*! \note Assumes all remote consoles are going to use a fd within the first 1024 */
static int fd_logging[1024]; /* Array for constant time access instead of a linked list. Even though we traverse the list for writing, to set logging on/off, we don't need to. */
static int active_remote_consoles = 0;

int bbs_set_fd_logging(int fd, int enabled)
{
Expand Down Expand Up @@ -254,6 +255,7 @@ int bbs_add_logging_fd(int fd)
rfd->maxdebug = MAX_DEBUG; /* By default, there is no local restriction on the max debug level */
RWLIST_INSERT_HEAD(&remote_log_fds, rfd, entry);
fd_logging[fd] = 1; /* Initialize to enabled */
active_remote_consoles++;
RWLIST_UNLOCK(&remote_log_fds);
bbs_debug(5, "Registered file descriptor %d for logging\n", fd);
return 0;
Expand All @@ -263,7 +265,10 @@ int bbs_remove_logging_fd(int fd)
{
struct remote_log_fd *rfd;

rfd = RWLIST_WRLOCK_REMOVE_BY_FIELD(&remote_log_fds, fd, fd, entry);
RWLIST_WRLOCK(&remote_log_fds);
rfd = RWLIST_REMOVE_BY_FIELD(&remote_log_fds, fd, fd, entry);
active_remote_consoles--;
RWLIST_UNLOCK(&remote_log_fds);
if (unlikely(!rfd)) {
bbs_error("File descriptor %d did not have logging\n", fd);
} else {
Expand Down Expand Up @@ -389,7 +394,7 @@ void __attribute__ ((format (gnu_printf, 6, 7))) __bbs_log(enum bbs_log_level lo
int thread_id;
int dynamic = 0, fulldynamic = 0;
int bytes;
int log_stdout;
int log_stdout, log_remote;
int need_reset = 0;
int skip_logfile = 0;

Expand Down Expand Up @@ -484,8 +489,10 @@ void __attribute__ ((format (gnu_printf, 6, 7))) __bbs_log(enum bbs_log_level lo

/* Race condition here is fine, but helgrind won't like it: */
log_stdout = logstdout;
log_remote = active_remote_consoles > 0; /* Small chance a brand new console could register between this check and traversing the remote consoles... but not a big deal. */

if (log_stdout) {
/* If the foreground or any remote consoles are active, prepare a log message for any connected consoles. */
if (log_stdout || log_remote) {
struct remote_log_fd *rfd;
if (loglevel == LOG_VERBOSE && verbose_special_formatting) {
const char *verbprefix = verbose_prefix(level);
Expand Down Expand Up @@ -517,7 +524,12 @@ void __attribute__ ((format (gnu_printf, 6, 7))) __bbs_log(enum bbs_log_level lo
}
}

term_puts(fullbuf);
/* Log to foreground console, if there is one */
if (log_stdout) {
term_puts(fullbuf);
}

/* Log to remote consoles */
RWLIST_RDLOCK(&remote_log_fds);
RWLIST_TRAVERSE(&remote_log_fds, rfd, entry) {
if (loglevel == LOG_DEBUG && level > rfd->maxdebug) {
Expand Down

0 comments on commit 5952cfb

Please sign in to comment.