blob: a4a9d6c1173d53c91b4ffe638930d9947e9f7e32 [file] [log] [blame]
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,6 +5,10 @@ ADD_DEFINITIONS(-Os -ggdb -Wall -Werror
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
+ADD_LIBRARY(fstools-bootparam SHARED
+ boot_param.c)
+INSTALL(TARGETS fstools-bootparam LIBRARY DESTINATION lib)
+
ADD_LIBRARY(fstools SHARED
libfstools/snapshot.c
libfstools/extroot.c
@@ -15,7 +19,7 @@ ADD_LIBRARY(fstools SHARED
libfstools/ubi.c
libfstools/rootdisk.c
libfstools/find.c)
-TARGET_LINK_LIBRARIES(fstools ubox)
+TARGET_LINK_LIBRARIES(fstools ubox fstools-bootparam)
INSTALL(TARGETS fstools LIBRARY DESTINATION lib)
ADD_LIBRARY(blkid-tiny SHARED
@@ -75,9 +79,9 @@ INSTALL(TARGETS blockd RUNTIME DESTINATI
ADD_EXECUTABLE(block block.c probe.c probe-libblkid.c)
IF(DEFINED CMAKE_UBIFS_EXTROOT)
ADD_DEFINITIONS(-DUBIFS_EXTROOT)
- TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ubi-utils ${json})
+ TARGET_LINK_LIBRARIES(block blkid-tiny fstools-bootparam dl uci ubox ubus blobmsg_json ubi-utils ${json})
ELSE(DEFINED CMAKE_UBIFS_EXTROOT)
- TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ${json})
+ TARGET_LINK_LIBRARIES(block blkid-tiny fstools-bootparam dl uci ubox ubus blobmsg_json ${json})
ENDIF(DEFINED CMAKE_UBIFS_EXTROOT)
INSTALL(TARGETS block RUNTIME DESTINATION sbin)
--- a/block.c
+++ b/block.c
@@ -47,6 +47,7 @@
#include <libubus.h>
#include "probe.h"
+#include "boot_param.h"
#define AUTOFS_MOUNT_PATH "/tmp/run/blockd/"
@@ -89,6 +90,9 @@ static LIST_HEAD(devices);
static int anon_mount, anon_swap, auto_mount, auto_swap, check_fs;
static unsigned int delay_root;
+static char *hide_block_devs[3];
+static uint32_t num_hide_block_devs;
+
enum {
CFG_ANON_MOUNT,
CFG_ANON_SWAP,
@@ -498,9 +502,12 @@ static struct probe_info* _probe_path(ch
return probe_path(path);
}
+static char* find_mount_point(char *block);
+
static int _cache_load(const char *path)
{
int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
+ uint32_t i;
int j;
glob_t gl;
@@ -509,8 +516,30 @@ static int _cache_load(const char *path)
for (j = 0; j < gl.gl_pathc; j++) {
struct probe_info *pr = _probe_path(gl.gl_pathv[j]);
- if (pr)
+ bool skip_curr = false;
+
+ if (pr) {
+ char *mp = find_mount_point(pr->dev);
+ if (mp) {
+ /* Skip blocks mounted as root or overlay */
+ if (!strcmp(mp, "/rom") ||
+ !strcmp(mp, "/overlay"))
+ continue;
+ }
+
+ for (i = 0; i < num_hide_block_devs; i++) {
+ /* Skip blocks used for dual boot */
+ if (!strcmp(hide_block_devs[i], pr->dev)) {
+ skip_curr = true;
+ break;
+ }
+ }
+
+ if (skip_curr)
+ continue;
+
list_add_tail(&pr->list, &devices);
+ }
}
globfree(&gl);
@@ -1801,6 +1830,26 @@ static int main_swapoff(int argc, char *
return 0;
}
+static bool add_hide_block_dev(char *path)
+{
+ if (num_hide_block_devs >= ARRAY_SIZE(hide_block_devs))
+ return false;
+
+ hide_block_devs[num_hide_block_devs++] = path;
+ return true;
+}
+
+static void hide_boot_param_dev(const char *name)
+{
+ char *path;
+
+ path = boot_param_get_dev(name);
+ if (path) {
+ if (!add_hide_block_dev(path))
+ free(path);
+ }
+}
+
int main(int argc, char **argv)
{
char *base = basename(*argv);
@@ -1810,6 +1859,10 @@ int main(int argc, char **argv)
ulog_open(-1, -1, "block");
ulog_threshold(LOG_NOTICE);
+ hide_boot_param_dev("rootfs_data_part");
+ hide_boot_param_dev("boot_rootfs_part");
+ hide_boot_param_dev("upgrade_rootfs_part");
+
if (!strcmp(base, "swapon"))
return main_swapon(argc, argv);
--- a/boot_param.c
+++ b/boot_param.c
@@ -0,0 +1,270 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <glob.h>
+#include <dlfcn.h>
+
+#include <blkid/blkid.h>
+#include <libubox/ulog.h>
+#include "boot_param.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+#define BOOT_PARAM_STR_MAX_LEN 256
+
+static struct {
+ bool loaded;
+ blkid_probe (*new_probe_from_filename)(const char *);
+ int (*do_safeprobe)(blkid_probe);
+ int (*probe_lookup_value)(blkid_probe, const char *, const char **, size_t *);
+ void (*free_probe)(blkid_probe);
+ int (*probe_enable_partitions)(blkid_probe, int);
+ int (*probe_set_partitions_flags)(blkid_probe, int);
+} libblkid = {};
+
+bool read_boot_param_bool(const char *name)
+{
+ char path[BOOT_PARAM_STR_MAX_LEN], val;
+ size_t len;
+ FILE *f;
+
+ snprintf(path, sizeof(path), "/sys/module/boot_param/parameters/%s",
+ name);
+
+ f = fopen(path, "rb");
+ if (!f)
+ return false;
+
+ len = fread(&val, 1, 1, f);
+ fclose(f);
+
+ if (len != 1)
+ return false;
+
+ return val == 'Y';
+}
+
+int read_boot_param_string(const char *name, char *val, size_t maxsize)
+{
+ char path[BOOT_PARAM_STR_MAX_LEN];
+ size_t len;
+ FILE *f;
+
+ snprintf(path, sizeof(path), "/sys/module/boot_param/parameters/%s",
+ name);
+
+ f = fopen(path, "rb");
+ if (!f) {
+ val[0] = 0;
+ return -1;
+ }
+
+ len = fread(val, 1, maxsize, f);
+ fclose(f);
+
+ while (len > 0) {
+ if (val[len - 1] != '\n' && val[len - 1] != '\r')
+ break;
+
+ len--;
+ }
+
+ if (len < maxsize)
+ val[len] = 0;
+
+ return len;
+}
+
+int write_boot_param_string(const char *name, const char *val)
+{
+ size_t wlen, len = strlen(val);
+ char path[BOOT_PARAM_STR_MAX_LEN];
+ FILE *f;
+
+ if (len >= BOOT_PARAM_STR_MAX_LEN)
+ return -1;
+
+ snprintf(path, sizeof(path), "/sys/module/boot_param/parameters/%s",
+ name);
+
+ f = fopen(path, "wb");
+ if (!f)
+ return -1;
+
+ wlen = fwrite(val, 1, len, f);
+ fclose(f);
+
+ return wlen;
+}
+
+static bool load_libblkid(void)
+{
+ void *lib;
+
+ if (libblkid.loaded)
+ return true;
+
+ lib = dlopen("libblkid.so", RTLD_GLOBAL);
+
+ if (!lib)
+ lib = dlopen("libblkid.so.1", RTLD_GLOBAL);
+
+ if (!lib)
+ return false;
+
+ libblkid.new_probe_from_filename = dlsym(lib, "blkid_new_probe_from_filename");
+ if (!libblkid.new_probe_from_filename)
+ return false;
+
+ libblkid.do_safeprobe = dlsym(lib, "blkid_do_safeprobe");
+ if (!libblkid.do_safeprobe)
+ return false;
+
+ libblkid.probe_lookup_value = dlsym(lib, "blkid_probe_lookup_value");
+ if (!libblkid.probe_lookup_value)
+ return false;
+
+ libblkid.free_probe = dlsym(lib, "blkid_free_probe");
+ if (!libblkid.free_probe)
+ return false;
+
+ libblkid.probe_enable_partitions = dlsym(lib, "blkid_probe_enable_partitions");
+ if (!libblkid.probe_enable_partitions)
+ return false;
+
+ libblkid.probe_set_partitions_flags = dlsym(lib, "blkid_probe_set_partitions_flags");
+ if (!libblkid.probe_set_partitions_flags)
+ return false;
+
+ libblkid.loaded = true;
+ return true;
+}
+
+static char *lookup_block_dev(const char *path, const char *key, bool is_uuid)
+{
+ int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
+ const char *type, *value;
+ char *result = NULL;
+ size_t len;
+ glob_t gl;
+ int i;
+
+ if (glob(path, gl_flags, NULL, &gl) < 0)
+ return NULL;
+
+ type = is_uuid ? "PART_ENTRY_UUID" : "PART_ENTRY_NAME";
+
+ for (i = 0; i < gl.gl_pathc; i++) {
+ blkid_probe pr = libblkid.new_probe_from_filename(gl.gl_pathv[i]);
+ if (!pr)
+ continue;
+
+ libblkid.probe_enable_partitions(pr, 1);
+ libblkid.probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS);
+
+ if (libblkid.do_safeprobe(pr))
+ goto free_pr;
+
+ if (!libblkid.probe_lookup_value(pr, type, &value, &len)) {
+ if (!strcmp(value, key))
+ result = strdup(gl.gl_pathv[i]);
+ }
+
+ free_pr:
+ libblkid.free_probe(pr);
+
+ if (result)
+ break;
+ }
+
+ globfree(&gl);
+
+ return result;
+}
+
+static char *find_block_dev(const char *key, bool is_uuid)
+{
+ char *devpath = NULL;
+ int i;
+
+ static const char *block_pats[] = {
+ "/dev/loop*",
+ "/dev/mmcblk*",
+ "/dev/sd*",
+ "/dev/hd*",
+ "/dev/md*",
+ "/dev/nvme*",
+ "/dev/vd*",
+ "/dev/xvd*",
+ "/dev/mapper/*",
+ };
+
+ if (!load_libblkid())
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(block_pats); i++) {
+ devpath = lookup_block_dev(block_pats[i], key, is_uuid);
+ if (devpath)
+ break;
+ }
+
+ return devpath;
+}
+
+char *blockdev_parse(const char *name)
+{
+ char *e, *part_dev_path;
+ struct stat st;
+
+ if (!name)
+ return NULL;
+
+ e = strchr(name, '=');
+ if (e) {
+ *e = 0;
+ e++;
+ }
+
+ if (!e) {
+ if (stat(name, &st))
+ return NULL;
+
+ if (!S_ISBLK(st.st_mode))
+ return NULL;
+
+ part_dev_path = strdup(name);
+ } else if (!strcmp(name, "PARTLABEL")) {
+ part_dev_path = find_block_dev(e, false);
+ } else if (!strcmp(name, "PARTUUID")) {
+ if (strlen(e) != 36)
+ return NULL;
+ part_dev_path = find_block_dev(e, true);
+ } else {
+ return NULL;
+ }
+
+ return part_dev_path;
+}
+
+char *boot_param_get_dev(const char *name)
+{
+ char partkey[BOOT_PARAM_STR_MAX_LEN];
+
+ read_boot_param_string(name, partkey, sizeof(partkey));
+
+ if (!partkey[0])
+ return NULL;
+
+ return blockdev_parse(partkey);
+}
--- a/boot_param.h
+++ b/boot_param.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _BOOT_PARAM_H_
+#define _BOOT_PARAM_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+
+bool read_boot_param_bool(const char *name);
+int read_boot_param_string(const char *name, char *val, size_t maxsize);
+int write_boot_param_string(const char *name, const char *val);
+
+char *blockdev_parse(const char *name);
+char *boot_param_get_dev(const char *name);
+
+#endif /* _BOOT_PARAM_H_ */
--- a/libfstools/rootdisk.c
+++ b/libfstools/rootdisk.c
@@ -26,6 +26,7 @@
#include "libfstools.h"
#include "volume.h"
+#include "../boot_param.h"
#include <linux/loop.h>
@@ -42,6 +43,7 @@ struct rootdev_volume {
struct volume v;
uint64_t offset;
char loop_name[32];
+ char *dev_path;
};
static const char *rootdev;
@@ -109,11 +111,15 @@ static int get_squashfs(struct squashfs_
static bool rootdisk_use_f2fs(struct rootdev_volume *p)
{
+ const char *dev = rootdev;
uint64_t size = 0;
bool ret = false;
int fd;
- fd = open(rootdev, O_RDONLY);
+ if (p->dev_path)
+ dev = p->dev_path;
+
+ fd = open(dev, O_RDONLY);
if (ioctl(fd, BLKGETSIZE64, &size) == 0)
ret = size - p->offset > F2FS_MINSIZE;
close(fd);
@@ -121,6 +127,30 @@ static bool rootdisk_use_f2fs(struct roo
return ret;
}
+static struct volume *find_existed_rootfs_data(void)
+{
+ struct rootdev_volume *p;
+ char *rootfs_data_dev;
+
+ rootfs_data_dev = boot_param_get_dev("rootfs_data_part");
+
+ if (!rootfs_data_dev)
+ return NULL;
+
+ ULOG_NOTE("Using existed rootfs_data device %s\n", rootfs_data_dev);
+
+ write_boot_param_string("rootfs_data_part", rootfs_data_dev);
+
+ p = calloc(1, sizeof(*p));
+ p->v.drv = &rootdisk_driver;
+ p->v.name = "rootfs_data";
+
+ p->offset = 0;
+ p->dev_path = rootfs_data_dev;
+
+ return &p->v;
+}
+
static struct volume *rootdisk_volume_find(char *name)
{
struct squashfs_super_block sb;
@@ -129,6 +159,9 @@ static struct volume *rootdisk_volume_fi
if (strcmp(name, "rootfs_data") != 0)
return NULL;
+ if (read_boot_param_bool("no_split_rootfs_data"))
+ return find_existed_rootfs_data();
+
if (!rootdev)
rootdev = get_rootdev("/");
if (!rootdev)
@@ -160,12 +193,16 @@ static struct volume *rootdisk_volume_fi
static int rootdisk_volume_identify(struct volume *v)
{
struct rootdev_volume *p = container_of(v, struct rootdev_volume, v);
+ const char *dev = rootdev;
int ret = FS_NONE;
uint32_t magic = 0;
size_t n;
FILE *f;
- f = fopen(rootdev, "r");
+ if (p->dev_path)
+ dev = p->dev_path;
+
+ f = fopen(dev, "r");
if (!f)
return ret;
@@ -265,6 +302,13 @@ static int rootdisk_volume_init(struct v
char str[128];
int ret = 0;
+ if (p->dev_path) {
+ /* Do not create loop device with no_split_rootfs_data set */
+ v->type = BLOCKDEV;
+ v->blk = p->dev_path;
+ goto do_format;
+ }
+
if (!p->loop_name[0] && rootdisk_create_loop(p) != 0) {
ULOG_ERR("unable to create loop device\n");
return -1;
@@ -273,6 +317,7 @@ static int rootdisk_volume_init(struct v
v->type = BLOCKDEV;
v->blk = p->loop_name;
+do_format:
switch (rootdisk_volume_identify(v)) {
case FS_NONE:
ULOG_INFO("rootdisk overlay filesystem has not been formatted yet\n");
--- a/mount_root.c
+++ b/mount_root.c
@@ -23,6 +23,8 @@
#include "libfstools/libfstools.h"
#include "libfstools/volume.h"
+#include "boot_param.h"
+
/*
* Called in the early (PREINIT) stage, when we immediately need some writable
* filesystem.
@@ -58,6 +60,12 @@ start(int argc, char *argv[1])
/* There isn't extroot, so just try to mount "rootfs_data" */
volume_init(data);
switch (volume_identify(data)) {
+ case -1:
+ /* Use ramoverlay if no "rootfs_data" device found with no_split_rootfs_data set */
+ if (!read_boot_param_bool("no_split_rootfs_data"))
+ break;
+
+ /* fall through */
case FS_NONE:
ULOG_WARN("no usable overlay filesystem found, using tmpfs overlay\n");
return ramoverlay();