1/*
2 * Copyright (c) 2000 Apple Computer, 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/*
24cc ionotify.c -o notify -Wall -Wno-four-char-constants -framework IOKit
25*/
26
27#include <ctype.h>
28#include <stdlib.h>
29#include <string.h>
30#include <assert.h>
31#include <limits.h>
32
33#include <mach/mach_interface.h>
34#include <IOKit/IOKitLib.h>
35
36mach_port_t	masterPort;
37
38void dumpIter( io_iterator_t iter, mach_port_t recvPort )
39{
40    kern_return_t	kr;
41    io_object_t		obj;
42    io_name_t		name;
43    io_string_t		path;
44    mach_port_t		iter3;
45
46    while( (obj = IOIteratorNext( iter))) {
47        assert( KERN_SUCCESS == (
48        kr = IORegistryEntryGetName( obj, name )
49        ));
50	printf("name:%s(%d)\n", name, obj);
51        kr = IORegistryEntryGetPath( obj, kIOServicePlane, path );
52        if( KERN_SUCCESS == kr) {
53
54	    // if the object is detached, getPath will fail
55            printf("path:%s\n", path);
56
57            // as will IOServiceAddInterestNotification
58            if( KERN_SUCCESS != (
59                    kr = IOServiceAddInterestNotificationMsg( obj, kIOGeneralInterest,
60                            recvPort, (unsigned int) obj, &iter3)
61            )) printf("IOServiceAddInterestNotification(%lx)\n", kr);
62            // can compare two kernel objects with IOObjectIsEqualTo() if we keep the object,
63            // otherwise, release
64            IOObjectRelease( obj );
65        }
66    }
67}
68
69
70void notifyTest( char * arg )
71{
72    kern_return_t	kr;
73    io_iterator_t	iter1, iter2, iter3;
74    mach_port_t		port;
75    io_service_t	obj;
76    io_name_t		name;
77    const char *	type;
78    IOServiceInterestContent * content;
79    vm_size_t		size;
80    unsigned long int  	notifyType;
81    unsigned long int  	ref;
82    struct {
83        mach_msg_header_t	msgHdr;
84        OSNotificationHeader	notifyHeader;
85        IOServiceInterestContent	content;
86        mach_msg_trailer_t	trailer;
87    } msg;
88
89    assert( KERN_SUCCESS == (
90    kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)
91    ));
92
93    type = kIOMatchedNotification;// or kIOPublishNotification;
94    assert( KERN_SUCCESS == (
95    kr = IOServiceAddNotification( masterPort, type,
96                                    IOServiceMatching( arg ),
97//                                    IOBSDNameMatching( masterPort, 0, arg ),
98                                    port, (unsigned int) type, &iter2 )
99    ));
100    printf("IOServiceAddNotification: %s: ", type );
101    // dumping the iterator gives us the current list
102    // and arms the notification for changes
103    dumpIter( iter2, port );
104    printf("\n");
105
106    type = kIOTerminatedNotification;
107    assert( KERN_SUCCESS == (
108    kr = IOServiceAddNotification( masterPort, type,
109                                    IOServiceMatching( arg ),
110                                    port, (unsigned int) type, &iter1 )
111    ));
112    printf("IOServiceAddNotification: %s: ", type );
113    dumpIter( iter1, port );
114    printf("\n");
115
116    type = kIOBusyInterest;
117    obj = IORegistryEntryFromPath( masterPort, kIOServicePlane ":/");
118    assert( obj );
119    assert( KERN_SUCCESS == (
120    kr = IOServiceAddInterestNotificationMsg( obj, type,
121                                           port, (unsigned int) obj, &iter3)
122    ));
123
124    printf("ports: iter1=%d, iter2=%d, rcv=%d\n", iter1, iter2, port);
125
126    do {
127	printf("waiting...\n");
128        assert( KERN_SUCCESS == (
129        kr = mach_msg(&msg.msgHdr, MACH_RCV_MSG,
130                    0, sizeof(msg), port, 0, MACH_PORT_NULL)
131        ));
132
133        assert( KERN_SUCCESS == (
134	kr = OSGetNotificationFromMessage( &msg.msgHdr, 0, &notifyType, &ref,
135			(void **) &content, &size )
136        ));
137
138	// we passed a string for the refcon
139        printf("got notification, type=%d, local=%d, remote=%d\n", notifyType,
140		msg.msgHdr.msgh_local_port, msg.msgHdr.msgh_remote_port );
141        if( notifyType == kIOServiceMessageNotificationType) {
142            obj = ref;
143            if( KERN_SUCCESS == (
144            kr = IORegistryEntryGetName( obj, name )
145                                 )) printf(name); else printf("???");
146            printf(": messageType %08lx, arg %08lx\n",
147                   content->messageType, content->messageArgument[0]);
148        } else {
149            printf("%s: ", ref );
150            // remote port is the notification (an iterator_t) that fired
151            dumpIter( msg.msgHdr.msgh_remote_port, port );
152        }
153
154    } while( TRUE );
155
156    IOObjectRelease( iter1 );
157    IOObjectRelease( iter2 );
158    IOObjectRelease( iter3 );
159}
160
161int
162main(int argc, char **argv)
163{
164	kern_return_t		kr;
165
166	/*
167	 * Get master device port
168	 */
169	assert( KERN_SUCCESS == (
170	kr = IOMasterPort(   bootstrap_port,
171			     &masterPort)
172	));
173
174	if( argc > 1)
175            notifyTest( argv[1] );
176	else
177	    printf("%s className\n", argv[0]);
178
179	printf("Exit\n");
180}
181
182