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>
48 #define ELILOALT_VERSION "0.02"
50 #define ELILO_ALT_NAME "EliloAlt"
51 #define OLDEFIVAR_DIR "/proc/efi/vars"
52 #define NEWEFIVAR_DIR "/sys/firmware/efi/vars"
53 #define ELILO_ALTVAR 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 *elilo_alt_name = ELILO_ALT_NAME;
86 static char *efi_vars_dir = NULL;
87 static char *elilo_altvar = NULL;
88 static char *elilo_newvar = NULL;
89 static char *elilo_delvar = NULL;
90 unsigned char efivars_version = -1;
92 static struct option cmd_options[]={
93 { "version", 0, 0, 1},
101 static void fatal_error(char *fmt,...) __attribute__((noreturn));
104 fatal_error(char *fmt, ...)
109 vfprintf(stderr, fmt, ap);
119 printf("Usage: %s [OPTIONS] cmdline\n", argv[0]);
121 printf( "-h, --help\t\tdisplay this help and exit\n"
122 "--version\t\toutput version information and exit\n"
123 "-s, --set cmdline\tset elilo alternate variable to cmdline\n"
124 "-p, --print\t\tprint elilo alternate variable\n"
125 "-d, --delete\t\tprint elilo alternate variable\n"
130 check_proc_efi(int find_entry)
133 struct dirent *entry;
134 static char name[1024];
137 fatal_error("This program must be run as root\n");
139 efi_vars = opendir(efi_vars_dir);
140 if (efi_vars == NULL) {
141 fatal_error("Cannot access %s\n", efi_vars_dir);
147 /* Find one entry we can open */
148 while ((entry = readdir(efi_vars)) != NULL) {
149 if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
153 fatal_error("Cannot find entry in %s\n", efi_vars_dir);
155 sprintf(name, "%s/%s", efi_vars_dir, entry->d_name);
168 if (efivars_version == 1) {
169 fd = open(elilo_altvar, O_WRONLY);
171 fatal_error("variable not defined\n");
174 fd = open(elilo_delvar, O_WRONLY);
176 fatal_error("can't open %s\n", elilo_delvar);
180 memset(&var, 0, sizeof(var));
182 for (i=0; i < sizeof(elilo_alt_name); i++) {
183 var.variablename[i] = (efi_char16_t)elilo_alt_name[i];
187 * we use NULL GUID so no need to initialize it now memset() did it
188 * writing with a datasize=0 will effectively delete the variable.
191 r = write(fd, &var, sizeof(var));
192 if (r != sizeof(var)) {
193 fatal_error("Variable %s defined but invalid content\n", elilo_altvar);
208 fd = open(elilo_altvar, O_RDONLY);
210 fatal_error("variable not defined\n");
213 memset(&var, 0, sizeof(var));
215 r = read(fd, &var, sizeof(var));
216 if (r != sizeof(var)) {
217 fatal_error("Variable %s defined but invalid content\n", elilo_altvar);
219 printf("EliloAlt=\"");
220 for(i=0; i < var.datasize; i+=1){
221 printf("%c", var.data[i]);
228 set_var(char *cmdline)
234 name = check_proc_efi(1);
236 if (cmdline == NULL) {
237 fatal_error("invalid cmdline argument\n");
243 fatal_error("Variable content is too long, must be <= 512 characters\n");
246 if (efivars_version == 1) {
247 fd = open(name, O_WRONLY);
249 fatal_error("can't open %s: %s\n", name,
253 fd = open(elilo_newvar, O_WRONLY);
255 fatal_error("can't open %s: %s\n", elilo_newvar,
259 memset(&var, 0, sizeof(var));
261 for (i=0; i < sizeof(elilo_alt_name); i++) {
262 var.variablename[i] = (efi_char16_t)elilo_alt_name[i];
265 for (i=0, j=0; i < l; i++, j+=2) {
266 var.data[j] = (efi_char16_t)cmdline[i];
268 /* +2 = include char16 for null termination */
271 var.attributes = EFI_VARIABLE_NON_VOLATILE
272 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
275 * we use NULL GUID so no need to initialize it now memset() did it
276 * writing with a datasize=0 will effectively delete the variable.
279 r = write(fd, &var, sizeof(var));
280 if (r != sizeof(var)) {
281 fatal_error("Variable %s defined but invalid content %d\n", elilo_altvar, r);
288 main(int argc, char **argv)
293 if (stat(OLDEFIVAR_DIR, &statbuf) == 0) {
294 efi_vars_dir = strdup(OLDEFIVAR_DIR);
296 } else if (stat(NEWEFIVAR_DIR, &statbuf) == 0) {
297 efi_vars_dir = strdup(NEWEFIVAR_DIR);
298 elilo_newvar = malloc(strlen(efi_vars_dir) +
299 strlen("new_var") + 2);
300 sprintf(elilo_newvar, "%s/%s", efi_vars_dir, "new_var");
301 elilo_delvar = malloc(strlen(efi_vars_dir) +
302 strlen("del_var") + 2);
303 sprintf(elilo_delvar, "%s/%s", efi_vars_dir, "del_var");
306 fatal_error("No EFI vars dir found\n\ttried:\n\t%s\n\t%s",
307 OLDEFIVAR_DIR, NEWEFIVAR_DIR);
309 elilo_altvar = malloc(strlen(efi_vars_dir)+strlen(ELILO_ALTVAR)+2);
310 sprintf(elilo_altvar, "%s/%s", efi_vars_dir, ELILO_ALTVAR);
312 while ((c=getopt_long(argc, argv,"hdps:", cmd_options, 0)) != -1) {
314 case 0: continue; /* fast path for options */
316 printf("Version %s Date: %s\n", ELILOALT_VERSION, __DATE__);
335 fatal_error("Unknown option\n");