|
@@ -20,7 +20,7 @@
|
|
|
|
|
|
typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
{
|
|
|
-
|
|
|
+
|
|
|
BSPackageFileTypeFile,
|
|
|
BSPackageFileTypeDirectory,
|
|
|
BSPackageFileTypeBlock,
|
|
@@ -240,7 +240,7 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if ([[currentPackage allKeys] count] > 4)
|
|
|
{
|
|
|
self = [super init];
|
|
@@ -259,7 +259,7 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
NSArray *allKeys = [theProps allKeys];
|
|
|
NSDictionary *mappedKeys = [DebPackageModel JSONKeyPathsByPropertyKey];
|
|
|
[ourProps enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
|
-
|
|
|
+
|
|
|
NSString *mappedProp = mappedKeys[obj];
|
|
|
|
|
|
//DLog(@"allkeys: %@", allKeys);
|
|
@@ -277,7 +277,7 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
//DLog(@"%@ doesnt respond to %@", self, mappedProp);
|
|
|
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
|
|
|
}];
|
|
|
|
|
@@ -301,10 +301,10 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
|
|
|
DLog(@"overwriting file: %@", theFile);
|
|
|
}
|
|
|
- FILE *fd = fopen([theFile UTF8String], "w+");
|
|
|
- const char *text = self.UTF8String;
|
|
|
- fwrite(text, strlen(text) + 1, 1, fd);
|
|
|
- fclose(fd);
|
|
|
+ FILE *fd = fopen([theFile UTF8String], "w+");
|
|
|
+ const char *text = self.UTF8String;
|
|
|
+ fwrite(text, strlen(text) + 1, 1, fd);
|
|
|
+ fclose(fd);
|
|
|
|
|
|
}
|
|
|
|
|
@@ -334,7 +334,7 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
@implementation PackageFile
|
|
|
|
|
|
- (void)_setFileTypeFromRaw:(NSString *)rawType {
|
|
|
-
|
|
|
+
|
|
|
_fileType = [PackageFile readableFileTypeForRawMode:rawType];
|
|
|
_type = [PackageFile fileTypeForRawMode:rawType];
|
|
|
|
|
@@ -403,7 +403,7 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
NSMutableDictionary *details = [NSMutableDictionary new];
|
|
|
NSArray *props = [self properties];
|
|
|
[props enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
|
-
|
|
|
+
|
|
|
NSString *cv = [self valueForKey:obj];
|
|
|
if (cv){
|
|
|
details[obj] = cv;
|
|
@@ -482,7 +482,7 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
__block NSInteger returnValue = 0; //0 = good to go 1 = over write warning, 2 = no go
|
|
|
__block NSMutableArray *_overwriteArray = [NSMutableArray new];
|
|
|
[self.files enumerateObjectsUsingBlock:^(PackageFile * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
|
-
|
|
|
+
|
|
|
if ([obj.fileType isEqualToString:@"file"]){
|
|
|
|
|
|
NSString *fullPath = [bootstrapPath stringByAppendingPathComponent:obj.path];
|
|
@@ -515,7 +515,7 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
ErrorReturn *er = [ErrorReturn new];
|
|
|
er.returnStatus = returnValue;
|
|
|
er.overwriteFiles = _overwriteArray;
|
|
|
-
|
|
|
+
|
|
|
return er;
|
|
|
}
|
|
|
|
|
@@ -652,7 +652,7 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
|
|
|
//@"drwxr-xr-x"
|
|
|
NSString *fileTypeChar = [permissionsAndType substringWithRange:NSMakeRange(0, 1)];
|
|
|
-
|
|
|
+
|
|
|
NSString *octalPermissions = [self octalFromSymbols:permissionsAndType];
|
|
|
NSString *octalUG = [self octalFromGroupSymbols:userGroup];
|
|
|
NSString *fileName = [path lastPathComponent];
|
|
@@ -697,7 +697,7 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
|
|
|
pf.permissions = octalPermissions;
|
|
|
pf.owner = octalUG;
|
|
@@ -785,7 +785,7 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
__block NSMutableArray *finalArray = [NSMutableArray new];
|
|
|
|
|
|
[fileList enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
|
-
|
|
|
+
|
|
|
PackageFile *file = [self packageFileFromLine:obj];
|
|
|
if (file) {
|
|
|
//DLog(@"%@", file);
|
|
@@ -793,7 +793,7 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
}
|
|
|
|
|
|
}];
|
|
|
-
|
|
|
+
|
|
|
Package *pkg = [Package new];
|
|
|
pkg.files = finalArray;
|
|
|
pkg.packageName = packageName;
|
|
@@ -895,7 +895,7 @@ typedef NS_ENUM(NSInteger, BSPackageFileType)
|
|
|
|
|
|
@end
|
|
|
|
|
|
-#define OPTION_FLAGS "o:f:b:"
|
|
|
+#define OPTION_FLAGS "o:f:b:l:d:hc"
|
|
|
|
|
|
|
|
|
char *progname;
|
|
@@ -905,10 +905,26 @@ static struct option longopts[] = {
|
|
|
{ "octal", required_argument, NULL, 'o' },
|
|
|
{ "file", required_argument, NULL, 'f' },
|
|
|
{ "bootstrap", required_argument, NULL, 'b' },
|
|
|
- { NULL, 0, NULL, 0 }
|
|
|
+ { "list", required_argument, NULL, 'l' },
|
|
|
+ { "delete", required_argument, NULL, 'd' },
|
|
|
+ { "help", no_argument, NULL, 'h' },
|
|
|
+ { "clean", no_argument, NULL, 'c' },
|
|
|
+ { NULL, 0, NULL, 0 }
|
|
|
};
|
|
|
|
|
|
-
|
|
|
+void cmd_help(){
|
|
|
+ printf("Usage: bootstrapTool [OPTIONS] FILE\n");
|
|
|
+ printf("Makes various modifications to a raw bootstrap folder\n\n");
|
|
|
+
|
|
|
+ printf(" -h, --help\t\t\tprints usage information\n");
|
|
|
+ printf(" -f, --file\t\t\tthe deb package file you with to install\n");
|
|
|
+ printf(" -b, --bootstrap\t\tthe bootstrap folder\n");
|
|
|
+ printf(" -d, --delete\t\t\tthe package you want to delete\n");
|
|
|
+ printf(" -l, --list\t\t\tlist all the packages installed on this bootstrap\n");
|
|
|
+ printf(" -c, --clean\t\t\tclean a bad status file from duplicate entries\n");
|
|
|
+
|
|
|
+ printf("\n");
|
|
|
+}
|
|
|
|
|
|
int main(int argc, const char * argv[]) {
|
|
|
@autoreleasepool {
|
|
@@ -922,6 +938,9 @@ int main(int argc, const char * argv[]) {
|
|
|
NSString *octalFile = nil;
|
|
|
NSString *debFile = nil;
|
|
|
NSString *bootstrapPath = nil;
|
|
|
+ NSString *bootstrapListPath = nil;
|
|
|
+ NSString *deletePackage = nil;
|
|
|
+ BOOL clean = FALSE;
|
|
|
while ((flag = getopt_long(argc, argv, OPTION_FLAGS, longopts, NULL)) != -1) {
|
|
|
switch(flag) {
|
|
|
case 'o':
|
|
@@ -938,21 +957,240 @@ int main(int argc, const char * argv[]) {
|
|
|
bootstrapPath = [NSString stringWithUTF8String:optarg];
|
|
|
break;
|
|
|
|
|
|
+ case 'l':
|
|
|
+
|
|
|
+ bootstrapListPath = [NSString stringWithUTF8String:optarg];
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'd':
|
|
|
+
|
|
|
+ deletePackage = [NSString stringWithUTF8String:optarg];
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'c':
|
|
|
+
|
|
|
+ clean = TRUE;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ cmd_help();
|
|
|
+ return -1;
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//DLog(@"folder: %@ project: %@", folder, project);
|
|
|
|
|
|
+ if (clean && bootstrapPath) {
|
|
|
+
|
|
|
+ NSString *statusFile = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/status"];
|
|
|
+
|
|
|
+ NSString *listContents = [NSString stringWithContentsOfFile:statusFile encoding:NSUTF8StringEncoding error:nil];
|
|
|
+ //clean up any errant spaces
|
|
|
+ listContents = [listContents stringByReplacingOccurrencesOfString:@"\n\n\n" withString:@"\n\n"];
|
|
|
+ listContents = [listContents stringByReplacingOccurrencesOfString:@"\n\n\n\n" withString:@"\n\n"];
|
|
|
+ [listContents writeToFile:statusFile atomically:TRUE];
|
|
|
+
|
|
|
+ DLog(@"\n [INFO] Cleaning status file: %@", statusFile);
|
|
|
+
|
|
|
+ NSString *testStatusFile = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/status"];
|
|
|
+ NSArray <DebPackageModel*> *installedPackages = [HelperClass statusInstalledPackagesFromFile:statusFile];
|
|
|
+ __block NSMutableString *newStatusFile = [NSMutableString new];
|
|
|
+ __block NSMutableArray *alreadyAdded = [NSMutableArray new];
|
|
|
+
|
|
|
+ [installedPackages enumerateObjectsUsingBlock:^(DebPackageModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
|
+
|
|
|
+ DLog(@"\n [INFO] Processing pacakge: %@", obj.package);
|
|
|
+
|
|
|
+ if (![alreadyAdded containsObject:obj.package]){
|
|
|
+
|
|
|
+ //duplicate check first
|
|
|
+ NSArray *doubleCheck = [installedPackages filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"package == %@", obj.package]];
|
|
|
+
|
|
|
+ if (doubleCheck.count > 1){
|
|
|
+
|
|
|
+ NSSortDescriptor *sortDesc = [NSSortDescriptor sortDescriptorWithKey:@"version" ascending:FALSE];
|
|
|
+ DebPackageModel *latestVersion = [[doubleCheck sortedArrayUsingDescriptors:@[sortDesc]] firstObject];
|
|
|
+ DLog(@"\n [INFO] We found a duplicate package, choosing latestVersion: %@", latestVersion);
|
|
|
+
|
|
|
+
|
|
|
+ [newStatusFile appendFormat:@"%@\n\n", latestVersion.rawString];
|
|
|
+ [alreadyAdded addObject:obj.package];
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+
|
|
|
+ [newStatusFile appendFormat:@"%@\n\n", obj.rawString];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ DLog(@"\n [INFO] We already had this package, skipping older duplicate: %@\n", obj.package);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }];
|
|
|
+
|
|
|
+ testStatusFile = [testStatusFile stringByReplacingOccurrencesOfString:@"\n\n\n" withString:@"\n\n"];
|
|
|
+
|
|
|
+ DLog(@"\n Writing new output file: %@\n", testStatusFile);
|
|
|
+
|
|
|
+ [newStatusFile writeToFile:testStatusFile atomically:TRUE];
|
|
|
+
|
|
|
+ DLog(@"\n Done!\n\n");
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if (deletePackage && bootstrapPath) {
|
|
|
+
|
|
|
+ __block NSString *postInstFile = nil;
|
|
|
+
|
|
|
+ NSString *statusFile = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/status"];
|
|
|
+ NSArray <DebPackageModel*> *installedPackages = [HelperClass statusInstalledPackagesFromFile:statusFile];
|
|
|
+
|
|
|
+ DebPackageModel *model = [[installedPackages filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"package == %@", deletePackage]] lastObject];
|
|
|
+
|
|
|
+ if (model) {
|
|
|
+
|
|
|
+
|
|
|
+ NSString *listName = [NSString stringWithFormat:@"%@.list", deletePackage];
|
|
|
+ NSString *infoPath = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/info"];
|
|
|
+ NSString *listFile = [infoPath stringByAppendingPathComponent:listName];
|
|
|
+
|
|
|
+ NSArray *listFiles = [FM contentsOfDirectoryAtPath:infoPath error:nil];
|
|
|
+
|
|
|
+ NSPredicate *blockPred = [NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
|
|
|
+
|
|
|
+ if ([evaluatedObject containsString:deletePackage]){
|
|
|
+ return TRUE;
|
|
|
+ }
|
|
|
+ return FALSE;
|
|
|
+ }];
|
|
|
+
|
|
|
+ NSArray *relatedFiles = [listFiles filteredArrayUsingPredicate:blockPred]; //any files in dpkg/info/deletePackage.*
|
|
|
+
|
|
|
+ DLog(@"\nWe have found the package, determining list details from: %@", listFile);
|
|
|
+
|
|
|
+ NSString *listContents = [NSString stringWithContentsOfFile:listFile encoding:NSUTF8StringEncoding error:nil];
|
|
|
+ DLog(@"\nContents: %@\n", listContents);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ DLog(@"\nFound package info files: %@\n", relatedFiles);
|
|
|
+
|
|
|
+ NSArray *files = [listContents componentsSeparatedByString:@"\n"];
|
|
|
+ __block NSMutableArray *filesToProcess = [NSMutableArray new];
|
|
|
+
|
|
|
+ [relatedFiles enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
|
+
|
|
|
+ NSString *fullPath = [infoPath stringByAppendingPathComponent:obj];
|
|
|
+ if([FM fileExistsAtPath:fullPath]){
|
|
|
+
|
|
|
+ if ([[obj pathExtension] isEqualToString:@"postinst"]){
|
|
|
+ postInstFile = fullPath;
|
|
|
+ }
|
|
|
+ [filesToProcess addObject:fullPath];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }];
|
|
|
+
|
|
|
+ [files enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
|
+
|
|
|
+ NSString *fullPath = [bootstrapPath stringByAppendingPathComponent:obj];
|
|
|
+ BOOL isDir = FALSE;
|
|
|
+ if([FM fileExistsAtPath:fullPath isDirectory:&isDir]){
|
|
|
+
|
|
|
+ if (!isDir){
|
|
|
+ DLog(@"found file: %@", fullPath);
|
|
|
+ [filesToProcess addObject:fullPath];
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }];
|
|
|
+
|
|
|
+ DLog(@"\nFiles to process: %@\n", filesToProcess);
|
|
|
+
|
|
|
+ NSString *error = [NSString stringWithFormat:@" [WARNING] We are about to delete '%@' from the bootstrap, this cannot be undone!", deletePackage];
|
|
|
+ if(![HelperClass shouldContinueWithError:error]){
|
|
|
+
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ [filesToProcess enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
|
+
|
|
|
+ [FM removeItemAtPath:obj error:nil];
|
|
|
+
|
|
|
+ }];
|
|
|
+
|
|
|
+ //TODO: delete the files here!
|
|
|
+
|
|
|
+
|
|
|
+ NSString *statusFile = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/status"];
|
|
|
+ [FM copyItemAtPath:statusFile toPath:[statusFile stringByAppendingPathExtension:@"bak"] error:nil];
|
|
|
+
|
|
|
+ __block NSMutableString *newStatusFile = [NSMutableString new];
|
|
|
+
|
|
|
+ [installedPackages enumerateObjectsUsingBlock:^(DebPackageModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
|
+
|
|
|
+ if (obj != model){
|
|
|
+
|
|
|
+ [newStatusFile appendFormat:@"%@\n\n", obj.rawString];
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ DLog(@"skipping the model we want to delete: %@", obj);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }];
|
|
|
+
|
|
|
+ [newStatusFile writeToFile:statusFile atomically:TRUE];
|
|
|
+
|
|
|
+
|
|
|
+ if (postInstFile) {
|
|
|
+
|
|
|
+ DLog(@"\n [WARNING] We found a postinst file, will not run this due to potential unexpected consequences off of the target device, displaying contents so you can determine if any additional steps are necessary\n");
|
|
|
+
|
|
|
+ DLog(@"\n\n%@ contents:\n%@\n\n", postInstFile, [NSString stringWithContentsOfFile:postInstFile encoding:NSUTF8StringEncoding error:nil]);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
if (octalFile) {
|
|
|
|
|
|
NSString *octal = [HelperClass octalFromSymbols:octalFile];
|
|
|
DLog(@"%@", octal);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bootstrapListPath) {
|
|
|
+
|
|
|
+ NSString *statusFile = [bootstrapListPath stringByAppendingPathComponent:@"Library/dpkg/status"];
|
|
|
+ NSArray *installedPackages = [HelperClass statusInstalledPackagesFromFile:statusFile];
|
|
|
+ DLog(@"%@", installedPackages);
|
|
|
+ return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
- if (debFile && bootstrapPath) {
|
|
|
|
|
|
+ if (debFile && bootstrapPath) {
|
|
|
+
|
|
|
NSString *statusFile = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/status"];
|
|
|
NSArray *installedPackages = [HelperClass statusInstalledPackagesFromFile:statusFile];
|
|
|
|
|
@@ -1021,7 +1259,7 @@ int main(int argc, const char * argv[]) {
|
|
|
//DLog(@"list: %@", output.listfile);
|
|
|
NSFileManager *man = [NSFileManager defaultManager];
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
|
|
|
NSString *tmpPath = [pwd stringByAppendingPathComponent:output.packageName];
|
|
@@ -1061,7 +1299,7 @@ int main(int argc, const char * argv[]) {
|
|
|
|
|
|
NSString *fullPath = [debian stringByAppendingPathComponent:obj];
|
|
|
if (![obj isEqualToString:@"control"]){
|
|
|
-
|
|
|
+
|
|
|
DLog(@"Copying file... %@\n\n", fullPath);
|
|
|
NSString *fileName = [NSString stringWithFormat:@"%@.%@", output.packageName, obj];
|
|
|
NSString *newPath = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/info"];
|
|
@@ -1114,7 +1352,7 @@ int main(int argc, const char * argv[]) {
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
//DLog(@"\n\nwe down here??\n\n");
|
|
|
|
|
|
//NSString *newString = [[HelperClass returnForProcess:[NSString stringWithFormat:@"/bin/cat %@", statusFile]] componentsJoinedByString:@"\n"];
|
|
@@ -1127,7 +1365,7 @@ int main(int argc, const char * argv[]) {
|
|
|
|
|
|
|
|
|
|
|
|
-// [statusContents writeToFile:statusFile atomically:TRUE encoding:NSUTF8StringEncoding error:nil];
|
|
|
+ // [statusContents writeToFile:statusFile atomically:TRUE encoding:NSUTF8StringEncoding error:nil];
|
|
|
|
|
|
|
|
|
|
|
@@ -1146,8 +1384,10 @@ int main(int argc, const char * argv[]) {
|
|
|
///usr/bin/find "$TARGET_DIR" -type f -not -path "$TARGET_DIR/DEBIAN/*" -exec "/sbin/md5 -r" {} \; | /usr/bin/awk '{ print $1 " " $2 }' | /usr/bin/sed "s|$TARGET_DIR/||g"
|
|
|
|
|
|
DLog(@"Done!\n\n");
|
|
|
-
|
|
|
+ return 0;
|
|
|
}
|
|
|
+ //if we got this far.. nothing happened, print help.
|
|
|
+ cmd_help();
|
|
|
|
|
|
}
|
|
|
return 0;
|