/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 1.0 (the 'License'). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License." * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ClientToServer.h" #include "ServerToClient.h" #include "DiskArbitrationTypes.h" #include "DiskArbitrationServerMain.h" #include "GetRegistry.h" #include "FSParticular.h" #define FILESYSTEM_ERROR 0 #define FILESYSTEM_MOUNTED 1 #define FILESYSTEM_MOUNTED_ALREADY 2 #define FILESYSTEM_NEEDS_REPAIR 3 #define ATTRREFDATA(ref) (((char *)(&(ref))) + (ref).attr_dataoffset) struct volattr { attrreference_t volnameref; unsigned char volumenamestorage[140]; }; struct volattrbuf { unsigned long length; struct volattr va; }; struct cominfo { text_encoding_t encoding; }; struct cominfobuf { unsigned long length; struct cominfo ci; }; int currentConsoleUser = -1; extern void autodiskmount(int ownership); /********************************************************************************************************/ /******************************************* Private Prototypes *****************************************/ static ClientPtr LookupBlueBox( void ); /********************************************************************************************************/ /********************************************************************************************************/ /******************************************* Private Functions ******************************************/ /********************************************************************************************************/ /** ripped off from workspace - start **/ void cleanUpAfterFork(void) { int fd, maxfd = getdtablesize(); /* Close all inherited file descriptors */ for (fd = 0; fd < maxfd; fd++) { close(fd); } /* Disassociate ourselves from any controlling tty */ if ((fd = open("/dev/tty", O_NDELAY)) >= 0) { ioctl(fd, TIOCNOTTY, 0); close(fd); } /* Reset the user and group id's to their real values */ setgid(getgid()); setuid(getuid()); /* stdin = /dev/null */ /* stdout = /dev/console */ /* stderr = stdout = /dev/console */ fd = open("/dev/null", O_RDONLY); fd = open("/dev/console", O_WRONLY); dup2(1, 2); } /********************************************************************************************************/ /******************************************* Public Functions *******************************************/ /********************************************************************************************************/ /******************************************* ClientDeath *******************************************/ void ClientDeath(mach_port_t client); void ClientDeath(mach_port_t client) { ClientPtr thisPtr, previousPtr; /* Deletes the first client record whose port matches. */ dwarning(("%s(client = $%08x)\n", __FUNCTION__, client)); /* Is the list empty? */ if ( g.Clients == NULL ) { goto NotFound; } /* Is it the first element of the list? */ if ( g.Clients->port == client ) { /* Save the pointer */ thisPtr = g.Clients; /* Unlink the record from the list */ g.Clients = g.Clients->next; /* Assert: thisPtr->port == client */ goto FoundIt; } /* Is it somewhere in the body of the list? */ previousPtr = g.Clients; /* Assert: previousPtr != NULL since g.Clients != NULL */ thisPtr = previousPtr->next; while ( thisPtr != NULL ) { /* Invariant: previousPtr != NULL and thisPtr != NULL and previousPtr->next == thisPtr */ if ( thisPtr->port == client ) { /* Unlink the record from the list */ previousPtr->next = thisPtr->next; /* Assert: thisPtr->port == client */ goto FoundIt; } /* Advance to the next element, reestablishing the invariant */ previousPtr = thisPtr; thisPtr = previousPtr->next; } /* If we get here, it means we never found a matching client record */ goto NotFound; FoundIt: /* Precondition: thisPtr->port == client */ dwarning(("Found client record to delete:\n")); PrintClient( thisPtr ); /* In case this client is mentioned on any ack lists, forge a no-error ack value. */ MakeDeadClientAgreeable( thisPtr ); /* Deallocate the port once, free the memory, decrement the count, and return */ { kern_return_t r; r = mach_port_deallocate( mach_task_self(), thisPtr->port ); if ( r ) dwarning(("%s(client = $%08x): mach_port_deallocate(...,$%08x) => $%08x: %s\n", __FUNCTION__, client, client, r, mach_error_string(r))); } if ( thisPtr->flags & kDiskArbIAmBlueBox ) { dwarning(("%s: Blue Box died, resetting gBlueBoxBootVolume = -1\n",__FUNCTION__)); SetBlueBoxBootVolume( -1 ); } { DiskPtr diskPtr; for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next) { if (diskPtr->retainingClient == thisPtr->pid) { if (diskPtr->flags & kDiskArbDiskAppearedUnrecognizableFormat) { diskPtr->state = kDiskStateNew; // mark the disk new so that someone else claims it } diskPtr->retainingClient = 0; } } } if (thisPtr->ackOnUnrecognizedDisk) { DiskPtr ackDisk = (DiskPtr)thisPtr->ackOnUnrecognizedDisk; ackDisk->retainingClient = 0; ackDisk->state = kDiskStateNew; ackDisk->lastClientAttemptedForUnrecognizedMessages = nil; thisPtr->ackOnUnrecognizedDisk = nil; } if (thisPtr->clientAuthRef) { AuthorizationFree(thisPtr->clientAuthRef, NULL); } free( thisPtr ); g.NumClients--; goto Return; NotFound: dwarning(("%s(client = $%08x): no matching client found!\n", __FUNCTION__, client)); goto Return; Return: dwarning(("%s($%08x), After:\n", __FUNCTION__, client)); PrintClients(); return; } // ClientDeath /******************************************* DiskArbRegister_rpc *******************************************/ kern_return_t DiskArbRegister_rpc ( mach_port_t server, mach_port_t client, unsigned flags) { kern_return_t err = 0; ClientPtr newClient = NULL; dwarning(("%s(client = $%08x, flags = $%08x)\n", __FUNCTION__, client, flags)); /* First, attempt to register for death notifications. If it fails, then deallocate the client-supplied port and exit with an error without creating a client record. */ if ( EnableDeathNotifications( client ) ) { dwarning(("%s(client = $%08x, flags = $%08x): EnableDeathNotifications() failed!\n", __FUNCTION__, (int)client, (int)flags)); { kern_return_t r; r = mach_port_deallocate( mach_task_self(), client ); dwarning(("%s(client = $%08x): mach_port_deallocate(...,$%08x) => $%08x: %s\n", __FUNCTION__, client, client, r, mach_error_string(r))); } err = -1; goto Return; } /* If we got this far, we can safely create a client record knowing that if the client dies we will be sent a MACH_NOTIFY_DEAD_NAME message. */ /* Allocate a new client record. */ newClient = NewClient(client, 0, flags); if ( newClient == NULL ) { dwarning(("%s(client = $%08x, flags = $%08x): NewClient failed!\n", __FUNCTION__, client, flags)); err = -1; goto Return; } else { StartDiskRegistrationCompleteThread(newClient); } PrintClients(); Return: return err; } // DiskArbRegister_rpc /******************************************* DiskArbDiskAppearedWithMountpointPing_rpc *******************************************/ kern_return_t DiskArbDiskAppearedWithMountpointPing_rpc ( mach_port_t server, DiskArbDiskIdentifier diskIdentifier, unsigned flags, DiskArbMountpoint mountpoint) { DiskPtr newDisk; kern_return_t err = 0; dwarning(("%s(diskIdentifier = '%s', flags = $%08x, mountpoint = '%s')\n", __FUNCTION__, diskIdentifier, flags, mountpoint)); newDisk = NewDisk( diskIdentifier, /*ioBSDName*/ 0, /*ioBSDUnit*/ NULL, /*ioContentOrNull*/ kDiskFamily_AFP, /*family*/ mountpoint, /*mountpoint*/ NULL, /*ioMediaNameOrNull*/ NULL, /*ioDeviceTreePathOrNull*/ NULL, /*service*/ -1, /*uid*/ flags ); if ( !newDisk ) /*flags*/ { dwarning(("%s: NewDisk() failed!\n", __FUNCTION__)); } else { newDisk->admCreatedMountPoint = 1; // this is so we clean up mountpoints created by other apps when we close down the remote connections } goto Return; Return: return err; } // DiskArbDiskAppearedWithMountpointPing_rpc /******************************************* DiskArbDiskAppearedWithMountpointPing_rpc *******************************************/ kern_return_t DiskArbDiskDisappearedPing_rpc ( mach_port_t server, DiskArbDiskIdentifier diskIdentifier, unsigned flags) { kern_return_t err = 0; DiskPtr diskPtr; dwarning(("%s(diskIdentifier = '%s', flags = $%08x)\n", __FUNCTION__, diskIdentifier, flags)); diskPtr = LookupDiskByIOBSDName( diskIdentifier ); if ( NULL == diskPtr ) { dwarning(("%s(diskIdentifier = '%s'): LookupDiskByIOBDSName failed\n", __FUNCTION__, diskIdentifier)); err = -1; goto Return; } err = UnmountAllPartitions( diskPtr, FALSE ); SendUnmountPostNotifyMsgsForOnePartition( diskPtr->ioBSDName, 0, 0 ); SendEjectPostNotifyMsgsForOnePartition( diskPtr->ioBSDName, 0, 0 ); FreeDisk( diskPtr ); if ( err ) goto Return; // PrintDisks(); goto Return; Return: return err; } // DiskArbDiskDisappearedPing_rpc /*** Local function for refresh ***/ static int DiskExistsInMountTable(DiskPtr diskPtr) { struct statfs *mntbuf; int numMounts; int index = 1; if ((numMounts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) { pwarning(("getmntinfo() call failed!\n")); } for (index=0; index < numMounts; index++) { char devdName[MAXPATHLEN]; if (strcmp(diskPtr->ioBSDName, mntbuf[index].f_mntfromname) == 0) { dwarning(("%s: Disk discovered in mount table as %s.\n", __FUNCTION__, mntbuf[index].f_mntfromname)); return TRUE; } sprintf(devdName, "/dev/%s", diskPtr->ioBSDName); if (strcmp(mntbuf[index].f_mntfromname, devdName) == 0) { dwarning(("%s: Disk discovered in mount table as %s.\n", __FUNCTION__, devdName)); return TRUE; } } dwarning(("%s: Disk NOT discovered in mount table at %s(did someone umount it)?\n", __FUNCTION__, diskPtr->ioBSDName)); return FALSE; } /******************************************* DiskArbRefresh_rpc *******************************************/ kern_return_t DiskArbRefresh_rpc ( mach_port_t server) { kern_return_t err = 0; int index = 1; struct statfs *mntbuf; int numMounts; DiskPtr diskPtr; // look for things newly mounted if ((numMounts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) { dwarning(("getmntinfo() call failed!\n")); } for (index=0; index < numMounts; index++) { char *dev_removed_name = NULL; if (strstr(mntbuf[index].f_mntfromname, "/dev/")) { dev_removed_name = mntbuf[index].f_mntfromname + 5; /* 5 = /dev/ */ } /* If the mountfrom name is 'fdesc', , or devfs, skip it */ if (strcmp(mntbuf[index].f_mntfromname, "fdesc") == 0) { continue; } else if (strcmp(mntbuf[index].f_mntfromname, "devfs") == 0) { continue; } else if (strcmp(mntbuf[index].f_mntfromname, "") == 0) { continue; } else if (strstr(mntbuf[index].f_mntfromname, "automount -fstab") != 0) { continue; } if (!dev_removed_name) { diskPtr = LookupDiskByIOBSDName( mntbuf[index].f_mntfromname ); } else { diskPtr = LookupDiskByIOBSDName( dev_removed_name ); } if (diskPtr && (diskPtr->mountpoint == NULL || (!strcmp(diskPtr->mountpoint, "")))) { int newDisks; DiskSetMountpoint(diskPtr, mntbuf[index].f_mntonname); dwarning(("%s: Disk updated in mount table (did someone mount one)?\n", __FUNCTION__)); dwarning(("%s %s %s\n", mntbuf[index].f_fstypename, mntbuf[index].f_mntonname, mntbuf[index].f_mntfromname)); diskPtr->state = kDiskStateNew; newDisks = SendDiskAppearedMsgs(); SendCompletedMsgs(kDiskArbCompletedDiskAppeared, newDisks); } else if (!diskPtr) { if ( ! NewDisk( dev_removed_name?dev_removed_name:mntbuf[index].f_mntfromname, 0, NULL, kDiskFamily_SCSI, mntbuf[index].f_mntonname, NULL, NULL, NULL, -1, kDiskArbDiskAppearedNoFlags ) ) { dwarning(("%s: NewDisk() failed!\n", __FUNCTION__)); } else { dwarning(("%s: NewDisk() discovered (did someone mount one)?\n", __FUNCTION__)); dwarning(("%s %s %s\n", mntbuf[index].f_fstypename, mntbuf[index].f_mntonname, mntbuf[index].f_mntfromname)); } } } for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next) { int exists = 0; if (diskPtr->mountpoint == NULL || (strcmp(diskPtr->mountpoint, "") == 0)) { continue; } // verify that each disk exists in the mount table exists = DiskExistsInMountTable(diskPtr); // otherwise - remove the disk if (!exists) { DiskSetMountpoint(diskPtr, ""); SetStateForOnePartition( diskPtr, kDiskStateNewlyUnmounted ); SendUnmountPostNotifyMsgsForOnePartition( diskPtr->ioBSDName, 0, 0 ); } } return err; } // DiskArbRefresh_rpc /******************************************* DiskArbRequestMount_rpc *******************************************/ kern_return_t DiskArbRequestMount_rpc ( mach_port_t server, DiskArbDiskIdentifier diskIdentifier, int takeUserOwnership) { kern_return_t err = 0; io_iterator_t ioIterator; mach_port_t masterPort; DiskPtr diskPtr; err = IOMasterPort(bootstrap_port, &masterPort); dwarning(("%s(diskIdentifier = '%s')\n", __FUNCTION__, diskIdentifier)); // get an iterator from the registry for IOMedia and get the disks out of the registry ... err = IOServiceGetMatchingServices(masterPort, IOServiceMatching("IOMedia"), &ioIterator); diskPtr = LookupDiskByIOBSDName( diskIdentifier ); if (diskPtr) { // unmount the disk and it's partitions ... UnmountAllPartitions(diskPtr, FALSE); // remove the disk from my tables FreeDisk(diskPtr); } GetDisksFromRegistry( ioIterator, 0 ); autodiskmount(takeUserOwnership); // is this sufficient? return err; } // DiskArbRequestMount_rpc /******************************************* DiskArbRegisterWithPID_rpc *******************************************/ kern_return_t DiskArbRegisterWithPID_rpc ( mach_port_t server, mach_port_t client, int pid, unsigned flags) { kern_return_t err = 0; ClientPtr clientPtr = NULL; dwarning(("%s(client = $%08x, pid = %d, flags = $%08x)\n", __FUNCTION__, client, pid, flags)); /* First, attempt to register for death notifications. If it fails, then deallocate the client-supplied port and exit with an error without creating a client record. */ if ( EnableDeathNotifications( client ) ) { dwarning(("%s(client = $%08x, pid = %d, flags = $%08x): EnableDeathNotifications() failed!\n", __FUNCTION__, (int)client, pid, (int)flags)); { kern_return_t r; r = mach_port_deallocate( mach_task_self(), client ); if ( r ) dwarning(("%s(client = $%08x): mach_port_deallocate(...,$%08x) => $%08x: %s\n", __FUNCTION__, client, client, r, mach_error_string(r))); } err = -1; goto Return; } /* If we got this far, we can safely create a client record knowing that if the client dies we will be sent a MACH_NOTIFY_DEAD_NAME message. */ /* Allocate a new client record. */ clientPtr = LookupClientByPID( pid ); if ( clientPtr ) { /* Update existing client record. */ dwarning(("%s(client = $%08x, pid = %d, flags = $%08x): updating existing client record:\n", __FUNCTION__, client, pid, flags)); PrintClient( clientPtr ); mach_port_deallocate( mach_task_self(), client ); clientPtr->port = client; // Should we mach_port_deallocate() whatever was in there before if it differs from the new value? clientPtr->flags = flags; clientPtr->state = kDiskStateNew; // Force a re-send of all the msgs. } else { /* Allocate a new client record. */ clientPtr = NewClient(client, pid, flags); if ( clientPtr == NULL ) { dwarning(("%s(client = $%08x, pid = %d, flags = $%08x): NewClient failed!\n", __FUNCTION__, client, pid, flags)); err = -1; } else { dwarning(("%s(client = $%08x, pid = %d, flags = $%08x): Starting Complete Registration Thread!\n", __FUNCTION__, client, pid, flags)); StartDiskRegistrationCompleteThread(clientPtr); } } PrintClients(); Return: //*errorCodePtr = err; return err; } // DiskArbRegisterWithPID_rpc /******************************************* DiskArbmarkPIDNew_rpc *******************************************/ kern_return_t DiskArbMarkPIDNew_rpc ( mach_port_t server, mach_port_t client, int pid, unsigned flags) { dwarning(("%s(client = $%08x, pid = %d, flags = $%08x)\n", __FUNCTION__, client, pid, flags)); ClientDeath(client); EnableDeathNotifications( client ); NewClient(client, pid, flags); return 0; } // DiskArbMarkPIDNew_rpc /******************************************* DiskArbUpdateClientWithPID_rpc *******************************************/ kern_return_t DiskArbUpdateClientWithPID_rpc ( mach_port_t server, int pid, unsigned flags) { ClientPtr clientPtr = LookupClientByPID( pid ); if ( clientPtr ) { /* Update existing client record. */ dwarning(("%s(pid = %d, flags = $%08x): updating existing client record:\n", __FUNCTION__, pid, flags)); PrintClient( clientPtr ); clientPtr->flags = flags; clientPtr->state = kDiskStateNew; // Force a re-send of all the msgs. } return 0; } // DiskArbUpdateClientWithPID_rpc /******************************************* DiskArbDeregister_rpc *******************************************/ kern_return_t DiskArbDeregister_rpc ( mach_port_t server, mach_port_t client) { dwarning(("%s(client = $%08x)\n", __FUNCTION__, client)); ClientDeath(client); return 0; } // DiskArbDeregister_rpc kern_return_t DiskArbDeregisterWithPID_rpc ( mach_port_t server, mach_port_t client, int pid) { dwarning(("%s(client = $%08x)\n", __FUNCTION__, client)); ClientDeath(client); return 0; } // DiskArbDeregisterWithPID_rpc /******************************************* DiskArbUnmountRequest_async_rpc *******************************************/ kern_return_t DiskArbUnmountRequest_async_rpc ( mach_port_t server, pid_t clientPid, DiskArbDiskIdentifier diskIdentifier, unsigned flags) { kern_return_t err = 0; DiskPtr diskPtr; ClientPtr clientPtr = LookupClientByPID(clientPid); dwarning(("%s(diskIdentifier = '%s', flags = $%08x)\n", __FUNCTION__, diskIdentifier, flags)); diskPtr = LookupDiskByIOBSDName( diskIdentifier ); if ( NULL == diskPtr ) { pwarning(("%s(diskIdentifier = '%s', flags = $%08x): LookupDiskByIOBDSName failed\n", __FUNCTION__, diskIdentifier, flags)); err = -1; if (clientPtr) { SendCallFailedMessage(clientPtr, NULL, kDiskArbUnmountRequestFailed, kDiskArbVolumeDoesNotExist); } goto Return; } if (!requestingClientHasPermissionToModifyDisk(clientPid, diskPtr, "system.volume.unmount")) { err = -1; if (clientPtr) { SendCallFailedMessage(clientPtr, diskPtr, kDiskArbUnmountRequestFailed, kDiskArbInsecureRequest); } goto Return; } if ( AreWeBusy() ) { pwarning(("%s(diskIdentifier = '%s', flags = $%08x): already busy\n", __FUNCTION__, diskIdentifier, flags)); err = -1; if (clientPtr) { SendCallFailedMessage(clientPtr, diskPtr, kDiskArbUnmountRequestFailed, kDiskArbIsBusy); } goto Return; } if (flags & kDiskArbForceUnmountFlag) { if (flags & kDiskArbUnmountOneFlag) { UnmountDisk( diskPtr, TRUE ); } else { UnmountAllPartitions( diskPtr, TRUE ); } } if (flags & kDiskArbUnmountOneFlag) { /* Mark just one of the partitions of this disk for unmounting (allocates ack-value tables, too). */ SetStateForOnePartition( diskPtr, kDiskStateToBeUnmounted ); } else { /* Mark all the partitions of this disk for unmounting (allocates ack-value tables, too). */ SetStateForAllPartitions( diskPtr, kDiskStateToBeUnmounted ); } /* Prepare a list of pre-unmount notifications to be sent. */ PrepareToSendPreUnmountMsgs(); /* Return to the main msg loop to process sending of pre-unmount msgs and receiving of acks. */ Return: return err; } // DiskArbUnmountRequest_async_rpc /******************************************* DiskArbUnmountPreNotifyAck_async_rpc *******************************************/ kern_return_t DiskArbUnmountPreNotifyAck_async_rpc( mach_port_t server, pid_t pid, DiskArbDiskIdentifier diskIdentifier, int errorCode) { kern_return_t err = 0; DiskPtr diskPtr; ClientPtr clientPtr; dwarning(("%s(pid = %d, diskIdentifier = '%s', errorCode = %d)\n", __FUNCTION__, pid, diskIdentifier, errorCode)); clientPtr = LookupClientByPID( pid ); if ( ! clientPtr ) { pwarning(("%s(pid = %d, diskIdentifier = '%s', errorCode = %d): no known client with this pid.\n", __FUNCTION__, pid, diskIdentifier, errorCode)); err = -1; goto Return; } clientPtr->numAcksRequired--; diskPtr = LookupDiskByIOBSDName( diskIdentifier ); if ( NULL == diskPtr ) { dwarning(("%s(pid = %d, diskIdentifier = '%s', errorCode = %d): LookupDiskByIOBDSName failed\n", __FUNCTION__, pid, diskIdentifier, errorCode)); err = -1; goto Return; } /* assert: diskPtr->state == kDiskStateToBeUnmounted/kDiskStateToBeUnmountedAndEjected */ UpdateAckValue( diskPtr->ackValues, pid, errorCode ); dwarning(("%s: ack values for '%s'\n", __FUNCTION__, diskPtr->ioBSDName)); PrintAckValues( diskPtr->ackValues ); /* Return to the main msg loop. It will check if enough acks were received. */ Return: return err; } // DiskArbUnmountPreNotifyAck_async_rpc /******************************************* DiskArbEjectRequest_async_rpc *******************************************/ kern_return_t DiskArbEjectRequest_async_rpc ( mach_port_t server, pid_t clientPid, DiskArbDiskIdentifier diskIdentifier, unsigned flags) { kern_return_t err = 0; DiskPtr diskPtr; ClientPtr clientPtr = LookupClientByPID(clientPid); dwarning(("%s(diskIdentifier = '%s', flags = $%08x)\n", __FUNCTION__, diskIdentifier, flags)); diskPtr = LookupDiskByIOBSDName( diskIdentifier ); if ( NULL == diskPtr ) { pwarning(("%s(diskIdentifier = '%s', flags = $%08x): LookupDiskByIOBDSName failed\n", __FUNCTION__, diskIdentifier, flags)); err = -1; if (clientPtr) { SendCallFailedMessage(clientPtr, NULL, kDiskArbEjectRequestFailed, kDiskArbVolumeDoesNotExist); } goto Return; } if (!requestingClientHasPermissionToModifyDisk(clientPid, diskPtr, "system.volume.eject")) { err = -1; if (clientPtr) { SendCallFailedMessage(clientPtr, diskPtr, kDiskArbEjectRequestFailed, kDiskArbInsecureRequest); } goto Return; } if ( AreWeBusy() ) { pwarning(("%s(diskIdentifier = '%s', flags = $%08x): already busy\n", __FUNCTION__, diskIdentifier, flags)); err = -1; if (clientPtr) { SendCallFailedMessage(clientPtr, diskPtr, kDiskArbEjectRequestFailed, kDiskArbIsBusy); } goto Return; } /* Mark all the partitions of this disk for ejection (allocates ack-value tables, too). */ SetStateForAllPartitions( diskPtr, kDiskStateToBeEjected ); /* Prepare a list of pre-eject notifications to be sent. */ PrepareToSendPreEjectMsgs(); /* Return to the main msg loop to process sending of pre-eject msgs and receiving of acks. */ Return: return err; } // DiskArbEjectRequest_async_rpc /******************************************* DiskArbEjectPreNotifyAck_async_rpc *******************************************/ kern_return_t DiskArbEjectPreNotifyAck_async_rpc( mach_port_t server, pid_t pid, DiskArbDiskIdentifier diskIdentifier, int errorCode) { kern_return_t err = 0; DiskPtr diskPtr; ClientPtr clientPtr; dwarning(("%s(pid = %d, diskIdentifier = '%s', errorCode = %d)\n", __FUNCTION__, pid, diskIdentifier, errorCode)); clientPtr = LookupClientByPID( pid ); if ( ! clientPtr ) { pwarning(("%s(pid = %d, diskIdentifier = '%s', errorCode = %d): no known client with this pid.\n", __FUNCTION__, pid, diskIdentifier, errorCode)); err = -1; goto Return; } clientPtr->numAcksRequired--; diskPtr = LookupDiskByIOBSDName( diskIdentifier ); if ( NULL == diskPtr ) { dwarning(("%s(pid = %d, diskIdentifier = '%s', errorCode = %d): LookupDiskByIOBDSName failed\n", __FUNCTION__, pid, diskIdentifier, errorCode)); err = -1; goto Return; } /* assert: diskPtr->state == kDiskStateToBeEjected */ UpdateAckValue( diskPtr->ackValues, pid, errorCode ); dwarning(("%s: ack values for '%s'\n", __FUNCTION__, diskPtr->ioBSDName)); PrintAckValues( diskPtr->ackValues ); /* Return to the main msg loop. It will check if enough acks were received. */ Return: return err; } // DiskArbEjectPreNotifyAck_async_rpc /******************************************* DiskArbUnmountAndEjectRequest_async_rpc *******************************************/ kern_return_t DiskArbUnmountAndEjectRequest_async_rpc ( mach_port_t server, pid_t clientPid, DiskArbDiskIdentifier diskIdentifier, unsigned flags) { kern_return_t err = 0; DiskPtr diskPtr; ClientPtr clientPtr = LookupClientByPID(clientPid); dwarning(("%s(diskIdentifier = '%s', flags = $%08x)\n", __FUNCTION__, diskIdentifier, flags)); diskPtr = LookupDiskByIOBSDName( diskIdentifier ); if ( NULL == diskPtr ) { pwarning(("%s(diskIdentifier = '%s', flags = $%08x): LookupDiskByIOBDSName failed\n", __FUNCTION__, diskIdentifier, flags)); err = -1; if (clientPtr) { SendCallFailedMessage(clientPtr, NULL, kDiskArbUnmountAndEjectRequestFailed, kDiskArbVolumeDoesNotExist); } goto Return; } if (!requestingClientHasPermissionToModifyDisk(clientPid, diskPtr, "system.volume.unmount.eject")) { err = -1; if (clientPtr) { SendCallFailedMessage(clientPtr, diskPtr, kDiskArbUnmountAndEjectRequestFailed, kDiskArbInsecureRequest); } goto Return; } if ( AreWeBusy() ) { pwarning(("%s(diskIdentifier = '%s', flags = $%08x): already busy\n", __FUNCTION__, diskIdentifier, flags)); err = -1; if (clientPtr) { SendCallFailedMessage(clientPtr, diskPtr, kDiskArbUnmountAndEjectRequestFailed, kDiskArbIsBusy); } goto Return; } if (flags & kDiskArbForceUnmountFlag) { UnmountAllPartitions( diskPtr, TRUE ); } /* Mark all the partitions of this disk for unmounting and ejection (allocates ack-value tables, too). */ SetStateForAllPartitions( diskPtr, kDiskStateToBeUnmountedAndEjected ); /* Prepare a list of pre-unmount notifications to be sent. */ /* When the unmount happens the disk will proceed to the kDiskStateToBeEjected state. */ PrepareToSendPreUnmountMsgs(); /* Return to the main msg loop to await acknowledgements. */ Return: return err; } // DiskArbUnmountAndEjectRequest_async_rpc /******************************************* DiskArbSetBlueBoxBootVolume_async_rpc *******************************************/ kern_return_t DiskArbSetBlueBoxBootVolume_async_rpc ( mach_port_t server, pid_t pid, int seqno) { kern_return_t err = 0; ClientPtr clientPtr; dwarning(("%s(%d): old gBlueBoxBootVolume = %d\n", __FUNCTION__, seqno, GetBlueBoxBootVolume())); clientPtr = LookupClientByPID( pid ); if ( ! clientPtr ) { pwarning(("%s(pid=%d,seqno=%d): no known client with this pid.\n", __FUNCTION__, pid, seqno)); err = -1; /* Do not exit early. Set the gBlueBoxBootVolume anyhow. */ } else { ClientPtr newClientPtr = LookupBlueBox(); /* Double-check that no other client record already has this flag set. */ if ( newClientPtr != NULL ) { dwarning(("%s(pid=%d,seqno=%d): BlueBox client already exists with pid=%d\n", __FUNCTION__, pid, seqno, newClientPtr->pid)); } clientPtr->flags |= kDiskArbIAmBlueBox; } SetBlueBoxBootVolume( seqno ); //Return: return err; } // DiskArbSetBlueBoxBootVolume_async_rpc /******************************************* DiskArbRequestDiskChange_rpc *******************************************/ kern_return_t DiskArbRequestDiskChange_rpc ( mach_port_t server, pid_t clientPid, DiskArbDiskIdentifier diskIdentifier, DiskArbMountpoint mountPoint, int flags) { kern_return_t err = 0; DiskPtr diskPtr; char deviceName[MAXPATHLEN]; int success = 0; char cookieFile[MAXPATHLEN]; struct stat sb; int i = 1; ClientPtr clientPtr = LookupClientByPID(clientPid); char newMountName[MAXPATHLEN]; char newVolumeName[MAXPATHLEN]; //char *newMountName = malloc(sizeof(char)*MAXPATHLEN); //char *newVolumeName = malloc(sizeof(char)*MAXPATHLEN); sprintf(deviceName, "/dev/r%s", (char *)diskIdentifier); sprintf(newMountName, "%s/%s", (char *)mountPath(), (char *)mountPoint); sprintf(newVolumeName, "%s", (char *)mountPoint); sprintf(cookieFile, "/%s/%s", newMountName, ADM_COOKIE_FILE); dwarning(("%s: renaming volume %s to %s and attempting to mount at %s\n", __FUNCTION__, diskIdentifier, mountPoint, newMountName)); diskPtr = LookupDiskByIOBSDName( diskIdentifier ); // we may have to modify the new mountpoint name until it matches up with an empty directory, otherwise we could end up with 2 /tmp's for example ... if ( NULL == diskPtr ) { pwarning(("%s(diskIdentifier = '%s', flags = $%08x): LookupDiskByIOBDSName failed\n", __FUNCTION__, diskIdentifier, flags)); err = -1; if (clientPtr) { SendCallFailedMessage(clientPtr, NULL, kDiskArbDiskChangeRequestFailed, kDiskArbVolumeDoesNotExist); } goto Return; } /* * 2758222 if (!requestingClientHasPermissionToModifyDisk(clientPid, diskPtr, "system.volume.rename")) { err = -1; if (clientPtr) { SendCallFailedMessage(clientPtr, diskPtr, kDiskArbDiskChangeRequestFailed, kDiskArbInsecureRequest); } goto Return; } */ if (diskPtr && IsNetwork(diskPtr)) { err = -1; if (clientPtr) { SendCallFailedMessage(clientPtr, diskPtr, kDiskArbDiskChangeRequestFailed, kDiskArbDiskIsNetwork); } goto Return; } if (strcmp(newMountName, diskPtr->mountpoint) == 0) { // the newName would be the same as the old name dwarning(("%s: attempt to rename volume %s to %s. The name is the same.\n", __FUNCTION__, diskIdentifier, diskPtr->mountpoint)); SendDiskChangedMsgs(diskIdentifier, newMountName, newVolumeName, flags, kDiskArbRenameSuccessful); return err; } while (1) { if (stat(newMountName, &sb) < 0) { if (errno == ENOENT) { break; } else if (errno == EIO) { /* do nothing */ } else { pwarning(("stat(%s) failed, %s\n", newMountName, strerror(errno))); return (FALSE); } } else if (rmdir(newMountName) == 0) { dwarning(("The asked for directory (%s) has been removed\n", newMountName)); /* it was an empty directory */ break; } else if (errno == ENOTEMPTY) { // some file exists, see if it's the ADM_COOKIE_FILE and if that is it remove the cookie and retry the rmdir if (stat(cookieFile, &sb) == 0) { if (remove(cookieFile) == 0) { if (rmdir(newMountName) == 0) { break; } } } } else { dwarning(("The asked for directory (%s) was not removed with errno = %d\n", newMountName, errno)); } sprintf(newMountName, "%s/%s %d", mountPath(), mountPoint, i); i++; } { #warning - renaming devices is FS specific. boolean_t is_hfs; boolean_t is_ufs; if (!diskPtr->mountedFilesystemName || !strlen(diskPtr->mountedFilesystemName)) { err = -1; goto Return; } else { is_hfs = (strcmp(diskPtr->mountedFilesystemName, "hfs") == 0); is_ufs = (strcmp(diskPtr->mountedFilesystemName, "ufs") == 0); } // change the disk name on device diskIdentifier if (is_hfs) { struct attrlist alist; struct volattrbuf volinfobuf; int result; alist.bitmapcount = 5; alist.commonattr = 0; alist.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME; alist.dirattr = 0; alist.fileattr = 0; alist.forkattr = 0; result = getattrlist(diskPtr->mountpoint, &alist, &volinfobuf, sizeof(volinfobuf), 0); if (result != 0) { dwarning(("Hey! Couldn't get current volume name")); }; strncpy(volinfobuf.va.volumenamestorage, mountPoint, sizeof(volinfobuf.va.volumenamestorage) - 1); volinfobuf.va.volumenamestorage[sizeof(volinfobuf.va.volumenamestorage) - 1] = (char)0; volinfobuf.va.volnameref.attr_dataoffset = (char *)(&volinfobuf.va.volumenamestorage) - (char *)(&volinfobuf.va.volnameref); volinfobuf.va.volnameref.attr_length = strlen(mountPoint); result = setattrlist(diskPtr->mountpoint, &alist, &volinfobuf.va, sizeof(volinfobuf.va), 0); if (result != 0) { dwarning(("Hey! Couldn't change volume name")); success = kDiskArbRenameUnsuccessful; // report that the name is the same strcpy(newMountName, diskPtr->mountpoint); } else { if (strcmp(diskPtr->mountpoint, "/")) { // report that the name is different int ret = rename(diskPtr->mountpoint, newMountName); if (ret == 0) { DiskSetMountpoint(diskPtr, newMountName); success = kDiskArbRenameSuccessful; } else { dwarning(("Hey! Couldn't change volume name, %d, %d return from rename\n", ret, errno)); success = kDiskArbRenameSuccessful | kDiskArbRenameRequiresRemount; } } else { strcpy(newMountName, "/"); strcpy(diskPtr->mountpoint, "/"); } // Let everyone know that the disk has changed it's path ... success = kDiskArbRenameSuccessful; } } else if (is_ufs) { if (renameUFSDevice(diskIdentifier, mountPoint)) { // successful volume rename if (strcmp(diskPtr->mountpoint, "/")) { // report that the name is different int ret = rename(diskPtr->mountpoint, newMountName); if (ret == 0) { DiskSetMountpoint(diskPtr, newMountName); success = kDiskArbRenameSuccessful; } else { dwarning(("Hey! Couldn't change volume name, %d, %d return from rename\n", ret, errno)); success = kDiskArbRenameSuccessful | kDiskArbRenameRequiresRemount; } } else { strcpy(diskPtr->mountpoint, "/"); strcpy(newMountName, "/"); } // DiskArbRequestMount_rpc(server, diskIdentifier, TRUE); success = kDiskArbRenameSuccessful; } else { dwarning(("Hey! Couldn't change volume name!")); success = kDiskArbRenameUnsuccessful; } } else { dwarning(("Hey! Couldn't change volume name since it isn't hfs or ufs!")); success = kDiskArbRenameUnsuccessful; } SendDiskChangedMsgs(diskIdentifier, newMountName, newVolumeName, flags, success); PrintDisks(); } Return: if (err == -1) { SendDiskChangedMsgs(diskIdentifier, newMountName, newVolumeName, flags, kDiskArbRenameUnsuccessful); } return err; } // DiskArbRequestDiskChange_rpc kern_return_t DiskArbSetCurrentUser_rpc ( mach_port_t server, pid_t clientPid, int user) { if (user == -1) { //someone logged out .. unmount the disks they mounted DiskPtr diskPtr; for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next) { if (diskPtr->mountedUser == currentConsoleUser && ( diskPtr->flags & kDiskArbDiskAppearedEjectableMask ) ) { // request an unmount on the disk if (diskPtr->ejectOnLogout) { DiskArbUnmountAndEjectRequest_async_rpc( 0, 0, diskPtr->ioBSDName, FALSE); } else { // unmount the disk and it's partitions ... DiskArbUnmountRequest_async_rpc( 0, 0, diskPtr->ioBSDName, FALSE); // arg! no wonder - have to reset the mountedUser to -1 diskPtr->mountedUser = user; } } } currentConsoleUser = user; } else { io_iterator_t ioIterator; mach_port_t masterPort; kern_return_t err; currentConsoleUser = user; err = IOMasterPort(bootstrap_port, &masterPort); // get an iterator from the registry for IOMedia and get the disks out of the registry ... err = IOServiceGetMatchingServices(masterPort, IOServiceMatching("IOMedia"), &ioIterator); GetDisksFromRegistry( ioIterator, 0 ); dwarning(("autodiskmount: Setting user to %d\n", user)); autodiskmount(TRUE); } return 0; } kern_return_t DiskArbSetVolumeEncoding_rpc (mach_port_t server, pid_t clientPid, DiskArbDiskIdentifier diskIdentifier, int volumeEncoding) { // what's the encoding? DiskPtr diskPtr; int isWritable; char bsdPath[MAXPATHLEN]; char encodingString[MAXPATHLEN]; boolean_t is_hfs; ClientPtr clientPtr = LookupClientByPID(clientPid); diskPtr = LookupDiskByIOBSDName( diskIdentifier ); dwarning(("%s: change volume %s encoding to %d\n", __FUNCTION__, diskIdentifier, volumeEncoding)); if ( NULL == diskPtr ) { pwarning(("%s(diskIdentifier = '%s'): LookupDiskByIOBDSName failed\n", __FUNCTION__, diskIdentifier)); if (clientPtr) { SendCallFailedMessage(clientPtr, NULL, kDiskArbSetEncodingRequestFailed, kDiskArbVolumeDoesNotExist); } return -1; } if (!requestingClientHasPermissionToModifyDisk(clientPid, diskPtr, "system.volume.setencoding")) { if (clientPtr) { SendCallFailedMessage(clientPtr, diskPtr, kDiskArbSetEncodingRequestFailed, kDiskArbInsecureRequest); } return -1; } sprintf(bsdPath,"/dev/%s", diskIdentifier); isWritable = ( diskPtr->flags & kDiskArbDiskAppearedLockedMask ) == 0; is_hfs = (strcmp(diskPtr->mountedFilesystemName, "hfs") == 0); if (!is_hfs) { if (clientPtr) { SendCallFailedMessage(clientPtr, diskPtr, kDiskArbSetEncodingRequestFailed, kDiskArbInvalidVolumeFormat); } return -1; } // build the string sprintf(encodingString, "-e=%d", volumeEncoding); // mount_hfs , the mount command for an HFS filesystem // -u to signal an update // or -ur to signal a read only update // -o to signal something or another // -e to signal encoding // encodingnumber // /dev/disk* , diskPtr->bsdName // /Volumes/VolName, diskPtr->mountPoint { const char *childArgv[] = { "/sbin/mount", isWritable?"-u":"-ur", "-o", encodingString, "-t", "hfs", bsdPath, diskPtr->mountpoint, 0 }; int pid; if ((pid = fork()) == 0) { /* CHILD PROCESS */ cleanUpAfterFork(); execve("/sbin/mount", childArgv, 0); exit(-127); } else if (pid > 0) { int statusp; int waitResult; int result; /* PARENT PROCESS */ dwarning(("wait4(pid=%d,&statusp,0,NULL)...\n", pid)); waitResult = wait4(pid,&statusp,0,NULL); dwarning(("wait4(pid=%d,&statusp,0,NULL) => %d\n", pid, waitResult)); if (waitResult > 0) { if (WIFEXITED(statusp)) { result = (int)(char)(WEXITSTATUS(statusp)); } } } } // now check and see if the encoding changed the name, and if it did so, trigger a volume rename on that volume { struct attrlist alist; struct volattrbuf volinfobuf; int result; int success = kDiskArbRenameSuccessful; struct stat sb; char newMountName[MAXPATHLEN]; char cookieFile[MAXPATHLEN]; int i = 1; alist.bitmapcount = 5; alist.commonattr = 0; alist.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME; alist.dirattr = 0; alist.fileattr = 0; alist.forkattr = 0; result = getattrlist(diskPtr->mountpoint, &alist, &volinfobuf, sizeof(volinfobuf), 0); if (result != 0) { dwarning(("Hey! Couldn't get current volume name")); }; sprintf(newMountName, "%s/%s", (char *)mountPath(), volinfobuf.va.volumenamestorage); sprintf(cookieFile, "/%s/%s", newMountName, ADM_COOKIE_FILE); if (strcmp(newMountName, diskPtr->mountpoint) != 0) { // the volume name is no longer the same, rename the mount point ... while (1) { if (stat(newMountName, &sb) < 0) { if (errno == ENOENT) { break; } else if (errno == EIO) { /* do nothing */ } else { pwarning(("stat(%s) failed, %s\n", newMountName, strerror(errno))); return (FALSE); } } else if (rmdir(newMountName) == 0) { dwarning(("The asked for directory (%s) has been removed\n", newMountName)); /* it was an empty directory */ break; } else if (errno == ENOTEMPTY) { // some file exists, see if it's the ADM_COOKIE_FILE and if that is it remove the cookie and retry the rmdir if (stat(cookieFile, &sb) == 0) { if (remove(cookieFile) == 0) { if (rmdir(newMountName) == 0) { break; } } } } else { dwarning(("The asked for directory (%s) was not removed with errno = %d\n", newMountName, errno)); } sprintf(newMountName, "%s/%s %d", mountPath(), volinfobuf.va.volumenamestorage, i); i++; } dwarning(("Encoding changed which is forcing a rename on %s to %s\n", diskPtr->mountpoint, newMountName)); if (strcmp(newMountName, diskPtr->mountpoint) != 0) { // the volume name is no longer the same, rename the mount point ... dwarning(("Encoding changed which is forcing a rename on %s to %s\n", diskPtr->mountpoint, newMountName)); if (strcmp(diskPtr->mountpoint, "/")) { // report that the name is different int ret = rename(diskPtr->mountpoint, newMountName); if (ret == 0) { DiskSetMountpoint(diskPtr, newMountName); success = kDiskArbRenameSuccessful; dwarning(("Changed volume name\n")); } else { dwarning(("Hey! Couldn't change volume name, %d, %d return from rename\n", ret, errno)); success = kDiskArbRenameUnsuccessful; } } else { strcpy(diskPtr->mountpoint, "/"); success = kDiskArbRenameUnsuccessful; } } } SendDiskChangedMsgs(diskIdentifier, newMountName, volinfobuf.va.volumenamestorage, 0, success); } return 0; } kern_return_t DiskArbGetVolumeEncoding_rpc (mach_port_t server, DiskArbDiskIdentifier diskIdentifier, int *volumeEncoding) { DiskPtr diskPtr; boolean_t is_hfs; *volumeEncoding = -1; diskPtr = LookupDiskByIOBSDName( diskIdentifier ); if (!diskPtr || !diskPtr->mountedFilesystemName) { return 0; } is_hfs = (strcmp(diskPtr->mountedFilesystemName, "hfs") == 0); if (is_hfs) { struct attrlist alist; struct cominfobuf cibuf; int result; alist.bitmapcount = 5; alist.commonattr = ATTR_CMN_SCRIPT; alist.volattr = 0; alist.dirattr = 0; alist.fileattr = 0; alist.forkattr = 0; result = getattrlist(diskPtr->mountpoint, &alist, &cibuf, sizeof(cibuf), 0); if (result != 0) { //error *volumeEncoding = -1; } else { *volumeEncoding = cibuf.ci.encoding; } } return 0; } /* -- Printer Arbitration -- */ static ClientPtr LookupBlueBox( void ) { ClientPtr result = NULL; ClientPtr clientPtr; dwarning(("=> %s()\n", __FUNCTION__)); for (clientPtr = g.Clients; clientPtr != NULL; clientPtr = clientPtr->next) { if ( clientPtr->flags & kDiskArbIAmBlueBox ) { result = clientPtr; goto Return; } } result = NULL; goto Return; Return: dwarning(("<= %s(): 0x%08x\n", __FUNCTION__, (int)result)); return result; } // LookupBlueBox kern_return_t DiskArbPrinter_Request_rpc ( mach_port_t server, pid_t pid, int locationID) { kern_return_t err = 0; ClientPtr clientPtr; ClientPtr bbClientPtr; dwarning(("=> %s(pid=%d,locationID=0x%08x)\n", __FUNCTION__, pid, locationID)); bbClientPtr = LookupBlueBox(); if ( ! bbClientPtr ) { clientPtr = LookupClientByPID( pid ); if ( ! clientPtr ) { // This could happen if the requester died before Blue Box could answer. dwarning(("%s(pid=%d,locationID=0x%08x): no known client with this pid.\n", __FUNCTION__, pid, locationID)); err = -1; goto Return; } dwarning(("%s: Blue Box is not registered\n", __FUNCTION__)); #warning Should this be in a thread err = DiskArbPrinter_FinalResponse_rpc( clientPtr->port, locationID, 0x00000001 /* answer */ ); goto Return; } /* Forward the question to Blue Box. */ #warning Should this be in a thread err = DiskArbPrinter_FinalRequest_rpc( bbClientPtr->port, pid, locationID ); goto Return; Return: return err; } // DiskArbPrinter_Request_rpc kern_return_t DiskArbPrinter_Response_rpc ( mach_port_t server, pid_t pid, int locationID, int answer) { kern_return_t err = 0; ClientPtr clientPtr; dwarning(("%s(pid=%d,locationID=0x%08x,answer=0x%08x)\n", __FUNCTION__, pid, locationID, answer)); /* Blue Box wants to let the requester with pid know the answer. */ clientPtr = LookupClientByPID( pid ); if ( ! clientPtr ) { // This could happen if the requester died before Blue Box could answer. dwarning(("%s(pid=%d,locationID=0x%08x,answer=0x%08x): no known client with this pid.\n", __FUNCTION__, pid, locationID, answer)); err = -1; goto Return; } /* Forward the message to the Blue Box */ #warning Should this be in a thread err = DiskArbPrinter_FinalResponse_rpc( clientPtr->port, locationID, answer ); goto Return; Return: return err; } // DiskArbPrinter_Response_rpc kern_return_t DiskArbPrinter_Release_rpc ( mach_port_t server, int locationID) { kern_return_t err = 0; ClientPtr bbClientPtr; dwarning(("=> %s(locationID=0x%08x)\n", __FUNCTION__, locationID)); bbClientPtr = LookupBlueBox(); if ( ! bbClientPtr ) { dwarning(("%s: Blue Box is not registered\n", __FUNCTION__)); err = 0; goto Return; } /* Forward the question to Blue Box. */ #warning Should this be in a thread err = DiskArbPrinter_FinalRelease_rpc( bbClientPtr->port, locationID ); goto Return; Return: return err; } // DiskArbPrinter_Release_rpc /* -- DEVICE RESERVATIONS -- */ kern_return_t DiskArbIsDeviceReservedForClient_rpc ( mach_port_t server, DiskArbDiskIdentifier diskIdentifier, pid_t clientPid) { DiskPtr diskPtr; DiskPtr wholePtr; ClientPtr clientPtr; int status = kDiskArbDeviceIsNotReserved; int pid = 0; clientPtr = LookupClientByPID(clientPid); if ( ! clientPtr ) { dwarning(("%s: client ptr not found %d", __FUNCTION__, clientPid)); return 0; } dwarning(("%s(diskIdentifier = '%s', from pid = '%d')\n", __FUNCTION__, diskIdentifier, clientPid)); diskPtr = LookupDiskByIOBSDName( diskIdentifier ); if (diskPtr) { wholePtr = LookupWholeDiskForThisPartition( diskPtr ); } else { dwarning(("%s: diskPtr not found %s", __FUNCTION__, diskIdentifier)); return 0; } if (!wholePtr) { pwarning(("%s: wholePtr not found, cannot retain reservation on %s", __FUNCTION__, diskIdentifier)); } if (wholePtr->retainingClient) { status = kDiskArbDeviceIsReserved; pid = wholePtr->retainingClient; } // call the client back #warning Should this be in a thread DiskArbDeviceReservationStatus_rpc(clientPtr->port, diskIdentifier, status, pid); return 0; } kern_return_t DiskArbRetainClientReservationForDevice_rpc ( mach_port_t server, DiskArbDiskIdentifier diskIdentifier, pid_t clientPid) { DiskPtr diskPtr; DiskPtr wholePtr; ClientPtr clientPtr = LookupClientByPID(clientPid); int pid = 0; if ( ! clientPtr ) { dwarning(("%s: client ptr not found %d", __FUNCTION__, clientPid)); return 0; } dwarning(("%s(diskIdentifier = '%s', pid = '%d')\n", __FUNCTION__, diskIdentifier, clientPid)); diskPtr = LookupDiskByIOBSDName( diskIdentifier ); if (diskPtr) { wholePtr = LookupWholeDiskForThisPartition( diskPtr ); } else { dwarning(("%s: diskPtr not found %s", __FUNCTION__, diskIdentifier)); return 0; } if (!wholePtr) { pwarning(("%s: wholePtr not found, cannot retain reservation on %s", __FUNCTION__, diskIdentifier)); } if (wholePtr->retainingClient) { ClientPtr remoteClientPtr = LookupClientByPID(wholePtr->retainingClient); if ( ! remoteClientPtr ) { dwarning(("%s: client ptr not found %d", __FUNCTION__, wholePtr->retainingClient)); return 0; } // here is where we ask the retaining client if they will give it up ... #warning Should this be in a thread DiskArbWillClientRelinquish_rpc(remoteClientPtr->port, diskIdentifier, clientPid); // if the application doesn't have a handler for this, the application will immediately callback and say "nope - I won't give it up" } else { wholePtr->retainingClient = clientPid; pid = wholePtr->retainingClient; // call the client back right away #warning Should this be in a thread DiskArbDeviceReservationStatus_rpc(clientPtr->port, diskIdentifier, kDiskArbDeviceReservationObtained, pid); } return 0; } kern_return_t DiskArbReleaseClientReservationForDevice_rpc ( mach_port_t server, DiskArbDiskIdentifier diskIdentifier, pid_t pid) { DiskPtr diskPtr; DiskPtr wholePtr; dwarning(("%s(diskIdentifier = '%s', pid = '%d')\n", __FUNCTION__, diskIdentifier, pid)); diskPtr = LookupDiskByIOBSDName( diskIdentifier ); if (diskPtr) { wholePtr = LookupWholeDiskForThisPartition( diskPtr ); } else { dwarning(("%s: diskPtr not found %s", __FUNCTION__, diskIdentifier)); return 0; } if (!wholePtr) { pwarning(("%s: wholePtr not found, cannot release reservation on %s", __FUNCTION__, diskIdentifier)); } else if (wholePtr->retainingClient == pid) { wholePtr->retainingClient = 0; } return 0; } kern_return_t DiskArbClientRelinquishesReservation_rpc ( mach_port_t server, DiskArbDiskIdentifier diskIdentifier, pid_t pid, pid_t releaseToClientPid, int status) { DiskPtr diskPtr; DiskPtr wholePtr; ClientPtr clientPtr = LookupClientByPID(releaseToClientPid); if ( ! clientPtr ) { dwarning(("%s: client ptr not found %d", __FUNCTION__, releaseToClientPid)); return 0; } dwarning(("%s(diskIdentifier = '%s', my pid = '%d', release to pid = '%d', status = '%d')\n", __FUNCTION__, diskIdentifier, pid, releaseToClientPid, status)); diskPtr = LookupDiskByIOBSDName( diskIdentifier ); if (diskPtr) { wholePtr = LookupWholeDiskForThisPartition( diskPtr ); } else { dwarning(("%s: diskPtr not found %s", __FUNCTION__, diskIdentifier)); return 0; } if (!wholePtr) { pwarning(("%s: wholePtr not found, cannot release reservation on %s", __FUNCTION__, diskIdentifier)); return 0; } if (status) { // now notify the person who asked that they now have or don't have the reservation wholePtr->retainingClient = releaseToClientPid; #warning Should this be in a thread DiskArbDeviceReservationStatus_rpc(clientPtr->port, diskIdentifier, kDiskArbDeviceReservationObtained, releaseToClientPid); } else { wholePtr->retainingClient = pid; #warning Should this be in a thread DiskArbDeviceReservationStatus_rpc(clientPtr->port, diskIdentifier, kDiskArbDeviceReservationRefused, pid); } return 0; } /* Unintialized Disk notifications */ kern_return_t DiskArbClientHandlesUnrecognizedDisks_rpc ( mach_port_t server, pid_t pid, int types, int priority) { ClientPtr clientPtr = LookupClientByPID(pid); if (!clientPtr) { dwarning(("%s : No client ptr for client pid %d\n", __FUNCTION__, pid)); } else { clientPtr->unrecognizedPriority = priority; clientPtr->notifyOnDiskTypes = types; } return 0; } kern_return_t DiskArbClientHandlesUninitializedDisks_rpc ( mach_port_t server, int clientPid, int flags) { kern_return_t err = 0; ClientPtr clientPtr; dwarning(("%s(%d:%d)\n", __FUNCTION__, clientPid, flags)); clientPtr = LookupClientByPID( clientPid ); if ( ! clientPtr ) { dwarning(("%s(pid=%d,flags=%d): no known client with this pid.\n", __FUNCTION__, clientPid, flags)); err = -1; } else { if (flags) { // or it in clientPtr->flags |= kDiskArbClientHandlesUninitializedDisks; } else { // and it out clientPtr->flags &= ~kDiskArbClientHandlesUninitializedDisks; } } return err; } kern_return_t DiskArbClientWillHandleUnrecognizedDisk_rpc ( mach_port_t server, DiskArbDiskIdentifier diskIdentifier, pid_t pid, int yesNo) { DiskPtr diskPtr = LookupDiskByIOBSDName( diskIdentifier ); ClientPtr clientPtr = LookupClientByPID( pid ); clientPtr->ackOnUnrecognizedDisk = nil; if (!clientPtr || !diskPtr) { return 0; } if (yesNo == FALSE) { /* Mark the disk new again, this will get the disk to get recognized as unrecognizable again in the next loop */ diskPtr->state = kDiskStateNew; } else { DiskPtr wholePtr = LookupWholeDiskForThisPartition( diskPtr ); diskPtr->retainingClient = pid; /* give a claim on the disk to the client */ if (wholePtr) { wholePtr->retainingClient = pid; } } return 0; } kern_return_t DiskArbSetSecuritySettingsForClient_rpc ( mach_port_t server, pid_t pid, DiskArbSecurityToken token) { kern_return_t err = 0; ClientPtr clientPtr = LookupClientByPID( pid ); if (!clientPtr) { dwarning(("%s(pid=%d): no known client with this pid.\n", __FUNCTION__, pid)); err = -1; } else { AuthorizationRef ref; int ok = AuthorizationCreateFromExternalForm((const AuthorizationExternalForm *)token, &ref); if (0 == ok && ref) { dwarning(("%s Setting token for (pid=%d)\n", __FUNCTION__, pid)); // good clientPtr->clientAuthRef = ref; } else { // bad } } return err; } static void EjectAllCDAndDVDMedia() { // spin through all disks, find whole media ones only, if it's a CD or DVD, eject it DiskPtr diskPtr; for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next) { DiskPtr wholePtr = LookupWholeDiskForThisPartition(diskPtr); if (wholePtr == diskPtr) { if ((diskPtr->flags & kDiskArbDiskAppearedCDROMMask) || (diskPtr->flags & kDiskArbDiskAppearedDVDROMMask)) { DiskArbUnmountAndEjectRequest_async_rpc( 0, 0, diskPtr->ioBSDName, FALSE); } } } } static void OpenVacantDriveDoor(io_registry_entry_t device) { io_registry_entry_t driver = 0; io_registry_entry_t media = 0; kern_return_t status = KERN_SUCCESS; status = IORegistryEntryGetChildEntry(device, kIOServicePlane, &driver); if (status != KERN_SUCCESS) goto OpenVacantDriveDoorErr; status = IORegistryEntryGetChildEntry(driver, kIOServicePlane, &media); if (status == KERN_SUCCESS) goto OpenVacantDriveDoorErr; IORegistryEntrySetCFProperty(device, CFSTR("TrayState"), kCFBooleanTrue); OpenVacantDriveDoorErr: if (driver) IOObjectRelease(driver); if (media) IOObjectRelease(media); } static void OpenAllVacantCDAndDVDDriveDoors() { CFMutableDictionaryRef description = 0; mach_port_t masterPort = 0; io_registry_entry_t device = 0; io_iterator_t devices = 0; kern_return_t status = KERN_SUCCESS; status = IOMasterPort(bootstrap_port, &masterPort); if (status != KERN_SUCCESS) goto OpenAllVacantCDAndDVDDriveDoorsErr; description = IOServiceMatching("IOCDBlockStorageDevice"); if (description == 0) goto OpenAllVacantCDAndDVDDriveDoorsErr; status = IOServiceGetMatchingServices(masterPort, description, &devices); if (status != KERN_SUCCESS) goto OpenAllVacantCDAndDVDDriveDoorsErr; description = 0; // (retain consumed in above call) while ( (device = IOIteratorNext(devices)) ) { OpenVacantDriveDoor(device); IOObjectRelease(device); } OpenAllVacantCDAndDVDDriveDoorsErr: if (description) CFRelease(description); if (devices) IOObjectRelease(devices); } kern_return_t DiskArbOpenVacantDriveDoors_rpc ( mach_port_t server ) { OpenAllVacantCDAndDVDDriveDoors(); return 0; } kern_return_t DiskArbEjectKeyPressed_rpc ( mach_port_t server ) { OpenAllVacantCDAndDVDDriveDoors(); EjectAllCDAndDVDMedia(); return 0; }