2011-01-18 09:24:57 +00:00
/*
* loader . c
*
* This is the installer loader . Its job is to somehow load the rest
* of the installer into memory and run it . This may require setting
* up some devices and networking , etc . The main point of this code is
* to stay SMALL ! Remember that , live by that , and learn to like it .
*
* Copyright ( C ) 1997 , 1998 , 1999 , 2000 , 2001 , 2002 , 2003 , 2004 , 2005 ,
* 2006 , 2007 Red Hat , Inc . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
* Author ( s ) : Erik Troan < ewt @ redhat . com >
* Matt Wilson < msw @ redhat . com >
* Michael Fulbright < msf @ redhat . com >
* Jeremy Katz < katzj @ redhat . com >
*/
# include <ctype.h>
# include <errno.h>
# include <execinfo.h>
# include <fcntl.h>
# include <newt.h>
# include <signal.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <strings.h>
# include <unistd.h>
# include <stdint.h>
# include <dirent.h>
# include <arpa/inet.h>
# include <sys/ioctl.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <sys/utsname.h>
# include <linux/fb.h>
# include <linux/serial.h>
# include <linux/vt.h>
# include <glib.h>
# ifdef USE_MTRACE
# include <mcheck.h>
# endif
# include "copy.h"
# include "getparts.h"
# include "loader.h"
# include "loadermisc.h" /* JKFIXME: functions here should be split out */
# include "log.h"
# include "lang.h"
# include "fwloader.h"
# include "kbd.h"
# include "kickstart.h"
# include "windows.h"
/* module stuff */
# include "modules.h"
# include "moduleinfo.h"
# include "driverdisk.h"
/* hardware stuff */
# include "hardware.h"
/* install method stuff */
# include "method.h"
# include "cdinstall.h"
# include "nfsinstall.h"
# include "hdinstall.h"
# include "urls.h"
# include "urlinstall.h"
# include "net.h"
# include "telnetd.h"
# include <selinux/selinux.h>
# include "selinux.h"
# include "../isys/imount.h"
# include "../isys/isys.h"
# include "../isys/stubs.h"
# include "../isys/lang.h"
# include "../isys/eddsupport.h"
# include "../isys/str.h"
/* maximum number of extra arguments that can be passed to the second stage */
# define MAX_EXTRA_ARGS 128
static char * extraArgs [ MAX_EXTRA_ARGS ] ;
static int hasGraphicalOverride ( ) ;
static int newtRunning = 0 ;
/* boot flags -- we need these in a lot of places */
uint64_t flags = LOADER_FLAGS_SELINUX ;
# ifdef INCLUDE_LOCAL
# include "cdinstall.h"
# include "hdinstall.h"
# endif
# ifdef INCLUDE_NETWORK
# include "nfsinstall.h"
# include "urlinstall.h"
# endif
int num_link_checks = 5 ;
int post_link_sleep = 0 ;
static pid_t init_pid = 1 ;
static int init_sig = SIGUSR1 ; /* default to shutdown=halt */
static const char * LANG_DEFAULT = " en_US.UTF-8 " ;
static struct installMethod installMethods [ ] = {
{ N_ ( " Local CD/DVD " ) , 0 , DEVICE_CDROM , mountCdromImage } ,
{ N_ ( " Hard drive " ) , 0 , DEVICE_DISK , mountHardDrive } ,
{ N_ ( " NFS directory " ) , 1 , DEVICE_NETWORK , mountNfsImage } ,
{ " URL " , 1 , DEVICE_NETWORK , mountUrlImage } ,
} ;
static int numMethods = sizeof ( installMethods ) / sizeof ( struct installMethod ) ;
static int expected_exit = 0 ;
void doExit ( int result )
{
expected_exit = 1 ;
exit ( result ) ;
}
void doSuspend ( void ) {
newtFinished ( ) ;
doExit ( 1 ) ;
}
void doShell ( void ) {
pid_t child ;
int status ;
newtSuspend ( ) ;
child = fork ( ) ;
if ( child = = 0 ) {
if ( execl ( " /sbin/bash " , " /sbin/bash " , " -i " , NULL ) = = - 1 ) {
logMessage ( ERROR , " %s (%d): %m " , __func__ , __LINE__ ) ;
_exit ( 1 ) ;
}
} else if ( child = = - 1 ) {
logMessage ( ERROR , " %s (%d): %m " , __func__ , __LINE__ ) ;
newtResume ( ) ;
} else {
if ( waitpid ( child , & status , 0 ) = = - 1 ) {
logMessage ( ERROR , " %s (%d): %m " , __func__ , __LINE__ ) ;
}
newtResume ( ) ;
}
}
void doGdbserver ( struct loaderData_s * loaderData ) {
int child , fd ;
char * pid ;
iface_t iface ;
/* If gdbserver is found, go ahead and run it on the loader process now
* before anything bad happens .
*/
if ( loaderData - > gdbServer & & ! access ( " /usr/bin/gdbserver " , X_OK ) ) {
pid_t loaderPid = getpid ( ) ;
iface_init_iface_t ( & iface ) ;
if ( kickstartNetworkUp ( loaderData , & iface ) ) {
logMessage ( ERROR , " can't run gdbserver due to no network " ) ;
return ;
}
checked_asprintf ( & pid , " %d " , loaderPid ) ;
if ( ! ( child = fork ( ) ) ) {
logMessage ( INFO , " starting gdbserver: %s %s %s %s " ,
" /usr/bin/gdbserver " , " --attach " , loaderData - > gdbServer ,
pid ) ;
fd = open ( " /dev/null " , O_RDONLY ) ;
close ( STDIN_FILENO ) ;
dup2 ( fd , STDIN_FILENO ) ;
close ( fd ) ;
fd = open ( " /dev/null " , O_WRONLY ) ;
close ( STDOUT_FILENO ) ;
dup2 ( fd , STDOUT_FILENO ) ;
close ( STDERR_FILENO ) ;
dup2 ( fd , STDERR_FILENO ) ;
close ( fd ) ;
if ( execl ( " /usr/bin/gdbserver " , " /usr/bin/gdbserver " , " --attach " ,
loaderData - > gdbServer , pid , NULL ) = = - 1 )
logMessage ( ERROR , " error running gdbserver: %m " ) ;
_exit ( 1 ) ;
}
}
}
void startNewt ( void ) {
if ( ! newtRunning ) {
char * buf ;
char * arch = getProductArch ( ) ;
checked_asprintf ( & buf , _ ( " Welcome to %s for %s " ) , getProductName ( ) , arch ) ;
/*
* Because currently initrd . img only has got the default English locale
* support , pretend for newtInit ( ) it is actually the used LANG so Newt
* knows how to compute character widths etc .
*/
char * lang = getenv ( " LANG " ) ;
if ( lang ) {
lang = strdup ( lang ) ;
}
setenv ( " LANG " , LANG_DEFAULT , 1 ) ;
newtInit ( ) ;
unsetenv ( " LANG " ) ;
/* restore the original LANG value */
if ( lang ) {
setenv ( " LANG " , lang , 1 ) ;
free ( lang ) ;
}
newtCls ( ) ;
newtDrawRootText ( 0 , 0 , buf ) ;
free ( buf ) ;
newtPushHelpLine ( _ ( " <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen " ) ) ;
newtRunning = 1 ;
if ( ! access ( " /bin/sh " , X_OK ) )
newtSetSuspendCallback ( ( void * ) doShell , NULL ) ;
}
}
void stopNewt ( void ) {
if ( newtRunning ) newtFinished ( ) ;
newtRunning = 0 ;
}
static gchar * productName = NULL ;
static gchar * productPath = NULL ;
static gchar * productArch = NULL ;
static void initProductInfo ( void ) {
gchar * contents = NULL ;
gchar * * lines = NULL , * * stamp = NULL ;
GError * fileErr = NULL ;
if ( ! g_file_get_contents ( " /.buildstamp " , & contents , NULL , & fileErr ) ) {
logMessage ( ERROR , " error reading .buildstamp: %s " , fileErr - > message ) ;
g_error_free ( fileErr ) ;
productName = g_strdup ( " anaconda " ) ;
productArch = g_strdup ( " unknown architecture " ) ;
productPath = g_strdup ( " anaconda " ) ;
return ;
}
/* .buildstamp uses the first 3 lines in this format:
* STAMP . productArch
* productName
* productPath
*/
lines = g_strsplit ( contents , " \n " , 0 ) ;
g_free ( contents ) ;
if ( ( lines ! = NULL ) & & ( g_strv_length ( lines ) > = 3 ) ) {
/* STAMP.productArch */
stamp = g_strsplit ( lines [ 0 ] , " . " , 0 ) ;
if ( ( stamp ! = NULL ) & & ( g_strv_length ( stamp ) = = 2 ) ) {
productArch = g_strdup ( stamp [ 1 ] ) ;
} else {
productArch = g_strdup ( " unknown architecture " ) ;
}
if ( stamp ) {
g_strfreev ( stamp ) ;
}
productName = g_strdup ( lines [ 1 ] ) ;
productPath = g_strdup ( lines [ 2 ] ) ;
} else {
productName = g_strdup ( " anaconda " ) ;
productArch = g_strdup ( " unknown architecture " ) ;
productPath = g_strdup ( " anaconda " ) ;
}
if ( lines ) {
g_strfreev ( lines ) ;
}
return ;
}
char * getProductName ( void ) {
if ( ! productName ) {
initProductInfo ( ) ;
}
return productName ;
}
char * getProductArch ( void ) {
if ( ! productArch ) {
initProductInfo ( ) ;
}
return productArch ;
}
char * getProductPath ( void ) {
if ( ! productPath ) {
initProductInfo ( ) ;
}
return productPath ;
}
void initializeConsole ( ) {
/* enable UTF-8 console */
setenv ( " LANG " , LANG_DEFAULT , 1 ) ;
printf ( " \033 %%G " ) ;
fflush ( stdout ) ;
isysLoadFont ( ) ;
isysSetUnicodeKeymap ( ) ;
}
/* fbcon is buggy and resets our color palette if we allocate a terminal
* after initializing it , so we initialize 9 of them before we need them .
* If it doesn ' t work , the user gets to suffer through having an ugly palette ,
* but things are still usable . */
static void initializeTtys ( void ) {
int fd , n ;
char dev [ ] = " /dev/ttyX " ;
for ( n = 9 ; n > 0 ; n - - ) {
sprintf ( dev , " /dev/tty%d " , n ) ;
mknod ( dev , 0600 | S_IFCHR , makedev ( 4 , n ) ) ;
fd = open ( dev , O_RDWR | O_NOCTTY ) ;
if ( fd > = 0 ) {
ioctl ( fd , VT_ACTIVATE , n ) ;
if ( n = = 1 )
ioctl ( fd , VT_WAITACTIVE , n ) ;
close ( fd ) ;
} else
logMessage ( ERROR , " failed to initialize %s " , dev ) ;
}
}
static void spawnShell ( void ) {
pid_t pid ;
if ( FL_SERIAL ( flags ) | | FL_NOSHELL ( flags ) ) {
logMessage ( INFO , " not spawning a shell " ) ;
return ;
} else if ( access ( " /bin/sh " , X_OK ) ) {
logMessage ( ERROR , " cannot open shell - /bin/sh doesn't exist " ) ;
return ;
}
if ( ! ( pid = fork ( ) ) ) {
int fd ;
fd = open ( " /dev/tty2 " , O_RDWR | O_NOCTTY ) ;
if ( fd < 0 ) {
logMessage ( ERROR , " cannot open /dev/tty2 -- no shell will be provided " ) ;
return ;
}
dup2 ( fd , 0 ) ;
dup2 ( fd , 1 ) ;
dup2 ( fd , 2 ) ;
close ( fd ) ;
setsid ( ) ;
/* enable UTF-8 console */
printf ( " \033 %%G " ) ;
fflush ( stdout ) ;
isysLoadFont ( ) ;
if ( ioctl ( 0 , TIOCSCTTY , NULL ) ) {
logMessage ( ERROR , " could not set new controlling tty " ) ;
}
signal ( SIGINT , SIG_DFL ) ;
signal ( SIGTSTP , SIG_DFL ) ;
if ( ! access ( " /tmp/updates/pyrc.py " , R_OK | X_OK ) )
setenv ( " PYTHONSTARTUP " , " /tmp/updates/pyrc.py " , 1 ) ;
else if ( ! access ( " /usr/lib/anaconda-runtime/pyrc.py " , R_OK | X_OK ) )
setenv ( " PYTHONSTARTUP " , " /usr/lib/anaconda-runtime/pyrc.py " , 1 ) ;
setenv ( " LD_LIBRARY_PATH " , LIBPATH , 1 ) ;
setenv ( " LANG " , " C " , 1 ) ;
if ( execl ( " /bin/sh " , " -/bin/sh " , NULL ) = = - 1 ) {
logMessage ( CRITICAL , " exec of /bin/sh failed: %m " ) ;
exit ( 1 ) ;
}
}
return ;
}
static void copyWarnFn ( char * msg ) {
logMessage ( WARNING , msg ) ;
}
static void copyErrorFn ( char * msg ) {
newtWinMessage ( _ ( " Error " ) , _ ( " OK " ) , _ ( msg ) ) ;
}
void loadUpdates ( struct loaderData_s * loaderData ) {
char * device = NULL , * part = NULL , * buf ;
char * * devNames = NULL ;
enum { UPD_DEVICE , UPD_PART , UPD_PROMPT , UPD_LOAD , UPD_DONE } stage = UPD_DEVICE ;
int rc , num = 0 ;
int dir = 1 ;
while ( stage ! = UPD_DONE ) {
switch ( stage ) {
case UPD_DEVICE : {
rc = getRemovableDevices ( & devNames ) ;
if ( rc = = 0 )
return ;
/* we don't need to ask which to use if they only have one */
if ( rc = = 1 ) {
device = strdup ( devNames [ 0 ] ) ;
free ( devNames ) ;
devNames = NULL ;
if ( dir = = - 1 )
return ;
stage = UPD_PART ;
break ;
}
dir = 1 ;
startNewt ( ) ;
rc = newtWinMenu ( _ ( " Update Disk Source " ) ,
_ ( " You have multiple devices which could serve "
" as sources for an update disk. Which would "
" you like to use? " ) , 40 , 10 , 10 ,
rc < 6 ? rc : 6 , devNames ,
& num , _ ( " OK " ) , _ ( " Cancel " ) , NULL ) ;
if ( rc = = 2 ) {
free ( devNames ) ;
devNames = NULL ;
return ;
}
device = strdup ( devNames [ num ] ) ;
free ( devNames ) ;
devNames = NULL ;
stage = UPD_PART ;
}
case UPD_PART : {
char * * part_list = getPartitionsList ( device ) ;
int nump = 0 , num = 0 ;
if ( part ! = NULL ) {
free ( part ) ;
part = NULL ;
}
if ( ( nump = lenPartitionsList ( part_list ) ) = = 0 ) {
if ( dir = = - 1 ) {
stage = UPD_DEVICE ;
} else {
checked_asprintf ( & part , " /dev/%s " , device ) ;
stage = UPD_PROMPT ;
}
break ;
}
dir = 1 ;
startNewt ( ) ;
rc = newtWinMenu ( _ ( " Update Disk Source " ) ,
_ ( " There are multiple partitions on this device "
" which could contain the update disk image. "
" Which would you like to use? " ) , 40 , 10 , 10 ,
nump < 6 ? nump : 6 , part_list , & num , _ ( " OK " ) ,
_ ( " Back " ) , NULL ) ;
if ( rc = = 2 ) {
freePartitionsList ( part_list ) ;
stage = UPD_DEVICE ;
dir = - 1 ;
break ;
}
part = strdup ( part_list [ num ] ) ;
stage = UPD_LOAD ;
}
case UPD_PROMPT :
checked_asprintf ( & buf , _ ( " Insert your updates disk into %s and "
" press \" OK \" to continue. " ) , part ) ;
rc = newtWinChoice ( _ ( " Updates Disk " ) , _ ( " OK " ) , _ ( " Back " ) , buf ) ;
free ( buf ) ;
buf = NULL ;
if ( rc = = 2 ) {
stage = UPD_PART ;
dir = - 1 ;
break ;
}
stage = UPD_LOAD ;
break ;
case UPD_LOAD :
logMessage ( INFO , " UPDATES device is %s " , part ) ;
if ( doPwMount ( part , " /tmp/update-disk " , " auto " , " ro " , NULL ) ) {
newtWinMessage ( _ ( " Error " ) , _ ( " OK " ) ,
_ ( " Failed to mount updates disk " ) ) ;
stage = UPD_PROMPT ;
break ;
} else {
/* Copy everything to /tmp/updates so we can unmount the disk */
winStatus ( 40 , 3 , _ ( " Updates " ) , _ ( " Reading anaconda updates " ) ) ;
if ( ! copyDirectory ( " /tmp/update-disk " , " /tmp/updates " , copyWarnFn ,
copyErrorFn ) ) {
dir = 1 ;
stage = UPD_DONE ;
}
newtPopWindow ( ) ;
umount ( " /tmp/update-disk " ) ;
}
case UPD_DONE :
break ;
}
}
return ;
}
static char * newUpdatesLocation ( const char * origLocation ) {
const char * location ;
char * retval = NULL ;
newtComponent f , okay , cancel , answer , locationEntry ;
newtGrid grid , buttons ;
startNewt ( ) ;
locationEntry = newtEntry ( - 1 , - 1 , NULL , 60 , & location , NEWT_FLAG_SCROLL ) ;
newtEntrySet ( locationEntry , origLocation , 1 ) ;
/* button bar at the bottom of the window */
buttons = newtButtonBar ( _ ( " OK " ) , & okay , _ ( " Cancel " ) , & cancel , NULL ) ;
grid = newtCreateGrid ( 1 , 3 ) ;
newtGridSetField ( grid , 0 , 0 , NEWT_GRID_COMPONENT ,
newtTextboxReflowed ( - 1 , - 1 , _ ( " Unable to download the updates image. Please modify the updates location below or press Cancel to proceed without updates.. " ) , 60 , 0 , 0 , 0 ) ,
0 , 0 , 0 , 0 , NEWT_ANCHOR_LEFT , 0 ) ;
newtGridSetField ( grid , 0 , 1 , NEWT_GRID_COMPONENT , locationEntry ,
0 , 1 , 0 , 0 , NEWT_ANCHOR_LEFT , 0 ) ;
newtGridSetField ( grid , 0 , 2 , NEWT_GRID_SUBGRID , buttons ,
0 , 1 , 0 , 0 , 0 , NEWT_GRID_FLAG_GROWX ) ;
f = newtForm ( NULL , NULL , 0 ) ;
newtGridAddComponentsToForm ( grid , f , 1 ) ;
newtGridWrappedWindow ( grid , _ ( " Error downloading updates image " ) ) ;
newtGridFree ( grid , 1 ) ;
/* run the form */
answer = newtRunForm ( f ) ;
if ( answer ! = cancel )
retval = strdup ( location ) ;
newtFormDestroy ( f ) ;
newtPopWindow ( ) ;
return retval ;
}
static int loadUpdatesFromRemote ( char * url , struct loaderData_s * loaderData ) {
int rc = getFileFromUrl ( url , " /tmp/updates.img " , loaderData ) ;
if ( rc ! = 0 ) {
char * newLocation = newUpdatesLocation ( url ) ;
if ( ! newLocation )
return rc ;
else
return loadUpdatesFromRemote ( newLocation , loaderData ) ;
}
copyUpdatesImg ( " /tmp/updates.img " ) ;
unlink ( " /tmp/updates.img " ) ;
return 0 ;
}
static void writeVNCPasswordFile ( char * pfile , char * password ) {
FILE * f ;
f = fopen ( pfile , " w+ " ) ;
fprintf ( f , " %s \n " , password ) ;
fclose ( f ) ;
}
/* XXX: read information from /etc/sysconfig/network-scripts/ifcfg-$INTERFACE
* ( written by linuxrc ) , the linuxrc mess should be firing up NM too
*/
static void readNetInfo ( struct loaderData_s * * ld ) {
int i ;
struct loaderData_s * loaderData = * ld ;
DIR * dp = NULL ;
FILE * f = NULL ;
struct dirent * ent = NULL ;
char * cfgfile = NULL ;
int bufsiz = 100 ;
char buf [ bufsiz ] ;
char * vname = NULL ;
char * vparm = NULL ;
/* when this function is called, we can assume only one network device
* config file has been written to / etc / sysconfig / network - scripts , so
* find it and read it
*/
dp = opendir ( " /etc/sysconfig/network-scripts " ) ;
if ( dp = = NULL ) {
return ;
}
while ( ( ent = readdir ( dp ) ) ! = NULL ) {
if ( ! strncmp ( ent - > d_name , " ifcfg- " , 6 ) ) {
checked_asprintf ( & cfgfile , " /etc/sysconfig/network-scripts/%s " ,
ent - > d_name ) ;
break ;
}
}
if ( dp ! = NULL ) {
if ( closedir ( dp ) = = - 1 ) {
logMessage ( DEBUGLVL , " %s (%d): %m " , __func__ , __LINE__ ) ;
abort ( ) ;
}
}
if ( cfgfile = = NULL ) {
logMessage ( DEBUGLVL , " no ifcfg files found in /etc/sysconfig/network-scripts " ) ;
return ;
}
if ( ( f = fopen ( cfgfile , " r " ) ) = = NULL ) {
logMessage ( DEBUGLVL , " %s (%d): %m " , __func__ , __LINE__ ) ;
free ( cfgfile ) ;
return ;
}
if ( ( vname = ( char * ) malloc ( sizeof ( char ) * 15 ) ) = = NULL ) {
logMessage ( DEBUGLVL , " %s (%d): %m " , __func__ , __LINE__ ) ;
abort ( ) ;
}
if ( ( vparm = ( char * ) malloc ( sizeof ( char ) * 85 ) ) = = NULL ) {
logMessage ( DEBUGLVL , " %s (%d): %m " , __func__ , __LINE__ ) ;
abort ( ) ;
}
/* make sure everything is NULL before we begin copying info */
loaderData - > ipv4 = NULL ;
loaderData - > netmask = NULL ;
loaderData - > gateway = NULL ;
loaderData - > dns = NULL ;
loaderData - > peerid = NULL ;
loaderData - > subchannels = NULL ;
loaderData - > portname = NULL ;
loaderData - > nettype = NULL ;
loaderData - > ctcprot = NULL ;
loaderData - > layer2 = NULL ;
loaderData - > portno = NULL ;
loaderData - > macaddr = NULL ;
# ifdef ENABLE_IPV6
loaderData - > ipv6 = NULL ;
loaderData - > gateway6 = NULL ;
# endif
/*
* The / tmp / netinfo file is written out by / sbin / init on s390x ( which is
* really the linuxrc . s390 script ) . It ' s a shell - sourcable file with
* various system settings needing for the system instance .
*
* The goal of this function is to read in only the network settings
* and populate the loaderData structure .
*/
while ( fgets ( buf , bufsiz , f ) ) {
/* trim whitespace from end */
i = 0 ;
while ( ! isspace ( buf [ i ] ) & & i < ( bufsiz - 1 ) )
i + + ;
buf [ i ] = ' \0 ' ;
/* break up var name and value */
if ( strstr ( buf , " = " ) ) {
vname = strtok ( buf , " = " ) ;
if ( vname = = NULL )
continue ;
vparm = strtok ( NULL , " = " ) ;
if ( vparm = = NULL )
continue ;
if ( ! strncmp ( vname , " IPADDR " , 6 ) )
loaderData - > ipv4 = strdup ( vparm ) ;
if ( ! strncmp ( vname , " NETMASK " , 7 ) )
loaderData - > netmask = strdup ( vparm ) ;
if ( ! strncmp ( vname , " GATEWAY " , 7 ) )
loaderData - > gateway = strdup ( vparm ) ;
if ( ! strncmp ( vname , " DNS " , 3 ) )
loaderData - > dns = strdup ( vparm ) ;
if ( ! strncmp ( vname , " MTU " , 3 ) ) {
errno = 0 ;
loaderData - > mtu = strtol ( vparm , NULL , 10 ) ;
if ( ( errno = = ERANGE & & ( loaderData - > mtu = = LONG_MIN | |
loaderData - > mtu = = LONG_MAX ) ) | |
( errno ! = 0 & & loaderData - > mtu = = 0 ) ) {
logMessage ( ERROR , " %s: %d: %m " , __func__ , __LINE__ ) ;
abort ( ) ;
}
}
if ( ! strncmp ( vname , " PEERID " , 6 ) )
loaderData - > peerid = strdup ( vparm ) ;
if ( ! strncmp ( vname , " SUBCHANNELS " , 12 ) )
loaderData - > subchannels = strdup ( vparm ) ;
if ( ! strncmp ( vname , " PORTNAME " , 8 ) )
loaderData - > portname = strdup ( vparm ) ;
if ( ! strncmp ( vname , " NETTYPE " , 7 ) )
loaderData - > nettype = strdup ( vparm ) ;
if ( ! strncmp ( vname , " CTCPROT " , 7 ) )
loaderData - > ctcprot = strdup ( vparm ) ;
if ( ! strncmp ( vname , " LAYER2 " , 6 ) )
loaderData - > layer2 = strdup ( vparm ) ;
if ( ! strncmp ( vname , " PORTNO " , 6 ) )
loaderData - > portno = strdup ( vparm ) ;
if ( ! strncmp ( vname , " MACADDR " , 7 ) )
loaderData - > macaddr = strdup ( vparm ) ;
if ( ! strncmp ( vname , " HOSTNAME " , 8 ) )
loaderData - > hostname = strdup ( vparm ) ;
}
}
if ( loaderData - > ipv4 & & loaderData - > netmask ) {
flags | = LOADER_FLAGS_HAVE_CMSCONF ;
}
if ( fclose ( f ) = = - 1 ) {
logMessage ( ERROR , " %s: %d: %m " , __func__ , __LINE__ ) ;
abort ( ) ;
}
if ( cfgfile ! = NULL ) {
free ( cfgfile ) ;
}
return ;
}
/* parse anaconda or pxelinux-style ip= arguments
* pxelinux format : ip = < client - ip > : < boot - server - ip > : < gw - ip > : < netmask >
* anaconda format : ip = < client - ip > netmask = < netmask > gateway = < gw - ip >
*/
static void parseCmdLineIp ( struct loaderData_s * loaderData , char * argv )
{
/* Detect pxelinux */
if ( strstr ( argv , " : " ) ! = NULL ) {
char * start , * end ;
/* IP */
start = argv + 3 ;
end = strstr ( start , " : " ) ;
loaderData - > ipv4 = strndup ( start , end - start ) ;
loaderData - > ipinfo_set = 1 ;
/* Boot server */
if ( end + 1 = = ' \0 ' )
return ;
start = end + 1 ;
end = strstr ( start , " : " ) ;
if ( end = = NULL )
return ;
/* Gateway */
if ( end + 1 = = ' \0 ' )
return ;
start = end + 1 ;
end = strstr ( start , " : " ) ;
if ( end = = NULL ) {
loaderData - > gateway = strdup ( start ) ;
return ;
} else {
loaderData - > gateway = strndup ( start , end - start ) ;
}
/* Netmask */
if ( end + 1 = = ' \0 ' )
return ;
start = end + 1 ;
loaderData - > netmask = strdup ( start ) ;
} else {
loaderData - > ipv4 = strdup ( argv + 3 ) ;
loaderData - > ipinfo_set = 1 ;
}
if ( loaderData - > ipinfo_set )
flags | = LOADER_FLAGS_IP_PARAM ;
}
# ifdef ENABLE_IPV6
/*
* parse anaconda ipv6 = arguments
*/
static void parseCmdLineIpv6 ( struct loaderData_s * loaderData , char * argv )
{
/* right now we only accept ipv6= arguments equal to:
* dhcp DHCPv6 call
* auto RFC 2461 neighbor discovery
*/
loaderData - > ipv6 = NULL ;
if ( ! strncmp ( str2lower ( argv ) , " ipv6=dhcp " , 9 ) ) {
loaderData - > ipv6 = strdup ( " dhcp " ) ;
} else if ( ! strncmp ( str2lower ( argv ) , " ipv6=auto " , 9 ) ) {
loaderData - > ipv6 = strdup ( " auto " ) ;
}
if ( loaderData - > ipv6 ! = NULL ) {
loaderData - > ipv6info_set = 1 ;
flags | = LOADER_FLAGS_IPV6_PARAM ;
}
return ;
}
# endif
static long argToLong ( char * arg , int offset ) {
long retval ;
errno = 0 ;
retval = strtol ( arg + offset , NULL , 10 ) ;
if ( ( errno = = ERANGE & & ( retval = = LONG_MIN | | retval = = LONG_MAX ) ) | |
( errno ! = 0 & & retval = = 0 ) ) {
logMessage ( ERROR , " %s: %d: %m " , __func__ , __LINE__ ) ;
abort ( ) ;
}
return retval ;
}
/* parses /proc/cmdline for any arguments which are important to us.
* NOTE : in test mode , can specify a cmdline with - - cmdline
*/
static void parseCmdLineFlags ( struct loaderData_s * loaderData ,
char * cmdLine ) {
int fd ;
char buf [ 1024 ] ;
int len ;
gint argc = 0 ;
gchar * * argv = NULL ;
GError * optErr = NULL ;
int numExtraArgs = 0 ;
int i ;
char * front ;
/* we want to default to graphical and allow override with 'text' */
flags | = LOADER_FLAGS_GRAPHICAL ;
/* if we have any explicit cmdline (probably test mode), we don't want
* to parse / proc / cmdline */
if ( ! cmdLine ) {
if ( ( fd = open ( " /proc/cmdline " , O_RDONLY ) ) < 0 ) return ;
len = read ( fd , buf , sizeof ( buf ) - 1 ) ;
close ( fd ) ;
if ( len < = 0 ) {
logMessage ( INFO , " kernel command line was empty " ) ;
return ;
}
buf [ len ] = ' \0 ' ;
cmdLine = buf ;
}
logMessage ( INFO , " kernel command line: %s " , cmdLine ) ;
if ( ! g_shell_parse_argv ( cmdLine , & argc , & argv , & optErr ) ) {
g_error_free ( optErr ) ;
return ;
}
for ( i = 0 ; i < argc ; i + + ) {
if ( ! strcasecmp ( argv [ i ] , " askmethod " ) )
flags | = LOADER_FLAGS_ASKMETHOD ;
else if ( ! strcasecmp ( argv [ i ] , " asknetwork " ) )
flags | = LOADER_FLAGS_ASKNETWORK ;
else if ( ! strcasecmp ( argv [ i ] , " noshell " ) )
flags | = LOADER_FLAGS_NOSHELL ;
else if ( ! strcasecmp ( argv [ i ] , " nokill " ) )
flags | = LOADER_FLAGS_NOKILL ;
else if ( ! strcasecmp ( argv [ i ] , " mediacheck " ) )
flags | = LOADER_FLAGS_MEDIACHECK ;
else if ( ! strcasecmp ( argv [ i ] , " allowwireless " ) )
flags | = LOADER_FLAGS_ALLOW_WIRELESS ;
else if ( ! strcasecmp ( argv [ i ] , " telnet " ) )
flags | = LOADER_FLAGS_TELNETD ;
else if ( ! strcasecmp ( argv [ i ] , " noprobe " ) )
flags | = LOADER_FLAGS_NOPROBE ;
else if ( ! strcasecmp ( argv [ i ] , " text " ) ) {
logMessage ( INFO , " text mode forced from cmdline " ) ;
flags | = LOADER_FLAGS_TEXT ;
flags & = ~ LOADER_FLAGS_GRAPHICAL ;
}
else if ( ! strcasecmp ( argv [ i ] , " graphical " ) ) {
logMessage ( INFO , " graphical mode forced from cmdline " ) ;
flags | = LOADER_FLAGS_GRAPHICAL ;
} else if ( ! strcasecmp ( argv [ i ] , " cmdline " ) ) {
logMessage ( INFO , " cmdline mode forced from cmdline " ) ;
flags | = LOADER_FLAGS_CMDLINE ;
} else if ( ! strncasecmp ( argv [ i ] , " updates= " , 8 ) )
loaderData - > updatessrc = strdup ( argv [ i ] + 8 ) ;
else if ( ! strncasecmp ( argv [ i ] , " updates " , 7 ) )
flags | = LOADER_FLAGS_UPDATES ;
else if ( ! strncasecmp ( argv [ i ] , " dogtail= " , 8 ) )
loaderData - > dogtailurl = strdup ( argv [ i ] + 8 ) ;
else if ( ! strncasecmp ( argv [ i ] , " dd= " , 3 ) | |
! strncasecmp ( argv [ i ] , " driverdisk= " , 11 ) ) {
loaderData - > ddsrc = strdup ( argv [ i ] +
( argv [ i ] [ 1 ] = = ' r ' ? 11 : 3 ) ) ;
}
else if ( ! strcasecmp ( argv [ i ] , " dd " ) | |
! strcasecmp ( argv [ i ] , " driverdisk " ) )
flags | = LOADER_FLAGS_MODDISK ;
else if ( ! strcasecmp ( argv [ i ] , " dlabel=on " ) )
flags | = LOADER_FLAGS_AUTOMODDISK ;
else if ( ! strcasecmp ( argv [ i ] , " dlabel=off " ) )
flags & = ~ LOADER_FLAGS_AUTOMODDISK ;
else if ( ! strcasecmp ( argv [ i ] , " rescue " ) )
flags | = LOADER_FLAGS_RESCUE ;
else if ( ! strcasecmp ( argv [ i ] , " nopass " ) )
flags | = LOADER_FLAGS_NOPASS ;
else if ( ! strcasecmp ( argv [ i ] , " serial " ) )
flags | = LOADER_FLAGS_SERIAL ;
else if ( ! strcasecmp ( argv [ i ] , " noipv4 " ) )
flags | = LOADER_FLAGS_NOIPV4 ;
# ifdef ENABLE_IPV6
else if ( ! strcasecmp ( argv [ i ] , " noipv6 " ) )
flags | = LOADER_FLAGS_NOIPV6 ;
# endif
else if ( ! strcasecmp ( argv [ i ] , " kssendmac " ) )
flags | = LOADER_FLAGS_KICKSTART_SEND_MAC ;
else if ( ! strcasecmp ( argv [ i ] , " kssendsn " ) )
flags | = LOADER_FLAGS_KICKSTART_SEND_SERIAL ;
/* deprecated hardware bits */
else if ( ! strcasecmp ( argv [ i ] , " nousbstorage " ) )
mlAddBlacklist ( " usb-storage " ) ;
else if ( ! strcasecmp ( argv [ i ] , " nousb " ) ) {
mlAddBlacklist ( " ehci-hcd " ) ;
mlAddBlacklist ( " ohci-hcd " ) ;
mlAddBlacklist ( " uhci-hcd " ) ;
} else if ( ! strcasecmp ( argv [ i ] , " nofirewire " ) )
mlAddBlacklist ( " firewire-ohci " ) ;
else if ( ! strncasecmp ( argv [ i ] , " loglevel= " , 9 ) ) {
if ( ! strcasecmp ( argv [ i ] + 9 , " debug " ) ) {
loaderData - > logLevel = strdup ( argv [ i ] + 9 ) ;
setLogLevel ( DEBUGLVL ) ;
}
else if ( ! strcasecmp ( argv [ i ] + 9 , " info " ) ) {
loaderData - > logLevel = strdup ( argv [ i ] + 9 ) ;
setLogLevel ( INFO ) ;
}
else if ( ! strcasecmp ( argv [ i ] + 9 , " warning " ) ) {
loaderData - > logLevel = strdup ( argv [ i ] + 9 ) ;
setLogLevel ( WARNING ) ;
}
else if ( ! strcasecmp ( argv [ i ] + 9 , " error " ) ) {
loaderData - > logLevel = strdup ( argv [ i ] + 9 ) ;
setLogLevel ( ERROR ) ;
}
else if ( ! strcasecmp ( argv [ i ] + 9 , " critical " ) ) {
loaderData - > logLevel = strdup ( argv [ i ] + 9 ) ;
setLogLevel ( CRITICAL ) ;
}
}
else if ( ! strncasecmp ( argv [ i ] , " ksdevice= " , 9 ) ) {
loaderData - > netDev = strdup ( argv [ i ] + 9 ) ;
loaderData - > netDev_set = 1 ;
}
else if ( ! strncmp ( argv [ i ] , " BOOTIF= " , 7 ) ) {
/* +10 so that we skip over the leading 01- */
loaderData - > bootIf = strdup ( argv [ i ] + 10 ) ;
/* scan the BOOTIF value and replace '-' with ':' */
front = loaderData - > bootIf ;
if ( front ) {
while ( * front ! = ' \0 ' ) {
if ( * front = = ' - ' )
* front = ' : ' ;
front + + ;
}
}
loaderData - > bootIf_set = 1 ;
} else if ( ! strncasecmp ( argv [ i ] , " dhcpclass= " , 10 ) ) {
loaderData - > netCls = strdup ( argv [ i ] + 10 ) ;
loaderData - > netCls_set = 1 ;
}
else if ( ! strcasecmp ( argv [ i ] , " ks " ) | | ! strncasecmp ( argv [ i ] , " ks= " , 3 ) )
loaderData - > ksFile = strdup ( argv [ i ] ) ;
else if ( ! strncasecmp ( argv [ i ] , " display= " , 8 ) )
setenv ( " DISPLAY " , argv [ i ] + 8 , 1 ) ;
else if ( ( ! strncasecmp ( argv [ i ] , " lang= " , 5 ) ) & &
( strlen ( argv [ i ] ) > 5 ) ) {
loaderData - > lang = strdup ( argv [ i ] + 5 ) ;
loaderData - > lang_set = 1 ;
}
else if ( ! strncasecmp ( argv [ i ] , " keymap= " , 7 ) & &
( strlen ( argv [ i ] ) > 7 ) ) {
loaderData - > kbd = strdup ( argv [ i ] + 7 ) ;
loaderData - > kbd_set = 1 ;
}
else if ( ! strncasecmp ( argv [ i ] , " method= " , 7 ) ) {
logMessage ( WARNING , " method= is deprecated. Please use repo= instead. " ) ;
loaderData - > instRepo = strdup ( argv [ i ] + 7 ) ;
}
else if ( ! strncasecmp ( argv [ i ] , " repo= " , 5 ) )
loaderData - > instRepo = strdup ( argv [ i ] + 5 ) ;
else if ( ! strncasecmp ( argv [ i ] , " stage2= " , 7 ) )
setStage2LocFromCmdline ( argv [ i ] + 7 , loaderData ) ;
else if ( ! strncasecmp ( argv [ i ] , " hostname= " , 9 ) )
loaderData - > hostname = strdup ( argv [ i ] + 9 ) ;
else if ( ! strncasecmp ( argv [ i ] , " ip= " , 3 ) )
parseCmdLineIp ( loaderData , argv [ i ] ) ;
# ifdef ENABLE_IPV6
else if ( ! strncasecmp ( argv [ i ] , " ipv6= " , 5 ) )
parseCmdLineIpv6 ( loaderData , argv [ i ] ) ;
# endif
else if ( ! strncasecmp ( argv [ i ] , " netmask= " , 8 ) )
loaderData - > netmask = strdup ( argv [ i ] + 8 ) ;
else if ( ! strncasecmp ( argv [ i ] , " gateway= " , 8 ) )
loaderData - > gateway = strdup ( argv [ i ] + 8 ) ;
else if ( ! strncasecmp ( argv [ i ] , " dns= " , 4 ) )
loaderData - > dns = strdup ( argv [ i ] + 4 ) ;
else if ( ! strncasecmp ( argv [ i ] , " ethtool= " , 8 ) )
loaderData - > ethtool = strdup ( argv [ i ] + 8 ) ;
else if ( ! strncasecmp ( argv [ i ] , " essid= " , 6 ) )
loaderData - > essid = strdup ( argv [ i ] + 6 ) ;
else if ( ! strncasecmp ( argv [ i ] , " mtu= " , 4 ) )
loaderData - > mtu = argToLong ( argv [ i ] , 4 ) ;
else if ( ! strncasecmp ( argv [ i ] , " wepkey= " , 7 ) )
loaderData - > wepkey = strdup ( argv [ i ] + 7 ) ;
else if ( ! strncasecmp ( argv [ i ] , " linksleep= " , 10 ) )
num_link_checks = argToLong ( argv [ i ] , 10 ) ;
else if ( ! strncasecmp ( argv [ i ] , " nicdelay= " , 9 ) )
post_link_sleep = argToLong ( argv [ i ] , 9 ) ;
else if ( ! strncasecmp ( argv [ i ] , " dhcptimeout= " , 12 ) )
loaderData - > dhcpTimeout = argToLong ( argv [ i ] , 12 ) ;
else if ( ! strncasecmp ( argv [ i ] , " selinux=0 " , 9 ) )
flags & = ~ LOADER_FLAGS_SELINUX ;
else if ( ! strncasecmp ( argv [ i ] , " selinux " , 7 ) )
flags | = LOADER_FLAGS_SELINUX ;
else if ( ! strncasecmp ( argv [ i ] , " gdb= " , 4 ) )
loaderData - > gdbServer = strdup ( argv [ i ] + 4 ) ;
else if ( ! strncasecmp ( argv [ i ] , " proxy= " , 6 ) )
splitProxyParam ( argv [ i ] + 6 , & loaderData - > proxyUser ,
& loaderData - > proxyPassword , & loaderData - > proxy ) ;
else if ( numExtraArgs < ( MAX_EXTRA_ARGS - 1 ) ) {
/* go through and append args we just want to pass on to */
/* the anaconda script, but don't want to represent as a */
/* LOADER_FLAGS_XXX since loader doesn't care about these */
/* particular options. */
/* do vncpassword case first */
if ( ! strncasecmp ( argv [ i ] , " vncpassword= " , 12 ) ) {
writeVNCPasswordFile ( " /tmp/vncpassword.dat " , argv [ i ] + 12 ) ;
}
else if ( ! strncasecmp ( argv [ i ] , " resolution= " , 11 ) | |
! strncasecmp ( argv [ i ] , " nomount " , 7 ) | |
! strncasecmp ( argv [ i ] , " vnc " , 3 ) | |
! strncasecmp ( argv [ i ] , " vncconnect= " , 11 ) | |
! strncasecmp ( argv [ i ] , " headless " , 8 ) | |
! strncasecmp ( argv [ i ] , " usefbx " , 6 ) | |
! strncasecmp ( argv [ i ] , " mpath " , 6 ) | |
! strncasecmp ( argv [ i ] , " nompath " , 8 ) | |
! strncasecmp ( argv [ i ] , " dmraid " , 6 ) | |
! strncasecmp ( argv [ i ] , " nodmraid " , 8 ) | |
! strncasecmp ( argv [ i ] , " xdriver= " , 8 ) | |
! strncasecmp ( argv [ i ] , " vesa " , 4 ) | |
! strncasecmp ( argv [ i ] , " syslog= " , 7 ) ) {
/* vnc implies graphical */
if ( ! strncasecmp ( argv [ i ] , " vnc " , 3 ) ) {
logMessage ( INFO , " vnc forced graphical mode from cmdline " ) ;
flags | = LOADER_FLAGS_GRAPHICAL ;
}
/* the following things require networking to be configured
* by loader , so an active connection is ready once we get
* to anaconda
*/
if ( ! strncasecmp ( argv [ i ] , " syslog " , 6 ) | |
! strncasecmp ( argv [ i ] , " vnc " , 3 ) | |
isKickstartFileRemote ( loaderData - > ksFile ) ) {
logMessage ( INFO , " early networking required for %s " ,
argv [ i ] ) ;
flags | = LOADER_FLAGS_EARLY_NETWORKING ;
}
if ( ! strncasecmp ( argv [ i ] , " vesa " , 4 ) ) {
checked_asprintf ( & extraArgs [ numExtraArgs ] ,
" --xdriver=vesa " ) ;
logMessage ( WARNING , " \" vesa \" command line argument is deprecated. use \" xdriver=vesa \" . " ) ;
} else {
checked_asprintf ( & extraArgs [ numExtraArgs ] , " --%s " ,
argv [ i ] ) ;
}
numExtraArgs + = 1 ;
if ( numExtraArgs > ( MAX_EXTRA_ARGS - 2 ) ) {
logMessage ( WARNING , " Too many command line arguments (max "
" allowed is %d), rest will be dropped. " ,
MAX_EXTRA_ARGS ) ;
}
}
}
}
readNetInfo ( & loaderData ) ;
/* NULL terminates the array of extra args */
extraArgs [ numExtraArgs ] = NULL ;
return ;
}
/* make sure they have enough ram */
static void checkForRam ( void ) {
if ( totalMemory ( ) < MIN_RAM ) {
char * buf ;
checked_asprintf ( & buf , _ ( " You do not have enough RAM to install %s "
" on this machine. " ) , getProductName ( ) ) ;
startNewt ( ) ;
newtWinMessage ( _ ( " Error " ) , _ ( " OK " ) , buf ) ;
free ( buf ) ;
stopNewt ( ) ;
doExit ( 0 ) ;
}
}
static int haveDeviceOfType ( int type ) {
struct device * * devices ;
devices = getDevices ( type ) ;
if ( devices ) {
return 1 ;
}
return 0 ;
}
static char * doLoaderMain ( struct loaderData_s * loaderData ,
moduleInfoSet modInfo ) {
enum { STEP_LANG , STEP_KBD , STEP_METHOD , STEP_DRIVER ,
STEP_DRIVERDISK , STEP_NETWORK , STEP_IFACE ,
STEP_IP , STEP_STAGE2 , STEP_DONE } step ;
char * url = NULL , * ret = NULL , * devName = NULL , * kbdtype = NULL ;
static iface_t iface ;
int i , rc = LOADER_NOOP , dir = 1 ;
int needsNetwork = 0 , class = - 1 ;
int skipMethodDialog = 0 , skipLangKbd = 0 ;
char * installNames [ 10 ] ;
int numValidMethods = 0 ;
int validMethods [ 10 ] ;
for ( i = 0 ; i < numMethods ; i + + , numValidMethods + + ) {
installNames [ numValidMethods ] = installMethods [ i ] . name ;
validMethods [ numValidMethods ] = i ;
}
installNames [ numValidMethods ] = NULL ;
/* Before anything else, see if there's a CD/DVD with a stage2 image on
* it . However if stage2 = was given , use that value as an override here .
* That will also then bypass any method selection UI in loader .
*/
if ( ! FL_ASKMETHOD ( flags ) ) {
url = findAnacondaCD ( " /mnt/stage2 " ) ;
if ( url ) {
setStage2LocFromCmdline ( url , loaderData ) ;
skipMethodDialog = 1 ;
logMessage ( INFO , " Detected stage 2 image on CD (url: %s) " , url ) ;
winStatus ( 50 , 3 , _ ( " Media Detected " ) ,
_ ( " Found local installation media " ) , 0 ) ;
sleep ( 3 ) ;
newtPopWindow ( ) ;
skipLangKbd = 1 ;
flags | = LOADER_FLAGS_NOPASS ;
} else if ( ! loaderData - > stage2Data & & loaderData - > instRepo ) {
/* If no CD/DVD with a stage2 image was found and we were given a
* repo = / method = parameter , try to piece together a valid setting
* for the stage2 = parameter based on that .
*/
char * tmp ;
checked_asprintf ( & tmp , " %s/images/install.img " ,
loaderData - > instRepo ) ;
logMessage ( INFO , " no stage2= given, assuming %s " , tmp ) ;
setStage2LocFromCmdline ( tmp , loaderData ) ;
free ( tmp ) ;
/* If we had to infer a stage2= location, but the repo= parameter
* we based this guess on was wrong , we need to correct the typo
* in both places . Unfortunately we can ' t really know what the
* user meant , so the best we can do is take the results of
* running stage2 = through the UI and chop off any / images / whatever
* path that ' s at the end of it .
*/
loaderData - > inferredStage2 = 1 ;
skipMethodDialog = 1 ;
} else if ( loaderData - > stage2Data ) {
skipMethodDialog = 1 ;
}
} else {
/* Needed because they have already been set when parsing cmdline.
* ( Leaks a little . )
*/
loaderData - > method = - 1 ;
loaderData - > stage2Data = NULL ;
}
i = 0 ;
step = STEP_LANG ;
while ( step ! = STEP_DONE ) {
switch ( step ) {
case STEP_LANG : {
if ( loaderData - > lang & & ( loaderData - > lang_set = = 1 ) )
setLanguage ( loaderData - > lang , 1 ) ;
else if ( FL_RESCUE ( flags ) | | ! skipLangKbd )
chooseLanguage ( & loaderData - > lang ) ;
step = STEP_KBD ;
dir = 1 ;
break ;
}
case STEP_KBD : {
if ( loaderData - > kbd & & ( loaderData - > kbd_set = = 1 ) ) {
/* JKFIXME: this is broken -- we should tell of the
* failure ; best by pulling code out in kbd . c to use */
if ( isysLoadKeymap ( loaderData - > kbd ) ) {
logMessage ( WARNING , " requested keymap %s is not valid, asking " ,
loaderData - > kbd ) ;
loaderData - > kbd = NULL ;
loaderData - > kbd_set = 0 ;
break ;
}
rc = LOADER_NOOP ;
} else if ( FL_RESCUE ( flags ) | | ! skipLangKbd ) {
/* JKFIXME: should handle kbdtype, too probably... but it
* just matters for sparc */
if ( ! FL_CMDLINE ( flags ) )
rc = chooseKeyboard ( loaderData , & kbdtype ) ;
else
rc = LOADER_NOOP ;
} else {
step = STEP_METHOD ;
dir = 1 ;
}
if ( rc = = LOADER_NOOP ) {
if ( dir = = - 1 )
step = STEP_LANG ;
else
step = STEP_METHOD ;
break ;
}
if ( rc = = LOADER_BACK ) {
step = STEP_LANG ;
dir = - 1 ;
} else {
step = STEP_METHOD ;
dir = 1 ;
}
break ;
}
case STEP_METHOD : {
if ( loaderData - > method ! = - 1 )
skipMethodDialog = 1 ;
else if ( FL_CMDLINE ( flags ) ) {
fprintf ( stderr , " No method given for cmdline mode, aborting \n " ) ;
doExit ( EXIT_FAILURE ) ;
}
/* If we already found a stage2 image, skip the prompt. */
if ( skipMethodDialog ) {
if ( dir = = 1 )
rc = 1 ;
else
rc = - 1 ;
} else {
/* we need to set these each time through so that we get
* updated for language changes ( # 83672 ) */
for ( i = 0 ; i < numMethods ; i + + ) {
installNames [ i ] = _ ( installMethods [ i ] . name ) ;
}
installNames [ i ] = NULL ;
rc = newtWinMenu ( FL_RESCUE ( flags ) ? _ ( " Rescue Method " ) :
_ ( " Installation Method " ) ,
FL_RESCUE ( flags ) ?
_ ( " What type of media contains the rescue "
" image? " ) :
_ ( " What type of media contains the installation "
" image? " ) ,
30 , 10 , 20 , 6 , installNames , & loaderData - > method ,
_ ( " OK " ) , _ ( " Back " ) , NULL ) ;
if ( rc = = 2 ) {
loaderData - > method = - 1 ;
}
}
if ( rc & & ( rc ! = 1 ) ) {
step = STEP_KBD ;
dir = - 1 ;
} else {
class = installMethods [ validMethods [ loaderData - > method ] ] . type ;
step = STEP_DRIVER ;
dir = 1 ;
}
break ;
}
case STEP_DRIVER : {
if ( ( FL_EARLY_NETWORKING ( flags ) & & haveDeviceOfType ( DEVICE_NETWORK ) ) | |
( class = = - 1 | | haveDeviceOfType ( class ) ) ) {
step = STEP_NETWORK ;
dir = 1 ;
class = - 1 ;
break ;
}
if ( skipLangKbd ) {
skipLangKbd = 0 ;
step = STEP_KBD ;
break ;
}
rc = newtWinTernary ( _ ( " No driver found " ) , _ ( " Select driver " ) ,
_ ( " Use a driver disk " ) , _ ( " Back " ) ,
_ ( " Unable to find any devices of the type "
" needed for this installation type. "
" Would you like to manually select your "
" driver or use a driver disk? " ) ) ;
if ( rc = = 2 ) {
step = STEP_DRIVERDISK ;
dir = 1 ;
break ;
} else if ( rc = = 3 ) {
step = STEP_METHOD ;
loaderData - > method = - 1 ;
dir = - 1 ;
break ;
}
chooseManualDriver ( installMethods [ validMethods [ loaderData - > method ] ] . type ,
loaderData ) ;
/* it doesn't really matter what we return here; we just want
* to reprobe and make sure we have the driver */
step = STEP_DRIVER ;
break ;
}
case STEP_DRIVERDISK : {
if ( skipLangKbd ) {
skipLangKbd = 0 ;
step = STEP_KBD ;
break ;
}
rc = loadDriverFromMedia ( class , loaderData , 0 , 0 ) ;
if ( rc = = LOADER_BACK ) {
step = STEP_DRIVER ;
dir = - 1 ;
break ;
}
/* need to come back to driver so that we can ensure that we found
* the right kind of driver after loading the driver disk */
step = STEP_DRIVER ;
break ;
}
case STEP_NETWORK : {
if ( ( ( installMethods [ validMethods [ loaderData - > method ] ] . type ! =
DEVICE_NETWORK ) & & ( ! hasGraphicalOverride ( ) ) & &
! FL_ASKNETWORK ( flags ) & &
! FL_EARLY_NETWORKING ( flags ) ) | |
( is_nm_connected ( ) ) ) {
needsNetwork = 0 ;
if ( dir = = 1 )
step = STEP_STAGE2 ;
else if ( dir = = - 1 )
step = STEP_METHOD ;
break ;
}
needsNetwork = 1 ;
if ( ! haveDeviceOfType ( DEVICE_NETWORK ) ) {
class = DEVICE_NETWORK ;
step = STEP_DRIVER ;
break ;
}
logMessage ( INFO , " need to set up networking " ) ;
memset ( & iface , 0 , sizeof ( iface ) ) ;
/* fall through to interface selection */
}
case STEP_IFACE : {
logMessage ( INFO , " going to pick interface " ) ;
/* skip configureTCPIP() screen for kickstart (#260621) */
if ( loaderData - > ksFile )
flags | = LOADER_FLAGS_IS_KICKSTART ;
if ( FL_HAVE_CMSCONF ( flags ) ) {
loaderData - > ipinfo_set = 1 ;
# ifdef ENABLE_IPV6
loaderData - > ipv6info_set = 1 ;
# endif
}
rc = chooseNetworkInterface ( loaderData ) ;
if ( ( rc = = LOADER_BACK ) | | ( rc = = LOADER_ERROR ) | |
( ( dir = = - 1 ) & & ( rc = = LOADER_NOOP ) ) ) {
/* don't skip method dialog iff we don't have url from ks or boot params */
if ( ! loaderData - > stage2Data ) {
loaderData - > method = - 1 ;
}
step = STEP_METHOD ;
dir = - 1 ;
break ;
}
devName = loaderData - > netDev ;
strcpy ( iface . device , devName ) ;
/* continue to ip config */
step = STEP_IP ;
dir = 1 ;
break ;
}
case STEP_IP : {
if ( ! needsNetwork | | dir = = - 1 ) {
step = STEP_METHOD ; /* only hit going back */
break ;
}
if ( ( ret = malloc ( INET6_ADDRSTRLEN + 1 ) ) = = NULL ) {
logMessage ( ERROR , " malloc failure for ret in STEP_IP " ) ;
doExit ( EXIT_FAILURE ) ;
}
logMessage ( INFO , " going to do getNetConfig " ) ;
/* s390 provides all config info by way of the CMS conf file */
if ( FL_HAVE_CMSCONF ( flags ) ) {
loaderData - > ipinfo_set = 1 ;
# ifdef ENABLE_IPV6
loaderData - > ipv6info_set = 1 ;
# endif
}
/* populate netDev based on any kickstart data */
setupIfaceStruct ( & iface , loaderData ) ;
rc = readNetConfig ( devName , & iface , loaderData - > netCls , loaderData - > method ) ;
/* set the hostname if we have that */
if ( loaderData - > hostname ) {
if ( sethostname ( loaderData - > hostname ,
strlen ( loaderData - > hostname ) ) ) {
logMessage ( ERROR , " error setting hostname to %s " ,
loaderData - > hostname ) ;
}
}
free ( ret ) ;
ret = NULL ;
if ( ( rc = = LOADER_BACK ) | |
( ( dir = = - 1 ) & & ( rc = = LOADER_NOOP ) ) ) {
needsNetwork = 1 ;
step = STEP_IFACE ;
dir = - 1 ;
break ;
}
/* retry */
if ( rc = = LOADER_ERROR ) {
needsNetwork = 1 ;
break ;
}
writeEnabledNetInfo ( & iface ) ;
step = STEP_STAGE2 ;
dir = 1 ;
break ;
}
case STEP_STAGE2 : {
if ( url ) {
logMessage ( INFO , " stage2 url is %s " , url ) ;
return url ;
}
logMessage ( INFO , " starting STEP_STAGE2 " ) ;
url = installMethods [ validMethods [ loaderData - > method ] ] . mountImage (
installMethods + validMethods [ loaderData - > method ] ,
" /mnt/stage2 " , loaderData ) ;
if ( ! url ) {
step = STEP_IP ;
loaderData - > ipinfo_set = 0 ;
# ifdef ENABLE_IPV6
loaderData - > ipv6info_set = 0 ;
# endif
loaderData - > method = - 1 ;
skipMethodDialog = 0 ;
dir = - 1 ;
} else {
logMessage ( INFO , " got stage2 at url %s " , url ) ;
step = STEP_DONE ;
dir = 1 ;
if ( loaderData - > invalidRepoParam ) {
char * newInstRepo ;
/* Doesn't contain /images? Let's not even try. */
if ( strstr ( url , " /images " ) = = NULL )
break ;
checked_asprintf ( & newInstRepo , " %.*s " ,
( int ) ( strstr ( url , " /images " ) - url ) , url ) ;
free ( loaderData - > instRepo ) ;
loaderData - > instRepo = newInstRepo ;
logMessage ( INFO , " reset repo= parameter to %s " ,
loaderData - > instRepo ) ;
}
}
break ;
}
case STEP_DONE :
break ;
}
}
return url ;
}
static int manualDeviceCheck ( struct loaderData_s * loaderData ) {
char * * devices ;
int i , j , rc , num = 0 ;
unsigned int width = 40 ;
char * buf ;
do {
/* FIXME */
devices = malloc ( 1 * sizeof ( * devices ) ) ;
j = 0 ;
devices [ j ] = NULL ;
if ( width > 70 )
width = 70 ;
if ( j > 0 ) {
buf = _ ( " The following devices have been found on your system. " ) ;
} else {
buf = _ ( " No device drivers have been loaded for your system. "
" Would you like to load any now? " ) ;
}
rc = newtWinMenu ( _ ( " Devices " ) , buf , width , 10 , 20 ,
( j > 6 ) ? 6 : j , devices , & num , _ ( " Done " ) ,
_ ( " Add Device " ) , NULL ) ;
/* no leaky */
for ( i = 0 ; i < j ; i + + )
free ( devices [ j ] ) ;
free ( devices ) ;
if ( rc ! = 2 )
break ;
chooseManualDriver ( DEVICE_ANY , loaderData ) ;
} while ( 1 ) ;
return 0 ;
}
/* JKFIXME: I don't really like this, but at least it isolates the ifdefs */
/* Either move dirname to %s_old or unlink depending on arch (unlink on all
* ! s390 { , x } arches ) . symlink to / mnt / runtime / dirname . dirname * MUST * start
* with a ' / ' */
static void migrate_runtime_directory ( char * dirname ) {
char * runtimedir ;
2011-07-02 13:05:18 +00:00
int ret ;
2011-01-18 09:24:57 +00:00
checked_asprintf ( & runtimedir , " /mnt/runtime%s " , dirname ) ;
if ( ! access ( runtimedir , X_OK ) ) {
if ( unlink ( dirname ) = = - 1 ) {
char * olddir ;
checked_asprintf ( & olddir , " %s_old " , dirname ) ;
2011-07-02 13:05:18 +00:00
ret = rename ( dirname , olddir ) ;
2011-01-18 09:24:57 +00:00
free ( olddir ) ;
}
2011-07-02 13:05:18 +00:00
ret = symlink ( runtimedir , dirname ) ;
2011-01-18 09:24:57 +00:00
}
free ( runtimedir ) ;
}
static int hasGraphicalOverride ( ) {
int i ;
if ( getenv ( " DISPLAY " ) )
return 1 ;
for ( i = 0 ; extraArgs [ i ] ! = NULL ; i + + ) {
if ( ! strncasecmp ( extraArgs [ i ] , " --vnc " , 5 ) )
return 1 ;
}
return 0 ;
}
void loaderSegvHandler ( int signum ) {
void * array [ 30 ] ;
size_t i ;
const char const * const errmsgs [ ] = {
" loader received SIG " ,
" ! Backtrace: \n " ,
" Loader exited unexpectedly! Backtrace: \n " ,
} ;
/* XXX This should really be in a glibc header somewhere... */
extern const char * const sys_sigabbrev [ NSIG ] ;
signal ( signum , SIG_DFL ) ; /* back to default */
newtFinished ( ) ;
if ( signum = = 0 ) {
i = write ( STDERR_FILENO , errmsgs [ 2 ] , strlen ( errmsgs [ 2 ] ) ) ;
} else {
i = write ( STDERR_FILENO , errmsgs [ 0 ] , strlen ( errmsgs [ 0 ] ) ) ;
i = write ( STDERR_FILENO , sys_sigabbrev [ signum ] ,
strlen ( sys_sigabbrev [ signum ] ) ) ;
i = write ( STDERR_FILENO , errmsgs [ 1 ] , strlen ( errmsgs [ 1 ] ) ) ;
}
i = backtrace ( array , 30 ) ;
backtrace_symbols_fd ( array , i , STDERR_FILENO ) ;
_exit ( 1 ) ;
}
void loaderExitHandler ( void )
{
if ( expected_exit )
return ;
loaderSegvHandler ( 0 ) ;
}
static void setupBacktrace ( void )
{
void * array ;
signal ( SIGSEGV , loaderSegvHandler ) ;
signal ( SIGABRT , loaderSegvHandler ) ;
atexit ( loaderExitHandler ) ;
/* Turns out, there's an initializer at the top of backtrace() that
* ( on some arches ) calls dlopen ( ) . dlopen ( ) , unsurprisingly , calls
* malloc ( ) . So , call backtrace ( ) early in signal handler setup so
* we can later safely call it from the signal handler itself . */
backtrace ( & array , 1 ) ;
}
void loaderUsrXHandler ( int signum ) {
logMessage ( INFO , " Remembering signal %d \n " , signum ) ;
init_sig = signum ;
}
static int anaconda_trace_init ( void ) {
# ifdef USE_MTRACE
setenv ( " MALLOC_TRACE " , " /malloc " , 1 ) ;
mtrace ( ) ;
# endif
/* We have to do this before we init bogl(), which doLoaderMain will do
* when setting fonts for different languages . It ' s also best if this
* is well before we might take a SEGV , so they ' ll go to tty8 */
initializeTtys ( ) ;
/* set up signal handler */
setupBacktrace ( ) ;
return 0 ;
}
static void add_to_path_env ( const char * env , const char * val )
{
char * oldenv , * newenv ;
oldenv = getenv ( env ) ;
if ( oldenv ) {
checked_asprintf ( & newenv , " %s:%s " , val , oldenv ) ;
oldenv = strdupa ( newenv ) ;
free ( newenv ) ;
newenv = oldenv ;
} else {
newenv = strdupa ( val ) ;
}
setenv ( env , newenv , 1 ) ;
}
static void loadScsiDhModules ( void )
{
struct utsname utsname ;
char * modules = NULL ;
char * tmp = NULL ;
struct dirent * ent = NULL ;
uname ( & utsname ) ;
checked_asprintf ( & tmp ,
" /lib/modules/%s/kernel/drivers/scsi/device_handler " , utsname . release ) ;
DIR * dir = opendir ( tmp ) ;
free ( tmp ) ;
if ( ! dir )
return ;
int fd = dirfd ( dir ) ;
while ( ( ent = readdir ( dir ) ) ! = NULL ) {
struct stat sb ;
if ( fstatat ( fd , ent - > d_name , & sb , 0 ) < 0 )
continue ;
size_t len = strlen ( ent - > d_name ) - 3 ;
if ( strcmp ( ent - > d_name + len , " .ko " ) )
continue ;
if ( S_ISREG ( sb . st_mode ) ) {
char modname [ len + 1 ] ;
strncpy ( modname , ent - > d_name , len ) ;
modname [ len ] = ' \0 ' ;
if ( modules & & modules [ 0 ] ) {
checked_asprintf ( & tmp , " %s:%s " , modules , modname ) ;
} else {
checked_asprintf ( & tmp , " %s " , modname ) ;
}
free ( modules ) ;
modules = tmp ;
}
}
closedir ( dir ) ;
mlLoadModuleSet ( modules ) ;
free ( modules ) ;
}
int main ( int argc , char * * argv ) {
2011-07-02 13:05:18 +00:00
int rc , ret , pid , status ;
2011-01-18 09:24:57 +00:00
struct stat sb ;
struct serial_struct si ;
char * arg ;
FILE * f ;
char twelve = 12 ;
moduleInfoSet modInfo ;
char * url = NULL ;
char * * argptr , * * tmparg ;
char * anacondaArgs [ 50 ] ;
struct loaderData_s loaderData ;
char * path , * fmt ;
GSList * dd , * dditer ;
gchar * cmdLine = NULL , * ksFile = NULL , * virtpcon = NULL ;
gboolean mediacheck = FALSE ;
gchar * * remaining = NULL ;
GOptionContext * optCon = g_option_context_new ( NULL ) ;
GError * optErr = NULL ;
GOptionEntry optionTable [ ] = {
{ " cmdline " , 0 , 0 , G_OPTION_ARG_STRING , & cmdLine , NULL , NULL } ,
{ " ksfile " , 0 , 0 , G_OPTION_ARG_STRING , & ksFile , NULL , NULL } ,
{ " mediacheck " , 0 , 0 , G_OPTION_ARG_NONE , & mediacheck , NULL , NULL } ,
{ " virtpconsole " , 0 , 0 , G_OPTION_ARG_STRING , & virtpcon , NULL , NULL } ,
{ G_OPTION_REMAINING , 0 , 0 , G_OPTION_ARG_STRING_ARRAY , & remaining ,
NULL , NULL } ,
{ NULL } ,
} ;
/* get init PID if we have it */
if ( ( f = fopen ( " /var/run/init.pid " , " r " ) ) ! = NULL ) {
char linebuf [ 256 ] ;
while ( fgets ( linebuf , sizeof ( linebuf ) , f ) ! = NULL ) {
errno = 0 ;
init_pid = strtol ( linebuf , NULL , 10 ) ;
if ( errno = = EINVAL | | errno = = ERANGE ) {
logMessage ( ERROR , " %s (%d): %m " , __func__ , __LINE__ ) ;
init_pid = 1 ;
}
}
fclose ( f ) ;
}
signal ( SIGUSR1 , loaderUsrXHandler ) ;
signal ( SIGUSR2 , loaderUsrXHandler ) ;
/* Make sure sort order is right. */
setenv ( " LC_COLLATE " , " C " , 1 ) ;
/* Very first thing, set up tracebacks and debug features. */
rc = anaconda_trace_init ( ) ;
/* now we parse command line options */
g_option_context_set_help_enabled ( optCon , FALSE ) ;
g_option_context_add_main_entries ( optCon , optionTable , NULL ) ;
if ( ! g_option_context_parse ( optCon , & argc , & argv , & optErr ) ) {
fprintf ( stderr , " bad option: %s \n " , optErr - > message ) ;
g_error_free ( optErr ) ;
g_option_context_free ( optCon ) ;
doExit ( 1 ) ;
}
g_option_context_free ( optCon ) ;
if ( remaining ) {
fprintf ( stderr , " unexpected argument: %s \n " , remaining [ 0 ] ) ;
g_strfreev ( remaining ) ;
doExit ( 1 ) ;
}
g_strfreev ( remaining ) ;
if ( ! access ( " /var/run/loader.run " , R_OK ) ) {
printf ( _ ( " loader has already been run. Starting shell. \n " ) ) ;
execl ( " /bin/sh " , " -/bin/sh " , NULL ) ;
doExit ( 0 ) ;
}
f = fopen ( " /var/run/loader.run " , " w+ " ) ;
fprintf ( f , " %d \n " , getpid ( ) ) ;
fclose ( f ) ;
/* The fstat checks disallows serial console if we're running through
a pty . This is handy for Japanese . */
fstat ( 0 , & sb ) ;
if ( major ( sb . st_rdev ) ! = 3 & & major ( sb . st_rdev ) ! = 136 & &
( virtpcon = = NULL ) ) {
if ( ( ioctl ( 0 , TIOCLINUX , & twelve ) < 0 ) & &
( ioctl ( 0 , TIOCGSERIAL , & si ) ! = - 1 ) )
flags | = LOADER_FLAGS_SERIAL ;
}
if ( mediacheck ) flags | = LOADER_FLAGS_MEDIACHECK ;
if ( ksFile ) flags | = LOADER_FLAGS_KICKSTART ;
if ( virtpcon ) flags | = LOADER_FLAGS_VIRTPCONSOLE ;
/* uncomment to send mac address in ks=http:/ header by default*/
flags | = LOADER_FLAGS_KICKSTART_SEND_MAC ;
/* JKFIXME: I do NOT like this... it also looks kind of bogus */
# if defined(__s390__) || defined(__s390x__)
flags | = LOADER_FLAGS_NOSHELL ;
# endif
openLog ( ) ;
/* XXX if RHEL, enable the AUTODD feature by default,
* but we should come with more general way how to control this */
if ( ! strncmp ( getProductName ( ) , " Red Hat " , 7 ) ) {
flags | = LOADER_FLAGS_AUTOMODDISK ;
}
memset ( & loaderData , 0 , sizeof ( loaderData ) ) ;
loaderData . method = - 1 ;
loaderData . fw_loader_pid = - 1 ;
loaderData . fw_search_pathz_len = - 1 ;
loaderData . dhcpTimeout = - 1 ;
extraArgs [ 0 ] = NULL ;
parseCmdLineFlags ( & loaderData , cmdLine ) ;
logMessage ( INFO , " anaconda version %s on %s starting " , VERSION , getProductArch ( ) ) ;
if ( ( FL_SERIAL ( flags ) | | FL_VIRTPCONSOLE ( flags ) ) & &
! hasGraphicalOverride ( ) ) {
logMessage ( INFO , " text mode forced due to serial/virtpconsole " ) ;
flags | = LOADER_FLAGS_TEXT ;
}
set_fw_search_path ( & loaderData , " /firmware:/lib/firmware " ) ;
start_fw_loader ( & loaderData ) ;
arg = " /lib/modules/module-info " ;
modInfo = newModuleInfoSet ( ) ;
if ( readModuleInfo ( arg , modInfo , NULL , 0 ) ) {
fprintf ( stderr , " failed to read %s \n " , arg ) ;
sleep ( 5 ) ;
stop_fw_loader ( & loaderData ) ;
doExit ( 1 ) ;
}
initializeConsole ( ) ;
checkForRam ( ) ;
/* iSeries vio console users will be ssh'ing in to the primary
partition , so use a terminal type that is appripriate */
if ( isVioConsole ( ) )
setenv ( " TERM " , " vt100 " , 1 ) ;
mlLoadModuleSet ( " cramfs:squashfs:iscsi_tcp " ) ;
loadScsiDhModules ( ) ;
# if !defined(__s390__) && !defined(__s390x__)
mlLoadModuleSet ( " floppy:edd:pcspkr:iscsi_ibft " ) ;
# endif
# ifdef ENABLE_IPV6
if ( ! FL_NOIPV6 ( flags ) )
mlLoadModule ( " ipv6 " , NULL ) ;
# endif
/* now let's do some initial hardware-type setup */
dasdSetup ( ) ;
# if defined(__powerpc__)
mlLoadModule ( " spufs " , NULL ) ;
# endif
if ( loaderData . lang & & ( loaderData . lang_set = = 1 ) ) {
setLanguage ( loaderData . lang , 1 ) ;
}
/* FIXME: this is a bit of a hack */
loaderData . modInfo = modInfo ;
/* Setup depmod & modprobe so we can load multiple DDs */
modprobeDDmode ( ) ;
/* If there is /.rundepmod file present, rerun depmod */
if ( ! access ( " /.rundepmod " , R_OK ) ) {
if ( system ( " depmod -a " ) ) {
/* this is not really fatal error, it might still work, log it */
logMessage ( ERROR , " Error running depmod -a for initrd overlay " ) ;
}
}
if ( FL_AUTOMODDISK ( flags ) ) {
/* Load all autodetected DDs */
logMessage ( INFO , " Trying to detect vendor driver discs " ) ;
dd = findDriverDiskByLabel ( ) ;
dditer = dd ;
while ( dditer ) {
/* load the DD */
if ( loadDriverDiskFromPartition ( & loaderData , ( char * ) ( dditer - > data ) ) ) {
logMessage ( ERROR , " Automatic driver disk loader failed for %s. " , ( char * ) ( dditer - > data ) ) ;
}
else {
logMessage ( INFO , " Automatic driver disk loader succeeded for %s. " , ( char * ) ( dditer - > data ) ) ;
}
/* clean the device record */
free ( ( char * ) ( dditer - > data ) ) ;
dditer - > data = NULL ;
/* next DD */
dditer = g_slist_next ( dditer ) ;
}
g_slist_free ( dd ) ;
}
if ( FL_MODDISK ( flags ) ) {
startNewt ( ) ;
loadDriverDisks ( DEVICE_ANY , & loaderData ) ;
}
if ( ! access ( " /dd.img " , R_OK ) ) {
logMessage ( INFO , " found /dd.img, loading drivers " ) ;
getDDFromSource ( & loaderData , " path:/dd.img " ) ;
}
/* Reset depmod & modprobe to normal mode and get the rest of drivers*/
modprobeNormalmode ( ) ;
/* this allows us to do an early load of modules specified on the
* command line to allow automating the load order of modules so that
* eg , certain scsi controllers are definitely first .
* FIXME : this syntax is likely to change in a future release
* but is done as a quick hack for the present .
*/
if ( ! mlInitModuleConfig ( ) ) {
logMessage ( ERROR , " unable to initialize kernel module loading " ) ;
abort ( ) ;
}
earlyModuleLoad ( 0 ) ;
busProbe ( FL_NOPROBE ( flags ) ) ;
/* Disable all network interfaces in NetworkManager by default */
# if !defined(__s390__) && !defined(__s390x__)
int i ;
if ( ( i = writeDisabledNetInfo ( ) ) ! = 0 ) {
logMessage ( ERROR , " writeDisabledNetInfo failure: %d " , i ) ;
}
# endif
/* Start NetworkManager now so it's always available to talk to. */
if ( iface_start_NetworkManager ( ) )
logMessage ( INFO , " failed to start NetworkManager " ) ;
if ( ! FL_CMDLINE ( flags ) )
startNewt ( ) ;
/* can't run gdbserver until after network modules are loaded */
doGdbserver ( & loaderData ) ;
/* JKFIXME: we'd really like to do this before the busprobe, but then
* we won ' t have network devices available ( and that ' s the only thing
* we support with this right now */
if ( loaderData . ddsrc ! = NULL ) {
getDDFromSource ( & loaderData , loaderData . ddsrc ) ;
}
/* JKFIXME: loaderData->ksFile is set to the arg from the command line,
* and then getKickstartFile ( ) changes it and sets FL_KICKSTART .
* kind of weird . */
if ( loaderData . ksFile | | ksFile ) {
logMessage ( INFO , " getting kickstart file " ) ;
if ( ! ksFile )
getKickstartFile ( & loaderData ) ;
if ( FL_KICKSTART ( flags ) & &
( ksReadCommands ( ( ksFile ) ? ksFile : loaderData . ksFile ) ! = LOADER_ERROR ) ) {
runKickstart ( & loaderData ) ;
}
}
if ( FL_TELNETD ( flags ) )
startTelnetd ( & loaderData ) ;
url = doLoaderMain ( & loaderData , modInfo ) ;
/* unlink dirs and link to the ones in /mnt/runtime */
migrate_runtime_directory ( " /usr " ) ;
migrate_runtime_directory ( " /lib " ) ;
migrate_runtime_directory ( " /lib64 " ) ;
2011-07-02 13:05:18 +00:00
ret = symlink ( " /mnt/runtime/etc/selinux " , " /etc/selinux " ) ;
2011-01-18 09:24:57 +00:00
copyDirectory ( " /mnt/runtime/etc " , " /etc " , NULL , copyErrorFn ) ;
copyDirectory ( " /mnt/runtime/var " , " /var " , NULL , copyErrorFn ) ;
/* now load SELinux policy before exec'ing anaconda and the shell
* ( if we ' re using SELinux ) */
if ( FL_SELINUX ( flags ) ) {
if ( mount ( " /selinux " , " /selinux " , " selinuxfs " , 0 , NULL ) ) {
logMessage ( ERROR , " failed to mount /selinux: %m, disabling SELinux " ) ;
flags & = ~ LOADER_FLAGS_SELINUX ;
} else {
if ( loadpolicy ( ) = = 0 ) {
setexeccon ( ANACONDA_CONTEXT ) ;
} else {
logMessage ( ERROR , " failed to load policy, disabling SELinux " ) ;
flags & = ~ LOADER_FLAGS_SELINUX ;
}
}
}
logMessage ( INFO , " getting ready to spawn shell now " ) ;
spawnShell ( ) ; /* we can attach gdb now :-) */
if ( FL_NOPROBE ( flags ) & & ! loaderData . ksFile ) {
startNewt ( ) ;
manualDeviceCheck ( & loaderData ) ;
}
if ( loaderData . updatessrc )
loadUpdatesFromRemote ( loaderData . updatessrc , & loaderData ) ;
else if ( FL_UPDATES ( flags ) )
loadUpdates ( & loaderData ) ;
/* make sure /tmp/updates exists so that magic in anaconda to */
/* symlink rhpl/ will work */
if ( access ( " /tmp/updates " , F_OK ) )
mkdirChain ( " /tmp/updates " ) ;
add_fw_search_dir ( & loaderData , " /tmp/updates/firmware " ) ;
add_fw_search_dir ( & loaderData , " /tmp/product/firmware " ) ;
add_to_path_env ( " PYTHONPATH " , " /tmp/updates " ) ;
add_to_path_env ( " PYTHONPATH " , " /tmp/updates/iw " ) ;
add_to_path_env ( " PYTHONPATH " , " /tmp/updates/textw " ) ;
add_to_path_env ( " PYTHONPATH " , " /tmp/product " ) ;
add_to_path_env ( " LD_LIBRARY_PATH " , " /tmp/updates " ) ;
add_to_path_env ( " LD_LIBRARY_PATH " , " /tmp/product " ) ;
add_to_path_env ( " PATH " , " /tmp/updates " ) ;
add_to_path_env ( " PATH " , " /tmp/product " ) ;
stop_fw_loader ( & loaderData ) ;
start_fw_loader ( & loaderData ) ;
mlLoadModuleSet ( " raid0:raid1:raid5:raid6:raid456:raid10:linear:dm-mod:dm-zero:dm-mirror:dm-snapshot:dm-multipath:dm-round-robin:dm-crypt:cbc:sha256:lrw:xts " ) ;
if ( ! access ( " /mnt/runtime/usr/lib/libunicode-lite.so.1 " , R_OK ) )
setenv ( " LD_PRELOAD " , " /mnt/runtime/usr/lib/libunicode-lite.so.1 " , 1 ) ;
if ( ! access ( " /mnt/runtime/usr/lib64/libunicode-lite.so.1 " , R_OK ) )
setenv ( " LD_PRELOAD " , " /mnt/runtime/usr/lib64/libunicode-lite.so.1 " , 1 ) ;
argptr = anacondaArgs ;
path = getenv ( " PATH " ) ;
while ( path & & path [ 0 ] ) {
int n = strcspn ( path , " : " ) ;
char c , * binpath ;
c = path [ n ] ;
path [ n ] = ' \0 ' ;
checked_asprintf ( & binpath , " %s/anaconda " , path ) ;
path [ n ] = c ;
if ( ! access ( binpath , X_OK ) ) {
* argptr + + = strdupa ( binpath ) ;
free ( binpath ) ;
break ;
}
free ( binpath ) ;
path + = n + 1 ;
}
logMessage ( INFO , " Running anaconda script %s " , * ( argptr - 1 ) ) ;
* argptr + + = " --stage2 " ;
if ( strncmp ( url , " ftp: " , 4 ) ) {
* argptr + + = url ;
} else {
2011-07-02 13:05:18 +00:00
int fd , ret ;
2011-01-18 09:24:57 +00:00
fd = open ( " /tmp/ftp-stage2 " , O_CREAT | O_TRUNC | O_RDWR , 0600 ) ;
2011-07-02 13:05:18 +00:00
ret = write ( fd , url , strlen ( url ) ) ;
ret = write ( fd , " \r " , 1 ) ;
2011-01-18 09:24:57 +00:00
close ( fd ) ;
* argptr + + = " @/tmp/ftp-stage2 " ;
}
/* add extra args - this potentially munges extraArgs */
tmparg = extraArgs ;
while ( * tmparg ) {
char * idx ;
logMessage ( DEBUGLVL , " adding extraArg %s " , * tmparg ) ;
idx = strchr ( * tmparg , ' = ' ) ;
if ( idx & & ( ( idx - * tmparg ) < strlen ( * tmparg ) ) ) {
* idx = ' \0 ' ;
* argptr + + = * tmparg ;
* argptr + + = idx + 1 ;
} else {
* argptr + + = * tmparg ;
}
tmparg + + ;
}
if ( FL_AUTOMODDISK ( flags ) )
* argptr + + = " --dlabel " ;
if ( FL_NOIPV4 ( flags ) )
* argptr + + = " --noipv4 " ;
# ifdef ENABLE_IPV6
if ( FL_NOIPV6 ( flags ) )
* argptr + + = " --noipv6 " ;
# endif
# if defined(__s390__) || defined(__s390x__)
* argptr + + = " --headless " ;
# endif
if ( FL_KICKSTART ( flags ) ) {
* argptr + + = " --kickstart " ;
* argptr + + = loaderData . ksFile ;
}
if ( FL_SERIAL ( flags ) )
* argptr + + = " --serial " ;
if ( FL_RESCUE ( flags ) ) {
* argptr + + = " --rescue " ;
} else {
if ( FL_TEXT ( flags ) )
* argptr + + = " -T " ;
else if ( FL_GRAPHICAL ( flags ) )
* argptr + + = " --graphical " ;
if ( FL_CMDLINE ( flags ) )
* argptr + + = " -C " ;
if ( ! FL_SELINUX ( flags ) )
* argptr + + = " --noselinux " ;
else if ( FL_SELINUX ( flags ) )
* argptr + + = " --selinux " ;
if ( FL_VIRTPCONSOLE ( flags ) ) {
* argptr + + = " --virtpconsole " ;
* argptr + + = virtpcon ;
}
if ( loaderData . updatessrc & & FL_UPDATES ( flags ) ) {
* argptr + + = " --updates " ;
* argptr + + = loaderData . updatessrc ;
}
if ( loaderData . dogtailurl ) {
* argptr + + = " --dogtail " ;
* argptr + + = loaderData . dogtailurl ;
}
if ( ( loaderData . lang ) & & ! FL_NOPASS ( flags ) ) {
* argptr + + = " --lang " ;
* argptr + + = loaderData . lang ;
}
if ( ( loaderData . kbd ) & & ! FL_NOPASS ( flags ) ) {
* argptr + + = " --keymap " ;
* argptr + + = loaderData . kbd ;
}
if ( loaderData . logLevel ) {
* argptr + + = " --loglevel " ;
* argptr + + = loaderData . logLevel ;
}
if ( loaderData . instRepo ) {
* argptr + + = " --repo " ;
if ( strncmp ( loaderData . instRepo , " ftp: " , 4 ) ) {
* argptr + + = loaderData . instRepo ;
} else {
2011-07-02 13:05:18 +00:00
int fd , ret ;
2011-01-18 09:24:57 +00:00
fd = open ( " /tmp/ftp-repo " , O_CREAT | O_TRUNC | O_RDWR , 0600 ) ;
2011-07-02 13:05:18 +00:00
ret = write ( fd , loaderData . instRepo , strlen ( loaderData . instRepo ) ) ;
ret = write ( fd , " \r " , 1 ) ;
2011-01-18 09:24:57 +00:00
close ( fd ) ;
* argptr + + = " @/tmp/ftp-repo " ;
}
}
if ( loaderData . proxy & & strcmp ( " " , loaderData . proxy ) ) {
* argptr + + = " --proxy " ;
* argptr + + = strdup ( loaderData . proxy ) ;
if ( loaderData . proxyUser & & strcmp ( loaderData . proxyUser , " " ) ) {
2011-07-02 13:05:18 +00:00
int fd , ret ;
2011-01-18 09:24:57 +00:00
fd = open ( " /tmp/proxy " , O_CREAT | O_TRUNC | O_RDWR , 0600 ) ;
2011-07-02 13:05:18 +00:00
ret = write ( fd , loaderData . proxyUser , strlen ( loaderData . proxyUser ) ) ;
ret = write ( fd , " \r \n " , 2 ) ;
2011-01-18 09:24:57 +00:00
if ( loaderData . proxyPassword & & strcmp ( loaderData . proxyPassword , " " ) ) {
2011-07-02 13:05:18 +00:00
ret = write ( fd , loaderData . proxyPassword , strlen ( loaderData . proxyPassword ) ) ;
ret = write ( fd , " \r \n " , 2 ) ;
2011-01-18 09:24:57 +00:00
}
close ( fd ) ;
* argptr + + = " --proxyAuth " ;
* argptr + + = " /tmp/proxy " ;
}
}
}
* argptr = NULL ;
stopNewt ( ) ;
closeLog ( ) ;
if ( FL_RESCUE ( flags ) ) {
fmt = _ ( " Running anaconda %s, the %s rescue mode - please wait. \n " ) ;
} else {
fmt = _ ( " Running anaconda %s, the %s system installer - please wait. \n " ) ;
}
printf ( fmt , VERSION , getProductName ( ) ) ;
if ( ! ( pid = fork ( ) ) ) {
if ( execv ( anacondaArgs [ 0 ] , anacondaArgs ) = = - 1 ) {
fprintf ( stderr , " exec of anaconda failed: %m \n " ) ;
doExit ( 1 ) ;
}
}
waitpid ( pid , & status , 0 ) ;
if ( ! WIFEXITED ( status ) | | ( WIFEXITED ( status ) & & WEXITSTATUS ( status ) ) ) {
rc = 1 ;
} else {
rc = 0 ;
}
if ( ( rc = = 0 ) & & ( FL_POWEROFF ( flags ) | | FL_HALT ( flags ) ) ) {
if ( ! ( pid = fork ( ) ) ) {
char * cmd = ( FL_POWEROFF ( flags ) ? strdup ( " /sbin/poweroff " ) :
strdup ( " /sbin/halt " ) ) ;
if ( execl ( cmd , cmd , NULL ) = = - 1 ) {
fprintf ( stderr , " exec of poweroff failed: %m \n " ) ;
doExit ( 1 ) ;
}
}
waitpid ( pid , & status , 0 ) ;
}
stop_fw_loader ( & loaderData ) ;
# if defined(__s390__) || defined(__s390x__)
/* at the latest possibility signal init=linuxrc.s390 to reboot/halt */
logMessage ( INFO , " Sending signal %d to process %d \n " ,
init_sig , init_pid ) ;
kill ( init_pid , init_sig ) ;
# endif
doExit ( rc ) ;
doExit ( 1 ) ;
}
/* vim:set sw=4 sts=4 et: */