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