Imported Debian patch 0.5.4-1
[debian/efibootmgr] / src / efibootmgr / efibootmgr.c
index 41841432d8cdbe4bcd864d84a4b829fe525f3242..5db0d9e65e1304d17dbeef09e6fe6631614f69f7 100644 (file)
@@ -1,7 +1,7 @@
 /*
   efibootmgr.c - Manipulates EFI variables as exported in /proc/efi/vars
 
-  Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+  Copyright (C) 2001-2004 Dell, Inc. <Matt_Domsch@dell.com>
 
     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 <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -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; i<length; i++) {
-               printf("%04x", order[i]);
+               printf("%04X", order[i]);
                if (i < (length-1))
                        printf(",");
        }
        printf("\n");
 }
 
+static int
+is_current_boot_entry(int b)
+{
+       list_t *pos;
+       var_entry_t *boot;
+
+       list_for_each(pos, &boot_entry_list) {
+               boot = list_entry(pos, var_entry_t, list);
+               if (boot->num == 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; i<length && *buffer; i++) {
                rc = sscanf(buffer, "%x", &num);
                if (rc == 1) order[i] = num & 0xFFFF;
+               else {
+                       fprintf(stderr,"\nInvalid hex characters in boot order: %s\n\n",buffer);
+                       return -1;
+               }
+               /* make sure this is an existing boot entry */
+               if (!is_current_boot_entry(order[i])) {
+                       fprintf (stderr,"\nboot entry %X does not exist\n\n",order[i]);
+                       return -1;
+               }
+
                /* Advance to the comma */ 
                while (*buffer && *buffer != ',') buffer++;
                /* Advance through the comma(s) */
@@ -624,23 +631,19 @@ parse_boot_order(char *buffer, uint16_t *order, int length)
 static efi_status_t
 set_boot_order()
 {
-       efi_variable_t var;
-       efi_guid_t guid = EFI_GLOBAL_VARIABLE;
-       uint16_t *n = (uint16_t *)var.Data;
+       efi_variable_t boot_order;
+       uint16_t *n = (uint16_t *)boot_order.Data;
 
        if (!opts.bootorder) return EFI_SUCCESS;
 
-       memset(&var, 0, sizeof(var));
-
-       efichar_from_char(var.VariableName, "BootOrder",
-                         1024);
-       memcpy(&var.VendorGuid, &guid, sizeof(guid));
-       var.Attributes = EFI_VARIABLE_NON_VOLATILE
-               | EFI_VARIABLE_BOOTSERVICE_ACCESS
-               | EFI_VARIABLE_RUNTIME_ACCESS;
+       memset(&boot_order, 0, sizeof(boot_order));
+       fill_var(&boot_order, "BootOrder");
 
-       var.DataSize = parse_boot_order(opts.bootorder, n, 1024/sizeof(uint16_t)) * sizeof(uint16_t);
-       return write_variable(&var);
+       boot_order.DataSize = parse_boot_order(opts.bootorder, n, 1024/sizeof(uint16_t)) * sizeof(uint16_t);
+       if (boot_order.DataSize < 0)
+               return 1;
+       else
+               return create_or_edit_variable(&boot_order);
 }
 
 static void
@@ -662,7 +665,11 @@ show_boot_vars()
                                load_option->description, 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;
 }