Show pagesourceOld revisionsBacklinksBack to top × Table of Contents Preinit and Root Mount and Firstboot Scripts Abstract Context: Boot Sequence Overview Preinit Failsafe Mount Root Filesystem First Boot Common Sourced rather than executed Executed with no parameters Executed with parameter 'switch2jffs' hook no_fo Preinit Operation Main Preinit Script Variables Hooks Development preinit_essentials preinit_main failsafe preinit_mount_root initramfs Firstboot Operation Main Firstboot Script Hooks switch2jffs no_fo jffs2reset Customizing the system Overriding Example Adding Example Architecture-specific notes Preinit and Root Mount and Firstboot Scripts Information may be outdated and obsolete information as of April, 2018; Overview, Preinit and Overview, Failsafe updated from April 2018 based on reading master code. See Rootfs on External Storage for information on external rootfs mounting. Abstract This document presents the preinit / firstboot boot sequence. The boot system is extensible via (new) packages such as rootfs on usb, or enhanced failsafe. We describe the portion of the OpenWrt boot sequence that occurs before the 'init' program is executed (when booting in multiuser mode), as well as the script that is responsible for creating and initializing the root filesystem on the first boot after flashing the device with OpenWrt. Context: Boot Sequence The basic OpenWrt boot sequence is: boot loader loads kernel kernel loads whilst scanning the mtd partition rootfs for a valid superblock for mounting the SquashFS partition (which contains /etc). More info at technical.details kernel calls /etc/preinit (the kernel considers this to be the init (or root) process /sbin/init now the init process, which in turn launches /sbin/procd -h /etc/hotplug-preinit.json (a.k.a., “plugd”) followed by /bin/sh /etc/preinit. Each is launched via fork and execvp and managed by the uloop library in libubox. /etc/preinit prepares system for multiuser mode /etc/preinit execs /sbin/init which becomes the init (or root) process and launches multiuser /sbin/init launches processes according to /etc/inittab. Typically the first process launched is /etc/init.d/rcS which causes the scripts in /etc/rc.d which begin with 'S' to be launched (in glob sort order). The /etc/rc.d directory is populated with symlinks to the scripts in /etc/init.d. Each script in /etc/init.d accepts enable and disable arguments for creating and removing the symlinks. These script initialize the system and also initialize daemons that wait for input, so that when all the scripts have executed the normal system is active. On first boot this initializing includes the process of preparing the root filesystem for use. Overview Preinit Preinit brings the system from raw kernel to ready for multiuser. To do so, as of April, 2018, /etc/preinit (ar71xx, Archer C7) performs the following tasks: Checks to see if $PREINIT is empty; if so exec /sbin/init and skip the rest Sources a set of files for common functions for boot/mount: /lib/functions.sh /lib/functions/preinit.sh /lib/functions/system.sh Prepares the “hooks” for the various stages of the preinit process preinit_essential preinit_main failsafe initramfs preinit_mount_root Source the contents of /lib/preinit/* which generally add sh functions to the appropriate hooks Runs the preinit_essential hooks Runs the preinit_main hooks On an ar71xx device (Archer C7) the default functions added to the various hooks include (with functions from device-specific files in italics): preinit_main do_ar71xx define_default_set_state do_sysinfo_generic preinit_set_mac_address set_preinit_iface preinit_ip pi_indicate_preinit failsafe_wait run_failsafe_hook failsafe (if “$pi_preinit_no_failsafe” != “y” and “$FAILSAFE” = “true”) indicate_failsafe failsafe_netlogin failsafe_shell indicate_regular_preinit do_mount_root (if “$INITRAMFS” != “1”) do_urandom_seed check_patch_ath10k_firmware run_init Presently unused hooks, at least for the ar71xx Archer C7, appear to include preinit_essential initramfs preinit_mount_root Failsafe The root file system is actually an overlay which can be consisted of a read-only SquashFS file system (mounted at /rom) and a writable JFFS2 partition (mounted under /overlay). In Failsafe mode only the squashfs FS will be mounted (changes made to jffs2 partitons will be ignored), plus the following steps: Notifies that failsafe mode is being entered (indicate_failsafe) Launches daemon to allow network logins (failsafe_netlogin) Allows login via serial console, if there is one (failsafe_shell) If the serial console login process exits, failsafe doesn't exit, but restarts the process for additional logins. Mount Root Filesystem all_jffs2 refers to a 'jffs2' target in menuconfig; e.g. firmware has no squashfs, but is purely a rw filesystem (jffs2), while, jffs2 in the following text refers to the jffs2 portion of a squashfs/jffs2 system. Kernel has previously mounted squashfs partition by scanning the mtd partition rootfs for a valid superblock (see step 2 of contextboot.sequencel) Make sure it's correct If there is no mtd device with label rootfs_data, then mounts /dev/root (e.g. squashfs or all_jffs2 with no squashfs) as root filesystem, and indicates that further steps should be skipped If mtd device rootfs_data has not already been formatted, mounts a tmpfs (ramdisk) as root filesystem, and indicates that further steps should be skipped. Mounts previously formatted jffs2 partition on /overlay and indicates successful mount. Makes successfully mounted /overlay (if it exists) the new root filesystem and moves previous root filesystem to /rom, and indicates to skip further steps. This is only reached on an error condition; attempts to mount a tmpfs (ramdisk) as root filesystem This is only reached if no other step succeeds; attempt to mount /dev/root (e.g. squashfs/all_jffs2) as root filesystem. * /overlay was previously named /jffs2. * NOTE: If volatile files (e.g. a config) were preserved across firmware update via sysupgrade, step 3 is skipped. Instead, preinit_main hangs while the rootfs_data partition is formatted and the jffs2 overlay is mounted. Hypothetically, this is fatal on systems with weak cpu and exceptionally large rootfs_data partitions. For more information consult this forum post. First Boot /sbin/firstboot may be referenced in three ways. It may be called as part of the system startup, in which cased it is called as /sbin/firstboot switch2jffs. It may be used as a standalone command with no parameters (.e.g. /sbin/firstboot) It may be sourced from another script Common Source /lib/functions/boot.sh for common functions (e.g. also used by preinit) Source files used by hooks Determine how called, and branch to appropriate commands. Sourced rather than executed Determine (and set variable for) MTD rootfs_data partition Determine (and set variable for) rom partition Determine (and set variable for) jffs2 partition Executed with no parameters Resets jffs2 to original settings, if possible. If jffs2 is not mounted, erases mtd and attempts format, mount, and pivot jffs2 as root. If jffs2 is mounted, firstboot runs hook jffs2reset Determine (and set variable for) MTD rootfs_data partition Determine (and set variable for) rom partition Determine (and set variable for) jffs2 partition Determine (and set variable to indicate) whether the mini overlay filesystem type is supported. If overlay is supported, remove all files on jffs2 and remount it. If overlay not supported, create directories and symlinks, copying only certain critical files Note: since r35712 the firstboot script requires an inputted 'y' as confirmation. If using firstboot in a reset button script, you need to get that y inputted, e.g. by using the yes command: yes | firstboot Executed with parameter 'switch2jffs' Determine (and set variable for) MTD rootfs_data partition Determine (and set variable for) rom partition Determine (and set variable for) jffs2 partition Determine if mini overlay is supported. If not run hook no_fo Otherwise, if mounted, skip the rest, otherwise mount under squashfs (/rom/jffs) Copy ramdisk to jffs2 Move /jffs to / (root) and move / (root) to /rom Cleanup hook no_fo Switch to kernel fs, get rid of union overlay and bind from /tmp/root Mount jffs (and make it safe for union) If not mounted, mount; copy from squashfs, and pivot so that /jffs is now / (root) Copy files from ramdisk Get rid of unnecessary mounts (cleanup) Preinit Operation Preinit consists of a number of scripts. The main script is /etc/preinit which reads in the scripts. The scripts define functions which they attach to hooks. These hooks are, when processed, launching the functions in the order they were added to the hooks. Currently there are five hooks used by the preinit system: preinit_essential preinit_main failsafe initramfs preinit_mount_root Each hook have a corresponding string variable containing the name of each function to be executed, separated by spaces. The hook variables have _hook appended to the hook name. Thus the name of the variable for the preinit_essential hook is preinit_essential_hook. Main Preinit Script The main preinit script is actually quite empty. It: Initializes some variables (including the hook variables) Defines the function pi_hook_add, which is used to add functions to a hook Defines the function pi_run_hook, which executes the functions that were added to a hook Sources (reads) the shell scripts under folder /lib/preinit/, in glob sort order Processes the hook preinit_essential Initializes variables used by preinit_main Processes the hook preinit_main That's it. Variables There are a number of variables that control options of preinit. Defaults are defined in the main script /etc/preinit defined by the base-files package. However the variables are customizable via make menuconfig, in section “Preinit configuration options”. The OpenWrt build process will then create the file /lib/preinit/00_preinit.conf which will be sourced by the main script. The variables defined at present are: Variable Description pi_ifname The device name of the network interface used to emit network messages during preinit (except failsafe) pi_ip The IP address of the preinit network (see above) pi_broadcast The broadcast address of the preinit network (see above) pi_netmask The netmask for the preinit network (see above) fs_failsafe_wait_timeout How long to pause while allowing the user to choose to enter failsafe mode. Default is two (2) seconds. pi_suppress_stderr If this is “y”, then output on standard error (stderr, file descriptor 2), is ignored during preinit. This is the default in previous versions of OpenWrt (which did not have this option) pi_init_suppress_stderr If pi_suppress_stderr is not “y” (i.e. stderr is not suppressed for preinit), then this option controls whether init, and process run by init, except those associated with a terminal device (e.g. tts/0, ttyS0, tty1, pts/0, or other similar devices) will have stderr suppressed (not that network terminals such as those from SSH are associated with a pseudo-terminal device such as pty0/pty1 and are thus unaffected). As with pi_suppress_stderr, the default, and behaviour from previous versions of OpenWrt is “y”. pi_init_path The default search PATH for binaries for commands run by init. Default is /bin:/sbin:/usr/bin:/usr/sbin pi_init_cmd The command to run as init. Default is /sbin/init pi_preinit_no_failsafe_netmsg suppress netmsg to say that one can enter failsafe mode pi_preinit_net_messages If enabled, show more network messages than just the message that one can enter failsafe mode There are also variables used in the operation of preinit. They are: Variable Description preinit_essential_hook Variable containing hook names to execute, in order, for hook preinit_essential preinit_main_hook Ditto, for preinit_main failsafe_hook Ditto, for failsafe initramfs_hook Ditto, for initramfs preinit_mount_root_hook Ditto, for preinit_mount_root pi_mount_skip_next During hook preinit_mount_root, skips most steps; usually set by a preceeding step pi_jffs2_mount_success During hook preinit_mount_root, used by steps following mount attempt to determine which action they should take Hooks The following sections describe the files and functions used by the various hooks. NB: The files, even though divided by hook here are all in the single /lib/preinit directory, and are thus combined in the directory lists, and are processed in glob sort order, not by hook (when sourcing them, the hooks specify the order of the execution of functions, which is as listed below) Development For the purposes of development, you will locate the files under $ROOTDIR/package/base-files/files/lib/preinit, for the existing files, and you can add new files anywhere that ultimately ends up in /lib/preinit on the router (while in preinit, e.g. not by user edits after read-write is mounted). preinit_essentials With the introduction of procd, effective in Chaos Calmer release, the tasks of this hook are done in c code and at least on some images (verified on a BRCM63xx one) this hook is unused. The preinit_essentials hook takes care of mounting essential kernel filesystems such as proc, and initializing the console. Files containing the functions executed by this hook File Functions 10_essential_fs do_mount_procfs, do_mount_sysfs, do_mount_tmpfs 20_device_fs_mount do_mount_devfs, do_mount_hotplug, do_mount_udev, choose_device_fs 30_device_daemons init_hotplug, init_udev, init_device_fs 40_init_shm init_shm 40_pts_mount do_mount_pts 50_choose_console choose_console 60_init_console init_console Functions, in order, executed by this hook (doesn't list the functions only called by other functions) Function Description do_mount_procfs mounts /proc do_mount_sysfs mounts /sys do_mount_tmpfs mounts /tmp choose_device_fs determines type of device daemon and the appropriate filesystem to mount on /dev for that device daemon init_device_fs launches daemons (if any) responsible for population /dev, and/or creating hotplug events when devices are added/removed (and for initial coldplug events) init_shm makes sure /dev/shm exists init_pts makes sure /dev/pts exists do_mount_pts mounts devpts on /dev/pts (pseudo-terminals) choose_console determines devices for stdin, stdout, and stderr init_console activates stdin, stdout, and stderr of preinit (and subsequent init) (prior to this they are not present in the environment) Functions which are called by other functions, rather than directly as part of a hook Function Description do_mount_devfs mount devfs on /dev do_mount_hotplug mount tmpfs on /dev (for hotplug) do_mount_udev mount tmpfs on /dev (for udev) init_hotplug set hotplug handler (actually initiated after console init) init_udev start udev preinit_main The preinit_main hook performs all the functions required of preinit, except those functions, like console, that are essential even for preinit tasks. File Description 10_indicate_preinit preinit_ip, preinit_ip_deconfig, preinit_net_echo, preinit_echo, pi_indicate_led, pi_indicate_preinit 30_failsafe_wait fs_wait_for_key, failsafe_wait 40_run_failsafe_hook run_failsafe_hook 50_indicate_regular_preinit indicate_regular_preinit_boot 60_init_hotplug init_hotplug 70_initramfs_test initramfs_test 80_mount_root do_mount_root 90_restore_config restore_config 99_10_run_init run_init Functions, in order, executed by this hook (doesn't list the functions only called by other functions) Function Description init_hotplug Initialize hotplug, if needed (that is for devfs). Hotplug or a device daemon is needed so that devices are available for use for preinit preinit_ip Initialize network interface (if one has been defined for as available for preinit) pi_indicate_preinit Send messages to console, network, and/or led, depending on which, if any, of these is present which say that we are in preinit mode failsafe_wait Emits messages (to network and console) that indicate the user has the option to enter failsafe mode and wait for the configured period of time (default two seconds) for the user to select failsafe mode run_failsafe_hook If user chooses to enter failsafe mode, run the *failsafe* hook (which at present doesn't return, which means no more functions from preinit_main get run on this boot) indicate_regular_preinit_boot Emits messages to network, console, and/or LED depending on which (if any) is present, indicating that it's a regular boot not a failsafe boot initramfs_test If initramfs is present run the *initramfs* hook and exit do_mount_root Executes hook *preinit_mount_root* restore_config If a previous configuration was stored by sysupgrade, restore it to the rootfs run_init Exec the command defined by `pi_init_cmd` with the environment variables defined by `pi_init_env`, plus PATH `pi_init_path` Functions which are called by other functions, rather than directly as part of a hook. Function Description preinit_ip_deconfig deconfigure interface used for preinit network messages etc preinit_net_echo emit a message on the preinit network interface preinit_echo emit a message on the (serial) console pi_indicate_led set LED status to indicate preinit mode fs_wait_for_key wait for reset button press, CTRL-C, or <some_key><ENTER>, with timeout failsafe Do what needs to done to prepare failsafe mode and enter it. File Description 10_indicate_failsafe indicate_failsafe_led, indicate_failsafe 99_10_failsafe_login failsafe_netlogin, failsafe_shell Functions, in order, executed by this hook (doesn't list the functions only called by other functions) Function Description indicate_failsafe Emit message/status to network, console, and/or LED (depending on which, if any, are present) indicating that the device is now in failsafe mode failsafe_netlogin Launch telnet daemon to allow telnet login on the defined network interface (if any) failsafe_shell Launch a shell for access via serial console (if present) Functions which are called by other functions, rather than directly as part of a hook Function Description indicate_failsafe_led set LED status to indicate preinit mode preinit_mount_root Mount the root filesystem File Description 05_mount_skip check_skip 10_check_for_mtd mount_no_mtd, check_for_mtd Functions, in order, executed by this hook (doesn't list the functions only called by other functions) Function Description check_for_mtd Check for a mtd partition named rootfs_data. If not present mount kernel fs as root (e.g. all_jjfs2 or squashfs only) and skip rest. check_for_jffs2 Check if jffs2 formatted yet. If not, mount ramoverlay and skip rest do_mount_jffs2 find jffs2 partition and mount it, indicating result rootfs_pivot if jffs2 mounted, make it root (/) and old root (squashfs) /rom , skipping rest on success do_mount_no_jffs2 If nothing was mounted so far, mount ramdisk (ram overlay), skipping rest on success do_mount_no_mtd If there was nothing mounted , mount /dev/root as root (/) Functions which are called by other functions, rather than directly as part of a hook Function Description mount_no_mtd if there is not mtd partition named rootfs_data, mount /dev/root as / (root). E.g. this can occur if the firmware filesystem is entirely a jffs2 partition, with no squashfs) mount_no_jffs2 mount ramdisk (ram overlay) if there is rootfs_data, but it has not been formatted yet) find_mount_jffs2 find and mount rootfs_data jffs2 partition on /jffs jffs2_not_mounted returns true (0) if jffs2 is not mounted initramfs No files or functions at this time. Firstboot Operation Main Firstboot Script Source common functions Source functions for hooks if block: if invoked as executable if called with `switch2jffs` parameter (i.e. from rcS) run hook `switch2jffs` if called standalone (e.g. from commandline) if there is a jffs2 partition mounted run hook `jffs2reset` else erase rootfs_data mtd partition format and remount it end end if sourced (that is not executed) set some variables end Hooks switch2jffs Make the filesystem that we want to be the rootfs, to be the rootfs File Description 10_determine_parts deterimine_mtd_part, determine_rom_part, determine_jffs2_part, set_mtd_part, set_rom_part, set_jffs2_part 20_has_mini_fo check_for_mini_fo 30_is_rootfs_mountedskip_if_rootfs_mounted 40_copy_ramoverlay copy_ramoverlay 50_pivot with_fo_pivot 99_10_with_fo_cleanup with_fo_cleanup Functions, in order, executed by this hook (doesn't list the functions only called by other functions) Function Description determine_mtd_part exit if no mtd partition at all determine_rom_part exit if not squashfs partition (firstboot not for all_jffs2) determine_jffs2_part figure out the jffs2 partition (assuming we have an mtd part check_for_mini_fo determine if we have mini_fo overlay in kernel. If not run *no_fo* hook skip_if_rootfs_mounted attempt mount jffs2 on /rom/jffs2. If partition already mounted exit copy_ramoverlay copy the data from the temporary rootfs (on the ramdisk overlay over the squashfs) to the new jffs2 partition with_fo_pivot make current jffs2 partition the root partition and the current root /rom with_fo_cleanup clean up unneeded mount of ramdisk, if possible Functions which are called by other functions, rather than directly as part of a hook Function Description set_mtd_part set variables for mtd partition set_rom_part set variable for squashfs (rom) partition set_jffs_part set variable for jffs2 partition no_fo Make the filesystem that we want to be the rootfs, to be the rootfs, given that we have no mini\_fo overlay filesystem File Description 10_no_fo_clear_overlay no_fo_clear_overlay 20_no_fo_mount_jffs no_fo_mount_jffs 30_no_fo_pivot no_fo_pivot 40_no_fo_copy_ram_overlay no_fo_copy_ram_overlay 99_10_no_fo_cleanup no_fo_cleanup Functions, in order, executed by this hook (doesn't list the functions only called by other functions) Function Description no_fo_clear_overlay stop ramdisk overlaying the squashfs no_fo_mount_jffs attempt to mount jffs (work around problem with union). If already mounted exit no_fo_pivot make jffs root and old root /rom no_fo_copy_ram_overlay copy data from ram overlay to jffs2 overlay of squashfs no_fo_cleanup get rid of extra binds and mounts jffs2reset Reset jffs2 to defaults File Description 10_rest_has_mini_fo reset_check_for_mini_fo 20_reset_clear_jffs reset_clear_jffs 30_reset_copy_rom reset_copy_rom Functions, in order, executed by this hook (doesn't list the functions only called by other functions) Function Description reset_check_for_mini_fo Determine if the kernel supports mini_fo overlay reset_clear_jffs if mini_fo is supported, erase all data in overlay and remount (resets back to 'pure' squashfs versions reset_copy_rom if mini_fo is not supported, make symlinks and copy critical files from squashfs to jffs Customizing the system NB: These files must be added to the *squashfs* (or if using a all_jffs2 system, to the jffs2). That means, for instance adding it to the image's rootfs. This can be done, for instace, by creating `${ROOTDIR}/files/filename` (with appropriate substitutions of course). Overriding Example Warning! This section describes actions that might damage your device or firmware. Proceed with care! Customizing the system is quite simple. We give an example of changing the message for preinit from '- preinit -' to '- setting the table for dinner -' Create a file that replaces the function `indicate_regular_preinit_boot`. `pi_indicate_preinit` is defined in `20_indicate_preinit`, so we define our replace functions in `25_dinner_not_router`. `/lib/preinit/25_dinner_not_router` pi_indicate_preinit() { echo "- setting the table for dinner -" preinit_net_echo "Dinner is just about ready!" pi_indicate_led } This results in the following boot log: NET: Registered protocol family 17 802.1Q VLAN Support v1.8 Ben Greear <greearb@candelatech.com> All bugs added by David S. Miller <davem@redhat.com> VFS: Mounted root (squashfs filesystem) readonly on device 31:2. Freeing unused kernel memory: 132k freed Please be patient, while OpenWrt loads ... eth1: link forced UP - 100/full - flow control off/off - setting the table for dinner - Press CTRL-C or Press f<ENTER> to enter failsafe mode switching to jffs2 mini_fo: using base directory: / mini_fo: using storage directory: /jffs - init - The default boot log is NET: Registered protocol family 17 802.1Q VLAN Support v1.8 Ben Greear <greearb@candelatech.com> All bugs added by David S. Miller <davem@redhat.com> VFS: Mounted root (squashfs filesystem) readonly on device 31:2. Freeing unused kernel memory: 132k freed Please be patient, while OpenWrt loads ... eth1: link forced UP - 100/full - flow control off/off - preinit - Press CTRL-C or Press f<ENTER> to enter failsafe mode switching to jffs2 mini_fo: using base directory: / mini_fo: using storage directory: /jffs - init - Adding Example As another example we will add a message to failsafe, between the notice that we're in failsafe mode in the shell. You could use this, for example, to create a text menu system, or to launch a simple web server (with cgi scripts) to permit the user to do failsafe things. We want to add the message, 'Remember, at this point there are no writable filesystems' We create the file `50_failsafe_remember_no_rw`, in `/lib/preinit` remember_no_rw() { echo "Remember, at this point there are no writable filesystems" } boot_hook_add failsafe remember_no_rw This creates the function `remember_no_rw` and adds it to the failsafe hook, in between `10_indicate_failsafe` and `99_10_failsafe_login` which define the other functions in the `failsafe` hook. This wasn't necessary for the previous example because the function was already in a hook. The boot log for this, when entering failsafe, is: VFS: Mounted root (squashfs filesystem) readonly on device 31:2. Freeing unused kernel memory: 132k freed Please be patient, while OpenWrt loads ... eth1: link forced UP - 100/full - flow control off/off - preinit - Press CTRL-C or Press f<ENTER> to enter failsafe mode f - failsafe - Remember, at this point there are no writable filesystems BusyBox v1.15.3 (2010-01-20 19:26:26 EST) built-in shell (ash) Enter 'help' for a list of built-in commands. ash: can't access tty; job control turned off _______ ________ __ | |.-----.-----.-----.| | | |.----.| |_ | - || _ | -__| || | | || _|| _| |_______|| __|_____|__|__||________||__| |____| |__| W I R E L E S S F R E E D O M KAMIKAZE (bleeding edge, r19235) ------------------ * 10 oz Vodka Shake well with ice and strain * 10 oz Triple sec mixture into 10 shot glasses. * 10 oz lime juice Salute! --------------------------------------------------- Architecture-specific notes Some architectures have additional files and functions (or overrides of the above functions) in order to accommodate specific needs of that hardware. In that case the files are located in the source tree under $ROOTDIR/target/linux/<architecture[/subarch]/base-files/lib/preinit. During build they are merged and appear under /lib/preinit along with the rest. This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.OKMore information about cookies Last modified: 2023/03/04 12:24by openwart