1/*
2 * Copyright (c) 1998-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include "DAServer.h"
25#include "DAServerServer.h"
26
27#include "DABase.h"
28#include "DACallback.h"
29#include "DADialog.h"
30#include "DADisk.h"
31#include "DAFileSystem.h"
32#include "DAInternal.h"
33#include "DALog.h"
34#include "DAMain.h"
35#include "DAMount.h"
36#include "DAPrivate.h"
37#include "DAQueue.h"
38#include "DASession.h"
39#include "DAStage.h"
40#include "DASupport.h"
41
42#include <paths.h>
43#include <servers/bootstrap.h>
44#include <sys/stat.h>
45#include <IOKit/IOMessage.h>
46#include <IOKit/storage/IOMedia.h>
47///w:start
48#include <SystemConfiguration/SCDynamicStoreCopySpecificPrivate.h>
49///w:end
50
51static CFMachPortRef       __gDAServer      = NULL;
52static mach_port_t         __gDAServerPort  = MACH_PORT_NULL;
53static mach_msg_header_t * __gDAServerReply = NULL;
54
55static void __DAMediaBusyStateChangedCallback( void * context, io_service_t service, void * argument );
56static void __DAMediaPropertyChangedCallback( void * context, io_service_t service, void * argument );
57
58static DADiskRef __DADiskListGetDisk( const char * diskID )
59{
60    CFIndex count;
61    CFIndex index;
62
63    count = CFArrayGetCount( gDADiskList );
64
65    for ( index = 0; index < count; index++ )
66    {
67        DADiskRef disk;
68
69        disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
70
71        if ( strcmp( DADiskGetID( disk ), diskID ) == 0 )
72        {
73            return disk;
74        }
75    }
76
77    return NULL;
78}
79
80static DADiskRef __DADiskListGetDiskWithIOMedia( io_service_t media )
81{
82    CFIndex count;
83    CFIndex index;
84
85    count = CFArrayGetCount( gDADiskList );
86
87    for ( index = 0; index < count; index++ )
88    {
89        DADiskRef disk;
90
91        disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
92
93        if ( IOObjectIsEqualTo( DADiskGetIOMedia( disk ), media ) )
94        {
95            return disk;
96        }
97    }
98
99    return NULL;
100}
101
102static void __DAMediaBusyStateChangedCallback( void * context, io_service_t service, void * argument )
103{
104    DADiskRef disk;
105
106    disk = __DADiskListGetDiskWithIOMedia( service );
107
108    if ( disk )
109    {
110        if ( argument )
111        {
112            DADiskSetBusy( disk, CFAbsoluteTimeGetCurrent( ) );
113        }
114        else
115        {
116            DADiskSetBusy( disk, 0 );
117        }
118    }
119}
120
121static void __DAMediaChangedCallback( void * context, io_service_t service, natural_t message, void * argument )
122{
123    switch ( message )
124    {
125        case kIOMessageServiceBusyStateChange:
126        {
127            __DAMediaBusyStateChangedCallback( context, service, argument );
128
129            break;
130        }
131        case kIOMessageServicePropertyChange:
132        {
133            __DAMediaPropertyChangedCallback( context, service, argument );
134
135            break;
136        }
137    }
138}
139
140static void __DAMediaPropertyChangedCallback( void * context, io_service_t service, void * argument )
141{
142    DADiskRef disk;
143
144    disk = __DADiskListGetDiskWithIOMedia( service );
145
146    if ( disk )
147    {
148        CFMutableArrayRef keys;
149
150        keys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
151
152        if ( keys )
153        {
154            CFMutableDictionaryRef properties = NULL;
155
156            IORegistryEntryCreateCFProperties( service, &properties, CFGetAllocator( disk ), 0 );
157
158            if ( properties )
159            {
160                CFTypeRef object;
161
162                object = CFDictionaryGetValue( properties, CFSTR( kIOMediaContentKey ) );
163
164                if ( DADiskCompareDescription( disk, kDADiskDescriptionMediaContentKey, object ) )
165                {
166                    DADiskSetDescription( disk, kDADiskDescriptionMediaContentKey, object );
167
168                    CFArrayAppendValue( keys, kDADiskDescriptionMediaContentKey );
169                }
170
171                object = CFDictionaryGetValue( properties, CFSTR( kIOMediaEjectableKey ) );
172
173                if ( DADiskCompareDescription( disk, kDADiskDescriptionMediaEjectableKey, object ) )
174                {
175                    DADiskSetDescription( disk, kDADiskDescriptionMediaEjectableKey, object );
176
177                    CFArrayAppendValue( keys, kDADiskDescriptionMediaEjectableKey );
178                }
179
180                object = CFDictionaryGetValue( properties, CFSTR( kIOMediaLeafKey ) );
181
182                if ( DADiskCompareDescription( disk, kDADiskDescriptionMediaLeafKey, object ) )
183                {
184                    DADiskSetDescription( disk, kDADiskDescriptionMediaLeafKey, object );
185
186                    CFArrayAppendValue( keys, kDADiskDescriptionMediaLeafKey );
187                }
188
189                object = CFDictionaryGetValue( properties, CFSTR( kIOMediaPreferredBlockSizeKey ) );
190
191                if ( DADiskCompareDescription( disk, kDADiskDescriptionMediaBlockSizeKey, object ) )
192                {
193                    DADiskSetDescription( disk, kDADiskDescriptionMediaBlockSizeKey, object );
194
195                    CFArrayAppendValue( keys, kDADiskDescriptionMediaBlockSizeKey );
196                }
197
198                object = CFDictionaryGetValue( properties, CFSTR( kIOMediaRemovableKey ) );
199
200                if ( DADiskCompareDescription( disk, kDADiskDescriptionMediaRemovableKey, object ) )
201                {
202                    DADiskSetDescription( disk, kDADiskDescriptionMediaRemovableKey, object );
203
204                    CFArrayAppendValue( keys, kDADiskDescriptionMediaRemovableKey );
205                }
206
207                object = CFDictionaryGetValue( properties, CFSTR( kIOMediaSizeKey ) );
208
209                if ( DADiskCompareDescription( disk, kDADiskDescriptionMediaSizeKey, object ) )
210                {
211                    DADiskSetDescription( disk, kDADiskDescriptionMediaSizeKey, object );
212
213                    CFArrayAppendValue( keys, kDADiskDescriptionMediaSizeKey );
214                }
215
216                object = CFDictionaryGetValue( properties, CFSTR( kIOMediaWholeKey ) );
217
218                if ( DADiskCompareDescription( disk, kDADiskDescriptionMediaWholeKey, object ) )
219                {
220                    DADiskSetDescription( disk, kDADiskDescriptionMediaWholeKey, object );
221
222                    CFArrayAppendValue( keys, kDADiskDescriptionMediaWholeKey );
223                }
224
225                object = CFDictionaryGetValue( properties, CFSTR( kIOMediaWritableKey ) );
226
227                if ( DADiskCompareDescription( disk, kDADiskDescriptionMediaWritableKey, object ) )
228                {
229                    DADiskSetDescription( disk, kDADiskDescriptionMediaWritableKey, object );
230
231                    CFArrayAppendValue( keys, kDADiskDescriptionMediaWritableKey );
232                }
233
234                if ( CFArrayGetCount( keys ) )
235                {
236                    DALogDebugHeader( "iokit [0] -> %s", gDAProcessNameID );
237
238                    DALogDebug( "  updated disk, id = %@.", disk );
239
240                    if ( DADiskGetState( disk, kDADiskStateStagedAppear ) )
241                    {
242                        DADiskDescriptionChangedCallback( disk, keys );
243                    }
244                }
245
246                CFRelease( properties );
247            }
248
249            CFRelease( keys );
250        }
251    }
252}
253
254static DASessionRef __DASessionListGetSession( mach_port_t sessionID )
255{
256    CFIndex count;
257    CFIndex index;
258
259    count = CFArrayGetCount( gDASessionList );
260
261    for ( index = 0; index < count; index++ )
262    {
263        DASessionRef session;
264
265        session = ( void * ) CFArrayGetValueAtIndex( gDASessionList, index );
266
267        if ( DASessionGetID( session ) == sessionID )
268        {
269            return session;
270        }
271    }
272
273    return NULL;
274}
275
276void _DAConfigurationCallback( SCDynamicStoreRef session, CFArrayRef keys, void * info )
277{
278    /*
279     * A console user has logged in or logged out.
280     */
281
282    CFStringRef previousUser;
283    gid_t       previousUserGID;
284    uid_t       previousUserUID;
285    CFArrayRef  previousUserList;
286    CFStringRef user;
287    gid_t       userGID;
288    uid_t       userUID;
289    CFArrayRef  userList;
290
291    DALogDebugHeader( "configd [0] -> %s", gDAProcessNameID );
292
293    previousUser     = gDAConsoleUser;
294    previousUserGID  = gDAConsoleUserGID;
295    previousUserUID  = gDAConsoleUserUID;
296    previousUserList = gDAConsoleUserList;
297
298    user     = ___SCDynamicStoreCopyConsoleUser( session, &userUID, &userGID );
299///w:start
300    if ( user )
301    {
302        /*
303         * Determine whether we need to wait for SystemUIServer.
304         */
305
306        if ( session ) /* not SystemUIServer */
307        {
308            CFIndex count;
309            CFIndex index;
310
311            count = 0;
312
313            if ( previousUserList )
314            {
315                count = CFArrayGetCount( previousUserList );
316            }
317
318            for ( index = 0; index < count; index++ )
319            {
320                CFDictionaryRef dictionary;
321
322                dictionary = ( void * ) CFArrayGetValueAtIndex( previousUserList, index );
323
324                if ( dictionary )
325                {
326                    CFStringRef string;
327
328                    string = CFDictionaryGetValue( dictionary, kSCConsoleSessionUserName );
329
330                    if ( CFEqual( string, user ) )
331                    {
332                        break;
333                    }
334                }
335            }
336
337            if ( index == count ) /* not Fast User Switch */
338            {
339                userList = SCDynamicStoreCopyConsoleInformation( session );
340
341                if ( userList ) /* not OS X Installer */
342                {
343                    CFRelease( user );
344                    CFRelease( userList );
345
346                    return; /* wait */
347                }
348            }
349        }
350    }
351///w:stop
352    userList = ___SCDynamicStoreCopyConsoleInformation( session );
353
354    gDAConsoleUser     = user;
355    gDAConsoleUserGID  = userGID;
356    gDAConsoleUserUID  = userUID;
357    gDAConsoleUserList = userList;
358
359    if ( gDAConsoleUser )
360    {
361        /*
362         * A console user has logged in.
363         */
364
365        DALogDebug( "  console user = %@ [%d].", gDAConsoleUser, gDAConsoleUserUID );
366    }
367    else
368    {
369        CFIndex count;
370        CFIndex index;
371
372        /*
373         * A console user has logged out.
374         */
375
376        DALogDebug( "  console user = none." );
377
378        count = 0;
379
380        if ( gDAConsoleUserList )
381        {
382            count = CFArrayGetCount( gDAConsoleUserList );
383        }
384
385        for ( index = 0; index < count; index++ )
386        {
387            CFDictionaryRef dictionary;
388
389            dictionary = CFArrayGetValueAtIndex( gDAConsoleUserList, index );
390
391            if ( ___CFDictionaryGetIntegerValue( dictionary, kSCConsoleSessionUID ) == previousUserUID )
392            {
393                break;
394            }
395        }
396
397        if ( index == count )
398        {
399            count = CFArrayGetCount( gDADiskList );
400
401            for ( index = 0; index < count; index++ )
402            {
403                DADiskRef disk;
404
405                disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
406
407                /*
408                 * Unmount this volume.
409                 */
410
411                if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanTrue )
412                {
413                    Boolean unmount;
414
415                    unmount = FALSE;
416
417                    if ( DADiskGetUserUID( disk ) )
418                    {
419                        if ( DADiskGetUserUID( disk ) == previousUserUID )
420                        {
421                            unmount = TRUE;
422                        }
423                    }
424
425                    if ( unmount )
426                    {
427                        DADiskUnmount( disk, kDADiskUnmountOptionDefault, NULL );
428                    }
429                }
430            }
431
432            for ( index = 0; index < count; index++ )
433            {
434                DADiskRef disk;
435
436                disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
437
438                /*
439                 * Eject this disk.
440                 */
441
442                if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWholeKey ) == kCFBooleanTrue )
443                {
444                    Boolean eject;
445
446                    eject = FALSE;
447
448                    if ( DADiskGetUserUID( disk ) )
449                    {
450                        if ( DADiskGetUserUID( disk ) == previousUserUID )
451                        {
452                            eject = TRUE;
453                        }
454                    }
455
456                    if ( eject )
457                    {
458                        DADiskEject( disk, kDADiskEjectOptionDefault, NULL );
459                    }
460                }
461            }
462        }
463    }
464
465    if ( gDAConsoleUserList )
466    {
467        CFIndex count;
468        CFIndex index;
469
470        /*
471         * A console user is logged in.
472         */
473
474        count = CFArrayGetCount( gDADiskList );
475
476        for ( index = 0; index < count; index++ )
477        {
478            DADiskRef disk;
479
480            disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
481///w:start
482            /*
483             * Set the BSD permissions for this media object.
484             */
485
486            if ( DADiskGetDescription( disk, kDADiskDescriptionMediaTypeKey ) )
487            {
488                mode_t deviceMode;
489                uid_t  deviceUser;
490
491                deviceMode = 0640;
492                deviceUser = gDAConsoleUserUID;
493
494                if ( CFArrayGetCount( gDAConsoleUserList ) > 1 )
495                {
496                    deviceMode = 0666;
497                    deviceUser = ___UID_ROOT;
498                }
499
500                if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanFalse )
501                {
502                    deviceMode &= 0444;
503                }
504
505                chmod( DADiskGetBSDPath( disk, TRUE  ), deviceMode );
506                chmod( DADiskGetBSDPath( disk, FALSE ), deviceMode );
507
508                chown( DADiskGetBSDPath( disk, TRUE  ), deviceUser, -1 );
509                chown( DADiskGetBSDPath( disk, FALSE ), deviceUser, -1 );
510            }
511///w:stop
512
513            /*
514             * Mount this volume.
515             */
516
517            if ( previousUserList == NULL )
518            {
519                if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanTrue )
520                {
521                    if ( DAMountGetPreference( disk, kDAMountPreferenceDefer ) )
522                    {
523                        DADiskMountWithArguments( disk, NULL, kDADiskMountOptionDefault, NULL, CFSTR( "automatic" ) );
524                    }
525                }
526            }
527        }
528    }
529    else
530    {
531        CFIndex count;
532        CFIndex index;
533
534        /*
535         * A console user is not logged in.
536         */
537
538        DAPreferenceListRefresh( );
539
540        count = CFArrayGetCount( gDADiskList );
541
542        for ( index = 0; index < count; index++ )
543        {
544            DADiskRef disk;
545
546            disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
547///w:start
548            /*
549             * Set the BSD permissions for this media object.
550             */
551
552            if ( DADiskGetDescription( disk, kDADiskDescriptionMediaTypeKey ) )
553            {
554                mode_t deviceMode;
555                uid_t  deviceUser;
556
557                deviceMode = 0640;
558                deviceUser = ___UID_ROOT;
559
560                if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanFalse )
561                {
562                    deviceMode &= 0444;
563                }
564
565                chmod( DADiskGetBSDPath( disk, TRUE  ), deviceMode );
566                chmod( DADiskGetBSDPath( disk, FALSE ), deviceMode );
567
568                chown( DADiskGetBSDPath( disk, TRUE  ), deviceUser, -1 );
569                chown( DADiskGetBSDPath( disk, FALSE ), deviceUser, -1 );
570            }
571///w:stop
572
573            /*
574             * Unmount this volume.
575             */
576
577            if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanTrue )
578            {
579                Boolean unmount;
580
581                unmount = FALSE;
582
583                if ( DAMountGetPreference( disk, kDAMountPreferenceDefer ) )
584                {
585                    if ( DADiskGetOption( disk, kDADiskOptionMountAutomaticNoDefer ) == FALSE )
586                    {
587                        unmount = TRUE;
588                    }
589                }
590
591                if ( DADiskGetOption( disk, kDADiskOptionEjectUponLogout ) )
592                {
593                    unmount = TRUE;
594                }
595
596                if ( unmount )
597                {
598                    DADiskUnmount( disk, kDADiskUnmountOptionDefault, NULL );
599                }
600            }
601        }
602
603        for ( index = 0; index < count; index++ )
604        {
605            DADiskRef disk;
606
607            disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
608
609            /*
610             * Eject this disk.
611             */
612
613            if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWholeKey ) == kCFBooleanTrue )
614            {
615                Boolean eject;
616
617                eject = FALSE;
618
619                if ( DADiskGetOption( disk, kDADiskOptionEjectUponLogout ) )
620                {
621                    eject = TRUE;
622                }
623
624                if ( eject )
625                {
626                    DADiskEject( disk, kDADiskEjectOptionDefault, NULL );
627                }
628            }
629        }
630    }
631
632    if ( previousUser )
633    {
634        CFRelease( previousUser );
635    }
636
637    if ( previousUserList )
638    {
639        CFRelease( previousUserList );
640    }
641
642    DAStageSignal( );
643}
644
645void _DAMediaAppearedCallback( void * context, io_iterator_t notification )
646{
647    /*
648     * Process the appearance of media objects in I/O Kit.
649     */
650
651    io_service_t media;
652
653    /*
654     * Iterate through the media objects.
655     */
656
657    while ( ( media = IOIteratorNext( notification ) ) )
658    {
659        DADiskRef disk;
660
661        /*
662         * Determine whether this is a re-registration.
663         */
664
665        disk = __DADiskListGetDiskWithIOMedia( media );
666
667        if ( disk )
668        {
669            __DAMediaPropertyChangedCallback( NULL, media, NULL );
670///w:start
671            if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanTrue )
672            {
673                if ( DADiskGetDescription( disk, kDADiskDescriptionMediaLeafKey ) == kCFBooleanFalse )
674                {
675                    DADiskProbe( disk, NULL );
676                }
677            }
678///w:stop
679        }
680        else
681        {
682            io_object_t busyNotification;
683            io_object_t propertyNotification;
684
685            /*
686             * Create the "media changed" notification.
687             */
688
689            busyNotification = IO_OBJECT_NULL;
690
691            IOServiceAddInterestNotification( gDAMediaPort, media, kIOBusyInterest, __DAMediaChangedCallback, NULL, &busyNotification );
692
693            propertyNotification = IO_OBJECT_NULL;
694
695            IOServiceAddInterestNotification( gDAMediaPort, media, kIOGeneralInterest, __DAMediaChangedCallback, NULL, &propertyNotification );
696
697            /*
698             * Create a disk object for this media object.
699             */
700
701            DALogDebugHeader( "iokit [0] -> %s", gDAProcessNameID );
702
703            disk = DADiskCreateFromIOMedia( kCFAllocatorDefault, media );
704
705            if ( disk )
706            {
707                /*
708                 * Determine whether a media object disappearance and appearance occurred.  We must do this
709                 * since the I/O Kit appearance queue is separate from the I/O Kit disappearance queue, and
710                 * we are in the midst of processing the appearance queue when we see a duplicate, which is
711                 * to say, there is a disappearance on the queue we have not processed yet and must process
712                 * it first.  The appearances and disappearances within each queue do occur in proper order.
713                 */
714
715                if ( ___CFArrayContainsValue( gDADiskList, disk ) )
716                {
717                    /*
718                     * Process the disappearance.
719                     */
720
721                    _DAMediaDisappearedCallback( ( void * ) ___CFArrayGetValue( gDADiskList, disk ), IO_OBJECT_NULL );
722
723                    assert( ___CFArrayContainsValue( gDADiskList, disk ) == FALSE );
724                }
725
726                /*
727                 * Set the "media changed" notification.
728                 */
729
730                if ( busyNotification )
731                {
732                    DADiskSetBusyNotification( disk, busyNotification );
733                }
734
735                if ( propertyNotification )
736                {
737                    DADiskSetPropertyNotification( disk, propertyNotification );
738                }
739
740                /*
741                 * Set the BSD permissions for this media object.
742                 */
743
744                if ( DADiskGetDescription( disk, kDADiskDescriptionMediaTypeKey ) )
745                {
746                    if ( DADiskGetMode( disk ) )
747                    {
748                        chmod( DADiskGetBSDPath( disk, TRUE  ), DADiskGetMode( disk ) & 0666 );
749                        chmod( DADiskGetBSDPath( disk, FALSE ), DADiskGetMode( disk ) & 0666 );
750                    }
751
752                    if ( gDAConsoleUserList )
753                    {
754///w:start
755                        mode_t deviceMode;
756                        uid_t  deviceUser;
757
758                        deviceMode = 0640;
759                        deviceUser = gDAConsoleUserUID;
760
761                        if ( CFArrayGetCount( gDAConsoleUserList ) > 1 )
762                        {
763                            deviceMode = 0666;
764                            deviceUser = ___UID_ROOT;
765                        }
766
767                        if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanFalse )
768                        {
769                            deviceMode &= 0444;
770                        }
771
772                        chmod( DADiskGetBSDPath( disk, TRUE  ), deviceMode );
773                        chmod( DADiskGetBSDPath( disk, FALSE ), deviceMode );
774
775                        chown( DADiskGetBSDPath( disk, TRUE  ), deviceUser, -1 );
776                        chown( DADiskGetBSDPath( disk, FALSE ), deviceUser, -1 );
777///w:stop
778                    }
779                }
780                else
781                {
782                    if ( DADiskGetMode( disk ) )
783                    {
784                        chmod( DADiskGetBSDPath( disk, TRUE  ), DADiskGetMode( disk ) & 0666 );
785                        chmod( DADiskGetBSDPath( disk, FALSE ), DADiskGetMode( disk ) & 0666 );
786                    }
787
788                    if ( DADiskGetUserGID( disk ) )
789                    {
790                        chown( DADiskGetBSDPath( disk, TRUE  ), -1, DADiskGetUserGID( disk ) );
791                        chown( DADiskGetBSDPath( disk, FALSE ), -1, DADiskGetUserGID( disk ) );
792                    }
793
794                    if ( DADiskGetUserUID( disk ) )
795                    {
796                        chown( DADiskGetBSDPath( disk, TRUE  ), DADiskGetUserUID( disk ), -1 );
797                        chown( DADiskGetBSDPath( disk, FALSE ), DADiskGetUserUID( disk ), -1 );
798                    }
799                }
800
801                /*
802                 * Set the BSD link for this media object.
803                 */
804
805                if ( DADiskGetBSDLink( disk, TRUE ) )
806                {
807                    int status;
808
809                    status = strncmp( DADiskGetBSDLink( disk, TRUE ), _PATH_DEV "disk", strlen( _PATH_DEV "disk" ) );
810
811                    if ( status )
812                    {
813                        status = link( DADiskGetBSDPath( disk, TRUE ), DADiskGetBSDLink( disk, TRUE ) );
814
815                        if ( status == 0 )
816                        {
817                            status = link( DADiskGetBSDPath( disk, FALSE ), DADiskGetBSDLink( disk, FALSE ) );
818
819                            if ( status )
820                            {
821                                unlink( DADiskGetBSDLink( disk, TRUE ) );
822                            }
823                        }
824                    }
825
826                    if ( status )
827                    {
828                        DALogDebugHeader( "iokit [0] -> %s", gDAProcessNameID );
829
830                        DALogError( "unable to link %@ to %s.", disk, DADiskGetBSDLink( disk, TRUE ) );
831
832                        DADiskSetBSDLink( disk, TRUE,  NULL );
833                        DADiskSetBSDLink( disk, FALSE, NULL );
834                    }
835                }
836
837                /*
838                 * Add the disk object to our tables.
839                 */
840
841                DALogDebugHeader( "iokit [0] -> %s", gDAProcessNameID );
842
843                DALogDebug( "  created disk, id = %@.", disk );
844
845                DAUnitSetState( disk, kDAUnitStateStagedUnreadable, FALSE );
846
847                CFArrayInsertValueAtIndex( gDADiskList, 0, disk );
848
849                CFRelease( disk );
850            }
851
852            if ( busyNotification )
853            {
854                IOObjectRelease( busyNotification );
855            }
856
857            if ( propertyNotification )
858            {
859                IOObjectRelease( propertyNotification );
860            }
861        }
862
863        IOObjectRelease( media );
864    }
865
866    DAStageSignal( );
867}
868
869void _DAMediaDisappearedCallback( void * context, io_iterator_t notification )
870{
871    /*
872     * Process the disappearance of media objects in I/O Kit.
873     */
874
875    io_service_t media;
876
877    /*
878     * Iterate through the media objects.
879     */
880
881    if ( context )
882    {
883        media = DADiskGetIOMedia( context );
884    }
885    else
886    {
887        media = IOIteratorNext( notification );
888    }
889
890    for ( ; media ; media = IOIteratorNext( notification ) )
891    {
892        DADiskRef disk;
893
894        /*
895         * Obtain the disk object for this media object.
896         */
897
898        disk = __DADiskListGetDiskWithIOMedia( media );
899
900        /*
901         * Determine whether a media object appearance and disappearance occurred.  We must do this
902         * since the I/O Kit appearance queue is separate from the I/O Kit disappearance queue, and
903         * we are in the midst of processing the disappearance queue when we see one missing, which
904         * is to say, there is an appearance on the queue we haven't processed yet and must process
905         * it first.  The appearances and disappearances within each queue do occur in proper order.
906         */
907
908        if ( disk == NULL )
909        {
910            /*
911             * Process the appearance.
912             */
913
914            assert( context == NULL );
915
916            _DAMediaAppearedCallback( NULL, gDAMediaAppearedNotification );
917
918            disk = __DADiskListGetDiskWithIOMedia( media );
919        }
920
921        if ( disk )
922        {
923            /*
924             * Remove the disk object from our tables.
925             */
926
927            DALogDebugHeader( "iokit [0] -> %s", gDAProcessNameID );
928
929            DALogDebug( "  removed disk, id = %@.", disk );
930
931            if ( DADiskGetBSDLink( disk, TRUE ) )
932            {
933                unlink( DADiskGetBSDLink( disk, TRUE ) );
934            }
935
936            if ( DADiskGetBSDLink( disk, FALSE ) )
937            {
938                unlink( DADiskGetBSDLink( disk, FALSE ) );
939            }
940
941            DAQueueReleaseDisk( disk );
942
943            if ( DADiskGetState( disk, kDADiskStateStagedAppear ) )
944            {
945                DADiskDisappearedCallback( disk );
946            }
947
948            if ( DADiskGetState( disk, kDADiskStateStagedMount ) )
949            {
950                DADiskUnmount( disk, kDADiskUnmountOptionForce, NULL );
951            }
952
953            DADiskSetState( disk, kDADiskStateZombie, TRUE );
954
955            ___CFArrayRemoveValue( gDADiskList, disk );
956        }
957
958        if ( context )
959        {
960            break;
961        }
962
963        IOObjectRelease( media );
964    }
965
966    DAStageSignal( );
967}
968
969void _DAServerCallback( CFMachPortRef port, void * parameter, CFIndex messageSize, void * info )
970{
971    mach_msg_header_t * message = parameter;
972
973    if ( message->msgh_id == MACH_NOTIFY_NO_SENDERS )
974    {
975        _DAServerSessionRelease( message->msgh_local_port );
976    }
977    else if ( DAServer_server( message, __gDAServerReply ) )
978    {
979        kern_return_t status;
980
981        status = ( __gDAServerReply->msgh_bits & MACH_MSGH_BITS_COMPLEX )
982                 ? KERN_SUCCESS
983                 : ( ( mig_reply_error_t * ) __gDAServerReply )->RetCode;
984
985        /*
986         * Any resources present in the request message are the responsibility of the service
987         * function, if it is successful in responding to the request.  Success is defined in
988         * two ways:
989         *
990         * o KERN_SUCCESS:  This says that the user�s request was processed, and all incoming
991         *                  resources have been recorded or deallocated by the server routine.
992         * o MIG_NO_REPLY:  This says that the user�s request was accepted,  and all incoming
993         *                  resources have been recorded or deallocated by the server routine.
994         *
995         * A reply should always be returned for any message received, unless the return code
996         * from the server was MIG_NO_REPLY or the request message does not have a reply port.
997         */
998
999        if ( status != MIG_NO_REPLY )
1000        {
1001            if ( status != KERN_SUCCESS )
1002            {
1003                message->msgh_remote_port = MACH_PORT_NULL;
1004
1005                mach_msg_destroy( message );
1006            }
1007
1008            if ( __gDAServerReply->msgh_remote_port )
1009            {
1010                status = mach_msg_send( __gDAServerReply );
1011
1012                if ( status == MACH_SEND_INVALID_DEST )
1013                {
1014                    mach_msg_destroy( __gDAServerReply );
1015                }
1016            }
1017        }
1018    }
1019}
1020
1021kern_return_t _DAServerDiskCopyDescription( mach_port_t _session, caddr_t _disk, vm_address_t * _description, mach_msg_type_number_t * _descriptionSize )
1022{
1023    kern_return_t status;
1024
1025    status = kDAReturnBadArgument;
1026
1027    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1028
1029    if ( _session )
1030    {
1031        DASessionRef session;
1032
1033        session = __DASessionListGetSession( _session );
1034
1035        if ( session )
1036        {
1037            DADiskRef disk;
1038
1039            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1040
1041            disk = __DADiskListGetDisk( _disk );
1042
1043            if ( disk )
1044            {
1045                CFDataRef description;
1046
1047                description = DADiskGetSerialization( disk );
1048
1049                if ( description )
1050                {
1051                    *_description = ___CFDataCopyBytes( description, _descriptionSize );
1052
1053                    if ( *_description )
1054                    {
1055                        DALogDebug( "  copied disk description, id = %@.", disk );
1056
1057                        status = kDAReturnSuccess;
1058                    }
1059                }
1060            }
1061        }
1062    }
1063
1064    if ( status )
1065    {
1066        DALogDebug( "unable to copy disk description, id = %s (status code 0x%08X).", _disk, status );
1067    }
1068
1069    return status;
1070}
1071
1072kern_return_t _DAServerDiskGetOptions( mach_port_t _session, caddr_t _disk, int32_t * _options )
1073{
1074    kern_return_t status;
1075
1076    status = kDAReturnBadArgument;
1077
1078    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1079
1080    if ( _session )
1081    {
1082        DASessionRef session;
1083
1084        session = __DASessionListGetSession( _session );
1085
1086        if ( session )
1087        {
1088            DADiskRef disk;
1089
1090            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1091
1092            disk = __DADiskListGetDisk( _disk );
1093
1094            if ( disk )
1095            {
1096                *_options = DADiskGetOptions( disk );
1097
1098                DALogDebug( "  got disk options, id = %@, options = 0x%08X.", disk, *_options );
1099
1100                status = kDAReturnSuccess;
1101            }
1102        }
1103    }
1104
1105    if ( status )
1106    {
1107        DALogDebug( "unable to get disk options, id = %s (status code 0x%08X).", _disk, status );
1108    }
1109
1110    return status;
1111}
1112
1113kern_return_t _DAServerDiskGetUserUID( mach_port_t _session, caddr_t _disk, uid_t * _userUID )
1114{
1115    kern_return_t status;
1116
1117    status = kDAReturnBadArgument;
1118
1119    if ( _session )
1120    {
1121        DASessionRef session;
1122
1123        session = __DASessionListGetSession( _session );
1124
1125        if ( session )
1126        {
1127            DADiskRef disk;
1128
1129            disk = __DADiskListGetDisk( _disk );
1130
1131            if ( disk )
1132            {
1133                *_userUID = DADiskGetUserUID( disk );
1134
1135                status = kDAReturnSuccess;
1136            }
1137        }
1138    }
1139
1140    return status;
1141}
1142
1143kern_return_t _DAServerDiskIsClaimed( mach_port_t _session, caddr_t _disk, boolean_t * _claimed )
1144{
1145    kern_return_t status;
1146
1147    status = kDAReturnBadArgument;
1148
1149    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1150
1151    if ( _session )
1152    {
1153        DASessionRef session;
1154
1155        session = __DASessionListGetSession( _session );
1156
1157        if ( session )
1158        {
1159            DADiskRef disk;
1160
1161            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1162
1163            disk = __DADiskListGetDisk( _disk );
1164
1165            if ( disk )
1166            {
1167                *_claimed = DADiskGetClaim( disk ) ? TRUE : FALSE;
1168
1169                DALogDebug( "  got disk claim state, id = %@, claimed = %s.", disk, *_claimed ? "true" : "false" );
1170
1171                status = kDAReturnSuccess;
1172            }
1173        }
1174    }
1175
1176    if ( status )
1177    {
1178        DALogDebug( "unable to get disk claim state, id = %s (status code 0x%08X).", _disk, status );
1179    }
1180
1181    return status;
1182}
1183
1184kern_return_t _DAServerDiskSetAdoption( mach_port_t _session, caddr_t _disk, boolean_t _adoption, security_token_t _token )
1185{
1186    kern_return_t status;
1187
1188    status = kDAReturnBadArgument;
1189
1190    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1191
1192    if ( _session )
1193    {
1194        DASessionRef session;
1195
1196        session = __DASessionListGetSession( _session );
1197
1198        if ( session )
1199        {
1200            DADiskRef disk;
1201
1202            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1203
1204            disk = __DADiskListGetDisk( _disk );
1205
1206            if ( disk )
1207            {
1208                status = DAAuthorize( session, _kDAAuthorizeOptionDefault, disk, _token.val[0], _token.val[1], _kDAAuthorizeRightAdopt );
1209
1210                if ( status == kDAReturnSuccess )
1211                {
1212                    DALogDebug( "  set disk adoption, id = %@, adoption = %s.", disk, _adoption ? "true" : "false" );
1213
1214                    status = _DADiskSetAdoption( disk, _adoption );
1215                }
1216            }
1217        }
1218    }
1219
1220    if ( status )
1221    {
1222         DALogDebug( "unable to set disk adoption, id = %s (status code 0x%08X).", _disk, status );
1223    }
1224
1225    return status;
1226}
1227
1228kern_return_t _DAServerDiskSetEncoding( mach_port_t _session, caddr_t _disk, int32_t encoding, security_token_t _token )
1229{
1230    kern_return_t status;
1231
1232    status = kDAReturnBadArgument;
1233
1234    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1235
1236    if ( _session )
1237    {
1238        DASessionRef session;
1239
1240        session = __DASessionListGetSession( _session );
1241
1242        if ( session )
1243        {
1244            DADiskRef disk;
1245
1246            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1247
1248            disk = __DADiskListGetDisk( _disk );
1249
1250            if ( disk )
1251            {
1252                status = DAAuthorize( session, _kDAAuthorizeOptionIsOwner, disk, _token.val[0], _token.val[1], _kDAAuthorizeRightEncode );
1253
1254                if ( status == kDAReturnSuccess )
1255                {
1256                    DALogDebug( "  set disk encoding, id = %@, encoding = %d.", disk, encoding );
1257
1258                    status = _DADiskSetEncoding( disk, encoding );
1259                }
1260            }
1261        }
1262    }
1263
1264    if ( status )
1265    {
1266        DALogDebug( "unable to set disk encoding, id = %s (status code 0x%08X).", _disk, status );
1267    }
1268
1269    return status;
1270}
1271
1272kern_return_t _DAServerDiskSetOptions( mach_port_t _session, caddr_t _disk, int32_t _options, int32_t _value )
1273{
1274    kern_return_t status;
1275
1276    status = kDAReturnBadArgument;
1277
1278    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1279
1280    if ( _session )
1281    {
1282        DASessionRef session;
1283
1284        session = __DASessionListGetSession( _session );
1285
1286        if ( session )
1287        {
1288            DADiskRef disk;
1289
1290            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1291
1292            disk = __DADiskListGetDisk( _disk );
1293
1294            if ( disk )
1295            {
1296                DALogDebug( "  set disk options, id = %@, options = 0x%08X, value = %s.", disk, _options, _value ? "true" : "false" );
1297
1298                if ( DADiskGetState( disk, kDADiskStateStagedAppear ) )
1299                {
1300                    if ( ( _options & kDADiskOptionPrivate ) )
1301                    {
1302                        if ( _value )
1303                        {
1304                            if ( DADiskGetOption( disk, kDADiskOptionPrivate ) == FALSE )
1305                            {
1306                                DADiskDisappearedCallback( disk );
1307
1308                                DAStageSignal( );
1309                            }
1310                        }
1311                        else
1312                        {
1313                            if ( DADiskGetOption( disk, kDADiskOptionPrivate ) )
1314                            {
1315                                DADiskSetOption( disk, kDADiskOptionPrivate, FALSE );
1316
1317                                DADiskAppearedCallback( disk );
1318
1319                                DAStageSignal( );
1320                            }
1321                        }
1322                    }
1323                }
1324
1325                DADiskSetOptions( disk, _options, _value );
1326
1327                status = kDAReturnSuccess;
1328            }
1329        }
1330    }
1331
1332    if ( status )
1333    {
1334        DALogDebug( "unable to set disk options, id = %s (status code 0x%08X).", _disk, status );
1335    }
1336
1337    return status;
1338}
1339
1340kern_return_t _DAServerDiskUnclaim( mach_port_t _session, caddr_t _disk )
1341{
1342    kern_return_t status;
1343
1344    status = kDAReturnBadArgument;
1345
1346    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1347
1348    if ( _session )
1349    {
1350        DASessionRef session;
1351
1352        session = __DASessionListGetSession( _session );
1353
1354        if ( session )
1355        {
1356            DADiskRef disk;
1357
1358            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1359
1360            disk = __DADiskListGetDisk( _disk );
1361
1362            if ( disk )
1363            {
1364                DACallbackRef callback;
1365
1366                callback = DADiskGetClaim( disk );
1367
1368                if ( callback )
1369                {
1370                    if ( DACallbackGetSession( callback ) == session )
1371                    {
1372                        DALogDebug( "  unclaimed disk, id = %@.", disk );
1373
1374                        DADiskSetClaim( disk, NULL );
1375
1376                        status = kDAReturnSuccess;
1377                    }
1378                }
1379            }
1380        }
1381    }
1382
1383    if ( status )
1384    {
1385        DALogDebug( "unable to unclaim disk, id = %s (status code 0x%08X).", _disk, status );
1386    }
1387
1388    return status;
1389}
1390
1391kern_return_t _DAServerSessionCopyCallbackQueue( mach_port_t _session, vm_address_t * _queue, mach_msg_type_number_t * _queueSize )
1392{
1393    kern_return_t status;
1394
1395    status = kDAReturnBadArgument;
1396
1397    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1398
1399    if ( _session )
1400    {
1401        DASessionRef session;
1402
1403        session = __DASessionListGetSession( _session );
1404
1405        if ( session )
1406        {
1407            CFMutableArrayRef callbacks;
1408
1409            DALogDebugHeader( "%s -> %@", gDAProcessNameID, session );
1410
1411            callbacks = DASessionGetCallbackQueue( session );
1412
1413            if ( callbacks )
1414            {
1415                CFIndex   count;
1416                CFIndex   index;
1417                CFDataRef queue;
1418
1419                count = CFArrayGetCount( callbacks );
1420
1421                for ( index = 0; index < count; index++ )
1422                {
1423                    DACallbackRef callback;
1424
1425                    callback = ( void * ) CFArrayGetValueAtIndex( callbacks, index );
1426
1427                    DACallbackSetDisk( callback, NULL );
1428
1429                    DACallbackSetMatch( callback, NULL );
1430
1431                    DACallbackSetSession( callback, NULL );
1432                }
1433
1434                queue = _DASerialize( kCFAllocatorDefault, callbacks );
1435
1436                if ( queue )
1437                {
1438                    *_queue = ___CFDataCopyBytes( queue, _queueSize );
1439
1440                    if ( *_queue )
1441                    {
1442                        DALogDebug( "  dispatched callback queue." );
1443
1444                        status = kDAReturnSuccess;
1445                    }
1446
1447                    CFRelease( queue );
1448                }
1449
1450                CFArrayRemoveAllValues( callbacks );
1451            }
1452
1453            DASessionSetState( session, kDASessionStateTimeout, FALSE );
1454        }
1455    }
1456
1457    if ( status )
1458    {
1459        DALogDebug( "unable to copy callback queue (status code 0x%08X).", status );
1460    }
1461
1462    return status;
1463}
1464
1465kern_return_t _DAServerSessionCreate( mach_port_t   _session,
1466                                      caddr_t       _name,
1467                                      pid_t         _pid,
1468                                      mach_port_t * _server )
1469{
1470    kern_return_t status;
1471
1472    status = kDAReturnBadArgument;
1473
1474    DALogDebugHeader( "%s [%d] -> %s", _name, _pid, gDAProcessNameID );
1475
1476    if ( _session )
1477    {
1478        DASessionRef session;
1479
1480        /*
1481         * Create the session.
1482         */
1483
1484        session = DASessionCreate( kCFAllocatorDefault, _name, _pid );
1485
1486        if ( session )
1487        {
1488            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1489
1490            DALogDebug( "  created session, id = %@.", session );
1491
1492            *_server = DASessionGetServerPort( session );
1493
1494            /*
1495             * Add the session object to our tables.
1496             */
1497
1498            ___vproc_transaction_begin( );
1499
1500            CFArrayAppendValue( gDASessionList, session );
1501
1502            /*
1503             * Add the session to our run loop.
1504             */
1505
1506            DASessionScheduleWithRunLoop( session, CFRunLoopGetCurrent( ), kCFRunLoopDefaultMode );
1507
1508            CFRelease( session );
1509
1510            status = kDAReturnSuccess;
1511        }
1512    }
1513
1514    if ( status )
1515    {
1516        DALogDebug( "unable to create session, id = %s [%d].", _name, _pid );
1517    }
1518
1519    return status;
1520}
1521
1522kern_return_t _DAServerSessionQueueRequest( mach_port_t            _session,
1523                                            int32_t                _kind,
1524                                            caddr_t                _argument0,
1525                                            int32_t                _argument1,
1526                                            vm_address_t           _argument2,
1527                                            mach_msg_type_number_t _argument2Size,
1528                                            vm_address_t           _argument3,
1529                                            mach_msg_type_number_t _argument3Size,
1530                                            mach_vm_offset_t       _address,
1531                                            mach_vm_offset_t       _context,
1532                                            security_token_t       _token )
1533{
1534    kern_return_t status;
1535
1536    status = kDAReturnBadArgument;
1537
1538    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1539
1540    if ( _session )
1541    {
1542        DASessionRef session;
1543
1544        session = __DASessionListGetSession( _session );
1545
1546        if ( session )
1547        {
1548            DADiskRef disk;
1549
1550            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1551
1552            disk = __DADiskListGetDisk( _argument0 );
1553
1554            if ( disk )
1555            {
1556                CFTypeRef     argument2 = NULL;
1557                CFTypeRef     argument3 = NULL;
1558                DACallbackRef callback;
1559                DARequestRef  request;
1560
1561                DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1562
1563                if ( _argument2 )
1564                {
1565                    argument2 = _DAUnserializeWithBytes( kCFAllocatorDefault, _argument2, _argument2Size );
1566                }
1567
1568                if ( _argument3 )
1569                {
1570                    argument3 = _DAUnserializeWithBytes( kCFAllocatorDefault, _argument3, _argument3Size );
1571                }
1572
1573                callback = DACallbackCreate( kCFAllocatorDefault, session, _address, _context, _kind, 0, NULL, NULL );
1574
1575                request = DARequestCreate( kCFAllocatorDefault, _kind, disk, _argument1, argument2, argument3, _token.val[0], _token.val[1], callback );
1576
1577                if ( request )
1578                {
1579                    switch ( _kind )
1580                    {
1581                        case _kDADiskEject:
1582                        {
1583                            status = DAAuthorize( session, _kDAAuthorizeOptionIsOwner, disk, _token.val[0], _token.val[1], _kDAAuthorizeRightUnmount );
1584
1585                            break;
1586                        }
1587                        case _kDADiskMount:
1588                        {
1589                            status = DAAuthorize( session, _kDAAuthorizeOptionIsOwner, disk, _token.val[0], _token.val[1], _kDAAuthorizeRightMount );
1590
1591                            break;
1592                        }
1593                        case _kDADiskRename:
1594                        {
1595                            status = DAAuthorize( session, _kDAAuthorizeOptionIsOwner, disk, _token.val[0], _token.val[1], _kDAAuthorizeRightRename );
1596
1597                            break;
1598                        }
1599                        case _kDADiskUnmount:
1600                        {
1601                            status = DAAuthorize( session, _kDAAuthorizeOptionIsOwner, disk, _token.val[0], _token.val[1], _kDAAuthorizeRightUnmount );
1602
1603                            break;
1604                        }
1605                        default:
1606                        {
1607                            status = kDAReturnSuccess;
1608
1609                            break;
1610                        }
1611                    }
1612
1613                    if ( status == kDAReturnSuccess )
1614                    {
1615                        DAQueueRequest( request );
1616
1617                        DALogDebug( "  queued solicitation, id = %016llX:%016llX, kind = %s, disk = %@, options = 0x%08X.",
1618                                    _address,
1619                                    _context,
1620                                    _DARequestKindGetName( _kind ),
1621                                    disk,
1622                                    _argument1 );
1623                    }
1624
1625                    CFRelease( request );
1626                }
1627
1628                if ( callback )
1629                {
1630                    CFRelease( callback );
1631                }
1632
1633                if ( argument2 )
1634                {
1635                    CFRelease( argument2 );
1636                }
1637
1638                if ( argument3 )
1639                {
1640                    CFRelease( argument3 );
1641                }
1642            }
1643        }
1644    }
1645
1646    if ( status )
1647    {
1648        DALogDebug( "unable to queue solicitation, id = %016llX:%016llX, kind = %s, disk = %s (status code 0x%08X).",
1649                    _address,
1650                    _context,
1651                    _DACallbackKindGetName( _kind ),
1652                    _argument0,
1653                    status );
1654    }
1655
1656    return status;
1657}
1658
1659kern_return_t _DAServerSessionQueueResponse( mach_port_t            _session,
1660                                             mach_vm_offset_t       _address,
1661                                             mach_vm_offset_t       _context,
1662                                             int32_t                _kind,
1663                                             caddr_t                _disk,
1664                                             vm_address_t           _response,
1665                                             mach_msg_type_number_t _responseSize,
1666                                             int32_t                _responseID )
1667{
1668    kern_return_t status;
1669
1670    status = kDAReturnBadArgument;
1671
1672    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1673
1674    if ( _session )
1675    {
1676        DASessionRef session;
1677
1678        session = __DASessionListGetSession( _session );
1679
1680        if ( session )
1681        {
1682            CFTypeRef response = NULL;
1683
1684            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1685
1686            if ( _response )
1687            {
1688                response = _DAUnserializeWithBytes( kCFAllocatorDefault, _response, _responseSize );
1689            }
1690
1691            if ( _DAResponseDispatch( response, _responseID ) == FALSE )
1692            {
1693                DALogDebug( "  dispatched response, id = %016llX:%016llX, kind = %s, disk = %s, orphaned.", _address, _context, _DACallbackKindGetName( _kind ), _disk );
1694            }
1695
1696            if ( response )
1697            {
1698                CFRelease( response );
1699            }
1700
1701            status = kDAReturnSuccess;
1702        }
1703    }
1704
1705    if ( status )
1706    {
1707        DALogDebug( "unable to dispatch response, id = %016llX:%016llX, disk = %s (status code 0x%08X).", _address, _context, _disk, status );
1708    }
1709
1710    return status;
1711}
1712
1713kern_return_t _DAServerSessionRegisterCallback( mach_port_t            _session,
1714                                                mach_vm_offset_t       _address,
1715                                                mach_vm_offset_t       _context,
1716                                                int32_t                _kind,
1717                                                int32_t                _order,
1718                                                vm_address_t           _match,
1719                                                mach_msg_type_number_t _matchSize,
1720                                                vm_address_t           _watch,
1721                                                mach_msg_type_number_t _watchSize )
1722{
1723    kern_return_t status;
1724
1725    status = kDAReturnBadArgument;
1726
1727    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1728
1729    if ( _session )
1730    {
1731        DASessionRef session;
1732
1733        session = __DASessionListGetSession( _session );
1734
1735        if ( session )
1736        {
1737            DACallbackRef   callback;
1738            CFDictionaryRef match = NULL;
1739            CFArrayRef      watch = NULL;
1740
1741            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1742
1743            if ( _match )
1744            {
1745                match = _DAUnserializeDiskDescriptionWithBytes( kCFAllocatorDefault, _match, _matchSize );
1746            }
1747
1748            if ( _watch )
1749            {
1750                watch = _DAUnserializeWithBytes( kCFAllocatorDefault, _watch, _watchSize );
1751            }
1752
1753            callback = DACallbackCreate( kCFAllocatorDefault, session, _address, _context, _kind, _order, match, watch );
1754
1755            if ( callback )
1756            {
1757                DASessionRegisterCallback( session, callback );
1758
1759                DALogDebug( "  registered callback, id = %016llX:%016llX, kind = %s.", _address, _context, _DACallbackKindGetName( _kind ) );
1760
1761                if ( DACallbackGetKind( callback ) == _kDADiskAppearedCallback )
1762                {
1763                    CFIndex count;
1764                    CFIndex index;
1765
1766                    count = CFArrayGetCount( gDADiskList );
1767
1768                    for ( index = 0; index < count; index++ )
1769                    {
1770                        DADiskRef disk;
1771
1772                        disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
1773
1774                        if ( DADiskGetState( disk, kDADiskStateStagedAppear ) )
1775                        {
1776                            DAQueueCallback( callback, disk, NULL );
1777                        }
1778                    }
1779
1780                    if ( gDAIdle )
1781                    {
1782                        DAQueueCallbacks( session, _kDAIdleCallback, NULL, NULL );
1783
1784                        DASessionSetState( session, kDASessionStateIdle, TRUE );
1785                    }
1786                }
1787                else if ( DACallbackGetKind( callback ) == _kDAIdleCallback )
1788                {
1789                    if ( gDAIdle )
1790                    {
1791                        DAQueueCallback( callback, NULL, NULL );
1792
1793                        DASessionSetState( session, kDASessionStateIdle, TRUE );
1794                    }
1795                    else
1796                    {
1797                        DASessionSetState( session, kDASessionStateIdle, FALSE );
1798                    }
1799                }
1800///w:start
1801                else if ( DACallbackGetKind( callback ) == _kDADiskEjectApprovalCallback )
1802                {
1803                    if ( strcmp( _DASessionGetName( session ), "SystemUIServer" ) == 0 )
1804                    {
1805                        CFStringRef key;
1806
1807                        key = SCDynamicStoreKeyCreateConsoleUser( kCFAllocatorDefault );
1808
1809                        if ( key )
1810                        {
1811                            CFMutableArrayRef keys;
1812
1813                            keys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
1814
1815                            if ( keys )
1816                            {
1817                                CFArrayAppendValue( keys, key );
1818
1819                                _DAConfigurationCallback( NULL, keys, NULL );
1820
1821                                CFRelease( keys );
1822                            }
1823
1824                            CFRelease( key );
1825                        }
1826                    }
1827                }
1828///w:stop
1829
1830                CFRelease( callback );
1831
1832                status = kDAReturnSuccess;
1833            }
1834
1835            if ( match )
1836            {
1837                CFRelease( match );
1838            }
1839
1840            if ( watch )
1841            {
1842                CFRelease( watch );
1843            }
1844        }
1845    }
1846
1847    if ( status )
1848    {
1849        DALogDebug( "unable to register callback, id = %016llX:%016llX, kind = %s (status code 0x%08X).", _address, _context, _DACallbackKindGetName( _kind ), status );
1850    }
1851
1852    return status;
1853}
1854
1855kern_return_t _DAServerSessionRelease( mach_port_t _session )
1856{
1857    kern_return_t status;
1858
1859    status = kDAReturnBadArgument;
1860
1861    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1862
1863    if ( _session )
1864    {
1865        DASessionRef session;
1866
1867        session = __DASessionListGetSession( _session );
1868
1869        if ( session )
1870        {
1871            CFMutableArrayRef callbacks;
1872
1873            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1874
1875            DALogDebug( "  removed session, id = %@.", session );
1876
1877            callbacks = DASessionGetCallbackQueue( session );
1878
1879            if ( callbacks )
1880            {
1881                CFArrayRemoveAllValues( callbacks );
1882            }
1883
1884            callbacks = DASessionGetCallbackRegister( session );
1885
1886            if ( callbacks )
1887            {
1888                CFArrayRemoveAllValues( callbacks );
1889            }
1890
1891            DAQueueReleaseSession( session );
1892
1893            /*
1894             * Remove the session from our run loop.
1895             */
1896
1897            DASessionUnscheduleFromRunLoop( session, CFRunLoopGetCurrent( ), kCFRunLoopDefaultMode );
1898
1899            /*
1900             * Remove the session object from our tables.
1901             */
1902
1903            DASessionSetState( session, kDASessionStateZombie, TRUE );
1904
1905            ___CFArrayRemoveValue( gDASessionList, session );
1906
1907            ___vproc_transaction_end( );
1908
1909            status = kDAReturnSuccess;
1910        }
1911    }
1912
1913    if ( status )
1914    {
1915        DALogDebug( "unable to release session, id = ? [?]:%d.", _session );
1916    }
1917
1918    return status;
1919}
1920
1921kern_return_t _DAServerSessionSetAuthorization( mach_port_t _session, AuthorizationExternalForm _authorization )
1922{
1923    kern_return_t status;
1924
1925    status = kDAReturnBadArgument;
1926
1927    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1928
1929    if ( _session )
1930    {
1931        DASessionRef session;
1932
1933        session = __DASessionListGetSession( _session );
1934
1935        if ( session )
1936        {
1937            AuthorizationRef authorization;
1938
1939            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1940
1941            status = AuthorizationCreateFromExternalForm( &_authorization, &authorization );
1942
1943            if ( status == errAuthorizationSuccess )
1944            {
1945                DASessionSetAuthorization( session, authorization );
1946
1947                DALogDebug( "  set authorization, id = %@.", session );
1948
1949                status = kDAReturnSuccess;
1950            }
1951        }
1952    }
1953
1954    if ( status )
1955    {
1956        DALogDebug( "unable to set authorization, id = ? [?]:%d.", _session );
1957    }
1958
1959    return status;
1960}
1961
1962kern_return_t _DAServerSessionSetClientPort( mach_port_t _session, mach_port_t _client )
1963{
1964    kern_return_t status;
1965
1966    status = kDAReturnBadArgument;
1967
1968    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
1969
1970    if ( _session )
1971    {
1972        DASessionRef session;
1973
1974        session = __DASessionListGetSession( _session );
1975
1976        if ( session )
1977        {
1978            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
1979
1980            DASessionSetClientPort( session, _client );
1981
1982            DALogDebug( "  set client port, id = %@.", session );
1983
1984            status = kDAReturnSuccess;
1985        }
1986    }
1987
1988    if ( status )
1989    {
1990        DALogDebug( "unable to set client port, id = ? [?]:%d.", _session );
1991    }
1992
1993    return status;
1994}
1995
1996kern_return_t _DAServerSessionUnregisterCallback( mach_port_t _session, mach_vm_offset_t _address, mach_vm_offset_t _context )
1997{
1998    kern_return_t status;
1999
2000    status = kDAReturnBadArgument;
2001
2002    DALogDebugHeader( "? [?]:%d -> %s", _session, gDAProcessNameID );
2003
2004    if ( _session )
2005    {
2006        DASessionRef session;
2007
2008        session = __DASessionListGetSession( _session );
2009
2010        if ( session )
2011        {
2012            DACallbackRef callback;
2013
2014            DALogDebugHeader( "%@ -> %s", session, gDAProcessNameID );
2015
2016            callback = DACallbackCreate( kCFAllocatorDefault, session, _address, _context, 0, 0, NULL, NULL );
2017
2018            if ( callback )
2019            {
2020                DAQueueUnregisterCallback( callback );
2021
2022                DASessionUnregisterCallback( session, callback );
2023
2024                DALogDebug( "  unregistered callback, id = %016llX:%016llX.", _address, _context );
2025
2026                CFRelease( callback );
2027
2028                status = kDAReturnSuccess;
2029            }
2030        }
2031    }
2032
2033    if ( status )
2034    {
2035        DALogDebug( "unable to unregister callback, id = %016llX:%016llX (status code 0x%08X).", _address, _context, status );
2036    }
2037
2038    return status;
2039}
2040
2041void _DAVolumeMountedCallback( CFMachPortRef port, void * parameter, CFIndex messageSize, void * info )
2042{
2043    struct statfs * mountList;
2044    int             mountListCount;
2045    int             mountListIndex;
2046
2047    mountListCount = getmntinfo( &mountList, MNT_NOWAIT );
2048
2049    for ( mountListIndex = 0; mountListIndex < mountListCount; mountListIndex++ )
2050    {
2051        DADiskRef disk;
2052
2053        disk = __DADiskListGetDisk( _DAVolumeGetID( mountList + mountListIndex ) );
2054
2055        if ( disk )
2056        {
2057            if ( DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ) == NULL )
2058            {
2059///w:start
2060                if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanFalse )
2061                {
2062                    DADiskProbe( disk, NULL );
2063                }
2064///w:stop
2065                DADiskRefresh( disk, NULL );
2066            }
2067        }
2068        else
2069        {
2070///w:start
2071            if ( strncmp( mountList[mountListIndex].f_mntfromname, _PATH_DEV "disk", strlen( _PATH_DEV "disk" ) ) )
2072///w:stop
2073            if ( ( mountList[mountListIndex].f_flags & MNT_UNION ) == 0 )
2074            {
2075                if ( strcmp( mountList[mountListIndex].f_fstypename, "devfs" ) )
2076                {
2077                    disk = DADiskCreateFromVolumePath( kCFAllocatorDefault, mountList + mountListIndex );
2078
2079                    if ( disk )
2080                    {
2081                        DALogDebugHeader( "bsd [0] -> %s", gDAProcessNameID );
2082
2083                        DALogDebug( "  created disk, id = %@.", disk );
2084
2085                        CFArrayInsertValueAtIndex( gDADiskList, 0, disk );
2086
2087                        DAStageSignal( );
2088
2089                        CFRelease( disk );
2090                    }
2091                }
2092            }
2093        }
2094    }
2095}
2096
2097void _DAVolumeUnmountedCallback( CFMachPortRef port, void * parameter, CFIndex messageSize, void * info )
2098{
2099    CFIndex count;
2100    CFIndex index;
2101
2102    count = CFArrayGetCount( gDADiskList );
2103
2104    for ( index = 0; index < count; index++ )
2105    {
2106        DADiskRef disk;
2107
2108        disk = ( void * ) CFArrayGetValueAtIndex( gDADiskList, index );
2109
2110        if ( DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ) )
2111        {
2112            DADiskRefresh( disk, NULL );
2113        }
2114    }
2115}
2116
2117CFRunLoopSourceRef DAServerCreateRunLoopSource( CFAllocatorRef allocator, CFIndex order )
2118{
2119    /*
2120     * Create a CFRunLoopSource for DAServer remote procedure calls.
2121     */
2122
2123    CFRunLoopSourceRef source = NULL;
2124
2125    /*
2126     * Initialize our minimal state.
2127     */
2128
2129    if ( __gDAServer == NULL )
2130    {
2131        /*
2132         * Register the Disk Arbitration master port.
2133         */
2134
2135        if ( __gDAServerPort == MACH_PORT_NULL )
2136        {
2137            bootstrap_check_in( bootstrap_port, _kDADaemonName, &__gDAServerPort );
2138        }
2139
2140        if ( __gDAServerPort )
2141        {
2142            /*
2143             * Create the Disk Arbitration master port.
2144             */
2145
2146            __gDAServer = CFMachPortCreateWithPort( allocator, __gDAServerPort, _DAServerCallback, NULL, NULL );
2147
2148            if ( __gDAServer )
2149            {
2150                __gDAServerReply = malloc( DAServer_subsystem.maxsize );
2151
2152                assert( __gDAServerReply );
2153            }
2154        }
2155    }
2156
2157    /*
2158     * Obtain the CFRunLoopSource for our CFMachPort.
2159     */
2160
2161    if ( __gDAServer )
2162    {
2163        source = CFMachPortCreateRunLoopSource( allocator, __gDAServer, order );
2164    }
2165
2166    return source;
2167}
2168