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