2019-07-17 01:04:50 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* SMB root file system support
*
* Copyright ( c ) 2019 Paulo Alcantara < palcantara @ suse . de >
*/
# include <linux/init.h>
# include <linux/fs.h>
# include <linux/types.h>
# include <linux/ctype.h>
# include <linux/string.h>
# include <linux/root_dev.h>
# include <linux/kernel.h>
# include <linux/in.h>
# include <linux/inet.h>
# include <net/ipconfig.h>
# define DEFAULT_MNT_OPTS \
" vers=1.0,cifsacl,mfsymlinks,rsize=1048576,wsize=65536,uid=0,gid=0, " \
" hard,rootfs "
static char root_dev [ 2048 ] __initdata = " " ;
static char root_opts [ 1024 ] __initdata = DEFAULT_MNT_OPTS ;
static __be32 __init parse_srvaddr ( char * start , char * end )
{
2019-09-16 06:45:42 +03:00
/* TODO: ipv6 support */
2019-07-17 01:04:50 +03:00
char addr [ sizeof ( " aaa.bbb.ccc.ddd " ) ] ;
int i = 0 ;
while ( start < end & & i < sizeof ( addr ) - 1 ) {
if ( isdigit ( * start ) | | * start = = ' . ' )
addr [ i + + ] = * start ;
start + + ;
}
addr [ i ] = ' \0 ' ;
return in_aton ( addr ) ;
}
/* cifsroot=//<server-ip>/<share>[,options] */
static int __init cifs_root_setup ( char * line )
{
char * s ;
int len ;
__be32 srvaddr = htonl ( INADDR_NONE ) ;
ROOT_DEV = Root_CIFS ;
if ( strlen ( line ) > 3 & & line [ 0 ] = = ' / ' & & line [ 1 ] = = ' / ' ) {
s = strchr ( & line [ 2 ] , ' / ' ) ;
if ( ! s | | s [ 1 ] = = ' \0 ' )
return 1 ;
2019-09-16 06:45:42 +03:00
/* make s point to ',' or '\0' at end of line */
2019-07-17 01:04:50 +03:00
s = strchrnul ( s , ' , ' ) ;
2019-09-16 06:45:42 +03:00
/* len is strlen(unc) + '\0' */
2019-07-17 01:04:50 +03:00
len = s - line + 1 ;
2019-09-16 06:45:42 +03:00
if ( len > sizeof ( root_dev ) ) {
2020-04-15 08:42:53 +03:00
pr_err ( " Root-CIFS: UNC path too long \n " ) ;
2019-09-16 06:45:42 +03:00
return 1 ;
}
strlcpy ( root_dev , line , len ) ;
srvaddr = parse_srvaddr ( & line [ 2 ] , s ) ;
if ( * s ) {
int n = snprintf ( root_opts ,
sizeof ( root_opts ) , " %s,%s " ,
2019-07-17 01:04:50 +03:00
DEFAULT_MNT_OPTS , s + 1 ) ;
2019-09-16 06:45:42 +03:00
if ( n > = sizeof ( root_opts ) ) {
2020-04-15 08:42:53 +03:00
pr_err ( " Root-CIFS: mount options string too long \n " ) ;
2019-09-16 06:45:42 +03:00
root_opts [ sizeof ( root_opts ) - 1 ] = ' \0 ' ;
return 1 ;
2019-07-17 01:04:50 +03:00
}
}
}
root_server_addr = srvaddr ;
return 1 ;
}
__setup ( " cifsroot= " , cifs_root_setup ) ;
int __init cifs_root_data ( char * * dev , char * * opts )
{
if ( ! root_dev [ 0 ] | | root_server_addr = = htonl ( INADDR_NONE ) ) {
2020-04-15 08:42:53 +03:00
pr_err ( " Root-CIFS: no SMB server address \n " ) ;
2019-07-17 01:04:50 +03:00
return - 1 ;
}
* dev = root_dev ;
* opts = root_opts ;
return 0 ;
}