summaryrefslogtreecommitdiffstats
path: root/common/environment.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/environment.c')
-rw-r--r--common/environment.c276
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;