views:

376

answers:

1

I would like to run a shell script, from a file or from an objective-c string (within the code). I would also like the shell script's result to be stored to a variable. I would not like the shell script to be split into arguments (such as setLaunchPath when I run it). For example: running this shell script "mount_webdav idisk.mac.com/mac_username /Volumes/mac_username" instead of "/bin/mount_webdav" then the arguments. Is there anyway to do this? I am using NSTask right now, but it has caused me some errors when I try to put the arguments with it. Here is the posed code:

(some of the .m file)

 NSString *doshellscript(NSString *cmd_launch_path, NSString *first_cmd_pt) {

 NSTask *task = [[NSTask alloc] init]; // Make a new task

 [task setLaunchPath: cmd_launch_path]; // Tell which command we are running

 [task setArguments: [NSArray arrayWithObjects: first_cmd_pt, nil]];

 [task setArguments: first_cmd_pt];

 NSPipe *pipe = [NSPipe pipe];

 [task setStandardOutput: pipe];

 [task launch];

  NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];

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

  [task release]; //Release the task into the world, thus destroying it.

  return string;
}


NSString *mount_idisk(NSString *mac_username) {

 doshellscript(@"/bin/mkdir", [@"/Volumes/" stringByAppendingString:mac_username]);

 NSString *path_tmp = [mac_username stringByAppendingString: @"/ /Volumes/"];

 NSString *idisk_path = [path_tmp stringByAppendingString:mac_username];

 //NSLog(@"%@", [@" http://idisk.mac.com/" stringByAppendingString: idisk_path]);

 NSString *finished_path = [@"http://idisk.mac.com/" stringByAppendingString: idisk_path];

 doshellscript(@"/sbin/mount_webdav", finished_path);
}

... Here is the line I am using to run it: mount_idisk("username");

+2  A: 

There is no way to pass a whole command line to NSTask.

For good reason; doing so is rife with security holes if you have any kind of string composition going on. Your string composition code would have to be fully cognizant of all of the rules of parsing a shell command line and would have to escape every possible combination of characters that might lead to arbitrary command execution.

The system() C API lets you execute arbitrary commands, but has no mechanism for capturing output directly. It would be easy to add something to your command line that spews the output into a temporary file that you later read, but doing so just adds more security holes above and beyond passing down a whole command line as a single string.

Wait... Looks like you have a straightforward bug:

[task setArguments: [NSArray arrayWithObjects: first_cmd_pt, nil]];
[task setArguments: first_cmd_pt];

Why are you setting and then re-setting the task's arguments?

Given that your mount_idisk() function is effectively composing the individual arguments and concatenating them together into a single string, why don't you simply stuff all the args into an NSArray and modify doshellscript() to take an array as the second parameter; the array of arguments?


You aren't creating the array of arguments correctly.

Namely:

NSArray *finished_path = [NSArray arrayWithObjects:@"http://idisk.mac.com/", mac_username, @"/ /Volumes/", mac_username, nil];

That line is creating an array contain 4 objects which are then treated as 4 separate arguments in the doshellscript() function and not the two arguments that you need.

Maybe something like:

NSString *mobileMeUserURL = [@"http://idisk.mac.com/" stringByAppendingString: mac_username];
NSString *localMountPath = [ @"/ /Volumes/" stringByAppendingString:  mac_username];
NSArray *arguments = [NSArray arrayWithObjects: mobileMeUserURL, localMountPath, nil];
bbum