-/* $OpenBSD: shutdown.c,v 1.47 2018/02/04 04:28:41 cheloha Exp $ */
+/* $OpenBSD: shutdown.c,v 1.48 2018/02/24 20:00:07 cheloha Exp $ */
/* $NetBSD: shutdown.c,v 1.9 1995/03/18 15:01:09 cgd Exp $ */
/*
#include <fcntl.h>
#include <sys/termios.h>
#include <pwd.h>
-#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
static time_t offset, shuttime;
static int dofast, dohalt, doreboot, dopower, dodump, mbuflen, nosync;
-static sig_atomic_t killflg;
+static sig_atomic_t killflg, timed_out;
static char *whom, mbuf[BUFSIZ];
void badtime(void);
die_you_gravy_sucking_pig_dog();
}
-static jmp_buf alarmbuf;
-
static char *restricted_environ[] = {
"PATH=" _PATH_STDPATH,
NULL
timewarn(int timeleft)
{
static char hostname[HOST_NAME_MAX+1];
- char wcmd[PATH_MAX + 4];
- extern char **environ;
static int first;
- FILE *pf;
+ int fd[2];
+ pid_t pid, wpid;
if (!first++)
(void)gethostname(hostname, sizeof(hostname));
- /* undoc -n option to wall suppresses normal wall banner */
- (void)snprintf(wcmd, sizeof(wcmd), "%s -n", _PATH_WALL);
- environ = restricted_environ;
- if (!(pf = popen(wcmd, "w"))) {
- syslog(LOG_ERR, "shutdown: can't find %s: %m", _PATH_WALL);
+ if (pipe(fd) == -1) {
+ syslog(LOG_ERR, "pipe: %m");
+ return;
+ }
+ switch (pid = fork()) {
+ case -1:
+ syslog(LOG_ERR, "fork: %m");
+ close(fd[0]);
+ close(fd[1]);
return;
+ case 0:
+ if (dup2(fd[0], STDIN_FILENO) == -1) {
+ syslog(LOG_ERR, "dup2: %m");
+ _exit(1);
+ }
+ if (fd[0] != STDIN_FILENO)
+ close(fd[0]);
+ close(fd[1]);
+ /* wall(1)'s undocumented '-n' flag suppresses its banner. */
+ execle(_PATH_WALL, _PATH_WALL, "-n", (char *)NULL,
+ restricted_environ);
+ syslog(LOG_ERR, "%s: %m", _PATH_WALL);
+ _exit(1);
+ default:
+ close(fd[0]);
}
- (void)fprintf(pf,
+ dprintf(fd[1],
"\007*** %sSystem shutdown message from %s@%s ***\007\n",
timeleft ? "": "FINAL ", whom, hostname);
if (timeleft > 10*60) {
struct tm *tm = localtime(&shuttime);
- fprintf(pf, "System going down at %d:%02d\n\n",
+ dprintf(fd[1], "System going down at %d:%02d\n\n",
tm->tm_hour, tm->tm_min);
} else if (timeleft > 59)
- (void)fprintf(pf, "System going down in %d minute%s\n\n",
+ dprintf(fd[1], "System going down in %d minute%s\n\n",
timeleft / 60, (timeleft > 60) ? "s" : "");
else if (timeleft)
- (void)fprintf(pf, "System going down in 30 seconds\n\n");
+ dprintf(fd[1], "System going down in 30 seconds\n\n");
else
- (void)fprintf(pf, "System going down IMMEDIATELY\n\n");
+ dprintf(fd[1], "System going down IMMEDIATELY\n\n");
if (mbuflen)
- (void)fwrite(mbuf, sizeof(*mbuf), mbuflen, pf);
+ (void)write(fd[1], mbuf, mbuflen);
+ close(fd[1]);
/*
- * play some games, just in case wall doesn't come back
- * probably unnecessary, given that wall is careful.
+ * If we wait longer than 30 seconds for wall(1) to exit we'll
+ * throw off our schedule.
*/
- if (!setjmp(alarmbuf)) {
- (void)signal(SIGALRM, timeout);
- (void)alarm((u_int)30);
- (void)pclose(pf);
- (void)alarm((u_int)0);
- (void)signal(SIGALRM, SIG_DFL);
+ signal(SIGALRM, timeout);
+ siginterrupt(SIGALRM, 1);
+ alarm(30);
+ while ((wpid = wait(NULL)) != pid && !timed_out)
+ continue;
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ if (timed_out) {
+ syslog(LOG_NOTICE,
+ "wall[%ld] is taking too long to exit; continuing",
+ (long)pid);
+ timed_out = 0;
}
}
void
timeout(int signo)
{
- longjmp(alarmbuf, 1); /* XXX signal/longjmp resource leaks */
+ timed_out = 1;
}
void