@ -52,6 +52,25 @@ static void __init find_tempdir(void)
strcat ( tempdir , " / " ) ;
}
/*
* Remove bytes from the front of the buffer and refill it so that if there ' s a
* partial string that we care about , it will be completed , and we can recognize
* it .
*/
static int pop ( int fd , char * buf , size_t size , size_t npop )
{
ssize_t n ;
size_t len = strlen ( & buf [ npop ] ) ;
memmove ( buf , & buf [ npop ] , len + 1 ) ;
n = read ( fd , & buf [ len ] , size - len - 1 ) ;
if ( n < 0 )
return - errno ;
buf [ len + n ] = ' \0 ' ;
return 1 ;
}
/*
* This will return 1 , with the first character in buf being the
* character following the next instance of c in the file . This will
@ -61,7 +80,6 @@ static void __init find_tempdir(void)
static int next ( int fd , char * buf , size_t size , char c )
{
ssize_t n ;
size_t len ;
char * ptr ;
while ( ( ptr = strchr ( buf , c ) ) = = NULL ) {
@ -74,20 +92,129 @@ static int next(int fd, char *buf, size_t size, char c)
buf [ n ] = ' \0 ' ;
}
ptr + + ;
len = strlen ( ptr ) ;
memmove ( buf , ptr , len + 1 ) ;
return pop ( fd , buf , size , ptr - buf + 1 ) ;
}
/*
* Decode an octal - escaped and space - terminated path of the form used by
* / proc / mounts . May be used to decode a path in - place . " out " must be at least
* as large as the input . The output is always null - terminated . " len " gets the
* length of the output , excluding the trailing null . Returns 0 if a full path
* was successfully decoded , otherwise an error .
*/
static int decode_path ( const char * in , char * out , size_t * len )
{
char * first = out ;
int c ;
int i ;
int ret = - EINVAL ;
while ( 1 ) {
switch ( * in ) {
case ' \0 ' :
goto out ;
case ' ' :
ret = 0 ;
goto out ;
case ' \\ ' :
in + + ;
c = 0 ;
for ( i = 0 ; i < 3 ; i + + ) {
if ( * in < ' 0 ' | | * in > ' 7 ' )
goto out ;
c = ( c < < 3 ) | ( * in + + - ' 0 ' ) ;
}
* ( unsigned char * ) out + + = ( unsigned char ) c ;
break ;
default :
* out + + = * in + + ;
break ;
}
}
out :
* out = ' \0 ' ;
* len = out - first ;
return ret ;
}
/*
* Computes the length of s when encoded with three - digit octal escape sequences
* for the characters in chars .
*/
static size_t octal_encoded_length ( const char * s , const char * chars )
{
size_t len = strlen ( s ) ;
while ( ( s = strpbrk ( s , chars ) ) ! = NULL ) {
len + = 3 ;
s + + ;
}
return len ;
}
enum {
OUTCOME_NOTHING_MOUNTED ,
OUTCOME_TMPFS_MOUNT ,
OUTCOME_NON_TMPFS_MOUNT ,
} ;
/* Read a line of /proc/mounts data looking for a tmpfs mount at "path". */
static int read_mount ( int fd , char * buf , size_t bufsize , const char * path ,
int * outcome )
{
int found ;
int match ;
char * space ;
size_t len ;
enum {
MATCH_NONE ,
MATCH_EXACT ,
MATCH_PARENT ,
} ;
found = next ( fd , buf , bufsize , ' ' ) ;
if ( found ! = 1 )
return found ;
/*
* Refill the buffer so that if there ' s a partial string that we care
* about , it will be completed , and we can recognize it .
* If there ' s no following space in the buffer , then this path is
* truncated , so it can ' t be the one we ' re looking for .
*/
n = read ( fd , & buf [ len ] , size - len - 1 ) ;
if ( n < 0 )
return - errno ;
space = strchr ( buf , ' ' ) ;
if ( space ) {
match = MATCH_NONE ;
if ( ! decode_path ( buf , buf , & len ) ) {
if ( ! strcmp ( buf , path ) )
match = MATCH_EXACT ;
else if ( ! strncmp ( buf , path , len )
& & ( path [ len ] = = ' / ' | | ! strcmp ( buf , " / " ) ) )
match = MATCH_PARENT ;
}
found = pop ( fd , buf , bufsize , space - buf + 1 ) ;
if ( found ! = 1 )
return found ;
switch ( match ) {
case MATCH_EXACT :
if ( ! strncmp ( buf , " tmpfs " , strlen ( " tmpfs " ) ) )
* outcome = OUTCOME_TMPFS_MOUNT ;
else
* outcome = OUTCOME_NON_TMPFS_MOUNT ;
break ;
buf [ len + n ] = ' \0 ' ;
return 1 ;
case MATCH_PARENT :
/* This mount obscures any previous ones. */
* outcome = OUTCOME_NOTHING_MOUNTED ;
break ;
}
}
return next ( fd , buf , bufsize , ' \n ' ) ;
}
/* which_tmpdir is called only during early boot */
@ -106,8 +233,12 @@ static int checked_tmpdir = 0;
*/
static void which_tmpdir ( void )
{
int fd , found ;
char buf [ 128 ] = { ' \0 ' } ;
int fd ;
int found ;
int outcome ;
char * path ;
char * buf ;
size_t bufsize ;
if ( checked_tmpdir )
return ;
@ -116,49 +247,66 @@ static void which_tmpdir(void)
printf ( " Checking for tmpfs mount on /dev/shm... " ) ;
path = realpath ( " /dev/shm " , NULL ) ;
if ( ! path ) {
printf ( " failed to check real path, errno = %d \n " , errno ) ;
return ;
}
printf ( " %s... " , path ) ;
/*
* The buffer needs to be able to fit the full octal - escaped path , a
* space , and a trailing null in order to successfully decode it .
*/
bufsize = octal_encoded_length ( path , " \t \n \\ " ) + 2 ;
if ( bufsize < 128 )
bufsize = 128 ;
buf = malloc ( bufsize ) ;
if ( ! buf ) {
printf ( " malloc failed, errno = %d \n " , errno ) ;
goto out ;
}
buf [ 0 ] = ' \0 ' ;
fd = open ( " /proc/mounts " , O_RDONLY ) ;
if ( fd < 0 ) {
printf ( " failed to open /proc/mounts, errno = %d \n " , errno ) ;
return ;
goto out1 ;
}
outcome = OUTCOME_NOTHING_MOUNTED ;
while ( 1 ) {
found = next ( fd , buf , ARRAY_SIZE ( buf ) , ' ' ) ;
if ( found ! = 1 )
break ;
if ( ! strncmp ( buf , " /dev/shm " , strlen ( " /dev/shm " ) ) )
goto found ;
found = next ( fd , buf , ARRAY_SIZE ( buf ) , ' \n ' ) ;
found = read_mount ( fd , buf , bufsize , path , & outcome ) ;
if ( found ! = 1 )
break ;
}
err :
if ( found = = 0 )
printf ( " nothing mounted on /dev/shm \n " ) ;
else if ( found < 0 )
if ( found < 0 ) {
printf ( " read returned errno %d \n " , - found ) ;
} else {
switch ( outcome ) {
case OUTCOME_TMPFS_MOUNT :
printf ( " OK \n " ) ;
default_tmpdir = " /dev/shm " ;
break ;
out :
close ( fd ) ;
return ;
found :
found = next ( fd , buf , ARRAY_SIZE ( buf ) , ' ' ) ;
if ( found ! = 1 )
goto err ;
case OUTCOME_NON_TMPFS_MOUNT :
printf ( " not tmpfs \n " ) ;
break ;
if ( strncmp ( buf , " tmpfs " , strlen ( " tmpfs " ) ) ) {
printf ( " not tmpfs \n " ) ;
goto out ;
default :
printf ( " nothing mounted on /dev/shm \n " ) ;
break ;
}
}
printf ( " OK \n " ) ;
default_tmpdir = " /dev/shm " ;
goto out ;
close ( fd ) ;
out1 :
free ( buf ) ;
out :
free ( path ) ;
}
static int __init make_tempfile ( const char * template , char * * out_tempname ,