ls.m 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. #define ARM
  2. #include <objc/runtime.h>
  3. #include <libgen.h>
  4. #include <dlfcn.h>
  5. #include <CoreFoundation/CoreFoundation.h>
  6. #ifdef ARM
  7. #include <Foundation/Foundation.h> // NSObject
  8. #endif
  9. @interface LSApplicationWorkspaceRemoteObserver : NSObject
  10. -(id)localObservers;
  11. @end
  12. @interface LSApplicationWorkspace : NSObject
  13. + (id) defaultWorkspace;
  14. @property (readonly) LSApplicationWorkspaceRemoteObserver * remoteObserver;
  15. - (BOOL) _LSPrivateSyncWithMobileInstallation;
  16. @end
  17. @interface PBAppDepot : NSObject
  18. + (id)sharedInstance;
  19. @property(retain, nonatomic) NSMutableDictionary *internalAppState;
  20. - (id)_addAppStateForIdentifier:(id)arg1;
  21. - (void)_save;
  22. - (void)_setNeedsNotifyAppStateDidChange;
  23. @end
  24. //#import "KBHelperClass.h"
  25. //
  26. // LSDTrip: A simple tool to demonstrate LaunchServices in OS X *and* iOS
  27. // -------
  28. //
  29. // Jonathan Levin, http://NeWOSXBook.com - @Morpheus______/@TechnoloGeeks
  30. //
  31. // License: free, but if you GitHub it or mod it, at least leave a mention.
  32. // And maybe get the book when it's finally out :-)
  33. //
  34. // Compile: gcc ls.m -o lsdtrip -lobjc -framework Foundation
  35. // or
  36. // gcc-iphone -DARM ls.m -o lsdtrip -lobjc -framework Foundation -framework MobileCoreServices
  37. //
  38. // (that "MobileCoreServices" is required for the dlopen(3) to work)
  39. //
  40. //
  41. // To run:
  42. // Usage: ls [apps|plugins|publicurls|privateurls] [-v]
  43. // whohas _url_
  44. // types
  45. // dump <<-- Try this
  46. //
  47. // Explanation:
  48. //
  49. // Shows what are (IMHO) the most useful of the LaunchServices APIs, as exported by
  50. // [Mobile]CoreServices. In iOS most of the good stuff isn't exported (t), instead wrapped
  51. // by LSApplicationWorkSpace, LSApplicationProxy, and friends. Even though the straight LS
  52. // and _LS calls are much nicer, I chose to use objective-C here in order to maintain
  53. // write-once-run-everywhere, and demonstrate yet again just how OS X and iOS really are
  54. // so similar.
  55. //
  56. // How this works:
  57. //
  58. // Over rather nice XPC to lsd (10.11/9.0) and friends. Full explanation in MOXiI 2.
  59. // (Chapter 5, "Promenade, A Tour of the OS X and iOS Frameworks", to be exact, where
  60. // many more "private" frameworks are exposed). But since I'm running behind with it,
  61. // I thought people would appreciate a hands-on preview :-) This is just one of the many
  62. // open source examples I have planned.
  63. //
  64. // PLEASE BE PATIENT. This should give you an idea of why MOXiI is delayed. At least I try
  65. // to keep everyone updated and drop examples along the way. And there's plenty more where
  66. // this came from. Just wait.
  67. //
  68. //
  69. // Improvements:
  70. //
  71. // - Can be made into pure C (i.e. not objective-C, .m), but that would make
  72. // the already ugly [] syntax even worse..
  73. //
  74. // - There's a whole undocumented side to LaunchServices (even as an allegedly
  75. // "public" framework that it is) one can add here. And I left the other
  76. // methods out in an #if 0 block, for future use.
  77. //
  78. // - The UUIDs aren't actually CFUUIDs. They're some $%#$%#$ NS...UUID, which
  79. // isn't compatible, so the UUIDs come with some 0s at the end. Meh.
  80. //
  81. // Ok. Let's begin:
  82. // My own prototypes and globals:
  83. CFStringRef dumpApp (NSObject *AppRef, int Verbose) ;
  84. NSObject * workspace; // Intentionally void * so as to NOT involve @interface files
  85. // OS X and iOS APIs are virtually identical, but the framework name is different
  86. #ifdef ARM
  87. #define CORE_SERVICE_FRAMEWORK "/System/Library/Frameworks/MobileCoreServices.framework/MobileCoreServices"
  88. #else
  89. #define CORE_SERVICE_FRAMEWORK "/System/Library/Frameworks/CoreServices.framework/CoreServices"
  90. #endif
  91. CFStringRef
  92. serializeCFArrayToCFString (CFArrayRef Array, CFStringRef Delimiter)
  93. {
  94. if (!Array) { return (CFSTR("(null)"));}
  95. CFMutableStringRef returned = CFStringCreateMutable(kCFAllocatorDefault, // CFAllocatorRef alloc,
  96. 4096); //CFIndex maxLength);
  97. int len = CFArrayGetCount(Array);
  98. int i = 0;
  99. for (i = 0; i < len ; i++)
  100. {
  101. CFTypeRef val = (CFTypeRef) CFArrayGetValueAtIndex(Array, i);
  102. if (i > 0) CFStringAppend(returned, Delimiter);
  103. // UGLY, I know. But PoC, people. PoC
  104. if (CFGetTypeID(val) == CFStringGetTypeID()) CFStringAppend(returned, val);
  105. else
  106. if (CFGetTypeID(val) == CFUUIDGetTypeID()){
  107. CFStringRef UUID = CFUUIDCreateString(kCFAllocatorDefault, val);
  108. CFStringAppend(returned, UUID);
  109. }
  110. else {
  111. CFStringAppend(returned, dumpApp (val, 0));
  112. };
  113. }
  114. return (returned);
  115. } // serializeCFArrayToCFstring
  116. CFStringRef
  117. dumpApp (NSObject *AppRef, int Verbose)
  118. {
  119. // App is an LSApplicationProxy object
  120. CFStringRef appID = (CFStringRef) [AppRef performSelector:@selector( applicationIdentifier)];
  121. CFStringRef appName = (CFStringRef)[AppRef performSelector:@selector(localizedName)];
  122. if (!appName) { appName = CFSTR("Not Set");}
  123. CFMutableStringRef out = CFStringCreateMutable(kCFAllocatorDefault, // CFAllocatorRef alloc,
  124. 4096); //CFIndex maxLength);
  125. CFStringAppendFormat(out, // CFMutableStringRef theString,
  126. NULL, // CFDictionaryRef formatOptions,
  127. CFSTR("\t%@ (%@)\n"),
  128. appName, appID);
  129. #if 0
  130. // Can also use objective-C to enumerate ivars..
  131. unsigned int ivarCount;
  132. Ivar *ivars = class_copyIvarList([AppRef class], &ivarCount);
  133. int i = 0;
  134. for (i = 0; i < ivarCount; i++)
  135. {
  136. fprintf(stderr,"\t%s: \n" , ivar_getName(ivars[i]));
  137. // etc.
  138. }
  139. #endif
  140. if (Verbose)
  141. {
  142. // Dump more
  143. CFStringAppendFormat(out, // CFMutableStringRef theString,
  144. NULL, // CFDictionaryRef formatOptions,
  145. CFSTR("\t\tExecutable: %@\n"),
  146. [AppRef performSelector:@selector(bundleExecutable)]);
  147. #ifdef ARM
  148. // Set on iOS. Can also use versionIdentifier here, but that requires working back from the
  149. // number to a version string (which LaunchServices lets you do with
  150. // LSVersionNumberCopyStringRepresentation/LSVersionNumberGetXXX()
  151. // But why bother when you have a short version string..
  152. CFStringAppendFormat(out, // CFMutableStringRef theString,
  153. NULL, // CFDictionaryRef formatOptions,
  154. CFSTR("\t\tVersion: %@\n"),
  155. (CFStringRef)[AppRef performSelector:@selector(shortVersionString)]);
  156. #endif
  157. // This is apparently unset..
  158. CFStringAppendFormat(out, // CFMutableStringRef theString,
  159. NULL, // CFDictionaryRef formatOptions,
  160. CFSTR("\t\tVendor Name: %@\n"),
  161. (CFStringRef)[AppRef performSelector:@selector(vendorName)]);
  162. CFStringAppendFormat(out, // CFMutableStringRef theString,
  163. NULL, // CFDictionaryRef formatOptions,
  164. CFSTR("\t\tMach-O UUIDs: %@\n"),
  165. serializeCFArrayToCFString((CFArrayRef)[AppRef performSelector:@selector(machOUUIDs)], CFSTR(",")));
  166. CFStringAppendFormat(out, // CFMutableStringRef theString,
  167. NULL, // CFDictionaryRef formatOptions,
  168. CFSTR("\t\tDisk Usage (Static): %@\n"),
  169. (CFStringRef)[AppRef performSelector:@selector(staticDiskUsage)]);
  170. #if 0
  171. // This apparently doesn't work in 9.2 anymore. Not sure about this..
  172. CFStringAppendFormat(out, // CFMutableStringRef theString,
  173. NULL, // CFDictionaryRef formatOptions,
  174. CFSTR("\t\tDisk Usage (Dynamic): %@\n"),
  175. (CFStringRef)[AppRef performSelector:@selector(dynamicDiskUsage)]);
  176. #endif
  177. CFArrayRef UIBackgroundModes = (CFArrayRef) [AppRef performSelector: @selector(UIBackgroundModes)];
  178. // This is a CFArray
  179. if (!CFArrayGetCount(UIBackgroundModes)) {
  180. CFStringAppend (out,CFSTR("\t\tno BackgroundModes"));
  181. }
  182. else
  183. CFStringAppendFormat(out, // CFMutableStringRef theString,
  184. NULL, // CFDictionaryRef formatOptions,
  185. CFSTR("\t\t BackgroundModes: %@"),
  186. serializeCFArrayToCFString((CFArrayRef)UIBackgroundModes, CFSTR(",")));
  187. CFStringAppend(out, CFSTR("\n"));
  188. #ifdef ARM
  189. // Only on iOS
  190. CFStringAppendFormat(out, // CFMutableStringRef theString,
  191. NULL, // CFDictionaryRef formatOptions,
  192. CFSTR("\t\tApplication DSID: %@\n"),
  193. (CFStringRef)[AppRef performSelector:@selector(applicationDSID)]);
  194. CFStringAppendFormat(out, // CFMutableStringRef theString,
  195. NULL, // CFDictionaryRef formatOptions,
  196. CFSTR("\t\tPurchaser DSID: %@\n"),
  197. (CFStringRef)[AppRef performSelector:@selector(purchaserDSID)]);
  198. CFStringAppendFormat(out, // CFMutableStringRef theString,
  199. NULL, // CFDictionaryRef formatOptions,
  200. CFSTR("\t\tDownloader DSID: %@\n"),
  201. (CFStringRef)[AppRef performSelector:@selector(downloaderDSID)]);
  202. #endif
  203. #if 0
  204. uint64_t modTime = (uint64_t)([AppRef performSelector:@selector( bundleModTime)]);
  205. fprintf(stderr, "\t\tBundle Mod Time: %llu\n", modTime);
  206. #endif
  207. int cont = (int)([AppRef performSelector:@selector( isContainerized)]);
  208. int restricted = (int)([AppRef performSelector:@selector( isRestricted)]);
  209. CFStringAppendFormat(out,
  210. NULL,
  211. CFSTR("\t\tContainerized: %@\n\t\tRestricted: %@\n"),
  212. (cont ? CFSTR("YES (q.v. App-Store Receipt URL for container)") : CFSTR("NO")),
  213. (restricted ? CFSTR("YES") : CFSTR("NO")));
  214. CFStringAppendFormat(out, // CFMutableStringRef theString,
  215. NULL, // CFDictionaryRef formatOptions,
  216. CFSTR("\t\tApp Store Receipt URL: %@\n"),
  217. (CFStringRef)[AppRef performSelector:@selector( appStoreReceiptURL)]);
  218. // These are from LSBundleProxy, which is the parent of LSApplicationProxy
  219. CFStringAppendFormat(out, // CFMutableStringRef theString,
  220. NULL, // CFDictionaryRef formatOptions,
  221. CFSTR("\t\tContainer URL: %@\n"),
  222. [AppRef performSelector:@selector(containerURL)]);
  223. CFDictionaryRef entitlements = (CFDictionaryRef) [AppRef performSelector:@selector(entitlements)];
  224. if (entitlements && CFDictionaryGetCount(entitlements) )
  225. {
  226. CFDataRef xml = CFPropertyListCreateXMLData(kCFAllocatorDefault,
  227. (CFPropertyListRef)entitlements);
  228. CFStringRef xmlAsString = CFStringCreateFromExternalRepresentation(NULL, xml, kCFStringEncodingUTF8);
  229. if (xmlAsString) {
  230. CFStringAppendFormat(out, // CFMutableStringRef theString,
  231. NULL, // CFDictionaryRef formatOptions,
  232. CFSTR("\t\tEntitlements:\n-----\n %@\n-----\n"),
  233. xmlAsString);
  234. }
  235. else { CFStringAppend (out, CFSTR("\t\tEntitlements: Internal error\n"));}
  236. } // entitlements
  237. else
  238. CFStringAppend(out,CFSTR("\t\tEntitlements: None\n"));
  239. } // Verbose
  240. return (out);
  241. }
  242. /*
  243. *
  244. Soooo much more, courtesy of JTool:
  245. -[LSApplicationProxy applicationIdentifier]:
  246. -[LSApplicationProxy roleIdentifier]:
  247. -[LSApplicationProxy bundleModTime]:
  248. -[LSApplicationProxy registeredDate]:
  249. -[LSApplicationProxy deviceFamily]:
  250. -[LSApplicationProxy minimumSystemVersion]:
  251. -[LSApplicationProxy sdkVersion]:
  252. -[LSApplicationProxy applicationType]:
  253. -[LSApplicationProxy itemName]:
  254. -[LSApplicationProxy sourceAppIdentifier]:
  255. -[LSApplicationProxy companionApplicationIdentifier]:
  256. -[LSApplicationProxy applicationVariant]:
  257. -[LSApplicationProxy storeCohortMetadata]:
  258. -[LSApplicationProxy shortVersionString]:
  259. -[LSApplicationProxy preferredArchitecture]:
  260. -[LSApplicationProxy familyID]:
  261. -[LSApplicationProxy groupContainers]:
  262. -[LSApplicationProxy directionsModes]:
  263. -[LSApplicationProxy UIBackgroundModes]:
  264. -[LSApplicationProxy audioComponents]:
  265. -[LSApplicationProxy externalAccessoryProtocols]:
  266. -[LSApplicationProxy VPNPlugins]:
  267. -[LSApplicationProxy plugInKitPlugins]:
  268. -[LSApplicationProxy appTags]:
  269. -[LSApplicationProxy requiredDeviceCapabilities]:
  270. -[LSApplicationProxy deviceIdentifierForVendor]:
  271. -[LSApplicationProxy ODRDiskUsage]:
  272. -[LSApplicationProxy storeFront]:
  273. -[LSApplicationProxy externalVersionIdentifier]:
  274. -[LSApplicationProxy betaExternalVersionIdentifier]:
  275. -[LSApplicationProxy appStoreReceiptURL]:
  276. -[LSApplicationProxy installProgress]:
  277. -[LSApplicationProxy installProgressSync]:
  278. -[LSApplicationProxy resourcesDirectoryURL]:
  279. -[LSApplicationProxy privateDocumentIconNames]:
  280. -[LSApplicationProxy setPrivateDocumentIconNames:]:
  281. -[LSApplicationProxy privateIconsDictionary]:
  282. -[LSApplicationProxy privateDocumentIconAllowOverride]:
  283. -[LSApplicationProxy setPrivateDocumentIconAllowOverride:]:
  284. -[LSApplicationProxy iconDataForVariant:]:
  285. -[LSApplicationProxy privateDocumentTypeOwner]:
  286. -[LSApplicationProxy setPrivateDocumentTypeOwner:]:
  287. -[LSApplicationProxy localizedName]:
  288. -[LSApplicationProxy localizedShortName]:
  289. -[LSApplicationProxy localizedNameForContext:]:
  290. -[LSApplicationProxy iconIsPrerendered]:
  291. -[LSApplicationProxy fileSharingEnabled]:
  292. -[LSApplicationProxy profileValidated]:
  293. -[LSApplicationProxy isAdHocCodeSigned]:
  294. -[LSApplicationProxy isPlaceholder]:
  295. -[LSApplicationProxy isAppUpdate]:
  296. -[LSApplicationProxy isNewsstandApp]:
  297. -[LSApplicationProxy isRestricted]:
  298. -[LSApplicationProxy supportsAudiobooks]:
  299. -[LSApplicationProxy supportsExternallyPlayableContent]:
  300. -[LSApplicationProxy supportsOpenInPlace]:
  301. -[LSApplicationProxy hasSettingsBundle]:
  302. -[LSApplicationProxy isInstalled]:
  303. -[LSApplicationProxy isWhitelisted]:
  304. -[LSApplicationProxy isBetaApp]:
  305. -[LSApplicationProxy isPurchasedReDownload]:
  306. -[LSApplicationProxy isWatchKitApp]:
  307. -[LSApplicationProxy hasMIDBasedSINF]:
  308. -[LSApplicationProxy missingRequiredSINF]:
  309. -[LSApplicationProxy isEqual:]:
  310. -[LSApplicationProxy hash]:
  311. -[LSApplicationProxy description]:
  312. -[LSApplicationProxy iconStyleDomain]:
  313. -[LSApplicationProxy userActivityStringForAdvertisementData:]:
  314. -[LSApplicationProxy populateNotificationData]:
  315. -[LSApplicationProxy itemID]:
  316. -[LSApplicationProxy installType]:
  317. -[LSApplicationProxy originalInstallType]:
  318. -[LSApplicationProxy groupIdentifiers]:
  319. -[LSApplicationProxy teamID]:
  320. -[LSApplicationProxy isContainerized]:
  321. */
  322. void
  323. dumpURL (CFStringRef URL, int Verbose)
  324. {
  325. CFMutableStringRef out = CFStringCreateMutable(kCFAllocatorDefault, // CFAllocatorRef alloc,
  326. 4096); //CFIndex maxLength);
  327. CFStringAppend(out, URL);
  328. if (Verbose) {
  329. CFArrayRef appsForURL = (CFArrayRef) [workspace performSelector:@selector(applicationsAvailableForHandlingURLScheme:) withObject:(id)URL];
  330. // This is a CFArray
  331. if (CFGetTypeID(appsForURL) != CFArrayGetTypeID())
  332. {
  333. fprintf(stderr, "Was expecting a CFArray of Apps!\n");
  334. exit(2);
  335. }
  336. if (!CFArrayGetCount (appsForURL)) CFStringAppend(out,CFSTR(" - Not claimed by anyone"));
  337. else {
  338. CFStringRef apps = serializeCFArrayToCFString (appsForURL, CFSTR("\n\t\t\t"));
  339. CFStringAppend (out, apps);
  340. CFRelease (apps);
  341. }
  342. }
  343. CFShow(out);
  344. CFRelease(out);
  345. }
  346. void
  347. dumpPlugin (NSObject *PluginRef, int Verbose)
  348. {
  349. CFStringRef pluginName = (CFStringRef) [PluginRef performSelector:@selector( localizedName)];
  350. CFStringRef pluginID = (CFStringRef) [PluginRef performSelector:@selector( pluginIdentifier)];
  351. CFUUIDRef pluginUUID = (CFUUIDRef)[PluginRef performSelector:@selector(pluginUUID)];
  352. CFStringRef out = CFStringCreateWithFormat(kCFAllocatorDefault,
  353. NULL, CFSTR("\t%@ (%@) - %@"),
  354. pluginName,pluginID, CFUUIDCreateString(kCFAllocatorDefault, pluginUUID));
  355. CFShow(out);
  356. } // end Dump
  357. int
  358. main (int argc, char **argv)
  359. {
  360. int verbose = 0;
  361. // So - why dup? because CFShow(), which I use extensively, write to stderr.
  362. // And I really CANNOT stand the whole CFStringToCstr $%#$%#$ just to get a stupid
  363. // printout! So instead, I save stderr, and then reopen stderr to stdout. This
  364. // way, the output can be grep(1)-ed easily.
  365. dup2(2,3);
  366. dup2(1,2);
  367. if (argc < 2)
  368. {
  369. fprintf(stderr, "Usage: %s [apps|plugins|publicurls|privateurls] [-v]\n", basename(argv[0]));
  370. fprintf(stderr, " app _bundle_id_ (implies -v for this app)\n");
  371. #ifdef ARM
  372. fprintf(stderr, " launch _bundle_id_\n");
  373. #endif
  374. fprintf(stderr, " whohas _url_ \n");
  375. fprintf(stderr, " types\n");
  376. fprintf(stderr, " dump\n");
  377. exit(0);
  378. }
  379. if (argv[2] && strcmp(argv[2], "-v")==0) verbose++;
  380. // Getting the LS* classes and functions we need here:
  381. // ---------------------------------------------------
  382. Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
  383. if (!LSApplicationWorkspace_class) {fprintf(stderr,"Unable to get Workspace class\n"); exit(1);}
  384. workspace = [LSApplicationWorkspace_class performSelector:@selector (defaultWorkspace)];
  385. if (!workspace) {fprintf(stderr,"Unable to get Workspace\n"); exit(2);}
  386. NSLog(@"workspace: %@", workspace);
  387. LSApplicationWorkspaceRemoteObserver *observer = [workspace remoteObserver];
  388. NSArray *localObservers = [observer localObservers];
  389. NSLog(@"local observers: %@", localObservers);
  390. // KBHelperClass *helperClass = [KBHelperClass new];
  391. //[helperClass doMagic];
  392. void *CS_handle = dlopen (CORE_SERVICE_FRAMEWORK, RTLD_NOW);
  393. if (!CS_handle) { fprintf(stderr,"Can't find %s!\n", CORE_SERVICE_FRAMEWORK); exit(2); };
  394. if (strncmp(argv[1], "app",3) == 0)
  395. {
  396. CFStringRef wantedBundleID = NULL;
  397. if (strcmp(argv[1], "apps")) // that is, not all apps
  398. {
  399. // expecting a bundle identifier here
  400. if (!argv[2]) { fprintf(stderr,"app option requires a specific bundle id. Try 'apps' to get a list\n");
  401. exit(5); }
  402. wantedBundleID = CFStringCreateWithCString(kCFAllocatorDefault, // CFAllocatorRef alloc,
  403. argv[2], // const char *cStr,
  404. kCFStringEncodingUTF8); //CFStringEncoding encoding);
  405. }
  406. CFArrayRef apps = (CFArrayRef) [workspace performSelector:@selector(allApplications)];
  407. // This is a CFArray
  408. if (CFGetTypeID(apps) != CFArrayGetTypeID())
  409. {
  410. fprintf(stderr, "Was expecting a CFArray of Apps!\n");
  411. exit(2);
  412. }
  413. int len = CFArrayGetCount(apps);
  414. int i = 0;
  415. for (i = 0; i < len ; i++)
  416. {
  417. CFTypeRef app = CFArrayGetValueAtIndex(apps,i);
  418. // Got app: Dump if want all, or if matches id.
  419. // I'm sure there's some Workspace method I missed to get an app by bundle ID, instead
  420. // of iterating over all of them..
  421. CFStringRef appID = (CFStringRef) [(id)app performSelector:@selector(applicationIdentifier)];
  422. if (appID && wantedBundleID)
  423. {
  424. if (CFEqual(appID, wantedBundleID))
  425. {
  426. CFStringRef dump = dumpApp(app, 1);
  427. CFShow(dump);
  428. CFRelease(dump);
  429. exit(0); // only one match here.
  430. }
  431. }
  432. else
  433. {
  434. CFStringRef dump = dumpApp(app, verbose);
  435. CFShow(dump);
  436. CFRelease(dump);
  437. }
  438. }
  439. if ( wantedBundleID) {
  440. fprintf(stderr,"Application with Bundle ID %s not found. Try '%s apps' first, and remember case-sensitivity\n",
  441. argv[2], argv[0]);
  442. exit(2);
  443. }
  444. exit(0);
  445. }
  446. if (strcmp(argv[1], "publicurls") == 0)
  447. {
  448. CFArrayRef puburls = (CFArrayRef) [workspace performSelector:@selector(publicURLSchemes)];
  449. // This is a CFArray
  450. if (CFGetTypeID(puburls) != CFArrayGetTypeID())
  451. {
  452. fprintf(stderr, "Was expecting a CFArray of publicURLSchemes!\n");
  453. exit(2);
  454. }
  455. int len = CFArrayGetCount(puburls);
  456. int i = 0;
  457. for (i = 0; i < len ; i++)
  458. {
  459. CFStringRef url = CFArrayGetValueAtIndex(puburls,i);
  460. dumpURL(url, verbose);
  461. }
  462. exit(0);
  463. }
  464. if (strcmp(argv[1], "privateurls") == 0)
  465. {
  466. CFArrayRef (privurls) = (CFArrayRef) [workspace performSelector:@selector(privateURLSchemes)];
  467. // This is a CFArray
  468. if (CFGetTypeID(privurls) != CFArrayGetTypeID())
  469. {
  470. fprintf(stderr, "Was expecting a CFArray of privateURLSchemes!\n");
  471. exit(2);
  472. }
  473. int len = CFArrayGetCount(privurls);
  474. int i = 0;
  475. for (i = 0; i < len ; i++)
  476. {
  477. CFStringRef url = CFArrayGetValueAtIndex(privurls,i);
  478. dumpURL(url, verbose);
  479. }
  480. exit(0);
  481. }
  482. if (strcmp(argv[1], "plugins") == 0)
  483. {
  484. CFArrayRef plugins = (CFArrayRef) [workspace performSelector:@selector(installedPlugins)];
  485. // This, too, is a CFArray
  486. if (CFGetTypeID(plugins) != CFArrayGetTypeID())
  487. {
  488. fprintf(stderr, "Was expecting a CFArray of plugins!\n");
  489. exit(2);
  490. }
  491. int len = CFArrayGetCount(plugins);
  492. int i = 0;
  493. for (i = 0; i < len ; i++)
  494. {
  495. CFTypeRef plugin = CFArrayGetValueAtIndex(plugins,i);
  496. dumpPlugin(plugin, verbose);
  497. }
  498. exit(0);
  499. }
  500. if (strcmp(argv[1], "types") == 0)
  501. {
  502. // I resort to dlopen/dlsym here to make linking simpler. You don't have to.
  503. typedef CFArrayRef (*UTCopyDeclaredTypeIdentifiersFunc)(void);
  504. UTCopyDeclaredTypeIdentifiersFunc UTCopyDeclaredTypeIdentifiers
  505. = dlsym (CS_handle, "_UTCopyDeclaredTypeIdentifiers");
  506. CFArrayRef utis = UTCopyDeclaredTypeIdentifiers();
  507. // As usual, this is an array..
  508. int len = CFArrayGetCount(utis);
  509. int i = 0;
  510. for (i = 0; i < len ; i++)
  511. {
  512. // Seriously, AAPL - couldn't you find a better acronym?
  513. CFTypeRef uti = CFArrayGetValueAtIndex(utis,i);
  514. CFShow(uti);
  515. }
  516. exit(0);
  517. }
  518. if (strcmp(argv[1], "whohas") == 0)
  519. {
  520. if (!argv[2]) {
  521. fprintf(stderr,"whohas: Option requires an URL Scheme or UTI as an argument!\n");
  522. exit(3);
  523. }
  524. CFStringRef url = CFStringCreateWithCString(kCFAllocatorDefault, // CFAllocatorRef alloc,
  525. argv[2], // const char *cStr,
  526. kCFStringEncodingUTF8); //CFStringEncoding encoding);
  527. dumpURL(url,1);
  528. exit(0);
  529. }
  530. #if 0
  531. // ignore this part for now
  532. if (strcmp(argv[1],"claims") == 0)
  533. {
  534. typedef CFStringRef (*LSCopyClaimedActivityIdentifiersAndDomainsFunc)(CFStringRef, CFStringRef);
  535. LSCopyClaimedActivityIdentifiersAndDomainsFunc
  536. LSCopyClaimedActivityIdentifiersAndDomains = dlsym (CS_handle, "_LSCopyClaimedActivityIdentifiersAndDomains");
  537. if (!LSCopyClaimedActivityIdentifiersAndDomains )
  538. {
  539. fprintf(stderr,"Unable to find LSCopyClaimedActivityIdentifiersAndDomains ");
  540. exit(3);
  541. }
  542. CFStringRef result = LSCopyClaimedActivityIdentifiersAndDomains (NULL, NULL);
  543. CFShow(result);
  544. exit(0);
  545. }
  546. #endif
  547. if (strcmp(argv[1],"launch") == 0)
  548. {
  549. if (!argv[2]) {
  550. fprintf(stderr,"launch: Option requires an argument!\n"); exit(3);
  551. }
  552. CFStringRef bundleID = CFStringCreateWithCString(kCFAllocatorDefault, // CFAllocatorRef alloc,
  553. argv[2], // const char *cStr,
  554. kCFStringEncodingUTF8); //CFStringEncoding encoding);
  555. int t = (int) [workspace performSelector:@selector(openApplicationWithBundleID:) withObject:(id) bundleID ];
  556. fprintf(stderr, "%s %s\n",
  557. t ? "Launched" : "Unable to launch",
  558. argv[2]);
  559. exit(0);
  560. }
  561. // And this is the real fun part:
  562. //
  563. // The little known "lsregister" utility in OS X is closed source, and un-man(1)ned,
  564. // But one of its coolest features is "dump" - to dump the LaunchServices Database.
  565. // Turns out this is a *single* line of code. And guess what -- it works on iOS too :-)
  566. //
  567. if (strcmp(argv[1], "dump") == 0)
  568. {
  569. typedef void (*LSDisplayDataFunc)(char *);
  570. LSDisplayDataFunc LSDisplayData;
  571. // If you want to get the raw format of the file, you can dump with this, instead:
  572. //extern _LSDisplayRawStoreData(char *, int);
  573. //_LSDisplayRawStoreData("/var/mobile/Library/Caches/com.apple.LaunchServices-134.csstore", (void *) 0xff);
  574. LSDisplayData = dlsym (CS_handle, "_LSDisplayData");
  575. if (!LSDisplayData) { fprintf(stderr, "Can't find LSDisplayData! Has Apple removed it by now? :-P"); exit(1);}
  576. // The argument expected here is the name of the CoreServices (LaunchServices)
  577. // DataStore - in iOS "/var/mobile/Library/Caches/com.apple.LaunchServices-###.csstore"
  578. // but turns out NULL works on both OS X and iOS!
  579. LSDisplayData("/private/var/containers/Data/System/97D6E4BA-C0BF-408B-AF63-1836844381AE/Library/Caches/com.apple.LaunchServices-175-v2.csstore");
  580. exit(0);
  581. }
  582. }