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  */
25*01f9868aSMarcel Telka /*
26*01f9868aSMarcel Telka  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
27*01f9868aSMarcel Telka  */
28753a6d45SSherry Moore 
29753a6d45SSherry Moore #ifndef	_GRBMIMPL_H
30753a6d45SSherry Moore #define	_GRBMIMPL_H
31753a6d45SSherry Moore 
32753a6d45SSherry Moore #ifdef	__cplusplus
33753a6d45SSherry Moore extern "C" {
34753a6d45SSherry Moore #endif
35753a6d45SSherry Moore 
36753a6d45SSherry Moore #include <sys/types.h>
37753a6d45SSherry Moore #include <sys/param.h>
38753a6d45SSherry Moore #include <sys/mntent.h>
39753a6d45SSherry Moore #include <sys/uadmin.h>
40*01f9868aSMarcel Telka #include <sys/dktp/fdisk.h>
41753a6d45SSherry Moore #include <libzfs.h>
42753a6d45SSherry Moore #include <libdevinfo.h>
43753a6d45SSherry Moore #include "libgrubmgmt.h"
44753a6d45SSherry Moore #include "libgrub_errno.h"
45753a6d45SSherry Moore 
46753a6d45SSherry Moore /*
47753a6d45SSherry Moore  * Macros for processing the GRUB menu.
48753a6d45SSherry Moore  */
49753a6d45SSherry Moore #define	GRUB_MENU	"/boot/grub/menu.lst"
50753a6d45SSherry Moore #define	BOOTSIGN_DIR	"/boot/grub/bootsign"
51753a6d45SSherry Moore #define	BOOTSIGN_LEN	(2 * MAXNAMELEN)
52753a6d45SSherry Moore #define	ZFS_BOOT_VAR	"$ZFS-BOOTFS"	/* ZFS boot option */
53753a6d45SSherry Moore #define	ISADIR_VAR	"$ISADIR"	/* ISADIR option */
54753a6d45SSherry Moore 
55753a6d45SSherry Moore #define	PRTNUM_INVALID	-1	/* Partition number invlaid */
56753a6d45SSherry Moore #define	SLCNUM_INVALID	-1	/* Slice number invalid */
57753a6d45SSherry Moore 
58753a6d45SSherry Moore #define	SLCNUM_FIRST		'a'
59753a6d45SSherry Moore #define	SLCNUM_WHOLE_DISK	'q'
60753a6d45SSherry Moore 
61753a6d45SSherry Moore #define	IS_SLCNUM_VALID(x)	((x) >= SLCNUM_FIRST && (x) < SLCNUM_WHOLE_DISK)
62*01f9868aSMarcel Telka #define	IS_PRTNUM_VALID(x)	((uint_t)(x) < FD_NUMPART + MAX_EXT_PARTS)
63753a6d45SSherry Moore 
64753a6d45SSherry Moore #define	GRBM_VALID_FLAG		((uint_t)1 << 31)
65753a6d45SSherry Moore #define	GRBM_MAXLINE		8192
66753a6d45SSherry Moore #define	IS_ENTRY_VALID(ent)	((ent) && ((ent)->ge_flags & GRBM_VALID_FLAG))
67753a6d45SSherry Moore #define	IS_BARG_VALID(barg)	((barg)->gb_flags & GRBM_VALID_FLAG)
68753a6d45SSherry Moore #define	IS_ENTRY_BARG_VALID(ent) \
69753a6d45SSherry Moore 	(IS_ENTRY_VALID(ent) && IS_BARG_VALID(&(ent)->ge_barg))
70753a6d45SSherry Moore #define	IS_LINE2BIG(buf, bfsz, len) \
71753a6d45SSherry Moore 	((len = strlen(buf)) == (bfsz) - 1 && (buf)[len - 1] != '\n')
72753a6d45SSherry Moore #define	IS_STR_NULL(x)	((x) == NULL ? "NULL" : (x))
73753a6d45SSherry Moore #define	GRUB_ENTRY_IS_XVM(fbarg) \
74753a6d45SSherry Moore 	(strstr(fbarg.gba_kernel, "xen.gz") != NULL)
75753a6d45SSherry Moore 
76753a6d45SSherry Moore enum {
77753a6d45SSherry Moore #define	menu_cmd(cmd, num, flags, parsef)	num,
78753a6d45SSherry Moore #define	menu_cmd_end(num)			num
79753a6d45SSherry Moore #include "libgrub_cmd.def"
80753a6d45SSherry Moore };
81753a6d45SSherry Moore 
82753a6d45SSherry Moore typedef struct _grub_fs {
83753a6d45SSherry Moore 	di_node_t		gf_diroot;
84753a6d45SSherry Moore 	di_devlink_handle_t	gf_dvlh;
85753a6d45SSherry Moore 	libzfs_handle_t		*gf_lzfh;
86753a6d45SSherry Moore } grub_fs_t;
87753a6d45SSherry Moore 
88753a6d45SSherry Moore 
89753a6d45SSherry Moore typedef struct _grub_cmd_desc {
90753a6d45SSherry Moore 	const char	*gcd_cmd;
91753a6d45SSherry Moore 	uint_t		gcd_num;
92753a6d45SSherry Moore 	int		gcd_flags;
93753a6d45SSherry Moore } grub_cmd_desc_t;
94753a6d45SSherry Moore 
95753a6d45SSherry Moore 
96753a6d45SSherry Moore enum {
97753a6d45SSherry Moore 	GRBM_UFS = 0,
98753a6d45SSherry Moore 	GRBM_ZFS_TOPFS = 0,
99753a6d45SSherry Moore 	GRBM_FS_TOP = 0,
100753a6d45SSherry Moore 	GRBM_ZFS_BOOTFS,
101753a6d45SSherry Moore 	GRBM_FS_MAX
102753a6d45SSherry Moore };
103753a6d45SSherry Moore 
104753a6d45SSherry Moore typedef struct _grub_root {
105753a6d45SSherry Moore 	char		gr_fstyp[MNTMAXSTR];
106753a6d45SSherry Moore 	char		gr_physpath[MAXPATHLEN];
107753a6d45SSherry Moore 	grub_fsdesc_t	gr_fs[GRBM_FS_MAX];
108753a6d45SSherry Moore } grub_root_t;
109753a6d45SSherry Moore 
110753a6d45SSherry Moore /*
111753a6d45SSherry Moore  * Data struct for the boot argument constructed from a GRUB menu entry
112753a6d45SSherry Moore  */
113753a6d45SSherry Moore typedef struct _grub_barg {
114753a6d45SSherry Moore 	grub_entry_t	*gb_entry;
115753a6d45SSherry Moore 	grub_line_t	*gb_errline;
116753a6d45SSherry Moore 	int		gb_walkret;	/* set to 0 when match found */
117753a6d45SSherry Moore 	uint_t		gb_flags;
118753a6d45SSherry Moore 	uint_t		gb_prtnum;
119753a6d45SSherry Moore 	uint_t		gb_slcnum;
120753a6d45SSherry Moore 	grub_root_t	gb_root;
121753a6d45SSherry Moore 	char		gb_bootsign[BOOTSIGN_LEN];
122753a6d45SSherry Moore 	char		gb_kernel[BOOTARGS_MAX];
123753a6d45SSherry Moore 	char		gb_module[BOOTARGS_MAX];
124753a6d45SSherry Moore } grub_barg_t;
125753a6d45SSherry Moore 
126753a6d45SSherry Moore 
127753a6d45SSherry Moore /* GRUB menu per-line classification */
128753a6d45SSherry Moore enum {
129753a6d45SSherry Moore 	GRUB_LINE_INVALID = 0,
130753a6d45SSherry Moore 	GRUB_LINE_EMPTY,
131753a6d45SSherry Moore 	GRUB_LINE_COMMENT,
132753a6d45SSherry Moore 	GRUB_LINE_GLOBAL,
133753a6d45SSherry Moore 	GRUB_LINE_ENTRY,
134753a6d45SSherry Moore 	GRUB_LINE_TITLE
135753a6d45SSherry Moore };
136753a6d45SSherry Moore 
137753a6d45SSherry Moore /*
138753a6d45SSherry Moore  * Data structures for menu.lst contents
139753a6d45SSherry Moore  */
140753a6d45SSherry Moore struct grub_line {
141753a6d45SSherry Moore 	grub_line_t	*gl_next;
142753a6d45SSherry Moore 	grub_line_t	*gl_prev;
143753a6d45SSherry Moore 	int		gl_line_num;	/* Line number in menu.lst */
144753a6d45SSherry Moore 	int		gl_entry_num;	/* menu boot entry #. */
145753a6d45SSherry Moore 					/* GRUB_ENTRY_DEFAULT if none */
146753a6d45SSherry Moore 	int		gl_flags;
147753a6d45SSherry Moore 	uint_t		gl_cmdtp;	/* recognized command type */
148753a6d45SSherry Moore 	char		*gl_cmd;
149753a6d45SSherry Moore 	char		*gl_sep;
150753a6d45SSherry Moore 	char		*gl_arg;
151753a6d45SSherry Moore 	char		*gl_line;
152753a6d45SSherry Moore };
153753a6d45SSherry Moore 
154753a6d45SSherry Moore struct grub_entry {
155753a6d45SSherry Moore 	grub_menu_t	*ge_menu;	/* grub_menu_t it belongs to */
156753a6d45SSherry Moore 	grub_entry_t	*ge_next;
157753a6d45SSherry Moore 	grub_entry_t	*ge_prev;
158753a6d45SSherry Moore 	grub_line_t	*ge_start;
159753a6d45SSherry Moore 	grub_line_t	*ge_end;
160753a6d45SSherry Moore 	int		ge_entry_num;
161753a6d45SSherry Moore 	uint_t		ge_flags;
162753a6d45SSherry Moore 	uint_t		ge_emask;	/* invalid lines mask */
163753a6d45SSherry Moore 	grub_barg_t	ge_barg;
164753a6d45SSherry Moore };
165753a6d45SSherry Moore 
166753a6d45SSherry Moore struct grub_menu {
167753a6d45SSherry Moore 	grub_line_t	*gm_start;
168753a6d45SSherry Moore 	grub_line_t	*gm_end;
169753a6d45SSherry Moore 	grub_line_t	*gm_curdefault;	/* line containing default */
170753a6d45SSherry Moore 	grub_entry_t	*gm_ent_start;	/* os entries */
171753a6d45SSherry Moore 	grub_entry_t	*gm_ent_end;
172753a6d45SSherry Moore 	grub_entry_t	*gm_ent_default;	/* default entry */
173753a6d45SSherry Moore 	uint_t		gm_line_num;	/* number of lines processed */
174753a6d45SSherry Moore 	uint_t		gm_entry_num;	/* number of entries processed */
175753a6d45SSherry Moore 	char		gm_path[MAXPATHLEN];
176753a6d45SSherry Moore 	grub_fs_t	gm_fs;
177753a6d45SSherry Moore 	grub_root_t	gm_root;
178753a6d45SSherry Moore };
179753a6d45SSherry Moore 
180753a6d45SSherry Moore /* File system helper functions */
181753a6d45SSherry Moore int grub_current_root(grub_fs_t *, grub_root_t *);
182753a6d45SSherry Moore grub_fsdesc_t *grub_get_rootfsd(const grub_root_t *);
183753a6d45SSherry Moore int grub_fsd_mount_tmp(grub_fsdesc_t *, const char *);
184753a6d45SSherry Moore void grub_fsd_umount_tmp(grub_fsdesc_t *);
185753a6d45SSherry Moore int grub_fsd_get_mountp(grub_fsdesc_t *fsd, char *fstyp);
186753a6d45SSherry Moore int grub_find_bootsign(grub_barg_t *barg);
187753a6d45SSherry Moore 
188753a6d45SSherry Moore 
189753a6d45SSherry Moore /* GRUB menu parse functions */
190753a6d45SSherry Moore int skip_line(const grub_line_t *lp, grub_barg_t *barg);
191753a6d45SSherry Moore int error_line(const grub_line_t *lp, grub_barg_t *barg);
192753a6d45SSherry Moore int kernel(const grub_line_t *lp, grub_barg_t *barg);
193753a6d45SSherry Moore int module(const grub_line_t *lp, grub_barg_t *barg);
194753a6d45SSherry Moore int dollar_kernel(const grub_line_t *lp, grub_barg_t *barg);
195753a6d45SSherry Moore int dollar_module(const grub_line_t *lp, grub_barg_t *barg);
196753a6d45SSherry Moore int findroot(const grub_line_t *lp, grub_barg_t *barg);
197753a6d45SSherry Moore int bootfs(const grub_line_t *lp, grub_barg_t *barg);
198753a6d45SSherry Moore size_t clean_path(char *path);
199753a6d45SSherry Moore 
200753a6d45SSherry Moore 
201753a6d45SSherry Moore /* GRUB entry functions */
202753a6d45SSherry Moore int grub_entry_construct_barg(grub_entry_t *ent);
203753a6d45SSherry Moore const char *grub_entry_get_fstyp(const grub_entry_t *ent);
204753a6d45SSherry Moore const char *grub_entry_get_kernel(const grub_entry_t *ent);
205753a6d45SSherry Moore const char *grub_entry_get_module(const grub_entry_t *ent);
206753a6d45SSherry Moore const grub_fsdesc_t *grub_entry_get_rootfs(const grub_entry_t *ent);
207753a6d45SSherry Moore size_t grub_entry_get_cmdline(grub_entry_t *ent, char *cmdline, size_t size);
208753a6d45SSherry Moore 
209753a6d45SSherry Moore /*
210753a6d45SSherry Moore  * GRUB menu parse/access funcions.
211753a6d45SSherry Moore  *
212753a6d45SSherry Moore  * Callers must call grub_menu_init() to to obtain a handle to the menu before
213753a6d45SSherry Moore  * calling any of the other functions, and call grub_menu_fini() to close.
214753a6d45SSherry Moore  *
215753a6d45SSherry Moore  * grub_menu_init:
216753a6d45SSherry Moore  *	Reads and parses GRUB menu file into a grub_menu_t data structure.
217753a6d45SSherry Moore  *	If grub_menu_path file path is NULL, will use 'currently active'
218753a6d45SSherry Moore  *	GRUB menu file.
219753a6d45SSherry Moore  * grub_menu_fini:
220753a6d45SSherry Moore  *	Frees all resources allocated by grub_menu_init().
221753a6d45SSherry Moore  *
222753a6d45SSherry Moore  * grub_menu_get_entry:
223753a6d45SSherry Moore  *	Returns a particular entry from the menu.
224753a6d45SSherry Moore  * grub_menu_next_entry:
225753a6d45SSherry Moore  * grub_menu_prev_entry:
226753a6d45SSherry Moore  *      Returns next or previous entry in the menu.
227753a6d45SSherry Moore  *      If current entry is NULL, return first or last entry.
228753a6d45SSherry Moore  *
229753a6d45SSherry Moore  * grub_menu_next_line:
230753a6d45SSherry Moore  * grub_menu_prev_line:
231753a6d45SSherry Moore  *      Returns next/prev (to the current) line in the menu.
232753a6d45SSherry Moore  *      If current line is NULL, returns first or last line.
233753a6d45SSherry Moore  * grub_menu_get_line:
234753a6d45SSherry Moore  *      Returns the specified line in the menu (line counter starts from one).
235753a6d45SSherry Moore  */
236753a6d45SSherry Moore int grub_menu_init(const char *grub_menu_path, grub_menu_t **menup);
237753a6d45SSherry Moore void grub_menu_fini(grub_menu_t *);
238753a6d45SSherry Moore grub_entry_t *grub_menu_get_entry(const grub_menu_t *menu, int num);
239753a6d45SSherry Moore grub_entry_t *grub_menu_next_entry(const grub_menu_t *menu,
240753a6d45SSherry Moore     const grub_entry_t *current);
241753a6d45SSherry Moore grub_entry_t *grub_menu_prev_entry(const grub_menu_t *menu,
242753a6d45SSherry Moore     const grub_entry_t *current);
243753a6d45SSherry Moore grub_line_t *grub_menu_next_line(const grub_menu_t *menu,
244753a6d45SSherry Moore     const grub_line_t *current);
245753a6d45SSherry Moore grub_line_t *grub_menu_prev_line(const grub_menu_t *menu,
246753a6d45SSherry Moore     const grub_line_t *current);
247753a6d45SSherry Moore 
248753a6d45SSherry Moore #ifdef __cplusplus
249753a6d45SSherry Moore }
250753a6d45SSherry Moore #endif
251753a6d45SSherry Moore 
252753a6d45SSherry Moore #endif	/* _GRBMIMPL_H */
253