//******************************************************************************
//*this code is protected by the GNU affero GPLv3
//*author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com>
//* <digital.ragnarok AT gmail dot com>
//******************************************************************************
#include <ulinux/compiler_types.h>
#include <ulinux/sysc.h>
#include <ulinux/types.h>
#include <ulinux/error.h>
#include <ulinux/fs.h>
#include <ulinux/dirent.h>
#include <ulinux/socket/socket.h>
#include <ulinux/socket/netlink.h>
#include <ulinux/wait.h>
#include <ulinux/signal/signal.h>
#include <ulinux/signal/siginfo.h>
#ifndef QUIET
#include <ulinux/file.h>
#include <ulinux/stat.h>
#include <ulinux/mmap.h>
#include <stdarg.h>
#include <ulinux/utils/ascii/string/vsprintf.h>
#endif
#include "modules.h"
#include "uevents.h"
#include "ramfs.h"
#include "globals.h"
#ifndef QUIET
k_u8 *g_dprintf_buf;
#endif
static void sigs_setup(void)
{
OUTC(PRE "setting up signals...");
k_ul mask=(~0);
k_l r=sysc(rt_sigprocmask,4,K_SIG_BLOCK,&mask,0,sizeof(mask));
if(K_ISERR(r)){
OUTC("ERROR:unable to block all signals (except KILL and STOP ;) )\n");
sysc(exit_group,1,-1);
}
OUTC("done\n");
}
static void newroot_mount(void)
{
OUTC(PRE "mounting root device /dev/" ROOT " on /newroot...\n");
k_l r=sysc(mount,5,"/dev/" ROOT,"/newroot",
ROOT_FS,K_MS_NOATIME|K_MS_NODIRATIME,ROOT_OPTIONS);
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to mount root\n",r);
sysc(exit_group,1,-1);
}
}
static void newroot_chdir()
{
OUTC(PRE "chdir to /newroot...");
k_l r=sysc(chdir,1,"/newroot");
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to chdir to /newroot\n",r);
sysc(exit_group,1,-1);
}
OUTC("done\n");
}
static void newroot_move(void)
{
OUTC(PRE "mount moving . (/newroot) to / ...");
k_l r=sysc(mount,5,".","/",0,K_MS_MOVE,0);
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to mount move . (/newroot) to /\n",r);
sysc(exit_group,1,-1);
}
OUTC("done\n");
}
static void newroot_chroot(void)
{
OUTC(PRE "chroot to . (/newroot)...");
k_l r=sysc(chroot,1,".");
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to chroot to . (/newroot)\n",r);
sysc(exit_group,1,-1);
}
OUTC("done\n");
}
static k_i sysinit_clone(void)
{
OUTC(PRE "clone and execve " SYSINIT "...\n");
k_l r=sysc(clone,5,K_SIGCHLD,0,0,0,0);
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to clone for sysinit\n",r);
sysc(exit_group,1,-1);
}
if(r) return (k_i)r;
k_ul mask=(~0);
r=sysc(rt_sigprocmask,4,K_SIG_UNBLOCK,&mask,0,sizeof(mask));
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to unblock all signals for sysinit\n",r);
sysc(exit_group,1,-1);
}
r=sysc(execve,4,SYSINIT,0,0,0);
if(K_ISERR(r))
OUT("ERROR(%ld):unable to run " SYSINIT "\n",r);
sysc(exit_group,1,-1);
__builtin_unreachable();
}
static k_i getty_spawn(k_u8 *tty)
{
OUT(PRE "getty %s...\n",tty);
k_l r=sysc(clone,5,K_SIGCHLD,0,0,0,0);
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to clone for getty(%s)\n",r,tty);
sysc(exit_group,1,-1);
}
if(r) return r;
k_ul mask=(~0);
r=sysc(rt_sigprocmask,4,K_SIG_UNBLOCK,&mask,0,sizeof(mask));
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to unblock all signals for getty(%s) clone\n",r,tty);
sysc(exit_group,1,-1);
}
r=sysc(setsid,0);
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to setsid the getty(%s) clone\n",r,tty);
sysc(exit_group,1,-1);
}
k_u8 *argv[]={(k_u8*)"/sbin/agetty",tty,0};
r=sysc(execve,4,"/sbin/agetty",argv,0,0);
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to run /sbin/agetty(%s)\n",r,tty);
sysc(exit_group,1,-1);
}
__builtin_unreachable();
}
static void sysinit(void)
{
k_i pid=sysinit_clone();
k_l r=sysc(waitid,5,K_P_PID,pid,0,K_WEXITED,0);
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to wait for " SYSINIT " to exit\n",r);
sysc(exit_group,1,-1);
}
}
static void loop(void)
{
k_i tty1=getty_spawn((k_u8*)"tty1");
k_i tty2=getty_spawn((k_u8*)"tty2");
while(1){
struct k_siginfo siginfo;
k_l r=sysc(waitid,5,K_P_ALL,0,&siginfo,K_WEXITED,0);
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to wait properly for getty clones to exit\n",r);
sysc(exit_group,1,-1);
}
if(siginfo.fields.sigchld.pid==tty1) tty1=getty_spawn((k_u8*)"tty1");
else if(siginfo.fields.sigchld.pid==tty2) tty2=getty_spawn((k_u8*)"tty2");
//ignore the other children
}
}
//fds 0,1 and 2 are rw /dev/console, see linux/init/main.c
void _start(void)
{
#ifndef QUIET
static k_u8 dprintf_buf[DPRINTF_BUF_SZ];
g_dprintf_buf=dprintf_buf;
#endif
//----------------------------------------------------------------------------
//mount rootfs
sigs_setup();
uevents_setup();
modules_load();
uevents_process();
uevents_cleanup();
newroot_mount();
ramfs_cleanup();
newroot_chdir();
newroot_move();
newroot_chroot();
//----------------------------------------------------------------------------
sysinit();
loop();
}