C - Executing bash command with 2 pipes - c

I have an assignment for which I have to create C programm which has to do the following: The mother proccess has to send via pipe to the child proccess the result of the command ps hax -o user | sort | uniq -c. The child proccess has to take this result and write it to a file users.log.
This is the code I have written:
int main(int argc, char **argv)
{
int file_number;
pid_t pid, pid_2, pid_3, pid_4;
int n, pd[2],fd[2], zd[2];
char line[MAXLINE];
if ( pipe(pd) < 0 || pipe(fd) < 0 || pipe(zd) < 0)
{
perror("cannot create pipe."); // failure on create pipe
exit(1);
}
if ( (pid = fork()) < 0)
{
perror("cannot fork"); // failure on creating child proccess
exit(1);
}
else if ( pid > 0) // mother proccess
{
dup2(zd[1], STDOUT_FILENO);
close(zd[0]);
close(zd[1]);
if ( (pid_4 = fork()) < 0)
{
perror("cannot fork.");
exit(1);
}
else if (pid_4 > 0)
{
dup2(pd[1], STDOUT_FILENO);
close(pd[0]);
close(pd[1]);
close(fd[0]);
close(fd[1]);
execl("/bin/ps", "ps", "hax", "-o", "user", (char *)0);
}
if ( (pid_2 = fork()) < 0)
{
perror("cannot fork.");
exit(1);
}
else if (pid_2 == 0)
{
dup2(pd[0], 0);
dup2(fd[1], 1);
close(pd[0]);
close(pd[1]);
close(fd[0]);
close(fd[1]);
execl("/bin/sort", "sort", "", (char *)0);
}
if ( (pid_3 = fork()) < 0)
{
perror("cannot fork.");
exit(1);
}
else if (pid_3 == 0)
{
dup2(fd[0], 0);
close(pd[0]);
close(pd[1]);
close(fd[0]);
close(fd[1]);
execl("/bin/uniq", "uniq", "-c", (char *)0);
}
close(pd[0]);
close(pd[1]);
close(fd[0]);
close(fd[1]);
pid_t terminated;
int stat;
while ((terminated = wait(&stat)) > 0)
{
printf("Child %d terminated.\n", terminated);
}
}
else // child proccess
{
FILE *fptr = fopen("users.log", "a+");
if (fptr == NULL)
fprintf(stderr, "could not open file.\n");
file_number = fileno(fptr); // getting the file descriptor of fptr
dup2(zd[0], STDIN_FILENO);
close(zd[1]);
close(zd[0]);
n = read(zd[0], line, MAXLINE);
printf("Output: (%.*s)\n", n, line);
write(file_number, line, n);
}
return 0;
}
Running the code seems not to produce the desired result. Nothing is written to the file and I get this error:
Signal 17 (CHLD) caught by hax (procps-ng version 3.3.10).
hax:display.c:66: please report this bug
What am I missing here?

Related

What is problem in my C piping for custom shell?

I making custom shell in c and when i give arguments for pipe it doesn't work as it should.
// Function where the piped system commands is executed
void execArgsPiped(char** parsed, char** parsedpipe)
{
// 0 is read end, 1 is write end
int pipefd[2];
pid_t p1, p2;
if (pipe(pipefd) < 0) {
red();
printf("\nPipe could not be initialized");
resetColor();
return;
}
p1 = fork();
if (p1 < 0) {
red();
printf("\nCould not fork");
return;
}
if (p1 == 0) {
// Child 1 executing..
// It only needs to write at the write end
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
if (execvp(parsed[0], parsed) < 0) {
red();
printf("\nCould not execute command 1..");
resetColor();
exit(0);
}
} else {
// Parent executing
p2 = fork();
if (p2 < 0) {
red();
printf("\nCould not fork");
resetColor();
return;
}
// Child 2 executing..
// It only needs to read at the read end
if (p2 == 0) {
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
if (execvp(parsedpipe[0], parsedpipe) < 0) {
red();
printf("\nCould not execute command 2..");
resetColor();
exit(0);
}
} else {
// parent executing, waiting for two children
wait(NULL);
wait(NULL);
}
}
}
For example calling /bin/cat filename | more, displays first two lines of file and shell breaks, or /bin/cat filename | cowsay nothing happens just breaks shell.
HELP
For anyone wondering read and write end closed before piping can end so code should look like.
// Function where the piped system commands is executed
void execArgsPiped(char** parsed, char** parsedpipe)
{
pid_t pid;
int fd[2];
pipe(fd);
pid = fork();
if(pid==0)
{
dup2(fd[WRITE_END], STDOUT_FILENO);
close(fd[READ_END]);
close(fd[WRITE_END]);
if (execv(parsed[0], parsed) < 0) {
printf("\nCould not execute command..");
}
exit(1);
}
else
{
pid=fork();
if(pid==0)
{
dup2(fd[READ_END], STDIN_FILENO);
close(fd[WRITE_END]);
close(fd[READ_END]);
if (execv(parsedpipe[0], parsedpipe) < 0) {
printf("\nCould not execute command..");
}
exit(1);
}
else
{
int status;
close(fd[READ_END]);
close(fd[WRITE_END]);
waitpid(pid, &status, 0);
}
}
}

How to pipe different processes? (C)

I'm trying to pipe two different processes to implement the terminal's functionality "|".
I need the new child to execute a command itself, and fork another process to execute a different command using the first process's output, then output the final process's results on the terminal.
Here's my code, I keep the original parent untouched because I need to continue executing the other parts of my program afterwards.
int exec_pipe(char **args, int index, int *i, char**** jobs){
int fd1[2];
pid_t pid, wpid;
int status;
int savedStdOut = dup(1);
int savedStdIn = dup(fileno(stdin));
if (pipe(fd1)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
pid = fork();
if (pid < 0)
{
fprintf(stderr, "fork Failed" );
return 1;
}else if (pid == 0)
{
// Child process
close(fd1[0]);
dup2(fd1[1], 1);
printf("%s\n", args[index - 1]);
if (execvp(args[0], args) == -1)
{
printf("command not found\n");
}
int childId = fork();
if(childId < 0){
fprintf(stderr, "fork Failed" );
return 1;
}else if(childId == 0){
// child of child of parent
fdopen(fd1[1], "r");
dup2(fd1[1], savedStdOut);
if (execvp(args[index + 1], args) == -1)
{
printf("command not found\n");
}
exit(EXIT_FAILURE);
}else {
// parent of child of child of parent
do
{
wpid = waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status)); // wait for child until it's exited or been killed
fdopen(savedStdIn, "r");
close(fd1[0]);
close(fd1[1]);
}
}else{
// Parent process
do
{
wpid = waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status)); // wait for child until it's exited or been killed
}
return 1;
}
I'm getting a "No such file or directory" error with the program ending with exit code 9.
Solved it based on some comments, thanks all!
int fd1[2];
pid_t pid;
// allocate two pipe sets
if (pipe(fd1) < 0)
{
perror("Failed to create pipe.");
return EXIT_FAILURE;
}
// launch first child process.
if ((pid = fork()) < 0)
{
perror("Failed to fork child(1)");
return EXIT_FAILURE;
}
if (pid == 0)
{
// child
// stdout = fd1(write)
if(strcmp(args[0], args[index - 1]) == 0)
{
dup2(fd1[WRITE], STDOUT_FILENO);
close(fd1[READ]);
close(fd1[WRITE]);
execlp(args[0], args[0], (char*) NULL);
fprintf(stderr, "failed to execute '%s'\n", args[0]);
exit(1);
}else{
dup2(fd1[WRITE], STDOUT_FILENO);
close(fd1[READ]);
close(fd1[WRITE]);
execlp(args[0], args[0], args[index - 1], (char*) NULL);
fprintf(stderr, "failed to execute '%s'\n", args[0]);
exit(1);
}
}else
{
// parent
// fork once more.
if ((pid = fork()) < 0)
{
perror("Failed to fork child(2)");
return EXIT_FAILURE;
}
if (pid == 0)
{
// child of child
// stdin = fd1(read)
dup2(fd1[READ], STDIN_FILENO);
close(fd1[WRITE]);
close(fd1[READ]);
execlp(args[index + 1], args[index + 1], (char*) NULL);
fprintf(stderr, "failed to execute '%s'\n", args[index + 1]);
exit(1);
}else{
int status;
close(fd1[READ]);
close(fd1[WRITE]);
waitpid(pid, &status, 0);
}
}

C program to pipe multiple commands

I have written the below method to fork and execute commands separated by multiple pipes( test with : ls -lrt | grep "check" | wc -l . However it is not resulting in any output, could any one please spot my mistake. Thanks.
void execCmd (pInfo *info)
{
int i, j, k, m;
struct comType *comm, *comm1, *comm2;
if(info->noOfPipes > 2)
{
// DOES NOT WORK
printf("Start\n");
comm=&(info->cArr[0]);
comm2=&(info->cArr[(info->ppNum)-1]);
int fds[2];
pipe(fds);
pid_t pid = fork();
if(pid == -1)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{
printf("1st child execution here\n");
close(fds[0]);
dup2(fds[1], STDOUT_FILENO);
close(fds[1]);
execvp(comm->cmd,comm->parms);
}
for (k=1;k<=((info->ppNum)-1);k++)
{
printf("For loop executionn number %d",k);
comm1=&(info->cArr[k]);
printf ("comm 1 : %s\n",comm1->cmd);
pid = fork();
if(pid == -1)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{
//2nd to n-1 child process
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
dup2(fds[1], STDOUT_FILENO);
close(fds[1]);
execvp(comm1->cmd,comm1->parms);
}
wait(NULL);
}
pid = fork();
if(pid == -1)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{
//nth child process
printf("Last child execution\n");
close(fds[1]);
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
execvp(comm2->cmd,comm2->parms);
}
close(fds[0]);
close(fds[1]);
wait(NULL);
wait(NULL);
}
}
This following code should give you an idea how to implement the pipelining:
#define STDIN 0
#define STDOUT 1
void exec_cmd(struct comType cmd) {
execvp(cmd->cmd, cmd->params);
}
void pipeCmds(struct comType* cmds) {
int fd[cmds_length * 2] = {0};
pid_t pid = 0;
for (int i = 0; i < cmds_length; i++) {
if (pid = fork() == 0) {
//child: make this cmd's output the other cmd's input
pipe(fd + (2*i) );
close(STDOUT);
dup(fd[i]);
if(i > 0) {
close(STDIN);
dup(fd[i-1]);
}
exec_cmd(cmds[i]);
close(fd[i]);
}
}
}
Note that the main idea is that each command is executed in a separate process (via fork) and the output goes to the next command's input rather than to the default stdout(with file descriptor 1), and the same for the input - stdin (file descriptor 0).

Piping in a while loop C

Im working on a shell that can handle pipes. the problem im runing into now is that when a pipe is found after both are done executing my shell exits. This is some sample code ive been working on to try and figure
int main(int argc, char** argv)
{
int fd[2];
pid_t pid;
pid_t pid2;
int childSt;
int hell;
struct arguments args;
char line[1024];
while (fgets(line, 1024, stdin)) {
line[strlen(line)-1] = '\0';
////////////////////////////////////////////////////////////// /
args = finArgs(line);
pipe(fd);
pid = fork();
if (pid > 0) // PARENT
{
pid2 = fork();
if(pid2 == 0){
close(fd[1]); //close write end
if (fd[0] != STDIN_FILENO)
{
if ((dup2(fd[0], STDIN_FILENO)) != STDIN_FILENO)
{
printf("dup2 error to stdin\n");
close(fd[0]);
}
}
if (execvp(args.pipeArgs[0], args.pipeArgs) < 0)
printf("parent error \n");
}
else {
wait(&childSt);
}
}
else // CHILD
{
close(fd[0]);
if (fd[1] != STDOUT_FILENO)
{
if ((dup2(fd[1], STDOUT_FILENO)) != STDOUT_FILENO)
{
printf("dup2 error to stdout\n");
close(fd[1]);
}
}
if (execvp(args.args[0], args.args) < 0)
printf("child error \n");
}
}
return(0);
}
here is some sample output
ls | wc
14 14 123
this is what i want but then the program exits.

C Programming 2 pipes

I want to set up 2 pipes in my program. I have 1 pipe working fine, but I don't know where to place the second pipe.
The pseudo code of my setup is shown below,
Here is it with curly braces sorry about that
//the first pipe:
pipe(pipe1)
//the second pipe:
pipe(pipe2)
pid = fork()
if(pid == 0) {
dup2(pipe1[1], 1)
close(pipe1[0])
execvp(beforepipe)
}
if(pid > 0) { //everything below is in here
pid2 = fork()
if(pid2 == 0){
//pipe1
dup2(pipe1[0],0)
dup2(out,1)
close(pipe1[1])
execvp(afterpipe)
//pipe2 does not work might need to be placed in different area
dup2(pipe1[1],1)
close(pipe1[0])
execvp(beforepipe1)
}
if(pid2 > 0){
close(pipe[0])
close(pipe[1])
wait() //this is an infinite for loop
pid3 = fork()
if(pid3 == 0){
dup2(pipe2[0],0)
dup2(out,1)
close(pipe2[1])
execvp(afterpipe2)
}
if(pid3 > 0) {
close(pipe2[0])
close(pipe2[1])
wait()
}
}
The position of the second pipe is in the wrong place or the code is altogether wrong.
Any suggestions?
Your main problem is that you are not closing anywhere near enough file descriptors. Given a file input1 in the current directory containing your string "eschew obfuscation\", this code works for me (but note how many file descriptors have to be closed!).
Rule of thumb: if a pipe is dup2()d or dup()d to standard input or output, close both file pipe file descriptors.
Example code (with debug tracing in place):
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/* command pipeline: cat input1 | tr a-z A-Z | tr \\ q */
int main(void)
{
int pipe1[2];
int pipe2[2];
pid_t pid1;
char *cmd1[] = { "cat", "input1", 0 };
char *cmd2[] = { "tr", "a-z", "A-Z", 0 };
char *cmd3[] = { "tr", "\\", "q", 0 };
if (pipe(pipe1) != 0 || pipe(pipe2) != 0)
{
perror("pipe failed");
return 1;
}
pid1 = fork();
if (pid1 < 0)
{
perror("fork 1 failed");
return 1;
}
if (pid1 == 0)
{
/* Child 1 - cat */
dup2(pipe1[1], 1);
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
execvp(cmd1[0], cmd1);
perror("failed to execute cmd1");
return 1;
}
printf("pid 1 = %d\n", pid1);
fflush(stdout);
pid_t pid2 = fork();
if (pid2 < 0)
{
perror("fork 2 failed");
return 1;
}
if (pid2 == 0)
{
/* Child 2 - tr a-z A-Z */
dup2(pipe1[0], 0);
dup2(pipe2[1], 1);
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
execvp(cmd2[0], cmd2);
perror("failed to execute cmd2");
return 1;
}
printf("pid 2 = %d\n", pid2);
fflush(stdout);
pid_t pid3 = fork();
if (pid3 < 0)
{
perror("fork 3 failed");
return 1;
}
if (pid3 == 0)
{
/* Child 3 - tr \\ q */
dup2(pipe2[0], 0);
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
execvp(cmd3[0], cmd3);
perror("failed to execute cmd3");
return 1;
}
printf("pid 3 = %d\n", pid3);
fflush(stdout);
/* Parent - wait for the kids to all die */
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
pid_t corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("Child %d died status 0x%.4X\n", corpse, status);
return 0;
}
execvp(afterpipe)
//pipe2 does not work might need to be placed in different area
dup2(pipe1[1],1)
close(pipe1[0])
execvp(beforepipe1)
I think the execvp() didnot return. So the code below the execvp() is irrelevent.

Resources