19160SSherry.Moore@Sun.COM /* 29160SSherry.Moore@Sun.COM * CDDL HEADER START 39160SSherry.Moore@Sun.COM * 49160SSherry.Moore@Sun.COM * The contents of this file are subject to the terms of the 59160SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License"). 69160SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License. 79160SSherry.Moore@Sun.COM * 89160SSherry.Moore@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 99160SSherry.Moore@Sun.COM * or http://www.opensolaris.org/os/licensing. 109160SSherry.Moore@Sun.COM * See the License for the specific language governing permissions 119160SSherry.Moore@Sun.COM * and limitations under the License. 129160SSherry.Moore@Sun.COM * 139160SSherry.Moore@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 149160SSherry.Moore@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 159160SSherry.Moore@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 169160SSherry.Moore@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 179160SSherry.Moore@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 189160SSherry.Moore@Sun.COM * 199160SSherry.Moore@Sun.COM * CDDL HEADER END 209160SSherry.Moore@Sun.COM */ 219160SSherry.Moore@Sun.COM /* 229160SSherry.Moore@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 239160SSherry.Moore@Sun.COM * Use is subject to license terms. 249160SSherry.Moore@Sun.COM */ 259160SSherry.Moore@Sun.COM 269160SSherry.Moore@Sun.COM /* 279160SSherry.Moore@Sun.COM * This file contains all the functions that manipualte the file 289160SSherry.Moore@Sun.COM * system where the GRUB menu resides. 299160SSherry.Moore@Sun.COM */ 309160SSherry.Moore@Sun.COM #include <stdio.h> 319160SSherry.Moore@Sun.COM #include <errno.h> 329160SSherry.Moore@Sun.COM #include <stdlib.h> 339160SSherry.Moore@Sun.COM #include <strings.h> 349160SSherry.Moore@Sun.COM #include <unistd.h> 359160SSherry.Moore@Sun.COM #include <fcntl.h> 369160SSherry.Moore@Sun.COM #include <assert.h> 379160SSherry.Moore@Sun.COM #include <sys/types.h> 389160SSherry.Moore@Sun.COM #include <sys/stat.h> 399160SSherry.Moore@Sun.COM #include <sys/mount.h> 409160SSherry.Moore@Sun.COM #include <sys/mntent.h> 419160SSherry.Moore@Sun.COM #include <sys/mnttab.h> 429160SSherry.Moore@Sun.COM #include <sys/fs/ufs_mount.h> 439160SSherry.Moore@Sun.COM #include <sys/dktp/fdisk.h> 449160SSherry.Moore@Sun.COM #include <libfstyp.h> 459160SSherry.Moore@Sun.COM 469160SSherry.Moore@Sun.COM #include "libgrub_impl.h" 479160SSherry.Moore@Sun.COM 489160SSherry.Moore@Sun.COM static int 499160SSherry.Moore@Sun.COM slice_match(const char *physpath, int slice) 509160SSherry.Moore@Sun.COM { 519160SSherry.Moore@Sun.COM const char *pos; 529160SSherry.Moore@Sun.COM 539160SSherry.Moore@Sun.COM return ((pos = strrchr(physpath, slice)) == NULL || 549160SSherry.Moore@Sun.COM pos[1] != 0 || pos[-1] != ':'); 559160SSherry.Moore@Sun.COM } 569160SSherry.Moore@Sun.COM 579160SSherry.Moore@Sun.COM /* 589160SSherry.Moore@Sun.COM * Returns zero if path contains ufs 599160SSherry.Moore@Sun.COM */ 609160SSherry.Moore@Sun.COM static int 619160SSherry.Moore@Sun.COM slice_ufs(const char *path) 629160SSherry.Moore@Sun.COM { 639160SSherry.Moore@Sun.COM int fd, ret; 649160SSherry.Moore@Sun.COM const char *id; 659160SSherry.Moore@Sun.COM fstyp_handle_t hdl; 669160SSherry.Moore@Sun.COM 679160SSherry.Moore@Sun.COM fd = open(path, O_RDONLY); 689160SSherry.Moore@Sun.COM if ((ret = fstyp_init(fd, 0, NULL, &hdl)) == 0) { 699160SSherry.Moore@Sun.COM ret = fstyp_ident(hdl, "ufs", &id); 709160SSherry.Moore@Sun.COM fstyp_fini(hdl); 719160SSherry.Moore@Sun.COM } 729160SSherry.Moore@Sun.COM (void) close(fd); 739160SSherry.Moore@Sun.COM return (ret); 749160SSherry.Moore@Sun.COM } 759160SSherry.Moore@Sun.COM 769160SSherry.Moore@Sun.COM 779160SSherry.Moore@Sun.COM static int 789160SSherry.Moore@Sun.COM get_sol_prtnum(const char *physpath) 799160SSherry.Moore@Sun.COM { 809160SSherry.Moore@Sun.COM int i, fd; 819160SSherry.Moore@Sun.COM char *pos; 829160SSherry.Moore@Sun.COM size_t sz; 839160SSherry.Moore@Sun.COM struct mboot *mb; 849160SSherry.Moore@Sun.COM struct ipart *ipart; 859160SSherry.Moore@Sun.COM char boot_sect[512]; 869160SSherry.Moore@Sun.COM char rdev[MAXNAMELEN]; 879160SSherry.Moore@Sun.COM 889160SSherry.Moore@Sun.COM (void) snprintf(rdev, sizeof (rdev), "/devices%s,raw", physpath); 899160SSherry.Moore@Sun.COM 909160SSherry.Moore@Sun.COM if ((pos = strrchr(rdev, ':')) == NULL) 919160SSherry.Moore@Sun.COM return (PRTNUM_INVALID); 929160SSherry.Moore@Sun.COM 939160SSherry.Moore@Sun.COM pos[1] = SLCNUM_WHOLE_DISK; 949160SSherry.Moore@Sun.COM 959160SSherry.Moore@Sun.COM fd = open(rdev, O_RDONLY); 969160SSherry.Moore@Sun.COM sz = read(fd, boot_sect, sizeof (boot_sect)); 979160SSherry.Moore@Sun.COM (void) close(fd); 989160SSherry.Moore@Sun.COM 999160SSherry.Moore@Sun.COM if (sz != sizeof (boot_sect)) 1009160SSherry.Moore@Sun.COM return (PRTNUM_INVALID); 1019160SSherry.Moore@Sun.COM 1029160SSherry.Moore@Sun.COM /* parse fdisk table */ 1039160SSherry.Moore@Sun.COM mb = (struct mboot *)(uintptr_t)boot_sect; 1049160SSherry.Moore@Sun.COM ipart = (struct ipart *)(uintptr_t)mb->parts; 1059160SSherry.Moore@Sun.COM for (i = 0; i < FD_NUMPART; ++i) { 1069160SSherry.Moore@Sun.COM if (ipart[i].systid == SUNIXOS || ipart[i].systid == SUNIXOS2) 1079160SSherry.Moore@Sun.COM return (i); 1089160SSherry.Moore@Sun.COM } 1099160SSherry.Moore@Sun.COM return (PRTNUM_INVALID); 1109160SSherry.Moore@Sun.COM } 1119160SSherry.Moore@Sun.COM 1129160SSherry.Moore@Sun.COM /* 1139160SSherry.Moore@Sun.COM * Get physpath, topfs and bootfs for ZFS root dataset. 1149160SSherry.Moore@Sun.COM * Return 0 on success, non-zero (not errno) on failure. 1159160SSherry.Moore@Sun.COM */ 1169160SSherry.Moore@Sun.COM static int 1179160SSherry.Moore@Sun.COM get_zfs_root(zfs_handle_t *zfh, grub_fs_t *fs, grub_root_t *root) 1189160SSherry.Moore@Sun.COM { 1199160SSherry.Moore@Sun.COM int ret; 1209160SSherry.Moore@Sun.COM zpool_handle_t *zph; 1219160SSherry.Moore@Sun.COM const char *name; 1229160SSherry.Moore@Sun.COM 1239160SSherry.Moore@Sun.COM if (zfs_get_type(zfh) != ZFS_TYPE_FILESYSTEM || 1249160SSherry.Moore@Sun.COM (name = zfs_get_name(zfh)) == NULL || 1259160SSherry.Moore@Sun.COM (zph = zpool_open(fs->gf_lzfh, name)) == NULL) 1269160SSherry.Moore@Sun.COM return (-1); 1279160SSherry.Moore@Sun.COM 1289160SSherry.Moore@Sun.COM if ((ret = zpool_get_physpath(zph, root->gr_physpath, 1299160SSherry.Moore@Sun.COM sizeof (root->gr_physpath))) == 0 && 1309160SSherry.Moore@Sun.COM (ret = zpool_get_prop(zph, ZPOOL_PROP_BOOTFS, 1319160SSherry.Moore@Sun.COM root->gr_fs[GRBM_ZFS_BOOTFS].gfs_dev, 1329160SSherry.Moore@Sun.COM sizeof (root->gr_fs[GRBM_ZFS_BOOTFS].gfs_dev), NULL)) == 0) { 1339160SSherry.Moore@Sun.COM 1349160SSherry.Moore@Sun.COM (void) strlcpy(root->gr_fs[GRBM_ZFS_TOPFS].gfs_dev, name, 1359160SSherry.Moore@Sun.COM sizeof (root->gr_fs[GRBM_ZFS_TOPFS].gfs_dev)); 1369160SSherry.Moore@Sun.COM (void) grub_fsd_get_mountp(root->gr_fs + GRBM_ZFS_BOOTFS, 1379160SSherry.Moore@Sun.COM MNTTYPE_ZFS); 1389160SSherry.Moore@Sun.COM (void) grub_fsd_get_mountp(root->gr_fs + GRBM_ZFS_TOPFS, 1399160SSherry.Moore@Sun.COM MNTTYPE_ZFS); 1409160SSherry.Moore@Sun.COM } 1419160SSherry.Moore@Sun.COM 1429160SSherry.Moore@Sun.COM zpool_close(zph); 1439160SSherry.Moore@Sun.COM return (ret); 1449160SSherry.Moore@Sun.COM } 1459160SSherry.Moore@Sun.COM 1469160SSherry.Moore@Sun.COM /* 1479160SSherry.Moore@Sun.COM * On entry physpath parameter supposed to contain: 1489160SSherry.Moore@Sun.COM * <disk_physpath>[<space><disk_physpath>]*. 1499160SSherry.Moore@Sun.COM * Retireives first <disk_physpath> that matches both partition and slice. 1509160SSherry.Moore@Sun.COM * If any partition and slice is acceptable, first <disk_physpath> is returned. 1519160SSherry.Moore@Sun.COM */ 1529160SSherry.Moore@Sun.COM static int 1539160SSherry.Moore@Sun.COM get_one_physpath(char *physpath, uint_t prtnum, uint_t slcnum) 1549160SSherry.Moore@Sun.COM { 1559160SSherry.Moore@Sun.COM int ret; 1569160SSherry.Moore@Sun.COM char *tmp, *tok; 1579160SSherry.Moore@Sun.COM 1589160SSherry.Moore@Sun.COM if (!IS_SLCNUM_VALID(slcnum) && !IS_PRTNUM_VALID(prtnum)) { 1599160SSherry.Moore@Sun.COM (void) strtok(physpath, " "); 1609160SSherry.Moore@Sun.COM return (0); 1619160SSherry.Moore@Sun.COM } 1629160SSherry.Moore@Sun.COM 1639160SSherry.Moore@Sun.COM if ((tmp = strdup(physpath)) == NULL) 1649160SSherry.Moore@Sun.COM return (errno); 1659160SSherry.Moore@Sun.COM 1669160SSherry.Moore@Sun.COM ret = ENODEV; 1679160SSherry.Moore@Sun.COM for (tok = strtok(tmp, " "); tok != NULL; tok = strtok(NULL, " ")) { 1689160SSherry.Moore@Sun.COM if ((ret = (slice_match(tok, slcnum) != 0 || 1699160SSherry.Moore@Sun.COM get_sol_prtnum(tok) != prtnum)) == 0) { 1709160SSherry.Moore@Sun.COM (void) strcpy(physpath, tok); 1719160SSherry.Moore@Sun.COM break; 1729160SSherry.Moore@Sun.COM } 1739160SSherry.Moore@Sun.COM } 1749160SSherry.Moore@Sun.COM 1759160SSherry.Moore@Sun.COM free(tmp); 176*9996SSherry.Moore@Sun.COM if (ret) 177*9996SSherry.Moore@Sun.COM ret = ENODEV; 1789160SSherry.Moore@Sun.COM return (ret); 1799160SSherry.Moore@Sun.COM } 1809160SSherry.Moore@Sun.COM 1819160SSherry.Moore@Sun.COM static int 1829160SSherry.Moore@Sun.COM zfs_bootsign(zfs_handle_t *zfh, void *data) 1839160SSherry.Moore@Sun.COM { 1849160SSherry.Moore@Sun.COM grub_barg_t *barg; 1859160SSherry.Moore@Sun.COM grub_menu_t *menu; 1869160SSherry.Moore@Sun.COM struct stat st; 1879160SSherry.Moore@Sun.COM char path[MAXPATHLEN]; 1889160SSherry.Moore@Sun.COM 1899160SSherry.Moore@Sun.COM barg = (grub_barg_t *)data; 1909160SSherry.Moore@Sun.COM menu = barg->gb_entry->ge_menu; 1919160SSherry.Moore@Sun.COM 1929160SSherry.Moore@Sun.COM do { 1939160SSherry.Moore@Sun.COM if (get_zfs_root(zfh, &menu->gm_fs, &barg->gb_root) != 0 || 1949160SSherry.Moore@Sun.COM get_one_physpath(barg->gb_root.gr_physpath, barg->gb_prtnum, 1959160SSherry.Moore@Sun.COM barg->gb_slcnum) != 0) 1969160SSherry.Moore@Sun.COM break; 1979160SSherry.Moore@Sun.COM 1989160SSherry.Moore@Sun.COM /* 1999160SSherry.Moore@Sun.COM * if top zfs dataset is not mounted, mount it now 2009160SSherry.Moore@Sun.COM */ 2019160SSherry.Moore@Sun.COM if (barg->gb_root.gr_fs[GRBM_ZFS_TOPFS].gfs_mountp[0] == 0) { 2029160SSherry.Moore@Sun.COM if (grub_fsd_mount_tmp(barg->gb_root.gr_fs + 2039160SSherry.Moore@Sun.COM GRBM_ZFS_TOPFS, MNTTYPE_ZFS) != 0) 2049160SSherry.Moore@Sun.COM break; 2059160SSherry.Moore@Sun.COM } 2069160SSherry.Moore@Sun.COM 2079160SSherry.Moore@Sun.COM /* check that bootsign exists and it is a regular file */ 2089160SSherry.Moore@Sun.COM (void) snprintf(path, sizeof (path), "%s%s", 2099160SSherry.Moore@Sun.COM barg->gb_root.gr_fs[GRBM_ZFS_TOPFS].gfs_mountp, 2109160SSherry.Moore@Sun.COM barg->gb_bootsign); 2119160SSherry.Moore@Sun.COM 2129160SSherry.Moore@Sun.COM if (lstat(path, &st) != 0 || S_ISREG(st.st_mode) == 0 || 2139160SSherry.Moore@Sun.COM (st.st_mode & S_IRUSR) == 0) 2149160SSherry.Moore@Sun.COM break; 2159160SSherry.Moore@Sun.COM 2169160SSherry.Moore@Sun.COM (void) strlcpy(barg->gb_root.gr_fstyp, MNTTYPE_ZFS, 2179160SSherry.Moore@Sun.COM sizeof (barg->gb_root.gr_fstyp)); 2189160SSherry.Moore@Sun.COM barg->gb_walkret = 0; 2199160SSherry.Moore@Sun.COM /* LINTED: E_CONSTANT_CONDITION */ 2209160SSherry.Moore@Sun.COM } while (0); 2219160SSherry.Moore@Sun.COM 2229160SSherry.Moore@Sun.COM grub_fsd_umount_tmp(barg->gb_root.gr_fs + GRBM_ZFS_TOPFS); 2239160SSherry.Moore@Sun.COM zfs_close(zfh); 2249160SSherry.Moore@Sun.COM 2259160SSherry.Moore@Sun.COM /* return non-zero to terminate the walk */ 2269160SSherry.Moore@Sun.COM return (barg->gb_walkret == 0); 2279160SSherry.Moore@Sun.COM } 2289160SSherry.Moore@Sun.COM 2299160SSherry.Moore@Sun.COM static int 2309160SSherry.Moore@Sun.COM get_devlink(di_devlink_t dl, void *arg) 2319160SSherry.Moore@Sun.COM { 2329160SSherry.Moore@Sun.COM const char *path; 2339160SSherry.Moore@Sun.COM grub_barg_t *barg; 2349160SSherry.Moore@Sun.COM 2359160SSherry.Moore@Sun.COM barg = (grub_barg_t *)arg; 2369160SSherry.Moore@Sun.COM if ((path = di_devlink_path(dl)) != NULL) 2379160SSherry.Moore@Sun.COM (void) strlcpy(barg->gb_root.gr_fs[GRBM_UFS].gfs_dev, path, 2389160SSherry.Moore@Sun.COM sizeof (barg->gb_root.gr_fs[GRBM_UFS].gfs_dev)); 2399160SSherry.Moore@Sun.COM return (DI_WALK_TERMINATE); 2409160SSherry.Moore@Sun.COM } 2419160SSherry.Moore@Sun.COM 2429160SSherry.Moore@Sun.COM static int 2439160SSherry.Moore@Sun.COM ufs_bootsign_check(grub_barg_t *barg) 2449160SSherry.Moore@Sun.COM { 2459160SSherry.Moore@Sun.COM int ret; 2469160SSherry.Moore@Sun.COM struct stat st; 2479160SSherry.Moore@Sun.COM grub_menu_t *mp; 2489160SSherry.Moore@Sun.COM char path[MAXPATHLEN]; 2499160SSherry.Moore@Sun.COM 2509160SSherry.Moore@Sun.COM mp = barg->gb_entry->ge_menu; 2519160SSherry.Moore@Sun.COM 2529160SSherry.Moore@Sun.COM /* get /dev/dsk link */ 2539160SSherry.Moore@Sun.COM if (di_devlink_walk(mp->gm_fs.gf_dvlh, "^dsk/", 2549160SSherry.Moore@Sun.COM barg->gb_root.gr_physpath, DI_PRIMARY_LINK, barg, get_devlink) != 0) 2559160SSherry.Moore@Sun.COM return (errno); 2569160SSherry.Moore@Sun.COM /* 2579160SSherry.Moore@Sun.COM * if disk is not mounted, mount it now 2589160SSherry.Moore@Sun.COM */ 2599160SSherry.Moore@Sun.COM if (grub_fsd_get_mountp(barg->gb_root.gr_fs + GRBM_UFS, 2609160SSherry.Moore@Sun.COM MNTTYPE_UFS) != 0) { 2619160SSherry.Moore@Sun.COM if ((ret = 2629160SSherry.Moore@Sun.COM slice_ufs(barg->gb_root.gr_fs[GRBM_UFS].gfs_dev)) != 0 || 2639160SSherry.Moore@Sun.COM (ret = grub_fsd_mount_tmp(barg->gb_root.gr_fs + GRBM_UFS, 2649160SSherry.Moore@Sun.COM MNTTYPE_UFS)) != 0) 2659160SSherry.Moore@Sun.COM return (ret); 2669160SSherry.Moore@Sun.COM } 2679160SSherry.Moore@Sun.COM 2689160SSherry.Moore@Sun.COM (void) snprintf(path, sizeof (path), "%s%s", 2699160SSherry.Moore@Sun.COM barg->gb_root.gr_fs[GRBM_UFS].gfs_mountp, barg->gb_bootsign); 2709160SSherry.Moore@Sun.COM 2719160SSherry.Moore@Sun.COM if (lstat(path, &st) == 0 && S_ISREG(st.st_mode) && 2729160SSherry.Moore@Sun.COM (st.st_mode & S_IRUSR) != 0) { 2739160SSherry.Moore@Sun.COM barg->gb_walkret = 0; 2749160SSherry.Moore@Sun.COM (void) strlcpy(barg->gb_root.gr_fstyp, MNTTYPE_UFS, 2759160SSherry.Moore@Sun.COM sizeof (barg->gb_root.gr_fstyp)); 2769160SSherry.Moore@Sun.COM } 2779160SSherry.Moore@Sun.COM 2789160SSherry.Moore@Sun.COM grub_fsd_umount_tmp(barg->gb_root.gr_fs + GRBM_UFS); 2799160SSherry.Moore@Sun.COM return (barg->gb_walkret); 2809160SSherry.Moore@Sun.COM } 2819160SSherry.Moore@Sun.COM 2829160SSherry.Moore@Sun.COM static int 2839160SSherry.Moore@Sun.COM ufs_bootsign(di_node_t node, di_minor_t minor, void *arg) 2849160SSherry.Moore@Sun.COM { 2859160SSherry.Moore@Sun.COM uint_t prtnum; 2869160SSherry.Moore@Sun.COM char *name, *path; 2879160SSherry.Moore@Sun.COM grub_barg_t *barg; 2889160SSherry.Moore@Sun.COM 2899160SSherry.Moore@Sun.COM barg = (grub_barg_t *)arg; 2909160SSherry.Moore@Sun.COM 2919160SSherry.Moore@Sun.COM if (di_minor_spectype(minor) != S_IFBLK) 2929160SSherry.Moore@Sun.COM return (DI_WALK_CONTINUE); 2939160SSherry.Moore@Sun.COM 2949160SSherry.Moore@Sun.COM name = di_minor_name(minor); 2959160SSherry.Moore@Sun.COM if (name[0] != barg->gb_slcnum || name[1] != 0) 2969160SSherry.Moore@Sun.COM return (DI_WALK_CONTINUE); 2979160SSherry.Moore@Sun.COM 2989160SSherry.Moore@Sun.COM path = di_devfs_path(node); 2999160SSherry.Moore@Sun.COM (void) snprintf(barg->gb_root.gr_physpath, 3009160SSherry.Moore@Sun.COM sizeof (barg->gb_root.gr_physpath), "%s:%c", path, barg->gb_slcnum); 3019160SSherry.Moore@Sun.COM di_devfs_path_free(path); 3029160SSherry.Moore@Sun.COM 3039160SSherry.Moore@Sun.COM prtnum = get_sol_prtnum(barg->gb_root.gr_physpath); 3049160SSherry.Moore@Sun.COM if (!IS_PRTNUM_VALID(prtnum)) 3059160SSherry.Moore@Sun.COM return (DI_WALK_CONTINUE); 3069160SSherry.Moore@Sun.COM 3079160SSherry.Moore@Sun.COM /* 3089160SSherry.Moore@Sun.COM * check only specified partition, slice 3099160SSherry.Moore@Sun.COM */ 3109160SSherry.Moore@Sun.COM 3119160SSherry.Moore@Sun.COM if (IS_PRTNUM_VALID(barg->gb_prtnum)) { 3129160SSherry.Moore@Sun.COM if (prtnum != barg->gb_prtnum || ufs_bootsign_check(barg) != 0) 3139160SSherry.Moore@Sun.COM return (DI_WALK_CONTINUE); 3149160SSherry.Moore@Sun.COM return (DI_WALK_TERMINATE); 3159160SSherry.Moore@Sun.COM } 3169160SSherry.Moore@Sun.COM 3179160SSherry.Moore@Sun.COM /* 3189160SSherry.Moore@Sun.COM * Walk through all slices in found solaris partition 3199160SSherry.Moore@Sun.COM */ 3209160SSherry.Moore@Sun.COM 3219160SSherry.Moore@Sun.COM barg->gb_prtnum = prtnum; 3229160SSherry.Moore@Sun.COM minor = DI_MINOR_NIL; 3239160SSherry.Moore@Sun.COM 3249160SSherry.Moore@Sun.COM while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 3259160SSherry.Moore@Sun.COM 3269160SSherry.Moore@Sun.COM if (di_minor_spectype(minor) != S_IFBLK) 3279160SSherry.Moore@Sun.COM continue; 3289160SSherry.Moore@Sun.COM 3299160SSherry.Moore@Sun.COM name = di_minor_name(minor); 3309160SSherry.Moore@Sun.COM if (!IS_SLCNUM_VALID(name[0]) || name[1] != 0) 3319160SSherry.Moore@Sun.COM continue; 3329160SSherry.Moore@Sun.COM 3339160SSherry.Moore@Sun.COM barg->gb_slcnum = name[0]; 3349160SSherry.Moore@Sun.COM path = strrchr(barg->gb_root.gr_physpath, ':'); 3359160SSherry.Moore@Sun.COM path[1] = barg->gb_slcnum; 3369160SSherry.Moore@Sun.COM 3379160SSherry.Moore@Sun.COM if (ufs_bootsign_check(barg) == 0) 3389160SSherry.Moore@Sun.COM return (DI_WALK_TERMINATE); 3399160SSherry.Moore@Sun.COM } 3409160SSherry.Moore@Sun.COM 3419160SSherry.Moore@Sun.COM barg->gb_prtnum = (uint_t)PRTNUM_INVALID; 3429160SSherry.Moore@Sun.COM barg->gb_slcnum = (uint_t)SLCNUM_WHOLE_DISK; 3439160SSherry.Moore@Sun.COM return (DI_WALK_CONTINUE); 3449160SSherry.Moore@Sun.COM } 3459160SSherry.Moore@Sun.COM 3469160SSherry.Moore@Sun.COM /* 3479160SSherry.Moore@Sun.COM * Differs from what GRUB is doing: GRUB searchs through all disks seen by bios 3489160SSherry.Moore@Sun.COM * for bootsign, if bootsign is found on ufs slice GRUB sets it as a root, 3499160SSherry.Moore@Sun.COM * if on zfs, then GRUB uses zfs slice as root only if bootsign wasn't found 3509160SSherry.Moore@Sun.COM * on other slices. 3519160SSherry.Moore@Sun.COM * That function first searches through all top datasets of active zpools, 3529160SSherry.Moore@Sun.COM * then if bootsign still not found walks through all disks and tries to 3539160SSherry.Moore@Sun.COM * find ufs slice with the bootsign. 3549160SSherry.Moore@Sun.COM */ 3559160SSherry.Moore@Sun.COM int 3569160SSherry.Moore@Sun.COM grub_find_bootsign(grub_barg_t *barg) 3579160SSherry.Moore@Sun.COM { 3589160SSherry.Moore@Sun.COM grub_menu_t *mp; 3599160SSherry.Moore@Sun.COM mp = barg->gb_entry->ge_menu; 3609160SSherry.Moore@Sun.COM 3619160SSherry.Moore@Sun.COM /* try to find bootsign over zfs pools */ 3629160SSherry.Moore@Sun.COM barg->gb_walkret = EG_BOOTSIGN; 3639160SSherry.Moore@Sun.COM (void) zfs_iter_root(mp->gm_fs.gf_lzfh, zfs_bootsign, barg); 3649160SSherry.Moore@Sun.COM 3659160SSherry.Moore@Sun.COM /* try ufs now */ 3669160SSherry.Moore@Sun.COM if (barg->gb_walkret != 0 && di_walk_minor(mp->gm_fs.gf_diroot, 3679160SSherry.Moore@Sun.COM DDI_NT_BLOCK, 0, barg, ufs_bootsign) != 0) 3689160SSherry.Moore@Sun.COM return (errno); 3699160SSherry.Moore@Sun.COM 3709160SSherry.Moore@Sun.COM return (barg->gb_walkret); 3719160SSherry.Moore@Sun.COM } 3729160SSherry.Moore@Sun.COM 3739160SSherry.Moore@Sun.COM /* 3749160SSherry.Moore@Sun.COM * Get current root file system. 3759160SSherry.Moore@Sun.COM * Return 0 on success, errno code on failure. 3769160SSherry.Moore@Sun.COM */ 3779160SSherry.Moore@Sun.COM int 3789160SSherry.Moore@Sun.COM grub_current_root(grub_fs_t *fs, grub_root_t *root) 3799160SSherry.Moore@Sun.COM { 3809160SSherry.Moore@Sun.COM int rc = 0; 3819160SSherry.Moore@Sun.COM FILE *fp = NULL; 3829160SSherry.Moore@Sun.COM char *name = NULL; 3839160SSherry.Moore@Sun.COM zfs_handle_t *zfh = NULL; 3849160SSherry.Moore@Sun.COM struct mnttab mp = {0}; 3859160SSherry.Moore@Sun.COM struct mnttab mpref = {0}; 3869160SSherry.Moore@Sun.COM char buf[MAXNAMELEN] = {0}; 3879160SSherry.Moore@Sun.COM 3889160SSherry.Moore@Sun.COM mpref.mnt_mountp = "/"; 3899160SSherry.Moore@Sun.COM 3909160SSherry.Moore@Sun.COM if ((fp = fopen(MNTTAB, "r")) == NULL) 3919160SSherry.Moore@Sun.COM return (errno); 3929160SSherry.Moore@Sun.COM 3939160SSherry.Moore@Sun.COM /* 3949160SSherry.Moore@Sun.COM * getmntany returns non-zero for failure, and sets errno 3959160SSherry.Moore@Sun.COM */ 3969160SSherry.Moore@Sun.COM rc = getmntany(fp, &mp, &mpref); 3979160SSherry.Moore@Sun.COM if (rc != 0) 3989160SSherry.Moore@Sun.COM rc = errno; 3999160SSherry.Moore@Sun.COM 4009160SSherry.Moore@Sun.COM (void) fclose(fp); 4019160SSherry.Moore@Sun.COM 4029160SSherry.Moore@Sun.COM if (rc != 0) 4039160SSherry.Moore@Sun.COM return (rc); 4049160SSherry.Moore@Sun.COM 4059160SSherry.Moore@Sun.COM (void) strlcpy(root->gr_fstyp, mp.mnt_fstype, sizeof (root->gr_fstyp)); 4069160SSherry.Moore@Sun.COM 4079160SSherry.Moore@Sun.COM if (strcmp(root->gr_fstyp, MNTTYPE_ZFS) == 0) { 4089160SSherry.Moore@Sun.COM 4099160SSherry.Moore@Sun.COM (void) strlcpy(buf, mp.mnt_special, sizeof (buf)); 4109160SSherry.Moore@Sun.COM if ((name = strtok(buf, "/")) == NULL) 4119160SSherry.Moore@Sun.COM return (EG_CURROOT); 4129160SSherry.Moore@Sun.COM 4139160SSherry.Moore@Sun.COM if ((zfh = zfs_open(fs->gf_lzfh, name, ZFS_TYPE_FILESYSTEM)) == 4149160SSherry.Moore@Sun.COM NULL) 4159160SSherry.Moore@Sun.COM return (EG_OPENZFS); 4169160SSherry.Moore@Sun.COM 4179160SSherry.Moore@Sun.COM /* 418*9996SSherry.Moore@Sun.COM * get_zfs_root returns non-zero on failure, not errno. 4199160SSherry.Moore@Sun.COM */ 4209160SSherry.Moore@Sun.COM if (get_zfs_root(zfh, fs, root)) 4219160SSherry.Moore@Sun.COM rc = EG_CURROOT; 422*9996SSherry.Moore@Sun.COM else 423*9996SSherry.Moore@Sun.COM /* 424*9996SSherry.Moore@Sun.COM * For mirrored root physpath would contain the list of 425*9996SSherry.Moore@Sun.COM * all bootable devices, pick up the first one. 426*9996SSherry.Moore@Sun.COM */ 427*9996SSherry.Moore@Sun.COM rc = get_one_physpath(root->gr_physpath, SLCNUM_INVALID, 428*9996SSherry.Moore@Sun.COM PRTNUM_INVALID); 4299160SSherry.Moore@Sun.COM 4309160SSherry.Moore@Sun.COM zfs_close(zfh); 4319160SSherry.Moore@Sun.COM 4329160SSherry.Moore@Sun.COM } else if (strcmp(mp.mnt_fstype, MNTTYPE_UFS) == 0) { 4339160SSherry.Moore@Sun.COM (void) strlcpy(root->gr_fs[GRBM_UFS].gfs_dev, mp.mnt_special, 4349160SSherry.Moore@Sun.COM sizeof (root->gr_fs[GRBM_UFS].gfs_dev)); 4359160SSherry.Moore@Sun.COM (void) strlcpy(root->gr_fs[GRBM_UFS].gfs_mountp, mp.mnt_mountp, 4369160SSherry.Moore@Sun.COM sizeof (root->gr_fs[GRBM_UFS].gfs_mountp)); 4379160SSherry.Moore@Sun.COM } else { 4389160SSherry.Moore@Sun.COM rc = EG_UNKNOWNFS; 4399160SSherry.Moore@Sun.COM } 4409160SSherry.Moore@Sun.COM 4419160SSherry.Moore@Sun.COM return (rc); 4429160SSherry.Moore@Sun.COM } 4439160SSherry.Moore@Sun.COM 4449160SSherry.Moore@Sun.COM grub_fsdesc_t * 4459160SSherry.Moore@Sun.COM grub_get_rootfsd(const grub_root_t *root) 4469160SSherry.Moore@Sun.COM { 4479160SSherry.Moore@Sun.COM grub_fsdesc_t *fsd = NULL; 4489160SSherry.Moore@Sun.COM 4499160SSherry.Moore@Sun.COM assert(root); 4509160SSherry.Moore@Sun.COM if (strcmp(MNTTYPE_UFS, root->gr_fstyp) == 0) 4519160SSherry.Moore@Sun.COM fsd = (grub_fsdesc_t *)root->gr_fs + GRBM_UFS; 4529160SSherry.Moore@Sun.COM else if (strcmp(MNTTYPE_ZFS, root->gr_fstyp) == 0) 4539160SSherry.Moore@Sun.COM fsd = (grub_fsdesc_t *)root->gr_fs + GRBM_ZFS_BOOTFS; 4549160SSherry.Moore@Sun.COM 4559160SSherry.Moore@Sun.COM return (fsd); 4569160SSherry.Moore@Sun.COM } 4579160SSherry.Moore@Sun.COM 4589160SSherry.Moore@Sun.COM /* 4599160SSherry.Moore@Sun.COM * Gets file systems mount point if any. 4609160SSherry.Moore@Sun.COM * Return 0 if filesystem is mounted, errno on failure. 4619160SSherry.Moore@Sun.COM */ 4629160SSherry.Moore@Sun.COM int 4639160SSherry.Moore@Sun.COM grub_fsd_get_mountp(grub_fsdesc_t *fsd, char *fstyp) 4649160SSherry.Moore@Sun.COM { 4659160SSherry.Moore@Sun.COM int rc; 4669160SSherry.Moore@Sun.COM FILE *fp = NULL; 4679160SSherry.Moore@Sun.COM struct mnttab mp = {0}; 4689160SSherry.Moore@Sun.COM struct mnttab mpref = {0}; 4699160SSherry.Moore@Sun.COM 4709160SSherry.Moore@Sun.COM fsd->gfs_mountp[0] = 0; 4719160SSherry.Moore@Sun.COM 4729160SSherry.Moore@Sun.COM if ((fp = fopen(MNTTAB, "r")) == NULL) 4739160SSherry.Moore@Sun.COM return (errno); 4749160SSherry.Moore@Sun.COM 4759160SSherry.Moore@Sun.COM mpref.mnt_special = fsd->gfs_dev; 4769160SSherry.Moore@Sun.COM mpref.mnt_fstype = fstyp; 4779160SSherry.Moore@Sun.COM 4789160SSherry.Moore@Sun.COM if ((rc = getmntany(fp, &mp, &mpref)) == 0) 4799160SSherry.Moore@Sun.COM (void) strlcpy(fsd->gfs_mountp, mp.mnt_mountp, 4809160SSherry.Moore@Sun.COM sizeof (fsd->gfs_mountp)); 4819160SSherry.Moore@Sun.COM else 4829160SSherry.Moore@Sun.COM rc = EG_GETMNTTAB; 4839160SSherry.Moore@Sun.COM 4849160SSherry.Moore@Sun.COM (void) fclose(fp); 4859160SSherry.Moore@Sun.COM return (rc); 4869160SSherry.Moore@Sun.COM } 4879160SSherry.Moore@Sun.COM 4889160SSherry.Moore@Sun.COM static const char tmp_mountp[] = "/tmp/.libgrubmgmt.%s.XXXXXX"; 4899160SSherry.Moore@Sun.COM 4909160SSherry.Moore@Sun.COM /* 4919160SSherry.Moore@Sun.COM * Mount file system at tmp_mountp. 4929160SSherry.Moore@Sun.COM * Return 0 on success, errno on failure. 4939160SSherry.Moore@Sun.COM */ 4949160SSherry.Moore@Sun.COM int 4959160SSherry.Moore@Sun.COM grub_fsd_mount_tmp(grub_fsdesc_t *fsd, const char *fstyp) 4969160SSherry.Moore@Sun.COM { 4979160SSherry.Moore@Sun.COM const char *pos; 4989160SSherry.Moore@Sun.COM void *data = NULL; 4999160SSherry.Moore@Sun.COM int dtsz = 0; 5009160SSherry.Moore@Sun.COM struct ufs_args ufs_args = {UFSMNT_LARGEFILES}; 5019160SSherry.Moore@Sun.COM char mntopts[MNT_LINE_MAX] = ""; 5029160SSherry.Moore@Sun.COM int rc = 0; 5039160SSherry.Moore@Sun.COM 5049160SSherry.Moore@Sun.COM assert(fsd); 5059160SSherry.Moore@Sun.COM assert(!fsd->gfs_is_tmp_mounted); 5069160SSherry.Moore@Sun.COM 5079160SSherry.Moore@Sun.COM fsd->gfs_mountp[0] = 0; 5089160SSherry.Moore@Sun.COM 5099160SSherry.Moore@Sun.COM if (strcmp(fstyp, MNTTYPE_UFS) == 0) { 5109160SSherry.Moore@Sun.COM (void) strlcpy(mntopts, MNTOPT_LARGEFILES, sizeof (mntopts)); 5119160SSherry.Moore@Sun.COM data = &ufs_args; 5129160SSherry.Moore@Sun.COM dtsz = sizeof (ufs_args); 5139160SSherry.Moore@Sun.COM } else if (strcmp(fstyp, MNTTYPE_ZFS) != 0) { 5149160SSherry.Moore@Sun.COM return (EG_UNKNOWNFS); 5159160SSherry.Moore@Sun.COM } 5169160SSherry.Moore@Sun.COM 5179160SSherry.Moore@Sun.COM /* construct name for temporary mount point */ 5189160SSherry.Moore@Sun.COM pos = strrchr(fsd->gfs_dev, '/'); 5199160SSherry.Moore@Sun.COM pos = (pos == NULL) ? fsd->gfs_dev : pos + 1; 5209160SSherry.Moore@Sun.COM 5219160SSherry.Moore@Sun.COM (void) snprintf(fsd->gfs_mountp, sizeof (fsd->gfs_mountp), 5229160SSherry.Moore@Sun.COM tmp_mountp, pos); 5239160SSherry.Moore@Sun.COM if (mkdtemp(fsd->gfs_mountp) != NULL) { 5249160SSherry.Moore@Sun.COM if ((rc = mount(fsd->gfs_dev, fsd->gfs_mountp, 5259160SSherry.Moore@Sun.COM MS_DATA | MS_OPTIONSTR | MS_RDONLY, 5269160SSherry.Moore@Sun.COM fstyp, data, dtsz, mntopts, sizeof (mntopts))) != 0) { 5279160SSherry.Moore@Sun.COM /* 5289160SSherry.Moore@Sun.COM * mount failed, collect errno and remove temp dir 5299160SSherry.Moore@Sun.COM */ 5309160SSherry.Moore@Sun.COM rc = errno; 5319160SSherry.Moore@Sun.COM (void) rmdir(fsd->gfs_mountp); 5329160SSherry.Moore@Sun.COM } 5339160SSherry.Moore@Sun.COM } else { 5349160SSherry.Moore@Sun.COM rc = errno; 5359160SSherry.Moore@Sun.COM } 5369160SSherry.Moore@Sun.COM 5379160SSherry.Moore@Sun.COM if (rc != 0) 5389160SSherry.Moore@Sun.COM fsd->gfs_mountp[0] = 0; 5399160SSherry.Moore@Sun.COM 5409160SSherry.Moore@Sun.COM /* 5419160SSherry.Moore@Sun.COM * Note that valid values for gfs_is_tmp_mounted are 0,1. 5429160SSherry.Moore@Sun.COM * Any other value indicates that something bad happened. 5439160SSherry.Moore@Sun.COM * Probably grub_fsd_umount_tmp() wasn't called or didn't 5449160SSherry.Moore@Sun.COM * work as expected. 5459160SSherry.Moore@Sun.COM */ 5469160SSherry.Moore@Sun.COM fsd->gfs_is_tmp_mounted += (rc == 0); 5479160SSherry.Moore@Sun.COM return (rc); 5489160SSherry.Moore@Sun.COM } 5499160SSherry.Moore@Sun.COM 5509160SSherry.Moore@Sun.COM /* 5519160SSherry.Moore@Sun.COM * Unmount file system at tmp_mountp. 5529160SSherry.Moore@Sun.COM */ 5539160SSherry.Moore@Sun.COM void 5549160SSherry.Moore@Sun.COM grub_fsd_umount_tmp(grub_fsdesc_t *fsd) 5559160SSherry.Moore@Sun.COM { 5569160SSherry.Moore@Sun.COM if (fsd == NULL) 5579160SSherry.Moore@Sun.COM return; 5589160SSherry.Moore@Sun.COM 5599160SSherry.Moore@Sun.COM if (fsd->gfs_is_tmp_mounted) { 5609160SSherry.Moore@Sun.COM if (fsd->gfs_mountp[0] != 0) { 5619160SSherry.Moore@Sun.COM (void) umount2(fsd->gfs_mountp, 0); 5629160SSherry.Moore@Sun.COM (void) rmdir(fsd->gfs_mountp); 5639160SSherry.Moore@Sun.COM fsd->gfs_mountp[0] = 0; 5649160SSherry.Moore@Sun.COM } 5659160SSherry.Moore@Sun.COM fsd->gfs_is_tmp_mounted = 0; 5669160SSherry.Moore@Sun.COM } 5679160SSherry.Moore@Sun.COM } 568