X-Git-Url: https://git.saurik.com/apple/system_cmds.git/blobdiff_plain/83f6dbe8135dc38ce4ac497ebea7f0ebc87d9199..a8daac8f698fa38f1ca3aaa2a3ed6ac20e5128e2:/shutdown.tproj/shutdown.c?ds=inline diff --git a/shutdown.tproj/shutdown.c b/shutdown.tproj/shutdown.c index 532649e..e7a7928 100644 --- a/shutdown.tproj/shutdown.c +++ b/shutdown.tproj/shutdown.c @@ -1,6 +1,7 @@ /* * Copyright (c) 1988, 1990, 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 @@ -10,11 +11,7 @@ * 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. * @@ -31,6 +28,7 @@ * SUCH DAMAGE. */ +#if 0 #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1988, 1990, 1993\n\ @@ -38,12 +36,13 @@ static const char copyright[] = #endif /* not lint */ #ifndef lint -#if 0 static char sccsid[] = "@(#)shutdown.c 8.4 (Berkeley) 4/28/95"; -#endif -static const char rcsid[] = - "$FreeBSD: src/sbin/shutdown/shutdown.c,v 1.23 2002/03/21 13:20:48 imp Exp $"; #endif /* not lint */ +#endif +#include +#ifndef __APPLE__ +__FBSDID("$FreeBSD: src/sbin/shutdown/shutdown.c,v 1.28 2005/01/25 08:40:51 delphij Exp $"); +#endif #include #include @@ -53,6 +52,7 @@ static const char rcsid[] = #include #include #include +#include #include #include #include @@ -61,11 +61,22 @@ static const char rcsid[] = #include #include -#include "pathnames.h" - #ifdef __APPLE__ -#define __unused -#endif +#include +#include +#include +#include + +#include "kextmanager.h" +#include +#include +#include // allocate +#include // task_self, etc +#include // bootstrap +#include + +#include "pathnames.h" +#endif /* __APPLE__ */ #ifdef DEBUG #undef _PATH_NOLOGIN @@ -97,9 +108,16 @@ struct interval { #undef S static time_t offset, shuttime; -static int dohalt, dopower, doreboot, killflg, mbuflen, oflag = 1; +#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__ @@ -114,11 +132,15 @@ 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) { char *p, *endp; struct passwd *pw; @@ -133,7 +155,7 @@ main(argc, argv) #ifndef __APPLE__ while ((ch = getopt(argc, argv, "-hknopr")) != -1) #else - while ((ch = getopt(argc, argv, "-hknor")) != -1) + while ((ch = getopt(argc, argv, "-hknorsu")) != -1) #endif switch (ch) { case '-': @@ -156,9 +178,17 @@ main(argc, argv) 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((char *)NULL); @@ -175,16 +205,19 @@ main(argc, argv) if (oflag && !(dohalt || dopower || doreboot)) usage("-o requires -h, -p or -r"); -#else - if (killflg + doreboot + dohalt > 1) - usage("incompatible switches -h, -k, and -r"); - - if (oflag && !(dohalt || doreboot)) - usage("-o requires -h or -r"); -#endif 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__ */ getoffset(*argv++); @@ -227,18 +260,26 @@ 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) + if (forkpid == -1) { + audit_shutdown(1); err(1, "fork"); + } if (forkpid) errx(0, "[pid %d]", forkpid); } + audit_shutdown(0); setsid(); #endif openlog("shutdown", LOG_CONS, LOG_AUTH); @@ -300,14 +341,15 @@ static const char *restricted_environ[] = { }; void -timewarn(timeleft) - int timeleft; +timewarn(int timeleft) { static int first; static char hostname[MAXHOSTNAMELEN + 1]; FILE *pf; char wcmd[MAXPATHLEN + 4]; - extern const char **environ; + + /* wall is sometimes missing, e.g. on install media */ + if (access(_PATH_WALL, X_OK) == -1) return; if (!first++) (void)gethostname(hostname, sizeof(hostname)); @@ -352,8 +394,7 @@ timewarn(timeleft) } void -timeout(signo) - int signo __unused; +timeout(int signo __unused) { longjmp(alarmbuf, 1); } @@ -365,15 +406,20 @@ log_and_exec_reboot_or_halt() 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", + syslog(LOG_NOTICE, "%s%s by %s: %s", #ifndef __APPLE__ doreboot ? "reboot" : dohalt ? "halt" : dopower ? "power-down" : #else - doreboot ? "reboot" : dohalt ? "halt" : + doreboot ? "reboot" : dohalt ? "halt" : dosleep ? "sleep" : #endif - "shutdown", whom, mbuf); + "shutdown", doups?" with UPS delay":"", whom, mbuf); #ifndef __APPLE__ (void)sleep(2); #endif @@ -391,17 +437,49 @@ die_you_gravy_sucking_pig_dog() #ifndef __APPLE__ else if (dopower) (void)printf("power-down"); -#endif if (nosync != NULL) (void)printf(" no sync"); +#else + else if (dosleep) + (void)printf("sleep"); +#endif (void)printf("\nkill -HUP 1\n"); #else +#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); + } + /* NOT-REACHED */ + +#else /* __APPLE__ */ if (!oflag) { (void)kill(1, doreboot ? SIGINT : /* reboot */ dohalt ? SIGUSR1 : /* halt */ -#ifndef __APPLE__ dopower ? SIGUSR2 : /* power-down */ -#endif SIGTERM); /* single-user */ } else { if (doreboot) { @@ -418,7 +496,6 @@ die_you_gravy_sucking_pig_dog() _PATH_HALT); warn(_PATH_HALT); } -#ifndef __APPLE__ else if (dopower) { execle(_PATH_HALT, "halt", "-l", "-p", nosync, (char *)NULL, empty_environ); @@ -426,9 +503,9 @@ die_you_gravy_sucking_pig_dog() _PATH_HALT); warn(_PATH_HALT); } -#endif (void)kill(1, SIGTERM); /* to single-user */ } +#endif /* __APPLE__ */ #endif finish(0); } @@ -436,8 +513,7 @@ die_you_gravy_sucking_pig_dog() #define ATOI2(p) (p[0] - '0') * 10 + (p[1] - '0'); p += 2; void -getoffset(timearg) - char *timearg; +getoffset(char *timearg) { struct tm *lt; char *p; @@ -540,12 +616,11 @@ nolog() (void)write(logfd, mbuf, strlen(mbuf)); (void)close(logfd); } -#endif +#endif /* !__APPLE__ */ } void -finish(signo) - int signo __unused; +finish(int signo __unused) { #ifndef __APPLE__ if (!killflg) @@ -561,13 +636,124 @@ badtime() } void -usage(cp) - const char *cp; +usage(const char *cp) { 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__ */ +