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
*
*/
2021-08-24 12:54:02 +03:00
# include <errno.h>
2004-01-20 21:32:43 +03:00
# include <stdlib.h>
2008-11-03 21:03:30 +03:00
# include <limits.h>
2004-01-20 21:32:43 +03:00
# include <unistd.h>
# include <string.h>
# include <sys/mount.h>
# include <sys/stat.h>
# include <sys/types.h>
2018-04-22 20:14:14 +03:00
# include <sys/sysmacros.h>
2008-03-13 19:12:12 +03:00
# include <sys/wait.h>
# ifndef DISABLE_NETWORK
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# endif
2004-01-20 21:32:43 +03:00
# include "log.h"
# include "modules.h"
# include "mount.h"
2008-03-13 19:12:12 +03:00
# include "dns.h"
2013-04-01 19:07:51 +04:00
# include "common.h"
2004-01-20 21:32:43 +03:00
# ifndef DISABLE_MEDIAS
/* WARNING: this won't work if the argument is not /dev/ based */
int ensure_dev_exists ( char * dev )
{
int major , minor ;
int type = S_IFBLK ; /* my default type is block. don't forget to change for chars */
char * name ;
struct stat buf ;
char * ptr ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
name = & dev [ 5 ] ; /* we really need that dev be passed as /dev/something.. */
if ( ! stat ( dev , & buf ) )
return 0 ; /* if the file already exists, we assume it's correct */
if ( name [ 0 ] = = ' s ' & & name [ 1 ] = = ' d ' ) {
/* SCSI disks */
major = 8 ;
minor = ( name [ 2 ] - ' a ' ) < < 4 ;
if ( name [ 3 ] & & name [ 4 ] )
minor + = 10 + ( name [ 4 ] - ' 0 ' ) ;
else if ( name [ 3 ] )
minor + = ( name [ 3 ] - ' 0 ' ) ;
} else if ( name [ 0 ] = = ' h ' & & name [ 1 ] = = ' d ' ) {
/* IDE disks/cd's */
if ( name [ 2 ] = = ' a ' )
major = 3 , minor = 0 ;
else if ( name [ 2 ] = = ' b ' )
major = 3 , minor = 64 ;
else if ( name [ 2 ] = = ' c ' )
major = 22 , minor = 0 ;
else if ( name [ 2 ] = = ' d ' )
major = 22 , minor = 64 ;
else if ( name [ 2 ] = = ' e ' )
major = 33 , minor = 0 ;
else if ( name [ 2 ] = = ' f ' )
major = 33 , minor = 64 ;
else if ( name [ 2 ] = = ' g ' )
major = 34 , minor = 0 ;
else if ( name [ 2 ] = = ' h ' )
major = 34 , minor = 64 ;
else
return - 1 ;
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
if ( name [ 3 ] & & name [ 4 ] )
minor + = 10 + ( name [ 4 ] - ' 0 ' ) ;
else if ( name [ 3 ] )
minor + = ( name [ 3 ] - ' 0 ' ) ;
} else if ( name [ 0 ] = = ' s ' & & name [ 1 ] = = ' r ' ) {
/* SCSI cd's */
major = 11 ;
minor = name [ 2 ] - ' 0 ' ;
} else if ( ptr_begins_static_str ( name , " ida/ " ) | |
ptr_begins_static_str ( name , " cciss/ " ) ) {
/* Compaq Smart Array "ida/c0d0{p1}" */
ptr = strchr ( name , ' / ' ) ;
2013-04-01 19:07:51 +04:00
mkdirs_dev ( " ida " , " cciss " , NULL ) ;
2004-01-20 21:32:43 +03:00
major = ptr_begins_static_str ( name , " ida/ " ) ? 72 : 104 + charstar_to_int ( ptr + 2 ) ;
ptr = strchr ( ptr , ' d ' ) ;
minor = 16 * charstar_to_int ( ptr + 1 ) ;
ptr = strchr ( ptr , ' p ' ) ;
minor + = charstar_to_int ( ptr + 1 ) ;
} else if ( ptr_begins_static_str ( name , " rd/ " ) ) {
/* DAC960 "rd/cXdXXpX" */
2013-04-01 19:07:51 +04:00
mkdir_dev ( " rd " ) ;
2004-01-20 21:32:43 +03:00
major = 48 + charstar_to_int ( name + 4 ) ;
ptr = strchr ( name + 4 , ' d ' ) ;
minor = 8 * charstar_to_int ( ptr + 1 ) ;
ptr = strchr ( ptr , ' p ' ) ;
minor + = charstar_to_int ( ptr + 1 ) ;
} else {
log_message ( " I don't know how to create device %s, please post bugreport to me! " , dev ) ;
return - 1 ;
}
if ( mknod ( dev , type | 0600 , makedev ( major , minor ) ) ) {
log_perror ( dev ) ;
return - 1 ;
}
2018-05-09 15:21:26 +03:00
2004-01-20 21:32:43 +03:00
return 0 ;
}
# endif /* DISABLE_MEDIAS */
2008-03-13 19:12:12 +03:00
# ifndef DISABLE_NETWORK
static int nfsmount ( char * dev , char * location )
{
char spec [ PATH_MAX + 17 ] , * sep ;
struct sockaddr_in saddr ;
2021-08-24 12:54:02 +03:00
pid_t pid ;
int n , status , ret = - 1 ;
2008-03-13 19:12:12 +03:00
if ( ( sep = strchr ( dev , ' : ' ) ) ) {
* sep = ' \0 ' ;
} else {
2013-08-21 17:30:56 +04:00
log_message ( " nfsmount: directory to mount not in host:dir format " ) ;
2021-08-24 12:54:02 +03:00
goto out ;
2008-03-13 19:12:12 +03:00
}
saddr . sin_family = AF_INET ;
if ( ! inet_aton ( dev , & saddr . sin_addr ) & &
mygethostbyname ( dev , & saddr . sin_addr ) ) {
2013-08-21 17:30:56 +04:00
log_message ( " nfsmount: can't get address for %s " , dev ) ;
2008-03-13 19:12:12 +03:00
* sep = ' : ' ;
2021-08-24 12:54:02 +03:00
goto out ;
2008-03-13 19:12:12 +03:00
}
* sep = ' : ' ;
strcpy ( spec , inet_ntoa ( saddr . sin_addr ) ) ;
n = strlen ( spec ) ;
strncpy ( spec + n , sep , sizeof ( spec ) - n ) ;
2013-08-21 17:30:56 +04:00
log_message ( " nfsmount %s %s " , spec , location ) ;
2008-03-13 19:12:12 +03:00
2021-08-24 12:54:02 +03:00
pid = fork ( ) ;
if ( pid < 0 ) {
log_message ( " %s: error: fork: %s " , __func__ , strerror ( errno ) ) ;
goto out ;
} else if ( pid = = 0 ) {
2013-08-21 17:30:56 +04:00
char * argv [ ] = { " /bin/nfsmount " , spec , location , NULL } ;
2021-08-24 12:54:02 +03:00
redirect2log ( STDOUT_FILENO ) ;
redirect2log ( STDERR_FILENO ) ;
redirect2null ( STDIN_FILENO ) ;
2008-03-13 19:12:12 +03:00
execve ( argv [ 0 ] , argv , NULL ) ;
exit ( 1 ) ;
2021-08-24 12:54:02 +03:00
} else {
if ( waitpid ( pid , & status , 0 ) < 0 ) {
log_message ( " %s: error: waitpid: %s " , __func__ , strerror ( errno ) ) ;
goto out ;
}
ret = ( WIFEXITED ( status ) & & ! WEXITSTATUS ( status ) ) ? 0 : - 1 ;
2008-03-13 19:12:12 +03:00
}
2021-08-24 12:54:02 +03:00
out :
return ret ;
2008-03-13 19:12:12 +03:00
}
2014-01-11 18:49:44 +04:00
# ifdef ENABLE_CIFS
2021-08-24 14:29:38 +03:00
static int cifsmount3 ( char * dev , char * location , const char * extra_opts )
2014-01-11 18:49:44 +04:00
{
char spec [ PATH_MAX + 19 ] , * sep , * ptr = dev ;
struct sockaddr_in saddr ;
2021-08-24 12:54:02 +03:00
pid_t pid ;
int n , status , ret = - 1 ;
2021-08-24 14:29:38 +03:00
const char * default_opts = " guest " ;
char * opts = NULL ;
if ( extra_opts ) {
if ( asprintf ( & opts , " %s,%s " , default_opts , extra_opts ) < 0 ) {
log_message ( " %s: error: asprintf " , __func__ ) ;
return - 1 ;
}
} else {
opts = strdup ( default_opts ) ;
if ( ! opts ) {
log_message ( " %s: error: strdup " , __func__ ) ;
return - 1 ;
}
}
2014-01-11 18:49:44 +04:00
while ( * ptr = = ' / ' ) ptr + + ;
if ( ( sep = strchr ( ptr , ' / ' ) ) ) {
* sep = ' \0 ' ;
} else {
log_message ( " cifsmount: directory to mount not in //host/dir format " ) ;
2021-08-24 12:54:02 +03:00
goto out ;
2014-01-11 18:49:44 +04:00
}
saddr . sin_family = AF_INET ;
if ( ! inet_aton ( ptr , & saddr . sin_addr ) & &
mygethostbyname ( ptr , & saddr . sin_addr ) ) {
log_message ( " cifsmount: can't get address for %s " , ptr ) ;
* sep = ' / ' ;
2021-08-24 12:54:02 +03:00
goto out ;
2014-01-11 18:49:44 +04:00
}
* sep = ' / ' ;
* spec = ' \0 ' ;
strcpy ( spec , " // " ) ;
strcat ( spec , inet_ntoa ( saddr . sin_addr ) ) ;
n = strlen ( spec ) ;
strncpy ( spec + n , sep , sizeof ( spec ) - n ) ;
2021-08-24 14:29:38 +03:00
log_message ( " /sbin/mount.cifs %s %s --verbose -o %s " , spec , location , opts ) ;
2014-01-11 18:49:44 +04:00
2021-08-24 12:54:02 +03:00
pid = fork ( ) ;
if ( pid < 0 ) {
log_message ( " %s: error: fork: %s " , __func__ , strerror ( errno ) ) ;
goto out ;
} else if ( pid = = 0 ) {
2021-08-24 14:29:38 +03:00
char * argv [ ] = { " /sbin/mount.cifs " , spec , location , " --verbose " , " -o " , opts , NULL } ;
2021-08-24 12:54:02 +03:00
redirect2log ( STDOUT_FILENO ) ;
redirect2log ( STDERR_FILENO ) ;
redirect2null ( STDIN_FILENO ) ;
2014-01-11 18:49:44 +04:00
execve ( argv [ 0 ] , argv , NULL ) ;
exit ( 1 ) ;
2021-08-24 12:54:02 +03:00
} else {
if ( waitpid ( pid , & status , 0 ) < 0 ) {
log_message ( " %s: error: waitpid: %s " , __func__ , strerror ( errno ) ) ;
goto out ;
}
ret = ( WIFEXITED ( status ) & & ! WEXITSTATUS ( status ) ) ? 0 : - 1 ;
2014-01-11 18:49:44 +04:00
}
2021-08-24 12:54:02 +03:00
out :
2021-08-24 14:29:38 +03:00
free ( opts ) ;
2021-08-24 12:54:02 +03:00
return ret ;
2014-01-11 18:49:44 +04:00
}
2021-08-24 14:29:38 +03:00
static int cifsmount ( char * dev , char * location )
{
int rc = 0 ;
static const char * fallbacks [ ] = {
" vers=2.1,sec=none " ,
" vers=2.0,sec=none " ,
" vers=1.0,sec=none " ,
NULL
} ;
const char * * opts = NULL ;
log_message ( " %s: attempting to mount %s with default protocol version " , __func__ , dev ) ;
rc = cifsmount3 ( dev , location , NULL ) ;
for ( opts = fallbacks ; rc < 0 & & * opts ; opts + + ) {
log_message ( " %s: failed, retrying with %s " , __func__ , * opts ) ;
rc = cifsmount3 ( dev , location , * opts ) ;
}
if ( rc < 0 ) {
log_message ( " %s: sorry, nothing worked " , __func__ ) ;
}
return rc ;
}
2014-01-11 18:49:44 +04:00
# endif
2008-03-13 19:12:12 +03:00
# endif
2004-01-20 21:32:43 +03:00
/* mounts, creating the device if needed+possible */
int my_mount ( char * dev , char * location , char * fs , int force_rw )
{
unsigned long flags = MS_MGC_VAL | ( force_rw ? 0 : MS_RDONLY ) ;
char * opts = NULL ;
struct stat buf ;
int rc ;
# ifndef DISABLE_MEDIAS
2014-01-11 18:49:44 +04:00
# ifdef ENABLE_CIFS
if ( strcmp ( fs , " nfs " ) & & strcmp ( fs , " cifs " ) ) {
# else
2004-01-20 21:32:43 +03:00
if ( strcmp ( fs , " nfs " ) ) {
2014-01-11 18:49:44 +04:00
# endif
2004-01-20 21:32:43 +03:00
rc = ensure_dev_exists ( dev ) ;
if ( rc ! = 0 ) {
log_message ( " could not create required device file " ) ;
return - 1 ;
}
}
# endif
log_message ( " mounting %s on %s as type %s " , dev , location , fs ) ;
if ( stat ( location , & buf ) ) {
if ( mkdir ( location , 0755 ) ) {
log_perror ( " could not create location dir " ) ;
return - 1 ;
}
} else if ( ! S_ISDIR ( buf . st_mode ) ) {
log_message ( " not a dir %s, will unlink and mkdir " , location ) ;
if ( unlink ( location ) ) {
log_perror ( " could not unlink " ) ;
return - 1 ;
}
if ( mkdir ( location , 0755 ) ) {
log_perror ( " could not create location dir " ) ;
return - 1 ;
}
}
2008-03-13 19:12:12 +03:00
# ifndef DISABLE_NETWORK
if ( ! strcmp ( fs , " nfs " ) ) {
return nfsmount ( dev , location ) ;
}
2014-01-11 18:49:44 +04:00
# ifdef ENABLE_CIFS
if ( ! strcmp ( fs , " cifs " ) ) {
return cifsmount ( dev , location ) ;
}
# endif
2008-03-13 19:12:12 +03:00
# endif
2004-01-20 21:32:43 +03:00
# ifndef DISABLE_MEDIAS
2005-04-12 23:32:01 +04:00
if ( ! strcmp ( fs , " squashfs " ) )
2008-03-01 22:02:06 +03:00
my_insmod ( " squashfs " , NULL ) ;
2005-04-12 23:32:01 +04:00
2005-02-16 20:51:48 +03:00
if ( ! strcmp ( fs , " ext2 " ) )
2008-03-01 22:02:06 +03:00
my_insmod ( " ext2 " , NULL ) ;
2013-07-16 17:39:08 +04:00
if ( ! strcmp ( fs , " ext3 " ) )
my_insmod ( " ext3 " , NULL ) ;
if ( ! strcmp ( fs , " ext4 " ) )
my_insmod ( " ext4 " , NULL ) ;
2005-02-16 20:51:48 +03:00
2004-01-20 21:32:43 +03:00
if ( ! strcmp ( fs , " vfat " ) ) {
2008-03-01 22:02:06 +03:00
my_insmod ( " vfat " , NULL ) ;
2004-01-20 21:32:43 +03:00
opts = " check=relaxed " ;
}
2021-03-23 08:08:02 +03:00
if ( ! strcmp ( fs , " exfat " ) ) {
my_insmod ( " exfat " , NULL ) ;
opts = " check=relaxed " ;
}
2005-03-02 20:48:28 +03:00
if ( ! strcmp ( fs , " ntfs " ) )
2008-03-01 22:02:06 +03:00
my_insmod ( " ntfs " , NULL ) ;
2005-03-02 20:48:28 +03:00
2004-01-20 21:32:43 +03:00
if ( ! strcmp ( fs , " reiserfs " ) )
2008-03-01 22:02:06 +03:00
my_insmod ( " reiserfs " , NULL ) ;
2004-01-20 21:32:43 +03:00
if ( ! strcmp ( fs , " iso9660 " ) )
2008-03-01 22:02:06 +03:00
my_insmod ( " isofs " , NULL ) ;
2004-01-20 21:32:43 +03:00
# endif
rc = mount ( dev , location , fs , flags , opts ) ;
if ( rc ! = 0 ) {
log_perror ( " mount failed " ) ;
rmdir ( location ) ;
}
return rc ;
}