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