19160SSherry.Moore@Sun.COM /*
29160SSherry.Moore@Sun.COM * CDDL HEADER START
39160SSherry.Moore@Sun.COM *
49160SSherry.Moore@Sun.COM * The contents of this file are subject to the terms of the
59160SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License").
69160SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License.
79160SSherry.Moore@Sun.COM *
89160SSherry.Moore@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99160SSherry.Moore@Sun.COM * or http://www.opensolaris.org/os/licensing.
109160SSherry.Moore@Sun.COM * See the License for the specific language governing permissions
119160SSherry.Moore@Sun.COM * and limitations under the License.
129160SSherry.Moore@Sun.COM *
139160SSherry.Moore@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149160SSherry.Moore@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159160SSherry.Moore@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169160SSherry.Moore@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179160SSherry.Moore@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189160SSherry.Moore@Sun.COM *
199160SSherry.Moore@Sun.COM * CDDL HEADER END
209160SSherry.Moore@Sun.COM */
219160SSherry.Moore@Sun.COM /*
229160SSherry.Moore@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
239160SSherry.Moore@Sun.COM * Use is subject to license terms.
249160SSherry.Moore@Sun.COM */
259160SSherry.Moore@Sun.COM
269160SSherry.Moore@Sun.COM /*
279160SSherry.Moore@Sun.COM * This file contains functions for manipulating the GRUB menu.
289160SSherry.Moore@Sun.COM */
299160SSherry.Moore@Sun.COM #include <stdio.h>
309160SSherry.Moore@Sun.COM #include <errno.h>
319160SSherry.Moore@Sun.COM #include <stdlib.h>
329160SSherry.Moore@Sun.COM #include <string.h>
339160SSherry.Moore@Sun.COM #include <unistd.h>
349160SSherry.Moore@Sun.COM #include <sys/types.h>
359160SSherry.Moore@Sun.COM #include <sys/mount.h>
369160SSherry.Moore@Sun.COM #include <stdarg.h>
379160SSherry.Moore@Sun.COM #include <assert.h>
389160SSherry.Moore@Sun.COM #include <ctype.h>
399160SSherry.Moore@Sun.COM
409160SSherry.Moore@Sun.COM #include "libgrub_impl.h"
419160SSherry.Moore@Sun.COM
429160SSherry.Moore@Sun.COM static const grub_cmd_desc_t grub_cmd_descs[GRBM_CMD_NUM] = {
439160SSherry.Moore@Sun.COM #define menu_cmd(cmd, num, flag, parsef) {cmd, num, flag},
449160SSherry.Moore@Sun.COM #include "libgrub_cmd.def"
459160SSherry.Moore@Sun.COM };
469160SSherry.Moore@Sun.COM
479160SSherry.Moore@Sun.COM static void
append_line(grub_menu_t * mp,grub_line_t * lp)489160SSherry.Moore@Sun.COM append_line(grub_menu_t *mp, grub_line_t *lp)
499160SSherry.Moore@Sun.COM {
509160SSherry.Moore@Sun.COM if (mp->gm_start == NULL) {
519160SSherry.Moore@Sun.COM mp->gm_start = lp;
529160SSherry.Moore@Sun.COM } else {
539160SSherry.Moore@Sun.COM mp->gm_end->gl_next = lp;
549160SSherry.Moore@Sun.COM lp->gl_prev = mp->gm_end;
559160SSherry.Moore@Sun.COM }
569160SSherry.Moore@Sun.COM mp->gm_end = lp;
579160SSherry.Moore@Sun.COM lp->gl_line_num = ++mp->gm_line_num;
589160SSherry.Moore@Sun.COM lp->gl_entry_num = GRUB_ENTRY_DEFAULT;
599160SSherry.Moore@Sun.COM }
609160SSherry.Moore@Sun.COM
619160SSherry.Moore@Sun.COM static void
process_line(grub_menu_t * mp)629160SSherry.Moore@Sun.COM process_line(grub_menu_t *mp)
639160SSherry.Moore@Sun.COM {
649160SSherry.Moore@Sun.COM int n;
659160SSherry.Moore@Sun.COM grub_line_t *lp;
669160SSherry.Moore@Sun.COM
679160SSherry.Moore@Sun.COM lp = mp->gm_end;
689160SSherry.Moore@Sun.COM n = sizeof (grub_cmd_descs) / sizeof (grub_cmd_descs[0]);
699160SSherry.Moore@Sun.COM
709160SSherry.Moore@Sun.COM /* search through the table of known commands */
719160SSherry.Moore@Sun.COM while (n-- != 0 && strcmp(lp->gl_cmd, grub_cmd_descs[n].gcd_cmd) != 0)
729160SSherry.Moore@Sun.COM ;
739160SSherry.Moore@Sun.COM
749160SSherry.Moore@Sun.COM /* unknown command */
759160SSherry.Moore@Sun.COM if (n < 0)
769160SSherry.Moore@Sun.COM return;
779160SSherry.Moore@Sun.COM
789160SSherry.Moore@Sun.COM /* we found command, fill lp fields */
799160SSherry.Moore@Sun.COM lp->gl_flags = grub_cmd_descs[n].gcd_flags;
809160SSherry.Moore@Sun.COM lp->gl_cmdtp = grub_cmd_descs[n].gcd_num;
819160SSherry.Moore@Sun.COM }
829160SSherry.Moore@Sun.COM
839160SSherry.Moore@Sun.COM
849160SSherry.Moore@Sun.COM static void
check_entry(grub_entry_t * ent)859160SSherry.Moore@Sun.COM check_entry(grub_entry_t *ent)
869160SSherry.Moore@Sun.COM {
879160SSherry.Moore@Sun.COM int i;
889160SSherry.Moore@Sun.COM uint_t emask;
899160SSherry.Moore@Sun.COM grub_line_t *lp;
909160SSherry.Moore@Sun.COM const grub_line_t * const lend = ent->ge_end->gl_next;
919160SSherry.Moore@Sun.COM
929160SSherry.Moore@Sun.COM emask = 0;
939160SSherry.Moore@Sun.COM for (i = 0, lp = ent->ge_start; lend != lp; lp = lp->gl_next, ++i) {
949160SSherry.Moore@Sun.COM lp->gl_entry_num = ent->ge_entry_num;
959160SSherry.Moore@Sun.COM if (lp->gl_flags == GRUB_LINE_INVALID ||
969160SSherry.Moore@Sun.COM lp->gl_flags == GRUB_LINE_GLOBAL) {
979160SSherry.Moore@Sun.COM emask |= 1 << i;
989160SSherry.Moore@Sun.COM lp->gl_flags = GRUB_LINE_INVALID;
999160SSherry.Moore@Sun.COM }
1009160SSherry.Moore@Sun.COM }
1019160SSherry.Moore@Sun.COM
1029160SSherry.Moore@Sun.COM if ((ent->ge_emask = emask) == 0)
1039160SSherry.Moore@Sun.COM ent->ge_flags |= GRBM_VALID_FLAG;
1049160SSherry.Moore@Sun.COM }
1059160SSherry.Moore@Sun.COM
1069160SSherry.Moore@Sun.COM static int
add_entry(grub_menu_t * mp,grub_line_t * start,grub_line_t * end)1079160SSherry.Moore@Sun.COM add_entry(grub_menu_t *mp, grub_line_t *start, grub_line_t *end)
1089160SSherry.Moore@Sun.COM {
1099160SSherry.Moore@Sun.COM grub_entry_t *ent;
1109160SSherry.Moore@Sun.COM
1119160SSherry.Moore@Sun.COM if ((ent = calloc(1, sizeof (*ent))) == NULL)
1129160SSherry.Moore@Sun.COM return (errno);
1139160SSherry.Moore@Sun.COM
1149160SSherry.Moore@Sun.COM ent->ge_start = start;
1159160SSherry.Moore@Sun.COM ent->ge_end = end;
1169160SSherry.Moore@Sun.COM
1179160SSherry.Moore@Sun.COM if (mp->gm_ent_end == NULL) {
1189160SSherry.Moore@Sun.COM mp->gm_ent_start = ent;
1199160SSherry.Moore@Sun.COM } else {
1209160SSherry.Moore@Sun.COM mp->gm_ent_end->ge_next = ent;
1219160SSherry.Moore@Sun.COM ent->ge_prev = mp->gm_ent_end;
1229160SSherry.Moore@Sun.COM }
1239160SSherry.Moore@Sun.COM mp->gm_ent_end = ent;
1249160SSherry.Moore@Sun.COM ent->ge_entry_num = mp->gm_entry_num++;
1259160SSherry.Moore@Sun.COM ent->ge_menu = mp;
1269160SSherry.Moore@Sun.COM return (0);
1279160SSherry.Moore@Sun.COM }
1289160SSherry.Moore@Sun.COM
1299160SSherry.Moore@Sun.COM static void
default_entry(grub_menu_t * mp)1309160SSherry.Moore@Sun.COM default_entry(grub_menu_t *mp)
1319160SSherry.Moore@Sun.COM {
1329160SSherry.Moore@Sun.COM uint_t defent;
1339160SSherry.Moore@Sun.COM grub_line_t *lp;
1349160SSherry.Moore@Sun.COM grub_entry_t *ent;
1359160SSherry.Moore@Sun.COM
1369160SSherry.Moore@Sun.COM defent = 0;
1379160SSherry.Moore@Sun.COM lp = mp->gm_curdefault;
1389160SSherry.Moore@Sun.COM
1399160SSherry.Moore@Sun.COM if (lp != NULL && lp->gl_flags == GRUB_LINE_GLOBAL &&
1409160SSherry.Moore@Sun.COM lp->gl_cmdtp == GRBM_DEFAULT_CMD) {
1419160SSherry.Moore@Sun.COM defent = strtoul(lp->gl_arg, NULL, 0);
1429160SSherry.Moore@Sun.COM if (defent >= mp->gm_entry_num)
1439160SSherry.Moore@Sun.COM defent = 0;
1449160SSherry.Moore@Sun.COM }
1459160SSherry.Moore@Sun.COM
1469160SSherry.Moore@Sun.COM for (ent = mp->gm_ent_start; ent != NULL && defent != ent->ge_entry_num;
1479160SSherry.Moore@Sun.COM ent = ent->ge_next)
1489160SSherry.Moore@Sun.COM ;
1499160SSherry.Moore@Sun.COM
1509160SSherry.Moore@Sun.COM mp->gm_ent_default = ent;
1519160SSherry.Moore@Sun.COM }
1529160SSherry.Moore@Sun.COM
1539160SSherry.Moore@Sun.COM static void
free_line(grub_line_t * lp)1549160SSherry.Moore@Sun.COM free_line(grub_line_t *lp)
1559160SSherry.Moore@Sun.COM {
1569160SSherry.Moore@Sun.COM if (lp == NULL)
1579160SSherry.Moore@Sun.COM return;
1589160SSherry.Moore@Sun.COM
1599160SSherry.Moore@Sun.COM free(lp->gl_cmd);
1609160SSherry.Moore@Sun.COM free(lp->gl_sep);
1619160SSherry.Moore@Sun.COM free(lp->gl_arg);
1629160SSherry.Moore@Sun.COM free(lp->gl_line);
1639160SSherry.Moore@Sun.COM free(lp);
1649160SSherry.Moore@Sun.COM }
1659160SSherry.Moore@Sun.COM
1669160SSherry.Moore@Sun.COM static void
free_linelist(grub_line_t * line)1679160SSherry.Moore@Sun.COM free_linelist(grub_line_t *line)
1689160SSherry.Moore@Sun.COM {
1699160SSherry.Moore@Sun.COM grub_line_t *lp;
1709160SSherry.Moore@Sun.COM
1719160SSherry.Moore@Sun.COM if (line == NULL)
1729160SSherry.Moore@Sun.COM return;
1739160SSherry.Moore@Sun.COM
1749160SSherry.Moore@Sun.COM while (line) {
1759160SSherry.Moore@Sun.COM lp = line;
1769160SSherry.Moore@Sun.COM line = lp->gl_next;
1779160SSherry.Moore@Sun.COM free_line(lp);
1789160SSherry.Moore@Sun.COM }
1799160SSherry.Moore@Sun.COM }
1809160SSherry.Moore@Sun.COM
1819160SSherry.Moore@Sun.COM static void
free_entries(grub_menu_t * mp)1829160SSherry.Moore@Sun.COM free_entries(grub_menu_t *mp)
1839160SSherry.Moore@Sun.COM {
1849160SSherry.Moore@Sun.COM grub_entry_t *ent, *tmp;
1859160SSherry.Moore@Sun.COM
1869160SSherry.Moore@Sun.COM if (mp == NULL)
1879160SSherry.Moore@Sun.COM return;
1889160SSherry.Moore@Sun.COM
1899160SSherry.Moore@Sun.COM for (ent = mp->gm_ent_start; (tmp = ent) != NULL;
1909160SSherry.Moore@Sun.COM ent = tmp->ge_next, free(tmp))
1919160SSherry.Moore@Sun.COM ;
1929160SSherry.Moore@Sun.COM
1939160SSherry.Moore@Sun.COM mp->gm_ent_start = NULL;
1949160SSherry.Moore@Sun.COM mp->gm_ent_end = NULL;
1959160SSherry.Moore@Sun.COM }
1969160SSherry.Moore@Sun.COM
1979160SSherry.Moore@Sun.COM static int
grub_menu_append_line(grub_menu_t * mp,const char * line)1989160SSherry.Moore@Sun.COM grub_menu_append_line(grub_menu_t *mp, const char *line)
1999160SSherry.Moore@Sun.COM {
2009160SSherry.Moore@Sun.COM int rc;
2019160SSherry.Moore@Sun.COM size_t n;
2029160SSherry.Moore@Sun.COM grub_line_t *lp;
2039160SSherry.Moore@Sun.COM
2049160SSherry.Moore@Sun.COM if (line == NULL)
2059160SSherry.Moore@Sun.COM return (EINVAL);
2069160SSherry.Moore@Sun.COM
2079160SSherry.Moore@Sun.COM rc = 0;
2089160SSherry.Moore@Sun.COM lp = NULL;
2099160SSherry.Moore@Sun.COM if ((lp = calloc(1, sizeof (*lp))) == NULL ||
2109160SSherry.Moore@Sun.COM (lp->gl_line = strdup(line)) == NULL) {
2119160SSherry.Moore@Sun.COM free(lp);
2129160SSherry.Moore@Sun.COM return (errno);
2139160SSherry.Moore@Sun.COM }
2149160SSherry.Moore@Sun.COM
2159160SSherry.Moore@Sun.COM /* skip initial white space */
2169160SSherry.Moore@Sun.COM line += strspn(line, " \t");
2179160SSherry.Moore@Sun.COM
2189160SSherry.Moore@Sun.COM /* process comment line */
2199160SSherry.Moore@Sun.COM if (line[0] == '#') {
2209160SSherry.Moore@Sun.COM if ((lp->gl_cmd =
2219160SSherry.Moore@Sun.COM strdup(grub_cmd_descs[GRBM_COMMENT_CMD].gcd_cmd)) == NULL ||
2229160SSherry.Moore@Sun.COM (lp->gl_sep =
2239160SSherry.Moore@Sun.COM strdup(grub_cmd_descs[GRBM_EMPTY_CMD].gcd_cmd)) == NULL ||
2249160SSherry.Moore@Sun.COM (lp->gl_arg = strdup(line + 1)) == NULL)
2259160SSherry.Moore@Sun.COM rc = errno;
2269160SSherry.Moore@Sun.COM } else {
2279160SSherry.Moore@Sun.COM /* get command */
2289160SSherry.Moore@Sun.COM n = strcspn(line, " \t=");
2299160SSherry.Moore@Sun.COM if ((lp->gl_cmd = malloc(n + 1)) == NULL)
2309160SSherry.Moore@Sun.COM rc = errno;
2319160SSherry.Moore@Sun.COM else
2329160SSherry.Moore@Sun.COM (void) strlcpy(lp->gl_cmd, line, n + 1);
2339160SSherry.Moore@Sun.COM
2349160SSherry.Moore@Sun.COM line += n;
2359160SSherry.Moore@Sun.COM
2369160SSherry.Moore@Sun.COM /* get separator */
2379160SSherry.Moore@Sun.COM n = strspn(line, " \t=");
2389160SSherry.Moore@Sun.COM if ((lp->gl_sep = malloc(n + 1)) == NULL)
2399160SSherry.Moore@Sun.COM rc = errno;
2409160SSherry.Moore@Sun.COM else
2419160SSherry.Moore@Sun.COM (void) strlcpy(lp->gl_sep, line, n + 1);
2429160SSherry.Moore@Sun.COM
2439160SSherry.Moore@Sun.COM line += n;
2449160SSherry.Moore@Sun.COM
2459160SSherry.Moore@Sun.COM /* get arguments */
2469160SSherry.Moore@Sun.COM if ((lp->gl_arg = strdup(line)) == NULL)
2479160SSherry.Moore@Sun.COM rc = errno;
2489160SSherry.Moore@Sun.COM }
2499160SSherry.Moore@Sun.COM
2509160SSherry.Moore@Sun.COM if (rc != 0) {
2519160SSherry.Moore@Sun.COM free_line(lp);
2529160SSherry.Moore@Sun.COM return (rc);
2539160SSherry.Moore@Sun.COM }
2549160SSherry.Moore@Sun.COM
2559160SSherry.Moore@Sun.COM append_line(mp, lp);
2569160SSherry.Moore@Sun.COM process_line(mp);
2579160SSherry.Moore@Sun.COM return (0);
2589160SSherry.Moore@Sun.COM }
2599160SSherry.Moore@Sun.COM
2609160SSherry.Moore@Sun.COM static int
grub_menu_process(grub_menu_t * mp)2619160SSherry.Moore@Sun.COM grub_menu_process(grub_menu_t *mp)
2629160SSherry.Moore@Sun.COM {
2639160SSherry.Moore@Sun.COM int ret;
2649160SSherry.Moore@Sun.COM grub_entry_t *ent;
2659160SSherry.Moore@Sun.COM grub_line_t *line, *start;
2669160SSherry.Moore@Sun.COM
2679160SSherry.Moore@Sun.COM /* Free remaininig entries, if any */
2689160SSherry.Moore@Sun.COM free_entries(mp);
2699160SSherry.Moore@Sun.COM
2709160SSherry.Moore@Sun.COM /*
2719160SSherry.Moore@Sun.COM * Walk through lines, till first 'title' command is encountered.
2729160SSherry.Moore@Sun.COM * Initialize globals.
2739160SSherry.Moore@Sun.COM */
2749160SSherry.Moore@Sun.COM for (line = mp->gm_start; line != NULL; line = line->gl_next) {
2759160SSherry.Moore@Sun.COM if (line->gl_flags == GRUB_LINE_GLOBAL &&
2769160SSherry.Moore@Sun.COM line->gl_cmdtp == GRBM_DEFAULT_CMD)
2779160SSherry.Moore@Sun.COM mp->gm_curdefault = line;
2789160SSherry.Moore@Sun.COM else if (line->gl_cmdtp == GRBM_TITLE_CMD)
2799160SSherry.Moore@Sun.COM break;
2809160SSherry.Moore@Sun.COM }
2819160SSherry.Moore@Sun.COM
2829160SSherry.Moore@Sun.COM /*
2839160SSherry.Moore@Sun.COM * Walk through remaining lines and recreate menu entries.
2849160SSherry.Moore@Sun.COM */
2859160SSherry.Moore@Sun.COM for (start = NULL; line != NULL; line = line->gl_next) {
2869160SSherry.Moore@Sun.COM if (line->gl_cmdtp == GRBM_TITLE_CMD) {
2879160SSherry.Moore@Sun.COM /* is first entry */
2889160SSherry.Moore@Sun.COM if (start != NULL &&
2899160SSherry.Moore@Sun.COM (ret = add_entry(mp, start, line->gl_prev)) != 0)
2909160SSherry.Moore@Sun.COM return (ret);
2919160SSherry.Moore@Sun.COM start = line;
2929160SSherry.Moore@Sun.COM }
2939160SSherry.Moore@Sun.COM }
2949160SSherry.Moore@Sun.COM
2959160SSherry.Moore@Sun.COM /* Add last entry */
2969160SSherry.Moore@Sun.COM if (start != NULL && (ret = add_entry(mp, start, mp->gm_end)) != 0)
2979160SSherry.Moore@Sun.COM return (ret);
2989160SSherry.Moore@Sun.COM
2999160SSherry.Moore@Sun.COM for (ent = mp->gm_ent_start; NULL != ent; ent = ent->ge_next)
3009160SSherry.Moore@Sun.COM check_entry(ent);
3019160SSherry.Moore@Sun.COM
3029160SSherry.Moore@Sun.COM default_entry(mp);
3039160SSherry.Moore@Sun.COM
3049160SSherry.Moore@Sun.COM return (0);
3059160SSherry.Moore@Sun.COM }
3069160SSherry.Moore@Sun.COM
3079160SSherry.Moore@Sun.COM static int
grub_fs_init(grub_fs_t * fs)3089160SSherry.Moore@Sun.COM grub_fs_init(grub_fs_t *fs)
3099160SSherry.Moore@Sun.COM {
3109160SSherry.Moore@Sun.COM assert(fs);
3119160SSherry.Moore@Sun.COM if ((fs->gf_lzfh = libzfs_init()) == NULL ||
3129160SSherry.Moore@Sun.COM (fs->gf_diroot = di_init("/", DINFOCPYALL | DINFOPATH))
3139160SSherry.Moore@Sun.COM == DI_NODE_NIL ||
3149160SSherry.Moore@Sun.COM (fs->gf_dvlh = di_devlink_init(NULL, 0)) == DI_LINK_NIL) {
3159160SSherry.Moore@Sun.COM return (EG_INITFS);
3169160SSherry.Moore@Sun.COM }
3179160SSherry.Moore@Sun.COM return (0);
3189160SSherry.Moore@Sun.COM }
3199160SSherry.Moore@Sun.COM
3209160SSherry.Moore@Sun.COM static void
grub_fs_fini(grub_fs_t * fs)3219160SSherry.Moore@Sun.COM grub_fs_fini(grub_fs_t *fs)
3229160SSherry.Moore@Sun.COM {
3239160SSherry.Moore@Sun.COM if (fs == NULL)
3249160SSherry.Moore@Sun.COM return;
3259160SSherry.Moore@Sun.COM
3269160SSherry.Moore@Sun.COM if (fs->gf_dvlh != DI_LINK_NIL)
3279160SSherry.Moore@Sun.COM (void) di_devlink_fini(&fs->gf_dvlh);
3289160SSherry.Moore@Sun.COM if (fs->gf_diroot != DI_NODE_NIL)
3299160SSherry.Moore@Sun.COM di_fini(fs->gf_diroot);
3309160SSherry.Moore@Sun.COM if (fs->gf_lzfh != NULL)
3319160SSherry.Moore@Sun.COM libzfs_fini(fs->gf_lzfh);
3329160SSherry.Moore@Sun.COM (void) memset(fs, 0, sizeof (*fs));
3339160SSherry.Moore@Sun.COM }
3349160SSherry.Moore@Sun.COM
3359160SSherry.Moore@Sun.COM /*
3369160SSherry.Moore@Sun.COM * Reads and parses GRUB menu file into a grub_menu_t data structure.
3379160SSherry.Moore@Sun.COM * If grub_menu_path file path is NULL, will use 'currently active'
3389160SSherry.Moore@Sun.COM * GRUB menu file.
3399160SSherry.Moore@Sun.COM *
3409160SSherry.Moore@Sun.COM * Memory for the menu data structure is allocated within the routine.
3419160SSherry.Moore@Sun.COM * Caller must call grub_menu_fini() to release memory after calling
3429160SSherry.Moore@Sun.COM * grub_menu_init().
3439160SSherry.Moore@Sun.COM */
3449160SSherry.Moore@Sun.COM int
grub_menu_init(const char * path,grub_menu_t ** menup)3459160SSherry.Moore@Sun.COM grub_menu_init(const char *path, grub_menu_t **menup)
3469160SSherry.Moore@Sun.COM {
3479160SSherry.Moore@Sun.COM FILE *fp;
3489160SSherry.Moore@Sun.COM char *cp;
3499160SSherry.Moore@Sun.COM grub_menu_t *mp;
3509160SSherry.Moore@Sun.COM int len, n, ret;
3519160SSherry.Moore@Sun.COM char buf[GRBM_MAXLINE];
3529160SSherry.Moore@Sun.COM
3539160SSherry.Moore@Sun.COM if (menup == NULL)
3549160SSherry.Moore@Sun.COM return (EINVAL);
3559160SSherry.Moore@Sun.COM
3569160SSherry.Moore@Sun.COM /*
3579160SSherry.Moore@Sun.COM * Allocate space, perform initialization
3589160SSherry.Moore@Sun.COM */
3599160SSherry.Moore@Sun.COM if ((mp = calloc(1, sizeof (*mp))) == NULL) {
3609160SSherry.Moore@Sun.COM *menup = mp;
3619160SSherry.Moore@Sun.COM return (errno);
3629160SSherry.Moore@Sun.COM }
3639160SSherry.Moore@Sun.COM
3649160SSherry.Moore@Sun.COM if ((ret = grub_fs_init(&mp->gm_fs)) != 0 ||
3659160SSherry.Moore@Sun.COM (ret = grub_current_root(&mp->gm_fs, &mp->gm_root)) != 0)
3669160SSherry.Moore@Sun.COM goto err_out1;
3679160SSherry.Moore@Sun.COM
3689160SSherry.Moore@Sun.COM if (path == NULL) {
3699160SSherry.Moore@Sun.COM /*
3709160SSherry.Moore@Sun.COM * Use default grub-menu.
3719160SSherry.Moore@Sun.COM * If top dataset is not mounted, mount it now.
3729160SSherry.Moore@Sun.COM */
3739160SSherry.Moore@Sun.COM if (mp->gm_root.gr_fs[GRBM_FS_TOP].gfs_mountp[0] == 0) {
3749160SSherry.Moore@Sun.COM if ((ret = grub_fsd_mount_tmp(mp->gm_root.gr_fs +
3759160SSherry.Moore@Sun.COM GRBM_FS_TOP, mp->gm_root.gr_fstyp)) != 0)
3769160SSherry.Moore@Sun.COM goto err_out1;
3779160SSherry.Moore@Sun.COM }
3789160SSherry.Moore@Sun.COM (void) snprintf(mp->gm_path, sizeof (mp->gm_path),
3799160SSherry.Moore@Sun.COM "%s/%s", mp->gm_root.gr_fs[GRBM_FS_TOP].gfs_mountp,
3809160SSherry.Moore@Sun.COM GRUB_MENU);
3819160SSherry.Moore@Sun.COM } else {
3829160SSherry.Moore@Sun.COM (void) strlcpy(mp->gm_path, path, sizeof (mp->gm_path));
3839160SSherry.Moore@Sun.COM }
3849160SSherry.Moore@Sun.COM
3859160SSherry.Moore@Sun.COM if ((fp = fopen(mp->gm_path, "r")) == NULL) {
3869160SSherry.Moore@Sun.COM ret = errno;
3879160SSherry.Moore@Sun.COM goto err_out1;
3889160SSherry.Moore@Sun.COM }
3899160SSherry.Moore@Sun.COM
3909160SSherry.Moore@Sun.COM cp = buf;
3919160SSherry.Moore@Sun.COM len = sizeof (buf);
3929160SSherry.Moore@Sun.COM
3939160SSherry.Moore@Sun.COM while (fgets(cp, len, fp) != NULL) {
3949160SSherry.Moore@Sun.COM
3959160SSherry.Moore@Sun.COM if (IS_LINE2BIG(cp, len, n)) {
3969160SSherry.Moore@Sun.COM ret = E2BIG;
3979160SSherry.Moore@Sun.COM break;
3989160SSherry.Moore@Sun.COM }
3999160SSherry.Moore@Sun.COM
4009160SSherry.Moore@Sun.COM /* remove white space at the end of line */
401*11002SKonstantin.Ananyev@Sun.COM for (; n != 0 && isspace(cp[n - 1]); --n)
4029160SSherry.Moore@Sun.COM ;
4039160SSherry.Moore@Sun.COM cp[n] = '\0';
4049160SSherry.Moore@Sun.COM
405*11002SKonstantin.Ananyev@Sun.COM if (n > 0 && cp[n - 1] == '\\') {
4069160SSherry.Moore@Sun.COM len -= n - 1;
4079160SSherry.Moore@Sun.COM assert(len >= 2);
4089160SSherry.Moore@Sun.COM cp += n - 1;
4099160SSherry.Moore@Sun.COM continue;
4109160SSherry.Moore@Sun.COM }
4119160SSherry.Moore@Sun.COM if ((ret = grub_menu_append_line(mp, buf)) != 0)
4129160SSherry.Moore@Sun.COM break;
4139160SSherry.Moore@Sun.COM
4149160SSherry.Moore@Sun.COM cp = buf;
4159160SSherry.Moore@Sun.COM len = sizeof (buf);
4169160SSherry.Moore@Sun.COM }
4179160SSherry.Moore@Sun.COM
4189160SSherry.Moore@Sun.COM if (fclose(fp) == EOF)
4199160SSherry.Moore@Sun.COM ret = errno;
4209160SSherry.Moore@Sun.COM else if (ret == 0)
4219160SSherry.Moore@Sun.COM ret = grub_menu_process(mp);
4229160SSherry.Moore@Sun.COM
4239160SSherry.Moore@Sun.COM err_out1:
4249160SSherry.Moore@Sun.COM grub_fsd_umount_tmp(mp->gm_root.gr_fs + GRBM_FS_TOP);
4259160SSherry.Moore@Sun.COM if (0 != ret) {
4269160SSherry.Moore@Sun.COM grub_menu_fini(mp);
4279160SSherry.Moore@Sun.COM mp = NULL;
4289160SSherry.Moore@Sun.COM }
4299160SSherry.Moore@Sun.COM *menup = mp;
4309160SSherry.Moore@Sun.COM return (ret);
4319160SSherry.Moore@Sun.COM }
4329160SSherry.Moore@Sun.COM
4339160SSherry.Moore@Sun.COM void
grub_menu_fini(grub_menu_t * mp)4349160SSherry.Moore@Sun.COM grub_menu_fini(grub_menu_t *mp)
4359160SSherry.Moore@Sun.COM {
4369160SSherry.Moore@Sun.COM if (mp == NULL)
4379160SSherry.Moore@Sun.COM return;
4389160SSherry.Moore@Sun.COM
4399160SSherry.Moore@Sun.COM grub_fs_fini(&mp->gm_fs);
4409160SSherry.Moore@Sun.COM free_entries(mp);
4419160SSherry.Moore@Sun.COM free_linelist(mp->gm_start);
4429160SSherry.Moore@Sun.COM free(mp);
4439160SSherry.Moore@Sun.COM }
4449160SSherry.Moore@Sun.COM
4459160SSherry.Moore@Sun.COM grub_line_t *
grub_menu_next_line(const grub_menu_t * mp,const grub_line_t * lp)4469160SSherry.Moore@Sun.COM grub_menu_next_line(const grub_menu_t *mp, const grub_line_t *lp)
4479160SSherry.Moore@Sun.COM {
4489160SSherry.Moore@Sun.COM assert(mp);
4499160SSherry.Moore@Sun.COM if (lp == NULL)
4509160SSherry.Moore@Sun.COM return (mp->gm_start);
4519160SSherry.Moore@Sun.COM else
4529160SSherry.Moore@Sun.COM return (lp->gl_next);
4539160SSherry.Moore@Sun.COM }
4549160SSherry.Moore@Sun.COM
4559160SSherry.Moore@Sun.COM grub_line_t *
grub_menu_prev_line(const grub_menu_t * mp,const grub_line_t * lp)4569160SSherry.Moore@Sun.COM grub_menu_prev_line(const grub_menu_t *mp, const grub_line_t *lp)
4579160SSherry.Moore@Sun.COM {
4589160SSherry.Moore@Sun.COM assert(mp);
4599160SSherry.Moore@Sun.COM if (lp == NULL)
4609160SSherry.Moore@Sun.COM return (mp->gm_end);
4619160SSherry.Moore@Sun.COM else
4629160SSherry.Moore@Sun.COM return (lp->gl_prev);
4639160SSherry.Moore@Sun.COM }
4649160SSherry.Moore@Sun.COM
4659160SSherry.Moore@Sun.COM grub_line_t *
grub_menu_get_line(const grub_menu_t * mp,int num)4669160SSherry.Moore@Sun.COM grub_menu_get_line(const grub_menu_t *mp, int num)
4679160SSherry.Moore@Sun.COM {
4689160SSherry.Moore@Sun.COM grub_line_t *lp;
4699160SSherry.Moore@Sun.COM
4709160SSherry.Moore@Sun.COM assert(mp);
4719160SSherry.Moore@Sun.COM if (num > mp->gm_line_num)
4729160SSherry.Moore@Sun.COM return (NULL);
4739160SSherry.Moore@Sun.COM for (lp = mp->gm_start; lp != NULL && num != lp->gl_line_num;
4749160SSherry.Moore@Sun.COM lp = lp->gl_next)
4759160SSherry.Moore@Sun.COM ;
4769160SSherry.Moore@Sun.COM return (lp);
4779160SSherry.Moore@Sun.COM }
4789160SSherry.Moore@Sun.COM
4799160SSherry.Moore@Sun.COM size_t
grub_menu_get_cmdline(const grub_menu_t * mp,int num,char * cmdl,size_t size)4809160SSherry.Moore@Sun.COM grub_menu_get_cmdline(const grub_menu_t *mp, int num, char *cmdl, size_t size)
4819160SSherry.Moore@Sun.COM {
4829160SSherry.Moore@Sun.COM grub_entry_t *ent;
4839160SSherry.Moore@Sun.COM
4849160SSherry.Moore@Sun.COM assert(mp);
4859160SSherry.Moore@Sun.COM if ((ent = grub_menu_get_entry(mp, num)) == NULL)
4869160SSherry.Moore@Sun.COM return (size_t)(-1);
4879160SSherry.Moore@Sun.COM
4889160SSherry.Moore@Sun.COM return (grub_entry_get_cmdline(ent, cmdl, size));
4899160SSherry.Moore@Sun.COM }
4909160SSherry.Moore@Sun.COM
4919160SSherry.Moore@Sun.COM grub_entry_t *
grub_menu_next_entry(const grub_menu_t * mp,const grub_entry_t * ent)4929160SSherry.Moore@Sun.COM grub_menu_next_entry(const grub_menu_t *mp, const grub_entry_t *ent)
4939160SSherry.Moore@Sun.COM {
4949160SSherry.Moore@Sun.COM assert(mp);
4959160SSherry.Moore@Sun.COM if (ent == NULL) {
4969160SSherry.Moore@Sun.COM return (mp->gm_ent_start);
4979160SSherry.Moore@Sun.COM } else {
4989160SSherry.Moore@Sun.COM assert(mp == ent->ge_menu);
4999160SSherry.Moore@Sun.COM return (ent->ge_next);
5009160SSherry.Moore@Sun.COM }
5019160SSherry.Moore@Sun.COM }
5029160SSherry.Moore@Sun.COM
5039160SSherry.Moore@Sun.COM grub_entry_t *
grub_menu_prev_entry(const grub_menu_t * mp,const grub_entry_t * ent)5049160SSherry.Moore@Sun.COM grub_menu_prev_entry(const grub_menu_t *mp, const grub_entry_t *ent)
5059160SSherry.Moore@Sun.COM {
5069160SSherry.Moore@Sun.COM assert(mp);
5079160SSherry.Moore@Sun.COM if (ent == NULL) {
5089160SSherry.Moore@Sun.COM return (mp->gm_ent_end);
5099160SSherry.Moore@Sun.COM } else {
5109160SSherry.Moore@Sun.COM assert(mp == ent->ge_menu);
5119160SSherry.Moore@Sun.COM return (ent->ge_prev);
5129160SSherry.Moore@Sun.COM }
5139160SSherry.Moore@Sun.COM }
5149160SSherry.Moore@Sun.COM
5159160SSherry.Moore@Sun.COM grub_entry_t *
grub_menu_get_entry(const grub_menu_t * mp,int num)5169160SSherry.Moore@Sun.COM grub_menu_get_entry(const grub_menu_t *mp, int num)
5179160SSherry.Moore@Sun.COM {
5189160SSherry.Moore@Sun.COM grub_entry_t *ent;
5199160SSherry.Moore@Sun.COM
5209160SSherry.Moore@Sun.COM assert(mp);
5219160SSherry.Moore@Sun.COM if (num == GRUB_ENTRY_DEFAULT) {
5229160SSherry.Moore@Sun.COM ent = mp->gm_ent_default;
5239160SSherry.Moore@Sun.COM } else if (num >= mp->gm_entry_num) {
5249160SSherry.Moore@Sun.COM ent = NULL;
5259160SSherry.Moore@Sun.COM } else {
5269160SSherry.Moore@Sun.COM for (ent = mp->gm_ent_start;
5279160SSherry.Moore@Sun.COM ent != NULL && num != ent->ge_entry_num;
5289160SSherry.Moore@Sun.COM ent = ent->ge_next)
5299160SSherry.Moore@Sun.COM ;
5309160SSherry.Moore@Sun.COM }
5319160SSherry.Moore@Sun.COM return (ent);
5329160SSherry.Moore@Sun.COM }
533