2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <errno.h>
2N/A#include <strings.h>
2N/A#include <ctype.h>
2N/A#include <sys/stat.h>
2N/A#include <fcntl.h>
2N/A#include <unistd.h>
2N/A#include <libintl.h>
2N/A#include <sys/types.h>
2N/A#include <sys/dkio.h>
2N/A#include <sys/vtoc.h>
2N/A#include <sys/mhd.h>
2N/A#include <sys/param.h>
2N/A#include <sys/dktp/fdisk.h>
2N/A#include <sys/efi_partition.h>
2N/A#include <sys/byteorder.h>
2N/A#include <sys/ddi.h>
2N/A#include <libdevinfo.h>
2N/A#include <sys/mount.h>
2N/A#include <sys/mntent.h>
2N/A#if defined(__i386) || defined(__amd64)
2N/A#include <libfdisk.h>
2N/A#endif
2N/A#include "libbootmgmt.h"
2N/A
2N/Aint bootmgmt_debug = 0;
2N/A
2N/A/* description of required partitions for error reporting of libzfs */
2N/A
2N/A#define EFI_SYSTEM_DESC "EFI System"
2N/A#define BIOS_BOOT_DESC "BIOS Boot"
2N/A
2N/A#define EFI_MAX_SUPPORTED_MINOR_NODE 6
2N/A
2N/A#if defined(__i386) || defined(__amd64)
2N/Astatic int check_mbr_label(int fd, char *pathname, uint64_t *sizep);
2N/A#endif
2N/A
2N/A/*
2N/A * Return whether we are running on a UEFI system.
2N/A *
2N/A * We recognize being on a UEFI system if a property named "efi-systab"
2N/A * exists on root node of device tree.
2N/A *
2N/A * No need to check for this on SPARC since we know it is not a UEFI system.
2N/A */
2N/A
2N/Aboolean_t
2N/Abootmgmt_is_uefi_system()
2N/A{
2N/A#if defined(__i386) || defined(__amd64)
2N/A
2N/A di_node_t root_node = DI_NODE_NIL;
2N/A char *propname = "efi-systab";
2N/A static int is_uefi = -1;
2N/A di_prop_t prop = DI_PROP_NIL;
2N/A
2N/A
2N/A if (is_uefi != -1)
2N/A return ((is_uefi == 1)? B_TRUE : B_FALSE);
2N/A
2N/A is_uefi = 0;
2N/A if ((root_node = di_init("/", DINFOCPYALL)) != DI_NODE_NIL) {
2N/A
2N/A while ((prop = di_prop_next(root_node, prop)) != DI_PROP_NIL) {
2N/A if (strcmp(propname, di_prop_name(prop)) == 0) {
2N/A is_uefi = 1;
2N/A break;
2N/A }
2N/A }
2N/A } else if (bootmgmt_debug)
2N/A (void) fprintf(stderr, "di_init or di_prom_init failed\n");
2N/A
2N/A if (root_node != DI_NODE_NIL)
2N/A di_fini(root_node);
2N/A
2N/A return ((is_uefi == 1)? B_TRUE : B_FALSE);
2N/A#else
2N/A return (B_FALSE);
2N/A#endif
2N/A}
2N/A
2N/A
2N/A#ifdef __sparc
2N/Astatic di_node_t
2N/Alocate_child(di_node_t parent, char *nodename)
2N/A{
2N/A di_node_t node;
2N/A for (node = di_child_node(parent); node != DI_NODE_NIL;
2N/A node = di_sibling_node(node)) {
2N/A if (strcmp(di_node_name(node), nodename) == 0)
2N/A return (node);
2N/A }
2N/A return (DI_NODE_NIL);
2N/A}
2N/A#endif
2N/A
2N/A
2N/Aboolean_t
2N/Abootmgmt_is_gpt_boot_capable(const char **msg)
2N/A{
2N/A if (msg)
2N/A *msg = NULL;
2N/A{
2N/A#ifdef __sparc
2N/A /*
2N/A * On SPARC machine, we can boot off an EFI/GPT label if OBP has
2N/A * support for it, i.e if a property named "gpt" exists on
2N/A * /packages/disk-label prom node in device tree
2N/A */
2N/A di_node_t node = DI_NODE_NIL;
2N/A di_node_t root_node = DI_NODE_NIL;
2N/A di_prom_handle_t phdl = DI_PROM_HANDLE_NIL;
2N/A di_prom_prop_t pp;
2N/A static int capable = -1;
2N/A static const char *omsg = NULL;
2N/A
2N/A if (capable != -1) {
2N/A if (msg)
2N/A *msg = omsg;
2N/A return ((capable == 1) ? B_TRUE : B_FALSE);
2N/A }
2N/A capable = 0;
2N/A if ((root_node = di_init("/", DINFOCPYALL)) != DI_NODE_NIL &&
2N/A (phdl = di_prom_init()) != DI_PROM_HANDLE_NIL) {
2N/A if ((node = locate_child(root_node, "packages")) != DI_NODE_NIL)
2N/A node = locate_child(node, "disk-label");
2N/A } else if (bootmgmt_debug)
2N/A (void) fprintf(stderr, "bootmgmt_is_gpt_boot_capable: di_init "
2N/A "or di_prom_init failed\n");
2N/A
2N/A if (node != DI_NODE_NIL) {
2N/A for (pp = di_prom_prop_next(phdl, node, DI_PROM_PROP_NIL);
2N/A pp != DI_PROM_PROP_NIL;
2N/A pp = di_prom_prop_next(phdl, node, pp)) {
2N/A if (strcmp("gpt", di_prom_prop_name(pp)) == 0) {
2N/A capable = 1;
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (phdl != DI_PROM_HANDLE_NIL)
2N/A di_prom_fini(phdl);
2N/A if (root_node != DI_NODE_NIL)
2N/A di_fini(root_node);
2N/A
2N/A if (!capable && msg)
2N/A *msg = dgettext(TEXT_DOMAIN,
2N/A "the OBP on this system does not support booting "
2N/A "Solaris from GPT-partitioned disks. Please contact "
2N/A "Oracle Support for an OBP update");
2N/A return ((capable == 1) ? B_TRUE : B_FALSE);
2N/A
2N/A#else
2N/A struct stat sb;
2N/A
2N/A /*
2N/A * This file path must be synchronized with pybootmgmt:
2N/A * (usr/src/lib/pybootmgmt/common/bootmgmt/backend/loader/grub2.py)
2N/A */
2N/A#define GRUB2_BIOS_KERNEL_IMG \
2N/A "/usr/lib/grub2/bios/lib/grub/i386-pc/kernel.img"
2N/A
2N/A /*
2N/A * If GRUB2 is installed, return TRUE, otherwise FALSE. This, of
2N/A * course doesn't cover cases where some other entity installed GRUB2
2N/A * elsewhere and is using it to boot the system. For that case,
2N/A * we would need to do deep inspection of the boot devices, which is
2N/A * a whole lot of pain for not much gain. It also doesn't cover the
2N/A * case of GRUB2 being installed in /, but not installed on the boot
2N/A * device. For UEFI systems, we just assume that we're using a GPT-
2N/A * aware boot loader.
2N/A */
2N/A if (bootmgmt_is_uefi_system() ||
2N/A stat(GRUB2_BIOS_KERNEL_IMG, &sb) == 0)
2N/A return (B_TRUE);
2N/A if (msg)
2N/A *msg = dgettext(TEXT_DOMAIN, "vital GRUB 2 "
2N/A "loader files in the root filesystem could not be "
2N/A "located. The system cannot boot Solaris from "
2N/A "GPT-partitioned disks without GRUB 2");
2N/A return (B_FALSE);
2N/A#endif
2N/A}
2N/A}
2N/A
2N/Astatic int
2N/Abootmgmt_check_pcfs(char *syspath)
2N/A{
2N/A char optbuf[MAX_MNTOPT_STR] = { '\0', };
2N/A char tmpdir[MAXPATHLEN];
2N/A char blockpath[MAXPATHLEN];
2N/A const char *p = syspath;
2N/A int pos;
2N/A
2N/A
2N/A if ((strncmp(syspath, "/dev/", 5) == 0) &&
2N/A (((p = strstr(syspath, "/rdsk/")) != NULL) ||
2N/A ((p = strstr(syspath, "/rlofi/")) != NULL) ||
2N/A ((p = strstr(syspath, "/rramdisk/")) != NULL) ||
2N/A ((p = strstr(syspath, "/rdmp/")) != NULL))) {
2N/A
2N/A pos = (uintptr_t)p - (uintptr_t)syspath;
2N/A (void) snprintf(blockpath, sizeof (blockpath), "%.*s%s",
2N/A pos + 1, syspath, p + 2);
2N/A } else {
2N/A (void) snprintf(blockpath, sizeof (blockpath), "%s", syspath);
2N/A }
2N/A
2N/A (void) strlcpy(tmpdir, "/tmp/.libbootmgmt-XXXXXXX",
2N/A sizeof (tmpdir));
2N/A
2N/A /* try to mount the file system, since fstyp is not reliable */
2N/A if (mkdtemp(tmpdir) == NULL) {
2N/A if (bootmgmt_debug)
2N/A (void) fprintf(stdout, "mkdtemp failed\n");
2N/A return (-2);
2N/A }
2N/A if (mount(blockpath, tmpdir, MS_RDONLY | MS_OPTIONSTR,
2N/A MNTTYPE_PCFS, NULL, 0, optbuf, MAX_MNTOPT_STR) == 0) {
2N/A if (bootmgmt_debug)
2N/A (void) fprintf(stdout, "mounted ok\n");
2N/A
2N/A (void) umount2(tmpdir, 0);
2N/A (void) rmdir(tmpdir);
2N/A return (0);
2N/A }
2N/A
2N/A if (bootmgmt_debug)
2N/A (void) fprintf(stdout, "mount failed %d, assuming no pcfs "
2N/A " exist on %s\n", errno, blockpath);
2N/A
2N/A (void) rmdir(tmpdir);
2N/A return (-1);
2N/A}
2N/A
2N/Aint
2N/Abootmgmt_get_required_part_info_on_base(ushort_t *tag, uint64_t *sizep,
2N/Achar **desc, char *rdiskpathname)
2N/A{
2N/A struct dk_gpt *efi_vtoc = NULL;
2N/A int fd = -1, err = -1;
2N/A
2N/A if ((fd = open(rdiskpathname, O_RDONLY|O_NDELAY)) < 0)
2N/A return (-1);
2N/A
2N/A if ((err = efi_alloc_and_read(fd, &efi_vtoc)) >= 0) {
2N/A int i, index;
2N/A int sysindex = -1;
2N/A int biosindex = -1;
2N/A ushort_t tmptag;
2N/A
2N/A for (i = 0; i < efi_vtoc->efi_nparts; i++) {
2N/A if (efi_vtoc->efi_parts[i].p_tag == V_SYSTEM &&
2N/A sysindex == -1)
2N/A sysindex = i;
2N/A else if (efi_vtoc->efi_parts[i].p_tag == V_BIOS_BOOT &&
2N/A biosindex == -1)
2N/A biosindex = i;
2N/A }
2N/A
2N/A if ((sysindex == -1 && biosindex == -1)) {
2N/A /* none found */
2N/A (void) close(fd);
2N/A efi_free(efi_vtoc);
2N/A return (-1);
2N/A } else if (sysindex != -1 && biosindex != -1) {
2N/A /* pick fw-appropriate */
2N/A if (bootmgmt_gpt_get_required_part_info(&tmptag, NULL,
2N/A NULL) == 0) {
2N/A if (tmptag == V_SYSTEM)
2N/A index = sysindex;
2N/A else
2N/A index = biosindex;
2N/A } else {
2N/A /* just pick the first one */
2N/A index = (sysindex < biosindex)? sysindex:
2N/A biosindex;
2N/A }
2N/A } else if (sysindex != -1)
2N/A index = sysindex;
2N/A else
2N/A index = biosindex;
2N/A
2N/A if (tag)
2N/A *tag = efi_vtoc->efi_parts[index].p_tag;
2N/A if (sizep)
2N/A *sizep = efi_vtoc->efi_parts[index].p_size *
2N/A efi_vtoc->efi_lbasize;
2N/A if (desc)
2N/A if (efi_vtoc->efi_parts[index].p_tag == V_SYSTEM)
2N/A *desc = strdup(EFI_SYSTEM_DESC);
2N/A else
2N/A *desc = strdup(BIOS_BOOT_DESC);
2N/A
2N/A (void) close(fd);
2N/A efi_free(efi_vtoc);
2N/A return (0);
2N/A }
2N/A
2N/A#if defined(__i386) || defined(__amd64)
2N/A else { /* check MBR */
2N/A
2N/A err = check_mbr_label(fd, rdiskpathname, sizep);
2N/A
2N/A /*
2N/A * Detect all conditions where we have an ESP in MBR on
2N/A * the base disk. We should never really get
2N/A * BOOT_REQ_PART_SAME_AS_VDEV.
2N/A */
2N/A
2N/A if (err == BOOT_REQ_PART_SAME_AS_VDEV ||
2N/A err == BOOT_REQ_PART_NOT_PCFS ||
2N/A err == BOOT_REQ_PART_EXISTS) {
2N/A
2N/A err = 0;
2N/A if (tag)
2N/A *tag = V_SYSTEM;
2N/A
2N/A if (desc)
2N/A *desc = strdup(EFI_SYSTEM_DESC);
2N/A }
2N/A }
2N/A
2N/A#endif
2N/A (void) close(fd);
2N/A return (err);
2N/A
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Get the required partition tag, size (in bytes) and a description
2N/A * for the partition for a GPT label.
2N/A *
2N/A * If an efi_vtoc is given, we will return the info on the first partition
2N/A * that matches "any" required boot partition.
2N/A *
2N/A * for desc, we allocate the iarea and caller will need to free it.
2N/A *
2N/A * Otherwise, we return the required partition info based on system requirement
2N/A * return values
2N/A * 0 if one is required/found
2N/A * -1 none is required/not found
2N/A */
2N/A/*ARGSUSED*/
2N/Aint
2N/Abootmgmt_gpt_get_required_part_info(ushort_t *tag, uint64_t *sizep,
2N/A char **desc)
2N/A{
2N/A
2N/A#if defined(__i386) || defined(__amd64)
2N/A if (bootmgmt_is_uefi_system()) {
2N/A if (tag)
2N/A *tag = V_SYSTEM;
2N/A if (sizep)
2N/A *sizep = REQUIRED_EFI_SYS_PARTITION_SIZE;
2N/A if (desc) {
2N/A *desc = strdup(EFI_SYSTEM_DESC);
2N/A }
2N/A } else {
2N/A if (tag)
2N/A *tag = V_BIOS_BOOT;
2N/A if (sizep)
2N/A *sizep = REQUIRED_BIOS_BOOT_PARTITION_SIZE;
2N/A if (desc)
2N/A *desc = strdup(BIOS_BOOT_DESC);
2N/A }
2N/A return (0);
2N/A#else
2N/A /* SPARC does not need any GPT required partition */
2N/A return (-1);
2N/A#endif
2N/A}
2N/A
2N/A/*
2N/A * Get the required partition tag, size (in bytes) and a description
2N/A * for the partition for a Legacy MBR label
2N/A * returns:
2N/A * -1 none is required
2N/A * 0 if one is required
2N/A */
2N/A/* ARGSUSED */
2N/Aint
2N/Abootmgmt_mbr_get_required_part_info(ushort_t *partid, uint64_t *sizep,
2N/A char **desc)
2N/A{
2N/A#if defined(__i386) || defined(__amd64)
2N/A if (bootmgmt_is_uefi_system()) {
2N/A if (partid)
2N/A *partid = EFI_FS; /* EFI_FS partition id */
2N/A if (sizep)
2N/A *sizep = REQUIRED_EFI_SYS_PARTITION_SIZE;
2N/A if (desc)
2N/A *desc = strdup(EFI_SYSTEM_DESC);
2N/A return (0);
2N/A }
2N/A return (-1);
2N/A#else
2N/A /* SPARC */
2N/A return (-1);
2N/A#endif
2N/A}
2N/A
2N/A/*
2N/A * handy utility to create a path, takes the give slice path,
2N/A * chops ending sx or px if any, append slice string (e.g "p", or "s")
2N/A * and pnum
2N/A */
2N/Astatic int
2N/Amakepath(char *slicepath, char *respath, int respathsize, char *str, int pnum)
2N/A{
2N/A
2N/A char ctdpath[MAXPATHLEN];
2N/A int len = strlen(slicepath);
2N/A
2N/A if (strlcpy(ctdpath, slicepath, MAXPATHLEN) > MAXPATHLEN)
2N/A return (-1);
2N/A
2N/A if (isdigit(ctdpath[len -1]) &&
2N/A (ctdpath [len - 2] == 's' || ctdpath [len - 2] == 'p'))
2N/A ctdpath[len - 2] = 0;
2N/A else if ((isdigit(ctdpath[len -1]) && isdigit(ctdpath[len - 2])) &&
2N/A (ctdpath [len - 3] == 's' || ctdpath [len - 3] == 'p'))
2N/A ctdpath[len - 3] = 0;
2N/A
2N/A (void) snprintf(respath, respathsize, "%s%s%d", ctdpath, str, pnum);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A
2N/A/*
2N/A * Given an EFI/GPT label, check whether we have the required partition.
2N/A *
2N/A * returns:
2N/A * BOOT_REQ_PART_NOT_REQUIRED if none is required.
2N/A * BOOT_REQ_PART_EXISTS if one is required and exists
2N/A * BOOT_REQ_PART_DOESNOT_EXIST if one is required and does not exist
2N/A * BOOT_ERR error (invalid arg)
2N/A */
2N/A
2N/Astatic int
2N/Acheck_efi_boot_label(struct dk_gpt *efi_vtoc, char *slicepathname)
2N/A{
2N/A int i;
2N/A ushort_t reqtag;
2N/A
2N/A if (bootmgmt_gpt_get_required_part_info(&reqtag, NULL, NULL) == -1) {
2N/A /* SPARC */
2N/A return (BOOT_REQ_PART_NOT_REQUIRED);
2N/A }
2N/A if (efi_vtoc == NULL)
2N/A return (BOOT_ERR);
2N/A
2N/A for (i = 0; i < efi_vtoc->efi_nparts; i++) {
2N/A if (efi_vtoc->efi_parts[i].p_tag == reqtag) {
2N/A char reqpath[MAXPATHLEN];
2N/A
2N/A if (i > EFI_MAX_SUPPORTED_MINOR_NODE)
2N/A return (BOOT_REQ_PART_NOT_IN_SUPPORTED_RANGE);
2N/A
2N/A if (makepath(slicepathname,
2N/A reqpath, MAXPATHLEN, "s", i) != 0)
2N/A return (BOOT_ERR);
2N/A
2N/A if (strcmp(slicepathname, reqpath) == 0)
2N/A return (BOOT_REQ_PART_SAME_AS_VDEV);
2N/A
2N/A if (reqtag == V_SYSTEM) {
2N/A /* make sure we have a pcfs on it */
2N/A if (bootmgmt_check_pcfs(reqpath) != 0)
2N/A return (BOOT_REQ_PART_NOT_PCFS);
2N/A }
2N/A
2N/A return (BOOT_REQ_PART_EXISTS);
2N/A }
2N/A }
2N/A
2N/A return (BOOT_REQ_PART_DOESNOT_EXIST);
2N/A}
2N/A
2N/A
2N/A
2N/A#if defined(__i386) || defined(__amd64)
2N/A
2N/A
2N/A/*
2N/A * Given an MBR label, check whether there is a preexisting ESP.
2N/A *
2N/A * returns:
2N/A * BOOT_REQ_PART_NOT_REQUIRED if none is required.
2N/A * BOOT_REQ_PART_EXISTS if one is required and exists
2N/A * BOOT_REQ_PART_DOESNOT_EXIST if one is required and does not exist
2N/A * BOOT_ERR if there was an error.
2N/A */
2N/A/* input pathname is /dev/rdsk/cxtxdxsN . fd corresponds to pathname */
2N/A/* check all requirements for a bootable VTOC labeled disk on a UEFI system */
2N/Astatic int
2N/Acheck_mbr_label(int fd, char *pathname, uint64_t *sizep)
2N/A{
2N/A char *bootsect = NULL;
2N/A struct mboot *mboot;
2N/A struct dk_minfo minfo;
2N/A struct ipart *ipart;
2N/A int i, sectsize, ret;
2N/A ext_part_t *epp = NULL;
2N/A uint32_t secnum, numsec;
2N/A int pno, rval;
2N/A char wholedisk[MAXPATHLEN];
2N/A
2N/A if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) != 0) {
2N/A return (BOOT_ERR);
2N/A }
2N/A
2N/A sectsize = (minfo.dki_lbsize != 0)? minfo.dki_lbsize : DEV_BSIZE;
2N/A
2N/A if ((bootsect = calloc(sectsize, 1)) == NULL) {
2N/A return (BOOT_ERR);
2N/A }
2N/A
2N/A if (ioctl(fd, DKIOCGMBOOT, bootsect) < 0) {
2N/A if (errno == ENOTTY) {
2N/A int wholefd = -1;
2N/A
2N/A if (makepath(pathname, wholedisk, MAXPATHLEN, "p", 0)
2N/A != 0) {
2N/A free(bootsect);
2N/A return (BOOT_ERR);
2N/A }
2N/A
2N/A if (((wholefd = open(wholedisk, O_RDONLY)) == -1) ||
2N/A (read(wholefd, bootsect, sectsize) != sectsize)) {
2N/A if (wholefd != -1)
2N/A (void) close(wholefd);
2N/A free(bootsect);
2N/A return (BOOT_ERR);
2N/A }
2N/A (void) close(wholefd);
2N/A } else {
2N/A free(bootsect);
2N/A return (BOOT_ERR);
2N/A }
2N/A }
2N/A
2N/A mboot = (struct mboot *)(uintptr_t)bootsect;
2N/A
2N/A if (LE_16(mboot->signature) != MBB_MAGIC) {
2N/A free(bootsect);
2N/A return (BOOT_REQ_PART_DOESNOT_EXIST);
2N/A }
2N/A
2N/A ipart = (struct ipart *)(uintptr_t)mboot->parts;
2N/A
2N/A for (i = 0; i < FD_NUMPART; i++) {
2N/A if (ipart->systid == EFI_FS) {
2N/A char syspath[MAXPATHLEN];
2N/A /* make sure we have a pcfs on it */
2N/A if (makepath(pathname,
2N/A syspath, MAXPATHLEN, "p", i + 1) != 0)
2N/A ret = BOOT_ERR;
2N/A else if (strcmp(syspath, pathname) == 0)
2N/A ret = BOOT_REQ_PART_SAME_AS_VDEV;
2N/A else if (bootmgmt_check_pcfs(syspath) != 0)
2N/A ret = BOOT_REQ_PART_NOT_PCFS;
2N/A else
2N/A ret = BOOT_REQ_PART_EXISTS;
2N/A if (sizep != NULL)
2N/A *sizep = (uint64_t)ipart->numsect * sectsize;
2N/A
2N/A free(bootsect);
2N/A return (ret);
2N/A }
2N/A ipart++;
2N/A }
2N/A
2N/A free(bootsect);
2N/A
2N/A /* check extended */
2N/A if (makepath(pathname, wholedisk, MAXPATHLEN, "p", 0) != 0)
2N/A return (BOOT_ERR);
2N/A
2N/A if ((rval = libfdisk_init(&epp, wholedisk, NULL, FDISK_READ_DISK))
2N/A != FDISK_SUCCESS) {
2N/A switch (rval) {
2N/A case FDISK_ENOVGEOM:
2N/A case FDISK_ENOPGEOM:
2N/A case FDISK_ENOLGEOM:
2N/A case FDISK_ENOLOGDRIVE:
2N/A case FDISK_EBADLOGDRIVE:
2N/A break;
2N/A case FDISK_EBADMAGIC:
2N/A default:
2N/A (void) fprintf(stderr, gettext("libfdisk_init "
2N/A "failed %d\n"), rval);
2N/A return (BOOT_ERR);
2N/A }
2N/A }
2N/A
2N/A if (epp != NULL) {
2N/A rval = fdisk_get_efi_fs_part(epp, &pno, &secnum, &numsec);
2N/A
2N/A libfdisk_fini(&epp);
2N/A
2N/A if (rval == FDISK_SUCCESS) {
2N/A char syspath[MAXPATHLEN];
2N/A
2N/A if (pno > (MAX_EXT_PARTS + FD_NUMPART))
2N/A return (BOOT_REQ_PART_NOT_IN_SUPPORTED_RANGE);
2N/A
2N/A if (sizep != NULL)
2N/A *sizep = (uint64_t)numsec * sectsize;
2N/A
2N/A /* make sure we have a pcfs on it */
2N/A if (makepath(pathname, syspath, MAXPATHLEN, "p",
2N/A pno) != 0)
2N/A return (BOOT_ERR);
2N/A else if (strcmp(syspath, pathname) == 0)
2N/A return (BOOT_REQ_PART_SAME_AS_VDEV);
2N/A else if (bootmgmt_check_pcfs(syspath) != 0)
2N/A return (BOOT_REQ_PART_NOT_PCFS);
2N/A else
2N/A return (BOOT_REQ_PART_EXISTS);
2N/A }
2N/A }
2N/A
2N/A return (BOOT_REQ_PART_DOESNOT_EXIST);
2N/A}
2N/A#endif
2N/A
2N/A
2N/A
2N/A/*
2N/A * check the disk for whether the label has all required boot partitions
2N/A * and whether system support booting off this label type
2N/A * input: diskpath
2N/A * out: labeltype will be set to type of label on the disk:
2N/A * MBR
2N/A * EFI
2N/A *
2N/A * return:
2N/A * BOOT_ERR if there was an error
2N/A * BOOT_REQ_PART_NOT_REQUIRED
2N/A * BOOT_REQ_PART_EXISTS
2N/A * BOOT_LABEL_SYSTEM_NOT_CAPABLE
2N/A * BOOT_REQ_PART_DOESNOT_EXIST
2N/A * XXX more was added
2N/A */
2N/A
2N/A
2N/Aint
2N/Abootmgmt_check_boot_sys_label(char *vdevpathname, int *labeltype,
2N/A const char **msg)
2N/A{
2N/A int fd = -1, ret = BOOT_REQ_PART_NOT_REQUIRED;
2N/A struct dk_gpt *efi_vtoc;
2N/A
2N/A if (bootmgmt_debug)
2N/A (void) fprintf(stdout, "check_disk_boot_label %s\n",
2N/A vdevpathname);
2N/A
2N/A *labeltype = 0;
2N/A if ((fd = open(vdevpathname, O_RDONLY|O_NDELAY)) < 0) {
2N/A if (bootmgmt_debug)
2N/A (void) fprintf(stderr,
2N/A "check_disk_boot_label open of %s failed\n",
2N/A vdevpathname);
2N/A return (BOOT_ERR);
2N/A }
2N/A
2N/A if ((efi_alloc_and_read(fd, &efi_vtoc)) >= 0) {
2N/A if (labeltype)
2N/A *labeltype = EFI_LABEL;
2N/A if (bootmgmt_is_gpt_boot_capable(msg) == B_FALSE) {
2N/A /* gpt label, system not gpt boot capable */
2N/A ret = BOOT_LABEL_SYSTEM_NOT_CAPABLE;
2N/A } else {
2N/A ret = check_efi_boot_label(efi_vtoc, vdevpathname);
2N/A }
2N/A } else {
2N/A *labeltype = VTOC_LABEL;
2N/A#if defined(__i386) || defined(__amd64)
2N/A *labeltype |= LEGACY_MBR_LABEL;
2N/A if (bootmgmt_is_uefi_system())
2N/A ret = check_mbr_label(fd, vdevpathname, NULL);
2N/A#endif
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * if efi_vtoc is set that is the gpt label on the disk
2N/A * path is /dev/rdsk/cxtxdx.
2N/A *
2N/A * returns:
2N/A * if none found 0, or all succeeded
2N/A * if error -1
2N/A */
2N/A
2N/Aint
2N/Abootmgmt_prepare_gpt_req_part(char *path, struct dk_gpt *efi_vtoc_in,
2N/A boolean_t force)
2N/A{
2N/A
2N/A char syspath[MAXPATHLEN];
2N/A int i, found = 0, rval;
2N/A char cmd[1024];
2N/A struct dk_gpt *local_efi_vtoc = NULL, *efi_vtoc;
2N/A
2N/A
2N/A if (efi_vtoc_in == NULL) {
2N/A int fd = -1;
2N/A if ((fd = open(path, O_RDONLY|O_NDELAY)) < 0)
2N/A return (-1);
2N/A if (efi_alloc_and_read(fd, &local_efi_vtoc) < 0)
2N/A return (-1);
2N/A efi_vtoc = local_efi_vtoc;
2N/A (void) close(fd);
2N/A } else
2N/A efi_vtoc = efi_vtoc_in;
2N/A
2N/A for (i = 0; i < efi_vtoc->efi_nparts; i++) {
2N/A if (efi_vtoc->efi_parts[i].p_tag == V_SYSTEM) {
2N/A found = 1;
2N/A break;
2N/A }
2N/A }
2N/A if (local_efi_vtoc != NULL)
2N/A efi_free(local_efi_vtoc);
2N/A
2N/A if (found == 0)
2N/A return (0);
2N/A
2N/A (void) snprintf(syspath, sizeof (syspath), "%s%s%d", path, "s", i);
2N/A
2N/A if (!force)
2N/A if (bootmgmt_check_pcfs(syspath) == 0)
2N/A return (0);
2N/A
2N/A (void) snprintf(cmd, sizeof (cmd), "/usr/sbin/mkfs -F pcfs "
2N/A "-o fat=32 %s < /dev/null", syspath);
2N/A
2N/A rval = system(cmd);
2N/A
2N/A if (bootmgmt_debug)
2N/A (void) fprintf(stdout, "%s returned %d\n", cmd, rval);
2N/A
2N/A return (rval);
2N/A}