]> git.saurik.com Git - apple/system_cmds.git/blobdiff - shutdown.tproj/shutdown.c
system_cmds-433.8.tar.gz
[apple/system_cmds.git] / shutdown.tproj / shutdown.c
index 889b0a05a31b1c2f5c8bc9b35dff81668d4229ff..e7a79289b8194c6e526a174903a1629ee4b24784 100644 (file)
@@ -1,29 +1,7 @@
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
- * Reserved.  This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License').  You may not use this file
- * except in compliance with the License.  Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
 /*
  * Copyright (c) 1988, 1990, 1993
- *      The Regents of the University of California.  All rights reserved.
+ *     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
  * 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. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *      This product includes software developed by the University of
- *      California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 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.
  *
  * SUCH DAMAGE.
  */
 
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1990, 1993\n\
+       The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)shutdown.c 8.4 (Berkeley) 4/28/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/sbin/shutdown/shutdown.c,v 1.28 2005/01/25 08:40:51 delphij Exp $");
+#endif
+
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <sys/syslog.h>
 
 #include <ctype.h>
+#include <err.h>
 #include <fcntl.h>
+#include <paths.h>
 #include <pwd.h>
 #include <setjmp.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <tzfile.h>
 #include <unistd.h>
 
+#ifdef __APPLE__
+#include <errno.h>
+#include <util.h>
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+
+#include "kextmanager.h"
+#include <IOKit/kext/kextmanager_types.h>
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <mach/mach_port.h>            // allocate
+#include <mach/mach.h>                 // task_self, etc
+#include <servers/bootstrap.h> // bootstrap
+#include <reboot2.h>
+
 #include "pathnames.h"
+#endif /* __APPLE__ */
 
 #ifdef DEBUG
 #undef _PATH_NOLOGIN
 #define        _PATH_NOLOGIN   "./nologin"
-#undef _PATH_FASTBOOT
-#define        _PATH_FASTBOOT  "./fastboot"
 #endif
 
 #define        H               *60*60
 struct interval {
        int timeleft, timetowait;
 } tlist[] = {
-       10 H,  5 H,      5 H,  3 H,      2 H,  1 H,     1 H, 30 M,
-       30 M, 10 M,     20 M, 10 M,     10 M,  5 M,     5 M,  3 M,
-        2 M,  1 M,      1 M, 30 S,     30 S, 30 S,
-        0, 0,
+       { 10 H,  5 H },
+       {  5 H,  3 H },
+       {  2 H,  1 H },
+       {  1 H, 30 M },
+       { 30 M, 10 M },
+       { 20 M, 10 M },
+       { 10 M,  5 M },
+       {  5 M,  3 M },
+       {  2 M,  1 M },
+       {  1 M, 30 S },
+       { 30 S, 30 S },
+       {  0  ,  0   }
 };
 #undef H
 #undef M
 #undef S
 
 static time_t offset, shuttime;
-static int dofast, dohalt, doreboot, killflg, mbuflen;
-static char *nosync, *whom, mbuf[BUFSIZ];
-
-void badtime __P((void));
-void die_you_gravy_sucking_pig_dog __P((void));
-void doitfast __P((void));
-void finish __P((int));
-void getoffset __P((char *));
-void loop __P((void));
-void nolog __P((void));
-void timeout __P((int));
-void timewarn __P((int));
-void usage __P((void));
+#ifdef __APPLE__
+static int dohalt, doreboot, doups, killflg, mbuflen, oflag;
+#else
+static int dohalt, dopower, doreboot, killflg, mbuflen, oflag;
+#endif
+static char mbuf[BUFSIZ];
+static const char *nosync, *whom;
+#ifdef __APPLE__
+static int dosleep;
+#endif
+
+void badtime(void);
+#ifdef __APPLE__
+void log_and_exec_reboot_or_halt(void);
+#else
+void die_you_gravy_sucking_pig_dog(void);
+#endif
+void finish(int);
+void getoffset(char *);
+void loop(void);
+void nolog(void);
+void timeout(int);
+void timewarn(int);
+void usage(const char *);
+#ifdef __APPLE__
+int audit_shutdown(int);
+int reserve_reboot(void);
+#endif
+
+extern const char **environ;
 
 int
-main(argc, argv)
-       int argc;
-       char *argv[];
+main(int argc, char **argv)
 {
-       extern int optind;
-       register char *p, *endp;
+       char *p, *endp;
        struct passwd *pw;
        int arglen, ch, len, readstdin;
 
 #ifndef DEBUG
-       if (geteuid()) {
-               (void)fprintf(stderr, "shutdown: NOT super-user\n");
-               exit(1);
-       }
+       if (geteuid())
+               errx(1, "NOT super-user");
 #endif
        nosync = NULL;
        readstdin = 0;
-       while ((ch = getopt(argc, argv, "-fhknr")) != EOF)
+#ifndef __APPLE__
+       while ((ch = getopt(argc, argv, "-hknopr")) != -1)
+#else
+       while ((ch = getopt(argc, argv, "-hknorsu")) != -1)
+#endif
                switch (ch) {
                case '-':
                        readstdin = 1;
                        break;
-               case 'f':
-                       dofast = 1;
-                       break;
                case 'h':
                        dohalt = 1;
                        break;
@@ -145,29 +170,55 @@ main(argc, argv)
                case 'n':
                        nosync = "-n";
                        break;
+               case 'o':
+                       oflag = 1;
+                       break;
+#ifndef __APPLE__
+               case 'p':
+                       dopower = 1;
+                       break;
+#endif
+        case 'u':
+            doups = 1;
+            break;
                case 'r':
                        doreboot = 1;
                        break;
+#ifdef __APPLE__
+               case 's':
+                       dosleep = 1;
+                       break;
+#endif
                case '?':
                default:
-                       usage();
+                       usage((char *)NULL);
                }
        argc -= optind;
        argv += optind;
 
        if (argc < 1)
-               usage();
+               usage((char *)NULL);
+
+#ifndef __APPLE__
+       if (killflg + doreboot + dohalt + dopower > 1)
+               usage("incompatible switches -h, -k, -p and -r");
+
+       if (oflag && !(dohalt || dopower || doreboot))
+               usage("-o requires -h, -p or -r");
+
+       if (nosync != NULL && !oflag)
+               usage("-n requires -o");
+#else /* !__APPLE__ */
+       if (killflg + doreboot + dohalt + dosleep > 1)
+               usage("incompatible switches -h, -k, -r, and -s");
+
+       if (!(dohalt || doreboot || dosleep || killflg))
+               usage("-h, -r, -s, or -k is required");
+               
+       if (doups && !dohalt)
+               usage("-u requires -h");
+#endif /* !__APPLE__ */
 
-       if (dofast && nosync) {
-               (void)fprintf(stderr,
-                   "shutdown: incompatible switches -f and -n.\n");
-               usage();
-       }
-       if (doreboot && dohalt) {
-               (void)fprintf(stderr,
-                   "shutdown: incompatible switches -h and -r.\n");
-               usage();
-       }
        getoffset(*argv++);
 
        if (*argv) {
@@ -209,26 +260,31 @@ main(argc, argv)
                whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
 
 #ifdef DEBUG
+       audit_shutdown(0);
        (void)putc('\n', stdout);
 #else
        (void)setpriority(PRIO_PROCESS, 0, PRIO_MIN);
+#ifdef __APPLE__
+       if (offset) {
+#else
        {
+#endif
                int forkpid;
 
                forkpid = fork();
                if (forkpid == -1) {
-                       perror("shutdown: fork");
-                       exit(1);
-               }
-               if (forkpid) {
-                       (void)printf("shutdown: [pid %d]\n", forkpid);
-                       exit(0);
+                       audit_shutdown(1);
+                       err(1, "fork");
                }
+               if (forkpid)
+                       errx(0, "[pid %d]", forkpid);
        }
+       audit_shutdown(0);
+       setsid();
 #endif
        openlog("shutdown", LOG_CONS, LOG_AUTH);
        loop();
-       /* NOTREACHED */
+       return(0);
 }
 
 void
@@ -248,14 +304,14 @@ loop()
        if (tp->timeleft < offset)
                (void)sleep((u_int)(offset - tp->timeleft));
        else {
-               while (offset < tp->timeleft)
+               while (tp->timeleft && offset < tp->timeleft)
                        ++tp;
                /*
                 * Warn now, if going to sleep more than a fifth of
                 * the next wait time.
                 */
-               if (sltime = offset - tp->timeleft) {
-                       if (sltime > tp->timetowait / 5)
+               if ((sltime = offset - tp->timeleft)) {
+                       if (sltime > (u_int)(tp->timetowait / 5))
                                timewarn(offset);
                        (void)sleep(sltime);
                }
@@ -270,25 +326,37 @@ loop()
                if (!tp->timeleft)
                        break;
        }
+#ifdef __APPLE__
+       log_and_exec_reboot_or_halt();
+#else
        die_you_gravy_sucking_pig_dog();
+#endif
 }
 
 static jmp_buf alarmbuf;
 
+static const char *restricted_environ[] = {
+       "PATH=" _PATH_STDPATH,
+       NULL
+};
+
 void
-timewarn(timeleft)
-       int timeleft;
+timewarn(int timeleft)
 {
        static int first;
        static char hostname[MAXHOSTNAMELEN + 1];
        FILE *pf;
        char wcmd[MAXPATHLEN + 4];
 
+       /* wall is sometimes missing, e.g. on install media */
+       if (access(_PATH_WALL, X_OK) == -1) return;
+
        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);
                return;
@@ -314,7 +382,7 @@ timewarn(timeleft)
 
        /*
         * play some games, just in case wall doesn't come back
-        * probably unecessary, given that wall is careful.
+        * probably unnecessary, given that wall is careful.
         */
        if (!setjmp(alarmbuf)) {
                (void)signal(SIGALRM, timeout);
@@ -326,49 +394,118 @@ timewarn(timeleft)
 }
 
 void
-timeout(signo)
-       int signo;
+timeout(int signo __unused)
 {
        longjmp(alarmbuf, 1);
 }
 
 void
+#ifdef __APPLE__
+log_and_exec_reboot_or_halt()
+#else
 die_you_gravy_sucking_pig_dog()
+#endif
 {
+#ifndef __APPLE__
+       char *empty_environ[] = { NULL };
+#else
+       if ((errno = reserve_reboot()))
+               err(1, "couldn't lock for reboot");
+#endif
 
-       syslog(LOG_NOTICE, "%s by %s: %s",
-           doreboot ? "reboot" : dohalt ? "halt" : "shutdown", whom, mbuf);
+       syslog(LOG_NOTICE, "%s%s by %s: %s",
+#ifndef __APPLE__
+           doreboot ? "reboot" : dohalt ? "halt" : dopower ? "power-down" : 
+#else
+           doreboot ? "reboot" : dohalt ? "halt" : dosleep ? "sleep" :
+#endif
+           "shutdown", doups?" with UPS delay":"", whom, mbuf);
+#ifndef __APPLE__
        (void)sleep(2);
+#endif
 
        (void)printf("\r\nSystem shutdown time has arrived\007\007\r\n");
        if (killflg) {
                (void)printf("\rbut you'll have to do it yourself\r\n");
-               finish(0);
+               exit(0);
        }
-       if (dofast)
-               doitfast();
 #ifdef DEBUG
        if (doreboot)
                (void)printf("reboot");
        else if (dohalt)
                (void)printf("halt");
-       if (nosync)
+#ifndef __APPLE__
+       else if (dopower)
+               (void)printf("power-down");
+       if (nosync != NULL)
                (void)printf(" no sync");
-       if (dofast)
-               (void)printf(" no fsck");
+#else
+       else if (dosleep)
+               (void)printf("sleep");
+#endif
        (void)printf("\nkill -HUP 1\n");
 #else
-       if (doreboot) {
-               execle(_PATH_REBOOT, "reboot", "-l", nosync, 0);
-               syslog(LOG_ERR, "shutdown: can't exec %s: %m.", _PATH_REBOOT);
-               perror("shutdown");
+#ifdef __APPLE__
+       if (dosleep) {
+               mach_port_t mp;
+               io_connect_t fb;
+               kern_return_t kr = IOMasterPort(bootstrap_port, &mp);
+               if (kr == kIOReturnSuccess) {
+                       fb = IOPMFindPowerManagement(mp);
+                       if (fb != IO_OBJECT_NULL) {
+                               IOReturn err = IOPMSleepSystem(fb);
+                               if (err != kIOReturnSuccess) {
+                                       fprintf(stderr, "shutdown: sleep failed (0x%08x)\n", err);
+                                       kr = -1;
+                               }
+                       }
+               }
+               exit((kr == kIOReturnSuccess) ? 0 : 1);
+       } else {
+               int howto = 0;
+
+               logwtmp("~", "shutdown", "");
+
+               if (dohalt) howto |= RB_HALT;
+               if (doups) howto |= RB_UPSDELAY;
+               if (nosync) howto |= RB_NOSYNC;
+
+               // launchd(8) handles reboot.  This call returns NULL on success.
+               exit(reboot2(howto) == NULL ? EXIT_SUCCESS : EXIT_FAILURE);
        }
-       else if (dohalt) {
-               execle(_PATH_HALT, "halt", "-l", nosync, 0);
-               syslog(LOG_ERR, "shutdown: can't exec %s: %m.", _PATH_HALT);
-               perror("shutdown");
+       /* NOT-REACHED */
+
+#else /* __APPLE__ */
+       if (!oflag) {
+               (void)kill(1, doreboot ? SIGINT :       /* reboot */
+                             dohalt ? SIGUSR1 :        /* halt */
+                             dopower ? SIGUSR2 :       /* power-down */
+                             SIGTERM);                 /* single-user */
+       } else {
+               if (doreboot) {
+                       execle(_PATH_REBOOT, "reboot", "-l", nosync, 
+                               (char *)NULL, empty_environ);
+                       syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
+                               _PATH_REBOOT);
+                       warn(_PATH_REBOOT);
+               }
+               else if (dohalt) {
+                       execle(_PATH_HALT, "halt", "-l", nosync,
+                               (char *)NULL, empty_environ);
+                       syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
+                               _PATH_HALT);
+                       warn(_PATH_HALT);
+               }
+               else if (dopower) {
+                       execle(_PATH_HALT, "halt", "-l", "-p", nosync,
+                               (char *)NULL, empty_environ);
+                       syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
+                               _PATH_HALT);
+                       warn(_PATH_HALT);
+               }
+               (void)kill(1, SIGTERM);         /* to single-user */
        }
-       (void)kill(1, SIGTERM);         /* to single user */
+#endif /* __APPLE__ */
 #endif
        finish(0);
 }
@@ -376,30 +513,33 @@ die_you_gravy_sucking_pig_dog()
 #define        ATOI2(p)        (p[0] - '0') * 10 + (p[1] - '0'); p += 2;
 
 void
-getoffset(timearg)
-       register char *timearg;
+getoffset(char *timearg)
 {
-       register struct tm *lt;
-       register char *p;
+       struct tm *lt;
+       char *p;
        time_t now;
+       int this_year;
+
+       (void)time(&now);
 
        if (!strcasecmp(timearg, "now")) {              /* now */
                offset = 0;
+               shuttime = now;
                return;
        }
 
-       (void)time(&now);
        if (*timearg == '+') {                          /* +minutes */
                if (!isdigit(*++timearg))
                        badtime();
-               offset = atoi(timearg) * 60;
+               if ((offset = atoi(timearg) * 60) < 0)
+                       badtime();
                shuttime = now + offset;
                return;
        }
 
        /* handle hh:mm by getting rid of the colon */
        for (p = timearg; *p; ++p)
-               if (!isascii(*p) || !isdigit(*p))
+               if (!isascii(*p) || !isdigit(*p)) {
                        if (*p == ':' && strlen(p) == 3) {
                                p[0] = p[1];
                                p[1] = p[2];
@@ -407,13 +547,24 @@ getoffset(timearg)
                        }
                        else
                                badtime();
+               }
 
        unsetenv("TZ");                                 /* OUR timezone */
        lt = localtime(&now);                           /* current time val */
 
        switch(strlen(timearg)) {
        case 10:
+               this_year = lt->tm_year;
                lt->tm_year = ATOI2(timearg);
+               /*
+                * check if the specified year is in the next century.
+                * allow for one year of user error as many people will
+                * enter n - 1 at the start of year n.
+                */
+               if (lt->tm_year < (this_year % 100) - 1)
+                       lt->tm_year += 100;
+               /* adjust for the year 2000 and beyond */
+               lt->tm_year += (this_year - (this_year % 100));
                /* FALLTHROUGH */
        case 8:
                lt->tm_mon = ATOI2(timearg);
@@ -435,34 +586,19 @@ getoffset(timearg)
                lt->tm_sec = 0;
                if ((shuttime = mktime(lt)) == -1)
                        badtime();
-               if ((offset = shuttime - now) < 0) {
-                       (void)fprintf(stderr,
-                           "shutdown: that time is already past.\n");
-                       exit(1);
-               }
+               if ((offset = shuttime - now) < 0)
+                       errx(1, "that time is already past.");
                break;
        default:
                badtime();
        }
 }
 
-#define        FSMSG   "fastboot file for fsck\n"
-void
-doitfast()
-{
-       int fastfd;
-
-       if ((fastfd = open(_PATH_FASTBOOT, O_WRONLY|O_CREAT|O_TRUNC,
-           0664)) >= 0) {
-               (void)write(fastfd, FSMSG, sizeof(FSMSG) - 1);
-               (void)close(fastfd);
-       }
-}
-
 #define        NOMSG   "\n\nNO LOGINS: System going down at "
 void
 nolog()
 {
+#ifndef __APPLE__
        int logfd;
        char *ct;
 
@@ -480,27 +616,144 @@ nolog()
                (void)write(logfd, mbuf, strlen(mbuf));
                (void)close(logfd);
        }
+#endif /* !__APPLE__ */
 }
 
 void
-finish(signo)
-       int signo;
+finish(int signo __unused)
 {
+#ifndef __APPLE__
        if (!killflg)
                (void)unlink(_PATH_NOLOGIN);
+#endif
        exit(0);
 }
 
 void
 badtime()
 {
-       (void)fprintf(stderr, "shutdown: bad time format.\n");
-       exit(1);
+       errx(1, "bad time format");
 }
 
 void
-usage()
+usage(const char *cp)
 {
-       fprintf(stderr, "usage: shutdown [-fhknr] shutdowntime [ message ]\n");
+       if (cp != NULL)
+               warnx("%s", cp);
+       (void)fprintf(stderr,
+#ifdef __APPLE__
+           "usage: shutdown [-] [-h [-u] [-n] | -r [-n] | -s | -k]"
+#else
+           "usage: shutdown [-] [-h | -p | -r | -k] [-o [-n]]"
+#endif
+           " time [warning-message ...]\n");
        exit(1);
 }
+
+#ifdef __APPLE__
+/*
+ * The following tokens are included in the audit record for shutdown
+ * header
+ * subject
+ * return
+ */  
+int audit_shutdown(int exitstatus)
+{
+       int aufd;
+       token_t *tok;
+       long au_cond;
+
+       /* If we are not auditing, don't cut an audit record; just return */
+       if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
+               fprintf(stderr, "shutdown: Could not determine audit condition\n");
+               return 0;
+       }
+       if (au_cond == AUC_NOAUDIT)
+               return 0;
+
+       if((aufd = au_open()) == -1) {
+               fprintf(stderr, "shutdown: Audit Error: au_open() failed\n");
+               exit(1);      
+       }
+
+       /* The subject that performed the operation */
+       if((tok = au_to_me()) == NULL) {
+               fprintf(stderr, "shutdown: Audit Error: au_to_me() failed\n");
+               exit(1);
+       }
+       au_write(aufd, tok);
+
+       /* success and failure status */
+       if((tok = au_to_return32(exitstatus, errno)) == NULL) {
+               fprintf(stderr, "shutdown: Audit Error: au_to_return32() failed\n");
+               exit(1);
+       }
+       au_write(aufd, tok);
+
+       if(au_close(aufd, 1, AUE_shutdown) == -1) {
+               fprintf(stderr, "shutdown: Audit Error: au_close() failed\n");
+               exit(1);
+       }
+       return 1;
+}
+
+
+// XX copied from reboot.tproj/reboot.c; it would be nice to share the code
+
+#define WAITFORLOCK 1
+/*
+ * contact kextd to lock for reboot
+ */
+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;
+
+    // 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 /* __APPLE__ */
+