Print this page
botadm patch


   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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2012 Milan Jurik. All rights reserved.

  24  */
  25 
  26 /*
  27  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  28  */
  29 
  30 /*
  31  * bootadm(1M) is a new utility for managing bootability of
  32  * Solaris *Newboot* environments. It has two primary tasks:
  33  *      - Allow end users to manage bootability of Newboot Solaris instances
  34  *      - Provide services to other subsystems in Solaris (primarily Install)
  35  */
  36 
  37 /* Headers */
  38 #include <stdio.h>
  39 #include <errno.h>
  40 #include <stdlib.h>
  41 #include <string.h>
  42 #include <unistd.h>
  43 #include <sys/types.h>


 101 
 102 typedef enum {
 103     OPT_ABSENT = 0,     /* No option */
 104     OPT_REQ,            /* option required */
 105     OPT_OPTIONAL        /* option may or may not be present */
 106 } option_t;
 107 
 108 typedef struct {
 109         char    *subcmd;
 110         option_t option;
 111         error_t (*handler)();
 112         int     unpriv;                 /* is this an unprivileged command */
 113 } subcmd_defn_t;
 114 
 115 #define LINE_INIT       0       /* lineNum initial value */
 116 #define ENTRY_INIT      -1      /* entryNum initial value */
 117 #define ALL_ENTRIES     -2      /* selects all boot entries */
 118 
 119 #define GRUB_DIR                "/boot/grub"
 120 #define GRUB_STAGE2             GRUB_DIR "/stage2"
 121 #define GRUB_MENU               "/boot/grub/menu.lst"
 122 #define MENU_TMP                "/boot/grub/menu.lst.tmp"
 123 #define GRUB_BACKUP_MENU        "/etc/lu/GRUB_backup_menu"
 124 #define RAMDISK_SPECIAL         "/ramdisk"
 125 #define STUBBOOT                "/stubboot"
 126 #define MULTIBOOT               "/platform/i86pc/multiboot"
 127 #define GRUBSIGN_DIR            "/boot/grub/bootsign"
 128 #define GRUBSIGN_BACKUP         "/etc/bootsign"
 129 #define GRUBSIGN_UFS_PREFIX     "rootfs"
 130 #define GRUBSIGN_ZFS_PREFIX     "pool_"
 131 #define GRUBSIGN_LU_PREFIX      "BE_"
 132 #define UFS_SIGNATURE_LIST      "/var/run/grub_ufs_signatures"
 133 #define ZFS_LEGACY_MNTPT        "/tmp/bootadm_mnt_zfs_legacy"
 134 
 135 #define BOOTADM_RDONLY_TEST     "BOOTADM_RDONLY_TEST"
 136 
 137 /* lock related */
 138 #define BAM_LOCK_FILE           "/var/run/bootadm.lock"
 139 #define LOCK_FILE_PERMS         (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
 140 
 141 #define CREATE_RAMDISK          "boot/solaris/bin/create_ramdisk"
 142 #define CREATE_DISKMAP          "boot/solaris/bin/create_diskmap"


 161 typedef enum zfs_mnted {
 162         ZFS_MNT_ERROR = -1,
 163         LEGACY_MOUNTED = 1,
 164         LEGACY_ALREADY,
 165         ZFS_MOUNTED,
 166         ZFS_ALREADY
 167 } zfs_mnted_t;
 168 
 169 /*
 170  * Default file attributes
 171  */
 172 #define DEFAULT_DEV_MODE        0644    /* default permissions */
 173 #define DEFAULT_DEV_UID         0       /* user root */
 174 #define DEFAULT_DEV_GID         3       /* group sys */
 175 
 176 /*
 177  * Menu related
 178  * menu_cmd_t and menu_cmds must be kept in sync
 179  */
 180 char *menu_cmds[] = {
 181         "default",      /* DEFAULT_CMD */
 182         "timeout",      /* TIMEOUT_CMD */
 183         "title",        /* TITLE_CMD */
 184         "root",         /* ROOT_CMD */
 185         "kernel",       /* KERNEL_CMD */
 186         "kernel$",      /* KERNEL_DOLLAR_CMD */
 187         "module",       /* MODULE_CMD */
 188         "module$",      /* MODULE_DOLLAR_CMD */
 189         " ",            /* SEP_CMD */
 190         "#",            /* COMMENT_CMD */
 191         "chainloader",  /* CHAINLOADER_CMD */
 192         "args",         /* ARGS_CMD */
 193         "findroot",     /* FINDROOT_CMD */
 194         "bootfs",       /* BOOTFS_CMD */

 195         NULL
 196 };
 197 
 198 #define OPT_ENTRY_NUM   "entry"
 199 
 200 /*
 201  * exec_cmd related
 202  */
 203 typedef struct {
 204         line_t *head;
 205         line_t *tail;
 206 } filelist_t;
 207 
 208 #define BOOT_FILE_LIST  "boot/solaris/filelist.ramdisk"
 209 #define ETC_FILE_LIST   "etc/boot/solaris/filelist.ramdisk"
 210 
 211 #define FILE_STAT       "boot/solaris/filestat.ramdisk"
 212 #define FILE_STAT_TMP   "boot/solaris/filestat.ramdisk.tmp"
 213 #define DIR_PERMS       (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
 214 #define FILE_STAT_MODE  (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)


4673         }
4674 
4675         return (BAM_SUCCESS);
4676 }
4677 
4678 int
4679 add_boot_entry(menu_t *mp,
4680         char *title,
4681         char *findroot,
4682         char *kernel,
4683         char *mod_kernel,
4684         char *module,
4685         char *bootfs)
4686 {
4687         int             lineNum;
4688         int             entryNum;
4689         char            linebuf[BAM_MAXLINE];
4690         menu_cmd_t      k_cmd;
4691         menu_cmd_t      m_cmd;
4692         const char      *fcn = "add_boot_entry()";

4693 
4694         assert(mp);
4695 
4696         INJECT_ERROR1("ADD_BOOT_ENTRY_FINDROOT_NULL", findroot = NULL);
4697         if (findroot == NULL) {
4698                 bam_error(NULL_FINDROOT);
4699                 return (BAM_ERROR);
4700         }
4701 
4702         if (title == NULL) {
4703                 title = "Solaris";      /* default to Solaris */
4704         }
4705         if (kernel == NULL) {
4706                 bam_error(SUBOPT_MISS, menu_cmds[KERNEL_CMD]);
4707                 return (BAM_ERROR);
4708         }
4709         if (module == NULL) {
4710                 if (bam_direct != BAM_DIRECT_DBOOT) {
4711                         bam_error(SUBOPT_MISS, menu_cmds[MODULE_CMD]);
4712                         return (BAM_ERROR);


4739          */
4740         (void) snprintf(linebuf, sizeof (linebuf), "%s%s",
4741             menu_cmds[COMMENT_CMD], BAM_BOOTADM_HDR);
4742         line_parser(mp, linebuf, &lineNum, &entryNum);
4743 
4744         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
4745             menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title);
4746         line_parser(mp, linebuf, &lineNum, &entryNum);
4747 
4748         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
4749             menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot);
4750         line_parser(mp, linebuf, &lineNum, &entryNum);
4751         BAM_DPRINTF((D_ADD_FINDROOT_NUM, fcn, lineNum, entryNum));
4752 
4753         if (bootfs != NULL) {
4754                 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
4755                     menu_cmds[BOOTFS_CMD], menu_cmds[SEP_CMD], bootfs);
4756                 line_parser(mp, linebuf, &lineNum, &entryNum);
4757         }
4758 










4759         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
4760             menu_cmds[k_cmd], menu_cmds[SEP_CMD], kernel);
4761         line_parser(mp, linebuf, &lineNum, &entryNum);

4762 
4763         if (mod_kernel != NULL) {
4764                 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
4765                     menu_cmds[m_cmd], menu_cmds[SEP_CMD], mod_kernel);
4766                 line_parser(mp, linebuf, &lineNum, &entryNum);
4767         }
4768 
4769         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
4770             menu_cmds[m_cmd], menu_cmds[SEP_CMD], module);
4771         line_parser(mp, linebuf, &lineNum, &entryNum);
4772 
4773         (void) snprintf(linebuf, sizeof (linebuf), "%s%s",
4774             menu_cmds[COMMENT_CMD], BAM_BOOTADM_FTR);
4775         line_parser(mp, linebuf, &lineNum, &entryNum);
4776 
4777         return (entryNum);
4778 }
4779 
4780 error_t
4781 delete_boot_entry(menu_t *mp, int entryNum, int quiet)


7095                 (void) unlink(UFS_SIGNATURE_LIST);
7096                 return (NULL);
7097         }
7098 
7099         free(fstype);
7100 
7101         if (bam_verbose)
7102                 bam_print(GRUBSIGN_FOUND_OR_CREATED, sign, osdev);
7103 
7104         fdiskpart = get_partition(osdev);
7105         INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart = -1);
7106         if (fdiskpart == -1) {
7107                 bam_error(FDISKPART_FAIL, osdev);
7108                 free(sign);
7109                 return (NULL);
7110         }
7111 
7112         slice = strrchr(osdev, 's');
7113 
7114         grubsign = s_calloc(1, MAXNAMELEN + 10);
7115         if (slice) {
7116                 (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d,%c)",
7117                     sign, fdiskpart, slice[1] + 'a' - '0');
7118         } else
7119                 (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d)",
7120                     sign, fdiskpart);

7121 
7122         free(sign);
7123 
7124         BAM_DPRINTF((D_GET_GRUBSIGN_SUCCESS, fcn, grubsign));
7125 
7126         return (grubsign);
7127 }
7128 
7129 static char *
7130 get_title(char *rootdir)
7131 {
7132         static char     title[80];
7133         char            *cp = NULL;
7134         char            release[PATH_MAX];
7135         FILE            *fp;
7136         const char      *fcn = "get_title()";
7137 
7138         /* open the /etc/release file */
7139         (void) snprintf(release, sizeof (release), "%s/etc/release", rootdir);
7140 
7141         fp = fopen(release, "r");
7142         if (fp == NULL) {
7143                 bam_error(OPEN_FAIL, release, strerror(errno));
7144                 cp = NULL;
7145                 goto out;
7146         }


7795                                 BAM_DPRINTF((D_MATCHED_TITLE, fcn, title));
7796                                 break;
7797                         }
7798                         BAM_DPRINTF((D_NOMATCH_TITLE, fcn, title, lp->arg));
7799                         continue;       /* check title only */
7800                 }
7801 
7802                 lp = lp->next;       /* advance to root line */
7803                 if (lp == NULL) {
7804                         continue;
7805                 } else if (lp->cmd != NULL &&
7806                     strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) == 0) {
7807                         INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_FINDROOT",
7808                             findroot = NULL);
7809                         if (findroot == NULL) {
7810                                 BAM_DPRINTF((D_NOMATCH_FINDROOT_NULL,
7811                                     fcn, lp->arg));
7812                                 continue;
7813                         }
7814                         /* findroot command found, try match  */
7815                         if (strcmp(lp->arg, findroot) != 0) {
7816                                 BAM_DPRINTF((D_NOMATCH_FINDROOT,
7817                                     fcn, findroot, lp->arg));
7818                                 continue;
7819                         }
7820                         BAM_DPRINTF((D_MATCHED_FINDROOT, fcn, findroot));
7821                         lp = lp->next;       /* advance to kernel line */
7822                 } else if (lp->cmd != NULL &&
7823                     strcmp(lp->cmd, menu_cmds[ROOT_CMD]) == 0) {
7824                         INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_ROOT", root = NULL);
7825                         if (root == NULL) {
7826                                 BAM_DPRINTF((D_NOMATCH_ROOT_NULL,
7827                                     fcn, lp->arg));
7828                                 continue;
7829                         }
7830                         /* root cmd found, try match */
7831                         if (strcmp(lp->arg, root) != 0) {
7832                                 BAM_DPRINTF((D_NOMATCH_ROOT,
7833                                     fcn, root, lp->arg));
7834                                 continue;
7835                         }


7853                 }
7854 
7855                 if (kernel &&
7856                     (!check_cmd(lp->cmd, KERNEL_CMD, lp->arg, kernel))) {
7857                         if (!(ent->flags & BAM_ENTRY_FAILSAFE) ||
7858                             !(ent->flags & BAM_ENTRY_DBOOT) ||
7859                             strcmp(kernel, DIRECT_BOOT_FAILSAFE_LINE) != 0)
7860                                 continue;
7861 
7862                         ent->flags |= BAM_ENTRY_UPGFSKERNEL;
7863 
7864                 }
7865                 BAM_DPRINTF((D_KERNEL_MATCH, fcn, kernel, lp->arg));
7866 
7867                 /*
7868                  * Check for matching module entry (failsafe or normal).
7869                  * If it fails to match, we go around the loop again.
7870                  * For xpv entries, there are two module lines, so we
7871                  * do the check twice.
7872                  */

7873                 lp = lp->next;       /* advance to module line */
7874                 if (check_cmd(lp->cmd, MODULE_CMD, lp->arg, module) ||
7875                     (((lp = lp->next) != NULL) &&
7876                     check_cmd(lp->cmd, MODULE_CMD, lp->arg, module))) {
7877                         /* match found */
7878                         BAM_DPRINTF((D_MODULE_MATCH, fcn, module, lp->arg));
7879                         break;
7880                 }
7881 
7882                 if (strcmp(module, FAILSAFE_ARCHIVE) == 0 &&
7883                     (strcmp(lp->prev->arg, FAILSAFE_ARCHIVE_32) == 0 ||
7884                     strcmp(lp->prev->arg, FAILSAFE_ARCHIVE_64) == 0)) {
7885                         ent->flags |= BAM_ENTRY_UPGFSMODULE;
7886                         break;
7887                 }
7888 
7889         }
7890 
7891         if (ent && entry_num) {
7892                 *entry_num = i;


7894 
7895         if (ent) {
7896                 BAM_DPRINTF((D_RETURN_RET, fcn, i));
7897         } else {
7898                 BAM_DPRINTF((D_RETURN_RET, fcn, BAM_ERROR));
7899         }
7900         return (ent);
7901 }
7902 
7903 static int
7904 update_boot_entry(menu_t *mp, char *title, char *findroot, char *root,
7905     char *kernel, char *mod_kernel, char *module, int root_opt)
7906 {
7907         int             i;
7908         int             change_kernel = 0;
7909         entry_t         *ent;
7910         line_t          *lp;
7911         line_t          *tlp;
7912         char            linebuf[BAM_MAXLINE];
7913         const char      *fcn = "update_boot_entry()";

7914 
7915         /* note: don't match on title, it's updated on upgrade */
7916         ent = find_boot_entry(mp, NULL, kernel, findroot, root, module,
7917             root_opt, &i);
7918         if ((ent == NULL) && (bam_direct == BAM_DIRECT_DBOOT)) {
7919                 /*
7920                  * We may be upgrading a kernel from multiboot to
7921                  * directboot.  Look for a multiboot entry. A multiboot
7922                  * entry will not have a findroot line.
7923                  */
7924                 ent = find_boot_entry(mp, NULL, "multiboot", NULL, root,
7925                     MULTIBOOT_ARCHIVE, root_opt, &i);
7926                 if (ent != NULL) {
7927                         BAM_DPRINTF((D_UPGRADE_FROM_MULTIBOOT, fcn, root));
7928                         change_kernel = 1;
7929                 }
7930         } else if (ent) {
7931                 BAM_DPRINTF((D_FOUND_FINDROOT, fcn, findroot));
7932         }
7933 


7950 
7951         tlp = lp;       /* title line */
7952         lp = lp->next;       /* root line */
7953 
7954         /* if no root or findroot command, create a new line_t */
7955         if ((lp->cmd != NULL) && (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) != 0 &&
7956             strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) != 0)) {
7957                 lp = s_calloc(1, sizeof (line_t));
7958                 bam_add_line(mp, ent, tlp, lp);
7959         } else {
7960                 if (lp->cmd != NULL)
7961                         free(lp->cmd);
7962 
7963                 free(lp->sep);
7964                 free(lp->arg);
7965                 free(lp->line);
7966         }
7967 
7968         lp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]);
7969         lp->sep = s_strdup(menu_cmds[SEP_CMD]);
7970         lp->arg = s_strdup(findroot);


7971         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
7972             menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot);
7973         lp->line = s_strdup(linebuf);

7974         BAM_DPRINTF((D_ADDING_FINDROOT_LINE, fcn, findroot));
7975 
7976         /* kernel line */
7977         lp = lp->next;
7978 
7979         if (ent->flags & BAM_ENTRY_UPGFSKERNEL) {
7980                 char            *params = NULL;

7981 
7982                 params = strstr(lp->line, "-s");
7983                 if (params != NULL)
7984                         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s%s",
7985                             menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD],
7986                             kernel, params+2);
7987                 else
7988                         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
7989                             menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD],
7990                             kernel);
7991 
7992                 if (lp->cmd != NULL)
7993                         free(lp->cmd);
7994 
7995                 free(lp->arg);
7996                 free(lp->line);
7997                 lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]);
7998                 lp->arg = s_strdup(strstr(linebuf, "/"));
7999                 lp->line = s_strdup(linebuf);
8000                 ent->flags &= ~BAM_ENTRY_UPGFSKERNEL;
8001                 BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, lp->prev->cmd));













8002         }
8003 
8004         if (change_kernel) {

8005                 /*
8006                  * We're upgrading from multiboot to directboot.
8007                  */


8008                 if (lp->cmd != NULL &&
8009                     strcmp(lp->cmd, menu_cmds[KERNEL_CMD]) == 0) {
8010                         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
8011                             menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD],
8012                             kernel);
8013                         free(lp->cmd);
8014                         free(lp->arg);
8015                         free(lp->line);
8016                         lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]);
8017                         lp->arg = s_strdup(kernel);
8018                         lp->line = s_strdup(linebuf);
8019                         lp = lp->next;
8020                         BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, kernel));






8021                 }
8022                 if (lp->cmd != NULL &&
8023                     strcmp(lp->cmd, menu_cmds[MODULE_CMD]) == 0) {
8024                         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
8025                             menu_cmds[MODULE_DOLLAR_CMD], menu_cmds[SEP_CMD],
8026                             module);
8027                         free(lp->cmd);
8028                         free(lp->arg);
8029                         free(lp->line);
8030                         lp->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]);
8031                         lp->arg = s_strdup(module);
8032                         lp->line = s_strdup(linebuf);
8033                         lp = lp->next;
8034                         BAM_DPRINTF((D_ADDING_MODULE_DOLLAR, fcn, module));
8035                 }
8036         }
8037 
8038         /* module line */
8039         lp = lp->next;
8040 


8393         /*
8394          * add a new menu entry based on opt and make it the default
8395          */
8396 
8397         fstype = get_fstype("/");
8398         INJECT_ERROR1("REBOOT_FSTYPE_NULL", fstype = NULL);
8399         if (fstype == NULL) {
8400                 bam_error(REBOOT_FSTYPE_FAILED);
8401                 return (BAM_ERROR);
8402         }
8403 
8404         osdev = get_special("/");
8405         INJECT_ERROR1("REBOOT_SPECIAL_NULL", osdev = NULL);
8406         if (osdev == NULL) {
8407                 free(fstype);
8408                 bam_error(REBOOT_SPECIAL_FAILED);
8409                 return (BAM_ERROR);
8410         }
8411 
8412         sign = find_existing_sign("/", osdev, fstype);

8413         INJECT_ERROR1("REBOOT_SIGN_NULL", sign = NULL);
8414         if (sign == NULL) {
8415                 free(fstype);
8416                 free(osdev);
8417                 bam_error(REBOOT_SIGN_FAILED);
8418                 return (BAM_ERROR);
8419         }
8420 
8421         free(osdev);
8422         (void) strlcpy(signbuf, sign, sizeof (signbuf));
8423         free(sign);
8424 
8425         assert(strchr(signbuf, '(') == NULL && strchr(signbuf, ',') == NULL &&
8426             strchr(signbuf, ')') == NULL);
8427 
8428         /*
8429          * There is no alternate root while doing reboot with args
8430          * This version of bootadm is only delivered with a DBOOT
8431          * version of Solaris.
8432          */


8841         if (mp->curdefault) {
8842                 entryNum = s_strtol(mp->curdefault->arg);
8843                 for (entryp = mp->entries; entryp; entryp = entryp->next) {
8844                         if (entryp->entryNum == entryNum)
8845                                 break;
8846                 }
8847                 if ((entryp != NULL) &&
8848                     ((entryp->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) == 0)) {
8849                         bam_error(DEFAULT_NOT_BAM);
8850                         return (BAM_ERROR);
8851                 }
8852         }
8853 
8854         entryp = find_boot_entry(mp, BOOTENV_RC_TITLE, NULL, NULL, NULL, NULL,
8855             0, &entryNum);
8856 
8857         if (entryp != NULL) {
8858                 for (ptr = entryp->start; ptr && ptr != entryp->end;
8859                     ptr = ptr->next) {
8860                         if (strncmp(ptr->cmd, menu_cmds[KERNEL_CMD],
8861                             sizeof (menu_cmds[KERNEL_CMD]) - 1) == 0) {
8862                                 kernelp = ptr;
8863                                 break;
8864                         }
8865                 }
8866                 if (kernelp == NULL) {
8867                         bam_error(NO_KERNEL, entryNum);
8868                         return (BAM_ERROR);
8869                 }
8870 
8871                 old_kernel_len = strcspn(kernelp->arg, " \t");
8872                 space = old_args = kernelp->arg + old_kernel_len;
8873                 while ((*old_args == ' ') || (*old_args == '\t'))
8874                         old_args++;
8875         }
8876 
8877         if (path == NULL) {
8878                 if (entryp == NULL) {
8879                         BAM_DPRINTF((D_GET_SET_KERNEL_NO_RC, fcn));
8880                         BAM_DPRINTF((D_RETURN_SUCCESS, fcn));
8881                         return (BAM_SUCCESS);


8929                     sizeof (DIRECT_BOOT_KERNEL) - 1) == 0))) {
8930                         kernelp = NULL;
8931                         (void) delete_boot_entry(mp, entryNum, DBE_PRINTERR);
8932                         restore_default_entry(mp, BAM_OLD_RC_DEF,
8933                             mp->old_rc_default);
8934                         mp->old_rc_default = NULL;
8935                         rv = BAM_WRITE;
8936                         BAM_DPRINTF((D_GET_SET_KERNEL_RESTORE_DEFAULT, fcn));
8937                         goto done;
8938                 }
8939 
8940                 if (optnum == KERNEL_CMD) {
8941                         /*
8942                          * At this point, we've already checked that old_args
8943                          * and entryp are valid pointers.  The "+ 2" is for
8944                          * a space a the string termination character.
8945                          */
8946                         new_str_len = (sizeof (DIRECT_BOOT_KERNEL) - 1) +
8947                             strlen(old_args) + 2;
8948                         new_arg = s_calloc(1, new_str_len);
8949                         (void) snprintf(new_arg, new_str_len, "%s %s",
8950                             DIRECT_BOOT_KERNEL, old_args);
8951                         free(kernelp->arg);
8952                         kernelp->arg = new_arg;
8953 
8954                         /*
8955                          * We have changed the kernel line, so we may need
8956                          * to update the archive line as well.
8957                          */
8958                         set_archive_line(entryp, kernelp);
8959                         BAM_DPRINTF((D_GET_SET_KERNEL_RESET_KERNEL_SET_ARG,
8960                             fcn, kernelp->arg));
8961                 } else {
8962                         /*
8963                          * We're resetting the boot args to nothing, so
8964                          * we only need to copy the kernel.  We've already
8965                          * checked that the kernel is not the default.
8966                          */
8967                         new_arg = s_calloc(1, old_kernel_len + 1);
8968                         (void) snprintf(new_arg, old_kernel_len + 1, "%s",
8969                             kernelp->arg);
8970                         free(kernelp->arg);


9091 
9092         /*
9093          * There was already an bootenv entry which we need to edit.
9094          */
9095         if (optnum == KERNEL_CMD) {
9096                 new_str_len = strlen(new_path) + strlen(old_args) + 2;
9097                 new_arg = s_calloc(1, new_str_len);
9098                 (void) snprintf(new_arg, new_str_len, "%s %s", new_path,
9099                     old_args);
9100                 free(kernelp->arg);
9101                 kernelp->arg = new_arg;
9102 
9103                 /*
9104                  * If we have changed the kernel line, we may need to update
9105                  * the archive line as well.
9106                  */
9107                 set_archive_line(entryp, kernelp);
9108                 BAM_DPRINTF((D_GET_SET_KERNEL_REPLACED_KERNEL_SAME_ARG, fcn,
9109                     kernelp->arg));
9110         } else {
9111                 new_str_len = old_kernel_len + strlen(path) + 8;

9112                 new_arg = s_calloc(1, new_str_len);
9113                 (void) strncpy(new_arg, kernelp->arg, old_kernel_len);
9114                 (void) strlcat(new_arg, " ", new_str_len);
9115                 (void) strlcat(new_arg, path, new_str_len);
9116                 free(kernelp->arg);
9117                 kernelp->arg = new_arg;
9118                 BAM_DPRINTF((D_GET_SET_KERNEL_SAME_KERNEL_REPLACED_ARG, fcn,
9119                     kernelp->arg));
9120         }
9121         rv = BAM_WRITE;
9122 
9123 done:
9124         if ((rv == BAM_WRITE) && kernelp)
9125                 update_line(kernelp);
9126         if (free_new_path)
9127                 free(new_path);
9128         if (rv == BAM_WRITE) {
9129                 BAM_DPRINTF((D_RETURN_SUCCESS, fcn));
9130         } else {
9131                 BAM_DPRINTF((D_RETURN_FAILURE, fcn));
9132         }
9133         return (rv);




   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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2012 Milan Jurik. All rights reserved.
  24  * Copyright 2012 Daniil Lunev. All rights reserved.
  25  */
  26 
  27 /*
  28  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  29  */
  30 
  31 /*
  32  * bootadm(1M) is a new utility for managing bootability of
  33  * Solaris *Newboot* environments. It has two primary tasks:
  34  *      - Allow end users to manage bootability of Newboot Solaris instances
  35  *      - Provide services to other subsystems in Solaris (primarily Install)
  36  */
  37 
  38 /* Headers */
  39 #include <stdio.h>
  40 #include <errno.h>
  41 #include <stdlib.h>
  42 #include <string.h>
  43 #include <unistd.h>
  44 #include <sys/types.h>


 102 
 103 typedef enum {
 104     OPT_ABSENT = 0,     /* No option */
 105     OPT_REQ,            /* option required */
 106     OPT_OPTIONAL        /* option may or may not be present */
 107 } option_t;
 108 
 109 typedef struct {
 110         char    *subcmd;
 111         option_t option;
 112         error_t (*handler)();
 113         int     unpriv;                 /* is this an unprivileged command */
 114 } subcmd_defn_t;
 115 
 116 #define LINE_INIT       0       /* lineNum initial value */
 117 #define ENTRY_INIT      -1      /* entryNum initial value */
 118 #define ALL_ENTRIES     -2      /* selects all boot entries */
 119 
 120 #define GRUB_DIR                "/boot/grub"
 121 #define GRUB_STAGE2             GRUB_DIR "/stage2"
 122 #define GRUB_MENU               "/boot/illumos.cfg"
 123 #define MENU_TMP                "/boot/illumos.cfg.tmp"
 124 #define GRUB_BACKUP_MENU        "/etc/lu/GRUB_backup_menu"
 125 #define RAMDISK_SPECIAL         "/ramdisk"
 126 #define STUBBOOT                "/stubboot"
 127 #define MULTIBOOT               "/platform/i86pc/multiboot"
 128 #define GRUBSIGN_DIR            "/boot/grub/bootsign"
 129 #define GRUBSIGN_BACKUP         "/etc/bootsign"
 130 #define GRUBSIGN_UFS_PREFIX     "rootfs"
 131 #define GRUBSIGN_ZFS_PREFIX     "pool_"
 132 #define GRUBSIGN_LU_PREFIX      "BE_"
 133 #define UFS_SIGNATURE_LIST      "/var/run/grub_ufs_signatures"
 134 #define ZFS_LEGACY_MNTPT        "/tmp/bootadm_mnt_zfs_legacy"
 135 
 136 #define BOOTADM_RDONLY_TEST     "BOOTADM_RDONLY_TEST"
 137 
 138 /* lock related */
 139 #define BAM_LOCK_FILE           "/var/run/bootadm.lock"
 140 #define LOCK_FILE_PERMS         (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
 141 
 142 #define CREATE_RAMDISK          "boot/solaris/bin/create_ramdisk"
 143 #define CREATE_DISKMAP          "boot/solaris/bin/create_diskmap"


 162 typedef enum zfs_mnted {
 163         ZFS_MNT_ERROR = -1,
 164         LEGACY_MOUNTED = 1,
 165         LEGACY_ALREADY,
 166         ZFS_MOUNTED,
 167         ZFS_ALREADY
 168 } zfs_mnted_t;
 169 
 170 /*
 171  * Default file attributes
 172  */
 173 #define DEFAULT_DEV_MODE        0644    /* default permissions */
 174 #define DEFAULT_DEV_UID         0       /* user root */
 175 #define DEFAULT_DEV_GID         3       /* group sys */
 176 
 177 /*
 178  * Menu related
 179  * menu_cmd_t and menu_cmds must be kept in sync
 180  */
 181 char *menu_cmds[] = {
 182         "default_entry",/* DEFAULT_CMD */
 183         "timeout",      /* TIMEOUT_CMD */
 184         "entry_name",   /* TITLE_CMD */
 185         "pool_uuid",    /* ROOT_CMD */
 186         "kernel_path$", /* KERNEL_CMD */
 187         "kernel_path",  /* KERNEL_DOLLAR_CMD */
 188         "module$",      /* MODULE_CMD */
 189         "module",       /* MODULE_DOLLAR_CMD */
 190         "=",            /* SEP_CMD */
 191         "#",            /* COMMENT_CMD */
 192         "chainloader",  /* CHAINLOADER_CMD */
 193         "args",         /* ARGS_CMD */
 194         "pool_label",   /* FINDROOT_CMD */
 195         "data_set",     /* BOOTFS_CMD */
 196         "kernel_options",/* KERNEL_OPTIONS_CMD */
 197         NULL
 198 };
 199 
 200 #define OPT_ENTRY_NUM   "entry"
 201 
 202 /*
 203  * exec_cmd related
 204  */
 205 typedef struct {
 206         line_t *head;
 207         line_t *tail;
 208 } filelist_t;
 209 
 210 #define BOOT_FILE_LIST  "boot/solaris/filelist.ramdisk"
 211 #define ETC_FILE_LIST   "etc/boot/solaris/filelist.ramdisk"
 212 
 213 #define FILE_STAT       "boot/solaris/filestat.ramdisk"
 214 #define FILE_STAT_TMP   "boot/solaris/filestat.ramdisk.tmp"
 215 #define DIR_PERMS       (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
 216 #define FILE_STAT_MODE  (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)


4675         }
4676 
4677         return (BAM_SUCCESS);
4678 }
4679 
4680 int
4681 add_boot_entry(menu_t *mp,
4682         char *title,
4683         char *findroot,
4684         char *kernel,
4685         char *mod_kernel,
4686         char *module,
4687         char *bootfs)
4688 {
4689         int             lineNum;
4690         int             entryNum;
4691         char            linebuf[BAM_MAXLINE];
4692         menu_cmd_t      k_cmd;
4693         menu_cmd_t      m_cmd;
4694         const char      *fcn = "add_boot_entry()";
4695         char * options = NULL;
4696 
4697         assert(mp);
4698 
4699         INJECT_ERROR1("ADD_BOOT_ENTRY_FINDROOT_NULL", findroot = NULL);
4700         if (findroot == NULL) {
4701                 bam_error(NULL_FINDROOT);
4702                 return (BAM_ERROR);
4703         }
4704 
4705         if (title == NULL) {
4706                 title = "Solaris";      /* default to Solaris */
4707         }
4708         if (kernel == NULL) {
4709                 bam_error(SUBOPT_MISS, menu_cmds[KERNEL_CMD]);
4710                 return (BAM_ERROR);
4711         }
4712         if (module == NULL) {
4713                 if (bam_direct != BAM_DIRECT_DBOOT) {
4714                         bam_error(SUBOPT_MISS, menu_cmds[MODULE_CMD]);
4715                         return (BAM_ERROR);


4742          */
4743         (void) snprintf(linebuf, sizeof (linebuf), "%s%s",
4744             menu_cmds[COMMENT_CMD], BAM_BOOTADM_HDR);
4745         line_parser(mp, linebuf, &lineNum, &entryNum);
4746 
4747         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
4748             menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title);
4749         line_parser(mp, linebuf, &lineNum, &entryNum);
4750 
4751         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
4752             menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot);
4753         line_parser(mp, linebuf, &lineNum, &entryNum);
4754         BAM_DPRINTF((D_ADD_FINDROOT_NUM, fcn, lineNum, entryNum));
4755 
4756         if (bootfs != NULL) {
4757                 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
4758                     menu_cmds[BOOTFS_CMD], menu_cmds[SEP_CMD], bootfs);
4759                 line_parser(mp, linebuf, &lineNum, &entryNum);
4760         }
4761 
4762         options = strpbrk(kernel, " \t");
4763         if (options)
4764                 ++options;
4765 
4766         (void) snprintf(linebuf, sizeof (linebuf), "%s%s",
4767             menu_cmds[k_cmd], menu_cmds[SEP_CMD]);
4768         (void) strncat(linebuf, kernel, options - kernel);
4769         line_parser(mp, linebuf, &lineNum, &entryNum);
4770 
4771         if (options) {
4772                 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
4773                     menu_cmds[KERNEL_OPTIONS_CMD], menu_cmds[SEP_CMD], options);
4774                 line_parser(mp, linebuf, &lineNum, &entryNum);
4775         }
4776 
4777         if (mod_kernel != NULL) {
4778                 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
4779                     menu_cmds[m_cmd], menu_cmds[SEP_CMD], mod_kernel);
4780                 line_parser(mp, linebuf, &lineNum, &entryNum);
4781         }
4782 
4783         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
4784             menu_cmds[m_cmd], menu_cmds[SEP_CMD], module);
4785         line_parser(mp, linebuf, &lineNum, &entryNum);
4786 
4787         (void) snprintf(linebuf, sizeof (linebuf), "%s%s",
4788             menu_cmds[COMMENT_CMD], BAM_BOOTADM_FTR);
4789         line_parser(mp, linebuf, &lineNum, &entryNum);
4790 
4791         return (entryNum);
4792 }
4793 
4794 error_t
4795 delete_boot_entry(menu_t *mp, int entryNum, int quiet)


7109                 (void) unlink(UFS_SIGNATURE_LIST);
7110                 return (NULL);
7111         }
7112 
7113         free(fstype);
7114 
7115         if (bam_verbose)
7116                 bam_print(GRUBSIGN_FOUND_OR_CREATED, sign, osdev);
7117 
7118         fdiskpart = get_partition(osdev);
7119         INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart = -1);
7120         if (fdiskpart == -1) {
7121                 bam_error(FDISKPART_FAIL, osdev);
7122                 free(sign);
7123                 return (NULL);
7124         }
7125 
7126         slice = strrchr(osdev, 's');
7127 
7128         grubsign = s_calloc(1, MAXNAMELEN + 10);
7129 /*      if (slice) {
7130                 (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d,%c)",
7131                     sign, fdiskpart, slice[1] + 'a' - '0');
7132         } else
7133                 (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d)",
7134                     sign, fdiskpart);*/
7135         grubsign = strdup(sign);
7136 
7137         free(sign);
7138 
7139         BAM_DPRINTF((D_GET_GRUBSIGN_SUCCESS, fcn, grubsign));
7140 
7141         return (strchr(grubsign,'_') + 1);
7142 }
7143 
7144 static char *
7145 get_title(char *rootdir)
7146 {
7147         static char     title[80];
7148         char            *cp = NULL;
7149         char            release[PATH_MAX];
7150         FILE            *fp;
7151         const char      *fcn = "get_title()";
7152 
7153         /* open the /etc/release file */
7154         (void) snprintf(release, sizeof (release), "%s/etc/release", rootdir);
7155 
7156         fp = fopen(release, "r");
7157         if (fp == NULL) {
7158                 bam_error(OPEN_FAIL, release, strerror(errno));
7159                 cp = NULL;
7160                 goto out;
7161         }


7810                                 BAM_DPRINTF((D_MATCHED_TITLE, fcn, title));
7811                                 break;
7812                         }
7813                         BAM_DPRINTF((D_NOMATCH_TITLE, fcn, title, lp->arg));
7814                         continue;       /* check title only */
7815                 }
7816 
7817                 lp = lp->next;       /* advance to root line */
7818                 if (lp == NULL) {
7819                         continue;
7820                 } else if (lp->cmd != NULL &&
7821                     strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) == 0) {
7822                         INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_FINDROOT",
7823                             findroot = NULL);
7824                         if (findroot == NULL) {
7825                                 BAM_DPRINTF((D_NOMATCH_FINDROOT_NULL,
7826                                     fcn, lp->arg));
7827                                 continue;
7828                         }
7829                         /* findroot command found, try match  */
7830                         if (strncmp(lp->arg, strchr(findroot, '_') + 1, strlen(lp->arg)) != 0) {
7831                                 BAM_DPRINTF((D_NOMATCH_FINDROOT,
7832                                     fcn, findroot, lp->arg));
7833                                 continue;
7834                         }
7835                         BAM_DPRINTF((D_MATCHED_FINDROOT, fcn, findroot));
7836                         lp = lp->next;       /* advance to kernel line */
7837                 } else if (lp->cmd != NULL &&
7838                     strcmp(lp->cmd, menu_cmds[ROOT_CMD]) == 0) {
7839                         INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_ROOT", root = NULL);
7840                         if (root == NULL) {
7841                                 BAM_DPRINTF((D_NOMATCH_ROOT_NULL,
7842                                     fcn, lp->arg));
7843                                 continue;
7844                         }
7845                         /* root cmd found, try match */
7846                         if (strcmp(lp->arg, root) != 0) {
7847                                 BAM_DPRINTF((D_NOMATCH_ROOT,
7848                                     fcn, root, lp->arg));
7849                                 continue;
7850                         }


7868                 }
7869 
7870                 if (kernel &&
7871                     (!check_cmd(lp->cmd, KERNEL_CMD, lp->arg, kernel))) {
7872                         if (!(ent->flags & BAM_ENTRY_FAILSAFE) ||
7873                             !(ent->flags & BAM_ENTRY_DBOOT) ||
7874                             strcmp(kernel, DIRECT_BOOT_FAILSAFE_LINE) != 0)
7875                                 continue;
7876 
7877                         ent->flags |= BAM_ENTRY_UPGFSKERNEL;
7878 
7879                 }
7880                 BAM_DPRINTF((D_KERNEL_MATCH, fcn, kernel, lp->arg));
7881 
7882                 /*
7883                  * Check for matching module entry (failsafe or normal).
7884                  * If it fails to match, we go around the loop again.
7885                  * For xpv entries, there are two module lines, so we
7886                  * do the check twice.
7887                  */
7888                 lp = lp->next;       /* advance to options line */
7889                 lp = lp->next;       /* advance to module line */
7890                 if (check_cmd(lp->cmd, MODULE_CMD, lp->arg, module) ||
7891                     (((lp = lp->next) != NULL) &&
7892                     check_cmd(lp->cmd, MODULE_CMD, lp->arg, module))) {
7893                         /* match found */
7894                         BAM_DPRINTF((D_MODULE_MATCH, fcn, module, lp->arg));
7895                         break;
7896                 }
7897 
7898                 if (strcmp(module, FAILSAFE_ARCHIVE) == 0 &&
7899                     (strcmp(lp->prev->arg, FAILSAFE_ARCHIVE_32) == 0 ||
7900                     strcmp(lp->prev->arg, FAILSAFE_ARCHIVE_64) == 0)) {
7901                         ent->flags |= BAM_ENTRY_UPGFSMODULE;
7902                         break;
7903                 }
7904 
7905         }
7906 
7907         if (ent && entry_num) {
7908                 *entry_num = i;


7910 
7911         if (ent) {
7912                 BAM_DPRINTF((D_RETURN_RET, fcn, i));
7913         } else {
7914                 BAM_DPRINTF((D_RETURN_RET, fcn, BAM_ERROR));
7915         }
7916         return (ent);
7917 }
7918 
7919 static int
7920 update_boot_entry(menu_t *mp, char *title, char *findroot, char *root,
7921     char *kernel, char *mod_kernel, char *module, int root_opt)
7922 {
7923         int             i;
7924         int             change_kernel = 0;
7925         entry_t         *ent;
7926         line_t          *lp;
7927         line_t          *tlp;
7928         char            linebuf[BAM_MAXLINE];
7929         const char      *fcn = "update_boot_entry()";
7930         char            *label;
7931 
7932         /* note: don't match on title, it's updated on upgrade */
7933         ent = find_boot_entry(mp, NULL, kernel, findroot, root, module,
7934             root_opt, &i);
7935         if ((ent == NULL) && (bam_direct == BAM_DIRECT_DBOOT)) {
7936                 /*
7937                  * We may be upgrading a kernel from multiboot to
7938                  * directboot.  Look for a multiboot entry. A multiboot
7939                  * entry will not have a findroot line.
7940                  */
7941                 ent = find_boot_entry(mp, NULL, "multiboot", NULL, root,
7942                     MULTIBOOT_ARCHIVE, root_opt, &i);
7943                 if (ent != NULL) {
7944                         BAM_DPRINTF((D_UPGRADE_FROM_MULTIBOOT, fcn, root));
7945                         change_kernel = 1;
7946                 }
7947         } else if (ent) {
7948                 BAM_DPRINTF((D_FOUND_FINDROOT, fcn, findroot));
7949         }
7950 


7967 
7968         tlp = lp;       /* title line */
7969         lp = lp->next;       /* root line */
7970 
7971         /* if no root or findroot command, create a new line_t */
7972         if ((lp->cmd != NULL) && (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) != 0 &&
7973             strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) != 0)) {
7974                 lp = s_calloc(1, sizeof (line_t));
7975                 bam_add_line(mp, ent, tlp, lp);
7976         } else {
7977                 if (lp->cmd != NULL)
7978                         free(lp->cmd);
7979 
7980                 free(lp->sep);
7981                 free(lp->arg);
7982                 free(lp->line);
7983         }
7984 
7985         lp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]);
7986         lp->sep = s_strdup(menu_cmds[SEP_CMD]);
7987         label = s_strdup(strchr(findroot, '_') + 1);
7988         *(strchr(label,',')) = 0;
7989         lp->arg = s_strdup(label);
7990         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
7991             menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], label);
7992         lp->line = s_strdup(linebuf);
7993         free(label);
7994         BAM_DPRINTF((D_ADDING_FINDROOT_LINE, fcn, findroot));
7995 
7996         /* kernel line */
7997         lp = lp->next;
7998 
7999         if (ent->flags & BAM_ENTRY_UPGFSKERNEL) {
8000                 char            *params = NULL;
8001                 char            *opts = NULL;
8002 
8003                 opts = strpbrk(kernel, " \t");
8004                 *opts++ = '\0';




8005                 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
8006                     menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD],
8007                     kernel);
8008 
8009                 if (lp->cmd != NULL)
8010                         free(lp->cmd);
8011 
8012                 free(lp->arg);
8013                 free(lp->line);
8014                 lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]);
8015                 lp->arg = s_strdup(strstr(linebuf, "/"));
8016                 lp->line = s_strdup(linebuf);
8017                 ent->flags &= ~BAM_ENTRY_UPGFSKERNEL;
8018                 BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, lp->prev->cmd));
8019 
8020                 lp = lp->next;
8021                 params = strstr(lp->arg, "-s");
8022                 free(lp->arg);
8023                 free(lp->line);
8024                 if (params)
8025                         (void) snprintf(linebuf, sizeof(linebuf), "%s%s%s -s",
8026                                 lp->cmd, menu_cmds[SEP_CMD],opts);
8027                 else
8028                         (void) snprintf(linebuf, sizeof(linebuf), "%s%s%s",
8029                                 lp->cmd, menu_cmds[SEP_CMD],opts);
8030                 lp->line = s_strdup(linebuf);
8031                 lp->arg = s_strdup(strchr(linebuf, '=') + 1);
8032         }
8033 
8034         if (change_kernel) {
8035                 char            *opts = NULL;
8036                 /*
8037                  * We're upgrading from multiboot to directboot.
8038                  */
8039                 opts = strpbrk(kernel, " \t");
8040                 *opts++ = '\0';
8041                 if (lp->cmd != NULL &&
8042                     strcmp(lp->cmd, menu_cmds[KERNEL_CMD]) == 0) {
8043                         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
8044                             menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD],
8045                             kernel);
8046                         free(lp->cmd);
8047                         free(lp->arg);
8048                         free(lp->line);
8049                         lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]);
8050                         lp->arg = s_strdup(kernel);
8051                         lp->line = s_strdup(linebuf);
8052                         lp = lp->next;
8053                         BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, kernel));
8054                         (void) snprintf(linebuf, sizeof(linebuf), "%s%s%s",
8055                                 lp->cmd, menu_cmds[SEP_CMD],opts);
8056                         free(lp->arg);
8057                         free(lp->line);
8058                         lp->line = s_strdup(linebuf);
8059                         lp->arg = s_strdup(strchr(linebuf, '=') + 1);
8060                 }
8061                 if (lp->cmd != NULL &&
8062                     strcmp(lp->cmd, menu_cmds[MODULE_CMD]) == 0) {
8063                         (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
8064                             menu_cmds[MODULE_DOLLAR_CMD], menu_cmds[SEP_CMD],
8065                             module);
8066                         free(lp->cmd);
8067                         free(lp->arg);
8068                         free(lp->line);
8069                         lp->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]);
8070                         lp->arg = s_strdup(module);
8071                         lp->line = s_strdup(linebuf);
8072                         lp = lp->next;
8073                         BAM_DPRINTF((D_ADDING_MODULE_DOLLAR, fcn, module));
8074                 }
8075         }
8076 
8077         /* module line */
8078         lp = lp->next;
8079 


8432         /*
8433          * add a new menu entry based on opt and make it the default
8434          */
8435 
8436         fstype = get_fstype("/");
8437         INJECT_ERROR1("REBOOT_FSTYPE_NULL", fstype = NULL);
8438         if (fstype == NULL) {
8439                 bam_error(REBOOT_FSTYPE_FAILED);
8440                 return (BAM_ERROR);
8441         }
8442 
8443         osdev = get_special("/");
8444         INJECT_ERROR1("REBOOT_SPECIAL_NULL", osdev = NULL);
8445         if (osdev == NULL) {
8446                 free(fstype);
8447                 bam_error(REBOOT_SPECIAL_FAILED);
8448                 return (BAM_ERROR);
8449         }
8450 
8451         sign = find_existing_sign("/", osdev, fstype);
8452         sign = strchr(sign, '_') + 1;
8453         INJECT_ERROR1("REBOOT_SIGN_NULL", sign = NULL);
8454         if (sign == NULL) {
8455                 free(fstype);
8456                 free(osdev);
8457                 bam_error(REBOOT_SIGN_FAILED);
8458                 return (BAM_ERROR);
8459         }
8460 
8461         free(osdev);
8462         (void) strlcpy(signbuf, sign, sizeof (signbuf));
8463         free(sign);
8464 
8465         assert(strchr(signbuf, '(') == NULL && strchr(signbuf, ',') == NULL &&
8466             strchr(signbuf, ')') == NULL);
8467 
8468         /*
8469          * There is no alternate root while doing reboot with args
8470          * This version of bootadm is only delivered with a DBOOT
8471          * version of Solaris.
8472          */


8881         if (mp->curdefault) {
8882                 entryNum = s_strtol(mp->curdefault->arg);
8883                 for (entryp = mp->entries; entryp; entryp = entryp->next) {
8884                         if (entryp->entryNum == entryNum)
8885                                 break;
8886                 }
8887                 if ((entryp != NULL) &&
8888                     ((entryp->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) == 0)) {
8889                         bam_error(DEFAULT_NOT_BAM);
8890                         return (BAM_ERROR);
8891                 }
8892         }
8893 
8894         entryp = find_boot_entry(mp, BOOTENV_RC_TITLE, NULL, NULL, NULL, NULL,
8895             0, &entryNum);
8896 
8897         if (entryp != NULL) {
8898                 for (ptr = entryp->start; ptr && ptr != entryp->end;
8899                     ptr = ptr->next) {
8900                         if (strncmp(ptr->cmd, menu_cmds[KERNEL_CMD],
8901                             sizeof (menu_cmds[KERNEL_CMD]) - 2) == 0) {
8902                                 kernelp = ptr;
8903                                 break;
8904                         }
8905                 }
8906                 if (kernelp == NULL) {
8907                         bam_error(NO_KERNEL, entryNum);
8908                         return (BAM_ERROR);
8909                 }
8910 
8911                 old_kernel_len = strcspn(kernelp->arg, " \t");
8912                 space = old_args = kernelp->arg + old_kernel_len;
8913                 while ((*old_args == ' ') || (*old_args == '\t'))
8914                         old_args++;
8915         }
8916 
8917         if (path == NULL) {
8918                 if (entryp == NULL) {
8919                         BAM_DPRINTF((D_GET_SET_KERNEL_NO_RC, fcn));
8920                         BAM_DPRINTF((D_RETURN_SUCCESS, fcn));
8921                         return (BAM_SUCCESS);


8969                     sizeof (DIRECT_BOOT_KERNEL) - 1) == 0))) {
8970                         kernelp = NULL;
8971                         (void) delete_boot_entry(mp, entryNum, DBE_PRINTERR);
8972                         restore_default_entry(mp, BAM_OLD_RC_DEF,
8973                             mp->old_rc_default);
8974                         mp->old_rc_default = NULL;
8975                         rv = BAM_WRITE;
8976                         BAM_DPRINTF((D_GET_SET_KERNEL_RESTORE_DEFAULT, fcn));
8977                         goto done;
8978                 }
8979 
8980                 if (optnum == KERNEL_CMD) {
8981                         /*
8982                          * At this point, we've already checked that old_args
8983                          * and entryp are valid pointers.  The "+ 2" is for
8984                          * a space a the string termination character.
8985                          */
8986                         new_str_len = (sizeof (DIRECT_BOOT_KERNEL) - 1) +
8987                             strlen(old_args) + 2;
8988                         new_arg = s_calloc(1, new_str_len);
8989                         (void) snprintf(new_arg, new_str_len, "%s",
8990                             DIRECT_BOOT_KERNEL);
8991                         free(kernelp->arg);
8992                         kernelp->arg = new_arg;
8993 
8994                         /*
8995                          * We have changed the kernel line, so we may need
8996                          * to update the archive line as well.
8997                          */
8998                         set_archive_line(entryp, kernelp);
8999                         BAM_DPRINTF((D_GET_SET_KERNEL_RESET_KERNEL_SET_ARG,
9000                             fcn, kernelp->arg));
9001                 } else {
9002                         /*
9003                          * We're resetting the boot args to nothing, so
9004                          * we only need to copy the kernel.  We've already
9005                          * checked that the kernel is not the default.
9006                          */
9007                         new_arg = s_calloc(1, old_kernel_len + 1);
9008                         (void) snprintf(new_arg, old_kernel_len + 1, "%s",
9009                             kernelp->arg);
9010                         free(kernelp->arg);


9131 
9132         /*
9133          * There was already an bootenv entry which we need to edit.
9134          */
9135         if (optnum == KERNEL_CMD) {
9136                 new_str_len = strlen(new_path) + strlen(old_args) + 2;
9137                 new_arg = s_calloc(1, new_str_len);
9138                 (void) snprintf(new_arg, new_str_len, "%s %s", new_path,
9139                     old_args);
9140                 free(kernelp->arg);
9141                 kernelp->arg = new_arg;
9142 
9143                 /*
9144                  * If we have changed the kernel line, we may need to update
9145                  * the archive line as well.
9146                  */
9147                 set_archive_line(entryp, kernelp);
9148                 BAM_DPRINTF((D_GET_SET_KERNEL_REPLACED_KERNEL_SAME_ARG, fcn,
9149                     kernelp->arg));
9150         } else {
9151                 kernelp = kernelp->next;
9152                 new_str_len = strlen(kernelp->arg) + strlen(path) + 8;
9153                 new_arg = s_calloc(1, new_str_len);
9154                 (void) strncpy(new_arg, kernelp->arg, strlen(kernelp->arg));
9155                 (void) strlcat(new_arg, " ", new_str_len);
9156                 (void) strlcat(new_arg, path, new_str_len);
9157                 free(kernelp->arg);
9158                 kernelp->arg = new_arg;
9159                 BAM_DPRINTF((D_GET_SET_KERNEL_SAME_KERNEL_REPLACED_ARG, fcn,
9160                     kernelp->arg));
9161         }
9162         rv = BAM_WRITE;
9163 
9164 done:
9165         if ((rv == BAM_WRITE) && kernelp)
9166                 update_line(kernelp);
9167         if (free_new_path)
9168                 free(new_path);
9169         if (rv == BAM_WRITE) {
9170                 BAM_DPRINTF((D_RETURN_SUCCESS, fcn));
9171         } else {
9172                 BAM_DPRINTF((D_RETURN_FAILURE, fcn));
9173         }
9174         return (rv);