static void get_findroot_cap(const char *osroot) { FILE *fp; char path[PATH_MAX]; char buf[BAM_MAXLINE]; struct stat sb; int dboot; int error; int ret; const char *fcn = "get_findroot_cap()"; assert(is_grub(osroot)); (void) snprintf(path, sizeof (path), "%s/%s", osroot, "boot/grub/capability"); if (stat(path, &sb) == -1) { bam_is_findroot = BAM_FINDROOT_ABSENT; BAM_DPRINTF((D_FINDROOT_ABSENT, fcn)); return; } fp = fopen(path, "r"); error = errno; INJECT_ERROR1("GET_CAP_FINDROOT_FOPEN", fp = NULL); if (fp == NULL) { bam_error(OPEN_FAIL, path, strerror(error)); return; } dboot = 0; while (s_fgets(buf, sizeof (buf), fp) != NULL) { if (strcmp(buf, "findroot") == 0) { BAM_DPRINTF((D_FINDROOT_PRESENT, fcn)); bam_is_findroot = BAM_FINDROOT_PRESENT; } if (strcmp(buf, "dboot") == 0) { BAM_DPRINTF((D_DBOOT_PRESENT, fcn)); dboot = 1; } } assert(dboot); if (bam_is_findroot == BAM_FINDROOT_UNKNOWN) { bam_is_findroot = BAM_FINDROOT_ABSENT; BAM_DPRINTF((D_FINDROOT_ABSENT, fcn)); } out: ret = fclose(fp); error = errno; INJECT_ERROR1("GET_CAP_FINDROOT_FCLOSE", ret = 1); if (ret != 0) { bam_error(CLOSE_FAIL, path, strerror(error)); } }
/* * Simply allocate a new line and copy in cmd + sep + arg */ void update_line(line_t *linep) { size_t size; const char *fcn = "update_line()"; BAM_DPRINTF(("%s: line before update: %s\n", fcn, linep->line)); free(linep->line); size = strlen(linep->cmd) + strlen(linep->sep) + strlen(linep->arg) + 1; linep->line = s_calloc(1, size); (void) snprintf(linep->line, size, "%s%s%s", linep->cmd, linep->sep, linep->arg); BAM_DPRINTF(("%s: line after update: %s\n", fcn, linep->line)); }
/* * Simply allocate a new line and copy in cmd + sep + arg */ void update_line(line_t *linep) { size_t size; const char *fcn = "update_line()"; BAM_DPRINTF((D_UPDATE_LINE_BEFORE, fcn, linep->line)); free(linep->line); size = strlen(linep->cmd) + strlen(linep->sep) + strlen(linep->arg) + 1; linep->line = s_calloc(1, size); (void) snprintf(linep->line, size, "%s%s%s", linep->cmd, linep->sep, linep->arg); BAM_DPRINTF((D_UPDATE_LINE_AFTER, fcn, linep->line)); }
static char * rskip_bspace(char *bound, char *ptr) { const char *fcn = "rskip_bspace()"; assert(bound); assert(ptr); assert(bound <= ptr); assert(*bound != ' ' && *bound != '\t' && *bound != '\n'); BAM_DPRINTF((D_RSKIP_BSPACE_ENTRY, fcn, ptr)); for (; ptr > bound; ptr--) { if (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') break; } BAM_DPRINTF((D_RSKIP_BSPACE_EXIT, fcn, ptr)); return (ptr); }
static char * rskip_bspace(char *bound, char *ptr) { const char *fcn = "rskip_bspace()"; assert(bound); assert(ptr); assert(bound <= ptr); assert(*bound != ' ' && *bound != '\t' && *bound != '\n'); BAM_DPRINTF(("%s: ptr on entry: %s\n", fcn, ptr)); for (; ptr > bound; ptr--) { if (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') break; } BAM_DPRINTF(("%s: ptr on exit: %s\n", fcn, ptr)); return (ptr); }
/* * Return true if root has been bfu'ed. bfu will blow away * var/sadm/system/admin/INST_RELEASE, so if it's still there, we can * assume the system has not been bfu'ed. */ static int is_bfu_system(const char *root) { static int is_bfu = -1; char path[PATH_MAX]; struct stat sb; const char *fcn = "is_bfu_system()"; if (is_bfu != -1) { BAM_DPRINTF((D_ALREADY_BFU_TEST, fcn, is_bfu ? "" : "NOT")); return (is_bfu); } (void) snprintf(path, sizeof (path), "%s/%s", root, INST_RELEASE); if (stat(path, &sb) != 0) { is_bfu = 1; BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); } else { is_bfu = 0; BAM_DPRINTF((D_RETURN_FAILURE, fcn)); } return (is_bfu); }
static char * skip_wspace(char *ptr) { const char *fcn = "skip_wspace()"; INJECT_ERROR1("SKIP_WSPACE", ptr = NULL); if (ptr == NULL) { BAM_DPRINTF((D_SKIP_WSPACE_PTR_NULL, fcn)); return (NULL); } BAM_DPRINTF((D_SKIP_WSPACE_ENTRY_PTR, fcn, ptr)); for (; *ptr != '\0'; ptr++) { if ((*ptr != ' ') && (*ptr != '\t') && (*ptr != '\n')) break; } ptr = (*ptr == '\0' ? NULL : ptr); BAM_DPRINTF((D_SKIP_WSPACE_EXIT_PTR, fcn, ptr ? ptr : "NULL")); return (ptr); }
static char * skip_wspace(char *ptr) { const char *fcn = "skip_wspace()"; INJECT_ERROR1("SKIP_WSPACE", ptr = NULL); if (ptr == NULL) { BAM_DPRINTF(("%s: NULL ptr\n", fcn)); return (NULL); } BAM_DPRINTF(("%s: ptr on entry: %s\n", fcn, ptr)); for (; *ptr != '\0'; ptr++) { if ((*ptr != ' ') && (*ptr != '\t') && (*ptr != '\n')) break; } ptr = (*ptr == '\0' ? NULL : ptr); BAM_DPRINTF(("%s: ptr on exit: %s\n", fcn, ptr ? ptr : "NULL")); return (ptr); }
/* * Return true if root has been bfu'ed. bfu will blow away * var/sadm/system/admin/INST_RELEASE, so if it's still there, we can * assume the system has not been bfu'ed. */ static int is_bfu_system(const char *root) { static int is_bfu = -1; char path[PATH_MAX]; struct stat sb; const char *fcn = "is_bfu_system()"; if (is_bfu != -1) { BAM_DPRINTF(("%s: already done bfu test. bfu is %s present\n", fcn, is_bfu ? "" : "NOT")); return (is_bfu); } (void) snprintf(path, sizeof (path), "%s/%s", root, INST_RELEASE); if (stat(path, &sb) != 0) { is_bfu = 1; BAM_DPRINTF(("%s: returning SUCCESS\n", fcn)); } else { is_bfu = 0; BAM_DPRINTF(("%s: returning FAILURE\n", fcn)); } return (is_bfu); }
/* * The parse_kernel_line function examines a menu.lst kernel line. For * multiboot, this is: * * kernel <multiboot path> <flags1> <kernel path> <flags2> * * <multiboot path> is either /platform/i86pc/multiboot or /boot/multiboot * * <kernel path> may be missing, or may be any full or relative path to unix. * We check for it by looking for a word ending in "/unix". If it ends * in "kernel/unix", we upgrade it to a 32-bit entry. If it ends in * "kernel/amd64/unix", we upgrade it to the default entry. Otherwise, * it's a custom kernel, and we skip it. * * <flags*> are anything that doesn't fit either of the above - these will be * copied over. * * For direct boot, the defaults are * * kernel$ <kernel path> <flags> * * <kernel path> is one of: * /platform/i86pc/kernel/$ISADIR/unix * /boot/platform/i86pc/kernel/$ISADIR/unix * /platform/i86pc/kernel/unix * /platform/i86pc/kernel/amd64/unix * /boot/platform/i86pc/kernel/unix * /boot/platform/i86pc/kernel/amd64/unix * * If <kernel path> is any of the last four, the command may also be "kernel". * * <flags> is anything that isn't <kernel path>. * * This function is only called to convert a multiboot entry to a dboot entry * * For safety, we do one more check: if the kernel path starts with /boot, * we verify that the new kernel exists before changing it. This is mainly * done for bfu, as it may cause the failsafe archives to be a different * boot architecture from the newly bfu'ed system. */ static error_t cvt_kernel_line(line_t *line, const char *osroot, entry_t *entry) { char path[PATH_MAX], path_64[PATH_MAX]; char linebuf[PATH_MAX]; char new_arg[PATH_MAX]; struct stat sb, sb_64; char *old_ptr; char *unix_ptr; char *flags1_ptr; char *flags2_ptr; const char *fcn = "cvt_kernel_line()"; BAM_DPRINTF((D_FUNC_ENTRY2, fcn, line->line, osroot)); /* * We only convert multiboot to dboot and nothing else. */ if (!(entry->flags & BAM_ENTRY_MULTIBOOT)) { BAM_DPRINTF((D_NOT_MULTIBOOT_CONVERT, fcn)); return (BAM_SUCCESS); } if (entry->flags & BAM_ENTRY_FAILSAFE) { /* * We're attempting to change failsafe to dboot. * In the bfu case, we may not have a dboot failsafe * kernel i.e. a "unix" under the "/boot" hierarchy. * If so, just emit a message in verbose mode and * return success. */ BAM_DPRINTF((D_TRYING_FAILSAFE_CVT_TO_DBOOT, fcn)); (void) snprintf(path, PATH_MAX, "%s%s", osroot, DIRECT_BOOT_FAILSAFE_32); (void) snprintf(path_64, PATH_MAX, "%s%s", osroot, DIRECT_BOOT_FAILSAFE_64); if (stat(path, &sb) != 0 && stat(path_64, &sb_64) != 0) { if (bam_verbose) { bam_error(FAILSAFE_MISSING, line->lineNum); } BAM_DPRINTF((D_NO_FAILSAFE_UNIX_CONVERT, fcn)); return (BAM_SUCCESS); } } /* * Make sure we have the correct cmd */ free(line->cmd); line->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]); BAM_DPRINTF((D_CVT_CMD_KERN_DOLLAR, fcn, line->cmd)); assert(sizeof (linebuf) > strlen(line->arg) + 32); (void) strlcpy(linebuf, line->arg, sizeof (linebuf)); old_ptr = strpbrk(linebuf, " \t\n"); old_ptr = skip_wspace(old_ptr); if (old_ptr == NULL) { /* * only multiboot and nothing else * i.e. flags1 = unix = flags2 = NULL */ flags1_ptr = unix_ptr = flags2_ptr = NULL; BAM_DPRINTF((D_FLAGS1_UNIX_FLAGS2_NULL, fcn)) goto create; }
error_t get_boot_cap(const char *osroot) { char fname[PATH_MAX]; char *image; uchar_t *ident; int fd; int m; multiboot_header_t *mbh; struct stat sb; int error; const char *fcn = "get_boot_cap()"; if (is_sparc()) { /* there is no non dboot sparc new-boot */ bam_direct = BAM_DIRECT_DBOOT; BAM_DPRINTF((D_IS_SPARC_DBOOT, fcn)); return (BAM_SUCCESS); } if (!is_grub(osroot)) { bam_error(NOT_GRUB_ROOT, osroot); return (BAM_ERROR); } (void) snprintf(fname, PATH_MAX, "%s/%s", osroot, "platform/i86pc/kernel/unix"); fd = open(fname, O_RDONLY); error = errno; INJECT_ERROR1("GET_CAP_UNIX_OPEN", fd = -1); if (fd < 0) { bam_error(OPEN_FAIL, fname, strerror(error)); return (BAM_ERROR); } /* * Verify that this is a sane unix at least 8192 bytes in length */ if (fstat(fd, &sb) == -1 || sb.st_size < 8192) { (void) close(fd); bam_error(INVALID_BINARY, fname); return (BAM_ERROR); } /* * mmap the first 8K */ image = mmap(NULL, 8192, PROT_READ, MAP_SHARED, fd, 0); error = errno; INJECT_ERROR1("GET_CAP_MMAP", image = MAP_FAILED); if (image == MAP_FAILED) { bam_error(MMAP_FAIL, fname, strerror(error)); return (BAM_ERROR); } ident = (uchar_t *)image; if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 || ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) { bam_error(NOT_ELF_FILE, fname); return (BAM_ERROR); } if (ident[EI_CLASS] != ELFCLASS32) { bam_error(WRONG_ELF_CLASS, fname, ident[EI_CLASS]); return (BAM_ERROR); } /* * The GRUB multiboot header must be 32-bit aligned and completely * contained in the 1st 8K of the file. If the unix binary has * a multiboot header, then it is a 'dboot' kernel. Otherwise, * this kernel must be booted via multiboot -- we call this a * 'multiboot' kernel. */ bam_direct = BAM_DIRECT_MULTIBOOT; for (m = 0; m < 8192 - sizeof (multiboot_header_t); m += 4) { mbh = (void *)(image + m); if (mbh->magic == MB_HEADER_MAGIC) { BAM_DPRINTF((D_IS_DBOOT, fcn)); bam_direct = BAM_DIRECT_DBOOT; break; } } (void) munmap(image, 8192); (void) close(fd); INJECT_ERROR1("GET_CAP_MULTIBOOT", bam_direct = BAM_DIRECT_MULTIBOOT); if (bam_direct == BAM_DIRECT_DBOOT) { if (bam_is_hv == BAM_HV_PRESENT) { BAM_DPRINTF((D_IS_XVM, fcn)); } else { BAM_DPRINTF((D_IS_NOT_XVM, fcn)); } } else { BAM_DPRINTF((D_IS_MULTIBOOT, fcn)); } /* Not a fatal error if this fails */ get_findroot_cap(osroot); BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); return (BAM_SUCCESS); }
/*ARGSUSED*/ error_t cvt_to_metal(menu_t *mp, char *osroot, char *menu_root) { const char *fcn = "cvt_to_metal()"; line_t *lp; entry_t *ent; size_t len, zfslen; char *delim = ","; char *newstr; char *osdev; char *title = NULL; char *findroot = NULL; char *bootfs = NULL; char *kernel = NULL; char *module = NULL; char *barchive_path = DIRECT_BOOT_ARCHIVE; char *kern_path = NULL; int curdef, newdef; int emit_bflag = 1; int ret = BAM_ERROR; assert(osroot); BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, "")); /* * First just check to verify osroot is a sane directory. */ if ((osdev = get_special(osroot)) == NULL) { bam_error(CANT_FIND_SPECIAL, osroot); return (BAM_ERROR); } free(osdev); /* * Found the GRUB signature on the target partitions, so now get the * default GRUB boot entry number from the menu.lst file */ curdef = atoi(mp->curdefault->arg); /* look for the first line of the matching boot entry */ for (ent = mp->entries; ((ent != NULL) && (ent->entryNum != curdef)); ent = ent->next) ; /* couldn't find it, so error out */ if (ent == NULL) { bam_error(CANT_FIND_DEFAULT, curdef); goto abort; } /* * Now process the entry itself. */ for (lp = ent->start; lp != NULL; lp = lp->next) { /* * Process important lines from menu.lst boot entry. */ if (lp->flags == BAM_TITLE) { title = alloca(strlen(lp->arg) + 1); (void) strcpy(title, lp->arg); } else if (strcmp(lp->cmd, "findroot") == 0) { findroot = alloca(strlen(lp->arg) + 1); (void) strcpy(findroot, lp->arg); } else if (strcmp(lp->cmd, "bootfs") == 0) { bootfs = alloca(strlen(lp->arg) + 1); (void) strcpy(bootfs, lp->arg); } else if (strcmp(lp->cmd, menu_cmds[MODULE_DOLLAR_CMD]) == 0) { if (strstr(lp->arg, "boot_archive") == NULL) { module = alloca(strlen(lp->arg) + 1); (void) strcpy(module, lp->arg); cvt_hyper_module(module, &kern_path); } else { barchive_path = alloca(strlen(lp->arg) + 1); (void) strcpy(barchive_path, lp->arg); } } else if ((strcmp(lp->cmd, menu_cmds[KERNEL_DOLLAR_CMD]) == 0) && (cvt_hyper_kernel(lp->arg) < 0)) { ret = BAM_NOCHANGE; goto abort; } if (lp == ent->end) break; } /* * If findroot, module or kern_path are NULL, the boot entry is * malformed. */ if (findroot == NULL) { bam_error(FINDROOT_NOT_FOUND, curdef); goto abort; } if (module == NULL) { bam_error(MODULE_NOT_PARSEABLE, curdef); goto abort; } if (kern_path == NULL) { bam_error(KERNEL_NOT_FOUND, curdef); goto abort; } /* * Assemble new kernel and module arguments from parsed values. * * First, change the kernel directory from the hypervisor version to * that needed for a metal kernel. */ newstr = modify_path(kern_path, HYPER_KERNEL_DIR, METAL_KERNEL_DIR); free(kern_path); kern_path = newstr; /* allocate initial space for the kernel path */ len = strlen(kern_path) + 1; zfslen = (zfs_boot ? (WHITESPC(1) + strlen(ZFS_BOOT)) : 0); if ((kernel = malloc(len + zfslen)) == NULL) { free(kern_path); bam_error(NO_MEM, len + zfslen); bam_exit(1); } (void) snprintf(kernel, len, "%s", kern_path); free(kern_path); if (zfs_boot) { char *zfsstr = alloca(zfslen + 1); (void) snprintf(zfsstr, zfslen + 1, " %s", ZFS_BOOT); (void) strcat(kernel, zfsstr); emit_bflag = 0; } /* * Process the bootenv.rc file to look for boot options that would be * the same as what the hypervisor had manually set, as we need not set * those explicitly. * * If there's no bootenv.rc, it's not an issue. */ parse_bootenvrc(osroot); /* * Don't emit a console setting if it's the same as what would be * set by bootenv.rc. */ if ((console_dev != NULL) && (bootenv_rc_console == NULL || (strcmp(console_dev, bootenv_rc_console) != 0))) { if (emit_bflag) { newstr = append_str(kernel, BFLAG, " "); free(kernel); kernel = append_str(newstr, "console=", " "); free(newstr); newstr = append_str(kernel, console_dev, ""); free(kernel); kernel = newstr; emit_bflag = 0; } else { newstr = append_str(kernel, "console=", ","); free(kernel); kernel = append_str(newstr, console_dev, ""); free(newstr); } } /* * We have to do some strange processing here because the hypervisor's * serial ports default to "9600,8,n,1,-" if "comX=auto" is specified, * or to "auto" if nothing is specified. * * This could result in a serial mode setting string being added when * it would otherwise not be needed, but it's better to play it safe. */ if (emit_bflag) { newstr = append_str(kernel, BFLAG, " "); free(kernel); kernel = newstr; delim = " "; emit_bflag = 0; } if ((serial_config[0] != NULL) && (bootenv_rc_serial[0] == NULL || (strcmp(serial_config[0], bootenv_rc_serial[0]) != 0))) { newstr = append_str(kernel, "ttya-mode='", delim); free(kernel); /* * Pass the serial configuration as the delimiter to * append_str() as it will be inserted between the current * string and the string we're appending, in this case the * closing single quote. */ kernel = append_str(newstr, "'", serial_config[0]); free(newstr); delim = ","; } if ((serial_config[1] != NULL) && (bootenv_rc_serial[1] == NULL || (strcmp(serial_config[1], bootenv_rc_serial[1]) != 0))) { newstr = append_str(kernel, "ttyb-mode='", delim); free(kernel); /* * Pass the serial configuration as the delimiter to * append_str() as it will be inserted between the current * string and the string we're appending, in this case the * closing single quote. */ kernel = append_str(newstr, "'", serial_config[1]); free(newstr); delim = ","; } /* shut off warning messages from the entry line parser */ if (ent->flags & BAM_ENTRY_BOOTADM) ent->flags &= ~BAM_ENTRY_BOOTADM; BAM_DPRINTF((D_CVT_CMD_KERN_DOLLAR, fcn, kernel)); BAM_DPRINTF((D_CVT_CMD_MOD_DOLLAR, fcn, module)); if ((newdef = add_boot_entry(mp, title, findroot, kernel, NULL, barchive_path, bootfs)) == BAM_ERROR) { free(kernel); return (newdef); } /* * Now try to delete the current default entry from the menu and add * the new hypervisor entry with the parameters we've setup. */ if (delete_boot_entry(mp, curdef, DBE_QUIET) == BAM_SUCCESS) newdef--; else bam_print(NEW_BOOT_ENTRY, title); free(kernel); /* * If we successfully created the new entry, set the default boot * entry to that entry and let the caller know the new menu should * be written out. */ return (set_global(mp, menu_cmds[DEFAULT_CMD], newdef)); abort: if (ret != BAM_NOCHANGE) bam_error(METAL_ABORT, osroot); return (ret); }
error_t cvt_to_hyper(menu_t *mp, char *osroot, char *extra_args) { const char *fcn = "cvt_to_hyper()"; line_t *lp; entry_t *ent; size_t len, zfslen; char *newstr; char *osdev; char *title = NULL; char *findroot = NULL; char *bootfs = NULL; char *kernel = NULL; char *mod_kernel = NULL; char *module = NULL; char *kern_path = NULL; char *kern_bargs = NULL; int curdef, newdef; int kp_allocated = 0; int ret = BAM_ERROR; assert(osroot); BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, extra_args)); /* * First just check to verify osroot is a sane directory. */ if ((osdev = get_special(osroot)) == NULL) { bam_error(CANT_FIND_SPECIAL, osroot); return (BAM_ERROR); } free(osdev); /* * While the effect is purely cosmetic, if osroot is "/" don't * bother prepending it to any paths as they are constructed to * begin with "/" anyway. */ if (strcmp(osroot, "/") == 0) osroot = ""; /* * Found the GRUB signature on the target partitions, so now get the * default GRUB boot entry number from the menu.lst file */ curdef = atoi(mp->curdefault->arg); /* look for the first line of the matching boot entry */ for (ent = mp->entries; ((ent != NULL) && (ent->entryNum != curdef)); ent = ent->next) ; /* couldn't find it, so error out */ if (ent == NULL) { bam_error(CANT_FIND_DEFAULT, curdef); goto abort; } /* * We found the proper menu entry, so first we need to process the * bootenv.rc file to look for boot options the hypervisor might need * passed as kernel start options such as the console device and serial * port parameters. * * If there's no bootenv.rc, it's not an issue. */ parse_bootenvrc(osroot); if (bootenv_rc_console != NULL) console_metal_to_hyper(bootenv_rc_console); if (bootenv_rc_serial[0] != NULL) (void) serial_metal_to_hyper("ttya-mode", bootenv_rc_serial[0]); if (bootenv_rc_serial[1] != NULL) (void) serial_metal_to_hyper("ttyb-mode", bootenv_rc_serial[1]); /* * Now process the entry itself. */ for (lp = ent->start; lp != NULL; lp = lp->next) { /* * Process important lines from menu.lst boot entry. */ if (lp->flags == BAM_TITLE) { title = alloca(strlen(lp->arg) + 1); (void) strcpy(title, lp->arg); } else if (strcmp(lp->cmd, "findroot") == 0) { findroot = alloca(strlen(lp->arg) + 1); (void) strcpy(findroot, lp->arg); } else if (strcmp(lp->cmd, "bootfs") == 0) { bootfs = alloca(strlen(lp->arg) + 1); (void) strcpy(bootfs, lp->arg); } else if (strcmp(lp->cmd, menu_cmds[MODULE_DOLLAR_CMD]) == 0) { module = alloca(strlen(lp->arg) + 1); (void) strcpy(module, lp->arg); } else if ((strcmp(lp->cmd, menu_cmds[KERNEL_DOLLAR_CMD]) == 0) && (ret = cvt_metal_kernel(lp->arg, &kern_path)) != 0) { if (ret < 0) { ret = BAM_ERROR; bam_error(KERNEL_NOT_PARSEABLE, curdef); } else ret = BAM_NOCHANGE; goto abort; } if (lp == ent->end) break; } /* * If findroot, module or kern_path are NULL, the boot entry is * malformed. */ if (findroot == NULL) { bam_error(FINDROOT_NOT_FOUND, curdef); goto abort; } if (module == NULL) { bam_error(MODULE_NOT_PARSEABLE, curdef); goto abort; } if (kern_path == NULL) { bam_error(KERNEL_NOT_FOUND, curdef); goto abort; } /* assemble new kernel and module arguments from parsed values */ if (console_dev != NULL) { kern_bargs = s_strdup(console_dev); if (serial_config[0] != NULL) { newstr = append_str(kern_bargs, serial_config[0], " "); free(kern_bargs); kern_bargs = newstr; } if (serial_config[1] != NULL) { newstr = append_str(kern_bargs, serial_config[1], " "); free(kern_bargs); kern_bargs = newstr; } } if ((extra_args != NULL) && (*extra_args != NULL)) { newstr = append_str(kern_bargs, extra_args, " "); free(kern_bargs); kern_bargs = newstr; } len = strlen(osroot) + strlen(XEN_MENU) + strlen(kern_bargs) + WHITESPC(1) + 1; kernel = alloca(len); if (kern_bargs != NULL) { if (*kern_bargs != NULL) (void) snprintf(kernel, len, "%s%s %s", osroot, XEN_MENU, kern_bargs); free(kern_bargs); } else { (void) snprintf(kernel, len, "%s%s", osroot, XEN_MENU); } /* * Change the kernel directory from the metal version to that needed for * the hypervisor. Convert either "direct boot" path to the default * path. */ if ((strcmp(kern_path, DIRECT_BOOT_32) == 0) || (strcmp(kern_path, DIRECT_BOOT_64) == 0)) { kern_path = HYPERVISOR_KERNEL; } else { newstr = modify_path(kern_path, METAL_KERNEL_DIR, HYPER_KERNEL_DIR); free(kern_path); kern_path = newstr; kp_allocated = 1; } /* * We need to allocate space for the kernel path (twice) plus an * intervening space, possibly the ZFS boot string, and NULL, * of course. */ len = (strlen(kern_path) * 2) + WHITESPC(1) + 1; zfslen = (zfs_boot ? (WHITESPC(1) + strlen(ZFS_BOOT)) : 0); mod_kernel = alloca(len + zfslen); (void) snprintf(mod_kernel, len, "%s %s", kern_path, kern_path); if (kp_allocated) free(kern_path); if (zfs_boot) { char *zfsstr = alloca(zfslen + 1); (void) snprintf(zfsstr, zfslen + 1, " %s", ZFS_BOOT); (void) strcat(mod_kernel, zfsstr); } /* shut off warning messages from the entry line parser */ if (ent->flags & BAM_ENTRY_BOOTADM) ent->flags &= ~BAM_ENTRY_BOOTADM; BAM_DPRINTF((D_CVT_CMD_KERN_DOLLAR, fcn, kernel)); BAM_DPRINTF((D_CVT_CMD_MOD_DOLLAR, fcn, mod_kernel)); if ((newdef = add_boot_entry(mp, title, findroot, kernel, mod_kernel, module, bootfs)) == BAM_ERROR) return (newdef); /* * Now try to delete the current default entry from the menu and add * the new hypervisor entry with the parameters we've setup. */ if (delete_boot_entry(mp, curdef, DBE_QUIET) == BAM_SUCCESS) newdef--; else bam_print(NEW_BOOT_ENTRY, title); /* * If we successfully created the new entry, set the default boot * entry to that entry and let the caller know the new menu should * be written out. */ return (set_global(mp, menu_cmds[DEFAULT_CMD], newdef)); abort: if (ret != BAM_NOCHANGE) bam_error(HYPER_ABORT, ((*osroot == NULL) ? "/" : osroot)); return (ret); }
static void parse_bootenvrc(char *osroot) { #define LINEBUF_SZ 1024 FILE *fp; char *rcpath; char line[LINEBUF_SZ]; /* make line buffer large but not ridiculous */ int len; assert(osroot); len = strlen(osroot) + strlen(BOOTRC_FILE) + 1; rcpath = alloca(len); (void) snprintf(rcpath, len, "%s%s", osroot, BOOTRC_FILE); /* if we couldn't open the bootenv.rc file, ignore the issue. */ if ((fp = fopen(rcpath, "r")) == NULL) { BAM_DPRINTF((D_NO_BOOTENVRC, rcpath, strerror(errno))); return; } while (s_fgets(line, LINEBUF_SZ, fp) != NULL) { char *parsestr, *token; int port = 0; /* we're only interested in parsing "setprop" directives. */ if (strncmp(line, "setprop", 7) != NULL) continue; /* eat initial "setprop" */ if ((parsestr = get_token(&token, line, " \t")) == NULL) { if (token != NULL) free(token); continue; } if (strcmp(token, "setprop") != 0) { free(token); continue; } free(token); /* get property name */ if ((parsestr = get_token(&token, parsestr, " \t")) == NULL) { if (token != NULL) free(token); continue; } if (strcmp(token, "console") == 0) { free(token); /* get console property value */ parsestr = get_token(&token, parsestr, " \t"); if (token == NULL) continue; if (bootenv_rc_console != NULL) free(bootenv_rc_console); bootenv_rc_console = s_strdup(token); continue; } /* check if it's a serial port setting */ if (strcmp(token, "ttya-mode") == 0) { free(token); port = 0; } else if (strcmp(token, "ttyb-mode") == 0) { free(token); port = 1; } else { /* nope, so check the next line */ free(token); continue; } /* get serial port setting */ parsestr = get_token(&token, parsestr, " \t"); if (token == NULL) continue; if (bootenv_rc_serial[port] != NULL) free(bootenv_rc_serial[port]); bootenv_rc_serial[port] = s_strdup(token); free(token); } (void) fclose(fp); }
/* * The parse_kernel_line function examines a menu.lst kernel line. For * multiboot, this is: * * kernel <multiboot path> <flags1> <kernel path> <flags2> * * <multiboot path> is either /platform/i86pc/multiboot or /boot/multiboot * * <kernel path> may be missing, or may be any full or relative path to unix. * We check for it by looking for a word ending in "/unix". If it ends * in "kernel/unix", we upgrade it to a 32-bit entry. If it ends in * "kernel/amd64/unix", we upgrade it to the default entry. Otherwise, * it's a custom kernel, and we skip it. * * <flags*> are anything that doesn't fit either of the above - these will be * copied over. * * For direct boot, the defaults are * * kernel$ <kernel path> <flags> * * <kernel path> is one of: * /platform/i86pc/kernel/$ISADIR/unix * /boot/platform/i86pc/kernel/$ISADIR/unix * /platform/i86pc/kernel/unix * /platform/i86pc/kernel/amd64/unix * /boot/platform/i86pc/kernel/unix * /boot/platform/i86pc/kernel/amd64/unix * * If <kernel path> is any of the last four, the command may also be "kernel". * * <flags> is anything that isn't <kernel path>. * * This function is only called to convert a multiboot entry to a dboot entry * * For safety, we do one more check: if the kernel path starts with /boot, * we verify that the new kernel exists before changing it. This is mainly * done for bfu, as it may cause the failsafe archives to be a different * boot architecture from the newly bfu'ed system. */ static error_t cvt_kernel_line(line_t *line, const char *osroot, entry_t *entry) { char path[PATH_MAX], path_64[PATH_MAX]; char linebuf[PATH_MAX]; char new_arg[PATH_MAX]; struct stat sb, sb_64; char *old_ptr; char *unix_ptr; char *flags1_ptr; char *flags2_ptr; const char *fcn = "cvt_kernel_line()"; BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, line->line, osroot)); /* * We only convert multiboot to dboot and nothing else. */ if (!(entry->flags & BAM_ENTRY_MULTIBOOT)) { BAM_DPRINTF(("%s: not MULTIBOOT, not converting\n", fcn)); return (BAM_SUCCESS); } if (entry->flags & BAM_ENTRY_FAILSAFE) { /* * We're attempting to change failsafe to dboot. * In the bfu case, we may not have a dboot failsafe * kernel i.e. a "unix" under the "/boot" hierarchy. * If so, just emit a message in verbose mode and * return success. */ BAM_DPRINTF(("%s: trying to convert failsafe to DBOOT\n", fcn)); (void) snprintf(path, PATH_MAX, "%s%s", osroot, DIRECT_BOOT_FAILSAFE_32); (void) snprintf(path_64, PATH_MAX, "%s%s", osroot, DIRECT_BOOT_FAILSAFE_64); if (stat(path, &sb) != 0 && stat(path_64, &sb_64) != 0) { if (bam_verbose) { bam_error(_("bootadm -m upgrade run, but the " "failsafe archives have not been\nupdated. " "Not updating line %d\n"), line->lineNum); } BAM_DPRINTF(("%s: no FAILSAFE unix, not converting\n", fcn)); return (BAM_SUCCESS); } } /* * Make sure we have the correct cmd */ free(line->cmd); line->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]); BAM_DPRINTF(("%s: converted kernel cmd to %s\n", fcn, line->cmd)); assert(sizeof (linebuf) > strlen(line->arg) + 32); (void) strlcpy(linebuf, line->arg, sizeof (linebuf)); old_ptr = strpbrk(linebuf, " \t\n"); old_ptr = skip_wspace(old_ptr); if (old_ptr == NULL) { /* * only multiboot and nothing else * i.e. flags1 = unix = flags2 = NULL */ flags1_ptr = unix_ptr = flags2_ptr = NULL; BAM_DPRINTF(("%s: NULL flags1, unix, flags2\n", fcn)) goto create; }