1753a6d45SSherry Moore /* 2753a6d45SSherry Moore * CDDL HEADER START 3753a6d45SSherry Moore * 4753a6d45SSherry Moore * The contents of this file are subject to the terms of the 5753a6d45SSherry Moore * Common Development and Distribution License (the "License"). 6753a6d45SSherry Moore * You may not use this file except in compliance with the License. 7753a6d45SSherry Moore * 8753a6d45SSherry Moore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9753a6d45SSherry Moore * or http://www.opensolaris.org/os/licensing. 10753a6d45SSherry Moore * See the License for the specific language governing permissions 11753a6d45SSherry Moore * and limitations under the License. 12753a6d45SSherry Moore * 13753a6d45SSherry Moore * When distributing Covered Code, include this CDDL HEADER in each 14753a6d45SSherry Moore * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15753a6d45SSherry Moore * If applicable, add the following below this CDDL HEADER, with the 16753a6d45SSherry Moore * fields enclosed by brackets "[]" replaced with your own identifying 17753a6d45SSherry Moore * information: Portions Copyright [yyyy] [name of copyright owner] 18753a6d45SSherry Moore * 19753a6d45SSherry Moore * CDDL HEADER END 20753a6d45SSherry Moore */ 21753a6d45SSherry Moore /* 22753a6d45SSherry Moore * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23753a6d45SSherry Moore * Use is subject to license terms. 24753a6d45SSherry Moore */ 2501f9868aSMarcel Telka /* 2601f9868aSMarcel Telka * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 27*57631629SToomas Soome * Copyright 2015 Toomas Soome <tsoome@me.com> 2801f9868aSMarcel Telka */ 29753a6d45SSherry Moore 30753a6d45SSherry Moore /* 3101f9868aSMarcel Telka * This file contains all the functions that manipulate the file 32753a6d45SSherry Moore * system where the GRUB menu resides. 33753a6d45SSherry Moore */ 34753a6d45SSherry Moore #include <stdio.h> 35753a6d45SSherry Moore #include <errno.h> 36753a6d45SSherry Moore #include <stdlib.h> 37753a6d45SSherry Moore #include <strings.h> 38753a6d45SSherry Moore #include <unistd.h> 39753a6d45SSherry Moore #include <fcntl.h> 40753a6d45SSherry Moore #include <assert.h> 41753a6d45SSherry Moore #include <sys/types.h> 42753a6d45SSherry Moore #include <sys/stat.h> 43753a6d45SSherry Moore #include <sys/mount.h> 44753a6d45SSherry Moore #include <sys/mntent.h> 45753a6d45SSherry Moore #include <sys/mnttab.h> 46*57631629SToomas Soome #include <sys/efi_partition.h> 47*57631629SToomas Soome #include <sys/vtoc.h> 48753a6d45SSherry Moore #include <sys/fs/ufs_mount.h> 49753a6d45SSherry Moore #include <sys/dktp/fdisk.h> 50753a6d45SSherry Moore #include <libfstyp.h> 5101f9868aSMarcel Telka #if defined(i386) || defined(__amd64) 5201f9868aSMarcel Telka #include <libfdisk.h> 5301f9868aSMarcel Telka #endif 54753a6d45SSherry Moore 55753a6d45SSherry Moore #include "libgrub_impl.h" 56753a6d45SSherry Moore 57753a6d45SSherry Moore static int 58753a6d45SSherry Moore slice_match(const char *physpath, int slice) 59753a6d45SSherry Moore { 60753a6d45SSherry Moore const char *pos; 61753a6d45SSherry Moore 62*57631629SToomas Soome /* always match whole disk slice */ 63*57631629SToomas Soome if (slice == SLCNUM_WHOLE_DISK) 64*57631629SToomas Soome return (0); 65*57631629SToomas Soome 66753a6d45SSherry Moore return ((pos = strrchr(physpath, slice)) == NULL || 67753a6d45SSherry Moore pos[1] != 0 || pos[-1] != ':'); 68753a6d45SSherry Moore } 69753a6d45SSherry Moore 70753a6d45SSherry Moore /* 71753a6d45SSherry Moore * Returns zero if path contains ufs 72753a6d45SSherry Moore */ 73753a6d45SSherry Moore static int 74753a6d45SSherry Moore slice_ufs(const char *path) 75753a6d45SSherry Moore { 76753a6d45SSherry Moore int fd, ret; 77753a6d45SSherry Moore const char *id; 78753a6d45SSherry Moore fstyp_handle_t hdl; 79753a6d45SSherry Moore 80753a6d45SSherry Moore fd = open(path, O_RDONLY); 81753a6d45SSherry Moore if ((ret = fstyp_init(fd, 0, NULL, &hdl)) == 0) { 82753a6d45SSherry Moore ret = fstyp_ident(hdl, "ufs", &id); 83753a6d45SSherry Moore fstyp_fini(hdl); 84753a6d45SSherry Moore } 85753a6d45SSherry Moore (void) close(fd); 86753a6d45SSherry Moore return (ret); 87753a6d45SSherry Moore } 88753a6d45SSherry Moore 89753a6d45SSherry Moore 90753a6d45SSherry Moore static int 91753a6d45SSherry Moore get_sol_prtnum(const char *physpath) 92753a6d45SSherry Moore { 93753a6d45SSherry Moore int i, fd; 94753a6d45SSherry Moore char *pos; 95753a6d45SSherry Moore size_t sz; 96753a6d45SSherry Moore struct mboot *mb; 97753a6d45SSherry Moore struct ipart *ipart; 98753a6d45SSherry Moore char boot_sect[512]; 99753a6d45SSherry Moore char rdev[MAXNAMELEN]; 10001f9868aSMarcel Telka #if defined(i386) || defined(__amd64) 10101f9868aSMarcel Telka ext_part_t *epp; 10201f9868aSMarcel Telka int ext_part_found = 0; 10301f9868aSMarcel Telka #endif 104753a6d45SSherry Moore 105753a6d45SSherry Moore (void) snprintf(rdev, sizeof (rdev), "/devices%s,raw", physpath); 106753a6d45SSherry Moore 107753a6d45SSherry Moore if ((pos = strrchr(rdev, ':')) == NULL) 108753a6d45SSherry Moore return (PRTNUM_INVALID); 109753a6d45SSherry Moore 110*57631629SToomas Soome /* 111*57631629SToomas Soome * first check for EFI partitioning, efi_alloc_and_read() 112*57631629SToomas Soome * will return partition number. 113*57631629SToomas Soome */ 114*57631629SToomas Soome if ((fd = open(rdev, O_RDONLY|O_NDELAY)) >= 0) { 115*57631629SToomas Soome struct dk_gpt *vtoc; 116*57631629SToomas Soome 117*57631629SToomas Soome if ((i = efi_alloc_and_read(fd, &vtoc)) >= 0) { 118*57631629SToomas Soome /* zfs is using V_USR */ 119*57631629SToomas Soome if (vtoc->efi_parts[i].p_tag != V_USR) 120*57631629SToomas Soome i = PRTNUM_INVALID; /* error */ 121*57631629SToomas Soome efi_free(vtoc); 122*57631629SToomas Soome (void) close(fd); 123*57631629SToomas Soome return (i); 124*57631629SToomas Soome } 125*57631629SToomas Soome (void) close(fd); 126*57631629SToomas Soome } else { 127*57631629SToomas Soome return (PRTNUM_INVALID); 128*57631629SToomas Soome } 129*57631629SToomas Soome 130753a6d45SSherry Moore pos[1] = SLCNUM_WHOLE_DISK; 131753a6d45SSherry Moore 132753a6d45SSherry Moore fd = open(rdev, O_RDONLY); 133753a6d45SSherry Moore sz = read(fd, boot_sect, sizeof (boot_sect)); 134753a6d45SSherry Moore (void) close(fd); 135753a6d45SSherry Moore 136753a6d45SSherry Moore if (sz != sizeof (boot_sect)) 137753a6d45SSherry Moore return (PRTNUM_INVALID); 138753a6d45SSherry Moore 139753a6d45SSherry Moore /* parse fdisk table */ 140753a6d45SSherry Moore mb = (struct mboot *)(uintptr_t)boot_sect; 141753a6d45SSherry Moore ipart = (struct ipart *)(uintptr_t)mb->parts; 142753a6d45SSherry Moore for (i = 0; i < FD_NUMPART; ++i) { 143753a6d45SSherry Moore if (ipart[i].systid == SUNIXOS || ipart[i].systid == SUNIXOS2) 144753a6d45SSherry Moore return (i); 14501f9868aSMarcel Telka 14601f9868aSMarcel Telka #if defined(i386) || defined(__amd64) 14701f9868aSMarcel Telka if (!fdisk_is_dos_extended(ipart[i].systid) || 14801f9868aSMarcel Telka (ext_part_found == 1)) 14901f9868aSMarcel Telka continue; 15001f9868aSMarcel Telka 15101f9868aSMarcel Telka ext_part_found = 1; 15201f9868aSMarcel Telka 15301f9868aSMarcel Telka if (libfdisk_init(&epp, rdev, NULL, FDISK_READ_DISK) == 15401f9868aSMarcel Telka FDISK_SUCCESS) { 15501f9868aSMarcel Telka uint32_t begs, nums; 15601f9868aSMarcel Telka int pno; 15701f9868aSMarcel Telka int rval; 15801f9868aSMarcel Telka 15901f9868aSMarcel Telka rval = fdisk_get_solaris_part(epp, &pno, &begs, &nums); 16001f9868aSMarcel Telka 16101f9868aSMarcel Telka libfdisk_fini(&epp); 16201f9868aSMarcel Telka 16301f9868aSMarcel Telka if (rval == FDISK_SUCCESS) 16401f9868aSMarcel Telka return (pno - 1); 16501f9868aSMarcel Telka } 16601f9868aSMarcel Telka #endif 167753a6d45SSherry Moore } 168753a6d45SSherry Moore return (PRTNUM_INVALID); 169753a6d45SSherry Moore } 170753a6d45SSherry Moore 171753a6d45SSherry Moore /* 172753a6d45SSherry Moore * Get physpath, topfs and bootfs for ZFS root dataset. 173753a6d45SSherry Moore * Return 0 on success, non-zero (not errno) on failure. 174753a6d45SSherry Moore */ 175753a6d45SSherry Moore static int 176753a6d45SSherry Moore get_zfs_root(zfs_handle_t *zfh, grub_fs_t *fs, grub_root_t *root) 177753a6d45SSherry Moore { 178753a6d45SSherry Moore int ret; 179753a6d45SSherry Moore zpool_handle_t *zph; 180753a6d45SSherry Moore const char *name; 181753a6d45SSherry Moore 182753a6d45SSherry Moore if (zfs_get_type(zfh) != ZFS_TYPE_FILESYSTEM || 183753a6d45SSherry Moore (name = zfs_get_name(zfh)) == NULL || 184753a6d45SSherry Moore (zph = zpool_open(fs->gf_lzfh, name)) == NULL) 185753a6d45SSherry Moore return (-1); 186753a6d45SSherry Moore 187753a6d45SSherry Moore if ((ret = zpool_get_physpath(zph, root->gr_physpath, 188753a6d45SSherry Moore sizeof (root->gr_physpath))) == 0 && 189753a6d45SSherry Moore (ret = zpool_get_prop(zph, ZPOOL_PROP_BOOTFS, 190753a6d45SSherry Moore root->gr_fs[GRBM_ZFS_BOOTFS].gfs_dev, 191c58b3526SAdam Stevko sizeof (root->gr_fs[GRBM_ZFS_BOOTFS].gfs_dev), NULL, 192c58b3526SAdam Stevko B_FALSE)) == 0) { 193753a6d45SSherry Moore 194753a6d45SSherry Moore (void) strlcpy(root->gr_fs[GRBM_ZFS_TOPFS].gfs_dev, name, 195753a6d45SSherry Moore sizeof (root->gr_fs[GRBM_ZFS_TOPFS].gfs_dev)); 196753a6d45SSherry Moore (void) grub_fsd_get_mountp(root->gr_fs + GRBM_ZFS_BOOTFS, 197753a6d45SSherry Moore MNTTYPE_ZFS); 198753a6d45SSherry Moore (void) grub_fsd_get_mountp(root->gr_fs + GRBM_ZFS_TOPFS, 199753a6d45SSherry Moore MNTTYPE_ZFS); 200753a6d45SSherry Moore } 201753a6d45SSherry Moore 202753a6d45SSherry Moore zpool_close(zph); 203753a6d45SSherry Moore return (ret); 204753a6d45SSherry Moore } 205753a6d45SSherry Moore 206753a6d45SSherry Moore /* 207753a6d45SSherry Moore * On entry physpath parameter supposed to contain: 208753a6d45SSherry Moore * <disk_physpath>[<space><disk_physpath>]*. 20901f9868aSMarcel Telka * Retrieves first <disk_physpath> that matches both partition and slice. 210753a6d45SSherry Moore * If any partition and slice is acceptable, first <disk_physpath> is returned. 211753a6d45SSherry Moore */ 212753a6d45SSherry Moore static int 213753a6d45SSherry Moore get_one_physpath(char *physpath, uint_t prtnum, uint_t slcnum) 214753a6d45SSherry Moore { 215753a6d45SSherry Moore int ret; 216753a6d45SSherry Moore char *tmp, *tok; 217753a6d45SSherry Moore 218753a6d45SSherry Moore if (!IS_SLCNUM_VALID(slcnum) && !IS_PRTNUM_VALID(prtnum)) { 219753a6d45SSherry Moore (void) strtok(physpath, " "); 220753a6d45SSherry Moore return (0); 221753a6d45SSherry Moore } 222753a6d45SSherry Moore 223753a6d45SSherry Moore if ((tmp = strdup(physpath)) == NULL) 224753a6d45SSherry Moore return (errno); 225753a6d45SSherry Moore 226753a6d45SSherry Moore ret = ENODEV; 227753a6d45SSherry Moore for (tok = strtok(tmp, " "); tok != NULL; tok = strtok(NULL, " ")) { 228753a6d45SSherry Moore if ((ret = (slice_match(tok, slcnum) != 0 || 229753a6d45SSherry Moore get_sol_prtnum(tok) != prtnum)) == 0) { 230753a6d45SSherry Moore (void) strcpy(physpath, tok); 231753a6d45SSherry Moore break; 232753a6d45SSherry Moore } 233753a6d45SSherry Moore } 234753a6d45SSherry Moore 235753a6d45SSherry Moore free(tmp); 2368c7cfd88SSherry Moore if (ret) 2378c7cfd88SSherry Moore ret = ENODEV; 238753a6d45SSherry Moore return (ret); 239753a6d45SSherry Moore } 240753a6d45SSherry Moore 241753a6d45SSherry Moore static int 242753a6d45SSherry Moore zfs_bootsign(zfs_handle_t *zfh, void *data) 243753a6d45SSherry Moore { 244753a6d45SSherry Moore grub_barg_t *barg; 245753a6d45SSherry Moore grub_menu_t *menu; 246753a6d45SSherry Moore struct stat st; 247753a6d45SSherry Moore char path[MAXPATHLEN]; 248753a6d45SSherry Moore 249753a6d45SSherry Moore barg = (grub_barg_t *)data; 250753a6d45SSherry Moore menu = barg->gb_entry->ge_menu; 251753a6d45SSherry Moore 252753a6d45SSherry Moore do { 253753a6d45SSherry Moore if (get_zfs_root(zfh, &menu->gm_fs, &barg->gb_root) != 0 || 254753a6d45SSherry Moore get_one_physpath(barg->gb_root.gr_physpath, barg->gb_prtnum, 255753a6d45SSherry Moore barg->gb_slcnum) != 0) 256753a6d45SSherry Moore break; 257753a6d45SSherry Moore 258753a6d45SSherry Moore /* 259753a6d45SSherry Moore * if top zfs dataset is not mounted, mount it now 260753a6d45SSherry Moore */ 261753a6d45SSherry Moore if (barg->gb_root.gr_fs[GRBM_ZFS_TOPFS].gfs_mountp[0] == 0) { 262753a6d45SSherry Moore if (grub_fsd_mount_tmp(barg->gb_root.gr_fs + 263753a6d45SSherry Moore GRBM_ZFS_TOPFS, MNTTYPE_ZFS) != 0) 264753a6d45SSherry Moore break; 265753a6d45SSherry Moore } 266753a6d45SSherry Moore 267753a6d45SSherry Moore /* check that bootsign exists and it is a regular file */ 268753a6d45SSherry Moore (void) snprintf(path, sizeof (path), "%s%s", 269753a6d45SSherry Moore barg->gb_root.gr_fs[GRBM_ZFS_TOPFS].gfs_mountp, 270753a6d45SSherry Moore barg->gb_bootsign); 271753a6d45SSherry Moore 272753a6d45SSherry Moore if (lstat(path, &st) != 0 || S_ISREG(st.st_mode) == 0 || 273753a6d45SSherry Moore (st.st_mode & S_IRUSR) == 0) 274753a6d45SSherry Moore break; 275753a6d45SSherry Moore 276753a6d45SSherry Moore (void) strlcpy(barg->gb_root.gr_fstyp, MNTTYPE_ZFS, 277753a6d45SSherry Moore sizeof (barg->gb_root.gr_fstyp)); 278753a6d45SSherry Moore barg->gb_walkret = 0; 279753a6d45SSherry Moore /* LINTED: E_CONSTANT_CONDITION */ 280753a6d45SSherry Moore } while (0); 281753a6d45SSherry Moore 282753a6d45SSherry Moore grub_fsd_umount_tmp(barg->gb_root.gr_fs + GRBM_ZFS_TOPFS); 283753a6d45SSherry Moore zfs_close(zfh); 284753a6d45SSherry Moore 285753a6d45SSherry Moore /* return non-zero to terminate the walk */ 286753a6d45SSherry Moore return (barg->gb_walkret == 0); 287753a6d45SSherry Moore } 288753a6d45SSherry Moore 289753a6d45SSherry Moore static int 290753a6d45SSherry Moore get_devlink(di_devlink_t dl, void *arg) 291753a6d45SSherry Moore { 292753a6d45SSherry Moore const char *path; 293753a6d45SSherry Moore grub_barg_t *barg; 294753a6d45SSherry Moore 295753a6d45SSherry Moore barg = (grub_barg_t *)arg; 296753a6d45SSherry Moore if ((path = di_devlink_path(dl)) != NULL) 297753a6d45SSherry Moore (void) strlcpy(barg->gb_root.gr_fs[GRBM_UFS].gfs_dev, path, 298753a6d45SSherry Moore sizeof (barg->gb_root.gr_fs[GRBM_UFS].gfs_dev)); 299753a6d45SSherry Moore return (DI_WALK_TERMINATE); 300753a6d45SSherry Moore } 301753a6d45SSherry Moore 302753a6d45SSherry Moore static int 303753a6d45SSherry Moore ufs_bootsign_check(grub_barg_t *barg) 304753a6d45SSherry Moore { 305753a6d45SSherry Moore int ret; 306753a6d45SSherry Moore struct stat st; 307753a6d45SSherry Moore grub_menu_t *mp; 308753a6d45SSherry Moore char path[MAXPATHLEN]; 309753a6d45SSherry Moore 310753a6d45SSherry Moore mp = barg->gb_entry->ge_menu; 311753a6d45SSherry Moore 312753a6d45SSherry Moore /* get /dev/dsk link */ 313753a6d45SSherry Moore if (di_devlink_walk(mp->gm_fs.gf_dvlh, "^dsk/", 314753a6d45SSherry Moore barg->gb_root.gr_physpath, DI_PRIMARY_LINK, barg, get_devlink) != 0) 315753a6d45SSherry Moore return (errno); 316753a6d45SSherry Moore /* 317753a6d45SSherry Moore * if disk is not mounted, mount it now 318753a6d45SSherry Moore */ 319753a6d45SSherry Moore if (grub_fsd_get_mountp(barg->gb_root.gr_fs + GRBM_UFS, 320753a6d45SSherry Moore MNTTYPE_UFS) != 0) { 321753a6d45SSherry Moore if ((ret = 322753a6d45SSherry Moore slice_ufs(barg->gb_root.gr_fs[GRBM_UFS].gfs_dev)) != 0 || 323753a6d45SSherry Moore (ret = grub_fsd_mount_tmp(barg->gb_root.gr_fs + GRBM_UFS, 324753a6d45SSherry Moore MNTTYPE_UFS)) != 0) 325753a6d45SSherry Moore return (ret); 326753a6d45SSherry Moore } 327753a6d45SSherry Moore 328753a6d45SSherry Moore (void) snprintf(path, sizeof (path), "%s%s", 329753a6d45SSherry Moore barg->gb_root.gr_fs[GRBM_UFS].gfs_mountp, barg->gb_bootsign); 330753a6d45SSherry Moore 331753a6d45SSherry Moore if (lstat(path, &st) == 0 && S_ISREG(st.st_mode) && 332753a6d45SSherry Moore (st.st_mode & S_IRUSR) != 0) { 333753a6d45SSherry Moore barg->gb_walkret = 0; 334753a6d45SSherry Moore (void) strlcpy(barg->gb_root.gr_fstyp, MNTTYPE_UFS, 335753a6d45SSherry Moore sizeof (barg->gb_root.gr_fstyp)); 336753a6d45SSherry Moore } 337753a6d45SSherry Moore 338753a6d45SSherry Moore grub_fsd_umount_tmp(barg->gb_root.gr_fs + GRBM_UFS); 339753a6d45SSherry Moore return (barg->gb_walkret); 340753a6d45SSherry Moore } 341753a6d45SSherry Moore 342753a6d45SSherry Moore static int 343753a6d45SSherry Moore ufs_bootsign(di_node_t node, di_minor_t minor, void *arg) 344753a6d45SSherry Moore { 345753a6d45SSherry Moore uint_t prtnum; 346753a6d45SSherry Moore char *name, *path; 347753a6d45SSherry Moore grub_barg_t *barg; 348753a6d45SSherry Moore 349753a6d45SSherry Moore barg = (grub_barg_t *)arg; 350753a6d45SSherry Moore 351753a6d45SSherry Moore if (di_minor_spectype(minor) != S_IFBLK) 352753a6d45SSherry Moore return (DI_WALK_CONTINUE); 353753a6d45SSherry Moore 354753a6d45SSherry Moore name = di_minor_name(minor); 355753a6d45SSherry Moore if (name[0] != barg->gb_slcnum || name[1] != 0) 356753a6d45SSherry Moore return (DI_WALK_CONTINUE); 357753a6d45SSherry Moore 358753a6d45SSherry Moore path = di_devfs_path(node); 359753a6d45SSherry Moore (void) snprintf(barg->gb_root.gr_physpath, 360753a6d45SSherry Moore sizeof (barg->gb_root.gr_physpath), "%s:%c", path, barg->gb_slcnum); 361753a6d45SSherry Moore di_devfs_path_free(path); 362753a6d45SSherry Moore 363753a6d45SSherry Moore prtnum = get_sol_prtnum(barg->gb_root.gr_physpath); 364753a6d45SSherry Moore if (!IS_PRTNUM_VALID(prtnum)) 365753a6d45SSherry Moore return (DI_WALK_CONTINUE); 366753a6d45SSherry Moore 367753a6d45SSherry Moore /* 368753a6d45SSherry Moore * check only specified partition, slice 369753a6d45SSherry Moore */ 370753a6d45SSherry Moore 371753a6d45SSherry Moore if (IS_PRTNUM_VALID(barg->gb_prtnum)) { 372753a6d45SSherry Moore if (prtnum != barg->gb_prtnum || ufs_bootsign_check(barg) != 0) 373753a6d45SSherry Moore return (DI_WALK_CONTINUE); 374753a6d45SSherry Moore return (DI_WALK_TERMINATE); 375753a6d45SSherry Moore } 376753a6d45SSherry Moore 377753a6d45SSherry Moore /* 378753a6d45SSherry Moore * Walk through all slices in found solaris partition 379753a6d45SSherry Moore */ 380753a6d45SSherry Moore 381753a6d45SSherry Moore barg->gb_prtnum = prtnum; 382753a6d45SSherry Moore minor = DI_MINOR_NIL; 383753a6d45SSherry Moore 384753a6d45SSherry Moore while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 385753a6d45SSherry Moore 386753a6d45SSherry Moore if (di_minor_spectype(minor) != S_IFBLK) 387753a6d45SSherry Moore continue; 388753a6d45SSherry Moore 389753a6d45SSherry Moore name = di_minor_name(minor); 390753a6d45SSherry Moore if (!IS_SLCNUM_VALID(name[0]) || name[1] != 0) 391753a6d45SSherry Moore continue; 392753a6d45SSherry Moore 393753a6d45SSherry Moore barg->gb_slcnum = name[0]; 394753a6d45SSherry Moore path = strrchr(barg->gb_root.gr_physpath, ':'); 395753a6d45SSherry Moore path[1] = barg->gb_slcnum; 396753a6d45SSherry Moore 397753a6d45SSherry Moore if (ufs_bootsign_check(barg) == 0) 398753a6d45SSherry Moore return (DI_WALK_TERMINATE); 399753a6d45SSherry Moore } 400753a6d45SSherry Moore 401753a6d45SSherry Moore barg->gb_prtnum = (uint_t)PRTNUM_INVALID; 402753a6d45SSherry Moore barg->gb_slcnum = (uint_t)SLCNUM_WHOLE_DISK; 403753a6d45SSherry Moore return (DI_WALK_CONTINUE); 404753a6d45SSherry Moore } 405753a6d45SSherry Moore 406753a6d45SSherry Moore /* 407753a6d45SSherry Moore * Differs from what GRUB is doing: GRUB searchs through all disks seen by bios 408753a6d45SSherry Moore * for bootsign, if bootsign is found on ufs slice GRUB sets it as a root, 409753a6d45SSherry Moore * if on zfs, then GRUB uses zfs slice as root only if bootsign wasn't found 410753a6d45SSherry Moore * on other slices. 411753a6d45SSherry Moore * That function first searches through all top datasets of active zpools, 412753a6d45SSherry Moore * then if bootsign still not found walks through all disks and tries to 413753a6d45SSherry Moore * find ufs slice with the bootsign. 414753a6d45SSherry Moore */ 415753a6d45SSherry Moore int 416753a6d45SSherry Moore grub_find_bootsign(grub_barg_t *barg) 417753a6d45SSherry Moore { 418753a6d45SSherry Moore grub_menu_t *mp; 419753a6d45SSherry Moore mp = barg->gb_entry->ge_menu; 420753a6d45SSherry Moore 421753a6d45SSherry Moore /* try to find bootsign over zfs pools */ 422753a6d45SSherry Moore barg->gb_walkret = EG_BOOTSIGN; 423753a6d45SSherry Moore (void) zfs_iter_root(mp->gm_fs.gf_lzfh, zfs_bootsign, barg); 424753a6d45SSherry Moore 425753a6d45SSherry Moore /* try ufs now */ 426753a6d45SSherry Moore if (barg->gb_walkret != 0 && di_walk_minor(mp->gm_fs.gf_diroot, 427753a6d45SSherry Moore DDI_NT_BLOCK, 0, barg, ufs_bootsign) != 0) 428753a6d45SSherry Moore return (errno); 429753a6d45SSherry Moore 430753a6d45SSherry Moore return (barg->gb_walkret); 431753a6d45SSherry Moore } 432753a6d45SSherry Moore 433753a6d45SSherry Moore /* 434753a6d45SSherry Moore * Get current root file system. 435753a6d45SSherry Moore * Return 0 on success, errno code on failure. 436753a6d45SSherry Moore */ 437753a6d45SSherry Moore int 438753a6d45SSherry Moore grub_current_root(grub_fs_t *fs, grub_root_t *root) 439753a6d45SSherry Moore { 440753a6d45SSherry Moore int rc = 0; 441753a6d45SSherry Moore FILE *fp = NULL; 442753a6d45SSherry Moore char *name = NULL; 443753a6d45SSherry Moore zfs_handle_t *zfh = NULL; 444753a6d45SSherry Moore struct mnttab mp = {0}; 445753a6d45SSherry Moore struct mnttab mpref = {0}; 446753a6d45SSherry Moore char buf[MAXNAMELEN] = {0}; 447753a6d45SSherry Moore 448753a6d45SSherry Moore mpref.mnt_mountp = "/"; 449753a6d45SSherry Moore 450753a6d45SSherry Moore if ((fp = fopen(MNTTAB, "r")) == NULL) 451753a6d45SSherry Moore return (errno); 452753a6d45SSherry Moore 453753a6d45SSherry Moore /* 454753a6d45SSherry Moore * getmntany returns non-zero for failure, and sets errno 455753a6d45SSherry Moore */ 456753a6d45SSherry Moore rc = getmntany(fp, &mp, &mpref); 457753a6d45SSherry Moore if (rc != 0) 458753a6d45SSherry Moore rc = errno; 459753a6d45SSherry Moore 460753a6d45SSherry Moore (void) fclose(fp); 461753a6d45SSherry Moore 462753a6d45SSherry Moore if (rc != 0) 463753a6d45SSherry Moore return (rc); 464753a6d45SSherry Moore 465753a6d45SSherry Moore (void) strlcpy(root->gr_fstyp, mp.mnt_fstype, sizeof (root->gr_fstyp)); 466753a6d45SSherry Moore 467753a6d45SSherry Moore if (strcmp(root->gr_fstyp, MNTTYPE_ZFS) == 0) { 468753a6d45SSherry Moore 469753a6d45SSherry Moore (void) strlcpy(buf, mp.mnt_special, sizeof (buf)); 470753a6d45SSherry Moore if ((name = strtok(buf, "/")) == NULL) 471753a6d45SSherry Moore return (EG_CURROOT); 472753a6d45SSherry Moore 473753a6d45SSherry Moore if ((zfh = zfs_open(fs->gf_lzfh, name, ZFS_TYPE_FILESYSTEM)) == 474753a6d45SSherry Moore NULL) 475753a6d45SSherry Moore return (EG_OPENZFS); 476753a6d45SSherry Moore 477753a6d45SSherry Moore /* 4788c7cfd88SSherry Moore * get_zfs_root returns non-zero on failure, not errno. 479753a6d45SSherry Moore */ 480753a6d45SSherry Moore if (get_zfs_root(zfh, fs, root)) 481753a6d45SSherry Moore rc = EG_CURROOT; 4828c7cfd88SSherry Moore else 4838c7cfd88SSherry Moore /* 4848c7cfd88SSherry Moore * For mirrored root physpath would contain the list of 4858c7cfd88SSherry Moore * all bootable devices, pick up the first one. 4868c7cfd88SSherry Moore */ 4878c7cfd88SSherry Moore rc = get_one_physpath(root->gr_physpath, SLCNUM_INVALID, 4888c7cfd88SSherry Moore PRTNUM_INVALID); 489753a6d45SSherry Moore 490753a6d45SSherry Moore zfs_close(zfh); 491753a6d45SSherry Moore 492753a6d45SSherry Moore } else if (strcmp(mp.mnt_fstype, MNTTYPE_UFS) == 0) { 493753a6d45SSherry Moore (void) strlcpy(root->gr_fs[GRBM_UFS].gfs_dev, mp.mnt_special, 494753a6d45SSherry Moore sizeof (root->gr_fs[GRBM_UFS].gfs_dev)); 495753a6d45SSherry Moore (void) strlcpy(root->gr_fs[GRBM_UFS].gfs_mountp, mp.mnt_mountp, 496753a6d45SSherry Moore sizeof (root->gr_fs[GRBM_UFS].gfs_mountp)); 497753a6d45SSherry Moore } else { 498753a6d45SSherry Moore rc = EG_UNKNOWNFS; 499753a6d45SSherry Moore } 500753a6d45SSherry Moore 501753a6d45SSherry Moore return (rc); 502753a6d45SSherry Moore } 503753a6d45SSherry Moore 504753a6d45SSherry Moore grub_fsdesc_t * 505753a6d45SSherry Moore grub_get_rootfsd(const grub_root_t *root) 506753a6d45SSherry Moore { 507753a6d45SSherry Moore grub_fsdesc_t *fsd = NULL; 508753a6d45SSherry Moore 509753a6d45SSherry Moore assert(root); 510753a6d45SSherry Moore if (strcmp(MNTTYPE_UFS, root->gr_fstyp) == 0) 511753a6d45SSherry Moore fsd = (grub_fsdesc_t *)root->gr_fs + GRBM_UFS; 512753a6d45SSherry Moore else if (strcmp(MNTTYPE_ZFS, root->gr_fstyp) == 0) 513753a6d45SSherry Moore fsd = (grub_fsdesc_t *)root->gr_fs + GRBM_ZFS_BOOTFS; 514753a6d45SSherry Moore 515753a6d45SSherry Moore return (fsd); 516753a6d45SSherry Moore } 517753a6d45SSherry Moore 518753a6d45SSherry Moore /* 519753a6d45SSherry Moore * Gets file systems mount point if any. 520753a6d45SSherry Moore * Return 0 if filesystem is mounted, errno on failure. 521753a6d45SSherry Moore */ 522753a6d45SSherry Moore int 523753a6d45SSherry Moore grub_fsd_get_mountp(grub_fsdesc_t *fsd, char *fstyp) 524753a6d45SSherry Moore { 525753a6d45SSherry Moore int rc; 526753a6d45SSherry Moore FILE *fp = NULL; 527753a6d45SSherry Moore struct mnttab mp = {0}; 528753a6d45SSherry Moore struct mnttab mpref = {0}; 529753a6d45SSherry Moore 530753a6d45SSherry Moore fsd->gfs_mountp[0] = 0; 531753a6d45SSherry Moore 532753a6d45SSherry Moore if ((fp = fopen(MNTTAB, "r")) == NULL) 533753a6d45SSherry Moore return (errno); 534753a6d45SSherry Moore 535753a6d45SSherry Moore mpref.mnt_special = fsd->gfs_dev; 536753a6d45SSherry Moore mpref.mnt_fstype = fstyp; 537753a6d45SSherry Moore 538753a6d45SSherry Moore if ((rc = getmntany(fp, &mp, &mpref)) == 0) 539753a6d45SSherry Moore (void) strlcpy(fsd->gfs_mountp, mp.mnt_mountp, 540753a6d45SSherry Moore sizeof (fsd->gfs_mountp)); 541753a6d45SSherry Moore else 542753a6d45SSherry Moore rc = EG_GETMNTTAB; 543753a6d45SSherry Moore 544753a6d45SSherry Moore (void) fclose(fp); 545753a6d45SSherry Moore return (rc); 546753a6d45SSherry Moore } 547753a6d45SSherry Moore 548753a6d45SSherry Moore static const char tmp_mountp[] = "/tmp/.libgrubmgmt.%s.XXXXXX"; 549753a6d45SSherry Moore 550753a6d45SSherry Moore /* 551753a6d45SSherry Moore * Mount file system at tmp_mountp. 552753a6d45SSherry Moore * Return 0 on success, errno on failure. 553753a6d45SSherry Moore */ 554753a6d45SSherry Moore int 555753a6d45SSherry Moore grub_fsd_mount_tmp(grub_fsdesc_t *fsd, const char *fstyp) 556753a6d45SSherry Moore { 557753a6d45SSherry Moore const char *pos; 558753a6d45SSherry Moore void *data = NULL; 559753a6d45SSherry Moore int dtsz = 0; 560753a6d45SSherry Moore struct ufs_args ufs_args = {UFSMNT_LARGEFILES}; 561753a6d45SSherry Moore char mntopts[MNT_LINE_MAX] = ""; 562753a6d45SSherry Moore int rc = 0; 563753a6d45SSherry Moore 564753a6d45SSherry Moore assert(fsd); 565753a6d45SSherry Moore assert(!fsd->gfs_is_tmp_mounted); 566753a6d45SSherry Moore 567753a6d45SSherry Moore fsd->gfs_mountp[0] = 0; 568753a6d45SSherry Moore 569753a6d45SSherry Moore if (strcmp(fstyp, MNTTYPE_UFS) == 0) { 570753a6d45SSherry Moore (void) strlcpy(mntopts, MNTOPT_LARGEFILES, sizeof (mntopts)); 571753a6d45SSherry Moore data = &ufs_args; 572753a6d45SSherry Moore dtsz = sizeof (ufs_args); 573753a6d45SSherry Moore } else if (strcmp(fstyp, MNTTYPE_ZFS) != 0) { 574753a6d45SSherry Moore return (EG_UNKNOWNFS); 575753a6d45SSherry Moore } 576753a6d45SSherry Moore 577753a6d45SSherry Moore /* construct name for temporary mount point */ 578753a6d45SSherry Moore pos = strrchr(fsd->gfs_dev, '/'); 579753a6d45SSherry Moore pos = (pos == NULL) ? fsd->gfs_dev : pos + 1; 580753a6d45SSherry Moore 581753a6d45SSherry Moore (void) snprintf(fsd->gfs_mountp, sizeof (fsd->gfs_mountp), 582753a6d45SSherry Moore tmp_mountp, pos); 583753a6d45SSherry Moore if (mkdtemp(fsd->gfs_mountp) != NULL) { 584753a6d45SSherry Moore if ((rc = mount(fsd->gfs_dev, fsd->gfs_mountp, 585753a6d45SSherry Moore MS_DATA | MS_OPTIONSTR | MS_RDONLY, 586753a6d45SSherry Moore fstyp, data, dtsz, mntopts, sizeof (mntopts))) != 0) { 587753a6d45SSherry Moore /* 588753a6d45SSherry Moore * mount failed, collect errno and remove temp dir 589753a6d45SSherry Moore */ 590753a6d45SSherry Moore rc = errno; 591753a6d45SSherry Moore (void) rmdir(fsd->gfs_mountp); 592753a6d45SSherry Moore } 593753a6d45SSherry Moore } else { 594753a6d45SSherry Moore rc = errno; 595753a6d45SSherry Moore } 596753a6d45SSherry Moore 597753a6d45SSherry Moore if (rc != 0) 598753a6d45SSherry Moore fsd->gfs_mountp[0] = 0; 599753a6d45SSherry Moore 600753a6d45SSherry Moore /* 601753a6d45SSherry Moore * Note that valid values for gfs_is_tmp_mounted are 0,1. 602753a6d45SSherry Moore * Any other value indicates that something bad happened. 603753a6d45SSherry Moore * Probably grub_fsd_umount_tmp() wasn't called or didn't 604753a6d45SSherry Moore * work as expected. 605753a6d45SSherry Moore */ 606753a6d45SSherry Moore fsd->gfs_is_tmp_mounted += (rc == 0); 607753a6d45SSherry Moore return (rc); 608753a6d45SSherry Moore } 609753a6d45SSherry Moore 610753a6d45SSherry Moore /* 611753a6d45SSherry Moore * Unmount file system at tmp_mountp. 612753a6d45SSherry Moore */ 613753a6d45SSherry Moore void 614753a6d45SSherry Moore grub_fsd_umount_tmp(grub_fsdesc_t *fsd) 615753a6d45SSherry Moore { 616753a6d45SSherry Moore if (fsd == NULL) 617753a6d45SSherry Moore return; 618753a6d45SSherry Moore 619753a6d45SSherry Moore if (fsd->gfs_is_tmp_mounted) { 620753a6d45SSherry Moore if (fsd->gfs_mountp[0] != 0) { 621753a6d45SSherry Moore (void) umount2(fsd->gfs_mountp, 0); 622753a6d45SSherry Moore (void) rmdir(fsd->gfs_mountp); 623753a6d45SSherry Moore fsd->gfs_mountp[0] = 0; 624753a6d45SSherry Moore } 625753a6d45SSherry Moore fsd->gfs_is_tmp_mounted = 0; 626753a6d45SSherry Moore } 627753a6d45SSherry Moore } 628