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 2012, Daniil Lunev. All rights reserved. 23 */ 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 #include <getopt.h> 29 #include <assert.h> 30 #include "grubadm.h" 31 #include "error.h" 32 #include "menu.h" 33 34 menu_list get_arg = { 0 }; 35 menu_list find_arg = { 0 }; 36 menu_list set_arg = { 0 }; 37 int get_timeout = 0; 38 int get_default = 0; 39 int get_serial = 0; 40 int get_terminal = 0; 41 int lst_flag = 0; 42 int new_flag = 0; 43 int all_flag = 0; 44 int del_flag = 0; 45 int fnd_flag = 0; 46 int hlp_flag = 0; 47 int get_flag = 0; 48 int set_flag = 0; 49 int cln_flag = 0; 50 int clr_flag = 0; 51 int enh_flag = 0; 52 int dih_flag = 0; 53 int num_flag = 0; 54 int number; 55 char * set_timeout = NULL; 56 char * set_default = NULL; 57 char * set_serial = NULL; 58 char * set_terminal = NULL; 59 char * alt_root = NULL; 60 61 static char opt_string[] = "landh?R:"; 62 static const struct option options[] = { 63 { "list", no_argument, NULL, 'l' }, 64 { "all", no_argument, NULL, 'a' }, 65 { "new", no_argument, NULL, 'n' }, 66 { "delete", no_argument, NULL, 'd' }, 67 { "help", no_argument, NULL, 'h' }, 68 { "name", required_argument, NULL, 4 }, 69 { "pool", required_argument, NULL, 5 }, 70 { "uuid", required_argument, NULL, 6 }, 71 { "dataset", required_argument, NULL, 7 }, 72 { "kernel", required_argument, NULL, 8 }, 73 { "module", required_argument, NULL, 9 }, 74 { "set-name", required_argument, NULL, 10 }, 75 { "set-pool", required_argument, NULL, 11 }, 76 { "set-uuid", required_argument, NULL, 12 }, 77 { "set-dataset", required_argument, NULL, 13 }, 78 { "set-kernel", required_argument, NULL, 14 }, 79 { "set-opts", required_argument, NULL, 15 }, 80 { "set-module", required_argument, NULL, 16 }, 81 { "set-default", required_argument, NULL, 17 }, 82 { "set-timeout", required_argument, NULL, 18 }, 83 { "get-name", no_argument, NULL, 19 }, 84 { "get-pool", no_argument, NULL, 20 }, 85 { "get-uuid", no_argument, NULL, 21 }, 86 { "get-dataset", no_argument, NULL, 22 }, 87 { "get-kernel", no_argument, NULL, 23 }, 88 { "get-opts", no_argument, NULL, 24 }, 89 { "get-modules", no_argument, NULL, 25 }, 90 { "get-default", no_argument, NULL, 26 }, 91 { "get-timeout", no_argument, NULL, 27 }, 92 { "get-all", no_argument, NULL, 28 }, 93 { "alt-root", required_argument, NULL, 'R' }, 94 { "default", no_argument, NULL, 30 }, 95 { "set-serial", required_argument, NULL, 31 }, 96 { "set-terminal", required_argument, NULL, 32 }, 97 { "get-serial", no_argument, NULL, 33 }, 98 { "get-terminal", no_argument, NULL, 34 }, 99 { "clone", no_argument, NULL, 35 }, 100 { "enable-hyper", no_argument, NULL, 36 }, 101 { "disable-hyper", no_argument, NULL, 37 }, 102 { "clear", no_argument, NULL, 38 }, 103 { "number", required_argument, NULL, 39 }, 104 { NULL, no_argument, NULL, 0 }, 105 }; 106 107 static void 108 usage () 109 { 110 printf ( 111 "Usage:\n" 112 "--list list all entries\n" 113 "--all apply actions to all appropriate entries\n" 114 "--new create new entry\n" 115 "--delete delete entry\n" 116 "--clone clone existing entry\n" 117 "--default set default entry properties\n" 118 "--help show this message\n" 119 "--number <opt> find entry by number (-1 = default entry)\n" 120 "--name <opt> find entry by name\n" 121 "--pool <opt> by pool name\n" 122 "--uuid <opt> by uuid\n" 123 "--dataset <opt> by dataset\n" 124 "--kernel <opt> by kernel\n" 125 "--module <opt> by module\n" 126 "--set-name <opt> set new name to entry\n" 127 "--set-pool <opt>\n" 128 "--set-uuid <opt>\n" 129 "--set-kernel <opt>\n" 130 "--set-opts <opt>\n" 131 "--set-module <opt>\n" 132 "--set-default <opt>\n" 133 "--set-timeout <opt>\n" 134 "--get-name get entry name\n" 135 "--get-pool\n" 136 "--get-uuid\n" 137 "--get-kernel\n" 138 "--get-opts\n" 139 "--get-module\n" 140 "--get-default\n" 141 "--get-timeout\n" 142 "--get-all retrieve all params of entry\n" 143 "--alt-root <opt> alternate root directory\n" 144 "--default set default fields value to entry\n" 145 "--set-serial set params of serial port\n" 146 "--set-terminal set default terminal\n" 147 "--get-serial get params of serial port" 148 "--get-terminal get default terminal\n" 149 "--enable-hyper convert entry to boot with xen\n" 150 "--disable-hyper convert entry to normal boot\n" 151 "--clear delete all entries\n" 152 ); 153 } 154 155 static char * 156 get_pool (const char * file) 157 { 158 char buf[MAX_STRING_SIZE]; 159 char * tmp; 160 FILE * pipe; 161 162 const char fnc[] = "get_pool"; 163 164 debug_print ("%s\narg: %s\n", fnc, file); 165 166 strcpy (buf, "/usr/bin/df -h "); 167 strcat (buf, file); 168 169 pipe = popen (buf, "r"); 170 if (! pipe) 171 return NULL; 172 173 fgets (buf, MAX_STRING_SIZE, pipe); 174 if (! fgets (buf, MAX_STRING_SIZE, pipe)) { 175 pclose (pipe); 176 return NULL; 177 } 178 179 pclose (pipe); 180 tmp = strchr (buf, '/'); 181 *tmp = 0; 182 tmp = strdup (buf); 183 return tmp; 184 } 185 186 static int 187 parse_args (int argc, char ** argv) 188 { 189 int opt = 0; 190 int index; 191 192 const char fnc[] = "parse_args"; 193 194 debug_print ("%s\n", fnc); 195 196 while ((opt = getopt_long (argc, argv, opt_string, options, &index)) != -1) { 197 switch (opt) { 198 case 'a': 199 ++all_flag; 200 break; 201 case 'd': 202 ++del_flag; 203 break; 204 case 'l': 205 ++lst_flag; 206 break; 207 case 'n': 208 ++new_flag; 209 break; 210 case 'h': 211 case '?': 212 ++hlp_flag; 213 break; 214 case 4: 215 ++fnd_flag; 216 strcpy (find_arg.entry.entry_name, optarg); 217 break; 218 case 5: 219 ++fnd_flag; 220 strcpy (find_arg.entry.pool_label, optarg); 221 break; 222 case 6: 223 ++fnd_flag; 224 strcpy (find_arg.entry.pool_uuid, optarg); 225 break; 226 case 7: 227 ++fnd_flag; 228 strcpy (find_arg.entry.dataset, optarg); 229 break; 230 case 8: 231 ++fnd_flag; 232 strcpy (find_arg.entry.kernel, optarg); 233 break; 234 case 9: 235 ++fnd_flag; 236 find_arg.entry.modules[(find_arg.entry.modules_amount)++] = strdup (optarg); 237 break; 238 case 10: 239 ++set_flag; 240 strcpy (set_arg.entry.entry_name, optarg); 241 break; 242 case 11: 243 ++set_flag; 244 strcpy (set_arg.entry.pool_label, optarg); 245 break; 246 case 12: 247 ++set_flag; 248 strcpy (set_arg.entry.pool_uuid, optarg); 249 break; 250 case 13: 251 ++set_flag; 252 strcpy (set_arg.entry.dataset, optarg); 253 break; 254 case 14: 255 ++set_flag; 256 strcpy (set_arg.entry.kernel, optarg); 257 break; 258 case 15: 259 ++set_flag; 260 strcpy (set_arg.entry.kernel_opts, optarg); 261 break; 262 case 16: 263 ++set_flag; 264 set_arg.entry.modules[(set_arg.entry.modules_amount)++] = strdup (optarg); 265 break; 266 case 17: 267 set_default = strdup (optarg); 268 break; 269 case 18: 270 set_timeout = strdup (optarg); 271 break; 272 case 19: 273 ++get_flag; 274 get_arg.entry.entry_name[0] = 1; 275 break; 276 case 20: 277 ++get_flag; 278 get_arg.entry.pool_label[0] = 1; 279 break; 280 case 21: 281 ++get_flag; 282 get_arg.entry.pool_uuid[0] = 1; 283 break; 284 case 22: 285 ++get_flag; 286 get_arg.entry.dataset[0] = 1; 287 break; 288 case 23: 289 ++get_flag; 290 get_arg.entry.kernel[0] = 1; 291 break; 292 case 24: 293 ++get_flag; 294 get_arg.entry.kernel_opts[0] = 1; 295 break; 296 case 25: 297 ++get_flag; 298 get_arg.entry.modules = (char**) 1; 299 break; 300 case 26: 301 ++get_default; 302 break; 303 case 27: 304 ++get_timeout; 305 break; 306 case 28: 307 ++get_flag; 308 memset (&(get_arg.entry), 0xFF, sizeof (menu_entry)); 309 break; 310 case 'R': 311 alt_root = strdup (optarg); 312 break; 313 case 30: 314 ++set_flag; 315 strcpy (set_arg.entry.entry_name, "Menuadm default"); 316 strcpy (set_arg.entry.pool_label, get_pool ("/")); 317 strcpy (set_arg.entry.kernel, "/platform/i86pc/kernel/$ISADIR/unix"); 318 strcpy (set_arg.entry.kernel_opts, "-B $ZFS_BOOTFS"); 319 set_arg.entry.modules[0] = strdup ("/platform/i86pc/$ISADIR/boot_archive"); 320 set_arg.entry.modules_amount = 1; 321 break; 322 case 31: 323 set_serial = strdup (optarg); 324 break; 325 case 32: 326 set_terminal = strdup (optarg); 327 break; 328 case 33: 329 ++get_serial; 330 break; 331 case 34: 332 ++get_terminal; 333 break; 334 case 35: 335 ++cln_flag; 336 break; 337 case 36: 338 ++enh_flag; 339 break; 340 case 37: 341 ++dih_flag; 342 break; 343 case 38: 344 ++clr_flag; 345 break; 346 case 39: 347 ++num_flag; 348 sscanf (optarg, "%d", &number); 349 break; 350 default: 351 return 0; 352 } 353 } 354 return 1; 355 } 356 357 static int 358 check_flags () 359 { 360 const char fnc[] = "check_flags"; 361 362 debug_print ("%s\n", fnc); 363 364 if (new_flag) 365 if (del_flag || all_flag || cln_flag || fnd_flag || num_flag) 366 return 0; 367 368 if (del_flag) 369 if ((! fnd_flag && ! num_flag) || set_flag || get_flag || cln_flag || enh_flag || dih_flag) 370 return 0; 371 372 if (cln_flag) 373 if (! fnd_flag || all_flag) 374 return 0; 375 376 if (fnd_flag) 377 if (num_flag) 378 return 0; 379 return 1; 380 } 381 382 static void 383 apply_set (menu_list * entry, menu_list * set) 384 { 385 unsigned int i = 0; 386 387 const char fnc[] = "apply_set"; 388 389 debug_print ("%s\n", fnc); 390 391 if (set->entry.entry_name[0]) 392 strcpy (entry->entry.entry_name, set->entry.entry_name); 393 394 if (set->entry.pool_label[0]) 395 strcpy (entry->entry.pool_label, set->entry.pool_label); 396 397 if (set->entry.pool_uuid[0]) 398 strcpy (entry->entry.pool_uuid, set->entry.pool_uuid); 399 400 if (set->entry.dataset[0]) 401 strcpy (entry->entry.dataset, set->entry.dataset); 402 403 if (set->entry.kernel[0]) 404 strcpy (entry->entry.kernel, set->entry.kernel); 405 406 if (set->entry.kernel_opts[0]) 407 strcpy (entry->entry.kernel_opts, set->entry.kernel_opts); 408 409 if (set->entry.modules_amount) { 410 for (i = 0; i < entry->entry.modules_amount; ++i) 411 free (entry->entry.modules[i]); 412 413 for (i = 0; i < set->entry.modules_amount; ++i) 414 entry->entry.modules[i] = strdup (set->entry.modules[i]); 415 416 entry->entry.modules_amount = set->entry.modules_amount; 417 } 418 } 419 420 static void 421 output_entry (menu_list * entry, menu_list * get) 422 { 423 unsigned int i = 0; 424 425 const char fnc[] = "output_entry"; 426 427 debug_print ("%s\n", fnc); 428 429 if (get->entry.entry_name[0]) 430 printf("%s\n", entry->entry.entry_name); 431 432 if (get->entry.pool_label[0]) 433 printf("%s\n", entry->entry.pool_label); 434 435 if (get->entry.pool_uuid[0]) 436 printf("%s\n", entry->entry.pool_uuid); 437 438 if (get->entry.dataset[0]) 439 printf("%s\n", entry->entry.dataset); 440 441 if (get->entry.kernel[0]) 442 printf("%s\n", entry->entry.kernel); 443 444 if (get->entry.kernel_opts[0]) 445 printf("%s\n", entry->entry.kernel_opts); 446 447 if (get->entry.modules) 448 for (i = 0; i < entry->entry.modules_amount; ++i) 449 printf("%s\n", entry->entry.modules[i]); 450 451 printf("-----------------------------------------\n"); 452 } 453 454 int 455 main (int argc, char ** argv) 456 { 457 char * pool; 458 char config[MAX_STRING_SIZE]; 459 char tmp_config[MAX_STRING_SIZE]; 460 menu_list * menu; 461 menu_list * tmp; 462 menu_list * entry; 463 int entries_amount; 464 int d_num; 465 466 check_debug (); 467 468 if (argc < 2) 469 ++lst_flag; 470 471 set_arg.entry.modules = (char **) calloc (MAX_MODULE_AMOUNT, sizeof (char *)); 472 find_arg.entry.modules = (char **) calloc (MAX_MODULE_AMOUNT, sizeof (char *)); 473 if (! parse_args (argc, argv)) 474 return 1; 475 476 if (hlp_flag) { 477 usage (); 478 return 0; 479 } 480 481 if (! check_flags ()) { 482 print_error ("wrong option set, check \"man grubadm\""); 483 return 1; 484 } 485 486 pool = get_pool (alt_root ?: "/"); 487 strcpy (config, "/"); 488 if (alt_root) 489 strcat (config, alt_root); 490 strcat (config, "/"); 491 strcat (config, pool); 492 strcat (config, "/"); 493 strcpy (tmp_config, config); 494 strcat (config, CONFIG_PATH); 495 strcat (tmp_config, TMP_CONFIG_PATH); 496 497 menu = parse_file (config, &entries_amount); 498 if (entries_amount == -1) { 499 return 1; 500 } 501 502 tmp = menu; 503 entry = NULL; 504 505 do { 506 if (clr_flag) { 507 menu = NULL; 508 break; 509 } 510 511 if (set_default) { 512 sscanf (set_default, "%d", &d_num); 513 if (d_num < entries_amount) 514 strcpy (default_entry, set_default); 515 } 516 517 if (set_timeout) 518 strcpy (timeout, set_timeout); 519 520 if (set_serial) 521 strcpy (serial, set_serial); 522 523 if (set_terminal) 524 strcpy (terminal, set_terminal); 525 526 if (fnd_flag) { 527 entry = find_entry (tmp, &find_arg); 528 if (! entry) { 529 print_error (MSG_ERR_NO_ENTRY); 530 break; 531 } 532 } 533 534 if (num_flag) { 535 if ((number < 0) || (number >= entries_amount)) { 536 if (! default_entry[0]) { 537 number = 0; 538 } else { 539 sscanf (default_entry, "%d", &number); 540 } 541 } 542 if (number >= entries_amount) 543 number = 0; 544 entry = get_entry_by_number (menu, number); 545 if (! entry) { 546 print_error (MSG_ERR_NO_ENTRY); 547 break; 548 } 549 } 550 551 if (cln_flag) { 552 entry = clone_entry (entry); 553 if (! entry) { 554 print_error (MSG_ERR_NO_ENTRY); 555 break; 556 } 557 } 558 559 if (set_flag) { 560 if (entry) 561 apply_set (entry, &set_arg); 562 else if (new_flag) 563 add_entry (&menu, &set_arg); 564 else 565 return 1; 566 } 567 568 if (enh_flag) 569 if (! enable_hyper (entry)) { 570 print_error (MSG_ERR_HYPER); 571 break; 572 } 573 574 if (dih_flag) 575 if (! disable_hyper (entry)) { 576 print_error (MSG_ERR_HYPER); 577 break; 578 } 579 580 if (cln_flag) 581 add_entry (&menu, entry); 582 583 if (get_flag) 584 if (entry) 585 output_entry (entry, &get_arg); 586 587 if (all_flag) 588 tmp = entry->next; 589 else 590 tmp = NULL; 591 592 if (del_flag) 593 delete_entry (&menu, entry); 594 } while (tmp); 595 596 if (get_default) 597 printf ("%s%s%s\n", cmd_list[CMD_DEFAULT], SEPARATOR, default_entry); 598 599 if (get_timeout) 600 printf ("%s%s%s\n", cmd_list[CMD_TIMEOUT], SEPARATOR, timeout); 601 602 if (get_serial) 603 printf ("%s%s%s\n", cmd_list[CMD_SERIAL], SEPARATOR, serial); 604 605 if (get_terminal) 606 printf ("%s%s%s\n", cmd_list[CMD_TERMINAL], SEPARATOR, terminal); 607 608 if (lst_flag) { 609 list_menu (menu); 610 } 611 612 write_menu (config, tmp_config, menu); 613 free_menu (&menu); 614 return 0; 615 }