1*9160SSherry.Moore@Sun.COM /* 2*9160SSherry.Moore@Sun.COM * CDDL HEADER START 3*9160SSherry.Moore@Sun.COM * 4*9160SSherry.Moore@Sun.COM * The contents of this file are subject to the terms of the 5*9160SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License"). 6*9160SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License. 7*9160SSherry.Moore@Sun.COM * 8*9160SSherry.Moore@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*9160SSherry.Moore@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*9160SSherry.Moore@Sun.COM * See the License for the specific language governing permissions 11*9160SSherry.Moore@Sun.COM * and limitations under the License. 12*9160SSherry.Moore@Sun.COM * 13*9160SSherry.Moore@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*9160SSherry.Moore@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*9160SSherry.Moore@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*9160SSherry.Moore@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*9160SSherry.Moore@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*9160SSherry.Moore@Sun.COM * 19*9160SSherry.Moore@Sun.COM * CDDL HEADER END 20*9160SSherry.Moore@Sun.COM */ 21*9160SSherry.Moore@Sun.COM /* 22*9160SSherry.Moore@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*9160SSherry.Moore@Sun.COM * Use is subject to license terms. 24*9160SSherry.Moore@Sun.COM */ 25*9160SSherry.Moore@Sun.COM 26*9160SSherry.Moore@Sun.COM /* 27*9160SSherry.Moore@Sun.COM * This file contains functions for manipulating the GRUB menu. 28*9160SSherry.Moore@Sun.COM */ 29*9160SSherry.Moore@Sun.COM #include <stdio.h> 30*9160SSherry.Moore@Sun.COM #include <errno.h> 31*9160SSherry.Moore@Sun.COM #include <stdlib.h> 32*9160SSherry.Moore@Sun.COM #include <string.h> 33*9160SSherry.Moore@Sun.COM #include <unistd.h> 34*9160SSherry.Moore@Sun.COM #include <sys/types.h> 35*9160SSherry.Moore@Sun.COM #include <sys/mount.h> 36*9160SSherry.Moore@Sun.COM #include <stdarg.h> 37*9160SSherry.Moore@Sun.COM #include <assert.h> 38*9160SSherry.Moore@Sun.COM #include <ctype.h> 39*9160SSherry.Moore@Sun.COM 40*9160SSherry.Moore@Sun.COM #include "libgrub_impl.h" 41*9160SSherry.Moore@Sun.COM 42*9160SSherry.Moore@Sun.COM static const grub_cmd_desc_t grub_cmd_descs[GRBM_CMD_NUM] = { 43*9160SSherry.Moore@Sun.COM #define menu_cmd(cmd, num, flag, parsef) {cmd, num, flag}, 44*9160SSherry.Moore@Sun.COM #include "libgrub_cmd.def" 45*9160SSherry.Moore@Sun.COM }; 46*9160SSherry.Moore@Sun.COM 47*9160SSherry.Moore@Sun.COM static void 48*9160SSherry.Moore@Sun.COM append_line(grub_menu_t *mp, grub_line_t *lp) 49*9160SSherry.Moore@Sun.COM { 50*9160SSherry.Moore@Sun.COM if (mp->gm_start == NULL) { 51*9160SSherry.Moore@Sun.COM mp->gm_start = lp; 52*9160SSherry.Moore@Sun.COM } else { 53*9160SSherry.Moore@Sun.COM mp->gm_end->gl_next = lp; 54*9160SSherry.Moore@Sun.COM lp->gl_prev = mp->gm_end; 55*9160SSherry.Moore@Sun.COM } 56*9160SSherry.Moore@Sun.COM mp->gm_end = lp; 57*9160SSherry.Moore@Sun.COM lp->gl_line_num = ++mp->gm_line_num; 58*9160SSherry.Moore@Sun.COM lp->gl_entry_num = GRUB_ENTRY_DEFAULT; 59*9160SSherry.Moore@Sun.COM } 60*9160SSherry.Moore@Sun.COM 61*9160SSherry.Moore@Sun.COM static void 62*9160SSherry.Moore@Sun.COM process_line(grub_menu_t *mp) 63*9160SSherry.Moore@Sun.COM { 64*9160SSherry.Moore@Sun.COM int n; 65*9160SSherry.Moore@Sun.COM grub_line_t *lp; 66*9160SSherry.Moore@Sun.COM 67*9160SSherry.Moore@Sun.COM lp = mp->gm_end; 68*9160SSherry.Moore@Sun.COM n = sizeof (grub_cmd_descs) / sizeof (grub_cmd_descs[0]); 69*9160SSherry.Moore@Sun.COM 70*9160SSherry.Moore@Sun.COM /* search through the table of known commands */ 71*9160SSherry.Moore@Sun.COM while (n-- != 0 && strcmp(lp->gl_cmd, grub_cmd_descs[n].gcd_cmd) != 0) 72*9160SSherry.Moore@Sun.COM ; 73*9160SSherry.Moore@Sun.COM 74*9160SSherry.Moore@Sun.COM /* unknown command */ 75*9160SSherry.Moore@Sun.COM if (n < 0) 76*9160SSherry.Moore@Sun.COM return; 77*9160SSherry.Moore@Sun.COM 78*9160SSherry.Moore@Sun.COM /* we found command, fill lp fields */ 79*9160SSherry.Moore@Sun.COM lp->gl_flags = grub_cmd_descs[n].gcd_flags; 80*9160SSherry.Moore@Sun.COM lp->gl_cmdtp = grub_cmd_descs[n].gcd_num; 81*9160SSherry.Moore@Sun.COM } 82*9160SSherry.Moore@Sun.COM 83*9160SSherry.Moore@Sun.COM 84*9160SSherry.Moore@Sun.COM static void 85*9160SSherry.Moore@Sun.COM check_entry(grub_entry_t *ent) 86*9160SSherry.Moore@Sun.COM { 87*9160SSherry.Moore@Sun.COM int i; 88*9160SSherry.Moore@Sun.COM uint_t emask; 89*9160SSherry.Moore@Sun.COM grub_line_t *lp; 90*9160SSherry.Moore@Sun.COM const grub_line_t * const lend = ent->ge_end->gl_next; 91*9160SSherry.Moore@Sun.COM 92*9160SSherry.Moore@Sun.COM emask = 0; 93*9160SSherry.Moore@Sun.COM for (i = 0, lp = ent->ge_start; lend != lp; lp = lp->gl_next, ++i) { 94*9160SSherry.Moore@Sun.COM lp->gl_entry_num = ent->ge_entry_num; 95*9160SSherry.Moore@Sun.COM if (lp->gl_flags == GRUB_LINE_INVALID || 96*9160SSherry.Moore@Sun.COM lp->gl_flags == GRUB_LINE_GLOBAL) { 97*9160SSherry.Moore@Sun.COM emask |= 1 << i; 98*9160SSherry.Moore@Sun.COM lp->gl_flags = GRUB_LINE_INVALID; 99*9160SSherry.Moore@Sun.COM } 100*9160SSherry.Moore@Sun.COM } 101*9160SSherry.Moore@Sun.COM 102*9160SSherry.Moore@Sun.COM if ((ent->ge_emask = emask) == 0) 103*9160SSherry.Moore@Sun.COM ent->ge_flags |= GRBM_VALID_FLAG; 104*9160SSherry.Moore@Sun.COM } 105*9160SSherry.Moore@Sun.COM 106*9160SSherry.Moore@Sun.COM static int 107*9160SSherry.Moore@Sun.COM add_entry(grub_menu_t *mp, grub_line_t *start, grub_line_t *end) 108*9160SSherry.Moore@Sun.COM { 109*9160SSherry.Moore@Sun.COM grub_entry_t *ent; 110*9160SSherry.Moore@Sun.COM 111*9160SSherry.Moore@Sun.COM if ((ent = calloc(1, sizeof (*ent))) == NULL) 112*9160SSherry.Moore@Sun.COM return (errno); 113*9160SSherry.Moore@Sun.COM 114*9160SSherry.Moore@Sun.COM ent->ge_start = start; 115*9160SSherry.Moore@Sun.COM ent->ge_end = end; 116*9160SSherry.Moore@Sun.COM 117*9160SSherry.Moore@Sun.COM if (mp->gm_ent_end == NULL) { 118*9160SSherry.Moore@Sun.COM mp->gm_ent_start = ent; 119*9160SSherry.Moore@Sun.COM } else { 120*9160SSherry.Moore@Sun.COM mp->gm_ent_end->ge_next = ent; 121*9160SSherry.Moore@Sun.COM ent->ge_prev = mp->gm_ent_end; 122*9160SSherry.Moore@Sun.COM } 123*9160SSherry.Moore@Sun.COM mp->gm_ent_end = ent; 124*9160SSherry.Moore@Sun.COM ent->ge_entry_num = mp->gm_entry_num++; 125*9160SSherry.Moore@Sun.COM ent->ge_menu = mp; 126*9160SSherry.Moore@Sun.COM return (0); 127*9160SSherry.Moore@Sun.COM } 128*9160SSherry.Moore@Sun.COM 129*9160SSherry.Moore@Sun.COM static void 130*9160SSherry.Moore@Sun.COM default_entry(grub_menu_t *mp) 131*9160SSherry.Moore@Sun.COM { 132*9160SSherry.Moore@Sun.COM uint_t defent; 133*9160SSherry.Moore@Sun.COM grub_line_t *lp; 134*9160SSherry.Moore@Sun.COM grub_entry_t *ent; 135*9160SSherry.Moore@Sun.COM 136*9160SSherry.Moore@Sun.COM defent = 0; 137*9160SSherry.Moore@Sun.COM lp = mp->gm_curdefault; 138*9160SSherry.Moore@Sun.COM 139*9160SSherry.Moore@Sun.COM if (lp != NULL && lp->gl_flags == GRUB_LINE_GLOBAL && 140*9160SSherry.Moore@Sun.COM lp->gl_cmdtp == GRBM_DEFAULT_CMD) { 141*9160SSherry.Moore@Sun.COM defent = strtoul(lp->gl_arg, NULL, 0); 142*9160SSherry.Moore@Sun.COM if (defent >= mp->gm_entry_num) 143*9160SSherry.Moore@Sun.COM defent = 0; 144*9160SSherry.Moore@Sun.COM } 145*9160SSherry.Moore@Sun.COM 146*9160SSherry.Moore@Sun.COM for (ent = mp->gm_ent_start; ent != NULL && defent != ent->ge_entry_num; 147*9160SSherry.Moore@Sun.COM ent = ent->ge_next) 148*9160SSherry.Moore@Sun.COM ; 149*9160SSherry.Moore@Sun.COM 150*9160SSherry.Moore@Sun.COM mp->gm_ent_default = ent; 151*9160SSherry.Moore@Sun.COM } 152*9160SSherry.Moore@Sun.COM 153*9160SSherry.Moore@Sun.COM static void 154*9160SSherry.Moore@Sun.COM free_line(grub_line_t *lp) 155*9160SSherry.Moore@Sun.COM { 156*9160SSherry.Moore@Sun.COM if (lp == NULL) 157*9160SSherry.Moore@Sun.COM return; 158*9160SSherry.Moore@Sun.COM 159*9160SSherry.Moore@Sun.COM free(lp->gl_cmd); 160*9160SSherry.Moore@Sun.COM free(lp->gl_sep); 161*9160SSherry.Moore@Sun.COM free(lp->gl_arg); 162*9160SSherry.Moore@Sun.COM free(lp->gl_line); 163*9160SSherry.Moore@Sun.COM free(lp); 164*9160SSherry.Moore@Sun.COM } 165*9160SSherry.Moore@Sun.COM 166*9160SSherry.Moore@Sun.COM static void 167*9160SSherry.Moore@Sun.COM free_linelist(grub_line_t *line) 168*9160SSherry.Moore@Sun.COM { 169*9160SSherry.Moore@Sun.COM grub_line_t *lp; 170*9160SSherry.Moore@Sun.COM 171*9160SSherry.Moore@Sun.COM if (line == NULL) 172*9160SSherry.Moore@Sun.COM return; 173*9160SSherry.Moore@Sun.COM 174*9160SSherry.Moore@Sun.COM while (line) { 175*9160SSherry.Moore@Sun.COM lp = line; 176*9160SSherry.Moore@Sun.COM line = lp->gl_next; 177*9160SSherry.Moore@Sun.COM free_line(lp); 178*9160SSherry.Moore@Sun.COM } 179*9160SSherry.Moore@Sun.COM } 180*9160SSherry.Moore@Sun.COM 181*9160SSherry.Moore@Sun.COM static void 182*9160SSherry.Moore@Sun.COM free_entries(grub_menu_t *mp) 183*9160SSherry.Moore@Sun.COM { 184*9160SSherry.Moore@Sun.COM grub_entry_t *ent, *tmp; 185*9160SSherry.Moore@Sun.COM 186*9160SSherry.Moore@Sun.COM if (mp == NULL) 187*9160SSherry.Moore@Sun.COM return; 188*9160SSherry.Moore@Sun.COM 189*9160SSherry.Moore@Sun.COM for (ent = mp->gm_ent_start; (tmp = ent) != NULL; 190*9160SSherry.Moore@Sun.COM ent = tmp->ge_next, free(tmp)) 191*9160SSherry.Moore@Sun.COM ; 192*9160SSherry.Moore@Sun.COM 193*9160SSherry.Moore@Sun.COM mp->gm_ent_start = NULL; 194*9160SSherry.Moore@Sun.COM mp->gm_ent_end = NULL; 195*9160SSherry.Moore@Sun.COM } 196*9160SSherry.Moore@Sun.COM 197*9160SSherry.Moore@Sun.COM static int 198*9160SSherry.Moore@Sun.COM grub_menu_append_line(grub_menu_t *mp, const char *line) 199*9160SSherry.Moore@Sun.COM { 200*9160SSherry.Moore@Sun.COM int rc; 201*9160SSherry.Moore@Sun.COM size_t n; 202*9160SSherry.Moore@Sun.COM grub_line_t *lp; 203*9160SSherry.Moore@Sun.COM 204*9160SSherry.Moore@Sun.COM if (line == NULL) 205*9160SSherry.Moore@Sun.COM return (EINVAL); 206*9160SSherry.Moore@Sun.COM 207*9160SSherry.Moore@Sun.COM rc = 0; 208*9160SSherry.Moore@Sun.COM lp = NULL; 209*9160SSherry.Moore@Sun.COM if ((lp = calloc(1, sizeof (*lp))) == NULL || 210*9160SSherry.Moore@Sun.COM (lp->gl_line = strdup(line)) == NULL) { 211*9160SSherry.Moore@Sun.COM free(lp); 212*9160SSherry.Moore@Sun.COM return (errno); 213*9160SSherry.Moore@Sun.COM } 214*9160SSherry.Moore@Sun.COM 215*9160SSherry.Moore@Sun.COM /* skip initial white space */ 216*9160SSherry.Moore@Sun.COM line += strspn(line, " \t"); 217*9160SSherry.Moore@Sun.COM 218*9160SSherry.Moore@Sun.COM /* process comment line */ 219*9160SSherry.Moore@Sun.COM if (line[0] == '#') { 220*9160SSherry.Moore@Sun.COM if ((lp->gl_cmd = 221*9160SSherry.Moore@Sun.COM strdup(grub_cmd_descs[GRBM_COMMENT_CMD].gcd_cmd)) == NULL || 222*9160SSherry.Moore@Sun.COM (lp->gl_sep = 223*9160SSherry.Moore@Sun.COM strdup(grub_cmd_descs[GRBM_EMPTY_CMD].gcd_cmd)) == NULL || 224*9160SSherry.Moore@Sun.COM (lp->gl_arg = strdup(line + 1)) == NULL) 225*9160SSherry.Moore@Sun.COM rc = errno; 226*9160SSherry.Moore@Sun.COM } else { 227*9160SSherry.Moore@Sun.COM /* get command */ 228*9160SSherry.Moore@Sun.COM n = strcspn(line, " \t="); 229*9160SSherry.Moore@Sun.COM if ((lp->gl_cmd = malloc(n + 1)) == NULL) 230*9160SSherry.Moore@Sun.COM rc = errno; 231*9160SSherry.Moore@Sun.COM else 232*9160SSherry.Moore@Sun.COM (void) strlcpy(lp->gl_cmd, line, n + 1); 233*9160SSherry.Moore@Sun.COM 234*9160SSherry.Moore@Sun.COM line += n; 235*9160SSherry.Moore@Sun.COM 236*9160SSherry.Moore@Sun.COM /* get separator */ 237*9160SSherry.Moore@Sun.COM n = strspn(line, " \t="); 238*9160SSherry.Moore@Sun.COM if ((lp->gl_sep = malloc(n + 1)) == NULL) 239*9160SSherry.Moore@Sun.COM rc = errno; 240*9160SSherry.Moore@Sun.COM else 241*9160SSherry.Moore@Sun.COM (void) strlcpy(lp->gl_sep, line, n + 1); 242*9160SSherry.Moore@Sun.COM 243*9160SSherry.Moore@Sun.COM line += n; 244*9160SSherry.Moore@Sun.COM 245*9160SSherry.Moore@Sun.COM /* get arguments */ 246*9160SSherry.Moore@Sun.COM if ((lp->gl_arg = strdup(line)) == NULL) 247*9160SSherry.Moore@Sun.COM rc = errno; 248*9160SSherry.Moore@Sun.COM } 249*9160SSherry.Moore@Sun.COM 250*9160SSherry.Moore@Sun.COM if (rc != 0) { 251*9160SSherry.Moore@Sun.COM free_line(lp); 252*9160SSherry.Moore@Sun.COM return (rc); 253*9160SSherry.Moore@Sun.COM } 254*9160SSherry.Moore@Sun.COM 255*9160SSherry.Moore@Sun.COM append_line(mp, lp); 256*9160SSherry.Moore@Sun.COM process_line(mp); 257*9160SSherry.Moore@Sun.COM return (0); 258*9160SSherry.Moore@Sun.COM } 259*9160SSherry.Moore@Sun.COM 260*9160SSherry.Moore@Sun.COM static int 261*9160SSherry.Moore@Sun.COM grub_menu_process(grub_menu_t *mp) 262*9160SSherry.Moore@Sun.COM { 263*9160SSherry.Moore@Sun.COM int ret; 264*9160SSherry.Moore@Sun.COM grub_entry_t *ent; 265*9160SSherry.Moore@Sun.COM grub_line_t *line, *start; 266*9160SSherry.Moore@Sun.COM 267*9160SSherry.Moore@Sun.COM /* Free remaininig entries, if any */ 268*9160SSherry.Moore@Sun.COM free_entries(mp); 269*9160SSherry.Moore@Sun.COM 270*9160SSherry.Moore@Sun.COM /* 271*9160SSherry.Moore@Sun.COM * Walk through lines, till first 'title' command is encountered. 272*9160SSherry.Moore@Sun.COM * Initialize globals. 273*9160SSherry.Moore@Sun.COM */ 274*9160SSherry.Moore@Sun.COM for (line = mp->gm_start; line != NULL; line = line->gl_next) { 275*9160SSherry.Moore@Sun.COM if (line->gl_flags == GRUB_LINE_GLOBAL && 276*9160SSherry.Moore@Sun.COM line->gl_cmdtp == GRBM_DEFAULT_CMD) 277*9160SSherry.Moore@Sun.COM mp->gm_curdefault = line; 278*9160SSherry.Moore@Sun.COM else if (line->gl_cmdtp == GRBM_TITLE_CMD) 279*9160SSherry.Moore@Sun.COM break; 280*9160SSherry.Moore@Sun.COM } 281*9160SSherry.Moore@Sun.COM 282*9160SSherry.Moore@Sun.COM /* 283*9160SSherry.Moore@Sun.COM * Walk through remaining lines and recreate menu entries. 284*9160SSherry.Moore@Sun.COM */ 285*9160SSherry.Moore@Sun.COM for (start = NULL; line != NULL; line = line->gl_next) { 286*9160SSherry.Moore@Sun.COM if (line->gl_cmdtp == GRBM_TITLE_CMD) { 287*9160SSherry.Moore@Sun.COM /* is first entry */ 288*9160SSherry.Moore@Sun.COM if (start != NULL && 289*9160SSherry.Moore@Sun.COM (ret = add_entry(mp, start, line->gl_prev)) != 0) 290*9160SSherry.Moore@Sun.COM return (ret); 291*9160SSherry.Moore@Sun.COM start = line; 292*9160SSherry.Moore@Sun.COM } 293*9160SSherry.Moore@Sun.COM } 294*9160SSherry.Moore@Sun.COM 295*9160SSherry.Moore@Sun.COM /* Add last entry */ 296*9160SSherry.Moore@Sun.COM if (start != NULL && (ret = add_entry(mp, start, mp->gm_end)) != 0) 297*9160SSherry.Moore@Sun.COM return (ret); 298*9160SSherry.Moore@Sun.COM 299*9160SSherry.Moore@Sun.COM for (ent = mp->gm_ent_start; NULL != ent; ent = ent->ge_next) 300*9160SSherry.Moore@Sun.COM check_entry(ent); 301*9160SSherry.Moore@Sun.COM 302*9160SSherry.Moore@Sun.COM default_entry(mp); 303*9160SSherry.Moore@Sun.COM 304*9160SSherry.Moore@Sun.COM return (0); 305*9160SSherry.Moore@Sun.COM } 306*9160SSherry.Moore@Sun.COM 307*9160SSherry.Moore@Sun.COM static int 308*9160SSherry.Moore@Sun.COM grub_fs_init(grub_fs_t *fs) 309*9160SSherry.Moore@Sun.COM { 310*9160SSherry.Moore@Sun.COM assert(fs); 311*9160SSherry.Moore@Sun.COM if ((fs->gf_lzfh = libzfs_init()) == NULL || 312*9160SSherry.Moore@Sun.COM (fs->gf_diroot = di_init("/", DINFOCPYALL | DINFOPATH)) 313*9160SSherry.Moore@Sun.COM == DI_NODE_NIL || 314*9160SSherry.Moore@Sun.COM (fs->gf_dvlh = di_devlink_init(NULL, 0)) == DI_LINK_NIL) { 315*9160SSherry.Moore@Sun.COM return (EG_INITFS); 316*9160SSherry.Moore@Sun.COM } 317*9160SSherry.Moore@Sun.COM return (0); 318*9160SSherry.Moore@Sun.COM } 319*9160SSherry.Moore@Sun.COM 320*9160SSherry.Moore@Sun.COM static void 321*9160SSherry.Moore@Sun.COM grub_fs_fini(grub_fs_t *fs) 322*9160SSherry.Moore@Sun.COM { 323*9160SSherry.Moore@Sun.COM if (fs == NULL) 324*9160SSherry.Moore@Sun.COM return; 325*9160SSherry.Moore@Sun.COM 326*9160SSherry.Moore@Sun.COM if (fs->gf_dvlh != DI_LINK_NIL) 327*9160SSherry.Moore@Sun.COM (void) di_devlink_fini(&fs->gf_dvlh); 328*9160SSherry.Moore@Sun.COM if (fs->gf_diroot != DI_NODE_NIL) 329*9160SSherry.Moore@Sun.COM di_fini(fs->gf_diroot); 330*9160SSherry.Moore@Sun.COM if (fs->gf_lzfh != NULL) 331*9160SSherry.Moore@Sun.COM libzfs_fini(fs->gf_lzfh); 332*9160SSherry.Moore@Sun.COM (void) memset(fs, 0, sizeof (*fs)); 333*9160SSherry.Moore@Sun.COM } 334*9160SSherry.Moore@Sun.COM 335*9160SSherry.Moore@Sun.COM /* 336*9160SSherry.Moore@Sun.COM * Reads and parses GRUB menu file into a grub_menu_t data structure. 337*9160SSherry.Moore@Sun.COM * If grub_menu_path file path is NULL, will use 'currently active' 338*9160SSherry.Moore@Sun.COM * GRUB menu file. 339*9160SSherry.Moore@Sun.COM * 340*9160SSherry.Moore@Sun.COM * Memory for the menu data structure is allocated within the routine. 341*9160SSherry.Moore@Sun.COM * Caller must call grub_menu_fini() to release memory after calling 342*9160SSherry.Moore@Sun.COM * grub_menu_init(). 343*9160SSherry.Moore@Sun.COM */ 344*9160SSherry.Moore@Sun.COM int 345*9160SSherry.Moore@Sun.COM grub_menu_init(const char *path, grub_menu_t **menup) 346*9160SSherry.Moore@Sun.COM { 347*9160SSherry.Moore@Sun.COM FILE *fp; 348*9160SSherry.Moore@Sun.COM char *cp; 349*9160SSherry.Moore@Sun.COM grub_menu_t *mp; 350*9160SSherry.Moore@Sun.COM int len, n, ret; 351*9160SSherry.Moore@Sun.COM char buf[GRBM_MAXLINE]; 352*9160SSherry.Moore@Sun.COM 353*9160SSherry.Moore@Sun.COM if (menup == NULL) 354*9160SSherry.Moore@Sun.COM return (EINVAL); 355*9160SSherry.Moore@Sun.COM 356*9160SSherry.Moore@Sun.COM /* 357*9160SSherry.Moore@Sun.COM * Allocate space, perform initialization 358*9160SSherry.Moore@Sun.COM */ 359*9160SSherry.Moore@Sun.COM if ((mp = calloc(1, sizeof (*mp))) == NULL) { 360*9160SSherry.Moore@Sun.COM *menup = mp; 361*9160SSherry.Moore@Sun.COM return (errno); 362*9160SSherry.Moore@Sun.COM } 363*9160SSherry.Moore@Sun.COM 364*9160SSherry.Moore@Sun.COM if ((ret = grub_fs_init(&mp->gm_fs)) != 0 || 365*9160SSherry.Moore@Sun.COM (ret = grub_current_root(&mp->gm_fs, &mp->gm_root)) != 0) 366*9160SSherry.Moore@Sun.COM goto err_out1; 367*9160SSherry.Moore@Sun.COM 368*9160SSherry.Moore@Sun.COM if (path == NULL) { 369*9160SSherry.Moore@Sun.COM /* 370*9160SSherry.Moore@Sun.COM * Use default grub-menu. 371*9160SSherry.Moore@Sun.COM * If top dataset is not mounted, mount it now. 372*9160SSherry.Moore@Sun.COM */ 373*9160SSherry.Moore@Sun.COM if (mp->gm_root.gr_fs[GRBM_FS_TOP].gfs_mountp[0] == 0) { 374*9160SSherry.Moore@Sun.COM if ((ret = grub_fsd_mount_tmp(mp->gm_root.gr_fs + 375*9160SSherry.Moore@Sun.COM GRBM_FS_TOP, mp->gm_root.gr_fstyp)) != 0) 376*9160SSherry.Moore@Sun.COM goto err_out1; 377*9160SSherry.Moore@Sun.COM } 378*9160SSherry.Moore@Sun.COM (void) snprintf(mp->gm_path, sizeof (mp->gm_path), 379*9160SSherry.Moore@Sun.COM "%s/%s", mp->gm_root.gr_fs[GRBM_FS_TOP].gfs_mountp, 380*9160SSherry.Moore@Sun.COM GRUB_MENU); 381*9160SSherry.Moore@Sun.COM } else { 382*9160SSherry.Moore@Sun.COM (void) strlcpy(mp->gm_path, path, sizeof (mp->gm_path)); 383*9160SSherry.Moore@Sun.COM } 384*9160SSherry.Moore@Sun.COM 385*9160SSherry.Moore@Sun.COM if ((fp = fopen(mp->gm_path, "r")) == NULL) { 386*9160SSherry.Moore@Sun.COM ret = errno; 387*9160SSherry.Moore@Sun.COM goto err_out1; 388*9160SSherry.Moore@Sun.COM } 389*9160SSherry.Moore@Sun.COM 390*9160SSherry.Moore@Sun.COM cp = buf; 391*9160SSherry.Moore@Sun.COM len = sizeof (buf); 392*9160SSherry.Moore@Sun.COM 393*9160SSherry.Moore@Sun.COM while (fgets(cp, len, fp) != NULL) { 394*9160SSherry.Moore@Sun.COM 395*9160SSherry.Moore@Sun.COM if (IS_LINE2BIG(cp, len, n)) { 396*9160SSherry.Moore@Sun.COM ret = E2BIG; 397*9160SSherry.Moore@Sun.COM break; 398*9160SSherry.Moore@Sun.COM } 399*9160SSherry.Moore@Sun.COM 400*9160SSherry.Moore@Sun.COM /* remove white space at the end of line */ 401*9160SSherry.Moore@Sun.COM for (; isspace(cp[n - 1]); --n) 402*9160SSherry.Moore@Sun.COM ; 403*9160SSherry.Moore@Sun.COM cp[n] = '\0'; 404*9160SSherry.Moore@Sun.COM 405*9160SSherry.Moore@Sun.COM if (cp[n - 1] == '\\') { 406*9160SSherry.Moore@Sun.COM len -= n - 1; 407*9160SSherry.Moore@Sun.COM assert(len >= 2); 408*9160SSherry.Moore@Sun.COM cp += n - 1; 409*9160SSherry.Moore@Sun.COM continue; 410*9160SSherry.Moore@Sun.COM } 411*9160SSherry.Moore@Sun.COM if ((ret = grub_menu_append_line(mp, buf)) != 0) 412*9160SSherry.Moore@Sun.COM break; 413*9160SSherry.Moore@Sun.COM 414*9160SSherry.Moore@Sun.COM cp = buf; 415*9160SSherry.Moore@Sun.COM len = sizeof (buf); 416*9160SSherry.Moore@Sun.COM } 417*9160SSherry.Moore@Sun.COM 418*9160SSherry.Moore@Sun.COM if (fclose(fp) == EOF) 419*9160SSherry.Moore@Sun.COM ret = errno; 420*9160SSherry.Moore@Sun.COM else if (ret == 0) 421*9160SSherry.Moore@Sun.COM ret = grub_menu_process(mp); 422*9160SSherry.Moore@Sun.COM 423*9160SSherry.Moore@Sun.COM err_out1: 424*9160SSherry.Moore@Sun.COM grub_fsd_umount_tmp(mp->gm_root.gr_fs + GRBM_FS_TOP); 425*9160SSherry.Moore@Sun.COM if (0 != ret) { 426*9160SSherry.Moore@Sun.COM grub_menu_fini(mp); 427*9160SSherry.Moore@Sun.COM mp = NULL; 428*9160SSherry.Moore@Sun.COM } 429*9160SSherry.Moore@Sun.COM *menup = mp; 430*9160SSherry.Moore@Sun.COM return (ret); 431*9160SSherry.Moore@Sun.COM } 432*9160SSherry.Moore@Sun.COM 433*9160SSherry.Moore@Sun.COM void 434*9160SSherry.Moore@Sun.COM grub_menu_fini(grub_menu_t *mp) 435*9160SSherry.Moore@Sun.COM { 436*9160SSherry.Moore@Sun.COM if (mp == NULL) 437*9160SSherry.Moore@Sun.COM return; 438*9160SSherry.Moore@Sun.COM 439*9160SSherry.Moore@Sun.COM grub_fs_fini(&mp->gm_fs); 440*9160SSherry.Moore@Sun.COM free_entries(mp); 441*9160SSherry.Moore@Sun.COM free_linelist(mp->gm_start); 442*9160SSherry.Moore@Sun.COM free(mp); 443*9160SSherry.Moore@Sun.COM } 444*9160SSherry.Moore@Sun.COM 445*9160SSherry.Moore@Sun.COM grub_line_t * 446*9160SSherry.Moore@Sun.COM grub_menu_next_line(const grub_menu_t *mp, const grub_line_t *lp) 447*9160SSherry.Moore@Sun.COM { 448*9160SSherry.Moore@Sun.COM assert(mp); 449*9160SSherry.Moore@Sun.COM if (lp == NULL) 450*9160SSherry.Moore@Sun.COM return (mp->gm_start); 451*9160SSherry.Moore@Sun.COM else 452*9160SSherry.Moore@Sun.COM return (lp->gl_next); 453*9160SSherry.Moore@Sun.COM } 454*9160SSherry.Moore@Sun.COM 455*9160SSherry.Moore@Sun.COM grub_line_t * 456*9160SSherry.Moore@Sun.COM grub_menu_prev_line(const grub_menu_t *mp, const grub_line_t *lp) 457*9160SSherry.Moore@Sun.COM { 458*9160SSherry.Moore@Sun.COM assert(mp); 459*9160SSherry.Moore@Sun.COM if (lp == NULL) 460*9160SSherry.Moore@Sun.COM return (mp->gm_end); 461*9160SSherry.Moore@Sun.COM else 462*9160SSherry.Moore@Sun.COM return (lp->gl_prev); 463*9160SSherry.Moore@Sun.COM } 464*9160SSherry.Moore@Sun.COM 465*9160SSherry.Moore@Sun.COM grub_line_t * 466*9160SSherry.Moore@Sun.COM grub_menu_get_line(const grub_menu_t *mp, int num) 467*9160SSherry.Moore@Sun.COM { 468*9160SSherry.Moore@Sun.COM grub_line_t *lp; 469*9160SSherry.Moore@Sun.COM 470*9160SSherry.Moore@Sun.COM assert(mp); 471*9160SSherry.Moore@Sun.COM if (num > mp->gm_line_num) 472*9160SSherry.Moore@Sun.COM return (NULL); 473*9160SSherry.Moore@Sun.COM for (lp = mp->gm_start; lp != NULL && num != lp->gl_line_num; 474*9160SSherry.Moore@Sun.COM lp = lp->gl_next) 475*9160SSherry.Moore@Sun.COM ; 476*9160SSherry.Moore@Sun.COM return (lp); 477*9160SSherry.Moore@Sun.COM } 478*9160SSherry.Moore@Sun.COM 479*9160SSherry.Moore@Sun.COM size_t 480*9160SSherry.Moore@Sun.COM grub_menu_get_cmdline(const grub_menu_t *mp, int num, char *cmdl, size_t size) 481*9160SSherry.Moore@Sun.COM { 482*9160SSherry.Moore@Sun.COM grub_entry_t *ent; 483*9160SSherry.Moore@Sun.COM 484*9160SSherry.Moore@Sun.COM assert(mp); 485*9160SSherry.Moore@Sun.COM if ((ent = grub_menu_get_entry(mp, num)) == NULL) 486*9160SSherry.Moore@Sun.COM return (size_t)(-1); 487*9160SSherry.Moore@Sun.COM 488*9160SSherry.Moore@Sun.COM return (grub_entry_get_cmdline(ent, cmdl, size)); 489*9160SSherry.Moore@Sun.COM } 490*9160SSherry.Moore@Sun.COM 491*9160SSherry.Moore@Sun.COM grub_entry_t * 492*9160SSherry.Moore@Sun.COM grub_menu_next_entry(const grub_menu_t *mp, const grub_entry_t *ent) 493*9160SSherry.Moore@Sun.COM { 494*9160SSherry.Moore@Sun.COM assert(mp); 495*9160SSherry.Moore@Sun.COM if (ent == NULL) { 496*9160SSherry.Moore@Sun.COM return (mp->gm_ent_start); 497*9160SSherry.Moore@Sun.COM } else { 498*9160SSherry.Moore@Sun.COM assert(mp == ent->ge_menu); 499*9160SSherry.Moore@Sun.COM return (ent->ge_next); 500*9160SSherry.Moore@Sun.COM } 501*9160SSherry.Moore@Sun.COM } 502*9160SSherry.Moore@Sun.COM 503*9160SSherry.Moore@Sun.COM grub_entry_t * 504*9160SSherry.Moore@Sun.COM grub_menu_prev_entry(const grub_menu_t *mp, const grub_entry_t *ent) 505*9160SSherry.Moore@Sun.COM { 506*9160SSherry.Moore@Sun.COM assert(mp); 507*9160SSherry.Moore@Sun.COM if (ent == NULL) { 508*9160SSherry.Moore@Sun.COM return (mp->gm_ent_end); 509*9160SSherry.Moore@Sun.COM } else { 510*9160SSherry.Moore@Sun.COM assert(mp == ent->ge_menu); 511*9160SSherry.Moore@Sun.COM return (ent->ge_prev); 512*9160SSherry.Moore@Sun.COM } 513*9160SSherry.Moore@Sun.COM } 514*9160SSherry.Moore@Sun.COM 515*9160SSherry.Moore@Sun.COM grub_entry_t * 516*9160SSherry.Moore@Sun.COM grub_menu_get_entry(const grub_menu_t *mp, int num) 517*9160SSherry.Moore@Sun.COM { 518*9160SSherry.Moore@Sun.COM grub_entry_t *ent; 519*9160SSherry.Moore@Sun.COM 520*9160SSherry.Moore@Sun.COM assert(mp); 521*9160SSherry.Moore@Sun.COM if (num == GRUB_ENTRY_DEFAULT) { 522*9160SSherry.Moore@Sun.COM ent = mp->gm_ent_default; 523*9160SSherry.Moore@Sun.COM } else if (num >= mp->gm_entry_num) { 524*9160SSherry.Moore@Sun.COM ent = NULL; 525*9160SSherry.Moore@Sun.COM } else { 526*9160SSherry.Moore@Sun.COM for (ent = mp->gm_ent_start; 527*9160SSherry.Moore@Sun.COM ent != NULL && num != ent->ge_entry_num; 528*9160SSherry.Moore@Sun.COM ent = ent->ge_next) 529*9160SSherry.Moore@Sun.COM ; 530*9160SSherry.Moore@Sun.COM } 531*9160SSherry.Moore@Sun.COM return (ent); 532*9160SSherry.Moore@Sun.COM } 533