Print this page
8226 missing boot environments cause bootadm list-menu to segfault
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/boot/bootadm/bootadm_loader.c
+++ new/usr/src/cmd/boot/bootadm/bootadm_loader.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2012 Milan Jurik. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28 28 * Copyright 2016 Toomas Soome <tsoome@me.com>
29 + * Copyright 2017 RackTop Systems.
29 30 */
30 31
31 32 /*
32 33 * Loader menu management.
33 34 */
34 35
35 36 #include <stdio.h>
36 37 #include <stdlib.h>
37 38 #include <string.h>
38 39 #include <wchar.h>
39 40 #include <errno.h>
40 41 #include <limits.h>
41 42 #include <alloca.h>
42 43 #include <unistd.h>
43 44 #include <sys/types.h>
44 45 #include <sys/stat.h>
45 46 #include <sys/queue.h>
46 47 #include <libbe.h>
47 48 #include <ficl.h>
48 49 #include <ficlplatform/emu.h>
49 50
50 51 #include "bootadm.h"
51 52
52 53 extern int bam_rootlen;
53 54 extern int bam_alt_root;
54 55 extern char *rootbuf;
55 56 extern char *bam_root;
56 57
57 58 #define BOOT_DIR "/boot"
58 59 #define CONF_DIR BOOT_DIR "/conf.d"
59 60 #define MENU BOOT_DIR "/menu.lst"
60 61 #define TRANSIENT BOOT_DIR "/transient.conf"
61 62 #define XEN_CONFIG CONF_DIR "/xen"
62 63
63 64 struct menu_entry {
64 65 int entry;
65 66 char *title;
66 67 char *bootfs;
67 68 STAILQ_ENTRY(menu_entry) next;
68 69 };
69 70 STAILQ_HEAD(menu_lst, menu_entry);
70 71
71 72 static error_t set_option(struct menu_lst *, char *, char *);
72 73 static error_t list_entry(struct menu_lst *, char *, char *);
73 74 static error_t update_entry(struct menu_lst *, char *, char *);
74 75 static error_t update_temp(struct menu_lst *, char *, char *);
75 76 static error_t list_setting(struct menu_lst *menu, char *, char *);
76 77 static error_t disable_hyper(struct menu_lst *, char *, char *);
77 78 static error_t enable_hyper(struct menu_lst *, char *, char *);
78 79
79 80 /* Menu related sub commands */
80 81 static subcmd_defn_t menu_subcmds[] = {
81 82 "set_option", OPT_ABSENT, set_option, 0, /* PUB */
82 83 "list_entry", OPT_OPTIONAL, list_entry, 1, /* PUB */
83 84 "update_entry", OPT_REQ, update_entry, 0, /* menu */
84 85 "update_temp", OPT_OPTIONAL, update_temp, 0, /* reboot */
85 86 "list_setting", OPT_OPTIONAL, list_setting, 1, /* menu */
86 87 "disable_hypervisor", OPT_ABSENT, disable_hyper, 0, /* menu */
87 88 "enable_hypervisor", OPT_ABSENT, enable_hyper, 0, /* menu */
88 89 NULL, 0, NULL, 0 /* must be last */
89 90 };
90 91
91 92 #define NUM_COLS (4)
92 93 struct col_info {
93 94 const char *col_name;
94 95 size_t width;
95 96 };
96 97
97 98 /*
98 99 * all columns output format
99 100 */
100 101 struct hdr_info {
101 102 struct col_info cols[NUM_COLS];
102 103 };
103 104
104 105 static void
105 106 print_hdr(struct hdr_info *hdr_info)
106 107 {
107 108 boolean_t first = B_TRUE;
108 109 size_t i;
109 110
110 111 for (i = 0; i < NUM_COLS; i++) {
111 112 struct col_info *col_info = &hdr_info->cols[i];
112 113 const char *name = col_info->col_name;
113 114 size_t width = col_info->width;
114 115
115 116 if (name == NULL)
116 117 continue;
117 118
118 119 if (first) {
119 120 (void) printf("%-*s", width, name);
120 121 first = B_FALSE;
121 122 } else
122 123 (void) printf(" %-*s", width, name);
123 124 }
124 125 (void) putchar('\n');
125 126 }
126 127
127 128 static void
128 129 init_hdr_cols(struct hdr_info *hdr)
129 130 {
130 131 struct col_info *col = hdr->cols;
131 132 size_t i;
132 133
133 134 col[0].col_name = _("Index");
134 135 col[1].col_name = _("Default");
135 136 col[2].col_name = _("Dataset");
136 137 col[3].col_name = _("Menu");
137 138 col[4].col_name = NULL;
138 139
139 140 for (i = 0; i < NUM_COLS; i++) {
140 141 const char *name = col[i].col_name;
141 142 col[i].width = 0;
142 143
143 144 if (name != NULL) {
144 145 wchar_t wname[128];
145 146 size_t sz = mbstowcs(wname, name, sizeof (wname) /
146 147 sizeof (wchar_t));
147 148 if (sz > 0) {
148 149 int wcsw = wcswidth(wname, sz);
149 150 if (wcsw > 0)
150 151 col[i].width = wcsw;
151 152 else
152 153 col[i].width = sz;
153 154 } else {
154 155 col[i].width = strlen(name);
155 156 }
156 157 }
157 158 }
158 159 }
159 160
160 161 static void
161 162 count_widths(struct hdr_info *hdr, struct menu_lst *menu)
162 163 {
163 164 size_t len[NUM_COLS];
164 165 struct menu_entry *entry;
165 166 int i;
166 167
167 168 for (i = 0; i < NUM_COLS; i++)
168 169 len[i] = hdr->cols[i].width + 1;
169 170
170 171 STAILQ_FOREACH(entry, menu, next) {
171 172 size_t bootfs_len = strlen(entry->bootfs);
172 173 if (bootfs_len > len[2])
173 174 len[2] = bootfs_len + 1;
174 175 }
↓ open down ↓ |
136 lines elided |
↑ open up ↑ |
175 176
176 177 for (i = 0; i < NUM_COLS; i++)
177 178 hdr->cols[i].width = len[i];
178 179 }
179 180
180 181 static void
181 182 print_menu_nodes(boolean_t parsable, struct hdr_info *hdr,
182 183 struct menu_lst *menu)
183 184 {
184 185 struct menu_entry *entry;
185 - int i = -1;
186 + int i = 0;
186 187 int rv;
187 188 be_node_list_t *be_nodes, *be_node;
188 189
189 190 rv = be_list(NULL, &be_nodes);
190 191 if (rv != BE_SUCCESS)
191 192 return;
192 193
193 194 STAILQ_FOREACH(entry, menu, next) {
194 - i++;
195 + boolean_t active = B_FALSE;
196 +
195 197 for (be_node = be_nodes; be_node;
196 198 be_node = be_node->be_next_node)
197 199 if (strcmp(be_node->be_root_ds, entry->bootfs) == 0)
198 - break;
200 + if (be_node->be_active_on_boot)
201 + active = B_TRUE;
199 202
200 203 if (parsable)
201 204 (void) printf("%d;%s;%s;%s\n", i,
202 - be_node->be_active_on_boot == B_TRUE? "*" : "-",
205 + active == B_TRUE ? "*" : "-",
203 206 entry->bootfs, entry->title);
204 207 else
205 208 (void) printf("%-*d %-*s %-*s %-*s\n",
206 209 hdr->cols[0].width, i,
207 210 hdr->cols[1].width,
208 - be_node->be_active_on_boot == B_TRUE? "*" : "-",
211 + active == B_TRUE ? "*" : "-",
209 212 hdr->cols[2].width, entry->bootfs,
210 213 hdr->cols[3].width, entry->title);
214 +
215 + i++;
211 216 }
212 217 be_free_list(be_nodes);
213 218 }
214 219
215 220 static void
216 221 print_nodes(boolean_t parsable, struct menu_lst *menu)
217 222 {
218 223 struct hdr_info hdr;
219 224
220 225 if (!parsable) {
221 226 init_hdr_cols(&hdr);
222 227 count_widths(&hdr, menu);
223 228 print_hdr(&hdr);
224 229 }
225 230
226 231 print_menu_nodes(parsable, &hdr, menu);
227 232 }
228 233
229 234 error_t
230 235 menu_read(struct menu_lst *menu, char *menu_path)
231 236 {
232 237 FILE *fp;
233 238 struct menu_entry *mp;
234 239 char buf[PATH_MAX];
235 240 char *title;
236 241 char *bootfs;
237 242 char *ptr;
238 243 int i = 0;
239 244 int ret = BAM_SUCCESS;
240 245
241 246 fp = fopen(menu_path, "r");
242 247 if (fp == NULL)
243 248 return (BAM_ERROR);
244 249
245 250 /*
246 251 * menu.lst entry is on two lines, one for title, one for bootfs
247 252 * so we process both lines in succession.
248 253 */
249 254 do {
250 255 if (fgets(buf, PATH_MAX, fp) == NULL) {
251 256 if (!feof(fp))
252 257 ret = BAM_ERROR;
253 258 (void) fclose(fp);
254 259 return (ret);
255 260 }
256 261 ptr = strchr(buf, '\n');
257 262 if (ptr != NULL)
258 263 *ptr = '\0';
259 264
260 265 ptr = strchr(buf, ' ');
261 266 if (ptr == NULL) {
262 267 (void) fclose(fp);
263 268 return (BAM_ERROR);
264 269 }
265 270 *ptr++ = '\0';
266 271 if (strcmp(buf, "title") != 0) {
267 272 (void) fclose(fp);
268 273 return (BAM_ERROR);
269 274 }
270 275 if ((title = strdup(ptr)) == NULL) {
271 276 (void) fclose(fp);
272 277 return (BAM_ERROR);
273 278 }
274 279
275 280 if (fgets(buf, PATH_MAX, fp) == NULL) {
276 281 free(title);
277 282 (void) fclose(fp);
278 283 return (BAM_ERROR);
279 284 }
280 285
281 286 ptr = strchr(buf, '\n');
282 287 if (ptr != NULL)
283 288 *ptr = '\0';
284 289
285 290 ptr = strchr(buf, ' ');
286 291 if (ptr == NULL) {
287 292 free(title);
288 293 (void) fclose(fp);
289 294 return (BAM_ERROR);
290 295 }
291 296 *ptr++ = '\0';
292 297 if (strcmp(buf, "bootfs") != 0) {
293 298 free(title);
294 299 (void) fclose(fp);
295 300 return (BAM_ERROR);
296 301 }
297 302 if ((bootfs = strdup(ptr)) == NULL) {
298 303 free(title);
299 304 (void) fclose(fp);
300 305 return (BAM_ERROR);
301 306 }
302 307 if ((mp = malloc(sizeof (struct menu_entry))) == NULL) {
303 308 free(title);
304 309 free(bootfs);
305 310 (void) fclose(fp);
306 311 return (BAM_ERROR);
307 312 }
308 313 mp->entry = i++;
309 314 mp->title = title;
310 315 mp->bootfs = bootfs;
311 316 STAILQ_INSERT_TAIL(menu, mp, next);
312 317 } while (feof(fp) == 0);
313 318
314 319 (void) fclose(fp);
315 320 return (ret);
316 321 }
317 322
318 323 void
319 324 menu_free(struct menu_lst *menu)
320 325 {
321 326 struct menu_entry *entry;
322 327 STAILQ_FOREACH(entry, menu, next) {
323 328 STAILQ_REMOVE_HEAD(menu, next);
324 329 free(entry->title);
325 330 free(entry->bootfs);
326 331 free(entry);
327 332 }
328 333 }
329 334
330 335 error_t
331 336 bam_loader_menu(char *subcmd, char *opt, int largc, char *largv[])
332 337 {
333 338 error_t ret;
334 339 char menu_path[PATH_MAX];
335 340 char clean_menu_root[PATH_MAX];
336 341 char menu_root[PATH_MAX];
337 342 struct stat sb;
338 343 error_t (*f)(struct menu_lst *, char *, char *);
339 344 char *special;
340 345 char *pool = NULL;
341 346 zfs_mnted_t zmnted;
342 347 char *zmntpt;
343 348 char *osdev;
344 349 char *osroot;
345 350 const char *fcn = "bam_loader_menu()";
346 351 struct menu_lst menu = {0};
347 352
348 353 STAILQ_INIT(&menu);
349 354
350 355 /*
351 356 * Check arguments
352 357 */
353 358 ret = check_subcmd_and_options(subcmd, opt, menu_subcmds, &f);
354 359 if (ret == BAM_ERROR) {
355 360 return (BAM_ERROR);
356 361 }
357 362
358 363 assert(bam_root);
359 364
360 365 (void) strlcpy(menu_root, bam_root, sizeof (menu_root));
361 366 osdev = osroot = NULL;
362 367
363 368 if (strcmp(subcmd, "update_entry") == 0) {
364 369 assert(opt);
365 370
366 371 osdev = strtok(opt, ",");
367 372 assert(osdev);
368 373 osroot = strtok(NULL, ",");
369 374 if (osroot) {
370 375 /* fixup bam_root so that it points at osroot */
371 376 if (realpath(osroot, rootbuf) == NULL) {
372 377 bam_error(_("cannot resolve path %s: %s\n"),
373 378 osroot, strerror(errno));
374 379 return (BAM_ERROR);
375 380 }
376 381 bam_alt_root = 1;
377 382 bam_root = rootbuf;
378 383 bam_rootlen = strlen(rootbuf);
379 384 }
380 385 }
381 386
382 387 if (stat(menu_root, &sb) == -1) {
383 388 bam_error(_("cannot find menu\n"));
384 389 return (BAM_ERROR);
385 390 }
386 391
387 392 if (!is_zfs(menu_root)) {
388 393 bam_error(_("only ZFS root is supported\n"));
389 394 return (BAM_ERROR);
390 395 }
391 396
392 397 assert(strcmp(menu_root, bam_root) == 0);
393 398 special = get_special(menu_root);
394 399 INJECT_ERROR1("Z_MENU_GET_SPECIAL", special = NULL);
395 400 if (special == NULL) {
396 401 bam_error(_("cant find special file for mount-point %s\n"),
397 402 menu_root);
398 403 return (BAM_ERROR);
399 404 }
400 405 pool = strtok(special, "/");
401 406 INJECT_ERROR1("Z_MENU_GET_POOL", pool = NULL);
402 407 if (pool == NULL) {
403 408 free(special);
404 409 bam_error(_("cant find pool for mount-point %s\n"), menu_root);
405 410 return (BAM_ERROR);
406 411 }
407 412 BAM_DPRINTF(("%s: derived pool=%s from special\n", fcn, pool));
408 413
409 414 zmntpt = mount_top_dataset(pool, &zmnted);
410 415 INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt = NULL);
411 416 if (zmntpt == NULL) {
412 417 bam_error(_("cannot mount pool dataset for pool: %s\n"), pool);
413 418 free(special);
414 419 return (BAM_ERROR);
415 420 }
416 421 BAM_DPRINTF(("%s: top dataset mountpoint=%s\n", fcn, zmntpt));
417 422
418 423 (void) strlcpy(menu_root, zmntpt, sizeof (menu_root));
419 424 BAM_DPRINTF(("%s: zfs menu_root=%s\n", fcn, menu_root));
420 425
421 426 elide_trailing_slash(menu_root, clean_menu_root,
422 427 sizeof (clean_menu_root));
423 428
424 429 BAM_DPRINTF(("%s: cleaned menu root is <%s>\n", fcn, clean_menu_root));
425 430
426 431 (void) strlcpy(menu_path, clean_menu_root, sizeof (menu_path));
427 432 (void) strlcat(menu_path, MENU, sizeof (menu_path));
428 433
429 434 BAM_DPRINTF(("%s: menu path is: %s\n", fcn, menu_path));
430 435
431 436 /*
432 437 * update_entry is special case, its used by installer
433 438 * and needs to create menu.lst file for loader
434 439 */
435 440 if (menu_read(&menu, menu_path) == BAM_ERROR &&
436 441 strcmp(subcmd, "update_entry") != 0) {
437 442 bam_error(_("cannot find menu file: %s\n"), menu_path);
438 443 if (special != NULL)
439 444 free(special);
440 445 return (BAM_ERROR);
441 446 }
442 447
443 448 /*
444 449 * If listing the menu, display the menu location
445 450 */
446 451 if (strcmp(subcmd, "list_entry") == 0)
447 452 bam_print(_("the location for the active menu is: %s\n"),
448 453 menu_path);
449 454
450 455 /*
451 456 * We already checked the following case in
452 457 * check_subcmd_and_suboptions() above. Complete the
453 458 * final step now.
454 459 */
455 460 if (strcmp(subcmd, "set_option") == 0) {
456 461 assert(largc == 1 && largv[0] && largv[1] == NULL);
457 462 opt = largv[0];
458 463 } else if ((strcmp(subcmd, "enable_hypervisor") != 0) &&
459 464 (strcmp(subcmd, "list_setting") != 0)) {
460 465 assert(largc == 0 && largv == NULL);
461 466 }
462 467
463 468 /*
464 469 * Once the sub-cmd handler has run
465 470 * only the line field is guaranteed to have valid values
466 471 */
467 472 if (strcmp(subcmd, "update_entry") == 0) {
468 473 ret = f(&menu, menu_root, osdev);
469 474 } else if (strcmp(subcmd, "upgrade") == 0) {
470 475 ret = f(&menu, bam_root, menu_root);
471 476 } else if (strcmp(subcmd, "list_entry") == 0) {
472 477 ret = f(&menu, menu_path, opt);
473 478 } else if (strcmp(subcmd, "list_setting") == 0) {
474 479 ret = f(&menu, ((largc > 0) ? largv[0] : ""),
475 480 ((largc > 1) ? largv[1] : ""));
476 481 } else if (strcmp(subcmd, "disable_hypervisor") == 0) {
477 482 if (is_sparc()) {
478 483 bam_error(_("%s operation unsupported on SPARC "
479 484 "machines\n"), subcmd);
480 485 ret = BAM_ERROR;
481 486 } else {
482 487 ret = f(&menu, bam_root, NULL);
483 488 }
484 489 } else if (strcmp(subcmd, "enable_hypervisor") == 0) {
485 490 if (is_sparc()) {
486 491 bam_error(_("%s operation unsupported on SPARC "
487 492 "machines\n"), subcmd);
488 493 ret = BAM_ERROR;
489 494 } else {
490 495 char *extra_args = NULL;
491 496
492 497 /*
493 498 * Compress all arguments passed in the largv[] array
494 499 * into one string that can then be appended to the
495 500 * end of the kernel$ string the routine to enable the
496 501 * hypervisor will build.
497 502 *
498 503 * This allows the caller to supply arbitrary unparsed
499 504 * arguments, such as dom0 memory settings or APIC
500 505 * options.
501 506 *
502 507 * This concatenation will be done without ANY syntax
503 508 * checking whatsoever, so it's the responsibility of
504 509 * the caller to make sure the arguments are valid and
505 510 * do not duplicate arguments the conversion routines
506 511 * may create.
507 512 */
508 513 if (largc > 0) {
509 514 int extra_len, i;
510 515
511 516 for (extra_len = 0, i = 0; i < largc; i++)
512 517 extra_len += strlen(largv[i]);
513 518
514 519 /*
515 520 * Allocate space for argument strings,
516 521 * intervening spaces and terminating NULL.
517 522 */
518 523 extra_args = alloca(extra_len + largc);
519 524
520 525 (void) strcpy(extra_args, largv[0]);
521 526
522 527 for (i = 1; i < largc; i++) {
523 528 (void) strcat(extra_args, " ");
524 529 (void) strcat(extra_args, largv[i]);
525 530 }
526 531 }
527 532
528 533 ret = f(&menu, bam_root, extra_args);
529 534 }
530 535 } else
531 536 ret = f(&menu, NULL, opt);
532 537
533 538 if (ret == BAM_WRITE) {
534 539 BAM_DPRINTF(("%s: writing menu to clean-menu-root: <%s>\n",
535 540 fcn, clean_menu_root));
536 541 /* ret = menu_write(clean_menu_root, menu); */
537 542 }
538 543
539 544 INJECT_ERROR1("POOL_SET", pool = "/pooldata");
540 545 assert((is_zfs(menu_root)) ^ (pool == NULL));
541 546 if (pool) {
542 547 (void) umount_top_dataset(pool, zmnted, zmntpt);
543 548 free(special);
544 549 }
545 550
546 551 menu_free(&menu);
547 552 return (ret);
548 553 }
549 554
550 555 /*
551 556 * To suppress output from ficl. We do not want to see messages
552 557 * from interpreting loader config.
553 558 */
554 559
555 560 /*ARGSUSED*/
556 561 static void
557 562 ficlTextOutSilent(ficlCallback *cb, char *text)
558 563 {
559 564 }
560 565
561 566 /*ARGSUSED*/
562 567 static error_t
563 568 set_option(struct menu_lst *menu, char *dummy, char *opt)
564 569 {
565 570 char path[PATH_MAX];
566 571 char *val;
567 572 char *rest;
568 573 int optval;
569 574 struct menu_entry *entry;
570 575 nvlist_t *be_attrs;
571 576 FILE *fp;
572 577 int rv, ret = BAM_SUCCESS;
573 578
574 579 assert(menu);
575 580 assert(opt);
576 581 assert(dummy == NULL);
577 582
578 583 val = strchr(opt, '=');
579 584 if (val != NULL) {
580 585 *val++ = '\0';
581 586 }
582 587
583 588 if (strcmp(opt, "default") == 0) {
584 589 errno = 0;
585 590 optval = strtol(val, &rest, 10);
586 591 if (errno != 0 || *rest != '\0') {
587 592 bam_error(_("invalid boot entry number: %s\n"), val);
588 593 return (BAM_ERROR);
589 594 }
590 595 STAILQ_FOREACH(entry, menu, next) {
591 596 if (entry->entry == optval)
592 597 break;
593 598 }
594 599 if (entry == NULL) {
595 600 bam_error(_("invalid boot entry number: %s\n"), val);
596 601 return (BAM_ERROR);
597 602 }
598 603 if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
599 604 bam_error(_("out of memory\n"));
600 605 return (BAM_ERROR);
601 606 }
602 607 if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
603 608 entry->title) != 0) {
604 609 bam_error(_("out of memory\n"));
605 610 nvlist_free(be_attrs);
606 611 return (BAM_ERROR);
607 612 }
608 613 ret = be_activate(be_attrs);
609 614 nvlist_free(be_attrs);
610 615 if (ret != 0)
611 616 ret = BAM_ERROR;
612 617 return (ret);
613 618 } else if (strcmp(opt, "timeout") == 0) {
614 619 errno = 0;
615 620 optval = strtol(val, &rest, 10);
616 621 if (errno != 0 || *rest != '\0') {
617 622 bam_error(_("invalid timeout: %s\n"), val);
618 623 return (BAM_ERROR);
619 624 }
620 625
621 626 (void) snprintf(path, PATH_MAX, "%s" CONF_DIR "/timeout",
622 627 bam_root);
623 628
624 629 fp = fopen(path, "w");
625 630 if (fp == NULL) {
626 631 bam_error(_("failed to open file: %s: %s\n"),
627 632 path, strerror(errno));
628 633 return (BAM_ERROR);
629 634 }
630 635 /*
631 636 * timeout=-1 is to disable auto boot in illumos, but
632 637 * loader needs "NO" to disable auto boot.
633 638 */
634 639 if (optval == -1)
635 640 rv = fprintf(fp, "autoboot_delay=\"NO\"\n");
636 641 else
637 642 rv = fprintf(fp, "autoboot_delay=\"%d\"\n", optval);
638 643
639 644 if (rv < 0) {
640 645 bam_error(_("write to file failed: %s: %s\n"),
641 646 path, strerror(errno));
642 647 (void) fclose(fp);
643 648 ret = BAM_ERROR;
644 649 } else
645 650 rv = fclose(fp);
646 651
647 652 if (rv < 0) {
648 653 bam_error(_("failed to close file: %s: %s\n"),
649 654 path, strerror(errno));
650 655 ret = BAM_ERROR;
651 656 }
652 657 if (ret == BAM_ERROR)
653 658 (void) unlink(path);
654 659
655 660 return (BAM_SUCCESS);
656 661 }
657 662
658 663 bam_error(_("invalid option: %s\n"), opt);
659 664 return (BAM_ERROR);
660 665 }
661 666
662 667 static int
663 668 bam_mount_be(struct menu_entry *entry, char **dir)
664 669 {
665 670 nvlist_t *be_attrs = NULL;
666 671 const char *tmpdir = getenv("TMPDIR");
667 672 const char *tmpname = "bam.XXXXXX";
668 673 be_node_list_t *be_node, *be_nodes = NULL;
669 674 int ret;
670 675
671 676 *dir = NULL;
672 677 if (tmpdir == NULL)
673 678 tmpdir = "/tmp";
674 679
675 680 ret = asprintf(dir, "%s/%s", tmpdir, tmpname);
676 681 if (ret < 0) {
677 682 return (BE_ERR_NOMEM);
678 683 }
679 684 *dir = mkdtemp(*dir);
680 685
681 686 if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
682 687 ret = BE_ERR_NOMEM;
683 688 goto out;
684 689 }
685 690
686 691 ret = be_list(NULL, &be_nodes);
687 692 if (ret != BE_SUCCESS) {
688 693 goto out;
689 694 }
690 695
691 696 for (be_node = be_nodes; be_node;
692 697 be_node = be_node->be_next_node)
693 698 if (strcmp(be_node->be_root_ds, entry->bootfs) == 0)
694 699 break;
695 700
696 701 if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
697 702 be_node->be_node_name) != 0) {
698 703 ret = BE_ERR_NOMEM;
699 704 goto out;
700 705 }
701 706
702 707 if (nvlist_add_string(be_attrs, BE_ATTR_MOUNTPOINT, *dir) != 0) {
703 708 ret = BE_ERR_NOMEM;
704 709 goto out;
705 710 }
706 711
707 712 ret = be_mount(be_attrs);
708 713 if (ret == BE_ERR_MOUNTED) {
709 714 /*
710 715 * if BE is mounted, dir does not point to correct directory
711 716 */
712 717 (void) rmdir(*dir);
713 718 free(*dir);
714 719 *dir = NULL;
715 720 }
716 721 out:
717 722 if (be_nodes != NULL)
718 723 be_free_list(be_nodes);
719 724 nvlist_free(be_attrs);
720 725 return (ret);
721 726 }
722 727
723 728 static int
724 729 bam_umount_be(char *dir)
725 730 {
726 731 nvlist_t *be_attrs;
727 732 int ret;
728 733
729 734 if (dir == NULL) /* nothing to do */
730 735 return (BE_SUCCESS);
731 736
732 737 if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0)
733 738 return (BE_ERR_NOMEM);
734 739
735 740 if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, dir) != 0) {
736 741 ret = BE_ERR_NOMEM;
737 742 goto out;
738 743 }
739 744
740 745 ret = be_unmount(be_attrs);
741 746 out:
742 747 nvlist_free(be_attrs);
743 748 return (ret);
744 749 }
745 750
746 751 /*
747 752 * display details of menu entry or single property
748 753 */
749 754 static error_t
750 755 list_menu_entry(struct menu_entry *entry, char *setting)
751 756 {
752 757 int ret = BAM_SUCCESS;
753 758 char *ptr, *dir;
754 759 char buf[MAX_INPUT];
755 760 ficlVm *vm;
756 761 int mounted;
757 762
758 763 mounted = bam_mount_be(entry, &dir);
759 764 if (mounted != BE_SUCCESS && mounted != BE_ERR_MOUNTED) {
760 765 if (dir != NULL) {
761 766 (void) rmdir(dir);
762 767 free(dir);
763 768 }
764 769 bam_error(_("%s is not mounted\n"), entry->title);
765 770 return (BAM_ERROR);
766 771 }
767 772
768 773 vm = bf_init("", ficlTextOutSilent);
769 774 if (vm == NULL) {
770 775 bam_error(_("error setting up forth interpreter\n"));
771 776 ret = BAM_ERROR;
772 777 goto done;
773 778 }
774 779
775 780 /* should only get FICL_VM_STATUS_OUT_OF_TEXT */
776 781 (void) snprintf(buf, MAX_INPUT, "set currdev=zfs:%s:",
777 782 entry->bootfs);
778 783 ret = ficlVmEvaluate(vm, buf);
779 784 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
780 785 bam_error(_("error interpreting boot config\n"));
781 786 ret = BAM_ERROR;
782 787 goto done;
783 788 }
784 789 (void) snprintf(buf, MAX_INPUT, "include /boot/forth/loader.4th");
785 790 ret = ficlVmEvaluate(vm, buf);
786 791 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
787 792 bam_error(_("error interpreting boot config\n"));
788 793 ret = BAM_ERROR;
789 794 goto done;
790 795 }
791 796 (void) snprintf(buf, MAX_INPUT, "start");
792 797 ret = ficlVmEvaluate(vm, buf);
793 798 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
794 799 bam_error(_("error interpreting boot config\n"));
795 800 ret = BAM_ERROR;
796 801 goto done;
797 802 }
798 803 (void) snprintf(buf, MAX_INPUT, "boot");
799 804 ret = ficlVmEvaluate(vm, buf);
800 805 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
801 806 bam_error(_("error interpreting boot config\n"));
802 807 ret = BAM_ERROR;
803 808 goto done;
804 809 }
805 810
806 811 ret = BAM_SUCCESS;
807 812 if (*setting == '\0')
808 813 (void) printf("\nTitle: %s\n", entry->title);
809 814 else if (strcasecmp(setting, "title") == 0) {
810 815 (void) printf("%s\n", entry->title);
811 816 goto done;
812 817 }
813 818
814 819 ptr = getenv("autoboot_delay");
815 820 if (ptr != NULL) {
816 821 char *timeout = "-1";
817 822
818 823 if (strcasecmp(ptr, "NO") != 0)
819 824 timeout = ptr;
820 825
821 826 if (*setting == '\0')
822 827 (void) printf("Timeout: %s\n", timeout);
823 828 else if (strcasecmp(setting, "timeout") == 0) {
824 829 (void) printf("%s\n", timeout);
825 830 goto done;
826 831 }
827 832
828 833 }
829 834 ptr = getenv("console");
830 835 if (ptr != NULL) {
831 836 if (*setting == '\0')
832 837 (void) printf("Console: %s\n", ptr);
833 838 else if (strcasecmp(setting, "console") == 0) {
834 839 (void) printf("%s\n", ptr);
835 840 goto done;
836 841 }
837 842 }
838 843
839 844 if (*setting == '\0')
840 845 (void) printf("Bootfs: %s\n", entry->bootfs);
841 846 else if (strcasecmp(setting, "bootfs") == 0) {
842 847 (void) printf("%s\n", entry->bootfs);
843 848 goto done;
844 849 }
845 850
846 851 ptr = getenv("xen_kernel");
847 852 if (ptr != NULL) {
848 853 if (*setting == '\0') {
849 854 (void) printf("Xen kernel: %s\n", ptr);
850 855 } else if (strcasecmp(setting, "xen_kernel") == 0) {
851 856 (void) printf("%s\n", ptr);
852 857 goto done;
853 858 }
854 859
855 860 if (*setting == '\0') {
856 861 (void) printf("Xen args: \"%s\"\n",
857 862 getenv("xen_cmdline"));
858 863 } else if (strcasecmp(setting, "xen_cmdline") == 0) {
859 864 (void) printf("%s\n", getenv("xen_cmdline"));
860 865 goto done;
861 866 }
862 867
863 868 if (*setting == '\0') {
864 869 (void) printf("Kernel: %s\n",
865 870 getenv("bootfile"));
866 871 } if (strcasecmp(setting, "kernel") == 0) {
867 872 (void) printf("%s\n", getenv("bootfile"));
868 873 goto done;
869 874 }
870 875 } else {
871 876 ptr = getenv("kernelname");
872 877 if (ptr != NULL) {
873 878 if (*setting == '\0') {
874 879 (void) printf("Kernel: %s\n", ptr);
875 880 } else if (strcasecmp(setting, "kernel") == 0) {
876 881 (void) printf("%s\n", ptr);
877 882 goto done;
878 883 }
879 884 }
880 885 }
881 886
882 887 ptr = getenv("boot-args");
883 888 if (ptr != NULL) {
884 889 if (*setting == '\0') {
885 890 (void) printf("Boot-args: \"%s\"\n", ptr);
886 891 } else if (strcasecmp(setting, "boot-args") == 0) {
887 892 (void) printf("%s\n", ptr);
888 893 goto done;
889 894 }
890 895 }
891 896
892 897 if (*setting == '\0' || strcasecmp(setting, "modules") == 0) {
893 898 (void) printf("\nModules:\n");
894 899 ficlVmSetTextOut(vm, ficlCallbackDefaultTextOut);
895 900 (void) snprintf(buf, MAX_INPUT, "show-module-options");
896 901 ret = ficlVmEvaluate(vm, buf);
897 902 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
898 903 bam_error(_("error interpreting boot config\n"));
899 904 ret = BAM_ERROR;
900 905 goto done;
901 906 }
902 907 ret = BAM_SUCCESS;
903 908 goto done;
904 909 }
905 910
906 911 /* if we got here with setting string, its unknown property */
907 912 if (*setting != '\0') {
908 913 bam_error(_("unknown property: %s\n"), setting);
909 914 ret = BAM_ERROR;
910 915 } else
911 916 ret = BAM_SUCCESS;
912 917 done:
913 918 bf_fini();
914 919 if (mounted != BE_ERR_MOUNTED) {
915 920 (void) bam_umount_be(dir);
916 921 }
917 922
918 923 if (dir != NULL) {
919 924 (void) rmdir(dir);
920 925 free(dir);
921 926 }
922 927
923 928 return (ret);
924 929 }
925 930
926 931 /*ARGSUSED*/
927 932 static error_t
928 933 list_entry(struct menu_lst *menu, char *menu_root, char *opt)
929 934 {
930 935 error_t ret = BAM_SUCCESS;
931 936 struct menu_entry *entry;
932 937 char *ptr, *title = NULL;
933 938 int i, e = -1;
934 939
935 940 if (opt == NULL) {
936 941 print_nodes(B_FALSE, menu);
937 942 return (ret);
938 943 }
939 944
940 945 if ((ptr = strchr(opt, '=')) == NULL) {
941 946 bam_error(_("invalid option: %s\n"), opt);
942 947 return (BAM_ERROR);
943 948 }
944 949
945 950 i = ptr - opt;
946 951 if (strncmp(opt, "entry", i) == 0) {
947 952 e = atoi(ptr+1);
948 953 } else if (strncmp(opt, "title", i) == 0) {
949 954 title = ptr+1;
950 955 } else {
951 956 bam_error(_("invalid option: %s\n"), opt);
952 957 return (BAM_ERROR);
953 958 }
954 959
955 960 STAILQ_FOREACH(entry, menu, next) {
956 961 if (title != NULL) {
957 962 if (strcmp(title, entry->title) == 0)
958 963 break;
959 964 } else if (entry->entry == e)
960 965 break;
961 966 }
962 967
963 968 if (entry == NULL) {
964 969 bam_error(_("no matching entry found\n"));
965 970 return (BAM_ERROR);
966 971 }
967 972
968 973 return (list_menu_entry(entry, ""));
969 974 }
970 975
971 976 /*
972 977 * For now this is just stub entry to support grub interface, the
973 978 * known consumer is installer ict.py code, calling as:
974 979 * bootadm update-menu -R /a -Z -o rdisk
975 980 * Later this can be converted to do something useful.
976 981 */
977 982 /*ARGSUSED*/
978 983 static error_t
979 984 update_entry(struct menu_lst *menu, char *menu_root, char *osdev)
980 985 {
981 986 char path[PATH_MAX];
982 987 char *pool = menu_root + 1;
983 988 be_node_list_t *be_nodes, *be_node;
984 989 int rv;
985 990 FILE *fp;
986 991
987 992 (void) snprintf(path, PATH_MAX, "%s%s", menu_root, MENU);
988 993 rv = be_list(NULL, &be_nodes);
989 994
990 995 if (rv != BE_SUCCESS)
991 996 return (BAM_ERROR);
992 997
993 998 fp = fopen(path, "w");
994 999 if (fp == NULL) {
995 1000 be_free_list(be_nodes);
996 1001 return (BAM_ERROR);
997 1002 }
998 1003
999 1004 for (be_node = be_nodes; be_node; be_node = be_node->be_next_node) {
1000 1005 if (strcmp(be_node->be_rpool, pool) == 0) {
1001 1006 (void) fprintf(fp, "title %s\n", be_node->be_node_name);
1002 1007 (void) fprintf(fp, "bootfs %s\n", be_node->be_root_ds);
1003 1008 }
1004 1009 }
1005 1010
1006 1011 be_free_list(be_nodes);
1007 1012 (void) fclose(fp);
1008 1013 return (BAM_SUCCESS);
1009 1014 }
1010 1015
1011 1016 /*ARGSUSED*/
1012 1017 static error_t
1013 1018 update_temp(struct menu_lst *menu, char *dummy, char *opt)
1014 1019 {
1015 1020 error_t ret = BAM_ERROR;
1016 1021 char path[PATH_MAX];
1017 1022 char buf[MAX_INPUT];
1018 1023 struct mnttab mpref = { 0 };
1019 1024 struct mnttab mp = { 0 };
1020 1025 ficlVm *vm;
1021 1026 char *env, *o;
1022 1027 FILE *fp;
1023 1028
1024 1029 (void) snprintf(path, PATH_MAX, "%s" TRANSIENT, bam_root);
1025 1030 /*
1026 1031 * if opt == NULL, remove transient config
1027 1032 */
1028 1033 if (opt == NULL) {
1029 1034 (void) unlink(path);
1030 1035 return (BAM_SUCCESS);
1031 1036 }
1032 1037
1033 1038 fp = fopen(MNTTAB, "r");
1034 1039 if (fp == NULL)
1035 1040 return (BAM_ERROR);
1036 1041
1037 1042 mpref.mnt_mountp = "/";
1038 1043 if (getmntany(fp, &mp, &mpref) != 0) {
1039 1044 (void) fclose(fp);
1040 1045 return (BAM_ERROR);
1041 1046 }
1042 1047 (void) fclose(fp);
1043 1048
1044 1049 vm = bf_init("", ficlTextOutSilent);
1045 1050 if (vm == NULL) {
1046 1051 bam_error(_("Error setting up forth interpreter\n"));
1047 1052 return (ret);
1048 1053 }
1049 1054
1050 1055 /*
1051 1056 * need to check current boot config, so fire up the ficl
1052 1057 * if its xen setup, we add option to boot-args list, not replacing it.
1053 1058 */
1054 1059 (void) snprintf(buf, MAX_INPUT, "set currdev=zfs:%s:", mp.mnt_special);
1055 1060 ret = ficlVmEvaluate(vm, buf);
1056 1061 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1057 1062 bam_error(_("Error interpreting boot config\n"));
1058 1063 bf_fini();
1059 1064 return (BAM_ERROR);
1060 1065 }
1061 1066 (void) snprintf(buf, MAX_INPUT, "include /boot/forth/loader.4th");
1062 1067 ret = ficlVmEvaluate(vm, buf);
1063 1068 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1064 1069 bam_error(_("Error interpreting boot config\n"));
1065 1070 bf_fini();
1066 1071 return (BAM_ERROR);
1067 1072 }
1068 1073 (void) snprintf(buf, MAX_INPUT, "start");
1069 1074 ret = ficlVmEvaluate(vm, buf);
1070 1075 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1071 1076 bam_error(_("Error interpreting boot config\n"));
1072 1077 bf_fini();
1073 1078 return (BAM_ERROR);
1074 1079 }
1075 1080 (void) snprintf(buf, MAX_INPUT, "boot");
1076 1081 ret = ficlVmEvaluate(vm, buf);
1077 1082 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1078 1083 bam_error(_("Error interpreting boot config\n"));
1079 1084 bf_fini();
1080 1085 return (BAM_ERROR);
1081 1086 }
1082 1087 bf_fini();
1083 1088
1084 1089 if (opt[0] == '-') {
1085 1090 env = getenv("xen_kernel");
1086 1091 fp = fopen(path, "w");
1087 1092 if (fp == NULL)
1088 1093 return (BAM_ERROR);
1089 1094
1090 1095 if (env != NULL) {
1091 1096 env = getenv("boot-args");
1092 1097 (void) fprintf(fp, "boot-args=\"%s %s\"\n", env, opt);
1093 1098 } else
1094 1099 (void) fprintf(fp, "boot-args=\"%s\"\n", opt);
1095 1100 (void) fclose(fp);
1096 1101 return (BAM_SUCCESS);
1097 1102 }
1098 1103
1099 1104 /*
1100 1105 * it should be the case with "kernel args"
1101 1106 * so, we split the opt at first space
1102 1107 * and store bootfile= and boot-args=
1103 1108 */
1104 1109 env = getenv("xen_kernel");
1105 1110
1106 1111 o = strchr(opt, ' ');
1107 1112 if (o == NULL) {
1108 1113 fp = fopen(path, "w");
1109 1114 if (fp == NULL)
1110 1115 return (BAM_ERROR);
1111 1116 (void) fprintf(fp, "bootfile=\"%s\"\n", opt);
1112 1117 (void) fclose(fp);
1113 1118 return (BAM_SUCCESS);
1114 1119 }
1115 1120 *o++ = '\0';
1116 1121 fp = fopen(path, "w");
1117 1122 if (fp == NULL)
1118 1123 return (BAM_ERROR);
1119 1124 (void) fprintf(fp, "bootfile=\"%s\"\n", opt);
1120 1125
1121 1126 if (env != NULL) {
1122 1127 env = getenv("boot-args");
1123 1128 (void) fprintf(fp, "boot-args=\"%s %s\"\n", env, opt);
1124 1129 } else
1125 1130 (void) fprintf(fp, "boot-args=\"%s\"\n", o);
1126 1131
1127 1132 (void) fflush(fp);
1128 1133 (void) fclose(fp);
1129 1134 return (ret);
1130 1135 }
1131 1136
1132 1137 static error_t
1133 1138 list_setting(struct menu_lst *menu, char *which, char *setting)
1134 1139 {
1135 1140 int entry = -1;
1136 1141 struct menu_entry *m;
1137 1142 be_node_list_t *be_nodes, *be_node = NULL;
1138 1143 int ret;
1139 1144
1140 1145 assert(which);
1141 1146 assert(setting);
1142 1147
1143 1148 /*
1144 1149 * which can be:
1145 1150 * "" - list default entry
1146 1151 * number - use for entry number
1147 1152 * property name
1148 1153 */
1149 1154 if (*which != '\0') {
1150 1155 if (isdigit(*which)) {
1151 1156 char *rest;
1152 1157 errno = 0;
1153 1158 entry = strtol(which, &rest, 10);
1154 1159 if (errno != 0 || *rest != '\0') {
1155 1160 bam_error(_("invalid boot entry number: %s\n"),
1156 1161 which);
1157 1162 return (BAM_ERROR);
1158 1163 }
1159 1164 } else
1160 1165 setting = which;
1161 1166 }
1162 1167
1163 1168 /* find default entry */
1164 1169 if (entry == -1) {
1165 1170 ret = be_list(NULL, &be_nodes);
1166 1171 if (ret != BE_SUCCESS) {
1167 1172 bam_error(_("No BE's found\n"));
1168 1173 return (BAM_ERROR);
1169 1174 }
1170 1175 STAILQ_FOREACH(m, menu, next) {
1171 1176 entry++;
1172 1177 for (be_node = be_nodes; be_node;
1173 1178 be_node = be_node->be_next_node)
1174 1179 if (strcmp(be_node->be_root_ds, m->bootfs) == 0)
1175 1180 break;
1176 1181 if (be_node->be_active_on_boot == B_TRUE)
1177 1182 break; /* found active node */
1178 1183 }
1179 1184 be_free_list(be_nodes);
1180 1185 if (be_node == NULL) {
1181 1186 bam_error(_("None of BE nodes is marked active\n"));
1182 1187 return (BAM_ERROR);
1183 1188 }
1184 1189 } else {
1185 1190 STAILQ_FOREACH(m, menu, next)
1186 1191 if (m->entry == entry)
1187 1192 break;
1188 1193
1189 1194 if (m == NULL) {
1190 1195 bam_error(_("no matching entry found\n"));
1191 1196 return (BAM_ERROR);
1192 1197 }
1193 1198 }
1194 1199
1195 1200 return (list_menu_entry(m, setting));
1196 1201 }
1197 1202
1198 1203 /*ARGSUSED*/
1199 1204 static error_t
1200 1205 disable_hyper(struct menu_lst *menu, char *osroot, char *opt)
1201 1206 {
1202 1207 char path[PATH_MAX];
1203 1208
1204 1209 (void) snprintf(path, PATH_MAX, "%s" XEN_CONFIG, bam_root);
1205 1210 (void) unlink(path);
1206 1211 return (BAM_SUCCESS);
1207 1212 }
1208 1213
1209 1214 /*ARGSUSED*/
1210 1215 static error_t
1211 1216 enable_hyper(struct menu_lst *menu, char *osroot, char *opt)
1212 1217 {
1213 1218 ficlVm *vm;
1214 1219 char path[PATH_MAX];
1215 1220 char buf[MAX_INPUT];
1216 1221 char *env;
1217 1222 FILE *fp;
1218 1223 struct mnttab mpref = { 0 };
1219 1224 struct mnttab mp = { 0 };
1220 1225 int ret;
1221 1226
1222 1227 fp = fopen(MNTTAB, "r");
1223 1228 if (fp == NULL)
1224 1229 return (BAM_ERROR);
1225 1230
1226 1231 mpref.mnt_mountp = "/";
1227 1232 if (getmntany(fp, &mp, &mpref) != 0) {
1228 1233 (void) fclose(fp);
1229 1234 return (BAM_ERROR);
1230 1235 }
1231 1236 (void) fclose(fp);
1232 1237
1233 1238 vm = bf_init("", ficlTextOutSilent);
1234 1239 if (vm == NULL) {
1235 1240 bam_error(_("Error setting up forth interpreter\n"));
1236 1241 return (BAM_ERROR);
1237 1242 }
1238 1243
1239 1244 /*
1240 1245 * need to check current boot config, so fire up the ficl
1241 1246 * if its xen setup, we add option to boot-args list, not replacing it.
1242 1247 */
1243 1248 (void) snprintf(buf, MAX_INPUT, "set currdev=zfs:%s:", mp.mnt_special);
1244 1249 ret = ficlVmEvaluate(vm, buf);
1245 1250 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1246 1251 bam_error(_("Error interpreting boot config\n"));
1247 1252 bf_fini();
1248 1253 return (BAM_ERROR);
1249 1254 }
1250 1255 (void) snprintf(buf, MAX_INPUT, "include /boot/forth/loader.4th");
1251 1256 ret = ficlVmEvaluate(vm, buf);
1252 1257 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1253 1258 bam_error(_("Error interpreting boot config\n"));
1254 1259 bf_fini();
1255 1260 return (BAM_ERROR);
1256 1261 }
1257 1262 (void) snprintf(buf, MAX_INPUT, "start");
1258 1263 ret = ficlVmEvaluate(vm, buf);
1259 1264 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1260 1265 bam_error(_("Error interpreting boot config\n"));
1261 1266 bf_fini();
1262 1267 return (BAM_ERROR);
1263 1268 }
1264 1269 (void) snprintf(buf, MAX_INPUT, "boot");
1265 1270 ret = ficlVmEvaluate(vm, buf);
1266 1271 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1267 1272 bam_error(_("Error interpreting boot config\n"));
1268 1273 bf_fini();
1269 1274 return (BAM_ERROR);
1270 1275 }
1271 1276 bf_fini();
1272 1277
1273 1278 (void) mkdir(CONF_DIR, 0755);
1274 1279 (void) snprintf(path, PATH_MAX, "%s" XEN_CONFIG, bam_root);
1275 1280 fp = fopen(path, "w");
1276 1281 if (fp == NULL) {
1277 1282 return (BAM_ERROR); /* error, cant write config */
1278 1283 }
1279 1284
1280 1285 errno = 0;
1281 1286 /*
1282 1287 * on write error, remove file to ensure we have bootable config.
1283 1288 * note we dont mind if config exists, it will get updated
1284 1289 */
1285 1290 (void) fprintf(fp, "xen_kernel=\"/boot/${ISADIR}/xen\"\n");
1286 1291 if (errno != 0)
1287 1292 goto error;
1288 1293
1289 1294 /*
1290 1295 * really simple and stupid console conversion.
1291 1296 * it really has to be gone, it belongs to milestone/xvm properties.
1292 1297 */
1293 1298 env = getenv("console");
1294 1299 if (env != NULL) {
1295 1300 if (strcmp(env, "ttya") == 0)
1296 1301 (void) fprintf(fp, "xen_cmdline=\"console=com1 %s\"\n",
1297 1302 opt);
1298 1303 else if (strcmp(env, "ttyb") == 0)
1299 1304 (void) fprintf(fp, "xen_cmdline=\"console=com2 %s\"\n",
1300 1305 opt);
1301 1306 else
1302 1307 (void) fprintf(fp, "xen_cmdline=\"console=vga %s\"\n",
1303 1308 opt);
1304 1309 } else
1305 1310 (void) fprintf(fp, "xen_cmdline=\"%s\"\n", opt);
1306 1311 if (errno != 0)
1307 1312 goto error;
1308 1313
1309 1314 (void) fprintf(fp,
1310 1315 "bootfile=\"/platform/i86xpv/kernel/${ISADIR}/unix\"\n");
1311 1316 if (errno != 0)
1312 1317 goto error;
1313 1318
1314 1319 (void) fprintf(fp,
1315 1320 "boot-args=\"/platform/i86xpv/kernel/${ISADIR}/unix\"\n");
1316 1321 if (errno != 0)
1317 1322 goto error;
1318 1323
1319 1324 (void) fclose(fp);
1320 1325 if (errno != 0) {
1321 1326 (void) unlink(path);
1322 1327 return (BAM_ERROR);
1323 1328 }
1324 1329 return (BAM_SUCCESS);
1325 1330 error:
1326 1331 (void) fclose(fp);
1327 1332 (void) unlink(path);
1328 1333 return (BAM_ERROR);
1329 1334 }
↓ open down ↓ |
1109 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX