I'm trying to get a better understanding of pipes and processes. I want to implement multiple chained pipes like cat test.txt | sort | uniq -c. I started my code with the cat test.txt, but it isn't working. It compiles, but when I provide a file name in the command line, for example, ./hwk ./test.txt. Nothing returns. Can someone take a look and give me some hints? I want to use loops because I want to be able to add more pipes. I know there's a lot of issues in my code, so I hope someone can give me some guidance on this topic. Thanks.
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#define SIZE 1024
int main (int argc, char **argv)
{
int num_pipe = 1;
int commands = num_pipe + 1; //number of commands is one more than the number of pipes
int fds[num_pipe * 2];
int status;
pid_t pid;
char *str_ptr;
//Pass Command
char *arrayOfCommands[] = {"cat", NULL};
//Setting up pipes
int i;
for (i = 0; i < num_pipe; i++){
if(pipe(fds + i * 2) == -1) {
perror("Error creating pipes");
exit(1);
}
}
int j = 0;
for (i = 0; i < commands - 1; ++i) {
pid = fork();
if (pid == 0) {
if (i < commands) {
if (dup2(fds[j+1], 1) < 0) {
perror("dup2 error");
exit(EXIT_FAILURE);
}
}
if (j != 0) {
if(dup2(fds[j-2], 0) < 0) {
perror("dup2 error");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < 2*num_pipe; i++) {
close(fds[i]);
}
if (execvp(arrayOfCommands[0], arrayOfCommands) < 0) {
perror("Array error");
exit(EXIT_FAILURE);
}
}
else if (pid < 0){
perror("Error");
exit(EXIT_FAILURE);
}
j += 2;
}
for (i = 0; i < 2 * num_pipe; i++){
close(fds[i]);
}
for (i = 0; i < num_pipe + 1; i++) {
wait(&status);
}
return 0;
}
I called this mainly minor adaptation of your program p3.c, compiling it to produce p3. Since there's only one command (cat) being invoked, I juggled things so that it will work correctly. When run as ./p3 p3.c, it prints out the content of the source code.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
static void err_exit(const char *str);
int main (int argc, char **argv)
{
int num_pipe = 0; // Just cat - no pipes
int commands = num_pipe + 1; // Number of commands is one more than the number of pipes
int fds[num_pipe * 2 + 1]; // Avoid size 0 array
char *arrayOfCommands[3] = { "cat", NULL, NULL};
if (argc != 2)
err_exit("Missing filename argument");
arrayOfCommands[1] = argv[1];
for (int i = 0; i < num_pipe; i++)
{
if (pipe(fds + i * 2) == -1)
err_exit("Error creating pipes");
}
int j = 0;
for (int i = 0; i < commands; ++i)
{
pid_t pid = fork();
if (pid == 0)
{
printf("%d: %s %s\n", (int)getpid(), arrayOfCommands[0], arrayOfCommands[1]);
fflush(stdout);
if (i < commands-1 && dup2(fds[j+1], 1) < 0)
err_exit("dup2 error");
if (j != 0 && dup2(fds[j-2], 0) < 0)
err_exit("dup2 error");
for (i = 0; i < 2*num_pipe; i++)
close(fds[i]);
execvp(arrayOfCommands[0], arrayOfCommands);
err_exit("Array error");
}
else if (pid < 0)
err_exit("Error");
j += 2;
}
for (int i = 0; i < 2 * num_pipe; i++)
close(fds[i]);
for (int i = 0; i < num_pipe + 1; i++)
{
int status;
pid_t pid = wait(&status);
printf("PID %d exited 0x%.4X\n", (int)pid, status);
}
return 0;
}
static void err_exit(const char *str)
{
perror(str);
exit(EXIT_FAILURE);
}
Check that works for you. Then you'll need to work out how you're going to create a second command. Your arrayOfCommands isn't going to help directly. You'll need another array of strings in some shape or form.
An extension to run cat file | rev. The changes are really quite minor. I created a_cat to handle the cat command, a_rev for the rev command, and a_cmds as the array of commands. It was also necessary to fix a loop on i to a loop on k.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
static void err_exit(const char *str);
int main (int argc, char **argv)
{
int num_pipe = 1;
int commands = num_pipe + 1; //number of commands is one more than the number of pipes
int fds[num_pipe * 2 + 1]; // Avoid size 0 array
char *a_cat[3] = { "cat", NULL, NULL};
char *a_rev[2] = { "rev", NULL};
char **a_cmds[] = { a_cat, a_rev };
if (argc != 2)
err_exit("Missing filename argument");
a_cat[1] = argv[1];
for (int i = 0; i < num_pipe; i++)
{
if (pipe(fds + i * 2) == -1)
err_exit("Error creating pipes");
}
int j = 0;
for (int i = 0; i < commands; ++i)
{
pid_t pid = fork();
if (pid == 0)
{
printf("%d: %s\n", (int)getpid(), a_cmds[i][0]);
fflush(stdout);
if (i < commands-1 && dup2(fds[j+1], 1) < 0)
err_exit("dup2 error");
if (j != 0 && dup2(fds[j-2], 0) < 0)
err_exit("dup2 error");
for (int k = 0; k < 2*num_pipe; k++)
close(fds[k]);
execvp(a_cmds[i][0], a_cmds[i]);
err_exit("Array error");
}
else if (pid < 0)
err_exit("Error");
j += 2;
}
for (int i = 0; i < 2 * num_pipe; i++)
close(fds[i]);
for (int i = 0; i < num_pipe + 1; i++)
{
int status;
pid_t pid = wait(&status);
printf("PID %d exited 0x%.4X\n", (int)pid, status);
}
return 0;
}
static void err_exit(const char *str)
{
perror(str);
exit(EXIT_FAILURE);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With