2004-01-20 21:32:43 +03:00
/*
* Guillaume Cottenceau ( gc @ mandrakesoft . com )
*
* Copyright 2000 MandrakeSoft
*
* This software may be freely redistributed under the terms of the GNU
* public license .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
*/
/*
* Portions from Erik Troan ( ewt @ redhat . com )
*
* Copyright 1996 Red Hat Software
*
*/
2008-02-29 17:37:40 +03:00
# include <errno.h>
# include <string.h>
# include <stdlib.h>
# include <stdio.h>
# include <unistd.h>
# include <dirent.h>
# include <fcntl.h>
2013-08-21 18:45:06 +04:00
# include <limits.h>
2008-02-29 17:37:40 +03:00
# include <sys/klog.h>
# include <sys/mount.h>
# include <sys/stat.h>
# include <sys/vfs.h>
# include <sys/wait.h>
2009-05-26 15:43:22 +04:00
# include <linux/vt.h>
2004-01-20 21:32:43 +03:00
# include "config-stage1.h"
2008-03-12 15:19:18 +03:00
# include "lomount.h"
2009-07-01 12:21:29 +04:00
# include "tools.h"
2013-04-01 19:07:51 +04:00
# include "common.h"
2004-01-20 21:32:43 +03:00
2008-02-29 17:37:40 +03:00
# define RAMFS_MAGIC 0x858458f6
# define TMPFS_MAGIC 0x01021994
2008-03-18 18:04:38 +03:00
# ifndef MNT_DETACH /* sys/mount.h still doesn't define it */
# define MNT_DETACH 2
# endif
2004-01-20 21:32:43 +03:00
char * env [ ] = {
2008-02-29 17:37:40 +03:00
" PATH=/usr/bin:/bin:/sbin:/usr/sbin " ,
2004-01-20 21:32:43 +03:00
" HOME=/ " ,
2010-12-02 13:29:53 +03:00
" RUN_INITRD=1 " ,
2004-01-20 21:32:43 +03:00
" TERM=linux " ,
" TERMINFO=/etc/terminfo " ,
NULL
} ;
2005-01-21 16:52:04 +03:00
char * * myenv = NULL ;
2004-01-20 21:32:43 +03:00
2010-12-02 13:05:12 +03:00
char * udevd [ ] = { " /sbin/udevd " , " udevd " , " --resolve-names=never " , NULL } ;
2008-09-03 21:39:12 +04:00
char * udevtrigger [ ] = { " /sbin/udevadm " , " udevadm " , " trigger " , NULL } ;
char * udevsettle [ ] = { " /sbin/udevadm " , " udevadm " , " settle " , NULL } ;
2008-03-12 15:19:18 +03:00
2009-07-06 17:19:52 +04:00
char * init_top [ ] = { " /sbin/init-top " , " init-top " , NULL } ;
char * init_premount [ ] = { " /sbin/init-premount " , " init-premount " , NULL } ;
char * init_bottom [ ] = { " /sbin/init-bottom " , " init-bottom " , NULL } ;
2008-03-12 15:19:18 +03:00
extern void stage1 ( ) ;
2013-08-21 18:56:14 +04:00
static void fatal ( const char * ) __attribute__ ( ( noreturn ) ) ;
2008-03-12 15:19:18 +03:00
2004-01-20 21:32:43 +03:00
/*
* this needs to handle the following cases :
*
2005-01-21 16:52:04 +03:00
* 1 ) run from a CD root filesystem
* 2 ) run from a read only nfs rooted filesystem
* 3 ) run from a floppy
* 4 ) run from a floppy that ' s been loaded into a ramdisk
2004-01-20 21:32:43 +03:00
*/
2013-08-21 18:56:14 +04:00
static void fatal ( const char * msg )
2004-01-20 21:32:43 +03:00
{
2013-08-22 18:27:41 +04:00
printf ( " FATAL ERROR IN INIT: %s \n I can't recover from this, "
2008-02-29 17:37:40 +03:00
" please reboot manually and send bugreport. \n " , msg ) ;
2004-01-20 21:32:43 +03:00
while ( 1 ) ;
}
2013-08-21 18:56:14 +04:00
static void warn ( char * msg )
2004-01-20 21:32:43 +03:00
{
printf ( " W: %s \n " , msg ) ;
}
2012-05-25 18:28:40 +04:00
static int _mknod ( const char * pathname , mode_t mode , dev_t dev )
{
int rc ;
rc = mknod ( pathname , mode , dev ) ;
if ( rc < 0 & & errno = = EEXIST )
rc = 0 ;
return rc ;
}
2004-01-20 21:32:43 +03:00
/* fork to:
* ( 1 ) watch / proc / kmsg and copy the stuff to / dev / tty4
* ( 2 ) listens to / dev / log and copy also this stuff ( log from programs )
*/
2013-08-21 18:56:14 +04:00
static pid_t doklog ( )
2004-01-20 21:32:43 +03:00
{
2007-03-03 00:48:18 +03:00
int in , out , i , ii ;
2008-02-29 17:37:40 +03:00
pid_t pid ;
2004-01-20 21:32:43 +03:00
char buf [ 1024 ] ;
/* open kernel message logger */
2008-02-29 17:37:40 +03:00
if ( ( in = open ( " /proc/kmsg " , O_RDONLY , 0 ) ) < 0 )
fatal ( " failed to open /proc/kmsg " ) ;
2004-01-20 21:32:43 +03:00
2012-05-25 18:28:40 +04:00
if ( _mknod ( " /dev/tty4 " , S_IFCHR , MKDEV ( 4 , 4 ) ) < 0 | |
2008-02-29 17:37:40 +03:00
( out = open ( " /dev/tty4 " , O_WRONLY , 0 ) ) < 0 )
fatal ( " failed to open /dev/tty4 " ) ;
2004-01-20 21:32:43 +03:00
2008-02-29 17:37:40 +03:00
if ( ( pid = fork ( ) ) ) {
if ( pid < 0 ) fatal ( " doklog " ) ;
2004-01-20 21:32:43 +03:00
close ( in ) ;
2008-02-29 17:37:40 +03:00
close ( out ) ;
return pid ;
2004-03-19 20:02:37 +03:00
}
2004-01-20 21:32:43 +03:00
2008-02-29 17:37:40 +03:00
/* child */
close ( 0 ) ;
close ( 1 ) ;
close ( 2 ) ;
2004-01-20 21:32:43 +03:00
/* disable on-console syslog output */
2008-02-29 17:37:40 +03:00
klogctl ( 8 , NULL , 1 ) ;
while ( 1 )
if ( ( i = read ( in , buf , sizeof ( buf ) ) ) > 0 )
ii = write ( out , buf , i ) ;
}
pid_t spawn ( char * av [ ] )
{
pid_t pid ;
if ( ( pid = fork ( ) ) ) {
if ( pid < 0 ) fatal ( av [ 0 ] ) ;
return pid ;
} else {
2008-09-03 21:39:12 +04:00
execve ( av [ 0 ] , & av [ 1 ] , env ) ;
2008-02-29 17:37:40 +03:00
perror ( av [ 0 ] ) ;
exit ( 1 ) ;
2004-01-20 21:32:43 +03:00
}
}
2013-08-21 18:56:14 +04:00
static void spawn_hook ( char * av [ ] )
2009-07-06 17:19:52 +04:00
{
struct stat st ;
int status ;
if ( stat ( av [ 0 ] , & st ) | | ! S_ISREG ( st . st_mode ) | | ! ( st . st_mode & S_IXUSR ) ) return ;
if ( waitpid ( spawn ( av ) , & status , 0 ) < 0 | | ! ( WIFEXITED ( status ) ) ) fatal ( av [ 0 ] ) ;
}
2013-08-21 18:56:14 +04:00
static void take_env ( int fd )
2005-01-21 16:52:04 +03:00
{
2007-04-12 20:38:53 +04:00
static char buf [ PIPE_BUF ] ;
2005-01-21 16:52:04 +03:00
char * p = buf ;
char * * ep ;
int i ;
if ( ( i = read ( fd , buf , sizeof ( buf ) ) ) < 0 ) {
2008-02-29 17:37:40 +03:00
warn ( " failed to read env from pipe " ) ;
2005-01-21 16:52:04 +03:00
myenv = env ;
return ;
}
close ( fd ) ;
buf [ i ] = ' \0 ' ;
if ( ( ep = myenv = malloc ( sizeof ( char * ) * 32 ) ) = = NULL ) {
2008-02-29 17:37:40 +03:00
warn ( " can't malloc env " ) ;
2005-01-21 16:52:04 +03:00
myenv = env ;
return ;
}
2008-02-29 17:37:40 +03:00
2005-01-21 16:52:04 +03:00
do {
* ep + + = p ;
p + = strlen ( p ) ;
} while ( + + p < buf + i ) ;
* ep = NULL ;
}
2004-11-30 17:44:10 +03:00
/*
initramfs cleaner
*/
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 ;
2008-02-29 17:37:40 +03:00
fatal ( what ) ;
2004-11-30 17:44:10 +03:00
}
2007-03-03 00:48:18 +03:00
return 0 ;
2004-11-30 17:44:10 +03:00
}
2004-01-20 21:32:43 +03:00
struct filesystem
{
char * dev ;
char * name ;
char * fs ;
int mounted ;
} ;
/* attempt to unmount all filesystems in /proc/mounts */
2013-08-21 18:56:14 +04:00
static void unmount_filesystems ( void )
2004-01-20 21:32:43 +03:00
{
int fd , size ;
char buf [ 65535 ] ; /* this should be big enough */
char * p ;
struct filesystem fs [ 500 ] ;
int numfs = 0 ;
int i , nb ;
printf ( " unmounting filesystems... \n " ) ;
fd = open ( " /proc/mounts " , O_RDONLY , 0 ) ;
if ( fd < 1 ) {
2008-02-29 17:37:40 +03:00
warn ( " failed to open /proc/mounts " ) ;
2004-01-20 21:32:43 +03:00
sleep ( 2 ) ;
return ;
}
size = read ( fd , buf , sizeof ( buf ) - 1 ) ;
buf [ size ] = ' \0 ' ;
close ( fd ) ;
p = buf ;
while ( * p ) {
fs [ numfs ] . mounted = 1 ;
fs [ numfs ] . dev = p ;
while ( * p ! = ' ' ) p + + ;
* p + + = ' \0 ' ;
fs [ numfs ] . name = p ;
while ( * p ! = ' ' ) p + + ;
* p + + = ' \0 ' ;
fs [ numfs ] . fs = p ;
while ( * p ! = ' ' ) p + + ;
* p + + = ' \0 ' ;
while ( * p ! = ' \n ' ) p + + ;
p + + ;
if ( strcmp ( fs [ numfs ] . name , " / " ) ! = 0 ) numfs + + ; /* skip if root, no need to take initrd root in account */
}
/* Pixel's ultra-optimized sorting algorithm:
multiple passes trying to umount everything until nothing moves
anymore ( a . k . a holy shotgun method ) */
do {
nb = 0 ;
for ( i = 0 ; i < numfs ; i + + ) {
/*printf("trying with %s\n", fs[i].name);*/
if ( fs [ i ] . mounted & & umount ( fs [ i ] . name ) = = 0 ) {
if ( strncmp ( fs [ i ] . dev + sizeof ( " /dev/ " ) - 1 , " loop " ,
sizeof ( " loop " ) - 1 ) = = 0 )
del_loop ( fs [ i ] . dev ) ;
printf ( " \t %s \n " , fs [ i ] . name ) ;
fs [ i ] . mounted = 0 ;
nb + + ;
}
}
} while ( nb ) ;
for ( i = nb = 0 ; i < numfs ; i + + )
if ( fs [ i ] . mounted ) {
printf ( " \t %s umount failed \n " , fs [ i ] . name ) ;
if ( strcmp ( fs [ i ] . fs , " ext2 " ) = = 0 ) nb + + ; /* don't count not-ext2 umount failed */
}
if ( nb ) {
2008-02-29 17:37:40 +03:00
fatal ( " failed to umount some filesystems \n " ) ;
2004-01-20 21:32:43 +03:00
}
}
int main ( int argc , char * * argv )
{
2010-12-10 22:58:22 +03:00
struct stat rst , cst , ist , pst ;
2004-11-30 17:44:10 +03:00
struct statfs sfs ;
2008-02-29 17:37:40 +03:00
pid_t pid , klogpid , udevpid ;
2008-03-01 19:16:25 +03:00
sigset_t sig ;
2004-01-20 21:32:43 +03:00
int wait_status ;
2008-02-29 17:37:40 +03:00
int fd = - 1 ;
2005-01-21 16:52:04 +03:00
int fds [ 2 ] ;
2009-07-01 12:21:29 +04:00
char * init = NULL ;
2008-02-29 17:37:40 +03:00
2005-01-21 16:52:04 +03:00
if ( mount ( " /proc " , " /proc " , " proc " , 0 , NULL ) )
2008-02-29 17:37:40 +03:00
fatal ( " failed to mount proc filesystem " ) ;
if ( mount ( " sysfs " , " /sys " , " sysfs " , 0 , NULL ) )
fatal ( " failed to mount sysfs filesystem " ) ;
2012-05-25 18:28:40 +04:00
2013-08-22 19:41:49 +04:00
if ( mount ( " udevfs " , " /dev " , " devtmpfs " , 0 , " size=8M,mode=0755 " ) ) {
switch ( errno ) {
case ENODEV :
2013-08-22 18:27:41 +04:00
/* There is no devtmpfs for current kernel, try mount tmpfs */
if ( mount ( " udev " , " /dev " , " tmpfs " , 0 , " size=8M,mode=0755 " ) )
fatal ( " failed to mount tmpfs filesystem " ) ;
2013-08-22 19:41:49 +04:00
case EBUSY :
/* Don't mount /dev if it is already mounted */
break ;
default :
fatal ( " failed to mount devtmpfs filesystem " ) ;
2012-05-25 18:28:40 +04:00
}
2013-08-22 19:41:49 +04:00
}
2008-02-29 17:37:40 +03:00
2004-01-20 21:32:43 +03:00
/* ignore Control-C and keyboard stop signals */
2008-03-01 19:16:25 +03:00
sigemptyset ( & sig ) ;
sigaddset ( & sig , SIGINT ) ;
sigaddset ( & sig , SIGTSTP ) ;
sigprocmask ( SIG_BLOCK , & sig , NULL ) ;
2004-01-20 21:32:43 +03:00
2012-05-25 18:28:40 +04:00
if ( _mknod ( " /dev/console " , S_IFCHR , MKDEV ( 5 , 1 ) ) < 0 | |
2008-02-29 17:37:40 +03:00
( fd = open ( " /dev/console " , O_RDWR , 0 ) ) < 0 ) {
fatal ( " failed to open /dev/console " ) ;
}
2005-01-21 16:52:04 +03:00
dup2 ( fd , 0 ) ;
dup2 ( fd , 1 ) ;
dup2 ( fd , 2 ) ;
close ( fd ) ;
2004-01-20 21:32:43 +03:00
2012-05-25 18:28:40 +04:00
if ( _mknod ( " /dev/null " , S_IFCHR , MKDEV ( 1 , 3 ) ) < 0 )
2008-02-29 17:37:40 +03:00
fatal ( " failed to create /dev/null " ) ;
2004-01-20 21:32:43 +03:00
/* I set me up as session leader (probably not necessary?) */
setsid ( ) ;
2004-03-19 20:02:37 +03:00
if ( ioctl ( 0 , TIOCSCTTY , NULL ) ) {
perror ( " TIOCSCTTY " ) ;
2008-02-29 17:37:40 +03:00
warn ( " could not set new controlling tty " ) ;
2004-03-19 20:02:37 +03:00
}
2004-01-20 21:32:43 +03:00
2008-02-29 17:37:40 +03:00
if ( sethostname ( " localhost.localdomain " , sizeof ( " localhost.localdomain " ) ) < 0 )
warn ( " could not set hostname " ) ;
2007-03-03 00:48:18 +03:00
2005-01-21 16:52:04 +03:00
/* the default domainname (as of 2.0.35) is "(none)", which confuses glibc */
2007-03-03 00:48:18 +03:00
if ( setdomainname ( " " , 0 ) < 0 )
2008-02-29 17:37:40 +03:00
warn ( " could not set domainname " ) ;
2013-04-01 19:07:51 +04:00
if ( mkdirs_dev ( " .initramfs " , " pts " , " shm " , NULL ) < 0 )
2008-02-29 17:37:40 +03:00
fatal ( " mkdir \n " ) ;
klogpid = doklog ( ) ;
2009-07-06 17:19:52 +04:00
spawn_hook ( init_top ) ;
2013-04-01 19:07:51 +04:00
if ( mkdirs_dev ( " .udev " , " .udev/db " , NULL ) < 0 )
2008-02-29 17:37:40 +03:00
fatal ( " /dev/.udev/db " ) ;
printf ( " Spawning udevd... " ) ;
udevpid = spawn ( udevd ) ;
2009-09-09 13:34:01 +04:00
usleep ( 500 ) ;
2013-04-01 19:07:51 +04:00
if ( mkdir_dev ( " .udev/queue " ) < 0 )
2008-02-29 17:37:40 +03:00
fatal ( " cannot create /dev/.udev/queue " ) ;
if ( waitpid ( spawn ( udevtrigger ) , & wait_status , 0 ) < 0 | |
! ( WIFEXITED ( wait_status ) ) )
warn ( " udevtrigger " ) ;
if ( waitpid ( spawn ( udevsettle ) , & wait_status , 0 ) < 0 | |
! ( WIFEXITED ( wait_status ) ) )
warn ( " udevsettle " ) ;
printf ( " done \n " ) ;
2004-01-20 21:32:43 +03:00
2009-07-06 17:19:52 +04:00
spawn_hook ( init_premount ) ;
2004-01-20 21:32:43 +03:00
/* Go into normal init mode - keep going, and then do a orderly shutdown
when :
1 ) install exits
2 ) we receive a SIGHUP
*/
2004-04-14 22:23:20 +04:00
printf ( " Running stage1... \n " ) ;
2005-01-21 16:52:04 +03:00
/* create a pipe for env passing */
2007-03-03 00:48:18 +03:00
if ( pipe ( fds ) < 0 )
2008-02-29 17:37:40 +03:00
fatal ( " failed to create env pipe " ) ;
2007-03-03 00:48:18 +03:00
2005-01-21 16:52:04 +03:00
fcntl ( fds [ 0 ] , F_SETFD , 1 ) ;
fcntl ( fds [ 1 ] , F_SETFD , 0 ) ;
2004-01-20 21:32:43 +03:00
2008-03-12 15:19:18 +03:00
if ( ( pid = fork ( ) ) ) {
if ( pid < 0 ) fatal ( " Failed to spawn stage1 " ) ;
close ( fds [ 1 ] ) ;
while ( pid ! = wait ( & wait_status ) ) ;
} else {
stage1 ( ) ;
}
2004-01-20 21:32:43 +03:00
2004-11-30 17:44:10 +03:00
if ( ! ( WIFEXITED ( wait_status ) ) ) {
/* something went wrong */
2008-02-29 17:37:40 +03:00
printf ( " wait_status: %i, install exited abnormally " , wait_status ) ;
2004-01-20 21:32:43 +03:00
if ( WIFSIGNALED ( wait_status ) )
printf ( " -- received signal %d " , WTERMSIG ( wait_status ) ) ;
printf ( " \n " ) ;
2004-11-30 17:44:10 +03:00
sync ( ) ; sync ( ) ;
printf ( " sending termination signals... " ) ;
kill ( - 1 , 15 ) ;
2004-01-20 21:32:43 +03:00
sleep ( 2 ) ;
2004-11-30 17:44:10 +03:00
printf ( " done \n " ) ;
printf ( " sending kill signals... " ) ;
kill ( - 1 , 9 ) ;
sleep ( 2 ) ;
printf ( " done \n " ) ;
unmount_filesystems ( ) ;
2004-01-20 21:32:43 +03:00
printf ( " you may safely reboot your system \n " ) ;
while ( 1 ) ;
}
2008-03-12 15:19:18 +03:00
take_env ( fds [ 0 ] ) ;
2005-01-21 16:52:04 +03:00
2008-02-29 17:37:40 +03:00
if ( waitpid ( spawn ( udevsettle ) , & wait_status , 0 ) < 0 | |
! ( WIFEXITED ( wait_status ) ) )
warn ( " udevsettle " ) ;
kill ( udevpid , 9 ) ;
waitpid ( udevpid , & wait_status , 0 ) ;
nuke_dir ( " /dev/.udev/queue " ) ;
2008-06-13 01:03:01 +04:00
if ( ( fd = open ( " /.udev_version " , O_RDONLY , 0 ) ) > 0 ) {
char buf [ 32 ] ;
int n = read ( fd , buf , sizeof ( buf ) ) ;
close ( fd ) ;
if ( ( fd = creat ( " /dev/.initramfs/udev_version " , 0 ) ) > 0 ) {
n = write ( fd , buf , n ) ;
close ( fd ) ;
} else fatal ( " creat() " ) ;
}
2009-07-06 17:19:52 +04:00
spawn_hook ( init_bottom ) ;
2008-02-29 17:37:40 +03:00
kill ( klogpid , 9 ) ;
waitpid ( klogpid , & wait_status , 0 ) ;
2005-01-21 16:52:04 +03:00
2009-05-26 15:43:22 +04:00
/* deallocate all unused consoles */
ioctl ( 0 , VT_DISALLOCATE , 0 ) ;
2004-12-01 18:10:51 +03:00
printf ( " Spawning init ... " ) ;
2005-01-21 16:52:04 +03:00
2004-11-30 17:44:10 +03:00
/* rest was seamlessy stolen from klibc */
/* First, change to the new root directory */
if ( chdir ( STAGE2_LOCATION ) )
2008-02-29 17:37:40 +03:00
fatal ( " chdir to new root " ) ;
2010-12-10 22:58:22 +03:00
if ( stat ( " /bin/plymouth " , & pst ) = = 0 ) {
char * plymouth [ ] = { " /bin/plymouth " , " plymouth " , " --newroot=/root " , NULL } ;
spawn ( plymouth ) ;
}
2010-12-01 14:53:42 +03:00
2004-11-30 17:44:10 +03:00
/* 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 */
2013-08-22 19:41:49 +04:00
if ( stat ( " / " , & rst ) | | stat ( " . " , & cst ) )
2008-02-29 17:37:40 +03:00
fatal ( " stat " ) ;
2005-01-24 21:12:06 +03:00
2004-11-30 17:44:10 +03:00
if ( rst . st_dev = = cst . st_dev )
2008-02-29 17:37:40 +03:00
fatal ( " current directory on the same filesystem as the root " ) ;
2005-01-24 21:12:06 +03:00
2004-11-30 17:44:10 +03:00
/* The initramfs should have /init */
if ( stat ( " /init " , & ist ) | | ! S_ISREG ( ist . st_mode ) )
2008-02-29 17:37:40 +03:00
fatal ( " can't find /init on initramfs " ) ;
2005-01-24 21:12:06 +03:00
2004-11-30 17:44:10 +03:00
/* Make sure we're on a ramfs */
if ( statfs ( " / " , & sfs ) )
2008-02-29 17:37:40 +03:00
fatal ( " statfs / " ) ;
2004-11-30 17:44:10 +03:00
if ( sfs . f_type ! = RAMFS_MAGIC & & sfs . f_type ! = TMPFS_MAGIC )
2008-02-29 17:37:40 +03:00
fatal ( " rootfs not a ramfs or tmpfs " ) ;
2005-01-24 21:12:06 +03:00
2004-11-30 17:44:10 +03:00
/* Okay, I think we should be safe... */
2005-01-24 21:12:06 +03:00
/* overmount image under new root if needed */
if ( statfs ( IMAGE_LOCATION , & sfs ) )
2008-03-18 18:04:38 +03:00
fatal ( " statfs() on " IMAGE_LOCATION ) ;
2005-01-24 21:12:06 +03:00
/* if something is mounted under IMAGE_LOCATION ? */
2005-01-26 16:43:53 +03:00
if ( sfs . f_type ! = RAMFS_MAGIC & & sfs . f_type ! = TMPFS_MAGIC ) {
2005-01-24 21:12:06 +03:00
if ( mount ( IMAGE_LOCATION , " . " IMAGE_LOCATION , NULL , MS_MOVE , NULL ) )
2008-03-18 18:04:38 +03:00
fatal ( " overmounting " IMAGE_LOCATION ) ;
2005-01-26 16:43:53 +03:00
/* test for nested mount: disk or nfs with iso image */
if ( statfs ( IMAGE_LOCATION , & sfs ) )
2008-03-18 18:04:38 +03:00
fatal ( " statfs() on nested " IMAGE_LOCATION ) ;
2005-01-26 16:43:53 +03:00
if ( sfs . f_type ! = RAMFS_MAGIC & & sfs . f_type ! = TMPFS_MAGIC )
2008-03-18 18:04:38 +03:00
if ( umount2 ( IMAGE_LOCATION , MNT_DETACH ) )
fatal ( " lazy umounting nested " IMAGE_LOCATION ) ;
2005-01-26 16:43:53 +03:00
}
2004-11-30 19:11:41 +03:00
2004-11-30 17:44:10 +03:00
umount ( " /sys " ) ;
2004-12-01 18:10:51 +03:00
umount ( " /proc/bus/usb " ) ;
2004-11-30 17:44:10 +03:00
umount ( " /proc " ) ;
2005-01-24 21:12:06 +03:00
2008-02-29 17:37:40 +03:00
if ( mount ( " /dev " , " ./dev " , NULL , MS_MOVE , NULL ) )
fatal ( " overmounting /dev " ) ;
2004-11-30 17:44:10 +03:00
/* Delete rootfs contents */
2008-02-29 17:37:40 +03:00
if ( nuke_dir ( " / " ) )
fatal ( " nuking initramfs contents " ) ;
2005-01-24 21:12:06 +03:00
2004-11-30 17:44:10 +03:00
/* Overmount the root */
2008-02-29 17:37:40 +03:00
if ( mount ( " . " , " / " , NULL , MS_MOVE , NULL ) )
fatal ( " overmounting root " ) ;
2005-01-24 21:12:06 +03:00
2004-11-30 17:44:10 +03:00
/* chroot, chdir */
2005-02-03 18:38:15 +03:00
if ( chroot ( " . " ) | | chdir ( " / " ) )
2008-02-29 17:37:40 +03:00
fatal ( " chroot " ) ;
2005-01-24 21:12:06 +03:00
2005-01-19 16:31:08 +03:00
/* Check for given init */
2009-07-01 12:21:29 +04:00
init = get_from_env ( " INIT " , myenv ) ;
2009-07-06 19:22:03 +04:00
if ( init = = NULL ) init = STAGE2_BINNAME ;
if ( stat ( init , & ist ) | | ! S_ISREG ( ist . st_mode ) | | ! ( ist . st_mode & S_IXUSR ) )
2008-02-29 17:37:40 +03:00
fatal ( " can't find init on root fs " ) ;
2005-01-24 21:12:06 +03:00
2005-01-26 16:43:53 +03:00
/* Spawn init */
printf ( " done. \n " ) ;
2008-05-22 18:19:34 +04:00
/* unblock signals */
sigprocmask ( SIG_UNBLOCK , & sig , NULL ) ;
2009-07-06 19:22:03 +04:00
argv [ 0 ] = init ;
2005-10-28 19:05:40 +04:00
execve ( argv [ 0 ] , argv , myenv ) ;
2008-02-29 17:37:40 +03:00
fatal ( " stage2 " ) ; /* Failed to spawn init */
2005-01-21 16:52:04 +03:00
return 0 ;
2004-01-20 21:32:43 +03:00
}