1*6423Sgw25295 /*
2*6423Sgw25295 * CDDL HEADER START
3*6423Sgw25295 *
4*6423Sgw25295 * The contents of this file are subject to the terms of the
5*6423Sgw25295 * Common Development and Distribution License (the "License").
6*6423Sgw25295 * You may not use this file except in compliance with the License.
7*6423Sgw25295 *
8*6423Sgw25295 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6423Sgw25295 * or http://www.opensolaris.org/os/licensing.
10*6423Sgw25295 * See the License for the specific language governing permissions
11*6423Sgw25295 * and limitations under the License.
12*6423Sgw25295 *
13*6423Sgw25295 * When distributing Covered Code, include this CDDL HEADER in each
14*6423Sgw25295 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6423Sgw25295 * If applicable, add the following below this CDDL HEADER, with the
16*6423Sgw25295 * fields enclosed by brackets "[]" replaced with your own identifying
17*6423Sgw25295 * information: Portions Copyright [yyyy] [name of copyright owner]
18*6423Sgw25295 *
19*6423Sgw25295 * CDDL HEADER END
20*6423Sgw25295 */
21*6423Sgw25295 /*
22*6423Sgw25295 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23*6423Sgw25295 * Use is subject to license terms.
24*6423Sgw25295 */
25*6423Sgw25295 #pragma ident "%Z%%M% %I% %E% SMI"
26*6423Sgw25295
27*6423Sgw25295 #include <sys/promif.h>
28*6423Sgw25295 #include <sys/salib.h>
29*6423Sgw25295
30*6423Sgw25295 #define MAX_CMDLINE 1600 /* from GRUB source */
31*6423Sgw25295
32*6423Sgw25295 char **titles;
33*6423Sgw25295 char **datasets;
34*6423Sgw25295
35*6423Sgw25295 int menu_entry_count;
36*6423Sgw25295 int menu_table_size;
37*6423Sgw25295
38*6423Sgw25295 int in_menu_entry;
39*6423Sgw25295
40*6423Sgw25295 #define ENTRY_ALLOC_COUNT 10
41*6423Sgw25295
42*6423Sgw25295 extern void set_default_fs(char *fsw_name);
43*6423Sgw25295 extern int mountroot(char *str);
44*6423Sgw25295
45*6423Sgw25295 void
init_table(void)46*6423Sgw25295 init_table(void)
47*6423Sgw25295 {
48*6423Sgw25295
49*6423Sgw25295 menu_entry_count = 0;
50*6423Sgw25295 titles = (char **)calloc(ENTRY_ALLOC_COUNT, sizeof (char *));
51*6423Sgw25295 datasets = (char **)calloc(ENTRY_ALLOC_COUNT, sizeof (char *));
52*6423Sgw25295 if (titles == NULL || datasets == NULL)
53*6423Sgw25295 prom_panic("out of mem");
54*6423Sgw25295 menu_table_size = ENTRY_ALLOC_COUNT;
55*6423Sgw25295 in_menu_entry = 0;
56*6423Sgw25295 }
57*6423Sgw25295
58*6423Sgw25295 void
add_title_entry(char * title_str)59*6423Sgw25295 add_title_entry(char *title_str)
60*6423Sgw25295 {
61*6423Sgw25295
62*6423Sgw25295 /* skip leading white space */
63*6423Sgw25295 while (isspace(*title_str))
64*6423Sgw25295 title_str++;
65*6423Sgw25295
66*6423Sgw25295 if (menu_entry_count == menu_table_size) {
67*6423Sgw25295 printf("Reallocating at count %d\n", menu_table_size);
68*6423Sgw25295 titles = (char **)realloc(titles,
69*6423Sgw25295 ENTRY_ALLOC_COUNT * sizeof (char *));
70*6423Sgw25295 datasets = (char **)realloc(datasets,
71*6423Sgw25295 ENTRY_ALLOC_COUNT * sizeof (char *));
72*6423Sgw25295 if (titles == NULL || datasets == NULL)
73*6423Sgw25295 prom_panic("out of mem");
74*6423Sgw25295 menu_table_size += ENTRY_ALLOC_COUNT;
75*6423Sgw25295 }
76*6423Sgw25295
77*6423Sgw25295 if (in_menu_entry)
78*6423Sgw25295 free(titles[menu_entry_count]);
79*6423Sgw25295 if ((titles[menu_entry_count] = strdup(title_str)) == NULL)
80*6423Sgw25295 prom_panic("out of mem");
81*6423Sgw25295 in_menu_entry = 1;
82*6423Sgw25295 }
83*6423Sgw25295
84*6423Sgw25295 void
add_dataset_entry(char * dataset_str)85*6423Sgw25295 add_dataset_entry(char *dataset_str)
86*6423Sgw25295 {
87*6423Sgw25295 char *cp;
88*6423Sgw25295
89*6423Sgw25295 /* skip leading white space */
90*6423Sgw25295 while (isspace(*dataset_str))
91*6423Sgw25295 dataset_str++;
92*6423Sgw25295
93*6423Sgw25295 /* if there is still any white space in the line, it's invalid */
94*6423Sgw25295 for (cp = dataset_str; *cp; cp++)
95*6423Sgw25295 if (isspace(*cp))
96*6423Sgw25295 break;
97*6423Sgw25295 if (*cp)
98*6423Sgw25295 return; /* dataset name was invalid */
99*6423Sgw25295
100*6423Sgw25295 if (!in_menu_entry)
101*6423Sgw25295 return; /* dataset line was not preceded by a title */
102*6423Sgw25295
103*6423Sgw25295 if ((datasets[menu_entry_count] = strdup(dataset_str)) == NULL)
104*6423Sgw25295 prom_panic("out of mem");
105*6423Sgw25295 menu_entry_count++;
106*6423Sgw25295 in_menu_entry = 0;
107*6423Sgw25295 }
108*6423Sgw25295
109*6423Sgw25295
110*6423Sgw25295 char *
trim_white_space(char * cp)111*6423Sgw25295 trim_white_space(char *cp)
112*6423Sgw25295 {
113*6423Sgw25295 char *ep;
114*6423Sgw25295
115*6423Sgw25295 /* skip leading white space */
116*6423Sgw25295 while (isspace(*cp))
117*6423Sgw25295 cp++;
118*6423Sgw25295
119*6423Sgw25295 /*
120*6423Sgw25295 * if the string contained nothing but white space, return a
121*6423Sgw25295 * null string.
122*6423Sgw25295 */
123*6423Sgw25295 if (*cp == '\0')
124*6423Sgw25295 return (cp);
125*6423Sgw25295
126*6423Sgw25295 /* truncate trailing white space */
127*6423Sgw25295 for (ep = cp + strlen(cp) - 1; isspace(*ep); ep--)
128*6423Sgw25295 ;
129*6423Sgw25295 ep++;
130*6423Sgw25295 *ep = '\0';
131*6423Sgw25295 return (cp);
132*6423Sgw25295 }
133*6423Sgw25295
134*6423Sgw25295 char *cons_gets(char *, int);
135*6423Sgw25295
136*6423Sgw25295 void
main(void * cif)137*6423Sgw25295 main(void *cif)
138*6423Sgw25295 {
139*6423Sgw25295 char linebuf[MAX_CMDLINE];
140*6423Sgw25295 FILE *file;
141*6423Sgw25295 char *cp, *ep;
142*6423Sgw25295 int n;
143*6423Sgw25295 unsigned long choice;
144*6423Sgw25295
145*6423Sgw25295 prom_init("bootlst", cif);
146*6423Sgw25295 set_default_fs("promfs");
147*6423Sgw25295 if (mountroot("bootfs") != 0)
148*6423Sgw25295 prom_panic("can't mount root");
149*6423Sgw25295
150*6423Sgw25295 if ((file = fopen("/boot/menu.lst", "r")) == NULL)
151*6423Sgw25295 prom_panic("can't open menu.lst");
152*6423Sgw25295 init_table();
153*6423Sgw25295
154*6423Sgw25295 while (fgets(linebuf, MAX_CMDLINE, file)) {
155*6423Sgw25295 cp = trim_white_space(linebuf);
156*6423Sgw25295
157*6423Sgw25295 /* skip comments and blank lines */
158*6423Sgw25295 if (*cp == '#' || *cp == '\0')
159*6423Sgw25295 continue;
160*6423Sgw25295
161*6423Sgw25295 /* find end of first keyword on line */
162*6423Sgw25295 for (ep = cp; !isspace(*ep) && *ep; ep++)
163*6423Sgw25295 ;
164*6423Sgw25295
165*6423Sgw25295 /* if at the end of the line, the line had no arguments */
166*6423Sgw25295 if (*ep == '\0')
167*6423Sgw25295 continue;
168*6423Sgw25295
169*6423Sgw25295 *ep = '\0';
170*6423Sgw25295
171*6423Sgw25295 if (strcmp(cp, "title") == 0) {
172*6423Sgw25295 add_title_entry(ep + 1);
173*6423Sgw25295 continue;
174*6423Sgw25295 }
175*6423Sgw25295
176*6423Sgw25295 if (strcmp(cp, "bootfs") == 0) {
177*6423Sgw25295 add_dataset_entry(ep + 1);
178*6423Sgw25295 continue;
179*6423Sgw25295 }
180*6423Sgw25295 }
181*6423Sgw25295
182*6423Sgw25295 if (menu_entry_count == 0)
183*6423Sgw25295 prom_panic("no menu entries found");
184*6423Sgw25295
185*6423Sgw25295 for (n = 0; n < menu_entry_count; n++) {
186*6423Sgw25295 printf("%d %s\n", n + 1, titles[n]);
187*6423Sgw25295 }
188*6423Sgw25295
189*6423Sgw25295 printf("Select environment to boot: [ 1 - %d ]: ", menu_entry_count);
190*6423Sgw25295
191*6423Sgw25295 while (cons_gets(linebuf, MAX_CMDLINE)) {
192*6423Sgw25295 /* cut off leading and trailing white space */
193*6423Sgw25295 cp = trim_white_space(linebuf);
194*6423Sgw25295 choice = strtoul(cp, NULL, 0);
195*6423Sgw25295
196*6423Sgw25295 /*
197*6423Sgw25295 * If the input is totally invalid, the return value of
198*6423Sgw25295 * strtoul() will be 0 or ULONG_MAX. Either way, it's
199*6423Sgw25295 * of the acceptable range.
200*6423Sgw25295 */
201*6423Sgw25295 if (choice == 0 || choice > menu_entry_count) {
202*6423Sgw25295 printf("Invalid entry.\n");
203*6423Sgw25295 continue;
204*6423Sgw25295 }
205*6423Sgw25295 /* XXX here is the result */
206*6423Sgw25295 printf("\nTo boot the selected entry, invoke:\n");
207*6423Sgw25295 printf("boot [<root-device>] -Z %s\n\n", datasets[choice - 1]);
208*6423Sgw25295 prom_exit_to_mon();
209*6423Sgw25295 }
210*6423Sgw25295 }
211