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