{"id":13711047,"url":"https://github.com/chris-se/tiny-initramfs","last_synced_at":"2025-03-15T14:30:29.059Z","repository":{"id":45469612,"uuid":"49087994","full_name":"chris-se/tiny-initramfs","owner":"chris-se","description":"A minimalistic initrd implementation","archived":false,"fork":false,"pushed_at":"2024-02-14T09:17:21.000Z","size":71,"stargazers_count":84,"open_issues_count":9,"forks_count":14,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-02-27T02:42:20.243Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chris-se.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-01-05T19:32:26.000Z","updated_at":"2025-02-24T16:58:50.000Z","dependencies_parsed_at":"2024-10-26T21:17:28.415Z","dependency_job_id":"343898e9-90bf-4688-be51-eab03d8b5b35","html_url":"https://github.com/chris-se/tiny-initramfs","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chris-se%2Ftiny-initramfs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chris-se%2Ftiny-initramfs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chris-se%2Ftiny-initramfs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chris-se%2Ftiny-initramfs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chris-se","download_url":"https://codeload.github.com/chris-se/tiny-initramfs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243742496,"owners_count":20340658,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T23:01:03.885Z","updated_at":"2025-03-15T14:30:28.776Z","avatar_url":"https://github.com/chris-se.png","language":"C","funding_links":[],"categories":["Projects"],"sub_categories":[],"readme":"tiny-initramfs - A minimalistic initramfs implementation\n========================================================\n\nThis is a very minimalistic [initramfs](https://en.wikipedia.org/wiki/Initramfs)\nimplementation for booting Linux systems. It has nearly no features,\nbut is very small and very fast. It is written purely in C, but uses\nonly parts of the standard library.\n\nThere are three primary use cases:\n\n * It is designed for systems where an initramfs is typically not\n   necessary (block device drivers + root file system compiled into the\n   kernel, no  separate /usr file system), but where an initramfs is\n   required for microcode upgrades. Instead of having to use a full\n   initramfs, which is larger (more time spent in the boot loader\n   loading it) and slower (because it does more), `tiny-initramfs` will\n   add next to no overhead.\n * In cases where `UUID`-based boot is wanted not a full initramfs.\n * In systems with a split `/usr` file system, it is necessary to mount\n   that in the initramfs already, else subtle problems may occur. If\n   `/usr` resides on a simple block device already known to the kernel\n   (without user space helpers such as udev), `tiny-initramfs` provides\n   a mechanism with very little overhead to mount it before the system\n   is started.\n\nFeatures\n--------\n\n * Simplicity: the implementation is really simple and very linear.\n   It's most likely easier to understand than other initramfs\n   implementations. The entire program is less about 2500 LoC, and that\n   includes the License headers in the files.\n * Size: the implementation is really small (see below).\n * Speed: there is no noticeable performance penalty, because very\n   little is done before execution is handed over to the operating\n   system proper.\n * Supports kernel-named devices, for example `root=/dev/sda1`.\n * Supports `root=0xMAJMIN`.\n * Supports `root=UUID=...` for ext2, ext3, ext4, xfs and btrfs.\n * Supports parsing `/etc/fstab` to determine if a separate `/usr`\n   partition exists and mounting that - as long as the entry there\n   follows the same rule as the `root=` parameter (kernel device name,\n   or `UUID=` entry for a select number of filesystems).\n * Supports the `root=`, `rootflags=`, `rootfstype=`, `rootdelay=`,\n   `rootwait`, `ro`, `rw` and `init=` parameters.\n * Default timeout of 180 seconds to wait for the root device to appear\n   (starts after the `rootdelay=` delay is over), after which a kernel\n   panic is caused; if `rootwait` is specified it will wait\n   indefinitely. (Recompilation is necessary for a larger timeout.)\n * Supports mounting NFSv4 file systems with `sec=sys` that do **not**\n   use the idampper, i.e. use raw UIDs/GIDs. For the `/usr` file system\n   the standard `/etc/fstab` entries are interpreted, for the root file\n   system one should use `root=/dev/nfs` and the `nfsroot=` parameter\n   (as documented in the kernel documentation). The network\n   configuration needs to be specified via the `ip=` kernel command\n   line parameter.\n * Very trivial module loading support (**no** automatic dependency\n   resolution).\n\nWhen compiled on an x86_64 system with the default `-Og` compiler flags,\nstatically linked against dietlibc 0.33~cvs20120325-6, the binary\nstripped and the resulting initramfs (without any modules added)\ncompressed with `gzip -9`, the images produced are between 9 kiB and\n14 kiB, depending on the feature set selected.\n\nUsing musl instead of dietlibc adds between 1.8 and 2.4 kiB to the\nresulting `initrd.img` size (depending on the feature set).\n\nUsing glibc instead of dietlibc adds around 310 kiB to the resulting\ninitrd image and is not recommended (although it will work).\n\nAdding modules to the initramfs will increase the size, and many block\ndevice and file system drivers are 100s of kiB in size. On the other\nhand, the kernel would be larger if they were compiled in, so the\nactual amount of space lost due to using modules is quite a bit\nsmaller.\n\nRequirements\n------------\n\n * The kernel should have the necessary block device and file system\n   drivers built-in that are required to access the root and `/usr`\n   file systems. **Warning:** this is not true for most default kernels\n   of mainstream  distributions, as they require a full initramfs to\n   load the modules required to mount the root file system.\n * If the necessary drivers are not built into the kernel, there is\n   limited support for loading modules from within the initramfs, see\n   below for details.\n * The kernel must have `CONFIG_DEVTMPFS` built-in, because this\n   implementation assumes the kernel will just create the devices by\n   itself. (This is true for most distribution kernels.)\n * NFSv4 requires at least kernel 3.5 on both server and client (in\n   order for raw UIDs/GIDs to work) and requires built-in kernel\n   support for network autoconfiguration (`CONFIG_IP_PNP` and for DHCP\n   support also `CONFIG_IP_PNP_DHCP`) as well as built-in kernel\n   support for NFSv4 (`CONFIG_NFS_FS` as well as `CONFIG_NFS_V4`).\n\nWhen not to use\n---------------\n\n * `tiny-initramfs` does not support `PARTUUID=` for mounting the root\n   or `/usr` file systems. It also doesn't support symlinks created by\n   udev (such as `/dev/disk/by-label/...`). Only the kernel names\n   themselves, such as `/dev/sda1`, as well as `UUID=` and hexadecimal\n   device numbers (`0xMAJMIN`, e.g. `0x801`) are supported.\n * NFSv2/NFSv3 are currently not supported.\n * When booting from USB storage you should always use `UUID=`, because\n   device names are not necessarily stable.\n * `/usr` on a FUSE file system, as they require user space helpers\n   running to be able to mount. Generally speaking, any file system\n   that can't be mounted with just a trivial `mount` syscall, but\n   requires a userspace helper, will not work.\n * Any complex storage setup, such as LVM, encryption, iSCSI, etc.\n   Basically, only things that the kernel provides devices for out of\n   the box (potentially with additional kernel parameters) is\n   supported.\n\nIf your setup falls into one of these cases, please use a full\ninitramfs instead of `tiny-initramfs`. It is not meant to replace\nthose, but provide a light-weight solution in cases where the\ncomplexities of a full initramfs are unnecessary.\n\nCaveats\n-------\n\n * Since the initramfs is supposed to be small, `fsck` will not be\n   executed by `tiny-initramfs`. For the `/` file system this is\n   perfectly fine, as most distributions support checking the root file\n   system at boot outside of the initramfs. But this doesn't work for\n   `/usr`, because e.g. `e2fsck` will not check a mounted file system\n   other than the root file system; and e.g. systemd passes `-M` to\n   `fsck` by default for non-root file systems, so mounted file systems\n   are excluded anyway. It shouldn't be too difficult to special-case\n   `/usr` here as well, but that work needs to be done if a file system\n   check at boot is to be performed for `/usr` with `tiny-initramfs`.\n   (Note that `e2fsck` plus the required libraries are about 2.5 MiB in\n   size, so having `fsck` present in the initramfs image is not in the\n   scope of `tiny-initramfs`, because it would remove all the\n   advantages.)\n * You need to make sure that a split-`/usr` file system is remounted\n   read-write if the `ro` option is passed on the kernel command line\n   (because `tiny-initramfs` will also mount `/usr` read-only then);\n   otherwise `/usr` will remain read-only after boot. If you use\n   systemd as your init system, or e.g. the newest Debian initscripts\n   (`2.88dsf-59.3` or higher) in conjunction with sysvinit, this should\n   work. `tiny-initramfs` itself doesn't care about which init system\n   is used, but the init system must be able to cope with the state\n   that `tiny-initramfs` leaves the  `/usr` file system in. This may\n   require changes to some scripts.\n * If `/usr` is a bind mount in `/etc/fstab`, this will currently fail,\n   even though it should be supportable. (It's on the TODO list, as\n   long as that doesn't require yet another file system.)\n * Overlay-type file systems for `/usr` are untested, but they should\n   work if they are compiled into the kernel. What is *not* supported\n   are overlay-type file systems for `/` and/or if something has to be\n   done prior to mounting these file systems (such as creating a\n   directory, or mounting an additional tmpfs or similar).\n * Booting from kernel-assembled RAID arrays (via `md=...`) should\n   work, but is untested. Don't combine this with `UUID=`, though, as\n   `tiny-initrd` currently does not check if a block device has array\n   metadata, so it could falsely identify a member device (instead of\n   the entire array) when using `UUID=` in some cases. But for arrays\n   that are assembled by the kernel via `md=...` the device name is\n   known anyway (typically `/dev/md0`), so this shouldn't be an issue.\n * NFS support is not thoroughly tested.\n * Host names are unsupported for NFS mounts, only IP addresses work.\n * While this is supposed to be portable, this has only been tested on\n   x86_64 (amd64). Since low-level kernel syscalls are performed, there\n   may be some issues on other architectures. Please report those if\n   they are present.\n\nHOWTO\n-----\n\nInstall an alternative libc implementation that's designed for embedded\nuse cases, such as [musl](http://www.musl-libc.org/) or\n[dietlibc](http://www.fefe.de/dietlibc/). This is strictly speaking not\nrequired, as the default glibc will also work, but then the binary size\nof the resulting binary will be far larger. If `tiny-initramfs` doesn't\nwork with your favorite libc implementation, please report this, so\nthat it may be fixed.\n\nFind out the compile command required to use your C library. For\nexample, with dietlibc it's `\"diet gcc\"`, with musl it's `musl-gcc`.\n\nUse\n\n    ./configure CC=\"diet gcc\"\n    make\n\nto compile the `tiny_initramfs` binary and\n\n    make initrd.img\n\nto auto-create the initramfs image. Replace `\"diet gcc\"` with the\nappropriate command for your libc implementation.\n\nNote that if you specify `CFLAGS` (potentially via your build system)\nyou should take care to specify `-Os` and *not* to specify any debug\n(`-g`) options, as those tend to increase the binary size quite a bit.\n`./configure` will warn you about it, but it not abort in that case,\nbecause the binary will work. Likewise, if you don't use an alternative\nlibc implementation but glibc, `./configure` will warn you about it,\nbecause that will increase the binary size by a factor of 10 to 20.\n\nYou may specify multiple options to enable/disable certain features in\nthe initramfs. Specifically, you can disable UUID mounting support\n(enabled by default), and you can enable NFSv4 support (disabled by\ndefault). A list of possible options is displayed when using\n\n    ./configure --help\n\nThe initramfs creation is really simple, you may also do so manually:\n\n 1. create an empty directory, let's call it `initramfs/`\n 2. copy `tiny_initramfs` to the directory, call it `init` (you can\n    call it something else, but then you also need to pass the\n    `rdinit=/newname` option to the kernel command line)\n 3. strip the binary to reduce it's size (optional)\n 4. create the `dev`, `proc` and `target` subdirectories\n 5. cpio the directory and compress it\n\nThe following commands do just that:\n\n    mkdir initramfs\n    cp tiny_initramfs initramfs/init\n    strip initramfs/init\n    mkdir initramfs/dev initramfs/proc initramfs/target\n    cd initramfs ; find . | cpio -o --quiet -R 0:0 -H newc | gzip \u003e ../initrd.img\n\nWith this there's now a (kernel-independent) initramfs image that may\nbe used to boot the system. Note that as of now there is no integration\nwith distributions, so configuring the boot loader etc. has to be done\nmanually.\n\nSupport for loading modules\n---------------------------\n\nThere is limited support for loading modules if `--enable-modules` is\nspecified during the `configure` invocation. To use this feature, one\nneeds to create a file `/modules` in the initramfs image that is of the\nfollowing format:\n\n    /file.ko options\n\nThe modules should not be in a sub-directory, because the directory\ncontaining them will not be cleaned-up by tiny-initramfs after mounting\nthe root file system. (Loading the modules will work though.)\n\nFor example, the virtio block device driver `virtio_blk` requires some\nadditional modules to work. Using `modprobe` one may find out which:\n\n    $ /sbin/modprobe --all --ignore-install --quiet --show-depends virtio_blk\n    insmod /lib/modules/[...]/kernel/drivers/virtio/virtio.ko\n    insmod /lib/modules/[...]/kernel/drivers/virtio/virtio_ring.ko\n    insmod /lib/modules/[...]/kernel/drivers/block/virtio_blk.ko\n\nIt turns out that this is not quite sufficient, because the\n`virtio_pci` driver is also required for `virtio_blk` to work (the\ndriver loads without `virtio_pci`, but doesn't work), so one may use:\n\n    $ /sbin/modprobe --all --ignore-install --quiet --show-depends virtio_blk virtio_pci\n    insmod /lib/modules/3.16.0-4-amd64/kernel/drivers/virtio/virtio.ko\n    insmod /lib/modules/3.16.0-4-amd64/kernel/drivers/virtio/virtio_ring.ko\n    insmod /lib/modules/3.16.0-4-amd64/kernel/drivers/block/virtio_blk.ko\n    insmod /lib/modules/3.16.0-4-amd64/kernel/drivers/virtio/virtio.ko\n    insmod /lib/modules/3.16.0-4-amd64/kernel/drivers/virtio/virtio_ring.ko\n    insmod /lib/modules/3.16.0-4-amd64/kernel/drivers/virtio/virtio_pci.ko\n\n(Note that in case soft dependencies are treated via `install` lines,\nthese have to be resolved manually. This is typically not the case for\ndrivers needed within initramfs, because other implementations also\nsuffer from the same issue. `install` is deprecated anyway according to\nthe manual page of `modprobe.d`.)\n\nOne may then copy these drivers to the initramfs image, and then add\na module file with the following contents:\n\n    /virtio.ko\n    /virtio_ring.ko\n    /virtio_blk.ko\n    /virtio.ko\n    /virtio_ring.ko\n    /virtio_pci.ko\n\nThe order is important, because dependency resolution is **not**\nperformed by tiny-initramfs, it has to be done while creating the\ninitramfs image. Duplicate entries are not a problem, because they will\nsilently be ignored (but you may remove duplicate entries if you don't\nchange the order otherwise).\n\nOptions may be specified when followed by a space (tab characters not\nsupported), for example:\n\n    /libata.ko noacpi\n\nDebugging\n---------\n\nIf an error occurs, tiny-initramfs will print an error message\nindicating the problem and then sleep for 10s before exiting. This is\nbecause exiting will cause a kernel panic, but typical kernel traces\nare so large that they replace the entire screen contents on a standard\nterminal, so that the original message is not visible anymore. The 10s\ndelay allows the user to see what the problem is.\n\nAdditionally, one may use the `--enable-debug` flag of `./configure` to\nmake `initrd.img` verbose (while increasing the size a bit). This makes\ndebugging easier, especially if the system hangs at a certain point.\nWhen compiled with that option, tiny-initramfs will print the contents\nof `/proc/self/mountinfo` and sleep for 5s after mounting the root (and\npotentially /usr) file systems before executing `init`.\n\nDesign considerations\n---------------------\n\nThe design of `tiny-initramfs` is as minimalistic as possible. The\nbuffered I/O functions from the `stdio.h` standard library are\ncompletely avoided, because they can increase the code size quite a\nbit, depending on the libc implementation. At one point an own\nminimalistic buffered I/O routine is implemented (much smaller than the\nfull standard library linked in).\n\nDynamic allocations are avoided and buffers on the stack are used. Code\nthat properly handles dynamic allocations tends to be longer, so this\nreduces code size. The buffers are sized generously (there are not that\nmany buffers that the amount of RAM used is a concern just yet, even\nfor small systems), so that no real flexibility is sacrificed.\n\nNone of this is extremely performance-critical (it is going to be quite\nfast regardless, because very little is done compared to even just\nrunning a shell), so no algorithm is optimized for speed directly. For\nexample, the mount option parser table is somewhat compressed to reduce\nthe code size (negation and recursive variants of mount options are not\nrepeated), to the point where further reduction would likely sacrifice\nthe readability of the code. Execution speed is achieved by doing very\nlittle, not by micro-optimizing algorithms.\n\nSometimes it is necessary to reimplement certain libc functions because\nusing the libc variants increase the image size too much. For example,\nusing `inet_ntoa` and `inet_aton` (to convert between ASCII to binary\nrepresentations of IP addresses) from the musl C library will cause\ninitramfs images (after compression) to be an additional 5 KiB larger\nas compared to the own implementation.\n\nOf course, changes that reduce the current code size even further (as\nlong as the code remains readable) are very welcome.\n\nFuture features\n---------------\n\nThere is no goal of adding too many additional features here, because\nany additional feature is going to increase the binary size, and this\nis supposed to be minimalistic and **not** a replacement for a full\ninitramfs. If you need advanced features, please use an already\nexisting solution. That said, there are a couple of things that might\nbe interesting regardless:\n\n * Minimalistic NFSv2/3 mounting support (akin to the current NFSv4\n   code).\n * Maybe support host name lookups for NFS mounts? (Probably not going\n   to happen, as an own DNS resolver will likely increase the image\n   size by too much - and is likely going to be rather complicated.)\n * Support `UUID=` for more filesystems, as long as they are really\n   simple. Currently, the implementation checks the magic bytes of a\n   given file system on the each device, and then compares the UUID at\n   the right position in the file system metadata. (See `devices.c` for\n   details on how this is implemented for the currently supported file\n   systems.)\n * Support for excluding MD/RAID/... devices when probing for UUIDs of\n   file systems.\n\nNote that the goal is to keep the `initrd.img` size smaller than 16 KiB\non all platforms, so a cutoff of 15 KiB is used on x86_64, to leave\nroom for different assembly code sizes etc., at least when used in a\nminimal configuration. Therefore, some features (such as `UUID=` and\nNFSv4 support) are compile-time optional.\n\nNote: any features missing from tiny-initramfs that would be required\nin a space-constrained environment (i.e. mainly embedded), where it was\ndesigned for, stand an excellent chance of being included later, at\nleast compile-time optional. Please make your case if you are missing\nsomething.\n\nTODO\n----\n\n * bind mounts for /usr\n * clean up the code a bit.\n * go through all messages printed and make sure they are uniform in\n   style\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchris-se%2Ftiny-initramfs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchris-se%2Ftiny-initramfs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchris-se%2Ftiny-initramfs/lists"}