summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Bingner <sam@bingner.com>2021-04-14 11:03:43 -1000
committerSam Bingner <sam@bingner.com>2021-04-14 11:09:28 -1000
commita54c077e0c76bbbc690743c45ba116061d9add58 (patch)
tree71e3e0ee0e5597a72b04019abf1c5d3f8c30d748
parent01e601c82db4ca5c8fa998d78b5250936942b240 (diff)
Better support for some older iOS versions
-rw-r--r--uicache.mm154
1 files changed, 84 insertions, 70 deletions
diff --git a/uicache.mm b/uicache.mm
index 7e4c830..31a6139 100644
--- a/uicache.mm
+++ b/uicache.mm
@@ -131,6 +131,7 @@
-(NSString*)applicationIdentifier;
-(_LSApplicationState*)appState;
-(NSURL*)bundleURL;
+-(NSURL*)resourcesDirectoryURL;
-(NSURL*)containerURL;
-(NSDate*)registeredDate;
@end
@@ -168,6 +169,12 @@ typedef enum {
+(id)actionWithReason:(id)reason options:(int64_t)options targetURL:(NSURL*)url;
@end
+@implementation LSApplicationProxy (uicache)
+-(NSURL*)appURL {
+ return [self respondsToSelector:@selector(bundleURL)]?[self bundleURL]:[self resourcesDirectoryURL];
+}
+@end
+
static int verbose=0;
static int standard_uicache(void);
static Class $MCMPluginKitPluginDataContainer;
@@ -192,25 +199,11 @@ NSArray *getAllApplications()
return [NSArray array];
}
-const char *getFileSystemRepresentation(NSURL *url)
-{
- if ([url respondsToSelector:@selector(fileSystemRepresentation)])
- return [url fileSystemRepresentation];
- void *buffer = malloc(0x400);
- if (buffer) {
- UInt8 *data = (UInt8 *)[NSData dataWithBytesNoCopy:buffer length:0x400].bytes;
- if (CFURLGetFileSystemRepresentation((__bridge CFURLRef)url, true, data, 0x400))
- return (const char *)buffer;
- free(buffer);
- }
- return "";
-}
-
int list_all_apps(void)
{
NSArray *allApps = getAllApplications();
for (LSApplicationProxy *app in allApps) {
- printf("%s : %s\n", [[app applicationIdentifier] UTF8String], getFileSystemRepresentation([app bundleURL]));
+ printf("%s : %s\n", app.applicationIdentifier.UTF8String, app.appURL.path.UTF8String);
}
return 0;
}
@@ -232,20 +225,26 @@ int list_app(NSString *appid) {
printf("Information for %s\n", appid.UTF8String);
if (hasAppState)
printf("State: %s\n", [[appState description] UTF8String]);
- printf("Path: %s\n", getFileSystemRepresentation([app bundleURL]));
- printf("Container Path: %s\n", getFileSystemRepresentation([app containerURL]));
+ printf("Path: %s\n", app.appURL.path.UTF8String);
+ printf("Container Path: %s\n", app.containerURL.path.UTF8String);
return 0;
}
+NSString *pathInApplications(NSString *path) {
+ NSArray *pathComponents = [path pathComponents];
+ if ([path hasPrefix:@"/Applications/"]) {
+ return [NSString pathWithComponents:[pathComponents subarrayWithRange:NSMakeRange(0, 3)]];
+ } else if ([path hasPrefix:@"/var/stash"] && [pathComponents[4] isEqualToString:@"Applications"]) {
+ // Matches /var/stash/*/Applications/
+ return [@"/Applications/" stringByAppendingPathComponent:pathComponents[5]];
+ }
+ return nil;
+}
+
NSString *getAppPath(NSString *path)
{
if (force) return path;
- path = [path stringByResolvingSymlinksInPath];
- if (![path hasPrefix:@"/Applications/"]) {
- fprintf(stderr, "Error: Path must be within /Applications/\n");
- return nil;
- }
- return [NSString pathWithComponents:[[path pathComponents] subarrayWithRange:NSMakeRange(0, 3)]];
+ return pathInApplications(path);;
}
bool appIsRegistered(NSString *path)
@@ -253,9 +252,9 @@ bool appIsRegistered(NSString *path)
if (force) return true;
@autoreleasepool {
path = getAppPath(path);
- if (!path) return false;
for (LSApplicationProxy *app in getAllApplications()) {
- if ([path isEqualToString:[[app bundleURL] path]]) return true;
+ NSString *appPath = getAppPath(app.appURL.path);
+ if ([path isEqualToString:appPath]) return true;
}
return false;
}
@@ -265,22 +264,24 @@ bool unregisterPath(NSString *path)
{
@autoreleasepool {
NSURL *url = nil;
- if (verbose) fprintf(stderr, "Unregistering %s\n", path.lastPathComponent.UTF8String);
if (![path hasPrefix:@"/"]) {
// Maybe it's an app_id
LSApplicationProxy *app = [LSApplicationProxy applicationProxyForIdentifier:path];
if (app) {
- url = [app bundleURL];
- if (verbose) fprintf(stderr, "Resolved bundle ID %s to path %s\n", path.UTF8String, getFileSystemRepresentation(url));
+ url = [app appURL];
+ if (verbose) fprintf(stderr, "Resolved bundle ID %s to path %s\n", path.UTF8String, url.path.UTF8String);
path = [url path];
}
} else {
path = getAppPath(path);
- if (path) {
- url = [NSURL fileURLWithPath:path];
+ if (!path) {
+ fprintf(stderr, "Error: Path \"%s\" must be within /Applications/\n", path.UTF8String);
+ return false;
}
+ url = [NSURL fileURLWithPath:path];
}
if (!url) return false;
+ if (verbose) fprintf(stderr, "Unregistering %s\n", path.lastPathComponent.UTF8String);
if (appIsRegistered(path) && ![workspace unregisterApplication:url]) {
fprintf(stderr, "Error: unregisterApplication failed for %s\n", path.lastPathComponent.UTF8String);
return false;
@@ -298,9 +299,10 @@ bool registerPath(NSString *path)
}
NSString *realPath = getAppPath(path);
if (!realPath) {
- if (verbose) fprintf(stderr, "unable to determine path for %s\n", path.UTF8String);
+ fprintf(stderr, "Error: Path \"%s\" must be within /Applications/\n", path.UTF8String);
return false;
}
+ if (verbose) fprintf(stderr, "Refreshing %s\n", realPath.lastPathComponent.UTF8String);
NSDictionary *infoDictionary = [NSDictionary dictionaryWithContentsOfFile:
[realPath stringByAppendingPathComponent:@"Info.plist"]];
NSString *bundleID = [infoDictionary objectForKey:@"CFBundleIdentifier"];
@@ -329,8 +331,8 @@ bool registerPath(NSString *path)
[NSMutableDictionary dictionary], @"_LSBundlePlugins",
nil];
- id appContainer = [$MCMAppDataContainer containerWithIdentifier:bundleID
- createIfNecessary:YES existed:NULL error:nil];
+ id appContainer = $MCMAppDataContainer?[$MCMAppDataContainer containerWithIdentifier:bundleID
+ createIfNecessary:YES existed:NULL error:nil]:nil;
NSString *appContainerPath = [[appContainer url] path];
if (appContainerPath) {
@@ -341,7 +343,7 @@ bool registerPath(NSString *path)
NSString *pluginPath = [pluginsPath stringByAppendingPathComponent:plugin];
NSString *pluginInfoPlistPath = [pluginPath stringByAppendingPathComponent:@"Info.plist"];
NSString *pluginBundleIdentifier = [[NSDictionary dictionaryWithContentsOfFile:pluginInfoPlistPath] objectForKey:@"CFBundleIdentifier"];
- if (pluginBundleIdentifier) {
+ if ($MCMPluginKitPluginDataContainer && pluginBundleIdentifier) {
id pluginContainer = [$MCMPluginKitPluginDataContainer containerWithIdentifier:pluginBundleIdentifier
createIfNecessary:YES existed:NULL error:nil];
NSURL *pluginContainerURL = [pluginContainer url];
@@ -556,6 +558,7 @@ pid_t pidOfCydia(void) {
if (verbose) fprintf(stderr, "Found Cydia running with PID: %d\n", pid);
return false;
}
+ if (verbose>2) fprintf(stderr, "%s is not Cydia...\n", program);
}
return true;
});
@@ -566,6 +569,38 @@ pid_t pidOfCydia(void) {
return -1;
}
+bool cydiaCache(pid_t cydia_pid) {
+ // We are in cydia and trying to refresh it - this will kill it. Let's schedule it for later.
+ if (verbose) fprintf(stderr, "Waiting to refresh Cydia...\n");
+ pid_t pid = fork();
+ if (pid == 0) {
+ setpgrp();
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
+ fclose(stdin);
+ freopen("/dev/null", "a", stderr);
+ freopen("/dev/null", "a", stdout);
+ pid = fork();
+ if (pid == 0) {
+ while (kill(cydia_pid, 0)==0) {
+ sleep(1);
+ }
+ const char *uicache = (*_NSGetArgv())[0];
+ execl(uicache, uicache, "-vvvvvvv", NULL);
+ fprintf(stderr, "Unable to exec\n");
+ fflush(stderr);
+ exit(-1);
+ }
+ exit(0);
+ } else if (pid > 0) {
+ int stat;
+ waitpid(pid, &stat, 0);
+ return true;
+ }
+ fprintf(stderr, "Unable to fork\n");
+ return false;
+}
+
int optimized_uicache(void) {
__block int rv=0;
NSMutableDictionary *registered = [NSMutableDictionary new];
@@ -583,36 +618,10 @@ int optimized_uicache(void) {
}
pid_t cydia_pid;
if ([found[2] isEqualToString:@"Cydia.app"] &&
- (cydia_pid = pidOfCydia()) > 0) {
- // We are in cydia and trying to refresh it - this will kill it. Let's schedule it for later.
- if (verbose) fprintf(stderr, "Waiting to refresh Cydia...\n");
- pid_t pid = fork();
- if (pid == 0) {
- setpgrp();
- signal(SIGHUP, SIG_IGN);
- signal(SIGPIPE, SIG_IGN);
- fclose(stdin);
- freopen("/dev/null", "a", stderr);
- freopen("/dev/null", "a", stdout);
- pid = fork();
- if (pid == 0) {
- while (kill(cydia_pid, 0)==0) {
- sleep(1);
- }
- const char *uicache = (*_NSGetArgv())[0];
- execl(uicache, uicache, "-vvvvvvv", NULL);
- fprintf(stderr, "Unable to exec\n");
- fflush(stderr);
- exit(-1);
- }
- exit(0);
- } else if (pid > 0) {
- int stat;
- waitpid(pid, &stat, 0);
- return;
- } else {
- fprintf(stderr, "Unable to fork\n");
- }
+ (cydia_pid = pidOfCydia()) > 0 &&
+ cydiaCache(cydia_pid)) {
+ // Is cydia and we queued a uicache in background so skip
+ return;
}
if (!registerPath(appPath)) rv++;
}
@@ -623,13 +632,14 @@ int optimized_uicache(void) {
NSMutableArray *finds = [NSMutableArray new];
if (verbose>1) fprintf(stderr, "Enumerating apps\n");
for (LSApplicationProxy *app in getAllApplications()) {
- NSString *path = [[app bundleURL] path];
- if (![path hasPrefix:@"/Applications/"]) continue;
+ NSString *path = pathInApplications([[app appURL] path]);
+ if (!path) continue;
if (verbose>1) fprintf(stderr, "Checking %s\n", path.lastPathComponent.UTF8String);
- NSDate *lastRegistered = [app registeredDate];
if ([fm fileExistsAtPath:path]) {
+ NSDate *lastRegistered = [app registeredDate];
+ pid_t cydia_pid;
// Check for updated components
NSTask *find = [NSTask new];
[find setLaunchPath:@"/usr/bin/find"];
@@ -740,14 +750,15 @@ int main(int argc, const char *argv[])
list_apps = true;
break;
case 'p':
- paths[@(optarg)] = @YES;
+ [paths setObject:@YES forKey:@(optarg)];
have_path = true;
break;
case 'r':
respring = true;
break;
case 'u':
- unregister_paths[@(optarg)] = @YES;
+ [unregister_paths setObject:@YES forKey:@(optarg)];
+ fprintf(stderr, "%s\n", optarg);
have_path = true;
break;
case 'v':
@@ -758,6 +769,7 @@ int main(int argc, const char *argv[])
}
}
if (list_apps) {
+ if (verbose>2) fprintf(stderr, "Listing apps\n");
if (do_all || have_path || respring) {
usage();
return 1;
@@ -768,16 +780,18 @@ int main(int argc, const char *argv[])
return list_all_apps();
}
if (do_all || !$MCMPluginKitPluginDataContainer || !$MCMAppDataContainer || !$LSApplicationWorkspace) {
+ if (verbose>2) fprintf(stderr, "Using standard uicache\n");
rv = standard_uicache();
} else if (have_path) {
+ if (verbose>2) fprintf(stderr, "Using per-path uicache\n");
for (NSString *path in [paths allKeys]) {
- if (verbose) fprintf(stderr, "Refreshing %s\n", path.UTF8String);
if (!registerPath(path)) rv++;
}
for (NSString *path in [unregister_paths allKeys]) {
if (!unregisterPath(path)) rv++;
}
} else {
+ if (verbose>2) fprintf(stderr, "Using optimized uicache\n");
rv += optimized_uicache();
}
if ( respring )