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