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 "/proc/efi/vars"
51 #define ELILO_ALTVAR EFIVAR_DIR"/"ELILO_ALT_NAME"-00000000-0000-0000-0000-000000000000"
53 #define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001
54 #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
55 #define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004
57 typedef unsigned long efi_status_t;
58 typedef uint8_t efi_bool_t;
59 typedef uint16_t efi_char16_t; /* UNICODE character */
62 * EFI GUID type definition
72 * EFI variable structure
74 typedef struct _efi_variable_t {
75 efi_char16_t variablename[1024/sizeof(efi_char16_t)];
76 efi_guid_t vendorguid;
81 } __attribute__((packed)) efi_variable_t;
83 static char *elilo_alt_name = ELILO_ALT_NAME;
85 static struct option cmd_options[]={
86 { "version", 0, 0, 1},
94 static void fatal_error(char *fmt,...) __attribute__((noreturn));
97 fatal_error(char *fmt, ...)
102 vfprintf(stderr, fmt, ap);
112 printf("Usage: %s [OPTIONS] cmdline\n", argv[0]);
114 printf( "-h, --help\t\tdisplay this help and exit\n"
115 "--version\t\toutput version information and exit\n"
116 "-s, --set cmdline\tset elilo alternate variable to cmdline\n"
117 "-p, --print\t\tprint elilo alternate variable\n"
118 "-d, --delete\t\tprint elilo alternate variable\n"
123 check_proc_efi(int find_entry)
126 struct dirent *entry;
127 static char name[1024];
130 fatal_error("This program must be run as root\n");
132 efi_vars = opendir(EFIVAR_DIR);
133 if (efi_vars == NULL) {
134 fatal_error("Cannot access %s\n", EFIVAR_DIR);
140 /* Find one entry we can open */
141 while ((entry = readdir(efi_vars)) != NULL) {
142 if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
146 fatal_error("Cannot find entry in %s\n", EFIVAR_DIR);
148 sprintf(name, "%s/%s", EFIVAR_DIR, entry->d_name);
161 fd = open(ELILO_ALTVAR, O_WRONLY);
163 fatal_error("variable not defined\n");
166 memset(&var, 0, sizeof(var));
168 for (i=0; i < sizeof(elilo_alt_name); i++) {
169 var.variablename[i] = (efi_char16_t)elilo_alt_name[i];
173 * we use NULL GUID so no need to initialize it now memset() did it
174 * writing with a datasize=0 will effectively delete the variable.
177 r = write(fd, &var, sizeof(var));
178 if (r != sizeof(var)) {
179 fatal_error("Variable %s defined but invalid content\n", ELILO_ALTVAR);
194 fd = open(ELILO_ALTVAR, O_RDONLY);
196 fatal_error("variable not defined\n");
199 memset(&var, 0, sizeof(var));
201 r = read(fd, &var, sizeof(var));
202 if (r != sizeof(var)) {
203 fatal_error("Variable %s defined but invalid content\n", ELILO_ALTVAR);
205 printf("EliloAlt=\"");
206 for(i=0; i < var.datasize; i+=1){
207 printf("%c", var.data[i]);
214 set_var(char *cmdline)
220 name = check_proc_efi(1);
222 if (cmdline == NULL) {
223 fatal_error("invalid cmdline argument\n");
229 fatal_error("Variable content is too long, must be <= 512 characters\n");
232 fd = open(name, O_WRONLY);
234 fatal_error("can't open %s: %s\n", ELILO_ALTVAR, strerror(errno));
237 memset(&var, 0, sizeof(var));
239 for (i=0; i < sizeof(elilo_alt_name); i++) {
240 var.variablename[i] = (efi_char16_t)elilo_alt_name[i];
243 for (i=0, j=0; i < l; i++, j+=2) {
244 var.data[j] = (efi_char16_t)cmdline[i];
246 /* +2 = include char16 for null termination */
249 var.attributes = EFI_VARIABLE_NON_VOLATILE
250 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
253 * we use NULL GUID so no need to initialize it now memset() did it
254 * writing with a datasize=0 will effectively delete the variable.
257 r = write(fd, &var, sizeof(var));
258 if (r != sizeof(var)) {
259 fatal_error("Variable %s defined but invalid content %d\n", ELILO_ALTVAR, r);
266 main(int argc, char **argv)
270 while ((c=getopt_long(argc, argv,"hdps:", cmd_options, 0)) != -1) {
272 case 0: continue; /* fast path for options */
274 printf("Version %s Date: %s\n", ELILOALT_VERSION, __DATE__);
293 fatal_error("Unknown option\n");