1ae115bc7Smrj /*
2ae115bc7Smrj  * CDDL HEADER START
3ae115bc7Smrj  *
4ae115bc7Smrj  * The contents of this file are subject to the terms of the
5ae115bc7Smrj  * Common Development and Distribution License (the "License").
6ae115bc7Smrj  * You may not use this file except in compliance with the License.
7ae115bc7Smrj  *
8ae115bc7Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ae115bc7Smrj  * or http://www.opensolaris.org/os/licensing.
10ae115bc7Smrj  * See the License for the specific language governing permissions
11ae115bc7Smrj  * and limitations under the License.
12ae115bc7Smrj  *
13ae115bc7Smrj  * When distributing Covered Code, include this CDDL HEADER in each
14ae115bc7Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ae115bc7Smrj  * If applicable, add the following below this CDDL HEADER, with the
16ae115bc7Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
17ae115bc7Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
18ae115bc7Smrj  *
19ae115bc7Smrj  * CDDL HEADER END
20ae115bc7Smrj  */
21ae115bc7Smrj /*
223028dfd6SFrank Van Der Linden  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23ae115bc7Smrj  * Use is subject to license terms.
24719db50fSToomas Soome  * Copyright 2017 Toomas Soome <tsoome@me.com>
25ae115bc7Smrj  */
26ae115bc7Smrj 
27ae115bc7Smrj #include <stdio.h>
28ae115bc7Smrj #include <errno.h>
29ae115bc7Smrj #include <stdlib.h>
30ae115bc7Smrj #include <string.h>
31ae115bc7Smrj #include <unistd.h>
32ae115bc7Smrj #include <sys/types.h>
33ae115bc7Smrj #include <sys/stat.h>
34ae115bc7Smrj #include <limits.h>
35ae115bc7Smrj #include <fcntl.h>
36ae115bc7Smrj #include <strings.h>
37ae115bc7Smrj 
38ae115bc7Smrj #include <sys/mman.h>
39ae115bc7Smrj #include <sys/elf.h>
40ae115bc7Smrj #include <sys/multiboot.h>
41ae115bc7Smrj 
42ae115bc7Smrj #include "bootadm.h"
43ae115bc7Smrj 
44ae115bc7Smrj direct_or_multi_t bam_direct = BAM_DIRECT_NOT_SET;
45843e1988Sjohnlev hv_t bam_is_hv = BAM_HV_UNKNOWN;
46eb2bd662Svikram findroot_t bam_is_findroot = BAM_FINDROOT_UNKNOWN;
47eb2bd662Svikram 
48eb2bd662Svikram static void
get_findroot_cap(const char * osroot)49eb2bd662Svikram get_findroot_cap(const char *osroot)
50eb2bd662Svikram {
51eb2bd662Svikram 	FILE		*fp;
52eb2bd662Svikram 	char		path[PATH_MAX];
53eb2bd662Svikram 	char		buf[BAM_MAXLINE];
54eb2bd662Svikram 	struct stat	sb;
55eb2bd662Svikram 	int		dboot;
56eb2bd662Svikram 	int		error;
57eb2bd662Svikram 	int		ret;
58eb2bd662Svikram 	const char	*fcn = "get_findroot_cap()";
59eb2bd662Svikram 
60eb2bd662Svikram 	(void) snprintf(path, sizeof (path), "%s/%s",
61eb2bd662Svikram 	    osroot, "boot/grub/capability");
62eb2bd662Svikram 
63eb2bd662Svikram 	if (stat(path, &sb) == -1) {
64eb2bd662Svikram 		bam_is_findroot = BAM_FINDROOT_ABSENT;
65c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: findroot capability absent\n", fcn));
66eb2bd662Svikram 		return;
67eb2bd662Svikram 	}
68eb2bd662Svikram 
69eb2bd662Svikram 	fp = fopen(path, "r");
70eb2bd662Svikram 	error = errno;
71eb2bd662Svikram 	INJECT_ERROR1("GET_CAP_FINDROOT_FOPEN", fp = NULL);
72eb2bd662Svikram 	if (fp == NULL) {
73c262cbbcSToomas Soome 		bam_error(_("failed to open file: %s: %s\n"), path,
74c262cbbcSToomas Soome 		    strerror(error));
75eb2bd662Svikram 		return;
76eb2bd662Svikram 	}
77eb2bd662Svikram 
783028dfd6SFrank Van Der Linden 	dboot = 0;
79eb2bd662Svikram 	while (s_fgets(buf, sizeof (buf), fp) != NULL) {
80eb2bd662Svikram 		if (strcmp(buf, "findroot") == 0) {
81c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: findroot capability present\n", fcn));
82eb2bd662Svikram 			bam_is_findroot = BAM_FINDROOT_PRESENT;
83eb2bd662Svikram 		}
84eb2bd662Svikram 		if (strcmp(buf, "dboot") == 0) {
85c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: dboot capability present\n", fcn));
86eb2bd662Svikram 			dboot = 1;
87eb2bd662Svikram 		}
88eb2bd662Svikram 	}
89eb2bd662Svikram 
90eb2bd662Svikram 	assert(dboot);
91eb2bd662Svikram 
92eb2bd662Svikram 	if (bam_is_findroot == BAM_FINDROOT_UNKNOWN) {
93eb2bd662Svikram 		bam_is_findroot = BAM_FINDROOT_ABSENT;
94c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: findroot capability absent\n", fcn));
95eb2bd662Svikram 	}
963bbf88b3SToomas Soome 
97eb2bd662Svikram 	ret = fclose(fp);
98eb2bd662Svikram 	error = errno;
99eb2bd662Svikram 	INJECT_ERROR1("GET_CAP_FINDROOT_FCLOSE", ret = 1);
100eb2bd662Svikram 	if (ret != 0) {
101c262cbbcSToomas Soome 		bam_error(_("failed to close file: %s: %s\n"),
102c262cbbcSToomas Soome 		    path, strerror(error));
103eb2bd662Svikram 	}
104eb2bd662Svikram }
105ae115bc7Smrj 
106ae115bc7Smrj error_t
get_boot_cap(const char * osroot)107eb2bd662Svikram get_boot_cap(const char *osroot)
108ae115bc7Smrj {
109eb2bd662Svikram 	char		fname[PATH_MAX];
110eb2bd662Svikram 	char		*image;
111eb2bd662Svikram 	uchar_t		*ident;
112719db50fSToomas Soome 	uchar_t		class;
113eb2bd662Svikram 	int		fd;
114eb2bd662Svikram 	int		m;
115ae115bc7Smrj 	multiboot_header_t *mbh;
116eb2bd662Svikram 	struct stat	sb;
117eb2bd662Svikram 	int		error;
118eb2bd662Svikram 	const char	*fcn = "get_boot_cap()";
119ae115bc7Smrj 
120eb2bd662Svikram 	if (is_sparc()) {
121986fd29aSsetje 		/* there is no non dboot sparc new-boot */
122986fd29aSsetje 		bam_direct = BAM_DIRECT_DBOOT;
123c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: is sparc - always DBOOT\n", fcn));
124986fd29aSsetje 		return (BAM_SUCCESS);
125986fd29aSsetje 	}
126986fd29aSsetje 
127719db50fSToomas Soome 	/*
128719db50fSToomas Soome 	 * The install media can support both 64 and 32 bit boot
129719db50fSToomas Soome 	 * by using boot archive as ramdisk image. However, to save
130719db50fSToomas Soome 	 * the memory, the ramdisk may only have either 32 or 64
131719db50fSToomas Soome 	 * bit kernel files. To avoid error message about missing unix,
132719db50fSToomas Soome 	 * we should try both variants here and only complain if neither
133719db50fSToomas Soome 	 * is found. Since the 64-bit systems are more common, we start
134719db50fSToomas Soome 	 * from amd64.
135719db50fSToomas Soome 	 */
136719db50fSToomas Soome 	class = ELFCLASS64;
137eb2bd662Svikram 	(void) snprintf(fname, PATH_MAX, "%s/%s", osroot,
138719db50fSToomas Soome 	    "platform/i86pc/kernel/amd64/unix");
139ae115bc7Smrj 	fd = open(fname, O_RDONLY);
140719db50fSToomas Soome 	if (fd < 0) {
141719db50fSToomas Soome 		class = ELFCLASS32;
142719db50fSToomas Soome 		(void) snprintf(fname, PATH_MAX, "%s/%s", osroot,
143719db50fSToomas Soome 		    "platform/i86pc/kernel/unix");
144719db50fSToomas Soome 		fd = open(fname, O_RDONLY);
145719db50fSToomas Soome 	}
146eb2bd662Svikram 	error = errno;
147eb2bd662Svikram 	INJECT_ERROR1("GET_CAP_UNIX_OPEN", fd = -1);
148ae115bc7Smrj 	if (fd < 0) {
149c262cbbcSToomas Soome 		bam_error(_("failed to open file: %s: %s\n"), fname,
150c262cbbcSToomas Soome 		    strerror(error));
151eb2bd662Svikram 		return (BAM_ERROR);
152eb2bd662Svikram 	}
153eb2bd662Svikram 
154eb2bd662Svikram 	/*
155eb2bd662Svikram 	 * Verify that this is a sane unix at least 8192 bytes in length
156eb2bd662Svikram 	 */
157eb2bd662Svikram 	if (fstat(fd, &sb) == -1 || sb.st_size < 8192) {
158eb2bd662Svikram 		(void) close(fd);
159c262cbbcSToomas Soome 		bam_error(_("invalid or corrupted binary: %s\n"), fname);
160ae115bc7Smrj 		return (BAM_ERROR);
161ae115bc7Smrj 	}
162ae115bc7Smrj 
163ae115bc7Smrj 	/*
164ae115bc7Smrj 	 * mmap the first 8K
165ae115bc7Smrj 	 */
166ae115bc7Smrj 	image = mmap(NULL, 8192, PROT_READ, MAP_SHARED, fd, 0);
167eb2bd662Svikram 	error = errno;
168eb2bd662Svikram 	INJECT_ERROR1("GET_CAP_MMAP", image = MAP_FAILED);
169ae115bc7Smrj 	if (image == MAP_FAILED) {
170c262cbbcSToomas Soome 		bam_error(_("failed to mmap file: %s: %s\n"), fname,
171c262cbbcSToomas Soome 		    strerror(error));
172ae115bc7Smrj 		return (BAM_ERROR);
173ae115bc7Smrj 	}
174ae115bc7Smrj 
175ae115bc7Smrj 	ident = (uchar_t *)image;
176ae115bc7Smrj 	if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 ||
177ae115bc7Smrj 	    ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) {
178c262cbbcSToomas Soome 		bam_error(_("%s is not an ELF file.\n"), fname);
179ae115bc7Smrj 		return (BAM_ERROR);
180ae115bc7Smrj 	}
181719db50fSToomas Soome 	if (ident[EI_CLASS] != class) {
182c262cbbcSToomas Soome 		bam_error(_("%s is wrong ELF class 0x%x\n"), fname,
183c262cbbcSToomas Soome 		    ident[EI_CLASS]);
184ae115bc7Smrj 		return (BAM_ERROR);
185ae115bc7Smrj 	}
186ae115bc7Smrj 
187ae115bc7Smrj 	/*
188ae115bc7Smrj 	 * The GRUB multiboot header must be 32-bit aligned and completely
189ae115bc7Smrj 	 * contained in the 1st 8K of the file.  If the unix binary has
190ae115bc7Smrj 	 * a multiboot header, then it is a 'dboot' kernel.  Otherwise,
191ae115bc7Smrj 	 * this kernel must be booted via multiboot -- we call this a
192ae115bc7Smrj 	 * 'multiboot' kernel.
193ae115bc7Smrj 	 */
194ae115bc7Smrj 	bam_direct = BAM_DIRECT_MULTIBOOT;
195ae115bc7Smrj 	for (m = 0; m < 8192 - sizeof (multiboot_header_t); m += 4) {
196ae115bc7Smrj 		mbh = (void *)(image + m);
197ae115bc7Smrj 		if (mbh->magic == MB_HEADER_MAGIC) {
198c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: is DBOOT unix\n", fcn));
199ae115bc7Smrj 			bam_direct = BAM_DIRECT_DBOOT;
200ae115bc7Smrj 			break;
201ae115bc7Smrj 		}
202ae115bc7Smrj 	}
203ae115bc7Smrj 	(void) munmap(image, 8192);
204ae115bc7Smrj 	(void) close(fd);
205843e1988Sjohnlev 
206eb2bd662Svikram 	INJECT_ERROR1("GET_CAP_MULTIBOOT", bam_direct = BAM_DIRECT_MULTIBOOT);
207843e1988Sjohnlev 	if (bam_direct == BAM_DIRECT_DBOOT) {
2083028dfd6SFrank Van Der Linden 		if (bam_is_hv == BAM_HV_PRESENT) {
209c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: is xVM system\n", fcn));
210843e1988Sjohnlev 		} else {
211c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: is *NOT* xVM system\n", fcn));
212843e1988Sjohnlev 		}
213eb2bd662Svikram 	} else {
214c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: is MULTIBOOT unix\n", fcn));
215843e1988Sjohnlev 	}
216843e1988Sjohnlev 
217eb2bd662Svikram 	/* Not a fatal error if this fails */
218eb2bd662Svikram 	get_findroot_cap(osroot);
219eb2bd662Svikram 
220c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
221ae115bc7Smrj 	return (BAM_SUCCESS);
222ae115bc7Smrj }
223ae115bc7Smrj 
224ae115bc7Smrj #define	INST_RELEASE	"var/sadm/system/admin/INST_RELEASE"
225ae115bc7Smrj 
226ae115bc7Smrj /*
227ae115bc7Smrj  * Return true if root has been bfu'ed.  bfu will blow away
228ae115bc7Smrj  * var/sadm/system/admin/INST_RELEASE, so if it's still there, we can
229ae115bc7Smrj  * assume the system has not been bfu'ed.
230ae115bc7Smrj  */
231ae115bc7Smrj static int
is_bfu_system(const char * root)232ae115bc7Smrj is_bfu_system(const char *root)
233ae115bc7Smrj {
234eb2bd662Svikram 	static int		is_bfu = -1;
235eb2bd662Svikram 	char			path[PATH_MAX];
236eb2bd662Svikram 	struct stat		sb;
237eb2bd662Svikram 	const char		*fcn = "is_bfu_system()";
238ae115bc7Smrj 
239eb2bd662Svikram 	if (is_bfu != -1) {
240c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: already done bfu test. bfu is %s present\n",
241c262cbbcSToomas Soome 		    fcn, is_bfu ? "" : "NOT"));
242ae115bc7Smrj 		return (is_bfu);
243eb2bd662Svikram 	}
244ae115bc7Smrj 
245ae115bc7Smrj 	(void) snprintf(path, sizeof (path), "%s/%s", root, INST_RELEASE);
246ae115bc7Smrj 	if (stat(path, &sb) != 0) {
247ae115bc7Smrj 		is_bfu = 1;
248c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
249ae115bc7Smrj 	} else {
250ae115bc7Smrj 		is_bfu = 0;
251c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
252ae115bc7Smrj 	}
253ae115bc7Smrj 	return (is_bfu);
254ae115bc7Smrj }
255ae115bc7Smrj 
256ae115bc7Smrj #define	MENU_URL(root)	(is_bfu_system(root) ?		\
257654b400cSJoshua M. Clulow 	"http://illumos.org/msg/SUNOS-8000-CF" :	\
258654b400cSJoshua M. Clulow 	"http://illumos.org/msg/SUNOS-8000-AK")
259ae115bc7Smrj 
260ae115bc7Smrj /*
261ae115bc7Smrj  * Simply allocate a new line and copy in cmd + sep + arg
262ae115bc7Smrj  */
263ae115bc7Smrj void
update_line(line_t * linep)264ae115bc7Smrj update_line(line_t *linep)
265ae115bc7Smrj {
266eb2bd662Svikram 	size_t		size;
267eb2bd662Svikram 	const char	*fcn = "update_line()";
268ae115bc7Smrj 
269c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: line before update: %s\n", fcn, linep->line));
270ae115bc7Smrj 	free(linep->line);
271ae115bc7Smrj 	size = strlen(linep->cmd) + strlen(linep->sep) + strlen(linep->arg) + 1;
272ae115bc7Smrj 	linep->line = s_calloc(1, size);
273ae115bc7Smrj 	(void) snprintf(linep->line, size, "%s%s%s", linep->cmd, linep->sep,
274ae115bc7Smrj 	    linep->arg);
275c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: line after update: %s\n", fcn, linep->line));
276eb2bd662Svikram }
277eb2bd662Svikram 
278eb2bd662Svikram static char *
skip_wspace(char * ptr)279eb2bd662Svikram skip_wspace(char *ptr)
280eb2bd662Svikram {
281eb2bd662Svikram 	const char		*fcn = "skip_wspace()";
282eb2bd662Svikram 
283eb2bd662Svikram 	INJECT_ERROR1("SKIP_WSPACE", ptr = NULL);
284eb2bd662Svikram 	if (ptr == NULL) {
285c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: NULL ptr\n", fcn));
286eb2bd662Svikram 		return (NULL);
287eb2bd662Svikram 	}
288eb2bd662Svikram 
289c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: ptr on entry: %s\n", fcn, ptr));
290eb2bd662Svikram 	for (; *ptr != '\0'; ptr++) {
291eb2bd662Svikram 		if ((*ptr != ' ') && (*ptr != '\t') &&
292eb2bd662Svikram 		    (*ptr != '\n'))
293eb2bd662Svikram 			break;
294eb2bd662Svikram 	}
295eb2bd662Svikram 
296eb2bd662Svikram 	ptr = (*ptr == '\0' ? NULL : ptr);
297eb2bd662Svikram 
298c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: ptr on exit: %s\n", fcn, ptr ? ptr : "NULL"));
299eb2bd662Svikram 
300eb2bd662Svikram 	return (ptr);
301eb2bd662Svikram }
302eb2bd662Svikram 
303eb2bd662Svikram static char *
rskip_bspace(char * bound,char * ptr)304eb2bd662Svikram rskip_bspace(char *bound, char *ptr)
305eb2bd662Svikram {
306eb2bd662Svikram 	const char		*fcn = "rskip_bspace()";
307eb2bd662Svikram 	assert(bound);
308eb2bd662Svikram 	assert(ptr);
309eb2bd662Svikram 	assert(bound <= ptr);
310eb2bd662Svikram 	assert(*bound != ' ' && *bound != '\t' && *bound != '\n');
311eb2bd662Svikram 
312c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: ptr on entry: %s\n", fcn, ptr));
313eb2bd662Svikram 	for (; ptr > bound; ptr--) {
314eb2bd662Svikram 		if (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')
315eb2bd662Svikram 			break;
316eb2bd662Svikram 	}
317eb2bd662Svikram 
318c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: ptr on exit: %s\n", fcn, ptr));
319eb2bd662Svikram 	return (ptr);
320ae115bc7Smrj }
321ae115bc7Smrj 
322ae115bc7Smrj /*
323ae115bc7Smrj  * The parse_kernel_line function examines a menu.lst kernel line.  For
324ae115bc7Smrj  * multiboot, this is:
325ae115bc7Smrj  *
326ae115bc7Smrj  * kernel <multiboot path> <flags1> <kernel path> <flags2>
327ae115bc7Smrj  *
328ae115bc7Smrj  * <multiboot path> is either /platform/i86pc/multiboot or /boot/multiboot
329ae115bc7Smrj  *
330ae115bc7Smrj  * <kernel path> may be missing, or may be any full or relative path to unix.
331ae115bc7Smrj  *	We check for it by looking for a word ending in "/unix".  If it ends
332ae115bc7Smrj  *	in "kernel/unix", we upgrade it to a 32-bit entry.  If it ends in
333ae115bc7Smrj  *	"kernel/amd64/unix", we upgrade it to the default entry.  Otherwise,
334ae115bc7Smrj  *	it's a custom kernel, and we skip it.
335ae115bc7Smrj  *
336ae115bc7Smrj  * <flags*> are anything that doesn't fit either of the above - these will be
337ae115bc7Smrj  *	copied over.
338ae115bc7Smrj  *
339ae115bc7Smrj  * For direct boot, the defaults are
340ae115bc7Smrj  *
341ae115bc7Smrj  * kernel$ <kernel path> <flags>
342ae115bc7Smrj  *
343ae115bc7Smrj  * <kernel path> is one of:
344ae115bc7Smrj  *	/platform/i86pc/kernel/$ISADIR/unix
345bbcc54bdSEnrico Perla - Sun Microsystems  *	/boot/platform/i86pc/kernel/$ISADIR/unix
346ae115bc7Smrj  *	/platform/i86pc/kernel/unix
347ae115bc7Smrj  *	/platform/i86pc/kernel/amd64/unix
348ae115bc7Smrj  *	/boot/platform/i86pc/kernel/unix
349bbcc54bdSEnrico Perla - Sun Microsystems  *	/boot/platform/i86pc/kernel/amd64/unix
350ae115bc7Smrj  *
351bbcc54bdSEnrico Perla - Sun Microsystems  * If <kernel path> is any of the last four, the command may also be "kernel".
352ae115bc7Smrj  *
353ae115bc7Smrj  * <flags> is anything that isn't <kernel path>.
354ae115bc7Smrj  *
355eb2bd662Svikram  * This function is only called to convert a multiboot entry to a dboot entry
356ae115bc7Smrj  *
357ae115bc7Smrj  * For safety, we do one more check: if the kernel path starts with /boot,
358ae115bc7Smrj  * we verify that the new kernel exists before changing it.  This is mainly
359ae115bc7Smrj  * done for bfu, as it may cause the failsafe archives to be a different
360ae115bc7Smrj  * boot architecture from the newly bfu'ed system.
361ae115bc7Smrj  */
362ae115bc7Smrj static error_t
cvt_kernel_line(line_t * line,const char * osroot,entry_t * entry)363eb2bd662Svikram cvt_kernel_line(line_t *line, const char *osroot, entry_t *entry)
364ae115bc7Smrj {
365bbcc54bdSEnrico Perla - Sun Microsystems 	char		path[PATH_MAX], path_64[PATH_MAX];
366eb2bd662Svikram 	char		linebuf[PATH_MAX];
367eb2bd662Svikram 	char		new_arg[PATH_MAX];
368bbcc54bdSEnrico Perla - Sun Microsystems 	struct stat	sb, sb_64;
369eb2bd662Svikram 	char		*old_ptr;
370eb2bd662Svikram 	char		*unix_ptr;
371eb2bd662Svikram 	char		*flags1_ptr;
372eb2bd662Svikram 	char		*flags2_ptr;
373eb2bd662Svikram 	const char	*fcn = "cvt_kernel_line()";
374eb2bd662Svikram 
375c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, line->line, osroot));
376ae115bc7Smrj 
377ae115bc7Smrj 	/*
378eb2bd662Svikram 	 * We only convert multiboot to dboot and nothing else.
379ae115bc7Smrj 	 */
380eb2bd662Svikram 	if (!(entry->flags & BAM_ENTRY_MULTIBOOT)) {
381c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: not MULTIBOOT, not converting\n", fcn));
382ae115bc7Smrj 		return (BAM_SUCCESS);
383ae115bc7Smrj 	}
384ae115bc7Smrj 
385eb2bd662Svikram 	if (entry->flags & BAM_ENTRY_FAILSAFE) {
386ae115bc7Smrj 		/*
387eb2bd662Svikram 		 * We're attempting to change failsafe to dboot.
388eb2bd662Svikram 		 * In the bfu case, we may not have a dboot failsafe
389eb2bd662Svikram 		 * kernel i.e. a "unix" under the "/boot" hierarchy.
390eb2bd662Svikram 		 * If so, just emit a message in verbose mode and
391eb2bd662Svikram 		 * return success.
392ae115bc7Smrj 		 */
393c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: trying to convert failsafe to DBOOT\n", fcn));
394eb2bd662Svikram 		(void) snprintf(path, PATH_MAX, "%s%s", osroot,
395bbcc54bdSEnrico Perla - Sun Microsystems 		    DIRECT_BOOT_FAILSAFE_32);
396bbcc54bdSEnrico Perla - Sun Microsystems 		(void) snprintf(path_64, PATH_MAX, "%s%s", osroot,
397bbcc54bdSEnrico Perla - Sun Microsystems 		    DIRECT_BOOT_FAILSAFE_64);
398bbcc54bdSEnrico Perla - Sun Microsystems 		if (stat(path, &sb) != 0 && stat(path_64, &sb_64) != 0) {
399ae115bc7Smrj 			if (bam_verbose) {
400c262cbbcSToomas Soome 				bam_error(_("bootadm -m upgrade run, but the "
401c262cbbcSToomas Soome 				    "failsafe archives have not been\nupdated. "
402c262cbbcSToomas Soome 				    "Not updating line %d\n"), line->lineNum);
403ae115bc7Smrj 			}
404c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: no FAILSAFE unix, not converting\n",
405c262cbbcSToomas Soome 			    fcn));
406ae115bc7Smrj 			return (BAM_SUCCESS);
407ae115bc7Smrj 		}
408ae115bc7Smrj 	}
409ae115bc7Smrj 
410ae115bc7Smrj 	/*
411bbcc54bdSEnrico Perla - Sun Microsystems 	 * Make sure we have the correct cmd
412ae115bc7Smrj 	 */
413bbcc54bdSEnrico Perla - Sun Microsystems 
414bbcc54bdSEnrico Perla - Sun Microsystems 	free(line->cmd);
415bbcc54bdSEnrico Perla - Sun Microsystems 	line->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]);
416c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: converted kernel cmd to %s\n", fcn, line->cmd));
417ae115bc7Smrj 
418eb2bd662Svikram 	assert(sizeof (linebuf) > strlen(line->arg) + 32);
419eb2bd662Svikram 	(void) strlcpy(linebuf, line->arg, sizeof (linebuf));
420ae115bc7Smrj 
421eb2bd662Svikram 	old_ptr = strpbrk(linebuf, " \t\n");
422eb2bd662Svikram 	old_ptr = skip_wspace(old_ptr);
423eb2bd662Svikram 	if (old_ptr == NULL) {
424eb2bd662Svikram 		/*
425eb2bd662Svikram 		 * only multiboot and nothing else
426eb2bd662Svikram 		 * i.e. flags1 = unix = flags2 = NULL
427eb2bd662Svikram 		 */
428eb2bd662Svikram 		flags1_ptr = unix_ptr = flags2_ptr = NULL;
429c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: NULL flags1, unix, flags2\n", fcn))
430eb2bd662Svikram 		goto create;
431ae115bc7Smrj 	}
432ae115bc7Smrj 
433ae115bc7Smrj 	/*
434ae115bc7Smrj 	 *
435eb2bd662Svikram 	 * old_ptr is either at "flags1" or "unix"
436ae115bc7Smrj 	 */
4373bbf88b3SToomas Soome 	if ((unix_ptr = strstr(old_ptr, "/unix")) != NULL) {
438eb2bd662Svikram 
439eb2bd662Svikram 		/*
440eb2bd662Svikram 		 * There is a  unix.
441eb2bd662Svikram 		 */
442c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: unix present\n", fcn));
443eb2bd662Svikram 
444eb2bd662Svikram 		/* See if there's a flags2 past unix */
445eb2bd662Svikram 		flags2_ptr = unix_ptr + strlen("/unix");
446eb2bd662Svikram 		flags2_ptr = skip_wspace(flags2_ptr);
447eb2bd662Svikram 		if (flags2_ptr) {
448c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: flags2 present: %s\n", fcn,
449c262cbbcSToomas Soome 			    flags2_ptr));
450eb2bd662Svikram 		} else {
451c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: flags2 absent\n", fcn));
452ae115bc7Smrj 		}
453ae115bc7Smrj 
454eb2bd662Svikram 		/* see if there is a flags1 before unix */
455eb2bd662Svikram 		unix_ptr = rskip_bspace(old_ptr, unix_ptr);
456ae115bc7Smrj 
457ae115bc7Smrj 		if (unix_ptr == old_ptr) {
458ae115bc7Smrj 			flags1_ptr = NULL;
459c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: flags1 absent\n", fcn));
460ae115bc7Smrj 		} else {
461ae115bc7Smrj 			flags1_ptr = old_ptr;
462eb2bd662Svikram 			*unix_ptr = '\0';
463eb2bd662Svikram 			unix_ptr++;
464c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: flags1 present: %s\n", fcn,
465c262cbbcSToomas Soome 			    flags1_ptr));
466ae115bc7Smrj 		}
467ae115bc7Smrj 
468eb2bd662Svikram 	} else  {
469eb2bd662Svikram 		/* There is no unix, there is only a bunch of flags */
470ae115bc7Smrj 		flags1_ptr = old_ptr;
471eb2bd662Svikram 		unix_ptr = flags2_ptr = NULL;
472c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: flags1 present: %s, unix, flags2 absent\n",
473c262cbbcSToomas Soome 		    fcn, flags1_ptr));
474ae115bc7Smrj 	}
475ae115bc7Smrj 
476eb2bd662Svikram 	/*
477eb2bd662Svikram 	 * With dboot, unix is fixed and is at the beginning. We need to
478eb2bd662Svikram 	 * migrate flags1 and flags2
479eb2bd662Svikram 	 */
480eb2bd662Svikram create:
481eb2bd662Svikram 	if (entry->flags & BAM_ENTRY_FAILSAFE) {
482eb2bd662Svikram 		(void) snprintf(new_arg, sizeof (new_arg), "%s",
483ae115bc7Smrj 		    DIRECT_BOOT_FAILSAFE_KERNEL);
484ae115bc7Smrj 	} else {
485eb2bd662Svikram 		(void) snprintf(new_arg, sizeof (new_arg), "%s",
486eb2bd662Svikram 		    DIRECT_BOOT_KERNEL);
487ae115bc7Smrj 	}
488c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: converted unix: %s\n", fcn, new_arg));
489ae115bc7Smrj 
490ae115bc7Smrj 	if (flags1_ptr != NULL) {
491eb2bd662Svikram 		(void) strlcat(new_arg, " ", sizeof (new_arg));
492eb2bd662Svikram 		(void) strlcat(new_arg, flags1_ptr, sizeof (new_arg));
493ae115bc7Smrj 	}
494eb2bd662Svikram 
495ae115bc7Smrj 	if (flags2_ptr != NULL) {
496eb2bd662Svikram 		(void) strlcat(new_arg, " ", sizeof (new_arg));
497eb2bd662Svikram 		(void) strlcat(new_arg, flags2_ptr, sizeof (new_arg));
498ae115bc7Smrj 	}
499ae115bc7Smrj 
500c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: converted unix with flags : %s\n", fcn, new_arg));
501eb2bd662Svikram 
502eb2bd662Svikram 	free(line->arg);
503eb2bd662Svikram 	line->arg = s_strdup(new_arg);
504eb2bd662Svikram 	update_line(line);
505c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: converted line is: %s\n", fcn, line->line));
506ae115bc7Smrj 	return (BAM_SUCCESS);
507ae115bc7Smrj }
508ae115bc7Smrj 
509ae115bc7Smrj /*
510ae115bc7Smrj  * Similar to above, except this time we're looking at a module line,
511ae115bc7Smrj  * which is quite a bit simpler.
512ae115bc7Smrj  *
513ae115bc7Smrj  * Under multiboot, the archive line is:
514ae115bc7Smrj  *
515ae115bc7Smrj  * module /platform/i86pc/boot_archive
516ae115bc7Smrj  *
517ae115bc7Smrj  * Under directboot, the archive line is:
518ae115bc7Smrj  *
519ae115bc7Smrj  * module$ /platform/i86pc/$ISADIR/boot_archive
520ae115bc7Smrj  *
521ae115bc7Smrj  * which may be specified exactly as either of:
522ae115bc7Smrj  *
523ae115bc7Smrj  * module /platform/i86pc/boot_archive
524ae115bc7Smrj  * module /platform/i86pc/amd64/boot_archive
525ae115bc7Smrj  *
526bbcc54bdSEnrico Perla - Sun Microsystems  * Under multiboot, the failsafe is:
527ae115bc7Smrj  *
528ae115bc7Smrj  * module /boot/x86.miniroot-safe
529bbcc54bdSEnrico Perla - Sun Microsystems  *
530bbcc54bdSEnrico Perla - Sun Microsystems  * Under dboot, the failsafe is:
531bbcc54bdSEnrico Perla - Sun Microsystems  *
532bbcc54bdSEnrico Perla - Sun Microsystems  * module$ /boot/$ISADIR/x86.miniroot-safe
533bbcc54bdSEnrico Perla - Sun Microsystems  *
534bbcc54bdSEnrico Perla - Sun Microsystems  * which may be specified exactly as either of:
535bbcc54bdSEnrico Perla - Sun Microsystems  *
536bbcc54bdSEnrico Perla - Sun Microsystems  * module /boot/x86.miniroot-safe
537bbcc54bdSEnrico Perla - Sun Microsystems  * module /boot/amd64/x86.miniroot-safe
538ae115bc7Smrj  */
539ae115bc7Smrj static error_t
cvt_module_line(line_t * line,entry_t * entry)540eb2bd662Svikram cvt_module_line(line_t *line, entry_t *entry)
541ae115bc7Smrj {
542eb2bd662Svikram 	const char		*fcn = "cvt_module_line()";
543eb2bd662Svikram 
544c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: entered. arg: %s\n", fcn, line->line));
545ae115bc7Smrj 
546ae115bc7Smrj 	/*
547eb2bd662Svikram 	 * We only convert multiboot to dboot and nothing else
548ae115bc7Smrj 	 */
549eb2bd662Svikram 	if (!(entry->flags & BAM_ENTRY_MULTIBOOT)) {
550c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: not MULTIBOOT, not converting\n", fcn));
551eb2bd662Svikram 		return (BAM_SUCCESS);
552ae115bc7Smrj 	}
553ae115bc7Smrj 
554eb2bd662Svikram 	if (entry->flags & BAM_ENTRY_FAILSAFE) {
555eb2bd662Svikram 		if (strcmp(line->arg, FAILSAFE_ARCHIVE) == 0) {
556c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: failsafe module line needs no "
557c262cbbcSToomas Soome 			    "conversion: %s\n", fcn, line->arg));
558c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
559eb2bd662Svikram 			return (BAM_SUCCESS);
560eb2bd662Svikram 		}
561eb2bd662Svikram 	} else if (strcmp(line->arg, MULTIBOOT_ARCHIVE) != 0) {
562c262cbbcSToomas Soome 		bam_error(_("module command on line %d not recognized.\n"),
563c262cbbcSToomas Soome 		    line->lineNum);
564c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
565eb2bd662Svikram 		return (BAM_MSG);
566ae115bc7Smrj 	}
567ae115bc7Smrj 
568bbcc54bdSEnrico Perla - Sun Microsystems 	free(line->cmd);
569bbcc54bdSEnrico Perla - Sun Microsystems 	free(line->arg);
570bbcc54bdSEnrico Perla - Sun Microsystems 	line->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]);
571bbcc54bdSEnrico Perla - Sun Microsystems 
572bbcc54bdSEnrico Perla - Sun Microsystems 	line->arg = s_strdup(entry->flags & BAM_ENTRY_FAILSAFE ?
573bbcc54bdSEnrico Perla - Sun Microsystems 	    FAILSAFE_ARCHIVE : DIRECT_BOOT_ARCHIVE);
574ae115bc7Smrj 
575eb2bd662Svikram 	update_line(line);
576c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: converted module line is: %s\n", fcn, line->line));
577c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
578ae115bc7Smrj 	return (BAM_SUCCESS);
579ae115bc7Smrj }
580ae115bc7Smrj 
581eb2bd662Svikram static void
bam_warn_hand_entries(menu_t * mp,char * osroot)582eb2bd662Svikram bam_warn_hand_entries(menu_t *mp, char *osroot)
583ae115bc7Smrj {
584eb2bd662Svikram 	int		hand_num;
585eb2bd662Svikram 	int		hand_max;
586eb2bd662Svikram 	int		*hand_list;
587eb2bd662Svikram 	int		i;
588eb2bd662Svikram 	entry_t		*entry;
589eb2bd662Svikram 	const char	*fcn = "bam_warn_hand_entries()";
590eb2bd662Svikram 
591eb2bd662Svikram 	if (bam_force) {
592eb2bd662Svikram 		/*
593eb2bd662Svikram 		 * No warning needed, we are automatically converting
594eb2bd662Svikram 		 * the "hand" entries
595eb2bd662Svikram 		 */
596c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: force specified, no warnings about hand "
597c262cbbcSToomas Soome 		    "entries\n",  fcn));
598eb2bd662Svikram 		return;
599eb2bd662Svikram 	}
600ae115bc7Smrj 
601eb2bd662Svikram 	hand_num = 0;
602eb2bd662Svikram 	hand_max = BAM_ENTRY_NUM;
603eb2bd662Svikram 	hand_list = s_calloc(1, hand_max);
604843e1988Sjohnlev 
605eb2bd662Svikram 	for (entry = mp->entries; entry; entry = entry->next) {
606eb2bd662Svikram 		if (entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU))
607eb2bd662Svikram 			continue;
608c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: found hand entry #: %d\n", fcn,
609c262cbbcSToomas Soome 		    entry->entryNum));
610eb2bd662Svikram 		if (++hand_num > hand_max) {
611eb2bd662Svikram 			hand_max *= 2;
612eb2bd662Svikram 			hand_list = s_realloc(hand_list,
613eb2bd662Svikram 			    hand_max * sizeof (int));
614eb2bd662Svikram 		}
615eb2bd662Svikram 		hand_list[hand_num - 1] = entry->entryNum;
616ae115bc7Smrj 	}
617ae115bc7Smrj 
618*bbf21555SRichard Lowe 	bam_error(_("bootadm(8) will only upgrade GRUB menu entries added "
619*bbf21555SRichard Lowe 	    "by \nbootadm(8) or lu(8). The following entries on %s will "
620c262cbbcSToomas Soome 	    "not be upgraded.\nFor details on manually updating entries, "
621c262cbbcSToomas Soome 	    "see %s\n"), osroot, MENU_URL(osroot));
622eb2bd662Svikram 	bam_print_stderr("Entry Number%s: ", (hand_num > 1) ?
623eb2bd662Svikram 	    "s" : "");
624eb2bd662Svikram 	for (i = 0; i < hand_num; i++) {
625eb2bd662Svikram 		bam_print_stderr("%d ", hand_list[i]);
626eb2bd662Svikram 	}
627eb2bd662Svikram 	bam_print_stderr("\n");
628eb2bd662Svikram }
629ae115bc7Smrj 
630eb2bd662Svikram static entry_t *
find_matching_entry(entry_t * estart,char * grubsign,char * grubroot,int root_opt)631eb2bd662Svikram find_matching_entry(
632eb2bd662Svikram 	entry_t *estart,
633eb2bd662Svikram 	char *grubsign,
634eb2bd662Svikram 	char *grubroot,
635eb2bd662Svikram 	int root_opt)
636eb2bd662Svikram {
637eb2bd662Svikram 	entry_t		*entry;
638eb2bd662Svikram 	line_t		*line;
639eb2bd662Svikram 	char		opt[10];
640eb2bd662Svikram 	const char	*fcn = "find_matching_entry()";
641ae115bc7Smrj 
642eb2bd662Svikram 	assert(grubsign);
643eb2bd662Svikram 	assert(root_opt == 0 || root_opt == 1);
644eb2bd662Svikram 
645eb2bd662Svikram 	(void) snprintf(opt, sizeof (opt), "%d", root_opt);
646c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: entered. args: %s %s %s\n", fcn, grubsign,
647c262cbbcSToomas Soome 	    grubroot, opt));
648ae115bc7Smrj 
649eb2bd662Svikram 	for (entry = estart; entry; entry = entry->next) {
650963390b4Svikram 
651eb2bd662Svikram 		if (!(entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) &&
652eb2bd662Svikram 		    !bam_force) {
653c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: skipping hand entry #: %d\n",
654c262cbbcSToomas Soome 			    fcn, entry->entryNum));
655843e1988Sjohnlev 			continue;
656843e1988Sjohnlev 		}
657843e1988Sjohnlev 
658eb2bd662Svikram 		if (entry->flags & BAM_ENTRY_ROOT) {
659eb2bd662Svikram 			for (line = entry->start; line; line = line->next) {
660eb2bd662Svikram 				if (line->cmd == NULL || line->arg == NULL) {
661eb2bd662Svikram 					if (line == entry->end) {
662c262cbbcSToomas Soome 						BAM_DPRINTF(("%s: entry has "
663c262cbbcSToomas Soome 						    "ended\n", fcn));
664eb2bd662Svikram 						break;
665eb2bd662Svikram 					} else {
666c262cbbcSToomas Soome 						BAM_DPRINTF(("%s: skipping "
667c262cbbcSToomas Soome 						    "NULL line\n", fcn));
668eb2bd662Svikram 						continue;
669ae115bc7Smrj 					}
670eb2bd662Svikram 				}
671eb2bd662Svikram 				if (strcmp(line->cmd, menu_cmds[ROOT_CMD])
672eb2bd662Svikram 				    == 0 && strcmp(line->arg, grubroot) == 0) {
673c262cbbcSToomas Soome 					BAM_DPRINTF(("%s: found matching root "
674c262cbbcSToomas Soome 					    "line: %s,%s\n", fcn,
675eb2bd662Svikram 					    line->line, grubsign));
676eb2bd662Svikram 					return (entry);
677eb2bd662Svikram 				}
678eb2bd662Svikram 				if (line == entry->end) {
679c262cbbcSToomas Soome 					BAM_DPRINTF(("%s: entry has ended\n",
680c262cbbcSToomas Soome 					    fcn));
681ae115bc7Smrj 					break;
682ae115bc7Smrj 				}
683eb2bd662Svikram 			}
684eb2bd662Svikram 		} else if (entry->flags & BAM_ENTRY_FINDROOT) {
685eb2bd662Svikram 			for (line = entry->start; line; line = line->next) {
686eb2bd662Svikram 				if (line->cmd == NULL || line->arg == NULL) {
687eb2bd662Svikram 					if (line == entry->end) {
688c262cbbcSToomas Soome 						BAM_DPRINTF(("%s: entry has "
689c262cbbcSToomas Soome 						    "ended\n", fcn));
690eb2bd662Svikram 						break;
691eb2bd662Svikram 					} else {
692c262cbbcSToomas Soome 						BAM_DPRINTF(("%s: skipping "
693c262cbbcSToomas Soome 						    "NULL line\n", fcn));
694eb2bd662Svikram 						continue;
695eb2bd662Svikram 					}
696eb2bd662Svikram 				}
697eb2bd662Svikram 				if (strcmp(line->cmd, menu_cmds[FINDROOT_CMD])
698eb2bd662Svikram 				    == 0 && strcmp(line->arg, grubsign) == 0) {
699c262cbbcSToomas Soome 					BAM_DPRINTF(("%s: found matching "
700c262cbbcSToomas Soome 					    "findroot line: %s,%s\n", fcn,
701eb2bd662Svikram 					    line->line, grubsign));
702eb2bd662Svikram 					return (entry);
703eb2bd662Svikram 				}
704eb2bd662Svikram 				if (line == entry->end) {
705c262cbbcSToomas Soome 					BAM_DPRINTF(("%s: entry has ended\n",
706c262cbbcSToomas Soome 					    fcn));
707ae115bc7Smrj 					break;
708eb2bd662Svikram 				}
709ae115bc7Smrj 			}
710eb2bd662Svikram 		} else if (root_opt) {
711eb2bd662Svikram 			/* Neither root nor findroot */
712c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: no root or findroot and root is "
713c262cbbcSToomas Soome 			    "opt: %d\n", fcn, entry->entryNum));
714eb2bd662Svikram 			return (entry);
715ae115bc7Smrj 		}
716eb2bd662Svikram 	}
717eb2bd662Svikram 
718c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: no matching entry found\n", fcn));
719eb2bd662Svikram 	return (NULL);
720eb2bd662Svikram }
721eb2bd662Svikram 
722eb2bd662Svikram /*
723eb2bd662Svikram  * The following is a set of routines that attempt to convert the
724eb2bd662Svikram  * menu entries for the supplied osroot into a format compatible
725eb2bd662Svikram  * with the GRUB installation on osroot.
726eb2bd662Svikram  *
727eb2bd662Svikram  * Each of these conversion routines make no assumptions about
728eb2bd662Svikram  * the current state of the menu entry, it does its best to
729eb2bd662Svikram  * convert the menu entry to the new state. In the process
730eb2bd662Svikram  * we may either upgrade or downgrade.
731eb2bd662Svikram  *
732eb2bd662Svikram  * We don't make any heroic efforts at conversion. It is better
733eb2bd662Svikram  * to be conservative and bail out at the first sign of error. We will
734eb2bd662Svikram  * in such cases, point the user at the knowledge-base article
735eb2bd662Svikram  * so that they can upgrade manually.
736eb2bd662Svikram  */
737eb2bd662Svikram static error_t
bam_add_findroot(menu_t * mp,char * grubsign,char * grubroot,int root_opt)738eb2bd662Svikram bam_add_findroot(menu_t *mp, char *grubsign, char *grubroot, int root_opt)
739eb2bd662Svikram {
740eb2bd662Svikram 	entry_t		*entry;
741eb2bd662Svikram 	line_t		*line;
742eb2bd662Svikram 	line_t		*newlp;
743eb2bd662Svikram 	int		update_num;
744eb2bd662Svikram 	char		linebuf[PATH_MAX];
745eb2bd662Svikram 	const char	*fcn = "bam_add_findroot()";
746eb2bd662Svikram 
747eb2bd662Svikram 	update_num = 0;
748eb2bd662Svikram 
749c262cbbcSToomas Soome 	bam_print(_("converting entries to findroot...\n"));
750eb2bd662Svikram 
7513bbf88b3SToomas Soome 	entry = find_matching_entry(mp->entries, grubsign, grubroot, root_opt);
7523bbf88b3SToomas Soome 	while (entry != NULL) {
753eb2bd662Svikram 		if (entry->flags & BAM_ENTRY_FINDROOT) {
754eb2bd662Svikram 			/* already converted */
755c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: entry %d already converted to "
756c262cbbcSToomas Soome 			    "findroot\n", fcn, entry->entryNum));
7573bbf88b3SToomas Soome 			entry = find_matching_entry(entry->next, grubsign,
7583bbf88b3SToomas Soome 			    grubroot, root_opt);
759ae115bc7Smrj 			continue;
760eb2bd662Svikram 		}
761eb2bd662Svikram 		for (line = entry->start; line; line = line->next) {
762eb2bd662Svikram 			if (line->cmd == NULL || line->arg == NULL) {
763eb2bd662Svikram 				if (line == entry->end) {
764c262cbbcSToomas Soome 					BAM_DPRINTF(("%s: entry has ended\n",
765c262cbbcSToomas Soome 					    fcn));
766eb2bd662Svikram 					break;
767eb2bd662Svikram 				} else {
768c262cbbcSToomas Soome 					BAM_DPRINTF(("%s: skipping NULL line\n",
769c262cbbcSToomas Soome 					    fcn));
770eb2bd662Svikram 					continue;
771eb2bd662Svikram 				}
772eb2bd662Svikram 			}
773eb2bd662Svikram 			if (strcmp(line->cmd, menu_cmds[TITLE_CMD]) == 0) {
774eb2bd662Svikram 				newlp = s_calloc(1, sizeof (line_t));
775eb2bd662Svikram 				newlp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]);
776eb2bd662Svikram 				newlp->sep = s_strdup(" ");
777eb2bd662Svikram 				newlp->arg = s_strdup(grubsign);
778eb2bd662Svikram 				(void) snprintf(linebuf, sizeof (linebuf),
779eb2bd662Svikram 				    "%s%s%s", newlp->cmd, newlp->sep,
780eb2bd662Svikram 				    newlp->arg);
781eb2bd662Svikram 				newlp->line = s_strdup(linebuf);
782eb2bd662Svikram 				bam_add_line(mp, entry, line, newlp);
783eb2bd662Svikram 				update_num = 1;
784eb2bd662Svikram 				entry->flags &= ~BAM_ENTRY_ROOT;
785eb2bd662Svikram 				entry->flags |= BAM_ENTRY_FINDROOT;
786c262cbbcSToomas Soome 				BAM_DPRINTF(("%s: added findroot line: %s\n",
787c262cbbcSToomas Soome 				    fcn, newlp->line));
788eb2bd662Svikram 				line = newlp;
789eb2bd662Svikram 			}
790eb2bd662Svikram 			if (strcmp(line->cmd, menu_cmds[ROOT_CMD]) == 0) {
791c262cbbcSToomas Soome 				BAM_DPRINTF(("%s: freeing root line: %s\n",
792c262cbbcSToomas Soome 				    fcn, line->line));
793eb2bd662Svikram 				unlink_line(mp, line);
794eb2bd662Svikram 				line_free(line);
795eb2bd662Svikram 			}
796eb2bd662Svikram 			if (line == entry->end) {
797c262cbbcSToomas Soome 				BAM_DPRINTF(("%s: entry has ended\n", fcn));
798eb2bd662Svikram 				break;
799eb2bd662Svikram 			}
800eb2bd662Svikram 		}
8013bbf88b3SToomas Soome 		entry = find_matching_entry(entry->next, grubsign, grubroot,
8023bbf88b3SToomas Soome 		    root_opt);
803eb2bd662Svikram 	}
804eb2bd662Svikram 
805eb2bd662Svikram 	if (update_num) {
806c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: updated numbering\n", fcn));
807eb2bd662Svikram 		update_numbering(mp);
808eb2bd662Svikram 	}
809eb2bd662Svikram 
810c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
811eb2bd662Svikram 	return (BAM_SUCCESS);
812eb2bd662Svikram }
813ae115bc7Smrj 
814eb2bd662Svikram static error_t
bam_add_hv(menu_t * mp,char * grubsign,char * grubroot,int root_opt)815eb2bd662Svikram bam_add_hv(menu_t *mp, char *grubsign, char *grubroot, int root_opt)
816eb2bd662Svikram {
817eb2bd662Svikram 	entry_t		*entry;
818eb2bd662Svikram 	const char	*fcn = "bam_add_hv()";
819eb2bd662Svikram 
820c262cbbcSToomas Soome 	bam_print(_("adding xVM entries...\n"));
821eb2bd662Svikram 
8223bbf88b3SToomas Soome 	entry = find_matching_entry(mp->entries, grubsign, grubroot, root_opt);
8233bbf88b3SToomas Soome 	while (entry != NULL) {
824eb2bd662Svikram 		if (entry->flags & BAM_ENTRY_HV) {
825c262cbbcSToomas Soome 			BAM_DPRINTF(("%s: entry %d already converted to "
826c262cbbcSToomas Soome 			    "xvm HV\n", fcn, entry->entryNum));
827eb2bd662Svikram 			return (BAM_SUCCESS);
828eb2bd662Svikram 		}
8293bbf88b3SToomas Soome 		entry = find_matching_entry(entry->next, grubsign, grubroot,
8303bbf88b3SToomas Soome 		    root_opt);
831eb2bd662Svikram 	}
832eb2bd662Svikram 
833eb2bd662Svikram 	(void) add_boot_entry(mp, NEW_HV_ENTRY, grubsign, XEN_MENU,
83444da779fSWilliam Kucharski 	    XEN_KERNEL_MODULE_LINE, DIRECT_BOOT_ARCHIVE, NULL);
835eb2bd662Svikram 
836c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: added xVM HV entry via add_boot_entry()\n", fcn));
837eb2bd662Svikram 
838eb2bd662Svikram 	update_numbering(mp);
839eb2bd662Svikram 
840c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
841eb2bd662Svikram 
842eb2bd662Svikram 	return (BAM_SUCCESS);
843eb2bd662Svikram }
844eb2bd662Svikram 
845eb2bd662Svikram static error_t
bam_add_dboot(menu_t * mp,char * osroot,char * grubsign,char * grubroot,int root_opt)846eb2bd662Svikram bam_add_dboot(
847eb2bd662Svikram 	menu_t *mp,
848eb2bd662Svikram 	char *osroot,
849eb2bd662Svikram 	char *grubsign,
850eb2bd662Svikram 	char *grubroot,
851eb2bd662Svikram 	int root_opt)
852eb2bd662Svikram {
853eb2bd662Svikram 	int		msg = 0;
854eb2bd662Svikram 	entry_t		*entry;
855eb2bd662Svikram 	line_t		*line;
856eb2bd662Svikram 	error_t		ret;
857eb2bd662Svikram 	const char 	*fcn = "bam_add_dboot()";
858eb2bd662Svikram 
859c262cbbcSToomas Soome 	bam_print(_("converting entries to dboot...\n"));
860eb2bd662Svikram 
8613bbf88b3SToomas Soome 	entry = find_matching_entry(mp->entries, grubsign, grubroot, root_opt);
8623bbf88b3SToomas Soome 	while (entry != NULL) {
863eb2bd662Svikram 		for (line = entry->start; line; line = line->next) {
864eb2bd662Svikram 			if (line->cmd == NULL || line->arg == NULL) {
865eb2bd662Svikram 				if (line == entry->end) {
866c262cbbcSToomas Soome 					BAM_DPRINTF(("%s: entry has ended\n",
867c262cbbcSToomas Soome 					    fcn));
868eb2bd662Svikram 					break;
869eb2bd662Svikram 				} else {
870c262cbbcSToomas Soome 					BAM_DPRINTF(("%s: skipping NULL line\n",
871c262cbbcSToomas Soome 					    fcn));
872eb2bd662Svikram 					continue;
873eb2bd662Svikram 				}
874eb2bd662Svikram 			}
875ae115bc7Smrj 
876ae115bc7Smrj 			/*
877eb2bd662Svikram 			 * If we have a kernel$ command, assume it
878eb2bd662Svikram 			 * is dboot already.  If it is not a dboot
879eb2bd662Svikram 			 * entry, something funny is going on and
880eb2bd662Svikram 			 * we will leave it alone
881ae115bc7Smrj 			 */
882eb2bd662Svikram 			if (strcmp(line->cmd, menu_cmds[KERNEL_CMD]) == 0) {
883eb2bd662Svikram 				ret = cvt_kernel_line(line, osroot, entry);
884eb2bd662Svikram 				INJECT_ERROR1("ADD_DBOOT_KERN_ERR",
885eb2bd662Svikram 				    ret = BAM_ERROR);
886eb2bd662Svikram 				INJECT_ERROR1("ADD_DBOOT_KERN_MSG",
887eb2bd662Svikram 				    ret = BAM_MSG);
888eb2bd662Svikram 				if (ret == BAM_ERROR) {
889c262cbbcSToomas Soome 					BAM_DPRINTF(("%s: cvt_kernel_line() "
890c262cbbcSToomas Soome 					    "failed\n", fcn));
891eb2bd662Svikram 					return (ret);
892eb2bd662Svikram 				} else if (ret == BAM_MSG) {
893eb2bd662Svikram 					msg = 1;
894c262cbbcSToomas Soome 					BAM_DPRINTF(("%s: BAM_MSG returned "
895c262cbbcSToomas Soome 					    "from cvt_kernel_line()\n", fcn));
896ae115bc7Smrj 				}
897eb2bd662Svikram 			}
898eb2bd662Svikram 			if (strcmp(line->cmd, menu_cmds[MODULE_CMD]) == 0) {
899eb2bd662Svikram 				ret = cvt_module_line(line, entry);
900eb2bd662Svikram 				INJECT_ERROR1("ADD_DBOOT_MOD_ERR",
901eb2bd662Svikram 				    ret = BAM_ERROR);
902eb2bd662Svikram 				INJECT_ERROR1("ADD_DBOOT_MOD_MSG",
903eb2bd662Svikram 				    ret = BAM_MSG);
904eb2bd662Svikram 				if (ret == BAM_ERROR) {
905c262cbbcSToomas Soome 					BAM_DPRINTF(("%s: cvt_module_line() "
906c262cbbcSToomas Soome 					    "failed\n", fcn));
907eb2bd662Svikram 					return (ret);
908eb2bd662Svikram 				} else if (ret == BAM_MSG) {
909c262cbbcSToomas Soome 					BAM_DPRINTF(("%s: BAM_MSG returned "
910c262cbbcSToomas Soome 					    "from cvt_module_line()\n", fcn));
911eb2bd662Svikram 					msg = 1;
912ae115bc7Smrj 				}
913ae115bc7Smrj 			}
914eb2bd662Svikram 
915eb2bd662Svikram 			if (line == entry->end) {
916c262cbbcSToomas Soome 				BAM_DPRINTF(("%s: entry has ended\n", fcn));
917ae115bc7Smrj 				break;
918eb2bd662Svikram 			}
919ae115bc7Smrj 		}
9203bbf88b3SToomas Soome 		entry = find_matching_entry(entry->next, grubsign, grubroot,
9213bbf88b3SToomas Soome 		    root_opt);
922ae115bc7Smrj 	}
923ae115bc7Smrj 
924eb2bd662Svikram 	ret = msg ? BAM_MSG : BAM_SUCCESS;
925c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: returning ret = %d\n", fcn, ret));
926eb2bd662Svikram 	return (ret);
927eb2bd662Svikram }
928eb2bd662Svikram 
929eb2bd662Svikram /*ARGSUSED*/
930eb2bd662Svikram error_t
upgrade_menu(menu_t * mp,char * osroot,char * menu_root)931eb2bd662Svikram upgrade_menu(menu_t *mp, char *osroot, char *menu_root)
932eb2bd662Svikram {
933eb2bd662Svikram 	char		*osdev;
934eb2bd662Svikram 	char		*grubsign;
935eb2bd662Svikram 	char		*grubroot;
936eb2bd662Svikram 	int		ret1;
937eb2bd662Svikram 	int		ret2;
938eb2bd662Svikram 	int		ret3;
939eb2bd662Svikram 	const char	*fcn = "upgrade_menu()";
940eb2bd662Svikram 
941eb2bd662Svikram 	assert(osroot);
942eb2bd662Svikram 	assert(menu_root);
943eb2bd662Svikram 
944c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, osroot, menu_root));
945eb2bd662Svikram 
946843e1988Sjohnlev 	/*
947eb2bd662Svikram 	 * We only support upgrades. Xen may not be present
948eb2bd662Svikram 	 * on smaller metaclusters so we don't check for that.
949843e1988Sjohnlev 	 */
950eb2bd662Svikram 	if (bam_is_findroot != BAM_FINDROOT_PRESENT ||
951eb2bd662Svikram 	    bam_direct != BAM_DIRECT_DBOOT) {
952c262cbbcSToomas Soome 		bam_error(_("automated downgrade of GRUB menu to older "
953c262cbbcSToomas Soome 		    "version not supported.\n"));
954eb2bd662Svikram 		return (BAM_ERROR);
955843e1988Sjohnlev 	}
956843e1988Sjohnlev 
957ae115bc7Smrj 	/*
958eb2bd662Svikram 	 * First get the GRUB signature
959ae115bc7Smrj 	 */
960eb2bd662Svikram 	osdev = get_special(osroot);
961eb2bd662Svikram 	INJECT_ERROR1("UPGRADE_OSDEV", osdev = NULL);
962eb2bd662Svikram 	if (osdev == NULL) {
963c262cbbcSToomas Soome 		bam_error(_("cant find special file for mount-point %s\n"),
964c262cbbcSToomas Soome 		    osroot);
965eb2bd662Svikram 		return (BAM_ERROR);
966eb2bd662Svikram 	}
967eb2bd662Svikram 
968eb2bd662Svikram 	grubsign = get_grubsign(osroot, osdev);
969eb2bd662Svikram 	INJECT_ERROR1("UPGRADE_GRUBSIGN", grubsign = NULL);
970eb2bd662Svikram 	if (grubsign == NULL) {
971eb2bd662Svikram 		free(osdev);
972c262cbbcSToomas Soome 		bam_error(_("cannot find GRUB signature for %s\n"), osroot);
973ae115bc7Smrj 		return (BAM_ERROR);
974ae115bc7Smrj 	}
975eb2bd662Svikram 
976eb2bd662Svikram 	/* not fatal if we can't get grubroot */
977eb2bd662Svikram 	grubroot = get_grubroot(osroot, osdev, menu_root);
978eb2bd662Svikram 	INJECT_ERROR1("UPGRADE_GRUBROOT", grubroot = NULL);
979eb2bd662Svikram 
980eb2bd662Svikram 	free(osdev);
981eb2bd662Svikram 
982eb2bd662Svikram 	ret1 = bam_add_findroot(mp, grubsign,
983eb2bd662Svikram 	    grubroot, root_optional(osroot, menu_root));
984eb2bd662Svikram 	INJECT_ERROR1("UPGRADE_ADD_FINDROOT", ret1 = BAM_ERROR);
985eb2bd662Svikram 	if (ret1 == BAM_ERROR)
986eb2bd662Svikram 		goto abort;
987eb2bd662Svikram 
9883028dfd6SFrank Van Der Linden 	if (bam_is_hv == BAM_HV_PRESENT) {
9893028dfd6SFrank Van Der Linden 		ret2 = bam_add_hv(mp, grubsign, grubroot,
9903028dfd6SFrank Van Der Linden 		    root_optional(osroot, menu_root));
9913028dfd6SFrank Van Der Linden 		INJECT_ERROR1("UPGRADE_ADD_HV", ret2 = BAM_ERROR);
9923028dfd6SFrank Van Der Linden 		if (ret2 == BAM_ERROR)
9933028dfd6SFrank Van Der Linden 			goto abort;
9943028dfd6SFrank Van Der Linden 	} else
9953028dfd6SFrank Van Der Linden 		ret2 = BAM_SUCCESS;
996eb2bd662Svikram 
997eb2bd662Svikram 	ret3 = bam_add_dboot(mp, osroot, grubsign,
998eb2bd662Svikram 	    grubroot, root_optional(osroot, menu_root));
999eb2bd662Svikram 	INJECT_ERROR1("UPGRADE_ADD_DBOOT", ret3 = BAM_ERROR);
1000eb2bd662Svikram 	if (ret3 == BAM_ERROR)
1001eb2bd662Svikram 		goto abort;
1002eb2bd662Svikram 
1003eb2bd662Svikram 	if (ret1 == BAM_MSG || ret2 == BAM_MSG || ret3 == BAM_MSG) {
1004c262cbbcSToomas Soome 		bam_error(_("one or more GRUB menu entries were not "
1005c262cbbcSToomas Soome 		    "automatically upgraded\nFor details on manually "
1006c262cbbcSToomas Soome 		    "updating entries, see %s\n"), MENU_URL(osroot));
1007eb2bd662Svikram 	} else {
1008eb2bd662Svikram 		bam_warn_hand_entries(mp, osroot);
1009eb2bd662Svikram 	}
1010eb2bd662Svikram 
1011eb2bd662Svikram 	free(grubsign);
1012eb2bd662Svikram 
1013c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: returning ret = %d\n", fcn, BAM_WRITE));
1014ae115bc7Smrj 	return (BAM_WRITE);
1015eb2bd662Svikram 
1016eb2bd662Svikram abort:
1017eb2bd662Svikram 	free(grubsign);
1018c262cbbcSToomas Soome 	bam_error(_("error upgrading GRUB menu entries on %s. Aborting.\n"
1019c262cbbcSToomas Soome 	    "For details on manually updating entries, see %s\n"), osroot,
1020c262cbbcSToomas Soome 	    MENU_URL(osroot));
1021eb2bd662Svikram 	return (BAM_ERROR);
1022ae115bc7Smrj }
1023