Executing a command from Objective C - objective-c

I want to execute a command from objective C (Cocoa framework). The command I am trying is as below. I tried with NSTask but it says "launch path not accessible" when I execute it.
sudo ifconfig en0 down
My code is:
- (void)testme {
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"sudo ifconfig en0 down"];
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 (#"command returned:\n%#", string);
[string release];
[task release];
}

sudo ifconfig en0 down is not a sensible launch path. The correct launch path for this command would be /usr/sbin/sudo.
Once that is done, you still need to pass the correct arguments to setArguments:. foo and bar.txt look like example code that you copied without reading.
MORE IMPORTANTLY, THOUGH, running sudo from NSTask will not work. You will need to use Authorization Services to launch a privileged command.

You need to specify the full executable path and you should specify the arguments as the arguments, not along with the launch path. NSTask ain't a shell, it internally uses syscalls (execv(), I guess) to invoke the command.
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/usr/bin/sudo"];
NSArray *arguments = #[#"ifconfig", #"en0", #"down"];
[task setArguments:arguments];

Related

How to get out put from a TOP terminal command using Obj-C?

I am trying to retrieve CPU usage of system using
top -F -R -o cpu
The command is running fine in terminal however I am not able to get the output in Objective c using the code given below:
-(NSString*)runCommand:(NSString*)commandToRun;
{
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"/bin/sh"];
NSArray *arguments = [NSArray arrayWithObjects:
#"-c" ,
[NSString stringWithFormat:#"%#", commandToRun],
nil];
NSLog(#"run command: %#",commandToRun);
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *output;
output = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
return output;
}
I am getting the empty string as a result.
Please suggest what should I do. Many thanks.
I haven't tried using top before in this way, I suspect the issue is related to top updating the output every second. In that case you could try a different top command:
top -F -R -o cpu -l 1
or use a different tool to get the data you want, like ps:
ps -vaA

Execute SSH Command on remote Linux Machine using Native Mac App. (Obj-C)

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.

Call shell script with argument in Mac application

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.

executing shell command with | (pipe) using NSTask

I'm trying to execute this comamnd ps -ef | grep test using NSTask but I can't get the | grep test to be included in the NSTask:
This is what I'm using currently to get the output of ps -ef into a string then I need to somehow get the pid of the process test
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"/bin/ps"];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: #"-ef", 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 (#"got\n%#", string);
Piping is a feature provided by shells, such as /bin/sh. You may try launching your command via such a shell:
/* ... */
[task setLaunchPath: #"/bin/sh"];
/* ... */
arguments = [NSArray arrayWithObjects: #"-c", #"ps -ef | grep test", nil];
However, if you let the user supply a value (instead of hard-coding e.g. test), you are making the program susceptible to shell injection attacks, which are kind of like SQL injection. An alternative, which doesn't suffer from this problem, is to use a pipe object to connect the standard output of ps with the standard input of grep:
NSTask *psTask = [[NSTask alloc] init];
NSTask *grepTask = [[NSTask alloc] init];
[psTask setLaunchPath: #"/bin/ps"];
[grepTask setLaunchPath: #"/bin/grep"];
[psTask setArguments: [NSArray arrayWithObjects: #"-ef", nil]];
[grepTask setArguments: [NSArray arrayWithObjects: #"test", nil]];
/* ps ==> grep */
NSPipe *pipeBetween = [NSPipe pipe];
[psTask setStandardOutput: pipeBetween];
[grepTask setStandardInput: pipeBetween];
/* grep ==> me */
NSPipe *pipeToMe = [NSPipe pipe];
[grepTask setStandardOutput: pipeToMe];
NSFileHandle *grepOutput = [pipeToMe fileHandleForReading];
[psTask launch];
[grepTask launch];
NSData *data = [grepOutput readDataToEndOfFile];
/* etc. */
This uses built-in Foundation functionality to perform the same steps as the shell does when it encounters the | character.
Finally as others have pointed out, the usage of grep is overkill. Just add this to your code:
NSArray *lines = [string componentsSeparatedByString:#"\n"];
NSArray *filteredLines = [lines filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: #"SELF contains[c] 'test'"]];
You may need to call [task waitUntilExit] before you launch the task, so that the process can finish running before you read the output.

Run terminal command with NSTask

I want to run a Terminal command in my program.
The command looks like this:
cd /path/to/file/; ./foo HTTPProxy 127.0.0.1
It works with system() but it doesn't work when I use NSTask.
system("cd /path/to/file/; ./foo HTTPProxy 127.0.0.1");
works fine but
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/path/to/file/./foo"];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task setArguments:[NSArray arrayWithObjects:#"HTTPProxy 127.0.0.1", nil]];
[task launch];
NSData *data = [file readDataToEndOfFile];
NSString *string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(string);
doesn't.
Output:
Command-line option 'HTTPProxy 127.0.0.1' with no value. Failing.
Has anybody an idea?
Now I think I have got it:
[task setArguments:[NSArray arrayWithObjects:#"HTTPProxy", #"127.0.0.1", nil]];
those are separate arguments in your invocation from the command line...
OLD ANSWER:
You could trying setting the current directory for execution:
– setCurrentDirectoryPath:
This is basically the effect of cd in the system version of your code.