4 * Copyright (C) 2002-2003 Hewlett-Packard Co
5 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
7 * This file is part of the ELILO, the EFI Linux boot loader.
9 * ELILO is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
14 * ELILO is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with ELILO; see the file COPYING. If not, write to the Free
21 * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
27 * This program is used to set the EliloAlt EFI variable to influence
28 * how elilo will behave at the next reboot. This variable is used
29 * to boot a certain kernel/configuration only once (debug, for instance).
31 * This is is supposed to be installed in /usr/sbin/eliloalt and must only
34 #include <sys/types.h>
47 #define ELILOALT_VERSION "0.02"
49 #define ELILO_ALT_NAME "EliloAlt"
50 #define EFIVAR_DIR "/sys/firmware/efi/vars"
51 #define OFIVAR_DIR "/proc/efi/vars"
52 #define ELILO_ALTVAR EFIVAR_DIR"/"ELILO_ALT_NAME"-00000000-0000-0000-0000-000000000000"
53 #define OLILO_ALTVAR OFIVAR_DIR"/"ELILO_ALT_NAME"-00000000-0000-0000-0000-000000000000"
55 #define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001
56 #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
57 #define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004
59 typedef unsigned long efi_status_t;
60 typedef uint8_t efi_bool_t;
61 typedef uint16_t efi_char16_t; /* UNICODE character */
64 * EFI GUID type definition
74 * EFI variable structure
76 typedef struct _efi_variable_t {
77 efi_char16_t variablename[1024/sizeof(efi_char16_t)];
78 efi_guid_t vendorguid;
83 } __attribute__((packed)) efi_variable_t;
85 static char *efivar_dir = EFIVAR_DIR;
86 static char *elilo_alt_name = ELILO_ALT_NAME;
87 static char *elilo_altvar = ELILO_ALTVAR;
89 static struct option cmd_options[]={
90 { "version", 0, 0, 1},
98 static void fatal_error(char *fmt,...) __attribute__((noreturn));
101 fatal_error(char *fmt, ...)
106 vfprintf(stderr, fmt, ap);
116 printf("Usage: %s [OPTIONS] cmdline\n", argv[0]);
118 printf( "-h, --help\t\tdisplay this help and exit\n"
119 "--version\t\toutput version information and exit\n"
120 "-s, --set cmdline\tset elilo alternate variable to cmdline\n"
121 "-p, --print\t\tprint elilo alternate variable\n"
122 "-d, --delete\t\tprint elilo alternate variable\n"
127 check_proc_efi(int find_entry)
130 struct dirent *entry;
131 static char name[1024];
134 fatal_error("This program must be run as root\n");
136 efi_vars = opendir(efivar_dir);
137 if (efi_vars == NULL) {
138 efivar_dir = OFIVAR_DIR;
139 elilo_altvar = OLILO_ALTVAR;
140 efi_vars = opendir(efivar_dir);
142 if (efi_vars == NULL) {
143 fatal_error("Can access neither %s nor %s\n",
144 EFIVAR_DIR, efivar_dir);
150 /* Find one entry we can open */
151 while ((entry = readdir(efi_vars)) != NULL) {
152 if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
156 fatal_error("Cannot find entry in %s\n", efivar_dir);
158 snprintf(name, 1023, "%s/%s", efivar_dir, entry->d_name);
172 fd = open(elilo_altvar, O_WRONLY);
174 fatal_error("variable not defined\n");
177 memset(&var, 0, sizeof(var));
179 for (i=0; i < sizeof(elilo_alt_name); i++) {
180 var.variablename[i] = (efi_char16_t)elilo_alt_name[i];
184 * we use NULL GUID so no need to initialize it now memset() did it
185 * writing with a datasize=0 will effectively delete the variable.
188 r = write(fd, &var, sizeof(var));
189 if (r != sizeof(var)) {
190 fatal_error("Variable %s defined but invalid content\n", elilo_altvar);
205 fd = open(elilo_altvar, O_RDONLY);
207 fatal_error("variable not defined\n");
210 memset(&var, 0, sizeof(var));
212 r = read(fd, &var, sizeof(var));
213 if (r != sizeof(var)) {
214 fatal_error("Variable %s defined but invalid content\n", elilo_altvar);
216 printf("EliloAlt=\"");
217 for(i=0; i < var.datasize; i+=1){
218 printf("%c", var.data[i]);
225 set_var(char *cmdline)
231 name = check_proc_efi(1);
233 if (cmdline == NULL) {
234 fatal_error("invalid cmdline argument\n");
240 fatal_error("Variable content is too long, must be <= 512 characters\n");
243 fd = open(name, O_WRONLY);
245 fatal_error("can't open %s: %s\n", elilo_altvar, strerror(errno));
248 memset(&var, 0, sizeof(var));
250 for (i=0; i < sizeof(elilo_alt_name); i++) {
251 var.variablename[i] = (efi_char16_t)elilo_alt_name[i];
254 for (i=0, j=0; i < l; i++, j+=2) {
255 var.data[j] = (efi_char16_t)cmdline[i];
257 /* +2 = include char16 for null termination */
260 var.attributes = EFI_VARIABLE_NON_VOLATILE
261 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
264 * we use NULL GUID so no need to initialize it now memset() did it
265 * writing with a datasize=0 will effectively delete the variable.
268 r = write(fd, &var, sizeof(var));
269 if (r != sizeof(var)) {
270 fatal_error("Variable %s defined but invalid content %d\n", elilo_altvar, r);
277 main(int argc, char **argv)
281 while ((c=getopt_long(argc, argv,"hdps:", cmd_options, 0)) != -1) {
283 case 0: continue; /* fast path for options */
285 printf("Version %s Date: %s\n", ELILOALT_VERSION, __DATE__);
304 fatal_error("Unknown option\n");