Merge pull request #463 from aanderse/switch_root

Add switch_root support for initramfs to real root transitions
This commit is contained in:
Joachim Wiberg
2026-01-03 00:49:07 +01:00
committed by GitHub
15 changed files with 653 additions and 11 deletions
+23
View File
@@ -288,4 +288,27 @@ Rescue mode can be disabled at build time with `configure --without-rescue`.
See the [Rescue Mode](config/rescue.md) section for more information.
**Switch Root**
Finit supports switching from an initramfs to a real root filesystem using
the built-in `initctl switch-root` command. This allows Finit to serve as
the init system in an initramfs for early boot tasks (LUKS unlock, LVM
activation, network boot) before transitioning to the real root.
```bash
# In initramfs, after mounting the real root:
initctl switch-root /mnt/root
```
The switch-root operation:
1. Runs the `HOOK_SWITCH_ROOT` hook for cleanup
2. Stops all services gracefully
3. Moves virtual filesystems (`/dev`, `/proc`, `/sys`, `/run`) to the new root
4. Deletes initramfs contents to free memory
5. Pivots to the new root and execs the new init
See the [Switch Root](switchroot.md) section for complete documentation.
[5]: https://en.wikipedia.org/wiki/Runlevel
+1
View File
@@ -39,6 +39,7 @@ Features
* [Cgroups v2](config/cgroups.md), both configuration and monitoring in [`initctl top`](initctl.md)
* [Plugin support](plugins.md) for customization
* Proper [rescue mode](config/rescue.md) with bundled `sulogin` for protected maintenance shell
* [Switch root](switchroot.md) support for initramfs-to-real-root transitions
* Integration with [watchdogd][] for full system supervision
* [Logging](config/logging.md) to kernel ring buffer before `syslogd` has started, see the
recommended [sysklogd][] project for complete logging integration
+22
View File
@@ -65,6 +65,7 @@ Commands:
halt Halt system
poweroff Halt and power off system
suspend Suspend system
switch-root NEWROOT [INIT] Switch to new root filesystem (initramfs only)
utmp show Raw dump of UTMP/WTMP db
```
@@ -143,3 +144,24 @@ Apr 8 12:37:46 alpine authpriv.info dropbear[2300]: Exit (root) from <192.168.1
Apr 8 15:02:11 alpine authpriv.info dropbear[2634]: Child connection from 192.168.121.1:48576
Apr 8 15:02:12 alpine authpriv.notice dropbear[2634]: Password auth succeeded for 'root' from 192.168.121.1:48576
```
Switch Root
-----------
The `switch-root` command is used when running Finit in an initramfs to
transition to the real root filesystem. This is similar to the standalone
`switch_root(8)` utility but integrated into Finit.
```
initctl switch-root /mnt/root [/sbin/init]
```
Requirements:
- Must be run during runlevel S (bootstrap) or runlevel 1
- The new root must be a mount point (different device than /)
- Can only be used when Finit is running as PID 1 in an initramfs
For complete documentation and usage examples, see the dedicated
[Switch Root](switchroot.md) section.
+10
View File
@@ -205,6 +205,16 @@ hook points:
new runlevel have been been stopped. When the hook has completed,
Finit continues to start all services in the new runlevel.
### Switch Root Hooks
* `HOOK_SWITCH_ROOT`, `hook/sys/switchroot`: Called when
`initctl switch-root` is issued, before the transition begins. Use
this hook to save state, unmount initramfs-only filesystems, or perform
cleanup before switching to the new root. Only runs when Finit is
operating as PID 1 in an initramfs.
See the [Switch Root](switchroot.md) section for more information.
### Shutdown Hooks
* `HOOK_NETWORK_DN`, `hook/net/down`: Called right after having changed
+148
View File
@@ -0,0 +1,148 @@
Switch Root
===========
Finit supports switching from an initramfs to a real root filesystem
using the `initctl switch-root` command. This is useful for systems
that use an initramfs for early boot (LUKS, LVM, network boot, etc.)
and need to transition to the real root before starting services.
Usage
-----
```sh
initctl switch-root NEWROOT [INIT]
```
- `NEWROOT`: Path to the mounted new root filesystem (e.g., `/mnt/root`)
- `INIT`: Optional path to init on the new root (default: `/sbin/init`)
Requirements
------------
1. Must be run during runlevel S (bootstrap) or runlevel 1
2. `NEWROOT` must be a mount point (different device than /)
3. `INIT` must exist and be executable on the new root
4. Finit must be running as PID 1 (in initramfs)
How It Works
------------
1. Runs `HOOK_SWITCH_ROOT` for any cleanup scripts/plugins
2. Runs `HOOK_SHUTDOWN` to notify plugins
3. Stops all services and kills remaining processes
4. Exits all plugins gracefully
5. Moves `/dev`, `/proc`, `/sys`, `/run` to new root
6. Deletes initramfs contents (if on tmpfs/ramfs) to free memory
7. Moves new root mount to `/`
8. Chroots to new root
9. Reopens `/dev/console` for stdin/stdout/stderr
10. Execs new init as PID 1
Example: Initramfs finit.conf
-----------------------------
Configuration file `/etc/finit.conf` in the initramfs:
```
# /etc/finit.conf in initramfs
# Mount the real root filesystem
run [S] name:mount-root /bin/mount /dev/sda1 /mnt/root -- Mounting root filesystem
# Switch to real root after mount completes
run [S] name:switch-root /sbin/initctl switch-root /mnt/root -- Switching to real root
```
For more complex setups (LUKS, LVM, etc.):
```
# Unlock LUKS volume
run [S] name:cryptsetup /sbin/cryptsetup open /dev/sda2 cryptroot -- Unlocking encrypted root
# Activate LVM
run [S] name:lvm /sbin/lvm vgchange -ay -- Activating LVM volumes
# Mount root
run [S] name:mount-root /bin/mount /dev/vg0/root /mnt/root -- Mounting root
# Switch root
run [S] name:switch-root /sbin/initctl switch-root /mnt/root -- Switching to real root
```
Example: Using Runlevel 1 for Switch Root
-----------------------------------------
For more complex initramfs setups where ordering of tasks becomes
difficult in runlevel S, you can perform the switch-root in runlevel 1:
```
# /etc/finit.conf in initramfs
# Start mdevd for device handling
service [S] name:mdevd notify:s6 /sbin/mdevd -D %n -- Device event daemon
run [S] name:coldplug <service/mdevd/ready> /sbin/mdevd-coldplug -- Coldplug devices
# Mount the real root filesystem (after devices are ready)
run [S] name:mount-root <run/coldplug/success> /bin/mount /dev/sda1 /mnt/root -- Mounting root
# Transition to runlevel 1 after all S tasks complete
# The switch-root runs cleanly in runlevel 1
run [1] name:switch-root /sbin/initctl switch-root /mnt/root -- Switching to real root
```
This approach separates the initramfs setup (runlevel S) from the
switch-root operation (runlevel 1), making task ordering simpler.
Hooks
-----
The `HOOK_SWITCH_ROOT` hook runs before the switch begins. Use it for:
- Saving state to the new root
- Unmounting initramfs-only mounts
- Cleanup tasks
Plugins can register for `HOOK_SWITCH_ROOT` just like other hooks:
```c
static void my_switch_root_hook(void *arg)
{
/* Cleanup before switch_root */
}
static plugin_t plugin = {
.name = "my-plugin",
.hook[HOOK_SWITCH_ROOT] = {
.cb = my_switch_root_hook
}
};
PLUGIN_INIT(plugin_init)
{
plugin_register(&plugin);
}
```
Conditions
----------
After switch_root, the new finit instance starts fresh. No conditions
or state are preserved across the switch. The new finit will:
1. Re-read `/etc/finit.conf` from the new root
2. Re-initialize all conditions
3. Start services according to the new configuration
See Also
--------
- [switch_root(8)](https://man7.org/linux/man-pages/man8/switch_root.8.html) - util-linux switch_root utility
- [Kernel initramfs documentation](https://docs.kernel.org/filesystems/ramfs-rootfs-initramfs.html)
+1
View File
@@ -79,6 +79,7 @@ nav:
- Limitations: config/limitations.md
- Usage:
- Commands & Status: initctl.md
- Switch Root: switchroot.md
- Rebooting & Halting: commands.md
- Command Line Options: cmdline.md
- Managing Services: service.md
+1
View File
@@ -63,6 +63,7 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
exec.c finit.c finit.h \
stty.c \
helpers.c helpers.h \
initramfs.c \
iwatch.c iwatch.h \
log.c log.h \
mdadm.c mount.c \
+53
View File
@@ -245,6 +245,46 @@ static void bypass_shutdown(void *unused)
do_shutdown(halt);
}
/*
* Handle switch_root API command.
* Parses data: "newroot\0newinit\0"
* Sends ACK before attempting switch_root since it doesn't return on success.
* Returns: result from switch_root() on failure, doesn't return on success.
*/
static int do_switch_root_api(int sd, struct init_request *rq)
{
char *newroot, *newinit = NULL;
char *ptr;
int result;
dbg("switch-root %s", rq->data);
strterm(rq->data, sizeof(rq->data));
newroot = rq->data;
ptr = strchr(newroot, '\0');
if (ptr && ptr < rq->data + sizeof(rq->data) - 1) {
ptr++;
if (*ptr)
newinit = ptr;
}
/*
* Send ACK first, since we won't return from
* switch_root() on success.
*/
rq->cmd = INIT_CMD_ACK;
if (write(sd, rq, sizeof(*rq)) != sizeof(*rq))
dbg("Failed sending ACK to client");
close(sd);
/* This does not return on success */
result = switch_root(newroot, newinit);
if (result)
logit(LOG_ERR, "switch_root failed: %s", strerror(errno));
return result;
}
static int do_reboot(int cmd, int timeout, char *buf, size_t len)
{
int rc = 1;
@@ -403,6 +443,15 @@ static void api_cb(uev_t *w, void *arg, int events)
rq.cmd, rq.data);
goto leave;
}
break;
case INIT_CMD_SWITCH_ROOT:
if (runlevel != INIT_LEVEL && runlevel != 1) {
warnx("switch-root only allowed in runlevel S or 1");
goto done;
}
break;
default:
break;
}
@@ -503,6 +552,10 @@ static void api_cb(uev_t *w, void *arg, int events)
result = do_reboot(rq.cmd, rq.sleeptime, rq.data, sizeof(rq.data));
break;
case INIT_CMD_SWITCH_ROOT:
do_switch_root_api(sd, &rq);
goto leave;
case INIT_CMD_ACK:
dbg("Client failed reading ACK");
goto leave;
+32 -6
View File
@@ -34,6 +34,8 @@
#endif
#include <sys/mount.h>
#include <sys/sysinfo.h> /* get_nprocs_conf() */
#include <sys/vfs.h>
#include <linux/magic.h>
#include "cgroup.h"
#include "finit.h"
@@ -841,6 +843,7 @@ void cgroup_config(void)
void cgroup_init(uev_ctx_t *ctx)
{
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
int mounted = 0;
char buf[80];
FILE *fp;
int fd;
@@ -851,14 +854,36 @@ void cgroup_init(uev_ctx_t *ctx)
#endif
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
if (errno == ENOENT)
if (errno == EBUSY) {
/*
* Already mounted - this happens after switch_root
* when cgroups were moved from the initramfs.
* Verify it's actually cgroup2 before proceeding.
*/
struct statfs sfs;
if (statfs(FINIT_CGPATH, &sfs) || sfs.f_type != CGROUP2_SUPER_MAGIC) {
logit(LOG_ERR, "Mount point %s busy but not cgroup2", FINIT_CGPATH);
avail = 0;
return;
}
dbg("cgroup2 already mounted at %s, reusing", FINIT_CGPATH);
} else if (errno == ENOENT) {
logit(LOG_INFO, "Kernel does not support cgroups v2, disabling.");
else if (errno == EPERM) /* Probably inside an unprivileged container */
avail = 0;
return;
} else if (errno == EPERM) {
/* Probably inside an unprivileged container */
logit(LOG_INFO, "Not allowed to mount cgroups v2, disabling.");
else
avail = 0;
return;
} else {
err(1, "Failed mounting cgroup v2");
avail = 0;
return;
avail = 0;
return;
}
} else {
mounted = 1;
}
avail = 1;
@@ -867,7 +892,8 @@ void cgroup_init(uev_ctx_t *ctx)
if (!fp) {
err(1, "Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
abort:
umount(FINIT_CGPATH);
if (mounted)
umount(FINIT_CGPATH);
avail = 0;
return;
}
+1
View File
@@ -98,6 +98,7 @@
#define INIT_CMD_HALT 21
#define INIT_CMD_POWEROFF 22
#define INIT_CMD_SUSPEND 23
#define INIT_CMD_SWITCH_ROOT 24 /* Switch to new root filesystem */
#define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */
#define INIT_CMD_SVC_ITER 129
#define INIT_CMD_SVC_QUERY 130
+56 -1
View File
@@ -646,6 +646,59 @@ int do_halt (char *arg) { return do_cmd(INIT_CMD_HALT); }
int do_poweroff(char *arg) { return do_cmd(INIT_CMD_POWEROFF); }
int do_suspend (char *arg) { return do_cmd(INIT_CMD_SUSPEND); }
/**
* do_switch_root - Switch to a new root filesystem (initramfs only)
* @argc: Number of arguments (1 or 2)
* @argv: [0] = newroot path, [1] = optional init path
*
* This command is only valid during runlevel S (bootstrap) or 1 when
* running from an initramfs. It stops all services, moves virtual
* filesystems, and exec's the new init.
*/
int do_switch_root(int argc, char *argv[])
{
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = INIT_CMD_SWITCH_ROOT,
};
char *newroot, *newinit = NULL;
size_t off;
if (argc < 1)
ERRX(2, "Usage: initctl switch-root NEWROOT [INIT]");
newroot = argv[0];
if (argc > 1)
newinit = argv[1];
/* Verify newroot exists */
if (access(newroot, F_OK))
ERR(1, "Cannot access %s", newroot);
/*
* Pack both strings into rq.data with null separators:
* "newroot\0newinit\0"
*/
strlcpy(rq.data, newroot, sizeof(rq.data));
off = strlen(newroot) + 1;
if (newinit && off < sizeof(rq.data) - 1)
strlcpy(rq.data + off, newinit, sizeof(rq.data) - off);
printf("Switching root to %s", newroot);
if (newinit)
printf(", init %s", newinit);
printf(" ...\n");
/*
* On success, finit exec's new init and we lose connection.
* A "failure" to read reply is actually expected on success.
*/
client_send(&rq, sizeof(rq));
return 0;
}
int utmp_show(char *file)
{
struct utmp *ut;
@@ -1474,7 +1527,8 @@ static int usage(int rc)
" reboot Reboot system\n"
" halt Halt system\n"
" poweroff Halt and power off system\n"
" suspend Suspend system\n");
" suspend Suspend system\n"
" switch-root ROOT [INIT] Switch to new root filesystem (initramfs)\n");
if (utmp)
fprintf(stderr,
@@ -1654,6 +1708,7 @@ int main(int argc, char *argv[])
{ "halt", NULL, do_halt, NULL, NULL },
{ "poweroff", NULL, do_poweroff, NULL, NULL },
{ "suspend", NULL, do_suspend, NULL, NULL },
{ "switch-root", NULL, NULL, NULL, do_switch_root },
{ "utmp", NULL, do_utmp, &utmp, NULL },
{ NULL, NULL, NULL, NULL, NULL }
+293
View File
@@ -0,0 +1,293 @@
/* Initramfs switch_root support
*
* Copyright (c) 2008-2025 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <errno.h>
#include <fcntl.h>
#include <ftw.h>
#include <limits.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/vfs.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/magic.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "cond.h"
#include "helpers.h"
#include "log.h"
#include "plugin.h"
#include "private.h"
#include "sig.h"
#include "util.h"
/* State for delete_cb(), nftw() doesn't support passing user data */
static const char *delete_skip;
static dev_t delete_rootdev;
/*
* nftw() callback to delete initramfs contents before switch_root.
* Skips the new root mount point and stays on the same filesystem.
*/
static int delete_cb(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
{
(void)tflag;
/* Skip root directory itself */
if (ftw->level == 0)
return 0;
/* Skip the new root mount point */
if (delete_skip && !strncmp(fpath, delete_skip, strlen(delete_skip)))
return 0;
/* Stay on the same filesystem (initramfs) */
if (sb->st_dev != delete_rootdev)
return 0;
remove(fpath);
return 0;
}
/*
* Recursively delete initramfs contents to free memory before switch_root.
*/
static void delete_initramfs_contents(dev_t rootdev, const char *skip)
{
delete_rootdev = rootdev;
delete_skip = skip;
nftw("/", delete_cb, 20, FTW_DEPTH | FTW_PHYS | FTW_MOUNT);
}
/*
* Check if we're running on a tmpfs/ramfs (initramfs)
*/
static int is_initramfs(void)
{
struct statfs sfs;
if (statfs("/", &sfs))
return 0;
return sfs.f_type == RAMFS_MAGIC || sfs.f_type == TMPFS_MAGIC;
}
/*
* Move a mount point from oldpath to newpath under newroot
*/
static int do_move_mount(const char *oldpath, const char *newroot)
{
char newpath[PATH_MAX];
struct stat st;
if (stat(oldpath, &st))
return 0; /* Not mounted, skip */
snprintf(newpath, sizeof(newpath), "%s%s", newroot, oldpath);
/* Create target directory if needed */
makedir(newpath, 0755);
if (mount(oldpath, newpath, NULL, MS_MOVE, NULL)) {
dbg("Failed to move %s to %s: %s", oldpath, newpath, strerror(errno));
return -1;
}
dbg("Moved %s to %s", oldpath, newpath);
return 0;
}
static int kill_cb(int pid, void *data)
{
int signo = *(int *)data;
kill(pid, signo);
return 0;
}
/*
* Perform switch_root to a new root filesystem
*
* This function does not return on success - it exec's the new init.
* On failure, it returns -1 and sets errno.
*/
int switch_root(const char *newroot, const char *newinit)
{
struct stat newroot_st, oldroot_st;
char init_path[PATH_MAX];
int console_fd;
dev_t rootdev;
int signo;
if (!newroot || !newroot[0]) {
errno = EINVAL;
return -1;
}
/* Default to /sbin/init if not specified */
if (!newinit || !newinit[0])
newinit = "/sbin/init";
/* Verify we're PID 1 */
if (getpid() != 1) {
logit(LOG_ERR, "switch_root must be run as PID 1");
errno = EPERM;
return -1;
}
/* Verify newroot exists and is a directory */
if (stat(newroot, &newroot_st) || !S_ISDIR(newroot_st.st_mode)) {
logit(LOG_ERR, "switch_root: %s is not a directory", newroot);
errno = ENOTDIR;
return -1;
}
/* Verify newroot is a mount point (different device than parent) */
if (stat("/", &oldroot_st)) {
logit(LOG_ERR, "switch_root: cannot stat /");
return -1;
}
if (newroot_st.st_dev == oldroot_st.st_dev) {
logit(LOG_ERR, "switch_root: %s is not a mount point", newroot);
errno = EINVAL;
return -1;
}
/* Verify init exists in new root */
snprintf(init_path, sizeof(init_path), "%s%s", newroot, newinit);
if (access(init_path, X_OK)) {
logit(LOG_ERR, "switch_root: %s not found or not executable", init_path);
errno = ENOENT;
return -1;
}
logit(LOG_NOTICE, "Performing switch_root to %s, init %s", newroot, newinit);
/* Run switch_root hook before we start tearing things down */
plugin_run_hooks(HOOK_SWITCH_ROOT);
/* Stop all services gracefully */
dbg("Stopping all services...");
halt = SHUT_OFF; /* Prevent actual shutdown */
/* Use existing shutdown logic to stop services */
api_exit();
log_exit();
plugin_run_hooks(HOOK_SHUTDOWN);
/* Kill remaining processes (except kernel threads and ourselves) */
signo = SIGTERM;
iterate_proc(kill_cb, &signo);
do_usleep(500000); /* Give them 500ms */
signo = SIGKILL;
iterate_proc(kill_cb, &signo);
/* Reap zombies */
while (waitpid(-1, NULL, WNOHANG) > 0)
;
/* Exit plugins */
plugin_exit();
cond_exit();
/* Move virtual filesystems to new root */
dbg("Moving virtual filesystems...");
do_move_mount("/dev", newroot);
do_move_mount("/proc", newroot);
do_move_mount("/sys", newroot);
do_move_mount("/run", newroot);
/* Change to new root directory */
if (chdir(newroot)) {
err(1, "Failed to chdir to %s", newroot);
return -1;
}
/* Delete contents of old root if we're on initramfs */
rootdev = oldroot_st.st_dev;
if (is_initramfs()) {
dbg("Deleting initramfs contents...");
delete_initramfs_contents(rootdev, newroot);
}
/* Mount --move newroot to / */
if (mount(newroot, "/", NULL, MS_MOVE, NULL)) {
err(1, "Failed to move %s to /", newroot);
return -1;
}
/* chroot to new root */
if (chroot(".")) {
err(1, "Failed to chroot to new root");
return -1;
}
if (chdir("/")) {
err(1, "Failed to chdir to /");
return -1;
}
/* Reopen console */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
console_fd = open("/dev/console", O_RDWR);
if (console_fd >= 0) {
dup2(console_fd, STDIN_FILENO);
dup2(console_fd, STDOUT_FILENO);
dup2(console_fd, STDERR_FILENO);
if (console_fd > STDERR_FILENO)
close(console_fd);
}
/* Reset signals to default */
sig_unblock();
/* Exec the new init - this does not return on success */
dbg("Executing %s...", newinit);
execl(newinit, newinit, NULL);
/* If we get here, exec failed */
err(1, "Failed to exec %s", newinit);
return -1;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+3
View File
@@ -81,6 +81,9 @@
CHOOSE(HOOK_SVC_RECONF, "nop"), \
CHOOSE(HOOK_RUNLEVEL_CHANGE, "nop"), \
\
/* Switch root hook, before transitioning */ \
CHOOSE(HOOK_SWITCH_ROOT, "hook/sys/switchroot"), \
\
/* Shutdown hooks, runlevel [06] */ \
CHOOSE(HOOK_NETWORK_DN, "hook/net/down"), \
CHOOSE(HOOK_SHUTDOWN, "hook/sys/shutdown"), \
+3
View File
@@ -59,6 +59,9 @@ void plugin_script_run(hook_point_t no);
int plugin_init (uev_ctx_t *ctx);
void plugin_exit (void);
void iterate_proc (int (*cb)(int, void *), void *data);
int switch_root (const char *newroot, const char *newinit);
#endif /* FINIT_PRIVATE_H_ */
/**
+6 -4
View File
@@ -77,7 +77,9 @@
#endif
#include <string.h> /* strerror() */
#include <sched.h>
#include <sys/mount.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/wait.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
@@ -206,7 +208,7 @@ static void fs_swapoff(void)
*
* https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/
*/
void do_iterate_proc(int (*cb)(int, void *), void *data)
void iterate_proc(int (*cb)(int, void *), void *data)
{
DIR *dirp;
@@ -288,7 +290,7 @@ static int do_wait(int secs)
;
has_proc = 0;
iterations--;
do_iterate_proc(status_cb, &has_proc);
iterate_proc(status_cb, &has_proc);
}
while (has_proc && iterations > 0);
@@ -320,10 +322,10 @@ void do_shutdown(shutop_t op)
* Tell remaining non-monitored processes to exit, give them
* time to exit gracefully, 2 sec was customary, we go for 1.
*/
do_iterate_proc(kill_cb, &signo);
iterate_proc(kill_cb, &signo);
if (do_wait(1)) {
signo = SIGKILL;
do_iterate_proc(kill_cb, &signo);
iterate_proc(kill_cb, &signo);
}
/* Exit plugins gracefully */