2 efibootmgr.c - Manipulates EFI variables as exported in /proc/efi/vars
4 Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
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.
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.
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
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 ??
48 #include "unparse_path.h"
50 #include "efibootmgr.h"
52 #ifndef EFIBOOTMGR_VERSION
53 #define EFIBOOTMGR_VERSION "unknown (fix Makefile!)"
57 typedef struct _var_entry {
60 efi_variable_t var_data;
65 /* global variables */
66 static LIST_HEAD(boot_entry_list);
67 static LIST_HEAD(blk_list);
68 efibootmgr_opt_t opts;
71 var_num_from_name(const char *pattern, char *name, uint16_t *num)
73 sscanf(name, pattern, num);
77 select_boot_var_names(const struct dirent *d)
80 rc = sscanf(d->d_name, "Boot0%03x-%*s", &num);
86 select_blk_var_names(const struct dirent *d)
89 return sscanf(d->d_name, "blk%x-%*s", &num);
94 read_boot_var_names(struct dirent ***namelist)
97 n = scandir(PROC_DIR_EFI_VARS, namelist, select_boot_var_names, alphasort);
99 perror("scandir " PROC_DIR_EFI_VARS);
100 fprintf(stderr, "You must 'modprobe efivars' before running efibootmgr.\n");
107 read_blk_var_names(struct dirent ***namelist)
110 n = scandir(PROC_DIR_EFI_VARS, namelist, select_blk_var_names, alphasort);
117 dirent_list_length(struct dirent **namelist)
120 if (!namelist) return 0;
121 for (i=0; namelist[i]; i++);
127 read_vars(struct dirent **namelist,
135 if (!namelist) return;
137 for (i=0; i < num_boot_names; i++)
140 entry = malloc(sizeof(var_entry_t));
142 memset(entry, 0, sizeof(var_entry_t));
144 status = read_variable(namelist[i]->d_name,
146 if (status != EFI_SUCCESS) break;
147 entry->name = namelist[i];
148 list_add_tail(&entry->list, head);
159 free_dirents(struct dirent **ptr, int num_dirents)
163 for (i=0; i < num_dirents; i++) {
175 compare(const void *a, const void *b)
179 memcpy(&n1, a, sizeof(n1));
180 memcpy(&n2, b, sizeof(n2));
181 if (n1 < n2) rc = -1;
182 if (n1 == n2) rc = 0;
189 Return an available boot variable number,
193 find_free_boot_var(list_t *boot_list)
195 int num_vars=0, i=0, found;
196 uint16_t *vars, free_number;
199 list_for_each(pos, boot_list) {
202 vars = malloc(sizeof(uint16_t) * num_vars);
203 if (!vars) return -1;
204 memset(vars, 0, sizeof(uint16_t) * num_vars);
206 list_for_each(pos, boot_list) {
207 boot = list_entry(pos, var_entry_t, list);
211 qsort(vars, i, sizeof(uint16_t), compare);
215 for (free_number = 0; free_number < num_vars && found; free_number++) {
217 list_for_each(pos, boot_list) {
218 boot = list_entry(pos, var_entry_t, list);
219 if (boot->num == free_number) {
226 if (found && num_vars) free_number = vars[num_vars-1] + 1;
233 warn_duplicate_name(list_t *boot_list)
237 EFI_LOAD_OPTION *load_option;
239 list_for_each(pos, boot_list) {
240 boot = list_entry(pos, var_entry_t, list);
241 load_option = (EFI_LOAD_OPTION *)
243 if (!efichar_char_strcmp(opts.label,
244 load_option->description)) {
245 fprintf(stderr, "** Warning ** : Boot%04x has same label %s\n",
254 make_boot_var(list_t *boot_list)
259 if (opts.bootnum == -1) free_number = find_free_boot_var(boot_list);
260 else free_number = opts.bootnum;
262 if (free_number == -1) return NULL;
264 /* Create a new var_entry_t object
268 boot = malloc(sizeof(*boot));
269 if (!boot) return NULL;
270 memset(boot, 0, sizeof(*boot));
271 boot->num = free_number;
272 if (!make_linux_efi_variable(&boot->var_data, free_number)) {
276 write_variable(&boot->var_data);
277 list_add_tail(&boot->list, boot_list);
282 read_boot_order(efi_variable_t *boot_order)
285 efi_guid_t guid = EFI_GLOBAL_VARIABLE;
286 char boot_order_name[80], text_uuid[40];
287 efi_guid_unparse(&guid, text_uuid);
289 memset(boot_order, 0, sizeof(*boot_order));
290 sprintf(boot_order_name, "BootOrder-%s", text_uuid);
292 status = read_variable(boot_order_name, boot_order);
293 if (status != EFI_SUCCESS && status != EFI_NOT_FOUND)
296 if (status == EFI_NOT_FOUND) {
298 efichar_from_char(boot_order->VariableName, "BootOrder",
300 memcpy(&boot_order->VendorGuid, &guid, sizeof(guid));
301 boot_order->Attributes = EFI_VARIABLE_NON_VOLATILE
302 | EFI_VARIABLE_BOOTSERVICE_ACCESS
303 | EFI_VARIABLE_RUNTIME_ACCESS;
313 add_to_boot_order(uint16_t num)
316 efi_variable_t boot_order;
317 uint64_t new_data_size;
318 uint16_t *new_data, *old_data;
320 status = read_boot_order(&boot_order);
321 if (status != EFI_SUCCESS) return status;
323 /* We've now got an array (in boot_order.Data) of the
324 boot order. First add our entry, then copy the old array.
326 old_data = (uint16_t *)&(boot_order.Data);
327 new_data_size = boot_order.DataSize + sizeof(uint16_t);
328 new_data = malloc(new_data_size);
331 memcpy(new_data+1, old_data, boot_order.DataSize);
333 /* Now new_data has what we need */
334 memcpy(&(boot_order.Data), new_data, new_data_size);
335 boot_order.DataSize = new_data_size;
336 return write_variable(&boot_order);
341 remove_from_boot_order(uint16_t num)
344 efi_variable_t boot_order;
345 uint64_t new_data_size;
346 uint16_t *new_data, *old_data;
349 status = read_boot_order(&boot_order);
350 if (status != EFI_SUCCESS) return status;
352 /* If it's empty, yea! */
353 if (!boot_order.DataSize) return EFI_SUCCESS;
355 /* We've now got an array (in boot_order.Data) of the
356 boot order. Simply copy the array, skipping the
357 entry we're deleting.
359 old_data = (uint16_t *)&(boot_order.Data);
360 /* Start with the same size */
361 new_data_size = boot_order.DataSize;
362 new_data = malloc(new_data_size);
363 for (old_i=0,new_i=0;
364 old_i < boot_order.DataSize / sizeof(uint16_t);
366 if (old_data[old_i] != num) {
367 /* Copy this value */
368 new_data[new_i] = old_data[old_i];
373 /* Now new_data has what we need */
374 new_data_size = new_i * sizeof(uint16_t);
375 memset(&(boot_order.Data), 0, boot_order.DataSize);
376 memcpy(&(boot_order.Data), new_data, new_data_size);
377 boot_order.DataSize = new_data_size;
379 return write_variable(&boot_order);
386 efi_variable_t boot_next;
387 efi_guid_t guid = EFI_GLOBAL_VARIABLE;
388 char boot_next_name[80], text_uuid[40];
389 uint16_t *n = (uint16_t *)(boot_next.Data);
391 efi_guid_unparse(&guid, text_uuid);
393 memset(&boot_next, 0, sizeof(boot_next));
394 sprintf(boot_next_name, "BootCurrent-%s", text_uuid);
396 status = read_variable(boot_next_name, &boot_next);
397 if (status) return -1;
406 efi_variable_t boot_next;
407 efi_guid_t guid = EFI_GLOBAL_VARIABLE;
408 char boot_next_name[80], text_uuid[40];
409 uint16_t *n = (uint16_t *)(boot_next.Data);
411 efi_guid_unparse(&guid, text_uuid);
413 memset(&boot_next, 0, sizeof(boot_next));
414 sprintf(boot_next_name, "BootNext-%s", text_uuid);
416 status = read_variable(boot_next_name, &boot_next);
417 if (status) return -1;
424 set_boot_next(uint16_t num)
427 efi_guid_t guid = EFI_GLOBAL_VARIABLE;
428 uint16_t *n = (uint16_t *)var.Data;
430 memset(&var, 0, sizeof(var));
432 efichar_from_char(var.VariableName, "BootNext",
434 memcpy(&var.VendorGuid, &guid, sizeof(guid));
436 var.DataSize = sizeof(uint16_t);
437 var.Attributes = EFI_VARIABLE_NON_VOLATILE
438 | EFI_VARIABLE_BOOTSERVICE_ACCESS
439 | EFI_VARIABLE_RUNTIME_ACCESS;
440 return write_variable(&var);
447 efi_guid_t guid = EFI_GLOBAL_VARIABLE;
449 memset(&var, 0, sizeof(var));
451 efichar_from_char(var.VariableName, "BootNext",
453 memcpy(&var.VendorGuid, &guid, sizeof(guid));
454 return write_variable(&var);
459 delete_boot_var(uint16_t num)
463 efi_guid_t guid = EFI_GLOBAL_VARIABLE;
467 sprintf(name, "Boot%04x", num);
469 memset(&var, 0, sizeof(var));
471 efichar_from_char(var.VariableName, name, 1024);
472 memcpy(&var.VendorGuid, &guid, sizeof(guid));
473 status = write_variable(&var);
475 if (status) return status;
477 list_for_each_safe(pos, n, &boot_entry_list) {
478 boot = list_entry(pos, var_entry_t, list);
479 if (boot->num == num) {
480 status = remove_from_boot_order(num);
481 if (status) return status;
482 list_del(&(boot->list));
483 break; /* short-circuit since it was found */
491 set_var_nums(const char *pattern, list_t *list)
497 list_for_each(pos, list) {
498 var = list_entry(pos, var_entry_t, list);
499 rc = sscanf(var->name->d_name, pattern, &num);
500 if (rc == 1) var->num = num;
505 static efi_variable_t *
506 find_pci_scsi_disk_blk(int fd, int bus, int device, int func,
512 unsigned char host, channel, id, lun;
514 efi_variable_t *blk_var;
517 memset(&idlun, 0, sizeof(idlun));
518 rc = get_scsi_idlun(fd, &idlun);
521 rc = disk_get_size(fd, &size);
523 idlun_to_components(&idlun, &host, &channel, &id, &lun);
525 list_for_each(pos, blk_list) {
526 blk = list_entry(pos, var_entry_t, list);
527 blk_var = blk->var_data;
529 if (!compare_pci_scsi_disk_blk(blk_var,
531 host, channel, id, lun,
542 /* The right blkX variable contains:
543 1) the PCI and SCSI information for the disk passed in disk_name
544 2) Does not contain a partition field
548 static efi_variable_t *
549 find_disk_blk(char *disk_name, list_t *blk_list)
551 efi_variable_t *disk_blk = NULL;
553 unsigned char bus=0,device=0,func=0;
554 int interface_type=interface_type_unknown;
555 unsigned int controllernum=0, disknum=0;
556 unsigned char part=0;
558 fd = open(disk_name, O_RDONLY|O_DIRECT);
559 rc = disk_get_pci(fd, &bus, &device, &func);
561 fprintf(stderr, "disk_get_pci() failed.\n");
564 rc = disk_info_from_fd(fd,
570 fprintf(stderr, "disk_info_from_fd() failed.\n");
573 switch (interface_type)
576 return find_pci_scsi_disk_blk(fd,bus,device,func,blk_list);
579 return find_pci_ata_disk_blk(fd,bus,device,func,blk_list);
582 return find_pci_i2o_disk_blk(fd,bus,device,func,blk_list);
585 return find_pci_md_disk_blk(fd,bus,device,func,blk_list);
595 unparse_boot_order(uint16_t *order, int length)
598 printf("BootOrder: ");
599 for (i=0; i<length; i++) {
600 printf("%04x", order[i]);
608 parse_boot_order(char *buffer, uint16_t *order, int length)
613 for (i=0; i<length && *buffer; i++) {
614 rc = sscanf(buffer, "%x", &num);
615 if (rc == 1) order[i] = num & 0xFFFF;
616 /* Advance to the comma */
617 while (*buffer && *buffer != ',') buffer++;
618 /* Advance through the comma(s) */
619 while (*buffer && *buffer == ',') buffer++;
628 efi_guid_t guid = EFI_GLOBAL_VARIABLE;
629 uint16_t *n = (uint16_t *)var.Data;
631 if (!opts.bootorder) return EFI_SUCCESS;
633 memset(&var, 0, sizeof(var));
635 efichar_from_char(var.VariableName, "BootOrder",
637 memcpy(&var.VendorGuid, &guid, sizeof(guid));
638 var.Attributes = EFI_VARIABLE_NON_VOLATILE
639 | EFI_VARIABLE_BOOTSERVICE_ACCESS
640 | EFI_VARIABLE_RUNTIME_ACCESS;
642 var.DataSize = parse_boot_order(opts.bootorder, n, 1024/sizeof(uint16_t)) * sizeof(uint16_t);
643 return write_variable(&var);
651 char description[80];
652 EFI_LOAD_OPTION *load_option;
653 EFI_DEVICE_PATH *path;
654 char text_path[1024], *p;
655 unsigned long optional_data_len=0;
657 list_for_each(pos, &boot_entry_list) {
658 boot = list_entry(pos, var_entry_t, list);
659 load_option = (EFI_LOAD_OPTION *)
661 efichar_to_char(description,
662 load_option->description, sizeof(description));
663 memset(text_path, 0, sizeof(text_path));
664 path = load_option_path(load_option);
665 printf("Boot%04x", boot->num);
666 if (load_option->attributes & LOAD_OPTION_ACTIVE)
669 printf("%s", description);
672 unparse_path(text_path, path,
673 load_option->file_path_list_length);
674 /* Print optional data */
676 boot->var_data.DataSize -
677 load_option->file_path_list_length -
678 ((char *)path - (char *)load_option);
679 if (optional_data_len) {
681 p += strlen(text_path);
682 unparse_raw_text(p, ((uint8_t *)path) +
683 load_option->file_path_list_length,
687 printf("\t%s", text_path);
699 efi_variable_t boot_order;
702 status = read_boot_order(&boot_order);
704 if (status != EFI_SUCCESS) {
705 perror("show_boot_order()");
709 /* We've now got an array (in boot_order.Data) of the
710 boot order. First add our entry, then copy the old array.
712 data = (uint16_t *)&(boot_order.Data);
713 if (boot_order.DataSize)
714 unparse_boot_order(data, boot_order.DataSize / sizeof(uint16_t));
723 EFI_LOAD_OPTION *load_option;
725 list_for_each(pos, &boot_entry_list) {
726 boot = list_entry(pos, var_entry_t, list);
727 load_option = (EFI_LOAD_OPTION *)
729 if (boot->num == opts.bootnum) {
730 if (opts.active == 1) {
731 if (load_option->attributes
732 & LOAD_OPTION_ACTIVE) return EFI_SUCCESS;
734 load_option->attributes
735 |= LOAD_OPTION_ACTIVE;
736 return write_variable(&boot->var_data);
739 else if (opts.active == 0) {
740 if (!(load_option->attributes
741 & LOAD_OPTION_ACTIVE))
744 load_option->attributes
745 &= ~LOAD_OPTION_ACTIVE;
746 return write_variable(&boot->var_data);
760 efi_guid_t guid = EFI_GLOBAL_VARIABLE;
762 memset(&var, 0, sizeof(var));
764 efichar_from_char(var.VariableName, "BootOrder",
766 memcpy(&var.VendorGuid, &guid, sizeof(guid));
767 return write_variable(&var);
774 printf("efibootmgr version %s\n", EFIBOOTMGR_VERSION);
775 printf("usage: efibootmgr [options]\n");
776 printf("\t-a | --active sets bootnum active\n");
777 printf("\t-A | --inactive sets bootnum inactive\n");
778 printf("\t-b | --bootnum XXXX modify BootXXXX (hex)\n");
779 printf("\t-B | --delete-bootnum delete bootnum (hex)\n");
780 printf("\t-c | --create create new variable bootnum and add to bootorder\n");
781 printf("\t-d | --disk disk (defaults to /dev/sda) containing loader\n");
782 printf("\t-e | --edd [1|3|-1] force EDD 1.0 or 3.0 creation variables, or guess\n");
783 printf("\t-E | --device num EDD 1.0 device number (defaults to 0x80)\n");
784 printf("\t-g | --gpt force disk with invalid PMBR to be treated as GPT\n");
785 printf("\t-H | --acpi_hid XXXX set the ACPI HID (used with -i)\n");
786 printf("\t-i | --iface name create a netboot entry for the named interface\n");
787 printf("\t-l | --loader name (defaults to \\elilo.efi)\n");
788 printf("\t-L | --label label Boot manager display label (defaults to \"Linux\")\n");
789 printf("\t-n | --bootnext XXXX set BootNext to XXXX (hex)\n");
790 printf("\t-N | --delete-bootnext delete BootNext\n");
791 printf("\t-o | --bootorder XXXX,YYYY,ZZZZ,... explicitly set BootOrder (hex)\n");
792 printf("\t-O | --delete-bootorder delete BootOrder\n");
793 printf("\t-p | --part part (defaults to 1) containing loader\n");
794 printf("\t-q | --quiet be quiet\n");
795 printf("\t-t | --test filename don't write to NVRAM, write to filename.\n");
796 printf("\t-u | --unicode | --UCS-2 pass extra args as UCS-2 (default is ASCII)\n");
797 printf("\t-U | --acpi_uid XXXX set the ACPI UID (used with -i)\n");
798 printf("\t-v | --verbose print additional information\n");
799 printf("\t-V | --version return version and exit\n");
800 printf("\t-w | --write-signature write unique sig to MBR if needed\n");
806 memset(&opts, 0, sizeof(opts));
807 opts.bootnum = -1; /* auto-detect */
808 opts.bootnext = -1; /* Don't set it */
809 opts.active = -1; /* Don't set it */
810 opts.edd10_devicenum = 0x80;
811 opts.loader = "\\elilo.efi";
812 opts.label = "Linux";
813 opts.disk = "/dev/sda";
821 parse_opts(int argc, char **argv)
824 int option_index = 0;
828 static struct option long_options[] =
829 /* name, has_arg, flag, val */
831 {"active", no_argument, 0, 'a'},
832 {"inactive", no_argument, 0, 'A'},
833 {"bootnum", required_argument, 0, 'b'},
834 {"delete-bootnum", no_argument, 0, 'B'},
835 {"create", no_argument, 0, 'c'},
836 {"disk", required_argument, 0, 'd'},
837 {"iface", required_argument, 0, 'i'},
838 {"acpi_hid", required_argument, 0, 'H' },
839 {"edd-device", required_argument, 0, 'E'},
840 {"edd30", required_argument, 0, 'e'},
841 {"gpt", no_argument, 0, 'g'},
842 {"loader", required_argument, 0, 'l'},
843 {"label", required_argument, 0, 'L'},
844 {"bootnext", required_argument, 0, 'n'},
845 {"delete-bootnext", no_argument, 0, 'N'},
846 {"bootorder", required_argument, 0, 'o'},
847 {"delete-bootorder", no_argument, 0, 'O'},
848 {"part", required_argument, 0, 'p'},
849 {"quiet", no_argument, 0, 'q'},
850 {"test", required_argument, 0, 't'},
851 {"unicode", no_argument, 0, 'u'},
852 {"UCS-2", no_argument, 0, 'u'},
853 {"acpi_uid", required_argument, 0, 'U' },
854 {"verbose", optional_argument, 0, 'v'},
855 {"version", no_argument, 0, 'V'},
856 {"write-signature", no_argument, 0, 'w'},
860 c = getopt_long (argc, argv,
861 "AaBb:cd:e:E:gH:i:l:L:n:No:Op:qt:uU:v::Vw",
862 long_options, &option_index);
875 opts.delete_boot = 1;
878 rc = sscanf(optarg, "%x", &num);
879 if (rc == 1) opts.bootnum = num;
888 rc = sscanf(optarg, "%d", &num);
889 if (rc == 1) opts.edd_version = num;
892 rc = sscanf(optarg, "%x", &num);
893 if (rc == 1) opts.edd10_devicenum = num;
899 rc = sscanf(optarg, "%x", &num);
900 if (rc == 1) opts.acpi_hid = num;
906 opts.loader = optarg;
912 opts.delete_bootnext = 1;
915 rc = sscanf(optarg, "%x", &num);
916 if (rc == 1) opts.bootnext = num;
919 opts.bootorder = optarg;
922 opts.delete_bootorder = 1;
925 rc = sscanf(optarg, "%u", &num);
926 if (rc == 1) opts.part = num;
932 opts.testfile = optarg;
939 rc = sscanf(optarg, "%x", &num);
940 if (rc == 1) opts.acpi_uid = num;
945 if (!strcmp(optarg, "v")) opts.verbose = 2;
946 if (!strcmp(optarg, "vv")) opts.verbose = 3;
947 rc = sscanf(optarg, "%d", &num);
948 if (rc == 1) opts.verbose = num;
952 opts.showversion = 1;
956 opts.write_signature = 1;
968 opts.optind = optind;
974 main(int argc, char **argv)
976 struct dirent **boot_names = NULL;
977 var_entry_t *new_boot = NULL;
978 int num, num_boot_names=0;
981 parse_opts(argc, argv);
982 if (opts.showversion) {
983 printf("version %s\n", EFIBOOTMGR_VERSION);
987 if (opts.iface && opts.acpi_hid == -1 && opts.acpi_uid == -1) {
988 fprintf(stderr, "\nYou must specify the ACPI HID and UID when using -i.\n\n");
992 if (!opts.testfile) {
993 num_boot_names = read_boot_var_names(&boot_names);
994 read_vars(boot_names, num_boot_names, &boot_entry_list);
995 set_var_nums("Boot%04x-%*s", &boot_entry_list);
997 if (opts.delete_boot) {
998 if (opts.bootnum == -1)
999 fprintf(stderr, "\nYou must specify a boot entry to delete (see the -b option).\n\n");
1001 delete_boot_var(opts.bootnum);
1004 if (opts.active >= 0) {
1010 warn_duplicate_name(&boot_entry_list);
1011 new_boot = make_boot_var(&boot_entry_list);
1012 /* Put this boot var in the right BootOrder */
1013 if (!opts.testfile && new_boot)
1014 add_to_boot_order(new_boot->num);
1017 if (!opts.testfile) {
1019 if (opts.delete_bootorder) {
1020 delete_boot_order();
1023 if (opts.bootorder) {
1028 if (opts.delete_bootnext) {
1032 if (opts.bootnext >= 0) {
1033 set_boot_next(opts.bootnext & 0xFFFF);
1037 num = read_boot_next();
1039 printf("BootNext: %04x\n", num);
1041 num = read_boot_current();
1043 printf("BootCurrent: %04x\n", num);
1049 free_dirents(boot_names, num_boot_names);