summaryrefslogtreecommitdiffstats
path: root/system_cmds/reboot.tproj/reboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'system_cmds/reboot.tproj/reboot.c')
-rw-r--r--system_cmds/reboot.tproj/reboot.c378
1 files changed, 378 insertions, 0 deletions
diff --git a/system_cmds/reboot.tproj/reboot.c b/system_cmds/reboot.tproj/reboot.c
new file mode 100644
index 0000000..5478704
--- /dev/null
+++ b/system_cmds/reboot.tproj/reboot.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 1980, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1980, 1986, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)reboot.c 8.1 (Berkeley) 6/5/93";
+#endif
+__unused static const char rcsid[] =
+ "$FreeBSD: src/sbin/reboot/reboot.c,v 1.17 2002/10/06 16:24:36 thomas Exp $";
+#endif /* not lint */
+
+#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_IPHONE && !TARGET_OS_SIMULATOR)
+#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 <bootstrap_priv.h>
+#include <reboot2.h>
+#include <utmpx.h>
+#include <sys/time.h>
+#endif
+
+void usage(void);
+u_int get_pageins(void);
+#if defined(__APPLE__) && !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+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;
+/* -p is irrelevant on OS X. It does that anyway. */
+#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_IPHONE && !TARGET_OS_SIMULATOR)
+ if (!qflag && !lflag) { // shutdown(8) has already checked w/kextd
+ 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
+
+ /* Log the reboot. */
+ 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 = SHUTDOWN_TIME;
+ gettimeofday(&utx.ut_tv, NULL);
+ pututxline(&utx);
+ }
+#else
+ logwtmp("~", "shutdown", "");
+#endif
+
+ /*
+ * Do a sync early on, so disks start transfers while we're off
+ * killing processes. Don't worry about writes done before the
+ * processes die, the reboot system call syncs the disks.
+ */
+ if (!nflag)
+ sync();
+
+#ifndef __APPLE__
+ /* Just stop init -- if we fail, we'll restart it. */
+ if (kill(1, SIGTSTP) == -1)
+ err(1, "SIGTSTP init");
+#endif
+
+ /* Ignore the SIGHUP we get when our parent shell dies. */
+ (void)signal(SIGHUP, SIG_IGN);
+
+#ifndef __APPLE__
+ /* Send a SIGTERM first, a chance to save the buffers. */
+ if (kill(-1, SIGTERM) == -1)
+ err(1, "SIGTERM processes");
+
+ /*
+ * After the processes receive the signal, start the rest of the
+ * buffers on their way. Wait 5 seconds between the SIGTERM and
+ * the SIGKILL to give everybody a chance. If there is a lot of
+ * paging activity then wait longer, up to a maximum of approx
+ * 60 seconds.
+ */
+ 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__
+ // launchd(8) handles reboot. This call returns NULL on success.
+ exit(reboot3(howto) == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+#else /* __APPLE__ */
+ reboot(howto);
+ /* FALLTHROUGH */
+
+restart:
+ sverrno = errno;
+ errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
+ strerror(sverrno));
+ /* NOTREACHED */
+#endif /* __APPLE__ */
+}
+
+void
+usage(void)
+{
+#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(void)
+{
+ 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_IPHONE && !TARGET_OS_SIMULATOR)
+// XX this routine is also in shutdown.tproj; it would be nice to share
+
+static bool
+kextdDisabled(void)
+{
+ uint32_t disabled = 0;
+ size_t sizeOfDisabled = sizeof(disabled);
+ if (sysctlbyname("hw.use_kernelmanagerd", &disabled, &sizeOfDisabled, NULL, 0) != 0) {
+ return false;
+ }
+ return (disabled != 0);
+}
+
+#define WAITFORLOCK 1
+/*
+ * contact kextd to lock for reboot
+ */
+int
+reserve_reboot(void)
+{
+ 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;
+
+ if (kextdDisabled()) {
+ /* no need to talk with kextd if it's not running */
+ return 0;
+ }
+
+ macherr = bootstrap_look_up2(bootstrap_port, KEXTD_SERVER_NAME, &kxport, 0, BOOTSTRAP_PRIVILEGED_SERVER);
+ if (macherr) goto finish;
+
+ // allocate a port to pass to kextd (in case we die)
+ 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;
+
+ // try to lock for reboot
+ 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) {
+ // reboot already in progress
+ rval = 0;
+ } else {
+ rval = busyStatus;
+ }
+
+finish:
+ // in general, we want to err on the side of allowing the reboot
+ if (macherr) {
+ if (macherr != BOOTSTRAP_UNKNOWN_SERVICE)
+ warnx("WARNING: couldn't lock kext manager for reboot: %s",
+ mach_error_string(macherr));
+ rval = 0;
+ }
+ // unless we got the lock, clean up our port
+ if (busyStatus != 0 && myport != MACH_PORT_NULL)
+ mach_port_mod_refs(tport, myport, MACH_PORT_RIGHT_RECEIVE, -1);
+
+ return rval;
+}
+#endif