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 all the functions that get/set fields
28*753a6d45SSherry Moore  * in a GRUB menu entry.
29*753a6d45SSherry Moore  */
30*753a6d45SSherry Moore #include <stdio.h>
31*753a6d45SSherry Moore #include <errno.h>
32*753a6d45SSherry Moore #include <stdlib.h>
33*753a6d45SSherry Moore #include <strings.h>
34*753a6d45SSherry Moore #include <unistd.h>
35*753a6d45SSherry Moore #include <sys/types.h>
36*753a6d45SSherry Moore #include <assert.h>
37*753a6d45SSherry Moore #include <ctype.h>
38*753a6d45SSherry Moore 
39*753a6d45SSherry Moore #include "libgrub_cmd.def"
40*753a6d45SSherry Moore #include "libgrub_impl.h"
41*753a6d45SSherry Moore 
42*753a6d45SSherry Moore typedef int (*barg_parsef_t)(const grub_line_t *, grub_barg_t *);
43*753a6d45SSherry Moore static const  barg_parsef_t barg_parse[] = {
44*753a6d45SSherry Moore #define	menu_cmd(cmd, num, flag, parsef)	parsef,
45*753a6d45SSherry Moore #include "libgrub_cmd.def"
46*753a6d45SSherry Moore };
47*753a6d45SSherry Moore 
48*753a6d45SSherry Moore /*
49*753a6d45SSherry Moore  * Remove extra '/', stops at first isspace character.
50*753a6d45SSherry Moore  * Return new string length.
51*753a6d45SSherry Moore  */
52*753a6d45SSherry Moore size_t
clean_path(char * path)53*753a6d45SSherry Moore clean_path(char *path)
54*753a6d45SSherry Moore {
55*753a6d45SSherry Moore 	int	i, c;
56*753a6d45SSherry Moore 	size_t	k, n;
57*753a6d45SSherry Moore 
58*753a6d45SSherry Moore 	n = strlen(path) + 1;
59*753a6d45SSherry Moore 
60*753a6d45SSherry Moore 	for (i = 0; (c = path[i]) != 0 && !isspace(c); i++) {
61*753a6d45SSherry Moore 		if (c == '/' && (k = strspn(path + i, "/") - 1) != 0) {
62*753a6d45SSherry Moore 			/* bcopy should deal with overlapping buffers */
63*753a6d45SSherry Moore 			n -= k;
64*753a6d45SSherry Moore 			bcopy(path + i + k, path + i, n - i);
65*753a6d45SSherry Moore 		}
66*753a6d45SSherry Moore 	}
67*753a6d45SSherry Moore 	return (n - 1);
68*753a6d45SSherry Moore }
69*753a6d45SSherry Moore 
70*753a6d45SSherry Moore /*
71*753a6d45SSherry Moore  * Construct boot command line from the ge_barg field
72*753a6d45SSherry Moore  */
73*753a6d45SSherry Moore static size_t
barg_cmdline(const grub_barg_t * barg,char * cmd,size_t size)74*753a6d45SSherry Moore barg_cmdline(const grub_barg_t *barg, char *cmd, size_t size)
75*753a6d45SSherry Moore {
76*753a6d45SSherry Moore 	size_t n;
77*753a6d45SSherry Moore 	const grub_fsdesc_t *fsd;
78*753a6d45SSherry Moore 
79*753a6d45SSherry Moore 	if (!IS_BARG_VALID(barg) ||
80*753a6d45SSherry Moore 	    (fsd = grub_get_rootfsd(&barg->gb_root)) == NULL)
81*753a6d45SSherry Moore 		return ((size_t)-1);
82*753a6d45SSherry Moore 
83*753a6d45SSherry Moore 	/* if disk/top dataset is mounted, use mount point */
84*753a6d45SSherry Moore 	if (fsd->gfs_mountp[0] != 0) {
85*753a6d45SSherry Moore 		if ((n = snprintf(cmd, size, "%s%s", fsd->gfs_mountp,
86*753a6d45SSherry Moore 		    barg->gb_kernel)) >= size)
87*753a6d45SSherry Moore 			return (n);
88*753a6d45SSherry Moore 		return (clean_path(cmd));
89*753a6d45SSherry Moore 	} else
90*753a6d45SSherry Moore 		return (snprintf(cmd, size, "%s %s", fsd->gfs_dev,
91*753a6d45SSherry Moore 		    barg->gb_kernel));
92*753a6d45SSherry Moore }
93*753a6d45SSherry Moore 
94*753a6d45SSherry Moore 
95*753a6d45SSherry Moore /*
96*753a6d45SSherry Moore  * Construct ge_barg field based on the other fields of the entry.
97*753a6d45SSherry Moore  * Return 0 on success, errno on failure.
98*753a6d45SSherry Moore  */
99*753a6d45SSherry Moore int
grub_entry_construct_barg(grub_entry_t * ent)100*753a6d45SSherry Moore grub_entry_construct_barg(grub_entry_t *ent)
101*753a6d45SSherry Moore {
102*753a6d45SSherry Moore 	int ret = 0;
103*753a6d45SSherry Moore 	grub_barg_t *barg;
104*753a6d45SSherry Moore 	grub_line_t *lp, *lend;
105*753a6d45SSherry Moore 	grub_menu_t *mp;
106*753a6d45SSherry Moore 
107*753a6d45SSherry Moore 	assert(ent);
108*753a6d45SSherry Moore 
109*753a6d45SSherry Moore 	barg = &ent->ge_barg;
110*753a6d45SSherry Moore 	mp = ent->ge_menu;
111*753a6d45SSherry Moore 
112*753a6d45SSherry Moore 	assert(barg);
113*753a6d45SSherry Moore 	assert(mp);
114*753a6d45SSherry Moore 
115*753a6d45SSherry Moore 	(void) memset(barg, 0, sizeof (*barg));
116*753a6d45SSherry Moore 	barg->gb_entry = ent;
117*753a6d45SSherry Moore 	(void) bcopy(&mp->gm_root, &barg->gb_root, sizeof (barg->gb_root));
118*753a6d45SSherry Moore 
119*753a6d45SSherry Moore 	lend = ent->ge_end->gl_next;
120*753a6d45SSherry Moore 	for (lp = ent->ge_start; lp != lend; lp = lp->gl_next) {
121*753a6d45SSherry Moore 		if (lp->gl_cmdtp >= GRBM_CMD_NUM)
122*753a6d45SSherry Moore 			ret = EG_INVALIDCMD;
123*753a6d45SSherry Moore 		else
124*753a6d45SSherry Moore 			ret = barg_parse[lp->gl_cmdtp](lp, barg);
125*753a6d45SSherry Moore 
126*753a6d45SSherry Moore 		if (ret != 0)
127*753a6d45SSherry Moore 			break;
128*753a6d45SSherry Moore 	}
129*753a6d45SSherry Moore 
130*753a6d45SSherry Moore 	barg->gb_errline = lp;
131*753a6d45SSherry Moore 	if (ret == 0) {
132*753a6d45SSherry Moore 		/* at least kernel and module should be defined */
133*753a6d45SSherry Moore 		if (barg->gb_kernel[0] != 0 && barg->gb_module[0] != 0)
134*753a6d45SSherry Moore 			barg->gb_flags |= GRBM_VALID_FLAG;
135*753a6d45SSherry Moore 	}
136*753a6d45SSherry Moore 
137*753a6d45SSherry Moore 	return (ret);
138*753a6d45SSherry Moore }
139*753a6d45SSherry Moore 
140*753a6d45SSherry Moore const char *
grub_entry_get_fstyp(const grub_entry_t * ent)141*753a6d45SSherry Moore grub_entry_get_fstyp(const grub_entry_t *ent)
142*753a6d45SSherry Moore {
143*753a6d45SSherry Moore 	if (IS_ENTRY_BARG_VALID(ent))
144*753a6d45SSherry Moore 		return (ent->ge_barg.gb_root.gr_fstyp);
145*753a6d45SSherry Moore 	else
146*753a6d45SSherry Moore 		return (NULL);
147*753a6d45SSherry Moore }
148*753a6d45SSherry Moore 
149*753a6d45SSherry Moore const char *
grub_entry_get_kernel(const grub_entry_t * ent)150*753a6d45SSherry Moore grub_entry_get_kernel(const grub_entry_t *ent)
151*753a6d45SSherry Moore {
152*753a6d45SSherry Moore 	if (IS_ENTRY_BARG_VALID(ent))
153*753a6d45SSherry Moore 		return (ent->ge_barg.gb_kernel);
154*753a6d45SSherry Moore 	else
155*753a6d45SSherry Moore 		return (NULL);
156*753a6d45SSherry Moore }
157*753a6d45SSherry Moore 
158*753a6d45SSherry Moore const char *
grub_entry_get_module(const grub_entry_t * ent)159*753a6d45SSherry Moore grub_entry_get_module(const grub_entry_t *ent)
160*753a6d45SSherry Moore {
161*753a6d45SSherry Moore 	if (IS_ENTRY_BARG_VALID(ent))
162*753a6d45SSherry Moore 		return (ent->ge_barg.gb_module);
163*753a6d45SSherry Moore 	else
164*753a6d45SSherry Moore 		return (NULL);
165*753a6d45SSherry Moore }
166*753a6d45SSherry Moore 
167*753a6d45SSherry Moore const char *
grub_entry_get_error_desc(const grub_entry_t * ent)168*753a6d45SSherry Moore grub_entry_get_error_desc(const grub_entry_t *ent)
169*753a6d45SSherry Moore {
170*753a6d45SSherry Moore 	assert(ent != NULL);
171*753a6d45SSherry Moore 	return ("Not implemented");
172*753a6d45SSherry Moore }
173*753a6d45SSherry Moore 
174*753a6d45SSherry Moore const grub_fsdesc_t *
grub_entry_get_rootfs(const grub_entry_t * ent)175*753a6d45SSherry Moore grub_entry_get_rootfs(const grub_entry_t *ent)
176*753a6d45SSherry Moore {
177*753a6d45SSherry Moore 	if (IS_ENTRY_BARG_VALID(ent))
178*753a6d45SSherry Moore 		return (grub_get_rootfsd(&ent->ge_barg.gb_root));
179*753a6d45SSherry Moore 	else
180*753a6d45SSherry Moore 		return (NULL);
181*753a6d45SSherry Moore }
182*753a6d45SSherry Moore 
183*753a6d45SSherry Moore size_t
grub_entry_get_cmdline(grub_entry_t * ent,char * cmdline,size_t size)184*753a6d45SSherry Moore grub_entry_get_cmdline(grub_entry_t *ent, char *cmdline, size_t size)
185*753a6d45SSherry Moore {
186*753a6d45SSherry Moore 	if (IS_ENTRY_VALID(ent) && (grub_entry_construct_barg(ent) == 0))
187*753a6d45SSherry Moore 		return (barg_cmdline(&ent->ge_barg, cmdline, size));
188*753a6d45SSherry Moore 	else
189*753a6d45SSherry Moore 		return ((size_t)-1);
190*753a6d45SSherry Moore 
191*753a6d45SSherry Moore }
192