fix(payload-import): remove mount(8) dependency and import by kernel-enumerated block devices via /proc/partitions

This commit is contained in:
vxtls 2026-03-02 07:53:37 -05:00
parent 45ba6a367d
commit 6b37393704
2 changed files with 170 additions and 54 deletions

View file

@ -7,41 +7,8 @@ set -ex
if [ "${PAYLOAD_REQUIRED}" = True ]; then
mkdir -p /external/distfiles
mkdir -p /proc
# Reliable enumeration in Fiwix: mount procfs and read /proc/partitions.
if [ ! -r /proc/partitions ]; then
mount -t proc proc /proc
fi
if [ ! -r /proc/partitions ]; then
echo "payload-import failed: /proc/partitions is unavailable." >&2
exit 1
fi
found_payload=0
while read -r major minor blocks name; do
case "${name}" in
""|name|ram*|loop*|fd*|sr*|md*|dm-*|nbd*)
continue
;;
*[0-9])
# Skip partitions (hda1, sdb2, ...); payload is a whole disk.
continue
;;
esac
dev_path="/dev/${name}"
[ -b "${dev_path}" ] || mknod -m 600 "${dev_path}" b "${major}" "${minor}"
if payload-import --probe "${dev_path}"; then
payload-import --device "${dev_path}" /external/distfiles
found_payload=1
break
fi
done < /proc/partitions
if [ "${found_payload}" != 1 ]; then
echo "payload-import failed: no payload image found in /proc/partitions." >&2
if ! payload-import /external/distfiles; then
echo "payload-import failed: no payload image found on block devices." >&2
exit 1
fi
fi

View file

@ -2,10 +2,12 @@
/* SPDX-License-Identifier: MIT */
#include <errno.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define MAGIC "LBPAYLD1"
@ -13,6 +15,11 @@
#define MAX_NAME_LEN 1024
#define COPY_BUFSZ 65536
/* mount(2) is available in the bootstrap libc, but some header stacks
* don't expose a prototype consistently. */
extern int mount(const char *source, const char *target,
const char *filesystemtype, unsigned int mountflags, const void *data);
static unsigned int read_u32le(const unsigned char *buf)
{
return (unsigned int)buf[0]
@ -106,6 +113,55 @@ static int has_payload_magic(const char *path)
return 0;
}
static int starts_with(const char *s, const char *prefix)
{
while (*prefix != 0) {
if (*s != *prefix) {
return 0;
}
s++;
prefix++;
}
return 1;
}
static int ends_with_digit(const char *s)
{
char c = 0;
while (*s != 0) {
c = *s;
s++;
}
return c >= '0' && c <= '9';
}
static int is_proc_partition_candidate(const char *name)
{
if (*name == 0 || strcmp(name, "name") == 0) {
return 0;
}
if (starts_with(name, "ram")
|| starts_with(name, "loop")
|| starts_with(name, "fd")
|| starts_with(name, "sr")
|| starts_with(name, "md")
|| starts_with(name, "dm-")
|| starts_with(name, "nbd")) {
return 0;
}
if (ends_with_digit(name)) {
/* Skip partitions; payload is attached as a whole disk. */
return 0;
}
return 1;
}
static unsigned int mkdev_u8(unsigned int major, unsigned int minor)
{
return ((major & 0xFFU) << 8) | (minor & 0xFFU);
}
static int extract_payload(const char *device, const char *dest_dir)
{
FILE *in;
@ -225,28 +281,110 @@ static int extract_payload(const char *device, const char *dest_dir)
return 0;
}
static int import_from_first_payload(const char *dest_dir)
static int ensure_proc_partitions(void)
{
const char *prefixes[] = {"/dev/sd", "/dev/hd", "/dev/vd", "/dev/xvd"};
int p;
struct stat st;
for (p = 0; p < 4; ++p) {
char letter;
for (letter = 'b'; letter <= 'z'; ++letter) {
char device[16];
if (snprintf(device, sizeof(device), "%s%c", prefixes[p], letter) >= (int)sizeof(device)) {
continue;
}
if (access(device, R_OK) != 0) {
continue;
}
if (has_payload_magic(device) == 0) {
return extract_payload(device, dest_dir);
}
if (stat("/proc/partitions", &st) == 0) {
return 0;
}
if (stat("/proc", &st) != 0) {
if (mkdir("/proc", 0755) != 0 && errno != EEXIST) {
return 1;
}
}
fputs("payload-import: no payload disk found\n", stderr);
if (mount("proc", "/proc", "proc", 0, (const void *)0) != 0) {
return 1;
}
if (stat("/proc/partitions", &st) != 0) {
return 1;
}
return 0;
}
static int import_from_proc_partitions(const char *dest_dir)
{
FILE *fp;
char line[256];
if (ensure_proc_partitions() != 0) {
return 1;
}
fp = fopen("/proc/partitions", "r");
if (fp == NULL) {
return 1;
}
while (fgets(line, sizeof(line), fp) != NULL) {
unsigned int major, minor, blocks;
char name[64];
char dev_path[96];
if (sscanf(line, " %u %u %u %63s", &major, &minor, &blocks, name) != 4) {
continue;
}
if (!is_proc_partition_candidate(name)) {
continue;
}
if (snprintf(dev_path, sizeof(dev_path), "/dev/%s", name) >= (int)sizeof(dev_path)) {
continue;
}
if (access(dev_path, F_OK) != 0) {
if (mknod(dev_path, S_IFBLK | 0600, mkdev_u8(major, minor)) != 0) {
continue;
}
}
if (has_payload_magic(dev_path) == 0) {
fclose(fp);
return extract_payload(dev_path, dest_dir);
}
}
fclose(fp);
return 2;
}
static int import_from_dev_nodes(const char *dest_dir)
{
DIR *dir;
struct dirent *entry;
dir = opendir("/dev");
if (dir == NULL) {
return 2;
}
entry = readdir(dir);
while (entry != NULL) {
char path[512];
struct stat st;
if (entry->d_name[0] == '.') {
entry = readdir(dir);
continue;
}
if (snprintf(path, sizeof(path), "/dev/%s", entry->d_name) >= (int)sizeof(path)) {
entry = readdir(dir);
continue;
}
if (lstat(path, &st) != 0 || !S_ISBLK(st.st_mode)) {
entry = readdir(dir);
continue;
}
if (has_payload_magic(path) == 0) {
closedir(dir);
return extract_payload(path, dest_dir);
}
entry = readdir(dir);
}
closedir(dir);
return 2;
}
@ -255,8 +393,9 @@ static void usage(const char *name)
fprintf(stderr,
"Usage:\n"
" %s --probe <device>\n"
" %s --from-proc <dest-dir>\n"
" %s [--device <device>] <dest-dir>\n",
name, name);
name, name, name);
}
int main(int argc, char **argv)
@ -268,6 +407,9 @@ int main(int argc, char **argv)
if (argc == 3 && strcmp(argv[1], "--probe") == 0) {
return has_payload_magic(argv[2]);
}
if (argc == 3 && strcmp(argv[1], "--from-proc") == 0) {
return import_from_proc_partitions(argv[2]);
}
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--device") == 0) {
@ -293,5 +435,12 @@ int main(int argc, char **argv)
if (device != NULL) {
return extract_payload(device, dest_dir);
}
return import_from_first_payload(dest_dir);
i = import_from_proc_partitions(dest_dir);
if (i == 0) {
return 0;
}
if (i == 1) {
fputs("payload-import: /proc/partitions unavailable, falling back to /dev scan\n", stderr);
}
return import_from_dev_nodes(dest_dir);
}