1*753a6d45SSherry Moore /* 2*753a6d45SSherry Moore * CDDL HEADER START 3*753a6d45SSherry Moore * 4*753a6d45SSherry Moore * The contents of this file are subject to the terms of the 5*753a6d45SSherry Moore * Common Development and Distribution License (the "License"). 6*753a6d45SSherry Moore * You may not use this file except in compliance with the License. 7*753a6d45SSherry Moore * 8*753a6d45SSherry Moore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*753a6d45SSherry Moore * or http://www.opensolaris.org/os/licensing. 10*753a6d45SSherry Moore * See the License for the specific language governing permissions 11*753a6d45SSherry Moore * and limitations under the License. 12*753a6d45SSherry Moore * 13*753a6d45SSherry Moore * When distributing Covered Code, include this CDDL HEADER in each 14*753a6d45SSherry Moore * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*753a6d45SSherry Moore * If applicable, add the following below this CDDL HEADER, with the 16*753a6d45SSherry Moore * fields enclosed by brackets "[]" replaced with your own identifying 17*753a6d45SSherry Moore * information: Portions Copyright [yyyy] [name of copyright owner] 18*753a6d45SSherry Moore * 19*753a6d45SSherry Moore * CDDL HEADER END 20*753a6d45SSherry Moore */ 21*753a6d45SSherry Moore /* 22*753a6d45SSherry Moore * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*753a6d45SSherry Moore * Use is subject to license terms. 24*753a6d45SSherry Moore */ 25*753a6d45SSherry Moore 26*753a6d45SSherry Moore /* 27*753a6d45SSherry Moore * This file contains functions for constructing boot arguments 28*753a6d45SSherry Moore * from GRUB menu for Fast Reboot. 29*753a6d45SSherry Moore */ 30*753a6d45SSherry Moore #include <stdio.h> 31*753a6d45SSherry Moore #include <stdlib.h> 32*753a6d45SSherry Moore #include <errno.h> 33*753a6d45SSherry Moore #include <strings.h> 34*753a6d45SSherry Moore #include <unistd.h> 35*753a6d45SSherry Moore #include <fcntl.h> 36*753a6d45SSherry Moore #include <assert.h> 37*753a6d45SSherry Moore #include <sys/types.h> 38*753a6d45SSherry Moore #include <sys/elf.h> 39*753a6d45SSherry Moore 40*753a6d45SSherry Moore #include "libgrub_impl.h" 41*753a6d45SSherry Moore 42*753a6d45SSherry Moore #if defined(__sparc) 43*753a6d45SSherry Moore #define CUR_ELFDATA ELFDATA2MSB 44*753a6d45SSherry Moore #elif defined(__i386) 45*753a6d45SSherry Moore #define CUR_ELFDATA ELFDATA2LSB 46*753a6d45SSherry Moore #endif /* __i386 */ 47*753a6d45SSherry Moore 48*753a6d45SSherry Moore /* 49*753a6d45SSherry Moore * Open the kernel file. 50*753a6d45SSherry Moore * Return zero on sucess or error code otherwise. 51*753a6d45SSherry Moore * On success the kernel file descriptor is returned in fdp. 52*753a6d45SSherry Moore */ 53*753a6d45SSherry Moore static int 54*753a6d45SSherry Moore get_kernel_fd(const char *path, int *fdp) 55*753a6d45SSherry Moore { 56*753a6d45SSherry Moore const char *bname; 57*753a6d45SSherry Moore int fd = -1, class, format; 58*753a6d45SSherry Moore char ident[EI_NIDENT]; 59*753a6d45SSherry Moore 60*753a6d45SSherry Moore /* kernel basename must be unix */ 61*753a6d45SSherry Moore if ((bname = strrchr(path, '/')) == NULL) 62*753a6d45SSherry Moore bname = path; 63*753a6d45SSherry Moore else 64*753a6d45SSherry Moore bname++; 65*753a6d45SSherry Moore 66*753a6d45SSherry Moore if (strcmp(bname, "unix") != 0) { 67*753a6d45SSherry Moore if (strcmp(bname, "xen.gz") == 0) 68*753a6d45SSherry Moore return (EG_XVMNOTSUP); 69*753a6d45SSherry Moore return (EG_NOTUNIX); 70*753a6d45SSherry Moore } 71*753a6d45SSherry Moore 72*753a6d45SSherry Moore if ((fd = open64(path, O_RDONLY)) >= 0 && 73*753a6d45SSherry Moore (pread64(fd, ident, sizeof (ident), 0) == sizeof (ident))) { 74*753a6d45SSherry Moore 75*753a6d45SSherry Moore class = ident[EI_CLASS]; 76*753a6d45SSherry Moore format = ident[EI_DATA]; 77*753a6d45SSherry Moore 78*753a6d45SSherry Moore if ((class == ELFCLASS32 || class == ELFCLASS64) && 79*753a6d45SSherry Moore (memcmp(&ident[EI_MAG0], ELFMAG, 4) == 0) && 80*753a6d45SSherry Moore format == CUR_ELFDATA) { 81*753a6d45SSherry Moore *fdp = fd; 82*753a6d45SSherry Moore return (0); 83*753a6d45SSherry Moore } 84*753a6d45SSherry Moore } 85*753a6d45SSherry Moore 86*753a6d45SSherry Moore if (fd >= 0) 87*753a6d45SSherry Moore (void) close(fd); 88*753a6d45SSherry Moore return (EG_OPENKERNFILE); 89*753a6d45SSherry Moore } 90*753a6d45SSherry Moore 91*753a6d45SSherry Moore /* 92*753a6d45SSherry Moore * Construct boot arguments for Fast Reboot from the ge_barg field of 93*753a6d45SSherry Moore * a GRUB menu entry. 94*753a6d45SSherry Moore * Return 0 on success, errno on failure. 95*753a6d45SSherry Moore */ 96*753a6d45SSherry Moore static int 97*753a6d45SSherry Moore barg2bootargs(const grub_barg_t *barg, grub_boot_args_t *fbarg) 98*753a6d45SSherry Moore { 99*753a6d45SSherry Moore int rc = 0; 100*753a6d45SSherry Moore char path[BOOTARGS_MAX]; 101*753a6d45SSherry Moore char rpath[BOOTARGS_MAX]; 102*753a6d45SSherry Moore const grub_fsdesc_t *fsd; 103*753a6d45SSherry Moore 104*753a6d45SSherry Moore assert(fbarg); 105*753a6d45SSherry Moore bzero(fbarg, sizeof (*fbarg)); 106*753a6d45SSherry Moore fbarg->gba_kernel_fd = -1; 107*753a6d45SSherry Moore 108*753a6d45SSherry Moore if (!IS_BARG_VALID(barg)) 109*753a6d45SSherry Moore return (EINVAL); 110*753a6d45SSherry Moore if ((fsd = grub_get_rootfsd(&barg->gb_root)) == NULL) 111*753a6d45SSherry Moore return (EG_UNKNOWNFS); 112*753a6d45SSherry Moore 113*753a6d45SSherry Moore bcopy(fsd, &fbarg->gba_fsd, sizeof (fbarg->gba_fsd)); 114*753a6d45SSherry Moore bcopy(barg->gb_kernel, fbarg->gba_kernel, sizeof (fbarg->gba_kernel)); 115*753a6d45SSherry Moore bcopy(barg->gb_module, fbarg->gba_module, sizeof (fbarg->gba_module)); 116*753a6d45SSherry Moore 117*753a6d45SSherry Moore if (fbarg->gba_fsd.gfs_mountp[0] == 0 && 118*753a6d45SSherry Moore (rc = grub_fsd_mount_tmp(&fbarg->gba_fsd, 119*753a6d45SSherry Moore barg->gb_root.gr_fstyp)) != 0) 120*753a6d45SSherry Moore return (rc); 121*753a6d45SSherry Moore 122*753a6d45SSherry Moore if (snprintf(path, sizeof (path), "%s%s", fbarg->gba_fsd.gfs_mountp, 123*753a6d45SSherry Moore fbarg->gba_kernel) >= sizeof (path)) { 124*753a6d45SSherry Moore rc = E2BIG; 125*753a6d45SSherry Moore goto err_out; 126*753a6d45SSherry Moore } 127*753a6d45SSherry Moore (void) strtok(path, " \t"); 128*753a6d45SSherry Moore (void) clean_path(path); 129*753a6d45SSherry Moore 130*753a6d45SSherry Moore /* 131*753a6d45SSherry Moore * GRUB requires absolute path, no symlinks, so do we 132*753a6d45SSherry Moore */ 133*753a6d45SSherry Moore if ((rc = resolvepath(path, rpath, sizeof (rpath))) == -1) 134*753a6d45SSherry Moore rc = errno; 135*753a6d45SSherry Moore else { 136*753a6d45SSherry Moore rpath[rc] = 0; 137*753a6d45SSherry Moore if (strcmp(rpath, path) != 0) 138*753a6d45SSherry Moore rc = EG_NOTABSPATH; 139*753a6d45SSherry Moore else 140*753a6d45SSherry Moore rc = get_kernel_fd(rpath, &fbarg->gba_kernel_fd); 141*753a6d45SSherry Moore } 142*753a6d45SSherry Moore 143*753a6d45SSherry Moore /* construct bootargs command-line */ 144*753a6d45SSherry Moore if (rc == 0 && snprintf(fbarg->gba_bootargs, 145*753a6d45SSherry Moore sizeof (fbarg->gba_bootargs), "%s %s", fbarg->gba_fsd.gfs_mountp, 146*753a6d45SSherry Moore fbarg->gba_kernel) >= sizeof (fbarg->gba_bootargs)) 147*753a6d45SSherry Moore rc = E2BIG; 148*753a6d45SSherry Moore 149*753a6d45SSherry Moore err_out: 150*753a6d45SSherry Moore if (rc != 0) 151*753a6d45SSherry Moore grub_cleanup_boot_args(fbarg); 152*753a6d45SSherry Moore 153*753a6d45SSherry Moore return (rc); 154*753a6d45SSherry Moore } 155*753a6d45SSherry Moore 156*753a6d45SSherry Moore /* 157*753a6d45SSherry Moore * Construct boot arguments for Fast Reboot from grub_menu_t. 158*753a6d45SSherry Moore * Return 0 on success, errno on failure. 159*753a6d45SSherry Moore */ 160*753a6d45SSherry Moore static int 161*753a6d45SSherry Moore grub_entry_get_boot_args(grub_entry_t *ent, grub_boot_args_t *fbarg) 162*753a6d45SSherry Moore { 163*753a6d45SSherry Moore int rc = EG_INVALIDENT; 164*753a6d45SSherry Moore 165*753a6d45SSherry Moore if (IS_ENTRY_VALID(ent) && (rc = grub_entry_construct_barg(ent)) == 0) 166*753a6d45SSherry Moore return (barg2bootargs(&ent->ge_barg, fbarg)); 167*753a6d45SSherry Moore else 168*753a6d45SSherry Moore return (rc); 169*753a6d45SSherry Moore } 170*753a6d45SSherry Moore 171*753a6d45SSherry Moore /* 172*753a6d45SSherry Moore * Construct boot arguments for Fast Reboot from grub_menu_t and the 173*753a6d45SSherry Moore * entry number. 174*753a6d45SSherry Moore * Return 0 on success, errno on failure. 175*753a6d45SSherry Moore */ 176*753a6d45SSherry Moore static int 177*753a6d45SSherry Moore grub_menu_get_boot_args(const grub_menu_t *mp, int num, 178*753a6d45SSherry Moore grub_boot_args_t *fbarg) 179*753a6d45SSherry Moore { 180*753a6d45SSherry Moore grub_entry_t *ent; 181*753a6d45SSherry Moore 182*753a6d45SSherry Moore assert(mp); 183*753a6d45SSherry Moore assert(fbarg); 184*753a6d45SSherry Moore 185*753a6d45SSherry Moore if ((ent = grub_menu_get_entry(mp, num)) == NULL) 186*753a6d45SSherry Moore return (EG_NOENTRY); 187*753a6d45SSherry Moore 188*753a6d45SSherry Moore return (grub_entry_get_boot_args(ent, fbarg)); 189*753a6d45SSherry Moore } 190*753a6d45SSherry Moore 191*753a6d45SSherry Moore /* 192*753a6d45SSherry Moore * Construct boot arguments from the specified GRUB menu entry. 193*753a6d45SSherry Moore * Caller must allocate space for fbarg, and call grub_cleanup_boot_args() 194*753a6d45SSherry Moore * when it's done with fbarg to clean up. 195*753a6d45SSherry Moore * 196*753a6d45SSherry Moore * Return 0 on success, errno on failure. 197*753a6d45SSherry Moore */ 198*753a6d45SSherry Moore int 199*753a6d45SSherry Moore grub_get_boot_args(grub_boot_args_t *fbarg, const char *menupath, int num) 200*753a6d45SSherry Moore { 201*753a6d45SSherry Moore int rc; 202*753a6d45SSherry Moore grub_menu_t *mp; 203*753a6d45SSherry Moore 204*753a6d45SSherry Moore assert(fbarg); 205*753a6d45SSherry Moore if ((rc = grub_menu_init(menupath, &mp)) == 0) { 206*753a6d45SSherry Moore rc = grub_menu_get_boot_args(mp, num, fbarg); 207*753a6d45SSherry Moore grub_menu_fini(mp); 208*753a6d45SSherry Moore } 209*753a6d45SSherry Moore return (rc); 210*753a6d45SSherry Moore } 211*753a6d45SSherry Moore 212*753a6d45SSherry Moore /* 213*753a6d45SSherry Moore * Clean up when done with fbarg: close file handle, unmount file 214*753a6d45SSherry Moore * systems. Must be safe to call even if not all the fields are 215*753a6d45SSherry Moore * set up. 216*753a6d45SSherry Moore */ 217*753a6d45SSherry Moore void 218*753a6d45SSherry Moore grub_cleanup_boot_args(grub_boot_args_t *fbarg) 219*753a6d45SSherry Moore { 220*753a6d45SSherry Moore if (fbarg == NULL) 221*753a6d45SSherry Moore return; 222*753a6d45SSherry Moore 223*753a6d45SSherry Moore (void) close(fbarg->gba_kernel_fd); 224*753a6d45SSherry Moore grub_fsd_umount_tmp(&fbarg->gba_fsd); 225*753a6d45SSherry Moore } 226