It seems i'm having some trouble understanding NSTask in Cocoa. The application that I want to launch is openSSL. Currently, I'm able to send the information (launch path, arguments etc.) and I can get a response as well using NSPipe. What I need to be able to do though is to respond to the input requests that the application asks for. With the following code, I can send and read a response from a file:
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: launchPath];
[task setArguments: arguments];
[task setCurrentDirectoryPath:dir];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *response = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
Once I launch the NSTask, I'm expected to provide things like the Domain Name, Country etc. The reason for my question is because I need to be able to generate a Certificate Signing Request with openSSL and send it, along with some other data, over to a server. The code above is not broken, I'm just not sure how I can go about sending over that input.
Also, if anyone has used some sort of openSSL implementation with Cocoa/ObjC and feels that it would be a better option than using NSTask, I'm completely open to that as well.
Thanks in Advance.
Not that anybody is looking at this, but if you are and didn't already know the answer, I found the solution but ended up using a different method. Instead of sending additional input, I would just pass the -subj parameter. However, the solution to what I was originally asking is as follows:
NSTask *task = [[NSTask alloc] init];
NSString *tmpdir=NSTemporaryDirectory();
[task setCurrentDirectoryPath:tmpdir];
[task setLaunchPath:#"/usr/bin/openssl"];
NSArray *sslarguments=#[#"req",#"-nodes",#"-newkey",#"rsa:2048",#"-keyout",#"myserver.key",#"-out",#"server.csr"];
[task setArguments:sslarguments];
NSPipe * in = [NSPipe pipe];
[task setStandardInput:in];
NSData *data=[#"GB\nYorks\n\nYork\SimuplanSL\nIT\nsomeone#simuplan.com" dataUsingEncoding:NSUTF8StringEncoding];
[task launch];
[[in fileHandleForWriting] writeData:data];
[task waitUntilExit];
I just had to write to a file in a temporary directory and feed it through the input pipe.
Related
I'm trying to run airport command to scan my wireless networks. Right now, the approach is to use NSTask. I'm running it as follow:
NSString *command = [NSString stringWithFormat:#"/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s"];
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/bin/sh"];
NSArray *args = [NSArray arrayWithObjects:#"-c", command, nil];
[task setArguments: args];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
[task launch];
[task waitUntilExit];
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];
NSString *string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"RESULT: %#", string);
The problem is that its output comes as "RESULT:" (empty output). Additionally, when I run the same command with "-I" option, it correctly lists my current network statuses. So, I suppose that I'm mistaking on how to proper read the output of the airport command with -s option. Can someone give a hint on how to proper read it?
Ok. By deeply investigating issues here, I've found this in my Console logs:
PMsandboxd: ([57108]) <MyApp>(57108) deny mach-lookup com.apple.airport
PMsandboxd: ([57108]) <MyApp>(57108) deny system-socket
PMsandboxd: ([57120]) sh(57120) deny file-read-data /dev/ttys003
PMairportd: Error: Scan failed (1)
PMsandboxd: ([57120]) airport(57120) deny system-socket
Well... looks like it is a permission issue. I'm still investigating here.
EDITED #1: Ok. If your app is sandboxed for Apple Store, sandbox deny NSTask from using airport scan!
I have a Mac Native app written with Xcode. I want to execute some SSH command using that application on remote servers and get the result back to user.
Is there any library/Framework exist for that? Is that possible?
You will want to use the NSTask class to execute an ssh command.
The following code was adapted from the answer to this question.
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"/usr/bin/ssh"]; // Tell the task to execute the ssh command
[task setArguments: [NSArray arrayWithObjects: #"<user>:<hostname>", #"<command>"]]; // Set the arguments for ssh to contain only your command. If other configuration is necessary, see the ssh(1) man page.
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading]; // This file handle is a reference to the output of the ssh command
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; // This string now contains the entire output of the ssh command.
I'm having trouble calling a shell script which takes an argument from my Cocoa application for Mac.
I have created the shell script, and put it in the app's local repository. It is called SCRIPT. It takes one argument which is a URL address.
I call the script as follows but nothing happens, no errors or messages, just the script stops after doing nothing.
NSString *address = [_addressField stringValue];
NSString *resPath = [[NSBundle mainBundle] resourcePath];
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: [NSString stringWithFormat:#"%#/SCRIPT", resPath]];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: address, nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *status;
status = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog (#"%#", status);
Thanks in advance everyone
The Objective-C code seams to work fine for me if i try with /bin/echo as launch path. So i guess the problem is with the script. Can you include the script in your question? note that the environment when running from a Cocoa application is probably quite different from when running in a interactive shell.
Could it be a permissions issue? Try invoking /bin/sh and setting the script path as the first argument.
I run a simple grep command in my Cocoa app like so:
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"/usr/bin/grep"];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: #"foo", #"bar.txt", nil];
[task setArguments: arguments];
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];
NSLog (#"grep returned:\n%#", string);
[string release];
[task release];
However, I am somewhat curious to know how commands entered through terminal, which don't give out an output and are not executed promptly unless exited with something like Control + C can be run with this technique. Something like running java -jar server.jar where it keeps running until quit out of the session. How would I do something like that where the session is not automatically ended once the command has been launched?
Would I just need to comment out the part where it releases the NSTask? Any suggestions would be nice!
When using NSTask with an underlying program that doesn’t exit immediately:
You shouldn’t use -[NSFileHandle readDataToEndOfFile] since there is no end of file. Instead, you should use -[NSFileHandle readInBackgroundAndNotify] to read the standard output pipe of that task in the background, and be notified when data is available;
You should use -[NSTask release] only when you’ve determined that the task shouldn’t run any more. In that case, prior to releasing the task, you should send its standard input the command that causes the underlying program to exit (e.g. the characters equivalent to control-d), or send it -terminate or -interrupt.
You shouldn’t use -waitUntilExit unless you’ve spawned a secondary thread to deal with that task.
I need to run multiple commands in sequence using NSTask and was wondering what would be a good way to tell if a task has finished so I can continue on to the next command. I'm using "sox" (which I am including in my application bundle) to create temporary audio files using input audio files, and then need to combine those temporary audio files into a single file. An example of the flow of processes (not the actual commands):
1) songA > tempA
2) songB > tempB
3)combine tempA tempB > songC
I'm using the following code to complete the first command:
NSArray *arguments;
arguments = [NSArray arrayWithObjects: #"songA", #"-f", #"-S", #"-G", #"-V", #"-b", #"24", #"-r", #"384k", #"tempA", nil];
NSString *path=[[NSBundle mainBundle] pathForResource:#"sox" ofType:nil];
NSTask *task;
task = [[NSTask alloc] init];
[task setStandardInput:[NSPipe pipe]];
[task setLaunchPath:path];
[task setArguments: arguments1];
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];
NSLog (#"stuff :\n%#", string);
[string release];
[task release];
Suppposing I needed to perform two more NSTask processes after this one had finished (using the output of the previous processs), what would be the best way to detect that one process has finished so that I can continue on to the next one.
Thanks.
Maybe not understand fully, but
[task waitUntilExit];
does not do the job?