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 /* 226448Svikram * Copyright 2008 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; 486448Svikram findroot_t bam_is_findroot = BAM_FINDROOT_UNKNOWN; 496448Svikram 506448Svikram static void 516448Svikram get_findroot_cap(const char *osroot) 526448Svikram { 536448Svikram FILE *fp; 546448Svikram char path[PATH_MAX]; 556448Svikram char buf[BAM_MAXLINE]; 566448Svikram struct stat sb; 576448Svikram int dboot; 586448Svikram int xVM; 596448Svikram int error; 606448Svikram int ret; 616448Svikram const char *fcn = "get_findroot_cap()"; 626448Svikram 636448Svikram assert(is_grub(osroot)); 646448Svikram 656448Svikram (void) snprintf(path, sizeof (path), "%s/%s", 666448Svikram osroot, "boot/grub/capability"); 676448Svikram 686448Svikram if (stat(path, &sb) == -1) { 696448Svikram bam_is_findroot = BAM_FINDROOT_ABSENT; 706448Svikram BAM_DPRINTF((D_FINDROOT_ABSENT, fcn)); 716448Svikram return; 726448Svikram } 736448Svikram 746448Svikram fp = fopen(path, "r"); 756448Svikram error = errno; 766448Svikram INJECT_ERROR1("GET_CAP_FINDROOT_FOPEN", fp = NULL); 776448Svikram if (fp == NULL) { 786448Svikram bam_error(OPEN_FAIL, path, strerror(error)); 796448Svikram return; 806448Svikram } 816448Svikram 826448Svikram dboot = xVM = 0; 836448Svikram while (s_fgets(buf, sizeof (buf), fp) != NULL) { 846448Svikram if (strcmp(buf, "findroot") == 0) { 856448Svikram BAM_DPRINTF((D_FINDROOT_PRESENT, fcn)); 866448Svikram bam_is_findroot = BAM_FINDROOT_PRESENT; 876448Svikram } 886448Svikram if (strcmp(buf, "dboot") == 0) { 896448Svikram BAM_DPRINTF((D_DBOOT_PRESENT, fcn)); 906448Svikram dboot = 1; 916448Svikram } 926448Svikram if (strcmp(buf, "xVM") == 0) { 936448Svikram BAM_DPRINTF((D_XVM_PRESENT, fcn)); 946448Svikram xVM = 1; 956448Svikram } 966448Svikram } 976448Svikram 986448Svikram assert(dboot); 996448Svikram assert(xVM); 1006448Svikram 1016448Svikram if (bam_is_findroot == BAM_FINDROOT_UNKNOWN) { 1026448Svikram bam_is_findroot = BAM_FINDROOT_ABSENT; 1036448Svikram BAM_DPRINTF((D_FINDROOT_ABSENT, fcn)); 1046448Svikram } 1056448Svikram out: 1066448Svikram ret = fclose(fp); 1076448Svikram error = errno; 1086448Svikram INJECT_ERROR1("GET_CAP_FINDROOT_FCLOSE", ret = 1); 1096448Svikram if (ret != 0) { 1106448Svikram bam_error(CLOSE_FAIL, path, strerror(error)); 1116448Svikram } 1126448Svikram } 1133446Smrj 1143446Smrj error_t 1156448Svikram get_boot_cap(const char *osroot) 1163446Smrj { 1176448Svikram char fname[PATH_MAX]; 1186448Svikram char *image; 1196448Svikram uchar_t *ident; 1206448Svikram int fd; 1216448Svikram int m; 1223446Smrj multiboot_header_t *mbh; 1236448Svikram struct stat sb; 1246448Svikram int error; 1256448Svikram const char *fcn = "get_boot_cap()"; 1263446Smrj 1276448Svikram if (is_sparc()) { 1285648Ssetje /* there is no non dboot sparc new-boot */ 1295648Ssetje bam_direct = BAM_DIRECT_DBOOT; 1306448Svikram BAM_DPRINTF((D_IS_SPARC_DBOOT, fcn)); 1315648Ssetje return (BAM_SUCCESS); 1325648Ssetje } 1335648Ssetje 1346448Svikram if (!is_grub(osroot)) { 1356448Svikram bam_error(NOT_GRUB_ROOT, osroot); 1366448Svikram return (BAM_ERROR); 1376448Svikram } 1386448Svikram 1396448Svikram (void) snprintf(fname, PATH_MAX, "%s/%s", osroot, 1403446Smrj "platform/i86pc/kernel/unix"); 1413446Smrj fd = open(fname, O_RDONLY); 1426448Svikram error = errno; 1436448Svikram INJECT_ERROR1("GET_CAP_UNIX_OPEN", fd = -1); 1443446Smrj if (fd < 0) { 1456448Svikram bam_error(OPEN_FAIL, fname, strerror(error)); 1466448Svikram return (BAM_ERROR); 1476448Svikram } 1486448Svikram 1496448Svikram /* 1506448Svikram * Verify that this is a sane unix at least 8192 bytes in length 1516448Svikram */ 1526448Svikram if (fstat(fd, &sb) == -1 || sb.st_size < 8192) { 1536448Svikram (void) close(fd); 1546448Svikram bam_error(INVALID_BINARY, fname); 1553446Smrj return (BAM_ERROR); 1563446Smrj } 1573446Smrj 1583446Smrj /* 1593446Smrj * mmap the first 8K 1603446Smrj */ 1613446Smrj image = mmap(NULL, 8192, PROT_READ, MAP_SHARED, fd, 0); 1626448Svikram error = errno; 1636448Svikram INJECT_ERROR1("GET_CAP_MMAP", image = MAP_FAILED); 1643446Smrj if (image == MAP_FAILED) { 1656448Svikram bam_error(MMAP_FAIL, fname, strerror(error)); 1663446Smrj return (BAM_ERROR); 1673446Smrj } 1683446Smrj 1693446Smrj ident = (uchar_t *)image; 1703446Smrj if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 || 1713446Smrj ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) { 1723446Smrj bam_error(NOT_ELF_FILE, fname); 1733446Smrj return (BAM_ERROR); 1743446Smrj } 1753446Smrj if (ident[EI_CLASS] != ELFCLASS32) { 1763446Smrj bam_error(WRONG_ELF_CLASS, fname, ident[EI_CLASS]); 1773446Smrj return (BAM_ERROR); 1783446Smrj } 1793446Smrj 1803446Smrj /* 1813446Smrj * The GRUB multiboot header must be 32-bit aligned and completely 1823446Smrj * contained in the 1st 8K of the file. If the unix binary has 1833446Smrj * a multiboot header, then it is a 'dboot' kernel. Otherwise, 1843446Smrj * this kernel must be booted via multiboot -- we call this a 1853446Smrj * 'multiboot' kernel. 1863446Smrj */ 1873446Smrj bam_direct = BAM_DIRECT_MULTIBOOT; 1883446Smrj for (m = 0; m < 8192 - sizeof (multiboot_header_t); m += 4) { 1893446Smrj mbh = (void *)(image + m); 1903446Smrj if (mbh->magic == MB_HEADER_MAGIC) { 1916448Svikram BAM_DPRINTF((D_IS_DBOOT, fcn)); 1923446Smrj bam_direct = BAM_DIRECT_DBOOT; 1933446Smrj break; 1943446Smrj } 1953446Smrj } 1963446Smrj (void) munmap(image, 8192); 1973446Smrj (void) close(fd); 1985084Sjohnlev 1996448Svikram INJECT_ERROR1("GET_CAP_MULTIBOOT", bam_direct = BAM_DIRECT_MULTIBOOT); 2005084Sjohnlev if (bam_direct == BAM_DIRECT_DBOOT) { 2016448Svikram (void) snprintf(fname, PATH_MAX, "%s/%s", osroot, XEN_32); 2025084Sjohnlev if (stat(fname, &sb) == 0) { 2035084Sjohnlev bam_is_hv = BAM_HV_PRESENT; 2046448Svikram BAM_DPRINTF((D_IS_XVM, fcn)); 2055084Sjohnlev } else { 2065084Sjohnlev bam_is_hv = BAM_HV_NO; 2076448Svikram BAM_DPRINTF((D_IS_NOT_XVM, fcn)); 2085084Sjohnlev } 2096448Svikram } else { 2106448Svikram BAM_DPRINTF((D_IS_MULTIBOOT, fcn)); 2115084Sjohnlev } 2125084Sjohnlev 2136448Svikram /* Not a fatal error if this fails */ 2146448Svikram get_findroot_cap(osroot); 2156448Svikram 2166448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 2173446Smrj return (BAM_SUCCESS); 2183446Smrj } 2193446Smrj 2203446Smrj #define INST_RELEASE "var/sadm/system/admin/INST_RELEASE" 2213446Smrj 2223446Smrj /* 2233446Smrj * Return true if root has been bfu'ed. bfu will blow away 2243446Smrj * var/sadm/system/admin/INST_RELEASE, so if it's still there, we can 2253446Smrj * assume the system has not been bfu'ed. 2263446Smrj */ 2273446Smrj static int 2283446Smrj is_bfu_system(const char *root) 2293446Smrj { 2306448Svikram static int is_bfu = -1; 2316448Svikram char path[PATH_MAX]; 2326448Svikram struct stat sb; 2336448Svikram const char *fcn = "is_bfu_system()"; 2343446Smrj 2356448Svikram if (is_bfu != -1) { 2366448Svikram BAM_DPRINTF((D_ALREADY_BFU_TEST, fcn, is_bfu ? "" : "NOT")); 2373446Smrj return (is_bfu); 2386448Svikram } 2393446Smrj 2403446Smrj (void) snprintf(path, sizeof (path), "%s/%s", root, INST_RELEASE); 2413446Smrj if (stat(path, &sb) != 0) { 2423446Smrj is_bfu = 1; 2436448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 2443446Smrj } else { 2453446Smrj is_bfu = 0; 2466448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 2473446Smrj } 2483446Smrj return (is_bfu); 2493446Smrj } 2503446Smrj 2513446Smrj #define MENU_URL(root) (is_bfu_system(root) ? \ 2523446Smrj "http://www.sun.com/msg/SUNOS-8000-CF" : \ 2533446Smrj "http://www.sun.com/msg/SUNOS-8000-AK") 2543446Smrj 2553446Smrj /* 2563446Smrj * Simply allocate a new line and copy in cmd + sep + arg 2573446Smrj */ 2583446Smrj void 2593446Smrj update_line(line_t *linep) 2603446Smrj { 2616448Svikram size_t size; 2626448Svikram const char *fcn = "update_line()"; 2633446Smrj 2646448Svikram BAM_DPRINTF((D_UPDATE_LINE_BEFORE, fcn, linep->line)); 2653446Smrj free(linep->line); 2663446Smrj size = strlen(linep->cmd) + strlen(linep->sep) + strlen(linep->arg) + 1; 2673446Smrj linep->line = s_calloc(1, size); 2683446Smrj (void) snprintf(linep->line, size, "%s%s%s", linep->cmd, linep->sep, 2693446Smrj linep->arg); 2706448Svikram BAM_DPRINTF((D_UPDATE_LINE_AFTER, fcn, linep->line)); 2716448Svikram } 2726448Svikram 2736448Svikram static char * 2746448Svikram skip_wspace(char *ptr) 2756448Svikram { 2766448Svikram const char *fcn = "skip_wspace()"; 2776448Svikram 2786448Svikram INJECT_ERROR1("SKIP_WSPACE", ptr = NULL); 2796448Svikram if (ptr == NULL) { 2806448Svikram BAM_DPRINTF((D_SKIP_WSPACE_PTR_NULL, fcn)); 2816448Svikram return (NULL); 2826448Svikram } 2836448Svikram 2846448Svikram BAM_DPRINTF((D_SKIP_WSPACE_ENTRY_PTR, fcn, ptr)); 2856448Svikram for (; *ptr != '\0'; ptr++) { 2866448Svikram if ((*ptr != ' ') && (*ptr != '\t') && 2876448Svikram (*ptr != '\n')) 2886448Svikram break; 2896448Svikram } 2906448Svikram 2916448Svikram ptr = (*ptr == '\0' ? NULL : ptr); 2926448Svikram 2936448Svikram BAM_DPRINTF((D_SKIP_WSPACE_EXIT_PTR, fcn, ptr ? ptr : "NULL")); 2946448Svikram 2956448Svikram return (ptr); 2966448Svikram } 2976448Svikram 2986448Svikram static char * 2996448Svikram rskip_bspace(char *bound, char *ptr) 3006448Svikram { 3016448Svikram const char *fcn = "rskip_bspace()"; 3026448Svikram assert(bound); 3036448Svikram assert(ptr); 3046448Svikram assert(bound <= ptr); 3056448Svikram assert(*bound != ' ' && *bound != '\t' && *bound != '\n'); 3066448Svikram 3076448Svikram BAM_DPRINTF((D_RSKIP_BSPACE_ENTRY, fcn, ptr)); 3086448Svikram for (; ptr > bound; ptr--) { 3096448Svikram if (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') 3106448Svikram break; 3116448Svikram } 3126448Svikram 3136448Svikram BAM_DPRINTF((D_RSKIP_BSPACE_EXIT, fcn, ptr)); 3146448Svikram return (ptr); 3153446Smrj } 3163446Smrj 3173446Smrj /* 3183446Smrj * The parse_kernel_line function examines a menu.lst kernel line. For 3193446Smrj * multiboot, this is: 3203446Smrj * 3213446Smrj * kernel <multiboot path> <flags1> <kernel path> <flags2> 3223446Smrj * 3233446Smrj * <multiboot path> is either /platform/i86pc/multiboot or /boot/multiboot 3243446Smrj * 3253446Smrj * <kernel path> may be missing, or may be any full or relative path to unix. 3263446Smrj * We check for it by looking for a word ending in "/unix". If it ends 3273446Smrj * in "kernel/unix", we upgrade it to a 32-bit entry. If it ends in 3283446Smrj * "kernel/amd64/unix", we upgrade it to the default entry. Otherwise, 3293446Smrj * it's a custom kernel, and we skip it. 3303446Smrj * 3313446Smrj * <flags*> are anything that doesn't fit either of the above - these will be 3323446Smrj * copied over. 3333446Smrj * 3343446Smrj * For direct boot, the defaults are 3353446Smrj * 3363446Smrj * kernel$ <kernel path> <flags> 3373446Smrj * 3383446Smrj * <kernel path> is one of: 3393446Smrj * /platform/i86pc/kernel/$ISADIR/unix 3403446Smrj * /platform/i86pc/kernel/unix 3413446Smrj * /platform/i86pc/kernel/amd64/unix 3423446Smrj * /boot/platform/i86pc/kernel/unix 3433446Smrj * 3443446Smrj * If <kernel path> is any of the last three, the command may also be "kernel". 3453446Smrj * 3463446Smrj * <flags> is anything that isn't <kernel path>. 3473446Smrj * 3486448Svikram * This function is only called to convert a multiboot entry to a dboot entry 3493446Smrj * 3503446Smrj * For safety, we do one more check: if the kernel path starts with /boot, 3513446Smrj * we verify that the new kernel exists before changing it. This is mainly 3523446Smrj * done for bfu, as it may cause the failsafe archives to be a different 3533446Smrj * boot architecture from the newly bfu'ed system. 3543446Smrj */ 3553446Smrj static error_t 3566448Svikram cvt_kernel_line(line_t *line, const char *osroot, entry_t *entry) 3573446Smrj { 3586448Svikram char path[PATH_MAX]; 3596448Svikram char linebuf[PATH_MAX]; 3606448Svikram char new_arg[PATH_MAX]; 3616448Svikram struct stat sb; 3626448Svikram char *old_ptr; 3636448Svikram char *unix_ptr; 3646448Svikram char *flags1_ptr; 3656448Svikram char *flags2_ptr; 3666448Svikram const char *fcn = "cvt_kernel_line()"; 3673446Smrj 3686448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, line->line, osroot)); 3693446Smrj 3703446Smrj /* 3716448Svikram * We only convert multiboot to dboot and nothing else. 3723446Smrj */ 3736448Svikram if (!(entry->flags & BAM_ENTRY_MULTIBOOT)) { 3746448Svikram BAM_DPRINTF((D_NOT_MULTIBOOT_CONVERT, fcn)); 3753446Smrj return (BAM_SUCCESS); 3763446Smrj } 3773446Smrj 3786448Svikram if (entry->flags & BAM_ENTRY_FAILSAFE) { 3793446Smrj /* 3806448Svikram * We're attempting to change failsafe to dboot. 3816448Svikram * In the bfu case, we may not have a dboot failsafe 3826448Svikram * kernel i.e. a "unix" under the "/boot" hierarchy. 3836448Svikram * If so, just emit a message in verbose mode and 3846448Svikram * return success. 3853446Smrj */ 3866448Svikram BAM_DPRINTF((D_TRYING_FAILSAFE_CVT_TO_DBOOT, fcn)); 3876448Svikram (void) snprintf(path, PATH_MAX, "%s%s", osroot, 3883446Smrj DIRECT_BOOT_FAILSAFE_KERNEL); 3893446Smrj if (stat(path, &sb) != 0) { 3903446Smrj if (bam_verbose) { 3916448Svikram bam_error(FAILSAFE_MISSING, line->lineNum); 3923446Smrj } 3936448Svikram BAM_DPRINTF((D_NO_FAILSAFE_UNIX_CONVERT, fcn)); 3943446Smrj return (BAM_SUCCESS); 3953446Smrj } 3963446Smrj } 3973446Smrj 3983446Smrj /* 3993446Smrj * Make sure we have the correct cmd - either kernel or kernel$ 4006448Svikram * The failsafe entry should always be kernel. 4013446Smrj */ 4026448Svikram if (!(entry->flags & BAM_ENTRY_FAILSAFE)) { 4036448Svikram free(line->cmd); 4046448Svikram line->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]); 4056448Svikram BAM_DPRINTF((D_CVT_CMD_KERN_DOLLAR, fcn, line->cmd)); 4066448Svikram } 4076448Svikram 4086448Svikram assert(sizeof (linebuf) > strlen(line->arg) + 32); 4096448Svikram (void) strlcpy(linebuf, line->arg, sizeof (linebuf)); 4103446Smrj 4116448Svikram old_ptr = strpbrk(linebuf, " \t\n"); 4126448Svikram old_ptr = skip_wspace(old_ptr); 4136448Svikram if (old_ptr == NULL) { 4146448Svikram /* 4156448Svikram * only multiboot and nothing else 4166448Svikram * i.e. flags1 = unix = flags2 = NULL 4176448Svikram */ 4186448Svikram flags1_ptr = unix_ptr = flags2_ptr = NULL; 4196448Svikram BAM_DPRINTF((D_FLAGS1_UNIX_FLAGS2_NULL, fcn)) 4206448Svikram goto create; 4213446Smrj } 4223446Smrj 4233446Smrj /* 4243446Smrj * 4256448Svikram * old_ptr is either at "flags1" or "unix" 4263446Smrj */ 4276448Svikram if (unix_ptr = strstr(old_ptr, "/unix")) { 4286448Svikram 4296448Svikram /* 4306448Svikram * There is a unix. 4316448Svikram */ 4326448Svikram BAM_DPRINTF((D_UNIX_PRESENT, fcn)); 4336448Svikram 4346448Svikram /* See if there's a flags2 past unix */ 4356448Svikram flags2_ptr = unix_ptr + strlen("/unix"); 4366448Svikram flags2_ptr = skip_wspace(flags2_ptr); 4376448Svikram if (flags2_ptr) { 4386448Svikram BAM_DPRINTF((D_FLAGS2_PRESENT, fcn, flags2_ptr)); 4396448Svikram } else { 4406448Svikram BAM_DPRINTF((D_FLAGS2_ABSENT, fcn)); 4413446Smrj } 4423446Smrj 4436448Svikram /* see if there is a flags1 before unix */ 4446448Svikram unix_ptr = rskip_bspace(old_ptr, unix_ptr); 4453446Smrj 4463446Smrj if (unix_ptr == old_ptr) { 4473446Smrj flags1_ptr = NULL; 4486448Svikram BAM_DPRINTF((D_FLAGS1_ABSENT, fcn)); 4493446Smrj } else { 4503446Smrj flags1_ptr = old_ptr; 4516448Svikram *unix_ptr = '\0'; 4526448Svikram unix_ptr++; 4536448Svikram BAM_DPRINTF((D_FLAGS1_PRESENT, fcn, flags1_ptr)); 4543446Smrj } 4553446Smrj 4566448Svikram } else { 4576448Svikram /* There is no unix, there is only a bunch of flags */ 4583446Smrj flags1_ptr = old_ptr; 4596448Svikram unix_ptr = flags2_ptr = NULL; 4606448Svikram BAM_DPRINTF((D_FLAGS1_ONLY, fcn, flags1_ptr)); 4613446Smrj } 4623446Smrj 4633446Smrj /* 4646448Svikram * With dboot, unix is fixed and is at the beginning. We need to 4656448Svikram * migrate flags1 and flags2 4663446Smrj */ 4676448Svikram create: 4686448Svikram if (entry->flags & BAM_ENTRY_FAILSAFE) { 4696448Svikram (void) snprintf(new_arg, sizeof (new_arg), "%s", 4706448Svikram DIRECT_BOOT_FAILSAFE_KERNEL); 4716448Svikram } else { 4726448Svikram (void) snprintf(new_arg, sizeof (new_arg), "%s", 4736448Svikram DIRECT_BOOT_KERNEL); 4746448Svikram } 4756448Svikram BAM_DPRINTF((D_CVTED_UNIX, fcn, new_arg)); 4763446Smrj 4776448Svikram if (flags1_ptr != NULL) { 4786448Svikram (void) strlcat(new_arg, " ", sizeof (new_arg)); 4796448Svikram (void) strlcat(new_arg, flags1_ptr, sizeof (new_arg)); 4803446Smrj } 4813446Smrj 4826448Svikram if (flags2_ptr != NULL) { 4836448Svikram (void) strlcat(new_arg, " ", sizeof (new_arg)); 4846448Svikram (void) strlcat(new_arg, flags2_ptr, sizeof (new_arg)); 4856448Svikram } 4866448Svikram 4876448Svikram BAM_DPRINTF((D_CVTED_UNIX_AND_FLAGS, fcn, new_arg)); 4886448Svikram 4896448Svikram free(line->arg); 4906448Svikram line->arg = s_strdup(new_arg); 4916448Svikram update_line(line); 4926448Svikram BAM_DPRINTF((D_CVTED_KERNEL_LINE, fcn, line->line)); 4933446Smrj return (BAM_SUCCESS); 4943446Smrj } 4953446Smrj 4963446Smrj /* 4973446Smrj * Similar to above, except this time we're looking at a module line, 4983446Smrj * which is quite a bit simpler. 4993446Smrj * 5003446Smrj * Under multiboot, the archive line is: 5013446Smrj * 5023446Smrj * module /platform/i86pc/boot_archive 5033446Smrj * 5043446Smrj * Under directboot, the archive line is: 5053446Smrj * 5063446Smrj * module$ /platform/i86pc/$ISADIR/boot_archive 5073446Smrj * 5083446Smrj * which may be specified exactly as either of: 5093446Smrj * 5103446Smrj * module /platform/i86pc/boot_archive 5113446Smrj * module /platform/i86pc/amd64/boot_archive 5123446Smrj * 5133446Smrj * For either dboot or multiboot, the failsafe is: 5143446Smrj * 5153446Smrj * module /boot/x86.miniroot-safe 5163446Smrj */ 5173446Smrj static error_t 5186448Svikram cvt_module_line(line_t *line, entry_t *entry) 5193446Smrj { 5206448Svikram const char *fcn = "cvt_module_line()"; 5216448Svikram 5226448Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, line->line)); 5233446Smrj 5243446Smrj /* 5256448Svikram * We only convert multiboot to dboot and nothing else 5263446Smrj */ 5276448Svikram if (!(entry->flags & BAM_ENTRY_MULTIBOOT)) { 5286448Svikram BAM_DPRINTF((D_NOT_MULTIBOOT_CONVERT, fcn)); 5293446Smrj return (BAM_SUCCESS); 5303446Smrj } 5313446Smrj 5326448Svikram if (entry->flags & BAM_ENTRY_FAILSAFE) { 5336448Svikram if (strcmp(line->arg, FAILSAFE_ARCHIVE) == 0) { 5346448Svikram BAM_DPRINTF((D_FAILSAFE_NO_CVT_NEEDED, fcn, line->arg)); 5356448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5366448Svikram return (BAM_SUCCESS); 5376448Svikram } 5386448Svikram } else if (strcmp(line->arg, MULTIBOOT_ARCHIVE) != 0) { 5396448Svikram bam_error(UNKNOWN_MODULE_LINE, line->lineNum); 5406448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5416448Svikram return (BAM_MSG); 5426448Svikram } 5436448Svikram 5446448Svikram if (entry->flags & BAM_ENTRY_FAILSAFE) { 5456448Svikram free(line->cmd); 5466448Svikram free(line->arg); 5476448Svikram line->cmd = s_strdup(menu_cmds[MODULE_CMD]); 5486448Svikram line->arg = s_strdup(FAILSAFE_ARCHIVE); 5496448Svikram } else { 5506448Svikram free(line->cmd); 5516448Svikram free(line->arg); 5526448Svikram line->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]); 5536448Svikram line->arg = s_strdup(DIRECT_BOOT_ARCHIVE); 5546448Svikram } 5556448Svikram 5566448Svikram update_line(line); 5576448Svikram BAM_DPRINTF((D_CVTED_MODULE, fcn, line->line)); 5586448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5596448Svikram return (BAM_SUCCESS); 5606448Svikram } 5616448Svikram 5626448Svikram static void 5636448Svikram bam_warn_hand_entries(menu_t *mp, char *osroot) 5646448Svikram { 5656448Svikram int hand_num; 5666448Svikram int hand_max; 5676448Svikram int *hand_list; 5686448Svikram int i; 5696448Svikram entry_t *entry; 5706448Svikram const char *fcn = "bam_warn_hand_entries()"; 5716448Svikram 5726448Svikram if (bam_force) { 5736448Svikram /* 5746448Svikram * No warning needed, we are automatically converting 5756448Svikram * the "hand" entries 5766448Svikram */ 5776448Svikram BAM_DPRINTF((D_FORCE_HAND_CVT, fcn)); 5786448Svikram return; 5796448Svikram } 5806448Svikram 5816448Svikram hand_num = 0; 5826448Svikram hand_max = BAM_ENTRY_NUM; 5836448Svikram hand_list = s_calloc(1, hand_max); 5846448Svikram 5856448Svikram for (entry = mp->entries; entry; entry = entry->next) { 5866448Svikram if (entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) 5876448Svikram continue; 5886448Svikram BAM_DPRINTF((D_FOUND_HAND, fcn, entry->entryNum)); 5896448Svikram if (++hand_num > hand_max) { 5906448Svikram hand_max *= 2; 5916448Svikram hand_list = s_realloc(hand_list, 5926448Svikram hand_max * sizeof (int)); 5936448Svikram } 5946448Svikram hand_list[hand_num - 1] = entry->entryNum; 5956448Svikram } 5966448Svikram 5976448Svikram bam_error(HAND_ADDED_ENTRIES, osroot, MENU_URL(osroot)); 5986448Svikram bam_print_stderr("Entry Number%s: ", (hand_num > 1) ? 5996448Svikram "s" : ""); 6006448Svikram for (i = 0; i < hand_num; i++) { 6016448Svikram bam_print_stderr("%d ", hand_list[i]); 6026448Svikram } 6036448Svikram bam_print_stderr("\n"); 6046448Svikram } 6053446Smrj 6066448Svikram static entry_t * 6076448Svikram find_matching_entry( 6086448Svikram entry_t *estart, 6096448Svikram char *grubsign, 6106448Svikram char *grubroot, 6116448Svikram int root_opt) 6126448Svikram { 6136448Svikram entry_t *entry; 6146448Svikram line_t *line; 6156448Svikram char opt[10]; 6166448Svikram const char *fcn = "find_matching_entry()"; 6176448Svikram 6186448Svikram assert(grubsign); 6196448Svikram assert(root_opt == 0 || root_opt == 1); 6206448Svikram 6216448Svikram (void) snprintf(opt, sizeof (opt), "%d", root_opt); 6226448Svikram BAM_DPRINTF((D_FUNC_ENTRY3, fcn, grubsign, grubroot, opt)); 6236448Svikram 6246448Svikram for (entry = estart; entry; entry = entry->next) { 625*6694Svikram 6266448Svikram if (!(entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) && 6276448Svikram !bam_force) { 6286448Svikram BAM_DPRINTF((D_SKIP_ENTRY, fcn, entry->entryNum)); 6296448Svikram continue; 6306448Svikram } 6316448Svikram 6326448Svikram if (entry->flags & BAM_ENTRY_ROOT) { 6336448Svikram for (line = entry->start; line; line = line->next) { 6346448Svikram if (line->cmd == NULL || line->arg == NULL) { 6356448Svikram if (line == entry->end) { 6366448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 6376448Svikram break; 6386448Svikram } else { 6396448Svikram BAM_DPRINTF((D_SKIP_NULL, fcn)); 6406448Svikram continue; 6416448Svikram } 6426448Svikram } 6436448Svikram if (strcmp(line->cmd, menu_cmds[ROOT_CMD]) 6446448Svikram == 0 && strcmp(line->arg, grubroot) == 0) { 6456448Svikram BAM_DPRINTF((D_ROOT_MATCH, fcn, 6466448Svikram line->line, grubsign)); 6476448Svikram return (entry); 6486448Svikram } 6496448Svikram if (line == entry->end) { 6506448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 6516448Svikram break; 6526448Svikram } 6536448Svikram } 6546448Svikram } else if (entry->flags & BAM_ENTRY_FINDROOT) { 6556448Svikram for (line = entry->start; line; line = line->next) { 6566448Svikram if (line->cmd == NULL || line->arg == NULL) { 6576448Svikram if (line == entry->end) { 6586448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 6596448Svikram break; 6606448Svikram } else { 6616448Svikram BAM_DPRINTF((D_SKIP_NULL, fcn)); 6626448Svikram continue; 6636448Svikram } 6646448Svikram } 6656448Svikram if (strcmp(line->cmd, menu_cmds[FINDROOT_CMD]) 6666448Svikram == 0 && strcmp(line->arg, grubsign) == 0) { 6676448Svikram BAM_DPRINTF((D_FINDROOT_MATCH, fcn, 6686448Svikram line->line, grubsign)); 6696448Svikram return (entry); 6706448Svikram } 6716448Svikram if (line == entry->end) { 6726448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 6736448Svikram break; 6746448Svikram } 6756448Svikram } 6766448Svikram } else if (root_opt) { 6776448Svikram /* Neither root nor findroot */ 6786448Svikram BAM_DPRINTF((D_NO_ROOT_FINDROOT, fcn, entry->entryNum)); 6796448Svikram return (entry); 6806448Svikram } 6813446Smrj } 6823446Smrj 6836448Svikram BAM_DPRINTF((D_NO_MATCH, fcn)); 6846448Svikram return (NULL); 6856448Svikram } 6866448Svikram 6876448Svikram /* 6886448Svikram * The following is a set of routines that attempt to convert the 6896448Svikram * menu entries for the supplied osroot into a format compatible 6906448Svikram * with the GRUB installation on osroot. 6916448Svikram * 6926448Svikram * Each of these conversion routines make no assumptions about 6936448Svikram * the current state of the menu entry, it does its best to 6946448Svikram * convert the menu entry to the new state. In the process 6956448Svikram * we may either upgrade or downgrade. 6966448Svikram * 6976448Svikram * We don't make any heroic efforts at conversion. It is better 6986448Svikram * to be conservative and bail out at the first sign of error. We will 6996448Svikram * in such cases, point the user at the knowledge-base article 7006448Svikram * so that they can upgrade manually. 7016448Svikram */ 7026448Svikram static error_t 7036448Svikram bam_add_findroot(menu_t *mp, char *grubsign, char *grubroot, int root_opt) 7046448Svikram { 7056448Svikram entry_t *entry; 7066448Svikram line_t *line; 7076448Svikram line_t *newlp; 7086448Svikram int update_num; 7096448Svikram char linebuf[PATH_MAX]; 7106448Svikram const char *fcn = "bam_add_findroot()"; 7116448Svikram 7126448Svikram update_num = 0; 7136448Svikram 7146448Svikram bam_print(CVT_FINDROOT); 7156448Svikram 7166448Svikram entry = mp->entries; 7176448Svikram for (; entry = find_matching_entry(entry, grubsign, grubroot, root_opt); 7186448Svikram entry = entry->next) { 7196448Svikram if (entry->flags & BAM_ENTRY_FINDROOT) { 7206448Svikram /* already converted */ 7216448Svikram BAM_DPRINTF((D_ALREADY_FINDROOT, fcn, entry->entryNum)); 7226448Svikram continue; 7236448Svikram } 7246448Svikram for (line = entry->start; line; line = line->next) { 7256448Svikram if (line->cmd == NULL || line->arg == NULL) { 7266448Svikram if (line == entry->end) { 7276448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 7286448Svikram break; 7296448Svikram } else { 7306448Svikram BAM_DPRINTF((D_SKIP_NULL, fcn)); 7316448Svikram continue; 7326448Svikram } 7336448Svikram } 7346448Svikram if (strcmp(line->cmd, menu_cmds[TITLE_CMD]) == 0) { 7356448Svikram newlp = s_calloc(1, sizeof (line_t)); 7366448Svikram newlp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]); 7376448Svikram newlp->sep = s_strdup(" "); 7386448Svikram newlp->arg = s_strdup(grubsign); 7396448Svikram (void) snprintf(linebuf, sizeof (linebuf), 7406448Svikram "%s%s%s", newlp->cmd, newlp->sep, 7416448Svikram newlp->arg); 7426448Svikram newlp->line = s_strdup(linebuf); 7436448Svikram bam_add_line(mp, entry, line, newlp); 7446448Svikram update_num = 1; 7456448Svikram entry->flags &= ~BAM_ENTRY_ROOT; 7466448Svikram entry->flags |= BAM_ENTRY_FINDROOT; 7476448Svikram BAM_DPRINTF((D_ADDED_FINDROOT, fcn, 7486448Svikram newlp->line)); 7496448Svikram line = newlp; 7506448Svikram } 7516448Svikram if (strcmp(line->cmd, menu_cmds[ROOT_CMD]) == 0) { 7526448Svikram BAM_DPRINTF((D_FREEING_ROOT, fcn, line->line)); 7536448Svikram unlink_line(mp, line); 7546448Svikram line_free(line); 7556448Svikram } 7566448Svikram if (line == entry->end) { 7576448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 7586448Svikram break; 7596448Svikram } 7606448Svikram } 7616448Svikram } 7626448Svikram 7636448Svikram if (update_num) { 7646448Svikram BAM_DPRINTF((D_UPDATED_NUMBERING, fcn)); 7656448Svikram update_numbering(mp); 7666448Svikram } 7676448Svikram 7686448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7696448Svikram return (BAM_SUCCESS); 7706448Svikram } 7716448Svikram 7726448Svikram static error_t 7736448Svikram bam_add_hv(menu_t *mp, char *grubsign, char *grubroot, int root_opt) 7746448Svikram { 7756448Svikram entry_t *entry; 7766448Svikram const char *fcn = "bam_add_hv()"; 7776448Svikram 7786448Svikram bam_print(CVT_HV); 7796448Svikram 7806448Svikram entry = mp->entries; 7816448Svikram for (; entry = find_matching_entry(entry, grubsign, grubroot, root_opt); 7826448Svikram entry = entry->next) { 7836448Svikram if (entry->flags & BAM_ENTRY_HV) { 7846448Svikram BAM_DPRINTF((D_ALREADY_HV, fcn, entry->entryNum)); 7856448Svikram return (BAM_SUCCESS); 7866448Svikram } 7876448Svikram } 7886448Svikram 7896448Svikram (void) add_boot_entry(mp, NEW_HV_ENTRY, grubsign, XEN_MENU, 7906448Svikram XEN_KERNEL_MODULE_LINE, DIRECT_BOOT_ARCHIVE); 7916448Svikram 7926448Svikram BAM_DPRINTF((D_ADDED_XVM_ENTRY, fcn)); 7936448Svikram 7946448Svikram update_numbering(mp); 7956448Svikram 7966448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7973446Smrj 7983446Smrj return (BAM_SUCCESS); 7993446Smrj } 8003446Smrj 8016448Svikram static error_t 8026448Svikram bam_add_dboot( 8036448Svikram menu_t *mp, 8046448Svikram char *osroot, 8056448Svikram char *grubsign, 8066448Svikram char *grubroot, 8076448Svikram int root_opt) 8086448Svikram { 8096448Svikram int msg = 0; 8106448Svikram entry_t *entry; 8116448Svikram line_t *line; 8126448Svikram error_t ret; 8136448Svikram const char *fcn = "bam_add_dboot()"; 8146448Svikram 8156448Svikram bam_print(CVT_DBOOT); 8166448Svikram 8176448Svikram entry = mp->entries; 8186448Svikram for (; entry = find_matching_entry(entry, grubsign, grubroot, root_opt); 8196448Svikram entry = entry->next) { 8206448Svikram for (line = entry->start; line; line = line->next) { 8216448Svikram if (line->cmd == NULL || line->arg == NULL) { 8226448Svikram if (line == entry->end) { 8236448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 8246448Svikram break; 8256448Svikram } else { 8266448Svikram BAM_DPRINTF((D_SKIP_NULL, fcn)); 8276448Svikram continue; 8286448Svikram } 8296448Svikram } 8306448Svikram 8316448Svikram /* 8326448Svikram * If we have a kernel$ command, assume it 8336448Svikram * is dboot already. If it is not a dboot 8346448Svikram * entry, something funny is going on and 8356448Svikram * we will leave it alone 8366448Svikram */ 8376448Svikram if (strcmp(line->cmd, menu_cmds[KERNEL_CMD]) == 0) { 8386448Svikram ret = cvt_kernel_line(line, osroot, entry); 8396448Svikram INJECT_ERROR1("ADD_DBOOT_KERN_ERR", 8406448Svikram ret = BAM_ERROR); 8416448Svikram INJECT_ERROR1("ADD_DBOOT_KERN_MSG", 8426448Svikram ret = BAM_MSG); 8436448Svikram if (ret == BAM_ERROR) { 8446448Svikram BAM_DPRINTF((D_CVT_KERNEL_FAIL, fcn)); 8456448Svikram return (ret); 8466448Svikram } else if (ret == BAM_MSG) { 8476448Svikram msg = 1; 8486448Svikram BAM_DPRINTF((D_CVT_KERNEL_MSG, fcn)); 8496448Svikram } 8506448Svikram } 8516448Svikram if (strcmp(line->cmd, menu_cmds[MODULE_CMD]) == 0) { 8526448Svikram ret = cvt_module_line(line, entry); 8536448Svikram INJECT_ERROR1("ADD_DBOOT_MOD_ERR", 8546448Svikram ret = BAM_ERROR); 8556448Svikram INJECT_ERROR1("ADD_DBOOT_MOD_MSG", 8566448Svikram ret = BAM_MSG); 8576448Svikram if (ret == BAM_ERROR) { 8586448Svikram BAM_DPRINTF((D_CVT_MODULE_FAIL, fcn)); 8596448Svikram return (ret); 8606448Svikram } else if (ret == BAM_MSG) { 8616448Svikram BAM_DPRINTF((D_CVT_MODULE_MSG, fcn)); 8626448Svikram msg = 1; 8636448Svikram } 8646448Svikram } 8656448Svikram 8666448Svikram if (line == entry->end) { 8676448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 8686448Svikram break; 8696448Svikram } 8706448Svikram } 8716448Svikram } 8726448Svikram 8736448Svikram ret = msg ? BAM_MSG : BAM_SUCCESS; 8746448Svikram BAM_DPRINTF((D_RETURN_RET, fcn, ret)); 8756448Svikram return (ret); 8766448Svikram } 8776448Svikram 8783446Smrj /*ARGSUSED*/ 8793446Smrj error_t 8806448Svikram upgrade_menu(menu_t *mp, char *osroot, char *menu_root) 8813446Smrj { 8826448Svikram char *osdev; 8836448Svikram char *grubsign; 8846448Svikram char *grubroot; 8856448Svikram int ret1; 8866448Svikram int ret2; 8876448Svikram int ret3; 8886448Svikram const char *fcn = "upgrade_menu()"; 8895084Sjohnlev 8906448Svikram assert(osroot); 8916448Svikram assert(menu_root); 8923446Smrj 8936448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 8943446Smrj 8956448Svikram /* 8966448Svikram * We only support upgrades. Xen may not be present 8976448Svikram * on smaller metaclusters so we don't check for that. 8986448Svikram */ 8996448Svikram if (bam_is_findroot != BAM_FINDROOT_PRESENT || 9006448Svikram bam_direct != BAM_DIRECT_DBOOT) { 9016448Svikram bam_error(DOWNGRADE_NOTSUP, osroot); 9026448Svikram return (BAM_ERROR); 9033446Smrj } 9043446Smrj 9053446Smrj /* 9066448Svikram * First get the GRUB signature 9075084Sjohnlev */ 9086448Svikram osdev = get_special(osroot); 9096448Svikram INJECT_ERROR1("UPGRADE_OSDEV", osdev = NULL); 9106448Svikram if (osdev == NULL) { 9116448Svikram bam_error(CANT_FIND_SPECIAL, osroot); 9126448Svikram return (BAM_ERROR); 9136448Svikram } 9146448Svikram 9156448Svikram grubsign = get_grubsign(osroot, osdev); 9166448Svikram INJECT_ERROR1("UPGRADE_GRUBSIGN", grubsign = NULL); 9176448Svikram if (grubsign == NULL) { 9186448Svikram free(osdev); 9196448Svikram bam_error(CANT_FIND_GRUBSIGN, osroot); 9206448Svikram return (BAM_ERROR); 9215084Sjohnlev } 9225084Sjohnlev 9236448Svikram /* not fatal if we can't get grubroot */ 9246448Svikram grubroot = get_grubroot(osroot, osdev, menu_root); 9256448Svikram INJECT_ERROR1("UPGRADE_GRUBROOT", grubroot = NULL); 9266448Svikram 9276448Svikram free(osdev); 9286448Svikram 9296448Svikram ret1 = bam_add_findroot(mp, grubsign, 9306448Svikram grubroot, root_optional(osroot, menu_root)); 9316448Svikram INJECT_ERROR1("UPGRADE_ADD_FINDROOT", ret1 = BAM_ERROR); 9326448Svikram if (ret1 == BAM_ERROR) 9336448Svikram goto abort; 9346448Svikram 9356448Svikram ret2 = bam_add_hv(mp, grubsign, grubroot, 9366448Svikram root_optional(osroot, menu_root)); 9376448Svikram INJECT_ERROR1("UPGRADE_ADD_HV", ret2 = BAM_ERROR); 9386448Svikram if (ret2 == BAM_ERROR) 9396448Svikram goto abort; 9406448Svikram 9416448Svikram ret3 = bam_add_dboot(mp, osroot, grubsign, 9426448Svikram grubroot, root_optional(osroot, menu_root)); 9436448Svikram INJECT_ERROR1("UPGRADE_ADD_DBOOT", ret3 = BAM_ERROR); 9446448Svikram if (ret3 == BAM_ERROR) 9456448Svikram goto abort; 9466448Svikram 9476448Svikram if (ret1 == BAM_MSG || ret2 == BAM_MSG || ret3 == BAM_MSG) { 9486448Svikram bam_error(CVT_TODO, MENU_URL(osroot)); 9496448Svikram } else { 9506448Svikram bam_warn_hand_entries(mp, osroot); 9513446Smrj } 9526448Svikram 9536448Svikram free(grubsign); 9546448Svikram 9556448Svikram BAM_DPRINTF((D_RETURN_RET, fcn, BAM_WRITE)); 9563446Smrj return (BAM_WRITE); 9576448Svikram 9586448Svikram abort: 9596448Svikram free(grubsign); 9606448Svikram bam_error(CVT_ABORT, osroot, MENU_URL(osroot)); 9616448Svikram return (BAM_ERROR); 9623446Smrj } 963