libgrub_cmd.c revision 57631629e78d7cda75d1f6ec529fc985298b24f4
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * CDDL HEADER START
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * The contents of this file are subject to the terms of the
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * Common Development and Distribution License (the "License").
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * You may not use this file except in compliance with the License.
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * See the License for the specific language governing permissions
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * and limitations under the License.
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * When distributing Covered Code, include this CDDL HEADER in each
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * If applicable, add the following below this CDDL HEADER, with the
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * fields enclosed by brackets "[]" replaced with your own identifying
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * information: Portions Copyright [yyyy] [name of copyright owner]
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * CDDL HEADER END
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * Use is subject to license terms.
1a902ef8628b0dffd6df5442354ab59bb8530962Hans Rosenfeld * Copyright 2015 Nexenta Systems, Inc.
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * This file contains all the functions that implement the following
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * GRUB commands:
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * kernel, kernel$, module, module$, findroot, bootfs
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * Return 0 on success, errno on failure.
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore#endif /* __i386 */
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore#define RESET_MODULE(barg) ((barg)->gb_module[0] = 0)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moorestatic const char cpuid_dev[] = "/dev/cpu/self/cpuid";
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * Return 1 if the system supports 64-bit mode, 0 if it doesn't,
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * or -1 on failure.
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if (pread(fd, &cpuid_regs, sizeof (cpuid_regs), 0x80000001) ==
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore ret = ((CPUID_AMD_EDX_LM & cpuid_regs.cp_edx) != 0);
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore#endif /* __i386 */
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * Expand $ISAIDR
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore/* ARGSUSED */
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore#endif /* __i386 */
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore#endif /* __i386 */
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * Expand $ZFS-BOOTFS
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moorebarg_bootfs_var(const grub_barg_t *barg, char *var, int sz)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if (strcmp(barg->gb_root.gr_fstyp, MNTTYPE_ZFS) == 0) {
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev BPROP_ZFSBOOTFS "=%s," BPROP_BOOTPATH "=\"%s\"",
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * Expand all the variables without appending them more than once.
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Mooreexpand_var(char *arg, size_t argsz, const char *var, size_t varsz,
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev * Searches first occurence of boot-property 'bprop' in str.
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev * str supposed to be in format:
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev * " [-B prop=[value][,prop=[value]]...]
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyevstatic const char *
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyevfind_bootprop(const char *str, const char *bprop)
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev const char *s;
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev while ((str = strstr(s, " -B")) != NULL ||
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev /* empty -B option, skip it */
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev /* boot property we are looking for? */
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev if (len == bplen && strncmp(s, bprop, bplen) == 0)
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev /* skip boot property value */
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev while ((s = strpbrk(s + 1, "\"\', \t")) != NULL) {
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev /* skip quoted */
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev /* unbalanced quotes */
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev /* no more boot properties */
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev /* no more boot properties in that -B block */
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev if (s[0] != ',')
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev * Add bootpath property to str if
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev * 1. zfs-bootfs property is set explicitly
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev * 2. bootpath property is not set
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyevupdate_bootpath(char *str, size_t strsz, const char *bootpath)
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev /* zfs-bootfs is not specified, or bootpath is allready set */
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev if ((bfs = find_bootprop(str, BPROP_ZFSBOOTFS)) == NULL ||
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev find_bootprop(str, BPROP_BOOTPATH) != NULL)
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev if (snprintf(buf + n, strsz - n, BPROP_BOOTPATH "=\"%s\",%s",
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore const char *zfn;
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore ret = (zfs_get_type(zfh) == ZFS_TYPE_FILESYSTEM &&
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore strcmp(barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev, zfn) == 0);
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore (void) zfs_iter_filesystems(zfh, match_bootfs, barg);
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore (void) memset(&barg->gb_root, 0, sizeof (barg->gb_root));
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore/* ARGSUSED */
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Mooreskip_line(const grub_line_t *lp, grub_barg_t *barg)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore/* ARGSUSED */
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Mooreerror_line(const grub_line_t *lp, grub_barg_t *barg)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moorekernel(const grub_line_t *lp, grub_barg_t *barg)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if (strlcpy(barg->gb_kernel, lp->gl_arg, sizeof (barg->gb_kernel)) >=
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Mooremodule(const grub_line_t *lp, grub_barg_t *barg)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if (strlcpy(barg->gb_module, lp->gl_arg, sizeof (barg->gb_module)) >=
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Mooredollar_kernel(const grub_line_t *lp, grub_barg_t *barg)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if (strlcpy(barg->gb_kernel, lp->gl_arg, sizeof (barg->gb_kernel)) >=
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore bfslen = barg_bootfs_var(barg, bootfs, sizeof (bootfs));
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore isalen = barg_isadir_var(isadir, sizeof (isadir));
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if (bfslen >= sizeof (bootfs) || isalen >= sizeof (isadir))
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if ((ret = expand_var(barg->gb_kernel, sizeof (barg->gb_kernel),
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore ZFS_BOOT_VAR, strlen(ZFS_BOOT_VAR), bootfs, bfslen)) != 0)
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev if ((ret = expand_var(barg->gb_kernel, sizeof (barg->gb_kernel),
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev ISADIR_VAR, strlen(ISADIR_VAR), isadir, isalen)) != 0)
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev if (strcmp(barg->gb_root.gr_fstyp, MNTTYPE_ZFS) == 0)
c5aaf10a7384f952835ab63586396916a6d3437dKonstantin Ananyev ret = update_bootpath(barg->gb_kernel, sizeof (barg->gb_kernel),
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Mooredollar_module(const grub_line_t *lp, grub_barg_t *barg)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if (strlcpy(barg->gb_module, lp->gl_arg, sizeof (barg->gb_module)) >=
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if ((isalen = barg_isadir_var(isadir, sizeof (isadir))) >= sizeof
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore ret = expand_var(barg->gb_module, sizeof (barg->gb_module),
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore ISADIR_VAR, strlen(ISADIR_VAR), isadir, isalen);
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moorefindroot(const grub_line_t *lp, grub_barg_t *barg)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore const char *sign;
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore const char *pos;
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if ((pos = strchr(sign, ',')) == NULL || (sz = pos - sign) == 0)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if (!IS_PRTNUM_VALID(barg->gb_prtnum = pos[0] - '0'))
57631629e78d7cda75d1f6ec529fc985298b24f4Toomas Soome * check the slice only when its presented
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore bcopy(BOOTSIGN_DIR "/", barg->gb_bootsign, bsz);
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moorebootfs(const grub_line_t *lp, grub_barg_t *barg)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore /* Check if root is zfs */
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if (strcmp(barg->gb_root.gr_fstyp, MNTTYPE_ZFS) != 0)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore gfs_devp = barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev;
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore gfs_dev_len = sizeof (barg->gb_root.gr_fs[GRBM_ZFS_BOOTFS].gfs_dev);
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * If the bootfs value is the same as the bootfs for the pool,
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore * do nothing.
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore if (strlcpy(gfs_devp, lp->gl_arg, gfs_dev_len) >= gfs_dev_len)
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore /* check if specified bootfs belongs to the root pool */
753a6d457b330b1b29b2d3eefcd0831116ce950dSherry Moore (void) zfs_iter_filesystems(zfh, match_bootfs, barg);