2

Since iPhone sandboxes its applications, I am unable to access the /bin/ folder. So I used an SSH connection to get the /bin/date binary file off the iPhone and I include it in my project. The path to my file is correct when I use NSLog it prints: /var/mobile/Applications/95078888-DDA8-4C1E-93DC-1F9E0A26E70A/Documents/date. The issue I come across is listed below. Does anyone know how I can fix this error?

*NOTE: If I run it in the simulator and use this code to execute any binary file compatible with mac OSX it works, but when I try to run it on the device with an iPhone binary file it causes me problems.

Error:

2012-08-09 14:23:13.757 TestBinary[7891:707] Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'couldn't fork: errno 1'

First throw call stack: (0x359b388f 0x335d7259 0x359b3789 0x359b37ab 0x34deb915 0xda5af 0x3590d3fd 0x330cee07 0x330cedc3 0x330ceda1 0x330ceb11 0x330cf449 0x330cd92b 0x330cd319 0x330b3695 0x330b2f3b 0x336a522b 0x35987523 0x359874c5 0x35986313 0x359094a5 0x3590936d 0x336a4439 0x330e1cd5 0xd9ecd 0xd9e98)

terminate called throwing an exception

Program received signal: “SIGABRT”. Data Formatters temporarily unavailable, will re-try after a 'continue'. (Can't find dlopen function, so it is not possible to load shared libraries.)

mi_cmd_stack_list_frames: Not enough frames in stack.

mi_cmd_stack_list_frames: Not enough frames in stack.

Code calling the date file:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

NSString *path = [NSString stringWithFormat:@"%@/date", documentsDirectory];

NSLog(@"%@", path);

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath: path];

NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];

NSFileHandle *file;
file = [pipe fileHandleForReading];

[task launch];

NSData *data;
data = [file readDataToEndOfFile];

NSString *string;
string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];

label.numberOfLines=0;
label.text = string;

[string release];
[task release]; 

My NSTask file:

#import <Foundation/NSObject.h>

@class NSString, NSArray, NSDictionary;

@interface NSTask : NSObject

- (id)init;

- (void)setLaunchPath:(NSString *)path;
- (void)setArguments:(NSArray *)arguments;
- (void)setEnvironment:(NSDictionary *)dict;
- (void)setCurrentDirectoryPath:(NSString *)path;
- (void)setStandardInput:(id)input;
- (void)setStandardOutput:(id)output;
- (void)setStandardError:(id)error;

- (NSString *)launchPath;
- (NSArray *)arguments;
- (NSDictionary *)environment;
- (NSString *)currentDirectoryPath;

- (id)standardInput;
- (id)standardOutput;
- (id)standardError;

- (void)launch;

- (void)interrupt; 
- (void)terminate; 

- (BOOL)suspend;
- (BOOL)resume;

- (int)processIdentifier; 
- (BOOL)isRunning;

- (int)terminationStatus;

@end

@interface NSTask (NSTaskConveniences)

+ (NSTask *)launchedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)arguments;

- (void)waitUntilExit;

@end

FOUNDATION_EXPORT NSString * const NSTaskDidTerminateNotification;
#endif

EDIT 1:

I use the following directory to unzip: https://github.com/samsoffes/ssziparchive

This is my code to unzip and execute:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

NSString *path2 = [[NSBundle mainBundle] pathForResource:@"date" ofType:@"zip"];
[SSZipArchive unzipFileAtPath: path2 toDestination:documentsDirectory];

NSString *path = [NSString stringWithFormat:@"%@/date", documentsDirectory];

NSFileManager* fileManager = [NSFileManager defaultManager];
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithDictionary:[fileManager attributesOfItemAtPath:path error:nil]];

[attributes setValue:[NSNumber numberWithShort: 0777] 
              forKey:NSFilePosixPermissions];
NSError* err;
[fileManager setAttributes: attributes ofItemAtPath: path error: &err];

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath: path];

NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];

NSFileHandle *file;
file = [pipe fileHandleForReading];

[task launch];

NSData *data;
data = [file readDataToEndOfFile];

NSString *string;
string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];

label.numberOfLines=0;
label.text = string;

[string release];
[task release]; 
MrHappyAsthma
  • 6,332
  • 9
  • 48
  • 78
  • That didn't answer my question. First off my device is jailbroken which is half of the answers, and also they clearly state that if you port over the header file then it should work for iOS even though its not supported by apple. And I can use this NSTask for other files ON DEVICE and they work fine. Its just the binary I am having issues with. – MrHappyAsthma Aug 09 '12 at 19:25

1 Answers1

1

I'm not sure exactly why this is happening, but when Xcode builds, it is somehow corrupting the date binary file. If you look at the original date file (under your project folder), and then find the same file under the Xcode build directory (e.g.):

/Users/myusername/Library/Developer/Xcode/DerivedData/HelloJB-gsokzlpnejddadbccgrfkxnumkyl/Build/Products/Release-iphoneos/HelloJB.app

you can run the diff command on the two files, and it will tell you that those binary files differ. That's going to be enough to cause this problem.

For some reason, Xcode is looking at that type of resource, and doing something to it. I know, for example, that it tries to use some kind of pngcrush utility on your app's png resources. Maybe this is similar.

Anyway, one way I found to fix this is to zip the date file on your Mac. Then, include date.zip as a bundle resource in your project. Clean and build. Xcode will not corrupt the zip file.

Now, when your app starts up, it will need to unzip the date.zip file from its bundle resources, and store the unzipped version in Documents, or Caches, or wherever you want it. You might need to remember to set the execute permission, too.

See this for programmatically unzipping files

Update:

After that, you may have to set the file to have executable permissions. Something like this:

NSFileManager* fileManager = [NSFileManager defaultManager];
NSMutableDictionary* attributes = [[NSMutableDictionary alloc] init];
NSNumber* permission = [NSNumber numberWithLong: 0755];
[attributes setObject:permission forKey: NSFilePosixPermissions];
NSError* err;
[fileManager setAttributes: attributes ofItemAtPath: filePath error: &err];
Community
  • 1
  • 1
Nate
  • 31,017
  • 13
  • 83
  • 207
  • I use the zip function from that link and it unzips fine but I think that the file is not executable when its unzipped. How do I change file permissions from within the app? (I just unzip it to the documents directory). – MrHappyAsthma Aug 15 '12 at 17:15
  • That does change the permissions fine. It causes the file to be executable according to the terminal "ls -al", however I still get the following error: " Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'couldn't fork: errno 1'". *Note: This is on device. – MrHappyAsthma Aug 19 '12 at 15:56
  • @MrHappyAsthma, please try this: ssh into your phone. Navigate to the directory where you **unzipped** the compressed `date` file. Then, scp that file back to your computer, and run a `diff` on the files. After uncompressing, are they exactly the same? If not, something didn't work right. I don't have time to write this from scratch, but if you update your question with the code you use to unzip date.zip, I could try running it on my end. Thanks. – Nate Aug 19 '12 at 21:36
  • They came out the same, and I also downloaded the MobileTerminal app from Cydia and I can execute my "date" after uncompressing via "cd /folders/" and then "date". So it has to be an issue in my the way I am trying to execute it via NSTask or something. I will update my code here in a second. – MrHappyAsthma Aug 23 '12 at 19:41