X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fefibootmgr%2Fefibootmgr.c.orig;fp=src%2Fefibootmgr%2Fefibootmgr.c.orig;h=5a1a0d94c1842e34cb99398f6fc2ac288f9d67ee;hb=08b92cb68b9f2371c663367e9d529391960e6106;hp=0000000000000000000000000000000000000000;hpb=d96a8f66c5fe2fac79073cc40e6f57f04c5bb4f1;p=debian%2Fefibootmgr diff --git a/src/efibootmgr/efibootmgr.c.orig b/src/efibootmgr/efibootmgr.c.orig new file mode 100644 index 0000000..5a1a0d9 --- /dev/null +++ b/src/efibootmgr/efibootmgr.c.orig @@ -0,0 +1,1045 @@ +/* + efibootmgr.c - Manipulates EFI variables as exported in /proc/efi/vars + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + This must tie the EFI_DEVICE_PATH to /boot/efi/elilo.efi + The EFI_DEVICE_PATH will look something like: + ACPI device path, length 12 bytes + Hardware Device Path, PCI, length 6 bytes + Messaging Device Path, SCSI, length 8 bytes, or ATAPI, length ?? + Media Device Path, Hard Drive, partition XX, length 30 bytes + Media Device Path, File Path, length ?? + End of Hardware Device Path, length 4 + Arguments passed to elilo, as UCS-2 characters, length ?? + +*/ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "list.h" +#include "efi.h" +#include "efichar.h" +#include "unparse_path.h" +#include "disk.h" +#include "efibootmgr.h" + + +#ifndef EFIBOOTMGR_VERSION +#define EFIBOOTMGR_VERSION "unknown (fix Makefile!)" +#endif + + +typedef struct _var_entry { + struct dirent *name; + uint16_t num; + efi_variable_t var_data; + list_t list; +} var_entry_t; + + +/* global variables */ +static LIST_HEAD(boot_entry_list); +static LIST_HEAD(blk_list); +efibootmgr_opt_t opts; + +static inline void +var_num_from_name(const char *pattern, char *name, uint16_t *num) +{ + sscanf(name, pattern, num); +} + +static void +fill_bootvar_name(char *dest, size_t len, const char *name) +{ + 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); +} + +static void +fill_var(efi_variable_t *var, const char *name) +{ + efi_guid_t guid = EFI_GLOBAL_VARIABLE; + + 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; +} + +static void +free_vars(list_t *head) +{ + list_t *pos, *n; + var_entry_t *boot; + + list_for_each_safe(pos, n, head) { + boot = list_entry(pos, var_entry_t, list); + list_del(&(boot->list)); + free(boot); + } +} + +static void +read_vars(struct dirent **namelist, + int num_boot_names, + list_t *head) +{ + efi_status_t status; + var_entry_t *entry; + int i; + + if (!namelist) return; + + for (i=0; i < num_boot_names; i++) + { + if (namelist[i]) { + entry = malloc(sizeof(var_entry_t)); + if (!entry) return; + memset(entry, 0, sizeof(var_entry_t)); + + status = read_variable(namelist[i]->d_name, + &entry->var_data); + if (status != EFI_SUCCESS) break; + entry->name = namelist[i]; + list_add_tail(&entry->list, head); + } + } + return; +} + + + + + +static void +free_dirents(struct dirent **ptr, int num_dirents) +{ + int i; + if (!ptr) return; + for (i=0; i < num_dirents; i++) { + if (ptr[i]) { + free(ptr[i]); + ptr[i] = NULL; + } + } + free(ptr); +} + + + +static int +compare(const void *a, const void *b) +{ + int rc = -1; + uint32_t n1, n2; + memcpy(&n1, a, sizeof(n1)); + memcpy(&n2, b, sizeof(n2)); + if (n1 < n2) rc = -1; + if (n1 == n2) rc = 0; + if (n2 > n2) rc = 1; + return rc; +} + + +/* + Return an available boot variable number, + or -1 on failure. +*/ +static int +find_free_boot_var(list_t *boot_list) +{ + int num_vars=0, i=0, found; + uint16_t *vars, free_number; + list_t *pos; + var_entry_t *boot; + list_for_each(pos, boot_list) { + num_vars++; + } + vars = malloc(sizeof(uint16_t) * num_vars); + if (!vars) return -1; + memset(vars, 0, sizeof(uint16_t) * num_vars); + + list_for_each(pos, boot_list) { + boot = list_entry(pos, var_entry_t, list); + vars[i] = boot->num; + i++; + } + qsort(vars, i, sizeof(uint16_t), compare); + found = 1; + + num_vars = i; + for (free_number = 0; free_number < num_vars && found; free_number++) { + found = 0; + list_for_each(pos, boot_list) { + boot = list_entry(pos, var_entry_t, list); + if (boot->num == free_number) { + found = 1; + break; + } + } + if (!found) break; + } + if (found && num_vars) free_number = vars[num_vars-1] + 1; + free(vars); + return free_number; +} + + +static void +warn_duplicate_name(list_t *boot_list) +{ + list_t *pos; + var_entry_t *boot; + EFI_LOAD_OPTION *load_option; + + list_for_each(pos, boot_list) { + boot = list_entry(pos, var_entry_t, list); + load_option = (EFI_LOAD_OPTION *) + boot->var_data.Data; + if (!efichar_char_strcmp(opts.label, + load_option->description)) { + fprintf(stderr, "** Warning ** : %.8s has same label %s\n", + boot->name->d_name, + opts.label); + } + } +} + + +static var_entry_t * +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 { + 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; + + /* Create a new var_entry_t object + and populate it. + */ + + boot = malloc(sizeof(*boot)); + if (!boot) return NULL; + memset(boot, 0, sizeof(*boot)); + boot->num = free_number; + if (!make_linux_efi_variable(&boot->var_data, free_number)) { + free(boot); + return NULL; + } + 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; + + status = read_boot(boot_order, "BootOrder"); + if (status != EFI_SUCCESS && status != EFI_NOT_FOUND) + return status; + + if (status == EFI_NOT_FOUND) { + fill_var(boot_order, "BootOrder"); + } + return EFI_SUCCESS; +} + + +static efi_status_t +add_to_boot_order(uint16_t num) +{ + efi_status_t status; + efi_variable_t boot_order; + uint64_t new_data_size; + uint16_t *new_data, *old_data; + + status = read_boot_order(&boot_order); + if (status != EFI_SUCCESS) return status; + + /* We've now got an array (in boot_order.Data) of the + boot order. First add our entry, then copy the old array. + */ + old_data = (uint16_t *)&(boot_order.Data); + new_data_size = boot_order.DataSize + sizeof(uint16_t); + new_data = malloc(new_data_size); + + new_data[0] = num; + memcpy(new_data+1, old_data, boot_order.DataSize); + + /* Now new_data has what we need */ + memcpy(&(boot_order.Data), new_data, new_data_size); + boot_order.DataSize = new_data_size; + return create_or_edit_variable(&boot_order); +} + + +static efi_status_t +remove_from_boot_order(uint16_t num) +{ + efi_status_t status; + efi_variable_t boot_order; + 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. + */ + old_data = (uint16_t *)&(boot_order.Data); + /* Start with the same size */ + new_data_size = boot_order.DataSize; + new_data = malloc(new_data_size); + for (old_i=0,new_i=0; + old_i < boot_order.DataSize / sizeof(uint16_t); + old_i++) { + if (old_data[old_i] != num) { + /* Copy this value */ + new_data[new_i] = old_data[old_i]; + new_i++; + } + } + + /* Now new_data has what we need */ + new_data_size = new_i * sizeof(uint16_t); + memset(&(boot_order.Data), 0, boot_order.DataSize); + memcpy(&(boot_order.Data), new_data, new_data_size); + boot_order.DataSize = new_data_size; + + return edit_variable(&boot_order); +} + +static efi_status_t +delete_var(const char *name) +{ + efi_variable_t var; + + memset(&var, 0, sizeof(var)); + fill_var(&var, name); + return delete_variable(&var); +} + +static int +read_boot_u16(const char *name) +{ + efi_status_t status; + efi_variable_t var; + uint16_t *n = (uint16_t *)(var.Data); + + memset(&var, 0, sizeof(var)); + status = read_boot(&var, name); + if (status) return -1; + return *n; +} + +static efi_status_t +set_boot_u16(const char *name, uint16_t num) +{ + efi_variable_t var; + uint16_t *n = (uint16_t *)var.Data; + + memset(&var, 0, sizeof(var)); + + fill_var(&var, name); + *n = num; + var.DataSize = sizeof(uint16_t); + return create_or_edit_variable(&var); +} + +static efi_status_t +delete_boot_var(uint16_t num) +{ + efi_status_t status; + efi_variable_t var; + char name[16]; + list_t *pos, *n; + var_entry_t *boot; + + 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); + } + + if (status) return status; + list_for_each_safe(pos, n, &boot_entry_list) { + boot = list_entry(pos, var_entry_t, list); + if (boot->num == num) { + status = remove_from_boot_order(num); + if (status) return status; + list_del(&(boot->list)); + break; /* short-circuit since it was found */ + } + } + return EFI_SUCCESS; +} + + +static void +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; + 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"); + } +} + +#if 0 +static efi_variable_t * +find_pci_scsi_disk_blk(int fd, int bus, int device, int func, + list_t *blk_list) +{ + list_t *pos; + int rc; + Scsi_Idlun idlun; + unsigned char host, channel, id, lun; + var_entry_t *blk; + efi_variable_t *blk_var; + long size = 0; + + memset(&idlun, 0, sizeof(idlun)); + rc = get_scsi_idlun(fd, &idlun); + if (rc) return NULL; + + rc = disk_get_size(fd, &size); + + idlun_to_components(&idlun, &host, &channel, &id, &lun); + + list_for_each(pos, blk_list) { + blk = list_entry(pos, var_entry_t, list); + blk_var = blk->var_data; + + if (!compare_pci_scsi_disk_blk(blk_var, + bus, device, func, + host, channel, id, lun, + 0, size)) { + return blk_var; + } + } + return NULL; +} + + + + +/* The right blkX variable contains: + 1) the PCI and SCSI information for the disk passed in disk_name + 2) Does not contain a partition field +*/ + + +static efi_variable_t * +find_disk_blk(char *disk_name, list_t *blk_list) +{ + efi_variable_t *disk_blk = NULL; + int fd, rc; + unsigned char bus=0,device=0,func=0; + int interface_type=interface_type_unknown; + unsigned int controllernum=0, disknum=0; + unsigned char part=0; + + fd = open(disk_name, O_RDONLY|O_DIRECT); + rc = disk_get_pci(fd, &bus, &device, &func); + if (rc) { + fprintf(stderr, "disk_get_pci() failed.\n"); + return NULL; + } + rc = disk_info_from_fd(fd, + &interface_type, + &controllernum, + &disknum, + &part); + if (rc) { + fprintf(stderr, "disk_info_from_fd() failed.\n"); + return NULL; + } + switch (interface_type) + { + case scsi: + return find_pci_scsi_disk_blk(fd,bus,device,func,blk_list); + break; + case ata: + return find_pci_ata_disk_blk(fd,bus,device,func,blk_list); + break; + case i2o: + return find_pci_i2o_disk_blk(fd,bus,device,func,blk_list); + break; + case md: + return find_pci_md_disk_blk(fd,bus,device,func,blk_list); + break; + default: + break; + } + return NULL; +} +#endif + +static void +unparse_boot_order(uint16_t *order, int length) +{ + int i; + printf("BootOrder: "); + for (i=0; ivar_data.Data; + efichar_to_char(description, + load_option->description, sizeof(description)); + memset(text_path, 0, sizeof(text_path)); + path = load_option_path(load_option); + 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(" "); + printf("%s", description); + + if (opts.verbose) { + unparse_path(text_path, path, + load_option->file_path_list_length); + /* Print optional data */ + optional_data_len = + boot->var_data.DataSize - + load_option->file_path_list_length - + ((char *)path - (char *)load_option); + if (optional_data_len) { + p = text_path; + p += strlen(text_path); + unparse_raw_text(p, ((uint8_t *)path) + + load_option->file_path_list_length, + optional_data_len); + } + + printf("\t%s", text_path); + } + printf("\n"); + } +} + + + +static void +show_boot_order() +{ + efi_status_t status; + efi_variable_t boot_order; + uint16_t *data; + + status = read_boot_order(&boot_order); + + if (status != EFI_SUCCESS) { + perror("show_boot_order()"); + return; + } + + /* We've now got an array (in boot_order.Data) of the + boot order. First add our entry, then copy the old array. + */ + data = (uint16_t *)&(boot_order.Data); + if (boot_order.DataSize) + unparse_boot_order(data, boot_order.DataSize / sizeof(uint16_t)); + +} + +static efi_status_t +set_active_state() +{ + list_t *pos; + var_entry_t *boot; + EFI_LOAD_OPTION *load_option; + + list_for_each(pos, &boot_entry_list) { + boot = list_entry(pos, var_entry_t, list); + load_option = (EFI_LOAD_OPTION *) + boot->var_data.Data; + if (boot->num == opts.bootnum) { + if (opts.active == 1) { + if (load_option->attributes + & LOAD_OPTION_ACTIVE) return EFI_SUCCESS; + else { + load_option->attributes + |= LOAD_OPTION_ACTIVE; + return edit_variable(&boot->var_data); + } + } + else if (opts.active == 0) { + if (!(load_option->attributes + & LOAD_OPTION_ACTIVE)) + return EFI_SUCCESS; + else { + load_option->attributes + &= ~LOAD_OPTION_ACTIVE; + return edit_variable(&boot->var_data); + } + } + } + } + return EFI_SUCCESS; +} + + + + +static void +usage() +{ + printf("efibootmgr version %s\n", EFIBOOTMGR_VERSION); + printf("usage: efibootmgr [options]\n"); + printf("\t-a | --active sets bootnum active\n"); + printf("\t-A | --inactive sets bootnum inactive\n"); + printf("\t-b | --bootnum XXXX modify BootXXXX (hex)\n"); + printf("\t-B | --delete-bootnum delete bootnum (hex)\n"); + printf("\t-c | --create create new variable bootnum and add to bootorder\n"); + printf("\t-d | --disk disk (defaults to /dev/sda) containing loader\n"); + printf("\t-e | --edd [1|3|-1] force EDD 1.0 or 3.0 creation variables, or guess\n"); + printf("\t-E | --device num EDD 1.0 device number (defaults to 0x80)\n"); + printf("\t-g | --gpt force disk with invalid PMBR to be treated as GPT\n"); + printf("\t-H | --acpi_hid XXXX set the ACPI HID (used with -i)\n"); + printf("\t-i | --iface name create a netboot entry for the named interface\n"); + printf("\t-l | --loader name (defaults to \\elilo.efi)\n"); + printf("\t-L | --label label Boot manager display label (defaults to \"Linux\")\n"); + printf("\t-n | --bootnext XXXX set BootNext to XXXX (hex)\n"); + printf("\t-N | --delete-bootnext delete BootNext\n"); + printf("\t-o | --bootorder XXXX,YYYY,ZZZZ,... explicitly set BootOrder (hex)\n"); + 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 | --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"); +} + +static void +set_default_opts() +{ + memset(&opts, 0, sizeof(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"; + opts.disk = "/dev/sda"; + opts.iface = NULL; + opts.part = 1; + opts.acpi_hid = -1; + opts.acpi_uid = -1; +} + +static void +parse_opts(int argc, char **argv) +{ + int c, num, rc; + int option_index = 0; + + while (1) + { + static struct option long_options[] = + /* name, has_arg, flag, val */ + { + {"active", no_argument, 0, 'a'}, + {"inactive", no_argument, 0, 'A'}, + {"bootnum", required_argument, 0, 'b'}, + {"delete-bootnum", no_argument, 0, 'B'}, + {"create", no_argument, 0, 'c'}, + {"disk", required_argument, 0, 'd'}, + {"iface", required_argument, 0, 'i'}, + {"acpi_hid", required_argument, 0, 'H'}, + {"edd-device", required_argument, 0, 'E'}, + {"edd30", required_argument, 0, 'e'}, + {"gpt", no_argument, 0, 'g'}, + {"loader", required_argument, 0, 'l'}, + {"label", required_argument, 0, 'L'}, + {"bootnext", required_argument, 0, 'n'}, + {"delete-bootnext", no_argument, 0, 'N'}, + {"bootorder", required_argument, 0, 'o'}, + {"delete-bootorder", no_argument, 0, 'O'}, + {"part", required_argument, 0, 'p'}, + {"quiet", no_argument, 0, 'q'}, + {"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'}, + {"verbose", optional_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, + {"write-signature", no_argument, 0, 'w'}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, + "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 'a': + opts.active = 1; + break; + case 'A': + opts.active = 0; + break; + case 'B': + opts.delete_boot = 1; + break; + case 'b': + rc = sscanf(optarg, "%X", &num); + if (rc == 1) opts.bootnum = num; + break; + case 'c': + opts.create = 1; + break; + case 'd': + opts.disk = optarg; + break; + case 'e': + rc = sscanf(optarg, "%d", &num); + if (rc == 1) opts.edd_version = num; + break; + case 'E': + rc = sscanf(optarg, "%x", &num); + if (rc == 1) opts.edd10_devicenum = num; + break; + case 'g': + opts.forcegpt = 1; + break; + case 'H': + rc = sscanf(optarg, "%x", &num); + if (rc == 1) opts.acpi_hid = num; + break; + case 'i': + opts.iface = optarg; + break; + case 'l': + opts.loader = optarg; + break; + case 'L': + opts.label = optarg; + break; + case 'N': + opts.delete_bootnext = 1; + break; + case 'n': + rc = sscanf(optarg, "%x", &num); + if (rc == 1) opts.bootnext = num; + break; + case 'o': + opts.bootorder = optarg; + break; + case 'O': + opts.delete_bootorder = 1; + break; + case 'p': + rc = sscanf(optarg, "%u", &num); + if (rc == 1) opts.part = num; + break; + case 'q': + opts.quiet = 1; + break; + case 1: + opts.testfile = optarg; + break; + case 't': + rc = sscanf(optarg, "%u", &num); + if (rc == 1) { + opts.timeout = num; + opts.set_timeout = 1; + } + break; + case 'T': + opts.delete_timeout = 1; + break; + case 'u': + opts.unicode = 1; + break; + + case 'U': + rc = sscanf(optarg, "%x", &num); + if (rc == 1) opts.acpi_uid = num; + break; + case 'v': + opts.verbose = 1; + if (optarg) { + if (!strcmp(optarg, "v")) opts.verbose = 2; + if (!strcmp(optarg, "vv")) opts.verbose = 3; + rc = sscanf(optarg, "%d", &num); + if (rc == 1) opts.verbose = num; + } + break; + case 'V': + opts.showversion = 1; + break; + + case 'w': + opts.write_signature = 1; + break; + + default: + usage(); + exit(1); + } + } + + if (optind < argc) { + opts.argc = argc; + opts.argv = argv; + opts.optind = optind; + } +} + + +int +main(int argc, char **argv) +{ + struct dirent **boot_names = NULL; + var_entry_t *new_boot = NULL; + int num, num_boot_names=0; + + set_default_opts(); + parse_opts(argc, argv); + if (opts.showversion) { + printf("version %s\n", EFIBOOTMGR_VERSION); + return 0; + } + + if (opts.iface && opts.acpi_hid == -1 && opts.acpi_uid == -1) { + fprintf(stderr, "\nYou must specify the ACPI HID and UID when using -i.\n\n"); + 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); + + if (opts.delete_boot) { + if (opts.bootnum == -1) + fprintf(stderr, "\nYou must specify a boot entry to delete (see the -b option).\n\n"); + else + delete_boot_var(opts.bootnum); + } + + if (opts.active >= 0) { + set_active_state(); + } + } + + if (opts.create) { + warn_duplicate_name(&boot_entry_list); + new_boot = make_boot_var(&boot_entry_list); + /* Put this boot var in the right BootOrder */ + if (!opts.testfile && new_boot) + add_to_boot_order(new_boot->num); + } + + if (!opts.testfile) { + + if (opts.delete_bootorder) { + delete_var("BootOrder"); + } + + if (opts.bootorder) { + set_boot_order(); + } + + + if (opts.delete_bootnext) { + delete_var("BootNext"); + } + + if (opts.delete_timeout) { + delete_var("Timeout"); + } + + if (opts.bootnext >= 0) { + set_boot_u16("BootNext", opts.bootnext & 0xFFFF); + } + + if (opts.set_timeout) { + set_boot_u16("Timeout", opts.timeout); + } + + if (!opts.quiet) { + num = read_boot_u16("BootNext"); + if (num != -1 ) { + printf("BootNext: %04X\n", num); + } + num = read_boot_u16("BootCurrent"); + if (num != -1) { + 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); + return 0; +} +