diff --git a/src/openrc-shutdown/broadcast.c b/src/openrc-shutdown/broadcast.c index f21ee95c4..f400c796c 100644 --- a/src/openrc-shutdown/broadcast.c +++ b/src/openrc-shutdown/broadcast.c @@ -14,11 +14,11 @@ */ +#include #include #include #include #include -#include #include #include #include @@ -37,14 +37,12 @@ # define _PATH_DEV "/dev/" #endif -static sigjmp_buf jbuf; - /* * Alarm handler */ -RC_NORETURN static void handler(int arg RC_UNUSED) +static void handler(int arg RC_UNUSED) { - siglongjmp(jbuf, 1); + /* do nothing */ } static void getuidtty(char **userp, char **ttyp) @@ -124,15 +122,11 @@ void broadcast(char *text) char *p; char *line = NULL; struct sigaction sa; + int fd; + FILE *tp; int flags; char *term = NULL; struct utmpx *utmp; - /* - * These are set across the sigsetjmp call, so they can't be stored on - * the stack, otherwise they might be clobbered. - */ - static int fd; - static FILE *tp; getuidtty(&user, &tty); @@ -159,6 +153,7 @@ void broadcast(char *text) if (fork() != 0) return; + /* Set up a noop signal handler to generate EINTR */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = handler; sigemptyset(&sa.sa_mask); @@ -179,24 +174,23 @@ void broadcast(char *text) } /* - * Open it non-delay + * Open it non-delay + * Set an alarm to generate EINTR in case we block. */ - if (sigsetjmp(jbuf, 1) == 0) { - alarm(2); - flags = O_WRONLY|O_NDELAY|O_NOCTTY; - if (file_isatty(term) && (fd = open(term, flags)) >= 0) { - if (isatty(fd) && (tp = fdopen(fd, "w")) != NULL) { - fputs(line, tp); - fputs(text, tp); - fflush(tp); - } + alarm(2); + flags = O_WRONLY|O_NDELAY|O_NOCTTY; + if (file_isatty(term) && (fd = open(term, flags)) >= 0) { + if (isatty(fd) && (tp = fdopen(fd, "w")) != NULL) { + if ((fputs(line, tp) == EOF || fputs(text, tp) == EOF) + && errno == EINTR) + /* Set another alarm for fclose */ + alarm(1); + fclose(tp); } + else + close(fd); } alarm(0); - if (fd >= 0) - close(fd); - if (tp != NULL) - fclose(tp); free(term); } endutxent();