#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1980, 1986, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif
#ifndef lint
#if 0
static char sccsid[] = "@(#)reboot.c 8.1 (Berkeley) 6/5/93";
#endif
static const char rcsid[] =
"$FreeBSD: src/sbin/reboot/reboot.c,v 1.17 2002/10/06 16:24:36 thomas Exp $";
#endif
#include <sys/reboot.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <signal.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <util.h>
#include <pwd.h>
#include <syslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef __APPLE__
#include <TargetConditionals.h>
#if !TARGET_OS_EMBEDDED
#include "kextmanager.h"
#include <IOKit/kext/kextmanager_types.h>
#endif
#include <mach/mach_port.h> // allocate
#include <mach/mach.h> // task_self, etc
#include <servers/bootstrap.h> // bootstrap
#include <reboot2.h>
#include <utmpx.h>
#include <sys/time.h>
#endif
void usage(void);
u_int get_pageins(void);
#if defined(__APPLE__) && !TARGET_OS_EMBEDDED
int reserve_reboot(void);
#endif
int dohalt;
int
main(int argc, char *argv[])
{
struct passwd *pw;
int ch, howto, kflag, lflag, nflag, qflag, uflag;
char *p;
const char *user;
#ifndef __APPLE__
int i, fd, pflag, sverrno;
u_int pageins;
char *kernel;
#endif
if (strstr((p = rindex(*argv, '/')) ? p + 1 : *argv, "halt")) {
dohalt = 1;
howto = RB_HALT;
} else
howto = 0;
kflag = lflag = nflag = qflag = 0;
#ifndef __APPLE__
while ((ch = getopt(argc, argv, "dk:lnpq")) != -1)
#else
while ((ch = getopt(argc, argv, "lnqu")) != -1)
#endif
switch(ch) {
#ifndef __APPLE__
case 'd':
howto |= RB_DUMP;
break;
case 'k':
kflag = 1;
kernel = optarg;
break;
#endif
case 'l':
lflag = 1;
break;
case 'n':
nflag = 1;
howto |= RB_NOSYNC;
break;
#ifndef __APPLE__
case 'p':
pflag = 1;
howto |= RB_POWEROFF;
break;
#endif
case 'u':
uflag = 1;
howto |= RB_UPSDELAY;
break;
case 'q':
qflag = 1;
howto |= RB_QUICK;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
#ifndef __APPLE__
if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT))
errx(1, "cannot dump (-d) when halting; must reboot instead");
#endif
if (geteuid()) {
errno = EPERM;
err(1, NULL);
}
#if defined(__APPLE__) && !TARGET_OS_EMBEDDED
if (!qflag && !lflag) { if ((errno = reserve_reboot()))
err(1, "couldn't lock for reboot");
}
#endif
if (qflag) {
reboot(howto);
err(1, NULL);
}
#ifndef __APPLE__
if (kflag) {
fd = open("/boot/nextboot.conf", O_WRONLY | O_CREAT, 0444);
if (fd > -1) {
(void)write(fd, "nextboot_enable=\"YES\"\n", 22);
(void)write(fd, "kernel=\"", 8L);
(void)write(fd, kernel, strlen(kernel));
(void)write(fd, "\"\n", 2);
close(fd);
}
}
#endif
if (!lflag) {
if ((user = getlogin()) == NULL)
user = (pw = getpwuid(getuid())) ?
pw->pw_name : "???";
if (dohalt) {
openlog("halt", 0, LOG_AUTH | LOG_CONS);
syslog(LOG_CRIT, "halted by %s%s", user,
(howto & RB_UPSDELAY) ? " with UPS delay":"");
} else {
openlog("reboot", 0, LOG_AUTH | LOG_CONS);
syslog(LOG_CRIT, "rebooted by %s", user);
}
}
#if defined(__APPLE__)
{
struct utmpx utx;
bzero(&utx, sizeof(utx));
utx.ut_type = BOOT_TIME;
gettimeofday(&utx.ut_tv, NULL);
pututxline(&utx);
int newvalue = 1;
sysctlbyname("kern.willshutdown", NULL, NULL, &newvalue, sizeof(newvalue));
}
#else
logwtmp("~", "shutdown", "");
#endif
if (!nflag)
sync();
#ifndef __APPLE__
if (kill(1, SIGTSTP) == -1)
err(1, "SIGTSTP init");
#endif
(void)signal(SIGHUP, SIG_IGN);
#ifndef __APPLE__
if (kill(-1, SIGTERM) == -1)
err(1, "SIGTERM processes");
sleep(2);
for (i = 0; i < 20; i++) {
pageins = get_pageins();
if (!nflag)
sync();
sleep(3);
if (get_pageins() == pageins)
break;
}
for (i = 1;; ++i) {
if (kill(-1, SIGKILL) == -1) {
if (errno == ESRCH)
break;
goto restart;
}
if (i > 5) {
(void)fprintf(stderr,
"WARNING: some process(es) wouldn't die\n");
break;
}
(void)sleep(2 * i);
}
#endif
#ifdef __APPLE__
exit(reboot2(howto) == NULL ? EXIT_SUCCESS : EXIT_FAILURE);
#else
reboot(howto);
restart:
sverrno = errno;
errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
strerror(sverrno));
#endif
}
void
usage()
{
#ifndef __APPLE__
(void)fprintf(stderr, "usage: %s [-dnpq] [-k kernel]\n",
#else
(void)fprintf(stderr, "usage: %s [-lnq]\n",
#endif
dohalt ? "halt" : "reboot");
exit(1);
}
u_int
get_pageins()
{
u_int pageins;
size_t len;
len = sizeof(pageins);
if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0)
!= 0) {
warnx("v_swappgsin");
return (0);
}
return pageins;
}
#if defined(__APPLE__) && !TARGET_OS_EMBEDDED
#define WAITFORLOCK 1
int
reserve_reboot()
{
int rval = ELAST + 1;
kern_return_t macherr = KERN_FAILURE;
mach_port_t kxport, tport = MACH_PORT_NULL, myport = MACH_PORT_NULL;
int busyStatus = ELAST + 1;
mountpoint_t busyVol;
macherr = bootstrap_look_up(bootstrap_port, KEXTD_SERVER_NAME, &kxport);
if (macherr) goto finish;
tport = mach_task_self();
if (tport == MACH_PORT_NULL) goto finish;
macherr = mach_port_allocate(tport, MACH_PORT_RIGHT_RECEIVE, &myport);
if (macherr) goto finish;
macherr = kextmanager_lock_reboot(kxport, myport, !WAITFORLOCK, busyVol,
&busyStatus);
if (macherr) goto finish;
if (busyStatus == EBUSY) {
warnx("%s is busy updating; waiting for lock", busyVol);
macherr = kextmanager_lock_reboot(kxport, myport, WAITFORLOCK,
busyVol, &busyStatus);
if (macherr) goto finish;
}
if (busyStatus == EALREADY) {
rval = 0;
} else {
rval = busyStatus;
}
finish:
if (macherr) {
if (macherr != BOOTSTRAP_UNKNOWN_SERVICE)
warnx("WARNING: couldn't lock kext manager for reboot: %s",
mach_error_string(macherr));
rval = 0;
}
if (busyStatus != 0 && myport != MACH_PORT_NULL)
mach_port_mod_refs(tport, myport, MACH_PORT_RIGHT_RECEIVE, -1);
return rval;
}
#endif