InputPackage.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. #import "InputPackage.h"
  2. #import "ErrorReturn.h"
  3. #import "HelperClass.h"
  4. @implementation InputPackage
  5. - (NSString*) description {
  6. NSString *orig = [super description];
  7. NSMutableDictionary *details = [NSMutableDictionary new];
  8. NSArray *props = [self properties];
  9. [props enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  10. NSString *cv = [self valueForKey:obj];
  11. if (cv){
  12. details[obj] = cv;
  13. }
  14. }];
  15. return [NSString stringWithFormat:@"%@ = %@", orig, details];
  16. }
  17. - (NSString *)listfile {
  18. __block NSMutableArray *outFiles = [NSMutableArray new];
  19. [self.files enumerateObjectsUsingBlock:^(InputPackageFile * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  20. if ([obj.fileType isEqualToString:@"link"]){ //does this need to handle things differently?
  21. [outFiles addObject:obj.path];
  22. } else {
  23. [outFiles addObject:obj.path];
  24. }
  25. }];
  26. return [outFiles componentsJoinedByString:@"\n"];
  27. }
  28. - (int)installToBootstrapPath:(NSString *)bootstrapPath {
  29. DLog(@"\nFound package: '%@' at version: '%@'...\n", self.packageName, self.version );
  30. NSString *statusFile = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/status"];
  31. NSArray *installedPackages = [HelperClass statusInstalledPackagesFromFile:statusFile];
  32. //DLog(@"installedPackages: %@", installedPackages);
  33. StatusPackageModel *model = [[installedPackages filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"package == %@", self.packageName]] lastObject];
  34. if (model) {
  35. DLog(@"\n [WARNING] This package has already been installed! %@", model);
  36. NSComparisonResult result = [self.version compare:model.version options:NSNumericSearch];
  37. DLog(@"\n [WARNING] Comparing version numbers...");
  38. switch (result) {
  39. case NSOrderedSame:
  40. DLog(@"\n [WARNING] %@ and %@ match!", self.version, model.version);
  41. break;
  42. case NSOrderedAscending:
  43. DLog(@"\n [WARNING] Package version %@ is less than installed version %@!", self.version, model.version);
  44. break;
  45. case NSOrderedDescending:
  46. DLog(@"\n [WARNING] Package version %@ is greater than installed version %@!", self.version, model.version);
  47. break;
  48. default:
  49. break;
  50. }
  51. }
  52. ErrorReturn *safePackage = [self errorReturnForBootstrap:bootstrapPath];
  53. if (safePackage.returnStatus != 0) { //zero is success
  54. if (safePackage.returnStatus == 1) //ovewrwrites, just warnings!
  55. {
  56. NSString *error = [NSString stringWithFormat:@" [WARNING] %@ will overwrite the following files: \n\n\t%@\n\n", self.path.lastPathComponent, [safePackage.overwriteFiles componentsJoinedByString:@"\n\t"]];
  57. if(![HelperClass shouldContinueWithError:error]){
  58. return -1;
  59. }
  60. } else if (safePackage.returnStatus == 2) //bail!!"
  61. {
  62. return 2;
  63. }
  64. }
  65. NSString *pwd = [[HelperClass returnForProcess:@"/bin/pwd"] componentsJoinedByString:@"\n"];
  66. NSFileManager *man = [NSFileManager defaultManager];
  67. NSString *tmpPath = [pwd stringByAppendingPathComponent:self.packageName];
  68. NSString *debian = [tmpPath stringByAppendingPathComponent:@"DEBIAN"];
  69. [man createDirectoryAtPath:tmpPath withIntermediateDirectories:TRUE attributes:nil error:nil];
  70. DLog(@"\nExtracting deb for processing...\n");
  71. [HelperClass returnForProcess:[NSString stringWithFormat:@"/usr/local/bin/dpkg -x %@ %@", self.path, tmpPath]];
  72. NSString *bootstrapInfoPath = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/info"];
  73. NSString *listFile = [bootstrapInfoPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.list", self.packageName]];
  74. NSString *md5s = [bootstrapInfoPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.md5sums", self.packageName]];
  75. DLog(@"\nCreating list file '%@'...\n", listFile);
  76. [self.listfile writeToFile:listFile atomically:TRUE encoding:NSUTF8StringEncoding error:nil];
  77. DLog(@"\nGenerating md5sums...\n");
  78. NSString *runString = [NSString stringWithFormat:@"/usr/bin/find %@ -type f -not -path \"*.DS_Store*\" -exec /sbin/md5 -r {} \\; | /usr/bin/awk '{ print $1 \" \" $2 }' | /usr/bin/sed \"s|%@||g\"", tmpPath, tmpPath];
  79. NSString *outputs = [[HelperClass returnForProcess:runString] componentsJoinedByString:@"\n"];
  80. DLog(@"\nCreating md5sum file '%@'...\n", md5s);
  81. [outputs writeToFile:md5s atomically:TRUE encoding:NSUTF8StringEncoding error:nil];
  82. [man createDirectoryAtPath:debian withIntermediateDirectories:TRUE attributes:nil error:nil];
  83. DLog(@"\nExtracting DEBIAN files for processing...\n");
  84. [HelperClass returnForProcess:[NSString stringWithFormat:@"/usr/local/bin/dpkg -e %@ %@", self.path, debian]];
  85. //NSString *nextPath = [tmpPath stringByAppendingPathComponent:@"DEBIAN"];
  86. DLog(@"\nCopying any necessary DEBIAN files to new locations...\n\n");
  87. __block NSString *postInstFile = nil;
  88. NSArray *files = [man contentsOfDirectoryAtPath:debian error:nil];
  89. [files enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  90. NSString *fullPath = [debian stringByAppendingPathComponent:obj];
  91. if (![obj isEqualToString:@"control"]){
  92. if ([obj isEqualToString:@"postinst"]){
  93. postInstFile = fullPath;
  94. }
  95. DLog(@"Copying file... %@\n\n", fullPath);
  96. NSString *fileName = [NSString stringWithFormat:@"%@.%@", self.packageName, obj];
  97. NSString *newPath = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/info"];
  98. newPath = [newPath stringByAppendingPathComponent:fileName];
  99. //DLog(@"newPath: %@", newPath);
  100. [man copyItemAtPath:fullPath toPath:newPath error:nil];
  101. } else {
  102. NSMutableString *controlFile = [[NSMutableString alloc] initWithContentsOfFile:fullPath encoding:NSUTF8StringEncoding error:nil];
  103. [controlFile replaceOccurrencesOfString:@"iphoneos-arm" withString:@"appletvos-arm64" options:NSLiteralSearch range:NSMakeRange(0, [controlFile length])];
  104. [controlFile appendString:@"Status: install ok installed"];
  105. //DLog(@"control file: -%@-\n", controlFile);
  106. NSString *statusFile = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/status"];
  107. [FM copyItemAtPath:statusFile toPath:[statusFile stringByAppendingPathExtension:@"bak"] error:nil];
  108. NSMutableString *statusContents = [[NSMutableString alloc] initWithContentsOfFile:statusFile encoding:NSUTF8StringEncoding error:nil];
  109. if (model) { //we found the package model, just replace the old string with our new one
  110. DLog(@"Updating status file for new package version...\n\n");
  111. [statusContents replaceOccurrencesOfString:model.rawString withString:controlFile options:NSLiteralSearch range:NSMakeRange(0, [statusContents length])];
  112. //[statusContents writeToFileWithoutAttributes:statusFile];
  113. [statusContents writeToFile:statusFile atomically:TRUE encoding:NSUTF8StringEncoding error:nil];
  114. } else {
  115. DLog(@"Updating status file for new package...\n\n");
  116. //DLog(@"down here??: -%@-\n", controlFile);
  117. [statusContents appendFormat:@"%@\n", controlFile];
  118. //DLog(@"\nnew status file: %@\n", statusContents);
  119. //[statusContents writeToFileWithoutAttributes:statusFile];
  120. [statusContents writeToFile:statusFile atomically:TRUE encoding:NSUTF8StringEncoding error:nil];
  121. }
  122. }
  123. }];
  124. //finally actually install the package onto the bootstrap
  125. DLog(@"Extracting package onto bootstrap folder...\n");
  126. [HelperClass returnForProcess:[NSString stringWithFormat:@"/usr/local/bin/dpkg -x %@ %@", self.path, bootstrapPath]];
  127. if (postInstFile) {
  128. DLog(@"\n [WARNING] We found a postinst file, will not run this due to potential unexpected consequences in your run environment! Displaying contents so you can determine if any additional steps are necessary. Contents will be delimited by a line -----\n");
  129. DLog(@"\n%@ Contents:\n\n---------------------\n\n%@\n\n---------------------\n\n", postInstFile, [NSString stringWithContentsOfFile:postInstFile encoding:NSUTF8StringEncoding error:nil]);
  130. }
  131. DLog(@"Done!\n\n");
  132. return 0;
  133. }
  134. - (void)repackageInCurrentDirectoryWithArch:(NSString *)newArch {
  135. NSString *fakeRoot = [HelperClass singleLineReturnForProcess:@"/usr/bin/which fakeroot"];
  136. NSString *pwd = [HelperClass singleLineReturnForProcess:@"/bin/pwd"];
  137. DLog(@"\nProcessing file: %@\n", self.path);
  138. InputPackage *output = self;
  139. DLog(@"\nFound package: '%@' at version: '%@'...\n", output.packageName, output.version );
  140. NSString *tmpPath = [pwd stringByAppendingPathComponent:output.packageName];
  141. NSString *debian = [tmpPath stringByAppendingPathComponent:@"DEBIAN"];
  142. [FM createDirectoryAtPath:tmpPath withIntermediateDirectories:TRUE attributes:nil error:nil];
  143. DLog(@"\nExtracting package contents for processing...\n");
  144. [HelperClass returnForProcess:[NSString stringWithFormat:@"/usr/local/bin/dpkg -x %@ %@", self.path, tmpPath]];
  145. [FM createDirectoryAtPath:debian withIntermediateDirectories:TRUE attributes:nil error:nil];
  146. DLog(@"\nExtracting DEBIAN files for processing...\n");
  147. [HelperClass returnForProcess:[NSString stringWithFormat:@"/usr/local/bin/dpkg -e %@ %@", self.path, debian]];
  148. if (newArch != nil) {
  149. NSString *controlPath = [debian stringByAppendingPathComponent:@"control"];
  150. NSMutableString *controlFile = [[NSMutableString alloc] initWithContentsOfFile:controlPath encoding:NSUTF8StringEncoding error:nil];
  151. //@"appletvos-arm64"
  152. [controlFile replaceOccurrencesOfString:@"iphoneos-arm" withString:newArch options:NSLiteralSearch range:NSMakeRange(0, [controlFile length])];
  153. [controlFile writeToFile:controlPath atomically:TRUE];
  154. }
  155. //at this point we have the files extracted, time to determine what needs to be changed
  156. NSArray *ignoreFiles = @[@".fauxsu", @".DS_Store"];
  157. NSArray *forbiddenRoots = @[@"etc", @"var", @"tmp"];
  158. //__block NSMutableArray *_overwriteArray = [NSMutableArray new];
  159. [self.files enumerateObjectsUsingBlock:^(InputPackageFile * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  160. if (obj.type == BSPackageFileTypeFile || obj.type == BSPackageFileTypeDirectory){
  161. //DLog(@"processing path: %@", obj.path);
  162. if ([obj.path isEqualToString:@"/private/var/mobile/Applications/"]){
  163. NSString *badPath = [tmpPath stringByAppendingPathComponent:obj.path];
  164. NSString *newPath = [tmpPath stringByAppendingPathComponent:@"Applications"];
  165. DLog(@"\n [INFO] Moving %@ to %@...", badPath, newPath);
  166. [FM moveItemAtPath:badPath toPath:newPath error:nil];
  167. [FM removeItemAtPath:[tmpPath stringByAppendingPathComponent:@"private"] error:nil];
  168. *stop = TRUE;
  169. }
  170. NSString *fullPath = [tmpPath stringByAppendingPathComponent:obj.path];
  171. if ([ignoreFiles containsObject:obj.path.lastPathComponent]){
  172. DLog(@"in ignore file list, purge");
  173. [FM removeItemAtPath:fullPath error:nil];
  174. }
  175. NSArray *pathComponents = [obj.path pathComponents];
  176. if ([pathComponents count] > 1)
  177. {
  178. NSString *rootPath = [pathComponents objectAtIndex:1];
  179. //DLog(@"\n Checking root path: %@ for file %@\n", rootPath, obj.path);
  180. if ([forbiddenRoots containsObject:rootPath])
  181. {
  182. DLog(@"\n [WARNING] package file: '%@' would overwrite symbolic link at '%@'\n", obj.path, rootPath);
  183. NSString *privateDir = [tmpPath stringByAppendingPathComponent:@"private"];
  184. if (![FM fileExistsAtPath:privateDir]){
  185. [FM createDirectoryAtPath:privateDir withIntermediateDirectories:TRUE attributes:nil error:nil];
  186. }
  187. //take <package_name>/[rootPath] (could be etc, var, tmp) and move to <package_name>/private/[rootPath]
  188. NSString *badPath = [tmpPath stringByAppendingPathComponent:rootPath];
  189. NSString *newPath = [privateDir stringByAppendingPathComponent:rootPath];
  190. DLog(@"\n [INFO] Moving %@ to %@...", badPath, newPath);
  191. [FM moveItemAtPath:badPath toPath:newPath error:nil];
  192. }
  193. }
  194. }
  195. }];
  196. NSString *depArchiveInfo = [NSString stringWithFormat:@"/usr/local/bin/dpkg -b %@", self.packageName];
  197. if (fakeRoot) {
  198. depArchiveInfo = [NSString stringWithFormat:@"%@ /usr/local/bin/dpkg -b %@", fakeRoot, self.packageName];
  199. }
  200. [[HelperClass returnForProcess:depArchiveInfo] componentsJoinedByString:@"\n"];
  201. DLog(@"\nDone!\n\n");
  202. //return er;
  203. }
  204. - (ErrorReturn *)errorReturnForBootstrap:(NSString *)bootstrapPath
  205. {
  206. NSArray *ignoreFiles = @[@".fauxsu", @".DS_Store"];
  207. NSArray *forbiddenRoots = @[@"etc", @"var", @"tmp"];
  208. NSFileManager *man = [NSFileManager defaultManager];
  209. __block NSInteger returnValue = 0; //0 = good to go 1 = over write warning, 2 = no go
  210. __block NSMutableArray *_overwriteArray = [NSMutableArray new];
  211. [self.files enumerateObjectsUsingBlock:^(InputPackageFile * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  212. if ([obj.fileType isEqualToString:@"file"]){
  213. NSString *fullPath = [bootstrapPath stringByAppendingPathComponent:obj.path];
  214. if ([man fileExistsAtPath:fullPath] && ![ignoreFiles containsObject:obj.basename]){
  215. //DLog(@"[WARNING] overwriting a file that already exists and isn't DS_Store or .fauxsu: %@", fullPath);
  216. [_overwriteArray addObject:obj.path];
  217. //*stop = TRUE;//return FALSE;
  218. returnValue = 1;
  219. }
  220. NSArray *pathComponents = [obj.path pathComponents];
  221. if ([pathComponents count] > 1)
  222. {
  223. NSString *rootPath = [pathComponents objectAtIndex:1];
  224. if ([forbiddenRoots containsObject:rootPath])
  225. {
  226. DLog(@"\n [ERROR] package file: '%@' would overwrite symbolic link at '%@'! Exiting!\n\n", obj.path, rootPath);
  227. *stop = TRUE;
  228. returnValue = 2;
  229. }
  230. }
  231. }
  232. }];
  233. ErrorReturn *er = [ErrorReturn new];
  234. er.returnStatus = returnValue;
  235. er.overwriteFiles = _overwriteArray;
  236. return er;
  237. }
  238. @end