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