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 functions for manipulating the GRUB menu. 28753a6d45SSherry Moore */ 29753a6d45SSherry Moore #include <stdio.h> 30753a6d45SSherry Moore #include <errno.h> 31753a6d45SSherry Moore #include <stdlib.h> 32753a6d45SSherry Moore #include <string.h> 33753a6d45SSherry Moore #include <unistd.h> 34753a6d45SSherry Moore #include <sys/types.h> 35753a6d45SSherry Moore #include <sys/mount.h> 36753a6d45SSherry Moore #include <stdarg.h> 37753a6d45SSherry Moore #include <assert.h> 38753a6d45SSherry Moore #include <ctype.h> 39753a6d45SSherry Moore 40753a6d45SSherry Moore #include "libgrub_impl.h" 41753a6d45SSherry Moore 42753a6d45SSherry Moore static const grub_cmd_desc_t grub_cmd_descs[GRBM_CMD_NUM] = { 43753a6d45SSherry Moore #define menu_cmd(cmd, num, flag, parsef) {cmd, num, flag}, 44753a6d45SSherry Moore #include "libgrub_cmd.def" 45753a6d45SSherry Moore }; 46753a6d45SSherry Moore 47753a6d45SSherry Moore static void 48753a6d45SSherry Moore append_line(grub_menu_t *mp, grub_line_t *lp) 49753a6d45SSherry Moore { 50753a6d45SSherry Moore if (mp->gm_start == NULL) { 51753a6d45SSherry Moore mp->gm_start = lp; 52753a6d45SSherry Moore } else { 53753a6d45SSherry Moore mp->gm_end->gl_next = lp; 54753a6d45SSherry Moore lp->gl_prev = mp->gm_end; 55753a6d45SSherry Moore } 56753a6d45SSherry Moore mp->gm_end = lp; 57753a6d45SSherry Moore lp->gl_line_num = ++mp->gm_line_num; 58753a6d45SSherry Moore lp->gl_entry_num = GRUB_ENTRY_DEFAULT; 59753a6d45SSherry Moore } 60753a6d45SSherry Moore 61753a6d45SSherry Moore static void 62753a6d45SSherry Moore process_line(grub_menu_t *mp) 63753a6d45SSherry Moore { 64753a6d45SSherry Moore int n; 65753a6d45SSherry Moore grub_line_t *lp; 66753a6d45SSherry Moore 67753a6d45SSherry Moore lp = mp->gm_end; 68753a6d45SSherry Moore n = sizeof (grub_cmd_descs) / sizeof (grub_cmd_descs[0]); 69753a6d45SSherry Moore 70753a6d45SSherry Moore /* search through the table of known commands */ 71753a6d45SSherry Moore while (n-- != 0 && strcmp(lp->gl_cmd, grub_cmd_descs[n].gcd_cmd) != 0) 72753a6d45SSherry Moore ; 73753a6d45SSherry Moore 74753a6d45SSherry Moore /* unknown command */ 75753a6d45SSherry Moore if (n < 0) 76753a6d45SSherry Moore return; 77753a6d45SSherry Moore 78753a6d45SSherry Moore /* we found command, fill lp fields */ 79753a6d45SSherry Moore lp->gl_flags = grub_cmd_descs[n].gcd_flags; 80753a6d45SSherry Moore lp->gl_cmdtp = grub_cmd_descs[n].gcd_num; 81753a6d45SSherry Moore } 82753a6d45SSherry Moore 83753a6d45SSherry Moore 84753a6d45SSherry Moore static void 85753a6d45SSherry Moore check_entry(grub_entry_t *ent) 86753a6d45SSherry Moore { 87753a6d45SSherry Moore int i; 88753a6d45SSherry Moore uint_t emask; 89753a6d45SSherry Moore grub_line_t *lp; 90753a6d45SSherry Moore const grub_line_t * const lend = ent->ge_end->gl_next; 91753a6d45SSherry Moore 92753a6d45SSherry Moore emask = 0; 93753a6d45SSherry Moore for (i = 0, lp = ent->ge_start; lend != lp; lp = lp->gl_next, ++i) { 94753a6d45SSherry Moore lp->gl_entry_num = ent->ge_entry_num; 95753a6d45SSherry Moore if (lp->gl_flags == GRUB_LINE_INVALID || 96753a6d45SSherry Moore lp->gl_flags == GRUB_LINE_GLOBAL) { 97753a6d45SSherry Moore emask |= 1 << i; 98753a6d45SSherry Moore lp->gl_flags = GRUB_LINE_INVALID; 99753a6d45SSherry Moore } 100753a6d45SSherry Moore } 101753a6d45SSherry Moore 102753a6d45SSherry Moore if ((ent->ge_emask = emask) == 0) 103753a6d45SSherry Moore ent->ge_flags |= GRBM_VALID_FLAG; 104753a6d45SSherry Moore } 105753a6d45SSherry Moore 106753a6d45SSherry Moore static int 107753a6d45SSherry Moore add_entry(grub_menu_t *mp, grub_line_t *start, grub_line_t *end) 108753a6d45SSherry Moore { 109753a6d45SSherry Moore grub_entry_t *ent; 110753a6d45SSherry Moore 111753a6d45SSherry Moore if ((ent = calloc(1, sizeof (*ent))) == NULL) 112753a6d45SSherry Moore return (errno); 113753a6d45SSherry Moore 114753a6d45SSherry Moore ent->ge_start = start; 115753a6d45SSherry Moore ent->ge_end = end; 116753a6d45SSherry Moore 117753a6d45SSherry Moore if (mp->gm_ent_end == NULL) { 118753a6d45SSherry Moore mp->gm_ent_start = ent; 119753a6d45SSherry Moore } else { 120753a6d45SSherry Moore mp->gm_ent_end->ge_next = ent; 121753a6d45SSherry Moore ent->ge_prev = mp->gm_ent_end; 122753a6d45SSherry Moore } 123753a6d45SSherry Moore mp->gm_ent_end = ent; 124753a6d45SSherry Moore ent->ge_entry_num = mp->gm_entry_num++; 125753a6d45SSherry Moore ent->ge_menu = mp; 126753a6d45SSherry Moore return (0); 127753a6d45SSherry Moore } 128753a6d45SSherry Moore 129753a6d45SSherry Moore static void 130753a6d45SSherry Moore default_entry(grub_menu_t *mp) 131753a6d45SSherry Moore { 132753a6d45SSherry Moore uint_t defent; 133753a6d45SSherry Moore grub_line_t *lp; 134753a6d45SSherry Moore grub_entry_t *ent; 135753a6d45SSherry Moore 136753a6d45SSherry Moore defent = 0; 137753a6d45SSherry Moore lp = mp->gm_curdefault; 138753a6d45SSherry Moore 139753a6d45SSherry Moore if (lp != NULL && lp->gl_flags == GRUB_LINE_GLOBAL && 140753a6d45SSherry Moore lp->gl_cmdtp == GRBM_DEFAULT_CMD) { 141753a6d45SSherry Moore defent = strtoul(lp->gl_arg, NULL, 0); 142753a6d45SSherry Moore if (defent >= mp->gm_entry_num) 143753a6d45SSherry Moore defent = 0; 144753a6d45SSherry Moore } 145753a6d45SSherry Moore 146753a6d45SSherry Moore for (ent = mp->gm_ent_start; ent != NULL && defent != ent->ge_entry_num; 147753a6d45SSherry Moore ent = ent->ge_next) 148753a6d45SSherry Moore ; 149753a6d45SSherry Moore 150753a6d45SSherry Moore mp->gm_ent_default = ent; 151753a6d45SSherry Moore } 152753a6d45SSherry Moore 153753a6d45SSherry Moore static void 154753a6d45SSherry Moore free_line(grub_line_t *lp) 155753a6d45SSherry Moore { 156753a6d45SSherry Moore if (lp == NULL) 157753a6d45SSherry Moore return; 158753a6d45SSherry Moore 159753a6d45SSherry Moore free(lp->gl_cmd); 160753a6d45SSherry Moore free(lp->gl_sep); 161753a6d45SSherry Moore free(lp->gl_arg); 162753a6d45SSherry Moore free(lp->gl_line); 163753a6d45SSherry Moore free(lp); 164753a6d45SSherry Moore } 165753a6d45SSherry Moore 166753a6d45SSherry Moore static void 167753a6d45SSherry Moore free_linelist(grub_line_t *line) 168753a6d45SSherry Moore { 169753a6d45SSherry Moore grub_line_t *lp; 170753a6d45SSherry Moore 171753a6d45SSherry Moore if (line == NULL) 172753a6d45SSherry Moore return; 173753a6d45SSherry Moore 174753a6d45SSherry Moore while (line) { 175753a6d45SSherry Moore lp = line; 176753a6d45SSherry Moore line = lp->gl_next; 177753a6d45SSherry Moore free_line(lp); 178753a6d45SSherry Moore } 179753a6d45SSherry Moore } 180753a6d45SSherry Moore 181753a6d45SSherry Moore static void 182753a6d45SSherry Moore free_entries(grub_menu_t *mp) 183753a6d45SSherry Moore { 184753a6d45SSherry Moore grub_entry_t *ent, *tmp; 185753a6d45SSherry Moore 186753a6d45SSherry Moore if (mp == NULL) 187753a6d45SSherry Moore return; 188753a6d45SSherry Moore 189753a6d45SSherry Moore for (ent = mp->gm_ent_start; (tmp = ent) != NULL; 190753a6d45SSherry Moore ent = tmp->ge_next, free(tmp)) 191753a6d45SSherry Moore ; 192753a6d45SSherry Moore 193753a6d45SSherry Moore mp->gm_ent_start = NULL; 194753a6d45SSherry Moore mp->gm_ent_end = NULL; 195753a6d45SSherry Moore } 196753a6d45SSherry Moore 197753a6d45SSherry Moore static int 198753a6d45SSherry Moore grub_menu_append_line(grub_menu_t *mp, const char *line) 199753a6d45SSherry Moore { 200753a6d45SSherry Moore int rc; 201753a6d45SSherry Moore size_t n; 202753a6d45SSherry Moore grub_line_t *lp; 203753a6d45SSherry Moore 204753a6d45SSherry Moore if (line == NULL) 205753a6d45SSherry Moore return (EINVAL); 206753a6d45SSherry Moore 207753a6d45SSherry Moore rc = 0; 208753a6d45SSherry Moore lp = NULL; 209753a6d45SSherry Moore if ((lp = calloc(1, sizeof (*lp))) == NULL || 210753a6d45SSherry Moore (lp->gl_line = strdup(line)) == NULL) { 211753a6d45SSherry Moore free(lp); 212753a6d45SSherry Moore return (errno); 213753a6d45SSherry Moore } 214753a6d45SSherry Moore 215753a6d45SSherry Moore /* skip initial white space */ 216753a6d45SSherry Moore line += strspn(line, " \t"); 217753a6d45SSherry Moore 218753a6d45SSherry Moore /* process comment line */ 219753a6d45SSherry Moore if (line[0] == '#') { 220753a6d45SSherry Moore if ((lp->gl_cmd = 221753a6d45SSherry Moore strdup(grub_cmd_descs[GRBM_COMMENT_CMD].gcd_cmd)) == NULL || 222753a6d45SSherry Moore (lp->gl_sep = 223753a6d45SSherry Moore strdup(grub_cmd_descs[GRBM_EMPTY_CMD].gcd_cmd)) == NULL || 224753a6d45SSherry Moore (lp->gl_arg = strdup(line + 1)) == NULL) 225753a6d45SSherry Moore rc = errno; 226753a6d45SSherry Moore } else { 227753a6d45SSherry Moore /* get command */ 228753a6d45SSherry Moore n = strcspn(line, " \t="); 229753a6d45SSherry Moore if ((lp->gl_cmd = malloc(n + 1)) == NULL) 230753a6d45SSherry Moore rc = errno; 231753a6d45SSherry Moore else 232753a6d45SSherry Moore (void) strlcpy(lp->gl_cmd, line, n + 1); 233753a6d45SSherry Moore 234753a6d45SSherry Moore line += n; 235753a6d45SSherry Moore 236753a6d45SSherry Moore /* get separator */ 237753a6d45SSherry Moore n = strspn(line, " \t="); 238753a6d45SSherry Moore if ((lp->gl_sep = malloc(n + 1)) == NULL) 239753a6d45SSherry Moore rc = errno; 240753a6d45SSherry Moore else 241753a6d45SSherry Moore (void) strlcpy(lp->gl_sep, line, n + 1); 242753a6d45SSherry Moore 243753a6d45SSherry Moore line += n; 244753a6d45SSherry Moore 245753a6d45SSherry Moore /* get arguments */ 246753a6d45SSherry Moore if ((lp->gl_arg = strdup(line)) == NULL) 247753a6d45SSherry Moore rc = errno; 248753a6d45SSherry Moore } 249753a6d45SSherry Moore 250753a6d45SSherry Moore if (rc != 0) { 251753a6d45SSherry Moore free_line(lp); 252753a6d45SSherry Moore return (rc); 253753a6d45SSherry Moore } 254753a6d45SSherry Moore 255753a6d45SSherry Moore append_line(mp, lp); 256753a6d45SSherry Moore process_line(mp); 257753a6d45SSherry Moore return (0); 258753a6d45SSherry Moore } 259753a6d45SSherry Moore 260753a6d45SSherry Moore static int 261753a6d45SSherry Moore grub_menu_process(grub_menu_t *mp) 262753a6d45SSherry Moore { 263753a6d45SSherry Moore int ret; 264753a6d45SSherry Moore grub_entry_t *ent; 265753a6d45SSherry Moore grub_line_t *line, *start; 266753a6d45SSherry Moore 267753a6d45SSherry Moore /* Free remaininig entries, if any */ 268753a6d45SSherry Moore free_entries(mp); 269753a6d45SSherry Moore 270753a6d45SSherry Moore /* 271753a6d45SSherry Moore * Walk through lines, till first 'title' command is encountered. 272753a6d45SSherry Moore * Initialize globals. 273753a6d45SSherry Moore */ 274753a6d45SSherry Moore for (line = mp->gm_start; line != NULL; line = line->gl_next) { 275753a6d45SSherry Moore if (line->gl_flags == GRUB_LINE_GLOBAL && 276753a6d45SSherry Moore line->gl_cmdtp == GRBM_DEFAULT_CMD) 277753a6d45SSherry Moore mp->gm_curdefault = line; 278753a6d45SSherry Moore else if (line->gl_cmdtp == GRBM_TITLE_CMD) 279753a6d45SSherry Moore break; 280753a6d45SSherry Moore } 281753a6d45SSherry Moore 282753a6d45SSherry Moore /* 283753a6d45SSherry Moore * Walk through remaining lines and recreate menu entries. 284753a6d45SSherry Moore */ 285753a6d45SSherry Moore for (start = NULL; line != NULL; line = line->gl_next) { 286753a6d45SSherry Moore if (line->gl_cmdtp == GRBM_TITLE_CMD) { 287753a6d45SSherry Moore /* is first entry */ 288753a6d45SSherry Moore if (start != NULL && 289753a6d45SSherry Moore (ret = add_entry(mp, start, line->gl_prev)) != 0) 290753a6d45SSherry Moore return (ret); 291753a6d45SSherry Moore start = line; 292753a6d45SSherry Moore } 293753a6d45SSherry Moore } 294753a6d45SSherry Moore 295753a6d45SSherry Moore /* Add last entry */ 296753a6d45SSherry Moore if (start != NULL && (ret = add_entry(mp, start, mp->gm_end)) != 0) 297753a6d45SSherry Moore return (ret); 298753a6d45SSherry Moore 299753a6d45SSherry Moore for (ent = mp->gm_ent_start; NULL != ent; ent = ent->ge_next) 300753a6d45SSherry Moore check_entry(ent); 301753a6d45SSherry Moore 302753a6d45SSherry Moore default_entry(mp); 303753a6d45SSherry Moore 304753a6d45SSherry Moore return (0); 305753a6d45SSherry Moore } 306753a6d45SSherry Moore 307753a6d45SSherry Moore static int 308753a6d45SSherry Moore grub_fs_init(grub_fs_t *fs) 309753a6d45SSherry Moore { 310753a6d45SSherry Moore assert(fs); 311753a6d45SSherry Moore if ((fs->gf_lzfh = libzfs_init()) == NULL || 312753a6d45SSherry Moore (fs->gf_diroot = di_init("/", DINFOCPYALL | DINFOPATH)) 313753a6d45SSherry Moore == DI_NODE_NIL || 314753a6d45SSherry Moore (fs->gf_dvlh = di_devlink_init(NULL, 0)) == DI_LINK_NIL) { 315753a6d45SSherry Moore return (EG_INITFS); 316753a6d45SSherry Moore } 317753a6d45SSherry Moore return (0); 318753a6d45SSherry Moore } 319753a6d45SSherry Moore 320753a6d45SSherry Moore static void 321753a6d45SSherry Moore grub_fs_fini(grub_fs_t *fs) 322753a6d45SSherry Moore { 323753a6d45SSherry Moore if (fs == NULL) 324753a6d45SSherry Moore return; 325753a6d45SSherry Moore 326753a6d45SSherry Moore if (fs->gf_dvlh != DI_LINK_NIL) 327753a6d45SSherry Moore (void) di_devlink_fini(&fs->gf_dvlh); 328753a6d45SSherry Moore if (fs->gf_diroot != DI_NODE_NIL) 329753a6d45SSherry Moore di_fini(fs->gf_diroot); 330753a6d45SSherry Moore if (fs->gf_lzfh != NULL) 331753a6d45SSherry Moore libzfs_fini(fs->gf_lzfh); 332753a6d45SSherry Moore (void) memset(fs, 0, sizeof (*fs)); 333753a6d45SSherry Moore } 334753a6d45SSherry Moore 335753a6d45SSherry Moore /* 336753a6d45SSherry Moore * Reads and parses GRUB menu file into a grub_menu_t data structure. 337753a6d45SSherry Moore * If grub_menu_path file path is NULL, will use 'currently active' 338753a6d45SSherry Moore * GRUB menu file. 339753a6d45SSherry Moore * 340753a6d45SSherry Moore * Memory for the menu data structure is allocated within the routine. 341753a6d45SSherry Moore * Caller must call grub_menu_fini() to release memory after calling 342753a6d45SSherry Moore * grub_menu_init(). 343753a6d45SSherry Moore */ 344753a6d45SSherry Moore int 345753a6d45SSherry Moore grub_menu_init(const char *path, grub_menu_t **menup) 346753a6d45SSherry Moore { 347753a6d45SSherry Moore FILE *fp; 348753a6d45SSherry Moore char *cp; 349753a6d45SSherry Moore grub_menu_t *mp; 350753a6d45SSherry Moore int len, n, ret; 351753a6d45SSherry Moore char buf[GRBM_MAXLINE]; 352753a6d45SSherry Moore 353753a6d45SSherry Moore if (menup == NULL) 354753a6d45SSherry Moore return (EINVAL); 355753a6d45SSherry Moore 356753a6d45SSherry Moore /* 357753a6d45SSherry Moore * Allocate space, perform initialization 358753a6d45SSherry Moore */ 359753a6d45SSherry Moore if ((mp = calloc(1, sizeof (*mp))) == NULL) { 360753a6d45SSherry Moore *menup = mp; 361753a6d45SSherry Moore return (errno); 362753a6d45SSherry Moore } 363753a6d45SSherry Moore 364753a6d45SSherry Moore if ((ret = grub_fs_init(&mp->gm_fs)) != 0 || 365753a6d45SSherry Moore (ret = grub_current_root(&mp->gm_fs, &mp->gm_root)) != 0) 366753a6d45SSherry Moore goto err_out1; 367753a6d45SSherry Moore 368753a6d45SSherry Moore if (path == NULL) { 369753a6d45SSherry Moore /* 370753a6d45SSherry Moore * Use default grub-menu. 371753a6d45SSherry Moore * If top dataset is not mounted, mount it now. 372753a6d45SSherry Moore */ 373753a6d45SSherry Moore if (mp->gm_root.gr_fs[GRBM_FS_TOP].gfs_mountp[0] == 0) { 374753a6d45SSherry Moore if ((ret = grub_fsd_mount_tmp(mp->gm_root.gr_fs + 375753a6d45SSherry Moore GRBM_FS_TOP, mp->gm_root.gr_fstyp)) != 0) 376753a6d45SSherry Moore goto err_out1; 377753a6d45SSherry Moore } 378753a6d45SSherry Moore (void) snprintf(mp->gm_path, sizeof (mp->gm_path), 379753a6d45SSherry Moore "%s/%s", mp->gm_root.gr_fs[GRBM_FS_TOP].gfs_mountp, 380753a6d45SSherry Moore GRUB_MENU); 381753a6d45SSherry Moore } else { 382753a6d45SSherry Moore (void) strlcpy(mp->gm_path, path, sizeof (mp->gm_path)); 383753a6d45SSherry Moore } 384753a6d45SSherry Moore 385753a6d45SSherry Moore if ((fp = fopen(mp->gm_path, "r")) == NULL) { 386753a6d45SSherry Moore ret = errno; 387753a6d45SSherry Moore goto err_out1; 388753a6d45SSherry Moore } 389753a6d45SSherry Moore 390753a6d45SSherry Moore cp = buf; 391753a6d45SSherry Moore len = sizeof (buf); 392753a6d45SSherry Moore 393753a6d45SSherry Moore while (fgets(cp, len, fp) != NULL) { 394753a6d45SSherry Moore 395753a6d45SSherry Moore if (IS_LINE2BIG(cp, len, n)) { 396753a6d45SSherry Moore ret = E2BIG; 397753a6d45SSherry Moore break; 398753a6d45SSherry Moore } 399753a6d45SSherry Moore 400753a6d45SSherry Moore /* remove white space at the end of line */ 401*372a97b1SKonstantin Ananyev for (; n != 0 && isspace(cp[n - 1]); --n) 402753a6d45SSherry Moore ; 403753a6d45SSherry Moore cp[n] = '\0'; 404753a6d45SSherry Moore 405*372a97b1SKonstantin Ananyev if (n > 0 && cp[n - 1] == '\\') { 406753a6d45SSherry Moore len -= n - 1; 407753a6d45SSherry Moore assert(len >= 2); 408753a6d45SSherry Moore cp += n - 1; 409753a6d45SSherry Moore continue; 410753a6d45SSherry Moore } 411753a6d45SSherry Moore if ((ret = grub_menu_append_line(mp, buf)) != 0) 412753a6d45SSherry Moore break; 413753a6d45SSherry Moore 414753a6d45SSherry Moore cp = buf; 415753a6d45SSherry Moore len = sizeof (buf); 416753a6d45SSherry Moore } 417753a6d45SSherry Moore 418753a6d45SSherry Moore if (fclose(fp) == EOF) 419753a6d45SSherry Moore ret = errno; 420753a6d45SSherry Moore else if (ret == 0) 421753a6d45SSherry Moore ret = grub_menu_process(mp); 422753a6d45SSherry Moore 423753a6d45SSherry Moore err_out1: 424753a6d45SSherry Moore grub_fsd_umount_tmp(mp->gm_root.gr_fs + GRBM_FS_TOP); 425753a6d45SSherry Moore if (0 != ret) { 426753a6d45SSherry Moore grub_menu_fini(mp); 427753a6d45SSherry Moore mp = NULL; 428753a6d45SSherry Moore } 429753a6d45SSherry Moore *menup = mp; 430753a6d45SSherry Moore return (ret); 431753a6d45SSherry Moore } 432753a6d45SSherry Moore 433753a6d45SSherry Moore void 434753a6d45SSherry Moore grub_menu_fini(grub_menu_t *mp) 435753a6d45SSherry Moore { 436753a6d45SSherry Moore if (mp == NULL) 437753a6d45SSherry Moore return; 438753a6d45SSherry Moore 439753a6d45SSherry Moore grub_fs_fini(&mp->gm_fs); 440753a6d45SSherry Moore free_entries(mp); 441753a6d45SSherry Moore free_linelist(mp->gm_start); 442753a6d45SSherry Moore free(mp); 443753a6d45SSherry Moore } 444753a6d45SSherry Moore 445753a6d45SSherry Moore grub_line_t * 446753a6d45SSherry Moore grub_menu_next_line(const grub_menu_t *mp, const grub_line_t *lp) 447753a6d45SSherry Moore { 448753a6d45SSherry Moore assert(mp); 449753a6d45SSherry Moore if (lp == NULL) 450753a6d45SSherry Moore return (mp->gm_start); 451753a6d45SSherry Moore else 452753a6d45SSherry Moore return (lp->gl_next); 453753a6d45SSherry Moore } 454753a6d45SSherry Moore 455753a6d45SSherry Moore grub_line_t * 456753a6d45SSherry Moore grub_menu_prev_line(const grub_menu_t *mp, const grub_line_t *lp) 457753a6d45SSherry Moore { 458753a6d45SSherry Moore assert(mp); 459753a6d45SSherry Moore if (lp == NULL) 460753a6d45SSherry Moore return (mp->gm_end); 461753a6d45SSherry Moore else 462753a6d45SSherry Moore return (lp->gl_prev); 463753a6d45SSherry Moore } 464753a6d45SSherry Moore 465753a6d45SSherry Moore grub_line_t * 466753a6d45SSherry Moore grub_menu_get_line(const grub_menu_t *mp, int num) 467753a6d45SSherry Moore { 468753a6d45SSherry Moore grub_line_t *lp; 469753a6d45SSherry Moore 470753a6d45SSherry Moore assert(mp); 471753a6d45SSherry Moore if (num > mp->gm_line_num) 472753a6d45SSherry Moore return (NULL); 473753a6d45SSherry Moore for (lp = mp->gm_start; lp != NULL && num != lp->gl_line_num; 474753a6d45SSherry Moore lp = lp->gl_next) 475753a6d45SSherry Moore ; 476753a6d45SSherry Moore return (lp); 477753a6d45SSherry Moore } 478753a6d45SSherry Moore 479753a6d45SSherry Moore size_t 480753a6d45SSherry Moore grub_menu_get_cmdline(const grub_menu_t *mp, int num, char *cmdl, size_t size) 481753a6d45SSherry Moore { 482753a6d45SSherry Moore grub_entry_t *ent; 483753a6d45SSherry Moore 484753a6d45SSherry Moore assert(mp); 485753a6d45SSherry Moore if ((ent = grub_menu_get_entry(mp, num)) == NULL) 486753a6d45SSherry Moore return (size_t)(-1); 487753a6d45SSherry Moore 488753a6d45SSherry Moore return (grub_entry_get_cmdline(ent, cmdl, size)); 489753a6d45SSherry Moore } 490753a6d45SSherry Moore 491753a6d45SSherry Moore grub_entry_t * 492753a6d45SSherry Moore grub_menu_next_entry(const grub_menu_t *mp, const grub_entry_t *ent) 493753a6d45SSherry Moore { 494753a6d45SSherry Moore assert(mp); 495753a6d45SSherry Moore if (ent == NULL) { 496753a6d45SSherry Moore return (mp->gm_ent_start); 497753a6d45SSherry Moore } else { 498753a6d45SSherry Moore assert(mp == ent->ge_menu); 499753a6d45SSherry Moore return (ent->ge_next); 500753a6d45SSherry Moore } 501753a6d45SSherry Moore } 502753a6d45SSherry Moore 503753a6d45SSherry Moore grub_entry_t * 504753a6d45SSherry Moore grub_menu_prev_entry(const grub_menu_t *mp, const grub_entry_t *ent) 505753a6d45SSherry Moore { 506753a6d45SSherry Moore assert(mp); 507753a6d45SSherry Moore if (ent == NULL) { 508753a6d45SSherry Moore return (mp->gm_ent_end); 509753a6d45SSherry Moore } else { 510753a6d45SSherry Moore assert(mp == ent->ge_menu); 511753a6d45SSherry Moore return (ent->ge_prev); 512753a6d45SSherry Moore } 513753a6d45SSherry Moore } 514753a6d45SSherry Moore 515753a6d45SSherry Moore grub_entry_t * 516753a6d45SSherry Moore grub_menu_get_entry(const grub_menu_t *mp, int num) 517753a6d45SSherry Moore { 518753a6d45SSherry Moore grub_entry_t *ent; 519753a6d45SSherry Moore 520753a6d45SSherry Moore assert(mp); 521753a6d45SSherry Moore if (num == GRUB_ENTRY_DEFAULT) { 522753a6d45SSherry Moore ent = mp->gm_ent_default; 523753a6d45SSherry Moore } else if (num >= mp->gm_entry_num) { 524753a6d45SSherry Moore ent = NULL; 525753a6d45SSherry Moore } else { 526753a6d45SSherry Moore for (ent = mp->gm_ent_start; 527753a6d45SSherry Moore ent != NULL && num != ent->ge_entry_num; 528753a6d45SSherry Moore ent = ent->ge_next) 529753a6d45SSherry Moore ; 530753a6d45SSherry Moore } 531753a6d45SSherry Moore return (ent); 532753a6d45SSherry Moore } 533