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