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 .
*
*/
/*
* ( 1 ) calculate dependencies
* ( 2 ) unarchive relevant modules
* ( 3 ) insmod them
*/
# include <stdlib.h>
# include <sys/types.h>
# include <sys/stat.h>
2008-02-29 20:06:47 +03:00
# include <sys/wait.h>
2004-01-20 21:32:43 +03:00
# include <sys/mount.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
# include <stdio.h>
2004-11-22 16:47:29 +03:00
# include <errno.h>
2004-01-20 21:32:43 +03:00
# include "stage1.h"
# include "log.h"
# include "frontend.h"
# include "mount.h"
# include "modules.h"
2004-11-22 16:47:29 +03:00
static const char * moderror ( int err )
{
switch ( err ) {
case ENOEXEC :
return " Invalid module format " ;
case ENOENT :
return " Unknown symbol in module " ;
case ESRCH :
return " Module has wrong symbol version " ;
case EINVAL :
return " Invalid parameters " ;
default :
return strerror ( err ) ;
}
}
static void * grab_file ( const char * filename , unsigned long * size )
{
unsigned int max = 16384 ;
int ret , fd ;
void * buffer = malloc ( max ) ;
fd = open ( filename , O_RDONLY , 0 ) ;
if ( fd < 0 )
return NULL ;
* size = 0 ;
while ( ( ret = read ( fd , buffer + * size , max - * size ) ) > 0 ) {
* size + = ret ;
if ( * size = = max )
buffer = realloc ( buffer , max * = 2 ) ;
}
if ( ret < 0 ) {
free ( buffer ) ;
buffer = NULL ;
}
close ( fd ) ;
return buffer ;
}
int insmod_call ( char * pathname , char * params )
{
void * file ;
unsigned long len ;
int rc = - 1 ;
file = grab_file ( pathname , & len ) ;
if ( ! file ) {
log_message ( " insmod: can't read '%s': %s " , pathname , strerror ( errno ) ) ;
return rc ;
}
rc = init_module ( file , len , params = = NULL ? " " : params ) ;
2007-03-03 00:48:18 +03:00
free ( file ) ;
2007-04-18 15:28:21 +04:00
if ( rc ! = 0 & & errno ! = EEXIST ) {
2004-11-22 16:47:29 +03:00
log_message ( " init_module: '%s': %s " , pathname , moderror ( errno ) ) ;
return rc ;
}
2007-04-18 15:28:21 +04:00
return 0 ;
2004-11-22 16:47:29 +03:00
}
2004-01-20 21:32:43 +03:00
2008-02-29 20:06:47 +03:00
static enum insmod_return modprobe ( const char * mod_name , char * options )
2004-01-20 21:32:43 +03:00
{
2008-02-29 20:06:47 +03:00
int pid , status ;
if ( ! ( pid = fork ( ) ) ) {
2015-11-03 21:31:35 +03:00
char * argv [ ] = { " /sbin/modprobe " , " -q " , ( char * ) mod_name , options , NULL } ;
2008-02-29 20:06:47 +03:00
execve ( argv [ 0 ] , argv , NULL ) ;
log_message ( " modprobe %s failed " , mod_name ) ;
}
waitpid ( pid , & status , 0 ) ;
return WIFEXITED ( status ) ? INSMOD_OK : INSMOD_FAILED ;
2004-01-20 21:32:43 +03:00
}
2008-02-29 20:06:47 +03:00
enum insmod_return my_insmod ( const char * mod_name , char * options )
2004-01-20 21:32:43 +03:00
{
int i ;
log_message ( " have to insmod %s " , mod_name ) ;
if ( IS_TESTING )
return INSMOD_OK ;
2008-02-29 20:06:47 +03:00
i = modprobe ( mod_name , options ) ;
2004-01-20 21:32:43 +03:00
if ( i = = 0 ) {
log_message ( " \t succeeded %s " , mod_name ) ;
} else
log_message ( " warning, insmod failed (%s %s) (%d) " , mod_name , options , i ) ;
2008-02-29 20:06:47 +03:00
return i ;
2004-01-20 21:32:43 +03:00
}
2008-02-29 20:06:47 +03:00
enum return_type ask_insmod ( )
2004-01-20 21:32:43 +03:00
{
2008-02-29 20:06:47 +03:00
return RETURN_ERROR ;
2004-01-20 21:32:43 +03:00
}
void update_modules ( void )
{
FILE * f ;
char * * disk_contents ;
char final_name [ 500 ] ;
char floppy_mount_location [ ] = " /tmp/floppy " ;
stg1_info_message ( " Please insert the Update Modules floppy. " ) ; ;
2008-02-29 20:06:47 +03:00
my_insmod ( " floppy " , NULL ) ;
2004-01-20 21:32:43 +03:00
if ( my_mount ( " /dev/fd0 " , floppy_mount_location , " ext2 " , 0 ) = = - 1 ) {
enum return_type results = ask_yes_no ( " I can't find a Linux ext2 floppy in first floppy drive. \n "
" Retry? " ) ;
if ( results = = RETURN_OK )
return update_modules ( ) ;
return ;
}
disk_contents = list_directory ( floppy_mount_location ) ;
if ( ! ( f = fopen ( " /tmp/floppy/to_load " , " rb " ) ) ) {
stg1_error_message ( " I can't find \" to_load \" file. " ) ;
umount ( floppy_mount_location ) ;
return update_modules ( ) ;
}
while ( 1 ) {
char module [ 500 ] ;
char * options ;
char * * entry = disk_contents ;
if ( ! fgets ( module , sizeof ( module ) , f ) ) break ;
if ( module [ 0 ] = = ' # ' | | strlen ( module ) = = 0 )
continue ;
while ( module [ strlen ( module ) - 1 ] = = ' \n ' )
module [ strlen ( module ) - 1 ] = ' \0 ' ;
options = strchr ( module , ' ' ) ;
if ( options ) {
options [ 0 ] = ' \0 ' ;
options + + ;
}
log_message ( " updatemodules: (%s) (%s) " , module , options ) ;
while ( entry & & * entry ) {
if ( ! strncmp ( * entry , module , strlen ( module ) ) & & ( * entry ) [ strlen ( module ) ] = = ' . ' ) {
sprintf ( final_name , " %s/%s " , floppy_mount_location , * entry ) ;
if ( insmod_call ( final_name , options ) ) {
log_message ( " \t %s (floppy): failed " , * entry ) ;
stg1_error_message ( " Insmod %s (floppy) failed. " , * entry ) ;
}
break ;
}
entry + + ;
}
if ( ! entry | | ! * entry ) {
2008-02-29 20:06:47 +03:00
enum insmod_return ret = my_insmod ( module , options ) ;
2004-01-20 21:32:43 +03:00
if ( ret ! = INSMOD_OK ) {
log_message ( " \t %s (marfile): failed " , module ) ;
stg1_error_message ( " Insmod %s (marfile) failed. " , module ) ;
}
}
}
fclose ( f ) ;
}