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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  27  */
  28 
  29 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  30 /*        All Rights Reserved   */
  31 
  32 /*
  33  * University Copyright- Copyright (c) 1982, 1986, 1988
  34  * The Regents of the University of California
  35  * All Rights Reserved
  36  *
  37  * University Acknowledgment- Portions of this document are derived from
  38  * software developed by the University of California, Berkeley, and its
  39  * contributors.
  40  * Portions contributed by Juergen Keil, <jk@tools.de>.
  41  */
  42 
  43 
  44 /*
  45  * Common code for halt(1M), poweroff(1M), and reboot(1M).  We use
  46  * argv[0] to determine which behavior to exhibit.
  47  */
  48 
  49 #include <stdio.h>
  50 #include <procfs.h>
  51 #include <sys/types.h>
  52 #include <sys/elf.h>
  53 #include <sys/systeminfo.h>
  54 #include <sys/stat.h>
  55 #include <sys/uadmin.h>
  56 #include <sys/mntent.h>
  57 #include <sys/mnttab.h>
  58 #include <sys/mount.h>
  59 #include <sys/fs/ufs_mount.h>
  60 #include <alloca.h>
  61 #include <assert.h>
  62 #include <errno.h>
  63 #include <fcntl.h>
  64 #include <libgen.h>
  65 #include <libscf.h>
  66 #include <libscf_priv.h>
  67 #include <limits.h>
  68 #include <locale.h>
  69 #include <libintl.h>
  70 #include <syslog.h>
  71 #include <signal.h>
  72 #include <strings.h>
  73 #include <unistd.h>
  74 #include <stdlib.h>
  75 #include <stdio.h>
  76 #include <strings.h>
  77 #include <time.h>
  78 #include <wait.h>
  79 #include <ctype.h>
  80 #include <utmpx.h>
  81 #include <pwd.h>
  82 #include <zone.h>
  83 #include <spawn.h>
  84 
  85 #include <libzfs.h>
  86 #if defined(__i386)
  87 #include <libgrubmgmt.h>
  88 #endif
  89 
  90 #if !defined(TEXT_DOMAIN)
  91 #define TEXT_DOMAIN     "SYS_TEST"
  92 #endif
  93 
  94 #if defined(__sparc)
  95 #define CUR_ELFDATA     ELFDATA2MSB
  96 #elif defined(__i386)
  97 #define CUR_ELFDATA     ELFDATA2LSB
  98 #endif
  99 
 100 static libzfs_handle_t *g_zfs;
 101 
 102 extern int audit_halt_setup(int, char **);
 103 extern int audit_halt_success(void);
 104 extern int audit_halt_fail(void);
 105 
 106 extern int audit_reboot_setup(void);
 107 extern int audit_reboot_success(void);
 108 extern int audit_reboot_fail(void);
 109 
 110 static char *cmdname;   /* basename(argv[0]), the name of the command */
 111 
 112 typedef struct ctidlist_struct {
 113         ctid_t ctid;
 114         struct ctidlist_struct *next;
 115 } ctidlist_t;
 116 
 117 static ctidlist_t *ctidlist = NULL;
 118 static ctid_t startdct = -1;
 119 
 120 #define FMRI_STARTD_CONTRACT \
 121         "svc:/system/svc/restarter:default/:properties/restarter/contract"
 122 
 123 #define BEADM_PROG      "/usr/sbin/beadm"
 124 #define BOOTADM_PROG    "/sbin/bootadm"
 125 #define ZONEADM_PROG    "/usr/sbin/zoneadm"
 126 
 127 /*
 128  * The length of FASTBOOT_MOUNTPOINT must be less than MAXPATHLEN.
 129  */
 130 #define FASTBOOT_MOUNTPOINT     "/tmp/.fastboot.root"
 131 
 132 /*
 133  * Fast Reboot related variables
 134  */
 135 static char     fastboot_mounted[MAXPATHLEN];
 136 
 137 #if defined(__i386)
 138 static grub_boot_args_t fbarg;
 139 static grub_boot_args_t *fbarg_used;
 140 static int fbarg_entnum = GRUB_ENTRY_DEFAULT;
 141 #endif  /* __i386 */
 142 
 143 static int validate_ufs_disk(char *, char *);
 144 static int validate_zfs_pool(char *, char *);
 145 
 146 static pid_t
 147 get_initpid()
 148 {
 149         static int init_pid = -1;
 150 
 151         if (init_pid == -1) {
 152                 if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid,
 153                     sizeof (init_pid)) != sizeof (init_pid)) {
 154                         assert(errno == ESRCH);
 155                         init_pid = -1;
 156                 }
 157         }
 158         return (init_pid);
 159 }
 160 
 161 /*
 162  * Quiesce or resume init using /proc.  When stopping init, we can't send
 163  * SIGTSTP (since init ignores it) or SIGSTOP (since the kernel won't permit
 164  * it).
 165  */
 166 static int
 167 direct_init(long command)
 168 {
 169         char ctlfile[MAXPATHLEN];
 170         pid_t pid;
 171         int ctlfd;
 172 
 173         assert(command == PCDSTOP || command == PCRUN);
 174         if ((pid = get_initpid()) == -1) {
 175                 return (-1);
 176         }
 177 
 178         (void) snprintf(ctlfile, sizeof (ctlfile), "/proc/%d/ctl", pid);
 179         if ((ctlfd = open(ctlfile, O_WRONLY)) == -1)
 180                 return (-1);
 181 
 182         if (command == PCDSTOP) {
 183                 if (write(ctlfd, &command, sizeof (long)) == -1) {
 184                         (void) close(ctlfd);
 185                         return (-1);
 186                 }
 187         } else {        /* command == PCRUN */
 188                 long cmds[2];
 189                 cmds[0] = command;
 190                 cmds[1] = 0;
 191                 if (write(ctlfd, cmds, sizeof (cmds)) == -1) {
 192                         (void) close(ctlfd);
 193                         return (-1);
 194                 }
 195         }
 196         (void) close(ctlfd);
 197         return (0);
 198 }
 199 
 200 static void
 201 stop_startd()
 202 {
 203         scf_handle_t *h;
 204         scf_property_t *prop = NULL;
 205         scf_value_t *val = NULL;
 206         uint64_t uint64;
 207 
 208         if ((h = scf_handle_create(SCF_VERSION)) == NULL)
 209                 return;
 210 
 211         if ((scf_handle_bind(h) != 0) ||
 212             ((prop = scf_property_create(h)) == NULL) ||
 213             ((val = scf_value_create(h)) == NULL))
 214                 goto out;
 215 
 216         if (scf_handle_decode_fmri(h, FMRI_STARTD_CONTRACT,
 217             NULL, NULL, NULL, NULL, prop, SCF_DECODE_FMRI_EXACT) != 0)
 218                 goto out;
 219 
 220         if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0 ||
 221             scf_property_get_value(prop, val) != 0 ||
 222             scf_value_get_count(val, &uint64) != 0)
 223                 goto out;
 224 
 225         startdct = (ctid_t)uint64;
 226         (void) sigsend(P_CTID, startdct, SIGSTOP);
 227 
 228 out:
 229         scf_property_destroy(prop);
 230         scf_value_destroy(val);
 231         scf_handle_destroy(h);
 232 }
 233 
 234 static void
 235 continue_startd()
 236 {
 237         if (startdct != -1)
 238                 (void) sigsend(P_CTID, startdct, SIGCONT);
 239 }
 240 
 241 #define FMRI_RESTARTER_PROP "/:properties/general/restarter"
 242 #define FMRI_CONTRACT_PROP "/:properties/restarter/contract"
 243 
 244 static int
 245 save_ctid(ctid_t ctid)
 246 {
 247         ctidlist_t *next;
 248 
 249         for (next = ctidlist; next != NULL; next = next->next)
 250                 if (next->ctid == ctid)
 251                         return (-1);
 252 
 253         next = (ctidlist_t *)malloc(sizeof (ctidlist_t));
 254         if (next == NULL)
 255                 return (-1);
 256 
 257         next->ctid = ctid;
 258         next->next = ctidlist;
 259         ctidlist = next;
 260         return (0);
 261 }
 262 
 263 static void
 264 stop_delegates()
 265 {
 266         ctid_t ctid;
 267         scf_handle_t *h;
 268         scf_scope_t *sc = NULL;
 269         scf_service_t *svc = NULL;
 270         scf_instance_t *inst = NULL;
 271         scf_snapshot_t *snap = NULL;
 272         scf_snapshot_t *isnap = NULL;
 273         scf_propertygroup_t *pg = NULL;
 274         scf_property_t *prop = NULL;
 275         scf_value_t *val = NULL;
 276         scf_iter_t *siter = NULL;
 277         scf_iter_t *iiter = NULL;
 278         char *fmri;
 279         ssize_t length;
 280 
 281         uint64_t uint64;
 282         ssize_t bytes;
 283 
 284         length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
 285         if (length <= 0)
 286                 return;
 287 
 288         length++;
 289         fmri = alloca(length * sizeof (char));
 290 
 291         if ((h = scf_handle_create(SCF_VERSION)) == NULL)
 292                 return;
 293 
 294         if (scf_handle_bind(h) != 0) {
 295                 scf_handle_destroy(h);
 296                 return;
 297         }
 298 
 299         if ((sc = scf_scope_create(h)) == NULL ||
 300             (svc = scf_service_create(h)) == NULL ||
 301             (inst = scf_instance_create(h)) == NULL ||
 302             (snap = scf_snapshot_create(h)) == NULL ||
 303             (pg = scf_pg_create(h)) == NULL ||
 304             (prop = scf_property_create(h)) == NULL ||
 305             (val = scf_value_create(h)) == NULL ||
 306             (siter = scf_iter_create(h)) == NULL ||
 307             (iiter = scf_iter_create(h)) == NULL)
 308                 goto out;
 309 
 310         if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) != 0)
 311                 goto out;
 312 
 313         if (scf_iter_scope_services(siter, sc) != 0)
 314                 goto out;
 315 
 316         while (scf_iter_next_service(siter, svc) == 1) {
 317 
 318                 if (scf_iter_service_instances(iiter, svc) != 0)
 319                         continue;
 320 
 321                 while (scf_iter_next_instance(iiter, inst) == 1) {
 322 
 323                         if ((scf_instance_get_snapshot(inst, "running",
 324                             snap)) != 0)
 325                                 isnap = NULL;
 326                         else
 327                                 isnap = snap;
 328 
 329                         if (scf_instance_get_pg_composed(inst, isnap,
 330                             SCF_PG_GENERAL, pg) != 0)
 331                                 continue;
 332 
 333                         if (scf_pg_get_property(pg, SCF_PROPERTY_RESTARTER,
 334                             prop) != 0 ||
 335                             scf_property_get_value(prop, val) != 0)
 336                                 continue;
 337 
 338                         bytes = scf_value_get_astring(val, fmri, length);
 339                         if (bytes <= 0 || bytes >= length)
 340                                 continue;
 341 
 342                         if (strlcat(fmri, FMRI_CONTRACT_PROP, length) >=
 343                             length)
 344                                 continue;
 345 
 346                         if (scf_handle_decode_fmri(h, fmri, NULL, NULL,
 347                             NULL, NULL, prop, SCF_DECODE_FMRI_EXACT) != 0)
 348                                 continue;
 349 
 350                         if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0 ||
 351                             scf_property_get_value(prop, val) != 0 ||
 352                             scf_value_get_count(val, &uint64) != 0)
 353                                 continue;
 354 
 355                         ctid = (ctid_t)uint64;
 356                         if (save_ctid(ctid) == 0) {
 357                                 (void) sigsend(P_CTID, ctid, SIGSTOP);
 358                         }
 359                 }
 360         }
 361 out:
 362         scf_scope_destroy(sc);
 363         scf_service_destroy(svc);
 364         scf_instance_destroy(inst);
 365         scf_snapshot_destroy(snap);
 366         scf_pg_destroy(pg);
 367         scf_property_destroy(prop);
 368         scf_value_destroy(val);
 369         scf_iter_destroy(siter);
 370         scf_iter_destroy(iiter);
 371 
 372         (void) scf_handle_unbind(h);
 373         scf_handle_destroy(h);
 374 }
 375 
 376 static void
 377 continue_delegates()
 378 {
 379         ctidlist_t *next;
 380         for (next = ctidlist; next != NULL; next = next->next)
 381                 (void) sigsend(P_CTID, next->ctid, SIGCONT);
 382 }
 383 
 384 #define FMRI_GDM "svc:/application/graphical-login/gdm:default"
 385 #define GDM_STOP_TIMEOUT        10      /* Give gdm 10 seconds to shut down */
 386 
 387 /*
 388  * If gdm is running, try to stop gdm.
 389  * Returns  0 on success, -1 on failure.
 390  */
 391 static int
 392 stop_gdm()
 393 {
 394         char *gdm_state = NULL;
 395         int retry = 0;
 396 
 397         /*
 398          * If gdm is running, try to stop gdm.
 399          */
 400         while ((gdm_state = smf_get_state(FMRI_GDM)) != NULL &&
 401             strcmp(gdm_state, SCF_STATE_STRING_ONLINE) == 0 &&
 402             retry++ < GDM_STOP_TIMEOUT) {
 403 
 404                 free(gdm_state);
 405 
 406                 /*
 407                  * Only need to disable once.
 408                  */
 409                 if (retry == 1 &&
 410                     smf_disable_instance(FMRI_GDM, SMF_TEMPORARY) != 0) {
 411                         (void) fprintf(stderr,
 412                             gettext("%s: Failed to stop %s: %s.\n"),
 413                             cmdname, FMRI_GDM, scf_strerror(scf_error()));
 414                         return (-1);
 415                 }
 416                 (void) sleep(1);
 417         }
 418 
 419         if (retry >= GDM_STOP_TIMEOUT) {
 420                 (void) fprintf(stderr, gettext("%s: Failed to stop %s.\n"),
 421                     cmdname, FMRI_GDM);
 422                 return (-1);
 423         }
 424 
 425         return (0);
 426 }
 427 
 428 
 429 static void
 430 stop_restarters()
 431 {
 432         stop_startd();
 433         stop_delegates();
 434 }
 435 
 436 static void
 437 continue_restarters()
 438 {
 439         continue_startd();
 440         continue_delegates();
 441 }
 442 
 443 /*
 444  * Copy an array of strings into buf, separated by spaces.  Returns 0 on
 445  * success.
 446  */
 447 static int
 448 gather_args(char **args, char *buf, size_t buf_sz)
 449 {
 450         if (strlcpy(buf, *args, buf_sz) >= buf_sz)
 451                 return (-1);
 452 
 453         for (++args; *args != NULL; ++args) {
 454                 if (strlcat(buf, " ", buf_sz) >= buf_sz)
 455                         return (-1);
 456                 if (strlcat(buf, *args, buf_sz) >= buf_sz)
 457                         return (-1);
 458         }
 459 
 460         return (0);
 461 }
 462 
 463 /*
 464  * Halt every zone on the system.  We are committed to doing a shutdown
 465  * even if something goes wrong here. If something goes wrong, we just
 466  * continue with the shutdown.  Return non-zero if we need to wait for zones to
 467  * halt later on.
 468  */
 469 static int
 470 halt_zones()
 471 {
 472         pid_t pid;
 473         zoneid_t *zones;
 474         size_t nz = 0, old_nz;
 475         int i;
 476         char zname[ZONENAME_MAX];
 477 
 478         /*
 479          * Get a list of zones. If the number of zones changes in between the
 480          * two zone_list calls, try again.
 481          */
 482 
 483         for (;;) {
 484                 (void) zone_list(NULL, &nz);
 485                 if (nz == 1)
 486                         return (0);
 487                 old_nz = nz;
 488                 zones = calloc(sizeof (zoneid_t), nz);
 489                 if (zones == NULL) {
 490                         (void) fprintf(stderr,
 491                             gettext("%s: Could not halt zones"
 492                             " (out of memory).\n"), cmdname);
 493                         return (0);
 494                 }
 495 
 496                 (void) zone_list(zones, &nz);
 497                 if (old_nz == nz)
 498                         break;
 499                 free(zones);
 500         }
 501 
 502         if (nz == 2) {
 503                 (void) fprintf(stderr, gettext("%s: Halting 1 zone.\n"),
 504                     cmdname);
 505         } else {
 506                 (void) fprintf(stderr, gettext("%s: Halting %i zones.\n"),
 507                     cmdname, nz - 1);
 508         }
 509 
 510         for (i = 0; i < nz; i++) {
 511                 if (zones[i] == GLOBAL_ZONEID)
 512                         continue;
 513                 if (getzonenamebyid(zones[i], zname, sizeof (zname)) < 0) {
 514                         /*
 515                          * getzonenamebyid should only fail if we raced with
 516                          * another process trying to shut down the zone.
 517                          * We assume this happened and ignore the error.
 518                          */
 519                         if (errno != EINVAL) {
 520                                 (void) fprintf(stderr,
 521                                     gettext("%s: Unexpected error while "
 522                                     "looking up zone %ul: %s.\n"),
 523                                     cmdname, zones[i], strerror(errno));
 524                         }
 525 
 526                         continue;
 527                 }
 528                 pid = fork();
 529                 if (pid < 0) {
 530                         (void) fprintf(stderr,
 531                             gettext("%s: Zone \"%s\" could not be"
 532                             " halted (could not fork(): %s).\n"),
 533                             cmdname, zname, strerror(errno));
 534                         continue;
 535                 }
 536                 if (pid == 0) {
 537                         (void) execl(ZONEADM_PROG, ZONEADM_PROG,
 538                             "-z", zname, "halt", NULL);
 539                         (void) fprintf(stderr,
 540                             gettext("%s: Zone \"%s\" could not be halted"
 541                             " (cannot exec(" ZONEADM_PROG "): %s).\n"),
 542                             cmdname, zname, strerror(errno));
 543                         exit(0);
 544                 }
 545         }
 546 
 547         return (1);
 548 }
 549 
 550 /*
 551  * This function tries to wait for all non-global zones to go away.
 552  * It will timeout if no progress is made for 5 seconds, or a total of
 553  * 30 seconds elapses.
 554  */
 555 
 556 static void
 557 check_zones_haltedness()
 558 {
 559         int t = 0, t_prog = 0;
 560         size_t nz = 0, last_nz;
 561 
 562         do {
 563                 last_nz = nz;
 564                 (void) zone_list(NULL, &nz);
 565                 if (nz == 1)
 566                         return;
 567 
 568                 (void) sleep(1);
 569 
 570                 if (last_nz > nz)
 571                         t_prog = 0;
 572 
 573                 t++;
 574                 t_prog++;
 575 
 576                 if (t == 10) {
 577                         if (nz == 2) {
 578                                 (void) fprintf(stderr,
 579                                     gettext("%s: Still waiting for 1 zone to "
 580                                     "halt. Will wait up to 20 seconds.\n"),
 581                                     cmdname);
 582                         } else {
 583                                 (void) fprintf(stderr,
 584                                     gettext("%s: Still waiting for %i zones "
 585                                     "to halt. Will wait up to 20 seconds.\n"),
 586                                     cmdname, nz - 1);
 587                         }
 588                 }
 589 
 590         } while ((t < 30) && (t_prog < 5));
 591 }
 592 
 593 
 594 /*
 595  * Validate that this is a root disk or dataset
 596  * Returns 0 if it is a root disk or dataset;
 597  * returns 1 if it is a disk argument or dataset, but not valid or not root;
 598  * returns -1 if it is not a valid argument or a disk argument.
 599  */
 600 static int
 601 validate_disk(char *arg, char *mountpoint)
 602 {
 603         static char root_dev_path[] = "/dev/dsk";
 604         char kernpath[MAXPATHLEN];
 605         struct stat64 statbuf;
 606         int rc = 0;
 607 
 608         if (strlen(arg) > MAXPATHLEN) {
 609                 (void) fprintf(stderr,
 610                     gettext("%s: Argument is too long\n"), cmdname);
 611                 return (-1);
 612         }
 613 
 614         bcopy(FASTBOOT_MOUNTPOINT, mountpoint, sizeof (FASTBOOT_MOUNTPOINT));
 615 
 616         if (strstr(arg, mountpoint) == NULL) {
 617                 /*
 618                  * Do a force umount just in case some other filesystem has
 619                  * been mounted there.
 620                  */
 621                 (void) umount2(mountpoint, MS_FORCE);
 622         }
 623 
 624         /* Create the directory if it doesn't already exist */
 625         if (lstat64(mountpoint, &statbuf) != 0) {
 626                 if (mkdirp(mountpoint, 0755) != 0) {
 627                         (void) fprintf(stderr,
 628                             gettext("Failed to create mountpoint %s\n"),
 629                             mountpoint);
 630                         return (-1);
 631                 }
 632         }
 633 
 634         if (strncmp(arg, root_dev_path, strlen(root_dev_path)) == 0) {
 635                 /* ufs root disk argument */
 636                 rc = validate_ufs_disk(arg, mountpoint);
 637         } else {
 638                 /* zfs root pool argument */
 639                 rc = validate_zfs_pool(arg, mountpoint);
 640         }
 641 
 642         if (rc != 0)
 643                 return (rc);
 644 
 645         (void) snprintf(kernpath, MAXPATHLEN, "%s/platform/i86pc/kernel/unix",
 646             mountpoint);
 647 
 648         if (stat64(kernpath, &statbuf) != 0) {
 649                 (void) fprintf(stderr,
 650                     gettext("%s: %s is not a root disk or dataset\n"),
 651                     cmdname, arg);
 652                 return (1);
 653         }
 654 
 655         return (0);
 656 }
 657 
 658 
 659 static int
 660 validate_ufs_disk(char *arg, char *mountpoint)
 661 {
 662         struct ufs_args ufs_args = { 0 };
 663         char mntopts[MNT_LINE_MAX] = MNTOPT_LARGEFILES;
 664 
 665         /* perform the mount */
 666         ufs_args.flags = UFSMNT_LARGEFILES;
 667         if (mount(arg, mountpoint, MS_DATA|MS_OPTIONSTR,
 668             MNTTYPE_UFS, &ufs_args, sizeof (ufs_args),
 669             mntopts, sizeof (mntopts)) != 0) {
 670                 perror(cmdname);
 671                 (void) fprintf(stderr,
 672                     gettext("%s: Failed to mount %s\n"), cmdname, arg);
 673                 return (-1);
 674         }
 675 
 676         return (0);
 677 }
 678 
 679 static int
 680 validate_zfs_pool(char *arg, char *mountpoint)
 681 {
 682         zfs_handle_t *zhp = NULL;
 683         char mntopts[MNT_LINE_MAX] = { '\0' };
 684         int rc = 0;
 685 
 686         if ((g_zfs = libzfs_init()) == NULL) {
 687                 (void) fprintf(stderr, gettext("Internal error: failed to "
 688                     "initialize ZFS library\n"));
 689                 return (-1);
 690         }
 691 
 692         /* Try to open the dataset */
 693         if ((zhp = zfs_open(g_zfs, arg,
 694             ZFS_TYPE_FILESYSTEM | ZFS_TYPE_DATASET)) == NULL)
 695                 return (-1);
 696 
 697         /* perform the mount */
 698         if (mount(zfs_get_name(zhp), mountpoint, MS_DATA|MS_OPTIONSTR|MS_RDONLY,
 699             MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
 700                 perror(cmdname);
 701                 (void) fprintf(stderr,
 702                     gettext("%s: Failed to mount %s\n"), cmdname, arg);
 703                 rc = -1;
 704         }
 705 
 706 validate_zfs_err_out:
 707         if (zhp != NULL)
 708                 zfs_close(zhp);
 709 
 710         libzfs_fini(g_zfs);
 711         return (rc);
 712 }
 713 
 714 /*
 715  * Return 0 if not zfs, or is zfs and have successfully constructed the
 716  * boot argument; returns non-zero otherwise.
 717  * At successful completion fpth contains pointer where mount point ends.
 718  * NOTE: arg is supposed to be the resolved path
 719  */
 720 static int
 721 get_zfs_bootfs_arg(const char *arg, const char ** fpth, int *is_zfs,
 722                 char *bootfs_arg)
 723 {
 724         zfs_handle_t *zhp = NULL;
 725         zpool_handle_t *zpoolp = NULL;
 726         FILE *mtabp = NULL;
 727         struct mnttab mnt;
 728         char *poolname = NULL;
 729         char physpath[MAXPATHLEN];
 730         char mntsp[ZPOOL_MAXNAMELEN];
 731         char bootfs[ZPOOL_MAXNAMELEN];
 732         int rc = 0;
 733         size_t mntlen = 0;
 734         size_t msz;
 735         static char fmt[] = "-B zfs-bootfs=%s,bootpath=\"%s\"";
 736 
 737         *fpth = arg;
 738         *is_zfs = 0;
 739 
 740         bzero(physpath, sizeof (physpath));
 741         bzero(bootfs, sizeof (bootfs));
 742 
 743         if ((mtabp = fopen(MNTTAB, "r")) == NULL) {
 744                 return (-1);
 745         }
 746 
 747         while (getmntent(mtabp, &mnt) == 0) {
 748                 if (strstr(arg, mnt.mnt_mountp) == arg &&
 749                     (msz = strlen(mnt.mnt_mountp)) > mntlen) {
 750                         mntlen = msz;
 751                         *is_zfs = strcmp(MNTTYPE_ZFS, mnt.mnt_fstype) == 0;
 752                         (void) strlcpy(mntsp, mnt.mnt_special, sizeof (mntsp));
 753                 }
 754         }
 755 
 756         (void) fclose(mtabp);
 757 
 758         if (mntlen > 1)
 759                 *fpth += mntlen;
 760 
 761         if (!*is_zfs)
 762                 return (0);
 763 
 764         if ((g_zfs = libzfs_init()) == NULL)
 765                 return (-1);
 766 
 767         /* Try to open the dataset */
 768         if ((zhp = zfs_open(g_zfs, mntsp,
 769             ZFS_TYPE_FILESYSTEM | ZFS_TYPE_DATASET)) == NULL) {
 770                 (void) fprintf(stderr, gettext("Cannot open %s\n"), mntsp);
 771                 rc = -1;
 772                 goto validate_zfs_err_out;
 773         }
 774 
 775         (void) strlcpy(bootfs, mntsp, sizeof (bootfs));
 776 
 777         if ((poolname = strtok(mntsp, "/")) == NULL) {
 778                 rc = -1;
 779                 goto validate_zfs_err_out;
 780         }
 781 
 782         if ((zpoolp = zpool_open(g_zfs, poolname)) == NULL) {
 783                 (void) fprintf(stderr, gettext("Cannot open %s\n"), poolname);
 784                 rc = -1;
 785                 goto validate_zfs_err_out;
 786         }
 787 
 788         if (zpool_get_physpath(zpoolp, physpath, sizeof (physpath)) != 0) {
 789                 (void) fprintf(stderr, gettext("Cannot find phys_path\n"));
 790                 rc = -1;
 791                 goto validate_zfs_err_out;
 792         }
 793 
 794         /*
 795          * For the mirror physpath would contain the list of all
 796          * bootable devices, pick up the first one.
 797          */
 798         (void) strtok(physpath, " ");
 799         if (snprintf(bootfs_arg, BOOTARGS_MAX, fmt, bootfs, physpath) >=
 800             BOOTARGS_MAX) {
 801                 rc = E2BIG;
 802                 (void) fprintf(stderr,
 803                     gettext("Boot arguments are too long\n"));
 804         }
 805 
 806 validate_zfs_err_out:
 807         if (zhp != NULL)
 808                 zfs_close(zhp);
 809 
 810         if (zpoolp != NULL)
 811                 zpool_close(zpoolp);
 812 
 813         libzfs_fini(g_zfs);
 814         return (rc);
 815 }
 816 
 817 /*
 818  * Validate that the file exists, and is an ELF file.
 819  * Returns 0 on success, -1 on failure.
 820  */
 821 static int
 822 validate_unix(char *arg, int *mplen, int *is_zfs, char *bootfs_arg)
 823 {
 824         const char *location;
 825         int class, format;
 826         unsigned char ident[EI_NIDENT];
 827         char physpath[MAXPATHLEN];
 828         int elffd = -1;
 829         size_t  sz;
 830 
 831         if ((sz = resolvepath(arg, physpath, sizeof (physpath) - 1)) ==
 832             (size_t)-1) {
 833                 (void) fprintf(stderr,
 834                     gettext("Cannot resolve path for %s: %s\n"),
 835                     arg, strerror(errno));
 836                 return (-1);
 837         }
 838         (void) strlcpy(arg, physpath, sz + 1);
 839 
 840         if (strlen(arg) > MAXPATHLEN) {
 841                 (void) fprintf(stderr,
 842                     gettext("%s: New kernel name is too long\n"), cmdname);
 843                 return (-1);
 844         }
 845 
 846         if (strncmp(basename(arg), "unix", 4) != 0) {
 847                 (void) fprintf(stderr,
 848                     gettext("%s: %s: Kernel name must be unix\n"),
 849                     cmdname, arg);
 850                 return (-1);
 851         }
 852 
 853         if (get_zfs_bootfs_arg(arg, &location, is_zfs, bootfs_arg) != 0)
 854                 goto err_out;
 855 
 856         *mplen = location - arg;
 857 
 858         if (strstr(location, "/boot/platform") == location) {
 859                 /*
 860                  * Rebooting to failsafe.
 861                  * Clear bootfs_arg and is_zfs flag.
 862                  */
 863                 bootfs_arg[0] = 0;
 864                 *is_zfs = 0;
 865         } else if (strstr(location, "/platform") != location) {
 866                 (void) fprintf(stderr,
 867                     gettext("%s: %s: No /platform in file name\n"),
 868                     cmdname, arg);
 869                 goto err_out;
 870         }
 871 
 872         if ((elffd = open64(arg, O_RDONLY)) < 0 ||
 873             (pread64(elffd, ident, EI_NIDENT, 0) != EI_NIDENT)) {
 874                 (void) fprintf(stderr, "%s: %s: %s\n",
 875                     cmdname, arg, strerror(errno));
 876                 goto err_out;
 877         }
 878 
 879         class = ident[EI_CLASS];
 880 
 881         if ((class != ELFCLASS32 && class != ELFCLASS64) ||
 882             memcmp(&ident[EI_MAG0], ELFMAG, 4) != 0) {
 883                 (void) fprintf(stderr,
 884                     gettext("%s: %s: Not a valid ELF file\n"), cmdname, arg);
 885                 goto err_out;
 886         }
 887 
 888         format = ident[EI_DATA];
 889 
 890         if (format != CUR_ELFDATA) {
 891                 (void) fprintf(stderr, gettext("%s: %s: Invalid data format\n"),
 892                     cmdname, arg);
 893                 goto err_out;
 894         }
 895 
 896         return (0);
 897 
 898 err_out:
 899         if (elffd >= 0) {
 900                 (void) close(elffd);
 901                 elffd = -1;
 902         }
 903         return (-1);
 904 }
 905 
 906 static int
 907 halt_exec(const char *path, ...)
 908 {
 909         pid_t           pid;
 910         int             i;
 911         int             st;
 912         const char      *arg;
 913         va_list vp;
 914         const char      *argv[256];
 915 
 916         if ((pid = fork()) == -1) {
 917                 return (errno);
 918         } else if (pid == 0) {
 919                 (void) fclose(stdout);
 920                 (void) fclose(stderr);
 921 
 922                 argv[0] = path;
 923                 i = 1;
 924 
 925                 va_start(vp, path);
 926 
 927                 do {
 928                         arg = va_arg(vp, const char *);
 929                         argv[i] = arg;
 930                 } while (arg != NULL &&
 931                     ++i != sizeof (argv) / sizeof (argv[0]));
 932 
 933                 va_end(vp);
 934 
 935                 (void) execve(path, (char * const *)argv, NULL);
 936                 (void) fprintf(stderr, gettext("Cannot execute %s: %s\n"),
 937                     path, strerror(errno));
 938                 exit(-1);
 939         } else {
 940                 if (waitpid(pid, &st, 0) == pid &&
 941                     !WIFSIGNALED(st) && WIFEXITED(st))
 942                         st = WEXITSTATUS(st);
 943                 else
 944                         st = -1;
 945         }
 946         return (st);
 947 }
 948 
 949 /*
 950  * Mount the specified BE.
 951  *
 952  * Upon success returns zero and copies bename string to mountpoint[]
 953  */
 954 static int
 955 fastboot_bename(const char *bename, char *mountpoint, size_t mpsz)
 956 {
 957         int rc;
 958 
 959         /*
 960          * Attempt to unmount the BE first in case it's already mounted
 961          * elsewhere.
 962          */
 963         (void) halt_exec(BEADM_PROG, "umount", bename, NULL);
 964 
 965         if ((rc = halt_exec(BEADM_PROG, "mount", bename, FASTBOOT_MOUNTPOINT,
 966             NULL)) != 0)
 967                 (void) fprintf(stderr,
 968                     gettext("%s: Unable to mount BE \"%s\" at %s\n"),
 969                     cmdname, bename, FASTBOOT_MOUNTPOINT);
 970         else
 971                 (void) strlcpy(mountpoint, FASTBOOT_MOUNTPOINT, mpsz);
 972 
 973         return (rc);
 974 }
 975 
 976 /*
 977  * Returns 0 on successful parsing of the arguments;
 978  * returns EINVAL on parsing failures that should abort the reboot attempt;
 979  * returns other error code to fall back to regular reboot.
 980  */
 981 static int
 982 parse_fastboot_args(char *bootargs_buf, size_t buf_size,
 983     int *is_dryrun, const char *bename)
 984 {
 985         char mountpoint[MAXPATHLEN];
 986         char bootargs_saved[BOOTARGS_MAX];
 987         char bootargs_scratch[BOOTARGS_MAX];
 988         char bootfs_arg[BOOTARGS_MAX];
 989         char unixfile[BOOTARGS_MAX];
 990         char *head, *newarg;
 991         int buflen;             /* length of the bootargs_buf */
 992         int mplen;              /* length of the mount point */
 993         int rootlen = 0;        /* length of the root argument */
 994         int unixlen = 0;        /* length of the unix argument */
 995         int off = 0;            /* offset into the new boot argument */
 996         int is_zfs = 0;
 997         int rc = 0;
 998 
 999         bzero(mountpoint, sizeof (mountpoint));
1000 
1001         /*
1002          * If argc is not 0, buflen is length of the argument being passed in;
1003          * else it is 0 as bootargs_buf has been initialized to all 0's.
1004          */
1005         buflen = strlen(bootargs_buf);
1006 
1007         /* Save a copy of the original argument */
1008         bcopy(bootargs_buf, bootargs_saved, buflen);
1009         bzero(&bootargs_saved[buflen], sizeof (bootargs_saved) - buflen);
1010 
1011         /* Save another copy to be used by strtok */
1012         bcopy(bootargs_buf, bootargs_scratch, buflen);
1013         bzero(&bootargs_scratch[buflen], sizeof (bootargs_scratch) - buflen);
1014         head = &bootargs_scratch[0];
1015 
1016         /* Get the first argument */
1017         newarg = strtok(bootargs_scratch, " ");
1018 
1019         /*
1020          * If this is a dry run request, verify that the drivers can handle
1021          * fast reboot.
1022          */
1023         if (newarg && strncasecmp(newarg, "dryrun", strlen("dryrun")) == 0) {
1024                 *is_dryrun = 1;
1025                 (void) system("/usr/sbin/devfsadm");
1026         }
1027 
1028         /*
1029          * Always perform a dry run to identify all the drivers that
1030          * need to implement devo_reset().
1031          */
1032         if (uadmin(A_SHUTDOWN, AD_FASTREBOOT_DRYRUN,
1033             (uintptr_t)bootargs_saved) != 0) {
1034                 (void) fprintf(stderr, gettext("%s: Not all drivers "
1035                     "have implemented quiesce(9E)\n"
1036                     "\tPlease see /var/adm/messages for drivers that haven't\n"
1037                     "\timplemented quiesce(9E).\n"), cmdname);
1038         } else if (*is_dryrun) {
1039                 (void) fprintf(stderr, gettext("%s: All drivers have "
1040                     "implemented quiesce(9E)\n"), cmdname);
1041         }
1042 
1043         /* Return if it is a true dry run. */
1044         if (*is_dryrun)
1045                 return (rc);
1046 
1047 #if defined(__i386)
1048         /* Read boot args from GRUB menu */
1049         if ((bootargs_buf[0] == 0 || isdigit(bootargs_buf[0])) &&
1050             bename == NULL) {
1051                 /*
1052                  * If no boot arguments are given, or a GRUB menu entry
1053                  * number is provided, process the GRUB menu.
1054                  */
1055                 int entnum;
1056                 if (bootargs_buf[0] == 0)
1057                         entnum = GRUB_ENTRY_DEFAULT;
1058                 else {
1059                         errno = 0;
1060                         entnum = strtoul(bootargs_buf, NULL, 10);
1061                         rc = errno;
1062                 }
1063 
1064                 if (rc == 0 && (rc = grub_get_boot_args(&fbarg, NULL,
1065                     entnum)) == 0) {
1066                         if (strlcpy(bootargs_buf, fbarg.gba_bootargs,
1067                             buf_size) >= buf_size) {
1068                                 grub_cleanup_boot_args(&fbarg);
1069                                 bcopy(bootargs_saved, bootargs_buf, buf_size);
1070                                 rc = E2BIG;
1071                         }
1072                 }
1073                 /* Failed to read GRUB menu, fall back to normal reboot */
1074                 if (rc != 0) {
1075                         (void) fprintf(stderr,
1076                             gettext("%s: Failed to process GRUB menu "
1077                             "entry for fast reboot.\n\t%s\n"),
1078                             cmdname, grub_strerror(rc));
1079                         (void) fprintf(stderr,
1080                             gettext("%s: Falling back to regular reboot.\n"),
1081                             cmdname);
1082                         return (-1);
1083                 }
1084                 /* No need to process further */
1085                 fbarg_used = &fbarg;
1086                 fbarg_entnum = entnum;
1087                 return (0);
1088         }
1089 #endif  /* __i386 */
1090 
1091         /* Zero out the boot argument buffer as we will reconstruct it */
1092         bzero(bootargs_buf, buf_size);
1093         bzero(bootfs_arg, sizeof (bootfs_arg));
1094         bzero(unixfile, sizeof (unixfile));
1095 
1096         if (bename && (rc = fastboot_bename(bename, mountpoint,
1097             sizeof (mountpoint))) != 0)
1098                 return (EINVAL);
1099 
1100 
1101         /*
1102          * If BE is not specified, look for disk argument to construct
1103          * mountpoint; if BE has been specified, mountpoint has already been
1104          * constructed.
1105          */
1106         if (newarg && newarg[0] != '-' && !bename) {
1107                 int tmprc;
1108 
1109                 if ((tmprc = validate_disk(newarg, mountpoint)) == 0) {
1110                         /*
1111                          * The first argument is a valid root argument.
1112                          * Get the next argument.
1113                          */
1114                         newarg = strtok(NULL, " ");
1115                         rootlen = (newarg) ? (newarg - head) : buflen;
1116                         (void) strlcpy(fastboot_mounted, mountpoint,
1117                             sizeof (fastboot_mounted));
1118 
1119                 } else if (tmprc == -1) {
1120                         /*
1121                          * Not a disk argument.  Use / as default root.
1122                          */
1123                         bcopy("/", mountpoint, 1);
1124                         bzero(&mountpoint[1], sizeof (mountpoint) - 1);
1125                 } else {
1126                         /*
1127                          * Disk argument, but not valid or not root.
1128                          * Return failure.
1129                          */
1130                         return (EINVAL);
1131                 }
1132         }
1133 
1134         /*
1135          * Make mountpoint the first part of unixfile.
1136          * If there is not disk argument, and BE has not been specified,
1137          * mountpoint could be empty.
1138          */
1139         mplen = strlen(mountpoint);
1140         bcopy(mountpoint, unixfile, mplen);
1141 
1142         /*
1143          * Look for unix argument
1144          */
1145         if (newarg && newarg[0] != '-') {
1146                 bcopy(newarg, &unixfile[mplen], strlen(newarg));
1147                 newarg = strtok(NULL, " ");
1148                 rootlen = (newarg) ? (newarg - head) : buflen;
1149         } else if (mplen != 0) {
1150                 /*
1151                  * No unix argument, but mountpoint is not empty, use
1152                  * /platform/i86pc/$ISADIR/kernel/unix as default.
1153                  */
1154                 char isa[20];
1155 
1156                 if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) != -1)
1157                         (void) snprintf(&unixfile[mplen],
1158                             sizeof (unixfile) - mplen,
1159                             "/platform/i86pc/kernel/%s/unix", isa);
1160                 else if (sysinfo(SI_ARCHITECTURE_32, isa, sizeof (isa)) != -1) {
1161                         (void) snprintf(&unixfile[mplen],
1162                             sizeof (unixfile) - mplen,
1163                             "/platform/i86pc/kernel/unix");
1164                 } else {
1165                         (void) fprintf(stderr,
1166                             gettext("%s: Unknown architecture"), cmdname);
1167                         return (EINVAL);
1168                 }
1169         }
1170 
1171         /*
1172          * We now have the complete unix argument.  Verify that it exists and
1173          * is an ELF file.  Split the argument up into mountpoint and unix
1174          * portions again.  This is necessary to handle cases where mountpoint
1175          * is specified on the command line as part of the unix argument,
1176          * such as this:
1177          *      # reboot -f /.alt/platform/i86pc/kernel/amd64/unix
1178          */
1179         unixlen = strlen(unixfile);
1180         if (unixlen > 0) {
1181                 if (validate_unix(unixfile, &mplen, &is_zfs,
1182                     bootfs_arg) != 0) {
1183                         /* Not a valid unix file */
1184                         return (EINVAL);
1185                 } else {
1186                         int space = 0;
1187                         /*
1188                          * Construct boot argument.
1189                          */
1190                         unixlen = strlen(unixfile);
1191 
1192                         /*
1193                          * mdep cannot start with space because bootadm
1194                          * creates bogus menu entries if it does.
1195                          */
1196                         if (mplen > 0) {
1197                                 bcopy(unixfile, bootargs_buf, mplen);
1198                                 (void) strcat(bootargs_buf, " ");
1199                                 space = 1;
1200                         }
1201                         bcopy(&unixfile[mplen], &bootargs_buf[mplen + space],
1202                             unixlen - mplen);
1203                         (void) strcat(bootargs_buf, " ");
1204                         off += unixlen + space + 1;
1205                 }
1206         } else {
1207                 /* Check to see if root is zfs */
1208                 const char      *dp;
1209                 (void) get_zfs_bootfs_arg("/", &dp, &is_zfs, bootfs_arg);
1210         }
1211 
1212         if (is_zfs && (buflen != 0 || bename != NULL))  {
1213                 /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
1214                 off += sprintf(bootargs_buf + off, "%s ", bootfs_arg);
1215         }
1216 
1217         /*
1218          * Copy the rest of the arguments
1219          */
1220         bcopy(&bootargs_saved[rootlen], &bootargs_buf[off], buflen - rootlen);
1221 
1222         return (rc);
1223 }
1224 
1225 #define MAXARGS         5
1226 
1227 static void
1228 do_archives_update(int do_fast_reboot)
1229 {
1230         int     r, i = 0;
1231         pid_t   pid;
1232         char    *cmd_argv[MAXARGS];
1233 
1234 
1235         cmd_argv[i++] = "/sbin/bootadm";
1236         cmd_argv[i++] = "-ea";
1237         cmd_argv[i++] = "update_all";
1238         if (do_fast_reboot)
1239                 cmd_argv[i++] = "fastboot";
1240         cmd_argv[i] = NULL;
1241 
1242         r = posix_spawn(&pid, cmd_argv[0], NULL, NULL, cmd_argv, NULL);
1243 
1244         /* if posix_spawn fails we emit a warning and continue */
1245 
1246         if (r != 0)
1247                 (void) fprintf(stderr, gettext("%s: WARNING, unable to start "
1248                     "boot archive update\n"), cmdname);
1249         else
1250                 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
1251                         ;
1252 }
1253 
1254 int
1255 main(int argc, char *argv[])
1256 {
1257         int qflag = 0, needlog = 1, nosync = 0;
1258         int fast_reboot = 0;
1259         int prom_reboot = 0;
1260         uintptr_t mdep = NULL;
1261         int cmd, fcn, c, aval, r;
1262         const char *usage;
1263         const char *optstring;
1264         zoneid_t zoneid = getzoneid();
1265         int need_check_zones = 0;
1266         char bootargs_buf[BOOTARGS_MAX];
1267         char *bootargs_orig = NULL;
1268         char *bename = NULL;
1269 
1270         const char * const resetting = "/etc/svc/volatile/resetting";
1271 
1272         (void) setlocale(LC_ALL, "");
1273         (void) textdomain(TEXT_DOMAIN);
1274 
1275         cmdname = basename(argv[0]);
1276 
1277         if (strcmp(cmdname, "halt") == 0) {
1278                 (void) audit_halt_setup(argc, argv);
1279                 optstring = "dlnqy";
1280                 usage = gettext("usage: %s [ -dlnqy ]\n");
1281                 cmd = A_SHUTDOWN;
1282                 fcn = AD_HALT;
1283         } else if (strcmp(cmdname, "poweroff") == 0) {
1284                 (void) audit_halt_setup(argc, argv);
1285                 optstring = "dlnqy";
1286                 usage = gettext("usage: %s [ -dlnqy ]\n");
1287                 cmd = A_SHUTDOWN;
1288                 fcn = AD_POWEROFF;
1289         } else if (strcmp(cmdname, "reboot") == 0) {
1290                 (void) audit_reboot_setup();
1291 #if defined(__i386)
1292                 optstring = "dlnqpfe:";
1293                 usage = gettext("usage: %s [ -dlnq(p|fe:) ] [ boot args ]\n");
1294 #else
1295                 optstring = "dlnqfp";
1296                 usage = gettext("usage: %s [ -dlnq(p|f) ] [ boot args ]\n");
1297 #endif
1298                 cmd = A_SHUTDOWN;
1299                 fcn = AD_BOOT;
1300         } else {
1301                 (void) fprintf(stderr,
1302                     gettext("%s: not installed properly\n"), cmdname);
1303                 return (1);
1304         }
1305 
1306         while ((c = getopt(argc, argv, optstring)) != EOF) {
1307                 switch (c) {
1308                 case 'd':
1309                         if (zoneid == GLOBAL_ZONEID)
1310                                 cmd = A_DUMP;
1311                         else {
1312                                 (void) fprintf(stderr,
1313                                     gettext("%s: -d only valid from global"
1314                                     " zone\n"), cmdname);
1315                                 return (1);
1316                         }
1317                         break;
1318                 case 'l':
1319                         needlog = 0;
1320                         break;
1321                 case 'n':
1322                         nosync = 1;
1323                         break;
1324                 case 'q':
1325                         qflag = 1;
1326                         break;
1327                 case 'y':
1328                         /*
1329                          * Option ignored for backwards compatibility.
1330                          */
1331                         break;
1332                 case 'f':
1333                         fast_reboot = 1;
1334                         break;
1335                 case 'p':
1336                         prom_reboot = 1;
1337                         break;
1338 #if defined(__i386)
1339                 case 'e':
1340                         bename = optarg;
1341                         break;
1342 #endif
1343                 default:
1344                         /*
1345                          * TRANSLATION_NOTE
1346                          * Don't translate the words "halt" or "reboot"
1347                          */
1348                         (void) fprintf(stderr, usage, cmdname);
1349                         return (1);
1350                 }
1351         }
1352 
1353         argc -= optind;
1354         argv += optind;
1355 
1356         if (argc != 0) {
1357                 if (fcn != AD_BOOT) {
1358                         (void) fprintf(stderr, usage, cmdname);
1359                         return (1);
1360                 }
1361 
1362                 /* Gather the arguments into bootargs_buf. */
1363                 if (gather_args(argv, bootargs_buf, sizeof (bootargs_buf)) !=
1364                     0) {
1365                         (void) fprintf(stderr,
1366                             gettext("%s: Boot arguments too long.\n"), cmdname);
1367                         return (1);
1368                 }
1369 
1370                 bootargs_orig = strdup(bootargs_buf);
1371                 mdep = (uintptr_t)bootargs_buf;
1372         } else {
1373                 /*
1374                  * Initialize it to 0 in case of fastboot, the buffer
1375                  * will be used.
1376                  */
1377                 bzero(bootargs_buf, sizeof (bootargs_buf));
1378         }
1379 
1380         if (geteuid() != 0) {
1381                 (void) fprintf(stderr,
1382                     gettext("%s: permission denied\n"), cmdname);
1383                 goto fail;
1384         }
1385 
1386         if (fast_reboot && prom_reboot) {
1387                 (void) fprintf(stderr,
1388                     gettext("%s: -p and -f are mutually exclusive\n"),
1389                     cmdname);
1390                 return (EINVAL);
1391         }
1392         /*
1393          * Check whether fast reboot is the default operating mode
1394          */
1395         if (fcn == AD_BOOT && !fast_reboot && !prom_reboot &&
1396             zoneid == GLOBAL_ZONEID) {
1397                 fast_reboot = scf_is_fastboot_default();
1398 
1399         }
1400 
1401         if (bename && !fast_reboot)     {
1402                 (void) fprintf(stderr, gettext("%s: -e only valid with -f\n"),
1403                     cmdname);
1404                 return (EINVAL);
1405         }
1406 
1407 #if defined(__sparc)
1408         if (fast_reboot) {
1409                 fast_reboot = 2;        /* need to distinguish each case */
1410         }
1411 #endif
1412 
1413         /*
1414          * If fast reboot, do some sanity check on the argument
1415          */
1416         if (fast_reboot == 1) {
1417                 int rc;
1418                 int is_dryrun = 0;
1419 
1420                 if (zoneid != GLOBAL_ZONEID)    {
1421                         (void) fprintf(stderr,
1422                             gettext("%s: Fast reboot only valid from global"
1423                             " zone\n"), cmdname);
1424                         return (EINVAL);
1425                 }
1426 
1427                 rc = parse_fastboot_args(bootargs_buf, sizeof (bootargs_buf),
1428                     &is_dryrun, bename);
1429 
1430                 /*
1431                  * If dry run, or if arguments are invalid, return.
1432                  */
1433                 if (is_dryrun)
1434                         return (rc);
1435                 else if (rc == EINVAL)
1436                         goto fail;
1437                 else if (rc != 0)
1438                         fast_reboot = 0;
1439 
1440                 /*
1441                  * For all the other errors, we continue on in case user
1442                  * user want to force fast reboot, or fall back to regular
1443                  * reboot.
1444                  */
1445                 if (strlen(bootargs_buf) != 0)
1446                         mdep = (uintptr_t)bootargs_buf;
1447         }
1448 
1449 #if 0   /* For debugging */
1450         if (mdep != NULL)
1451                 (void) fprintf(stderr, "mdep = %s\n", (char *)mdep);
1452 #endif
1453 
1454         if (needlog) {
1455                 char *user = getlogin();
1456                 struct passwd *pw;
1457                 char *tty;
1458 
1459                 openlog(cmdname, 0, LOG_AUTH);
1460                 if (user == NULL && (pw = getpwuid(getuid())) != NULL)
1461                         user = pw->pw_name;
1462                 if (user == NULL)
1463                         user = "root";
1464 
1465                 tty = ttyname(1);
1466 
1467                 if (tty == NULL)
1468                         syslog(LOG_CRIT, "initiated by %s", user);
1469                 else
1470                         syslog(LOG_CRIT, "initiated by %s on %s", user, tty);
1471         }
1472 
1473         /*
1474          * We must assume success and log it before auditd is terminated.
1475          */
1476         if (fcn == AD_BOOT)
1477                 aval = audit_reboot_success();
1478         else
1479                 aval = audit_halt_success();
1480 
1481         if (aval == -1) {
1482                 (void) fprintf(stderr,
1483                     gettext("%s: can't turn off auditd\n"), cmdname);
1484                 if (needlog)
1485                         (void) sleep(5); /* Give syslogd time to record this */
1486         }
1487 
1488         (void) signal(SIGHUP, SIG_IGN); /* for remote connections */
1489 
1490         /*
1491          * We start to fork a bunch of zoneadms to halt any active zones.
1492          * This will proceed with halt in parallel until we call
1493          * check_zone_haltedness later on.
1494          */
1495         if (zoneid == GLOBAL_ZONEID && cmd != A_DUMP) {
1496                 need_check_zones = halt_zones();
1497         }
1498 
1499 #if defined(__i386)
1500         /* set new default entry in the GRUB entry */
1501         if (fbarg_entnum != GRUB_ENTRY_DEFAULT) {
1502                 char buf[32];
1503                 (void) snprintf(buf, sizeof (buf), "default=%u", fbarg_entnum);
1504                 (void) halt_exec(BOOTADM_PROG, "set-menu", buf, NULL);
1505         }
1506 #endif  /* __i386 */
1507 
1508         /* if we're dumping, do the archive update here and don't defer it */
1509         if (cmd == A_DUMP && zoneid == GLOBAL_ZONEID && !nosync)
1510                 do_archives_update(fast_reboot);
1511 
1512         /*
1513          * If we're not forcing a crash dump, mark the system as quiescing for
1514          * smf(5)'s benefit, and idle the init process.
1515          */
1516         if (cmd != A_DUMP) {
1517                 if (direct_init(PCDSTOP) == -1) {
1518                         /*
1519                          * TRANSLATION_NOTE
1520                          * Don't translate the word "init"
1521                          */
1522                         (void) fprintf(stderr,
1523                             gettext("%s: can't idle init\n"), cmdname);
1524                         goto fail;
1525                 }
1526 
1527                 if (creat(resetting, 0755) == -1)
1528                         (void) fprintf(stderr,
1529                             gettext("%s: could not create %s.\n"),
1530                             cmdname, resetting);
1531         }
1532 
1533         /*
1534          * Make sure we don't get stopped by a jobcontrol shell
1535          * once we start killing everybody.
1536          */
1537         (void) signal(SIGTSTP, SIG_IGN);
1538         (void) signal(SIGTTIN, SIG_IGN);
1539         (void) signal(SIGTTOU, SIG_IGN);
1540         (void) signal(SIGPIPE, SIG_IGN);
1541         (void) signal(SIGTERM, SIG_IGN);
1542 
1543         /*
1544          * Try to stop gdm so X has a chance to return the screen and
1545          * keyboard to a sane state.
1546          */
1547         if (fast_reboot == 1 && stop_gdm() != 0) {
1548                 (void) fprintf(stderr,
1549                     gettext("%s: Falling back to regular reboot.\n"), cmdname);
1550                 fast_reboot = 0;
1551                 mdep = (uintptr_t)bootargs_orig;
1552         } else if (bootargs_orig) {
1553                 free(bootargs_orig);
1554         }
1555 
1556         if (cmd != A_DUMP) {
1557                 /*
1558                  * Stop all restarters so they do not try to restart services
1559                  * that are terminated.
1560                  */
1561                 stop_restarters();
1562 
1563                 /*
1564                  * Wait a little while for zones to shutdown.
1565                  */
1566                 if (need_check_zones) {
1567                         check_zones_haltedness();
1568 
1569                         (void) fprintf(stderr,
1570                             gettext("%s: Completing system halt.\n"),
1571                             cmdname);
1572                 }
1573         }
1574 
1575         /*
1576          * If we're not forcing a crash dump, give everyone 5 seconds to
1577          * handle a SIGTERM and clean up properly.
1578          */
1579         if (cmd != A_DUMP) {
1580                 int     start, end, delta;
1581 
1582                 (void) kill(-1, SIGTERM);
1583                 start = time(NULL);
1584 
1585                 if (zoneid == GLOBAL_ZONEID && !nosync)
1586                         do_archives_update(fast_reboot);
1587 
1588                 end = time(NULL);
1589                 delta = end - start;
1590                 if (delta < 5)
1591                         (void) sleep(5 - delta);
1592         }
1593 
1594         (void) signal(SIGINT, SIG_IGN);
1595 
1596         if (!qflag && !nosync) {
1597                 struct utmpx wtmpx;
1598 
1599                 bzero(&wtmpx, sizeof (struct utmpx));
1600                 (void) strcpy(wtmpx.ut_line, "~");
1601                 (void) time(&wtmpx.ut_tv.tv_sec);
1602 
1603                 if (cmd == A_DUMP)
1604                         (void) strcpy(wtmpx.ut_name, "crash dump");
1605                 else
1606                         (void) strcpy(wtmpx.ut_name, "shutdown");
1607 
1608                 (void) updwtmpx(WTMPX_FILE, &wtmpx);
1609                 sync();
1610         }
1611 
1612         if (cmd == A_DUMP && nosync != 0)
1613                 (void) uadmin(A_DUMP, AD_NOSYNC, NULL);
1614 
1615         if (fast_reboot)
1616                 fcn = AD_FASTREBOOT;
1617 
1618         if (uadmin(cmd, fcn, mdep) == -1)
1619                 (void) fprintf(stderr, "%s: uadmin failed: %s\n",
1620                     cmdname, strerror(errno));
1621         else
1622                 (void) fprintf(stderr, "%s: uadmin unexpectedly returned 0\n",
1623                     cmdname);
1624 
1625         do {
1626                 r = remove(resetting);
1627         } while (r != 0 && errno == EINTR);
1628 
1629         if (r != 0 && errno != ENOENT)
1630                 (void) fprintf(stderr, gettext("%s: could not remove %s.\n"),
1631                     cmdname, resetting);
1632 
1633         if (direct_init(PCRUN) == -1) {
1634                 /*
1635                  * TRANSLATION_NOTE
1636                  * Don't translate the word "init"
1637                  */
1638                 (void) fprintf(stderr,
1639                     gettext("%s: can't resume init\n"), cmdname);
1640         }
1641 
1642         continue_restarters();
1643 
1644         if (get_initpid() != -1)
1645                 /* tell init to restate current level */
1646                 (void) kill(get_initpid(), SIGHUP);
1647 
1648 fail:
1649         if (fcn == AD_BOOT)
1650                 (void) audit_reboot_fail();
1651         else
1652                 (void) audit_halt_fail();
1653 
1654         if (fast_reboot == 1) {
1655                 if (bename) {
1656                         (void) halt_exec(BEADM_PROG, "umount", bename, NULL);
1657 
1658                 } else if (strlen(fastboot_mounted) != 0) {
1659                         (void) umount(fastboot_mounted);
1660 #if defined(__i386)
1661                 } else if (fbarg_used != NULL) {
1662                         grub_cleanup_boot_args(fbarg_used);
1663 #endif  /* __i386 */
1664                 }
1665         }
1666 
1667         return (1);
1668 }