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 iodisplayregistry.c -o iodisplayregistry -framework IOKit -Wall
25*/
26
27
28#include <assert.h>
29
30#include <CoreFoundation/CoreFoundation.h>
31
32#include <IOKit/IOKitLib.h>
33#include <IOKit/IOCFSerialize.h>
34
35static mach_port_t masterPort;
36
37static void indent(Boolean node, int depth, UInt64 stackOfBits);
38static void properties(io_registry_entry_t service,
39                       int depth,
40                       UInt64 stackOfBits);
41static void traverse(unsigned int options,
42                     io_name_t plane, io_iterator_t services,
43                     io_registry_entry_t first,
44                     int depth, UInt64 stackOfBits);
45
46enum {
47    kDoPropsOption = 1,
48    kDoRootOption  = 2
49};
50
51int main(int argc, char **argv)
52{
53    io_registry_entry_t	root;
54    char *		plane;
55    unsigned int	options;
56    kern_return_t 	status;   ///na
57    int			arg;
58
59    // Parse args
60
61    plane = kIOServicePlane;
62    options = kDoPropsOption;
63    for(arg = 1; arg < argc; arg++)
64    {
65	if ('-' == argv[arg][0]) switch(argv[arg][1])
66	{
67	    case 'h':
68		printf("%s [-p] [-r] [-h] [plane]\n", argv[0]);
69		exit(0);
70		break;
71	    case 'p':
72		options &= ~kDoPropsOption;
73		break;
74	    case 'r':
75		options |= kDoRootOption;
76		break;
77	}
78	else
79	{
80            plane = argv[arg];
81	}
82    }
83
84    // Obtain the I/O Kit communication handle.
85
86//    status = IOGetMasterPort(&masterPort);
87    status = IOMasterPort(bootstrap_port, &masterPort);
88    assert(status == KERN_SUCCESS);
89
90    // Obtain the registry root entry.
91
92    root = IORegistryGetRootEntry(masterPort);
93    assert(root);
94
95    // Traverse below the root in the plane.
96
97    traverse(options, plane, 0, root, 0, 0);
98
99    // Quit.
100
101    exit(0);
102}
103
104void traverse(unsigned int options,
105	      io_name_t plane, io_iterator_t services,
106	      io_registry_entry_t serviceUpNext,
107	      int depth, UInt64 stackOfBits)
108{
109    io_registry_entry_t service;                                ///ok
110    Boolean		doProps;
111
112    // We loop for every service in the list of services provided.
113
114    while ( (service = serviceUpNext) )
115    {
116        io_iterator_t		children;
117        Boolean			hasChildren;
118        io_name_t    		name;
119        kern_return_t		status;
120	io_registry_entry_t	child;
121	int			busy;
122
123        // Obtain the next service entry, if any.
124
125        serviceUpNext = IOIteratorNext(services);
126
127        // Obtain the current service entry's children, if any.
128
129        status = IORegistryEntryGetChildIterator(service,
130                                                 plane,
131                                                 &children);
132        assert(status == KERN_SUCCESS);
133
134        child = IOIteratorNext(children); ///ok
135        hasChildren = child ? true : false;
136
137        // Save has-more-siblings state into stackOfBits for this depth.
138
139        if (serviceUpNext)
140            stackOfBits |=  (1 << depth);
141        else
142            stackOfBits &= ~(1 << depth);
143
144        // Save has-children state into stackOfBits for this depth.
145
146        if (hasChildren)
147            stackOfBits |=  (2 << depth);
148        else
149            stackOfBits &= ~(2 << depth);
150
151        indent(true, depth, stackOfBits);
152
153        // Print out the name of the service.
154
155        status = IORegistryEntryGetName(service, name);
156        assert(status == KERN_SUCCESS);
157
158        printf("%s", name);
159
160	if (strcmp("Root", name))
161            doProps = (options & kDoPropsOption) != 0;
162	else
163            doProps = (options & kDoRootOption) != 0;
164
165        // Print out the class of the service.
166
167        status = IOObjectGetClass(service, name);
168        assert(status == KERN_SUCCESS);
169        printf("  <class %s", name);
170
171	status = IOServiceGetBusyState(service, &busy);
172	if(status == KERN_SUCCESS)
173            printf(", busy %d", busy);
174
175        // Print out the retain count of the service.
176
177        printf(", retain count %d>\n", IOObjectGetRetainCount(service));
178
179        // Print out the properties of the service.
180
181	if (doProps)
182            properties(service, depth, stackOfBits);
183
184        // Recurse down.
185
186	traverse(options, plane, children, child, depth + 1, stackOfBits);
187
188        // Release resources.
189
190        IOObjectRelease(children); children = 0;
191        IOObjectRelease(service);  service  = 0;
192    }
193}
194
195struct indent_ctxt {
196    int depth;
197    UInt64 stackOfBits;
198};
199
200static void printCFString(CFStringRef string)
201{
202    CFIndex	len;
203    char *	buffer;
204
205    len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(string),
206	    CFStringGetSystemEncoding()) + sizeof('\0');
207    buffer = malloc(len);
208    if (buffer && CFStringGetCString(string, buffer, len,
209                                  CFStringGetSystemEncoding()) )
210	printf(buffer);
211
212    if (buffer)
213	free(buffer);
214}
215
216static void printEntry(const void *key, const void *value, void *context)
217{
218    struct indent_ctxt * ctxt = context;
219
220#if 1
221    // IOKit pretty
222    CFDataRef	data;
223
224    indent(false, ctxt->depth, ctxt->stackOfBits);
225    printf("  ");
226    printCFString( (CFStringRef)key );
227    printf(" = ");
228
229    data = IOCFSerialize((CFStringRef)value, kNilOptions);
230    if( data) {
231        if( 10000 > CFDataGetLength(data))
232            printf(CFDataGetBytePtr(data));
233        else
234            printf("<is BIG>");
235        CFRelease(data);
236    } else
237        printf("<IOCFSerialize failed>");
238    printf("\n");
239
240#else
241    // CF ugly
242    CFStringRef 	 keyStr = (CFStringRef) key;
243    CFStringRef 	 valueStr = CFCopyDescription((CFTypeRef) val);
244    CFStringRef 	 outStr;
245
246    indent(false, ctxt->depth, ctxt->stackOfBits);
247    outStr = CFStringCreateWithFormat(kCFAllocatorDefault, 0,
248                CFSTR("  %@ = %@\n"), keyStr, valueStr);
249    assert(outStr);
250    printCFString(outStr);
251    CFRelease(valueStr);
252    CFRelease(outStr);
253#endif
254}
255
256static void properties(io_registry_entry_t service,
257                       int depth,
258                       UInt64 stackOfBits)
259{
260    CFDictionaryRef	dictionary; ///ok
261    kern_return_t	status;     ///na
262    struct indent_ctxt	context;
263
264    context.depth = depth;
265    context.stackOfBits = stackOfBits;
266
267    // Prepare to print out the service's properties.
268    indent(false, context.depth, context.stackOfBits);
269    printf("{\n");
270
271    // Obtain the service's properties.
272
273    status = IORegistryEntryCreateCFProperties(service,
274				    (CFTypeRef *) &dictionary,
275                                    kCFAllocatorDefault, kNilOptions);
276    assert( KERN_SUCCESS == status );
277    assert( CFDictionaryGetTypeID() == CFGetTypeID(dictionary));
278
279    CFDictionaryApplyFunction(dictionary,
280		(CFDictionaryApplierFunction) printEntry, &context);
281
282    CFRelease(dictionary);
283
284    indent(false, context.depth, context.stackOfBits);
285    printf("}\n");
286    indent(false, context.depth, context.stackOfBits);
287    printf("\n");
288
289}
290
291void indent(Boolean node, int depth, UInt64 stackOfBits)
292{
293    int i;
294
295    // stackOfBits representation, given current depth is n:
296    //   bit n+1             = does depth n have children?       1=yes, 0=no
297    //   bit [n, .. i .., 0] = does depth i have more siblings?  1=yes, 0=no
298
299    if (node)
300    {
301        for (i = 0; i < depth; i++)
302            printf( (stackOfBits & (1 << i)) ? "| " : "  " );
303
304        printf("+-o ");
305    }
306    else // if (!node)
307    {
308        for (i = 0; i <= depth + 1; i++)
309            printf( (stackOfBits & (1 << i)) ? "| " : "  " );
310    }
311}
312