Imported Debian patch 0.5.1-1
[debian/efibootmgr] / src / efibootmgr / efibootmgr.c
1 /*
2   efibootmgr.c - Manipulates EFI variables as exported in /proc/efi/vars
3
4   Copyright (C) 2001-2004 Dell, Inc. <Matt_Domsch@dell.com>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20
21   This must tie the EFI_DEVICE_PATH to /boot/efi/elilo.efi
22   The  EFI_DEVICE_PATH will look something like:
23     ACPI device path, length 12 bytes
24     Hardware Device Path, PCI, length 6 bytes
25     Messaging Device Path, SCSI, length 8 bytes, or ATAPI, length ??
26     Media Device Path, Hard Drive, partition XX, length 30 bytes
27     Media Device Path, File Path, length ??
28     End of Hardware Device Path, length 4
29     Arguments passed to elilo, as UCS-2 characters, length ??
30
31 */
32
33 #define _GNU_SOURCE
34
35 #include <ctype.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <stdint.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <dirent.h>
44 #include <unistd.h>
45 #include <getopt.h>
46 #include "list.h"
47 #include "efi.h"
48 #include "efichar.h"
49 #include "unparse_path.h"
50 #include "disk.h"
51 #include "efibootmgr.h"
52
53
54 #ifndef EFIBOOTMGR_VERSION
55 #define EFIBOOTMGR_VERSION "unknown (fix Makefile!)"
56 #endif
57
58
59 typedef struct _var_entry {
60         struct dirent *name;
61         uint16_t       num;
62         efi_variable_t var_data;
63         list_t         list;
64 } var_entry_t;
65
66
67 /* global variables */
68 static  LIST_HEAD(boot_entry_list);
69 static  LIST_HEAD(blk_list);
70 efibootmgr_opt_t opts;
71
72 static inline void
73 var_num_from_name(const char *pattern, char *name, uint16_t *num)
74 {
75         sscanf(name, pattern, num);
76 }
77
78 static void
79 fill_bootvar_name(char *dest, size_t len, const char *name)
80 {
81         efi_guid_t guid = EFI_GLOBAL_VARIABLE;
82         char text_uuid[40];
83         efi_guid_unparse(&guid, text_uuid);
84         snprintf(dest, len, "%s-%s", name, text_uuid);
85 }
86
87 static void
88 fill_var(efi_variable_t *var, const char *name)
89 {
90         efi_guid_t guid = EFI_GLOBAL_VARIABLE;
91
92         efichar_from_char(var->VariableName, name, 1024);
93         memcpy(&var->VendorGuid, &guid, sizeof(guid));
94         var->Attributes = EFI_VARIABLE_NON_VOLATILE
95                 | EFI_VARIABLE_BOOTSERVICE_ACCESS
96                 | EFI_VARIABLE_RUNTIME_ACCESS;
97 }
98
99
100 static void
101 read_vars(struct dirent **namelist,
102           int num_boot_names,
103           list_t *head)
104 {
105         efi_status_t status;
106         var_entry_t *entry;
107         int i;
108
109         if (!namelist) return;
110
111         for (i=0; i < num_boot_names; i++)
112         {
113                 if (namelist[i]) {
114                         entry = malloc(sizeof(var_entry_t));
115                         if (!entry) return;
116                         memset(entry, 0, sizeof(var_entry_t));
117
118                         status = read_variable(namelist[i]->d_name,
119                                                &entry->var_data);
120                         if (status != EFI_SUCCESS) break;
121                         entry->name = namelist[i];
122                         list_add_tail(&entry->list, head);
123                 }
124         }
125         return;
126 }
127
128
129
130
131
132 static void
133 free_dirents(struct dirent **ptr, int num_dirents)
134 {
135         int i;
136         if (!ptr) return;
137         for (i=0; i < num_dirents; i++) {
138                 if (ptr[i]) {
139                         free(ptr[i]);
140                         ptr[i] = NULL;
141                 }
142         }
143         free(ptr);
144 }
145
146
147
148 static int
149 compare(const void *a, const void *b)
150 {
151         int rc = -1;
152         uint32_t n1, n2;
153         memcpy(&n1, a, sizeof(n1));
154         memcpy(&n2, b, sizeof(n2));
155         if (n1 < n2) rc = -1;
156         if (n1 == n2) rc = 0;
157         if (n2 > n2) rc = 1;
158         return rc;
159 }
160
161
162 /*
163   Return an available boot variable number,
164   or -1 on failure.
165 */
166 static int
167 find_free_boot_var(list_t *boot_list)
168 {
169         int num_vars=0, i=0, found;
170         uint16_t *vars, free_number;
171         list_t *pos;
172         var_entry_t *boot;
173         list_for_each(pos, boot_list) {
174                 num_vars++;
175         }
176         vars = malloc(sizeof(uint16_t) * num_vars);
177         if (!vars) return -1;
178         memset(vars, 0, sizeof(uint16_t) * num_vars);
179
180         list_for_each(pos, boot_list) {
181                 boot = list_entry(pos, var_entry_t, list);
182                 vars[i] = boot->num;
183                         i++;
184         }
185         qsort(vars, i, sizeof(uint16_t), compare);
186         found = 1;
187
188         num_vars = i;
189         for (free_number = 0; free_number < num_vars && found; free_number++) {
190                 found = 0;
191                 list_for_each(pos, boot_list) {
192                         boot = list_entry(pos, var_entry_t, list);
193                         if (boot->num == free_number) {
194                                 found = 1;
195                                 break;
196                         }
197                 }
198                 if (!found) break;
199         }
200         if (found && num_vars) free_number = vars[num_vars-1] + 1;
201         free(vars);
202         return free_number;
203 }
204
205
206 static void
207 warn_duplicate_name(list_t *boot_list)
208 {
209         list_t *pos;
210         var_entry_t *boot;
211         EFI_LOAD_OPTION *load_option;
212
213         list_for_each(pos, boot_list) {
214                 boot = list_entry(pos, var_entry_t, list);
215                 load_option = (EFI_LOAD_OPTION *)
216                         boot->var_data.Data;
217                 if (!efichar_char_strcmp(opts.label,
218                                          load_option->description)) {
219                         fprintf(stderr, "** Warning ** : %.8s has same label %s\n",
220                                boot->name->d_name,
221                                opts.label);
222                 }
223         }
224 }
225
226
227 static var_entry_t *
228 make_boot_var(list_t *boot_list)
229 {
230         var_entry_t *boot;
231         int free_number;
232         list_t *pos;
233
234         if (opts.bootnum == -1)
235                 free_number = find_free_boot_var(boot_list);
236         else {
237                 list_for_each(pos, boot_list) {
238                         boot = list_entry(pos, var_entry_t, list);
239                         if (boot->num == opts.bootnum) {
240                                 fprintf(stderr, "** Warning ** : bootnum %04X "
241                                         "already exists\n", opts.bootnum);
242                                 return NULL;
243                         }
244                 }
245                 free_number = opts.bootnum;
246         }
247
248         if (free_number == -1) return NULL;
249
250         /* Create a new var_entry_t object
251            and populate it.
252         */
253
254         boot = malloc(sizeof(*boot));
255         if (!boot) return NULL;
256         memset(boot, 0, sizeof(*boot));
257         boot->num = free_number;
258         if (!make_linux_efi_variable(&boot->var_data, free_number)) {
259                 free(boot);
260                 return NULL;
261         }
262         create_variable(&boot->var_data);
263         list_add_tail(&boot->list, boot_list);
264         return boot;
265 }
266
267
268
269 static efi_status_t
270 read_boot(efi_variable_t *var, const char *name)
271 {
272         char name_guid[PATH_MAX];
273
274         memset(var, 0, sizeof(*var));
275         fill_bootvar_name(name_guid, sizeof(name_guid), name);
276         return read_variable(name_guid, var);
277 }
278
279 static efi_status_t
280 read_boot_order(efi_variable_t *boot_order)
281 {
282         efi_status_t status;
283
284         status = read_boot(boot_order, "BootOrder");
285         if (status != EFI_SUCCESS && status != EFI_NOT_FOUND)
286                 return status;
287
288         if (status == EFI_NOT_FOUND) {
289                 fill_var(boot_order, "BootOrder");
290         }
291         return EFI_SUCCESS;
292 }
293
294
295 static efi_status_t
296 add_to_boot_order(uint16_t num)
297 {
298         efi_status_t status;
299         efi_variable_t boot_order;
300         uint64_t new_data_size;
301         uint16_t *new_data, *old_data;
302
303         status = read_boot_order(&boot_order);
304         if (status != EFI_SUCCESS) return status;
305
306         /* We've now got an array (in boot_order.Data) of the
307            boot order.  First add our entry, then copy the old array.
308         */
309         old_data = (uint16_t *)&(boot_order.Data);
310         new_data_size = boot_order.DataSize + sizeof(uint16_t);
311         new_data = malloc(new_data_size);
312
313         new_data[0] = num;
314         memcpy(new_data+1, old_data, boot_order.DataSize);
315
316         /* Now new_data has what we need */
317         memcpy(&(boot_order.Data), new_data, new_data_size);
318         boot_order.DataSize = new_data_size;
319         return create_or_edit_variable(&boot_order);
320 }
321
322
323 static efi_status_t
324 remove_from_boot_order(uint16_t num)
325 {
326         efi_status_t status;
327         efi_variable_t boot_order;
328         uint64_t new_data_size;
329         uint16_t *new_data, *old_data;
330         int old_i,new_i;
331         char boot_order_name[PATH_MAX];
332
333         status = read_boot_order(&boot_order);
334         if (status != EFI_SUCCESS) return status;
335         /* If it's empty, yea! */
336         if (!boot_order.DataSize) return EFI_SUCCESS;
337
338         fill_bootvar_name(boot_order_name, sizeof(boot_order_name),
339                           "BootOrder");
340
341         /* We've now got an array (in boot_order.Data) of the
342            boot order.  Simply copy the array, skipping the
343            entry we're deleting.
344         */
345         old_data = (uint16_t *)&(boot_order.Data);
346         /* Start with the same size */
347         new_data_size = boot_order.DataSize;
348         new_data = malloc(new_data_size);
349         for (old_i=0,new_i=0;
350              old_i < boot_order.DataSize / sizeof(uint16_t);
351              old_i++) {
352                 if (old_data[old_i] != num) {
353                                 /* Copy this value */
354                         new_data[new_i] = old_data[old_i];
355                         new_i++;
356                 }
357         }
358
359         /* Now new_data has what we need */
360         new_data_size = new_i * sizeof(uint16_t);
361         memset(&(boot_order.Data), 0, boot_order.DataSize);
362         memcpy(&(boot_order.Data), new_data, new_data_size);
363         boot_order.DataSize = new_data_size;
364
365         return edit_variable(&boot_order);
366 }
367
368 static efi_status_t
369 delete_var(const char *name)
370 {
371         efi_variable_t var;
372
373         memset(&var, 0, sizeof(var));
374         fill_var(&var, name);
375         return delete_variable(&var);
376 }
377
378 static int
379 read_boot_u16(const char *name)
380 {
381         efi_status_t status;
382         efi_variable_t var;
383         uint16_t *n = (uint16_t *)(var.Data);
384
385         memset(&var, 0, sizeof(var));
386         status = read_boot(&var, name);
387         if (status) return -1;
388         return *n;
389 }
390
391 static efi_status_t
392 set_boot_u16(const char *name, uint16_t num)
393 {
394         efi_variable_t var;
395         uint16_t *n = (uint16_t *)var.Data;
396
397         memset(&var, 0, sizeof(var));
398
399         fill_var(&var, name);
400         *n = num;
401         var.DataSize = sizeof(uint16_t);
402         return create_or_edit_variable(&var);
403 }
404
405 static efi_status_t
406 delete_boot_var(uint16_t num)
407 {
408         efi_status_t status;
409         efi_variable_t var;
410         char name[16];
411         list_t *pos, *n;
412         var_entry_t *boot;
413
414         snprintf(name, sizeof(name), "Boot%04X", num);
415         memset(&var, 0, sizeof(var));
416         fill_var(&var, name);
417         status = delete_variable(&var);
418
419         /* For backwards compatibility, try to delete abcdef entries as well */
420         if (status) {
421                 snprintf(name, sizeof(name), "Boot%04x", num);
422                 memset(&var, 0, sizeof(var));
423                 fill_var(&var, name);
424                 status = delete_variable(&var);
425         }
426
427         if (status) return status;
428         list_for_each_safe(pos, n, &boot_entry_list) {
429                 boot = list_entry(pos, var_entry_t, list);
430                 if (boot->num == num) {
431                         status = remove_from_boot_order(num);
432                         if (status) return status;
433                         list_del(&(boot->list));
434                         break; /* short-circuit since it was found */
435                 }
436         }
437         return EFI_SUCCESS;
438 }
439
440
441 static void
442 set_var_nums(const char *pattern, list_t *list)
443 {
444         list_t *pos;
445         var_entry_t *var;
446         int num=0, rc;
447         char *name;
448         int warn=0;
449
450         list_for_each(pos, list) {
451                 var = list_entry(pos, var_entry_t, list);
452                 rc = sscanf(var->name->d_name, pattern, &num);
453                 if (rc == 1) {
454                         var->num = num;
455                         name = var->name->d_name; /* shorter name */
456                         if ((isalpha(name[4]) && islower(name[4])) ||
457                             (isalpha(name[5]) && islower(name[5])) ||
458                             (isalpha(name[6]) && islower(name[6])) ||
459                             (isalpha(name[7]) && islower(name[7]))) {
460                                 fprintf(stderr, "** Warning ** : %.8s is not "
461                                         "EFI 1.10 compliant (lowercase hex in name)\n", name);
462                                 warn++;
463                         }
464                 }
465         }
466         if (warn) {
467                 fprintf(stderr, "** Warning ** : please recreate these using efibootmgr to remove this warning.\n");
468         }
469 }
470
471 #if 0
472 static efi_variable_t *
473 find_pci_scsi_disk_blk(int fd, int bus, int device, int func,
474                        list_t *blk_list)
475 {
476         list_t *pos;
477         int rc;
478         Scsi_Idlun idlun;
479         unsigned char host, channel, id, lun;
480         var_entry_t *blk;
481         efi_variable_t *blk_var;
482         long size = 0;
483
484         memset(&idlun, 0, sizeof(idlun));
485         rc = get_scsi_idlun(fd, &idlun);
486         if (rc) return NULL;
487
488         rc = disk_get_size(fd, &size);
489
490         idlun_to_components(&idlun, &host, &channel, &id, &lun);
491
492         list_for_each(pos, blk_list) {
493                 blk = list_entry(pos, var_entry_t, list);
494                 blk_var = blk->var_data;
495
496                 if (!compare_pci_scsi_disk_blk(blk_var,
497                                                bus, device, func,
498                                                host, channel, id, lun,
499                                                0, size)) {
500                         return blk_var;
501                 }
502         }
503         return NULL;
504 }
505
506
507
508
509 /* The right blkX variable contains:
510    1) the PCI and SCSI information for the disk passed in disk_name
511    2) Does not contain a partition field 
512 */
513
514
515 static efi_variable_t *
516 find_disk_blk(char *disk_name, list_t *blk_list)
517 {
518         efi_variable_t *disk_blk = NULL;
519         int fd, rc;
520         unsigned char bus=0,device=0,func=0;
521         int interface_type=interface_type_unknown;
522         unsigned int controllernum=0, disknum=0;
523         unsigned char part=0;
524
525         fd = open(disk_name, O_RDONLY|O_DIRECT);
526         rc = disk_get_pci(fd, &bus, &device, &func);
527         if (rc) {
528                 fprintf(stderr, "disk_get_pci() failed.\n");
529                 return NULL;
530         }
531         rc = disk_info_from_fd(fd,
532                                &interface_type,
533                                &controllernum,
534                                &disknum,
535                                &part);
536         if (rc) {
537                 fprintf(stderr, "disk_info_from_fd() failed.\n");
538                 return NULL;
539         }
540         switch (interface_type)
541         {
542         case scsi:
543                 return find_pci_scsi_disk_blk(fd,bus,device,func,blk_list);
544                 break;
545         case ata:
546                 return find_pci_ata_disk_blk(fd,bus,device,func,blk_list);
547                 break;
548         case i2o:
549                 return find_pci_i2o_disk_blk(fd,bus,device,func,blk_list);
550                 break;
551         case md:
552                 return find_pci_md_disk_blk(fd,bus,device,func,blk_list);
553                 break;
554         default:
555                 break;
556         }
557         return NULL;
558 }
559 #endif
560
561 static void
562 unparse_boot_order(uint16_t *order, int length)
563 {
564         int i;
565         printf("BootOrder: ");
566         for (i=0; i<length; i++) {
567                 printf("%04X", order[i]);
568                 if (i < (length-1))
569                         printf(",");
570         }
571         printf("\n");
572 }
573
574 static int
575 parse_boot_order(char *buffer, uint16_t *order, int length)
576 {
577         int i;
578         int num, rc;
579
580         for (i=0; i<length && *buffer; i++) {
581                 rc = sscanf(buffer, "%x", &num);
582                 if (rc == 1) order[i] = num & 0xFFFF;
583                 /* Advance to the comma */ 
584                 while (*buffer && *buffer != ',') buffer++;
585                 /* Advance through the comma(s) */
586                 while (*buffer && *buffer == ',') buffer++;
587         }
588         return i;
589 }
590
591 static efi_status_t
592 set_boot_order()
593 {
594         efi_variable_t boot_order;
595         uint16_t *n = (uint16_t *)boot_order.Data;
596
597         if (!opts.bootorder) return EFI_SUCCESS;
598
599         memset(&boot_order, 0, sizeof(boot_order));
600         fill_var(&boot_order, "BootOrder");
601
602         boot_order.DataSize = parse_boot_order(opts.bootorder, n, 1024/sizeof(uint16_t)) * sizeof(uint16_t);
603         return create_or_edit_variable(&boot_order);
604 }
605
606 static void
607 show_boot_vars()
608 {
609         list_t *pos;
610         var_entry_t *boot;
611         char description[80];
612         EFI_LOAD_OPTION *load_option;
613         EFI_DEVICE_PATH *path;
614         char text_path[1024], *p;
615         unsigned long optional_data_len=0;
616
617         list_for_each(pos, &boot_entry_list) {
618                 boot = list_entry(pos, var_entry_t, list);
619                 load_option = (EFI_LOAD_OPTION *)
620                         boot->var_data.Data;
621                 efichar_to_char(description,
622                                 load_option->description, sizeof(description));
623                 memset(text_path, 0, sizeof(text_path));
624                 path = load_option_path(load_option);
625                 if (boot->name)
626                         printf("%.8s", boot->name->d_name);
627                 else
628                         printf("Boot%04X", boot->num);
629
630                 if (load_option->attributes & LOAD_OPTION_ACTIVE)
631                         printf("* ");
632                 else    printf("  ");
633                 printf("%s", description);
634
635                 if (opts.verbose) {
636                         unparse_path(text_path, path,
637                                      load_option->file_path_list_length);
638                         /* Print optional data */
639                         optional_data_len =
640                                 boot->var_data.DataSize -
641                                 load_option->file_path_list_length -
642                                 ((char *)path - (char *)load_option);
643                         if (optional_data_len) {
644                                 p = text_path;
645                                 p += strlen(text_path);
646                                 unparse_raw_text(p, ((uint8_t *)path) +
647                                                  load_option->file_path_list_length,
648                                                  optional_data_len);
649                         }
650
651                         printf("\t%s", text_path);
652                 }
653                 printf("\n");
654         }
655 }
656
657
658
659 static void
660 show_boot_order()
661 {
662         efi_status_t status;
663         efi_variable_t boot_order;
664         uint16_t *data;
665
666         status = read_boot_order(&boot_order);
667
668         if (status != EFI_SUCCESS) {
669                 perror("show_boot_order()");
670                 return;
671         }
672
673         /* We've now got an array (in boot_order.Data) of the
674            boot order.  First add our entry, then copy the old array.
675         */
676         data = (uint16_t *)&(boot_order.Data);
677         if (boot_order.DataSize)
678                 unparse_boot_order(data, boot_order.DataSize / sizeof(uint16_t));
679
680 }
681
682 static efi_status_t
683 set_active_state()
684 {
685         list_t *pos;
686         var_entry_t *boot;
687         EFI_LOAD_OPTION *load_option;
688
689         list_for_each(pos, &boot_entry_list) {
690                 boot = list_entry(pos, var_entry_t, list);
691                 load_option = (EFI_LOAD_OPTION *)
692                         boot->var_data.Data;
693                 if (boot->num == opts.bootnum) {
694                         if (opts.active == 1) {
695                                 if (load_option->attributes
696                                     & LOAD_OPTION_ACTIVE) return EFI_SUCCESS;
697                                 else {
698                                         load_option->attributes
699                                                 |= LOAD_OPTION_ACTIVE;
700                                         return edit_variable(&boot->var_data);
701                                 }
702                         }
703                         else if (opts.active == 0) {
704                                 if (!(load_option->attributes
705                                       & LOAD_OPTION_ACTIVE))
706                                         return EFI_SUCCESS;
707                                 else {
708                                         load_option->attributes
709                                                 &= ~LOAD_OPTION_ACTIVE;
710                                         return edit_variable(&boot->var_data);
711                                 }
712                         }
713                 }
714         }
715         return EFI_SUCCESS;
716 }
717
718
719
720
721 static void
722 usage()
723 {
724         printf("efibootmgr version %s\n", EFIBOOTMGR_VERSION);
725         printf("usage: efibootmgr [options]\n");
726         printf("\t-a | --active         sets bootnum active\n");
727         printf("\t-A | --inactive       sets bootnum inactive\n");
728         printf("\t-b | --bootnum XXXX   modify BootXXXX (hex)\n");
729         printf("\t-B | --delete-bootnum delete bootnum (hex)\n");
730         printf("\t-c | --create         create new variable bootnum and add to bootorder\n");
731         printf("\t-d | --disk disk       (defaults to /dev/sda) containing loader\n");
732         printf("\t-e | --edd [1|3|-1]   force EDD 1.0 or 3.0 creation variables, or guess\n");
733         printf("\t-E | --device num      EDD 1.0 device number (defaults to 0x80)\n");
734         printf("\t-g | --gpt            force disk with invalid PMBR to be treated as GPT\n");
735         printf("\t-H | --acpi_hid XXXX  set the ACPI HID (used with -i)\n");
736         printf("\t-i | --iface name     create a netboot entry for the named interface\n");
737         printf("\t-l | --loader name     (defaults to \\elilo.efi)\n");
738         printf("\t-L | --label label     Boot manager display label (defaults to \"Linux\")\n");
739         printf("\t-n | --bootnext XXXX   set BootNext to XXXX (hex)\n");
740         printf("\t-N | --delete-bootnext delete BootNext\n");
741         printf("\t-o | --bootorder XXXX,YYYY,ZZZZ,...     explicitly set BootOrder (hex)\n");
742         printf("\t-O | --delete-bootorder delete BootOrder\n");
743         printf("\t-p | --part part        (defaults to 1) containing loader\n");
744         printf("\t-q | --quiet            be quiet\n");
745         printf("\t   | --test filename    don't write to NVRAM, write to filename.\n");
746         printf("\t-t | --timeout seconds  set boot manager timeout waiting for user input.\n");
747         printf("\t-T | --delete-timeout   delete Timeout.\n");
748         printf("\t-u | --unicode | --UCS-2  pass extra args as UCS-2 (default is ASCII)\n");
749         printf("\t-U | --acpi_uid XXXX    set the ACPI UID (used with -i)\n");
750         printf("\t-v | --verbose          print additional information\n");
751         printf("\t-V | --version          return version and exit\n");
752         printf("\t-w | --write-signature  write unique sig to MBR if needed\n");
753 }
754
755 static void
756 set_default_opts()
757 {
758         memset(&opts, 0, sizeof(opts));
759         opts.bootnum         = -1;   /* auto-detect */
760         opts.bootnext        = -1;   /* Don't set it */
761         opts.active          = -1;   /* Don't set it */
762         opts.timeout         = -1;   /* Don't set it */
763         opts.edd10_devicenum = 0x80;
764         opts.loader          = "\\elilo.efi";
765         opts.label           = "Linux";
766         opts.disk            = "/dev/sda";
767         opts.iface           = NULL;
768         opts.part            = 1;
769         opts.acpi_hid        = -1;
770         opts.acpi_uid        = -1;
771 }
772
773 static void
774 parse_opts(int argc, char **argv)
775 {
776         int c, num, rc;
777         int option_index = 0;
778
779         while (1)
780         {
781                 static struct option long_options[] =
782                         /* name, has_arg, flag, val */
783                 {
784                         {"active",                 no_argument, 0, 'a'},
785                         {"inactive",               no_argument, 0, 'A'},
786                         {"bootnum",          required_argument, 0, 'b'},
787                         {"delete-bootnum",         no_argument, 0, 'B'},
788                         {"create",                 no_argument, 0, 'c'},
789                         {"disk",             required_argument, 0, 'd'},
790                         {"iface",            required_argument, 0, 'i'},
791                         {"acpi_hid",         required_argument, 0, 'H'},
792                         {"edd-device",       required_argument, 0, 'E'},
793                         {"edd30",            required_argument, 0, 'e'},
794                         {"gpt",                    no_argument, 0, 'g'},
795                         {"loader",           required_argument, 0, 'l'},
796                         {"label",            required_argument, 0, 'L'},
797                         {"bootnext",         required_argument, 0, 'n'},
798                         {"delete-bootnext",        no_argument, 0, 'N'},
799                         {"bootorder",        required_argument, 0, 'o'},
800                         {"delete-bootorder",       no_argument, 0, 'O'},
801                         {"part",             required_argument, 0, 'p'},
802                         {"quiet",                  no_argument, 0, 'q'},
803                         {"test",             required_argument, 0,   1},
804                         {"timeout",          required_argument, 0, 't'},
805                         {"delete-timeout",         no_argument, 0, 'T'},
806                         {"unicode",                no_argument, 0, 'u'},
807                         {"UCS-2",                  no_argument, 0, 'u'},
808                         {"acpi_uid",         required_argument, 0, 'U'},
809                         {"verbose",          optional_argument, 0, 'v'},
810                         {"version",                no_argument, 0, 'V'},
811                         {"write-signature",        no_argument, 0, 'w'},
812                         {0, 0, 0, 0}
813                 };
814
815                 c = getopt_long (argc, argv,
816                                  "AaBb:cd:e:E:gH:i:l:L:n:No:Op:qt:TuU:v::Vw",
817                                  long_options, &option_index);
818                 if (c == -1)
819                         break;
820
821                 switch (c)
822                 {
823                 case 'a':
824                         opts.active = 1;
825                         break;
826                 case 'A':
827                         opts.active = 0;
828                         break;
829                 case 'B':
830                         opts.delete_boot = 1;
831                         break;
832                 case 'b':
833                         rc = sscanf(optarg, "%X", &num);
834                         if (rc == 1) opts.bootnum = num;
835                         break;
836                 case 'c':
837                         opts.create = 1;
838                         break;
839                 case 'd':
840                         opts.disk = optarg;
841                         break;
842                 case 'e':
843                         rc = sscanf(optarg, "%d", &num);
844                         if (rc == 1) opts.edd_version = num;
845                         break;
846                 case 'E':
847                         rc = sscanf(optarg, "%x", &num);
848                         if (rc == 1) opts.edd10_devicenum = num;
849                         break;
850                 case 'g':
851                         opts.forcegpt = 1;
852                         break;
853                 case 'H':
854                         rc = sscanf(optarg, "%x", &num);
855                         if (rc == 1) opts.acpi_hid = num;
856                         break;
857                 case 'i':
858                         opts.iface = optarg;
859                         break;
860                 case 'l':
861                         opts.loader = optarg;
862                         break;
863                 case 'L':
864                         opts.label = optarg;
865                         break;
866                 case 'N':
867                         opts.delete_bootnext = 1;
868                         break;
869                 case 'n':
870                         rc = sscanf(optarg, "%x", &num);
871                         if (rc == 1) opts.bootnext = num;
872                         break;
873                 case 'o':
874                         opts.bootorder = optarg;
875                         break;
876                 case 'O':
877                         opts.delete_bootorder = 1;
878                         break;
879                 case 'p':
880                         rc = sscanf(optarg, "%u", &num);
881                         if (rc == 1) opts.part = num;
882                         break;
883                 case 'q':
884                         opts.quiet = 1;
885                         break;
886                 case 1:
887                         opts.testfile = optarg;
888                         break;
889                 case 't':
890                         rc = sscanf(optarg, "%u", &num);
891                         if (rc == 1) {
892                                 opts.timeout = num;
893                                 opts.set_timeout = 1;
894                         }
895                         break;
896                 case 'T':
897                         opts.delete_timeout = 1;
898                         break;
899                 case 'u':
900                         opts.unicode = 1;
901                         break;
902
903                 case 'U':
904                         rc = sscanf(optarg, "%x", &num);
905                         if (rc == 1) opts.acpi_uid = num;
906                         break;
907                 case 'v':
908                         opts.verbose = 1;
909                         if (optarg) {
910                                 if (!strcmp(optarg, "v"))  opts.verbose = 2;
911                                 if (!strcmp(optarg, "vv")) opts.verbose = 3;
912                                 rc = sscanf(optarg, "%d", &num);
913                                 if (rc == 1)  opts.verbose = num;
914                         }
915                         break;
916                 case 'V':
917                         opts.showversion = 1;
918                         break;
919
920                 case 'w':
921                         opts.write_signature = 1;
922                         break;
923
924                 default:
925                         usage();
926                         exit(1);
927                 }
928         }
929
930         if (optind < argc) {
931                 opts.argc = argc;
932                 opts.argv = argv;
933                 opts.optind = optind;
934         }
935 }
936
937
938 int
939 main(int argc, char **argv)
940 {
941         struct dirent  **boot_names = NULL;
942         var_entry_t *new_boot = NULL;
943         int num, num_boot_names=0;
944
945         set_default_opts();
946         parse_opts(argc, argv);
947         if (opts.showversion) {
948                 printf("version %s\n", EFIBOOTMGR_VERSION);
949                 return 0;
950         }
951
952         if (opts.iface && opts.acpi_hid == -1 && opts.acpi_uid == -1) {
953                 fprintf(stderr, "\nYou must specify the ACPI HID and UID when using -i.\n\n");
954                 return 1;
955         }
956
957         if (!opts.testfile)
958                 set_fs_kernel_calls();
959
960         if (!opts.testfile) {
961                 num_boot_names = read_boot_var_names(&boot_names);
962                 read_vars(boot_names, num_boot_names, &boot_entry_list);
963                 set_var_nums("Boot%04X-%*s", &boot_entry_list);
964
965                 if (opts.delete_boot) {
966                         if (opts.bootnum == -1)
967                                 fprintf(stderr, "\nYou must specify a boot entry to delete (see the -b option).\n\n");
968                         else
969                                 delete_boot_var(opts.bootnum);
970                 }
971
972                 if (opts.active >= 0) {
973                         set_active_state();
974                 }
975         }
976
977         if (opts.create) {
978                 warn_duplicate_name(&boot_entry_list);
979                 new_boot = make_boot_var(&boot_entry_list);
980                 /* Put this boot var in the right BootOrder */
981                 if (!opts.testfile && new_boot)
982                         add_to_boot_order(new_boot->num);
983         }
984
985         if (!opts.testfile) {
986
987                 if (opts.delete_bootorder) {
988                         delete_var("BootOrder");
989                 }
990
991                 if (opts.bootorder) {
992                         set_boot_order();
993                 }
994
995
996                 if (opts.delete_bootnext) {
997                         delete_var("BootNext");
998                 }
999
1000                 if (opts.delete_timeout) {
1001                         delete_var("Timeout");
1002                 }
1003
1004                 if (opts.bootnext >= 0) {
1005                         set_boot_u16("BootNext", opts.bootnext & 0xFFFF);
1006                 }
1007
1008                 if (opts.set_timeout) {
1009                         set_boot_u16("Timeout", opts.timeout);
1010                 }
1011
1012                 if (!opts.quiet) {
1013                         num = read_boot_u16("BootNext");
1014                         if (num != -1 ) {
1015                                 printf("BootNext: %04X\n", num);
1016                         }
1017                         num = read_boot_u16("BootCurrent");
1018                         if (num != -1) {
1019                                 printf("BootCurrent: %04X\n", num);
1020                         }
1021                         num = read_boot_u16("Timeout");
1022                         if (num != -1) {
1023                                 printf("Timeout: %u seconds\n", num);
1024                         }
1025                         show_boot_order();
1026                         show_boot_vars();
1027                 }
1028         }
1029         free_dirents(boot_names, num_boot_names);
1030         return 0;
1031 }
1032