initrd/bin/run-init源代码来源与klibc-2.0.4/usr/kinit目录

run-init源代码

下载

klibc,一种C标准库,开发者为汉·彼得·艾文(Hans Peter Anvin)。它是自由软件,采用GNU 通用公共许可协议或BSD许可协议。它主要应用于Linux开机流程中,而且它也是早期用户空间(Early user space)与initramfs的一部份。在此时,这些应用程序无法使用glibc。它也适用于嵌入式系统的开发。


#include <stdlib.h>

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "run-init.h"

static const char *program;

static void __attribute__ ((noreturn)) usage(void)
{
    fprintf(stderr,
        "Usage: exec %s [-d caps] [-c consoledev] /real-root /sbin/init [args]\n",
        program);
    exit(1);
}

int main(int argc, char *argv[])
{
    /* Command-line options and defaults */
    const char *console = "/dev/console";
    const char *realroot;
    const char *init;
    const char *error;
    const char *drop_caps = NULL;
    char **initargs;

    /* Variables... */
    int o;

    /* Parse the command line */
    program = argv[0];

    while ((o = getopt(argc, argv, "c:d:")) != -1) {
        if (o == 'c') {
            console = optarg;
        } else if (o == 'd') {
            drop_caps = optarg;
        } else {
            usage();
        }
    }

    if (argc - optind < 2)
        usage();

    realroot = argv[optind];
    init = argv[optind + 1];
    initargs = argv + optind + 1;

    error = run_init(realroot, console, drop_caps, init, initargs);

    /* If run_init returns, something went wrong */
    fprintf(stderr, "%s: %s: %s\n", program, error, strerror(errno));
    return 1;

}

runinitlib.c文件清单

/*
 * run_init(realroot, consoledev, drop_caps, init, initargs)
 *
 * This function should be called as the last thing in kinit,
 * from initramfs, it does the following:
 *
 * - Delete all files in the initramfs;
 * - Remounts /real-root onto the root filesystem;
 * - Chroots;
 * - Drops comma-separated list of capabilities;
 * - Opens /dev/console;
 * - Spawns the specified init program (with arguments.)
 *
 * On failure, returns a human-readable error message.
 */

#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include "run-init.h"
#include "capabilities.h"

/* Make it possible to compile on glibc by including constants that the
   always-behind shipped glibc headers may not include.  Classic example
   on why the lack of ABI headers screw us up. */
#ifndef TMPFS_MAGIC
# define TMPFS_MAGIC    0x01021994
#endif
#ifndef RAMFS_MAGIC
# define RAMFS_MAGIC    0x858458f6
#endif
#ifndef MS_MOVE
# define MS_MOVE    8192
#endif

static int nuke(const char *what);

static int nuke_dirent(int len, const char *dir, const char *name, dev_t me)
{
    int bytes = len + strlen(name) + 2;
    char path[bytes];
    int xlen;
    struct stat st;

    xlen = snprintf(path, bytes, "%s/%s", dir, name);
    assert(xlen < bytes);

    if (lstat(path, &st))
        return ENOENT;    /* Return 0 since already gone? */

    if (st.st_dev != me)
        return 0;    /* DO NOT recurse down mount points!!!!! */

    return nuke(path);
}

/* Wipe the contents of a directory, but not the directory itself */
static int nuke_dir(const char *what)
{
    int len = strlen(what);
    DIR *dir;
    struct dirent *d;
    int err = 0;
    struct stat st;

    if (lstat(what, &st))
        return errno;

    if (!S_ISDIR(st.st_mode))
        return ENOTDIR;

    if (!(dir = opendir(what))) {
        /* EACCES means we can't read it.  Might be empty and removable;
           if not, the rmdir() in nuke() will trigger an error. */
        return (errno == EACCES) ? 0 : errno;
    }

    while ((d = readdir(dir))) {
        /* Skip . and .. */
        if (d->d_name[0] == '.' &&
            (d->d_name[1] == '\0' ||
             (d->d_name[1] == '.' && d->d_name[2] == '\0')))
            continue;

        err = nuke_dirent(len, what, d->d_name, st.st_dev);
        if (err) {
            closedir(dir);
            return err;
        }
    }

    closedir(dir);

    return 0;
}

static int nuke(const char *what)
{
    int rv;
    int err = 0;

    rv = unlink(what);
    if (rv < 0) {
        if (errno == EISDIR) {
            /* It's a directory. */
            err = nuke_dir(what);
            if (!err)
                err = rmdir(what) ? errno : err;
        } else {
            err = errno;
        }
    }

    if (err) {
        errno = err;
        return err;
    } else {
        return 0;
    }
}

const char *run_init(const char *realroot, const char *console,
             const char *drop_caps, const char *init,
             char **initargs)
{
    struct stat rst, cst;
    struct statfs sfs;
    int confd;

    /* First, change to the new root directory */
    if (chdir(realroot))
        return "chdir to new root";

    /* This is a potentially highly destructive program.  Take some
       extra precautions. */

    /* Make sure the current directory is not on the same filesystem
       as the root directory */
    if (stat("/", &rst) || stat(".", &cst))
        return "stat";

    if (rst.st_dev == cst.st_dev)
        return "current directory on the same filesystem as the root";

    /* Make sure we're on a ramfs */
    if (statfs("/", &sfs))
        return "statfs /";
    if (sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC)
        return "rootfs not a ramfs or tmpfs";

    /* Okay, I think we should be safe... */

    /* Delete rootfs contents */
    if (nuke_dir("/"))
        return "nuking initramfs contents";

    /* Overmount the root */
    if (mount(".", "/", NULL, MS_MOVE, NULL))
        return "overmounting root";

    /* chroot, chdir */
    if (chroot(".") || chdir("/"))
        return "chroot";

    /* Drop capabilities */
    if (drop_capabilities(drop_caps) < 0)
        return "dropping capabilities";

    /* Open /dev/console */
    if ((confd = open(console, O_RDWR)) < 0)
        return "opening console";
    dup2(confd, 0);
    dup2(confd, 1);
    dup2(confd, 2);
    close(confd);

    /* Spawn init */
    execv(init, initargs);
    return init;        /* Failed to spawn init */
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值