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 }