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 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 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 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 * 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 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