2006-01-06 00:18:59 -08:00
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
# include <string.h>
# include <errno.h>
# include <signal.h>
# include <dirent.h>
2006-01-06 00:19:01 -08:00
# include <sys/fcntl.h>
2006-01-06 00:18:59 -08:00
# include <sys/stat.h>
# include <sys/param.h>
# include "init.h"
# include "os.h"
# include "user.h"
# include "mode.h"
# define UML_DIR "~ / .uml / "
# define UMID_LEN 64
/* Changed by set_umid, which is run early in boot */
char umid [ UMID_LEN ] = { 0 } ;
/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */
static char * uml_dir = UML_DIR ;
static int __init make_uml_dir ( void )
{
char dir [ 512 ] = { ' \0 ' } ;
2006-01-06 00:19:01 -08:00
int len , err ;
2006-01-06 00:18:59 -08:00
if ( * uml_dir = = ' ~ ' ) {
char * home = getenv ( " HOME " ) ;
2006-01-06 00:19:01 -08:00
err = - ENOENT ;
2006-01-06 00:18:59 -08:00
if ( home = = NULL ) {
2006-01-06 00:19:01 -08:00
printk ( " make_uml_dir : no value in environment for "
2006-01-06 00:18:59 -08:00
" $HOME \n " ) ;
2006-01-06 00:19:01 -08:00
goto err ;
2006-01-06 00:18:59 -08:00
}
strlcpy ( dir , home , sizeof ( dir ) ) ;
uml_dir + + ;
}
strlcat ( dir , uml_dir , sizeof ( dir ) ) ;
len = strlen ( dir ) ;
if ( len > 0 & & dir [ len - 1 ] ! = ' / ' )
strlcat ( dir , " / " , sizeof ( dir ) ) ;
2006-01-06 00:19:01 -08:00
err = - ENOMEM ;
2006-01-06 00:18:59 -08:00
uml_dir = malloc ( strlen ( dir ) + 1 ) ;
if ( uml_dir = = NULL ) {
printf ( " make_uml_dir : malloc failed, errno = %d \n " , errno ) ;
2006-01-06 00:19:01 -08:00
goto err ;
2006-01-06 00:18:59 -08:00
}
strcpy ( uml_dir , dir ) ;
if ( ( mkdir ( uml_dir , 0777 ) < 0 ) & & ( errno ! = EEXIST ) ) {
printf ( " Failed to mkdir '%s': %s \n " , uml_dir , strerror ( errno ) ) ;
2006-01-06 00:19:01 -08:00
err = - errno ;
goto err_free ;
2006-01-06 00:18:59 -08:00
}
return 0 ;
2006-01-06 00:19:01 -08:00
err_free :
free ( uml_dir ) ;
err :
uml_dir = NULL ;
return err ;
2006-01-06 00:18:59 -08:00
}
static int actually_do_remove ( char * dir )
{
DIR * directory ;
struct dirent * ent ;
int len ;
char file [ 256 ] ;
directory = opendir ( dir ) ;
2006-01-06 00:19:01 -08:00
if ( directory = = NULL )
return - errno ;
2006-01-06 00:18:59 -08:00
while ( ( ent = readdir ( directory ) ) ! = NULL ) {
if ( ! strcmp ( ent - > d_name , " . " ) | | ! strcmp ( ent - > d_name , " .. " ) )
continue ;
len = strlen ( dir ) + sizeof ( " / " ) + strlen ( ent - > d_name ) + 1 ;
2006-01-06 00:19:01 -08:00
if ( len > sizeof ( file ) )
return - E2BIG ;
2006-01-06 00:18:59 -08:00
sprintf ( file , " %s/%s " , dir , ent - > d_name ) ;
2006-01-06 00:19:01 -08:00
if ( unlink ( file ) < 0 )
return - errno ;
2006-01-06 00:18:59 -08:00
}
2006-01-06 00:19:01 -08:00
if ( rmdir ( dir ) < 0 )
return - errno ;
return 0 ;
2006-01-06 00:18:59 -08:00
}
2006-01-06 00:19:01 -08:00
/* This says that there isn't already a user of the specified directory even if
* there are errors during the checking . This is because if these errors
* happen , the directory is unusable by the pre - existing UML , so we might as
* well take it over . This could happen either by
* the existing UML somehow corrupting its umid directory
* something other than UML sticking stuff in the directory
* this boot racing with a shutdown of the other UML
* In any of these cases , the directory isn ' t useful for anything else .
*/
2006-01-06 00:18:59 -08:00
static int not_dead_yet ( char * dir )
{
char file [ strlen ( uml_dir ) + UMID_LEN + sizeof ( " /pid \0 " ) ] ;
char pid [ sizeof ( " nnnnn \0 " ) ] , * end ;
2006-01-06 00:19:01 -08:00
int dead , fd , p , n , err ;
n = snprintf ( file , sizeof ( file ) , " %s/pid " , dir ) ;
if ( n > = sizeof ( file ) ) {
printk ( " not_dead_yet - pid filename too long \n " ) ;
err = - E2BIG ;
goto out ;
}
2006-01-06 00:18:59 -08:00
dead = 0 ;
2006-01-06 00:19:01 -08:00
fd = open ( file , O_RDONLY ) ;
2006-04-10 22:53:38 -07:00
if ( fd < 0 ) {
fd = - errno ;
2006-01-06 00:18:59 -08:00
if ( fd ! = - ENOENT ) {
printk ( " not_dead_yet : couldn't open pid file '%s', "
" err = %d \n " , file , - fd ) ;
}
2006-01-06 00:19:01 -08:00
goto out ;
2006-01-06 00:18:59 -08:00
}
2006-01-06 00:19:01 -08:00
err = 0 ;
n = read ( fd , pid , sizeof ( pid ) ) ;
2006-04-10 22:53:38 -07:00
if ( n < 0 ) {
printk ( " not_dead_yet : couldn't read pid file '%s', "
" err = %d \n " , file , errno ) ;
goto out_close ;
} else if ( n = = 0 ) {
2006-01-06 00:19:01 -08:00
printk ( " not_dead_yet : couldn't read pid file '%s', "
2006-04-10 22:53:38 -07:00
" 0-byte read \n " , file ) ;
2006-01-06 00:19:01 -08:00
goto out_close ;
}
p = strtoul ( pid , & end , 0 ) ;
if ( end = = pid ) {
printk ( " not_dead_yet : couldn't parse pid file '%s', "
" errno = %d \n " , file , errno ) ;
goto out_close ;
2006-01-06 00:18:59 -08:00
}
2006-01-06 00:19:01 -08:00
2006-03-27 01:14:39 -08:00
if ( ( kill ( p , 0 ) = = 0 ) | | ( errno ! = ESRCH ) ) {
printk ( " umid \" %s \" is already in use by pid %d \n " , umid , p ) ;
2006-01-06 00:19:01 -08:00
return 1 ;
2006-03-27 01:14:39 -08:00
}
2006-01-06 00:19:01 -08:00
err = actually_do_remove ( dir ) ;
if ( err )
printk ( " not_dead_yet - actually_do_remove failed with "
" err = %d \n " , err ) ;
return err ;
2006-04-10 22:53:38 -07:00
out_close :
2006-01-06 00:19:01 -08:00
close ( fd ) ;
2006-04-10 22:53:38 -07:00
out :
2006-01-06 00:19:01 -08:00
return 0 ;
2006-01-06 00:18:59 -08:00
}
static void __init create_pid_file ( void )
{
char file [ strlen ( uml_dir ) + UMID_LEN + sizeof ( " /pid \0 " ) ] ;
char pid [ sizeof ( " nnnnn \0 " ) ] ;
int fd , n ;
if ( umid_file_name ( " pid " , file , sizeof ( file ) ) )
return ;
2006-01-06 00:19:01 -08:00
fd = open ( file , O_RDWR | O_CREAT | O_EXCL , 0644 ) ;
2006-01-06 00:18:59 -08:00
if ( fd < 0 ) {
2006-01-06 00:19:01 -08:00
printk ( " Open of machine pid file \" %s \" failed: %s \n " ,
2006-05-01 12:16:00 -07:00
file , strerror ( errno ) ) ;
2006-01-06 00:18:59 -08:00
return ;
}
2006-01-06 00:19:01 -08:00
snprintf ( pid , sizeof ( pid ) , " %d \n " , getpid ( ) ) ;
n = write ( fd , pid , strlen ( pid ) ) ;
2006-01-06 00:18:59 -08:00
if ( n ! = strlen ( pid ) )
2006-05-01 12:16:00 -07:00
printk ( " Write of pid file failed - err = %d \n " , errno ) ;
2006-01-06 00:19:01 -08:00
close ( fd ) ;
2006-01-06 00:18:59 -08:00
}
2006-01-06 00:19:01 -08:00
int __init set_umid ( char * name )
2006-01-06 00:18:59 -08:00
{
if ( strlen ( name ) > UMID_LEN - 1 )
2006-01-06 00:19:01 -08:00
return - E2BIG ;
2006-01-06 00:18:59 -08:00
strlcpy ( umid , name , sizeof ( umid ) ) ;
return 0 ;
}
static int umid_setup = 0 ;
2006-01-06 00:19:01 -08:00
int __init make_umid ( void )
2006-01-06 00:18:59 -08:00
{
int fd , err ;
char tmp [ 256 ] ;
2006-01-06 00:19:01 -08:00
if ( umid_setup )
return 0 ;
2006-01-06 00:18:59 -08:00
make_uml_dir ( ) ;
if ( * umid = = ' \0 ' ) {
strlcpy ( tmp , uml_dir , sizeof ( tmp ) ) ;
2006-01-06 00:19:01 -08:00
strlcat ( tmp , " XXXXXX " , sizeof ( tmp ) ) ;
2006-01-06 00:18:59 -08:00
fd = mkstemp ( tmp ) ;
if ( fd < 0 ) {
2006-01-06 00:19:01 -08:00
printk ( " make_umid - mkstemp(%s) failed: %s \n " ,
tmp , strerror ( errno ) ) ;
err = - errno ;
goto err ;
2006-01-06 00:18:59 -08:00
}
2006-01-06 00:19:01 -08:00
close ( fd ) ;
set_umid ( & tmp [ strlen ( uml_dir ) ] ) ;
2006-01-06 00:18:59 -08:00
/* There's a nice tiny little race between this unlink and
* the mkdir below . It ' d be nice if there were a mkstemp
* for directories .
*/
2006-01-06 00:19:01 -08:00
if ( unlink ( tmp ) ) {
err = - errno ;
goto err ;
}
2006-01-06 00:18:59 -08:00
}
2006-01-06 00:19:01 -08:00
snprintf ( tmp , sizeof ( tmp ) , " %s%s " , uml_dir , umid ) ;
2006-01-06 00:18:59 -08:00
err = mkdir ( tmp , 0777 ) ;
if ( err < 0 ) {
2006-01-06 00:19:01 -08:00
err = - errno ;
2006-03-27 01:14:39 -08:00
if ( err ! = - EEXIST )
2006-01-06 00:19:01 -08:00
goto err ;
2006-03-27 01:14:39 -08:00
/* 1 -> this umid is already in use
* < 0 - > we couldn ' t remove the umid directory
* In either case , we can ' t use this umid , so return - EEXIST .
*/
if ( not_dead_yet ( tmp ) ! = 0 )
2006-01-06 00:19:01 -08:00
goto err ;
err = mkdir ( tmp , 0777 ) ;
2006-01-06 00:18:59 -08:00
}
2006-03-27 01:14:39 -08:00
if ( err ) {
err = - errno ;
printk ( " Failed to create '%s' - err = %d \n " , umid , - errno ) ;
goto err ;
2006-01-06 00:18:59 -08:00
}
umid_setup = 1 ;
create_pid_file ( ) ;
2006-03-27 01:14:39 -08:00
err = 0 ;
2006-01-06 00:19:01 -08:00
err :
return err ;
2006-01-06 00:18:59 -08:00
}
static int __init make_umid_init ( void )
{
2006-03-27 01:14:39 -08:00
if ( ! make_umid ( ) )
return 0 ;
/* If initializing with the given umid failed, then try again with
* a random one .
*/
printk ( " Failed to initialize umid \" %s \" , trying with a random umid \n " ,
umid ) ;
* umid = ' \0 ' ;
2006-01-06 00:19:01 -08:00
make_umid ( ) ;
2006-01-06 00:18:59 -08:00
2006-01-06 00:19:01 -08:00
return 0 ;
2006-01-06 00:18:59 -08:00
}
__initcall ( make_umid_init ) ;
int __init umid_file_name ( char * name , char * buf , int len )
{
int n , err ;
2006-01-06 00:19:01 -08:00
err = make_umid ( ) ;
if ( err )
return err ;
2006-01-06 00:18:59 -08:00
2006-01-06 00:19:01 -08:00
n = snprintf ( buf , len , " %s%s/%s " , uml_dir , umid , name ) ;
if ( n > = len ) {
2006-01-06 00:18:59 -08:00
printk ( " umid_file_name : buffer too short \n " ) ;
2006-01-06 00:19:01 -08:00
return - E2BIG ;
2006-01-06 00:18:59 -08:00
}
2006-01-06 00:19:01 -08:00
return 0 ;
2006-01-06 00:18:59 -08:00
}
2006-01-06 00:19:01 -08:00
char * get_umid ( void )
2006-01-06 00:18:59 -08:00
{
return umid ;
}
static int __init set_uml_dir ( char * name , int * add )
{
2006-01-06 00:19:01 -08:00
if ( * name = = ' \0 ' ) {
printf ( " uml_dir can't be an empty string \n " ) ;
return 0 ;
2006-01-06 00:18:59 -08:00
}
2006-01-06 00:19:01 -08:00
if ( name [ strlen ( name ) - 1 ] = = ' / ' ) {
uml_dir = name ;
return 0 ;
}
uml_dir = malloc ( strlen ( name ) + 2 ) ;
if ( uml_dir = = NULL ) {
printf ( " Failed to malloc uml_dir - error = %d \n " , errno ) ;
/* Return 0 here because do_initcalls doesn't look at
* the return value .
*/
return 0 ;
}
sprintf ( uml_dir , " %s/ " , name ) ;
return 0 ;
2006-01-06 00:18:59 -08:00
}
__uml_setup ( " uml_dir= " , set_uml_dir ,
" uml_dir=<directory> \n "
" The location to place the pid and umid files. \n \n "
) ;
static void remove_umid_dir ( void )
{
2006-01-06 00:19:01 -08:00
char dir [ strlen ( uml_dir ) + UMID_LEN + 1 ] , err ;
2006-01-06 00:18:59 -08:00
sprintf ( dir , " %s%s " , uml_dir , umid ) ;
2006-01-06 00:19:01 -08:00
err = actually_do_remove ( dir ) ;
if ( err )
printf ( " remove_umid_dir - actually_do_remove failed with "
" err = %d \n " , err ) ;
2006-01-06 00:18:59 -08:00
}
__uml_exitcall ( remove_umid_dir ) ;