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);
|