Danny Anderson
Danny Anderson

Reputation: 21

In C, how can I copy part of an array of strings for use as an argv in execve?

My code is really messy right now, so I think it would be easier to convey what I'm trying to do by just describing it.

I'm working on a shell for homework that needs to be able to redirect output to a file, just like the default shell. We were provided a preexisting shell and asked to modify it. The shell already sets up an argv for execve, but in order to implement redirection I need to remove the last two entries from the argv the program built (> and the file name), and after testing that by just freeing up the last two entries I think it's probably better to just make a copy, minus those two entries, as this program handles freeing up the argv and if I try to do that at some point before the predesignated time to do so I run into problems when I try to run another command.

My point is I'm having a hard time copying part of an array of strings that's going to serve as an argv. I've seen a couple of solutions posted, but they're all in C++, and I'm asked to do this in C.

Alternatively, I suppose it would also be sufficient if I could properly empty part of an argv. Here's the code I tried:

for(i=0;i<10;i++)
{
    if(my_argv[i] == NULL)
    {
        break;
    }
    if(strcmp(my_argv[i], ">") == 0)
    {
        if(my_argv[i+1] != NULL)
        {
            strncpy(fileName, my_argv[i+1], strlen(my_argv[i+1]));
            strncat(fileName, "\0", 1);
            //bzero(my_argv[i+1], strlen(my_argv[i+1])+1);
            //my_argv[i+1] = NULL;
            //free(my_argv[i+1]);
        } else {
            printf("no file name given\n");
            return;
        }
        //bzero(my_argv[i], strlen(my_argv[i])+1);
        //my_argv[i] = NULL;
        //free(my_argv[i]);
        redirectOutput(cmd, fileName);
        return;
    }
}

The commented sections are where I copied in code from the function that empties my_argv to attempt to free up the contents of argv where the > and file name are. It still runs without those lines, but then I kick the can down the road with having to deal with the extra entries in my redirectOutput() function, which is an absolute train wreck. The free_argv() function looks like this:

void free_argv()
{
    int index;
    for(index=0;my_argv[index]!=NULL;index++) {
        bzero(my_argv[index], strlen(my_argv[index])+1);
        my_argv[index] = NULL;
        free(my_argv[index]);
    }
}

Upvotes: 2

Views: 91

Answers (1)

John Bollinger
John Bollinger

Reputation: 181008

You're going to much more work than you need to do. You can safely do whatever you want to the pre-prepared argv, as long as you do it after the fork(), in the child (before the execve(), of course). No such modifications will affect the parent, and you don't need to worry about any cleanup because the exec replaces the old process image with the new one.

Example:

/* these are already provided: */
char *filename =    /* ... */;
char **child_argv = /* ... */;
char **child_env  = /* ... */;

pid_t pid = fork();

if (pid == 0) {
    /* the child */
    char **arg;

    for (arg = child_argv; *arg && strcmp(*arg, ">"); arg += 1) { /* empty */ }
    *arg = NULL; /* terminate the arg list at the ">", if present */

    /* no need to clean up anything before execve() */

    execve(filename, child_argv, child_env);
    exit(1);  /* execve() failed */
} else if (pid < 0) {
    /* handle error */
}

/* the parent continues ... */

Upvotes: 1

Related Questions