Reputation: 21
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
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