0

I'm trying to run a shell script using posix_spawn, by trying to convert from NSArray to char array with a NULL in the last element, I end up crashing my system. Below is the original code that has no error.

NSArray *arg_array = nil;
arg_array = @[@"/bin/bash", @"/var/somefile.sh"];
char **argv = NULL;
NSInteger numargv = arg_array.count;

if (numargv) {
    argv = (char **)calloc(numargv, sizeof(char*))  ;

    if (argv) {

        for (NSInteger i=0;i<numargv;i++) {
            NSString *nsString = arg_array[i];

            if (i==0){
                NSArray* spliteArray = [nsString componentsSeparatedByString: @"/"];
                NSString* cStringFirstArgv = [spliteArray lastObject];
                nsString = cStringFirstArgv;
            }

            char *cString = (char *)malloc([nsString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1); // + 1 for \0

            if (cString) {  
                strcpy(cString, nsString.UTF8String);
                argv[i] = cString;
            } else {
                // error
            }
        }
    } 
}


pid_t pid;
int status;
//const char *argv[] = {"bash", "/var/test.sh", NULL}; This is what I expected argv to be, a NULL in the last element
posix_spawnp(&pid, "bash", NULL, NULL, (char* const*)argv, NULL);
waitpid(pid, &status, WEXITED);

argv currently is {"bash", "/var/test.sh"}, however I trying to make it to an array like this:{"bash", "/var/test.sh", NULL} so that I could run posix_spawn successfully. Any idea how to fix this? Thanks in advance!

3
  • Well, you need calloc(numargv + 1 in the first place. Commented Aug 12, 2019 at 14:03
  • That's what I did too, but it end up crashing the system. Commented Aug 12, 2019 at 14:07
  • You just need cStringWithEncoding: Commented Aug 12, 2019 at 14:50

1 Answer 1

1

The following will work:

NSArray *arg_array = nil;
arg_array = @[@"/bin/bash", @"/var/somefile.sh"];
char **argv = NULL;
NSInteger numargv = arg_array.count;

argv = (char **)calloc(numargv + 1, sizeof(char*));

if (argv) {
    for (NSInteger i = 0; i < numargv; i++) {
        NSString *nsString = arg_array[i];

        if (i == 0){
            NSString* application = [[nsString componentsSeparatedByString: @"/"] lastObject];
            nsString = application;
        }

        NSData* stringData = [nsString dataUsingEncoding:[NSString defaultCStringEncoding]];

        char *cString = (char *)malloc(stringData.length + 1);
        [stringData getBytes:cString length:stringData.length];
        cString[stringData.length] = 0;

        argv[i] = cString;
    }
}

pid_t pid;
int status;
//const char *argv[] = {"bash", "/var/test.sh", NULL}; This is what I expected argv to be, a NULL in the last element
posix_spawnp(&pid, "bash", NULL, NULL, (char* const*)argv, NULL);
waitpid(pid, &status, WEXITED);

I think there were two problems in your code:

  1. You were missing the +1 in your calloc for the NULL terminator.
  2. You don't actually set the ending 0 for your string arguments.
Sign up to request clarification or add additional context in comments.

1 Comment

Your code is so much more cleaner, and I didn't realize using NSData is more easier! Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.