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 #include <stdio.h> 273446Smrj #include <errno.h> 283446Smrj #include <stdlib.h> 293446Smrj #include <string.h> 303446Smrj #include <unistd.h> 313446Smrj #include <sys/types.h> 323446Smrj #include <sys/stat.h> 333446Smrj #include <limits.h> 343446Smrj #include <fcntl.h> 353446Smrj #include <strings.h> 363446Smrj 373446Smrj #include <sys/mman.h> 383446Smrj #include <sys/elf.h> 393446Smrj #include <sys/multiboot.h> 403446Smrj 413446Smrj #include "message.h" 423446Smrj #include "bootadm.h" 433446Smrj 443446Smrj direct_or_multi_t bam_direct = BAM_DIRECT_NOT_SET; 455084Sjohnlev hv_t bam_is_hv = BAM_HV_UNKNOWN; 466448Svikram findroot_t bam_is_findroot = BAM_FINDROOT_UNKNOWN; 476448Svikram 486448Svikram static void 496448Svikram get_findroot_cap(const char *osroot) 506448Svikram { 516448Svikram FILE *fp; 526448Svikram char path[PATH_MAX]; 536448Svikram char buf[BAM_MAXLINE]; 546448Svikram struct stat sb; 556448Svikram int dboot; 566448Svikram int xVM; 576448Svikram int error; 586448Svikram int ret; 596448Svikram const char *fcn = "get_findroot_cap()"; 606448Svikram 616448Svikram assert(is_grub(osroot)); 626448Svikram 636448Svikram (void) snprintf(path, sizeof (path), "%s/%s", 646448Svikram osroot, "boot/grub/capability"); 656448Svikram 666448Svikram if (stat(path, &sb) == -1) { 676448Svikram bam_is_findroot = BAM_FINDROOT_ABSENT; 686448Svikram BAM_DPRINTF((D_FINDROOT_ABSENT, fcn)); 696448Svikram return; 706448Svikram } 716448Svikram 726448Svikram fp = fopen(path, "r"); 736448Svikram error = errno; 746448Svikram INJECT_ERROR1("GET_CAP_FINDROOT_FOPEN", fp = NULL); 756448Svikram if (fp == NULL) { 766448Svikram bam_error(OPEN_FAIL, path, strerror(error)); 776448Svikram return; 786448Svikram } 796448Svikram 806448Svikram dboot = xVM = 0; 816448Svikram while (s_fgets(buf, sizeof (buf), fp) != NULL) { 826448Svikram if (strcmp(buf, "findroot") == 0) { 836448Svikram BAM_DPRINTF((D_FINDROOT_PRESENT, fcn)); 846448Svikram bam_is_findroot = BAM_FINDROOT_PRESENT; 856448Svikram } 866448Svikram if (strcmp(buf, "dboot") == 0) { 876448Svikram BAM_DPRINTF((D_DBOOT_PRESENT, fcn)); 886448Svikram dboot = 1; 896448Svikram } 906448Svikram if (strcmp(buf, "xVM") == 0) { 916448Svikram BAM_DPRINTF((D_XVM_PRESENT, fcn)); 926448Svikram xVM = 1; 936448Svikram } 946448Svikram } 956448Svikram 966448Svikram assert(dboot); 976448Svikram assert(xVM); 986448Svikram 996448Svikram if (bam_is_findroot == BAM_FINDROOT_UNKNOWN) { 1006448Svikram bam_is_findroot = BAM_FINDROOT_ABSENT; 1016448Svikram BAM_DPRINTF((D_FINDROOT_ABSENT, fcn)); 1026448Svikram } 1036448Svikram out: 1046448Svikram ret = fclose(fp); 1056448Svikram error = errno; 1066448Svikram INJECT_ERROR1("GET_CAP_FINDROOT_FCLOSE", ret = 1); 1076448Svikram if (ret != 0) { 1086448Svikram bam_error(CLOSE_FAIL, path, strerror(error)); 1096448Svikram } 1106448Svikram } 1113446Smrj 1123446Smrj error_t 1136448Svikram get_boot_cap(const char *osroot) 1143446Smrj { 1156448Svikram char fname[PATH_MAX]; 1166448Svikram char *image; 1176448Svikram uchar_t *ident; 1186448Svikram int fd; 1196448Svikram int m; 1203446Smrj multiboot_header_t *mbh; 1216448Svikram struct stat sb; 1226448Svikram int error; 1236448Svikram const char *fcn = "get_boot_cap()"; 1243446Smrj 1256448Svikram if (is_sparc()) { 1265648Ssetje /* there is no non dboot sparc new-boot */ 1275648Ssetje bam_direct = BAM_DIRECT_DBOOT; 1286448Svikram BAM_DPRINTF((D_IS_SPARC_DBOOT, fcn)); 1295648Ssetje return (BAM_SUCCESS); 1305648Ssetje } 1315648Ssetje 1326448Svikram if (!is_grub(osroot)) { 1336448Svikram bam_error(NOT_GRUB_ROOT, osroot); 1346448Svikram return (BAM_ERROR); 1356448Svikram } 1366448Svikram 1376448Svikram (void) snprintf(fname, PATH_MAX, "%s/%s", osroot, 1383446Smrj "platform/i86pc/kernel/unix"); 1393446Smrj fd = open(fname, O_RDONLY); 1406448Svikram error = errno; 1416448Svikram INJECT_ERROR1("GET_CAP_UNIX_OPEN", fd = -1); 1423446Smrj if (fd < 0) { 1436448Svikram bam_error(OPEN_FAIL, fname, strerror(error)); 1446448Svikram return (BAM_ERROR); 1456448Svikram } 1466448Svikram 1476448Svikram /* 1486448Svikram * Verify that this is a sane unix at least 8192 bytes in length 1496448Svikram */ 1506448Svikram if (fstat(fd, &sb) == -1 || sb.st_size < 8192) { 1516448Svikram (void) close(fd); 1526448Svikram bam_error(INVALID_BINARY, fname); 1533446Smrj return (BAM_ERROR); 1543446Smrj } 1553446Smrj 1563446Smrj /* 1573446Smrj * mmap the first 8K 1583446Smrj */ 1593446Smrj image = mmap(NULL, 8192, PROT_READ, MAP_SHARED, fd, 0); 1606448Svikram error = errno; 1616448Svikram INJECT_ERROR1("GET_CAP_MMAP", image = MAP_FAILED); 1623446Smrj if (image == MAP_FAILED) { 1636448Svikram bam_error(MMAP_FAIL, fname, strerror(error)); 1643446Smrj return (BAM_ERROR); 1653446Smrj } 1663446Smrj 1673446Smrj ident = (uchar_t *)image; 1683446Smrj if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 || 1693446Smrj ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) { 1703446Smrj bam_error(NOT_ELF_FILE, fname); 1713446Smrj return (BAM_ERROR); 1723446Smrj } 1733446Smrj if (ident[EI_CLASS] != ELFCLASS32) { 1743446Smrj bam_error(WRONG_ELF_CLASS, fname, ident[EI_CLASS]); 1753446Smrj return (BAM_ERROR); 1763446Smrj } 1773446Smrj 1783446Smrj /* 1793446Smrj * The GRUB multiboot header must be 32-bit aligned and completely 1803446Smrj * contained in the 1st 8K of the file. If the unix binary has 1813446Smrj * a multiboot header, then it is a 'dboot' kernel. Otherwise, 1823446Smrj * this kernel must be booted via multiboot -- we call this a 1833446Smrj * 'multiboot' kernel. 1843446Smrj */ 1853446Smrj bam_direct = BAM_DIRECT_MULTIBOOT; 1863446Smrj for (m = 0; m < 8192 - sizeof (multiboot_header_t); m += 4) { 1873446Smrj mbh = (void *)(image + m); 1883446Smrj if (mbh->magic == MB_HEADER_MAGIC) { 1896448Svikram BAM_DPRINTF((D_IS_DBOOT, fcn)); 1903446Smrj bam_direct = BAM_DIRECT_DBOOT; 1913446Smrj break; 1923446Smrj } 1933446Smrj } 1943446Smrj (void) munmap(image, 8192); 1953446Smrj (void) close(fd); 1965084Sjohnlev 1976448Svikram INJECT_ERROR1("GET_CAP_MULTIBOOT", bam_direct = BAM_DIRECT_MULTIBOOT); 1985084Sjohnlev if (bam_direct == BAM_DIRECT_DBOOT) { 1996448Svikram (void) snprintf(fname, PATH_MAX, "%s/%s", osroot, XEN_32); 2005084Sjohnlev if (stat(fname, &sb) == 0) { 2015084Sjohnlev bam_is_hv = BAM_HV_PRESENT; 2026448Svikram BAM_DPRINTF((D_IS_XVM, fcn)); 2035084Sjohnlev } else { 2045084Sjohnlev bam_is_hv = BAM_HV_NO; 2056448Svikram BAM_DPRINTF((D_IS_NOT_XVM, fcn)); 2065084Sjohnlev } 2076448Svikram } else { 2086448Svikram BAM_DPRINTF((D_IS_MULTIBOOT, fcn)); 2095084Sjohnlev } 2105084Sjohnlev 2116448Svikram /* Not a fatal error if this fails */ 2126448Svikram get_findroot_cap(osroot); 2136448Svikram 2146448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 2153446Smrj return (BAM_SUCCESS); 2163446Smrj } 2173446Smrj 2183446Smrj #define INST_RELEASE "var/sadm/system/admin/INST_RELEASE" 2193446Smrj 2203446Smrj /* 2213446Smrj * Return true if root has been bfu'ed. bfu will blow away 2223446Smrj * var/sadm/system/admin/INST_RELEASE, so if it's still there, we can 2233446Smrj * assume the system has not been bfu'ed. 2243446Smrj */ 2253446Smrj static int 2263446Smrj is_bfu_system(const char *root) 2273446Smrj { 2286448Svikram static int is_bfu = -1; 2296448Svikram char path[PATH_MAX]; 2306448Svikram struct stat sb; 2316448Svikram const char *fcn = "is_bfu_system()"; 2323446Smrj 2336448Svikram if (is_bfu != -1) { 2346448Svikram BAM_DPRINTF((D_ALREADY_BFU_TEST, fcn, is_bfu ? "" : "NOT")); 2353446Smrj return (is_bfu); 2366448Svikram } 2373446Smrj 2383446Smrj (void) snprintf(path, sizeof (path), "%s/%s", root, INST_RELEASE); 2393446Smrj if (stat(path, &sb) != 0) { 2403446Smrj is_bfu = 1; 2416448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 2423446Smrj } else { 2433446Smrj is_bfu = 0; 2446448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 2453446Smrj } 2463446Smrj return (is_bfu); 2473446Smrj } 2483446Smrj 2493446Smrj #define MENU_URL(root) (is_bfu_system(root) ? \ 2503446Smrj "http://www.sun.com/msg/SUNOS-8000-CF" : \ 2513446Smrj "http://www.sun.com/msg/SUNOS-8000-AK") 2523446Smrj 2533446Smrj /* 2543446Smrj * Simply allocate a new line and copy in cmd + sep + arg 2553446Smrj */ 2563446Smrj void 2573446Smrj update_line(line_t *linep) 2583446Smrj { 2596448Svikram size_t size; 2606448Svikram const char *fcn = "update_line()"; 2613446Smrj 2626448Svikram BAM_DPRINTF((D_UPDATE_LINE_BEFORE, fcn, linep->line)); 2633446Smrj free(linep->line); 2643446Smrj size = strlen(linep->cmd) + strlen(linep->sep) + strlen(linep->arg) + 1; 2653446Smrj linep->line = s_calloc(1, size); 2663446Smrj (void) snprintf(linep->line, size, "%s%s%s", linep->cmd, linep->sep, 2673446Smrj linep->arg); 2686448Svikram BAM_DPRINTF((D_UPDATE_LINE_AFTER, fcn, linep->line)); 2696448Svikram } 2706448Svikram 2716448Svikram static char * 2726448Svikram skip_wspace(char *ptr) 2736448Svikram { 2746448Svikram const char *fcn = "skip_wspace()"; 2756448Svikram 2766448Svikram INJECT_ERROR1("SKIP_WSPACE", ptr = NULL); 2776448Svikram if (ptr == NULL) { 2786448Svikram BAM_DPRINTF((D_SKIP_WSPACE_PTR_NULL, fcn)); 2796448Svikram return (NULL); 2806448Svikram } 2816448Svikram 2826448Svikram BAM_DPRINTF((D_SKIP_WSPACE_ENTRY_PTR, fcn, ptr)); 2836448Svikram for (; *ptr != '\0'; ptr++) { 2846448Svikram if ((*ptr != ' ') && (*ptr != '\t') && 2856448Svikram (*ptr != '\n')) 2866448Svikram break; 2876448Svikram } 2886448Svikram 2896448Svikram ptr = (*ptr == '\0' ? NULL : ptr); 2906448Svikram 2916448Svikram BAM_DPRINTF((D_SKIP_WSPACE_EXIT_PTR, fcn, ptr ? ptr : "NULL")); 2926448Svikram 2936448Svikram return (ptr); 2946448Svikram } 2956448Svikram 2966448Svikram static char * 2976448Svikram rskip_bspace(char *bound, char *ptr) 2986448Svikram { 2996448Svikram const char *fcn = "rskip_bspace()"; 3006448Svikram assert(bound); 3016448Svikram assert(ptr); 3026448Svikram assert(bound <= ptr); 3036448Svikram assert(*bound != ' ' && *bound != '\t' && *bound != '\n'); 3046448Svikram 3056448Svikram BAM_DPRINTF((D_RSKIP_BSPACE_ENTRY, fcn, ptr)); 3066448Svikram for (; ptr > bound; ptr--) { 3076448Svikram if (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') 3086448Svikram break; 3096448Svikram } 3106448Svikram 3116448Svikram BAM_DPRINTF((D_RSKIP_BSPACE_EXIT, fcn, ptr)); 3126448Svikram return (ptr); 3133446Smrj } 3143446Smrj 3153446Smrj /* 3163446Smrj * The parse_kernel_line function examines a menu.lst kernel line. For 3173446Smrj * multiboot, this is: 3183446Smrj * 3193446Smrj * kernel <multiboot path> <flags1> <kernel path> <flags2> 3203446Smrj * 3213446Smrj * <multiboot path> is either /platform/i86pc/multiboot or /boot/multiboot 3223446Smrj * 3233446Smrj * <kernel path> may be missing, or may be any full or relative path to unix. 3243446Smrj * We check for it by looking for a word ending in "/unix". If it ends 3253446Smrj * in "kernel/unix", we upgrade it to a 32-bit entry. If it ends in 3263446Smrj * "kernel/amd64/unix", we upgrade it to the default entry. Otherwise, 3273446Smrj * it's a custom kernel, and we skip it. 3283446Smrj * 3293446Smrj * <flags*> are anything that doesn't fit either of the above - these will be 3303446Smrj * copied over. 3313446Smrj * 3323446Smrj * For direct boot, the defaults are 3333446Smrj * 3343446Smrj * kernel$ <kernel path> <flags> 3353446Smrj * 3363446Smrj * <kernel path> is one of: 3373446Smrj * /platform/i86pc/kernel/$ISADIR/unix 338*8104SEnrico.Perla@Sun.COM * /boot/platform/i86pc/kernel/$ISADIR/unix 3393446Smrj * /platform/i86pc/kernel/unix 3403446Smrj * /platform/i86pc/kernel/amd64/unix 3413446Smrj * /boot/platform/i86pc/kernel/unix 342*8104SEnrico.Perla@Sun.COM * /boot/platform/i86pc/kernel/amd64/unix 3433446Smrj * 344*8104SEnrico.Perla@Sun.COM * If <kernel path> is any of the last four, 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 { 358*8104SEnrico.Perla@Sun.COM char path[PATH_MAX], path_64[PATH_MAX]; 3596448Svikram char linebuf[PATH_MAX]; 3606448Svikram char new_arg[PATH_MAX]; 361*8104SEnrico.Perla@Sun.COM struct stat sb, sb_64; 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, 388*8104SEnrico.Perla@Sun.COM DIRECT_BOOT_FAILSAFE_32); 389*8104SEnrico.Perla@Sun.COM (void) snprintf(path_64, PATH_MAX, "%s%s", osroot, 390*8104SEnrico.Perla@Sun.COM DIRECT_BOOT_FAILSAFE_64); 391*8104SEnrico.Perla@Sun.COM if (stat(path, &sb) != 0 && stat(path_64, &sb_64) != 0) { 3923446Smrj if (bam_verbose) { 3936448Svikram bam_error(FAILSAFE_MISSING, line->lineNum); 3943446Smrj } 3956448Svikram BAM_DPRINTF((D_NO_FAILSAFE_UNIX_CONVERT, fcn)); 3963446Smrj return (BAM_SUCCESS); 3973446Smrj } 3983446Smrj } 3993446Smrj 4003446Smrj /* 401*8104SEnrico.Perla@Sun.COM * Make sure we have the correct cmd 4023446Smrj */ 403*8104SEnrico.Perla@Sun.COM 404*8104SEnrico.Perla@Sun.COM free(line->cmd); 405*8104SEnrico.Perla@Sun.COM line->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]); 406*8104SEnrico.Perla@Sun.COM BAM_DPRINTF((D_CVT_CMD_KERN_DOLLAR, fcn, line->cmd)); 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 * 513*8104SEnrico.Perla@Sun.COM * Under multiboot, the failsafe is: 5143446Smrj * 5153446Smrj * module /boot/x86.miniroot-safe 516*8104SEnrico.Perla@Sun.COM * 517*8104SEnrico.Perla@Sun.COM * Under dboot, the failsafe is: 518*8104SEnrico.Perla@Sun.COM * 519*8104SEnrico.Perla@Sun.COM * module$ /boot/$ISADIR/x86.miniroot-safe 520*8104SEnrico.Perla@Sun.COM * 521*8104SEnrico.Perla@Sun.COM * which may be specified exactly as either of: 522*8104SEnrico.Perla@Sun.COM * 523*8104SEnrico.Perla@Sun.COM * module /boot/x86.miniroot-safe 524*8104SEnrico.Perla@Sun.COM * module /boot/amd64/x86.miniroot-safe 5253446Smrj */ 5263446Smrj static error_t 5276448Svikram cvt_module_line(line_t *line, entry_t *entry) 5283446Smrj { 5296448Svikram const char *fcn = "cvt_module_line()"; 5306448Svikram 5316448Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, line->line)); 5323446Smrj 5333446Smrj /* 5346448Svikram * We only convert multiboot to dboot and nothing else 5353446Smrj */ 5366448Svikram if (!(entry->flags & BAM_ENTRY_MULTIBOOT)) { 5376448Svikram BAM_DPRINTF((D_NOT_MULTIBOOT_CONVERT, fcn)); 5383446Smrj return (BAM_SUCCESS); 5393446Smrj } 5403446Smrj 5416448Svikram if (entry->flags & BAM_ENTRY_FAILSAFE) { 5426448Svikram if (strcmp(line->arg, FAILSAFE_ARCHIVE) == 0) { 5436448Svikram BAM_DPRINTF((D_FAILSAFE_NO_CVT_NEEDED, fcn, line->arg)); 5446448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5456448Svikram return (BAM_SUCCESS); 5466448Svikram } 5476448Svikram } else if (strcmp(line->arg, MULTIBOOT_ARCHIVE) != 0) { 5486448Svikram bam_error(UNKNOWN_MODULE_LINE, line->lineNum); 5496448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5506448Svikram return (BAM_MSG); 5516448Svikram } 5526448Svikram 553*8104SEnrico.Perla@Sun.COM free(line->cmd); 554*8104SEnrico.Perla@Sun.COM free(line->arg); 555*8104SEnrico.Perla@Sun.COM line->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]); 556*8104SEnrico.Perla@Sun.COM 557*8104SEnrico.Perla@Sun.COM line->arg = s_strdup(entry->flags & BAM_ENTRY_FAILSAFE ? 558*8104SEnrico.Perla@Sun.COM FAILSAFE_ARCHIVE : DIRECT_BOOT_ARCHIVE); 5596448Svikram 5606448Svikram update_line(line); 5616448Svikram BAM_DPRINTF((D_CVTED_MODULE, fcn, line->line)); 5626448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5636448Svikram return (BAM_SUCCESS); 5646448Svikram } 5656448Svikram 5666448Svikram static void 5676448Svikram bam_warn_hand_entries(menu_t *mp, char *osroot) 5686448Svikram { 5696448Svikram int hand_num; 5706448Svikram int hand_max; 5716448Svikram int *hand_list; 5726448Svikram int i; 5736448Svikram entry_t *entry; 5746448Svikram const char *fcn = "bam_warn_hand_entries()"; 5756448Svikram 5766448Svikram if (bam_force) { 5776448Svikram /* 5786448Svikram * No warning needed, we are automatically converting 5796448Svikram * the "hand" entries 5806448Svikram */ 5816448Svikram BAM_DPRINTF((D_FORCE_HAND_CVT, fcn)); 5826448Svikram return; 5836448Svikram } 5846448Svikram 5856448Svikram hand_num = 0; 5866448Svikram hand_max = BAM_ENTRY_NUM; 5876448Svikram hand_list = s_calloc(1, hand_max); 5886448Svikram 5896448Svikram for (entry = mp->entries; entry; entry = entry->next) { 5906448Svikram if (entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) 5916448Svikram continue; 5926448Svikram BAM_DPRINTF((D_FOUND_HAND, fcn, entry->entryNum)); 5936448Svikram if (++hand_num > hand_max) { 5946448Svikram hand_max *= 2; 5956448Svikram hand_list = s_realloc(hand_list, 5966448Svikram hand_max * sizeof (int)); 5976448Svikram } 5986448Svikram hand_list[hand_num - 1] = entry->entryNum; 5996448Svikram } 6006448Svikram 6016448Svikram bam_error(HAND_ADDED_ENTRIES, osroot, MENU_URL(osroot)); 6026448Svikram bam_print_stderr("Entry Number%s: ", (hand_num > 1) ? 6036448Svikram "s" : ""); 6046448Svikram for (i = 0; i < hand_num; i++) { 6056448Svikram bam_print_stderr("%d ", hand_list[i]); 6066448Svikram } 6076448Svikram bam_print_stderr("\n"); 6086448Svikram } 6093446Smrj 6106448Svikram static entry_t * 6116448Svikram find_matching_entry( 6126448Svikram entry_t *estart, 6136448Svikram char *grubsign, 6146448Svikram char *grubroot, 6156448Svikram int root_opt) 6166448Svikram { 6176448Svikram entry_t *entry; 6186448Svikram line_t *line; 6196448Svikram char opt[10]; 6206448Svikram const char *fcn = "find_matching_entry()"; 6216448Svikram 6226448Svikram assert(grubsign); 6236448Svikram assert(root_opt == 0 || root_opt == 1); 6246448Svikram 6256448Svikram (void) snprintf(opt, sizeof (opt), "%d", root_opt); 6266448Svikram BAM_DPRINTF((D_FUNC_ENTRY3, fcn, grubsign, grubroot, opt)); 6276448Svikram 6286448Svikram for (entry = estart; entry; entry = entry->next) { 6296694Svikram 6306448Svikram if (!(entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) && 6316448Svikram !bam_force) { 6326448Svikram BAM_DPRINTF((D_SKIP_ENTRY, fcn, entry->entryNum)); 6336448Svikram continue; 6346448Svikram } 6356448Svikram 6366448Svikram if (entry->flags & BAM_ENTRY_ROOT) { 6376448Svikram for (line = entry->start; line; line = line->next) { 6386448Svikram if (line->cmd == NULL || line->arg == NULL) { 6396448Svikram if (line == entry->end) { 6406448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 6416448Svikram break; 6426448Svikram } else { 6436448Svikram BAM_DPRINTF((D_SKIP_NULL, fcn)); 6446448Svikram continue; 6456448Svikram } 6466448Svikram } 6476448Svikram if (strcmp(line->cmd, menu_cmds[ROOT_CMD]) 6486448Svikram == 0 && strcmp(line->arg, grubroot) == 0) { 6496448Svikram BAM_DPRINTF((D_ROOT_MATCH, fcn, 6506448Svikram line->line, grubsign)); 6516448Svikram return (entry); 6526448Svikram } 6536448Svikram if (line == entry->end) { 6546448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 6556448Svikram break; 6566448Svikram } 6576448Svikram } 6586448Svikram } else if (entry->flags & BAM_ENTRY_FINDROOT) { 6596448Svikram for (line = entry->start; line; line = line->next) { 6606448Svikram if (line->cmd == NULL || line->arg == NULL) { 6616448Svikram if (line == entry->end) { 6626448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 6636448Svikram break; 6646448Svikram } else { 6656448Svikram BAM_DPRINTF((D_SKIP_NULL, fcn)); 6666448Svikram continue; 6676448Svikram } 6686448Svikram } 6696448Svikram if (strcmp(line->cmd, menu_cmds[FINDROOT_CMD]) 6706448Svikram == 0 && strcmp(line->arg, grubsign) == 0) { 6716448Svikram BAM_DPRINTF((D_FINDROOT_MATCH, fcn, 6726448Svikram line->line, grubsign)); 6736448Svikram return (entry); 6746448Svikram } 6756448Svikram if (line == entry->end) { 6766448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 6776448Svikram break; 6786448Svikram } 6796448Svikram } 6806448Svikram } else if (root_opt) { 6816448Svikram /* Neither root nor findroot */ 6826448Svikram BAM_DPRINTF((D_NO_ROOT_FINDROOT, fcn, entry->entryNum)); 6836448Svikram return (entry); 6846448Svikram } 6853446Smrj } 6863446Smrj 6876448Svikram BAM_DPRINTF((D_NO_MATCH, fcn)); 6886448Svikram return (NULL); 6896448Svikram } 6906448Svikram 6916448Svikram /* 6926448Svikram * The following is a set of routines that attempt to convert the 6936448Svikram * menu entries for the supplied osroot into a format compatible 6946448Svikram * with the GRUB installation on osroot. 6956448Svikram * 6966448Svikram * Each of these conversion routines make no assumptions about 6976448Svikram * the current state of the menu entry, it does its best to 6986448Svikram * convert the menu entry to the new state. In the process 6996448Svikram * we may either upgrade or downgrade. 7006448Svikram * 7016448Svikram * We don't make any heroic efforts at conversion. It is better 7026448Svikram * to be conservative and bail out at the first sign of error. We will 7036448Svikram * in such cases, point the user at the knowledge-base article 7046448Svikram * so that they can upgrade manually. 7056448Svikram */ 7066448Svikram static error_t 7076448Svikram bam_add_findroot(menu_t *mp, char *grubsign, char *grubroot, int root_opt) 7086448Svikram { 7096448Svikram entry_t *entry; 7106448Svikram line_t *line; 7116448Svikram line_t *newlp; 7126448Svikram int update_num; 7136448Svikram char linebuf[PATH_MAX]; 7146448Svikram const char *fcn = "bam_add_findroot()"; 7156448Svikram 7166448Svikram update_num = 0; 7176448Svikram 7186448Svikram bam_print(CVT_FINDROOT); 7196448Svikram 7206448Svikram entry = mp->entries; 7216448Svikram for (; entry = find_matching_entry(entry, grubsign, grubroot, root_opt); 7226448Svikram entry = entry->next) { 7236448Svikram if (entry->flags & BAM_ENTRY_FINDROOT) { 7246448Svikram /* already converted */ 7256448Svikram BAM_DPRINTF((D_ALREADY_FINDROOT, fcn, entry->entryNum)); 7266448Svikram continue; 7276448Svikram } 7286448Svikram for (line = entry->start; line; line = line->next) { 7296448Svikram if (line->cmd == NULL || line->arg == NULL) { 7306448Svikram if (line == entry->end) { 7316448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 7326448Svikram break; 7336448Svikram } else { 7346448Svikram BAM_DPRINTF((D_SKIP_NULL, fcn)); 7356448Svikram continue; 7366448Svikram } 7376448Svikram } 7386448Svikram if (strcmp(line->cmd, menu_cmds[TITLE_CMD]) == 0) { 7396448Svikram newlp = s_calloc(1, sizeof (line_t)); 7406448Svikram newlp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]); 7416448Svikram newlp->sep = s_strdup(" "); 7426448Svikram newlp->arg = s_strdup(grubsign); 7436448Svikram (void) snprintf(linebuf, sizeof (linebuf), 7446448Svikram "%s%s%s", newlp->cmd, newlp->sep, 7456448Svikram newlp->arg); 7466448Svikram newlp->line = s_strdup(linebuf); 7476448Svikram bam_add_line(mp, entry, line, newlp); 7486448Svikram update_num = 1; 7496448Svikram entry->flags &= ~BAM_ENTRY_ROOT; 7506448Svikram entry->flags |= BAM_ENTRY_FINDROOT; 7516448Svikram BAM_DPRINTF((D_ADDED_FINDROOT, fcn, 7526448Svikram newlp->line)); 7536448Svikram line = newlp; 7546448Svikram } 7556448Svikram if (strcmp(line->cmd, menu_cmds[ROOT_CMD]) == 0) { 7566448Svikram BAM_DPRINTF((D_FREEING_ROOT, fcn, line->line)); 7576448Svikram unlink_line(mp, line); 7586448Svikram line_free(line); 7596448Svikram } 7606448Svikram if (line == entry->end) { 7616448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 7626448Svikram break; 7636448Svikram } 7646448Svikram } 7656448Svikram } 7666448Svikram 7676448Svikram if (update_num) { 7686448Svikram BAM_DPRINTF((D_UPDATED_NUMBERING, fcn)); 7696448Svikram update_numbering(mp); 7706448Svikram } 7716448Svikram 7726448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7736448Svikram return (BAM_SUCCESS); 7746448Svikram } 7756448Svikram 7766448Svikram static error_t 7776448Svikram bam_add_hv(menu_t *mp, char *grubsign, char *grubroot, int root_opt) 7786448Svikram { 7796448Svikram entry_t *entry; 7806448Svikram const char *fcn = "bam_add_hv()"; 7816448Svikram 7826448Svikram bam_print(CVT_HV); 7836448Svikram 7846448Svikram entry = mp->entries; 7856448Svikram for (; entry = find_matching_entry(entry, grubsign, grubroot, root_opt); 7866448Svikram entry = entry->next) { 7876448Svikram if (entry->flags & BAM_ENTRY_HV) { 7886448Svikram BAM_DPRINTF((D_ALREADY_HV, fcn, entry->entryNum)); 7896448Svikram return (BAM_SUCCESS); 7906448Svikram } 7916448Svikram } 7926448Svikram 7936448Svikram (void) add_boot_entry(mp, NEW_HV_ENTRY, grubsign, XEN_MENU, 7946448Svikram XEN_KERNEL_MODULE_LINE, DIRECT_BOOT_ARCHIVE); 7956448Svikram 7966448Svikram BAM_DPRINTF((D_ADDED_XVM_ENTRY, fcn)); 7976448Svikram 7986448Svikram update_numbering(mp); 7996448Svikram 8006448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 8013446Smrj 8023446Smrj return (BAM_SUCCESS); 8033446Smrj } 8043446Smrj 8056448Svikram static error_t 8066448Svikram bam_add_dboot( 8076448Svikram menu_t *mp, 8086448Svikram char *osroot, 8096448Svikram char *grubsign, 8106448Svikram char *grubroot, 8116448Svikram int root_opt) 8126448Svikram { 8136448Svikram int msg = 0; 8146448Svikram entry_t *entry; 8156448Svikram line_t *line; 8166448Svikram error_t ret; 8176448Svikram const char *fcn = "bam_add_dboot()"; 8186448Svikram 8196448Svikram bam_print(CVT_DBOOT); 8206448Svikram 8216448Svikram entry = mp->entries; 8226448Svikram for (; entry = find_matching_entry(entry, grubsign, grubroot, root_opt); 8236448Svikram entry = entry->next) { 8246448Svikram for (line = entry->start; line; line = line->next) { 8256448Svikram if (line->cmd == NULL || line->arg == NULL) { 8266448Svikram if (line == entry->end) { 8276448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 8286448Svikram break; 8296448Svikram } else { 8306448Svikram BAM_DPRINTF((D_SKIP_NULL, fcn)); 8316448Svikram continue; 8326448Svikram } 8336448Svikram } 8346448Svikram 8356448Svikram /* 8366448Svikram * If we have a kernel$ command, assume it 8376448Svikram * is dboot already. If it is not a dboot 8386448Svikram * entry, something funny is going on and 8396448Svikram * we will leave it alone 8406448Svikram */ 8416448Svikram if (strcmp(line->cmd, menu_cmds[KERNEL_CMD]) == 0) { 8426448Svikram ret = cvt_kernel_line(line, osroot, entry); 8436448Svikram INJECT_ERROR1("ADD_DBOOT_KERN_ERR", 8446448Svikram ret = BAM_ERROR); 8456448Svikram INJECT_ERROR1("ADD_DBOOT_KERN_MSG", 8466448Svikram ret = BAM_MSG); 8476448Svikram if (ret == BAM_ERROR) { 8486448Svikram BAM_DPRINTF((D_CVT_KERNEL_FAIL, fcn)); 8496448Svikram return (ret); 8506448Svikram } else if (ret == BAM_MSG) { 8516448Svikram msg = 1; 8526448Svikram BAM_DPRINTF((D_CVT_KERNEL_MSG, fcn)); 8536448Svikram } 8546448Svikram } 8556448Svikram if (strcmp(line->cmd, menu_cmds[MODULE_CMD]) == 0) { 8566448Svikram ret = cvt_module_line(line, entry); 8576448Svikram INJECT_ERROR1("ADD_DBOOT_MOD_ERR", 8586448Svikram ret = BAM_ERROR); 8596448Svikram INJECT_ERROR1("ADD_DBOOT_MOD_MSG", 8606448Svikram ret = BAM_MSG); 8616448Svikram if (ret == BAM_ERROR) { 8626448Svikram BAM_DPRINTF((D_CVT_MODULE_FAIL, fcn)); 8636448Svikram return (ret); 8646448Svikram } else if (ret == BAM_MSG) { 8656448Svikram BAM_DPRINTF((D_CVT_MODULE_MSG, fcn)); 8666448Svikram msg = 1; 8676448Svikram } 8686448Svikram } 8696448Svikram 8706448Svikram if (line == entry->end) { 8716448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 8726448Svikram break; 8736448Svikram } 8746448Svikram } 8756448Svikram } 8766448Svikram 8776448Svikram ret = msg ? BAM_MSG : BAM_SUCCESS; 8786448Svikram BAM_DPRINTF((D_RETURN_RET, fcn, ret)); 8796448Svikram return (ret); 8806448Svikram } 8816448Svikram 8823446Smrj /*ARGSUSED*/ 8833446Smrj error_t 8846448Svikram upgrade_menu(menu_t *mp, char *osroot, char *menu_root) 8853446Smrj { 8866448Svikram char *osdev; 8876448Svikram char *grubsign; 8886448Svikram char *grubroot; 8896448Svikram int ret1; 8906448Svikram int ret2; 8916448Svikram int ret3; 8926448Svikram const char *fcn = "upgrade_menu()"; 8935084Sjohnlev 8946448Svikram assert(osroot); 8956448Svikram assert(menu_root); 8963446Smrj 8976448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 8983446Smrj 8996448Svikram /* 9006448Svikram * We only support upgrades. Xen may not be present 9016448Svikram * on smaller metaclusters so we don't check for that. 9026448Svikram */ 9036448Svikram if (bam_is_findroot != BAM_FINDROOT_PRESENT || 9046448Svikram bam_direct != BAM_DIRECT_DBOOT) { 9056448Svikram bam_error(DOWNGRADE_NOTSUP, osroot); 9066448Svikram return (BAM_ERROR); 9073446Smrj } 9083446Smrj 9093446Smrj /* 9106448Svikram * First get the GRUB signature 9115084Sjohnlev */ 9126448Svikram osdev = get_special(osroot); 9136448Svikram INJECT_ERROR1("UPGRADE_OSDEV", osdev = NULL); 9146448Svikram if (osdev == NULL) { 9156448Svikram bam_error(CANT_FIND_SPECIAL, osroot); 9166448Svikram return (BAM_ERROR); 9176448Svikram } 9186448Svikram 9196448Svikram grubsign = get_grubsign(osroot, osdev); 9206448Svikram INJECT_ERROR1("UPGRADE_GRUBSIGN", grubsign = NULL); 9216448Svikram if (grubsign == NULL) { 9226448Svikram free(osdev); 9236448Svikram bam_error(CANT_FIND_GRUBSIGN, osroot); 9246448Svikram return (BAM_ERROR); 9255084Sjohnlev } 9265084Sjohnlev 9276448Svikram /* not fatal if we can't get grubroot */ 9286448Svikram grubroot = get_grubroot(osroot, osdev, menu_root); 9296448Svikram INJECT_ERROR1("UPGRADE_GRUBROOT", grubroot = NULL); 9306448Svikram 9316448Svikram free(osdev); 9326448Svikram 9336448Svikram ret1 = bam_add_findroot(mp, grubsign, 9346448Svikram grubroot, root_optional(osroot, menu_root)); 9356448Svikram INJECT_ERROR1("UPGRADE_ADD_FINDROOT", ret1 = BAM_ERROR); 9366448Svikram if (ret1 == BAM_ERROR) 9376448Svikram goto abort; 9386448Svikram 9396448Svikram ret2 = bam_add_hv(mp, grubsign, grubroot, 9406448Svikram root_optional(osroot, menu_root)); 9416448Svikram INJECT_ERROR1("UPGRADE_ADD_HV", ret2 = BAM_ERROR); 9426448Svikram if (ret2 == BAM_ERROR) 9436448Svikram goto abort; 9446448Svikram 9456448Svikram ret3 = bam_add_dboot(mp, osroot, grubsign, 9466448Svikram grubroot, root_optional(osroot, menu_root)); 9476448Svikram INJECT_ERROR1("UPGRADE_ADD_DBOOT", ret3 = BAM_ERROR); 9486448Svikram if (ret3 == BAM_ERROR) 9496448Svikram goto abort; 9506448Svikram 9516448Svikram if (ret1 == BAM_MSG || ret2 == BAM_MSG || ret3 == BAM_MSG) { 9526448Svikram bam_error(CVT_TODO, MENU_URL(osroot)); 9536448Svikram } else { 9546448Svikram bam_warn_hand_entries(mp, osroot); 9553446Smrj } 9566448Svikram 9576448Svikram free(grubsign); 9586448Svikram 9596448Svikram BAM_DPRINTF((D_RETURN_RET, fcn, BAM_WRITE)); 9603446Smrj return (BAM_WRITE); 9616448Svikram 9626448Svikram abort: 9636448Svikram free(grubsign); 9646448Svikram bam_error(CVT_ABORT, osroot, MENU_URL(osroot)); 9656448Svikram return (BAM_ERROR); 9663446Smrj } 967