X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fefibootmgr%2Fefibootmgr.c;h=5db0d9e65e1304d17dbeef09e6fe6631614f69f7;hb=438378f384ede73602fcdfd288e45ac41d933bb0;hp=41841432d8cdbe4bcd864d84a4b829fe525f3242;hpb=98db23750431fa650821f391aca2ce1898cb8020;p=debian%2Fefibootmgr diff --git a/src/efibootmgr/efibootmgr.c b/src/efibootmgr/efibootmgr.c index 4184143..5db0d9e 100644 --- a/src/efibootmgr/efibootmgr.c +++ b/src/efibootmgr/efibootmgr.c @@ -1,7 +1,7 @@ /* efibootmgr.c - Manipulates EFI variables as exported in /proc/efi/vars - Copyright (C) 2001 Dell Computer Corporation + Copyright (C) 2001-2004 Dell, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,6 +32,7 @@ #define _GNU_SOURCE +#include #include #include #include @@ -49,6 +50,7 @@ #include "disk.h" #include "efibootmgr.h" + #ifndef EFIBOOTMGR_VERSION #define EFIBOOTMGR_VERSION "unknown (fix Makefile!)" #endif @@ -73,55 +75,39 @@ var_num_from_name(const char *pattern, char *name, uint16_t *num) sscanf(name, pattern, num); } -static int -select_boot_var_names(const struct dirent *d) +static void +fill_bootvar_name(char *dest, size_t len, const char *name) { - int num, rc; - rc = sscanf(d->d_name, "Boot0%03x-%*s", &num); - return rc; + efi_guid_t guid = EFI_GLOBAL_VARIABLE; + char text_uuid[40]; + efi_guid_unparse(&guid, text_uuid); + snprintf(dest, len, "%s-%s", name, text_uuid); } -#if 0 -static int -select_blk_var_names(const struct dirent *d) +static void +fill_var(efi_variable_t *var, const char *name) { - int num; - return sscanf(d->d_name, "blk%x-%*s", &num); -} -#endif + efi_guid_t guid = EFI_GLOBAL_VARIABLE; -static int -read_boot_var_names(struct dirent ***namelist) -{ - int n; - n = scandir(PROC_DIR_EFI_VARS, namelist, select_boot_var_names, alphasort); - if (n < 0) { - perror("scandir " PROC_DIR_EFI_VARS); - fprintf(stderr, "You must 'modprobe efivars' before running efibootmgr.\n"); - } - return n; + efichar_from_char(var->VariableName, name, 1024); + memcpy(&var->VendorGuid, &guid, sizeof(guid)); + var->Attributes = EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS; } -#if 0 -static int -read_blk_var_names(struct dirent ***namelist) +static void +free_vars(list_t *head) { - int n; - n = scandir(PROC_DIR_EFI_VARS, namelist, select_blk_var_names, alphasort); - if (n < 0) - perror("scandir"); - return n; -} + list_t *pos, *n; + var_entry_t *boot; -static int -dirent_list_length(struct dirent **namelist) -{ - int i; - if (!namelist) return 0; - for (i=0; namelist[i]; i++); - return i; + list_for_each_safe(pos, n, head) { + boot = list_entry(pos, var_entry_t, list); + list_del(&(boot->list)); + free(boot); + } } -#endif static void read_vars(struct dirent **namelist, @@ -242,8 +228,8 @@ warn_duplicate_name(list_t *boot_list) boot->var_data.Data; if (!efichar_char_strcmp(opts.label, load_option->description)) { - fprintf(stderr, "** Warning ** : Boot%04x has same label %s\n", - boot->num, + fprintf(stderr, "** Warning ** : %.8s has same label %s\n", + boot->name->d_name, opts.label); } } @@ -255,9 +241,21 @@ make_boot_var(list_t *boot_list) { var_entry_t *boot; int free_number; + list_t *pos; - if (opts.bootnum == -1) free_number = find_free_boot_var(boot_list); - else free_number = opts.bootnum; + if (opts.bootnum == -1) + free_number = find_free_boot_var(boot_list); + else { + list_for_each(pos, boot_list) { + boot = list_entry(pos, var_entry_t, list); + if (boot->num == opts.bootnum) { + fprintf(stderr, "** Warning ** : bootnum %04X " + "already exists\n", opts.bootnum); + return NULL; + } + } + free_number = opts.bootnum; + } if (free_number == -1) return NULL; @@ -273,42 +271,39 @@ make_boot_var(list_t *boot_list) free(boot); return NULL; } - write_variable(&boot->var_data); + create_variable(&boot->var_data); list_add_tail(&boot->list, boot_list); return boot; } + + +static efi_status_t +read_boot(efi_variable_t *var, const char *name) +{ + char name_guid[PATH_MAX]; + + memset(var, 0, sizeof(*var)); + fill_bootvar_name(name_guid, sizeof(name_guid), name); + return read_variable(name_guid, var); +} + static efi_status_t read_boot_order(efi_variable_t *boot_order) { efi_status_t status; - efi_guid_t guid = EFI_GLOBAL_VARIABLE; - char boot_order_name[80], text_uuid[40]; - efi_guid_unparse(&guid, text_uuid); - - memset(boot_order, 0, sizeof(*boot_order)); - sprintf(boot_order_name, "BootOrder-%s", text_uuid); - status = read_variable(boot_order_name, boot_order); + status = read_boot(boot_order, "BootOrder"); if (status != EFI_SUCCESS && status != EFI_NOT_FOUND) return status; if (status == EFI_NOT_FOUND) { - /* Create it */ - efichar_from_char(boot_order->VariableName, "BootOrder", - 1024); - memcpy(&boot_order->VendorGuid, &guid, sizeof(guid)); - boot_order->Attributes = EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_BOOTSERVICE_ACCESS - | EFI_VARIABLE_RUNTIME_ACCESS; - return status; + fill_var(boot_order, "BootOrder"); } return EFI_SUCCESS; } - - static efi_status_t add_to_boot_order(uint16_t num) { @@ -333,7 +328,7 @@ add_to_boot_order(uint16_t num) /* Now new_data has what we need */ memcpy(&(boot_order.Data), new_data, new_data_size); boot_order.DataSize = new_data_size; - return write_variable(&boot_order); + return create_or_edit_variable(&boot_order); } @@ -345,13 +340,16 @@ remove_from_boot_order(uint16_t num) uint64_t new_data_size; uint16_t *new_data, *old_data; int old_i,new_i; + char boot_order_name[PATH_MAX]; status = read_boot_order(&boot_order); if (status != EFI_SUCCESS) return status; - /* If it's empty, yea! */ if (!boot_order.DataSize) return EFI_SUCCESS; + fill_bootvar_name(boot_order_name, sizeof(boot_order_name), + "BootOrder"); + /* We've now got an array (in boot_order.Data) of the boot order. Simply copy the array, skipping the entry we're deleting. @@ -376,104 +374,72 @@ remove_from_boot_order(uint16_t num) memcpy(&(boot_order.Data), new_data, new_data_size); boot_order.DataSize = new_data_size; - return write_variable(&boot_order); + return edit_variable(&boot_order); } -static int -read_boot_current() +static efi_status_t +delete_var(const char *name) { - efi_status_t status; - efi_variable_t boot_next; - efi_guid_t guid = EFI_GLOBAL_VARIABLE; - char boot_next_name[80], text_uuid[40]; - uint16_t *n = (uint16_t *)(boot_next.Data); - - efi_guid_unparse(&guid, text_uuid); - - memset(&boot_next, 0, sizeof(boot_next)); - sprintf(boot_next_name, "BootCurrent-%s", text_uuid); - - status = read_variable(boot_next_name, &boot_next); - if (status) return -1; + efi_variable_t var; - return *n; + memset(&var, 0, sizeof(var)); + fill_var(&var, name); + return delete_variable(&var); } static int -read_boot_next() +read_boot_u16(const char *name) { efi_status_t status; - efi_variable_t boot_next; - efi_guid_t guid = EFI_GLOBAL_VARIABLE; - char boot_next_name[80], text_uuid[40]; - uint16_t *n = (uint16_t *)(boot_next.Data); - - efi_guid_unparse(&guid, text_uuid); - - memset(&boot_next, 0, sizeof(boot_next)); - sprintf(boot_next_name, "BootNext-%s", text_uuid); + efi_variable_t var; + uint16_t *n = (uint16_t *)(var.Data); - status = read_variable(boot_next_name, &boot_next); + memset(&var, 0, sizeof(var)); + status = read_boot(&var, name); if (status) return -1; - return *n; } - static efi_status_t -set_boot_next(uint16_t num) +set_boot_u16(const char *name, uint16_t num) { efi_variable_t var; - efi_guid_t guid = EFI_GLOBAL_VARIABLE; uint16_t *n = (uint16_t *)var.Data; memset(&var, 0, sizeof(var)); - efichar_from_char(var.VariableName, "BootNext", - 1024); - memcpy(&var.VendorGuid, &guid, sizeof(guid)); + fill_var(&var, name); *n = num; var.DataSize = sizeof(uint16_t); - var.Attributes = EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_BOOTSERVICE_ACCESS - | EFI_VARIABLE_RUNTIME_ACCESS; - return write_variable(&var); -} - -static efi_status_t -delete_boot_next() -{ - efi_variable_t var; - efi_guid_t guid = EFI_GLOBAL_VARIABLE; - - memset(&var, 0, sizeof(var)); - - efichar_from_char(var.VariableName, "BootNext", - 1024); - memcpy(&var.VendorGuid, &guid, sizeof(guid)); - return write_variable(&var); + return create_or_edit_variable(&var); } - static efi_status_t delete_boot_var(uint16_t num) { efi_status_t status; efi_variable_t var; - efi_guid_t guid = EFI_GLOBAL_VARIABLE; - char name[80]; + char name[16]; list_t *pos, *n; var_entry_t *boot; - sprintf(name, "Boot%04x", num); + snprintf(name, sizeof(name), "Boot%04X", num); memset(&var, 0, sizeof(var)); + fill_var(&var, name); + status = delete_variable(&var); + + /* For backwards compatibility, try to delete abcdef entries as well */ + if (status) { + snprintf(name, sizeof(name), "Boot%04x", num); + memset(&var, 0, sizeof(var)); + fill_var(&var, name); + status = delete_variable(&var); + } - efichar_from_char(var.VariableName, name, 1024); - memcpy(&var.VendorGuid, &guid, sizeof(guid)); - status = write_variable(&var); - - if (status) return status; - + if (status) { + fprintf (stderr,"\nboot entry: %X not found\n\n",num); + return status; + } list_for_each_safe(pos, n, &boot_entry_list) { boot = list_entry(pos, var_entry_t, list); if (boot->num == num) { @@ -493,11 +459,27 @@ set_var_nums(const char *pattern, list_t *list) list_t *pos; var_entry_t *var; int num=0, rc; + char *name; + int warn=0; list_for_each(pos, list) { var = list_entry(pos, var_entry_t, list); rc = sscanf(var->name->d_name, pattern, &num); - if (rc == 1) var->num = num; + if (rc == 1) { + var->num = num; + name = var->name->d_name; /* shorter name */ + if ((isalpha(name[4]) && islower(name[4])) || + (isalpha(name[5]) && islower(name[5])) || + (isalpha(name[6]) && islower(name[6])) || + (isalpha(name[7]) && islower(name[7]))) { + fprintf(stderr, "** Warning ** : %.8s is not " + "EFI 1.10 compliant (lowercase hex in name)\n", name); + warn++; + } + } + } + if (warn) { + fprintf(stderr, "** Warning ** : please recreate these using efibootmgr to remove this warning.\n"); } } @@ -597,13 +579,28 @@ unparse_boot_order(uint16_t *order, int length) int i; printf("BootOrder: "); for (i=0; inum == b) + return 1; + } + return 0; +} + + static int parse_boot_order(char *buffer, uint16_t *order, int length) { @@ -613,6 +610,16 @@ parse_boot_order(char *buffer, uint16_t *order, int length) for (i=0; idescription, sizeof(description)); memset(text_path, 0, sizeof(text_path)); path = load_option_path(load_option); - printf("Boot%04x", boot->num); + if (boot->name) + printf("%.8s", boot->name->d_name); + else + printf("Boot%04X", boot->num); + if (load_option->attributes & LOAD_OPTION_ACTIVE) printf("* "); else printf(" "); @@ -733,7 +740,7 @@ set_active_state() else { load_option->attributes |= LOAD_OPTION_ACTIVE; - return write_variable(&boot->var_data); + return edit_variable(&boot->var_data); } } else if (opts.active == 0) { @@ -743,30 +750,18 @@ set_active_state() else { load_option->attributes &= ~LOAD_OPTION_ACTIVE; - return write_variable(&boot->var_data); + return edit_variable(&boot->var_data); } } } } - return EFI_SUCCESS; + /* if we reach here then the bootnumber supplied was not found */ + fprintf(stderr,"\nboot entry %x not found\n\n",opts.bootnum); + return EFI_NOT_FOUND; } -static efi_status_t -delete_boot_order() -{ - efi_variable_t var; - efi_guid_t guid = EFI_GLOBAL_VARIABLE; - - memset(&var, 0, sizeof(var)); - - efichar_from_char(var.VariableName, "BootOrder", - 1024); - memcpy(&var.VendorGuid, &guid, sizeof(guid)); - return write_variable(&var); -} - static void usage() @@ -792,12 +787,15 @@ usage() printf("\t-O | --delete-bootorder delete BootOrder\n"); printf("\t-p | --part part (defaults to 1) containing loader\n"); printf("\t-q | --quiet be quiet\n"); - printf("\t-t | --test filename don't write to NVRAM, write to filename.\n"); + printf("\t | --test filename don't write to NVRAM, write to filename.\n"); + printf("\t-t | --timeout seconds set boot manager timeout waiting for user input.\n"); + printf("\t-T | --delete-timeout delete Timeout.\n"); printf("\t-u | --unicode | --UCS-2 pass extra args as UCS-2 (default is ASCII)\n"); printf("\t-U | --acpi_uid XXXX set the ACPI UID (used with -i)\n"); printf("\t-v | --verbose print additional information\n"); printf("\t-V | --version return version and exit\n"); printf("\t-w | --write-signature write unique sig to MBR if needed\n"); + printf("\t-@ | --append-binary-args file append extra args from file (use \"-\" for stdin)\n"); } static void @@ -807,6 +805,7 @@ set_default_opts() opts.bootnum = -1; /* auto-detect */ opts.bootnext = -1; /* Don't set it */ opts.active = -1; /* Don't set it */ + opts.timeout = -1; /* Don't set it */ opts.edd10_devicenum = 0x80; opts.loader = "\\elilo.efi"; opts.label = "Linux"; @@ -835,7 +834,7 @@ parse_opts(int argc, char **argv) {"create", no_argument, 0, 'c'}, {"disk", required_argument, 0, 'd'}, {"iface", required_argument, 0, 'i'}, - {"acpi_hid", required_argument, 0, 'H' }, + {"acpi_hid", required_argument, 0, 'H'}, {"edd-device", required_argument, 0, 'E'}, {"edd30", required_argument, 0, 'e'}, {"gpt", no_argument, 0, 'g'}, @@ -847,24 +846,30 @@ parse_opts(int argc, char **argv) {"delete-bootorder", no_argument, 0, 'O'}, {"part", required_argument, 0, 'p'}, {"quiet", no_argument, 0, 'q'}, - {"test", required_argument, 0, 't'}, + {"test", required_argument, 0, 1}, + {"timeout", required_argument, 0, 't'}, + {"delete-timeout", no_argument, 0, 'T'}, {"unicode", no_argument, 0, 'u'}, {"UCS-2", no_argument, 0, 'u'}, - {"acpi_uid", required_argument, 0, 'U' }, + {"acpi_uid", required_argument, 0, 'U'}, {"verbose", optional_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"write-signature", no_argument, 0, 'w'}, + {"append-binary-args", required_argument, 0, '@'}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, - "AaBb:cd:e:E:gH:i:l:L:n:No:Op:qt:uU:v::Vw", + "AaBb:cd:e:E:gH:i:l:L:n:No:Op:qt:TuU:v::Vw@:", long_options, &option_index); if (c == -1) break; switch (c) { + case '@': + opts.extra_opts_file = optarg; + break; case 'a': opts.active = 1; break; @@ -875,8 +880,12 @@ parse_opts(int argc, char **argv) opts.delete_boot = 1; break; case 'b': - rc = sscanf(optarg, "%x", &num); + rc = sscanf(optarg, "%X", &num); if (rc == 1) opts.bootnum = num; + else { + fprintf (stderr,"invalid hex value %s\n",optarg); + exit(1); + } break; case 'c': opts.create = 1; @@ -887,10 +896,18 @@ parse_opts(int argc, char **argv) case 'e': rc = sscanf(optarg, "%d", &num); if (rc == 1) opts.edd_version = num; + else { + fprintf (stderr,"invalid numeric value %s\n",optarg); + exit(1); + } break; case 'E': rc = sscanf(optarg, "%x", &num); if (rc == 1) opts.edd10_devicenum = num; + else { + fprintf (stderr,"invalid hex value %s\n",optarg); + exit(1); + } break; case 'g': opts.forcegpt = 1; @@ -898,6 +915,10 @@ parse_opts(int argc, char **argv) case 'H': rc = sscanf(optarg, "%x", &num); if (rc == 1) opts.acpi_hid = num; + else { + fprintf (stderr,"invalid hex value %s\n",optarg); + exit(1); + } break; case 'i': opts.iface = optarg; @@ -914,6 +935,10 @@ parse_opts(int argc, char **argv) case 'n': rc = sscanf(optarg, "%x", &num); if (rc == 1) opts.bootnext = num; + else { + fprintf (stderr,"invalid hex value %s\n",optarg); + exit(1); + } break; case 'o': opts.bootorder = optarg; @@ -924,13 +949,31 @@ parse_opts(int argc, char **argv) case 'p': rc = sscanf(optarg, "%u", &num); if (rc == 1) opts.part = num; + else { + fprintf (stderr,"invalid numeric value %s\n",optarg); + exit(1); + } break; case 'q': opts.quiet = 1; break; - case 't': + case 1: opts.testfile = optarg; break; + case 't': + rc = sscanf(optarg, "%u", &num); + if (rc == 1) { + opts.timeout = num; + opts.set_timeout = 1; + } + else { + fprintf (stderr,"invalid numeric value %s\n",optarg); + exit(1); + } + break; + case 'T': + opts.delete_timeout = 1; + break; case 'u': opts.unicode = 1; break; @@ -938,6 +981,10 @@ parse_opts(int argc, char **argv) case 'U': rc = sscanf(optarg, "%x", &num); if (rc == 1) opts.acpi_uid = num; + else { + fprintf (stderr,"invalid hex value %s\n",optarg); + exit(1); + } break; case 'v': opts.verbose = 1; @@ -946,6 +993,10 @@ parse_opts(int argc, char **argv) if (!strcmp(optarg, "vv")) opts.verbose = 3; rc = sscanf(optarg, "%d", &num); if (rc == 1) opts.verbose = num; + else { + fprintf (stderr,"invalid numeric value %s\n",optarg); + exit(1); + } } break; case 'V': @@ -976,6 +1027,7 @@ main(int argc, char **argv) struct dirent **boot_names = NULL; var_entry_t *new_boot = NULL; int num, num_boot_names=0; + efi_status_t ret=0; set_default_opts(); parse_opts(argc, argv); @@ -989,64 +1041,97 @@ main(int argc, char **argv) return 1; } + if (!opts.testfile) + set_fs_kernel_calls(); + if (!opts.testfile) { num_boot_names = read_boot_var_names(&boot_names); read_vars(boot_names, num_boot_names, &boot_entry_list); - set_var_nums("Boot%04x-%*s", &boot_entry_list); + set_var_nums("Boot%04X-%*s", &boot_entry_list); if (opts.delete_boot) { - if (opts.bootnum == -1) + if (opts.bootnum == -1) { fprintf(stderr, "\nYou must specify a boot entry to delete (see the -b option).\n\n"); + return 1; + } else - delete_boot_var(opts.bootnum); + ret = delete_boot_var(opts.bootnum); } if (opts.active >= 0) { - set_active_state(); + if (opts.bootnum == -1) { + fprintf(stderr, "\nYou must specify a boot entry to delete (see the -b option).\n\n"); + return 1; + } + else + ret=set_active_state(); } } if (opts.create) { warn_duplicate_name(&boot_entry_list); new_boot = make_boot_var(&boot_entry_list); + if (!new_boot) + return 1; + /* Put this boot var in the right BootOrder */ if (!opts.testfile && new_boot) - add_to_boot_order(new_boot->num); + ret=add_to_boot_order(new_boot->num); } if (!opts.testfile) { if (opts.delete_bootorder) { - delete_boot_order(); + ret=delete_var("BootOrder"); } if (opts.bootorder) { - set_boot_order(); + ret=set_boot_order(); } if (opts.delete_bootnext) { - delete_boot_next(); + ret=delete_var("BootNext"); + } + + if (opts.delete_timeout) { + ret=delete_var("Timeout"); } if (opts.bootnext >= 0) { - set_boot_next(opts.bootnext & 0xFFFF); + if (!is_current_boot_entry(opts.bootnext & 0xFFFF)){ + fprintf (stderr,"\n\nboot entry %X does not exist\n\n", + opts.bootnext); + return 1; + } + ret=set_boot_u16("BootNext", opts.bootnext & 0xFFFF); } - if (!opts.quiet) { - num = read_boot_next(); + if (opts.set_timeout) { + ret=set_boot_u16("Timeout", opts.timeout); + } + + if (!opts.quiet && ret == 0) { + num = read_boot_u16("BootNext"); if (num != -1 ) { - printf("BootNext: %04x\n", num); + printf("BootNext: %04X\n", num); } - num = read_boot_current(); + num = read_boot_u16("BootCurrent"); if (num != -1) { - printf("BootCurrent: %04x\n", num); + printf("BootCurrent: %04X\n", num); + } + num = read_boot_u16("Timeout"); + if (num != -1) { + printf("Timeout: %u seconds\n", num); } show_boot_order(); show_boot_vars(); } } free_dirents(boot_names, num_boot_names); + free_vars(&boot_entry_list); + if (ret) + return 1; return 0; }