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 )
*
2018-04-22 16:12:26 +03:00
* Copyright 1996 Red Hat Software
2004-01-20 21:32:43 +03:00
*
*/
2007-02-27 16:54:57 +03:00
# include <sys/types.h>
# include <sys/stat.h>
2004-01-20 21:32:43 +03:00
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
// #include <sys/socket.h>
# include <net/if.h>
# include <arpa/inet.h>
# include <net/route.h>
# include <sys/ioctl.h>
# include <sys/mount.h>
# include <stdio.h>
# include <netdb.h>
# include <resolv.h>
# include "stage1.h"
# include "frontend.h"
# include "modules.h"
# include "probing.h"
# include "log.h"
# include "mount.h"
2005-02-04 23:28:52 +03:00
# include "lomount.h"
2004-01-20 21:32:43 +03:00
# include "automatic.h"
# include "dhcp.h"
# include "adsl.h"
# include "url.h"
# include "dns.h"
# include "network.h"
2018-04-22 17:13:06 +03:00
# include "udev.h"
2004-01-20 21:32:43 +03:00
2007-08-02 20:45:59 +04:00
extern char version [ ] ;
2004-01-20 21:32:43 +03:00
static void error_message_net ( void ) /* reduce code size */
{
stg1_error_message ( " Could not configure network. " ) ;
}
int configure_net_device ( struct interface_info * intf )
{
struct ifreq req ;
struct rtentry route ;
int s ;
struct sockaddr_in addr ;
struct in_addr ia ;
char ip [ 20 ] , nm [ 20 ] , nw [ 20 ] , bc [ 20 ] ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
addr . sin_family = AF_INET ;
addr . sin_port = 0 ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
memcpy ( & ia , & intf - > ip , sizeof ( intf - > ip ) ) ;
strcpy ( ip , inet_ntoa ( ia ) ) ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
memcpy ( & ia , & intf - > netmask , sizeof ( intf - > netmask ) ) ;
strcpy ( nm , inet_ntoa ( ia ) ) ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
memcpy ( & ia , & intf - > broadcast , sizeof ( intf - > broadcast ) ) ;
strcpy ( bc , inet_ntoa ( ia ) ) ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
memcpy ( & ia , & intf - > network , sizeof ( intf - > network ) ) ;
strcpy ( nw , inet_ntoa ( ia ) ) ;
log_message ( " configuring device %s ip: %s nm: %s nw: %s bc: %s " , intf - > device , ip , nm , nw , bc ) ;
if ( IS_TESTING )
return 0 ;
s = socket ( AF_INET , SOCK_DGRAM , 0 ) ;
if ( s < 0 ) {
log_perror ( " socket " ) ;
error_message_net ( ) ;
return 1 ;
}
strcpy ( req . ifr_name , intf - > device ) ;
if ( intf - > is_up = = 1 ) {
log_message ( " interface already up, downing before reconfigure " ) ;
req . ifr_flags = 0 ;
if ( ioctl ( s , SIOCSIFFLAGS , & req ) ) {
close ( s ) ;
log_perror ( " SIOCSIFFLAGS (downing) " ) ;
error_message_net ( ) ;
return 1 ;
}
}
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
/* sets IP address */
addr . sin_port = 0 ;
memcpy ( & addr . sin_addr , & intf - > ip , sizeof ( intf - > ip ) ) ;
memcpy ( & req . ifr_addr , & addr , sizeof ( addr ) ) ;
if ( ioctl ( s , SIOCSIFADDR , & req ) ) {
close ( s ) ;
log_perror ( " SIOCSIFADDR " ) ;
error_message_net ( ) ;
return 1 ;
}
/* sets broadcast */
memcpy ( & addr . sin_addr , & intf - > broadcast , sizeof ( intf - > broadcast ) ) ;
memcpy ( & req . ifr_broadaddr , & addr , sizeof ( addr ) ) ;
if ( ioctl ( s , SIOCSIFBRDADDR , & req ) ) {
close ( s ) ;
log_perror ( " SIOCSIFBRDADDR " ) ;
error_message_net ( ) ;
return 1 ;
}
/* sets netmask */
memcpy ( & addr . sin_addr , & intf - > netmask , sizeof ( intf - > netmask ) ) ;
memcpy ( & req . ifr_netmask , & addr , sizeof ( addr ) ) ;
if ( ioctl ( s , SIOCSIFNETMASK , & req ) ) {
close ( s ) ;
log_perror ( " SIOCSIFNETMASK " ) ;
error_message_net ( ) ;
return 1 ;
}
if ( intf - > is_ptp )
req . ifr_flags = IFF_UP | IFF_RUNNING | IFF_POINTOPOINT | IFF_NOARP ;
else
req . ifr_flags = IFF_UP | IFF_RUNNING | IFF_BROADCAST ;
/* brings up networking! */
if ( ioctl ( s , SIOCSIFFLAGS , & req ) ) {
close ( s ) ;
log_perror ( " SIOCSIFFLAGS (upping) " ) ;
error_message_net ( ) ;
return 1 ;
}
memset ( & route , 0 , sizeof ( route ) ) ;
route . rt_dev = intf - > device ;
route . rt_flags = RTF_UP ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
memcpy ( & addr . sin_addr , & intf - > network , sizeof ( intf - > network ) ) ;
memcpy ( & route . rt_dst , & addr , sizeof ( addr ) ) ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
memcpy ( & addr . sin_addr , & intf - > netmask , sizeof ( intf - > netmask ) ) ;
memcpy ( & route . rt_genmask , & addr , sizeof ( addr ) ) ;
/* adds route */
if ( ioctl ( s , SIOCADDRT , & route ) ) {
close ( s ) ;
log_perror ( " SIOCADDRT " ) ;
error_message_net ( ) ;
return 1 ;
}
close ( s ) ;
intf - > is_up = 1 ;
if ( intf - > boot_proto ! = BOOTPROTO_DHCP & & ! streq ( intf - > device , " lo " ) ) {
/* I need to sleep a bit in order for kernel to finish
init of the network device ; if not , first sendto ( ) for
gethostbyaddr will get an EINVAL . */
wait_message ( " Bringing up networking... " ) ;
sleep ( 2 ) ;
remove_wait_message ( ) ;
}
return 0 ;
}
2018-05-09 15:21:26 +03:00
/* host network informations */
2004-01-20 21:32:43 +03:00
char * hostname = NULL ;
char * domain = NULL ;
2007-09-19 00:46:56 +04:00
char * rootpath = NULL ;
2004-01-20 21:32:43 +03:00
struct in_addr gateway = { 0 } ;
struct in_addr dns_server = { 0 } ;
struct in_addr dns_server2 = { 0 } ;
2007-09-19 00:46:56 +04:00
struct in_addr next_server = { 0 } ;
2004-01-20 21:32:43 +03:00
static int add_default_route ( void )
{
int s ;
struct rtentry route ;
struct sockaddr_in addr ;
if ( IS_TESTING )
return 0 ;
if ( gateway . s_addr = = 0 ) {
log_message ( " no gateway provided, can't add default route " ) ;
return 0 ;
}
s = socket ( AF_INET , SOCK_DGRAM , 0 ) ;
if ( s < 0 ) {
close ( s ) ;
log_perror ( " socket " ) ;
error_message_net ( ) ;
return 1 ;
}
memset ( & route , 0 , sizeof ( route ) ) ;
addr . sin_family = AF_INET ;
addr . sin_port = 0 ;
addr . sin_addr = gateway ;
memcpy ( & route . rt_gateway , & addr , sizeof ( addr ) ) ;
addr . sin_addr . s_addr = INADDR_ANY ;
memcpy ( & route . rt_dst , & addr , sizeof ( addr ) ) ;
memcpy ( & route . rt_genmask , & addr , sizeof ( addr ) ) ;
route . rt_flags = RTF_UP | RTF_GATEWAY ;
route . rt_metric = 0 ;
if ( ioctl ( s , SIOCADDRT , & route ) ) {
close ( s ) ;
log_perror ( " SIOCADDRT " ) ;
error_message_net ( ) ;
return 1 ;
}
close ( s ) ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
return 0 ;
}
static int write_resolvconf ( void ) {
char * filename = " /etc/resolv.conf " ;
FILE * f ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
if ( dns_server . s_addr = = 0 ) {
log_message ( " resolvconf needs a dns server " ) ;
return - 1 ;
}
f = fopen ( filename , " w " ) ;
if ( ! f ) {
log_perror ( filename ) ;
return - 1 ;
}
if ( domain )
fprintf ( f , " search %s \n " , domain ) ; /* we can live without the domain search (user will have to enter fully-qualified names) */
fprintf ( f , " nameserver %s \n " , inet_ntoa ( dns_server ) ) ;
if ( dns_server2 . s_addr ! = 0 )
fprintf ( f , " nameserver %s \n " , inet_ntoa ( dns_server2 ) ) ;
fclose ( f ) ;
res_init ( ) ; /* reinit the resolver so DNS changes take affect */
return 0 ;
}
static int save_netinfo ( struct interface_info * intf ) {
2018-04-22 20:22:55 +03:00
char mask [ 12 ] ;
2005-02-18 22:55:32 +03:00
unsigned m , hl ;
int i ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
if ( hostname )
2005-02-17 17:30:26 +03:00
add_to_env ( " HOSTNAME " , hostname ) ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
if ( domain )
2005-02-17 17:30:26 +03:00
add_to_env ( " DOMAINNAME " , domain ) ;
2005-07-05 18:35:10 +04:00
if ( dns_server . s_addr ! = 0 )
add_to_env ( " DNS_SERVER " , inet_ntoa ( dns_server ) ) ;
if ( dns_server2 . s_addr ! = 0 )
add_to_env ( " DNS_SERVER2 " , inet_ntoa ( dns_server2 ) ) ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
if ( gateway . s_addr ! = 0 )
2005-02-17 17:30:26 +03:00
add_to_env ( " GATEWAY " , inet_ntoa ( gateway ) ) ;
2004-01-20 21:32:43 +03:00
2005-02-17 17:30:26 +03:00
add_to_env ( " DEVICE " , intf - > device ) ;
2004-01-20 21:32:43 +03:00
if ( intf - > boot_proto = = BOOTPROTO_DHCP )
2005-02-17 17:30:26 +03:00
add_to_env ( " BOOTPROTO " , strdup ( " dhcp " ) ) ;
2004-01-20 21:32:43 +03:00
else if ( intf - > boot_proto = = BOOTPROTO_STATIC ) {
2005-02-17 17:30:26 +03:00
add_to_env ( " BOOTPROTO " , strdup ( " static " ) ) ;
add_to_env ( " IPADDR " , inet_ntoa ( intf - > ip ) ) ;
add_to_env ( " NETMASK " , inet_ntoa ( intf - > netmask ) ) ;
add_to_env ( " NETWORK " , inet_ntoa ( intf - > network ) ) ;
add_to_env ( " BROADCAST " , inet_ntoa ( intf - > broadcast ) ) ;
2005-02-18 22:55:32 +03:00
hl = ntohl ( intf - > netmask . s_addr ) ;
for ( i = 32 , m = 0xffffffff ; m > hl ; m < < = 1 , i - - ) ;
2018-04-22 20:22:55 +03:00
snprintf ( mask , sizeof ( mask ) , " %d " , i ) ;
2005-02-18 22:55:32 +03:00
add_to_env ( " NETBITS " , mask ) ;
2004-01-20 21:32:43 +03:00
} else if ( intf - > boot_proto = = BOOTPROTO_ADSL_PPPOE ) {
2005-02-17 17:30:26 +03:00
add_to_env ( " BOOTPROTO " , strdup ( " adsl_pppoe " ) ) ;
add_to_env ( " USER " , intf - > user ) ;
add_to_env ( " PASS " , intf - > pass ) ;
2004-01-20 21:32:43 +03:00
}
return 0 ;
}
char * guess_netmask ( char * ip_addr )
{
struct in_addr addr ;
unsigned long int tmp ;
if ( streq ( ip_addr , " " ) | | ! inet_aton ( ip_addr , & addr ) )
return " " ;
log_message ( " guessing netmask " ) ;
tmp = ntohl ( addr . s_addr ) ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
if ( ( ( tmp & 0xFF000000 ) > > 24 ) < = 127 )
return " 255.0.0.0 " ;
else if ( ( ( tmp & 0xFF000000 ) > > 24 ) < = 191 )
return " 255.255.0.0 " ;
2018-05-09 15:21:26 +03:00
else
2004-01-20 21:32:43 +03:00
return " 255.255.255.0 " ;
}
static void static_ip_callback ( char * * strings )
{
struct in_addr addr ;
if ( ! inet_aton ( strings [ 0 ] , & addr ) )
return ;
if ( ! strcmp ( strings [ 1 ] , " " ) ) {
char * ptr ;
strings [ 1 ] = strdup ( strings [ 0 ] ) ;
ptr = strrchr ( strings [ 1 ] , ' . ' ) ;
if ( ptr )
* ( ptr + 1 ) = ' \0 ' ;
}
if ( ! strcmp ( strings [ 2 ] , " " ) )
strings [ 2 ] = strdup ( strings [ 1 ] ) ;
if ( ! strcmp ( strings [ 3 ] , " " ) )
strings [ 3 ] = strdup ( guess_netmask ( strings [ 0 ] ) ) ;
}
static enum return_type setup_network_interface ( struct interface_info * intf )
{
enum return_type results ;
2018-05-09 15:21:26 +03:00
# ifndef DISABLE_ADSL
2004-01-20 21:32:43 +03:00
char * bootprotos [ ] = { " Static " , " DHCP " , " ADSL " , NULL } ;
char * bootprotos_auto [ ] = { " static " , " dhcp " , " adsl " } ;
2005-02-28 22:26:48 +03:00
# else
char * bootprotos [ ] = { " Static " , " DHCP " , NULL } ;
char * bootprotos_auto [ ] = { " static " , " dhcp " } ;
2018-05-09 15:21:26 +03:00
# endif
2004-01-20 21:32:43 +03:00
char * choice ;
results = ask_from_list_auto ( " Please choose the desired IP attribution. " , bootprotos , & choice , " network " , bootprotos_auto ) ;
if ( results ! = RETURN_OK )
return results ;
if ( ! strcmp ( choice , " Static " ) ) {
char * questions [ ] = { " IP of this machine " , " IP of DNS " , " IP of default gateway " , " Netmask " , NULL } ;
char * questions_auto [ ] = { " ip " , " dns " , " gateway " , " netmask " } ;
static char * * answers = NULL ;
struct in_addr addr ;
results = ask_from_entries_auto ( " Please enter the network information. (leave netmask void for Internet standard) " ,
questions , & answers , 16 , questions_auto , static_ip_callback ) ;
if ( results ! = RETURN_OK )
return setup_network_interface ( intf ) ;
if ( streq ( answers [ 0 ] , " " ) | | ! inet_aton ( answers [ 0 ] , & addr ) ) {
stg1_error_message ( " Invalid IP address. " ) ;
return setup_network_interface ( intf ) ;
}
memcpy ( & intf - > ip , & addr , sizeof ( addr ) ) ;
if ( ! inet_aton ( answers [ 1 ] , & dns_server ) ) {
log_message ( " invalid DNS " ) ;
dns_server . s_addr = 0 ; /* keep an understandable state */
}
if ( ! inet_aton ( answers [ 2 ] , & gateway ) ) {
log_message ( " invalid gateway " ) ;
gateway . s_addr = 0 ; /* keep an understandable state */
}
if ( ( streq ( answers [ 3 ] , " " ) & & inet_aton ( guess_netmask ( answers [ 0 ] ) , & addr ) )
| | inet_aton ( answers [ 3 ] , & addr ) )
memcpy ( & intf - > netmask , & addr , sizeof ( addr ) ) ;
else {
stg1_error_message ( " Invalid netmask. " ) ;
return setup_network_interface ( intf ) ;
}
* ( ( uint32_t * ) & intf - > broadcast ) = ( * ( ( uint32_t * ) & intf - > ip ) &
* ( ( uint32_t * ) & intf - > netmask ) ) | ~ ( * ( ( uint32_t * ) & intf - > netmask ) ) ;
inet_aton ( " 255.255.255.255 " , & addr ) ;
if ( ! memcmp ( & addr , & intf - > netmask , sizeof ( addr ) ) ) {
log_message ( " netmask is 255.255.255.255 -> point to point device " ) ;
intf - > network = gateway ;
intf - > is_ptp = 1 ;
} else {
* ( ( uint32_t * ) & intf - > network ) = * ( ( uint32_t * ) & intf - > ip ) & * ( ( uint32_t * ) & intf - > netmask ) ;
intf - > is_ptp = 0 ;
}
intf - > boot_proto = BOOTPROTO_STATIC ;
if ( configure_net_device ( intf ) )
return RETURN_ERROR ;
} else if ( streq ( choice , " DHCP " ) ) {
results = perform_dhcp ( intf ) ;
2009-03-12 17:52:25 +03:00
if ( results ! = RETURN_OK )
return RETURN_BACK ;
2004-01-20 21:32:43 +03:00
intf - > boot_proto = BOOTPROTO_DHCP ;
if ( configure_net_device ( intf ) )
2009-03-12 17:52:25 +03:00
return RETURN_BACK ;
2005-02-28 22:26:48 +03:00
# ifndef DISABLE_ADSL
2004-01-20 21:32:43 +03:00
} else if ( streq ( choice , " ADSL " ) ) {
results = perform_adsl ( intf ) ;
if ( results = = RETURN_BACK )
return setup_network_interface ( intf ) ;
if ( results = = RETURN_ERROR )
return results ;
2018-05-09 15:21:26 +03:00
# endif
2004-01-20 21:32:43 +03:00
} else
return RETURN_ERROR ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
return add_default_route ( ) ;
}
static enum return_type configure_network ( struct interface_info * intf )
{
char * dnshostname ;
if ( hostname & & domain )
return RETURN_OK ;
dnshostname = mygethostbyaddr ( inet_ntoa ( intf - > ip ) ) ;
if ( dnshostname ) {
hostname = strdup ( dnshostname ) ;
2008-04-16 14:40:56 +04:00
domain = strchr ( strdup ( hostname ) , ' . ' ) ;
if ( domain ) {
log_message ( " got hostname and domain from dns entry, %s and %s " , hostname , + + domain ) ;
return RETURN_OK ;
}
2004-01-20 21:32:43 +03:00
}
log_message ( " reverse name lookup on self failed " ) ;
if ( domain )
return RETURN_OK ;
if ( dns_server . s_addr ! = 0 ) {
wait_message ( " Trying to resolve dns... " ) ;
dnshostname = mygethostbyaddr ( inet_ntoa ( dns_server ) ) ;
remove_wait_message ( ) ;
}
2008-04-16 14:40:56 +04:00
if ( dnshostname & & ( ( domain = strchr ( strdup ( dnshostname ) , ' . ' ) ) ! = NULL ) ) {
log_message ( " got domain from DNS fullname, %s " , + + domain ) ;
2004-01-20 21:32:43 +03:00
} else {
enum return_type results ;
char * questions [ ] = { " Host name " , " Domain name " , NULL } ;
char * questions_auto [ ] = { " hostname " , " domain " } ;
static char * * answers = NULL ;
char * boulet ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
log_message ( " reverse name lookup on DNS failed " ) ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
results = ask_from_entries_auto ( " I could not guess hostname and domain name; please fill in this information. "
" Valid answers are for example: `mybox' for hostname and `mynetwork.com' for "
" domain name, for a machine called `mybox.mynetwork.com' on the Internet. " ,
questions , & answers , 32 , questions_auto , NULL ) ;
if ( results ! = RETURN_OK )
return results ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
hostname = answers [ 0 ] ;
if ( ( boulet = strchr ( hostname , ' . ' ) ) ! = NULL )
boulet [ 0 ] = ' \0 ' ;
domain = answers [ 1 ] ;
}
return RETURN_OK ;
}
static enum return_type bringup_networking ( struct interface_info * intf )
{
static struct interface_info loopback ;
enum return_type results = RETURN_ERROR ;
2018-05-09 15:21:26 +03:00
2008-02-29 20:05:35 +03:00
my_insmod ( " af_packet " , NULL ) ;
2004-01-20 21:32:43 +03:00
while ( results ! = RETURN_OK ) {
results = setup_network_interface ( intf ) ;
if ( results ! = RETURN_OK )
return results ;
write_resolvconf ( ) ;
results = configure_network ( intf ) ;
}
write_resolvconf ( ) ; /* maybe we have now domain to write also */
if ( loopback . is_up = = 0 ) {
int rc ;
strcpy ( loopback . device , " lo " ) ;
loopback . is_ptp = 0 ;
loopback . is_up = 0 ;
loopback . ip . s_addr = htonl ( 0x7f000001 ) ;
loopback . netmask . s_addr = htonl ( 0xff000000 ) ;
loopback . broadcast . s_addr = htonl ( 0x7fffffff ) ;
loopback . network . s_addr = htonl ( 0x7f000000 ) ;
rc = configure_net_device ( & loopback ) ;
if ( rc )
return RETURN_ERROR ;
}
return RETURN_OK ;
}
static char * interface_select ( void )
{
char * * interfaces , * * ptr ;
char * descriptions [ 50 ] ;
2018-04-22 17:13:06 +03:00
char * choice = NULL ;
int i = 0 ;
2004-01-20 21:32:43 +03:00
enum return_type results ;
2009-03-12 17:52:25 +03:00
static int current_iface_auto = 0 ;
2004-01-20 21:32:43 +03:00
2018-04-22 17:13:06 +03:00
udev_settle ( ) ;
2004-01-20 21:32:43 +03:00
2018-04-22 17:13:06 +03:00
if ( ( interfaces = get_net_devices ( ) ) ! = NULL ) {
for ( ptr = interfaces ; * ptr ; i + + )
ptr + + ;
2004-01-20 21:32:43 +03:00
}
2018-04-22 17:13:06 +03:00
if ( i = = 0 ) {
free_net_devices ( interfaces ) ;
return choice ;
}
if ( i = = 1 ) {
choice = strdup ( interfaces [ 0 ] ) ;
free_net_devices ( interfaces ) ;
return choice ;
2004-01-20 21:32:43 +03:00
}
2018-04-22 17:13:06 +03:00
for ( i = 0 ; interfaces [ i ] ; i + + )
descriptions [ i ] = get_net_intf_description ( interfaces [ i ] ) ;
2004-01-20 21:32:43 +03:00
2009-03-12 19:05:51 +03:00
if ( IS_AUTOMATIC ) {
2018-04-22 16:12:26 +03:00
if ( streq ( get_auto_value ( " interface " ) , " " ) ) {
2018-04-22 17:13:06 +03:00
if ( interfaces [ current_iface_auto ] = = NULL )
2009-03-12 19:05:51 +03:00
unset_param ( MODE_AUTOMATIC ) ; /* we are in a fallback mode */
2018-04-22 17:13:06 +03:00
else {
choice = strdup ( interfaces [ current_iface_auto + + ] ) ;
for ( i = 0 ; interfaces [ i ] ; i + + )
free ( descriptions [ i ] ) ;
free_net_devices ( interfaces ) ;
return choice ;
}
2018-04-22 16:12:26 +03:00
} else {
2009-03-12 19:05:51 +03:00
if ( current_iface_auto + + > 1 )
unset_param ( MODE_AUTOMATIC ) ; /* if interface was defined make only one try */
2018-04-22 16:12:26 +03:00
}
2009-03-12 17:52:25 +03:00
}
2015-03-27 10:41:24 +03:00
results = ask_from_list_comments_auto ( " Please choose the network device to boot from. " ,
2018-04-22 16:12:26 +03:00
interfaces , descriptions , & choice , " interface " , interfaces ) ;
2018-04-22 17:13:06 +03:00
for ( i = 0 ; interfaces [ i ] ; i + + )
free ( descriptions [ i ] ) ;
free_net_devices ( interfaces ) ;
2004-01-20 21:32:43 +03:00
if ( results ! = RETURN_OK )
return NULL ;
return choice ;
}
/* -=-=-- */
static enum return_type intf_select_and_up ( void )
{
static struct interface_info intf [ 20 ] ;
static int num_interfaces = 0 ;
2008-11-12 17:23:06 +03:00
static int already_done = 0 ;
2004-01-20 21:32:43 +03:00
struct interface_info * sel_intf = NULL ;
int i ;
enum return_type results ;
2008-11-12 17:23:06 +03:00
char * iface = NULL ;
2018-04-22 16:12:26 +03:00
if ( already_done )
return RETURN_OK ;
2008-11-12 17:23:06 +03:00
2018-04-22 17:13:06 +03:00
intf_select_and_up_again :
for ( i = 0 ; i < 15 ; i + + ) {
if ( ( iface = interface_select ( ) ) ! = NULL )
break ;
sleep ( 1 ) ;
}
if ( iface = = NULL ) {
stg1_error_message ( " No network device found. " ) ;
i = ask_insmod ( ) ;
2004-01-20 21:32:43 +03:00
return RETURN_BACK ;
2018-04-22 17:13:06 +03:00
}
2018-04-22 16:12:26 +03:00
for ( i = 0 ; i < num_interfaces ; i + + )
2004-01-20 21:32:43 +03:00
if ( ! strcmp ( intf [ i ] . device , iface ) )
sel_intf = & ( intf [ i ] ) ;
2018-04-22 16:12:26 +03:00
2004-01-20 21:32:43 +03:00
if ( sel_intf = = NULL ) {
sel_intf = & ( intf [ num_interfaces ] ) ;
strcpy ( sel_intf - > device , iface ) ;
sel_intf - > is_up = 0 ;
num_interfaces + + ;
}
2009-03-12 17:52:25 +03:00
log_message ( " trying with iface %s " , sel_intf - > device ) ;
2004-01-20 21:32:43 +03:00
results = bringup_networking ( sel_intf ) ;
2009-03-12 17:52:25 +03:00
if ( results = = RETURN_BACK )
2018-04-22 17:13:06 +03:00
goto intf_select_and_up_again ;
2004-01-20 21:32:43 +03:00
2008-11-12 17:23:06 +03:00
if ( results = = RETURN_OK ) {
2004-01-20 21:32:43 +03:00
save_netinfo ( sel_intf ) ;
2008-11-12 17:23:06 +03:00
already_done = 1 ;
}
2004-01-20 21:32:43 +03:00
return results ;
}
2008-11-12 17:23:06 +03:00
enum return_type net_prepare ( void )
{
return ( * ( get_auto_value ( " network " ) ) = = ' \0 ' ) ? RETURN_OK : intf_select_and_up ( ) ;
}
2004-01-20 21:32:43 +03:00
enum return_type nfs_prepare ( void )
{
2007-08-02 20:45:59 +04:00
char * questions [ ] = { " NFS server name " , " Directory " , NULL } ;
2004-01-20 21:32:43 +03:00
char * questions_auto [ ] = { " server " , " directory " , NULL } ;
2007-08-02 20:45:59 +04:00
char msg [ 256 ] ;
2004-01-20 21:32:43 +03:00
static char * * answers = NULL ;
char * nfsmount_location ;
2005-02-02 22:26:15 +03:00
char * ramdisk_path ;
2004-01-20 21:32:43 +03:00
enum return_type results = intf_select_and_up ( ) ;
2005-02-02 22:26:15 +03:00
struct stat st ;
2005-02-04 23:28:52 +03:00
int iso = 0 ;
2004-01-20 21:32:43 +03:00
if ( results ! = RETURN_OK )
return results ;
2010-11-22 19:56:35 +03:00
update_splash ( " prepare " ) ;
2004-01-20 21:32:43 +03:00
do {
2007-08-02 20:45:59 +04:00
snprintf ( msg , sizeof ( msg ) , " Please enter the name or IP address of your NFS server, "
" and the directory (or ISO image file) containing the %s Distribution. " , version ) ;
results = ask_from_entries_auto ( msg , questions , & answers , 40 , questions_auto , NULL ) ;
2004-01-20 21:32:43 +03:00
if ( results ! = RETURN_OK | | streq ( answers [ 0 ] , " " ) ) {
2007-09-19 00:46:56 +04:00
if ( next_server . s_addr & & rootpath ! = NULL ) {
log_message ( " Using params supplied by DHCP " ) ;
nfsmount_location = malloc ( strlen ( rootpath ) + 17 ) ;
strcpy ( nfsmount_location , inet_ntoa ( next_server ) ) ;
strcat ( nfsmount_location , " : " ) ;
strcat ( nfsmount_location , rootpath ) ;
} else {
unset_param ( MODE_AUTOMATIC ) ; /* we are in a fallback mode */
return nfs_prepare ( ) ;
}
} else {
nfsmount_location = malloc ( strlen ( answers [ 0 ] ) + strlen ( answers [ 1 ] ) + 2 ) ;
strcpy ( nfsmount_location , answers [ 0 ] ) ;
strcat ( nfsmount_location , " : " ) ;
strcat ( nfsmount_location , answers [ 1 ] ) ;
2004-01-20 21:32:43 +03:00
}
2007-09-19 00:46:56 +04:00
2004-01-20 21:32:43 +03:00
if ( my_mount ( nfsmount_location , IMAGE_LOCATION , " nfs " , 0 ) = = - 1 ) {
2005-02-04 23:28:52 +03:00
char location_full [ 500 ] ;
char * s ;
2018-05-09 15:21:26 +03:00
2005-02-04 23:28:52 +03:00
/* iso pathname ? */
s = strrchr ( nfsmount_location , ' / ' ) ;
if ( s = = NULL | | s = = nfsmount_location ) {
stg1_error_message ( " I can't mount the directory from the NFS server. " ) ;
results = RETURN_BACK ;
continue ;
}
2018-05-09 15:21:26 +03:00
2005-02-04 23:28:52 +03:00
* s + + = 0 ;
log_message ( " assuming ISO image, NFS path:%s " , nfsmount_location ) ;
if ( my_mount ( nfsmount_location , IMAGE_LOCATION , " nfs " , 0 ) = = - 1 ) {
stg1_error_message ( " I can't mount the directory from the NFS server. " ) ;
results = RETURN_BACK ;
continue ;
}
2018-05-09 15:21:26 +03:00
2005-02-04 23:28:52 +03:00
strcpy ( location_full , IMAGE_LOCATION ) ;
strcat ( location_full , " / " ) ;
strcat ( location_full , s ) ;
2018-05-09 15:21:26 +03:00
2005-02-04 23:28:52 +03:00
log_message ( " assuming ISO image, path:%s " , location_full ) ;
if ( ! stat ( location_full , & st ) & & ! S_ISREG ( st . st_mode ) ) {
stg1_error_message ( " Not a ISO image: %s " , location_full ) ;
umount ( IMAGE_LOCATION ) ;
results = RETURN_BACK ;
continue ;
}
if ( lomount ( location_full , IMAGE_LOCATION ) ) {
2007-08-02 20:45:59 +04:00
stg1_error_message ( " Could not mount file %s as an ISO image of the %s Distribution. " , location_full , version ) ;
2005-02-04 23:28:52 +03:00
umount ( IMAGE_LOCATION ) ;
results = RETURN_BACK ;
continue ;
}
iso = 1 ;
2005-03-02 20:48:28 +03:00
add_to_env ( " PIGGYBACK " , " 1 " ) ;
2004-01-20 21:32:43 +03:00
}
2005-02-02 22:26:15 +03:00
ramdisk_path = get_ramdisk_path ( NULL ) ;
if ( access ( ramdisk_path , R_OK ) ) {
2007-08-02 20:45:59 +04:00
stg1_error_message ( " That NFS volume does not seem to contain the %s Distribution. " , version ) ;
2004-01-20 21:32:43 +03:00
umount ( IMAGE_LOCATION ) ;
2005-02-04 23:28:52 +03:00
if ( iso ) umount ( IMAGE_LOCATION ) ;
2004-01-20 21:32:43 +03:00
results = RETURN_BACK ;
}
2005-02-02 22:26:15 +03:00
} while ( results = = RETURN_BACK ) ;
2004-01-20 21:32:43 +03:00
2007-08-02 20:45:59 +04:00
log_message ( " found the %s Installation, good news! " , version ) ;
2004-01-20 21:32:43 +03:00
2005-02-02 22:26:15 +03:00
stat ( ramdisk_path , & st ) ;
if ( S_ISDIR ( st . st_mode ) ) {
mount ( ramdisk_path , STAGE2_LOCATION , NULL , MS_BIND , NULL ) ;
} else {
do_losetup ( LIVE_DEVICE , ramdisk_path ) ;
my_mount ( LIVE_DEVICE , STAGE2_LOCATION , ( IS_LIVE ) ? LIVEFS : STAGE2FS , 0 ) ;
}
2017-12-07 17:50:32 +03:00
free ( ramdisk_path ) ;
2004-01-20 21:32:43 +03:00
method_name = strdup ( " nfs " ) ;
2005-01-21 16:52:04 +03:00
add_to_env ( " METHOD " , method_name ) ;
add_to_env ( " HOST " , answers [ 0 ] ) ;
2021-04-05 12:05:51 +03:00
add_to_env ( " PREFIX " , " / " ) ;
add_to_env ( " DIRECTORY " , answers [ 1 ] ) ;
2010-11-22 19:56:35 +03:00
update_splash ( " found_media " ) ;
2004-01-20 21:32:43 +03:00
return RETURN_OK ;
}
2014-01-11 18:49:44 +04:00
# ifdef ENABLE_CIFS
enum return_type cifs_prepare ( void )
{
char * questions [ ] = { " Samba server name " , " Directory " , NULL } ;
char * questions_auto [ ] = { " server " , " directory " , NULL } ;
char msg [ 256 ] ;
static char * * answers = NULL ;
char * cifsmount_location ;
char * ramdisk_path ;
enum return_type results = intf_select_and_up ( ) ;
struct stat st ;
int iso = 0 ;
if ( results ! = RETURN_OK )
return results ;
update_splash ( " prepare " ) ;
do {
snprintf ( msg , sizeof ( msg ) , " Please enter the name or IP address of your Samba server, "
" and the directory (or ISO image file) containing the %s Distribution. " , version ) ;
results = ask_from_entries_auto ( msg , questions , & answers , 40 , questions_auto , NULL ) ;
if ( results ! = RETURN_OK | | streq ( answers [ 0 ] , " " ) ) {
if ( next_server . s_addr & & rootpath ! = NULL ) {
log_message ( " Using params supplied by DHCP " ) ;
cifsmount_location = malloc ( strlen ( rootpath ) + 19 ) ;
strcpy ( cifsmount_location , " // " ) ;
strcat ( cifsmount_location , inet_ntoa ( next_server ) ) ;
if ( rootpath [ 0 ] ! = ' / ' )
strcat ( cifsmount_location , " / " ) ;
strcat ( cifsmount_location , rootpath ) ;
} else {
unset_param ( MODE_AUTOMATIC ) ; /* we are in a fallback mode */
return cifs_prepare ( ) ;
}
} else {
cifsmount_location = malloc ( strlen ( answers [ 0 ] ) + strlen ( answers [ 1 ] ) + 4 ) ;
strcpy ( cifsmount_location , " // " ) ;
strcat ( cifsmount_location , answers [ 0 ] ) ;
if ( answers [ 1 ] [ 0 ] ! = ' / ' )
strcat ( cifsmount_location , " / " ) ;
strcat ( cifsmount_location , answers [ 1 ] ) ;
}
if ( my_mount ( cifsmount_location , IMAGE_LOCATION , " cifs " , 0 ) = = - 1 ) {
char location_full [ 500 ] ;
char * s , * r ;
/* iso pathname ? */
s = strrchr ( cifsmount_location , ' / ' ) ;
r = strchr ( cifsmount_location + 2 , ' / ' ) ;
if ( s = = NULL | | s = = cifsmount_location | | s = = r ) {
stg1_error_message ( " I can't try to get location of ISO image directory at Samba server. " ) ;
results = RETURN_BACK ;
continue ;
}
* s + + = 0 ;
log_message ( " assuming ISO image, Samba path:%s " , cifsmount_location ) ;
if ( my_mount ( cifsmount_location , IMAGE_LOCATION , " cifs " , 0 ) = = - 1 ) {
stg1_error_message ( " I can't mount the directory from the Samba server. " ) ;
results = RETURN_BACK ;
continue ;
}
strcpy ( location_full , IMAGE_LOCATION ) ;
strcat ( location_full , " / " ) ;
strcat ( location_full , s ) ;
log_message ( " assuming ISO image, path:%s " , location_full ) ;
if ( ! stat ( location_full , & st ) & & ! S_ISREG ( st . st_mode ) ) {
stg1_error_message ( " Not a ISO image: %s " , location_full ) ;
umount ( IMAGE_LOCATION ) ;
results = RETURN_BACK ;
continue ;
}
if ( lomount ( location_full , IMAGE_LOCATION ) ) {
stg1_error_message ( " Could not mount file %s as an ISO image of the %s Distribution. " , location_full , version ) ;
umount ( IMAGE_LOCATION ) ;
results = RETURN_BACK ;
continue ;
}
iso = 1 ;
add_to_env ( " PIGGYBACK " , " 1 " ) ;
}
ramdisk_path = get_ramdisk_path ( NULL ) ;
if ( access ( ramdisk_path , R_OK ) ) {
stg1_error_message ( " That Samba volume does not seem to contain the %s Distribution. " , version ) ;
umount ( IMAGE_LOCATION ) ;
if ( iso ) umount ( IMAGE_LOCATION ) ;
results = RETURN_BACK ;
}
} while ( results = = RETURN_BACK ) ;
log_message ( " found the %s Installation, good news! " , version ) ;
stat ( ramdisk_path , & st ) ;
if ( S_ISDIR ( st . st_mode ) ) {
mount ( ramdisk_path , STAGE2_LOCATION , NULL , MS_BIND , NULL ) ;
} else {
do_losetup ( LIVE_DEVICE , ramdisk_path ) ;
my_mount ( LIVE_DEVICE , STAGE2_LOCATION , ( IS_LIVE ) ? LIVEFS : STAGE2FS , 0 ) ;
}
method_name = strdup ( " cifs " ) ;
add_to_env ( " METHOD " , method_name ) ;
add_to_env ( " HOST " , answers [ 0 ] ) ;
2021-04-05 12:05:51 +03:00
add_to_env ( " PREFIX " , " / " ) ;
add_to_env ( " DIRECTORY " , answers [ 1 ] ) ;
2014-01-11 18:49:44 +04:00
update_splash ( " found_media " ) ;
return RETURN_OK ;
}
# endif
2004-01-20 21:32:43 +03:00
enum return_type ftp_prepare ( void )
{
2007-08-02 20:45:59 +04:00
char * questions [ ] = { " FTP server " , " Directory " , " Login " , " Password " , NULL } ;
2004-01-20 21:32:43 +03:00
char * questions_auto [ ] = { " server " , " directory " , " user " , " pass " , NULL } ;
static char * * answers = NULL ;
enum return_type results ;
2010-11-22 19:56:35 +03:00
update_splash ( " prepare " ) ;
2004-01-20 21:32:43 +03:00
results = intf_select_and_up ( ) ;
if ( results ! = RETURN_OK )
return results ;
do {
char location_full [ 500 ] ;
int ftp_serv_response ;
int fd , size ;
2017-12-07 17:50:32 +03:00
char * tmp ;
2004-01-20 21:32:43 +03:00
2007-08-02 20:45:59 +04:00
snprintf ( location_full , sizeof ( location_full ) ,
" Please enter the name or IP address of the FTP server, "
" the directory containing the %s Distribution, "
" and the login/pass if necessary (leave login blank for anonymous). " , version ) ;
results = ask_from_entries_auto ( location_full , questions , & answers , 40 , questions_auto , NULL ) ;
2004-01-20 21:32:43 +03:00
if ( results ! = RETURN_OK | | streq ( answers [ 0 ] , " " ) ) {
unset_param ( MODE_AUTOMATIC ) ; /* we are in a fallback mode */
return ftp_prepare ( ) ;
}
log_message ( " FTP: trying to connect to %s " , answers [ 0 ] ) ;
ftp_serv_response = ftp_open_connection ( answers [ 0 ] , answers [ 2 ] , answers [ 3 ] , " " ) ;
if ( ftp_serv_response < 0 ) {
log_message ( " FTP: error connect %d " , ftp_serv_response ) ;
if ( ftp_serv_response = = FTPERR_BAD_HOSTNAME )
stg1_error_message ( " Error: bad hostname. " ) ;
else if ( ftp_serv_response = = FTPERR_FAILED_CONNECT )
stg1_error_message ( " Error: failed to connect to remote host. " ) ;
else
stg1_error_message ( " Error: couldn't connect. " ) ;
results = RETURN_BACK ;
continue ;
}
strcpy ( location_full , answers [ 1 ] ) ;
2017-12-07 17:50:32 +03:00
tmp = get_ramdisk_realname ( ) ;
strcat ( location_full , tmp ) ;
free ( tmp ) ;
2004-01-20 21:32:43 +03:00
log_message ( " FTP: trying to retrieve %s " , location_full ) ;
fd = ftp_start_download ( ftp_serv_response , location_full , & size ) ;
if ( fd < 0 ) {
log_message ( " FTP: error get %d " , fd ) ;
if ( fd = = FTPERR_PASSIVE_ERROR )
stg1_error_message ( " Error: error with passive connection. " ) ;
else if ( fd = = FTPERR_FILE_NOT_FOUND )
stg1_error_message ( " Error: file not found (%s). " , location_full ) ;
else if ( fd = = FTPERR_BAD_SERVER_RESPONSE )
stg1_error_message ( " Error: bad server response (server too busy?). " ) ;
else
stg1_error_message ( " Error: couldn't retrieve Installation program. " ) ;
results = RETURN_BACK ;
continue ;
}
2021-08-18 14:40:18 +03:00
if ( ! ramdisk_possible ( size ) ) {
close ( fd ) ;
close ( ftp_serv_response ) ;
stg1_error_message ( " FTP install needs more than %u Mbytes of memory (detected %u Mbytes). " ,
BYTES2MB ( size ) * 2 , BYTES2MB ( total_memory ( ) ) ) ;
return RETURN_ERROR ;
}
2004-01-20 21:32:43 +03:00
log_message ( " FTP: size of download %d bytes " , size ) ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
results = load_ramdisk_fd ( fd , size ) ;
if ( results = = RETURN_OK )
ftp_end_data_command ( ftp_serv_response ) ;
else
return results ;
method_name = strdup ( " ftp " ) ;
2005-01-21 16:52:04 +03:00
add_to_env ( " METHOD " , method_name ) ;
2004-01-20 21:32:43 +03:00
add_to_env ( " HOST " , answers [ 0 ] ) ;
add_to_env ( " PREFIX " , answers [ 1 ] ) ;
if ( strcmp ( answers [ 2 ] , " " ) ) {
add_to_env ( " LOGIN " , answers [ 2 ] ) ;
add_to_env ( " PASSWORD " , answers [ 3 ] ) ;
}
}
while ( results = = RETURN_BACK ) ;
2010-11-22 19:56:35 +03:00
update_splash ( " found_media " ) ;
2004-01-20 21:32:43 +03:00
return RETURN_OK ;
}
enum return_type http_prepare ( void )
{
2007-08-02 20:45:59 +04:00
char * questions [ ] = { " HTTP server " , " Directory " , NULL } ;
2004-01-20 21:32:43 +03:00
char * questions_auto [ ] = { " server " , " directory " , NULL } ;
static char * * answers = NULL ;
enum return_type results ;
2010-11-22 19:56:35 +03:00
update_splash ( " prepare " ) ;
2005-04-21 15:06:44 +04:00
2004-01-20 21:32:43 +03:00
results = intf_select_and_up ( ) ;
if ( results ! = RETURN_OK )
return results ;
do {
char location_full [ 500 ] ;
2017-12-07 17:50:32 +03:00
char * tmp ;
2021-08-08 12:53:45 +03:00
int fd ;
unsigned long size ;
2021-08-08 13:03:54 +03:00
int is_iso = 0 ;
2004-01-20 21:32:43 +03:00
2007-08-02 20:45:59 +04:00
snprintf ( location_full , sizeof ( location_full ) ,
" Please enter the name or IP address of the HTTP server, "
" and the directory containing the %s Distribution. " , version ) ;
results = ask_from_entries_auto ( location_full , questions , & answers , 40 , questions_auto , NULL ) ;
2004-01-20 21:32:43 +03:00
if ( results ! = RETURN_OK | | streq ( answers [ 0 ] , " " ) ) {
unset_param ( MODE_AUTOMATIC ) ; /* we are in a fallback mode */
return http_prepare ( ) ;
}
strcpy ( location_full , answers [ 1 ] ) ;
2021-08-08 13:03:54 +03:00
log_message ( " HTTP: trying to retrieve %s " , location_full ) ;
fd = http_download_file ( answers [ 0 ] , location_full , & size ) ;
if ( fd > = 0 ) {
is_iso = 1 ;
goto download ;
}
2017-12-07 17:50:32 +03:00
tmp = get_ramdisk_realname ( ) ;
strcat ( location_full , tmp ) ;
free ( tmp ) ;
2004-01-20 21:32:43 +03:00
log_message ( " HTTP: trying to retrieve %s " , location_full ) ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
fd = http_download_file ( answers [ 0 ] , location_full , & size ) ;
if ( fd < 0 ) {
log_message ( " HTTP: error %d " , fd ) ;
if ( fd = = FTPERR_FAILED_CONNECT )
stg1_error_message ( " Error: couldn't connect to server. " ) ;
else
stg1_error_message ( " Error: couldn't get file (%s). " , location_full ) ;
results = RETURN_BACK ;
continue ;
}
2021-08-08 13:03:54 +03:00
download :
2021-08-18 14:33:23 +03:00
if ( ! ramdisk_possible ( size ) ) {
close ( fd ) ;
stg1_error_message ( " HTTP install needs more than %u Mbytes of memory (detected %u Mbytes). " ,
BYTES2MB ( size ) * 2 , BYTES2MB ( total_memory ( ) ) ) ;
return RETURN_ERROR ;
}
2021-08-08 12:53:45 +03:00
log_message ( " HTTP: size of download %lu bytes " , size ) ;
2018-05-09 15:21:26 +03:00
2021-08-08 13:03:54 +03:00
results = load_ramdisk_or_iso ( fd , size , is_iso ) ;
2019-08-29 18:56:37 +03:00
close ( fd ) ;
if ( results ! = RETURN_OK )
2004-01-20 21:32:43 +03:00
return RETURN_ERROR ;
method_name = strdup ( " http " ) ;
2005-01-21 16:52:04 +03:00
add_to_env ( " METHOD " , method_name ) ;
2005-02-03 21:10:15 +03:00
add_to_env ( " HOST " , answers [ 0 ] ) ;
add_to_env ( " PREFIX " , answers [ 1 ] ) ;
2004-01-20 21:32:43 +03:00
}
while ( results = = RETURN_BACK ) ;
2010-11-22 19:56:35 +03:00
update_splash ( " found_media " ) ;
2004-01-20 21:32:43 +03:00
return RETURN_OK ;
}