+#include <sys/types.h>
+
+#include <Menes/ObjectHandle.h>
+
+void Finish(const char *finish) {
+ if (finish == NULL)
+ return;
+
+ const char *cydia(getenv("CYDIA"));
+ if (cydia == NULL)
+ return;
+
+ int fd([[[[NSString stringWithUTF8String:cydia] componentsSeparatedByString:@" "] objectAtIndex:0] intValue]);
+
+ FILE *fout(fdopen(fd, "w"));
+ fprintf(fout, "finish:%s\n", finish);
+ fclose(fout);
+}
+
+static bool setnsfpn(const char *path) {
+ return system([[NSString stringWithFormat:@"/usr/libexec/cydia/setnsfpn %s", path] UTF8String]) == 0;
+}
+
+enum StashStatus {
+ StashDone,
+ StashFail,
+ StashGood,
+};
+
+static StashStatus MoveStash() {
+ struct stat stat;
+
+ if (lstat("/var/stash", &stat) == -1)
+ return errno == ENOENT ? StashGood : StashFail;
+ else if (S_ISLNK(stat.st_mode))
+ return StashGood;
+ else if (!S_ISDIR(stat.st_mode))
+ return StashFail;
+
+ if (lstat("/var/db/stash", &stat) == -1) {
+ if (errno == ENOENT)
+ goto move;
+ else return StashFail;
+ } else if (S_ISLNK(stat.st_mode))
+ // XXX: this is fixable
+ return StashFail;
+ else if (!S_ISDIR(stat.st_mode))
+ return StashFail;
+ else {
+ if (!setnsfpn("/var/db/stash"))
+ return StashFail;
+ if (system("mv -t /var/stash /var/db/stash/*") != 0)
+ return StashFail;
+ if (rmdir("/var/db/stash") == -1)
+ return StashFail;
+ } move:
+
+ if (!setnsfpn("/var/stash"))
+ return StashFail;
+
+ if (rename("/var/stash", "/var/db/stash") == -1)
+ return StashFail;
+ if (symlink("/var/db/stash", "/var/stash") != -1)
+ return StashDone;
+ if (rename("/var/db/stash", "/var/stash") != -1)
+ return StashFail;
+
+ fprintf(stderr, "/var/stash misplaced -- DO NOT REBOOT\n");
+ return StashFail;
+}
+
+static bool FixProtections() {
+ const char *path("/var/lib");
+ mkdir(path, 0755);
+ if (!setnsfpn(path)) {
+ fprintf(stderr, "failed to setnsfpn %s\n", path);
+ return false;
+ }
+
+ return true;
+}
+
+static void FixPermissions() {
+ DIR *stash(opendir("/var/stash"));
+ if (stash == NULL)
+ return;