DiskArbitrationServerMain.c [plain text]
#include <libc.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <mach/message.h>
#include <servers/bootstrap.h>
#include <mach/mach_error.h>
#include <pthread.h>
#include <assert.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <dev/disk.h>
#include <IOKit/OSMessageNotification.h>
#include <IOKit/IOKitLib.h>
#include "ServerToClient.h"
#include "ClientToServer.h"
#include "DiskArbitrationTypes.h"
#include "GetRegistry.h"
#include "FSParticular.h"
#include <mach/mach_interface.h>
#include <IOKit/IOBSD.h>
#include <IOKit/storage/IOMedia.h>
#include <syslog.h>
#include "DiskArbitrationServerMain.h"
mach_port_t ioMasterPort;
void autodiskmount(int ownership);
#ifdef DEBUG
int gDebug = 1;
#else
int gDebug = 0;
#endif
int gDaemon;
extern void ClientDeath(mach_port_t clientPort);
extern boolean_t ClientToServer_server(mach_msg_header_t * msg, mach_msg_header_t * reply);
enum {
kMsgSize = 2048, };
static char * programName = NULL;
mach_port_t gNotifyPort = MACH_PORT_NULL;
static int gBlueBoxBootVolume = -1;
static kern_return_t InitNotifyPort(void);
static mach_port_t GetNotifyPort(void);
static boolean_t MessageIsNotificationDeath(const mach_msg_header_t *msg, mach_port_t *deadPort);
static int NextSequenceNumber( void );
struct IONotificationMsg {
mach_msg_header_t msgHdr;
OSNotificationHeader notifyHeader;
mach_msg_trailer_t trailer;
};
CFStringRef yankedHeader;
CFStringRef yankedMessage;
CFStringRef unrecognizedHeader;
CFStringRef unrecognizedMessage;
CFStringRef ejectString;
CFStringRef ignoreString;
CFStringRef initString;
typedef struct IONotificationMsg IONotificationMsg, * IONotificationMsgPtr;
static void HandleIONotificationMsg( IONotificationMsgPtr ioNotificationMsgPtr );
void * YankedDiskThread(void * args)
{
SInt32 retval = ERR_SUCCESS;
CFURLRef daFrameworkURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/System/Library/PrivateFrameworks/DiskArbitration.framework"), kCFURLPOSIXPathStyle, TRUE);
retval = CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, daFrameworkURL, yankedHeader, yankedMessage, NULL);
CFRelease(daFrameworkURL);
return NULL;
}
void StartYankedDiskMessage()
{
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, YankedDiskThread, nil);
pthread_attr_destroy(&attr);
}
static kern_return_t InitNotifyPort(void)
{
kern_return_t r;
r = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &gNotifyPort);
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) mach_port_allocate failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return MACH_PORT_NULL;
}
dwarning(("%s: gNotifyPort = $%08x\n", programName, (int)gNotifyPort));
return r;
}
static mach_port_t GetNotifyPort(void)
{
return gNotifyPort;
}
static boolean_t MessageIsNotificationDeath(const mach_msg_header_t *msg, mach_port_t *deadPort)
{
boolean_t result;
if ( GetNotifyPort() == msg->msgh_local_port )
{
if ( MACH_NOTIFY_DEAD_NAME == msg->msgh_id )
{
if ( deadPort != NULL )
{
const mach_dead_name_notification_t *deathMessage = (const mach_dead_name_notification_t *)msg;
*deadPort = deathMessage->not_port;
}
result = TRUE;
goto Return;
}
else if ( INTERNAL_MSG == msg->msgh_id)
{
dwarning(("Internal message received"));
result = FALSE;
goto Return;
}
else
{
LogErrorMessage("(%s:%d) received unrecognized message (id=0x%x) on notify port\n", __FILE__, __LINE__, (int)msg->msgh_id);
result = FALSE;
goto Return;
}
}
else
{
result = FALSE;
goto Return;
}
Return:
return result;
}
void LogErrorMessage(const char *format, ...)
{
va_list ap;
va_start(ap, format);
openlog(programName, LOG_PID | LOG_CONS, LOG_DAEMON);
vsyslog(LOG_ERR, format, ap);
closelog();
vfprintf(stderr, format, ap);
va_end(ap);
}
static void HandleIONotificationMsg( IONotificationMsgPtr msg )
{
kern_return_t r;
unsigned long int notifyType;
unsigned long int ref;
r = OSGetNotificationFromMessage(
&msg->msgHdr, 0, ¬ifyType, &ref, 0, 0 ); if ( r )
{
dwarning(("%s(%d): OSGetNotificationFromMessage returned error %d\n", __FUNCTION__, __LINE__, (int)r));
goto Return;
}
dwarning(("got notification, type=%d(%s), local=%d, remote=%d\n",
(int)notifyType, (char*)ref,
(int)msg->msgHdr.msgh_local_port,
(int)msg->msgHdr.msgh_remote_port ));
if (notifyType != 102) { GetDisksFromRegistry( (io_iterator_t) msg->msgHdr.msgh_remote_port );
autodiskmount(FALSE);
} else {
io_iterator_t iter = (io_iterator_t) msg->msgHdr.msgh_remote_port;
io_registry_entry_t entry;
while ( entry = IOIteratorNext( iter ) )
{
kern_return_t kr;
CFDictionaryRef properties = 0; CFStringRef string = 0; io_name_t ioMediaName;
char * ioBSDName = NULL;
DiskPtr dp;
kr = IORegistryEntryGetName(entry, ioMediaName);
if ( KERN_SUCCESS != kr )
{
dwarning(("can't obtain name for media object\n"));
continue;
}
kr = IORegistryEntryCreateCFProperties(entry, &properties, kCFAllocatorDefault, kNilOptions);
if ( KERN_SUCCESS != kr )
{
dwarning(("can't obtain properties for '%s'\n", ioMediaName));
continue;
}
assert(CFGetTypeID(properties) == CFDictionaryGetTypeID());
string = (CFStringRef) CFDictionaryGetValue(properties, CFSTR(kIOBSDNameKey));
if (!string) {
dwarning(("can't obtain properties for ioBSDName\n"));
continue;
}
ioBSDName = daCreateCStringFromCFString(string);
dp = LookupDiskByIOBSDName( ioBSDName );
if (dp != NULL) {
if (dp->mountpoint && strlen(dp->mountpoint)) {
DiskPtr wholeDiskPtr = LookupWholeDiskForThisPartition( dp );
if (wholeDiskPtr && !wholeDiskPtr->wholeDiskHasBeenYanked) {
wholeDiskPtr->wholeDiskHasBeenYanked++;
StartYankedDiskMessage();
}
}
kr = UnmountDisk( dp, TRUE );
SendUnmountPostNotifyMsgsForOnePartition( dp->ioBSDName, 0, 0 );
SendEjectPostNotifyMsgsForOnePartition( dp->ioBSDName, 0, 0 );
FreeDisk( dp );
}
IOObjectRelease(entry);
if ( properties ) CFRelease( properties );
if ( ioBSDName ) free( ioBSDName );
}
}
Return:
return;
}
ClientPtr NewClient( mach_port_t port, unsigned pid, unsigned flags )
{
ClientPtr result;
result = (ClientPtr) malloc( sizeof( * result ) );
if ( result == NULL )
{
dwarning(("%s(port = $%08x, pid = %d, flags = $%08x): malloc failed!\n", __FUNCTION__, port, pid, flags));
goto Return;
}
result->next = g.Clients;
g.Clients = result;
result->port = port;
result->pid = pid;
result->flags = flags;
result->state = kDiskStateNew;
result->numAcksRequired = 0;
g.NumClients ++ ;
Return:
return result;
}
void PrintClient(ClientPtr clientPtr)
{
if ( ! clientPtr ) return;
dwarning(("port = $%08x, pid = %5d, flags = $%08x, numAcksRequired = %d\n", clientPtr->port, clientPtr->pid, clientPtr->flags, clientPtr->numAcksRequired));
}
void PrintClients(void)
{
ClientPtr clientPtr;
int i;
if ( ! gDebug ) goto Return;
dwarning(("g.NumClients = %d\n", g.NumClients));
for (clientPtr = g.Clients, i = 0; clientPtr != NULL; clientPtr = clientPtr->next, i++)
{
PrintClient( clientPtr );
}
Return:
return;
}
ClientPtr LookupClientByPID( pid_t pid )
{
ClientPtr clientPtr;
for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next)
{
if ( clientPtr->pid == pid )
{
goto Return;
}
}
Return:
return clientPtr;
}
DiskPtr NewDisk( char * ioBSDName,
int ioBSDUnit,
char * ioContentOrNull,
DiskFamily family,
char * mountpoint,
char * ioMediaNameOrNull,
char * ioDeviceTreePathOrNull,
io_object_t service,
unsigned flags )
{
DiskPtr result;
dwarning(("%s(ioBSDName = '%s', ioContentOrNull = '%s', family = %d, mountpoint = '%s', ioMediaNameOrNull = '%s', ioDeviceTreePathOrNull = '%s', flags = $%08x)\n",
__FUNCTION__,
ioBSDName,
ioContentOrNull ? ioContentOrNull : "(NULL)",
family,
mountpoint,
ioMediaNameOrNull ? ioMediaNameOrNull : "(NULL)",
ioDeviceTreePathOrNull ? ioDeviceTreePathOrNull : "(NULL)",
flags ));
result = (DiskPtr) malloc( sizeof( * result ) );
if ( result == NULL )
{
dwarning(("%s(...): malloc failed!\n", __FUNCTION__));
goto Return;
}
bzero( result, sizeof( * result ) );
result->next = g.Disks;
g.Disks = result;
result->ioBSDName = strdup( ioBSDName ? ioBSDName : "" );
result->ioBSDUnit = ioBSDUnit;
result->ioContent = strdup( ioContentOrNull ? ioContentOrNull : "" );
result->family = family;
result->mountpoint = strdup( mountpoint ? mountpoint : "" );
result->service = service;
dwarning(("setting a diskPtr->service\n"));
if ( ioMediaNameOrNull )
{
result->ioMediaNameOrNull = strdup( ioMediaNameOrNull );
}
else
{
result->ioMediaNameOrNull = NULL;
}
result->ioDeviceTreePath = strdup( ioDeviceTreePathOrNull ? ioDeviceTreePathOrNull : "" );
result->flags = flags;
result->sequenceNumber = ( 0 == strcmp( result->mountpoint, "" ) ) ? -1 : NextSequenceNumber();
result->state = kDiskStateNew;
result->ackValues = NULL;
result->mountedUser = currentConsoleUser; result->wholeDiskContainsMountedChild = 0;
g.NumDisks ++ ;
g.NumDisksAddedOrDeleted ++;
Return:
return result;
}
boolean_t IsWhole( DiskPtr diskPtr )
{
boolean_t result;
result = ( 0 != ( diskPtr->flags & kDiskArbDiskAppearedWholeDiskMask ) );
return result;
}
boolean_t IsNetwork( DiskPtr diskPtr )
{
boolean_t result;
result = ( 0 != ( diskPtr->flags & kDiskArbDiskAppearedNetworkDiskMask ) );
return result;
}
static int NextSequenceNumber( void )
{
int maxSequenceNumber;
int result;
DiskPtr diskPtr;
dwarning(("%s...\n", __FUNCTION__));
maxSequenceNumber = -1;
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( diskPtr->sequenceNumber > maxSequenceNumber )
{
maxSequenceNumber = diskPtr->sequenceNumber;
}
}
result = maxSequenceNumber + 1;
dwarning(("%s => %d\n", __FUNCTION__, result ));
return result;
}
void DiskSetMountpoint( DiskPtr diskPtr, const char * mountpoint )
{
if ( diskPtr->mountpoint )
{
free( diskPtr->mountpoint );
}
diskPtr->mountpoint = strdup( mountpoint ? mountpoint : "" );
diskPtr->sequenceNumber = NextSequenceNumber();
}
DiskPtr LookupDiskByIOBSDName( char * ioBSDName )
{
DiskPtr diskPtr;
if (!ioBSDName) {
pwarning(("%s(null ioBSDName passed! abort!)\n", __FUNCTION__));
return nil;
}
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if (!diskPtr->ioBSDName) {
continue;
}
if ( 0 == strcmp( ioBSDName, diskPtr->ioBSDName ) )
{
goto Return;
}
}
Return:
return diskPtr;
}
void FreeAllDisks( )
{
DiskPtr oldDiskPtr= g.Disks;
DiskPtr newDiskPtr= g.Disks;
while (oldDiskPtr) {
newDiskPtr = oldDiskPtr->next;
FreeDisk(oldDiskPtr);
oldDiskPtr = newDiskPtr;
}
}
int UnmountDisk( DiskPtr diskPtr, int forceUnmount )
{
int result = 0;
struct stat sb;
char cookieFile[MAXPATHLEN];
sprintf(cookieFile, "/%s/%s", diskPtr->mountpoint, ADM_COOKIE_FILE);
dwarning(("%s('%s')\n", __FUNCTION__, diskPtr->ioBSDName));
if ( 0 == strcmp( diskPtr->mountpoint, "" ) )
{
dwarning(("%s('%s'): disk not mounted\n", __FUNCTION__, diskPtr->ioBSDName));
SetStateForOnePartition( diskPtr, kDiskStateIdle );
goto Return;
}
result = unmount( diskPtr->mountpoint, (forceUnmount ? MNT_FORCE : 0) );
if ( -1 == result )
{
result = errno;
LogErrorMessage("%s('%s') unmount('%s') failed: %d (%s)\n", __FUNCTION__, diskPtr->ioBSDName, diskPtr->mountpoint, result, strerror(result));
SetStateForOnePartition( diskPtr, kDiskStateIdle );
goto Return;
}
result = rmdir( diskPtr->mountpoint );
if ( -1 == result )
{
result = errno;
if (result == ENOTEMPTY) {
if (stat(cookieFile, &sb) == 0) {
if (remove(cookieFile) == 0) {
if (rmdir(diskPtr->mountpoint) != 0) {
LogErrorMessage("%s('%s') rmdir('%s') failed: %d (%s)\n", __FUNCTION__, diskPtr->ioBSDName, diskPtr->mountpoint, result, strerror(result));
result = errno;
} else {
result = 0;
}
}
}
}
}
free( diskPtr->mountpoint );
diskPtr->mountpoint = strdup( "" );
SetStateForOnePartition( diskPtr, kDiskStateNewlyUnmounted );
Return:
if ( result ) dwarning(("%s('%s') error: %d (%s)\n", __FUNCTION__, diskPtr->ioBSDName, result, strerror(result)));
return result;
}
int UnmountAllPartitions( DiskPtr diskPtr, int forceUnmount )
{
int result = 0;
DiskPtr dp;
int family1, family2;
int deviceNum1, deviceNum2;
if (diskPtr->ioBSDName && strlen(diskPtr->ioBSDName)) {
dwarning(("%s('%s')\n", __FUNCTION__, diskPtr->ioBSDName));
}
if ( IsNetwork( diskPtr ) )
{
result = UnmountDisk( diskPtr, forceUnmount ); goto Return;
}
family1 = diskPtr->family;
deviceNum1 = diskPtr->ioBSDUnit;
for (dp = g.Disks; dp != NULL; dp = dp->next)
{
family2 = dp->family;
deviceNum2 = dp->ioBSDUnit;
if ( family1 == family2 && deviceNum1 == deviceNum2 )
{
int err;
err = UnmountDisk( dp , forceUnmount); if ( err && ! result )
{
result = err;
}
}
}
Return:
return result;
}
int EjectDisk( DiskPtr diskPtr )
{
int result = 0;
int fd = -1;
char livePartitionPathname[PATH_MAX];
DiskPtr wholeDiskPtr;
dwarning(("%s('%s')\n", __FUNCTION__, diskPtr->ioBSDName));
if ( IsNetwork( diskPtr ) )
{
if ( 0 == strcmp( "", diskPtr->mountpoint ) )
{
SetStateForOnePartition( diskPtr, kDiskStateNewlyEjected );
}
goto Return;
}
wholeDiskPtr = LookupWholeDiskForThisPartition( diskPtr );
if ( NULL == wholeDiskPtr )
{
result = EINVAL;
LogErrorMessage("%s('%s') can't find whole media\n", __FUNCTION__, diskPtr->ioBSDName);
SetStateForAllPartitions( diskPtr, kDiskStateIdle );
goto Return;
}
sprintf(livePartitionPathname, "/dev/r%s", wholeDiskPtr->ioBSDName);
dwarning(("%s: livePartitionPathname = '%s'\n", __FUNCTION__, livePartitionPathname));
fd = open(livePartitionPathname, O_RDONLY);
if ( -1 == fd )
{
result = errno;
LogErrorMessage("%s('%s') open('%s') failed: %d (%s)\n", __FUNCTION__, diskPtr->ioBSDName, livePartitionPathname, result, strerror(result));
SetStateForAllPartitions( diskPtr, kDiskStateIdle );
goto Return;
}
if (diskPtr) {
SetStateForAllPartitions( diskPtr, kDiskStateNewlyEjected );
}
result = ioctl(fd, DKIOCEJECT, 0);
if ( -1 == result )
{
result = errno;
LogErrorMessage("%s('%s') ioctl(DKIOCEJECT) failed: %d (%s)\n", __FUNCTION__, diskPtr->ioBSDName, result, strerror(result));
SetStateForAllPartitions( diskPtr, kDiskStateIdle );
goto Return;
}
Return:
if ( fd >= 0 )
{
close( fd );
}
return result;
}
void FreeDisk( DiskPtr diskPtr )
{
DiskPtr dp;
DiskPtr * dpp;
dwarning(("%s('%s')\n", __FUNCTION__, diskPtr->ioBSDName));
for ( dpp = & g.Disks, dp = * dpp;
dp != NULL;
dpp = & (dp->next), dp = * dpp )
{
if ( dp == diskPtr )
{
*dpp = dp->next;
free( diskPtr->ioBSDName );
diskPtr->ioBSDName = NULL; free( diskPtr->ioContent );
diskPtr->ioContent = NULL; free( diskPtr->mountpoint );
diskPtr->mountpoint = NULL; if ( diskPtr->ioMediaNameOrNull)
{
free( diskPtr->ioMediaNameOrNull);
diskPtr->ioMediaNameOrNull = NULL; }
free( diskPtr->ioDeviceTreePath );
diskPtr->ioDeviceTreePath = NULL;
if ( diskPtr->ackValues )
{
FreeAckValues( diskPtr->ackValues );
}
diskPtr->ackValues = NULL;
IOObjectRelease(diskPtr->service);
free( diskPtr );
g.NumDisks --;
g.NumDisksAddedOrDeleted ++;
goto Return;
}
}
Return:
return;
}
void PrintDisks(void)
{
DiskPtr diskPtr;
int i;
if ( ! gDebug ) goto Return;
dwarning(("g.NumDisks = %d\n", g.NumDisks));
dwarning(("g.NumDisksAddedOrDeleted = %d\n", g.NumDisksAddedOrDeleted));
dwarning(("%2s %4s %10s %9s %5s %8s %25s %35s %8s %40s %35s %3s\n", "#", "seq#", "BSDName", "flags", "state", "BSDUnit", "Content", "FS Type", "MediaName", "DeviceTreePath", "mountpoint", "uid"));
for (diskPtr = g.Disks, i = 0; diskPtr != NULL; diskPtr = diskPtr->next, i++)
{
dwarning(("%2d %4d %10s $%08x %5d %8d %25s %35s %8s %40s %35s %3d\n",
i,
diskPtr->sequenceNumber,
diskPtr->ioBSDName,
diskPtr->flags,
diskPtr->state,
diskPtr->ioBSDUnit,
diskPtr->ioContent,
diskPtr->mountedFilesystemName,
diskPtr->ioMediaNameOrNull ? diskPtr->ioMediaNameOrNull : "<null>",
diskPtr->ioDeviceTreePath,
diskPtr->mountpoint ? diskPtr->mountpoint : "<not mounted>",
diskPtr->mountedUser
));
PrintAckValues( diskPtr->ackValues );
}
Return:
return;
}
int IsStateNeedingAckValueTable( DiskState diskState );
int IsStateNeedingAckValueTable( DiskState diskState )
{
switch ( diskState )
{
case kDiskStateToBeEjected:
case kDiskStateToBeUnmounted:
case kDiskStateToBeUnmountedAndEjected:
return 1;
break;
default:
return 0;
break;
}
}
void SetStateForOnePartition( DiskPtr diskPtr, DiskState newState )
{
dwarning(("%s('%s',state=%s (%d))\n", __FUNCTION__, diskPtr->ioBSDName, DISKSTATE(newState),newState));
if ( diskPtr->ackValues )
{
FreeAckValues( diskPtr->ackValues );
}
diskPtr->state = newState;
if ( IsStateNeedingAckValueTable( newState ) )
{
diskPtr->ackValues = NewAckValues( NumClientsDesiringAsyncNotification() );
}
else
{
diskPtr->ackValues = NULL;
}
}
void SetStateForAllPartitions( DiskPtr diskPtr, DiskState newState )
{
DiskPtr diskPtr2;
int family1, family2;
int deviceNum1, deviceNum2;
dwarning(("%s('%s',newState=%s (%d))\n", __FUNCTION__, diskPtr->ioBSDName, DISKSTATE(newState),newState));
if ( IsNetwork( diskPtr ) )
{
SetStateForOnePartition( diskPtr, newState );
goto Return;
}
family1 = diskPtr->family;
deviceNum1 = diskPtr->ioBSDUnit;
for (diskPtr2 = g.Disks; diskPtr2 != NULL; diskPtr2 = diskPtr2->next)
{
family2 = diskPtr2->family;
deviceNum2 = diskPtr2->ioBSDUnit;
if ( family1 == family2 && deviceNum1 == deviceNum2 )
{
SetStateForOnePartition( diskPtr2, newState );
}
}
Return:
return;
}
int NumPartitionsMountedFromThisDisk( DiskPtr diskPtr )
{
int result = 0; DiskPtr diskPtr2;
int family1, family2;
int deviceNum1, deviceNum2;
if ( IsNetwork( diskPtr ) )
{
result = ( 0 != strcmp("", diskPtr->mountpoint) );
goto Return;
}
family1 = diskPtr->family;
deviceNum1 = diskPtr->ioBSDUnit;
for (diskPtr2 = g.Disks; diskPtr2 != NULL; diskPtr2 = diskPtr2->next)
{
family2 = diskPtr2->family;
deviceNum2 = diskPtr2->ioBSDUnit;
if ( family1 == family2 && deviceNum1 == deviceNum2 && 0 != strcmp( "", diskPtr2->mountpoint ) )
{
result ++ ;
}
}
Return:
dwarning(("%s('%s') => %d\n", __FUNCTION__, diskPtr->ioBSDName, result));
return result;
}
int NumPartitionsToBeUnmountedAndEjectedFromThisDisk( DiskPtr diskPtr )
{
int result = 0; DiskPtr diskPtr2;
int family1, family2;
int deviceNum1, deviceNum2;
if ( IsNetwork( diskPtr ) )
{
result = ( 0 != strcmp("", diskPtr->mountpoint) );
goto Return;
}
family1 = diskPtr->family;
deviceNum1 = diskPtr->ioBSDUnit;
for (diskPtr2 = g.Disks; diskPtr2 != NULL; diskPtr2 = diskPtr2->next)
{
family2 = diskPtr2->family;
deviceNum2 = diskPtr2->ioBSDUnit;
if ( family1 == family2 && deviceNum1 == deviceNum2 && diskPtr2->state == kDiskStateToBeUnmountedAndEjected )
{
result ++ ;
}
}
Return:
dwarning(("%s('%s') => %d\n", __FUNCTION__, diskPtr->ioBSDName, result));
return result;
}
DiskPtr LookupWholeDiskForThisPartition( DiskPtr diskPtr )
{
DiskPtr diskPtr2;
int family1, family2;
int deviceNum1, deviceNum2;
if ( IsNetwork( diskPtr ) )
{
diskPtr2 = diskPtr;
goto Return;
}
family1 = diskPtr->family;
deviceNum1 = diskPtr->ioBSDUnit;
for (diskPtr2 = g.Disks; diskPtr2 != NULL; diskPtr2 = diskPtr2->next)
{
family2 = diskPtr2->family;
deviceNum2 = diskPtr2->ioBSDUnit;
if ( family1 == family2 && deviceNum1 == deviceNum2 && IsWhole( diskPtr2 ) )
{
goto Return;
}
}
Return:
if ( diskPtr2 )
{
dwarning(("%s('%s') => '%s'\n", __FUNCTION__, diskPtr->ioBSDName, STR(diskPtr2->ioBSDName)));
}
else
{
dwarning(("%s('%s') => NULL\n", __FUNCTION__, diskPtr->ioBSDName));
}
return diskPtr2;
}
DiskPtr LookupWholeDiskToBeEjected( void )
{
DiskPtr diskPtr;
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( ! ( IsWhole( diskPtr) || IsNetwork( diskPtr ) ) )
{
continue;
}
if ( ! ( ( diskPtr->state == kDiskStateToBeUnmountedAndEjected ) || ( diskPtr->state == kDiskStateToBeEjected ) ) )
{
continue;
}
goto Return;
}
Return:
if ( diskPtr )
{
dwarning(("%s() => '%s' (state=%s (%d))\n", __FUNCTION__, STR(diskPtr->ioBSDName), DISKSTATE(diskPtr->state), diskPtr->state));
}
else
{
dwarning(("%s() => NULL\n", __FUNCTION__));
}
return diskPtr;
}
kern_return_t EnableDeathNotifications(mach_port_t port)
{
kern_return_t r;
mach_port_t oldPort;
dwarning(("%s($%08x)\n", __FUNCTION__, port));
r = mach_port_request_notification(mach_task_self(), port, MACH_NOTIFY_DEAD_NAME, 0, GetNotifyPort(), MACH_MSG_TYPE_MAKE_SEND_ONCE, &oldPort);
if ( r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) failed to set up death notifications for port %d: {0x%x} %s\n", __FILE__, __LINE__, (int)port, r, mach_error_string(r));
}
return r;
}
AckValues * NewAckValues( int size )
{
AckValue * v;
AckValues * result;
dwarning(("%s(%d)\n", __FUNCTION__, size));
v = (AckValue *)malloc( sizeof( AckValue ) * size );
if ( v == NULL )
{
result = NULL;
goto Return;
}
bzero( v, sizeof( AckValue ) * size );
result = (AckValues *)malloc( sizeof( AckValues ) );
if ( result == NULL )
{
free( v );
goto Return;
}
bzero ( result, sizeof( AckValues ) );
result->physicalLength = size;
result->logicalLength = 0;
result->ackValues = v;
Return:
return result;
}
void FreeAckValues( AckValues * ackValues )
{
dwarning(("%s(0x%08x)\n", __FUNCTION__, (unsigned)ackValues));
if ( ! ackValues ) goto Return;
if ( ackValues->ackValues )
{
free( ackValues->ackValues );
ackValues->ackValues = NULL;
}
free( ackValues );
Return:
return;
}
void ClearAckValuesForAllDisks()
{
DiskPtr diskPtr;
AckValues * p;
int i;
dwarning(("%s\n", __FUNCTION__));
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if (p = diskPtr->ackValues )
{
for (i = 0; i < p->logicalLength; i++)
{
p->ackValues[ i ].state = kAckReceived;
p->ackValues[ i ].errorCode = 0;
}
}
}
return;
}
void InitAckValue( AckValues * p, pid_t pid )
{
dwarning(("%s(0x%08x, pid=%d)\n", __FUNCTION__, (unsigned)p, (unsigned)pid));
p->ackValues[ p->logicalLength ].pid = pid;
p->ackValues[ p->logicalLength ].state = kSendMsg;
p->ackValues[ p->logicalLength ].errorCode = 0;
if ( p->logicalLength < p->physicalLength )
{
p->logicalLength ++ ;
}
else
{
LogErrorMessage("(%s:%d) %s(0x%08x, pid=%d): error: ! ( p->logicalLength < p->physicalLength )\n", __FILE__, __LINE__, __FUNCTION__, (unsigned)p, (unsigned)pid);
}
}
void UpdateAckValue( AckValues * p, pid_t pid, int errorCode )
{
int i;
dwarning(("%s(0x%08x, pid=%d, errorCode=%d)\n", __FUNCTION__, (unsigned)p, (unsigned)pid, errorCode));
if ( ! p )
{
LogErrorMessage("(%s:%d) %s(0x%08x, pid=%d, errorCode=%d): null pointer\n", __FILE__, __LINE__, __FUNCTION__, (unsigned)p, (unsigned)pid, errorCode);
goto Return;
}
for (i = 0; i < p->logicalLength; i++)
{
if ( p->ackValues[ i ].pid == pid )
{
if ( p->ackValues[ i ].state == kWaitingForAck )
{
p->ackValues[ i ].state = kAckReceived;
}
else
{
LogErrorMessage("(%s:%d) %s(0x%08x, pid=%d, errorCode=%d): error: state != kWaitingForAck\n", __FILE__, __LINE__, __FUNCTION__, (unsigned)p, (unsigned)pid, errorCode);
}
p->ackValues[ i ].errorCode = errorCode;
goto Return;
}
}
dwarning(("%s: ERROR, pid=%d not found!\n", __FUNCTION__, pid));
LogErrorMessage("(%s:%d) %s(0x%08x, pid=%d, errorCode=%d): error: pid not found\n", __FILE__, __LINE__, __FUNCTION__, (unsigned)p, (unsigned)pid, errorCode);
Return:
return;
}
int NumUnsetAckValues( AckValues * p )
{
int result;
int i;
result = 0;
for (i = 0; i < p->logicalLength; i++)
{
if ( p->ackValues[ i ].state != kAckReceived )
{
result ++ ;
}
}
return result;
}
int NumUnsetAckValuesForAllDisks( void )
{
DiskPtr diskPtr;
int result;
result = 0;
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( diskPtr->ackValues )
{
result += NumUnsetAckValues( diskPtr->ackValues );
}
}
dwarning(("%s => %d\n", __FUNCTION__, result));
return result;
}
void PrintAckValues( AckValues * p )
{
int i;
if ( ! gDebug ) goto Return;
if ( ! p ) goto Return;
for (i = 0; i < p->logicalLength; i++)
{
dwarning(("%2d: pid = %d, state = %d, errorCode = %d\n", i, p->ackValues[ i ].pid, p->ackValues[ i ].state, p->ackValues[ i ].errorCode));
}
Return:
return;
}
AckValue * GetDissenterFromAckValues( AckValues * ackValuesPtr )
{
AckValue * result;
int i;
for (i = 0; i < ackValuesPtr->logicalLength; i++)
{
result = & ackValuesPtr->ackValues[ i ];
if ( result->state == kAckReceived && result->errorCode != 0 )
{
goto Return;
}
}
result = NULL;
Return:
return result;
}
AckValue * GetDissenterFromAckValuesForAllDisks( void )
{
AckValue * result;
DiskPtr diskPtr;
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( diskPtr->ackValues )
{
result = GetDissenterFromAckValues( diskPtr->ackValues );
if ( result )
{
goto Return;
}
}
}
result = NULL;
Return:
return result;
}
AckValue * GetUnresponderFromAckValues( AckValues * ackValuesPtr )
{
AckValue * result;
int i;
for (i = 0; i < ackValuesPtr->logicalLength; i++)
{
result = & ackValuesPtr->ackValues[ i ];
if ( result->state == kWaitingForAck )
{
goto Return;
}
}
result = NULL;
Return:
return result;
}
AckValue * GetUnresponderFromAckValuesForAllDisks( void )
{
AckValue * result;
DiskPtr diskPtr;
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( diskPtr->ackValues )
{
result = GetUnresponderFromAckValues( diskPtr->ackValues );
if ( result )
{
goto Return;
}
}
}
result = NULL;
Return:
return result;
}
void MakeDeadClientAgreeable( ClientPtr clientPtr )
{
DiskPtr diskPtr;
int i;
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( diskPtr->ackValues )
{
for (i = 0; i < diskPtr->ackValues->logicalLength; i++)
{
if ( clientPtr->pid == diskPtr->ackValues->ackValues[ i ].pid )
{
diskPtr->ackValues->ackValues[ i ].state = kAckReceived;
diskPtr->ackValues->ackValues[ i ].errorCode = 0;
}
}
}
}
}
unsigned NumClientsDesiringAsyncNotification( void )
{
unsigned result = 0;
ClientPtr clientPtr;
for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next)
{
if ( clientPtr->flags & kDiskArbNotifyAsync )
{
result ++ ;
}
}
return result;
}
typedef struct {
int diskAppearedType;
mach_port_t port;
char *ioBSDName; unsigned flags;
char *mountpoint; int pid;
char *ioDeviceTreePath;
char *ioContent; int sequenceNumber;
} DiskThreadRecord;
static void * NotifyDiskAppeared(void * args)
{
DiskThreadRecord *record = args;
kern_return_t r;
if ( record->diskAppearedType == kDiskArbNotifyDiskAppearedWithoutMountpoint )
{
r = DiskArbDiskAppearedWithoutMountpoint_rpc(record->port, record->ioBSDName, record->flags);
}
else if ( record->diskAppearedType == kDiskArbNotifyDiskAppearedWithMountpoint )
{
r = DiskArbDiskAppearedWithMountpoint_rpc(record->port, record->ioBSDName, record->flags, record->mountpoint);
}
else if ( record->diskAppearedType == kDiskArbNotifyDiskAppeared )
{
r = DiskArbDiskAppeared_rpc(record->port, record->ioBSDName, record->flags, record->mountpoint, record->ioContent);
}
else if ( record->diskAppearedType == kDiskArbNotifyDiskAppeared2 )
{
r = DiskArbDiskAppeared2_rpc(record->port, record->ioBSDName, record->flags, record->mountpoint, record->ioContent, record->ioDeviceTreePath, record->sequenceNumber);
}
if ( r ) dwarning(("... $%08x: %s\n", r, mach_error_string(r)));
if ( r == MACH_SEND_INVALID_DEST )
{
dwarning(("Dead client! Port = $%08x (pid=%d)\n", record->port, record->pid));
}
free(record->ioBSDName);
free(record->ioDeviceTreePath);
free(record->ioContent);
free(record->mountpoint);
free(record);
return NULL;
}
static void * NotifyDiskRegistrationComplete(void * args)
{
ClientPtr client = args;
kern_return_t r;
r = DiskArbRegistrationComplete_rpc(client->port);
if ( r ) dwarning(("... $%08x: %s\n", r, mach_error_string(r)));
if ( r == MACH_SEND_INVALID_DEST )
{
dwarning(("Dead client! Port = $%08x\n", client->port));
}
return NULL;
}
static void * NotifyDiskMessagesCompleted(void * args)
{
DiskThreadRecord *record = args;
kern_return_t r;
r = DiskArbNotificationComplete_rpc(record->port, record->sequenceNumber);
if ( r ) dwarning(("... $%08x: %s\n", r, mach_error_string(r)));
if ( r == MACH_SEND_INVALID_DEST )
{
dwarning(("Dead client! Port = $%08x\n", record->port));
}
free(record);
return NULL;
}
static void * NotifyClientDisconnected(void * args)
{
ClientPtr client = args;
kern_return_t r;
r = DiskArbClientDisconnected_rpc(client->port);
if ( r ) dwarning(("... $%08x: %s\n", r, mach_error_string(r)));
if ( r == MACH_SEND_INVALID_DEST )
{
dwarning(("Dead client! Port = $%08x\n", client->port));
}
return NULL;
}
static void * NotifyBlueBoxMessages(void * args)
{
DiskThreadRecord *record = args;
kern_return_t r;
r = DiskArbBlueBoxBootVolumeUpdated_async_rpc(record->port, record->sequenceNumber);
if ( r ) dwarning(("... $%08x: %s\n", r, mach_error_string(r)));
if ( r == MACH_SEND_INVALID_DEST )
{
dwarning(("Dead client! Port = $%08x\n", record->port));
}
free(record);
return NULL;
}
static void * NotifyDiskChanged(void * args)
{
DiskThreadRecord *record = args;
kern_return_t r;
r = DiskArbDiskChanged_rpc(record->port, record->ioBSDName, record->mountpoint, record->ioContent, record->flags, record->sequenceNumber);
if ( r ) dwarning(("... $%08x: %s\n", r, mach_error_string(r)));
if ( r == MACH_SEND_INVALID_DEST )
{
dwarning(("Dead client! Port = $%08x\n", record->port));
}
free(record);
return NULL;
}
static void * NotifyUnrecognizedDiskInserted(void * args)
{
DiskThreadRecord *record = args;
kern_return_t r;
r = DiskArbUnknownFileSystemInserted_rpc(record->port, record->ioBSDName, record->mountpoint, record->ioContent, record->flags, record->sequenceNumber, record->diskAppearedType);
if ( r ) dwarning(("... $%08x: %s\n", r, mach_error_string(r)));
if ( r == MACH_SEND_INVALID_DEST )
{
dwarning(("Dead client! Port = $%08x\n", record->port));
}
free(record);
return NULL;
}
static void StartDiskAppearedThread(DiskThreadRecord * record)
{
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, NotifyDiskAppeared, record);
pthread_attr_destroy(&attr);
}
static void StartDiskMessagesCompleted(DiskThreadRecord * record)
{
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, NotifyDiskMessagesCompleted, record);
pthread_attr_destroy(&attr);
}
static void StartBlueBoxNotificationThread(DiskThreadRecord * record)
{
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, NotifyBlueBoxMessages, record);
pthread_attr_destroy(&attr);
}
void StartDiskRegistrationCompleteThread(ClientPtr client)
{
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, NotifyDiskRegistrationComplete, client);
pthread_attr_destroy(&attr);
}
void StartClientDisconnectedThread(ClientPtr client)
{
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, NotifyClientDisconnected, client);
pthread_attr_destroy(&attr);
}
void StartDiskChangedThread(DiskThreadRecord * record)
{
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, NotifyDiskChanged, record);
pthread_attr_destroy(&attr);
}
void StartUnrecognizedDiskThread(DiskThreadRecord * record)
{
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, NotifyUnrecognizedDiskInserted, record);
pthread_attr_destroy(&attr);
}
void SendClientWasDisconnectedMsg(ClientPtr clientPtr)
{
DiskThreadRecord * record = malloc(sizeof(DiskThreadRecord));
dwarning(("DiskArbClientDisconnected_rpc($%08x) ...\n", clientPtr->port));
record->port = clientPtr->port;
StartClientDisconnectedThread(clientPtr);
}
void SendDiskAppearedMsgs( void )
{
ClientPtr clientPtr;
DiskPtr diskPtr;
dwarning(("%s\n", __FUNCTION__));
for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next)
{
if ( ( kClientStateNew == clientPtr->state ) && ( clientPtr->flags & kDiskArbNotifyBlueBoxBootVolumeUpdated ) )
{
DiskThreadRecord * record = malloc(sizeof(DiskThreadRecord));
dwarning(("DiskArbBlueBoxBootVolumeUpdated_async_rpc($%08x (pid=%d), gBlueBoxBootVolume=%d) ...\n", clientPtr->port, clientPtr->pid, gBlueBoxBootVolume));
record->sequenceNumber = gBlueBoxBootVolume;
record->port = clientPtr->port;
StartBlueBoxNotificationThread(record);
}
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( ( kClientStateNew == clientPtr->state ) || ( kDiskStateNew == diskPtr->state ) )
{
if ((diskPtr->flags & kDiskArbDiskAppearedUnrecognizableFormat) && (clientPtr->flags & kDiskArbNotifyUnrecognizedVolumes) ) {
SendUnrecognizedDiskMsgs(clientPtr->port, diskPtr->ioBSDName, "", "", (!((diskPtr->flags & kDiskArbDiskAppearedLockedMask) == kDiskArbDiskAppearedLockedMask)), ((diskPtr->flags & kDiskArbDiskAppearedEjectableMask) == kDiskArbDiskAppearedEjectableMask), ((diskPtr->flags & kDiskArbDiskAppearedWholeDiskMask) == kDiskArbDiskAppearedWholeDiskMask));
continue;
}
if ( (clientPtr->flags & kDiskArbNotifyDiskAppearedWithoutMountpoint) && 0 == strcmp("",diskPtr->mountpoint) )
{
DiskThreadRecord * record = malloc(sizeof(DiskThreadRecord));
dwarning(("DiskArbDiskAppearedWithoutMountpoint_rpc($%08x (pid=%d), '%s', $%08x) ...\n", clientPtr->port, clientPtr->pid, diskPtr->ioBSDName, diskPtr->flags));
record->diskAppearedType = kDiskArbNotifyDiskAppearedWithoutMountpoint;
record->port = clientPtr->port;
record->ioBSDName = strdup( diskPtr->ioBSDName );
record->flags = diskPtr->flags;
record->mountpoint = strdup( diskPtr->mountpoint );
record->pid = clientPtr->pid;
record->ioContent = strdup(diskPtr->ioContent);
record->ioDeviceTreePath = strdup(diskPtr->ioDeviceTreePath);
record->sequenceNumber = diskPtr->sequenceNumber;
StartDiskAppearedThread(record);
}
if ( (clientPtr->flags & kDiskArbNotifyDiskAppearedWithMountpoint) && 0 != strcmp("",diskPtr->mountpoint) )
{
DiskThreadRecord * record = malloc(sizeof(DiskThreadRecord));
dwarning(("DiskArbDiskAppearedWithMountpoint_rpc($%08x (pid=%d), '%s', $%08x, '%s') ...\n", clientPtr->port, clientPtr->pid, diskPtr->ioBSDName, diskPtr->flags, diskPtr->mountpoint));
record->diskAppearedType = kDiskArbNotifyDiskAppearedWithMountpoint;
record->port = clientPtr->port;
record->ioBSDName = strdup( diskPtr->ioBSDName );
record->flags = diskPtr->flags;
record->mountpoint = strdup( diskPtr->mountpoint );
record->pid = clientPtr->pid;
record->ioContent = strdup(diskPtr->ioContent);
record->ioDeviceTreePath = strdup(diskPtr->ioDeviceTreePath);
record->sequenceNumber = diskPtr->sequenceNumber;
StartDiskAppearedThread(record);
}
if ( clientPtr->flags & kDiskArbNotifyDiskAppeared )
{
DiskThreadRecord * record = malloc(sizeof(DiskThreadRecord));
dwarning(("DiskArbDiskAppeared_rpc($%08x (pid=%d), '%s', $%08x, '%s', '%s') ...\n", clientPtr->port, clientPtr->pid, diskPtr->ioBSDName, diskPtr->flags, diskPtr->mountpoint, diskPtr->ioContent));
record->diskAppearedType = kDiskArbNotifyDiskAppeared;
record->port = clientPtr->port;
record->ioBSDName = strdup( diskPtr->ioBSDName );
record->flags = diskPtr->flags;
record->mountpoint = strdup( diskPtr->mountpoint );
record->pid = clientPtr->pid;
record->ioContent = strdup(diskPtr->ioContent);
record->ioDeviceTreePath = strdup(diskPtr->ioDeviceTreePath);
record->sequenceNumber = diskPtr->sequenceNumber;
StartDiskAppearedThread(record);
}
if ( clientPtr->flags & kDiskArbNotifyDiskAppeared2 )
{
DiskThreadRecord * record = malloc(sizeof(DiskThreadRecord));
dwarning(("DiskArbDiskAppeared2_rpc($%08x (pid=%d), '%s', $%08x, '%s', '%s', '%s', %d) ...\n", clientPtr->port, clientPtr->pid, diskPtr->ioBSDName, diskPtr->flags, diskPtr->mountpoint, diskPtr->ioContent, diskPtr->ioDeviceTreePath, diskPtr->sequenceNumber));
record->diskAppearedType = kDiskArbNotifyDiskAppeared2;
record->port = clientPtr->port;
record->ioBSDName = strdup( diskPtr->ioBSDName );
record->flags = diskPtr->flags;
record->mountpoint = strdup( diskPtr->mountpoint );
record->pid = clientPtr->pid;
record->ioContent = strdup(diskPtr->ioContent);
record->ioDeviceTreePath = strdup(diskPtr->ioDeviceTreePath);
record->sequenceNumber = diskPtr->sequenceNumber;
StartDiskAppearedThread(record);
}
}
}
}
for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next)
{
if ( kClientStateNew == clientPtr->state ) clientPtr->state = kClientStateIdle;
}
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( kDiskStateNew == diskPtr->state ) SetStateForOnePartition( diskPtr, kDiskStateIdle );
}
}
void SendUnrecognizedDiskMsgs(mach_port_t port, char *devname, char *fstype, char *deviceType, int isWritable, int isRemovable, int isWhole )
{
DiskThreadRecord * record = malloc(sizeof(DiskThreadRecord));
dwarning(("DiskArbUnknownFileSystemInserted_rpc($%08x) ...\n", port));
record->diskAppearedType = isWhole;
record->port = port;
record->ioBSDName = strdup( devname );
record->flags = isWritable;
record->mountpoint = strdup( fstype );
record->pid = 0;
record->ioContent = strdup(deviceType);
record->ioDeviceTreePath = strdup("");
record->sequenceNumber = isRemovable;
StartUnrecognizedDiskThread(record);
}
void SendDiskChangedMsgs(char *devname, char *newMountpoint, char *newVolumeName, int flags, int success)
{
ClientPtr clientPtr;
dwarning(("%s\n", __FUNCTION__));
for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next)
{
if ( ( clientPtr->flags & kDiskArbNotifyChangedDisks ) ) {
DiskThreadRecord * record = malloc(sizeof(DiskThreadRecord));
dwarning(("DiskArbDiskChanged_rpc($%08x (pid=%d)) ...\n", clientPtr->port, clientPtr->pid));
record->diskAppearedType = 0;
record->port = clientPtr->port;
record->ioBSDName = strdup( devname );
record->flags = flags;
record->mountpoint = strdup( newMountpoint );
record->pid = 0;
record->ioContent = strdup(newVolumeName);
record->ioDeviceTreePath = strdup("");
record->sequenceNumber = success;
StartDiskChangedThread(record);
}
}
}
void SendUnmountCommitMsgs( void )
{
ClientPtr clientPtr;
DiskPtr diskPtr;
kern_return_t r = 0;
dwarning(("%s\n", __FUNCTION__));
for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next)
{
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( kDiskStateNewlyUnmounted == diskPtr->state || kDiskStateNewlyEjected == diskPtr->state )
{
if ( clientPtr->flags & kDiskArbNotifyUnmount )
{
dwarning(("DiskArbUnmountCommit($%08x (pid=%d), '%s') ...\n", clientPtr->port, clientPtr->pid, diskPtr->ioBSDName));
if ( r == MACH_SEND_INVALID_DEST )
{
dwarning(("Dead client! Port = $%08x (pid=%d)\n", clientPtr->port, clientPtr->pid));
}
}
}
}
}
}
void PrepareToSendPreUnmountMsgs( void )
{
ClientPtr clientPtr;
DiskPtr diskPtr;
dwarning(("%s\n", __FUNCTION__));
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( kDiskStateToBeUnmounted == diskPtr->state || kDiskStateToBeUnmountedAndEjected == diskPtr->state )
{
for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next)
{
if ( clientPtr->flags & kDiskArbNotifyAsync )
{
InitAckValue( diskPtr->ackValues, clientPtr->pid );
}
}
}
}
}
void PrepareToSendPreEjectMsgs( void )
{
ClientPtr clientPtr;
DiskPtr diskPtr;
dwarning(("%s\n", __FUNCTION__));
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( kDiskStateToBeEjected == diskPtr->state )
{
for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next)
{
if ( clientPtr->flags & kDiskArbNotifyAsync )
{
InitAckValue( diskPtr->ackValues, clientPtr->pid );
}
}
}
}
}
void SendPreUnmountMsgs( void )
{
DiskPtr diskPtr;
int i;
dwarning(("%s\n", __FUNCTION__));
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( kDiskStateToBeUnmounted == diskPtr->state || kDiskStateToBeUnmountedAndEjected == diskPtr->state )
{
for (i = 0; i < diskPtr->ackValues->logicalLength; i++)
{
ClientPtr clientPtr;
kern_return_t r;
if ( diskPtr->ackValues->ackValues[ i ].state != kSendMsg )
{
continue;
}
clientPtr = LookupClientByPID( diskPtr->ackValues->ackValues[ i ].pid );
if ( ! clientPtr )
{
pwarning(("%s: pid = %d: no known client with this pid.\n", __FUNCTION__, diskPtr->ackValues->ackValues[ i ].pid));
}
if ( clientPtr->numAcksRequired > 0 )
{
continue;
}
dwarning(("DiskArbUnmountPreNotify_async_rpc($%08x (pid=%d), '%s', flags=$%08x) ...\n", clientPtr->port, clientPtr->pid, diskPtr->ioBSDName, 0 ));
r = DiskArbUnmountPreNotify_async_rpc(clientPtr->port, diskPtr->ioBSDName, 0 );
if ( r ) dwarning(("... $%08x: %s\n", r, mach_error_string(r)));
if ( r == MACH_SEND_INVALID_DEST )
{
dwarning(("Dead client! Port = $%08x (pid=%d)\n", clientPtr->port, clientPtr->pid));
}
if ( ! r )
{
clientPtr->numAcksRequired++;
}
diskPtr->ackValues->ackValues[ i ].state = kWaitingForAck;
}
}
}
}
void SendPreEjectMsgs( void )
{
DiskPtr diskPtr;
int i;
dwarning(("%s\n", __FUNCTION__));
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( kDiskStateToBeEjected == diskPtr->state )
{
for (i = 0; i < diskPtr->ackValues->logicalLength; i++)
{
ClientPtr clientPtr;
kern_return_t r;
if ( diskPtr->ackValues->ackValues[ i ].state != kSendMsg )
{
continue;
}
clientPtr = LookupClientByPID( diskPtr->ackValues->ackValues[ i ].pid );
if ( ! clientPtr )
{
pwarning(("%s: pid = %d: no known client with this pid.\n", __FUNCTION__, diskPtr->ackValues->ackValues[ i ].pid));
}
if ( clientPtr->numAcksRequired > 0 )
{
continue;
}
dwarning(("DiskArbEjectPreNotify_async_rpc($%08x (pid=%d), '%s', flags=$%08x) ...\n", clientPtr->port, clientPtr->pid, diskPtr->ioBSDName, 0 ));
r = DiskArbEjectPreNotify_async_rpc(clientPtr->port, diskPtr->ioBSDName, 0 );
if ( r ) dwarning(("... $%08x: %s\n", r, mach_error_string(r)));
if ( r == MACH_SEND_INVALID_DEST )
{
dwarning(("Dead client! Port = $%08x (pid=%d)\n", clientPtr->port, clientPtr->pid));
}
if ( ! r )
{
clientPtr->numAcksRequired++;
}
diskPtr->ackValues->ackValues[ i ].state = kWaitingForAck;
}
}
}
}
void SendUnmountPostNotifyMsgsForOnePartition( char * ioBSDName, int errorCode, pid_t pid )
{
ClientPtr clientPtr;
dwarning(("%s('%s', errorCode = %d, pid = %d)\n", __FUNCTION__, ioBSDName, errorCode, pid));
for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next)
{
if ( clientPtr->flags & kDiskArbNotifyAsync )
{
kern_return_t r;
dwarning(("DiskArbUnmountPostNotify_async_rpc($%08x (pid=%d), '%s', errorCode=%d, pid=%d) ...\n", clientPtr->port, clientPtr->pid, ioBSDName, errorCode, pid));
r = DiskArbUnmountPostNotify_async_rpc(clientPtr->port, ioBSDName, errorCode, pid);
if ( r ) dwarning(("... $%08x: %s\n", r, mach_error_string(r)));
if ( r == MACH_SEND_INVALID_DEST )
{
dwarning(("Dead client! Port = $%08x (pid=%d)\n", clientPtr->port, clientPtr->pid));
}
}
}
}
void SendEjectPostNotifyMsgsForOnePartition( char * ioBSDName, int errorCode, pid_t pid )
{
ClientPtr clientPtr;
dwarning(("%s('%s', errorCode = %d, pid = %d)\n", __FUNCTION__, ioBSDName, errorCode, pid));
for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next)
{
if ( clientPtr->flags & kDiskArbNotifyAsync )
{
kern_return_t r;
dwarning(("DiskArbEjectPostNotify_async_rpc($%08x (pid=%d), '%s', errorCode=%d, pid=%d) ...\n", clientPtr->port, clientPtr->pid, ioBSDName, errorCode, pid));
r = DiskArbEjectPostNotify_async_rpc(clientPtr->port, ioBSDName, errorCode, pid);
if ( r ) dwarning(("... $%08x: %s\n", r, mach_error_string(r)));
if ( r == MACH_SEND_INVALID_DEST )
{
dwarning(("Dead client! Port = $%08x (pid=%d)\n", clientPtr->port, clientPtr->pid));
}
}
}
}
void SendEjectPostNotifyMsgsForAllPartitions( DiskPtr diskPtr, int errorCode, pid_t pid )
{
DiskPtr diskPtr2;
int family1, family2;
int deviceNum1, deviceNum2;
dwarning(("%s('%s', errorCode = %d, pid = %d)\n", __FUNCTION__, diskPtr->ioBSDName, errorCode, pid));
if ( IsNetwork( diskPtr ) )
{
SendEjectPostNotifyMsgsForOnePartition( diskPtr->ioBSDName, errorCode, pid );
goto Return;
}
family1 = diskPtr->family;
deviceNum1 = diskPtr->ioBSDUnit;
for (diskPtr2 = g.Disks; diskPtr2 != NULL; diskPtr2 = diskPtr2->next)
{
family2 = diskPtr2->family;
deviceNum2 = diskPtr2->ioBSDUnit;
if ( family1 == family2 && deviceNum1 == deviceNum2 )
{
SendEjectPostNotifyMsgsForOnePartition( diskPtr2->ioBSDName, errorCode, pid );
}
}
Return:
return;
}
void SendBlueBoxBootVolumeUpdatedMsgs( void )
{
ClientPtr clientPtr;
dwarning(("%s()\n", __FUNCTION__));
for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next)
{
if ( clientPtr->flags & kDiskArbNotifyBlueBoxBootVolumeUpdated )
{
DiskThreadRecord * record = malloc(sizeof(DiskThreadRecord));
dwarning(("DiskArbBlueBoxBootVolumeUpdated_async_rpc($%08x (pid=%d), gBlueBoxBootVolume=%d) ...\n", clientPtr->port, clientPtr->pid, gBlueBoxBootVolume));
record->sequenceNumber = gBlueBoxBootVolume;
record->port = clientPtr->port;
StartBlueBoxNotificationThread(record);
}
}
}
void SendCompletedMsgs( int messageType )
{
ClientPtr clientPtr;
dwarning(("%s(%d)\n", __FUNCTION__, messageType));
for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next)
{
if ( ( clientPtr->flags & kDiskArbNotifyCompleted ) ) {
DiskThreadRecord * record = malloc(sizeof(DiskThreadRecord));
dwarning(("DiskArbNotificationComplete_rpc($%08x (messageType=%d)) ...\n", clientPtr->port, messageType));
record->port = clientPtr->port;
record->sequenceNumber = messageType;
StartDiskMessagesCompleted(record);
}
}
}
void SetBlueBoxBootVolume( int seqno )
{
dwarning(("%s(seqno=%d)\n", __FUNCTION__, seqno));
gBlueBoxBootVolume = seqno;
SendBlueBoxBootVolumeUpdatedMsgs();
}
int GetBlueBoxBootVolume( void )
{
return gBlueBoxBootVolume;
}
void CompleteUnmount( void )
{
DiskPtr diskPtr;
AckValue * avp;
int errorCode_out = 0;
pid_t pid_out = 0;
DiskPtr wholeDiskToBeEjectedOrNULL;
dwarning(("%s\n", __FUNCTION__));
if ( 0 != NumUnsetAckValuesForAllDisks() )
{
goto Return;
}
wholeDiskToBeEjectedOrNULL = LookupWholeDiskToBeEjected();
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next)
{
if ( diskPtr->state != kDiskStateToBeUnmounted && diskPtr->state != kDiskStateToBeUnmountedAndEjected )
{
continue;
}
avp = GetDissenterFromAckValues( diskPtr->ackValues );
if ( NULL == avp )
{
int err;
dwarning(("%s: there was no dissenter for '%s'\n", __FUNCTION__, diskPtr->ioBSDName));
err = UnmountDisk( diskPtr, FALSE );
if ( err )
{
dwarning(("%s: the unmount failed\n", __FUNCTION__));
errorCode_out = err;
pid_out = -1;
}
else
{
errorCode_out = 0;
pid_out = -1;
}
}
else
{
dwarning(("%s: there was a dissenter for '%s'\n", __FUNCTION__, diskPtr->ioBSDName));
errorCode_out = avp->errorCode;
pid_out = avp->pid;
SetStateForOnePartition( diskPtr, kDiskStateIdle );
}
SendUnmountPostNotifyMsgsForOnePartition( diskPtr->ioBSDName, errorCode_out, pid_out );
}
if ( wholeDiskToBeEjectedOrNULL && ( 0 == NumPartitionsMountedFromThisDisk( wholeDiskToBeEjectedOrNULL ) ) )
{
SetStateForAllPartitions( wholeDiskToBeEjectedOrNULL, kDiskStateToBeEjected );
PrepareToSendPreEjectMsgs();
}
Return:
return;
}
void CompleteEject( void )
{
DiskPtr diskPtr;
AckValue * avp;
int errorCode_out = 0;
pid_t pid_out = 0;
dwarning(("%s\n", __FUNCTION__));
if ( 0 != NumUnsetAckValuesForAllDisks() )
{
goto Return;
}
diskPtr = LookupWholeDiskToBeEjected();
if ( ! diskPtr )
{
LogErrorMessage("%s(): LookupWholeDiskToBeEjected() => NULL\n", __FUNCTION__);
goto Return;
}
avp = GetDissenterFromAckValuesForAllDisks();
if ( NULL == avp )
{
int err;
dwarning(("%s: there was no dissenter\n", __FUNCTION__));
err = EjectDisk( diskPtr );
if ( err )
{
dwarning(("%s: the eject failed\n", __FUNCTION__));
errorCode_out = err;
pid_out = -1;
}
else
{
errorCode_out = 0;
pid_out = -1;
}
}
else
{
dwarning(("%s: there was a dissenter\n", __FUNCTION__));
errorCode_out = avp->errorCode;
pid_out = avp->pid;
SetStateForAllPartitions( diskPtr, kDiskStateIdle );
}
SendEjectPostNotifyMsgsForAllPartitions( diskPtr, errorCode_out, pid_out );
Return:
return;
}
DiskState AreWeBusy( void )
{
DiskState result;
DiskPtr diskPtr;
result = kDiskStateIdle;
for (diskPtr = g.Disks; diskPtr != NULL ; diskPtr = diskPtr->next)
{
switch ( diskPtr->state )
{
case kDiskStateToBeUnmounted:
if ( kDiskStateIdle == result )
{
result = diskPtr->state;
}
else if ( result != diskPtr->state )
{
dwarning(("%s: incompatible disk states: %s (%d) vs. %s (%d)\n", __FUNCTION__, DISKSTATE(diskPtr->state), diskPtr->state, DISKSTATE(result), result));
}
break;
case kDiskStateToBeEjected:
if ( kDiskStateIdle == result )
{
result = diskPtr->state;
}
else if ( result != diskPtr->state )
{
dwarning(("%s: incompatible disk states: %s (%d) vs. %s (%d)\n", __FUNCTION__, DISKSTATE(diskPtr->state), diskPtr->state, DISKSTATE(result), result));
}
break;
case kDiskStateToBeUnmountedAndEjected:
if ( kDiskStateIdle == result || kDiskStateToBeEjected == result )
{
result = diskPtr->state;
}
else if ( result != diskPtr->state )
{
dwarning(("%s: incompatible disk states: %s (%d) vs. %s (%d)\n", __FUNCTION__, DISKSTATE(diskPtr->state), diskPtr->state, DISKSTATE(result), result));
}
break;
case kDiskStateIdle:
case kDiskStateNew:
case kDiskStateNewlyEjected:
case kDiskStateNewlyUnmounted:
default:
break;
}
}
dwarning(("%s() => %s (%d)\n", __FUNCTION__, DISKSTATE(result), result));
return result;
}
DiskState AreWeBusyForDisk( DiskPtr diskPtr )
{
DiskState result;
result = kDiskStateIdle;
switch ( diskPtr->state )
{
case kDiskStateToBeUnmounted:
if ( kDiskStateIdle == result )
{
result = diskPtr->state;
}
else if ( result != diskPtr->state )
{
dwarning(("%s: incompatible disk states: %s (%d) vs. %s (%d)\n", __FUNCTION__, DISKSTATE(diskPtr->state), diskPtr->state, DISKSTATE(result), result));
}
break;
case kDiskStateToBeEjected:
if ( kDiskStateIdle == result )
{
result = diskPtr->state;
}
else if ( result != diskPtr->state )
{
dwarning(("%s: incompatible disk states: %s (%d) vs. %s (%d)\n", __FUNCTION__, DISKSTATE(diskPtr->state), diskPtr->state, DISKSTATE(result), result));
}
break;
case kDiskStateToBeUnmountedAndEjected:
if ( kDiskStateIdle == result || kDiskStateToBeEjected == result )
{
result = diskPtr->state;
}
else if ( result != diskPtr->state )
{
dwarning(("%s: incompatible disk states: %s (%d) vs. %s (%d)\n", __FUNCTION__, DISKSTATE(diskPtr->state), diskPtr->state, DISKSTATE(result), result));
}
break;
case kDiskStateIdle:
case kDiskStateNew:
case kDiskStateNewlyEjected:
case kDiskStateNewlyUnmounted:
default:
break;
}
dwarning(("%s() => %s (%d)\n", __FUNCTION__, DISKSTATE(result), result));
return result;
}
static void
writepid(void)
{
FILE *fp;
fp = fopen(PID_FILE, "w");
if (fp != NULL)
{
fprintf(fp, "%d\n", getpid());
fclose(fp);
}
}
int DiskArbitrationServerMain(int argc, char* argv[])
{
kern_return_t r;
mach_port_t serverPort;
mach_port_t ioNotificationPort;
const char * ioNotificationType;
io_iterator_t ioIterator; io_iterator_t ioIterator2; io_registry_entry_t entry;
mach_port_t portSet;
mach_msg_header_t* msg;
mach_msg_header_t* reply;
mach_msg_timeout_t timeout;
programName = argv[0];
if ((argc > 1) && (argv[1][0] == '-') && (argv[1][1] == 'd'))
{
gDebug = 1;
gDaemon = 0;
dwarning(("DiskArbitration is not a daemon\n"));
}
else
{
gDaemon = 1;
dwarning(("DiskArbitration is a daemon\n"));
}
msg = (mach_msg_header_t*)malloc(kMsgSize);
reply = (mach_msg_header_t*)malloc(kMsgSize);
cacheFileSystemDictionaries();
cacheFileSystemMatchingArray();
if (gDebug) {
printArgsForFsname("ufs");
printArgsForFsname("hfs");
printArgsForFsname("cd9660");
printArgsForFsname("msdos");
printArgsForFsname("udf");
printArgsForFsname("cdda");
printArgsForFsname("foobar");
}
r = InitNotifyPort();
if (r != KERN_SUCCESS)
{
return -1;
}
r = IOMasterPort(bootstrap_port, &ioMasterPort);
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) IOMasterPort failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
r = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &ioNotificationPort);
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) mach_port_allocate failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
ioNotificationType = kIOFirstMatchNotification;
r = IOServiceAddNotification( ioMasterPort, ioNotificationType,
IOServiceMatching( "IOMedia" ),
ioNotificationPort, (unsigned int) ioNotificationType,
&ioIterator );
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) IOServiceAddNotification failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
GetDisksFromRegistry( ioIterator );
ioNotificationType = kIOTerminatedNotification;
r = IOServiceAddNotification( ioMasterPort, ioNotificationType,
IOServiceMatching( "IOMedia" ),
ioNotificationPort, (unsigned int) ioNotificationType,
&ioIterator2 );
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) IOServiceAddNotification failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
while ( entry = IOIteratorNext( ioIterator2 ) ) { IOObjectRelease( entry );
}
autodiskmount(FALSE);
dwarning(("Non-debug version calls daemon() here...\n"));
if ( gDaemon )
{
FreeAllDisks();
if (-1 == daemon(0, 0))
{
return -1;
}
r = InitNotifyPort();
if (r != KERN_SUCCESS)
{
return -1;
}
r = IOMasterPort(bootstrap_port, &ioMasterPort);
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) IOMasterPort failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
r = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &ioNotificationPort);
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) mach_port_allocate failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
ioNotificationType = kIOFirstMatchNotification;
r = IOServiceAddNotification( ioMasterPort, ioNotificationType,
IOServiceMatching( "IOMedia" ),
ioNotificationPort, (unsigned int) ioNotificationType,
&ioIterator );
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) IOServiceAddNotification failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
GetDisksFromRegistry( ioIterator );
ioNotificationType = kIOTerminatedNotification;
r = IOServiceAddNotification( ioMasterPort, ioNotificationType,
IOServiceMatching( "IOMedia" ),
ioNotificationPort, (unsigned int) ioNotificationType,
&ioIterator2 );
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) IOServiceAddNotification failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
while ( entry = IOIteratorNext( ioIterator2 ) ) { IOObjectRelease( entry );
}
autodiskmount(FALSE);
}
{
yankedHeader = YANKED_HEADER;
yankedMessage = YANKED_MESSAGE;
unrecognizedHeader = UNINITED_HEADER;
unrecognizedMessage = UNINITED_MESSAGE;
ejectString = EJECT_BUTTON;
ignoreString = IGNORE_BUTTON;
initString = INIT_BUTTON;
}
r = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &serverPort);
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) mach_port_allocate failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
r = mach_port_insert_right(mach_task_self(), serverPort, serverPort, MACH_MSG_TYPE_MAKE_SEND);
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) mach_port_insert_right failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
dwarning(("%s: serverPort = %d\n", programName, (int)serverPort));
r = bootstrap_register(bootstrap_port, DISKARB_SERVER_NAME, serverPort);
if (r != KERN_SUCCESS)
{
return -1;
}
r = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &portSet);
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) mach_port_allocate failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
r = mach_port_move_member(mach_task_self(), GetNotifyPort(), portSet);
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) mach_port_move_member (notify port) failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
r = mach_port_move_member(mach_task_self(), serverPort, portSet);
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) mach_port_move_member (server port) failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
r = mach_port_move_member(mach_task_self(), ioNotificationPort, portSet);
if (r != KERN_SUCCESS)
{
LogErrorMessage("(%s:%d) mach_port_move_member (IO notification port) failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
return -1;
}
writepid();
while( 1 )
{
DiskPtr diskPtr;
DiskPtr nextDiskPtr;
mach_port_t deadPort;
DiskState busyState;
busyState = AreWeBusy();
if ( kDiskStateToBeUnmounted == busyState || kDiskStateToBeUnmountedAndEjected == busyState )
{
CompleteUnmount();
if (NumUnsetAckValuesForAllDisks() == 0) {
SendCompletedMsgs(kDiskArbCompletedPostUnmount);
}
busyState = AreWeBusy();
}
if ( kDiskStateToBeEjected == busyState )
{
CompleteEject();
if (NumUnsetAckValuesForAllDisks() == 0) {
SendCompletedMsgs(kDiskArbCompletedPostEject);
}
busyState = AreWeBusy();
}
if ( kDiskStateToBeUnmounted == busyState || kDiskStateToBeUnmountedAndEjected == busyState )
{
SendPreUnmountMsgs();
}
if ( kDiskStateToBeEjected == busyState )
{
SendPreEjectMsgs();
}
if ( kDiskStateIdle == busyState )
{
SendDiskAppearedMsgs();
SendCompletedMsgs(kDiskArbCompletedDiskAppeared);
}
nextDiskPtr = g.Disks;
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = nextDiskPtr)
{
nextDiskPtr = diskPtr->next;
switch ( diskPtr->state )
{
case kDiskStateNewlyUnmounted:
SetStateForOnePartition( diskPtr, kDiskStateIdle );
break;
case kDiskStateNewlyEjected:
FreeDisk( diskPtr );
break;
case kDiskStateIdle:
case kDiskStateNew:
case kDiskStateToBeUnmounted:
case kDiskStateToBeEjected:
case kDiskStateToBeUnmountedAndEjected:
default:
break;
}
}
if ( g.NumDisksAddedOrDeleted )
{
PrintDisks();
g.NumDisksAddedOrDeleted = 0;
}
if (NumUnsetAckValuesForAllDisks() != 0) {
timeout = (mach_msg_timeout_t)(15000);
} else {
timeout = MACH_MSG_TIMEOUT_NONE;
}
dwarning(("%s: mach_msg\n", programName));
r = mach_msg(msg, MACH_RCV_MSG | (MACH_MSG_TIMEOUT_NONE == timeout ? 0 : MACH_RCV_TIMEOUT), 0, kMsgSize, portSet, timeout, MACH_PORT_NULL);
if (r == MACH_RCV_TIMED_OUT) {
AckValue *unresponder = GetUnresponderFromAckValuesForAllDisks();
if (unresponder && unresponder->pid) {
Client *unrespondingClient = LookupClientByPID(unresponder->pid);
mach_port_t unrespondingPort = unrespondingClient->port;
dwarning(("**********Someone (pid = (%d)) isn't responding to a sent acknowledgement request\n", unresponder->pid));
SendClientWasDisconnectedMsg(unrespondingClient);
ClientDeath(unrespondingPort);
} else {
dwarning(("Someone timed out, but we don't know who ..."));
}
}
if (r != KERN_SUCCESS) {
LogErrorMessage("(%s:%d) mach_msg failed: {0x%x} %s\n", __FILE__, __LINE__, r, mach_error_string(r));
continue;
}
if ( msg->msgh_local_port == GetNotifyPort() )
{
dwarning(("%s: Message received on notification port\n", programName));
if ( MessageIsNotificationDeath( msg, & deadPort ) == TRUE )
{
dwarning(("Death of port %d\n", (int)deadPort));
{
kern_return_t r;
r = mach_port_deallocate( mach_task_self(), deadPort );
if ( r ) dwarning(("%s(client = $%08x): mach_port_deallocate(...,$%08x) => $%08x: %s\n", __FUNCTION__, (int)deadPort, (int)deadPort, r, mach_error_string(r)));
}
ClientDeath( deadPort );
}
else
{
}
}
else if ( msg->msgh_local_port == serverPort )
{
dwarning(("%s: Message received on server port from port $%08x\n", programName, (int)(msg->msgh_remote_port)));
bzero( reply, sizeof( mach_msg_header_t ) );
(void) ClientToServer_server(msg, reply);
(void) mach_msg_send(reply);
}
else if ( msg->msgh_local_port == ioNotificationPort )
{
dwarning(("%s: Message received on IO notification port from port $%08x\n", programName, (int)(msg->msgh_remote_port)));
HandleIONotificationMsg( (IONotificationMsgPtr) msg );
}
else
{
LogErrorMessage("Unrecognized receive port %d.\n", (int)(msg->msgh_local_port));
}
}
dwarning(("%s: exit\n", programName));
return -1;
}