efivars.c revision 2eec67acbb00593e414549a7e5b35eb7dd776b1b
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include "util.h"
#include "utf8.h"
#include "efivars.h"
#ifdef ENABLE_EFI
#define LOAD_OPTION_ACTIVE 0x00000001
#define MEDIA_DEVICE_PATH 0x04
#define MEDIA_HARDDRIVE_DP 0x01
#define MEDIA_FILEPATH_DP 0x04
#define SIGNATURE_TYPE_GUID 0x02
#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
#define END_DEVICE_PATH_TYPE 0x7f
#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
struct boot_option {
} __attribute__((packed));
struct drive_path {
char signature[16];
} __attribute__((packed));
struct device_path {
union {
struct drive_path drive;
};
} __attribute__((packed));
bool is_efi_boot(void) {
}
int r;
_cleanup_free_ void *v = NULL;
size_t s;
uint8_t b;
if (r < 0)
return r;
if (s != 1)
return -EINVAL;
b = *(uint8_t *)v;
r = b > 0;
return r;
}
int is_efi_secure_boot(void) {
return read_flag("SecureBoot");
}
int is_efi_secure_boot_setup_mode(void) {
return read_flag("SetupMode");
}
int efi_get_variable(
const char *name,
void **value,
_cleanup_free_ char *p = NULL;
uint32_t a;
ssize_t n;
void *r;
if (asprintf(&p,
"/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
return -ENOMEM;
if (fd < 0)
return -errno;
return -errno;
return -EIO;
return -E2BIG;
if (n < 0)
return -errno;
if (n != sizeof(a))
return -EIO;
if (!r)
return -ENOMEM;
if (n < 0) {
free(r);
return -errno;
}
free(r);
return -EIO;
}
/* Always NUL terminate (2 bytes, to protect UTF-16) */
*value = r;
if (attribute)
*attribute = a;
return 0;
}
int efi_set_variable(
const char *name,
const void *value,
struct var {
char buf[];
char *p = NULL;
int fd = -1;
int r;
if (asprintf(&p,
"/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
return -ENOMEM;
if (size == 0) {
r = unlink(p);
goto finish;
}
if (fd < 0) {
r = -errno;
goto finish;
}
if (!buf) {
r = -errno;
goto finish;
}
if (r < 0) {
r = -errno;
goto finish;
}
r = -EIO;
goto finish;
}
if (fd >= 0)
free(p);
return r;
}
_cleanup_free_ void *s = NULL;
int r;
char *x;
if (r < 0)
return r;
x = utf16_to_utf8(s, ss);
if (!x)
return -ENOMEM;
*p = x;
return 0;
}
size_t l = 0;
while (s[l] > 0)
l++;
return (l+1) * sizeof(uint16_t);
}
struct uuid {
} _packed_;
}
int efi_get_boot_option(
char **title,
char **path,
bool *active) {
struct boot_option {
} _packed_;
struct drive_path {
char signature[16];
} _packed_;
struct device_path {
union {
struct drive_path drive;
};
} _packed_;
char boot_id[9];
size_t l;
struct boot_option *header;
char *s = NULL;
char *p = NULL;
int err;
if (err < 0)
return err;
if (l < sizeof(struct boot_option))
return -ENOENT;
return -EINVAL;
if (title) {
if (!s) {
goto err;
}
}
dnext = 0;
struct device_path *dpath;
break;
/* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
break;
/* Type 0x04 – Media Device Path */
continue;
/* Sub-Type 1 – Hard Drive */
/* 0x02 – GUID Partition Table */
continue;
/* 0x02 – GUID signature */
continue;
if (part_uuid)
continue;
}
/* Sub-Type 4 – File Path */
continue;
}
}
}
if (title)
*title = s;
if (part_uuid)
if (path)
*path = p;
if (active)
return 0;
err:
free(s);
free(p);
return err;
}
int i;
for (i = 0; src[i] != '\0'; i++)
dest[i] = '\0';
}
struct guid {
} __attribute__((packed));
}
uint16_t *p;
for (p = s; *p; p++)
if (*p == '/')
*p = '\\';
return s;
}
char *efi_tilt_backslashes(char *s) {
char *p;
for (p = s; *p; p++)
if (*p == '\\')
*p = '/';
return s;
}
char boot_id[9];
char *buf;
struct boot_option *option;
struct device_path *devicep;
int err;
sizeof(struct drive_path) +
if (!buf) {
goto finish;
}
/* header */
/* partition info */
/* path to loader */
/* end of path */
return err;
}
char boot_id[9];
}
void *buf;
size_t l;
int r;
if (r < 0)
return r;
if (l <= 0) {
return -ENOENT;
}
if ((l % sizeof(uint16_t) > 0) ||
return -EINVAL;
}
return (int) (l / sizeof(uint16_t));
}
}
static int boot_id_hex(const char s[4]) {
int i;
int id = 0;
for (i = 0; i < 4; i++)
if (s[i] >= '0' && s[i] <= '9')
else if (s[i] >= 'A' && s[i] <= 'F')
else
return -EINVAL;
return id;
}
return (int)*a - (int)*b;
}
int count = 0, r;
if (!dir)
return -errno;
int id;
uint16_t *t;
continue;
continue;
continue;
if (id < 0)
continue;
if (!t) {
r = -ENOMEM;
goto fail;
}
list = t;
}
return count;
fail:
return r;
}
_cleanup_free_ char *j = NULL;
int r;
uint64_t x = 0;
assert(u);
if (r < 0)
return r;
r = safe_atou64(j, &x);
if (r < 0)
return r;
*u = x;
return 0;
}
uint64_t x, y;
int r;
if (r < 0)
return r;
if (r < 0)
return r;
if (y == 0 || y < x)
return -EIO;
if (y > USEC_PER_HOUR)
return -EIO;
*firmware = x;
*loader = y;
return 0;
}
int efi_loader_get_device_part_uuid(sd_id128_t *u) {
_cleanup_free_ char *p = NULL;
int r, parsed[16];
if (r < 0)
return r;
if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
return -EIO;
if (u) {
unsigned i;
for (i = 0; i < ELEMENTSOF(parsed); i++)
}
return 0;
}
#endif