I got the piping of several commands working. Now Id like to execute this with received arguments (*argv[]
) and not hard coded like here.
Ived tried using the rest of the execve family but no progress. Ive been thinking to put everything (argv) in an array of pointers and adding NULL at the end of where each pointer points, then iterate through it.
Passed argument ( ,
included): echo "test" , wc , cowsay
int main(int argc, char *argv[]) {
char *echo[] = {"echo", "test", NULL};
char *rev[] = {"rev", NULL};
char *wc[] = {"wc", NULL};
char **cmd[] = {echo, wc, rev, NULL};
loop_pipe(cmd);
return (0);
}
void loop_pipe(char ***cmd) {
int p[2];
pid_t pid;
int fd_in = 0;
while (*cmd != NULL) {
pipe(p);
if ((pid = fork()) == -1) {
exit(EXIT_FAILURE);
} else if (pid == 0) {
dup2(fd_in, 0); //change the input according to the old one
if (*(cmd 1) != NULL)
dup2(p[1], 1);
close(p[0]);
execvp((*cmd)[0], *cmd);
exit(EXIT_FAILURE);
} else {
wait(NULL);
close(p[1]);
fd_in = p[0]; //save the input for the next command
cmd ;
}
}
}
CodePudding user response:
You did all the multiprocessing part. You only need to do some array shuffling, to convert array of strings to array of arrays of strings.
If you don’t mind iterating the array two times, you can do like the following:
int main(int argc, char *argv[]) {
// count the commas
int n = 0;
for (int k = 1; k < argc; k ) {
if (strcmp(argv[k], ",") == 0)
n ;
}
int stage_count = n 1;
// allocate the pipeline stage list
char ***cmd = calloc(stage_count 1, sizeof(char**));
// fill arguments for each stage
int stage = 0;
int first_arg = 1; // index of the first argument of current stage
for (int k = 1; k <= argc; k ) {
// stage arguments are terminated by a comma,
// except of the last, where k == argc
if ((k == argc) || (strcmp(argv[k], ",") == 0)) {
// now, k is one greater than the index of the last argument of that stage
int arg_count = k - first_arg;
// save arguments for one pipeline stage
// (note that only char pointers are copied, not the data they point to)
// (also, you can use `malloc` but don’t forget to write terminating NULL then)
char **args = calloc(arg_count 1, sizeof(char*));
memcpy(args, argv first_arg, arg_count * sizeof(char*));
cmd[stage] = args;
stage ;
first_arg = k 1; // k refers to the delimiter so the next stage arguments start at k 1
}
}
loop_pipe(cmd);
return 0;
}
You can refine this using special properties of argv
, e.g. that argv[argc] == NULL
, or that argv
, as well as the argument strings themselves, is actually writable.