xref: /illumos-gate/usr/src/lib/libgrubmgmt/common/libgrub_cmd.c (revision c5aaf10a7384f952835ab63586396916a6d3437d)
1753a6d45SSherry Moore /*
2753a6d45SSherry Moore  * CDDL HEADER START
3753a6d45SSherry Moore  *
4753a6d45SSherry Moore  * The contents of this file are subject to the terms of the
5753a6d45SSherry Moore  * Common Development and Distribution License (the "License").
6753a6d45SSherry Moore  * You may not use this file except in compliance with the License.
7753a6d45SSherry Moore  *
8753a6d45SSherry Moore  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9753a6d45SSherry Moore  * or http://www.opensolaris.org/os/licensing.
10753a6d45SSherry Moore  * See the License for the specific language governing permissions
11753a6d45SSherry Moore  * and limitations under the License.
12753a6d45SSherry Moore  *
13753a6d45SSherry Moore  * When distributing Covered Code, include this CDDL HEADER in each
14753a6d45SSherry Moore  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15753a6d45SSherry Moore  * If applicable, add the following below this CDDL HEADER, with the
16753a6d45SSherry Moore  * fields enclosed by brackets "[]" replaced with your own identifying
17753a6d45SSherry Moore  * information: Portions Copyright [yyyy] [name of copyright owner]
18753a6d45SSherry Moore  *
19753a6d45SSherry Moore  * CDDL HEADER END
20753a6d45SSherry Moore  */
21753a6d45SSherry Moore /*
22753a6d45SSherry Moore  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23753a6d45SSherry Moore  * Use is subject to license terms.
24753a6d45SSherry Moore  */
25753a6d45SSherry Moore 
26753a6d45SSherry Moore /*
27753a6d45SSherry Moore  * This file contains all the functions that implement the following
28753a6d45SSherry Moore  * GRUB commands:
29753a6d45SSherry Moore  *	kernel, kernel$, module, module$, findroot, bootfs
30753a6d45SSherry Moore  * Return 0 on success, errno on failure.
31753a6d45SSherry Moore  */
32753a6d45SSherry Moore #include <stdio.h>
33753a6d45SSherry Moore #include <stdlib.h>
34753a6d45SSherry Moore #include <assert.h>
35753a6d45SSherry Moore #include <alloca.h>
36753a6d45SSherry Moore #include <errno.h>
37753a6d45SSherry Moore #include <strings.h>
38753a6d45SSherry Moore #include <unistd.h>
39753a6d45SSherry Moore #include <fcntl.h>
40753a6d45SSherry Moore #include <sys/types.h>
41753a6d45SSherry Moore #include <sys/fs/ufs_mount.h>
42753a6d45SSherry Moore #include <sys/dktp/fdisk.h>
43753a6d45SSherry Moore #if defined(__i386)
44753a6d45SSherry Moore #include <sys/x86_archext.h>
45753a6d45SSherry Moore #endif /* __i386 */
46753a6d45SSherry Moore 
47753a6d45SSherry Moore #include "libgrub_impl.h"
48753a6d45SSherry Moore 
49753a6d45SSherry Moore #define	RESET_MODULE(barg)	((barg)->gb_module[0] = 0)
50753a6d45SSherry Moore 
51*c5aaf10aSKonstantin Ananyev #define	BPROP_ZFSBOOTFS	"zfs-bootfs"
52*c5aaf10aSKonstantin Ananyev #define	BPROP_BOOTPATH	"bootpath"
53*c5aaf10aSKonstantin Ananyev 
54753a6d45SSherry Moore #if defined(__i386)
55753a6d45SSherry Moore static const char cpuid_dev[] = "/dev/cpu/self/cpuid";
56753a6d45SSherry Moore 
57753a6d45SSherry Moore /*
58753a6d45SSherry Moore  * Return 1 if the system supports 64-bit mode, 0 if it doesn't,
59753a6d45SSherry Moore  * or -1 on failure.
60753a6d45SSherry Moore  */
61753a6d45SSherry Moore static int
62753a6d45SSherry Moore cpuid_64bit_capable(void)
63753a6d45SSherry Moore {
64753a6d45SSherry Moore 	int fd, ret = -1;
65753a6d45SSherry Moore 	struct {
66753a6d45SSherry Moore 		uint32_t cp_eax, cp_ebx, cp_ecx, cp_edx;
67753a6d45SSherry Moore 	} cpuid_regs;
68753a6d45SSherry Moore 
69753a6d45SSherry Moore 	if ((fd = open(cpuid_dev, O_RDONLY)) == -1)
70753a6d45SSherry Moore 		return (ret);
71753a6d45SSherry Moore 
72753a6d45SSherry Moore 	if (pread(fd, &cpuid_regs, sizeof (cpuid_regs), 0x80000001) ==
73753a6d45SSherry Moore 	    sizeof (cpuid_regs))
74753a6d45SSherry Moore 		ret = ((CPUID_AMD_EDX_LM & cpuid_regs.cp_edx) != 0);
75753a6d45SSherry Moore 
76753a6d45SSherry Moore 	(void) close(fd);
77753a6d45SSherry Moore 	return (ret);
78753a6d45SSherry Moore }
79753a6d45SSherry Moore #endif /* __i386 */
80753a6d45SSherry Moore 
81753a6d45SSherry Moore 
82753a6d45SSherry Moore /*
83753a6d45SSherry Moore  * Expand $ISAIDR
84753a6d45SSherry Moore  */
85753a6d45SSherry Moore #if !defined(__i386)
86753a6d45SSherry Moore /* ARGSUSED */
87753a6d45SSherry Moore #endif /* __i386 */
88753a6d45SSherry Moore static size_t
89753a6d45SSherry Moore barg_isadir_var(char *var, int sz)
90753a6d45SSherry Moore {
91753a6d45SSherry Moore #if defined(__i386)
92753a6d45SSherry Moore 	if (cpuid_64bit_capable() == 1)
93753a6d45SSherry Moore 		return (strlcpy(var, "amd64", sz));
94753a6d45SSherry Moore #endif /* __i386 */
95753a6d45SSherry Moore 
96753a6d45SSherry Moore 	var[0] = 0;
97753a6d45SSherry Moore 	return (0);
98753a6d45SSherry Moore }
99753a6d45SSherry Moore 
100753a6d45SSherry Moore /*
101753a6d45SSherry Moore  * Expand $ZFS-BOOTFS
102753a6d45SSherry Moore  */
103753a6d45SSherry Moore static size_t
104753a6d45SSherry Moore barg_bootfs_var(const grub_barg_t *barg, char *var, int sz)
105753a6d45SSherry Moore {
106753a6d45SSherry Moore 	int n;
107753a6d45SSherry Moore 
108753a6d45SSherry Moore 	assert(barg);
109753a6d45SSherry Moore 	if (strcmp(barg->gb_root.gr_fstyp, MNTTYPE_ZFS) == 0) {
110*c5aaf10aSKonstantin Ananyev 		n = snprintf(var, sz,
111*c5aaf10aSKonstantin Ananyev 		    BPROP_ZFSBOOTFS "=%s," BPROP_BOOTPATH "=\"%s\"",
112753a6d45SSherry Moore 		    barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev,
113753a6d45SSherry Moore 		    barg->gb_root.gr_physpath);
114753a6d45SSherry Moore 	} else	{
115753a6d45SSherry Moore 		var[0] = 0;
116753a6d45SSherry Moore 		n = 0;
117753a6d45SSherry Moore 	}
118753a6d45SSherry Moore 	return (n);
119753a6d45SSherry Moore }
120753a6d45SSherry Moore 
121753a6d45SSherry Moore /*
122753a6d45SSherry Moore  * Expand all the variables without appending them more than once.
123753a6d45SSherry Moore  */
124753a6d45SSherry Moore static int
125753a6d45SSherry Moore expand_var(char *arg, size_t argsz, const char *var, size_t varsz,
126753a6d45SSherry Moore     char *val, size_t valsz)
127753a6d45SSherry Moore {
128753a6d45SSherry Moore 	char	*sp = arg;
129753a6d45SSherry Moore 	size_t	sz = argsz, len;
130753a6d45SSherry Moore 	char	*buf, *dst, *src;
131753a6d45SSherry Moore 	int	ret = 0;
132753a6d45SSherry Moore 
133753a6d45SSherry Moore 	buf = alloca(argsz);
134753a6d45SSherry Moore 	dst = buf;
135753a6d45SSherry Moore 
136753a6d45SSherry Moore 	while ((src = strstr(sp, var)) != NULL) {
137753a6d45SSherry Moore 
138753a6d45SSherry Moore 		len = src - sp;
139753a6d45SSherry Moore 
140753a6d45SSherry Moore 		if (len + valsz > sz) {
141753a6d45SSherry Moore 			ret = E2BIG;
142753a6d45SSherry Moore 			break;
143753a6d45SSherry Moore 		}
144753a6d45SSherry Moore 
145753a6d45SSherry Moore 		(void) bcopy(sp, dst, len);
146753a6d45SSherry Moore 		(void) bcopy(val, dst + len, valsz);
147753a6d45SSherry Moore 		dst += len + valsz;
148753a6d45SSherry Moore 		sz -= len + valsz;
149753a6d45SSherry Moore 		sp = src + varsz;
150753a6d45SSherry Moore 	}
151753a6d45SSherry Moore 
152753a6d45SSherry Moore 	if (strlcpy(dst, sp, sz) >= sz)
153753a6d45SSherry Moore 		ret = E2BIG;
154753a6d45SSherry Moore 
155753a6d45SSherry Moore 	if (ret == 0)
156753a6d45SSherry Moore 		bcopy(buf, arg, argsz);
157753a6d45SSherry Moore 	return (ret);
158753a6d45SSherry Moore }
159753a6d45SSherry Moore 
160*c5aaf10aSKonstantin Ananyev /*
161*c5aaf10aSKonstantin Ananyev  * Searches first occurence of boot-property 'bprop' in str.
162*c5aaf10aSKonstantin Ananyev  * str supposed to be in format:
163*c5aaf10aSKonstantin Ananyev  * " [-B prop=[value][,prop=[value]]...]
164*c5aaf10aSKonstantin Ananyev  */
165*c5aaf10aSKonstantin Ananyev static const char *
166*c5aaf10aSKonstantin Ananyev find_bootprop(const char *str, const char *bprop)
167*c5aaf10aSKonstantin Ananyev {
168*c5aaf10aSKonstantin Ananyev 	const char *s;
169*c5aaf10aSKonstantin Ananyev 	size_t bplen, len;
170*c5aaf10aSKonstantin Ananyev 
171*c5aaf10aSKonstantin Ananyev 	assert(str);
172*c5aaf10aSKonstantin Ananyev 	assert(bprop);
173*c5aaf10aSKonstantin Ananyev 
174*c5aaf10aSKonstantin Ananyev 	bplen = strlen(bprop);
175*c5aaf10aSKonstantin Ananyev 	s = str;
176*c5aaf10aSKonstantin Ananyev 
177*c5aaf10aSKonstantin Ananyev 	while ((str = strstr(s, " -B")) != NULL ||
178*c5aaf10aSKonstantin Ananyev 	    (str = strstr(s, "\t-B")) != NULL) {
179*c5aaf10aSKonstantin Ananyev 		s = str + 3;
180*c5aaf10aSKonstantin Ananyev 		len = strspn(s, " \t");
181*c5aaf10aSKonstantin Ananyev 
182*c5aaf10aSKonstantin Ananyev 		/* empty -B option, skip it */
183*c5aaf10aSKonstantin Ananyev 		if (len != 0 && s[len] == '-')
184*c5aaf10aSKonstantin Ananyev 			continue;
185*c5aaf10aSKonstantin Ananyev 
186*c5aaf10aSKonstantin Ananyev 		s += len;
187*c5aaf10aSKonstantin Ananyev 		do {
188*c5aaf10aSKonstantin Ananyev 			len = strcspn(s, "= \t");
189*c5aaf10aSKonstantin Ananyev 			if (s[len] !=  '=')
190*c5aaf10aSKonstantin Ananyev 				break;
191*c5aaf10aSKonstantin Ananyev 
192*c5aaf10aSKonstantin Ananyev 			/* boot property we are looking for? */
193*c5aaf10aSKonstantin Ananyev 			if (len == bplen && strncmp(s, bprop, bplen) == 0)
194*c5aaf10aSKonstantin Ananyev 				return (s);
195*c5aaf10aSKonstantin Ananyev 
196*c5aaf10aSKonstantin Ananyev 			s += len;
197*c5aaf10aSKonstantin Ananyev 
198*c5aaf10aSKonstantin Ananyev 			/* skip boot property value */
199*c5aaf10aSKonstantin Ananyev 			while ((s = strpbrk(s + 1, "\"\', \t")) != NULL) {
200*c5aaf10aSKonstantin Ananyev 
201*c5aaf10aSKonstantin Ananyev 				/* skip quoted */
202*c5aaf10aSKonstantin Ananyev 				if (s[0] == '\"' || s[0] == '\'') {
203*c5aaf10aSKonstantin Ananyev 					if ((s = strchr(s + 1, s[0])) == NULL) {
204*c5aaf10aSKonstantin Ananyev 						/* unbalanced quotes */
205*c5aaf10aSKonstantin Ananyev 						return (s);
206*c5aaf10aSKonstantin Ananyev 					}
207*c5aaf10aSKonstantin Ananyev 				}
208*c5aaf10aSKonstantin Ananyev 				else
209*c5aaf10aSKonstantin Ananyev 					break;
210*c5aaf10aSKonstantin Ananyev 			}
211*c5aaf10aSKonstantin Ananyev 
212*c5aaf10aSKonstantin Ananyev 			/* no more boot properties */
213*c5aaf10aSKonstantin Ananyev 			if (s == NULL)
214*c5aaf10aSKonstantin Ananyev 				return (s);
215*c5aaf10aSKonstantin Ananyev 
216*c5aaf10aSKonstantin Ananyev 			/* no more boot properties in that -B block */
217*c5aaf10aSKonstantin Ananyev 			if (s[0] != ',')
218*c5aaf10aSKonstantin Ananyev 				break;
219*c5aaf10aSKonstantin Ananyev 
220*c5aaf10aSKonstantin Ananyev 			s += strspn(s, ",");
221*c5aaf10aSKonstantin Ananyev 		} while (s[0] != ' ' && s[0] != '\t');
222*c5aaf10aSKonstantin Ananyev 	}
223*c5aaf10aSKonstantin Ananyev 	return (NULL);
224*c5aaf10aSKonstantin Ananyev }
225*c5aaf10aSKonstantin Ananyev 
226*c5aaf10aSKonstantin Ananyev /*
227*c5aaf10aSKonstantin Ananyev  * Add bootpath property to str if
228*c5aaf10aSKonstantin Ananyev  * 	1. zfs-bootfs property is set explicitly
229*c5aaf10aSKonstantin Ananyev  * and
230*c5aaf10aSKonstantin Ananyev  * 	2. bootpath property is not set
231*c5aaf10aSKonstantin Ananyev  */
232*c5aaf10aSKonstantin Ananyev static int
233*c5aaf10aSKonstantin Ananyev update_bootpath(char *str, size_t strsz, const char *bootpath)
234*c5aaf10aSKonstantin Ananyev {
235*c5aaf10aSKonstantin Ananyev 	size_t n;
236*c5aaf10aSKonstantin Ananyev 	char *buf;
237*c5aaf10aSKonstantin Ananyev 	const char *bfs;
238*c5aaf10aSKonstantin Ananyev 
239*c5aaf10aSKonstantin Ananyev 	/* zfs-bootfs is not specified, or bootpath is allready set */
240*c5aaf10aSKonstantin Ananyev 	if ((bfs = find_bootprop(str, BPROP_ZFSBOOTFS)) == NULL ||
241*c5aaf10aSKonstantin Ananyev 	    find_bootprop(str, BPROP_BOOTPATH) != NULL)
242*c5aaf10aSKonstantin Ananyev 		return (0);
243*c5aaf10aSKonstantin Ananyev 
244*c5aaf10aSKonstantin Ananyev 	n = bfs - str;
245*c5aaf10aSKonstantin Ananyev 	buf = alloca(strsz);
246*c5aaf10aSKonstantin Ananyev 
247*c5aaf10aSKonstantin Ananyev 	bcopy(str, buf, n);
248*c5aaf10aSKonstantin Ananyev 	if (snprintf(buf + n, strsz - n, BPROP_BOOTPATH "=\"%s\",%s",
249*c5aaf10aSKonstantin Ananyev 	    bootpath, bfs) >= strsz - n)
250*c5aaf10aSKonstantin Ananyev 		return (E2BIG);
251*c5aaf10aSKonstantin Ananyev 
252*c5aaf10aSKonstantin Ananyev 	bcopy(buf, str, strsz);
253*c5aaf10aSKonstantin Ananyev 	return (0);
254*c5aaf10aSKonstantin Ananyev }
255*c5aaf10aSKonstantin Ananyev 
256753a6d45SSherry Moore static int
257753a6d45SSherry Moore match_bootfs(zfs_handle_t *zfh, void *data)
258753a6d45SSherry Moore {
259753a6d45SSherry Moore 	int		ret;
260753a6d45SSherry Moore 	const char	*zfn;
261753a6d45SSherry Moore 	grub_barg_t	*barg = (grub_barg_t *)data;
262753a6d45SSherry Moore 
263753a6d45SSherry Moore 	ret = (zfs_get_type(zfh) == ZFS_TYPE_FILESYSTEM &&
264753a6d45SSherry Moore 	    (zfn = zfs_get_name(zfh)) != NULL &&
265753a6d45SSherry Moore 	    strcmp(barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev, zfn) == 0);
266753a6d45SSherry Moore 
267753a6d45SSherry Moore 	if (ret != 0)
268753a6d45SSherry Moore 		barg->gb_walkret = 0;
269753a6d45SSherry Moore 	else
270753a6d45SSherry Moore 		(void) zfs_iter_filesystems(zfh, match_bootfs, barg);
271753a6d45SSherry Moore 
272753a6d45SSherry Moore 	zfs_close(zfh);
273753a6d45SSherry Moore 	return (barg->gb_walkret == 0);
274753a6d45SSherry Moore }
275753a6d45SSherry Moore 
276753a6d45SSherry Moore static void
277753a6d45SSherry Moore reset_root(grub_barg_t *barg)
278753a6d45SSherry Moore {
279753a6d45SSherry Moore 	(void) memset(&barg->gb_root, 0, sizeof (barg->gb_root));
280753a6d45SSherry Moore 	barg->gb_bootsign[0] = 0;
281753a6d45SSherry Moore 	barg->gb_kernel[0] = 0;
282753a6d45SSherry Moore 	RESET_MODULE(barg);
283753a6d45SSherry Moore }
284753a6d45SSherry Moore 
285753a6d45SSherry Moore /* ARGSUSED */
286753a6d45SSherry Moore int
287753a6d45SSherry Moore skip_line(const grub_line_t *lp, grub_barg_t *barg)
288753a6d45SSherry Moore {
289753a6d45SSherry Moore 	return (0);
290753a6d45SSherry Moore }
291753a6d45SSherry Moore 
292753a6d45SSherry Moore /* ARGSUSED */
293753a6d45SSherry Moore int
294753a6d45SSherry Moore error_line(const grub_line_t *lp, grub_barg_t *barg)
295753a6d45SSherry Moore {
296fda66240SKonstantin Ananyev 	if (lp->gl_cmdtp == GRBM_ROOT_CMD)
297fda66240SKonstantin Ananyev 		return (EG_ROOTNOTSUPP);
298753a6d45SSherry Moore 	return (EG_INVALIDLINE);
299753a6d45SSherry Moore }
300753a6d45SSherry Moore 
301753a6d45SSherry Moore int
302753a6d45SSherry Moore kernel(const grub_line_t *lp, grub_barg_t *barg)
303753a6d45SSherry Moore {
304753a6d45SSherry Moore 	RESET_MODULE(barg);
305753a6d45SSherry Moore 	if (strlcpy(barg->gb_kernel, lp->gl_arg, sizeof (barg->gb_kernel)) >=
306753a6d45SSherry Moore 	    sizeof (barg->gb_kernel))
307753a6d45SSherry Moore 		return (E2BIG);
308753a6d45SSherry Moore 
309753a6d45SSherry Moore 	return (0);
310753a6d45SSherry Moore }
311753a6d45SSherry Moore 
312753a6d45SSherry Moore int
313753a6d45SSherry Moore module(const grub_line_t *lp, grub_barg_t *barg)
314753a6d45SSherry Moore {
315753a6d45SSherry Moore 	if (strlcpy(barg->gb_module, lp->gl_arg, sizeof (barg->gb_module)) >=
316753a6d45SSherry Moore 	    sizeof (barg->gb_module))
317753a6d45SSherry Moore 		return (E2BIG);
318753a6d45SSherry Moore 
319753a6d45SSherry Moore 	return (0);
320753a6d45SSherry Moore }
321753a6d45SSherry Moore 
322753a6d45SSherry Moore int
323753a6d45SSherry Moore dollar_kernel(const grub_line_t *lp, grub_barg_t *barg)
324753a6d45SSherry Moore {
325753a6d45SSherry Moore 	int	ret;
326753a6d45SSherry Moore 	size_t	bfslen, isalen;
327753a6d45SSherry Moore 	char	isadir[32];
328753a6d45SSherry Moore 	char	bootfs[BOOTARGS_MAX];
329753a6d45SSherry Moore 
330753a6d45SSherry Moore 	RESET_MODULE(barg);
331753a6d45SSherry Moore 	if (strlcpy(barg->gb_kernel, lp->gl_arg, sizeof (barg->gb_kernel)) >=
332753a6d45SSherry Moore 	    sizeof (barg->gb_kernel))
333753a6d45SSherry Moore 		return (E2BIG);
334753a6d45SSherry Moore 
335753a6d45SSherry Moore 	bfslen = barg_bootfs_var(barg, bootfs, sizeof (bootfs));
336753a6d45SSherry Moore 	isalen = barg_isadir_var(isadir, sizeof (isadir));
337753a6d45SSherry Moore 
338753a6d45SSherry Moore 	if (bfslen >= sizeof (bootfs) || isalen >= sizeof (isadir))
339753a6d45SSherry Moore 		return (EINVAL);
340753a6d45SSherry Moore 
341753a6d45SSherry Moore 	if ((ret = expand_var(barg->gb_kernel, sizeof (barg->gb_kernel),
342753a6d45SSherry Moore 	    ZFS_BOOT_VAR, strlen(ZFS_BOOT_VAR), bootfs, bfslen)) != 0)
343753a6d45SSherry Moore 		return (ret);
344753a6d45SSherry Moore 
345*c5aaf10aSKonstantin Ananyev 	if ((ret = expand_var(barg->gb_kernel, sizeof (barg->gb_kernel),
346*c5aaf10aSKonstantin Ananyev 	    ISADIR_VAR, strlen(ISADIR_VAR), isadir, isalen)) != 0)
347*c5aaf10aSKonstantin Ananyev 		return (ret);
348*c5aaf10aSKonstantin Ananyev 
349*c5aaf10aSKonstantin Ananyev 	if (strcmp(barg->gb_root.gr_fstyp, MNTTYPE_ZFS) == 0)
350*c5aaf10aSKonstantin Ananyev 		ret = update_bootpath(barg->gb_kernel, sizeof (barg->gb_kernel),
351*c5aaf10aSKonstantin Ananyev 		    barg->gb_root.gr_physpath);
352753a6d45SSherry Moore 
353753a6d45SSherry Moore 	return (ret);
354753a6d45SSherry Moore }
355753a6d45SSherry Moore 
356753a6d45SSherry Moore int
357753a6d45SSherry Moore dollar_module(const grub_line_t *lp, grub_barg_t *barg)
358753a6d45SSherry Moore {
359753a6d45SSherry Moore 	int	ret;
360753a6d45SSherry Moore 	size_t	isalen;
361753a6d45SSherry Moore 	char	isadir[32];
362753a6d45SSherry Moore 
363753a6d45SSherry Moore 	if (strlcpy(barg->gb_module, lp->gl_arg, sizeof (barg->gb_module)) >=
364753a6d45SSherry Moore 	    sizeof (barg->gb_module))
365753a6d45SSherry Moore 		return (E2BIG);
366753a6d45SSherry Moore 
367753a6d45SSherry Moore 	if ((isalen = barg_isadir_var(isadir, sizeof (isadir))) >= sizeof
368753a6d45SSherry Moore 	    (isadir))
369753a6d45SSherry Moore 		return (EINVAL);
370753a6d45SSherry Moore 
371753a6d45SSherry Moore 	ret = expand_var(barg->gb_module, sizeof (barg->gb_module),
372753a6d45SSherry Moore 	    ISADIR_VAR, strlen(ISADIR_VAR), isadir, isalen);
373753a6d45SSherry Moore 
374753a6d45SSherry Moore 	return (ret);
375753a6d45SSherry Moore }
376753a6d45SSherry Moore 
377753a6d45SSherry Moore 
378753a6d45SSherry Moore int
379753a6d45SSherry Moore findroot(const grub_line_t *lp, grub_barg_t *barg)
380753a6d45SSherry Moore {
381753a6d45SSherry Moore 	size_t sz, bsz;
382753a6d45SSherry Moore 	const char *sign;
383753a6d45SSherry Moore 
384753a6d45SSherry Moore 	reset_root(barg);
385753a6d45SSherry Moore 
386753a6d45SSherry Moore 	sign = lp->gl_arg;
387753a6d45SSherry Moore 	barg->gb_prtnum = (uint_t)PRTNUM_INVALID;
388753a6d45SSherry Moore 	barg->gb_slcnum = (uint_t)SLCNUM_WHOLE_DISK;
389753a6d45SSherry Moore 
390753a6d45SSherry Moore 	if (sign[0] == '(') {
391753a6d45SSherry Moore 		const char *pos;
392753a6d45SSherry Moore 
393753a6d45SSherry Moore 		++sign;
394753a6d45SSherry Moore 		if ((pos = strchr(sign, ',')) == NULL || (sz = pos - sign) == 0)
395753a6d45SSherry Moore 			return (EG_FINDROOTFMT);
396753a6d45SSherry Moore 
397753a6d45SSherry Moore 		++pos;
398753a6d45SSherry Moore 		if (!IS_PRTNUM_VALID(barg->gb_prtnum = pos[0] - '0'))
399753a6d45SSherry Moore 			return (EG_FINDROOTFMT);
400753a6d45SSherry Moore 
401753a6d45SSherry Moore 		++pos;
402753a6d45SSherry Moore 		if (pos[0] != ',' ||
403753a6d45SSherry Moore 		    !IS_SLCNUM_VALID(barg->gb_slcnum = pos[1]) ||
404753a6d45SSherry Moore 		    pos[2] != ')')
405753a6d45SSherry Moore 			return (EG_FINDROOTFMT);
406753a6d45SSherry Moore 	} else {
407753a6d45SSherry Moore 		sz = strlen(sign);
408753a6d45SSherry Moore 	}
409753a6d45SSherry Moore 
410753a6d45SSherry Moore 	bsz = strlen(BOOTSIGN_DIR "/");
411753a6d45SSherry Moore 	if (bsz + sz + 1 > sizeof (barg->gb_bootsign))
412753a6d45SSherry Moore 		return (E2BIG);
413753a6d45SSherry Moore 
414753a6d45SSherry Moore 	bcopy(BOOTSIGN_DIR "/", barg->gb_bootsign, bsz);
415753a6d45SSherry Moore 	bcopy(sign, barg->gb_bootsign + bsz, sz);
416753a6d45SSherry Moore 	barg->gb_bootsign [bsz + sz] = 0;
417753a6d45SSherry Moore 
418753a6d45SSherry Moore 	return (grub_find_bootsign(barg));
419753a6d45SSherry Moore }
420753a6d45SSherry Moore 
421753a6d45SSherry Moore int
422753a6d45SSherry Moore bootfs(const grub_line_t *lp, grub_barg_t *barg)
423753a6d45SSherry Moore {
424753a6d45SSherry Moore 	zfs_handle_t	*zfh;
425753a6d45SSherry Moore 	grub_menu_t	*mp = barg->gb_entry->ge_menu;
426753a6d45SSherry Moore 	char		*gfs_devp;
427753a6d45SSherry Moore 	size_t		gfs_dev_len;
428753a6d45SSherry Moore 
429753a6d45SSherry Moore 	/* Check if root is zfs */
430753a6d45SSherry Moore 	if (strcmp(barg->gb_root.gr_fstyp, MNTTYPE_ZFS) != 0)
431753a6d45SSherry Moore 		return (EG_NOTZFS);
432753a6d45SSherry Moore 
433753a6d45SSherry Moore 	gfs_devp = barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev;
434753a6d45SSherry Moore 	gfs_dev_len = sizeof (barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev);
435753a6d45SSherry Moore 
436753a6d45SSherry Moore 	/*
437753a6d45SSherry Moore 	 * If the bootfs value is the same as the bootfs for the pool,
438753a6d45SSherry Moore 	 * do nothing.
439753a6d45SSherry Moore 	 */
440753a6d45SSherry Moore 	if (strcmp(lp->gl_arg, gfs_devp) == 0)
441753a6d45SSherry Moore 		return (0);
442753a6d45SSherry Moore 
443753a6d45SSherry Moore 	if (strlcpy(gfs_devp, lp->gl_arg, gfs_dev_len) >= gfs_dev_len)
444753a6d45SSherry Moore 		return (E2BIG);
445753a6d45SSherry Moore 
446753a6d45SSherry Moore 	/* check if specified bootfs belongs to the root pool */
447753a6d45SSherry Moore 	if ((zfh = zfs_open(mp->gm_fs.gf_lzfh,
448753a6d45SSherry Moore 	    barg->gb_root.gr_fs[GRBM_ZFS_TOPFS].gfs_dev,
449753a6d45SSherry Moore 	    ZFS_TYPE_FILESYSTEM)) == NULL)
450753a6d45SSherry Moore 		return (EG_OPENZFS);
451753a6d45SSherry Moore 
452753a6d45SSherry Moore 	barg->gb_walkret = EG_UNKBOOTFS;
453753a6d45SSherry Moore 	(void) zfs_iter_filesystems(zfh, match_bootfs, barg);
454753a6d45SSherry Moore 	zfs_close(zfh);
455753a6d45SSherry Moore 
456753a6d45SSherry Moore 	if (barg->gb_walkret == 0)
457753a6d45SSherry Moore 		(void) grub_fsd_get_mountp(barg->gb_root.gr_fs +
458753a6d45SSherry Moore 		    GRBM_ZFS_BOOTFS, MNTTYPE_ZFS);
459753a6d45SSherry Moore 
460753a6d45SSherry Moore 	return (barg->gb_walkret);
461753a6d45SSherry Moore }
462