1/* 2 * Copyright (c) 2009 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/* 24cc ioclasscount.c -o /tmp/ioclasscount -Wall -framework IOKit -framework CoreFoundation 25 */ 26 27#include <sysexits.h> 28 #include <malloc/malloc.h> 29#include <CoreFoundation/CoreFoundation.h> 30#include <IOKit/IOKitLib.h> 31#include <IOKit/IOKitKeys.h> 32 33/********************************************************************* 34*********************************************************************/ 35static int compareClassNames(const void * left, const void * right) 36{ 37 switch (CFStringCompare(*((CFStringRef *)left), *((CFStringRef *)right), 38 (CFStringCompareFlags)kCFCompareCaseInsensitive)) { 39 case kCFCompareLessThan: 40 return -1; 41 break; 42 case kCFCompareEqualTo: 43 return 0; 44 break; 45 case kCFCompareGreaterThan: 46 return 1; 47 break; 48 default: 49 fprintf(stderr, "fatal error\n"); 50 exit(EX_OSERR); 51 return 0; 52 break; 53 } 54} 55 56/********************************************************************* 57*********************************************************************/ 58static Boolean printInstanceCount( 59 CFDictionaryRef dict, 60 CFStringRef name, 61 char ** nameCString, 62 Boolean addNewlineFlag) 63{ 64 int result = FALSE; 65 CFIndex nameLength = 0; 66 static char * nameBuffer = NULL; // free if nameCString is NULL 67 CFNumberRef num = NULL; // do not release 68 SInt32 num32 = 0; 69 Boolean gotName = FALSE; 70 Boolean gotNum = FALSE; 71 72 nameLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(name), 73 kCFStringEncodingUTF8); 74 if (!nameCString || !*nameCString) { 75 nameBuffer = (char *)malloc((1 + nameLength) * sizeof(char)); 76 } else if ((1 + nameLength) > malloc_size(nameBuffer)) { 77 nameBuffer = (char *)realloc(*nameCString, 78 (1 + nameLength) * sizeof(char)); 79 } 80 if (nameBuffer) { 81 gotName = CFStringGetCString(name, nameBuffer, 1 + nameLength, 82 kCFStringEncodingUTF8); 83 } else { 84 fprintf(stderr, "Memory allocation failure.\n"); 85 goto finish; 86 } 87 88 /* Note that errors displaying the name and value are not considered 89 * fatal and do not affect the exit status of the program. 90 */ 91 printf("%s = ", gotName ? nameBuffer : "??"); 92 93 num = (CFNumberRef)CFDictionaryGetValue(dict, name); 94 if (num) { 95 96 if (CFNumberGetTypeID() == CFGetTypeID(num)) { 97 gotNum = CFNumberGetValue(num, kCFNumberSInt32Type, &num32); 98 } 99 if (gotNum) { 100 printf("%lu", (unsigned long)num32); 101 } else { 102 printf("?? (error reading/converting value)"); 103 } 104 } else { 105 printf("<no such class>"); 106 } 107 108 if (addNewlineFlag) { 109 printf("\n"); 110 } else { 111 printf(", "); 112 } 113 114 result = TRUE; 115 116finish: 117 if (nameCString) { 118 *nameCString = nameBuffer; 119 } else { 120 if (nameBuffer) free(nameBuffer); 121 } 122 return result; 123} 124 125/********************************************************************* 126*********************************************************************/ 127int main(int argc, char ** argv) 128{ 129 int result = EX_OSERR; 130 kern_return_t status = KERN_FAILURE; 131 io_registry_entry_t root = IO_OBJECT_NULL; // must IOObjectRelease() 132 CFMutableDictionaryRef rootProps = NULL; // must release 133 CFDictionaryRef diagnostics = NULL; // do not release 134 CFDictionaryRef classes = NULL; // do not release 135 CFStringRef * classNames = NULL; // must free 136 CFStringRef className = NULL; // must release 137 char * nameCString = NULL; // must free 138 139 // Obtain the registry root entry. 140 141 root = IORegistryGetRootEntry(kIOMasterPortDefault); 142 if (!root) { 143 fprintf(stderr, "Error: Can't get registry root.\n"); 144 goto finish; 145 } 146 147 status = IORegistryEntryCreateCFProperties(root, 148 &rootProps, kCFAllocatorDefault, kNilOptions); 149 if (KERN_SUCCESS != status) { 150 fprintf(stderr, "Error: Can't read registry root properties.\n"); 151 goto finish; 152 } 153 if (CFDictionaryGetTypeID() != CFGetTypeID(rootProps)) { 154 fprintf(stderr, "Error: Registry root properties not a dictionary.\n"); 155 goto finish; 156 } 157 158 diagnostics = (CFDictionaryRef)CFDictionaryGetValue(rootProps, 159 CFSTR(kIOKitDiagnosticsKey)); 160 if (!diagnostics) { 161 fprintf(stderr, "Error: Allocation information missing.\n"); 162 goto finish; 163 } 164 if (CFDictionaryGetTypeID() != CFGetTypeID(diagnostics)) { 165 fprintf(stderr, "Error: Allocation information not a dictionary.\n"); 166 goto finish; 167 } 168 169 classes = (CFDictionaryRef)CFDictionaryGetValue(diagnostics, CFSTR("Classes")); 170 if (!classes) { 171 fprintf(stderr, "Error: Class information missing.\n"); 172 goto finish; 173 } 174 if (CFDictionaryGetTypeID() != CFGetTypeID(classes)) { 175 fprintf(stderr, "Error: Class information not a dictionary.\n"); 176 goto finish; 177 } 178 179 if (argc < 2) { 180 CFIndex index, count; 181 182 count = CFDictionaryGetCount(classes); 183 classNames = (CFStringRef *)calloc(count, sizeof(CFStringRef)); 184 if (!classNames) { 185 fprintf(stderr, "Memory allocation failure.\n"); 186 goto finish; 187 } 188 CFDictionaryGetKeysAndValues(classes, (const void **)classNames, NULL); 189 qsort(classNames, count, sizeof(CFStringRef), &compareClassNames); 190 191 for (index = 0; index < count; index++) { 192 printInstanceCount(classes, classNames[index], &nameCString, 193 /* addNewline? */ TRUE); 194 } 195 196 } else { 197 uint32_t index = 0; 198 for (index = 1; index < argc; index++ ) { 199 200 if (className) CFRelease(className); 201 className = NULL; 202 203 className = CFStringCreateWithCString(kCFAllocatorDefault, 204 argv[index], kCFStringEncodingUTF8); 205 if (!className) { 206 fprintf(stderr, "Error: Can't create CFString for '%s'.\n", 207 argv[index]); 208 goto finish; 209 } 210 printInstanceCount(classes, className, &nameCString, 211 /* addNewline? */ (index + 1 == argc)); 212 } 213 } 214 215 result = EX_OK; 216finish: 217 if (rootProps) CFRelease(rootProps); 218 if (root != IO_OBJECT_NULL) IOObjectRelease(root); 219 if (classNames) free(classNames); 220 if (className) CFRelease(className); 221 if (nameCString) free(nameCString); 222 223 return result; 224} 225 226