diff options
Diffstat (limited to 'common/environment.c')
-rw-r--r-- | common/environment.c | 276 |
1 files changed, 81 insertions, 195 deletions
diff --git a/common/environment.c b/common/environment.c index aba6dcde48..39cad0c16a 100644 --- a/common/environment.c +++ b/common/environment.c @@ -1,18 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program 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 General Public License for more details. - * */ /** @@ -38,8 +26,10 @@ #include <environment.h> #include <globalvar.h> #include <libfile.h> +#include <block.h> +#include <efi/partition.h> +#include <bootsource.h> #else -# define errno_str(x) ("void") #define EXPORT_SYMBOL(x) #endif @@ -56,21 +46,88 @@ struct action_data { void *writep; struct envfs_entry *env; }; -#define PAD4(x) ((x + 3) & ~3) #ifdef __BAREBOX__ #define TMPDIR "/.defaultenv" -static char *default_environment_path = "/dev/env0"; +static char *default_environment_path; -void default_environment_path_set(char *path) +void default_environment_path_set(const char *path) { - default_environment_path = path; + free(default_environment_path); + + default_environment_path = xstrdup(path); } -char *default_environment_path_get(void) +static guid_t partition_barebox_env_guid = PARTITION_BAREBOX_ENVIRONMENT_GUID; + +/* + * default_environment_path_search - look for environment partition + * + * This searches for a barebox environment partition on block devices. barebox + * environment partitions are recognized by the guid + * 6c3737f2-07f8-45d1-ad45-15d260aab24d. The device barebox itself has booted + * from is preferred over other devices. + * + * @return: The cdev providing the environment of found, NULL otherwise + */ +static struct cdev *default_environment_path_search(void) { + struct cdev *part; + struct device_node *boot_node; + int max_score = 0; + struct cdev *env_cdev = NULL; + struct block_device *blk; + + if (!IS_ENABLED(CONFIG_BLOCK)) + return NULL; + + boot_node = bootsource_of_node_get(NULL); + + if (boot_node) { + struct device *dev; + + dev = of_find_device_by_node(boot_node); + if (dev) + device_detect(dev); + } + + for_each_block_device(blk) { + int score = 0; + + part = cdev_find_child_by_gpt_typeuuid(&blk->cdev, + &partition_barebox_env_guid); + if (IS_ERR(part)) + continue; + + score++; + + if (boot_node && boot_node == blk->cdev.device_node) + score++; + + if (score > max_score) { + max_score = score; + env_cdev = part; + } + } + + return env_cdev; +} + +const char *default_environment_path_get(void) +{ + struct cdev *cdev; + + if (default_environment_path) + return default_environment_path; + + cdev = default_environment_path_search(); + if (cdev) + default_environment_path = basprintf("/dev/%s", cdev->name); + else + default_environment_path = xstrdup("/dev/env0"); + return default_environment_path; } @@ -228,17 +285,6 @@ static int file_remove_action(const char *filename, struct stat *statbuf, } #endif -static int dir_remove_action(const char *filename, struct stat *statbuf, - void *userdata, int depth) -{ - if (!depth) - return 1; - - rmdir(filename); - - return 1; -} - /** * Make the current environment persistent * @param[in] filename where to store @@ -321,7 +367,7 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags) envfd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); if (envfd < 0) { - printf("could not open %s: %s\n", filename, errno_str()); + printf("could not open %s: %m\n", filename); ret = -errno; goto out1; } @@ -330,7 +376,7 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags) /* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */ if (ret && errno != ENOSYS && errno != EOPNOTSUPP) { - printf("could not unprotect %s: %s\n", filename, errno_str()); + printf("could not unprotect %s: %m\n", filename); goto out; } @@ -338,7 +384,7 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags) /* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */ if (ret && errno != ENOSYS && errno != EOPNOTSUPP) { - printf("could not erase %s: %s\n", filename, errno_str()); + printf("could not erase %s: %m\n", filename); goto out; } @@ -361,7 +407,7 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags) /* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */ if (ret && errno != ENOSYS && errno != EOPNOTSUPP) { - printf("could not protect %s: %s\n", filename, errno_str()); + printf("could not protect %s: %m\n", filename); goto out; } @@ -382,166 +428,6 @@ out1: } EXPORT_SYMBOL(envfs_save); -static int envfs_check_super(struct envfs_super *super, size_t *size) -{ - if (ENVFS_32(super->magic) != ENVFS_MAGIC) { - printf("envfs: no envfs (magic mismatch) - envfs never written?\n"); - return -EIO; - } - - if (crc32(0, super, sizeof(*super) - 4) != ENVFS_32(super->sb_crc)) { - printf("wrong crc on env superblock\n"); - return -EIO; - } - - if (super->major < ENVFS_MAJOR) - printf("envfs version %d.%d loaded into %d.%d\n", - super->major, super->minor, - ENVFS_MAJOR, ENVFS_MINOR); - - *size = ENVFS_32(super->size); - - return 0; -} - -static int envfs_check_data(struct envfs_super *super, const void *buf, size_t size) -{ - uint32_t crc; - - crc = crc32(0, buf, size); - if (crc != ENVFS_32(super->crc)) { - printf("wrong crc on env\n"); - return -EIO; - } - - return 0; -} - -static int envfs_load_data(struct envfs_super *super, void *buf, size_t size, - const char *dir, unsigned flags) -{ - int fd, ret = 0; - char *str, *tmp; - int headerlen_full; - /* for envfs < 1.0 */ - struct envfs_inode_end inode_end_dummy; - struct stat s; - - inode_end_dummy.mode = ENVFS_32(S_IRWXU | S_IRWXG | S_IRWXO); - inode_end_dummy.magic = ENVFS_32(ENVFS_INODE_END_MAGIC); - - while (size) { - struct envfs_inode *inode; - struct envfs_inode_end *inode_end; - uint32_t inode_size, inode_headerlen, namelen; - - inode = buf; - buf += sizeof(struct envfs_inode); - - if (ENVFS_32(inode->magic) != ENVFS_INODE_MAGIC) { - printf("envfs: wrong magic\n"); - ret = -EIO; - goto out; - } - inode_size = ENVFS_32(inode->size); - inode_headerlen = ENVFS_32(inode->headerlen); - namelen = strlen(inode->data) + 1; - if (super->major < 1) - inode_end = &inode_end_dummy; - else - inode_end = buf + PAD4(namelen); - - debug("loading %s size %d namelen %d headerlen %d\n", inode->data, - inode_size, namelen, inode_headerlen); - - str = concat_path_file(dir, inode->data); - - headerlen_full = PAD4(inode_headerlen); - buf += headerlen_full; - - if (ENVFS_32(inode_end->magic) != ENVFS_INODE_END_MAGIC) { - printf("envfs: wrong inode_end_magic\n"); - ret = -EIO; - goto out; - } - - tmp = strdup(str); - make_directory(dirname(tmp)); - free(tmp); - - ret = stat(str, &s); - if (!ret && (flags & ENV_FLAG_NO_OVERWRITE)) { - printf("skip %s\n", str); - goto skip; - } - - if (S_ISLNK(ENVFS_32(inode_end->mode))) { - debug("symlink: %s -> %s\n", str, (char*)buf); - if (!strcmp(buf, basename(str))) { - unlink(str); - } else { - if (!ret) - unlink(str); - - ret = symlink(buf, str); - if (ret < 0) - printf("symlink: %s -> %s : %s\n", - str, (char*)buf, strerror(-errno)); - } - free(str); - } else { - fd = open(str, O_WRONLY | O_CREAT | O_TRUNC, 0644); - free(str); - if (fd < 0) { - printf("Open %s\n", errno_str()); - ret = fd; - goto out; - } - - ret = write(fd, buf, inode_size); - if (ret < inode_size) { - perror("write"); - ret = -errno; - close(fd); - goto out; - } - close(fd); - } -skip: - buf += PAD4(inode_size); - size -= headerlen_full + PAD4(inode_size) + - sizeof(struct envfs_inode); - } - - recursive_action(dir, ACTION_RECURSE | ACTION_DEPTHFIRST, NULL, - dir_remove_action, NULL, 0); - - ret = 0; -out: - return ret; -} - -int envfs_load_from_buf(void *buf, int len, const char *dir, unsigned flags) -{ - int ret; - size_t size; - struct envfs_super *super = buf; - - buf = super + 1; - - ret = envfs_check_super(super, &size); - if (ret) - return ret; - - ret = envfs_check_data(super, buf, size); - if (ret) - return ret; - - ret = envfs_load_data(super, buf, size, dir, flags); - - return ret; -} - /** * Restore the last environment into the current one * @param[in] filename from where to restore @@ -569,7 +455,7 @@ int envfs_load(const char *filename, const char *dir, unsigned flags) envfd = open(filename, O_RDONLY); if (envfd < 0) { - printf("environment load %s: %s\n", filename, errno_str()); + printf("environment load %s: %m\n", filename); if (errno == ENOENT) printf("Maybe you have to create the partition.\n"); return -1; |