[LEDE-DEV] [PATCH RFC] uinit: add package with init for initramfs

Rafał Miłecki zajec5 at gmail.com
Mon Mar 27 23:32:08 PDT 2017


From: Rafał Miłecki <rafal at milecki.pl>

In OpenWrt/LEDE we always got hacks for mounting rootfs. They were
needed because we couldn't use bootargs properly due to various reasons
(e.g. dynamically created partitions).

The proper solution for this (instead of hacking a kernel) is to use
initramfs with init that will initialize rootfs. Right now this init
implementation only mounts "rootfs" parition and switches to it. So
far this allows dropping kernel patch setting ROOT_DEV.

The next step is to implement ubi support (attaching & mounting a
"rootfs" volume).

In future this will also allow us to implement more feature like:
1) Cleaning/preparing UBI partition (important for bootloaders that
   don't empty whole partition before flashing).
2) Resizing data partition to use whole space (important for images for
   hard drives or SD cards).

This package installs init to the $(TARGET_ROOTFS_DIR)/initramfs/ . This
will require integrating with LEDE in order to:
1) Always use initramfs
2) Add above directory for non-initramfs images to the
   CONFIG_INITRAMFS_SOURCE

Signed-off-by: Rafał Miłecki <rafal at milecki.pl>
---
Apart from obvious questions (is this OK? what to change? how to package it
properly?) I'm wondering about license. Do you think GPLv2 is fine for this?
---
 package/system/uinit/Makefile           |  27 +++++
 package/system/uinit/src/CMakeLists.txt |   8 ++
 package/system/uinit/src/main.c         | 187 ++++++++++++++++++++++++++++++++
 3 files changed, 222 insertions(+)
 create mode 100644 package/system/uinit/Makefile
 create mode 100644 package/system/uinit/src/CMakeLists.txt
 create mode 100644 package/system/uinit/src/main.c

diff --git a/package/system/uinit/Makefile b/package/system/uinit/Makefile
new file mode 100644
index 0000000000..0b636dbbb4
--- /dev/null
+++ b/package/system/uinit/Makefile
@@ -0,0 +1,27 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=uinit
+PKG_RELEASE:=1
+
+CMAKE_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/uinit
+  SECTION:=base
+  CATEGORY:=Base system
+  TITLE:=uinit for initramfs
+endef
+
+define Build/Prepare
+	mkdir -p $(PKG_BUILD_DIR)
+	$(CP) ./src/* $(PKG_BUILD_DIR)/
+endef
+
+define Package/uinit/install
+	$(INSTALL_DIR) $(TARGET_ROOTFS_DIR)/initramfs
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/init $(TARGET_ROOTFS_DIR)/initramfs/
+endef
+
+$(eval $(call BuildPackage,uinit))
diff --git a/package/system/uinit/src/CMakeLists.txt b/package/system/uinit/src/CMakeLists.txt
new file mode 100644
index 0000000000..991c58f662
--- /dev/null
+++ b/package/system/uinit/src/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.6)
+
+project(uinit)
+set(CMAKE_C_FLAGS "-Wall")
+
+add_executable(init main.c)
+target_compile_definitions(init PUBLIC _GNU_SOURCE)
+install(TARGETS init RUNTIME DESTINATION /)
diff --git a/package/system/uinit/src/main.c b/package/system/uinit/src/main.c
new file mode 100644
index 0000000000..298f12268a
--- /dev/null
+++ b/package/system/uinit/src/main.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2017 Rafał Miłecki <rafal at milecki.pl>
+ *
+ * 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.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <unistd.h>
+
+#if 0
+#include <dirent.h>
+static int ls(const char *path)
+{
+	DIR *dir;
+	struct dirent *dp;
+
+	dir = opendir(path);
+	if (!dir)
+		return errno;
+
+	printf("Listing %s\n", path);
+	while ((dp = readdir(dir))) {
+		struct stat fileStat;
+
+		if (stat(dp->d_name, &fileStat)) {
+			fprintf(stderr, "Failed to stat %s\n", dp->d_name);
+			continue;
+		}
+		printf((S_ISDIR(fileStat.st_mode)) ? "d" : "-");
+		printf((fileStat.st_mode & S_IRUSR) ? "r" : "-");
+		printf((fileStat.st_mode & S_IWUSR) ? "w" : "-");
+		printf((fileStat.st_mode & S_IXUSR) ? "x" : "-");
+		printf((fileStat.st_mode & S_IRGRP) ? "r" : "-");
+		printf((fileStat.st_mode & S_IWGRP) ? "w" : "-");
+		printf((fileStat.st_mode & S_IXGRP) ? "x" : "-");
+		printf((fileStat.st_mode & S_IROTH) ? "r" : "-");
+		printf((fileStat.st_mode & S_IWOTH) ? "w" : "-");
+		printf((fileStat.st_mode & S_IXOTH) ? "x" : "-");
+		printf("\t%s\n", dp->d_name);
+	}
+
+	closedir(dir);
+
+	return 0;
+}
+
+static int cat(const char *path)
+{
+	FILE *fp;
+	char line[64];
+
+	fp = fopen(path, "r");
+	if (!fp)
+		return -EIO;
+
+	printf("Content of %s:\n", path);
+	while (fgets(line, sizeof(line), fp)) {
+		printf("%s", line);
+	}
+	printf("\n");
+
+	fclose(fp);
+
+	return 0;
+}
+#endif
+
+static int mount_basics()
+{
+	if (mount("proc", "/proc", "proc", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID, 0))
+		return errno;
+
+	if (mount("sysfs", "/sys", "sysfs", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID, 0))
+		return errno;
+
+	if (mount("devtmpfs", "/dev", "devtmpfs", MS_NOATIME | MS_NOSUID, "mode=0755,size=512K"))
+		return errno;
+
+	return 0;
+}
+
+static int find_block_mtd(char *name, char *mtdblock, size_t size)
+{
+	FILE *fp;
+	char line[64];
+	int index = -ENOENT;
+
+	fp = fopen("/proc/mtd", "r");
+	if (!fp)
+		return -EIO;
+
+	while (fgets(line, sizeof(line), fp)) {
+		char dev[8];
+		int i;
+
+		if (sscanf(line, "mtd%d: %*x %*x \"%7[^\"]", &i, dev) == 2) {
+			if (!strcmp(dev, name)) {
+				index = i;
+				if (mtdblock)
+					snprintf(mtdblock, size, "/dev/mtdblock%d", index);
+				break;
+			}
+		}
+	}
+
+	fclose(fp);
+
+	return index;
+}
+
+static int mount_rootfs()
+{
+	char mtdblock[32];
+	int index;
+
+	index = find_block_mtd("rootfs", mtdblock, sizeof(mtdblock));
+	if (index < 0) {
+		fprintf(stderr, "Failed to find rootfs: %d\n", index);
+		return index;
+	}
+
+	if (mount(mtdblock, "/mnt", "squashfs", MS_RDONLY, 0))
+		return errno;
+
+	return 0;
+}
+
+static int switch_root()
+{
+	if (mount("/proc", "/mnt/proc", NULL, MS_NOATIME | MS_MOVE, NULL))
+		return errno;
+
+	if (mount("/sys", "/mnt/sys", NULL, MS_NOATIME | MS_MOVE, NULL))
+		return errno;
+
+	if (mount("/dev", "/mnt/dev", NULL, MS_NOATIME | MS_MOVE, NULL))
+		return errno;
+
+	if (chdir("/mnt"))
+		return errno;
+
+	if (mount(".", "/", NULL, MS_MOVE, NULL))
+		return errno;
+
+	if (chroot("."))
+		return errno;
+
+	if (chdir("/"))
+		return errno;
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int err;
+
+	err = mount_basics();
+	if (err) {
+		fprintf(stderr, "Failed to mount basic points: %d\n", err);
+		return err;
+	}
+
+	err = mount_rootfs();
+	if (err) {
+		fprintf(stderr, "Failed to mount rootfs: %d\n", err);
+		return err;
+	}
+
+	err = switch_root();
+	if (err) {
+		fprintf(stderr, "Failed to switch to the new root: %d\n", err);
+		return err;
+	}
+
+	printf("Successfully switched to the mounted rootfs\n");
+
+	execl("/sbin/init", "/sbin/init", (char *)NULL);
+
+	return 0;
+}
-- 
2.11.0




More information about the Lede-dev mailing list