Running shell script with NSTask causes posix_spawn error - objective-c

I'm trying to run a shell script with NSTask with the following code:
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/Users/username/connect.sh"];
[task launch];
But I get An uncaught exception was raised and Couldn't posix_spawn: error 8
If I just run the script in terminal, everything works.
Here is what the script contains:
if [ ! -d ~/Remote/username/projects ]
then
sshfs -C -p 22 user#remotecomputer.com:/home/username ~/Remote/username
fi

You can also add #!/bin/bash to the start of your script:
#!/bin/bash
if [ ! -d ~/Remote/username/projects ]
then
sshfs -C -p 22 user#remotecomputer.com:/home/username ~/Remote/username
fi

You need to use setLaunchPath like this:
[task setLaunchPath:#"/bin/sh"];
Then use setArguments for your script:
[task setArguments: [NSArray arrayWithObjects: #"~/connect.sh", nil]];

Related

How check if output of bash script contains a certain string in Objective-C?

I would like to do something if the output of a shell script contains the string "Caddy 2 serving static files on :2015". This is what I have so far but the beach ball is just spinning. It seems it is because of the last command in my bash script which starts a server. There is no exit in the bash script so it does not end. The output of the bash script is correct and I can see "Caddy 2 serving static files on :2015". But it seems this code is only working with a bash script which has a end.
If someone wants to try, here you can download the executable caddy file which I am using in my bash script: https://caddyserver.com/download
- (IBAction)localHost:(id)sender
{
// execute bash script to start server
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/bin/bash"];
[task setArguments:[NSArray arrayWithObjects:[[NSBundle mainBundle] pathForResource:#"caddy-start" ofType:#""], nil]];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task launch];
NSData *data = [file readDataToEndOfFile];
NSString *result = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(result);
NSString *string = result;
NSString *substring = #"Caddy 2 serving static files on :2015";
if ([string rangeOfString:substring].location != NSNotFound) {
NSLog(#"Yes it does contain that substring");
}
else if ([string rangeOfString:substring].location == NSNotFound) {
NSLog(#"No it does NOT contain that substring");
}
}
And here is my bash script:
#!/bin/bash
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
cd "${DIR}"
pwd
#open http://localhost:2015
# kill server if already running
kill -9 $(lsof -ti:2015)
(./caddy_darwin_amd64 stop) &
(./caddy_darwin_amd64 file-server --listen :2015 --root Content/) &

Variable in NSTask - Objective-C Cocoa

I want to use command line in Cocoa for record of the password in a bunch of keys.
But I can't insert a variable at line. How to make it?
How $pass to provide me self.PassKey?
self.PassKey = [_PassTextField stringValue];
NSTask *taskPass = [[NSTask alloc] init];
[taskPass setLaunchPath:#"/bin/bash"];
[taskPass setArguments:[NSArray arrayWithObjects: #"-c", #"/usr/bin/security delete-generic-password -a ${USER} -s post | security add-generic-password -a ${USER} -s post -w $pass", nil]];
[taskPass launch];
Thanks for any help!
Thanks to all for the help and such prompt reply!
So works:
self.PassKey = [_PassTextField stringValue];
NSLog(#"text changed: %#", self.PassKey); ///I printed in a window the password 12345
NSString * command = [NSString stringWithFormat:#"/usr/bin/security delete-generic-password -a ${USER} -s post | security add-generic-password -a ${USER} -s post -w %#", self.PassKey]; ///I receive a line /usr/bin/security delete-generic-password -a ${USER} -s postftp | security add-generic-password -a ${USER} -s postftp -w 12345
NSLog(#"command line: %#", command);
NSTask *taskPass = [[NSTask alloc] init];
[taskPass setLaunchPath:#"/bin/bash"];
[taskPass setArguments:[NSArray arrayWithObjects: #"-c", command, nil]];
[taskPass launch];
Record of the password in a bunch of keys results.

Run NSTask synchronously

I have an .app file that I'm running through NSTask and I wish the thread to be blocked till .app execution is over.
My current code is:
NSTask *task = [[NSTask alloc] init];
task.launchPath = #"/bin/bash";
task.arguments = [NSArray arrayWithObjects:#"-c", "/usr/bin/open myApp.app", nil];
[task launch];
[task waitUntilExit]; // doesn't guarantee task will wait until exit according to docs
I know I can use NSTask.terminationHandler but since I have a lot of tasks I don't want to get into a callback hell situation (and also I don't care if everything will run sync and take some time)
(I also tried adding nohup to the execution command but it didn't made the affect i wanted.)
Is there a way to execute NSTask synchronously and wait until execution is over?
It seems that the problem was in the open command which executes the app and return context even if execution is not over.
I found out that open has a -W argument:
-W, --wait-apps Blocks until the used applications are closed (even if they were already running).
adding this argument solved my problem.
final code:
NSTask *task = [[NSTask alloc] init];
task.launchPath = #"/bin/bash";
task.arguments = [NSArray arrayWithObjects:#"-c", "/usr/bin/open -W myApp.app", nil];
[task launch];
[task waitUntilExit];

Start Application as specific user from LaunchDaemon

I am currently trying to launch an Application in /Applications from a LaunchDaemon as specific user. Is there a way that I can launch this application without giving the program root privileges? I am writing the Daemon in objective C.
In your launch daemon's plist, which should reside in /Library/LaunchDaemons, you can set the UserName key:
<key>UserName</key>
<string>userForThisProcess</string>
where userForThisProcess is the user you want to use to run the application.
I have solved this issue in a little quirky way now. I use NSTask in conjunction with sudo and open. Maybe someone needs this in the future:
+ (bool)start_app_bundle_as_user:(NSString *)path with_user_name:(NSString *)user_name
{
NSString *cmd = [NSString stringWithFormat:#"/usr/bin/sudo -i -u %# -- open -a %#", user_name, path];
NSTask *task = [[NSTask alloc] init];
NSArray *args = [NSArray arrayWithObjects:#"-c", cmd, nil];
[task setLaunchPath:#"/bin/sh"];
[task setArguments:args];
[task launch];
[task waitUntilExit];
return [task terminationStatus] == 0;
}

execute lame with NSTask but No Output

I'm new to Objective-C. Currently I'm trying to execute lame with NSTask. The following code seems to be working because Xcode's output space shows me lame's standardoutput i.e. shows same as lame's output on Terminal.
But I can't get any output file i.e. test.mp3 on my desktop. Why I can't get any output? Is there any wrong with my code?
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/usr/local/bin/lame"];
[task setArguments:[NSArray arrayWithObjects:#"/Users/xanadu62/Music/test.wav",nil]];
[task setStandardOutput:[NSFileHandle fileHandleForWritingAtPath:#"/Users/xanadu62/Desktop/test.mp3"]];
[task launch];
Also, I'd like to use "--preset extreme" as lame option. But "task setArguments:" doesn't allow to use this option as argument. I'd like to know how can I solve this issue too.
Try it this way:
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/usr/local/bin/lame"];
[task setArguments: [NSArray arrayWithObjects:
#"--preset",
#"extreme",
#"/Users/xanadu62/Music/test.wav",
#"/Users/xanadu62/Desktop/test.mp3",
nil]
];
[task launch];
You don't need to use pipes.
usage: lame [options] <infile> [outfile]
<infile> and/or <outfile> can be "-", which means stdin/stdout.
Never used lame, but by looking at the docs the correct terminal command would be
"lame --preset extreme /Users/lawrencepires/Desktop/test.mp3 /Users/lawrencepires/Desktop/test1.mp3"
test.mp3 being the input file, test1.mp3 being the output file.
Working Code - (may be worth changing for live output)
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
[self lameconvert];
}
- (void)lameconvert {
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/usr/local/bin/lame"];
NSArray *argArray = [NSArray arrayWithObjects:#"--preset",#"extreme",#"/Users/xanadu62/Music/test.wav",#"/Users/xanadu62/Music/test.wav",nil];
[task setArguments:argArray];
[task launch];
[task waitUntilExit];
NSLog(#"Conversion Complete");
}
#end