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-05-09 15:21:26 +03:00
* Copyright 1996 Red Hat Software
2004-01-20 21:32:43 +03:00
*
*/
/*
* This contains stuff related to probing :
* ( 1 ) any ( actually only SCSI , NET , CPQ , USB Controllers ) devices ( autoprobe for PCI and USB )
* ( 2 ) IDE media
* ( 3 ) SCSI media
* ( 4 ) ETH devices
*/
# include <stdlib.h>
# include <unistd.h>
# include <stdio.h>
# include <string.h>
# include <sys/types.h>
# include <sys/stat.h>
2008-03-15 23:59:16 +03:00
# include <sys/socket.h>
2004-01-20 21:32:43 +03:00
# include <fcntl.h>
# include <net/if.h>
# include <sys/ioctl.h>
# include <sys/mount.h>
2007-02-27 16:11:49 +03:00
# include <dirent.h>
2004-01-20 21:32:43 +03:00
# include "stage1.h"
# include "log.h"
# include "frontend.h"
# include "modules.h"
# include "probing.h"
struct media_info {
char * name ;
char * model ;
enum media_type type ;
} ;
# ifndef DISABLE_NETWORK
struct net_description_elem
{
char * intf_name ;
char * intf_description ;
} ;
2018-04-22 15:48:10 +03:00
static char * net_dev_black_list [ ] = { " lo " , " wlan " , /* add what you need here! */ NULL } ;
2004-01-20 21:32:43 +03:00
static struct net_description_elem net_descriptions [ 50 ] ;
static int net_descr_number = 0 ;
static char * intf_descr_for_discover = NULL ;
static char * net_intf_too_early_name [ 50 ] ; /* for modules providing more than one net intf */
static int net_intf_too_early_number = 0 ;
static int net_intf_too_early_ptr = 0 ;
void net_discovered_interface ( char * intf_name )
{
if ( ! intf_descr_for_discover ) {
net_intf_too_early_name [ net_intf_too_early_number + + ] = strdup ( intf_name ) ;
return ;
}
if ( ! intf_name ) {
if ( net_intf_too_early_ptr > = net_intf_too_early_number ) {
log_message ( " NET: was expecting another network interface (broken net module?) " ) ;
return ;
}
net_descriptions [ net_descr_number ] . intf_name = net_intf_too_early_name [ net_intf_too_early_ptr + + ] ;
}
else
net_descriptions [ net_descr_number ] . intf_name = strdup ( intf_name ) ;
net_descriptions [ net_descr_number ] . intf_description = strdup ( intf_descr_for_discover ) ;
intf_descr_for_discover = NULL ;
net_descr_number + + ;
}
char * get_net_intf_description ( char * intf_name )
{
2008-02-29 20:09:32 +03:00
char dev [ SYSFS_PATH_MAX ] ;
char drv [ SYSFS_PATH_MAX ] ;
ssize_t i ;
2018-05-09 15:21:26 +03:00
2008-02-29 20:09:32 +03:00
snprintf ( dev , SYSFS_PATH_MAX , " /sys/class/net/%s/device/driver " , intf_name ) ;
if ( ( i = readlink ( dev , drv , SYSFS_PATH_MAX ) ) > 0 ) {
drv [ i ] = ' \0 ' ;
2008-03-01 19:16:25 +03:00
return strdup ( strrchr ( drv , ' / ' ) + 1 ) ;
2008-02-29 20:09:32 +03:00
} else {
return strdup ( " unknown " ) ;
}
2004-01-20 21:32:43 +03:00
}
# endif
# ifndef DISABLE_MEDIAS
static struct media_info * medias = NULL ;
2011-12-16 20:03:42 +04:00
static int usb_not_there ( void )
{
2011-12-16 22:24:21 +04:00
DIR * dir = opendir ( " /sys/module/usb_storage " ) ;
if ( dir ) closedir ( dir ) ;
return ! dir ;
2011-12-16 20:03:42 +04:00
}
2007-03-01 19:25:26 +03:00
static void find_media ( void )
2007-02-27 16:11:49 +03:00
{
2007-03-01 19:25:26 +03:00
FILE * f ;
2007-02-27 16:11:49 +03:00
DIR * dir = NULL ;
struct dirent * dirent = NULL ;
struct stat st ;
2007-03-01 19:25:26 +03:00
struct media_info tmp [ 50 ] ;
2007-02-27 16:11:49 +03:00
char path [ SYSFS_PATH_MAX ] ;
2007-03-01 19:25:26 +03:00
char buf [ 512 ] ;
2007-02-27 16:11:49 +03:00
char * s ;
2011-12-16 20:03:42 +04:00
int i = 0 , count = 0 ;
2007-03-01 19:25:26 +03:00
2008-02-29 18:14:39 +03:00
if ( medias )
2007-03-01 19:25:26 +03:00
free ( medias ) ; /* that does not free the strings, by the way */
2011-12-16 20:03:42 +04:00
log_message ( " checking for /sys/module/usb_storage directory " ) ;
if ( usb_not_there ( ) ) {
wait_message ( " Waiting for USB storage devices to show up... " ) ;
my_insmod ( " usb_storage " , NULL ) ;
2015-02-26 20:37:07 +03:00
my_insmod ( " sd_mod " , NULL ) ;
2016-10-24 20:51:31 +03:00
my_insmod ( " uas " , NULL ) ;
2011-12-19 22:10:52 +04:00
while ( usb_not_there ( ) & & ( i < 10 ) ) {
2011-12-16 20:03:42 +04:00
sleep ( 1 ) ;
i + + ;
2011-12-19 22:10:52 +04:00
}
2008-04-16 15:36:23 +04:00
remove_wait_message ( ) ;
}
2007-02-27 16:11:49 +03:00
if ( ( dir = opendir ( " /sys/block " ) ) = = NULL ) {
log_message ( " failed to open /sys/block directory " ) ;
return ;
}
while ( ( dirent = readdir ( dir ) ) ! = NULL ) {
2007-03-01 19:25:26 +03:00
if ( ! strcmp ( dirent - > d_name , " . " ) | |
! strcmp ( dirent - > d_name , " .. " ) ) continue ;
2017-12-08 16:12:52 +03:00
2007-02-27 16:11:49 +03:00
memset ( path , 0 , SYSFS_PATH_MAX ) ;
strcpy ( path , " /sys/block/ " ) ;
strcat ( path , dirent - > d_name ) ;
s = path + strlen ( path ) ;
2004-01-20 21:32:43 +03:00
2007-03-01 19:25:26 +03:00
/* probe for scsi type */
strcat ( path , " /device/type " ) ;
if ( lstat ( path , & st ) = = 0 & & S_ISREG ( st . st_mode ) ) {
tmp [ count ] . name = strdup ( dirent - > d_name ) ;
tmp [ count ] . type = UNKNOWN_MEDIA ;
if ( ( f = fopen ( path , " r " ) ) ! = NULL ) {
2017-12-08 16:12:52 +03:00
int type = SCSI_TYPE_DISK ;
if ( fgets ( buf , sizeof ( buf ) , f ) > 0 ) {
2018-11-17 22:53:22 +03:00
if ( ! strncmp ( buf , " MMC " , 3 ) | | ! strncmp ( buf , " SD " , 2 ) )
2017-12-08 16:12:52 +03:00
tmp [ count ] . type = DISK ;
else if ( sscanf ( buf , " %d " , & type ) > 0 ) {
if ( type = = SCSI_TYPE_DISK ) tmp [ count ] . type = DISK ;
else if ( type = = SCSI_TYPE_ROM ) tmp [ count ] . type = CDROM ;
else if ( type = = SCSI_TYPE_TAPE ) tmp [ count ] . type = TAPE ;
}
2007-03-01 19:25:26 +03:00
}
fclose ( f ) ;
}
2004-01-20 21:32:43 +03:00
2007-03-01 19:25:26 +03:00
* s = 0 ;
strcat ( path , " /device/model " ) ;
if ( ( f = fopen ( path , " r " ) ) ! = NULL ) {
if ( fgets ( buf , sizeof ( buf ) , f ) ) {
2007-08-02 20:08:13 +04:00
if ( buf [ strlen ( buf ) - 1 ] = = ' \n ' )
buf [ strlen ( buf ) - 1 ] = 0 ;
2007-03-01 19:25:26 +03:00
tmp [ count ] . model = strdup ( buf ) ;
}
fclose ( f ) ;
} else {
tmp [ count ] . model = strdup ( " (unknown) " ) ;
}
2004-01-20 21:32:43 +03:00
2007-03-01 19:25:26 +03:00
log_message ( " SCSI/%d: %s is a %s " , tmp [ count ] . type , tmp [ count ] . name , tmp [ count ] . model ) ;
count + + ;
2004-01-20 21:32:43 +03:00
continue ;
}
2007-03-01 19:25:26 +03:00
/* assume ide */
* s = 0 ;
strcat ( s , " /device/media " ) ;
if ( lstat ( path , & st ) = = 0 & & S_ISREG ( st . st_mode ) ) {
tmp [ count ] . name = strdup ( dirent - > d_name ) ;
2004-01-20 21:32:43 +03:00
tmp [ count ] . type = UNKNOWN_MEDIA ;
2007-03-01 19:25:26 +03:00
if ( ( f = fopen ( path , " r " ) ) ! = NULL ) {
if ( fgets ( buf , sizeof ( buf ) , f ) ) {
if ( ! strncmp ( " disk " , buf , 4 ) )
2004-01-20 21:32:43 +03:00
tmp [ count ] . type = DISK ;
2007-03-01 19:25:26 +03:00
else if ( ! strncmp ( " cdrom " , buf , 5 ) )
tmp [ count ] . type = CDROM ;
else if ( ! strncmp ( " tape " , buf , 4 ) )
tmp [ count ] . type = TAPE ;
else if ( ! strncmp ( " floppy " , buf , 6 ) )
tmp [ count ] . type = FLOPPY ;
2004-01-20 21:32:43 +03:00
}
2007-03-01 19:25:26 +03:00
fclose ( f ) ;
2004-01-20 21:32:43 +03:00
}
2007-03-01 19:25:26 +03:00
/* grab model */
strcpy ( path , " /proc/ide/ " ) ;
strcat ( path , dirent - > d_name ) ;
strcat ( path , " /model " ) ;
if ( ( f = fopen ( path , " r " ) ) ! = NULL ) {
if ( fgets ( buf , sizeof ( buf ) , f ) ) {
2007-08-02 20:08:13 +04:00
if ( buf [ strlen ( buf ) - 1 ] = = ' \n ' )
buf [ strlen ( buf ) - 1 ] = 0 ;
2007-03-01 19:25:26 +03:00
tmp [ count ] . model = strdup ( buf ) ;
2004-01-20 21:32:43 +03:00
}
2007-03-01 19:25:26 +03:00
fclose ( f ) ;
} else {
tmp [ count ] . model = strdup ( " (none) " ) ;
2004-01-20 21:32:43 +03:00
}
2007-03-01 19:25:26 +03:00
log_message ( " IDE/%d: %s is a %s " , tmp [ count ] . type , tmp [ count ] . name , tmp [ count ] . model ) ;
count + + ;
2004-01-20 21:32:43 +03:00
}
}
2007-03-01 19:25:26 +03:00
closedir ( dir ) ;
2004-01-20 21:32:43 +03:00
tmp [ count ] . name = NULL ;
count + + ;
medias = memdup ( tmp , sizeof ( struct media_info ) * count ) ;
}
/* Finds by media */
void get_medias ( enum media_type media , char * * * names , char * * * models )
{
struct media_info * m ;
2016-12-26 14:42:05 +03:00
char * tmp_names [ 250 ] ;
char * tmp_models [ 250 ] ;
2004-01-20 21:32:43 +03:00
int count ;
find_media ( ) ;
m = medias ;
count = 0 ;
while ( m & & m - > name ) {
2012-02-10 18:18:48 +04:00
/* detect hybrid iso images (those dumped to a USB stick) */
if ( ( m - > type = = media ) | | ( ( media = = CDROM ) & & ( m - > type = = DISK ) ) ) {
2004-01-20 21:32:43 +03:00
tmp_names [ count ] = strdup ( m - > name ) ;
tmp_models [ count + + ] = strdup ( m - > model ) ;
}
m + + ;
}
tmp_names [ count ] = NULL ;
tmp_models [ count + + ] = NULL ;
* names = memdup ( tmp_names , sizeof ( char * ) * count ) ;
* models = memdup ( tmp_models , sizeof ( char * ) * count ) ;
}
# endif /* DISABLE_MEDIAS */
# ifndef DISABLE_NETWORK
2021-08-02 02:49:42 +03:00
static int net_device_has_carrier ( const char * device ) {
int fd = - 1 ;
char * p = NULL ;
int ret = 0 ;
char state = ' \0 ' ;
if ( asprintf ( & p , " /sys/class/net/%s/carrier " , device ) = = - 1 ) {
log_message ( " net_device_has_carrier: OOM " ) ;
return 0 ;
}
fd = open ( p , O_RDONLY ) ;
if ( fd < 0 ) {
log_perror ( " net_device_has_carrier: failed to open sysfs knob " ) ;
goto out ;
}
if ( read ( fd , & state , 1 ) ! = 1 ) {
log_perror ( " net_device_has_carrier: failed to read sysfs knob " ) ;
goto out ;
}
ret = ! ! ( state = = ' 1 ' ) ;
out :
if ( p ) {
free ( p ) ;
p = NULL ;
}
if ( fd > = 0 ) {
close ( fd ) ;
fd = - 1 ;
}
return ret ;
}
2008-02-29 18:14:39 +03:00
static int net_device_available ( char * device )
2004-11-22 16:47:29 +03:00
{
2004-01-20 21:32:43 +03:00
struct ifreq req ;
int s ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
s = socket ( AF_INET , SOCK_DGRAM , 0 ) ;
if ( s < 0 ) {
log_perror ( device ) ;
return 0 ;
}
strcpy ( req . ifr_name , device ) ;
if ( ioctl ( s , SIOCGIFFLAGS , & req ) ) {
/* if we can't get the flags, the networking device isn't available */
close ( s ) ;
return 0 ;
}
2021-08-02 02:49:42 +03:00
if ( ! ( req . ifr_flags & IFF_UP ) ) {
req . ifr_flags | = IFF_UP ;
if ( ioctl ( s , SIOCSIFFLAGS , & req ) ) {
log_perror ( " ifup " ) ;
/* skip the interface we can't bring up */
}
/* XXX: we want to report only interfaces with carrier as available.
* However calling net_device_has_carrier right after ifup is useless :
* the kernel needs some time to figure out if the carrier is present .
* Therefore report that this interface is * not * available .
* intf_select_and_up will wait a second and retry if necessary
* ( i . e . no interfaces with carrier have been found ) , and on the next
* attempt ` device ` will be already up , and we ' ll check if ` device `
* has the carrier .
*
* Sounds a bit tricky ? A simple solution is to put sleep ( 1 ) after
* ifup , but there might be quite a number of interfaces ( I ' ve got
* boards with 4 and 6 Ethernets ) , and sleeping for O ( N ) seconds
* for no good reason might be annoying .
* Oh , alternatively we could setup a full - fledged event loop and
* wait for netlink notifications , but that ' s too much code and
* * complexity * .
*/
close ( s ) ;
return 0 ;
}
/* `device` was already up (perhaps we've brought it up during
* previous calls ) , check if it has the carrier
*/
2004-01-20 21:32:43 +03:00
close ( s ) ;
2021-08-02 02:49:42 +03:00
return net_device_has_carrier ( device ) ;
2004-01-20 21:32:43 +03:00
}
char * * get_net_devices ( void )
{
2013-02-14 17:08:46 +04:00
DIR * sys_net ;
2018-04-22 15:48:10 +03:00
char * tmp [ 50 ] = { NULL } ;
2013-02-14 17:08:46 +04:00
struct dirent * ent ;
2018-04-22 15:48:10 +03:00
int drop , j , i = 0 ;
2004-01-20 21:32:43 +03:00
2018-04-22 15:48:10 +03:00
sys_net = opendir ( " /sys/class/net " ) ;
if ( sys_net = = NULL )
return memdup ( tmp , sizeof ( tmp [ 0 ] ) ) ;
while ( ( ent = readdir ( sys_net ) ) ! = NULL )
{
/* check interface name in black list */
for ( drop = j = 0 ; net_dev_black_list [ j ] ! = NULL ; j + + )
if ( strncmp ( ent - > d_name , net_dev_black_list [ j ] , strlen ( net_dev_black_list [ j ] ) ) = = 0 ) {
drop = - 1 ;
break ;
}
if ( ! drop & & net_device_available ( ent - > d_name ) ) {
2013-02-14 17:08:46 +04:00
tmp [ i + + ] = strdup ( ent - > d_name ) ;
}
2004-01-20 21:32:43 +03:00
}
tmp [ i + + ] = NULL ;
2018-04-22 15:48:10 +03:00
closedir ( sys_net ) ;
return memdup ( tmp , sizeof ( tmp [ 0 ] ) * i ) ;
}
2004-01-20 21:32:43 +03:00
2018-04-22 15:48:10 +03:00
/* reverse for get_net_devices() to avoid memory leaks */
void free_net_devices ( char * * list )
{
char * * item ;
for ( item = list ; * item ; item + + ) {
free ( * item ) ;
* item = NULL ;
}
free ( list ) ;
2004-01-20 21:32:43 +03:00
}
# endif /* DISABLE_NETWORK */