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 /* 22*10405SFrank.Vanderlinden@Sun.COM * Copyright 2009 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 error; 576448Svikram int ret; 586448Svikram const char *fcn = "get_findroot_cap()"; 596448Svikram 606448Svikram assert(is_grub(osroot)); 616448Svikram 626448Svikram (void) snprintf(path, sizeof (path), "%s/%s", 636448Svikram osroot, "boot/grub/capability"); 646448Svikram 656448Svikram if (stat(path, &sb) == -1) { 666448Svikram bam_is_findroot = BAM_FINDROOT_ABSENT; 676448Svikram BAM_DPRINTF((D_FINDROOT_ABSENT, fcn)); 686448Svikram return; 696448Svikram } 706448Svikram 716448Svikram fp = fopen(path, "r"); 726448Svikram error = errno; 736448Svikram INJECT_ERROR1("GET_CAP_FINDROOT_FOPEN", fp = NULL); 746448Svikram if (fp == NULL) { 756448Svikram bam_error(OPEN_FAIL, path, strerror(error)); 766448Svikram return; 776448Svikram } 786448Svikram 79*10405SFrank.Vanderlinden@Sun.COM dboot = 0; 806448Svikram while (s_fgets(buf, sizeof (buf), fp) != NULL) { 816448Svikram if (strcmp(buf, "findroot") == 0) { 826448Svikram BAM_DPRINTF((D_FINDROOT_PRESENT, fcn)); 836448Svikram bam_is_findroot = BAM_FINDROOT_PRESENT; 846448Svikram } 856448Svikram if (strcmp(buf, "dboot") == 0) { 866448Svikram BAM_DPRINTF((D_DBOOT_PRESENT, fcn)); 876448Svikram dboot = 1; 886448Svikram } 896448Svikram } 906448Svikram 916448Svikram assert(dboot); 926448Svikram 936448Svikram if (bam_is_findroot == BAM_FINDROOT_UNKNOWN) { 946448Svikram bam_is_findroot = BAM_FINDROOT_ABSENT; 956448Svikram BAM_DPRINTF((D_FINDROOT_ABSENT, fcn)); 966448Svikram } 976448Svikram out: 986448Svikram ret = fclose(fp); 996448Svikram error = errno; 1006448Svikram INJECT_ERROR1("GET_CAP_FINDROOT_FCLOSE", ret = 1); 1016448Svikram if (ret != 0) { 1026448Svikram bam_error(CLOSE_FAIL, path, strerror(error)); 1036448Svikram } 1046448Svikram } 1053446Smrj 1063446Smrj error_t 1076448Svikram get_boot_cap(const char *osroot) 1083446Smrj { 1096448Svikram char fname[PATH_MAX]; 1106448Svikram char *image; 1116448Svikram uchar_t *ident; 1126448Svikram int fd; 1136448Svikram int m; 1143446Smrj multiboot_header_t *mbh; 1156448Svikram struct stat sb; 1166448Svikram int error; 1176448Svikram const char *fcn = "get_boot_cap()"; 1183446Smrj 1196448Svikram if (is_sparc()) { 1205648Ssetje /* there is no non dboot sparc new-boot */ 1215648Ssetje bam_direct = BAM_DIRECT_DBOOT; 1226448Svikram BAM_DPRINTF((D_IS_SPARC_DBOOT, fcn)); 1235648Ssetje return (BAM_SUCCESS); 1245648Ssetje } 1255648Ssetje 1266448Svikram if (!is_grub(osroot)) { 1276448Svikram bam_error(NOT_GRUB_ROOT, osroot); 1286448Svikram return (BAM_ERROR); 1296448Svikram } 1306448Svikram 1316448Svikram (void) snprintf(fname, PATH_MAX, "%s/%s", osroot, 1323446Smrj "platform/i86pc/kernel/unix"); 1333446Smrj fd = open(fname, O_RDONLY); 1346448Svikram error = errno; 1356448Svikram INJECT_ERROR1("GET_CAP_UNIX_OPEN", fd = -1); 1363446Smrj if (fd < 0) { 1376448Svikram bam_error(OPEN_FAIL, fname, strerror(error)); 1386448Svikram return (BAM_ERROR); 1396448Svikram } 1406448Svikram 1416448Svikram /* 1426448Svikram * Verify that this is a sane unix at least 8192 bytes in length 1436448Svikram */ 1446448Svikram if (fstat(fd, &sb) == -1 || sb.st_size < 8192) { 1456448Svikram (void) close(fd); 1466448Svikram bam_error(INVALID_BINARY, fname); 1473446Smrj return (BAM_ERROR); 1483446Smrj } 1493446Smrj 1503446Smrj /* 1513446Smrj * mmap the first 8K 1523446Smrj */ 1533446Smrj image = mmap(NULL, 8192, PROT_READ, MAP_SHARED, fd, 0); 1546448Svikram error = errno; 1556448Svikram INJECT_ERROR1("GET_CAP_MMAP", image = MAP_FAILED); 1563446Smrj if (image == MAP_FAILED) { 1576448Svikram bam_error(MMAP_FAIL, fname, strerror(error)); 1583446Smrj return (BAM_ERROR); 1593446Smrj } 1603446Smrj 1613446Smrj ident = (uchar_t *)image; 1623446Smrj if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 || 1633446Smrj ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) { 1643446Smrj bam_error(NOT_ELF_FILE, fname); 1653446Smrj return (BAM_ERROR); 1663446Smrj } 1673446Smrj if (ident[EI_CLASS] != ELFCLASS32) { 1683446Smrj bam_error(WRONG_ELF_CLASS, fname, ident[EI_CLASS]); 1693446Smrj return (BAM_ERROR); 1703446Smrj } 1713446Smrj 1723446Smrj /* 1733446Smrj * The GRUB multiboot header must be 32-bit aligned and completely 1743446Smrj * contained in the 1st 8K of the file. If the unix binary has 1753446Smrj * a multiboot header, then it is a 'dboot' kernel. Otherwise, 1763446Smrj * this kernel must be booted via multiboot -- we call this a 1773446Smrj * 'multiboot' kernel. 1783446Smrj */ 1793446Smrj bam_direct = BAM_DIRECT_MULTIBOOT; 1803446Smrj for (m = 0; m < 8192 - sizeof (multiboot_header_t); m += 4) { 1813446Smrj mbh = (void *)(image + m); 1823446Smrj if (mbh->magic == MB_HEADER_MAGIC) { 1836448Svikram BAM_DPRINTF((D_IS_DBOOT, fcn)); 1843446Smrj bam_direct = BAM_DIRECT_DBOOT; 1853446Smrj break; 1863446Smrj } 1873446Smrj } 1883446Smrj (void) munmap(image, 8192); 1893446Smrj (void) close(fd); 1905084Sjohnlev 1916448Svikram INJECT_ERROR1("GET_CAP_MULTIBOOT", bam_direct = BAM_DIRECT_MULTIBOOT); 1925084Sjohnlev if (bam_direct == BAM_DIRECT_DBOOT) { 193*10405SFrank.Vanderlinden@Sun.COM if (bam_is_hv == BAM_HV_PRESENT) { 1946448Svikram BAM_DPRINTF((D_IS_XVM, fcn)); 1955084Sjohnlev } else { 1966448Svikram BAM_DPRINTF((D_IS_NOT_XVM, fcn)); 1975084Sjohnlev } 1986448Svikram } else { 1996448Svikram BAM_DPRINTF((D_IS_MULTIBOOT, fcn)); 2005084Sjohnlev } 2015084Sjohnlev 2026448Svikram /* Not a fatal error if this fails */ 2036448Svikram get_findroot_cap(osroot); 2046448Svikram 2056448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 2063446Smrj return (BAM_SUCCESS); 2073446Smrj } 2083446Smrj 2093446Smrj #define INST_RELEASE "var/sadm/system/admin/INST_RELEASE" 2103446Smrj 2113446Smrj /* 2123446Smrj * Return true if root has been bfu'ed. bfu will blow away 2133446Smrj * var/sadm/system/admin/INST_RELEASE, so if it's still there, we can 2143446Smrj * assume the system has not been bfu'ed. 2153446Smrj */ 2163446Smrj static int 2173446Smrj is_bfu_system(const char *root) 2183446Smrj { 2196448Svikram static int is_bfu = -1; 2206448Svikram char path[PATH_MAX]; 2216448Svikram struct stat sb; 2226448Svikram const char *fcn = "is_bfu_system()"; 2233446Smrj 2246448Svikram if (is_bfu != -1) { 2256448Svikram BAM_DPRINTF((D_ALREADY_BFU_TEST, fcn, is_bfu ? "" : "NOT")); 2263446Smrj return (is_bfu); 2276448Svikram } 2283446Smrj 2293446Smrj (void) snprintf(path, sizeof (path), "%s/%s", root, INST_RELEASE); 2303446Smrj if (stat(path, &sb) != 0) { 2313446Smrj is_bfu = 1; 2326448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 2333446Smrj } else { 2343446Smrj is_bfu = 0; 2356448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 2363446Smrj } 2373446Smrj return (is_bfu); 2383446Smrj } 2393446Smrj 2403446Smrj #define MENU_URL(root) (is_bfu_system(root) ? \ 2413446Smrj "http://www.sun.com/msg/SUNOS-8000-CF" : \ 2423446Smrj "http://www.sun.com/msg/SUNOS-8000-AK") 2433446Smrj 2443446Smrj /* 2453446Smrj * Simply allocate a new line and copy in cmd + sep + arg 2463446Smrj */ 2473446Smrj void 2483446Smrj update_line(line_t *linep) 2493446Smrj { 2506448Svikram size_t size; 2516448Svikram const char *fcn = "update_line()"; 2523446Smrj 2536448Svikram BAM_DPRINTF((D_UPDATE_LINE_BEFORE, fcn, linep->line)); 2543446Smrj free(linep->line); 2553446Smrj size = strlen(linep->cmd) + strlen(linep->sep) + strlen(linep->arg) + 1; 2563446Smrj linep->line = s_calloc(1, size); 2573446Smrj (void) snprintf(linep->line, size, "%s%s%s", linep->cmd, linep->sep, 2583446Smrj linep->arg); 2596448Svikram BAM_DPRINTF((D_UPDATE_LINE_AFTER, fcn, linep->line)); 2606448Svikram } 2616448Svikram 2626448Svikram static char * 2636448Svikram skip_wspace(char *ptr) 2646448Svikram { 2656448Svikram const char *fcn = "skip_wspace()"; 2666448Svikram 2676448Svikram INJECT_ERROR1("SKIP_WSPACE", ptr = NULL); 2686448Svikram if (ptr == NULL) { 2696448Svikram BAM_DPRINTF((D_SKIP_WSPACE_PTR_NULL, fcn)); 2706448Svikram return (NULL); 2716448Svikram } 2726448Svikram 2736448Svikram BAM_DPRINTF((D_SKIP_WSPACE_ENTRY_PTR, fcn, ptr)); 2746448Svikram for (; *ptr != '\0'; ptr++) { 2756448Svikram if ((*ptr != ' ') && (*ptr != '\t') && 2766448Svikram (*ptr != '\n')) 2776448Svikram break; 2786448Svikram } 2796448Svikram 2806448Svikram ptr = (*ptr == '\0' ? NULL : ptr); 2816448Svikram 2826448Svikram BAM_DPRINTF((D_SKIP_WSPACE_EXIT_PTR, fcn, ptr ? ptr : "NULL")); 2836448Svikram 2846448Svikram return (ptr); 2856448Svikram } 2866448Svikram 2876448Svikram static char * 2886448Svikram rskip_bspace(char *bound, char *ptr) 2896448Svikram { 2906448Svikram const char *fcn = "rskip_bspace()"; 2916448Svikram assert(bound); 2926448Svikram assert(ptr); 2936448Svikram assert(bound <= ptr); 2946448Svikram assert(*bound != ' ' && *bound != '\t' && *bound != '\n'); 2956448Svikram 2966448Svikram BAM_DPRINTF((D_RSKIP_BSPACE_ENTRY, fcn, ptr)); 2976448Svikram for (; ptr > bound; ptr--) { 2986448Svikram if (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') 2996448Svikram break; 3006448Svikram } 3016448Svikram 3026448Svikram BAM_DPRINTF((D_RSKIP_BSPACE_EXIT, fcn, ptr)); 3036448Svikram return (ptr); 3043446Smrj } 3053446Smrj 3063446Smrj /* 3073446Smrj * The parse_kernel_line function examines a menu.lst kernel line. For 3083446Smrj * multiboot, this is: 3093446Smrj * 3103446Smrj * kernel <multiboot path> <flags1> <kernel path> <flags2> 3113446Smrj * 3123446Smrj * <multiboot path> is either /platform/i86pc/multiboot or /boot/multiboot 3133446Smrj * 3143446Smrj * <kernel path> may be missing, or may be any full or relative path to unix. 3153446Smrj * We check for it by looking for a word ending in "/unix". If it ends 3163446Smrj * in "kernel/unix", we upgrade it to a 32-bit entry. If it ends in 3173446Smrj * "kernel/amd64/unix", we upgrade it to the default entry. Otherwise, 3183446Smrj * it's a custom kernel, and we skip it. 3193446Smrj * 3203446Smrj * <flags*> are anything that doesn't fit either of the above - these will be 3213446Smrj * copied over. 3223446Smrj * 3233446Smrj * For direct boot, the defaults are 3243446Smrj * 3253446Smrj * kernel$ <kernel path> <flags> 3263446Smrj * 3273446Smrj * <kernel path> is one of: 3283446Smrj * /platform/i86pc/kernel/$ISADIR/unix 3298104SEnrico.Perla@Sun.COM * /boot/platform/i86pc/kernel/$ISADIR/unix 3303446Smrj * /platform/i86pc/kernel/unix 3313446Smrj * /platform/i86pc/kernel/amd64/unix 3323446Smrj * /boot/platform/i86pc/kernel/unix 3338104SEnrico.Perla@Sun.COM * /boot/platform/i86pc/kernel/amd64/unix 3343446Smrj * 3358104SEnrico.Perla@Sun.COM * If <kernel path> is any of the last four, the command may also be "kernel". 3363446Smrj * 3373446Smrj * <flags> is anything that isn't <kernel path>. 3383446Smrj * 3396448Svikram * This function is only called to convert a multiboot entry to a dboot entry 3403446Smrj * 3413446Smrj * For safety, we do one more check: if the kernel path starts with /boot, 3423446Smrj * we verify that the new kernel exists before changing it. This is mainly 3433446Smrj * done for bfu, as it may cause the failsafe archives to be a different 3443446Smrj * boot architecture from the newly bfu'ed system. 3453446Smrj */ 3463446Smrj static error_t 3476448Svikram cvt_kernel_line(line_t *line, const char *osroot, entry_t *entry) 3483446Smrj { 3498104SEnrico.Perla@Sun.COM char path[PATH_MAX], path_64[PATH_MAX]; 3506448Svikram char linebuf[PATH_MAX]; 3516448Svikram char new_arg[PATH_MAX]; 3528104SEnrico.Perla@Sun.COM struct stat sb, sb_64; 3536448Svikram char *old_ptr; 3546448Svikram char *unix_ptr; 3556448Svikram char *flags1_ptr; 3566448Svikram char *flags2_ptr; 3576448Svikram const char *fcn = "cvt_kernel_line()"; 3583446Smrj 3596448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, line->line, osroot)); 3603446Smrj 3613446Smrj /* 3626448Svikram * We only convert multiboot to dboot and nothing else. 3633446Smrj */ 3646448Svikram if (!(entry->flags & BAM_ENTRY_MULTIBOOT)) { 3656448Svikram BAM_DPRINTF((D_NOT_MULTIBOOT_CONVERT, fcn)); 3663446Smrj return (BAM_SUCCESS); 3673446Smrj } 3683446Smrj 3696448Svikram if (entry->flags & BAM_ENTRY_FAILSAFE) { 3703446Smrj /* 3716448Svikram * We're attempting to change failsafe to dboot. 3726448Svikram * In the bfu case, we may not have a dboot failsafe 3736448Svikram * kernel i.e. a "unix" under the "/boot" hierarchy. 3746448Svikram * If so, just emit a message in verbose mode and 3756448Svikram * return success. 3763446Smrj */ 3776448Svikram BAM_DPRINTF((D_TRYING_FAILSAFE_CVT_TO_DBOOT, fcn)); 3786448Svikram (void) snprintf(path, PATH_MAX, "%s%s", osroot, 3798104SEnrico.Perla@Sun.COM DIRECT_BOOT_FAILSAFE_32); 3808104SEnrico.Perla@Sun.COM (void) snprintf(path_64, PATH_MAX, "%s%s", osroot, 3818104SEnrico.Perla@Sun.COM DIRECT_BOOT_FAILSAFE_64); 3828104SEnrico.Perla@Sun.COM if (stat(path, &sb) != 0 && stat(path_64, &sb_64) != 0) { 3833446Smrj if (bam_verbose) { 3846448Svikram bam_error(FAILSAFE_MISSING, line->lineNum); 3853446Smrj } 3866448Svikram BAM_DPRINTF((D_NO_FAILSAFE_UNIX_CONVERT, fcn)); 3873446Smrj return (BAM_SUCCESS); 3883446Smrj } 3893446Smrj } 3903446Smrj 3913446Smrj /* 3928104SEnrico.Perla@Sun.COM * Make sure we have the correct cmd 3933446Smrj */ 3948104SEnrico.Perla@Sun.COM 3958104SEnrico.Perla@Sun.COM free(line->cmd); 3968104SEnrico.Perla@Sun.COM line->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]); 3978104SEnrico.Perla@Sun.COM BAM_DPRINTF((D_CVT_CMD_KERN_DOLLAR, fcn, line->cmd)); 3986448Svikram 3996448Svikram assert(sizeof (linebuf) > strlen(line->arg) + 32); 4006448Svikram (void) strlcpy(linebuf, line->arg, sizeof (linebuf)); 4013446Smrj 4026448Svikram old_ptr = strpbrk(linebuf, " \t\n"); 4036448Svikram old_ptr = skip_wspace(old_ptr); 4046448Svikram if (old_ptr == NULL) { 4056448Svikram /* 4066448Svikram * only multiboot and nothing else 4076448Svikram * i.e. flags1 = unix = flags2 = NULL 4086448Svikram */ 4096448Svikram flags1_ptr = unix_ptr = flags2_ptr = NULL; 4106448Svikram BAM_DPRINTF((D_FLAGS1_UNIX_FLAGS2_NULL, fcn)) 4116448Svikram goto create; 4123446Smrj } 4133446Smrj 4143446Smrj /* 4153446Smrj * 4166448Svikram * old_ptr is either at "flags1" or "unix" 4173446Smrj */ 4186448Svikram if (unix_ptr = strstr(old_ptr, "/unix")) { 4196448Svikram 4206448Svikram /* 4216448Svikram * There is a unix. 4226448Svikram */ 4236448Svikram BAM_DPRINTF((D_UNIX_PRESENT, fcn)); 4246448Svikram 4256448Svikram /* See if there's a flags2 past unix */ 4266448Svikram flags2_ptr = unix_ptr + strlen("/unix"); 4276448Svikram flags2_ptr = skip_wspace(flags2_ptr); 4286448Svikram if (flags2_ptr) { 4296448Svikram BAM_DPRINTF((D_FLAGS2_PRESENT, fcn, flags2_ptr)); 4306448Svikram } else { 4316448Svikram BAM_DPRINTF((D_FLAGS2_ABSENT, fcn)); 4323446Smrj } 4333446Smrj 4346448Svikram /* see if there is a flags1 before unix */ 4356448Svikram unix_ptr = rskip_bspace(old_ptr, unix_ptr); 4363446Smrj 4373446Smrj if (unix_ptr == old_ptr) { 4383446Smrj flags1_ptr = NULL; 4396448Svikram BAM_DPRINTF((D_FLAGS1_ABSENT, fcn)); 4403446Smrj } else { 4413446Smrj flags1_ptr = old_ptr; 4426448Svikram *unix_ptr = '\0'; 4436448Svikram unix_ptr++; 4446448Svikram BAM_DPRINTF((D_FLAGS1_PRESENT, fcn, flags1_ptr)); 4453446Smrj } 4463446Smrj 4476448Svikram } else { 4486448Svikram /* There is no unix, there is only a bunch of flags */ 4493446Smrj flags1_ptr = old_ptr; 4506448Svikram unix_ptr = flags2_ptr = NULL; 4516448Svikram BAM_DPRINTF((D_FLAGS1_ONLY, fcn, flags1_ptr)); 4523446Smrj } 4533446Smrj 4543446Smrj /* 4556448Svikram * With dboot, unix is fixed and is at the beginning. We need to 4566448Svikram * migrate flags1 and flags2 4573446Smrj */ 4586448Svikram create: 4596448Svikram if (entry->flags & BAM_ENTRY_FAILSAFE) { 4606448Svikram (void) snprintf(new_arg, sizeof (new_arg), "%s", 4616448Svikram DIRECT_BOOT_FAILSAFE_KERNEL); 4626448Svikram } else { 4636448Svikram (void) snprintf(new_arg, sizeof (new_arg), "%s", 4646448Svikram DIRECT_BOOT_KERNEL); 4656448Svikram } 4666448Svikram BAM_DPRINTF((D_CVTED_UNIX, fcn, new_arg)); 4673446Smrj 4686448Svikram if (flags1_ptr != NULL) { 4696448Svikram (void) strlcat(new_arg, " ", sizeof (new_arg)); 4706448Svikram (void) strlcat(new_arg, flags1_ptr, sizeof (new_arg)); 4713446Smrj } 4723446Smrj 4736448Svikram if (flags2_ptr != NULL) { 4746448Svikram (void) strlcat(new_arg, " ", sizeof (new_arg)); 4756448Svikram (void) strlcat(new_arg, flags2_ptr, sizeof (new_arg)); 4766448Svikram } 4776448Svikram 4786448Svikram BAM_DPRINTF((D_CVTED_UNIX_AND_FLAGS, fcn, new_arg)); 4796448Svikram 4806448Svikram free(line->arg); 4816448Svikram line->arg = s_strdup(new_arg); 4826448Svikram update_line(line); 4836448Svikram BAM_DPRINTF((D_CVTED_KERNEL_LINE, fcn, line->line)); 4843446Smrj return (BAM_SUCCESS); 4853446Smrj } 4863446Smrj 4873446Smrj /* 4883446Smrj * Similar to above, except this time we're looking at a module line, 4893446Smrj * which is quite a bit simpler. 4903446Smrj * 4913446Smrj * Under multiboot, the archive line is: 4923446Smrj * 4933446Smrj * module /platform/i86pc/boot_archive 4943446Smrj * 4953446Smrj * Under directboot, the archive line is: 4963446Smrj * 4973446Smrj * module$ /platform/i86pc/$ISADIR/boot_archive 4983446Smrj * 4993446Smrj * which may be specified exactly as either of: 5003446Smrj * 5013446Smrj * module /platform/i86pc/boot_archive 5023446Smrj * module /platform/i86pc/amd64/boot_archive 5033446Smrj * 5048104SEnrico.Perla@Sun.COM * Under multiboot, the failsafe is: 5053446Smrj * 5063446Smrj * module /boot/x86.miniroot-safe 5078104SEnrico.Perla@Sun.COM * 5088104SEnrico.Perla@Sun.COM * Under dboot, the failsafe is: 5098104SEnrico.Perla@Sun.COM * 5108104SEnrico.Perla@Sun.COM * module$ /boot/$ISADIR/x86.miniroot-safe 5118104SEnrico.Perla@Sun.COM * 5128104SEnrico.Perla@Sun.COM * which may be specified exactly as either of: 5138104SEnrico.Perla@Sun.COM * 5148104SEnrico.Perla@Sun.COM * module /boot/x86.miniroot-safe 5158104SEnrico.Perla@Sun.COM * module /boot/amd64/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 5448104SEnrico.Perla@Sun.COM free(line->cmd); 5458104SEnrico.Perla@Sun.COM free(line->arg); 5468104SEnrico.Perla@Sun.COM line->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]); 5478104SEnrico.Perla@Sun.COM 5488104SEnrico.Perla@Sun.COM line->arg = s_strdup(entry->flags & BAM_ENTRY_FAILSAFE ? 5498104SEnrico.Perla@Sun.COM FAILSAFE_ARCHIVE : DIRECT_BOOT_ARCHIVE); 5506448Svikram 5516448Svikram update_line(line); 5526448Svikram BAM_DPRINTF((D_CVTED_MODULE, fcn, line->line)); 5536448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5546448Svikram return (BAM_SUCCESS); 5556448Svikram } 5566448Svikram 5576448Svikram static void 5586448Svikram bam_warn_hand_entries(menu_t *mp, char *osroot) 5596448Svikram { 5606448Svikram int hand_num; 5616448Svikram int hand_max; 5626448Svikram int *hand_list; 5636448Svikram int i; 5646448Svikram entry_t *entry; 5656448Svikram const char *fcn = "bam_warn_hand_entries()"; 5666448Svikram 5676448Svikram if (bam_force) { 5686448Svikram /* 5696448Svikram * No warning needed, we are automatically converting 5706448Svikram * the "hand" entries 5716448Svikram */ 5726448Svikram BAM_DPRINTF((D_FORCE_HAND_CVT, fcn)); 5736448Svikram return; 5746448Svikram } 5756448Svikram 5766448Svikram hand_num = 0; 5776448Svikram hand_max = BAM_ENTRY_NUM; 5786448Svikram hand_list = s_calloc(1, hand_max); 5796448Svikram 5806448Svikram for (entry = mp->entries; entry; entry = entry->next) { 5816448Svikram if (entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) 5826448Svikram continue; 5836448Svikram BAM_DPRINTF((D_FOUND_HAND, fcn, entry->entryNum)); 5846448Svikram if (++hand_num > hand_max) { 5856448Svikram hand_max *= 2; 5866448Svikram hand_list = s_realloc(hand_list, 5876448Svikram hand_max * sizeof (int)); 5886448Svikram } 5896448Svikram hand_list[hand_num - 1] = entry->entryNum; 5906448Svikram } 5916448Svikram 5926448Svikram bam_error(HAND_ADDED_ENTRIES, osroot, MENU_URL(osroot)); 5936448Svikram bam_print_stderr("Entry Number%s: ", (hand_num > 1) ? 5946448Svikram "s" : ""); 5956448Svikram for (i = 0; i < hand_num; i++) { 5966448Svikram bam_print_stderr("%d ", hand_list[i]); 5976448Svikram } 5986448Svikram bam_print_stderr("\n"); 5996448Svikram } 6003446Smrj 6016448Svikram static entry_t * 6026448Svikram find_matching_entry( 6036448Svikram entry_t *estart, 6046448Svikram char *grubsign, 6056448Svikram char *grubroot, 6066448Svikram int root_opt) 6076448Svikram { 6086448Svikram entry_t *entry; 6096448Svikram line_t *line; 6106448Svikram char opt[10]; 6116448Svikram const char *fcn = "find_matching_entry()"; 6126448Svikram 6136448Svikram assert(grubsign); 6146448Svikram assert(root_opt == 0 || root_opt == 1); 6156448Svikram 6166448Svikram (void) snprintf(opt, sizeof (opt), "%d", root_opt); 6176448Svikram BAM_DPRINTF((D_FUNC_ENTRY3, fcn, grubsign, grubroot, opt)); 6186448Svikram 6196448Svikram for (entry = estart; entry; entry = entry->next) { 6206694Svikram 6216448Svikram if (!(entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) && 6226448Svikram !bam_force) { 6236448Svikram BAM_DPRINTF((D_SKIP_ENTRY, fcn, entry->entryNum)); 6246448Svikram continue; 6256448Svikram } 6266448Svikram 6276448Svikram if (entry->flags & BAM_ENTRY_ROOT) { 6286448Svikram for (line = entry->start; line; line = line->next) { 6296448Svikram if (line->cmd == NULL || line->arg == NULL) { 6306448Svikram if (line == entry->end) { 6316448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 6326448Svikram break; 6336448Svikram } else { 6346448Svikram BAM_DPRINTF((D_SKIP_NULL, fcn)); 6356448Svikram continue; 6366448Svikram } 6376448Svikram } 6386448Svikram if (strcmp(line->cmd, menu_cmds[ROOT_CMD]) 6396448Svikram == 0 && strcmp(line->arg, grubroot) == 0) { 6406448Svikram BAM_DPRINTF((D_ROOT_MATCH, fcn, 6416448Svikram line->line, grubsign)); 6426448Svikram return (entry); 6436448Svikram } 6446448Svikram if (line == entry->end) { 6456448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 6466448Svikram break; 6476448Svikram } 6486448Svikram } 6496448Svikram } else if (entry->flags & BAM_ENTRY_FINDROOT) { 6506448Svikram for (line = entry->start; line; line = line->next) { 6516448Svikram if (line->cmd == NULL || line->arg == NULL) { 6526448Svikram if (line == entry->end) { 6536448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 6546448Svikram break; 6556448Svikram } else { 6566448Svikram BAM_DPRINTF((D_SKIP_NULL, fcn)); 6576448Svikram continue; 6586448Svikram } 6596448Svikram } 6606448Svikram if (strcmp(line->cmd, menu_cmds[FINDROOT_CMD]) 6616448Svikram == 0 && strcmp(line->arg, grubsign) == 0) { 6626448Svikram BAM_DPRINTF((D_FINDROOT_MATCH, fcn, 6636448Svikram line->line, grubsign)); 6646448Svikram return (entry); 6656448Svikram } 6666448Svikram if (line == entry->end) { 6676448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 6686448Svikram break; 6696448Svikram } 6706448Svikram } 6716448Svikram } else if (root_opt) { 6726448Svikram /* Neither root nor findroot */ 6736448Svikram BAM_DPRINTF((D_NO_ROOT_FINDROOT, fcn, entry->entryNum)); 6746448Svikram return (entry); 6756448Svikram } 6763446Smrj } 6773446Smrj 6786448Svikram BAM_DPRINTF((D_NO_MATCH, fcn)); 6796448Svikram return (NULL); 6806448Svikram } 6816448Svikram 6826448Svikram /* 6836448Svikram * The following is a set of routines that attempt to convert the 6846448Svikram * menu entries for the supplied osroot into a format compatible 6856448Svikram * with the GRUB installation on osroot. 6866448Svikram * 6876448Svikram * Each of these conversion routines make no assumptions about 6886448Svikram * the current state of the menu entry, it does its best to 6896448Svikram * convert the menu entry to the new state. In the process 6906448Svikram * we may either upgrade or downgrade. 6916448Svikram * 6926448Svikram * We don't make any heroic efforts at conversion. It is better 6936448Svikram * to be conservative and bail out at the first sign of error. We will 6946448Svikram * in such cases, point the user at the knowledge-base article 6956448Svikram * so that they can upgrade manually. 6966448Svikram */ 6976448Svikram static error_t 6986448Svikram bam_add_findroot(menu_t *mp, char *grubsign, char *grubroot, int root_opt) 6996448Svikram { 7006448Svikram entry_t *entry; 7016448Svikram line_t *line; 7026448Svikram line_t *newlp; 7036448Svikram int update_num; 7046448Svikram char linebuf[PATH_MAX]; 7056448Svikram const char *fcn = "bam_add_findroot()"; 7066448Svikram 7076448Svikram update_num = 0; 7086448Svikram 7096448Svikram bam_print(CVT_FINDROOT); 7106448Svikram 7116448Svikram entry = mp->entries; 7126448Svikram for (; entry = find_matching_entry(entry, grubsign, grubroot, root_opt); 7136448Svikram entry = entry->next) { 7146448Svikram if (entry->flags & BAM_ENTRY_FINDROOT) { 7156448Svikram /* already converted */ 7166448Svikram BAM_DPRINTF((D_ALREADY_FINDROOT, fcn, entry->entryNum)); 7176448Svikram continue; 7186448Svikram } 7196448Svikram for (line = entry->start; line; line = line->next) { 7206448Svikram if (line->cmd == NULL || line->arg == NULL) { 7216448Svikram if (line == entry->end) { 7226448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 7236448Svikram break; 7246448Svikram } else { 7256448Svikram BAM_DPRINTF((D_SKIP_NULL, fcn)); 7266448Svikram continue; 7276448Svikram } 7286448Svikram } 7296448Svikram if (strcmp(line->cmd, menu_cmds[TITLE_CMD]) == 0) { 7306448Svikram newlp = s_calloc(1, sizeof (line_t)); 7316448Svikram newlp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]); 7326448Svikram newlp->sep = s_strdup(" "); 7336448Svikram newlp->arg = s_strdup(grubsign); 7346448Svikram (void) snprintf(linebuf, sizeof (linebuf), 7356448Svikram "%s%s%s", newlp->cmd, newlp->sep, 7366448Svikram newlp->arg); 7376448Svikram newlp->line = s_strdup(linebuf); 7386448Svikram bam_add_line(mp, entry, line, newlp); 7396448Svikram update_num = 1; 7406448Svikram entry->flags &= ~BAM_ENTRY_ROOT; 7416448Svikram entry->flags |= BAM_ENTRY_FINDROOT; 7426448Svikram BAM_DPRINTF((D_ADDED_FINDROOT, fcn, 7436448Svikram newlp->line)); 7446448Svikram line = newlp; 7456448Svikram } 7466448Svikram if (strcmp(line->cmd, menu_cmds[ROOT_CMD]) == 0) { 7476448Svikram BAM_DPRINTF((D_FREEING_ROOT, fcn, line->line)); 7486448Svikram unlink_line(mp, line); 7496448Svikram line_free(line); 7506448Svikram } 7516448Svikram if (line == entry->end) { 7526448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 7536448Svikram break; 7546448Svikram } 7556448Svikram } 7566448Svikram } 7576448Svikram 7586448Svikram if (update_num) { 7596448Svikram BAM_DPRINTF((D_UPDATED_NUMBERING, fcn)); 7606448Svikram update_numbering(mp); 7616448Svikram } 7626448Svikram 7636448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7646448Svikram return (BAM_SUCCESS); 7656448Svikram } 7666448Svikram 7676448Svikram static error_t 7686448Svikram bam_add_hv(menu_t *mp, char *grubsign, char *grubroot, int root_opt) 7696448Svikram { 7706448Svikram entry_t *entry; 7716448Svikram const char *fcn = "bam_add_hv()"; 7726448Svikram 7736448Svikram bam_print(CVT_HV); 7746448Svikram 7756448Svikram entry = mp->entries; 7766448Svikram for (; entry = find_matching_entry(entry, grubsign, grubroot, root_opt); 7776448Svikram entry = entry->next) { 7786448Svikram if (entry->flags & BAM_ENTRY_HV) { 7796448Svikram BAM_DPRINTF((D_ALREADY_HV, fcn, entry->entryNum)); 7806448Svikram return (BAM_SUCCESS); 7816448Svikram } 7826448Svikram } 7836448Svikram 7846448Svikram (void) add_boot_entry(mp, NEW_HV_ENTRY, grubsign, XEN_MENU, 7856448Svikram XEN_KERNEL_MODULE_LINE, DIRECT_BOOT_ARCHIVE); 7866448Svikram 7876448Svikram BAM_DPRINTF((D_ADDED_XVM_ENTRY, fcn)); 7886448Svikram 7896448Svikram update_numbering(mp); 7906448Svikram 7916448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7923446Smrj 7933446Smrj return (BAM_SUCCESS); 7943446Smrj } 7953446Smrj 7966448Svikram static error_t 7976448Svikram bam_add_dboot( 7986448Svikram menu_t *mp, 7996448Svikram char *osroot, 8006448Svikram char *grubsign, 8016448Svikram char *grubroot, 8026448Svikram int root_opt) 8036448Svikram { 8046448Svikram int msg = 0; 8056448Svikram entry_t *entry; 8066448Svikram line_t *line; 8076448Svikram error_t ret; 8086448Svikram const char *fcn = "bam_add_dboot()"; 8096448Svikram 8106448Svikram bam_print(CVT_DBOOT); 8116448Svikram 8126448Svikram entry = mp->entries; 8136448Svikram for (; entry = find_matching_entry(entry, grubsign, grubroot, root_opt); 8146448Svikram entry = entry->next) { 8156448Svikram for (line = entry->start; line; line = line->next) { 8166448Svikram if (line->cmd == NULL || line->arg == NULL) { 8176448Svikram if (line == entry->end) { 8186448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 8196448Svikram break; 8206448Svikram } else { 8216448Svikram BAM_DPRINTF((D_SKIP_NULL, fcn)); 8226448Svikram continue; 8236448Svikram } 8246448Svikram } 8256448Svikram 8266448Svikram /* 8276448Svikram * If we have a kernel$ command, assume it 8286448Svikram * is dboot already. If it is not a dboot 8296448Svikram * entry, something funny is going on and 8306448Svikram * we will leave it alone 8316448Svikram */ 8326448Svikram if (strcmp(line->cmd, menu_cmds[KERNEL_CMD]) == 0) { 8336448Svikram ret = cvt_kernel_line(line, osroot, entry); 8346448Svikram INJECT_ERROR1("ADD_DBOOT_KERN_ERR", 8356448Svikram ret = BAM_ERROR); 8366448Svikram INJECT_ERROR1("ADD_DBOOT_KERN_MSG", 8376448Svikram ret = BAM_MSG); 8386448Svikram if (ret == BAM_ERROR) { 8396448Svikram BAM_DPRINTF((D_CVT_KERNEL_FAIL, fcn)); 8406448Svikram return (ret); 8416448Svikram } else if (ret == BAM_MSG) { 8426448Svikram msg = 1; 8436448Svikram BAM_DPRINTF((D_CVT_KERNEL_MSG, fcn)); 8446448Svikram } 8456448Svikram } 8466448Svikram if (strcmp(line->cmd, menu_cmds[MODULE_CMD]) == 0) { 8476448Svikram ret = cvt_module_line(line, entry); 8486448Svikram INJECT_ERROR1("ADD_DBOOT_MOD_ERR", 8496448Svikram ret = BAM_ERROR); 8506448Svikram INJECT_ERROR1("ADD_DBOOT_MOD_MSG", 8516448Svikram ret = BAM_MSG); 8526448Svikram if (ret == BAM_ERROR) { 8536448Svikram BAM_DPRINTF((D_CVT_MODULE_FAIL, fcn)); 8546448Svikram return (ret); 8556448Svikram } else if (ret == BAM_MSG) { 8566448Svikram BAM_DPRINTF((D_CVT_MODULE_MSG, fcn)); 8576448Svikram msg = 1; 8586448Svikram } 8596448Svikram } 8606448Svikram 8616448Svikram if (line == entry->end) { 8626448Svikram BAM_DPRINTF((D_ENTRY_END, fcn)); 8636448Svikram break; 8646448Svikram } 8656448Svikram } 8666448Svikram } 8676448Svikram 8686448Svikram ret = msg ? BAM_MSG : BAM_SUCCESS; 8696448Svikram BAM_DPRINTF((D_RETURN_RET, fcn, ret)); 8706448Svikram return (ret); 8716448Svikram } 8726448Svikram 8733446Smrj /*ARGSUSED*/ 8743446Smrj error_t 8756448Svikram upgrade_menu(menu_t *mp, char *osroot, char *menu_root) 8763446Smrj { 8776448Svikram char *osdev; 8786448Svikram char *grubsign; 8796448Svikram char *grubroot; 8806448Svikram int ret1; 8816448Svikram int ret2; 8826448Svikram int ret3; 8836448Svikram const char *fcn = "upgrade_menu()"; 8845084Sjohnlev 8856448Svikram assert(osroot); 8866448Svikram assert(menu_root); 8873446Smrj 8886448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 8893446Smrj 8906448Svikram /* 8916448Svikram * We only support upgrades. Xen may not be present 8926448Svikram * on smaller metaclusters so we don't check for that. 8936448Svikram */ 8946448Svikram if (bam_is_findroot != BAM_FINDROOT_PRESENT || 8956448Svikram bam_direct != BAM_DIRECT_DBOOT) { 8966448Svikram bam_error(DOWNGRADE_NOTSUP, osroot); 8976448Svikram return (BAM_ERROR); 8983446Smrj } 8993446Smrj 9003446Smrj /* 9016448Svikram * First get the GRUB signature 9025084Sjohnlev */ 9036448Svikram osdev = get_special(osroot); 9046448Svikram INJECT_ERROR1("UPGRADE_OSDEV", osdev = NULL); 9056448Svikram if (osdev == NULL) { 9066448Svikram bam_error(CANT_FIND_SPECIAL, osroot); 9076448Svikram return (BAM_ERROR); 9086448Svikram } 9096448Svikram 9106448Svikram grubsign = get_grubsign(osroot, osdev); 9116448Svikram INJECT_ERROR1("UPGRADE_GRUBSIGN", grubsign = NULL); 9126448Svikram if (grubsign == NULL) { 9136448Svikram free(osdev); 9146448Svikram bam_error(CANT_FIND_GRUBSIGN, osroot); 9156448Svikram return (BAM_ERROR); 9165084Sjohnlev } 9175084Sjohnlev 9186448Svikram /* not fatal if we can't get grubroot */ 9196448Svikram grubroot = get_grubroot(osroot, osdev, menu_root); 9206448Svikram INJECT_ERROR1("UPGRADE_GRUBROOT", grubroot = NULL); 9216448Svikram 9226448Svikram free(osdev); 9236448Svikram 9246448Svikram ret1 = bam_add_findroot(mp, grubsign, 9256448Svikram grubroot, root_optional(osroot, menu_root)); 9266448Svikram INJECT_ERROR1("UPGRADE_ADD_FINDROOT", ret1 = BAM_ERROR); 9276448Svikram if (ret1 == BAM_ERROR) 9286448Svikram goto abort; 9296448Svikram 930*10405SFrank.Vanderlinden@Sun.COM if (bam_is_hv == BAM_HV_PRESENT) { 931*10405SFrank.Vanderlinden@Sun.COM ret2 = bam_add_hv(mp, grubsign, grubroot, 932*10405SFrank.Vanderlinden@Sun.COM root_optional(osroot, menu_root)); 933*10405SFrank.Vanderlinden@Sun.COM INJECT_ERROR1("UPGRADE_ADD_HV", ret2 = BAM_ERROR); 934*10405SFrank.Vanderlinden@Sun.COM if (ret2 == BAM_ERROR) 935*10405SFrank.Vanderlinden@Sun.COM goto abort; 936*10405SFrank.Vanderlinden@Sun.COM } else 937*10405SFrank.Vanderlinden@Sun.COM ret2 = BAM_SUCCESS; 9386448Svikram 9396448Svikram ret3 = bam_add_dboot(mp, osroot, grubsign, 9406448Svikram grubroot, root_optional(osroot, menu_root)); 9416448Svikram INJECT_ERROR1("UPGRADE_ADD_DBOOT", ret3 = BAM_ERROR); 9426448Svikram if (ret3 == BAM_ERROR) 9436448Svikram goto abort; 9446448Svikram 9456448Svikram if (ret1 == BAM_MSG || ret2 == BAM_MSG || ret3 == BAM_MSG) { 9466448Svikram bam_error(CVT_TODO, MENU_URL(osroot)); 9476448Svikram } else { 9486448Svikram bam_warn_hand_entries(mp, osroot); 9493446Smrj } 9506448Svikram 9516448Svikram free(grubsign); 9526448Svikram 9536448Svikram BAM_DPRINTF((D_RETURN_RET, fcn, BAM_WRITE)); 9543446Smrj return (BAM_WRITE); 9556448Svikram 9566448Svikram abort: 9576448Svikram free(grubsign); 9586448Svikram bam_error(CVT_ABORT, osroot, MENU_URL(osroot)); 9596448Svikram return (BAM_ERROR); 9603446Smrj } 961