1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /* 43 * Common code for halt(1M), poweroff(1M), and reboot(1M). We use 44 * argv[0] to determine which behavior to exhibit. 45 */ 46 47 #include <sys/stat.h> 48 #include <sys/types.h> 49 #include <sys/uadmin.h> 50 #include <alloca.h> 51 #include <assert.h> 52 #include <errno.h> 53 #include <fcntl.h> 54 #include <libgen.h> 55 #include <libscf.h> 56 #include <locale.h> 57 #include <libintl.h> 58 #include <syslog.h> 59 #include <signal.h> 60 #include <strings.h> 61 #include <unistd.h> 62 #include <stdlib.h> 63 #include <stdio.h> 64 #include <strings.h> 65 #include <time.h> 66 #include <utmpx.h> 67 #include <pwd.h> 68 #include <zone.h> 69 #if !defined(TEXT_DOMAIN) 70 #define TEXT_DOMAIN "SYS_TEST" 71 #endif 72 73 extern int audit_halt_setup(int, char **); 74 extern int audit_halt_success(void); 75 extern int audit_halt_fail(void); 76 77 extern int audit_reboot_setup(void); 78 extern int audit_reboot_success(void); 79 extern int audit_reboot_fail(void); 80 81 typedef struct ctidlist_struct { 82 ctid_t ctid; 83 struct ctidlist_struct *next; 84 } ctidlist_t; 85 86 static ctidlist_t *ctidlist = NULL; 87 static ctid_t startdct = -1; 88 89 #define FMRI_STARTD_CONTRACT \ 90 "svc:/system/svc/restarter:default/:properties/restarter/contract" 91 92 #define ZONEADM_PROG "/usr/sbin/zoneadm" 93 94 static void 95 stop_startd() 96 { 97 ctid_t ctid; 98 99 scf_handle_t *h; 100 scf_property_t *prop = NULL; 101 scf_value_t *val = NULL; 102 uint64_t uint64; 103 int ret; 104 105 h = scf_handle_create(SCF_VERSION); 106 if (h == NULL) 107 return; 108 109 ret = scf_handle_bind(h); 110 if (ret) { 111 scf_handle_destroy(h); 112 return; 113 } 114 115 prop = scf_property_create(h); 116 val = scf_value_create(h); 117 118 if (!(prop && val)) 119 goto out; 120 121 ret = scf_handle_decode_fmri(h, FMRI_STARTD_CONTRACT, 122 NULL, NULL, NULL, NULL, prop, SCF_DECODE_FMRI_EXACT); 123 if (ret) 124 goto out; 125 126 ret = scf_property_is_type(prop, SCF_TYPE_COUNT); 127 if (ret) 128 goto out; 129 130 ret = scf_property_get_value(prop, val); 131 if (ret) 132 goto out; 133 134 ret = scf_value_get_count(val, &uint64); 135 if (ret) 136 goto out; 137 138 ctid = (ctid_t)uint64; 139 startdct = ctid; 140 (void) sigsend(P_CTID, ctid, SIGSTOP); 141 142 out: 143 if (prop) 144 scf_property_destroy(prop); 145 if (val) 146 scf_value_destroy(val); 147 148 (void) scf_handle_unbind(h); 149 scf_handle_destroy(h); 150 } 151 152 static void 153 continue_startd() 154 { 155 if (startdct != -1) 156 (void) sigsend(P_CTID, startdct, SIGCONT); 157 } 158 159 #define FMRI_RESTARTER_PROP "/:properties/general/restarter" 160 #define FMRI_CONTRACT_PROP "/:properties/restarter/contract" 161 162 static int 163 save_ctid(ctid_t ctid) 164 { 165 ctidlist_t *next; 166 167 for (next = ctidlist; next != NULL; next = next->next) 168 if (next->ctid == ctid) 169 return (-1); 170 171 next = (ctidlist_t *)malloc(sizeof (ctidlist_t)); 172 if (next == NULL) 173 return (-1); 174 175 next->ctid = ctid; 176 next->next = ctidlist; 177 ctidlist = next; 178 return (0); 179 } 180 181 static void 182 stop_delegates() 183 { 184 ctid_t ctid; 185 scf_handle_t *h; 186 scf_scope_t *sc = NULL; 187 scf_service_t *svc = NULL; 188 scf_instance_t *inst = NULL; 189 scf_snapshot_t *snap = NULL; 190 scf_snapshot_t *isnap = NULL; 191 scf_propertygroup_t *pg = NULL; 192 scf_property_t *prop = NULL; 193 scf_value_t *val = NULL; 194 scf_iter_t *siter = NULL; 195 scf_iter_t *iiter = NULL; 196 char *fmri; 197 ssize_t length; 198 199 uint64_t uint64; 200 ssize_t bytes; 201 int ret; 202 203 length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 204 if (length <= 0) 205 return; 206 207 length++; 208 fmri = alloca(length * sizeof (char)); 209 210 h = scf_handle_create(SCF_VERSION); 211 if (!h) 212 return; 213 214 ret = scf_handle_bind(h); 215 if (ret) { 216 scf_handle_destroy(h); 217 return; 218 } 219 220 sc = scf_scope_create(h); 221 svc = scf_service_create(h); 222 inst = scf_instance_create(h); 223 snap = scf_snapshot_create(h); 224 pg = scf_pg_create(h); 225 prop = scf_property_create(h); 226 val = scf_value_create(h); 227 siter = scf_iter_create(h); 228 iiter = scf_iter_create(h); 229 230 if (!(sc && svc && inst && snap && 231 pg && prop && val && siter && iiter)) 232 goto out; 233 234 ret = scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc); 235 if (ret) 236 goto out; 237 238 ret = scf_iter_scope_services(siter, sc); 239 if (ret) 240 goto out; 241 242 while (scf_iter_next_service(siter, svc) == 1) { 243 244 ret = scf_iter_service_instances(iiter, svc); 245 if (ret) 246 continue; 247 248 while (scf_iter_next_instance(iiter, inst) == 1) { 249 250 ret = scf_instance_get_snapshot(inst, "running", snap); 251 if (ret) 252 isnap = NULL; 253 else 254 isnap = snap; 255 256 ret = scf_instance_get_pg_composed(inst, isnap, 257 SCF_PG_GENERAL, pg); 258 if (ret) 259 continue; 260 261 ret = scf_pg_get_property(pg, "restarter", prop); 262 if (ret) 263 continue; 264 265 ret = scf_property_is_type(prop, SCF_TYPE_ASTRING); 266 if (ret) 267 continue; 268 269 ret = scf_property_get_value(prop, val); 270 if (ret) 271 continue; 272 273 bytes = scf_value_get_astring(val, fmri, length); 274 if (bytes <= 0 || bytes >= length) 275 continue; 276 277 if (strlcat(fmri, FMRI_CONTRACT_PROP, length) >= 278 length) 279 continue; 280 281 ret = scf_handle_decode_fmri(h, fmri, NULL, NULL, 282 NULL, NULL, prop, SCF_DECODE_FMRI_EXACT); 283 if (ret) 284 continue; 285 286 ret = scf_property_is_type(prop, SCF_TYPE_COUNT); 287 if (ret) 288 continue; 289 290 ret = scf_property_get_value(prop, val); 291 if (ret) 292 continue; 293 294 ret = scf_value_get_count(val, &uint64); 295 if (ret) 296 continue; 297 298 ctid = (ctid_t)uint64; 299 if (save_ctid(ctid) == 0) { 300 (void) sigsend(P_CTID, ctid, SIGSTOP); 301 } 302 } 303 } 304 out: 305 if (sc) 306 scf_scope_destroy(sc); 307 if (svc) 308 scf_service_destroy(svc); 309 if (inst) 310 scf_instance_destroy(inst); 311 if (snap) 312 scf_snapshot_destroy(snap); 313 if (pg) 314 scf_pg_destroy(pg); 315 if (prop) 316 scf_property_destroy(prop); 317 if (val) 318 scf_value_destroy(val); 319 if (siter) 320 scf_iter_destroy(siter); 321 if (iiter) 322 scf_iter_destroy(iiter); 323 324 (void) scf_handle_unbind(h); 325 scf_handle_destroy(h); 326 } 327 328 static void 329 continue_delegates() 330 { 331 ctidlist_t *next; 332 for (next = ctidlist; next != NULL; next = next->next) 333 (void) sigsend(P_CTID, next->ctid, SIGCONT); 334 } 335 336 static void 337 stop_restarters() 338 { 339 stop_startd(); 340 stop_delegates(); 341 } 342 343 static void 344 continue_restarters() 345 { 346 continue_startd(); 347 continue_delegates(); 348 } 349 350 /* 351 * Copy an array of strings into buf, separated by spaces. Returns 0 on 352 * success. 353 */ 354 static int 355 gather_args(char **args, char *buf, size_t buf_sz) 356 { 357 if (strlcpy(buf, *args, buf_sz) >= buf_sz) 358 return (-1); 359 360 for (++args; *args != NULL; ++args) { 361 if (strlcat(buf, " ", buf_sz) >= buf_sz) 362 return (-1); 363 if (strlcat(buf, *args, buf_sz) >= buf_sz) 364 return (-1); 365 } 366 367 return (0); 368 } 369 370 /* 371 * Halt every zone on the system. We are committed to doing a shutdown 372 * even if something goes wrong here. If something goes wrong, we just 373 * continue with the shutdown. Return non-zero if we need to wait for zones to 374 * halt later on. 375 */ 376 static int 377 halt_zones(const char *name) 378 { 379 pid_t pid; 380 zoneid_t *zones; 381 size_t nz, old_nz; 382 int i; 383 char zname[ZONENAME_MAX]; 384 385 /* 386 * Get a list of zones. If the number of zones changes in between the 387 * two zone_list calls, try again. 388 */ 389 390 for (;;) { 391 (void) zone_list(NULL, &nz); 392 if (nz == 1) 393 return (0); 394 old_nz = nz; 395 zones = calloc(sizeof (zoneid_t), nz); 396 if (zones == NULL) { 397 (void) fprintf(stderr, 398 gettext("%s: Could not halt zones" 399 " (out of memory).\n"), name); 400 return (0); 401 } 402 403 (void) zone_list(zones, &nz); 404 if (old_nz == nz) 405 break; 406 free(zones); 407 } 408 409 if (nz == 2) { 410 (void) fprintf(stderr, 411 gettext("%s: Halting 1 zone.\n"), 412 name); 413 } else { 414 (void) fprintf(stderr, 415 gettext("%s: Halting %i zones.\n"), 416 name, nz - 1); 417 } 418 419 for (i = 0; i < nz; i++) { 420 if (zones[i] == GLOBAL_ZONEID) 421 continue; 422 if (getzonenamebyid(zones[i], zname, sizeof (zname)) < 0) { 423 /* 424 * getzonenamebyid should only fail if we raced with 425 * another process trying to shut down the zone. 426 * We assume this happened and ignore the error. 427 */ 428 if (errno != EINVAL) { 429 (void) fprintf(stderr, 430 gettext("%s: Unexpected error while " 431 "looking up zone %ul: %s.\n"), 432 name, zones[i], strerror(errno)); 433 } 434 435 continue; 436 } 437 pid = fork(); 438 if (pid < 0) { 439 (void) fprintf(stderr, 440 gettext("%s: Zone \"%s\" could not be" 441 " halted (could not fork(): %s).\n"), 442 name, zname, strerror(errno)); 443 continue; 444 } 445 if (pid == 0) { 446 (void) execl(ZONEADM_PROG, ZONEADM_PROG, 447 "-z", zname, "halt", NULL); 448 (void) fprintf(stderr, 449 gettext("%s: Zone \"%s\" could not be halted" 450 " (cannot exec(" ZONEADM_PROG "): %s).\n"), 451 name, zname, strerror(errno)); 452 exit(0); 453 } 454 } 455 456 return (1); 457 } 458 459 /* 460 * This function tries to wait for all non-global zones to go away. 461 * It will timeout if no progress is made for 5 seconds, or a total of 462 * 30 seconds elapses. 463 */ 464 465 static void 466 check_zones_haltedness(const char *name) 467 { 468 int t = 0, t_prog = 0; 469 size_t nz = 0, last_nz; 470 471 do { 472 last_nz = nz; 473 (void) zone_list(NULL, &nz); 474 if (nz == 1) 475 return; 476 477 (void) sleep(1); 478 479 if (last_nz > nz) 480 t_prog = 0; 481 482 t++; 483 t_prog++; 484 485 if (t == 10) { 486 if (nz == 2) { 487 (void) fprintf(stderr, 488 gettext("%s: Still waiting for 1 zone to " 489 "halt. Will wait up to 20 seconds.\n"), 490 name); 491 } else { 492 (void) fprintf(stderr, 493 gettext("%s: Still waiting for %i zones " 494 "to halt. Will wait up to 20 seconds.\n"), 495 name, nz - 1); 496 } 497 } 498 499 } while ((t < 30) && (t_prog < 5)); 500 } 501 502 int 503 main(int argc, char *argv[]) 504 { 505 char *cmdname = basename(argv[0]); 506 char *ttyn = ttyname(STDERR_FILENO); 507 508 int qflag = 0, needlog = 1, nosync = 0; 509 uintptr_t mdep = NULL; 510 int cmd, fcn, c, aval, r; 511 const char *usage; 512 zoneid_t zoneid = getzoneid(); 513 pid_t init_pid = 1; 514 int need_check_zones; 515 516 char bootargs_buf[257]; /* uadmin()'s buffer is 257 bytes. */ 517 518 const char * const resetting = "/etc/svc/volatile/resetting"; 519 520 521 (void) setlocale(LC_ALL, ""); 522 (void) textdomain(TEXT_DOMAIN); 523 524 if (strcmp(cmdname, "halt") == 0) { 525 (void) audit_halt_setup(argc, argv); 526 usage = gettext("usage: %s [ -dlnqy ]\n"); 527 cmd = A_SHUTDOWN; 528 fcn = AD_HALT; 529 } else if (strcmp(cmdname, "poweroff") == 0) { 530 (void) audit_halt_setup(argc, argv); 531 usage = gettext("usage: %s [ -dlnqy ]\n"); 532 cmd = A_SHUTDOWN; 533 fcn = AD_POWEROFF; 534 } else if (strcmp(cmdname, "reboot") == 0) { 535 (void) audit_reboot_setup(); 536 usage = gettext("usage: %s [ -dlnq ] [ boot args ]\n"); 537 cmd = A_SHUTDOWN; 538 fcn = AD_BOOT; 539 } else { 540 (void) fprintf(stderr, 541 gettext("%s: not installed properly\n"), cmdname); 542 return (1); 543 } 544 545 while ((c = getopt(argc, argv, "dlnqy")) != EOF) { 546 switch (c) { 547 case 'd': 548 if (zoneid == GLOBAL_ZONEID) 549 cmd = A_DUMP; 550 else { 551 (void) fprintf(stderr, 552 gettext("%s: -d only valid from global" 553 " zone\n"), cmdname); 554 return (1); 555 } 556 break; 557 case 'l': 558 needlog = 0; 559 break; 560 case 'n': 561 nosync = 1; 562 break; 563 case 'q': 564 qflag = 1; 565 break; 566 case 'y': 567 ttyn = NULL; 568 break; 569 default: 570 /* 571 * TRANSLATION_NOTE 572 * Don't translate the words "halt" or "reboot" 573 */ 574 (void) fprintf(stderr, usage, cmdname); 575 return (1); 576 } 577 } 578 579 argc -= optind; 580 argv += optind; 581 582 if (argc != 0) { 583 if (fcn != AD_BOOT) { 584 (void) fprintf(stderr, usage, cmdname); 585 return (1); 586 } 587 588 /* Gather the arguments into bootargs_buf. */ 589 if (gather_args(argv, bootargs_buf, sizeof (bootargs_buf)) != 590 0) { 591 (void) fprintf(stderr, 592 gettext("%s: Boot arguments too long.\n"), cmdname); 593 return (1); 594 } 595 mdep = (uintptr_t)bootargs_buf; 596 } 597 598 if (geteuid() != 0) { 599 (void) fprintf(stderr, 600 gettext("%s: permission denied\n"), cmdname); 601 goto fail; 602 } 603 604 if (fcn != AD_BOOT && ttyn != NULL && 605 strncmp(ttyn, "/dev/term/", strlen("/dev/term/")) == 0) { 606 /* 607 * TRANSLATION_NOTE 608 * Don't translate ``halt -y'' 609 */ 610 (void) fprintf(stderr, 611 gettext("%s: dangerous on a dialup;"), cmdname); 612 (void) fprintf(stderr, 613 gettext("use ``%s -y'' if you are really sure\n"), cmdname); 614 goto fail; 615 } 616 617 if (needlog) { 618 char *user = getlogin(); 619 struct passwd *pw; 620 621 openlog(cmdname, 0, LOG_AUTH); 622 if (user == NULL && (pw = getpwuid(getuid())) != NULL) 623 user = pw->pw_name; 624 if (user == NULL) 625 user = "root"; 626 syslog(LOG_CRIT, "%sed by %s", cmdname, user); 627 } 628 629 /* 630 * We must assume success and log it before auditd is terminated. 631 */ 632 if (fcn == AD_BOOT) 633 aval = audit_reboot_success(); 634 else 635 aval = audit_halt_success(); 636 637 if (aval == -1) { 638 (void) fprintf(stderr, 639 gettext("%s: can't turn off auditd\n"), cmdname); 640 if (needlog) 641 (void) sleep(5); /* Give syslogd time to record this */ 642 } 643 644 (void) signal(SIGHUP, SIG_IGN); /* for remote connections */ 645 646 if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid, 647 sizeof (init_pid)) != sizeof (init_pid)) { 648 assert(errno == ESRCH); 649 init_pid = -1; 650 } 651 652 /* 653 * We start to fork a bunch of zoneadms to halt any active zones. 654 * This will proceed with halt in parallel until we call 655 * check_zone_haltedness later on. 656 */ 657 if (zoneid == GLOBAL_ZONEID && cmd != A_DUMP) { 658 need_check_zones = halt_zones(cmdname); 659 } 660 661 662 /* sync boot archive in the global zone */ 663 if (getzoneid() == GLOBAL_ZONEID && !nosync) { 664 (void) system("/sbin/bootadm -a update_all"); 665 } 666 667 /* 668 * If we're not forcing a crash dump, mark the system as quiescing for 669 * smf(5)'s benefit, and idle the init process. 670 */ 671 if (cmd != A_DUMP) { 672 if (init_pid != -1 && kill(init_pid, SIGTSTP) == -1) { 673 /* 674 * TRANSLATION_NOTE 675 * Don't translate the word "init" 676 */ 677 (void) fprintf(stderr, 678 gettext("%s: can't idle init\n"), cmdname); 679 680 goto fail; 681 } 682 683 if (creat(resetting, 0755) == -1) 684 (void) fprintf(stderr, 685 gettext("%s: could not create %s.\n"), 686 cmdname, resetting); 687 688 /* 689 * Stop all restarters so they do not try to restart services 690 * that are terminated. 691 */ 692 stop_restarters(); 693 694 /* 695 * Wait a little while for zones to shutdown. 696 */ 697 if (need_check_zones) { 698 check_zones_haltedness(cmdname); 699 700 (void) fprintf(stderr, 701 gettext("%s: Completing system halt.\n"), 702 cmdname); 703 } 704 } 705 706 /* 707 * Make sure we don't get stopped by a jobcontrol shell 708 * once we start killing everybody. 709 */ 710 (void) signal(SIGTSTP, SIG_IGN); 711 (void) signal(SIGTTIN, SIG_IGN); 712 (void) signal(SIGTTOU, SIG_IGN); 713 (void) signal(SIGTERM, SIG_IGN); 714 715 /* 716 * If we're not forcing a crash dump, give everyone 5 seconds to 717 * handle a SIGTERM and clean up properly. 718 */ 719 if (cmd != A_DUMP) { 720 (void) kill(-1, SIGTERM); 721 (void) sleep(5); 722 } 723 724 if (!qflag && !nosync) { 725 struct utmpx wtmpx; 726 727 bzero(&wtmpx, sizeof (struct utmpx)); 728 (void) strcpy(wtmpx.ut_line, "~"); 729 (void) time(&wtmpx.ut_tv.tv_sec); 730 731 if (cmd == A_DUMP) 732 (void) strcpy(wtmpx.ut_name, "crash dump"); 733 else 734 (void) strcpy(wtmpx.ut_name, "shutdown"); 735 736 (void) updwtmpx(WTMPX_FILE, &wtmpx); 737 sync(); 738 } 739 740 if (cmd == A_DUMP && nosync != 0) 741 (void) uadmin(A_DUMP, AD_NOSYNC, NULL); 742 743 (void) uadmin(cmd, fcn, mdep); 744 perror(cmdname); 745 do 746 r = remove(resetting); 747 while (r != 0 && errno == EINTR); 748 if (r != 0 && errno != ENOENT) 749 (void) fprintf(stderr, gettext("%s: could not remove %s.\n"), 750 cmdname, resetting); 751 752 continue_restarters(); 753 754 if (init_pid != -1) 755 /* tell init to restate current level */ 756 (void) kill(init_pid, SIGHUP); 757 758 fail: 759 if (fcn == AD_BOOT) 760 (void) audit_reboot_fail(); 761 else 762 (void) audit_halt_fail(); 763 764 return (1); 765 } 766