1*9160SSherry.Moore@Sun.COM /* 2*9160SSherry.Moore@Sun.COM * CDDL HEADER START 3*9160SSherry.Moore@Sun.COM * 4*9160SSherry.Moore@Sun.COM * The contents of this file are subject to the terms of the 5*9160SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License"). 6*9160SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License. 7*9160SSherry.Moore@Sun.COM * 8*9160SSherry.Moore@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*9160SSherry.Moore@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*9160SSherry.Moore@Sun.COM * See the License for the specific language governing permissions 11*9160SSherry.Moore@Sun.COM * and limitations under the License. 12*9160SSherry.Moore@Sun.COM * 13*9160SSherry.Moore@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*9160SSherry.Moore@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*9160SSherry.Moore@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*9160SSherry.Moore@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*9160SSherry.Moore@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*9160SSherry.Moore@Sun.COM * 19*9160SSherry.Moore@Sun.COM * CDDL HEADER END 20*9160SSherry.Moore@Sun.COM */ 21*9160SSherry.Moore@Sun.COM /* 22*9160SSherry.Moore@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*9160SSherry.Moore@Sun.COM * Use is subject to license terms. 24*9160SSherry.Moore@Sun.COM */ 25*9160SSherry.Moore@Sun.COM 26*9160SSherry.Moore@Sun.COM /* 27*9160SSherry.Moore@Sun.COM * This file contains all the functions that manipualte the file 28*9160SSherry.Moore@Sun.COM * system where the GRUB menu resides. 29*9160SSherry.Moore@Sun.COM */ 30*9160SSherry.Moore@Sun.COM #include <stdio.h> 31*9160SSherry.Moore@Sun.COM #include <errno.h> 32*9160SSherry.Moore@Sun.COM #include <stdlib.h> 33*9160SSherry.Moore@Sun.COM #include <strings.h> 34*9160SSherry.Moore@Sun.COM #include <unistd.h> 35*9160SSherry.Moore@Sun.COM #include <fcntl.h> 36*9160SSherry.Moore@Sun.COM #include <assert.h> 37*9160SSherry.Moore@Sun.COM #include <sys/types.h> 38*9160SSherry.Moore@Sun.COM #include <sys/stat.h> 39*9160SSherry.Moore@Sun.COM #include <sys/mount.h> 40*9160SSherry.Moore@Sun.COM #include <sys/mntent.h> 41*9160SSherry.Moore@Sun.COM #include <sys/mnttab.h> 42*9160SSherry.Moore@Sun.COM #include <sys/fs/ufs_mount.h> 43*9160SSherry.Moore@Sun.COM #include <sys/dktp/fdisk.h> 44*9160SSherry.Moore@Sun.COM #include <libfstyp.h> 45*9160SSherry.Moore@Sun.COM 46*9160SSherry.Moore@Sun.COM #include "libgrub_impl.h" 47*9160SSherry.Moore@Sun.COM 48*9160SSherry.Moore@Sun.COM static int 49*9160SSherry.Moore@Sun.COM slice_match(const char *physpath, int slice) 50*9160SSherry.Moore@Sun.COM { 51*9160SSherry.Moore@Sun.COM const char *pos; 52*9160SSherry.Moore@Sun.COM 53*9160SSherry.Moore@Sun.COM return ((pos = strrchr(physpath, slice)) == NULL || 54*9160SSherry.Moore@Sun.COM pos[1] != 0 || pos[-1] != ':'); 55*9160SSherry.Moore@Sun.COM } 56*9160SSherry.Moore@Sun.COM 57*9160SSherry.Moore@Sun.COM /* 58*9160SSherry.Moore@Sun.COM * Returns zero if path contains ufs 59*9160SSherry.Moore@Sun.COM */ 60*9160SSherry.Moore@Sun.COM static int 61*9160SSherry.Moore@Sun.COM slice_ufs(const char *path) 62*9160SSherry.Moore@Sun.COM { 63*9160SSherry.Moore@Sun.COM int fd, ret; 64*9160SSherry.Moore@Sun.COM const char *id; 65*9160SSherry.Moore@Sun.COM fstyp_handle_t hdl; 66*9160SSherry.Moore@Sun.COM 67*9160SSherry.Moore@Sun.COM fd = open(path, O_RDONLY); 68*9160SSherry.Moore@Sun.COM if ((ret = fstyp_init(fd, 0, NULL, &hdl)) == 0) { 69*9160SSherry.Moore@Sun.COM ret = fstyp_ident(hdl, "ufs", &id); 70*9160SSherry.Moore@Sun.COM fstyp_fini(hdl); 71*9160SSherry.Moore@Sun.COM } 72*9160SSherry.Moore@Sun.COM (void) close(fd); 73*9160SSherry.Moore@Sun.COM return (ret); 74*9160SSherry.Moore@Sun.COM } 75*9160SSherry.Moore@Sun.COM 76*9160SSherry.Moore@Sun.COM 77*9160SSherry.Moore@Sun.COM static int 78*9160SSherry.Moore@Sun.COM get_sol_prtnum(const char *physpath) 79*9160SSherry.Moore@Sun.COM { 80*9160SSherry.Moore@Sun.COM int i, fd; 81*9160SSherry.Moore@Sun.COM char *pos; 82*9160SSherry.Moore@Sun.COM size_t sz; 83*9160SSherry.Moore@Sun.COM struct mboot *mb; 84*9160SSherry.Moore@Sun.COM struct ipart *ipart; 85*9160SSherry.Moore@Sun.COM char boot_sect[512]; 86*9160SSherry.Moore@Sun.COM char rdev[MAXNAMELEN]; 87*9160SSherry.Moore@Sun.COM 88*9160SSherry.Moore@Sun.COM (void) snprintf(rdev, sizeof (rdev), "/devices%s,raw", physpath); 89*9160SSherry.Moore@Sun.COM 90*9160SSherry.Moore@Sun.COM if ((pos = strrchr(rdev, ':')) == NULL) 91*9160SSherry.Moore@Sun.COM return (PRTNUM_INVALID); 92*9160SSherry.Moore@Sun.COM 93*9160SSherry.Moore@Sun.COM pos[1] = SLCNUM_WHOLE_DISK; 94*9160SSherry.Moore@Sun.COM 95*9160SSherry.Moore@Sun.COM fd = open(rdev, O_RDONLY); 96*9160SSherry.Moore@Sun.COM sz = read(fd, boot_sect, sizeof (boot_sect)); 97*9160SSherry.Moore@Sun.COM (void) close(fd); 98*9160SSherry.Moore@Sun.COM 99*9160SSherry.Moore@Sun.COM if (sz != sizeof (boot_sect)) 100*9160SSherry.Moore@Sun.COM return (PRTNUM_INVALID); 101*9160SSherry.Moore@Sun.COM 102*9160SSherry.Moore@Sun.COM /* parse fdisk table */ 103*9160SSherry.Moore@Sun.COM mb = (struct mboot *)(uintptr_t)boot_sect; 104*9160SSherry.Moore@Sun.COM ipart = (struct ipart *)(uintptr_t)mb->parts; 105*9160SSherry.Moore@Sun.COM for (i = 0; i < FD_NUMPART; ++i) { 106*9160SSherry.Moore@Sun.COM if (ipart[i].systid == SUNIXOS || ipart[i].systid == SUNIXOS2) 107*9160SSherry.Moore@Sun.COM return (i); 108*9160SSherry.Moore@Sun.COM } 109*9160SSherry.Moore@Sun.COM return (PRTNUM_INVALID); 110*9160SSherry.Moore@Sun.COM } 111*9160SSherry.Moore@Sun.COM 112*9160SSherry.Moore@Sun.COM /* 113*9160SSherry.Moore@Sun.COM * Get physpath, topfs and bootfs for ZFS root dataset. 114*9160SSherry.Moore@Sun.COM * Return 0 on success, non-zero (not errno) on failure. 115*9160SSherry.Moore@Sun.COM */ 116*9160SSherry.Moore@Sun.COM static int 117*9160SSherry.Moore@Sun.COM get_zfs_root(zfs_handle_t *zfh, grub_fs_t *fs, grub_root_t *root) 118*9160SSherry.Moore@Sun.COM { 119*9160SSherry.Moore@Sun.COM int ret; 120*9160SSherry.Moore@Sun.COM zpool_handle_t *zph; 121*9160SSherry.Moore@Sun.COM const char *name; 122*9160SSherry.Moore@Sun.COM 123*9160SSherry.Moore@Sun.COM if (zfs_get_type(zfh) != ZFS_TYPE_FILESYSTEM || 124*9160SSherry.Moore@Sun.COM (name = zfs_get_name(zfh)) == NULL || 125*9160SSherry.Moore@Sun.COM (zph = zpool_open(fs->gf_lzfh, name)) == NULL) 126*9160SSherry.Moore@Sun.COM return (-1); 127*9160SSherry.Moore@Sun.COM 128*9160SSherry.Moore@Sun.COM if ((ret = zpool_get_physpath(zph, root->gr_physpath, 129*9160SSherry.Moore@Sun.COM sizeof (root->gr_physpath))) == 0 && 130*9160SSherry.Moore@Sun.COM (ret = zpool_get_prop(zph, ZPOOL_PROP_BOOTFS, 131*9160SSherry.Moore@Sun.COM root->gr_fs[GRBM_ZFS_BOOTFS].gfs_dev, 132*9160SSherry.Moore@Sun.COM sizeof (root->gr_fs[GRBM_ZFS_BOOTFS].gfs_dev), NULL)) == 0) { 133*9160SSherry.Moore@Sun.COM 134*9160SSherry.Moore@Sun.COM (void) strlcpy(root->gr_fs[GRBM_ZFS_TOPFS].gfs_dev, name, 135*9160SSherry.Moore@Sun.COM sizeof (root->gr_fs[GRBM_ZFS_TOPFS].gfs_dev)); 136*9160SSherry.Moore@Sun.COM (void) grub_fsd_get_mountp(root->gr_fs + GRBM_ZFS_BOOTFS, 137*9160SSherry.Moore@Sun.COM MNTTYPE_ZFS); 138*9160SSherry.Moore@Sun.COM (void) grub_fsd_get_mountp(root->gr_fs + GRBM_ZFS_TOPFS, 139*9160SSherry.Moore@Sun.COM MNTTYPE_ZFS); 140*9160SSherry.Moore@Sun.COM } 141*9160SSherry.Moore@Sun.COM 142*9160SSherry.Moore@Sun.COM zpool_close(zph); 143*9160SSherry.Moore@Sun.COM return (ret); 144*9160SSherry.Moore@Sun.COM } 145*9160SSherry.Moore@Sun.COM 146*9160SSherry.Moore@Sun.COM /* 147*9160SSherry.Moore@Sun.COM * On entry physpath parameter supposed to contain: 148*9160SSherry.Moore@Sun.COM * <disk_physpath>[<space><disk_physpath>]*. 149*9160SSherry.Moore@Sun.COM * Retireives first <disk_physpath> that matches both partition and slice. 150*9160SSherry.Moore@Sun.COM * If any partition and slice is acceptable, first <disk_physpath> is returned. 151*9160SSherry.Moore@Sun.COM */ 152*9160SSherry.Moore@Sun.COM static int 153*9160SSherry.Moore@Sun.COM get_one_physpath(char *physpath, uint_t prtnum, uint_t slcnum) 154*9160SSherry.Moore@Sun.COM { 155*9160SSherry.Moore@Sun.COM int ret; 156*9160SSherry.Moore@Sun.COM char *tmp, *tok; 157*9160SSherry.Moore@Sun.COM 158*9160SSherry.Moore@Sun.COM if (!IS_SLCNUM_VALID(slcnum) && !IS_PRTNUM_VALID(prtnum)) { 159*9160SSherry.Moore@Sun.COM (void) strtok(physpath, " "); 160*9160SSherry.Moore@Sun.COM return (0); 161*9160SSherry.Moore@Sun.COM } 162*9160SSherry.Moore@Sun.COM 163*9160SSherry.Moore@Sun.COM if ((tmp = strdup(physpath)) == NULL) 164*9160SSherry.Moore@Sun.COM return (errno); 165*9160SSherry.Moore@Sun.COM 166*9160SSherry.Moore@Sun.COM ret = ENODEV; 167*9160SSherry.Moore@Sun.COM for (tok = strtok(tmp, " "); tok != NULL; tok = strtok(NULL, " ")) { 168*9160SSherry.Moore@Sun.COM if ((ret = (slice_match(tok, slcnum) != 0 || 169*9160SSherry.Moore@Sun.COM get_sol_prtnum(tok) != prtnum)) == 0) { 170*9160SSherry.Moore@Sun.COM (void) strcpy(physpath, tok); 171*9160SSherry.Moore@Sun.COM break; 172*9160SSherry.Moore@Sun.COM } 173*9160SSherry.Moore@Sun.COM } 174*9160SSherry.Moore@Sun.COM 175*9160SSherry.Moore@Sun.COM free(tmp); 176*9160SSherry.Moore@Sun.COM return (ret); 177*9160SSherry.Moore@Sun.COM } 178*9160SSherry.Moore@Sun.COM 179*9160SSherry.Moore@Sun.COM static int 180*9160SSherry.Moore@Sun.COM zfs_bootsign(zfs_handle_t *zfh, void *data) 181*9160SSherry.Moore@Sun.COM { 182*9160SSherry.Moore@Sun.COM grub_barg_t *barg; 183*9160SSherry.Moore@Sun.COM grub_menu_t *menu; 184*9160SSherry.Moore@Sun.COM struct stat st; 185*9160SSherry.Moore@Sun.COM char path[MAXPATHLEN]; 186*9160SSherry.Moore@Sun.COM 187*9160SSherry.Moore@Sun.COM barg = (grub_barg_t *)data; 188*9160SSherry.Moore@Sun.COM menu = barg->gb_entry->ge_menu; 189*9160SSherry.Moore@Sun.COM 190*9160SSherry.Moore@Sun.COM do { 191*9160SSherry.Moore@Sun.COM if (get_zfs_root(zfh, &menu->gm_fs, &barg->gb_root) != 0 || 192*9160SSherry.Moore@Sun.COM get_one_physpath(barg->gb_root.gr_physpath, barg->gb_prtnum, 193*9160SSherry.Moore@Sun.COM barg->gb_slcnum) != 0) 194*9160SSherry.Moore@Sun.COM break; 195*9160SSherry.Moore@Sun.COM 196*9160SSherry.Moore@Sun.COM /* 197*9160SSherry.Moore@Sun.COM * if top zfs dataset is not mounted, mount it now 198*9160SSherry.Moore@Sun.COM */ 199*9160SSherry.Moore@Sun.COM if (barg->gb_root.gr_fs[GRBM_ZFS_TOPFS].gfs_mountp[0] == 0) { 200*9160SSherry.Moore@Sun.COM if (grub_fsd_mount_tmp(barg->gb_root.gr_fs + 201*9160SSherry.Moore@Sun.COM GRBM_ZFS_TOPFS, MNTTYPE_ZFS) != 0) 202*9160SSherry.Moore@Sun.COM break; 203*9160SSherry.Moore@Sun.COM } 204*9160SSherry.Moore@Sun.COM 205*9160SSherry.Moore@Sun.COM /* check that bootsign exists and it is a regular file */ 206*9160SSherry.Moore@Sun.COM (void) snprintf(path, sizeof (path), "%s%s", 207*9160SSherry.Moore@Sun.COM barg->gb_root.gr_fs[GRBM_ZFS_TOPFS].gfs_mountp, 208*9160SSherry.Moore@Sun.COM barg->gb_bootsign); 209*9160SSherry.Moore@Sun.COM 210*9160SSherry.Moore@Sun.COM if (lstat(path, &st) != 0 || S_ISREG(st.st_mode) == 0 || 211*9160SSherry.Moore@Sun.COM (st.st_mode & S_IRUSR) == 0) 212*9160SSherry.Moore@Sun.COM break; 213*9160SSherry.Moore@Sun.COM 214*9160SSherry.Moore@Sun.COM (void) strlcpy(barg->gb_root.gr_fstyp, MNTTYPE_ZFS, 215*9160SSherry.Moore@Sun.COM sizeof (barg->gb_root.gr_fstyp)); 216*9160SSherry.Moore@Sun.COM barg->gb_walkret = 0; 217*9160SSherry.Moore@Sun.COM /* LINTED: E_CONSTANT_CONDITION */ 218*9160SSherry.Moore@Sun.COM } while (0); 219*9160SSherry.Moore@Sun.COM 220*9160SSherry.Moore@Sun.COM grub_fsd_umount_tmp(barg->gb_root.gr_fs + GRBM_ZFS_TOPFS); 221*9160SSherry.Moore@Sun.COM zfs_close(zfh); 222*9160SSherry.Moore@Sun.COM 223*9160SSherry.Moore@Sun.COM /* return non-zero to terminate the walk */ 224*9160SSherry.Moore@Sun.COM return (barg->gb_walkret == 0); 225*9160SSherry.Moore@Sun.COM } 226*9160SSherry.Moore@Sun.COM 227*9160SSherry.Moore@Sun.COM static int 228*9160SSherry.Moore@Sun.COM get_devlink(di_devlink_t dl, void *arg) 229*9160SSherry.Moore@Sun.COM { 230*9160SSherry.Moore@Sun.COM const char *path; 231*9160SSherry.Moore@Sun.COM grub_barg_t *barg; 232*9160SSherry.Moore@Sun.COM 233*9160SSherry.Moore@Sun.COM barg = (grub_barg_t *)arg; 234*9160SSherry.Moore@Sun.COM if ((path = di_devlink_path(dl)) != NULL) 235*9160SSherry.Moore@Sun.COM (void) strlcpy(barg->gb_root.gr_fs[GRBM_UFS].gfs_dev, path, 236*9160SSherry.Moore@Sun.COM sizeof (barg->gb_root.gr_fs[GRBM_UFS].gfs_dev)); 237*9160SSherry.Moore@Sun.COM return (DI_WALK_TERMINATE); 238*9160SSherry.Moore@Sun.COM } 239*9160SSherry.Moore@Sun.COM 240*9160SSherry.Moore@Sun.COM static int 241*9160SSherry.Moore@Sun.COM ufs_bootsign_check(grub_barg_t *barg) 242*9160SSherry.Moore@Sun.COM { 243*9160SSherry.Moore@Sun.COM int ret; 244*9160SSherry.Moore@Sun.COM struct stat st; 245*9160SSherry.Moore@Sun.COM grub_menu_t *mp; 246*9160SSherry.Moore@Sun.COM char path[MAXPATHLEN]; 247*9160SSherry.Moore@Sun.COM 248*9160SSherry.Moore@Sun.COM mp = barg->gb_entry->ge_menu; 249*9160SSherry.Moore@Sun.COM 250*9160SSherry.Moore@Sun.COM /* get /dev/dsk link */ 251*9160SSherry.Moore@Sun.COM if (di_devlink_walk(mp->gm_fs.gf_dvlh, "^dsk/", 252*9160SSherry.Moore@Sun.COM barg->gb_root.gr_physpath, DI_PRIMARY_LINK, barg, get_devlink) != 0) 253*9160SSherry.Moore@Sun.COM return (errno); 254*9160SSherry.Moore@Sun.COM /* 255*9160SSherry.Moore@Sun.COM * if disk is not mounted, mount it now 256*9160SSherry.Moore@Sun.COM */ 257*9160SSherry.Moore@Sun.COM if (grub_fsd_get_mountp(barg->gb_root.gr_fs + GRBM_UFS, 258*9160SSherry.Moore@Sun.COM MNTTYPE_UFS) != 0) { 259*9160SSherry.Moore@Sun.COM if ((ret = 260*9160SSherry.Moore@Sun.COM slice_ufs(barg->gb_root.gr_fs[GRBM_UFS].gfs_dev)) != 0 || 261*9160SSherry.Moore@Sun.COM (ret = grub_fsd_mount_tmp(barg->gb_root.gr_fs + GRBM_UFS, 262*9160SSherry.Moore@Sun.COM MNTTYPE_UFS)) != 0) 263*9160SSherry.Moore@Sun.COM return (ret); 264*9160SSherry.Moore@Sun.COM } 265*9160SSherry.Moore@Sun.COM 266*9160SSherry.Moore@Sun.COM (void) snprintf(path, sizeof (path), "%s%s", 267*9160SSherry.Moore@Sun.COM barg->gb_root.gr_fs[GRBM_UFS].gfs_mountp, barg->gb_bootsign); 268*9160SSherry.Moore@Sun.COM 269*9160SSherry.Moore@Sun.COM if (lstat(path, &st) == 0 && S_ISREG(st.st_mode) && 270*9160SSherry.Moore@Sun.COM (st.st_mode & S_IRUSR) != 0) { 271*9160SSherry.Moore@Sun.COM barg->gb_walkret = 0; 272*9160SSherry.Moore@Sun.COM (void) strlcpy(barg->gb_root.gr_fstyp, MNTTYPE_UFS, 273*9160SSherry.Moore@Sun.COM sizeof (barg->gb_root.gr_fstyp)); 274*9160SSherry.Moore@Sun.COM } 275*9160SSherry.Moore@Sun.COM 276*9160SSherry.Moore@Sun.COM grub_fsd_umount_tmp(barg->gb_root.gr_fs + GRBM_UFS); 277*9160SSherry.Moore@Sun.COM return (barg->gb_walkret); 278*9160SSherry.Moore@Sun.COM } 279*9160SSherry.Moore@Sun.COM 280*9160SSherry.Moore@Sun.COM static int 281*9160SSherry.Moore@Sun.COM ufs_bootsign(di_node_t node, di_minor_t minor, void *arg) 282*9160SSherry.Moore@Sun.COM { 283*9160SSherry.Moore@Sun.COM uint_t prtnum; 284*9160SSherry.Moore@Sun.COM char *name, *path; 285*9160SSherry.Moore@Sun.COM grub_barg_t *barg; 286*9160SSherry.Moore@Sun.COM 287*9160SSherry.Moore@Sun.COM barg = (grub_barg_t *)arg; 288*9160SSherry.Moore@Sun.COM 289*9160SSherry.Moore@Sun.COM if (di_minor_spectype(minor) != S_IFBLK) 290*9160SSherry.Moore@Sun.COM return (DI_WALK_CONTINUE); 291*9160SSherry.Moore@Sun.COM 292*9160SSherry.Moore@Sun.COM name = di_minor_name(minor); 293*9160SSherry.Moore@Sun.COM if (name[0] != barg->gb_slcnum || name[1] != 0) 294*9160SSherry.Moore@Sun.COM return (DI_WALK_CONTINUE); 295*9160SSherry.Moore@Sun.COM 296*9160SSherry.Moore@Sun.COM path = di_devfs_path(node); 297*9160SSherry.Moore@Sun.COM (void) snprintf(barg->gb_root.gr_physpath, 298*9160SSherry.Moore@Sun.COM sizeof (barg->gb_root.gr_physpath), "%s:%c", path, barg->gb_slcnum); 299*9160SSherry.Moore@Sun.COM di_devfs_path_free(path); 300*9160SSherry.Moore@Sun.COM 301*9160SSherry.Moore@Sun.COM prtnum = get_sol_prtnum(barg->gb_root.gr_physpath); 302*9160SSherry.Moore@Sun.COM if (!IS_PRTNUM_VALID(prtnum)) 303*9160SSherry.Moore@Sun.COM return (DI_WALK_CONTINUE); 304*9160SSherry.Moore@Sun.COM 305*9160SSherry.Moore@Sun.COM /* 306*9160SSherry.Moore@Sun.COM * check only specified partition, slice 307*9160SSherry.Moore@Sun.COM */ 308*9160SSherry.Moore@Sun.COM 309*9160SSherry.Moore@Sun.COM if (IS_PRTNUM_VALID(barg->gb_prtnum)) { 310*9160SSherry.Moore@Sun.COM if (prtnum != barg->gb_prtnum || ufs_bootsign_check(barg) != 0) 311*9160SSherry.Moore@Sun.COM return (DI_WALK_CONTINUE); 312*9160SSherry.Moore@Sun.COM return (DI_WALK_TERMINATE); 313*9160SSherry.Moore@Sun.COM } 314*9160SSherry.Moore@Sun.COM 315*9160SSherry.Moore@Sun.COM /* 316*9160SSherry.Moore@Sun.COM * Walk through all slices in found solaris partition 317*9160SSherry.Moore@Sun.COM */ 318*9160SSherry.Moore@Sun.COM 319*9160SSherry.Moore@Sun.COM barg->gb_prtnum = prtnum; 320*9160SSherry.Moore@Sun.COM minor = DI_MINOR_NIL; 321*9160SSherry.Moore@Sun.COM 322*9160SSherry.Moore@Sun.COM while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 323*9160SSherry.Moore@Sun.COM 324*9160SSherry.Moore@Sun.COM if (di_minor_spectype(minor) != S_IFBLK) 325*9160SSherry.Moore@Sun.COM continue; 326*9160SSherry.Moore@Sun.COM 327*9160SSherry.Moore@Sun.COM name = di_minor_name(minor); 328*9160SSherry.Moore@Sun.COM if (!IS_SLCNUM_VALID(name[0]) || name[1] != 0) 329*9160SSherry.Moore@Sun.COM continue; 330*9160SSherry.Moore@Sun.COM 331*9160SSherry.Moore@Sun.COM barg->gb_slcnum = name[0]; 332*9160SSherry.Moore@Sun.COM path = strrchr(barg->gb_root.gr_physpath, ':'); 333*9160SSherry.Moore@Sun.COM path[1] = barg->gb_slcnum; 334*9160SSherry.Moore@Sun.COM 335*9160SSherry.Moore@Sun.COM if (ufs_bootsign_check(barg) == 0) 336*9160SSherry.Moore@Sun.COM return (DI_WALK_TERMINATE); 337*9160SSherry.Moore@Sun.COM } 338*9160SSherry.Moore@Sun.COM 339*9160SSherry.Moore@Sun.COM barg->gb_prtnum = (uint_t)PRTNUM_INVALID; 340*9160SSherry.Moore@Sun.COM barg->gb_slcnum = (uint_t)SLCNUM_WHOLE_DISK; 341*9160SSherry.Moore@Sun.COM return (DI_WALK_CONTINUE); 342*9160SSherry.Moore@Sun.COM } 343*9160SSherry.Moore@Sun.COM 344*9160SSherry.Moore@Sun.COM /* 345*9160SSherry.Moore@Sun.COM * Differs from what GRUB is doing: GRUB searchs through all disks seen by bios 346*9160SSherry.Moore@Sun.COM * for bootsign, if bootsign is found on ufs slice GRUB sets it as a root, 347*9160SSherry.Moore@Sun.COM * if on zfs, then GRUB uses zfs slice as root only if bootsign wasn't found 348*9160SSherry.Moore@Sun.COM * on other slices. 349*9160SSherry.Moore@Sun.COM * That function first searches through all top datasets of active zpools, 350*9160SSherry.Moore@Sun.COM * then if bootsign still not found walks through all disks and tries to 351*9160SSherry.Moore@Sun.COM * find ufs slice with the bootsign. 352*9160SSherry.Moore@Sun.COM */ 353*9160SSherry.Moore@Sun.COM int 354*9160SSherry.Moore@Sun.COM grub_find_bootsign(grub_barg_t *barg) 355*9160SSherry.Moore@Sun.COM { 356*9160SSherry.Moore@Sun.COM grub_menu_t *mp; 357*9160SSherry.Moore@Sun.COM mp = barg->gb_entry->ge_menu; 358*9160SSherry.Moore@Sun.COM 359*9160SSherry.Moore@Sun.COM /* try to find bootsign over zfs pools */ 360*9160SSherry.Moore@Sun.COM barg->gb_walkret = EG_BOOTSIGN; 361*9160SSherry.Moore@Sun.COM (void) zfs_iter_root(mp->gm_fs.gf_lzfh, zfs_bootsign, barg); 362*9160SSherry.Moore@Sun.COM 363*9160SSherry.Moore@Sun.COM /* try ufs now */ 364*9160SSherry.Moore@Sun.COM if (barg->gb_walkret != 0 && di_walk_minor(mp->gm_fs.gf_diroot, 365*9160SSherry.Moore@Sun.COM DDI_NT_BLOCK, 0, barg, ufs_bootsign) != 0) 366*9160SSherry.Moore@Sun.COM return (errno); 367*9160SSherry.Moore@Sun.COM 368*9160SSherry.Moore@Sun.COM return (barg->gb_walkret); 369*9160SSherry.Moore@Sun.COM } 370*9160SSherry.Moore@Sun.COM 371*9160SSherry.Moore@Sun.COM /* 372*9160SSherry.Moore@Sun.COM * Get current root file system. 373*9160SSherry.Moore@Sun.COM * Return 0 on success, errno code on failure. 374*9160SSherry.Moore@Sun.COM */ 375*9160SSherry.Moore@Sun.COM int 376*9160SSherry.Moore@Sun.COM grub_current_root(grub_fs_t *fs, grub_root_t *root) 377*9160SSherry.Moore@Sun.COM { 378*9160SSherry.Moore@Sun.COM int rc = 0; 379*9160SSherry.Moore@Sun.COM FILE *fp = NULL; 380*9160SSherry.Moore@Sun.COM char *name = NULL; 381*9160SSherry.Moore@Sun.COM zfs_handle_t *zfh = NULL; 382*9160SSherry.Moore@Sun.COM struct mnttab mp = {0}; 383*9160SSherry.Moore@Sun.COM struct mnttab mpref = {0}; 384*9160SSherry.Moore@Sun.COM char buf[MAXNAMELEN] = {0}; 385*9160SSherry.Moore@Sun.COM 386*9160SSherry.Moore@Sun.COM mpref.mnt_mountp = "/"; 387*9160SSherry.Moore@Sun.COM 388*9160SSherry.Moore@Sun.COM if ((fp = fopen(MNTTAB, "r")) == NULL) 389*9160SSherry.Moore@Sun.COM return (errno); 390*9160SSherry.Moore@Sun.COM 391*9160SSherry.Moore@Sun.COM /* 392*9160SSherry.Moore@Sun.COM * getmntany returns non-zero for failure, and sets errno 393*9160SSherry.Moore@Sun.COM */ 394*9160SSherry.Moore@Sun.COM rc = getmntany(fp, &mp, &mpref); 395*9160SSherry.Moore@Sun.COM if (rc != 0) 396*9160SSherry.Moore@Sun.COM rc = errno; 397*9160SSherry.Moore@Sun.COM 398*9160SSherry.Moore@Sun.COM (void) fclose(fp); 399*9160SSherry.Moore@Sun.COM 400*9160SSherry.Moore@Sun.COM if (rc != 0) 401*9160SSherry.Moore@Sun.COM return (rc); 402*9160SSherry.Moore@Sun.COM 403*9160SSherry.Moore@Sun.COM (void) strlcpy(root->gr_fstyp, mp.mnt_fstype, sizeof (root->gr_fstyp)); 404*9160SSherry.Moore@Sun.COM 405*9160SSherry.Moore@Sun.COM if (strcmp(root->gr_fstyp, MNTTYPE_ZFS) == 0) { 406*9160SSherry.Moore@Sun.COM 407*9160SSherry.Moore@Sun.COM (void) strlcpy(buf, mp.mnt_special, sizeof (buf)); 408*9160SSherry.Moore@Sun.COM if ((name = strtok(buf, "/")) == NULL) 409*9160SSherry.Moore@Sun.COM return (EG_CURROOT); 410*9160SSherry.Moore@Sun.COM 411*9160SSherry.Moore@Sun.COM if ((zfh = zfs_open(fs->gf_lzfh, name, ZFS_TYPE_FILESYSTEM)) == 412*9160SSherry.Moore@Sun.COM NULL) 413*9160SSherry.Moore@Sun.COM return (EG_OPENZFS); 414*9160SSherry.Moore@Sun.COM 415*9160SSherry.Moore@Sun.COM /* 416*9160SSherry.Moore@Sun.COM * get_zfs_root returns non-zero on failure, not 417*9160SSherry.Moore@Sun.COM * errno. 418*9160SSherry.Moore@Sun.COM */ 419*9160SSherry.Moore@Sun.COM if (get_zfs_root(zfh, fs, root)) 420*9160SSherry.Moore@Sun.COM rc = EG_CURROOT; 421*9160SSherry.Moore@Sun.COM 422*9160SSherry.Moore@Sun.COM zfs_close(zfh); 423*9160SSherry.Moore@Sun.COM 424*9160SSherry.Moore@Sun.COM } else if (strcmp(mp.mnt_fstype, MNTTYPE_UFS) == 0) { 425*9160SSherry.Moore@Sun.COM (void) strlcpy(root->gr_fs[GRBM_UFS].gfs_dev, mp.mnt_special, 426*9160SSherry.Moore@Sun.COM sizeof (root->gr_fs[GRBM_UFS].gfs_dev)); 427*9160SSherry.Moore@Sun.COM (void) strlcpy(root->gr_fs[GRBM_UFS].gfs_mountp, mp.mnt_mountp, 428*9160SSherry.Moore@Sun.COM sizeof (root->gr_fs[GRBM_UFS].gfs_mountp)); 429*9160SSherry.Moore@Sun.COM } else { 430*9160SSherry.Moore@Sun.COM rc = EG_UNKNOWNFS; 431*9160SSherry.Moore@Sun.COM } 432*9160SSherry.Moore@Sun.COM 433*9160SSherry.Moore@Sun.COM return (rc); 434*9160SSherry.Moore@Sun.COM } 435*9160SSherry.Moore@Sun.COM 436*9160SSherry.Moore@Sun.COM grub_fsdesc_t * 437*9160SSherry.Moore@Sun.COM grub_get_rootfsd(const grub_root_t *root) 438*9160SSherry.Moore@Sun.COM { 439*9160SSherry.Moore@Sun.COM grub_fsdesc_t *fsd = NULL; 440*9160SSherry.Moore@Sun.COM 441*9160SSherry.Moore@Sun.COM assert(root); 442*9160SSherry.Moore@Sun.COM if (strcmp(MNTTYPE_UFS, root->gr_fstyp) == 0) 443*9160SSherry.Moore@Sun.COM fsd = (grub_fsdesc_t *)root->gr_fs + GRBM_UFS; 444*9160SSherry.Moore@Sun.COM else if (strcmp(MNTTYPE_ZFS, root->gr_fstyp) == 0) 445*9160SSherry.Moore@Sun.COM fsd = (grub_fsdesc_t *)root->gr_fs + GRBM_ZFS_BOOTFS; 446*9160SSherry.Moore@Sun.COM 447*9160SSherry.Moore@Sun.COM return (fsd); 448*9160SSherry.Moore@Sun.COM } 449*9160SSherry.Moore@Sun.COM 450*9160SSherry.Moore@Sun.COM /* 451*9160SSherry.Moore@Sun.COM * Gets file systems mount point if any. 452*9160SSherry.Moore@Sun.COM * Return 0 if filesystem is mounted, errno on failure. 453*9160SSherry.Moore@Sun.COM */ 454*9160SSherry.Moore@Sun.COM int 455*9160SSherry.Moore@Sun.COM grub_fsd_get_mountp(grub_fsdesc_t *fsd, char *fstyp) 456*9160SSherry.Moore@Sun.COM { 457*9160SSherry.Moore@Sun.COM int rc; 458*9160SSherry.Moore@Sun.COM FILE *fp = NULL; 459*9160SSherry.Moore@Sun.COM struct mnttab mp = {0}; 460*9160SSherry.Moore@Sun.COM struct mnttab mpref = {0}; 461*9160SSherry.Moore@Sun.COM 462*9160SSherry.Moore@Sun.COM fsd->gfs_mountp[0] = 0; 463*9160SSherry.Moore@Sun.COM 464*9160SSherry.Moore@Sun.COM if ((fp = fopen(MNTTAB, "r")) == NULL) 465*9160SSherry.Moore@Sun.COM return (errno); 466*9160SSherry.Moore@Sun.COM 467*9160SSherry.Moore@Sun.COM mpref.mnt_special = fsd->gfs_dev; 468*9160SSherry.Moore@Sun.COM mpref.mnt_fstype = fstyp; 469*9160SSherry.Moore@Sun.COM 470*9160SSherry.Moore@Sun.COM if ((rc = getmntany(fp, &mp, &mpref)) == 0) 471*9160SSherry.Moore@Sun.COM (void) strlcpy(fsd->gfs_mountp, mp.mnt_mountp, 472*9160SSherry.Moore@Sun.COM sizeof (fsd->gfs_mountp)); 473*9160SSherry.Moore@Sun.COM else 474*9160SSherry.Moore@Sun.COM rc = EG_GETMNTTAB; 475*9160SSherry.Moore@Sun.COM 476*9160SSherry.Moore@Sun.COM (void) fclose(fp); 477*9160SSherry.Moore@Sun.COM return (rc); 478*9160SSherry.Moore@Sun.COM } 479*9160SSherry.Moore@Sun.COM 480*9160SSherry.Moore@Sun.COM static const char tmp_mountp[] = "/tmp/.libgrubmgmt.%s.XXXXXX"; 481*9160SSherry.Moore@Sun.COM 482*9160SSherry.Moore@Sun.COM /* 483*9160SSherry.Moore@Sun.COM * Mount file system at tmp_mountp. 484*9160SSherry.Moore@Sun.COM * Return 0 on success, errno on failure. 485*9160SSherry.Moore@Sun.COM */ 486*9160SSherry.Moore@Sun.COM int 487*9160SSherry.Moore@Sun.COM grub_fsd_mount_tmp(grub_fsdesc_t *fsd, const char *fstyp) 488*9160SSherry.Moore@Sun.COM { 489*9160SSherry.Moore@Sun.COM const char *pos; 490*9160SSherry.Moore@Sun.COM void *data = NULL; 491*9160SSherry.Moore@Sun.COM int dtsz = 0; 492*9160SSherry.Moore@Sun.COM struct ufs_args ufs_args = {UFSMNT_LARGEFILES}; 493*9160SSherry.Moore@Sun.COM char mntopts[MNT_LINE_MAX] = ""; 494*9160SSherry.Moore@Sun.COM int rc = 0; 495*9160SSherry.Moore@Sun.COM 496*9160SSherry.Moore@Sun.COM assert(fsd); 497*9160SSherry.Moore@Sun.COM assert(!fsd->gfs_is_tmp_mounted); 498*9160SSherry.Moore@Sun.COM 499*9160SSherry.Moore@Sun.COM fsd->gfs_mountp[0] = 0; 500*9160SSherry.Moore@Sun.COM 501*9160SSherry.Moore@Sun.COM if (strcmp(fstyp, MNTTYPE_UFS) == 0) { 502*9160SSherry.Moore@Sun.COM (void) strlcpy(mntopts, MNTOPT_LARGEFILES, sizeof (mntopts)); 503*9160SSherry.Moore@Sun.COM data = &ufs_args; 504*9160SSherry.Moore@Sun.COM dtsz = sizeof (ufs_args); 505*9160SSherry.Moore@Sun.COM } else if (strcmp(fstyp, MNTTYPE_ZFS) != 0) { 506*9160SSherry.Moore@Sun.COM return (EG_UNKNOWNFS); 507*9160SSherry.Moore@Sun.COM } 508*9160SSherry.Moore@Sun.COM 509*9160SSherry.Moore@Sun.COM /* construct name for temporary mount point */ 510*9160SSherry.Moore@Sun.COM pos = strrchr(fsd->gfs_dev, '/'); 511*9160SSherry.Moore@Sun.COM pos = (pos == NULL) ? fsd->gfs_dev : pos + 1; 512*9160SSherry.Moore@Sun.COM 513*9160SSherry.Moore@Sun.COM (void) snprintf(fsd->gfs_mountp, sizeof (fsd->gfs_mountp), 514*9160SSherry.Moore@Sun.COM tmp_mountp, pos); 515*9160SSherry.Moore@Sun.COM if (mkdtemp(fsd->gfs_mountp) != NULL) { 516*9160SSherry.Moore@Sun.COM if ((rc = mount(fsd->gfs_dev, fsd->gfs_mountp, 517*9160SSherry.Moore@Sun.COM MS_DATA | MS_OPTIONSTR | MS_RDONLY, 518*9160SSherry.Moore@Sun.COM fstyp, data, dtsz, mntopts, sizeof (mntopts))) != 0) { 519*9160SSherry.Moore@Sun.COM /* 520*9160SSherry.Moore@Sun.COM * mount failed, collect errno and remove temp dir 521*9160SSherry.Moore@Sun.COM */ 522*9160SSherry.Moore@Sun.COM rc = errno; 523*9160SSherry.Moore@Sun.COM (void) rmdir(fsd->gfs_mountp); 524*9160SSherry.Moore@Sun.COM } 525*9160SSherry.Moore@Sun.COM } else { 526*9160SSherry.Moore@Sun.COM rc = errno; 527*9160SSherry.Moore@Sun.COM } 528*9160SSherry.Moore@Sun.COM 529*9160SSherry.Moore@Sun.COM if (rc != 0) 530*9160SSherry.Moore@Sun.COM fsd->gfs_mountp[0] = 0; 531*9160SSherry.Moore@Sun.COM 532*9160SSherry.Moore@Sun.COM /* 533*9160SSherry.Moore@Sun.COM * Note that valid values for gfs_is_tmp_mounted are 0,1. 534*9160SSherry.Moore@Sun.COM * Any other value indicates that something bad happened. 535*9160SSherry.Moore@Sun.COM * Probably grub_fsd_umount_tmp() wasn't called or didn't 536*9160SSherry.Moore@Sun.COM * work as expected. 537*9160SSherry.Moore@Sun.COM */ 538*9160SSherry.Moore@Sun.COM fsd->gfs_is_tmp_mounted += (rc == 0); 539*9160SSherry.Moore@Sun.COM return (rc); 540*9160SSherry.Moore@Sun.COM } 541*9160SSherry.Moore@Sun.COM 542*9160SSherry.Moore@Sun.COM /* 543*9160SSherry.Moore@Sun.COM * Unmount file system at tmp_mountp. 544*9160SSherry.Moore@Sun.COM */ 545*9160SSherry.Moore@Sun.COM void 546*9160SSherry.Moore@Sun.COM grub_fsd_umount_tmp(grub_fsdesc_t *fsd) 547*9160SSherry.Moore@Sun.COM { 548*9160SSherry.Moore@Sun.COM if (fsd == NULL) 549*9160SSherry.Moore@Sun.COM return; 550*9160SSherry.Moore@Sun.COM 551*9160SSherry.Moore@Sun.COM if (fsd->gfs_is_tmp_mounted) { 552*9160SSherry.Moore@Sun.COM if (fsd->gfs_mountp[0] != 0) { 553*9160SSherry.Moore@Sun.COM (void) umount2(fsd->gfs_mountp, 0); 554*9160SSherry.Moore@Sun.COM (void) rmdir(fsd->gfs_mountp); 555*9160SSherry.Moore@Sun.COM fsd->gfs_mountp[0] = 0; 556*9160SSherry.Moore@Sun.COM } 557*9160SSherry.Moore@Sun.COM fsd->gfs_is_tmp_mounted = 0; 558*9160SSherry.Moore@Sun.COM } 559*9160SSherry.Moore@Sun.COM } 560