1*3446Smrj /* 2*3446Smrj * CDDL HEADER START 3*3446Smrj * 4*3446Smrj * The contents of this file are subject to the terms of the 5*3446Smrj * Common Development and Distribution License (the "License"). 6*3446Smrj * You may not use this file except in compliance with the License. 7*3446Smrj * 8*3446Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*3446Smrj * or http://www.opensolaris.org/os/licensing. 10*3446Smrj * See the License for the specific language governing permissions 11*3446Smrj * and limitations under the License. 12*3446Smrj * 13*3446Smrj * When distributing Covered Code, include this CDDL HEADER in each 14*3446Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*3446Smrj * If applicable, add the following below this CDDL HEADER, with the 16*3446Smrj * fields enclosed by brackets "[]" replaced with your own identifying 17*3446Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 18*3446Smrj * 19*3446Smrj * CDDL HEADER END 20*3446Smrj */ 21*3446Smrj /* 22*3446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*3446Smrj * Use is subject to license terms. 24*3446Smrj */ 25*3446Smrj 26*3446Smrj #pragma ident "%Z%%M% %I% %E% SMI" 27*3446Smrj 28*3446Smrj #include <stdio.h> 29*3446Smrj #include <errno.h> 30*3446Smrj #include <stdlib.h> 31*3446Smrj #include <string.h> 32*3446Smrj #include <unistd.h> 33*3446Smrj #include <sys/types.h> 34*3446Smrj #include <sys/stat.h> 35*3446Smrj #include <limits.h> 36*3446Smrj #include <fcntl.h> 37*3446Smrj #include <strings.h> 38*3446Smrj 39*3446Smrj #include <sys/mman.h> 40*3446Smrj #include <sys/elf.h> 41*3446Smrj #include <sys/multiboot.h> 42*3446Smrj 43*3446Smrj #include "message.h" 44*3446Smrj #include "bootadm.h" 45*3446Smrj 46*3446Smrj direct_or_multi_t bam_direct = BAM_DIRECT_NOT_SET; 47*3446Smrj 48*3446Smrj error_t 49*3446Smrj dboot_or_multiboot(const char *root) 50*3446Smrj { 51*3446Smrj char fname[PATH_MAX]; 52*3446Smrj char *image; 53*3446Smrj uchar_t *ident; 54*3446Smrj int fd, m; 55*3446Smrj multiboot_header_t *mbh; 56*3446Smrj 57*3446Smrj (void) snprintf(fname, PATH_MAX, "%s/%s", root, 58*3446Smrj "platform/i86pc/kernel/unix"); 59*3446Smrj fd = open(fname, O_RDONLY); 60*3446Smrj if (fd < 0) { 61*3446Smrj bam_error(OPEN_FAIL, fname, strerror(errno)); 62*3446Smrj return (BAM_ERROR); 63*3446Smrj } 64*3446Smrj 65*3446Smrj /* 66*3446Smrj * mmap the first 8K 67*3446Smrj */ 68*3446Smrj image = mmap(NULL, 8192, PROT_READ, MAP_SHARED, fd, 0); 69*3446Smrj if (image == MAP_FAILED) { 70*3446Smrj bam_error(MMAP_FAIL, fname, strerror(errno)); 71*3446Smrj return (BAM_ERROR); 72*3446Smrj } 73*3446Smrj 74*3446Smrj ident = (uchar_t *)image; 75*3446Smrj if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 || 76*3446Smrj ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) { 77*3446Smrj bam_error(NOT_ELF_FILE, fname); 78*3446Smrj return (BAM_ERROR); 79*3446Smrj } 80*3446Smrj if (ident[EI_CLASS] != ELFCLASS32) { 81*3446Smrj bam_error(WRONG_ELF_CLASS, fname, ident[EI_CLASS]); 82*3446Smrj return (BAM_ERROR); 83*3446Smrj } 84*3446Smrj 85*3446Smrj /* 86*3446Smrj * The GRUB multiboot header must be 32-bit aligned and completely 87*3446Smrj * contained in the 1st 8K of the file. If the unix binary has 88*3446Smrj * a multiboot header, then it is a 'dboot' kernel. Otherwise, 89*3446Smrj * this kernel must be booted via multiboot -- we call this a 90*3446Smrj * 'multiboot' kernel. 91*3446Smrj */ 92*3446Smrj bam_direct = BAM_DIRECT_MULTIBOOT; 93*3446Smrj for (m = 0; m < 8192 - sizeof (multiboot_header_t); m += 4) { 94*3446Smrj mbh = (void *)(image + m); 95*3446Smrj if (mbh->magic == MB_HEADER_MAGIC) { 96*3446Smrj bam_direct = BAM_DIRECT_DBOOT; 97*3446Smrj break; 98*3446Smrj } 99*3446Smrj } 100*3446Smrj (void) munmap(image, 8192); 101*3446Smrj (void) close(fd); 102*3446Smrj return (BAM_SUCCESS); 103*3446Smrj } 104*3446Smrj 105*3446Smrj #define INST_RELEASE "var/sadm/system/admin/INST_RELEASE" 106*3446Smrj 107*3446Smrj /* 108*3446Smrj * Return true if root has been bfu'ed. bfu will blow away 109*3446Smrj * var/sadm/system/admin/INST_RELEASE, so if it's still there, we can 110*3446Smrj * assume the system has not been bfu'ed. 111*3446Smrj */ 112*3446Smrj static int 113*3446Smrj is_bfu_system(const char *root) 114*3446Smrj { 115*3446Smrj static int is_bfu = -1; 116*3446Smrj char path[PATH_MAX]; 117*3446Smrj struct stat sb; 118*3446Smrj 119*3446Smrj if (is_bfu != -1) 120*3446Smrj return (is_bfu); 121*3446Smrj 122*3446Smrj (void) snprintf(path, sizeof (path), "%s/%s", root, INST_RELEASE); 123*3446Smrj if (stat(path, &sb) != 0) { 124*3446Smrj is_bfu = 1; 125*3446Smrj } else { 126*3446Smrj is_bfu = 0; 127*3446Smrj } 128*3446Smrj return (is_bfu); 129*3446Smrj } 130*3446Smrj 131*3446Smrj #define MENU_URL(root) (is_bfu_system(root) ? \ 132*3446Smrj "http://www.sun.com/msg/SUNOS-8000-CF" : \ 133*3446Smrj "http://www.sun.com/msg/SUNOS-8000-AK") 134*3446Smrj 135*3446Smrj /* 136*3446Smrj * Simply allocate a new line and copy in cmd + sep + arg 137*3446Smrj */ 138*3446Smrj void 139*3446Smrj update_line(line_t *linep) 140*3446Smrj { 141*3446Smrj size_t size; 142*3446Smrj 143*3446Smrj free(linep->line); 144*3446Smrj size = strlen(linep->cmd) + strlen(linep->sep) + strlen(linep->arg) + 1; 145*3446Smrj linep->line = s_calloc(1, size); 146*3446Smrj (void) snprintf(linep->line, size, "%s%s%s", linep->cmd, linep->sep, 147*3446Smrj linep->arg); 148*3446Smrj } 149*3446Smrj 150*3446Smrj /* 151*3446Smrj * The parse_kernel_line function examines a menu.lst kernel line. For 152*3446Smrj * multiboot, this is: 153*3446Smrj * 154*3446Smrj * kernel <multiboot path> <flags1> <kernel path> <flags2> 155*3446Smrj * 156*3446Smrj * <multiboot path> is either /platform/i86pc/multiboot or /boot/multiboot 157*3446Smrj * 158*3446Smrj * <kernel path> may be missing, or may be any full or relative path to unix. 159*3446Smrj * We check for it by looking for a word ending in "/unix". If it ends 160*3446Smrj * in "kernel/unix", we upgrade it to a 32-bit entry. If it ends in 161*3446Smrj * "kernel/amd64/unix", we upgrade it to the default entry. Otherwise, 162*3446Smrj * it's a custom kernel, and we skip it. 163*3446Smrj * 164*3446Smrj * <flags*> are anything that doesn't fit either of the above - these will be 165*3446Smrj * copied over. 166*3446Smrj * 167*3446Smrj * For direct boot, the defaults are 168*3446Smrj * 169*3446Smrj * kernel$ <kernel path> <flags> 170*3446Smrj * 171*3446Smrj * <kernel path> is one of: 172*3446Smrj * /platform/i86pc/kernel/$ISADIR/unix 173*3446Smrj * /platform/i86pc/kernel/unix 174*3446Smrj * /platform/i86pc/kernel/amd64/unix 175*3446Smrj * /boot/platform/i86pc/kernel/unix 176*3446Smrj * 177*3446Smrj * If <kernel path> is any of the last three, the command may also be "kernel". 178*3446Smrj * 179*3446Smrj * <flags> is anything that isn't <kernel path>. 180*3446Smrj * 181*3446Smrj * This function is only called if it applies to our target boot environment. 182*3446Smrj * If we can't make any sense of the kernel line, an error is printed and 183*3446Smrj * BAM_ERROR is returned. 184*3446Smrj * 185*3446Smrj * The desired install type is given in the global variable bam_direct. 186*3446Smrj * If the kernel line is of a different install type, we change it to the 187*3446Smrj * preferred type. If the kernel line is already of the correct install 188*3446Smrj * type, we do nothing. Either way, BAM_SUCCESS is returned. 189*3446Smrj * 190*3446Smrj * For safety, we do one more check: if the kernel path starts with /boot, 191*3446Smrj * we verify that the new kernel exists before changing it. This is mainly 192*3446Smrj * done for bfu, as it may cause the failsafe archives to be a different 193*3446Smrj * boot architecture from the newly bfu'ed system. 194*3446Smrj */ 195*3446Smrj static error_t 196*3446Smrj parse_kernel_line(line_t *linep, const char *root, uint8_t *flags) 197*3446Smrj { 198*3446Smrj char path[PATH_MAX]; 199*3446Smrj int len, left, total_len; 200*3446Smrj struct stat sb; 201*3446Smrj char *new_ptr, *new_arg, *old_ptr; 202*3446Smrj menu_cmd_t which; 203*3446Smrj 204*3446Smrj /* Used when changing a multiboot line to dboot */ 205*3446Smrj char *unix_ptr, *flags1_ptr, *flags2_ptr; 206*3446Smrj 207*3446Smrj /* 208*3446Smrj * Note that BAM_ENTRY_DBOOT refers to the entry we're looking at, not 209*3446Smrj * necessarily the system type. 210*3446Smrj */ 211*3446Smrj if (strncmp(linep->arg, DIRECT_BOOT_32, 212*3446Smrj sizeof (DIRECT_BOOT_32) - 1) == 0) { 213*3446Smrj *flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_32BIT; 214*3446Smrj } else if ((strncmp(linep->arg, DIRECT_BOOT_KERNEL, 215*3446Smrj sizeof (DIRECT_BOOT_KERNEL) - 1) == 0) || 216*3446Smrj (strncmp(linep->arg, DIRECT_BOOT_64, 217*3446Smrj sizeof (DIRECT_BOOT_64) - 1) == 0) || 218*3446Smrj (strncmp(linep->arg, DIRECT_BOOT_FAILSAFE_KERNEL, 219*3446Smrj sizeof (DIRECT_BOOT_FAILSAFE_KERNEL) - 1) == 0)) { 220*3446Smrj *flags |= BAM_ENTRY_DBOOT; 221*3446Smrj } else if ((strncmp(linep->arg, MULTI_BOOT, 222*3446Smrj sizeof (MULTI_BOOT) - 1) == 0) || 223*3446Smrj (strncmp(linep->arg, MULTI_BOOT_FAILSAFE, 224*3446Smrj sizeof (MULTI_BOOT_FAILSAFE) - 1) == 0)) { 225*3446Smrj *flags &= ~BAM_ENTRY_DBOOT; 226*3446Smrj } else { 227*3446Smrj bam_error(NO_KERNEL_MATCH, linep->lineNum, MENU_URL(root)); 228*3446Smrj return (BAM_ERROR); 229*3446Smrj } 230*3446Smrj 231*3446Smrj if (((*flags & BAM_ENTRY_DBOOT) && (bam_direct == BAM_DIRECT_DBOOT)) || 232*3446Smrj (((*flags & BAM_ENTRY_DBOOT) == 0) && 233*3446Smrj (bam_direct == BAM_DIRECT_MULTIBOOT))) { 234*3446Smrj 235*3446Smrj /* No action needed */ 236*3446Smrj return (BAM_SUCCESS); 237*3446Smrj } 238*3446Smrj 239*3446Smrj if (*flags & BAM_ENTRY_MINIROOT) { 240*3446Smrj /* 241*3446Smrj * We're changing boot architectures - make sure 242*3446Smrj * the multiboot failsafe still exists. 243*3446Smrj */ 244*3446Smrj (void) snprintf(path, PATH_MAX, "%s%s", root, 245*3446Smrj (*flags & BAM_ENTRY_DBOOT) ? MULTI_BOOT_FAILSAFE : 246*3446Smrj DIRECT_BOOT_FAILSAFE_KERNEL); 247*3446Smrj if (stat(path, &sb) != 0) { 248*3446Smrj if (bam_verbose) { 249*3446Smrj bam_error(FAILSAFE_MISSING, linep->lineNum); 250*3446Smrj } 251*3446Smrj return (BAM_SUCCESS); 252*3446Smrj } 253*3446Smrj } 254*3446Smrj 255*3446Smrj /* 256*3446Smrj * Make sure we have the correct cmd - either kernel or kernel$ 257*3446Smrj * The failsafe entry should always be KERNEL_CMD. 258*3446Smrj */ 259*3446Smrj which = ((bam_direct == BAM_DIRECT_MULTIBOOT) || 260*3446Smrj (*flags & BAM_ENTRY_MINIROOT)) ? KERNEL_CMD : KERNEL_DOLLAR_CMD; 261*3446Smrj free(linep->cmd); 262*3446Smrj len = strlen(menu_cmds[which]) + 1; 263*3446Smrj linep->cmd = s_calloc(1, len); 264*3446Smrj (void) strncpy(linep->cmd, menu_cmds[which], len); 265*3446Smrj 266*3446Smrj /* 267*3446Smrj * Since all arguments are copied, the new arg string should be close 268*3446Smrj * in size to the old one. Just add 32 to cover the difference in 269*3446Smrj * the boot path. 270*3446Smrj */ 271*3446Smrj total_len = strlen(linep->arg) + 32; 272*3446Smrj new_arg = s_calloc(1, total_len); 273*3446Smrj old_ptr = strchr(linep->arg, ' '); 274*3446Smrj if (old_ptr != NULL) 275*3446Smrj old_ptr++; 276*3446Smrj 277*3446Smrj /* 278*3446Smrj * Transitioning from dboot to multiboot is pretty simple. We 279*3446Smrj * copy in multiboot and any args. 280*3446Smrj */ 281*3446Smrj if (bam_direct == BAM_DIRECT_MULTIBOOT) { 282*3446Smrj if (old_ptr == NULL) { 283*3446Smrj (void) snprintf(new_arg, total_len, "%s", 284*3446Smrj (*flags & BAM_ENTRY_MINIROOT) ? 285*3446Smrj MULTI_BOOT_FAILSAFE : MULTI_BOOT); 286*3446Smrj } else { 287*3446Smrj (void) snprintf(new_arg, total_len, "%s %s", 288*3446Smrj (*flags & BAM_ENTRY_MINIROOT) ? 289*3446Smrj MULTI_BOOT_FAILSAFE : MULTI_BOOT, old_ptr); 290*3446Smrj } 291*3446Smrj goto done; 292*3446Smrj } 293*3446Smrj 294*3446Smrj /* 295*3446Smrj * Transitioning from multiboot to directboot is a bit more 296*3446Smrj * complicated, since we may have two sets of arguments to 297*3446Smrj * copy and a unix path to parse. 298*3446Smrj * 299*3446Smrj * First, figure out if there's a unix path. 300*3446Smrj */ 301*3446Smrj if ((old_ptr != NULL) && 302*3446Smrj ((unix_ptr = strstr(old_ptr, "/unix")) != NULL)) { 303*3446Smrj /* See if there's anything past unix */ 304*3446Smrj flags2_ptr = unix_ptr + sizeof ("/unix"); 305*3446Smrj if (*flags2_ptr == '\0') { 306*3446Smrj flags2_ptr = NULL; 307*3446Smrj } 308*3446Smrj 309*3446Smrj while ((unix_ptr > old_ptr) && (*unix_ptr != ' ')) 310*3446Smrj unix_ptr--; 311*3446Smrj 312*3446Smrj if (unix_ptr == old_ptr) { 313*3446Smrj flags1_ptr = NULL; 314*3446Smrj } else { 315*3446Smrj flags1_ptr = old_ptr; 316*3446Smrj } 317*3446Smrj 318*3446Smrj if (strstr(unix_ptr, "kernel/unix") != NULL) { 319*3446Smrj *flags |= BAM_ENTRY_32BIT; 320*3446Smrj } else if ((strstr(unix_ptr, "kernel/amd64/unix") == NULL) && 321*3446Smrj (!bam_force)) { 322*3446Smrj /* 323*3446Smrj * If the above strstr returns NULL, but bam_force is 324*3446Smrj * set, we'll be upgrading an Install kernel. The 325*3446Smrj * result probably won't be what was intended, but we'll 326*3446Smrj * try it anyways. 327*3446Smrj */ 328*3446Smrj return (BAM_SKIP); 329*3446Smrj } 330*3446Smrj } else if (old_ptr != NULL) { 331*3446Smrj flags1_ptr = old_ptr; 332*3446Smrj unix_ptr = flags1_ptr + strlen(old_ptr); 333*3446Smrj flags2_ptr = NULL; 334*3446Smrj } else { 335*3446Smrj unix_ptr = flags1_ptr = flags2_ptr = NULL; 336*3446Smrj } 337*3446Smrj 338*3446Smrj if (*flags & BAM_ENTRY_MINIROOT) { 339*3446Smrj (void) snprintf(new_arg, total_len, "%s", 340*3446Smrj DIRECT_BOOT_FAILSAFE_KERNEL); 341*3446Smrj } else if (*flags & BAM_ENTRY_32BIT) { 342*3446Smrj (void) snprintf(new_arg, total_len, "%s", DIRECT_BOOT_32); 343*3446Smrj } else { 344*3446Smrj (void) snprintf(new_arg, total_len, "%s", DIRECT_BOOT_KERNEL); 345*3446Smrj } 346*3446Smrj 347*3446Smrj /* 348*3446Smrj * We now want to copy flags1_ptr through unix_ptr, and 349*3446Smrj * flags2_ptr through the end of the string 350*3446Smrj */ 351*3446Smrj if (flags1_ptr != NULL) { 352*3446Smrj len = strlcat(new_arg, " ", total_len); 353*3446Smrj left = total_len - len; 354*3446Smrj new_ptr = new_arg + len; 355*3446Smrj 356*3446Smrj if ((unix_ptr - flags1_ptr) < left) 357*3446Smrj left = (unix_ptr - flags1_ptr) + 1; 358*3446Smrj (void) strlcpy(new_ptr, flags1_ptr, left); 359*3446Smrj } 360*3446Smrj if (flags2_ptr != NULL) { 361*3446Smrj (void) strlcat(new_arg, " ", total_len); 362*3446Smrj (void) strlcat(new_arg, flags2_ptr, total_len); 363*3446Smrj } 364*3446Smrj 365*3446Smrj done: 366*3446Smrj free(linep->arg); 367*3446Smrj linep->arg = new_arg; 368*3446Smrj update_line(linep); 369*3446Smrj return (BAM_SUCCESS); 370*3446Smrj } 371*3446Smrj 372*3446Smrj /* 373*3446Smrj * Similar to above, except this time we're looking at a module line, 374*3446Smrj * which is quite a bit simpler. 375*3446Smrj * 376*3446Smrj * Under multiboot, the archive line is: 377*3446Smrj * 378*3446Smrj * module /platform/i86pc/boot_archive 379*3446Smrj * 380*3446Smrj * Under directboot, the archive line is: 381*3446Smrj * 382*3446Smrj * module$ /platform/i86pc/$ISADIR/boot_archive 383*3446Smrj * 384*3446Smrj * which may be specified exactly as either of: 385*3446Smrj * 386*3446Smrj * module /platform/i86pc/boot_archive 387*3446Smrj * module /platform/i86pc/amd64/boot_archive 388*3446Smrj * 389*3446Smrj * For either dboot or multiboot, the failsafe is: 390*3446Smrj * 391*3446Smrj * module /boot/x86.miniroot-safe 392*3446Smrj */ 393*3446Smrj static error_t 394*3446Smrj parse_module_line(line_t *linep, const char *root, uint8_t flags) 395*3446Smrj { 396*3446Smrj int len; 397*3446Smrj menu_cmd_t which; 398*3446Smrj char *new; 399*3446Smrj 400*3446Smrj /* 401*3446Smrj * If necessary, BAM_ENTRY_MINIROOT was already set in flags 402*3446Smrj * in upgrade_menu(). We re-check BAM_ENTRY_DBOOT here in here 403*3446Smrj * in case the kernel and module lines differ. 404*3446Smrj */ 405*3446Smrj if ((strcmp(linep->arg, DIRECT_BOOT_ARCHIVE) == 0) || 406*3446Smrj (strcmp(linep->arg, DIRECT_BOOT_ARCHIVE_64) == 0)) { 407*3446Smrj flags |= BAM_ENTRY_DBOOT; 408*3446Smrj } else if ((strcmp(linep->arg, MULTI_BOOT_ARCHIVE) == 0) || 409*3446Smrj (strcmp(linep->arg, MINIROOT) == 0)) { 410*3446Smrj flags &= ~BAM_ENTRY_DBOOT; 411*3446Smrj } else { 412*3446Smrj bam_error(NO_MODULE_MATCH, linep->lineNum, MENU_URL(root)); 413*3446Smrj return (BAM_ERROR); 414*3446Smrj } 415*3446Smrj 416*3446Smrj if (((flags & BAM_ENTRY_DBOOT) && (bam_direct == BAM_DIRECT_DBOOT)) || 417*3446Smrj (((flags & BAM_ENTRY_DBOOT) == 0) && 418*3446Smrj (bam_direct == BAM_DIRECT_MULTIBOOT)) || 419*3446Smrj ((flags & BAM_ENTRY_MINIROOT) && 420*3446Smrj (strcmp(linep->cmd, menu_cmds[MODULE_CMD]) == 0))) { 421*3446Smrj 422*3446Smrj /* No action needed */ 423*3446Smrj return (BAM_SUCCESS); 424*3446Smrj } 425*3446Smrj 426*3446Smrj /* 427*3446Smrj * Make sure we have the correct cmd - either module or module$ 428*3446Smrj * The failsafe entry should always be MODULE_CMD. 429*3446Smrj */ 430*3446Smrj which = ((bam_direct == BAM_DIRECT_MULTIBOOT) || 431*3446Smrj (flags & BAM_ENTRY_MINIROOT)) ? MODULE_CMD : MODULE_DOLLAR_CMD; 432*3446Smrj free(linep->cmd); 433*3446Smrj len = strlen(menu_cmds[which]) + 1; 434*3446Smrj linep->cmd = s_calloc(1, len); 435*3446Smrj (void) strncpy(linep->cmd, menu_cmds[which], len); 436*3446Smrj 437*3446Smrj if (flags & BAM_ENTRY_MINIROOT) { 438*3446Smrj new = MINIROOT; 439*3446Smrj } else if ((bam_direct == BAM_DIRECT_DBOOT) && 440*3446Smrj ((flags & BAM_ENTRY_32BIT) == 0)) { 441*3446Smrj new = DIRECT_BOOT_ARCHIVE; 442*3446Smrj } else { 443*3446Smrj new = MULTI_BOOT_ARCHIVE; 444*3446Smrj } 445*3446Smrj 446*3446Smrj free(linep->arg); 447*3446Smrj len = strlen(new) + 1; 448*3446Smrj linep->arg = s_calloc(1, len); 449*3446Smrj (void) strncpy(linep->arg, new, len); 450*3446Smrj update_line(linep); 451*3446Smrj 452*3446Smrj return (BAM_SUCCESS); 453*3446Smrj } 454*3446Smrj 455*3446Smrj /*ARGSUSED*/ 456*3446Smrj error_t 457*3446Smrj upgrade_menu(menu_t *mp, char *root, char *opt) 458*3446Smrj { 459*3446Smrj entry_t *cur_entry; 460*3446Smrj line_t *cur_line; 461*3446Smrj int i, skipit = 0, num_entries = 0; 462*3446Smrj int *hand_entries = NULL; 463*3446Smrj boolean_t found_kernel = B_FALSE; 464*3446Smrj error_t rv; 465*3446Smrj char *rootdev, *grubdisk = NULL; 466*3446Smrj 467*3446Smrj rootdev = get_special(root); 468*3446Smrj if (rootdev) { 469*3446Smrj grubdisk = os_to_grubdisk(rootdev, strlen(root) == 1); 470*3446Smrj free(rootdev); 471*3446Smrj rootdev = NULL; 472*3446Smrj } 473*3446Smrj 474*3446Smrj /* Loop through all OS entries in the menu.lst file */ 475*3446Smrj for (cur_entry = mp->entries; cur_entry != NULL; 476*3446Smrj cur_entry = cur_entry->next, skipit = 0) { 477*3446Smrj 478*3446Smrj if ((cur_entry->flags & BAM_ENTRY_CHAINLOADER) || 479*3446Smrj ((cur_entry->flags & BAM_ENTRY_MINIROOT) && !bam_force)) 480*3446Smrj continue; 481*3446Smrj 482*3446Smrj /* 483*3446Smrj * We only change entries added by bootadm and live upgrade, 484*3446Smrj * and warn on the rest, unless the -f flag was passed. 485*3446Smrj */ 486*3446Smrj if ((!(cur_entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU))) && 487*3446Smrj !bam_force) { 488*3446Smrj if (num_entries == 0) { 489*3446Smrj hand_entries = s_calloc(1, sizeof (int)); 490*3446Smrj } else { 491*3446Smrj hand_entries = s_realloc(hand_entries, 492*3446Smrj (num_entries + 1) * sizeof (int)); 493*3446Smrj } 494*3446Smrj hand_entries[num_entries++] = cur_entry->entryNum; 495*3446Smrj continue; 496*3446Smrj } 497*3446Smrj 498*3446Smrj /* 499*3446Smrj * We make two loops through the lines. First, we check if 500*3446Smrj * there is a root entry, and if so, whether we should be 501*3446Smrj * checking this entry. 502*3446Smrj */ 503*3446Smrj if ((grubdisk != NULL) && (cur_entry->flags & BAM_ENTRY_ROOT)) { 504*3446Smrj for (cur_line = cur_entry->start; cur_line != NULL; 505*3446Smrj cur_line = cur_line->next) { 506*3446Smrj if ((cur_line->cmd == NULL) || 507*3446Smrj (cur_line->arg == NULL)) 508*3446Smrj continue; 509*3446Smrj 510*3446Smrj if (strcmp(cur_line->cmd, 511*3446Smrj menu_cmds[ROOT_CMD]) == 0) { 512*3446Smrj if (strcmp(cur_line->arg, 513*3446Smrj grubdisk) != 0) { 514*3446Smrj /* A different slice */ 515*3446Smrj skipit = 1; 516*3446Smrj } 517*3446Smrj break; 518*3446Smrj } 519*3446Smrj if (cur_line == cur_entry->end) 520*3446Smrj break; 521*3446Smrj } 522*3446Smrj } 523*3446Smrj if (skipit) 524*3446Smrj continue; 525*3446Smrj 526*3446Smrj for (cur_line = cur_entry->start; cur_line != NULL; 527*3446Smrj cur_line = cur_line->next) { 528*3446Smrj 529*3446Smrj /* 530*3446Smrj * We only compare for the length of KERNEL_CMD, 531*3446Smrj * so that KERNEL_DOLLAR_CMD will also match. 532*3446Smrj */ 533*3446Smrj if (strncmp(cur_line->cmd, menu_cmds[KERNEL_CMD], 534*3446Smrj strlen(menu_cmds[KERNEL_CMD])) == 0) { 535*3446Smrj rv = parse_kernel_line(cur_line, root, 536*3446Smrj &(cur_entry->flags)); 537*3446Smrj if (rv == BAM_SKIP) { 538*3446Smrj break; 539*3446Smrj } else if (rv != BAM_SUCCESS) { 540*3446Smrj return (rv); 541*3446Smrj } 542*3446Smrj found_kernel = B_TRUE; 543*3446Smrj } else if (strncmp(cur_line->cmd, 544*3446Smrj menu_cmds[MODULE_CMD], 545*3446Smrj strlen(menu_cmds[MODULE_CMD])) == 0) { 546*3446Smrj rv = parse_module_line(cur_line, root, 547*3446Smrj cur_entry->flags); 548*3446Smrj if (rv != BAM_SUCCESS) { 549*3446Smrj return (rv); 550*3446Smrj } 551*3446Smrj } 552*3446Smrj if (cur_line == cur_entry->end) 553*3446Smrj break; 554*3446Smrj } 555*3446Smrj } 556*3446Smrj 557*3446Smrj /* 558*3446Smrj * We only want to output one error, to avoid confusing a user. We 559*3446Smrj * rank "No kernels changed" as a higher priority than "will not 560*3446Smrj * update hand-added entries", since the former implies the latter. 561*3446Smrj */ 562*3446Smrj if (found_kernel == B_FALSE) { 563*3446Smrj bam_error(NO_KERNELS_FOUND, MENU_URL(root)); 564*3446Smrj return (BAM_ERROR); 565*3446Smrj } else if (num_entries > 0) { 566*3446Smrj bam_error(HAND_ADDED_ENTRY, MENU_URL(root)); 567*3446Smrj bam_print_stderr("Entry Number%s: ", (num_entries > 1) ? 568*3446Smrj "s" : ""); 569*3446Smrj for (i = 0; i < num_entries; i++) { 570*3446Smrj bam_print_stderr("%d ", hand_entries[i]); 571*3446Smrj } 572*3446Smrj bam_print_stderr("\n"); 573*3446Smrj } 574*3446Smrj return (BAM_WRITE); 575*3446Smrj } 576