#include "DAPrivate.h"
#include "DAInternal.h"
#include "DALog.h"
#include "DAMain.h"
#include "DAMount.h"
#include "DAQueue.h"
#include "DAStage.h"
#include "DAThread.h"
#include <sysexits.h>
#include <unistd.h>
#include <FSPrivate.h>
#include <sys/attr.h>
#include <sys/mount.h>
#include <sys/wait.h>
static int __DADiskRefreshRemoveMountPoint( void * context )
{
CFURLRef mountpoint = context;
DAMountRemoveMountPoint( mountpoint );
CFRelease( mountpoint );
return 0;
}
static int __DAFileSystemSetAdoption( DAFileSystemRef filesystem, CFURLRef mountpoint, Boolean adoption )
{
char * path = NULL;
int status = 0;
path = ___CFURLCopyFileSystemRepresentation( mountpoint );
if ( path == NULL ) { status = EINVAL; goto __DAFileSystemSetAdoptionErr; }
status = fork( );
if ( status == -1 ) { status = errno; goto __DAFileSystemSetAdoptionErr; }
if ( status == 0 )
{
execle( "/usr/sbin/vsdbutil",
"/usr/sbin/vsdbutil",
adoption ? "-a" : "-d",
path,
NULL,
NULL );
exit( EX_OSERR );
}
waitpid( status, &status, 0 );
status = WIFEXITED( status ) ? ( ( char ) WEXITSTATUS( status ) ) : status;
if ( status ) { goto __DAFileSystemSetAdoptionErr; }
__DAFileSystemSetAdoptionErr:
if ( path ) free( path );
return status;
}
static int __DAFileSystemSetEncoding( DAFileSystemRef filesystem, CFURLRef mountpoint, CFStringEncoding encoding )
{
struct statfs fs = { 0 };
char * path = NULL;
int status = 0;
path = ___CFURLCopyFileSystemRepresentation( mountpoint );
if ( path == NULL ) { status = EINVAL; goto __DAFileSystemSetEncodingErr; }
status = ___statfs( path, &fs, MNT_NOWAIT );
if ( status == -1 ) { status = errno; goto __DAFileSystemSetEncodingErr; }
status = fork( );
if ( status == -1 ) { status = errno; goto __DAFileSystemSetEncodingErr; }
if ( status == 0 )
{
char option[16];
snprintf( option, sizeof( option ), "-o-e=%d", ( int ) encoding );
execle( "/sbin/mount",
"/sbin/mount",
"-t",
fs.f_fstypename,
"-u",
option,
( fs.f_flags & MNT_NODEV ) ? "-onodev" : "-odev",
( fs.f_flags & MNT_NOEXEC ) ? "-onoexec" : "-oexec",
( fs.f_flags & MNT_NOSUID ) ? "-onosuid" : "-osuid",
( fs.f_flags & MNT_RDONLY ) ? "-ordonly" : "-orw",
( fs.f_flags & MNT_IGNORE_OWNERSHIP ) ? "-onoowners" : "-oowners",
fs.f_mntfromname,
fs.f_mntonname,
NULL,
NULL );
exit( EX_OSERR );
}
waitpid( status, &status, 0 );
status = WIFEXITED( status ) ? ( ( char ) WEXITSTATUS( status ) ) : status;
if ( status ) { goto __DAFileSystemSetEncodingErr; }
__DAFileSystemSetEncodingErr:
if ( path ) free( path );
return status;
}
DAReturn _DADiskRefresh( DADiskRef disk )
{
DAReturn status;
status = kDAReturnUnsupported;
if ( DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ) )
{
struct statfs * mountList;
int mountListCount;
int mountListIndex;
mountListCount = getmntinfo( &mountList, MNT_NOWAIT );
for ( mountListIndex = 0; mountListIndex < mountListCount; mountListIndex++ )
{
if ( strcmp( _DAVolumeGetID( mountList + mountListIndex ), DADiskGetID( disk ) ) == 0 )
{
break;
}
}
if ( mountListIndex < mountListCount )
{
CFMutableArrayRef keys;
keys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( keys )
{
CFTypeRef object;
if ( strcmp( mountList[mountListIndex].f_fstypename, "hfs" ) == 0 )
{
object = _FSCopyNameForVolumeFormatAtURL( DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ) );
if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeTypeKey, object ) )
{
DADiskSetDescription( disk, kDADiskDescriptionVolumeTypeKey, object );
CFArrayAppendValue( keys, kDADiskDescriptionVolumeTypeKey );
}
if ( object )
{
CFRelease( object );
}
}
if ( CFArrayGetCount( keys ) )
{
DALogDebugHeader( "bsd [0] -> %s", gDAProcessNameID );
DALogDebug( " updated disk, id = %@.", disk );
if ( DADiskGetState( disk, kDADiskStateStagedAppear ) )
{
DADiskDescriptionChangedCallback( disk, keys );
}
}
CFRelease( keys );
}
}
else
{
CFURLRef mountpoint;
mountpoint = DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey );
CFRetain( mountpoint );
DAThreadExecute( __DADiskRefreshRemoveMountPoint, ( void * ) mountpoint, NULL, NULL );
DADiskSetBypath( disk, NULL );
if ( DADiskGetDescription( disk, kDADiskDescriptionMediaPathKey ) )
{
DADiskSetDescription( disk, kDADiskDescriptionVolumePathKey, NULL );
DADiskDescriptionChangedCallback( disk, kDADiskDescriptionVolumePathKey );
}
else
{
DALogDebugHeader( "bsd [0] -> %s", gDAProcessNameID );
DALogDebug( " removed disk, id = %@.", disk );
DADiskDisappearedCallback( disk );
DADiskSetDescription( disk, kDADiskDescriptionVolumePathKey, NULL );
DADiskSetState( disk, kDADiskStateZombie, TRUE );
___CFArrayRemoveValue( gDADiskList, disk );
}
DAStageSignal( );
}
status = kDAReturnSuccess;
}
else
{
struct statfs * mountList;
int mountListCount;
int mountListIndex;
mountListCount = getmntinfo( &mountList, MNT_NOWAIT );
for ( mountListIndex = 0; mountListIndex < mountListCount; mountListIndex++ )
{
if ( strcmp( _DAVolumeGetID( mountList + mountListIndex ), DADiskGetID( disk ) ) == 0 )
{
break;
}
}
if ( mountListIndex < mountListCount )
{
CFURLRef path;
path = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault,
( void * ) mountList[mountListIndex].f_mntonname,
strlen( mountList[mountListIndex].f_mntonname ),
TRUE );
if ( path )
{
DADiskSetBypath( disk, path );
DADiskSetDescription( disk, kDADiskDescriptionVolumePathKey, path );
DADiskDescriptionChangedCallback( disk, kDADiskDescriptionVolumePathKey );
DAStageSignal( );
CFRelease( path );
}
}
status = kDAReturnSuccess;
}
return status;
}
DAReturn _DADiskSetAdoption( DADiskRef disk, Boolean adoption )
{
CFURLRef path;
DAReturn status;
path = DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey );
if ( path == NULL ) { status = kDAReturnBadArgument; goto _DADiskSetAdoptionErr; }
status = __DAFileSystemSetAdoption( DADiskGetFileSystem( disk ), path, adoption );
if ( status ) { status = unix_err( status ); goto _DADiskSetAdoptionErr; }
_DADiskSetAdoptionErr:
return status;
}
DAReturn _DADiskSetEncoding( DADiskRef disk, CFStringEncoding encoding )
{
CFMutableArrayRef keys = NULL;
CFStringRef name1 = NULL;
CFStringRef name2 = NULL;
CFURLRef path1 = NULL;
CFURLRef path2 = NULL;
DAReturn status = kDAReturnSuccess;
path1 = DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey );
if ( path1 == NULL ) { status = kDAReturnBadArgument; goto _DADiskSetEncodingErr; }
status = __DAFileSystemSetEncoding( DADiskGetFileSystem( disk ), path1, encoding );
if ( status ) { status = unix_err( status ); goto _DADiskSetEncodingErr; }
keys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( keys == NULL ) { status = kDAReturnNoResources; goto _DADiskSetEncodingErr; }
name1 = DADiskGetDescription( disk, kDADiskDescriptionVolumeNameKey );
if ( name1 == NULL ) { status = kDAReturnError; goto _DADiskSetEncodingErr; }
name2 = _DAFileSystemCopyName( DADiskGetFileSystem( disk ), path1 );
if ( name2 == NULL ) { status = kDAReturnError; goto _DADiskSetEncodingErr; }
status = CFEqual( name1, name2 );
DADiskSetDescription( disk, kDADiskDescriptionVolumeNameKey, name2 );
CFArrayAppendValue( keys, kDADiskDescriptionVolumeNameKey );
if ( status == FALSE )
path2 = DAMountCreateMountPointWithAction( disk, kDAMountPointActionMove );
status = kDAReturnSuccess;
if ( path2 )
{
DADiskSetBypath( disk, path2 );
DADiskSetDescription( disk, kDADiskDescriptionVolumePathKey, path2 );
CFArrayAppendValue( keys, kDADiskDescriptionVolumePathKey );
}
DADiskDescriptionChangedCallback( disk, keys );
_DADiskSetEncodingErr:
if ( keys ) CFRelease( keys );
if ( name2 ) CFRelease( name2 );
if ( path2 ) CFRelease( path2 );
return status;
}
Boolean _DAUnitIsUnreadable( DADiskRef disk )
{
CFIndex count;
CFIndex index;
count = CFArrayGetCount( gDADiskList );
for ( index = 0; index < count; index++ )
{
DADiskRef item;
item = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
if ( DADiskGetBSDUnit( disk ) == DADiskGetBSDUnit( item ) )
{
CFStringRef name;
name = DADiskGetDescription( item, kDADiskDescriptionMediaBSDNameKey );
if ( DADiskGetClaim( item ) )
{
return FALSE;
}
if ( DADiskGetState( item, _kDADiskStateMountAutomatic ) == FALSE )
{
return FALSE;
}
if ( DADiskGetDescription( item, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanTrue )
{
return FALSE;
}
if ( DADiskGetDescription( item, kDADiskDescriptionMediaLeafKey ) == kCFBooleanFalse )
{
CFIndex subcount;
CFIndex subindex;
subcount = CFArrayGetCount( gDADiskList );
for ( subindex = 0; subindex < subcount; subindex++ )
{
DADiskRef subitem;
subitem = ( void * ) CFArrayGetValueAtIndex( gDADiskList, subindex );
if ( item != subitem )
{
CFStringRef subname;
subname = DADiskGetDescription( subitem, kDADiskDescriptionMediaBSDNameKey );
if ( subname )
{
if ( CFStringHasPrefix( subname, name ) )
{
break;
}
}
}
}
if ( subindex == subcount )
{
return FALSE;
}
}
}
}
return TRUE;
}