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