summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Xu (Hello71) <alex_y_xu@yahoo.ca>2019-07-26 20:17:54 -0400
committerAlex Xu (Hello71) <alex_y_xu@yahoo.ca>2019-07-26 20:17:54 -0400
commitefd5d866be3cdb9c2b5b3221319fbc80aa0d039b (patch)
tree5aa6603f47e56bcc380db0274513b95240727e64
downloadminitramfs-efd5d866be3cdb9c2b5b3221319fbc80aa0d039b.tar.xz
minitramfs-efd5d866be3cdb9c2b5b3221319fbc80aa0d039b.zip
Initial commit
-rw-r--r--.gitignore8
-rw-r--r--Makefile27
-rw-r--r--gen_init_cpio.c624
-rw-r--r--init51
-rwxr-xr-xmake91
-rw-r--r--passwd1
-rw-r--r--unlock3
7 files changed, 805 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..13dca84
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+/amd-uc.img
+/authorized_keys
+/ding.wav
+/dropbear_*_key
+/gen_init_cpio
+/initramfs.d
+/initramfs.img
+/kernel
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0b2d171
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,27 @@
+all: initramfs.img amd-uc.img
+
+initramfs.img:
+ ./make
+
+-include initramfs.d
+
+amd-uc.img: kernel/x86/microcode/AuthenticAMD.bin
+ echo $^ | bsdcpio -o -H newc -R 0:0 > $@
+
+kernel/x86/microcode/AuthenticAMD.bin: /lib/firmware/amd-ucode/microcode_amd_fam17h.bin /lib/firmware/amd/amd_sev_fam17h_model0xh.sbin
+ mkdir -p $(@D)
+ cat $^ > $@
+
+install: /boot/initramfs.img /boot/amd-uc.img
+
+/boot/initramfs.img: initramfs.img
+ rm -f $@.old $@.new
+ cp $< $@.new
+ if [ -e $@ ]; then mv $@ $@.old; fi
+ mv $@.new $@
+
+/boot/amd-uc.img: amd-uc.img
+ cp $< $@
+
+clean:
+ $(RM) -r initramfs.img initramfs.d amd-uc.img kernel
diff --git a/gen_init_cpio.c b/gen_init_cpio.c
new file mode 100644
index 0000000..03b2118
--- /dev/null
+++ b/gen_init_cpio.c
@@ -0,0 +1,624 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+
+/*
+ * Original work by Jeff Garzik
+ *
+ * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
+ * Hard link support by Luciano Rocha
+ */
+
+#define xstr(s) #s
+#define str(s) xstr(s)
+
+static unsigned int offset;
+static unsigned int ino = 721;
+static time_t default_mtime;
+
+struct file_handler {
+ const char *type;
+ int (*handler)(const char *line);
+};
+
+static void push_string(const char *name)
+{
+ unsigned int name_len = strlen(name) + 1;
+
+ fputs(name, stdout);
+ putchar(0);
+ offset += name_len;
+}
+
+static void push_pad (void)
+{
+ while (offset & 3) {
+ putchar(0);
+ offset++;
+ }
+}
+
+static void push_rest(const char *name)
+{
+ unsigned int name_len = strlen(name) + 1;
+ unsigned int tmp_ofs;
+
+ fputs(name, stdout);
+ putchar(0);
+ offset += name_len;
+
+ tmp_ofs = name_len + 110;
+ while (tmp_ofs & 3) {
+ putchar(0);
+ offset++;
+ tmp_ofs++;
+ }
+}
+
+static void push_hdr(const char *s)
+{
+ fputs(s, stdout);
+ offset += 110;
+}
+
+static void cpio_trailer(void)
+{
+ char s[256];
+ const char name[] = "TRAILER!!!";
+
+ sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ "070701", /* magic */
+ 0, /* ino */
+ 0, /* mode */
+ (long) 0, /* uid */
+ (long) 0, /* gid */
+ 1, /* nlink */
+ (long) 0, /* mtime */
+ 0, /* filesize */
+ 0, /* major */
+ 0, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name)+1, /* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+
+ while (offset % 512) {
+ putchar(0);
+ offset++;
+ }
+}
+
+static int cpio_mkslink(const char *name, const char *target,
+ unsigned int mode, uid_t uid, gid_t gid)
+{
+ char s[256];
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ "070701", /* magic */
+ ino++, /* ino */
+ S_IFLNK | mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 1, /* nlink */
+ (long) default_mtime, /* mtime */
+ (unsigned)strlen(target)+1, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_string(name);
+ push_pad();
+ push_string(target);
+ push_pad();
+ return 0;
+}
+
+static int cpio_mkslink_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ char target[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int rc = -1;
+
+ if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
+ fprintf(stderr, "Unrecognized dir format '%s'", line);
+ goto fail;
+ }
+ rc = cpio_mkslink(name, target, mode, uid, gid);
+ fail:
+ return rc;
+}
+
+static int cpio_mkgeneric(const char *name, unsigned int mode,
+ uid_t uid, gid_t gid)
+{
+ char s[256];
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ "070701", /* magic */
+ ino++, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 2, /* nlink */
+ (long) default_mtime, /* mtime */
+ 0, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+ return 0;
+}
+
+enum generic_types {
+ GT_DIR,
+ GT_PIPE,
+ GT_SOCK
+};
+
+struct generic_type {
+ const char *type;
+ mode_t mode;
+};
+
+static struct generic_type generic_type_table[] = {
+ [GT_DIR] = {
+ .type = "dir",
+ .mode = S_IFDIR
+ },
+ [GT_PIPE] = {
+ .type = "pipe",
+ .mode = S_IFIFO
+ },
+ [GT_SOCK] = {
+ .type = "sock",
+ .mode = S_IFSOCK
+ }
+};
+
+static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
+{
+ char name[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int rc = -1;
+
+ if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
+ fprintf(stderr, "Unrecognized %s format '%s'",
+ line, generic_type_table[gt].type);
+ goto fail;
+ }
+ mode |= generic_type_table[gt].mode;
+ rc = cpio_mkgeneric(name, mode, uid, gid);
+ fail:
+ return rc;
+}
+
+static int cpio_mkdir_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_DIR);
+}
+
+static int cpio_mkpipe_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_PIPE);
+}
+
+static int cpio_mksock_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_SOCK);
+}
+
+static int cpio_mknod(const char *name, unsigned int mode,
+ uid_t uid, gid_t gid, char dev_type,
+ unsigned int maj, unsigned int min)
+{
+ char s[256];
+
+ if (dev_type == 'b')
+ mode |= S_IFBLK;
+ else
+ mode |= S_IFCHR;
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ "070701", /* magic */
+ ino++, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 1, /* nlink */
+ (long) default_mtime, /* mtime */
+ 0, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ maj, /* rmajor */
+ min, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+ return 0;
+}
+
+static int cpio_mknod_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ char dev_type;
+ unsigned int maj;
+ unsigned int min;
+ int rc = -1;
+
+ if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
+ name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
+ fprintf(stderr, "Unrecognized nod format '%s'", line);
+ goto fail;
+ }
+ rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
+ fail:
+ return rc;
+}
+
+static int cpio_mkfile(const char *name, const char *location,
+ unsigned int mode, uid_t uid, gid_t gid,
+ unsigned int nlinks)
+{
+ char s[256];
+ char *filebuf = NULL;
+ struct stat buf;
+ long size;
+ int file = -1;
+ int retval;
+ int rc = -1;
+ int namesize;
+ unsigned int i;
+
+ mode |= S_IFREG;
+
+ file = open (location, O_RDONLY);
+ if (file < 0) {
+ fprintf (stderr, "File %s could not be opened for reading\n", location);
+ goto error;
+ }
+
+ retval = fstat(file, &buf);
+ if (retval) {
+ fprintf(stderr, "File %s could not be stat()'ed\n", location);
+ goto error;
+ }
+
+ filebuf = malloc(buf.st_size);
+ if (!filebuf) {
+ fprintf (stderr, "out of memory\n");
+ goto error;
+ }
+
+ retval = read (file, filebuf, buf.st_size);
+ if (retval < 0) {
+ fprintf (stderr, "Can not read %s file\n", location);
+ goto error;
+ }
+
+ size = 0;
+ for (i = 1; i <= nlinks; i++) {
+ /* data goes on last link */
+ if (i == nlinks) size = buf.st_size;
+
+ if (name[0] == '/')
+ name++;
+ namesize = strlen(name) + 1;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08lX%08X%08X%08X%08X%08X%08X",
+ "070701", /* magic */
+ ino, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ nlinks, /* nlink */
+ (long) buf.st_mtime, /* mtime */
+ size, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ namesize, /* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_string(name);
+ push_pad();
+
+ if (size) {
+ if (fwrite(filebuf, size, 1, stdout) != 1) {
+ fprintf(stderr, "writing filebuf failed\n");
+ goto error;
+ }
+ offset += size;
+ push_pad();
+ }
+
+ name += namesize;
+ }
+ ino++;
+ rc = 0;
+
+error:
+ if (filebuf) free(filebuf);
+ if (file >= 0) close(file);
+ return rc;
+}
+
+static char *cpio_replace_env(char *new_location)
+{
+ char expanded[PATH_MAX + 1];
+ char *start, *end, *var;
+
+ while ((start = strstr(new_location, "${")) &&
+ (end = strchr(start + 2, '}'))) {
+ *start = *end = 0;
+ var = getenv(start + 2);
+ snprintf(expanded, sizeof expanded, "%s%s%s",
+ new_location, var ? var : "", end + 1);
+ strcpy(new_location, expanded);
+ }
+
+ return new_location;
+}
+
+static int cpio_mkfile_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ char *dname = NULL; /* malloc'ed buffer for hard links */
+ char location[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int nlinks = 1;
+ int end = 0, dname_len = 0;
+ int rc = -1;
+
+ if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
+ "s %o %d %d %n",
+ name, location, &mode, &uid, &gid, &end)) {
+ fprintf(stderr, "Unrecognized file format '%s'", line);
+ goto fail;
+ }
+ if (end && isgraph(line[end])) {
+ int len;
+ int nend;
+
+ dname = malloc(strlen(line));
+ if (!dname) {
+ fprintf (stderr, "out of memory (%d)\n", dname_len);
+ goto fail;
+ }
+
+ dname_len = strlen(name) + 1;
+ memcpy(dname, name, dname_len);
+
+ do {
+ nend = 0;
+ if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
+ name, &nend) < 1)
+ break;
+ len = strlen(name) + 1;
+ memcpy(dname + dname_len, name, len);
+ dname_len += len;
+ nlinks++;
+ end += nend;
+ } while (isgraph(line[end]));
+ } else {
+ dname = name;
+ }
+ rc = cpio_mkfile(dname, cpio_replace_env(location),
+ mode, uid, gid, nlinks);
+ fail:
+ if (dname_len) free(dname);
+ return rc;
+}
+
+static void usage(const char *prog)
+{
+ fprintf(stderr, "Usage:\n"
+ "\t%s [-t <timestamp>] <cpio_list>\n"
+ "\n"
+ "<cpio_list> is a file containing newline separated entries that\n"
+ "describe the files to be included in the initramfs archive:\n"
+ "\n"
+ "# a comment\n"
+ "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
+ "dir <name> <mode> <uid> <gid>\n"
+ "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
+ "slink <name> <target> <mode> <uid> <gid>\n"
+ "pipe <name> <mode> <uid> <gid>\n"
+ "sock <name> <mode> <uid> <gid>\n"
+ "\n"
+ "<name> name of the file/dir/nod/etc in the archive\n"
+ "<location> location of the file in the current filesystem\n"
+ " expands shell variables quoted with ${}\n"
+ "<target> link target\n"
+ "<mode> mode/permissions of the file\n"
+ "<uid> user id (0=root)\n"
+ "<gid> group id (0=root)\n"
+ "<dev_type> device type (b=block, c=character)\n"
+ "<maj> major number of nod\n"
+ "<min> minor number of nod\n"
+ "<hard links> space separated list of other links to file\n"
+ "\n"
+ "example:\n"
+ "# A simple initramfs\n"
+ "dir /dev 0755 0 0\n"
+ "nod /dev/console 0600 0 0 c 5 1\n"
+ "dir /root 0700 0 0\n"
+ "dir /sbin 0755 0 0\n"
+ "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
+ "\n"
+ "<timestamp> is time in seconds since Epoch that will be used\n"
+ "as mtime for symlinks, special files and directories. The default\n"
+ "is to use the current time for these entries.\n",
+ prog);
+}
+
+struct file_handler file_handler_table[] = {
+ {
+ .type = "file",
+ .handler = cpio_mkfile_line,
+ }, {
+ .type = "nod",
+ .handler = cpio_mknod_line,
+ }, {
+ .type = "dir",
+ .handler = cpio_mkdir_line,
+ }, {
+ .type = "slink",
+ .handler = cpio_mkslink_line,
+ }, {
+ .type = "pipe",
+ .handler = cpio_mkpipe_line,
+ }, {
+ .type = "sock",
+ .handler = cpio_mksock_line,
+ }, {
+ .type = NULL,
+ .handler = NULL,
+ }
+};
+
+#define LINE_SIZE (2 * PATH_MAX + 50)
+
+int main (int argc, char *argv[])
+{
+ FILE *cpio_list;
+ char line[LINE_SIZE];
+ char *args, *type;
+ int ec = 0;
+ int line_nr = 0;
+ const char *filename;
+
+ default_mtime = time(NULL);
+ while (1) {
+ int opt = getopt(argc, argv, "t:h");
+ char *invalid;
+
+ if (opt == -1)
+ break;
+ switch (opt) {
+ case 't':
+ default_mtime = strtol(optarg, &invalid, 10);
+ if (!*optarg || *invalid) {
+ fprintf(stderr, "Invalid timestamp: %s\n",
+ optarg);
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ exit(opt == 'h' ? 0 : 1);
+ }
+ }
+
+ if (argc - optind != 1) {
+ usage(argv[0]);
+ exit(1);
+ }
+ filename = argv[optind];
+ if (!strcmp(filename, "-"))
+ cpio_list = stdin;
+ else if (!(cpio_list = fopen(filename, "r"))) {
+ fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
+ filename, strerror(errno));
+ usage(argv[0]);
+ exit(1);
+ }
+
+ while (fgets(line, LINE_SIZE, cpio_list)) {
+ int type_idx;
+ size_t slen = strlen(line);
+
+ line_nr++;
+
+ if ('#' == *line) {
+ /* comment - skip to next line */
+ continue;
+ }
+
+ if (! (type = strtok(line, " \t"))) {
+ fprintf(stderr,
+ "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
+ line_nr, line);
+ ec = -1;
+ break;
+ }
+
+ if ('\n' == *type) {
+ /* a blank line */
+ continue;
+ }
+
+ if (slen == strlen(type)) {
+ /* must be an empty line */
+ continue;
+ }
+
+ if (! (args = strtok(NULL, "\n"))) {
+ fprintf(stderr,
+ "ERROR: incorrect format, newline required line %d: '%s'\n",
+ line_nr, line);
+ ec = -1;
+ }
+
+ for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
+ int rc;
+ if (! strcmp(line, file_handler_table[type_idx].type)) {
+ if ((rc = file_handler_table[type_idx].handler(args))) {
+ ec = rc;
+ fprintf(stderr, " line %d\n", line_nr);
+ }
+ break;
+ }
+ }
+
+ if (NULL == file_handler_table[type_idx].type) {
+ fprintf(stderr, "unknown file type line %d: '%s'\n",
+ line_nr, line);
+ }
+ }
+ if (ec == 0)
+ cpio_trailer();
+
+ exit(ec);
+}
diff --git a/init b/init
new file mode 100644
index 0000000..ee906d1
--- /dev/null
+++ b/init
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+trap 'kill $dropbear_pid; exec sh' EXIT
+
+case "$PATH" in
+ */*) ;;
+ *) export PATH="/usr/sbin:/usr/bin:/sbin:/bin" ;;
+esac
+
+mount -t proc proc /proc
+mount -t devtmpfs devtmpfs /dev
+mkdir -p /dev/pts
+mount -t devpts devpts /dev/pts
+mount -t sysfs sysfs /sys
+
+(
+ip link set eth0 up
+ip addr add 192.168.0.7/24 dev eth0
+exec dropbear -F -s -p 2222 -K 30
+) &
+dropbear_pid=$!
+
+enc_root=$(findfs UUID=26748575-d7a7-418b-8f68-21be7c937500) || exit
+(
+amixer sset Master on
+amixer sset Master 30%
+aplay -Dhw:0,0 /usr/share/sounds/ding.wav
+) >/dev/null 2>&1 &
+cryptsetup open --tries 65535 --allow-discards "$enc_root" root || [ -e /dev/mapper/root ] || exit
+
+kill $dropbear_pid
+dropbear_pid=
+
+e2fsck -C 0 -E inode_count_fullmap -p /dev/mapper/root
+e2fsck_r=$?
+if [ $(( e2fsck_r & 2 )) = 2 ]; then
+ reboot -f
+fi
+case "$e2fsck_r" in
+ 0|1) ;;
+ *) exit
+esac
+
+mount -o nodev,commit=30 /dev/mapper/root /mnt || exit
+cd /mnt
+umount /dev/pts
+mount --move /dev dev
+mount --move /proc proc
+mount --move /sys sys
+
+exec switch_root /mnt /usr/lib/systemd/systemd
diff --git a/make b/make
new file mode 100755
index 0000000..6d150ba
--- /dev/null
+++ b/make
@@ -0,0 +1,91 @@
+#!/bin/sh
+
+set -e
+
+scriptloc=${BASH_SOURCE:-$0}
+scriptdir=${scriptloc%/*}
+
+gen_cpio_list() {
+ cat << EOF
+dir /dev 0755 0 0
+dir /mnt 0755 0 0
+dir /proc 0755 0 0
+dir /run 0755 0 0
+dir /run/cryptsetup 0755 0 0
+dir /sys 0755 0 0
+
+nod /dev/console 0600 0 0 c 5 1
+
+slink /bin/sh busybox 0755 0 0
+slink /etc/mtab /proc/self/mounts 0755 0 0
+
+slink /usr/lib64/libgcc_s.so libgcc_s.so.1 0755 0 0
+file /usr/lib64/libgcc_s.so.1 /usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/libgcc_s.so.1 0755 0 0
+
+file /bin/busybox /bin/busybox 0755 0 0
+file /etc/passwd $scriptdir/passwd 0644 0 0
+file /etc/dropbear/dropbear_rsa_host_key $scriptdir/dropbear_rsa_host_key 0600 0 0
+file /etc/dropbear/dropbear_ecdsa_host_key $scriptdir/dropbear_ecdsa_host_key 0600 0 0
+file /init $scriptdir/init 0755 0 0
+file /lib/firmware/radeon/CAYMAN_mc.bin /lib/firmware/radeon/CAYMAN_mc.bin 0644 0 0
+file /lib/firmware/radeon/CAYMAN_me.bin /lib/firmware/radeon/CAYMAN_me.bin 0644 0 0
+file /lib/firmware/radeon/CAYMAN_pfp.bin /lib/firmware/radeon/CAYMAN_pfp.bin 0644 0 0
+file /lib/firmware/radeon/CAYMAN_rlc.bin /lib/firmware/radeon/CAYMAN_rlc.bin 0644 0 0
+file /lib/firmware/radeon/CAYMAN_smc.bin /lib/firmware/radeon/CAYMAN_smc.bin 0644 0 0
+file /lib/firmware/radeon/SUMO_uvd.bin /lib/firmware/radeon/SUMO_uvd.bin 0644 0 0
+file /lib/firmware/rtl_nic/rtl8168h-2.fw /lib/firmware/rtl_nic/rtl8168h-2.fw 0644 0 0
+file /lib64/libnss_files.so.2 /lib64/libnss_files.so.2 0755 0 0
+file /root/.ssh/authorized_keys $scriptdir/authorized_keys 0600 0 0
+file /unlock $scriptdir/unlock 0755 0 0
+file /usr/share/alsa/cards/HDA-Intel.conf /usr/share/alsa/cards/HDA-Intel.conf 0644 0 0
+file /usr/share/alsa/cards/USB-Audio.conf /usr/share/alsa/cards/USB-Audio.conf 0644 0 0
+file /usr/share/sounds/ding.wav $scriptdir/ding.wav 0644 0 0
+EOF
+ find /usr/share/alsa \
+ \( -name cards -o -name speaker-test -o -name ucm -o -name topology \) -prune -o \
+ -type f -print | while read f; do
+ printf 'file %s %s 0644 0 0\n' "$f" "$f"
+ done
+ for cmd in cryptsetup e2fsck aplay amixer dropbear; do
+ cmdp="$(command -v "$cmd")"
+ # builtin
+ if [ "$cmd" = "$cmdp" ]; then
+ continue
+ fi
+ ldd "$cmdp" | while read a b c d; do
+ if [ "$b" = '=>' ]; then
+ printf 'file /lib64/%s %s 0755 0 0\n' "${c##*/}" "$c"
+ else
+ # interpreter
+ case "$a" in
+ /*) printf 'file %s %s 0755 0 0\n' "$a" "$a" ;;
+ esac
+ fi
+ done
+ printf 'file %s %s 0755 0 0\n' "$cmdp" "$cmdp"
+ done
+}
+
+gen_dir_ents() {
+ while read type target args; do
+ printf '%s %s %s\n' "$type" "$target" "$args"
+ while [ "${target%/*}" != '' ]; do
+ target=${target%/*}
+ printf 'dir %s 0755 0 0\n' "$target"
+ done
+ done
+}
+
+gen_depfile() {
+ echo "initramfs.img: make" >&3
+ while read type target source args; do
+ printf '%s %s %s %s\n' "$type" "$target" "$source" "$args"
+ if [ "$type" = file ]; then
+ echo "initramfs.img: $source" >&3
+ fi
+ done
+}
+
+gen_cpio_list | gen_dir_ents | sort -u | gen_depfile 3>initramfs.d | "${scriptdir}"/gen_init_cpio -t 0 - | xz --x86 --lzma2=preset=9e --check=crc32 -c > initramfs.img
+
+# vim:ft=sh:
diff --git a/passwd b/passwd
new file mode 100644
index 0000000..eb85a55
--- /dev/null
+++ b/passwd
@@ -0,0 +1 @@
+root:x:0:0:root:/root:/bin/sh
diff --git a/unlock b/unlock
new file mode 100644
index 0000000..d034674
--- /dev/null
+++ b/unlock
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+cryptsetup open /dev/nvme0n1p2 root && pkill cryptsetup