/*******************************************************************************
this code is protected by the GNU affero GPLv3
author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com>
*******************************************************************************/
/*
we use libraries based on C posix runtime, then we need this to fetch
environment variables from the C posix runtime
*/
#include <stdlib.h>
#include <ulinux/compiler_types.h>
#include <ulinux/sysc.h>
#include <ulinux/types.h>
#include <ulinux/error.h>
#include <ulinux/fs.h>
#include <ulinux/signal/signal.h>
#include <ulinux/utils/mem.h>
#include <ulinux/utils/ascii/string/string.h>
#define INIT_C
#include "out.h"
#include "ulinux_namespace.h"
#include "modules.h"
#include "uevents.h"
#include "ramfs.h"
#include "globals.h"
#undef INIT_C
static void sigs_setup(void)
{
ul mask=(~0);
l r;
OUT(PRE "setting up signals...\n");
r=rt_sigprocmask(SIG_BLOCK,&mask,0,sizeof(mask));
if(ISERR(r)){
OUT("ERROR:unable to block all signals (except KILL and STOP)\n");
exit_group(-1);
}
OUT("done\n");
}
static void sysfs_mount(void)
{
OUT(PRE "mounting sysfs...\n");
l r=mount(0,"/sys","sysfs",MS_NOATIME|MS_NODIRATIME,0);
if(ISERR(r)){
OUT("ERROR(%ld):unable to mount sysfs\n",r);
exit_group(-1);
}
}
static void sysfs_umount(void)
{
OUT(PRE "umounting sysfs...\n");
l r=umount("/sys");
if(ISERR(r)){
OUT("ERROR(%ld):unable to umount sysfs\n",r);
exit_group(-1);
}
}
static void proc_mount(void)
{
OUT(PRE "mounting proc...\n");
l r=mount(0,"/proc","proc",MS_NOATIME|MS_NODIRATIME,0);
if(ISERR(r)){
OUT("ERROR(%ld):unable to mount proc\n",r);
exit_group(-1);
}
}
static void proc_umount(void)
{
OUT(PRE "umounting proc...\n");
l r=umount("/proc");
if(ISERR(r)){
OUT("ERROR(%ld):unable to umount proc\n",r);
exit_group(-1);
}
}
static void devtmpfs_mount(void)
{
OUT(PRE "mounting devtmpfs...\n");
l r=mount(0,"/dev","devtmpfs",MS_NOATIME|MS_NODIRATIME,0);
if(ISERR(r)){
OUT("ERROR(%ld):unable to mount devtmpfs\n",r);
exit_group(-1);
}
}
static void devtmpfs_umount(void)
{
OUT(PRE "umounting devtmpfs...\n");
l r=umount("/dev");
if(ISERR(r)){
OUT("ERROR(%ld):unable to umount devtmpfs\n",r);
exit_group(-1);
}
}
static void newroot_mount(void)
{
OUT(PRE "mounting root device %s on /newroot, root file system is %s...\n",
root_dev_path,root_fs_type);
l r=mount(root_dev_path,"/newroot",root_fs_type,MS_NOATIME|MS_NODIRATIME,0);
if(ISERR(r)){
OUT("ERROR(%ld):unable to mount root\n",r);
exit_group(-1);
}
}
static void newroot_chdir()
{
OUT(PRE "chdir to /newroot...");
l r=chdir("/newroot");
if(ISERR(r)){
OUT("ERROR(%ld):unable to chdir to /newroot\n",r);
exit_group(-1);
}
OUT("done\n");
}
static void newroot_move(void)
{
OUT(PRE "mount moving . (/newroot) to / ...");
l r=mount(".","/",0,MS_MOVE,0);
if(ISERR(r)){
OUT("ERROR(%ld):unable to mount move . (/newroot) to /\n",r);
exit_group(-1);
}
OUT("done\n");
}
static void newroot_chroot(void)
{
OUT(PRE "chroot to . (/newroot)...");
l r=chroot(".");
if(ISERR(r)){
OUT("ERROR(%ld):unable to chroot to . (/newroot)\n",r);
exit_group(-1);
}
OUT("done\n");
}
/*this parameter *must* be around*/
#define PARAM_NAME "cinitramfs_root_uuid"
static void root_uuid_get(i argc, c **argv)
{
u8 arg;
/*we should use libc getenv to be friendly with the C runtime*/
root_uuid=(u8*)getenv(PARAM_NAME);
if(root_uuid) return;
/*it's not in the environment, then could be in argv, see
Documentation/kernel-parameters.txt*/
if(argc==1) goto fatal_err;
arg=1;
loop{
if(strncmp(argv[arg],PARAM_NAME,sizeof(PARAM_NAME)-1)==0) break;
if(++arg==argc) goto fatal_err;
}
root_uuid=(u8*)argv[arg];
loop if(*root_uuid++==(u8)'=') break;/*lookup for the key/value separator*/
return;
fatal_err:
OUT(PRE "ERROR:unable to find " PARAM_NAME "\n");
exit_group(-1);
}
#undef PARAM_NAME
static void command_line_parse(i argc, c **argv)
{
root_uuid_get(argc, argv);
}
/*
fds 0,1 and 2 are rw /dev/console, see linux/init/main.
Since we use standard C libs, be nice with the C runtime and use main instead of
_start entry point.
*/
i main(i argc,c **argv)
{
u8 r0;
l r1;
#ifndef QUIET
static u8 dprintf_buf[DPRINTF_BUF_SZ];
g_dprintf_buf=dprintf_buf;
#endif
sigs_setup();
command_line_parse(argc,argv);
uevents_setup();
sysfs_mount();
proc_mount();
devtmpfs_mount();
modules_setup();
modules_probe_static();
modules_probe_drivers();
r0=uevents_process();
if(r0==ROOT_NOT_FOUND){
OUT(PRE "terminating cinitramfs since no proper root was found\n");
exit_group(-1);
}
/*from here, we located our root*/
uevents_cleanup();
modules_probe_name(root_fs_type);
modules_cleanup();
newroot_mount();
devtmpfs_umount();
proc_umount();
sysfs_umount();
ramfs_cleanup();
newroot_chdir();
newroot_move();
newroot_chroot();
r1=execve("/bin/init");
if(ISERR(r1)){OUT("ERROR(%ld):unable to execve /bin/init\n",r1);}
exit_group(-1);
/*unreachable*/
}