13446Smrj /* 23446Smrj * CDDL HEADER START 33446Smrj * 43446Smrj * The contents of this file are subject to the terms of the 53446Smrj * Common Development and Distribution License (the "License"). 63446Smrj * You may not use this file except in compliance with the License. 73446Smrj * 83446Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93446Smrj * or http://www.opensolaris.org/os/licensing. 103446Smrj * See the License for the specific language governing permissions 113446Smrj * and limitations under the License. 123446Smrj * 133446Smrj * When distributing Covered Code, include this CDDL HEADER in each 143446Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153446Smrj * If applicable, add the following below this CDDL HEADER, with the 163446Smrj * fields enclosed by brackets "[]" replaced with your own identifying 173446Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 183446Smrj * 193446Smrj * CDDL HEADER END 203446Smrj */ 213446Smrj /* 223446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 233446Smrj * Use is subject to license terms. 243446Smrj */ 253446Smrj 263446Smrj #pragma ident "%Z%%M% %I% %E% SMI" 273446Smrj 283446Smrj #include <stdio.h> 293446Smrj #include <errno.h> 303446Smrj #include <stdlib.h> 313446Smrj #include <string.h> 323446Smrj #include <unistd.h> 333446Smrj #include <sys/types.h> 343446Smrj #include <sys/stat.h> 353446Smrj #include <limits.h> 363446Smrj #include <fcntl.h> 373446Smrj #include <strings.h> 383446Smrj 393446Smrj #include <sys/mman.h> 403446Smrj #include <sys/elf.h> 413446Smrj #include <sys/multiboot.h> 423446Smrj 433446Smrj #include "message.h" 443446Smrj #include "bootadm.h" 453446Smrj 463446Smrj direct_or_multi_t bam_direct = BAM_DIRECT_NOT_SET; 475084Sjohnlev hv_t bam_is_hv = BAM_HV_UNKNOWN; 483446Smrj 493446Smrj error_t 503446Smrj dboot_or_multiboot(const char *root) 513446Smrj { 523446Smrj char fname[PATH_MAX]; 533446Smrj char *image; 543446Smrj uchar_t *ident; 553446Smrj int fd, m; 563446Smrj multiboot_header_t *mbh; 575084Sjohnlev struct stat sb; 583446Smrj 59*5648Ssetje if (!is_grub(root)) { 60*5648Ssetje /* there is no non dboot sparc new-boot */ 61*5648Ssetje bam_direct = BAM_DIRECT_DBOOT; 62*5648Ssetje return (BAM_SUCCESS); 63*5648Ssetje } 64*5648Ssetje 653446Smrj (void) snprintf(fname, PATH_MAX, "%s/%s", root, 663446Smrj "platform/i86pc/kernel/unix"); 673446Smrj fd = open(fname, O_RDONLY); 683446Smrj if (fd < 0) { 693446Smrj bam_error(OPEN_FAIL, fname, strerror(errno)); 703446Smrj return (BAM_ERROR); 713446Smrj } 723446Smrj 733446Smrj /* 743446Smrj * mmap the first 8K 753446Smrj */ 763446Smrj image = mmap(NULL, 8192, PROT_READ, MAP_SHARED, fd, 0); 773446Smrj if (image == MAP_FAILED) { 783446Smrj bam_error(MMAP_FAIL, fname, strerror(errno)); 793446Smrj return (BAM_ERROR); 803446Smrj } 813446Smrj 823446Smrj ident = (uchar_t *)image; 833446Smrj if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 || 843446Smrj ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) { 853446Smrj bam_error(NOT_ELF_FILE, fname); 863446Smrj return (BAM_ERROR); 873446Smrj } 883446Smrj if (ident[EI_CLASS] != ELFCLASS32) { 893446Smrj bam_error(WRONG_ELF_CLASS, fname, ident[EI_CLASS]); 903446Smrj return (BAM_ERROR); 913446Smrj } 923446Smrj 933446Smrj /* 943446Smrj * The GRUB multiboot header must be 32-bit aligned and completely 953446Smrj * contained in the 1st 8K of the file. If the unix binary has 963446Smrj * a multiboot header, then it is a 'dboot' kernel. Otherwise, 973446Smrj * this kernel must be booted via multiboot -- we call this a 983446Smrj * 'multiboot' kernel. 993446Smrj */ 1003446Smrj bam_direct = BAM_DIRECT_MULTIBOOT; 1013446Smrj for (m = 0; m < 8192 - sizeof (multiboot_header_t); m += 4) { 1023446Smrj mbh = (void *)(image + m); 1033446Smrj if (mbh->magic == MB_HEADER_MAGIC) { 1043446Smrj bam_direct = BAM_DIRECT_DBOOT; 1053446Smrj break; 1063446Smrj } 1073446Smrj } 1083446Smrj (void) munmap(image, 8192); 1093446Smrj (void) close(fd); 1105084Sjohnlev 1115084Sjohnlev if (bam_direct == BAM_DIRECT_DBOOT) { 1125084Sjohnlev (void) snprintf(fname, PATH_MAX, "%s/%s", root, XEN_32); 1135084Sjohnlev if (stat(fname, &sb) == 0) { 1145084Sjohnlev bam_is_hv = BAM_HV_PRESENT; 1155084Sjohnlev } else { 1165084Sjohnlev bam_is_hv = BAM_HV_NO; 1175084Sjohnlev } 1185084Sjohnlev } 1195084Sjohnlev 1203446Smrj return (BAM_SUCCESS); 1213446Smrj } 1223446Smrj 1233446Smrj #define INST_RELEASE "var/sadm/system/admin/INST_RELEASE" 1243446Smrj 1253446Smrj /* 1263446Smrj * Return true if root has been bfu'ed. bfu will blow away 1273446Smrj * var/sadm/system/admin/INST_RELEASE, so if it's still there, we can 1283446Smrj * assume the system has not been bfu'ed. 1293446Smrj */ 1303446Smrj static int 1313446Smrj is_bfu_system(const char *root) 1323446Smrj { 1333446Smrj static int is_bfu = -1; 1343446Smrj char path[PATH_MAX]; 1353446Smrj struct stat sb; 1363446Smrj 1373446Smrj if (is_bfu != -1) 1383446Smrj return (is_bfu); 1393446Smrj 1403446Smrj (void) snprintf(path, sizeof (path), "%s/%s", root, INST_RELEASE); 1413446Smrj if (stat(path, &sb) != 0) { 1423446Smrj is_bfu = 1; 1433446Smrj } else { 1443446Smrj is_bfu = 0; 1453446Smrj } 1463446Smrj return (is_bfu); 1473446Smrj } 1483446Smrj 1493446Smrj #define MENU_URL(root) (is_bfu_system(root) ? \ 1503446Smrj "http://www.sun.com/msg/SUNOS-8000-CF" : \ 1513446Smrj "http://www.sun.com/msg/SUNOS-8000-AK") 1523446Smrj 1533446Smrj /* 1543446Smrj * Simply allocate a new line and copy in cmd + sep + arg 1553446Smrj */ 1563446Smrj void 1573446Smrj update_line(line_t *linep) 1583446Smrj { 1593446Smrj size_t size; 1603446Smrj 1613446Smrj free(linep->line); 1623446Smrj size = strlen(linep->cmd) + strlen(linep->sep) + strlen(linep->arg) + 1; 1633446Smrj linep->line = s_calloc(1, size); 1643446Smrj (void) snprintf(linep->line, size, "%s%s%s", linep->cmd, linep->sep, 1653446Smrj linep->arg); 1663446Smrj } 1673446Smrj 1683446Smrj /* 1693446Smrj * The parse_kernel_line function examines a menu.lst kernel line. For 1703446Smrj * multiboot, this is: 1713446Smrj * 1723446Smrj * kernel <multiboot path> <flags1> <kernel path> <flags2> 1733446Smrj * 1743446Smrj * <multiboot path> is either /platform/i86pc/multiboot or /boot/multiboot 1753446Smrj * 1763446Smrj * <kernel path> may be missing, or may be any full or relative path to unix. 1773446Smrj * We check for it by looking for a word ending in "/unix". If it ends 1783446Smrj * in "kernel/unix", we upgrade it to a 32-bit entry. If it ends in 1793446Smrj * "kernel/amd64/unix", we upgrade it to the default entry. Otherwise, 1803446Smrj * it's a custom kernel, and we skip it. 1813446Smrj * 1823446Smrj * <flags*> are anything that doesn't fit either of the above - these will be 1833446Smrj * copied over. 1843446Smrj * 1853446Smrj * For direct boot, the defaults are 1863446Smrj * 1873446Smrj * kernel$ <kernel path> <flags> 1883446Smrj * 1893446Smrj * <kernel path> is one of: 1903446Smrj * /platform/i86pc/kernel/$ISADIR/unix 1913446Smrj * /platform/i86pc/kernel/unix 1923446Smrj * /platform/i86pc/kernel/amd64/unix 1933446Smrj * /boot/platform/i86pc/kernel/unix 1943446Smrj * 1953446Smrj * If <kernel path> is any of the last three, the command may also be "kernel". 1963446Smrj * 1973446Smrj * <flags> is anything that isn't <kernel path>. 1983446Smrj * 1993446Smrj * This function is only called if it applies to our target boot environment. 2003446Smrj * If we can't make any sense of the kernel line, an error is printed and 2013446Smrj * BAM_ERROR is returned. 2023446Smrj * 2033446Smrj * The desired install type is given in the global variable bam_direct. 2043446Smrj * If the kernel line is of a different install type, we change it to the 2053446Smrj * preferred type. If the kernel line is already of the correct install 2063446Smrj * type, we do nothing. Either way, BAM_SUCCESS is returned. 2073446Smrj * 2083446Smrj * For safety, we do one more check: if the kernel path starts with /boot, 2093446Smrj * we verify that the new kernel exists before changing it. This is mainly 2103446Smrj * done for bfu, as it may cause the failsafe archives to be a different 2113446Smrj * boot architecture from the newly bfu'ed system. 2123446Smrj */ 2133446Smrj static error_t 2143446Smrj parse_kernel_line(line_t *linep, const char *root, uint8_t *flags) 2153446Smrj { 2163446Smrj char path[PATH_MAX]; 2173446Smrj int len, left, total_len; 2183446Smrj struct stat sb; 2193446Smrj char *new_ptr, *new_arg, *old_ptr; 2203446Smrj menu_cmd_t which; 2213446Smrj 2223446Smrj /* Used when changing a multiboot line to dboot */ 2233446Smrj char *unix_ptr, *flags1_ptr, *flags2_ptr; 2243446Smrj 2253446Smrj /* 2263446Smrj * Note that BAM_ENTRY_DBOOT refers to the entry we're looking at, not 2273446Smrj * necessarily the system type. 2283446Smrj */ 2293446Smrj if (strncmp(linep->arg, DIRECT_BOOT_32, 2303446Smrj sizeof (DIRECT_BOOT_32) - 1) == 0) { 2313446Smrj *flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_32BIT; 2323446Smrj } else if ((strncmp(linep->arg, DIRECT_BOOT_KERNEL, 2333446Smrj sizeof (DIRECT_BOOT_KERNEL) - 1) == 0) || 2343446Smrj (strncmp(linep->arg, DIRECT_BOOT_64, 2353446Smrj sizeof (DIRECT_BOOT_64) - 1) == 0) || 2363446Smrj (strncmp(linep->arg, DIRECT_BOOT_FAILSAFE_KERNEL, 2373446Smrj sizeof (DIRECT_BOOT_FAILSAFE_KERNEL) - 1) == 0)) { 2383446Smrj *flags |= BAM_ENTRY_DBOOT; 2393446Smrj } else if ((strncmp(linep->arg, MULTI_BOOT, 2403446Smrj sizeof (MULTI_BOOT) - 1) == 0) || 2413446Smrj (strncmp(linep->arg, MULTI_BOOT_FAILSAFE, 2423446Smrj sizeof (MULTI_BOOT_FAILSAFE) - 1) == 0)) { 2433446Smrj *flags &= ~BAM_ENTRY_DBOOT; 2443446Smrj } else { 2453446Smrj bam_error(NO_KERNEL_MATCH, linep->lineNum, MENU_URL(root)); 2463446Smrj return (BAM_ERROR); 2473446Smrj } 2483446Smrj 2493446Smrj if (((*flags & BAM_ENTRY_DBOOT) && (bam_direct == BAM_DIRECT_DBOOT)) || 2503446Smrj (((*flags & BAM_ENTRY_DBOOT) == 0) && 2513446Smrj (bam_direct == BAM_DIRECT_MULTIBOOT))) { 2523446Smrj 2533446Smrj /* No action needed */ 2543446Smrj return (BAM_SUCCESS); 2553446Smrj } 2563446Smrj 2573446Smrj if (*flags & BAM_ENTRY_MINIROOT) { 2583446Smrj /* 2593446Smrj * We're changing boot architectures - make sure 2603446Smrj * the multiboot failsafe still exists. 2613446Smrj */ 2623446Smrj (void) snprintf(path, PATH_MAX, "%s%s", root, 2633446Smrj (*flags & BAM_ENTRY_DBOOT) ? MULTI_BOOT_FAILSAFE : 2643446Smrj DIRECT_BOOT_FAILSAFE_KERNEL); 2653446Smrj if (stat(path, &sb) != 0) { 2663446Smrj if (bam_verbose) { 2673446Smrj bam_error(FAILSAFE_MISSING, linep->lineNum); 2683446Smrj } 2693446Smrj return (BAM_SUCCESS); 2703446Smrj } 2713446Smrj } 2723446Smrj 2733446Smrj /* 2743446Smrj * Make sure we have the correct cmd - either kernel or kernel$ 2753446Smrj * The failsafe entry should always be KERNEL_CMD. 2763446Smrj */ 2773446Smrj which = ((bam_direct == BAM_DIRECT_MULTIBOOT) || 2783446Smrj (*flags & BAM_ENTRY_MINIROOT)) ? KERNEL_CMD : KERNEL_DOLLAR_CMD; 2793446Smrj free(linep->cmd); 2803446Smrj len = strlen(menu_cmds[which]) + 1; 2813446Smrj linep->cmd = s_calloc(1, len); 2823446Smrj (void) strncpy(linep->cmd, menu_cmds[which], len); 2833446Smrj 2843446Smrj /* 2853446Smrj * Since all arguments are copied, the new arg string should be close 2863446Smrj * in size to the old one. Just add 32 to cover the difference in 2873446Smrj * the boot path. 2883446Smrj */ 2893446Smrj total_len = strlen(linep->arg) + 32; 2903446Smrj new_arg = s_calloc(1, total_len); 2913446Smrj old_ptr = strchr(linep->arg, ' '); 2923446Smrj if (old_ptr != NULL) 2933446Smrj old_ptr++; 2943446Smrj 2953446Smrj /* 2963446Smrj * Transitioning from dboot to multiboot is pretty simple. We 2973446Smrj * copy in multiboot and any args. 2983446Smrj */ 2993446Smrj if (bam_direct == BAM_DIRECT_MULTIBOOT) { 3003446Smrj if (old_ptr == NULL) { 3013446Smrj (void) snprintf(new_arg, total_len, "%s", 3023446Smrj (*flags & BAM_ENTRY_MINIROOT) ? 3033446Smrj MULTI_BOOT_FAILSAFE : MULTI_BOOT); 3043446Smrj } else { 3053446Smrj (void) snprintf(new_arg, total_len, "%s %s", 3063446Smrj (*flags & BAM_ENTRY_MINIROOT) ? 3073446Smrj MULTI_BOOT_FAILSAFE : MULTI_BOOT, old_ptr); 3083446Smrj } 3093446Smrj goto done; 3103446Smrj } 3113446Smrj 3123446Smrj /* 3133446Smrj * Transitioning from multiboot to directboot is a bit more 3143446Smrj * complicated, since we may have two sets of arguments to 3153446Smrj * copy and a unix path to parse. 3163446Smrj * 3173446Smrj * First, figure out if there's a unix path. 3183446Smrj */ 3193446Smrj if ((old_ptr != NULL) && 3203446Smrj ((unix_ptr = strstr(old_ptr, "/unix")) != NULL)) { 3213446Smrj /* See if there's anything past unix */ 3223446Smrj flags2_ptr = unix_ptr + sizeof ("/unix"); 3233446Smrj if (*flags2_ptr == '\0') { 3243446Smrj flags2_ptr = NULL; 3253446Smrj } 3263446Smrj 3273446Smrj while ((unix_ptr > old_ptr) && (*unix_ptr != ' ')) 3283446Smrj unix_ptr--; 3293446Smrj 3303446Smrj if (unix_ptr == old_ptr) { 3313446Smrj flags1_ptr = NULL; 3323446Smrj } else { 3333446Smrj flags1_ptr = old_ptr; 3343446Smrj } 3353446Smrj 3363446Smrj if (strstr(unix_ptr, "kernel/unix") != NULL) { 3373446Smrj *flags |= BAM_ENTRY_32BIT; 3383446Smrj } else if ((strstr(unix_ptr, "kernel/amd64/unix") == NULL) && 3393446Smrj (!bam_force)) { 3403446Smrj /* 3413446Smrj * If the above strstr returns NULL, but bam_force is 3423446Smrj * set, we'll be upgrading an Install kernel. The 3433446Smrj * result probably won't be what was intended, but we'll 3443446Smrj * try it anyways. 3453446Smrj */ 3463446Smrj return (BAM_SKIP); 3473446Smrj } 3483446Smrj } else if (old_ptr != NULL) { 3493446Smrj flags1_ptr = old_ptr; 3503446Smrj unix_ptr = flags1_ptr + strlen(old_ptr); 3513446Smrj flags2_ptr = NULL; 3523446Smrj } else { 3533446Smrj unix_ptr = flags1_ptr = flags2_ptr = NULL; 3543446Smrj } 3553446Smrj 3563446Smrj if (*flags & BAM_ENTRY_MINIROOT) { 3573446Smrj (void) snprintf(new_arg, total_len, "%s", 3583446Smrj DIRECT_BOOT_FAILSAFE_KERNEL); 3593446Smrj } else if (*flags & BAM_ENTRY_32BIT) { 3603446Smrj (void) snprintf(new_arg, total_len, "%s", DIRECT_BOOT_32); 3613446Smrj } else { 3623446Smrj (void) snprintf(new_arg, total_len, "%s", DIRECT_BOOT_KERNEL); 3633446Smrj } 3643446Smrj 3653446Smrj /* 3663446Smrj * We now want to copy flags1_ptr through unix_ptr, and 3673446Smrj * flags2_ptr through the end of the string 3683446Smrj */ 3693446Smrj if (flags1_ptr != NULL) { 3703446Smrj len = strlcat(new_arg, " ", total_len); 3713446Smrj left = total_len - len; 3723446Smrj new_ptr = new_arg + len; 3733446Smrj 3743446Smrj if ((unix_ptr - flags1_ptr) < left) 3753446Smrj left = (unix_ptr - flags1_ptr) + 1; 3763446Smrj (void) strlcpy(new_ptr, flags1_ptr, left); 3773446Smrj } 3783446Smrj if (flags2_ptr != NULL) { 3793446Smrj (void) strlcat(new_arg, " ", total_len); 3803446Smrj (void) strlcat(new_arg, flags2_ptr, total_len); 3813446Smrj } 3823446Smrj 3833446Smrj done: 3843446Smrj free(linep->arg); 3853446Smrj linep->arg = new_arg; 3863446Smrj update_line(linep); 3873446Smrj return (BAM_SUCCESS); 3883446Smrj } 3893446Smrj 3903446Smrj /* 3913446Smrj * Similar to above, except this time we're looking at a module line, 3923446Smrj * which is quite a bit simpler. 3933446Smrj * 3943446Smrj * Under multiboot, the archive line is: 3953446Smrj * 3963446Smrj * module /platform/i86pc/boot_archive 3973446Smrj * 3983446Smrj * Under directboot, the archive line is: 3993446Smrj * 4003446Smrj * module$ /platform/i86pc/$ISADIR/boot_archive 4013446Smrj * 4023446Smrj * which may be specified exactly as either of: 4033446Smrj * 4043446Smrj * module /platform/i86pc/boot_archive 4053446Smrj * module /platform/i86pc/amd64/boot_archive 4063446Smrj * 4073446Smrj * For either dboot or multiboot, the failsafe is: 4083446Smrj * 4093446Smrj * module /boot/x86.miniroot-safe 4103446Smrj */ 4113446Smrj static error_t 4123446Smrj parse_module_line(line_t *linep, const char *root, uint8_t flags) 4133446Smrj { 4143446Smrj int len; 4153446Smrj menu_cmd_t which; 4163446Smrj char *new; 4173446Smrj 4183446Smrj /* 4193446Smrj * If necessary, BAM_ENTRY_MINIROOT was already set in flags 4203446Smrj * in upgrade_menu(). We re-check BAM_ENTRY_DBOOT here in here 4213446Smrj * in case the kernel and module lines differ. 4223446Smrj */ 4233446Smrj if ((strcmp(linep->arg, DIRECT_BOOT_ARCHIVE) == 0) || 4243446Smrj (strcmp(linep->arg, DIRECT_BOOT_ARCHIVE_64) == 0)) { 4253446Smrj flags |= BAM_ENTRY_DBOOT; 4263446Smrj } else if ((strcmp(linep->arg, MULTI_BOOT_ARCHIVE) == 0) || 4273446Smrj (strcmp(linep->arg, MINIROOT) == 0)) { 4283446Smrj flags &= ~BAM_ENTRY_DBOOT; 4293446Smrj } else { 4303446Smrj bam_error(NO_MODULE_MATCH, linep->lineNum, MENU_URL(root)); 4313446Smrj return (BAM_ERROR); 4323446Smrj } 4333446Smrj 4343446Smrj if (((flags & BAM_ENTRY_DBOOT) && (bam_direct == BAM_DIRECT_DBOOT)) || 4353446Smrj (((flags & BAM_ENTRY_DBOOT) == 0) && 4363446Smrj (bam_direct == BAM_DIRECT_MULTIBOOT)) || 4373446Smrj ((flags & BAM_ENTRY_MINIROOT) && 4383446Smrj (strcmp(linep->cmd, menu_cmds[MODULE_CMD]) == 0))) { 4393446Smrj 4403446Smrj /* No action needed */ 4413446Smrj return (BAM_SUCCESS); 4423446Smrj } 4433446Smrj 4443446Smrj /* 4453446Smrj * Make sure we have the correct cmd - either module or module$ 4463446Smrj * The failsafe entry should always be MODULE_CMD. 4473446Smrj */ 4483446Smrj which = ((bam_direct == BAM_DIRECT_MULTIBOOT) || 4493446Smrj (flags & BAM_ENTRY_MINIROOT)) ? MODULE_CMD : MODULE_DOLLAR_CMD; 4503446Smrj free(linep->cmd); 4513446Smrj len = strlen(menu_cmds[which]) + 1; 4523446Smrj linep->cmd = s_calloc(1, len); 4533446Smrj (void) strncpy(linep->cmd, menu_cmds[which], len); 4543446Smrj 4553446Smrj if (flags & BAM_ENTRY_MINIROOT) { 4563446Smrj new = MINIROOT; 4573446Smrj } else if ((bam_direct == BAM_DIRECT_DBOOT) && 4583446Smrj ((flags & BAM_ENTRY_32BIT) == 0)) { 4593446Smrj new = DIRECT_BOOT_ARCHIVE; 4603446Smrj } else { 4613446Smrj new = MULTI_BOOT_ARCHIVE; 4623446Smrj } 4633446Smrj 4643446Smrj free(linep->arg); 4653446Smrj len = strlen(new) + 1; 4663446Smrj linep->arg = s_calloc(1, len); 4673446Smrj (void) strncpy(linep->arg, new, len); 4683446Smrj update_line(linep); 4693446Smrj 4703446Smrj return (BAM_SUCCESS); 4713446Smrj } 4723446Smrj 4733446Smrj /*ARGSUSED*/ 4743446Smrj error_t 4753446Smrj upgrade_menu(menu_t *mp, char *root, char *opt) 4763446Smrj { 4773446Smrj entry_t *cur_entry; 4783446Smrj line_t *cur_line; 4795084Sjohnlev int i, skipit, num_entries, found_hv; 4803446Smrj int *hand_entries = NULL; 4813446Smrj boolean_t found_kernel = B_FALSE; 4823446Smrj error_t rv; 4833446Smrj char *rootdev, *grubdisk = NULL; 4843446Smrj 4855084Sjohnlev skipit = num_entries = found_hv = 0; 4865084Sjohnlev 4873446Smrj rootdev = get_special(root); 4883446Smrj if (rootdev) { 4893446Smrj grubdisk = os_to_grubdisk(rootdev, strlen(root) == 1); 4903446Smrj free(rootdev); 4913446Smrj rootdev = NULL; 4923446Smrj } 4933446Smrj 4943446Smrj /* Loop through all OS entries in the menu.lst file */ 4953446Smrj for (cur_entry = mp->entries; cur_entry != NULL; 4963446Smrj cur_entry = cur_entry->next, skipit = 0) { 4973446Smrj 4983446Smrj if ((cur_entry->flags & BAM_ENTRY_CHAINLOADER) || 4993446Smrj ((cur_entry->flags & BAM_ENTRY_MINIROOT) && !bam_force)) 5003446Smrj continue; 5013446Smrj 5023446Smrj /* 5033446Smrj * We only change entries added by bootadm and live upgrade, 5043446Smrj * and warn on the rest, unless the -f flag was passed. 5053446Smrj */ 5063446Smrj if ((!(cur_entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU))) && 5073446Smrj !bam_force) { 5083446Smrj if (num_entries == 0) { 5093446Smrj hand_entries = s_calloc(1, sizeof (int)); 5103446Smrj } else { 5113446Smrj hand_entries = s_realloc(hand_entries, 5123446Smrj (num_entries + 1) * sizeof (int)); 5133446Smrj } 5143446Smrj hand_entries[num_entries++] = cur_entry->entryNum; 5153446Smrj continue; 5163446Smrj } 5173446Smrj 5185084Sjohnlev if (cur_entry->flags & BAM_ENTRY_HV) { 5195084Sjohnlev found_hv = 1; 5205084Sjohnlev continue; 5215084Sjohnlev } 5225084Sjohnlev 5233446Smrj /* 5243446Smrj * We make two loops through the lines. First, we check if 5253446Smrj * there is a root entry, and if so, whether we should be 5263446Smrj * checking this entry. 5273446Smrj */ 5283446Smrj if ((grubdisk != NULL) && (cur_entry->flags & BAM_ENTRY_ROOT)) { 5293446Smrj for (cur_line = cur_entry->start; cur_line != NULL; 5303446Smrj cur_line = cur_line->next) { 5313446Smrj if ((cur_line->cmd == NULL) || 5323446Smrj (cur_line->arg == NULL)) 5333446Smrj continue; 5343446Smrj 5353446Smrj if (strcmp(cur_line->cmd, 5363446Smrj menu_cmds[ROOT_CMD]) == 0) { 5373446Smrj if (strcmp(cur_line->arg, 5383446Smrj grubdisk) != 0) { 5393446Smrj /* A different slice */ 5403446Smrj skipit = 1; 5413446Smrj } 5423446Smrj break; 5433446Smrj } 5443446Smrj if (cur_line == cur_entry->end) 5453446Smrj break; 5463446Smrj } 5473446Smrj } 5483446Smrj if (skipit) 5493446Smrj continue; 5503446Smrj 5513446Smrj for (cur_line = cur_entry->start; cur_line != NULL; 5523446Smrj cur_line = cur_line->next) { 5533446Smrj 5543446Smrj /* 5553446Smrj * We only compare for the length of KERNEL_CMD, 5563446Smrj * so that KERNEL_DOLLAR_CMD will also match. 5573446Smrj */ 5583446Smrj if (strncmp(cur_line->cmd, menu_cmds[KERNEL_CMD], 5593446Smrj strlen(menu_cmds[KERNEL_CMD])) == 0) { 5603446Smrj rv = parse_kernel_line(cur_line, root, 5613446Smrj &(cur_entry->flags)); 5623446Smrj if (rv == BAM_SKIP) { 5633446Smrj break; 5643446Smrj } else if (rv != BAM_SUCCESS) { 5653446Smrj return (rv); 5663446Smrj } 5673446Smrj found_kernel = B_TRUE; 5683446Smrj } else if (strncmp(cur_line->cmd, 5693446Smrj menu_cmds[MODULE_CMD], 5703446Smrj strlen(menu_cmds[MODULE_CMD])) == 0) { 5713446Smrj rv = parse_module_line(cur_line, root, 5723446Smrj cur_entry->flags); 5733446Smrj if (rv != BAM_SUCCESS) { 5743446Smrj return (rv); 5753446Smrj } 5763446Smrj } 5773446Smrj if (cur_line == cur_entry->end) 5783446Smrj break; 5793446Smrj } 5803446Smrj } 5813446Smrj 5823446Smrj /* 5835084Sjohnlev * If we're upgrading to a virtualized kernel and there are no 5845084Sjohnlev * hv entries in menu.lst, we need to add one. 5855084Sjohnlev */ 5865084Sjohnlev if ((bam_is_hv == BAM_HV_PRESENT) && (found_hv == 0)) { 5875084Sjohnlev (void) add_boot_entry(mp, NEW_HV_ENTRY, grubdisk, 5885084Sjohnlev XEN_MENU, KERNEL_MODULE_LINE, DIRECT_BOOT_ARCHIVE); 5895084Sjohnlev } 5905084Sjohnlev 5915084Sjohnlev /* 5923446Smrj * We only want to output one error, to avoid confusing a user. We 5933446Smrj * rank "No kernels changed" as a higher priority than "will not 5943446Smrj * update hand-added entries", since the former implies the latter. 5953446Smrj */ 5963446Smrj if (found_kernel == B_FALSE) { 5973446Smrj bam_error(NO_KERNELS_FOUND, MENU_URL(root)); 5983446Smrj return (BAM_ERROR); 5993446Smrj } else if (num_entries > 0) { 6003446Smrj bam_error(HAND_ADDED_ENTRY, MENU_URL(root)); 6013446Smrj bam_print_stderr("Entry Number%s: ", (num_entries > 1) ? 6023446Smrj "s" : ""); 6033446Smrj for (i = 0; i < num_entries; i++) { 6043446Smrj bam_print_stderr("%d ", hand_entries[i]); 6053446Smrj } 6063446Smrj bam_print_stderr("\n"); 6073446Smrj } 6083446Smrj return (BAM_WRITE); 6093446Smrj } 610