1/* 2 * Copyright (c) 1988, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Portions copyright (c) 2007 Apple Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#if 0 32#ifndef lint 33static const char copyright[] = 34"@(#) Copyright (c) 1988, 1990, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"; 36#endif /* not lint */ 37 38#ifndef lint 39static char sccsid[] = "@(#)shutdown.c 8.4 (Berkeley) 4/28/95"; 40#endif /* not lint */ 41#endif 42#include <sys/cdefs.h> 43#ifndef __APPLE__ 44__FBSDID("$FreeBSD: src/sbin/shutdown/shutdown.c,v 1.28 2005/01/25 08:40:51 delphij Exp $"); 45#endif 46 47#include <sys/param.h> 48#include <sys/time.h> 49#include <sys/resource.h> 50#include <sys/syslog.h> 51 52#include <ctype.h> 53#include <err.h> 54#include <fcntl.h> 55#include <paths.h> 56#include <pwd.h> 57#include <setjmp.h> 58#include <signal.h> 59#include <stdio.h> 60#include <stdlib.h> 61#include <string.h> 62#include <unistd.h> 63 64#ifdef __APPLE__ 65#include <errno.h> 66#include <util.h> 67#include <bsm/libbsm.h> 68#include <bsm/audit_uevents.h> 69#include <vproc.h> 70#include <vproc_priv.h> 71 72#include "kextmanager.h" 73#include <IOKit/kext/kextmanager_types.h> 74#include <IOKit/pwr_mgt/IOPMLib.h> 75#include <mach/mach_port.h> // allocate 76#include <mach/mach.h> // task_self, etc 77#include <servers/bootstrap.h> // bootstrap 78#include <bootstrap_priv.h> 79#include <reboot2.h> 80#include <utmpx.h> 81#include <sys/sysctl.h> 82 83#include "pathnames.h" 84#endif /* __APPLE__ */ 85 86#ifdef DEBUG 87#undef _PATH_NOLOGIN 88#define _PATH_NOLOGIN "./nologin" 89#endif 90 91#define H *60*60 92#define M *60 93#define S *1 94#define NOLOG_TIME 5*60 95struct interval { 96 int timeleft, timetowait; 97} tlist[] = { 98 { 10 H, 5 H }, 99 { 5 H, 3 H }, 100 { 2 H, 1 H }, 101 { 1 H, 30 M }, 102 { 30 M, 10 M }, 103 { 20 M, 10 M }, 104 { 10 M, 5 M }, 105 { 5 M, 3 M }, 106 { 2 M, 1 M }, 107 { 1 M, 30 S }, 108 { 30 S, 30 S }, 109 { 0 , 0 } 110}; 111#undef H 112#undef M 113#undef S 114 115static time_t offset, shuttime; 116#ifdef __APPLE__ 117static int dohalt, doreboot, doups, killflg, mbuflen, oflag; 118#else 119static int dohalt, dopower, doreboot, killflg, mbuflen, oflag; 120#endif 121static char mbuf[BUFSIZ]; 122static const char *nosync, *whom; 123#ifdef __APPLE__ 124static int dosleep; 125#endif 126 127void badtime(void); 128#ifdef __APPLE__ 129void log_and_exec_reboot_or_halt(void); 130#else 131void die_you_gravy_sucking_pig_dog(void); 132#endif 133void finish(int); 134void getoffset(char *); 135void loop(void); 136void nolog(void); 137void timeout(int); 138void timewarn(int); 139void usage(const char *); 140#ifdef __APPLE__ 141int audit_shutdown(int); 142int reserve_reboot(void); 143#endif 144 145extern const char **environ; 146 147int 148main(int argc, char **argv) 149{ 150 char *p, *endp; 151 struct passwd *pw; 152 int arglen, ch, len, readstdin; 153 154#ifndef DEBUG 155 if (geteuid()) 156 errx(1, "NOT super-user"); 157#endif 158 nosync = NULL; 159 readstdin = 0; 160#ifndef __APPLE__ 161 while ((ch = getopt(argc, argv, "-hknopr")) != -1) 162#else 163 while ((ch = getopt(argc, argv, "-hknorsu")) != -1) 164#endif 165 switch (ch) { 166 case '-': 167 readstdin = 1; 168 break; 169 case 'h': 170 dohalt = 1; 171 break; 172 case 'k': 173 killflg = 1; 174 break; 175 case 'n': 176 nosync = "-n"; 177 break; 178 case 'o': 179 oflag = 1; 180 break; 181#ifndef __APPLE__ 182 case 'p': 183 dopower = 1; 184 break; 185#endif 186 case 'u': 187 doups = 1; 188 break; 189 case 'r': 190 doreboot = 1; 191 break; 192#ifdef __APPLE__ 193 case 's': 194 dosleep = 1; 195 break; 196#endif 197 case '?': 198 default: 199 usage((char *)NULL); 200 } 201 argc -= optind; 202 argv += optind; 203 204 if (argc < 1) 205 usage((char *)NULL); 206 207#ifndef __APPLE__ 208 if (killflg + doreboot + dohalt + dopower > 1) 209 usage("incompatible switches -h, -k, -p and -r"); 210 211 if (oflag && !(dohalt || dopower || doreboot)) 212 usage("-o requires -h, -p or -r"); 213 214 if (nosync != NULL && !oflag) 215 usage("-n requires -o"); 216#else /* !__APPLE__ */ 217 if (killflg + doreboot + dohalt + dosleep > 1) 218 usage("incompatible switches -h, -k, -r, and -s"); 219 220 if (!(dohalt || doreboot || dosleep || killflg)) 221 usage("-h, -r, -s, or -k is required"); 222 223 if (doups && !dohalt) 224 usage("-u requires -h"); 225#endif /* !__APPLE__ */ 226 227 getoffset(*argv++); 228 229 if (*argv) { 230 for (p = mbuf, len = sizeof(mbuf); *argv; ++argv) { 231 arglen = strlen(*argv); 232 if ((len -= arglen) <= 2) 233 break; 234 if (p != mbuf) 235 *p++ = ' '; 236 memmove(p, *argv, arglen); 237 p += arglen; 238 } 239 *p = '\n'; 240 *++p = '\0'; 241 } 242 243 if (readstdin) { 244 p = mbuf; 245 endp = mbuf + sizeof(mbuf) - 2; 246 for (;;) { 247 if (!fgets(p, endp - p + 1, stdin)) 248 break; 249 for (; *p && p < endp; ++p); 250 if (p == endp) { 251 *p = '\n'; 252 *++p = '\0'; 253 break; 254 } 255 } 256 } 257 mbuflen = strlen(mbuf); 258 259 if (offset) 260 (void)printf("Shutdown at %.24s.\n", ctime(&shuttime)); 261 else 262 (void)printf("Shutdown NOW!\n"); 263 264 if (!(whom = getlogin())) 265 whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; 266 267#ifdef DEBUG 268 audit_shutdown(0); 269 (void)putc('\n', stdout); 270#else 271 (void)setpriority(PRIO_PROCESS, 0, PRIO_MIN); 272#ifdef __APPLE__ 273 if (offset) { 274#else 275 { 276#endif 277 int forkpid; 278 279 forkpid = fork(); 280 if (forkpid == -1) { 281 audit_shutdown(1); 282 err(1, "fork"); 283 } 284 if (forkpid) 285 errx(0, "[pid %d]", forkpid); 286#ifdef __APPLE__ 287 /* 5863185: reboot2() needs to talk to launchd. */ 288 if (_vprocmgr_detach_from_console(0) != NULL) 289 warnx("can't detach from console"); 290#endif /* __APPLE__ */ 291 } 292 audit_shutdown(0); 293 setsid(); 294#endif 295 openlog("shutdown", LOG_CONS, LOG_AUTH); 296 loop(); 297 return(0); 298} 299 300void 301loop() 302{ 303 struct interval *tp; 304 u_int sltime; 305 int logged; 306 307 if (offset <= NOLOG_TIME) { 308 logged = 1; 309 nolog(); 310 } 311 else 312 logged = 0; 313 tp = tlist; 314 if (tp->timeleft < offset) 315 (void)sleep((u_int)(offset - tp->timeleft)); 316 else { 317 while (tp->timeleft && offset < tp->timeleft) 318 ++tp; 319 /* 320 * Warn now, if going to sleep more than a fifth of 321 * the next wait time. 322 */ 323 if ((sltime = offset - tp->timeleft)) { 324 if (sltime > (u_int)(tp->timetowait / 5)) 325 timewarn(offset); 326 (void)sleep(sltime); 327 } 328 } 329 for (;; ++tp) { 330 timewarn(tp->timeleft); 331 if (!logged && tp->timeleft <= NOLOG_TIME) { 332 logged = 1; 333 nolog(); 334 } 335 (void)sleep((u_int)tp->timetowait); 336 if (!tp->timeleft) 337 break; 338 } 339#ifdef __APPLE__ 340 log_and_exec_reboot_or_halt(); 341#else 342 die_you_gravy_sucking_pig_dog(); 343#endif 344} 345 346static jmp_buf alarmbuf; 347 348static const char *restricted_environ[] = { 349 "PATH=" _PATH_STDPATH, 350 NULL 351}; 352 353void 354timewarn(int timeleft) 355{ 356 static int first; 357 static char hostname[MAXHOSTNAMELEN + 1]; 358 FILE *pf; 359 char wcmd[MAXPATHLEN + 4]; 360 361 /* wall is sometimes missing, e.g. on install media */ 362 if (access(_PATH_WALL, X_OK) == -1) return; 363 364 if (!first++) 365 (void)gethostname(hostname, sizeof(hostname)); 366 367 /* undoc -n option to wall suppresses normal wall banner */ 368 (void)snprintf(wcmd, sizeof(wcmd), "%s -n", _PATH_WALL); 369 environ = restricted_environ; 370 if (!(pf = popen(wcmd, "w"))) { 371 syslog(LOG_ERR, "shutdown: can't find %s: %m", _PATH_WALL); 372 return; 373 } 374 375 (void)fprintf(pf, 376 "\007*** %sSystem shutdown message from %s@%s ***\007\n", 377 timeleft ? "": "FINAL ", whom, hostname); 378 379 if (timeleft > 10*60) 380 (void)fprintf(pf, "System going down at %5.5s\n\n", 381 ctime(&shuttime) + 11); 382 else if (timeleft > 59) 383 (void)fprintf(pf, "System going down in %d minute%s\n\n", 384 timeleft / 60, (timeleft > 60) ? "s" : ""); 385 else if (timeleft) 386 (void)fprintf(pf, "System going down in 30 seconds\n\n"); 387 else 388 (void)fprintf(pf, "System going down IMMEDIATELY\n\n"); 389 390 if (mbuflen) 391 (void)fwrite(mbuf, sizeof(*mbuf), mbuflen, pf); 392 393 /* 394 * play some games, just in case wall doesn't come back 395 * probably unnecessary, given that wall is careful. 396 */ 397 if (!setjmp(alarmbuf)) { 398 (void)signal(SIGALRM, timeout); 399 (void)alarm((u_int)30); 400 (void)pclose(pf); 401 (void)alarm((u_int)0); 402 (void)signal(SIGALRM, SIG_DFL); 403 } 404} 405 406void 407timeout(int signo __unused) 408{ 409 longjmp(alarmbuf, 1); 410} 411 412void 413#ifdef __APPLE__ 414log_and_exec_reboot_or_halt() 415#else 416die_you_gravy_sucking_pig_dog() 417#endif 418{ 419#ifndef __APPLE__ 420 char *empty_environ[] = { NULL }; 421#else 422 if ((errno = reserve_reboot())) { 423 warn("couldn't lock for reboot"); 424 finish(0); 425 } 426#endif 427 428 syslog(LOG_NOTICE, "%s%s by %s: %s", 429#ifndef __APPLE__ 430 doreboot ? "reboot" : dohalt ? "halt" : dopower ? "power-down" : 431#else 432 doreboot ? "reboot" : dohalt ? "halt" : dosleep ? "sleep" : 433#endif 434 "shutdown", doups?" with UPS delay":"", whom, mbuf); 435#ifndef __APPLE__ 436 (void)sleep(2); 437#endif 438 439 (void)printf("\r\nSystem shutdown time has arrived\007\007\r\n"); 440 if (killflg) { 441 (void)printf("\rbut you'll have to do it yourself\r\n"); 442 exit(0); 443 } 444#ifdef DEBUG 445 if (doreboot) 446 (void)printf("reboot"); 447 else if (dohalt) 448 (void)printf("halt"); 449#ifndef __APPLE__ 450 else if (dopower) 451 (void)printf("power-down"); 452 if (nosync != NULL) 453 (void)printf(" no sync"); 454#else 455 else if (dosleep) 456 (void)printf("sleep"); 457#endif 458 (void)printf("\nkill -HUP 1\n"); 459#else 460#ifdef __APPLE__ 461 if (dosleep) { 462 mach_port_t mp; 463 io_connect_t fb; 464 kern_return_t kr = IOMasterPort(bootstrap_port, &mp); 465 if (kr == kIOReturnSuccess) { 466 fb = IOPMFindPowerManagement(mp); 467 if (fb != IO_OBJECT_NULL) { 468 IOReturn err = IOPMSleepSystem(fb); 469 if (err != kIOReturnSuccess) { 470 fprintf(stderr, "shutdown: sleep failed (0x%08x)\n", err); 471 kr = -1; 472 } 473 } 474 } 475 } else { 476 int howto = 0; 477 478#if defined(__APPLE__) 479 { 480 struct utmpx utx; 481 bzero(&utx, sizeof(utx)); 482 utx.ut_type = SHUTDOWN_TIME; 483 gettimeofday(&utx.ut_tv, NULL); 484 pututxline(&utx); 485 486 int newvalue = 1; 487 sysctlbyname("kern.willshutdown", NULL, NULL, &newvalue, sizeof(newvalue)); 488 } 489#else 490 logwtmp("~", "shutdown", ""); 491#endif 492 493 if (dohalt) howto |= RB_HALT; 494 if (doups) howto |= RB_UPSDELAY; 495 if (nosync) howto |= RB_NOSYNC; 496 497 // launchd(8) handles reboot. This call returns NULL on success. 498 if (reboot2(howto)) { 499 syslog(LOG_ERR, "shutdown: launchd reboot failed."); 500 } 501 } 502#else /* __APPLE__ */ 503 if (!oflag) { 504 (void)kill(1, doreboot ? SIGINT : /* reboot */ 505 dohalt ? SIGUSR1 : /* halt */ 506 dopower ? SIGUSR2 : /* power-down */ 507 SIGTERM); /* single-user */ 508 } else { 509 if (doreboot) { 510 execle(_PATH_REBOOT, "reboot", "-l", nosync, 511 (char *)NULL, empty_environ); 512 syslog(LOG_ERR, "shutdown: can't exec %s: %m.", 513 _PATH_REBOOT); 514 warn(_PATH_REBOOT); 515 } 516 else if (dohalt) { 517 execle(_PATH_HALT, "halt", "-l", nosync, 518 (char *)NULL, empty_environ); 519 syslog(LOG_ERR, "shutdown: can't exec %s: %m.", 520 _PATH_HALT); 521 warn(_PATH_HALT); 522 } 523 else if (dopower) { 524 execle(_PATH_HALT, "halt", "-l", "-p", nosync, 525 (char *)NULL, empty_environ); 526 syslog(LOG_ERR, "shutdown: can't exec %s: %m.", 527 _PATH_HALT); 528 warn(_PATH_HALT); 529 } 530 (void)kill(1, SIGTERM); /* to single-user */ 531 } 532#endif /* __APPLE__ */ 533#endif 534 finish(0); 535} 536 537#define ATOI2(p) (p[0] - '0') * 10 + (p[1] - '0'); p += 2; 538 539void 540getoffset(char *timearg) 541{ 542 struct tm *lt; 543 char *p; 544 time_t now; 545 int this_year; 546 547 (void)time(&now); 548 549 if (!strcasecmp(timearg, "now")) { /* now */ 550 offset = 0; 551 shuttime = now; 552 return; 553 } 554 555 if (*timearg == '+') { /* +minutes */ 556 if (!isdigit(*++timearg)) 557 badtime(); 558 if ((offset = atoi(timearg) * 60) < 0) 559 badtime(); 560 shuttime = now + offset; 561 return; 562 } 563 564 /* handle hh:mm by getting rid of the colon */ 565 for (p = timearg; *p; ++p) 566 if (!isascii(*p) || !isdigit(*p)) { 567 if (*p == ':' && strlen(p) == 3) { 568 p[0] = p[1]; 569 p[1] = p[2]; 570 p[2] = '\0'; 571 } 572 else 573 badtime(); 574 } 575 576 unsetenv("TZ"); /* OUR timezone */ 577 lt = localtime(&now); /* current time val */ 578 579 switch(strlen(timearg)) { 580 case 10: 581 this_year = lt->tm_year; 582 lt->tm_year = ATOI2(timearg); 583 /* 584 * check if the specified year is in the next century. 585 * allow for one year of user error as many people will 586 * enter n - 1 at the start of year n. 587 */ 588 if (lt->tm_year < (this_year % 100) - 1) 589 lt->tm_year += 100; 590 /* adjust for the year 2000 and beyond */ 591 lt->tm_year += (this_year - (this_year % 100)); 592 /* FALLTHROUGH */ 593 case 8: 594 lt->tm_mon = ATOI2(timearg); 595 if (--lt->tm_mon < 0 || lt->tm_mon > 11) 596 badtime(); 597 /* FALLTHROUGH */ 598 case 6: 599 lt->tm_mday = ATOI2(timearg); 600 if (lt->tm_mday < 1 || lt->tm_mday > 31) 601 badtime(); 602 /* FALLTHROUGH */ 603 case 4: 604 lt->tm_hour = ATOI2(timearg); 605 if (lt->tm_hour < 0 || lt->tm_hour > 23) 606 badtime(); 607 lt->tm_min = ATOI2(timearg); 608 if (lt->tm_min < 0 || lt->tm_min > 59) 609 badtime(); 610 lt->tm_sec = 0; 611 if ((shuttime = mktime(lt)) == -1) 612 badtime(); 613 if ((offset = shuttime - now) < 0) 614 errx(1, "that time is already past."); 615 break; 616 default: 617 badtime(); 618 } 619} 620 621#define NOMSG "\n\nNO LOGINS: System going down at " 622void 623nolog() 624{ 625 int logfd; 626 char *ct; 627 628 (void)unlink(_PATH_NOLOGIN); /* in case linked to another file */ 629 (void)signal(SIGINT, finish); 630 (void)signal(SIGHUP, finish); 631 (void)signal(SIGQUIT, finish); 632 (void)signal(SIGTERM, finish); 633 if ((logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC, 634 0664)) >= 0) { 635 (void)write(logfd, NOMSG, sizeof(NOMSG) - 1); 636 ct = ctime(&shuttime); 637 (void)write(logfd, ct + 11, 5); 638 (void)write(logfd, "\n\n", 2); 639 (void)write(logfd, mbuf, strlen(mbuf)); 640 (void)close(logfd); 641 } 642} 643 644void 645finish(int signo __unused) 646{ 647 if (!killflg) 648 (void)unlink(_PATH_NOLOGIN); 649 exit(0); 650} 651 652void 653badtime() 654{ 655 errx(1, "bad time format"); 656} 657 658void 659usage(const char *cp) 660{ 661 if (cp != NULL) 662 warnx("%s", cp); 663 (void)fprintf(stderr, 664#ifdef __APPLE__ 665 "usage: shutdown [-] [-h [-u] [-n] | -r [-n] | -s | -k]" 666#else 667 "usage: shutdown [-] [-h | -p | -r | -k] [-o [-n]]" 668#endif 669 " time [warning-message ...]\n"); 670 exit(1); 671} 672 673#ifdef __APPLE__ 674/* 675 * The following tokens are included in the audit record for shutdown 676 * header 677 * subject 678 * return 679 */ 680int audit_shutdown(int exitstatus) 681{ 682 int aufd; 683 token_t *tok; 684 long au_cond; 685 686 /* If we are not auditing, don't cut an audit record; just return */ 687 if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) { 688 fprintf(stderr, "shutdown: Could not determine audit condition\n"); 689 return 0; 690 } 691 if (au_cond == AUC_NOAUDIT) 692 return 0; 693 694 if((aufd = au_open()) == -1) { 695 fprintf(stderr, "shutdown: Audit Error: au_open() failed\n"); 696 exit(1); 697 } 698 699 /* The subject that performed the operation */ 700 if((tok = au_to_me()) == NULL) { 701 fprintf(stderr, "shutdown: Audit Error: au_to_me() failed\n"); 702 exit(1); 703 } 704 au_write(aufd, tok); 705 706 /* success and failure status */ 707 if((tok = au_to_return32(exitstatus, errno)) == NULL) { 708 fprintf(stderr, "shutdown: Audit Error: au_to_return32() failed\n"); 709 exit(1); 710 } 711 au_write(aufd, tok); 712 713 if(au_close(aufd, 1, AUE_shutdown) == -1) { 714 fprintf(stderr, "shutdown: Audit Error: au_close() failed\n"); 715 exit(1); 716 } 717 return 1; 718} 719 720 721// XX copied from reboot.tproj/reboot.c; it would be nice to share the code 722 723#define WAITFORLOCK 1 724/* 725 * contact kextd to lock for reboot 726 */ 727int 728reserve_reboot() 729{ 730 int rval = ELAST + 1; 731 kern_return_t macherr = KERN_FAILURE; 732 mach_port_t kxport, tport = MACH_PORT_NULL, myport = MACH_PORT_NULL; 733 int busyStatus = ELAST + 1; 734 mountpoint_t busyVol; 735 736 macherr = bootstrap_look_up2(bootstrap_port, KEXTD_SERVER_NAME, &kxport, 0, BOOTSTRAP_PRIVILEGED_SERVER); 737 if (macherr) goto finish; 738 739 // allocate a port to pass to kextd (in case we die) 740 tport = mach_task_self(); 741 if (tport == MACH_PORT_NULL) goto finish; 742 macherr = mach_port_allocate(tport, MACH_PORT_RIGHT_RECEIVE, &myport); 743 if (macherr) goto finish; 744 745 // try to lock for reboot 746 macherr = kextmanager_lock_reboot(kxport, myport, !WAITFORLOCK, busyVol, 747 &busyStatus); 748 if (macherr) goto finish; 749 750 if (busyStatus == EBUSY) { 751 warnx("%s is busy updating; waiting for lock", busyVol); 752 macherr = kextmanager_lock_reboot(kxport, myport, WAITFORLOCK, 753 busyVol, &busyStatus); 754 if (macherr) goto finish; 755 } 756 757 if (busyStatus == EALREADY) { 758 // reboot already in progress 759 rval = 0; 760 } else { 761 rval = busyStatus; 762 } 763 764finish: 765 // in general, we want to err on the side of allowing the reboot 766 if (macherr) { 767 if (macherr != BOOTSTRAP_UNKNOWN_SERVICE) 768 warnx("WARNING: couldn't lock kext manager for reboot: %s", 769 mach_error_string(macherr)); 770 rval = 0; 771 } 772 // unless we got the lock, clean up our port 773 if (busyStatus != 0 && myport != MACH_PORT_NULL) 774 mach_port_mod_refs(tport, myport, MACH_PORT_RIGHT_RECEIVE, -1); 775 776 return rval; 777} 778#endif /* __APPLE__ */ 779 780