xref: /onnv-gate/usr/src/lib/libgrubmgmt/common/libgrub_cmd.c (revision 9769:35075388110e)
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 
51*9769SKonstantin.Ananyev@Sun.COM #define	BPROP_ZFSBOOTFS	"zfs-bootfs"
52*9769SKonstantin.Ananyev@Sun.COM #define	BPROP_BOOTPATH	"bootpath"
53*9769SKonstantin.Ananyev@Sun.COM 
549160SSherry.Moore@Sun.COM #if defined(__i386)
559160SSherry.Moore@Sun.COM static const char cpuid_dev[] = "/dev/cpu/self/cpuid";
569160SSherry.Moore@Sun.COM 
579160SSherry.Moore@Sun.COM /*
589160SSherry.Moore@Sun.COM  * Return 1 if the system supports 64-bit mode, 0 if it doesn't,
599160SSherry.Moore@Sun.COM  * or -1 on failure.
609160SSherry.Moore@Sun.COM  */
619160SSherry.Moore@Sun.COM static int
cpuid_64bit_capable(void)629160SSherry.Moore@Sun.COM cpuid_64bit_capable(void)
639160SSherry.Moore@Sun.COM {
649160SSherry.Moore@Sun.COM 	int fd, ret = -1;
659160SSherry.Moore@Sun.COM 	struct {
669160SSherry.Moore@Sun.COM 		uint32_t cp_eax, cp_ebx, cp_ecx, cp_edx;
679160SSherry.Moore@Sun.COM 	} cpuid_regs;
689160SSherry.Moore@Sun.COM 
699160SSherry.Moore@Sun.COM 	if ((fd = open(cpuid_dev, O_RDONLY)) == -1)
709160SSherry.Moore@Sun.COM 		return (ret);
719160SSherry.Moore@Sun.COM 
729160SSherry.Moore@Sun.COM 	if (pread(fd, &cpuid_regs, sizeof (cpuid_regs), 0x80000001) ==
739160SSherry.Moore@Sun.COM 	    sizeof (cpuid_regs))
749160SSherry.Moore@Sun.COM 		ret = ((CPUID_AMD_EDX_LM & cpuid_regs.cp_edx) != 0);
759160SSherry.Moore@Sun.COM 
769160SSherry.Moore@Sun.COM 	(void) close(fd);
779160SSherry.Moore@Sun.COM 	return (ret);
789160SSherry.Moore@Sun.COM }
799160SSherry.Moore@Sun.COM #endif /* __i386 */
809160SSherry.Moore@Sun.COM 
819160SSherry.Moore@Sun.COM 
829160SSherry.Moore@Sun.COM /*
839160SSherry.Moore@Sun.COM  * Expand $ISAIDR
849160SSherry.Moore@Sun.COM  */
859160SSherry.Moore@Sun.COM #if !defined(__i386)
869160SSherry.Moore@Sun.COM /* ARGSUSED */
879160SSherry.Moore@Sun.COM #endif /* __i386 */
889160SSherry.Moore@Sun.COM static size_t
barg_isadir_var(char * var,int sz)899160SSherry.Moore@Sun.COM barg_isadir_var(char *var, int sz)
909160SSherry.Moore@Sun.COM {
919160SSherry.Moore@Sun.COM #if defined(__i386)
929160SSherry.Moore@Sun.COM 	if (cpuid_64bit_capable() == 1)
939160SSherry.Moore@Sun.COM 		return (strlcpy(var, "amd64", sz));
949160SSherry.Moore@Sun.COM #endif /* __i386 */
959160SSherry.Moore@Sun.COM 
969160SSherry.Moore@Sun.COM 	var[0] = 0;
979160SSherry.Moore@Sun.COM 	return (0);
989160SSherry.Moore@Sun.COM }
999160SSherry.Moore@Sun.COM 
1009160SSherry.Moore@Sun.COM /*
1019160SSherry.Moore@Sun.COM  * Expand $ZFS-BOOTFS
1029160SSherry.Moore@Sun.COM  */
1039160SSherry.Moore@Sun.COM static size_t
barg_bootfs_var(const grub_barg_t * barg,char * var,int sz)1049160SSherry.Moore@Sun.COM barg_bootfs_var(const grub_barg_t *barg, char *var, int sz)
1059160SSherry.Moore@Sun.COM {
1069160SSherry.Moore@Sun.COM 	int n;
1079160SSherry.Moore@Sun.COM 
1089160SSherry.Moore@Sun.COM 	assert(barg);
1099160SSherry.Moore@Sun.COM 	if (strcmp(barg->gb_root.gr_fstyp, MNTTYPE_ZFS) == 0) {
110*9769SKonstantin.Ananyev@Sun.COM 		n = snprintf(var, sz,
111*9769SKonstantin.Ananyev@Sun.COM 		    BPROP_ZFSBOOTFS "=%s," BPROP_BOOTPATH "=\"%s\"",
1129160SSherry.Moore@Sun.COM 		    barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev,
1139160SSherry.Moore@Sun.COM 		    barg->gb_root.gr_physpath);
1149160SSherry.Moore@Sun.COM 	} else	{
1159160SSherry.Moore@Sun.COM 		var[0] = 0;
1169160SSherry.Moore@Sun.COM 		n = 0;
1179160SSherry.Moore@Sun.COM 	}
1189160SSherry.Moore@Sun.COM 	return (n);
1199160SSherry.Moore@Sun.COM }
1209160SSherry.Moore@Sun.COM 
1219160SSherry.Moore@Sun.COM /*
1229160SSherry.Moore@Sun.COM  * Expand all the variables without appending them more than once.
1239160SSherry.Moore@Sun.COM  */
1249160SSherry.Moore@Sun.COM static int
expand_var(char * arg,size_t argsz,const char * var,size_t varsz,char * val,size_t valsz)1259160SSherry.Moore@Sun.COM expand_var(char *arg, size_t argsz, const char *var, size_t varsz,
1269160SSherry.Moore@Sun.COM     char *val, size_t valsz)
1279160SSherry.Moore@Sun.COM {
1289160SSherry.Moore@Sun.COM 	char	*sp = arg;
1299160SSherry.Moore@Sun.COM 	size_t	sz = argsz, len;
1309160SSherry.Moore@Sun.COM 	char	*buf, *dst, *src;
1319160SSherry.Moore@Sun.COM 	int	ret = 0;
1329160SSherry.Moore@Sun.COM 
1339160SSherry.Moore@Sun.COM 	buf = alloca(argsz);
1349160SSherry.Moore@Sun.COM 	dst = buf;
1359160SSherry.Moore@Sun.COM 
1369160SSherry.Moore@Sun.COM 	while ((src = strstr(sp, var)) != NULL) {
1379160SSherry.Moore@Sun.COM 
1389160SSherry.Moore@Sun.COM 		len = src - sp;
1399160SSherry.Moore@Sun.COM 
1409160SSherry.Moore@Sun.COM 		if (len + valsz > sz) {
1419160SSherry.Moore@Sun.COM 			ret = E2BIG;
1429160SSherry.Moore@Sun.COM 			break;
1439160SSherry.Moore@Sun.COM 		}
1449160SSherry.Moore@Sun.COM 
1459160SSherry.Moore@Sun.COM 		(void) bcopy(sp, dst, len);
1469160SSherry.Moore@Sun.COM 		(void) bcopy(val, dst + len, valsz);
1479160SSherry.Moore@Sun.COM 		dst += len + valsz;
1489160SSherry.Moore@Sun.COM 		sz -= len + valsz;
1499160SSherry.Moore@Sun.COM 		sp = src + varsz;
1509160SSherry.Moore@Sun.COM 	}
1519160SSherry.Moore@Sun.COM 
1529160SSherry.Moore@Sun.COM 	if (strlcpy(dst, sp, sz) >= sz)
1539160SSherry.Moore@Sun.COM 		ret = E2BIG;
1549160SSherry.Moore@Sun.COM 
1559160SSherry.Moore@Sun.COM 	if (ret == 0)
1569160SSherry.Moore@Sun.COM 		bcopy(buf, arg, argsz);
1579160SSherry.Moore@Sun.COM 	return (ret);
1589160SSherry.Moore@Sun.COM }
1599160SSherry.Moore@Sun.COM 
160*9769SKonstantin.Ananyev@Sun.COM /*
161*9769SKonstantin.Ananyev@Sun.COM  * Searches first occurence of boot-property 'bprop' in str.
162*9769SKonstantin.Ananyev@Sun.COM  * str supposed to be in format:
163*9769SKonstantin.Ananyev@Sun.COM  * " [-B prop=[value][,prop=[value]]...]
164*9769SKonstantin.Ananyev@Sun.COM  */
165*9769SKonstantin.Ananyev@Sun.COM static const char *
find_bootprop(const char * str,const char * bprop)166*9769SKonstantin.Ananyev@Sun.COM find_bootprop(const char *str, const char *bprop)
167*9769SKonstantin.Ananyev@Sun.COM {
168*9769SKonstantin.Ananyev@Sun.COM 	const char *s;
169*9769SKonstantin.Ananyev@Sun.COM 	size_t bplen, len;
170*9769SKonstantin.Ananyev@Sun.COM 
171*9769SKonstantin.Ananyev@Sun.COM 	assert(str);
172*9769SKonstantin.Ananyev@Sun.COM 	assert(bprop);
173*9769SKonstantin.Ananyev@Sun.COM 
174*9769SKonstantin.Ananyev@Sun.COM 	bplen = strlen(bprop);
175*9769SKonstantin.Ananyev@Sun.COM 	s = str;
176*9769SKonstantin.Ananyev@Sun.COM 
177*9769SKonstantin.Ananyev@Sun.COM 	while ((str = strstr(s, " -B")) != NULL ||
178*9769SKonstantin.Ananyev@Sun.COM 	    (str = strstr(s, "\t-B")) != NULL) {
179*9769SKonstantin.Ananyev@Sun.COM 		s = str + 3;
180*9769SKonstantin.Ananyev@Sun.COM 		len = strspn(s, " \t");
181*9769SKonstantin.Ananyev@Sun.COM 
182*9769SKonstantin.Ananyev@Sun.COM 		/* empty -B option, skip it */
183*9769SKonstantin.Ananyev@Sun.COM 		if (len != 0 && s[len] == '-')
184*9769SKonstantin.Ananyev@Sun.COM 			continue;
185*9769SKonstantin.Ananyev@Sun.COM 
186*9769SKonstantin.Ananyev@Sun.COM 		s += len;
187*9769SKonstantin.Ananyev@Sun.COM 		do {
188*9769SKonstantin.Ananyev@Sun.COM 			len = strcspn(s, "= \t");
189*9769SKonstantin.Ananyev@Sun.COM 			if (s[len] !=  '=')
190*9769SKonstantin.Ananyev@Sun.COM 				break;
191*9769SKonstantin.Ananyev@Sun.COM 
192*9769SKonstantin.Ananyev@Sun.COM 			/* boot property we are looking for? */
193*9769SKonstantin.Ananyev@Sun.COM 			if (len == bplen && strncmp(s, bprop, bplen) == 0)
194*9769SKonstantin.Ananyev@Sun.COM 				return (s);
195*9769SKonstantin.Ananyev@Sun.COM 
196*9769SKonstantin.Ananyev@Sun.COM 			s += len;
197*9769SKonstantin.Ananyev@Sun.COM 
198*9769SKonstantin.Ananyev@Sun.COM 			/* skip boot property value */
199*9769SKonstantin.Ananyev@Sun.COM 			while ((s = strpbrk(s + 1, "\"\', \t")) != NULL) {
200*9769SKonstantin.Ananyev@Sun.COM 
201*9769SKonstantin.Ananyev@Sun.COM 				/* skip quoted */
202*9769SKonstantin.Ananyev@Sun.COM 				if (s[0] == '\"' || s[0] == '\'') {
203*9769SKonstantin.Ananyev@Sun.COM 					if ((s = strchr(s + 1, s[0])) == NULL) {
204*9769SKonstantin.Ananyev@Sun.COM 						/* unbalanced quotes */
205*9769SKonstantin.Ananyev@Sun.COM 						return (s);
206*9769SKonstantin.Ananyev@Sun.COM 					}
207*9769SKonstantin.Ananyev@Sun.COM 				}
208*9769SKonstantin.Ananyev@Sun.COM 				else
209*9769SKonstantin.Ananyev@Sun.COM 					break;
210*9769SKonstantin.Ananyev@Sun.COM 			}
211*9769SKonstantin.Ananyev@Sun.COM 
212*9769SKonstantin.Ananyev@Sun.COM 			/* no more boot properties */
213*9769SKonstantin.Ananyev@Sun.COM 			if (s == NULL)
214*9769SKonstantin.Ananyev@Sun.COM 				return (s);
215*9769SKonstantin.Ananyev@Sun.COM 
216*9769SKonstantin.Ananyev@Sun.COM 			/* no more boot properties in that -B block */
217*9769SKonstantin.Ananyev@Sun.COM 			if (s[0] != ',')
218*9769SKonstantin.Ananyev@Sun.COM 				break;
219*9769SKonstantin.Ananyev@Sun.COM 
220*9769SKonstantin.Ananyev@Sun.COM 			s += strspn(s, ",");
221*9769SKonstantin.Ananyev@Sun.COM 		} while (s[0] != ' ' && s[0] != '\t');
222*9769SKonstantin.Ananyev@Sun.COM 	}
223*9769SKonstantin.Ananyev@Sun.COM 	return (NULL);
224*9769SKonstantin.Ananyev@Sun.COM }
225*9769SKonstantin.Ananyev@Sun.COM 
226*9769SKonstantin.Ananyev@Sun.COM /*
227*9769SKonstantin.Ananyev@Sun.COM  * Add bootpath property to str if
228*9769SKonstantin.Ananyev@Sun.COM  * 	1. zfs-bootfs property is set explicitly
229*9769SKonstantin.Ananyev@Sun.COM  * and
230*9769SKonstantin.Ananyev@Sun.COM  * 	2. bootpath property is not set
231*9769SKonstantin.Ananyev@Sun.COM  */
232*9769SKonstantin.Ananyev@Sun.COM static int
update_bootpath(char * str,size_t strsz,const char * bootpath)233*9769SKonstantin.Ananyev@Sun.COM update_bootpath(char *str, size_t strsz, const char *bootpath)
234*9769SKonstantin.Ananyev@Sun.COM {
235*9769SKonstantin.Ananyev@Sun.COM 	size_t n;
236*9769SKonstantin.Ananyev@Sun.COM 	char *buf;
237*9769SKonstantin.Ananyev@Sun.COM 	const char *bfs;
238*9769SKonstantin.Ananyev@Sun.COM 
239*9769SKonstantin.Ananyev@Sun.COM 	/* zfs-bootfs is not specified, or bootpath is allready set */
240*9769SKonstantin.Ananyev@Sun.COM 	if ((bfs = find_bootprop(str, BPROP_ZFSBOOTFS)) == NULL ||
241*9769SKonstantin.Ananyev@Sun.COM 	    find_bootprop(str, BPROP_BOOTPATH) != NULL)
242*9769SKonstantin.Ananyev@Sun.COM 		return (0);
243*9769SKonstantin.Ananyev@Sun.COM 
244*9769SKonstantin.Ananyev@Sun.COM 	n = bfs - str;
245*9769SKonstantin.Ananyev@Sun.COM 	buf = alloca(strsz);
246*9769SKonstantin.Ananyev@Sun.COM 
247*9769SKonstantin.Ananyev@Sun.COM 	bcopy(str, buf, n);
248*9769SKonstantin.Ananyev@Sun.COM 	if (snprintf(buf + n, strsz - n, BPROP_BOOTPATH "=\"%s\",%s",
249*9769SKonstantin.Ananyev@Sun.COM 	    bootpath, bfs) >= strsz - n)
250*9769SKonstantin.Ananyev@Sun.COM 		return (E2BIG);
251*9769SKonstantin.Ananyev@Sun.COM 
252*9769SKonstantin.Ananyev@Sun.COM 	bcopy(buf, str, strsz);
253*9769SKonstantin.Ananyev@Sun.COM 	return (0);
254*9769SKonstantin.Ananyev@Sun.COM }
255*9769SKonstantin.Ananyev@Sun.COM 
2569160SSherry.Moore@Sun.COM static int
match_bootfs(zfs_handle_t * zfh,void * data)2579160SSherry.Moore@Sun.COM match_bootfs(zfs_handle_t *zfh, void *data)
2589160SSherry.Moore@Sun.COM {
2599160SSherry.Moore@Sun.COM 	int		ret;
2609160SSherry.Moore@Sun.COM 	const char	*zfn;
2619160SSherry.Moore@Sun.COM 	grub_barg_t	*barg = (grub_barg_t *)data;
2629160SSherry.Moore@Sun.COM 
2639160SSherry.Moore@Sun.COM 	ret = (zfs_get_type(zfh) == ZFS_TYPE_FILESYSTEM &&
2649160SSherry.Moore@Sun.COM 	    (zfn = zfs_get_name(zfh)) != NULL &&
2659160SSherry.Moore@Sun.COM 	    strcmp(barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev, zfn) == 0);
2669160SSherry.Moore@Sun.COM 
2679160SSherry.Moore@Sun.COM 	if (ret != 0)
2689160SSherry.Moore@Sun.COM 		barg->gb_walkret = 0;
2699160SSherry.Moore@Sun.COM 	else
2709160SSherry.Moore@Sun.COM 		(void) zfs_iter_filesystems(zfh, match_bootfs, barg);
2719160SSherry.Moore@Sun.COM 
2729160SSherry.Moore@Sun.COM 	zfs_close(zfh);
2739160SSherry.Moore@Sun.COM 	return (barg->gb_walkret == 0);
2749160SSherry.Moore@Sun.COM }
2759160SSherry.Moore@Sun.COM 
2769160SSherry.Moore@Sun.COM static void
reset_root(grub_barg_t * barg)2779160SSherry.Moore@Sun.COM reset_root(grub_barg_t *barg)
2789160SSherry.Moore@Sun.COM {
2799160SSherry.Moore@Sun.COM 	(void) memset(&barg->gb_root, 0, sizeof (barg->gb_root));
2809160SSherry.Moore@Sun.COM 	barg->gb_bootsign[0] = 0;
2819160SSherry.Moore@Sun.COM 	barg->gb_kernel[0] = 0;
2829160SSherry.Moore@Sun.COM 	RESET_MODULE(barg);
2839160SSherry.Moore@Sun.COM }
2849160SSherry.Moore@Sun.COM 
2859160SSherry.Moore@Sun.COM /* ARGSUSED */
2869160SSherry.Moore@Sun.COM int
skip_line(const grub_line_t * lp,grub_barg_t * barg)2879160SSherry.Moore@Sun.COM skip_line(const grub_line_t *lp, grub_barg_t *barg)
2889160SSherry.Moore@Sun.COM {
2899160SSherry.Moore@Sun.COM 	return (0);
2909160SSherry.Moore@Sun.COM }
2919160SSherry.Moore@Sun.COM 
2929160SSherry.Moore@Sun.COM /* ARGSUSED */
2939160SSherry.Moore@Sun.COM int
error_line(const grub_line_t * lp,grub_barg_t * barg)2949160SSherry.Moore@Sun.COM error_line(const grub_line_t *lp, grub_barg_t *barg)
2959160SSherry.Moore@Sun.COM {
2969444SKonstantin.Ananyev@Sun.COM 	if (lp->gl_cmdtp == GRBM_ROOT_CMD)
2979444SKonstantin.Ananyev@Sun.COM 		return (EG_ROOTNOTSUPP);
2989160SSherry.Moore@Sun.COM 	return (EG_INVALIDLINE);
2999160SSherry.Moore@Sun.COM }
3009160SSherry.Moore@Sun.COM 
3019160SSherry.Moore@Sun.COM int
kernel(const grub_line_t * lp,grub_barg_t * barg)3029160SSherry.Moore@Sun.COM kernel(const grub_line_t *lp, grub_barg_t *barg)
3039160SSherry.Moore@Sun.COM {
3049160SSherry.Moore@Sun.COM 	RESET_MODULE(barg);
3059160SSherry.Moore@Sun.COM 	if (strlcpy(barg->gb_kernel, lp->gl_arg, sizeof (barg->gb_kernel)) >=
3069160SSherry.Moore@Sun.COM 	    sizeof (barg->gb_kernel))
3079160SSherry.Moore@Sun.COM 		return (E2BIG);
3089160SSherry.Moore@Sun.COM 
3099160SSherry.Moore@Sun.COM 	return (0);
3109160SSherry.Moore@Sun.COM }
3119160SSherry.Moore@Sun.COM 
3129160SSherry.Moore@Sun.COM int
module(const grub_line_t * lp,grub_barg_t * barg)3139160SSherry.Moore@Sun.COM module(const grub_line_t *lp, grub_barg_t *barg)
3149160SSherry.Moore@Sun.COM {
3159160SSherry.Moore@Sun.COM 	if (strlcpy(barg->gb_module, lp->gl_arg, sizeof (barg->gb_module)) >=
3169160SSherry.Moore@Sun.COM 	    sizeof (barg->gb_module))
3179160SSherry.Moore@Sun.COM 		return (E2BIG);
3189160SSherry.Moore@Sun.COM 
3199160SSherry.Moore@Sun.COM 	return (0);
3209160SSherry.Moore@Sun.COM }
3219160SSherry.Moore@Sun.COM 
3229160SSherry.Moore@Sun.COM int
dollar_kernel(const grub_line_t * lp,grub_barg_t * barg)3239160SSherry.Moore@Sun.COM dollar_kernel(const grub_line_t *lp, grub_barg_t *barg)
3249160SSherry.Moore@Sun.COM {
3259160SSherry.Moore@Sun.COM 	int	ret;
3269160SSherry.Moore@Sun.COM 	size_t	bfslen, isalen;
3279160SSherry.Moore@Sun.COM 	char	isadir[32];
3289160SSherry.Moore@Sun.COM 	char	bootfs[BOOTARGS_MAX];
3299160SSherry.Moore@Sun.COM 
3309160SSherry.Moore@Sun.COM 	RESET_MODULE(barg);
3319160SSherry.Moore@Sun.COM 	if (strlcpy(barg->gb_kernel, lp->gl_arg, sizeof (barg->gb_kernel)) >=
3329160SSherry.Moore@Sun.COM 	    sizeof (barg->gb_kernel))
3339160SSherry.Moore@Sun.COM 		return (E2BIG);
3349160SSherry.Moore@Sun.COM 
3359160SSherry.Moore@Sun.COM 	bfslen = barg_bootfs_var(barg, bootfs, sizeof (bootfs));
3369160SSherry.Moore@Sun.COM 	isalen = barg_isadir_var(isadir, sizeof (isadir));
3379160SSherry.Moore@Sun.COM 
3389160SSherry.Moore@Sun.COM 	if (bfslen >= sizeof (bootfs) || isalen >= sizeof (isadir))
3399160SSherry.Moore@Sun.COM 		return (EINVAL);
3409160SSherry.Moore@Sun.COM 
3419160SSherry.Moore@Sun.COM 	if ((ret = expand_var(barg->gb_kernel, sizeof (barg->gb_kernel),
3429160SSherry.Moore@Sun.COM 	    ZFS_BOOT_VAR, strlen(ZFS_BOOT_VAR), bootfs, bfslen)) != 0)
3439160SSherry.Moore@Sun.COM 		return (ret);
3449160SSherry.Moore@Sun.COM 
345*9769SKonstantin.Ananyev@Sun.COM 	if ((ret = expand_var(barg->gb_kernel, sizeof (barg->gb_kernel),
346*9769SKonstantin.Ananyev@Sun.COM 	    ISADIR_VAR, strlen(ISADIR_VAR), isadir, isalen)) != 0)
347*9769SKonstantin.Ananyev@Sun.COM 		return (ret);
348*9769SKonstantin.Ananyev@Sun.COM 
349*9769SKonstantin.Ananyev@Sun.COM 	if (strcmp(barg->gb_root.gr_fstyp, MNTTYPE_ZFS) == 0)
350*9769SKonstantin.Ananyev@Sun.COM 		ret = update_bootpath(barg->gb_kernel, sizeof (barg->gb_kernel),
351*9769SKonstantin.Ananyev@Sun.COM 		    barg->gb_root.gr_physpath);
3529160SSherry.Moore@Sun.COM 
3539160SSherry.Moore@Sun.COM 	return (ret);
3549160SSherry.Moore@Sun.COM }
3559160SSherry.Moore@Sun.COM 
3569160SSherry.Moore@Sun.COM int
dollar_module(const grub_line_t * lp,grub_barg_t * barg)3579160SSherry.Moore@Sun.COM dollar_module(const grub_line_t *lp, grub_barg_t *barg)
3589160SSherry.Moore@Sun.COM {
3599160SSherry.Moore@Sun.COM 	int	ret;
3609160SSherry.Moore@Sun.COM 	size_t	isalen;
3619160SSherry.Moore@Sun.COM 	char	isadir[32];
3629160SSherry.Moore@Sun.COM 
3639160SSherry.Moore@Sun.COM 	if (strlcpy(barg->gb_module, lp->gl_arg, sizeof (barg->gb_module)) >=
3649160SSherry.Moore@Sun.COM 	    sizeof (barg->gb_module))
3659160SSherry.Moore@Sun.COM 		return (E2BIG);
3669160SSherry.Moore@Sun.COM 
3679160SSherry.Moore@Sun.COM 	if ((isalen = barg_isadir_var(isadir, sizeof (isadir))) >= sizeof
3689160SSherry.Moore@Sun.COM 	    (isadir))
3699160SSherry.Moore@Sun.COM 		return (EINVAL);
3709160SSherry.Moore@Sun.COM 
3719160SSherry.Moore@Sun.COM 	ret = expand_var(barg->gb_module, sizeof (barg->gb_module),
3729160SSherry.Moore@Sun.COM 	    ISADIR_VAR, strlen(ISADIR_VAR), isadir, isalen);
3739160SSherry.Moore@Sun.COM 
3749160SSherry.Moore@Sun.COM 	return (ret);
3759160SSherry.Moore@Sun.COM }
3769160SSherry.Moore@Sun.COM 
3779160SSherry.Moore@Sun.COM 
3789160SSherry.Moore@Sun.COM int
findroot(const grub_line_t * lp,grub_barg_t * barg)3799160SSherry.Moore@Sun.COM findroot(const grub_line_t *lp, grub_barg_t *barg)
3809160SSherry.Moore@Sun.COM {
3819160SSherry.Moore@Sun.COM 	size_t sz, bsz;
3829160SSherry.Moore@Sun.COM 	const char *sign;
3839160SSherry.Moore@Sun.COM 
3849160SSherry.Moore@Sun.COM 	reset_root(barg);
3859160SSherry.Moore@Sun.COM 
3869160SSherry.Moore@Sun.COM 	sign = lp->gl_arg;
3879160SSherry.Moore@Sun.COM 	barg->gb_prtnum = (uint_t)PRTNUM_INVALID;
3889160SSherry.Moore@Sun.COM 	barg->gb_slcnum = (uint_t)SLCNUM_WHOLE_DISK;
3899160SSherry.Moore@Sun.COM 
3909160SSherry.Moore@Sun.COM 	if (sign[0] == '(') {
3919160SSherry.Moore@Sun.COM 		const char *pos;
3929160SSherry.Moore@Sun.COM 
3939160SSherry.Moore@Sun.COM 		++sign;
3949160SSherry.Moore@Sun.COM 		if ((pos = strchr(sign, ',')) == NULL || (sz = pos - sign) == 0)
3959160SSherry.Moore@Sun.COM 			return (EG_FINDROOTFMT);
3969160SSherry.Moore@Sun.COM 
3979160SSherry.Moore@Sun.COM 		++pos;
3989160SSherry.Moore@Sun.COM 		if (!IS_PRTNUM_VALID(barg->gb_prtnum = pos[0] - '0'))
3999160SSherry.Moore@Sun.COM 			return (EG_FINDROOTFMT);
4009160SSherry.Moore@Sun.COM 
4019160SSherry.Moore@Sun.COM 		++pos;
4029160SSherry.Moore@Sun.COM 		if (pos[0] != ',' ||
4039160SSherry.Moore@Sun.COM 		    !IS_SLCNUM_VALID(barg->gb_slcnum = pos[1]) ||
4049160SSherry.Moore@Sun.COM 		    pos[2] != ')')
4059160SSherry.Moore@Sun.COM 			return (EG_FINDROOTFMT);
4069160SSherry.Moore@Sun.COM 	} else {
4079160SSherry.Moore@Sun.COM 		sz = strlen(sign);
4089160SSherry.Moore@Sun.COM 	}
4099160SSherry.Moore@Sun.COM 
4109160SSherry.Moore@Sun.COM 	bsz = strlen(BOOTSIGN_DIR "/");
4119160SSherry.Moore@Sun.COM 	if (bsz + sz + 1 > sizeof (barg->gb_bootsign))
4129160SSherry.Moore@Sun.COM 		return (E2BIG);
4139160SSherry.Moore@Sun.COM 
4149160SSherry.Moore@Sun.COM 	bcopy(BOOTSIGN_DIR "/", barg->gb_bootsign, bsz);
4159160SSherry.Moore@Sun.COM 	bcopy(sign, barg->gb_bootsign + bsz, sz);
4169160SSherry.Moore@Sun.COM 	barg->gb_bootsign [bsz + sz] = 0;
4179160SSherry.Moore@Sun.COM 
4189160SSherry.Moore@Sun.COM 	return (grub_find_bootsign(barg));
4199160SSherry.Moore@Sun.COM }
4209160SSherry.Moore@Sun.COM 
4219160SSherry.Moore@Sun.COM int
bootfs(const grub_line_t * lp,grub_barg_t * barg)4229160SSherry.Moore@Sun.COM bootfs(const grub_line_t *lp, grub_barg_t *barg)
4239160SSherry.Moore@Sun.COM {
4249160SSherry.Moore@Sun.COM 	zfs_handle_t	*zfh;
4259160SSherry.Moore@Sun.COM 	grub_menu_t	*mp = barg->gb_entry->ge_menu;
4269160SSherry.Moore@Sun.COM 	char		*gfs_devp;
4279160SSherry.Moore@Sun.COM 	size_t		gfs_dev_len;
4289160SSherry.Moore@Sun.COM 
4299160SSherry.Moore@Sun.COM 	/* Check if root is zfs */
4309160SSherry.Moore@Sun.COM 	if (strcmp(barg->gb_root.gr_fstyp, MNTTYPE_ZFS) != 0)
4319160SSherry.Moore@Sun.COM 		return (EG_NOTZFS);
4329160SSherry.Moore@Sun.COM 
4339160SSherry.Moore@Sun.COM 	gfs_devp = barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev;
4349160SSherry.Moore@Sun.COM 	gfs_dev_len = sizeof (barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev);
4359160SSherry.Moore@Sun.COM 
4369160SSherry.Moore@Sun.COM 	/*
4379160SSherry.Moore@Sun.COM 	 * If the bootfs value is the same as the bootfs for the pool,
4389160SSherry.Moore@Sun.COM 	 * do nothing.
4399160SSherry.Moore@Sun.COM 	 */
4409160SSherry.Moore@Sun.COM 	if (strcmp(lp->gl_arg, gfs_devp) == 0)
4419160SSherry.Moore@Sun.COM 		return (0);
4429160SSherry.Moore@Sun.COM 
4439160SSherry.Moore@Sun.COM 	if (strlcpy(gfs_devp, lp->gl_arg, gfs_dev_len) >= gfs_dev_len)
4449160SSherry.Moore@Sun.COM 		return (E2BIG);
4459160SSherry.Moore@Sun.COM 
4469160SSherry.Moore@Sun.COM 	/* check if specified bootfs belongs to the root pool */
4479160SSherry.Moore@Sun.COM 	if ((zfh = zfs_open(mp->gm_fs.gf_lzfh,
4489160SSherry.Moore@Sun.COM 	    barg->gb_root.gr_fs[GRBM_ZFS_TOPFS].gfs_dev,
4499160SSherry.Moore@Sun.COM 	    ZFS_TYPE_FILESYSTEM)) == NULL)
4509160SSherry.Moore@Sun.COM 		return (EG_OPENZFS);
4519160SSherry.Moore@Sun.COM 
4529160SSherry.Moore@Sun.COM 	barg->gb_walkret = EG_UNKBOOTFS;
4539160SSherry.Moore@Sun.COM 	(void) zfs_iter_filesystems(zfh, match_bootfs, barg);
4549160SSherry.Moore@Sun.COM 	zfs_close(zfh);
4559160SSherry.Moore@Sun.COM 
4569160SSherry.Moore@Sun.COM 	if (barg->gb_walkret == 0)
4579160SSherry.Moore@Sun.COM 		(void) grub_fsd_get_mountp(barg->gb_root.gr_fs +
4589160SSherry.Moore@Sun.COM 		    GRBM_ZFS_BOOTFS, MNTTYPE_ZFS);
4599160SSherry.Moore@Sun.COM 
4609160SSherry.Moore@Sun.COM 	return (barg->gb_walkret);
4619160SSherry.Moore@Sun.COM }
462