xref: /onnv-gate/usr/src/lib/libgrubmgmt/common/libgrub_cmd.c (revision 9444:ea6878d0d074)
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 implement the following
289160SSherry.Moore@Sun.COM  * GRUB commands:
299160SSherry.Moore@Sun.COM  *	kernel, kernel$, module, module$, findroot, bootfs
309160SSherry.Moore@Sun.COM  * Return 0 on success, errno on failure.
319160SSherry.Moore@Sun.COM  */
329160SSherry.Moore@Sun.COM #include <stdio.h>
339160SSherry.Moore@Sun.COM #include <stdlib.h>
349160SSherry.Moore@Sun.COM #include <assert.h>
359160SSherry.Moore@Sun.COM #include <alloca.h>
369160SSherry.Moore@Sun.COM #include <errno.h>
379160SSherry.Moore@Sun.COM #include <strings.h>
389160SSherry.Moore@Sun.COM #include <unistd.h>
399160SSherry.Moore@Sun.COM #include <fcntl.h>
409160SSherry.Moore@Sun.COM #include <sys/types.h>
419160SSherry.Moore@Sun.COM #include <sys/fs/ufs_mount.h>
429160SSherry.Moore@Sun.COM #include <sys/dktp/fdisk.h>
439160SSherry.Moore@Sun.COM #if defined(__i386)
449160SSherry.Moore@Sun.COM #include <sys/x86_archext.h>
459160SSherry.Moore@Sun.COM #endif /* __i386 */
469160SSherry.Moore@Sun.COM 
479160SSherry.Moore@Sun.COM #include "libgrub_impl.h"
489160SSherry.Moore@Sun.COM 
499160SSherry.Moore@Sun.COM #define	RESET_MODULE(barg)	((barg)->gb_module[0] = 0)
509160SSherry.Moore@Sun.COM 
519160SSherry.Moore@Sun.COM #if defined(__i386)
529160SSherry.Moore@Sun.COM static const char cpuid_dev[] = "/dev/cpu/self/cpuid";
539160SSherry.Moore@Sun.COM 
549160SSherry.Moore@Sun.COM /*
559160SSherry.Moore@Sun.COM  * Return 1 if the system supports 64-bit mode, 0 if it doesn't,
569160SSherry.Moore@Sun.COM  * or -1 on failure.
579160SSherry.Moore@Sun.COM  */
589160SSherry.Moore@Sun.COM static int
599160SSherry.Moore@Sun.COM cpuid_64bit_capable(void)
609160SSherry.Moore@Sun.COM {
619160SSherry.Moore@Sun.COM 	int fd, ret = -1;
629160SSherry.Moore@Sun.COM 	struct {
639160SSherry.Moore@Sun.COM 		uint32_t cp_eax, cp_ebx, cp_ecx, cp_edx;
649160SSherry.Moore@Sun.COM 	} cpuid_regs;
659160SSherry.Moore@Sun.COM 
669160SSherry.Moore@Sun.COM 	if ((fd = open(cpuid_dev, O_RDONLY)) == -1)
679160SSherry.Moore@Sun.COM 		return (ret);
689160SSherry.Moore@Sun.COM 
699160SSherry.Moore@Sun.COM 	if (pread(fd, &cpuid_regs, sizeof (cpuid_regs), 0x80000001) ==
709160SSherry.Moore@Sun.COM 	    sizeof (cpuid_regs))
719160SSherry.Moore@Sun.COM 		ret = ((CPUID_AMD_EDX_LM & cpuid_regs.cp_edx) != 0);
729160SSherry.Moore@Sun.COM 
739160SSherry.Moore@Sun.COM 	(void) close(fd);
749160SSherry.Moore@Sun.COM 	return (ret);
759160SSherry.Moore@Sun.COM }
769160SSherry.Moore@Sun.COM #endif /* __i386 */
779160SSherry.Moore@Sun.COM 
789160SSherry.Moore@Sun.COM 
799160SSherry.Moore@Sun.COM /*
809160SSherry.Moore@Sun.COM  * Expand $ISAIDR
819160SSherry.Moore@Sun.COM  */
829160SSherry.Moore@Sun.COM #if !defined(__i386)
839160SSherry.Moore@Sun.COM /* ARGSUSED */
849160SSherry.Moore@Sun.COM #endif /* __i386 */
859160SSherry.Moore@Sun.COM static size_t
869160SSherry.Moore@Sun.COM barg_isadir_var(char *var, int sz)
879160SSherry.Moore@Sun.COM {
889160SSherry.Moore@Sun.COM #if defined(__i386)
899160SSherry.Moore@Sun.COM 	if (cpuid_64bit_capable() == 1)
909160SSherry.Moore@Sun.COM 		return (strlcpy(var, "amd64", sz));
919160SSherry.Moore@Sun.COM #endif /* __i386 */
929160SSherry.Moore@Sun.COM 
939160SSherry.Moore@Sun.COM 	var[0] = 0;
949160SSherry.Moore@Sun.COM 	return (0);
959160SSherry.Moore@Sun.COM }
969160SSherry.Moore@Sun.COM 
979160SSherry.Moore@Sun.COM /*
989160SSherry.Moore@Sun.COM  * Expand $ZFS-BOOTFS
999160SSherry.Moore@Sun.COM  */
1009160SSherry.Moore@Sun.COM static size_t
1019160SSherry.Moore@Sun.COM barg_bootfs_var(const grub_barg_t *barg, char *var, int sz)
1029160SSherry.Moore@Sun.COM {
1039160SSherry.Moore@Sun.COM 	int n;
1049160SSherry.Moore@Sun.COM 
1059160SSherry.Moore@Sun.COM 	assert(barg);
1069160SSherry.Moore@Sun.COM 	if (strcmp(barg->gb_root.gr_fstyp, MNTTYPE_ZFS) == 0) {
1079160SSherry.Moore@Sun.COM 		n = snprintf(var, sz, "zfs-bootfs=%s,bootpath=\"%s\"",
1089160SSherry.Moore@Sun.COM 		    barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev,
1099160SSherry.Moore@Sun.COM 		    barg->gb_root.gr_physpath);
1109160SSherry.Moore@Sun.COM 	} else	{
1119160SSherry.Moore@Sun.COM 		var[0] = 0;
1129160SSherry.Moore@Sun.COM 		n = 0;
1139160SSherry.Moore@Sun.COM 	}
1149160SSherry.Moore@Sun.COM 	return (n);
1159160SSherry.Moore@Sun.COM }
1169160SSherry.Moore@Sun.COM 
1179160SSherry.Moore@Sun.COM /*
1189160SSherry.Moore@Sun.COM  * Expand all the variables without appending them more than once.
1199160SSherry.Moore@Sun.COM  */
1209160SSherry.Moore@Sun.COM static int
1219160SSherry.Moore@Sun.COM expand_var(char *arg, size_t argsz, const char *var, size_t varsz,
1229160SSherry.Moore@Sun.COM     char *val, size_t valsz)
1239160SSherry.Moore@Sun.COM {
1249160SSherry.Moore@Sun.COM 	char	*sp = arg;
1259160SSherry.Moore@Sun.COM 	size_t	sz = argsz, len;
1269160SSherry.Moore@Sun.COM 	char	*buf, *dst, *src;
1279160SSherry.Moore@Sun.COM 	int	ret = 0;
1289160SSherry.Moore@Sun.COM 
1299160SSherry.Moore@Sun.COM 	buf = alloca(argsz);
1309160SSherry.Moore@Sun.COM 	dst = buf;
1319160SSherry.Moore@Sun.COM 
1329160SSherry.Moore@Sun.COM 	while ((src = strstr(sp, var)) != NULL) {
1339160SSherry.Moore@Sun.COM 
1349160SSherry.Moore@Sun.COM 		len = src - sp;
1359160SSherry.Moore@Sun.COM 
1369160SSherry.Moore@Sun.COM 		if (len + valsz > sz) {
1379160SSherry.Moore@Sun.COM 			ret = E2BIG;
1389160SSherry.Moore@Sun.COM 			break;
1399160SSherry.Moore@Sun.COM 		}
1409160SSherry.Moore@Sun.COM 
1419160SSherry.Moore@Sun.COM 		(void) bcopy(sp, dst, len);
1429160SSherry.Moore@Sun.COM 		(void) bcopy(val, dst + len, valsz);
1439160SSherry.Moore@Sun.COM 		dst += len + valsz;
1449160SSherry.Moore@Sun.COM 		sz -= len + valsz;
1459160SSherry.Moore@Sun.COM 		sp = src + varsz;
1469160SSherry.Moore@Sun.COM 	}
1479160SSherry.Moore@Sun.COM 
1489160SSherry.Moore@Sun.COM 	if (strlcpy(dst, sp, sz) >= sz)
1499160SSherry.Moore@Sun.COM 		ret = E2BIG;
1509160SSherry.Moore@Sun.COM 
1519160SSherry.Moore@Sun.COM 	if (ret == 0)
1529160SSherry.Moore@Sun.COM 		bcopy(buf, arg, argsz);
1539160SSherry.Moore@Sun.COM 	return (ret);
1549160SSherry.Moore@Sun.COM }
1559160SSherry.Moore@Sun.COM 
1569160SSherry.Moore@Sun.COM static int
1579160SSherry.Moore@Sun.COM match_bootfs(zfs_handle_t *zfh, void *data)
1589160SSherry.Moore@Sun.COM {
1599160SSherry.Moore@Sun.COM 	int		ret;
1609160SSherry.Moore@Sun.COM 	const char	*zfn;
1619160SSherry.Moore@Sun.COM 	grub_barg_t	*barg = (grub_barg_t *)data;
1629160SSherry.Moore@Sun.COM 
1639160SSherry.Moore@Sun.COM 	ret = (zfs_get_type(zfh) == ZFS_TYPE_FILESYSTEM &&
1649160SSherry.Moore@Sun.COM 	    (zfn = zfs_get_name(zfh)) != NULL &&
1659160SSherry.Moore@Sun.COM 	    strcmp(barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev, zfn) == 0);
1669160SSherry.Moore@Sun.COM 
1679160SSherry.Moore@Sun.COM 	if (ret != 0)
1689160SSherry.Moore@Sun.COM 		barg->gb_walkret = 0;
1699160SSherry.Moore@Sun.COM 	else
1709160SSherry.Moore@Sun.COM 		(void) zfs_iter_filesystems(zfh, match_bootfs, barg);
1719160SSherry.Moore@Sun.COM 
1729160SSherry.Moore@Sun.COM 	zfs_close(zfh);
1739160SSherry.Moore@Sun.COM 	return (barg->gb_walkret == 0);
1749160SSherry.Moore@Sun.COM }
1759160SSherry.Moore@Sun.COM 
1769160SSherry.Moore@Sun.COM static void
1779160SSherry.Moore@Sun.COM reset_root(grub_barg_t *barg)
1789160SSherry.Moore@Sun.COM {
1799160SSherry.Moore@Sun.COM 	(void) memset(&barg->gb_root, 0, sizeof (barg->gb_root));
1809160SSherry.Moore@Sun.COM 	barg->gb_bootsign[0] = 0;
1819160SSherry.Moore@Sun.COM 	barg->gb_kernel[0] = 0;
1829160SSherry.Moore@Sun.COM 	RESET_MODULE(barg);
1839160SSherry.Moore@Sun.COM }
1849160SSherry.Moore@Sun.COM 
1859160SSherry.Moore@Sun.COM /* ARGSUSED */
1869160SSherry.Moore@Sun.COM int
1879160SSherry.Moore@Sun.COM skip_line(const grub_line_t *lp, grub_barg_t *barg)
1889160SSherry.Moore@Sun.COM {
1899160SSherry.Moore@Sun.COM 	return (0);
1909160SSherry.Moore@Sun.COM }
1919160SSherry.Moore@Sun.COM 
1929160SSherry.Moore@Sun.COM /* ARGSUSED */
1939160SSherry.Moore@Sun.COM int
1949160SSherry.Moore@Sun.COM error_line(const grub_line_t *lp, grub_barg_t *barg)
1959160SSherry.Moore@Sun.COM {
196*9444SKonstantin.Ananyev@Sun.COM 	if (lp->gl_cmdtp == GRBM_ROOT_CMD)
197*9444SKonstantin.Ananyev@Sun.COM 		return (EG_ROOTNOTSUPP);
1989160SSherry.Moore@Sun.COM 	return (EG_INVALIDLINE);
1999160SSherry.Moore@Sun.COM }
2009160SSherry.Moore@Sun.COM 
2019160SSherry.Moore@Sun.COM int
2029160SSherry.Moore@Sun.COM kernel(const grub_line_t *lp, grub_barg_t *barg)
2039160SSherry.Moore@Sun.COM {
2049160SSherry.Moore@Sun.COM 	RESET_MODULE(barg);
2059160SSherry.Moore@Sun.COM 	if (strlcpy(barg->gb_kernel, lp->gl_arg, sizeof (barg->gb_kernel)) >=
2069160SSherry.Moore@Sun.COM 	    sizeof (barg->gb_kernel))
2079160SSherry.Moore@Sun.COM 		return (E2BIG);
2089160SSherry.Moore@Sun.COM 
2099160SSherry.Moore@Sun.COM 	return (0);
2109160SSherry.Moore@Sun.COM }
2119160SSherry.Moore@Sun.COM 
2129160SSherry.Moore@Sun.COM int
2139160SSherry.Moore@Sun.COM module(const grub_line_t *lp, grub_barg_t *barg)
2149160SSherry.Moore@Sun.COM {
2159160SSherry.Moore@Sun.COM 	if (strlcpy(barg->gb_module, lp->gl_arg, sizeof (barg->gb_module)) >=
2169160SSherry.Moore@Sun.COM 	    sizeof (barg->gb_module))
2179160SSherry.Moore@Sun.COM 		return (E2BIG);
2189160SSherry.Moore@Sun.COM 
2199160SSherry.Moore@Sun.COM 	return (0);
2209160SSherry.Moore@Sun.COM }
2219160SSherry.Moore@Sun.COM 
2229160SSherry.Moore@Sun.COM int
2239160SSherry.Moore@Sun.COM dollar_kernel(const grub_line_t *lp, grub_barg_t *barg)
2249160SSherry.Moore@Sun.COM {
2259160SSherry.Moore@Sun.COM 	int	ret;
2269160SSherry.Moore@Sun.COM 	size_t	bfslen, isalen;
2279160SSherry.Moore@Sun.COM 	char	isadir[32];
2289160SSherry.Moore@Sun.COM 	char	bootfs[BOOTARGS_MAX];
2299160SSherry.Moore@Sun.COM 
2309160SSherry.Moore@Sun.COM 	RESET_MODULE(barg);
2319160SSherry.Moore@Sun.COM 	if (strlcpy(barg->gb_kernel, lp->gl_arg, sizeof (barg->gb_kernel)) >=
2329160SSherry.Moore@Sun.COM 	    sizeof (barg->gb_kernel))
2339160SSherry.Moore@Sun.COM 		return (E2BIG);
2349160SSherry.Moore@Sun.COM 
2359160SSherry.Moore@Sun.COM 	bfslen = barg_bootfs_var(barg, bootfs, sizeof (bootfs));
2369160SSherry.Moore@Sun.COM 	isalen = barg_isadir_var(isadir, sizeof (isadir));
2379160SSherry.Moore@Sun.COM 
2389160SSherry.Moore@Sun.COM 	if (bfslen >= sizeof (bootfs) || isalen >= sizeof (isadir))
2399160SSherry.Moore@Sun.COM 		return (EINVAL);
2409160SSherry.Moore@Sun.COM 
2419160SSherry.Moore@Sun.COM 	if ((ret = expand_var(barg->gb_kernel, sizeof (barg->gb_kernel),
2429160SSherry.Moore@Sun.COM 	    ZFS_BOOT_VAR, strlen(ZFS_BOOT_VAR), bootfs, bfslen)) != 0)
2439160SSherry.Moore@Sun.COM 		return (ret);
2449160SSherry.Moore@Sun.COM 
2459160SSherry.Moore@Sun.COM 	ret = expand_var(barg->gb_kernel, sizeof (barg->gb_kernel),
2469160SSherry.Moore@Sun.COM 	    ISADIR_VAR, strlen(ISADIR_VAR), isadir, isalen);
2479160SSherry.Moore@Sun.COM 
2489160SSherry.Moore@Sun.COM 	return (ret);
2499160SSherry.Moore@Sun.COM }
2509160SSherry.Moore@Sun.COM 
2519160SSherry.Moore@Sun.COM int
2529160SSherry.Moore@Sun.COM dollar_module(const grub_line_t *lp, grub_barg_t *barg)
2539160SSherry.Moore@Sun.COM {
2549160SSherry.Moore@Sun.COM 	int	ret;
2559160SSherry.Moore@Sun.COM 	size_t	isalen;
2569160SSherry.Moore@Sun.COM 	char	isadir[32];
2579160SSherry.Moore@Sun.COM 
2589160SSherry.Moore@Sun.COM 	if (strlcpy(barg->gb_module, lp->gl_arg, sizeof (barg->gb_module)) >=
2599160SSherry.Moore@Sun.COM 	    sizeof (barg->gb_module))
2609160SSherry.Moore@Sun.COM 		return (E2BIG);
2619160SSherry.Moore@Sun.COM 
2629160SSherry.Moore@Sun.COM 	if ((isalen = barg_isadir_var(isadir, sizeof (isadir))) >= sizeof
2639160SSherry.Moore@Sun.COM 	    (isadir))
2649160SSherry.Moore@Sun.COM 		return (EINVAL);
2659160SSherry.Moore@Sun.COM 
2669160SSherry.Moore@Sun.COM 	ret = expand_var(barg->gb_module, sizeof (barg->gb_module),
2679160SSherry.Moore@Sun.COM 	    ISADIR_VAR, strlen(ISADIR_VAR), isadir, isalen);
2689160SSherry.Moore@Sun.COM 
2699160SSherry.Moore@Sun.COM 	return (ret);
2709160SSherry.Moore@Sun.COM }
2719160SSherry.Moore@Sun.COM 
2729160SSherry.Moore@Sun.COM 
2739160SSherry.Moore@Sun.COM int
2749160SSherry.Moore@Sun.COM findroot(const grub_line_t *lp, grub_barg_t *barg)
2759160SSherry.Moore@Sun.COM {
2769160SSherry.Moore@Sun.COM 	size_t sz, bsz;
2779160SSherry.Moore@Sun.COM 	const char *sign;
2789160SSherry.Moore@Sun.COM 
2799160SSherry.Moore@Sun.COM 	reset_root(barg);
2809160SSherry.Moore@Sun.COM 
2819160SSherry.Moore@Sun.COM 	sign = lp->gl_arg;
2829160SSherry.Moore@Sun.COM 	barg->gb_prtnum = (uint_t)PRTNUM_INVALID;
2839160SSherry.Moore@Sun.COM 	barg->gb_slcnum = (uint_t)SLCNUM_WHOLE_DISK;
2849160SSherry.Moore@Sun.COM 
2859160SSherry.Moore@Sun.COM 	if (sign[0] == '(') {
2869160SSherry.Moore@Sun.COM 		const char *pos;
2879160SSherry.Moore@Sun.COM 
2889160SSherry.Moore@Sun.COM 		++sign;
2899160SSherry.Moore@Sun.COM 		if ((pos = strchr(sign, ',')) == NULL || (sz = pos - sign) == 0)
2909160SSherry.Moore@Sun.COM 			return (EG_FINDROOTFMT);
2919160SSherry.Moore@Sun.COM 
2929160SSherry.Moore@Sun.COM 		++pos;
2939160SSherry.Moore@Sun.COM 		if (!IS_PRTNUM_VALID(barg->gb_prtnum = pos[0] - '0'))
2949160SSherry.Moore@Sun.COM 			return (EG_FINDROOTFMT);
2959160SSherry.Moore@Sun.COM 
2969160SSherry.Moore@Sun.COM 		++pos;
2979160SSherry.Moore@Sun.COM 		if (pos[0] != ',' ||
2989160SSherry.Moore@Sun.COM 		    !IS_SLCNUM_VALID(barg->gb_slcnum = pos[1]) ||
2999160SSherry.Moore@Sun.COM 		    pos[2] != ')')
3009160SSherry.Moore@Sun.COM 			return (EG_FINDROOTFMT);
3019160SSherry.Moore@Sun.COM 	} else {
3029160SSherry.Moore@Sun.COM 		sz = strlen(sign);
3039160SSherry.Moore@Sun.COM 	}
3049160SSherry.Moore@Sun.COM 
3059160SSherry.Moore@Sun.COM 	bsz = strlen(BOOTSIGN_DIR "/");
3069160SSherry.Moore@Sun.COM 	if (bsz + sz + 1 > sizeof (barg->gb_bootsign))
3079160SSherry.Moore@Sun.COM 		return (E2BIG);
3089160SSherry.Moore@Sun.COM 
3099160SSherry.Moore@Sun.COM 	bcopy(BOOTSIGN_DIR "/", barg->gb_bootsign, bsz);
3109160SSherry.Moore@Sun.COM 	bcopy(sign, barg->gb_bootsign + bsz, sz);
3119160SSherry.Moore@Sun.COM 	barg->gb_bootsign [bsz + sz] = 0;
3129160SSherry.Moore@Sun.COM 
3139160SSherry.Moore@Sun.COM 	return (grub_find_bootsign(barg));
3149160SSherry.Moore@Sun.COM }
3159160SSherry.Moore@Sun.COM 
3169160SSherry.Moore@Sun.COM int
3179160SSherry.Moore@Sun.COM bootfs(const grub_line_t *lp, grub_barg_t *barg)
3189160SSherry.Moore@Sun.COM {
3199160SSherry.Moore@Sun.COM 	zfs_handle_t	*zfh;
3209160SSherry.Moore@Sun.COM 	grub_menu_t	*mp = barg->gb_entry->ge_menu;
3219160SSherry.Moore@Sun.COM 	char		*gfs_devp;
3229160SSherry.Moore@Sun.COM 	size_t		gfs_dev_len;
3239160SSherry.Moore@Sun.COM 
3249160SSherry.Moore@Sun.COM 	/* Check if root is zfs */
3259160SSherry.Moore@Sun.COM 	if (strcmp(barg->gb_root.gr_fstyp, MNTTYPE_ZFS) != 0)
3269160SSherry.Moore@Sun.COM 		return (EG_NOTZFS);
3279160SSherry.Moore@Sun.COM 
3289160SSherry.Moore@Sun.COM 	gfs_devp = barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev;
3299160SSherry.Moore@Sun.COM 	gfs_dev_len = sizeof (barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev);
3309160SSherry.Moore@Sun.COM 
3319160SSherry.Moore@Sun.COM 	/*
3329160SSherry.Moore@Sun.COM 	 * If the bootfs value is the same as the bootfs for the pool,
3339160SSherry.Moore@Sun.COM 	 * do nothing.
3349160SSherry.Moore@Sun.COM 	 */
3359160SSherry.Moore@Sun.COM 	if (strcmp(lp->gl_arg, gfs_devp) == 0)
3369160SSherry.Moore@Sun.COM 		return (0);
3379160SSherry.Moore@Sun.COM 
3389160SSherry.Moore@Sun.COM 	if (strlcpy(gfs_devp, lp->gl_arg, gfs_dev_len) >= gfs_dev_len)
3399160SSherry.Moore@Sun.COM 		return (E2BIG);
3409160SSherry.Moore@Sun.COM 
3419160SSherry.Moore@Sun.COM 	/* check if specified bootfs belongs to the root pool */
3429160SSherry.Moore@Sun.COM 	if ((zfh = zfs_open(mp->gm_fs.gf_lzfh,
3439160SSherry.Moore@Sun.COM 	    barg->gb_root.gr_fs[GRBM_ZFS_TOPFS].gfs_dev,
3449160SSherry.Moore@Sun.COM 	    ZFS_TYPE_FILESYSTEM)) == NULL)
3459160SSherry.Moore@Sun.COM 		return (EG_OPENZFS);
3469160SSherry.Moore@Sun.COM 
3479160SSherry.Moore@Sun.COM 	barg->gb_walkret = EG_UNKBOOTFS;
3489160SSherry.Moore@Sun.COM 	(void) zfs_iter_filesystems(zfh, match_bootfs, barg);
3499160SSherry.Moore@Sun.COM 	zfs_close(zfh);
3509160SSherry.Moore@Sun.COM 
3519160SSherry.Moore@Sun.COM 	if (barg->gb_walkret == 0)
3529160SSherry.Moore@Sun.COM 		(void) grub_fsd_get_mountp(barg->gb_root.gr_fs +
3539160SSherry.Moore@Sun.COM 		    GRBM_ZFS_BOOTFS, MNTTYPE_ZFS);
3549160SSherry.Moore@Sun.COM 
3559160SSherry.Moore@Sun.COM 	return (barg->gb_walkret);
3569160SSherry.Moore@Sun.COM }
357