From 97bd07c9b40659a197c4be1d07adf19ae95f5949 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 4 Aug 2016 13:48:34 -0400 Subject: [PATCH] efivar: add an api to inspect errors that occurred in more detail. I'm tired of manually debugging everything in the world, so add this API that gives our callers more detail and verbosity about errors that occur. Signed-off-by: Peter Jones --- gcc.specs | 2 +- src/Makefile | 2 +- src/error.c | 151 ++++++++++++++++++++++++++++++++++++++++++++ src/include/efivar/efivar.h | 58 +++++++++++++++++ src/libefivar.map.in | 3 + 5 files changed, 214 insertions(+), 2 deletions(-) create mode 100644 src/error.c diff --git a/gcc.specs b/gcc.specs index 0d4bbda..a9c3ce5 100644 --- a/gcc.specs +++ b/gcc.specs @@ -2,7 +2,7 @@ + -D_GNU_SOURCE *efivar_cpp_options: - -Werror -Wall -std=gnu11 -Wextra + -Werror -Wall -std=gnu11 -Wextra -Wno-nonnull-compare *cpp_options: + %(efivar_cpp_options) diff --git a/src/Makefile b/src/Makefile index 826266a..5216602 100644 --- a/src/Makefile +++ b/src/Makefile @@ -14,7 +14,7 @@ TARGETS=$(LIBTARGETS) $(STATICLIBTARGETS) $(BINTARGETS) $(PCTARGETS) LIBEFIBOOT_SOURCES = crc32.c creator.c disk.c gpt.c linux.c loadopt.c LIBEFIBOOT_OBJECTS = $(patsubst %.c,%.o,$(LIBEFIBOOT_SOURCES)) LIBEFIVAR_SOURCES = dp.c dp-acpi.c dp-hw.c dp-media.c dp-message.c \ - efivarfs.c export.c guid.c guids.S guid-symbols.c \ + efivarfs.c error.c export.c guid.c guids.S guid-symbols.c \ lib.c vars.c LIBEFIVAR_OBJECTS = $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(LIBEFIVAR_SOURCES))) EFIVAR_SOURCES = efivar.c diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..e8e3004 --- /dev/null +++ b/src/error.c @@ -0,0 +1,151 @@ +/* + * libefiboot - library for the manipulation of EFI boot variables + * Copyright 2012-2015 Red Hat, Inc. + * Copyright (C) 2000-2001 Dell Computer Corporation + * + * This library is free software; you can redistribute it and/or + * modify it 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. + * + * This library 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 this library; if not, see + * . + * + */ +#include +#include +#include +#include +#include +#include + + +typedef struct { + int error; + char *filename; + char *function; + int line; + char *message; +} error_table_entry; + +static error_table_entry *error_table; +static unsigned int current; + +int +__attribute__((__visibility__ ("default"))) +__attribute__((__nonnull__ (2, 3, 4, 5, 6))) +efi_error_get(unsigned int n, + char ** const filename, + char ** const function, + int *line, + char ** const message, + int *error + ) +{ + if (!filename || !function || !line || !message || !error) { + errno = EINVAL; + return -1; + } + + if (n >= current) + return 0; + + *filename = error_table[n].filename; + *function = error_table[n].function; + *line = error_table[n].line; + *message = error_table[n].message; + *error = error_table[n].error; + + return 1; +} + +int +__attribute__((__visibility__ ("default"))) +__attribute__((__nonnull__ (1, 2, 5))) +__attribute__((__format__ (printf, 5, 6))) +efi_error_set(const char *filename, + const char *function, + int line, + int error, + const char *fmt, ...) +{ + error_table_entry et = { 0, }; + error_table_entry *table; + char *tmp; + + table = realloc(error_table, sizeof(et) * (current +1)); + if (!table) + goto err; + error_table = table; + + et.error = error; + et.line = line; + tmp = filename ? strdup(filename) : NULL; + if (!tmp) + goto err; + et.filename = tmp; + + tmp = function ? strdup(function) : NULL; + if (!tmp) + goto err; + et.function = tmp; + + if (fmt) { + int rc; + int saved_errno; + va_list ap; + + tmp = NULL; + va_start(ap, fmt); + rc = vasprintf(&tmp, fmt, ap); + saved_errno = errno; + va_end(ap); + errno = saved_errno; + if (rc < 0) + goto err; + et.message = tmp; + } + + memcpy(&error_table[current], &et, sizeof(et)); + current += 1; + return current; +err: + if (et.filename) + free(et.filename); + if (et.function) + free(et.function); + if (et.message) + free(et.message); + errno = ENOMEM; + return -1; +} + +void +__attribute__((__visibility__ ("default"))) +__attribute__((destructor)) +efi_error_clear(void) +{ + if (error_table) { + for (unsigned int i = 0; i < current; i++) { + error_table_entry *et = &error_table[i]; + + if (et->filename) + free(et->filename); + if (et->function) + free(et->function); + if (et->message) + free(et->message); + + memset(et, '\0', sizeof(*et)); + } + free(error_table); + } + error_table = NULL; + current = 0; +} diff --git a/src/include/efivar/efivar.h b/src/include/efivar/efivar.h index 21f6b46..27dc34e 100644 --- a/src/include/efivar/efivar.h +++ b/src/include/efivar/efivar.h @@ -151,6 +151,64 @@ extern int efi_variable_get_attributes(efi_variable_t *var, uint64_t *attrs) extern int efi_variable_realize(efi_variable_t *var) __attribute__((__nonnull__ (1))); +#ifndef EFIVAR_BUILD_ENVIRONMENT +extern int efi_error_get(unsigned int n, + char ** const filename, + char ** const function, + int *line, + char ** const message, + int *error) + __attribute__((__nonnull__ (2, 3, 4, 5, 6))); +extern int efi_error_set(const char *filename, + const char *function, + int line, + int error, + const char *fmt, ...) + __attribute__((__visibility__ ("default"))) + __attribute__((__nonnull__ (1, 2, 5))) + __attribute__((__format__ (printf, 5, 6))); +extern void efi_error_clear(void); +#else +static inline int +__attribute__((__nonnull__ (2, 3, 4, 5, 6))) +efi_error_get(unsigned int n __attribute__((__unused__)), + char ** const filename __attribute__((__unused__)), + char ** const function __attribute__((__unused__)), + int *line __attribute__((__unused__)), + char ** const message __attribute__((__unused__)), + int *error __attribute__((__unused__))) +{ + return 0; +} + +static inline int +__attribute__((__nonnull__ (1, 2, 5))) +__attribute__((__format__ (printf, 5, 6))) +efi_error_set(const char *filename __attribute__((__unused__)), + const char *function __attribute__((__unused__)), + int line __attribute__((__unused__)), + int error __attribute__((__unused__)), + const char *fmt __attribute__((__unused__)), + ...) +{ + return 0; +} + +static inline void +efi_error_clear(void) +{ + return; +} +#endif + +#define efi_error_real__(errval, file, function, line, fmt, args...) \ + efi_error_set(file, function, line, errval, (fmt), ## args) + +#define efi_error(fmt, args...) \ + efi_error_real__(errno, __FILE__, __func__, __LINE__, (fmt), ## args) +#define efi_error_val(errval, msg, args...) \ + efi_error_real__(errval, __FILE__, __func__, __LINE__, (fmt), ## args) + #include #endif /* EFIVAR_H */ diff --git a/src/libefivar.map.in b/src/libefivar.map.in index ce627c8..145eb75 100644 --- a/src/libefivar.map.in +++ b/src/libefivar.map.in @@ -100,4 +100,7 @@ LIBEFIVAR_0.24 { } LIBEFIVAR_0.0; LIBEFIVAR_@@VERSION@@ { + global: efi_error_set; + efi_error_get; + efi_error_clear; }; -- 2.11.0