/
githubmirror
/
efivar
Обзор
Документация
Войти
/
githubmirror
/
efivar
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
28
src/generics.h
189 строк
5 KB
Peter Jones
Use efi_error() at lots of places.
10 авг 2016, 22:23
10 авг 2016, 22:23
db72014
Код
Авторство
О чём код?
/* * Copyright 2012-2016 Red Hat, Inc. * * 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 * <http://www.gnu.org/licenses/>. * */ #ifndef LIBEFIVAR_GENERIC_NEXT_VARIABLE_NAME_H #define LIBEFIVAR_GENERIC_NEXT_VARIABLE_NAME_H 1 #include <dirent.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <limits.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include "guid.h" static DIR *dir; static inline int __attribute__((unused)) generic_get_next_variable_name(const char *path, efi_guid_t **guid, char **name) { static char ret_name[NAME_MAX+1]; static efi_guid_t ret_guid; if (!guid || !name) { errno = EINVAL; efi_error("invalid arguments"); return -1; } /* if only one of guid and name are null, there's no "next" variable, * because the current variable is invalid. */ if ((*guid == NULL && *name != NULL) || (*guid != NULL && *name == NULL)) { errno = EINVAL; efi_error("invalid arguments"); return -1; } /* if dir is NULL, we're also starting over */ if (!dir) { dir = opendir(path); if (!dir) { efi_error("opendir(%s) failed", path); return -1; } int fd = dirfd(dir); if (fd < 0) { typeof(errno) errno_value = errno; efi_error("dirfd failed"); closedir(dir); errno = errno_value; return -1; } int flags = fcntl(fd, F_GETFD); if (flags < 0) { efi_error("fcntl(fd, F_GETFD) failed"); } else { flags |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, flags) < 0) efi_error("fcntl(fd, F_SETFD, flags | FD_CLOEXEC) failed"); } *guid = NULL; *name = NULL; } struct dirent *de = NULL; char *guidtext = "8be4df61-93ca-11d2-aa0d-00e098032b8c"; size_t guidlen = strlen(guidtext); while (1) { de = readdir(dir); if (de == NULL) { closedir(dir); dir = NULL; return 0; } /* a proper entry must have space for a guid, a dash, and * the variable name */ size_t namelen = strlen(de->d_name); if (namelen < guidlen + 2) continue; int rc = text_to_guid(de->d_name +namelen -guidlen, &ret_guid); if (rc < 0) { closedir(dir); dir = NULL; errno = EINVAL; efi_error("text_to_guid failed"); return -1; } strncpy(ret_name, de->d_name, sizeof(ret_name)); ret_name[namelen - guidlen - 1] = '\0'; *guid = &ret_guid; *name = ret_name; break; } return 1; } static void __attribute__((destructor)) close_dir(void); static void close_dir(void) { if (dir != NULL) { closedir(dir); dir = NULL; } } /* this is a simple read/delete/write implementation of "update". Good luck. * -- pjones */ static int __attribute__((__unused__)) __attribute__((__flatten__)) generic_append_variable(efi_guid_t guid, const char *name, uint8_t *new_data, size_t new_data_size, uint32_t new_attributes) { int rc; uint8_t *data = NULL; size_t data_size = 0; uint32_t attributes = 0; rc = efi_get_variable(guid, name, &data, &data_size, &attributes); if (rc >= 0) { if ((attributes | EFI_VARIABLE_APPEND_WRITE) != (new_attributes | EFI_VARIABLE_APPEND_WRITE)) { free(data); errno = EINVAL; return -1; } uint8_t *d = malloc(data_size + new_data_size); size_t ds = data_size + new_data_size; memcpy(d, data, data_size); memcpy(d + data_size, new_data, new_data_size); attributes &= ~EFI_VARIABLE_APPEND_WRITE; rc = efi_del_variable(guid, name); if (rc < 0) { efi_error("efi_del_variable failed"); free(data); free(d); return rc; } /* if this doesn't work, we accidentally deleted. There's * really not much to do about it, so return the error and * let our caller attempt to clean up :/ */ rc = efi_set_variable(guid, name, d, ds, attributes, 0600); if (rc < 0) efi_error("efi_set_variable failed"); free(d); free(data); } else if (errno == ENOENT) { data = new_data; data_size = new_data_size; attributes = new_attributes & ~EFI_VARIABLE_APPEND_WRITE; rc = efi_set_variable(guid, name, data, data_size, attributes, 0600); } if (rc < 0) efi_error("efi_set_variable failed"); return rc; } #endif /* LIBEFIVAR_GENERIC_NEXT_VARIABLE_NAME_H */