2005-09-17 06:27:50 +04:00
# include <stdio.h>
# include <stdlib.h>
# include <stddef.h>
# include <stdarg.h>
# include <unistd.h>
# include <errno.h>
# include <string.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/mman.h>
2006-04-19 09:21:43 +04:00
# include <sys/statfs.h>
2005-09-17 06:27:50 +04:00
# include "kern_util.h"
# include "user.h"
# include "user_util.h"
# include "mem_user.h"
# include "init.h"
# include "os.h"
# include "tempfile.h"
# include "kern_constants.h"
# include <sys/param.h>
2006-04-19 09:21:43 +04:00
static char * default_tmpdir = " /tmp " ;
2005-09-17 06:27:50 +04:00
static char * tempdir = NULL ;
static void __init find_tempdir ( void )
{
char * dirs [ ] = { " TMP " , " TEMP " , " TMPDIR " , NULL } ;
int i ;
char * dir = NULL ;
if ( tempdir ! = NULL ) return ; /* We've already been called */
for ( i = 0 ; dirs [ i ] ; i + + ) {
dir = getenv ( dirs [ i ] ) ;
if ( ( dir ! = NULL ) & & ( * dir ! = ' \0 ' ) )
break ;
}
if ( ( dir = = NULL ) | | ( * dir = = ' \0 ' ) )
2006-04-19 09:21:43 +04:00
dir = default_tmpdir ;
2005-09-17 06:27:50 +04:00
tempdir = malloc ( strlen ( dir ) + 2 ) ;
if ( tempdir = = NULL ) {
fprintf ( stderr , " Failed to malloc tempdir, "
" errno = %d \n " , errno ) ;
return ;
}
strcpy ( tempdir , dir ) ;
strcat ( tempdir , " / " ) ;
}
2006-04-19 09:21:43 +04:00
/* This will return 1, with the first character in buf being the
* character following the next instance of c in the file . This will
* read the file as needed . If there ' s an error , - errno is returned ;
* if the end of the file is reached , 0 is returned .
*/
static int next ( int fd , char * buf , int size , char c )
{
2006-06-30 12:55:54 +04:00
int n , len ;
2006-04-19 09:21:43 +04:00
char * ptr ;
while ( ( ptr = strchr ( buf , c ) ) = = NULL ) {
n = read ( fd , buf , size - 1 ) ;
if ( n = = 0 )
return 0 ;
else if ( n < 0 )
return - errno ;
buf [ n ] = ' \0 ' ;
}
ptr + + ;
2006-06-30 12:55:54 +04:00
len = strlen ( ptr ) ;
memmove ( buf , ptr , len + 1 ) ;
/* Refill the buffer so that if there's a partial string that we care
* about , it will be completed , and we can recognize it .
*/
n = read ( fd , & buf [ len ] , size - len - 1 ) ;
if ( n < 0 )
return - errno ;
buf [ len + n ] = ' \0 ' ;
2006-04-19 09:21:43 +04:00
return 1 ;
}
static int checked_tmpdir = 0 ;
/* Look for a tmpfs mounted at /dev/shm. I couldn't find a cleaner
* way to do this than to parse / proc / mounts . statfs will return the
* same filesystem magic number and fs id for both / dev and / dev / shm
* when they are both tmpfs , so you can ' t tell if they are different
* filesystems . Also , there seems to be no other way of finding the
* mount point of a filesystem from within it .
*
* If a / dev / shm tmpfs entry is found , then we switch to using it .
* Otherwise , we stay with the default / tmp .
*/
static void which_tmpdir ( void )
{
int fd , found ;
char buf [ 128 ] = { ' \0 ' } ;
if ( checked_tmpdir )
return ;
checked_tmpdir = 1 ;
printf ( " Checking for tmpfs mount on /dev/shm... " ) ;
fd = open ( " /proc/mounts " , O_RDONLY ) ;
if ( fd < 0 ) {
printf ( " failed to open /proc/mounts, errno = %d \n " , errno ) ;
return ;
}
while ( 1 ) {
2006-09-26 10:33:00 +04:00
found = next ( fd , buf , ARRAY_SIZE ( buf ) , ' ' ) ;
2006-04-19 09:21:43 +04:00
if ( found ! = 1 )
break ;
if ( ! strncmp ( buf , " /dev/shm " , strlen ( " /dev/shm " ) ) )
goto found ;
2006-09-26 10:33:00 +04:00
found = next ( fd , buf , ARRAY_SIZE ( buf ) , ' \n ' ) ;
2006-04-19 09:21:43 +04:00
if ( found ! = 1 )
break ;
}
err :
if ( found = = 0 )
printf ( " nothing mounted on /dev/shm \n " ) ;
else if ( found < 0 )
printf ( " read returned errno %d \n " , - found ) ;
2006-09-29 12:58:51 +04:00
out :
close ( fd ) ;
2006-04-19 09:21:43 +04:00
return ;
found :
2006-09-26 10:33:00 +04:00
found = next ( fd , buf , ARRAY_SIZE ( buf ) , ' ' ) ;
2006-04-19 09:21:43 +04:00
if ( found ! = 1 )
goto err ;
if ( strncmp ( buf , " tmpfs " , strlen ( " tmpfs " ) ) ) {
printf ( " not tmpfs \n " ) ;
2006-09-29 12:58:51 +04:00
goto out ;
2006-04-19 09:21:43 +04:00
}
printf ( " OK \n " ) ;
default_tmpdir = " /dev/shm " ;
2006-09-29 12:58:51 +04:00
goto out ;
2006-04-19 09:21:43 +04:00
}
2005-09-17 06:27:50 +04:00
/*
* This proc still used in tt - mode
* ( file : kernel / tt / ptproxy / proxy . c , proc : start_debugger ) .
* So it isn ' t ' static ' yet .
*/
int make_tempfile ( const char * template , char * * out_tempname , int do_unlink )
{
2006-04-11 09:53:39 +04:00
char * tempname ;
2005-09-17 06:27:50 +04:00
int fd ;
2006-04-19 09:21:43 +04:00
which_tmpdir ( ) ;
2006-04-11 09:53:39 +04:00
tempname = malloc ( MAXPATHLEN ) ;
2005-09-17 06:27:50 +04:00
find_tempdir ( ) ;
2006-04-11 09:53:39 +04:00
if ( template [ 0 ] ! = ' / ' )
2005-09-17 06:27:50 +04:00
strcpy ( tempname , tempdir ) ;
else
2006-04-11 09:53:39 +04:00
tempname [ 0 ] = ' \0 ' ;
2005-09-17 06:27:50 +04:00
strcat ( tempname , template ) ;
fd = mkstemp ( tempname ) ;
if ( fd < 0 ) {
fprintf ( stderr , " open - cannot create %s: %s \n " , tempname ,
strerror ( errno ) ) ;
2006-04-11 09:53:39 +04:00
goto out ;
2005-09-17 06:27:50 +04:00
}
if ( do_unlink & & ( unlink ( tempname ) < 0 ) ) {
perror ( " unlink " ) ;
2006-04-11 09:53:39 +04:00
goto out ;
2005-09-17 06:27:50 +04:00
}
if ( out_tempname ) {
2006-04-11 09:53:39 +04:00
* out_tempname = tempname ;
} else {
free ( tempname ) ;
2005-09-17 06:27:50 +04:00
}
return ( fd ) ;
2006-04-11 09:53:39 +04:00
out :
free ( tempname ) ;
return - 1 ;
2005-09-17 06:27:50 +04:00
}
# define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
/*
* This proc is used in start_up . c
* So it isn ' t ' static ' .
*/
2005-11-07 11:58:57 +03:00
int create_tmp_file ( unsigned long long len )
2005-09-17 06:27:50 +04:00
{
int fd , err ;
char zero ;
fd = make_tempfile ( TEMPNAME_TEMPLATE , NULL , 1 ) ;
if ( fd < 0 ) {
exit ( 1 ) ;
}
err = fchmod ( fd , 0777 ) ;
if ( err < 0 ) {
perror ( " os_mode_fd " ) ;
exit ( 1 ) ;
}
2006-06-30 12:55:55 +04:00
/* Seek to len - 1 because writing a character there will
* increase the file size by one byte , to the desired length .
*/
if ( lseek64 ( fd , len - 1 , SEEK_SET ) < 0 ) {
perror ( " os_seek_file " ) ;
2005-09-17 06:27:50 +04:00
exit ( 1 ) ;
}
zero = 0 ;
err = os_write_file ( fd , & zero , 1 ) ;
if ( err ! = 1 ) {
errno = - err ;
perror ( " os_write_file " ) ;
exit ( 1 ) ;
}
return ( fd ) ;
}
2005-11-07 11:58:57 +03:00
int create_mem_file ( unsigned long long len )
2005-09-17 06:27:50 +04:00
{
int err , fd ;
2006-03-31 14:30:08 +04:00
fd = create_tmp_file ( len ) ;
2005-09-17 06:27:50 +04:00
err = os_set_exec_close ( fd , 1 ) ;
if ( err < 0 ) {
errno = - err ;
perror ( " exec_close " ) ;
}
return ( fd ) ;
}
2006-04-19 09:21:43 +04:00
void check_tmpexec ( void )
{
void * addr ;
int err , fd = create_tmp_file ( UM_KERN_PAGE_SIZE ) ;
addr = mmap ( NULL , UM_KERN_PAGE_SIZE ,
PROT_READ | PROT_WRITE | PROT_EXEC , MAP_PRIVATE , fd , 0 ) ;
printf ( " Checking PROT_EXEC mmap in %s... " , tempdir ) ;
fflush ( stdout ) ;
if ( addr = = MAP_FAILED ) {
err = errno ;
perror ( " failed " ) ;
if ( err = = EPERM )
printf ( " %s must be not mounted noexec \n " , tempdir ) ;
exit ( 1 ) ;
}
printf ( " OK \n " ) ;
munmap ( addr , UM_KERN_PAGE_SIZE ) ;
close ( fd ) ;
}