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
*
*/
# ifndef INIT_HEADERS
# include "init-libc-headers.h"
# else
# include INIT_HEADERS
# endif
# include "config-stage1.h"
# if defined(__powerpc__)
# define TIOCSCTTY 0x540
# endif
char * env [ ] = {
" PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:/mnt/bin:/mnt/usr/bin " ,
" LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib:/usr/X11R6/lib:/mnt/usr/X11R6/lib " ,
" HOME=/ " ,
" TERM=linux " ,
" TERMINFO=/etc/terminfo " ,
NULL
} ;
/*
* this needs to handle the following cases :
*
* 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
*
*/
int testing ;
int klog_pid ;
void fatal_error ( char * msg )
{
2004-03-19 20:02:37 +03:00
printf ( " FATAL ERROR IN INIT: %s : %s \n \n I can't recover from this, please reboot manually and send bugreport. \n " , msg , strerror ( errno ) ) ;
2004-01-20 21:32:43 +03:00
while ( 1 ) ;
}
void print_error ( char * msg )
{
printf ( " E: %s \n " , msg ) ;
}
void print_warning ( char * msg )
{
printf ( " W: %s \n " , msg ) ;
}
void print_int_init ( int fd , int i )
{
char buf [ 10 ] ;
char * chptr = buf + 9 ;
int j = 0 ;
if ( i < 0 )
{
write ( 1 , " - " , 1 ) ;
i = - 1 * i ;
}
while ( i )
{
* chptr - - = ' 0 ' + ( i % 10 ) ;
j + + ;
i = i / 10 ;
}
write ( fd , chptr + 1 , j ) ;
}
void print_str_init ( int fd , char * string )
{
write ( fd , string , strlen ( string ) ) ;
}
/* 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 )
*/
void doklog ( )
{
fd_set readset , unixs ;
int in , out , i ;
int log ;
int s ;
int sock = - 1 ;
struct sockaddr_un sockaddr ;
char buf [ 1024 ] ;
int readfd ;
/* open kernel message logger */
in = open ( " /proc/kmsg " , O_RDONLY , 0 ) ;
if ( in < 0 ) {
print_error ( " could not open /proc/kmsg " ) ;
return ;
}
if ( ( log = open ( " /tmp/syslog " , O_WRONLY | O_CREAT , 0644 ) ) < 0 ) {
2004-03-19 20:02:37 +03:00
perror ( " /tmp/syslog " ) ;
2004-01-20 21:32:43 +03:00
print_error ( " error opening /tmp/syslog " ) ;
sleep ( 5 ) ;
return ;
}
if ( ( klog_pid = fork ( ) ) ) {
close ( in ) ;
close ( log ) ;
return ;
} else {
close ( 0 ) ;
close ( 1 ) ;
close ( 2 ) ;
}
out = open ( " /dev/tty4 " , O_WRONLY , 0 ) ;
2004-03-19 20:02:37 +03:00
if ( out < 0 ) {
perror ( " can't open /dev/tty4 " ) ;
2004-01-20 21:32:43 +03:00
print_warning ( " couldn't open tty for syslog -- still using /tmp/syslog \n " ) ;
2004-03-19 20:02:37 +03:00
}
2004-01-20 21:32:43 +03:00
/* now open the syslog socket */
// ############# LINUX 2.4 /dev/log IS BUGGED! --> apparently the syslogs can't reach me, and it's full up after a while
// sockaddr.sun_family = AF_UNIX;
// strncpy(sockaddr.sun_path, "/dev/log", UNIX_PATH_MAX);
// sock = socket(AF_UNIX, SOCK_STREAM, 0);
// if (sock < 0) {
// printf("error creating socket: %d\n", errno);
// sleep(5);
// }
//
// print_str_init(log, "] got socket\n");
// if (bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr.sun_family) + strlen(sockaddr.sun_path))) {
// print_str_init(log, "] bind error: ");
// print_int_init(log, errno);
// print_str_init(log, "\n");
// sleep(// }
//
// print_str_init(log, "] bound socket\n");
// chmod("/dev/log", 0666);
// if (listen(sock, 5)) {
// print_str_init(log, "] listen error: ");
// print_int_init(log, errno);
// print_str_init(log, "\n");
// sleep(5);
// }
/* disable on-console syslog output */
syslog ( 8 , NULL , 1 ) ;
print_str_init ( log , " ] kernel/system logger ok \n " ) ;
FD_ZERO ( & unixs ) ;
while ( 1 ) {
memcpy ( & readset , & unixs , sizeof ( unixs ) ) ;
if ( sock > = 0 )
FD_SET ( sock , & readset ) ;
FD_SET ( in , & readset ) ;
i = select ( 20 , & readset , NULL , NULL , NULL ) ;
if ( i < = 0 )
continue ;
/* has /proc/kmsg things to tell us? */
if ( FD_ISSET ( in , & readset ) ) {
i = read ( in , buf , sizeof ( buf ) ) ;
if ( i > 0 ) {
if ( out > = 0 )
write ( out , buf , i ) ;
write ( log , buf , i ) ;
}
}
/* examine some fd's in the hope to find some syslog outputs from programs */
for ( readfd = 0 ; readfd < 20 ; + + readfd ) {
if ( FD_ISSET ( readfd , & readset ) & & FD_ISSET ( readfd , & unixs ) ) {
i = read ( readfd , buf , sizeof ( buf ) ) ;
if ( i > 0 ) {
/* grep out the output of RPM telling that it installed/removed some packages */
if ( ! strstr ( buf , " mdk installed " ) & & ! strstr ( buf , " mdk removed " ) ) {
if ( out > = 0 )
write ( out , buf , i ) ;
write ( log , buf , i ) ;
}
} else if ( i = = 0 ) {
/* socket closed */
close ( readfd ) ;
FD_CLR ( readfd , & unixs ) ;
}
}
}
/* the socket has moved, new stuff to do */
if ( sock > = 0 & & FD_ISSET ( sock , & readset ) ) {
s = sizeof ( sockaddr ) ;
readfd = accept ( sock , ( struct sockaddr * ) & sockaddr , & s ) ;
if ( readfd < 0 ) {
char * msg_error = " ] error in accept \n " ;
if ( out > = 0 )
write ( out , msg_error , strlen ( msg_error ) ) ;
write ( log , msg_error , strlen ( msg_error ) ) ;
close ( sock ) ;
sock = - 1 ;
}
else
FD_SET ( readfd , & unixs ) ;
}
}
}
# define LOOP_CLR_FD 0x4C01
void del_loop ( char * device )
{
int fd ;
if ( ( fd = open ( device , O_RDONLY , 0 ) ) < 0 ) {
printf ( " del_loop open failed \n " ) ;
return ;
}
if ( ioctl ( fd , LOOP_CLR_FD , 0 ) < 0 ) {
printf ( " del_loop ioctl failed " ) ;
return ;
}
close ( fd ) ;
}
struct filesystem
{
char * dev ;
char * name ;
char * fs ;
int mounted ;
} ;
/* attempt to unmount all filesystems in /proc/mounts */
void unmount_filesystems ( void )
{
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 ) {
print_error ( " failed to open /proc/mounts " ) ;
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 ) {
printf ( " failed to umount some filesystems \n " ) ;
while ( 1 ) ;
}
}
int exit_value_rescue = 66 ;
# define DEV_PERM 00400|00200|00040|00020
# define CHR_DEV 0020000|DEV_PERM
# define BLK_DEV 0060000|DEV_PERM
2004-03-10 19:54:55 +03:00
//static _syscall3(int,mknod,char *,a1,mode_t,a2,dev_t,a3)
2004-01-20 21:32:43 +03:00
int main ( int argc , char * * argv )
{
pid_t installpid , childpid ;
int wait_status ;
int fd ;
int abnormal_termination = 0 ;
int end_stage2 = 0 ;
//char *argv2[4] = {"ls","-l","/dev/",0};
/* getpid() != 1 should work, by linuxrc tends to get a larger pid */
testing = ( getpid ( ) > 50 ) ;
/*
mknod ( " /dev/ram3 " , BLK_DEV , MKDEV ( 1 , 3 ) ) ;
mknod ( " /dev/fd0 " , BLK_DEV , MKDEV ( 2 , 0 ) ) ;
mknod ( " /dev/loop3 " , BLK_DEV , MKDEV ( 7 , 3 ) ) ;
mknod ( " /dev/mem " , CHR_DEV , MKDEV ( 1 , 1 ) ) ;
mknod ( " /dev/null " , CHR_DEV , MKDEV ( 1 , 3 ) ) ;
mknod ( " /dev/ptyp0 " , CHR_DEV , MKDEV ( 2 , 0 ) ) ;
mknod ( " /dev/ttyp0 " , CHR_DEV , MKDEV ( 3 , 0 ) ) ;
mknod ( " /dev/tty0 " , CHR_DEV , MKDEV ( 4 , 0 ) ) ;
mknod ( " /dev/tty1 " , CHR_DEV , MKDEV ( 4 , 1 ) ) ;
mknod ( " /dev/tty2 " , CHR_DEV , MKDEV ( 4 , 2 ) ) ;
mknod ( " /dev/tty3 " , CHR_DEV , MKDEV ( 4 , 3 ) ) ;
mknod ( " /dev/tty4 " , CHR_DEV , MKDEV ( 4 , 4 ) ) ;
mknod ( " /dev/tty5 " , CHR_DEV , MKDEV ( 4 , 5 ) ) ;
mknod ( " /dev/tty6 " , CHR_DEV , MKDEV ( 4 , 6 ) ) ;
mknod ( " /dev/tty7 " , CHR_DEV , MKDEV ( 4 , 7 ) ) ;
mknod ( " /dev/ttyS0 " , CHR_DEV , MKDEV ( 4 , 64 ) ) ;
mknod ( " /dev/console " , CHR_DEV , MKDEV ( 5 , 1 ) ) ;
mknod ( " /dev/fb0 " , CHR_DEV , MKDEV ( 29 , 0 ) ) ;
mknod ( " /dev/ppp " , CHR_DEV , MKDEV ( 108 , 0 ) ) ;
*/
//execve("/bin/ls",argv2,0);
if ( ! testing ) {
/* turn off screen blanking */
printf ( " \033 [9;0] " ) ;
printf ( " \033 [8] " ) ;
}
else
printf ( " *** TESTING MODE *** \n " ) ;
2004-04-14 22:23:20 +04:00
// printf("\n\t\t\t\033[1;40mWelcome to \033[1;36mALT Linux\033[0;39m\n\n");
2004-01-20 21:32:43 +03:00
if ( ! testing ) {
if ( mount ( " /proc " , " /proc " , " proc " , 0 , NULL ) )
fatal_error ( " Unable to mount proc filesystem " ) ;
}
/* ignore Control-C and keyboard stop signals */
signal ( SIGINT , SIG_IGN ) ;
signal ( SIGTSTP , SIG_IGN ) ;
if ( ! testing ) {
fd = open ( " /dev/tty1 " , O_RDWR , 0 ) ;
2004-03-19 20:02:37 +03:00
if ( fd < 0 ) {
perror ( " can't open /dev/tty1 " ) ;
2004-01-20 21:32:43 +03:00
/* try with devfs */
fd = open ( " /dev/vc/1 " , O_RDWR , 0 ) ;
2004-03-19 20:02:37 +03:00
}
2004-01-20 21:32:43 +03:00
if ( fd < 0 )
fatal_error ( " failed to open /dev/tty1 and /dev/vc/1 " ) ;
dup2 ( fd , 0 ) ;
dup2 ( fd , 1 ) ;
dup2 ( fd , 2 ) ;
close ( fd ) ;
}
/* 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 " ) ;
2004-01-20 21:32:43 +03:00
print_error ( " could not set new controlling tty " ) ;
2004-03-19 20:02:37 +03:00
}
2004-01-20 21:32:43 +03:00
if ( ! testing ) {
char my_hostname [ ] = " localhost.localdomain " ;
sethostname ( my_hostname , sizeof ( my_hostname ) ) ;
/* the default domainname (as of 2.0.35) is "(none)", which confuses
glibc */
setdomainname ( " " , 0 ) ;
}
if ( ! testing )
doklog ( ) ;
/* 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 " ) ;
2004-01-20 21:32:43 +03:00
if ( ! ( installpid = fork ( ) ) ) {
/* child */
char * child_argv [ 2 ] ;
child_argv [ 0 ] = " /sbin/stage1 " ;
child_argv [ 1 ] = NULL ;
2004-03-19 20:02:37 +03:00
sleep ( 10 ) ;
2004-01-20 21:32:43 +03:00
execve ( child_argv [ 0 ] , child_argv , env ) ;
printf ( " error in exec of stage1 :-( \n " ) ;
return 0 ;
}
while ( ! end_stage2 ) {
childpid = wait4 ( - 1 , & wait_status , 0 , NULL ) ;
if ( childpid = = installpid )
end_stage2 = 1 ;
}
if ( ! WIFEXITED ( wait_status ) | | ( WEXITSTATUS ( wait_status ) ! = 0 & & WEXITSTATUS ( wait_status ) ! = exit_value_rescue ) ) {
printf ( " wait_status: %i, install exited abnormally :-( " , wait_status ) ;
if ( WIFSIGNALED ( wait_status ) )
printf ( " -- received signal %d " , WTERMSIG ( wait_status ) ) ;
printf ( " \n " ) ;
abnormal_termination = 1 ;
} else if ( WIFEXITED ( wait_status ) & & WEXITSTATUS ( wait_status ) = = exit_value_rescue ) {
kill ( klog_pid , 9 ) ;
printf ( " exiting init -- giving hand to rescue \n " ) ;
return 0 ;
} else
printf ( " install succeeded \n " ) ;
if ( testing )
return 0 ;
sync ( ) ; sync ( ) ;
printf ( " sending termination signals... " ) ;
kill ( - 1 , 15 ) ;
sleep ( 2 ) ;
printf ( " done \n " ) ;
printf ( " sending kill signals... " ) ;
kill ( - 1 , 9 ) ;
sleep ( 2 ) ;
printf ( " done \n " ) ;
unmount_filesystems ( ) ;
if ( ! abnormal_termination ) {
printf ( " rebooting system \n " ) ;
sleep ( 2 ) ;
reboot ( 0xfee1dead , 672274793 , 0x01234567 ) ;
} else {
printf ( " you may safely reboot your system \n " ) ;
while ( 1 ) ;
}
return 0 ;
}