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.
Related
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?
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).
I'm writing a program that executes the word count command on the child process. The father process should send a sequence of lines entered by the user trough a pipeline to the child process.
I tried to do this but I ended up with an error.
This is my code:
int main ()
{
int fd[2];
char buff;
int pid;
int pip;
pid = fork();
pip = pipe(fd);
if (pid != 0)
{
pip = pipe(fd);
if (pipe == 0)
{
while (read(fd[0], &buff,1) > 0 )
{
write (fd[1],&buff,1);
}
close(fd[0]);
_exit(0);
}
}
else
{
dup2(fd[1],1);
close(fd[1]);
execlp ("wc","wc",NULL);
_exit(-1);
}
return 0;
}
I've also tried to use dup2 to associate the standard input from the child to the read descriptor of the pipe created by the father process.
But I get this error : wc: standard input: Input/output error.
How can I solve this?
UPDATED (the error is solved but I get an infinite loop)
int main ()
{
int fd[2];
char buff;
int pid;
int pip;
pip = pipe(fd);
if (pip == 0)
{
pid = fork();
if (pid != 0)
{
while (read(fd[0], &buff,1) > 0 )
{
write (fd[1],&buff,1);
}
close(fd[0]);
}
else {
dup2(fd[1],1);
close(fd[1]);
execlp ("wc","wc",NULL);
_exit(-1);
}
}
return 0;
}
#include <unistd.h>
int main ()
{
int fd[2];
char buff;
int pid;
int pip;
int status;
pip = pipe(fd);
if (pip == 0)
{
pid = fork();
if (pid != 0)
{
close(fd[0]);
while (read(0, &buff,1) > 0 )
{
write (fd[1],&buff,1); /* your old loop forwarded internally in the pipe only*/
}
close(fd[1]);
} else {
dup2(fd[0],0); /* you had dup2(fd[1], 1), replacing stdout of wc with the write end from wc */
close(fd[0]);
close(fd[1]);
execlp ("wc","wc",NULL);
_exit(-1);
}
}
wait(&status); /* reap the child process */
return 0;
}
I have been working on creating a pipe in c between two programs, reader.c and writer.c. I haven't been able to get the input for the pipe program to work. The pipe program is supposed to take in a int, send it to the writer program, which then pipes its output into the reader program for the final output. Below is the code for the three classes. I think I am close but can anyone help me get the initial int input argv[2] into the writer class then into the reader class?
pipe program (communicat.c)
int main(int argc, char *argv[])
{
int fd[2];
pid_t childpid;
int result;
if (argc != 2)
{
printf("usage: communicate count\n");
return -1;
}
pipe(fd);
childpid = fork();
if (childpid == -1)
{
printf("Error in fork; program terminated\n");
return -1;
}
if(childpid == 0)
{
close(1);
dup(fd[1]);
execlp("writer", "writer", fd[1],(char *) NULL);
}
else
{
childpid = fork();
}
if( childpid == 0)
{
close(0);
dup(fd[0]);
close(fd[0]);
close(fd[1]);
execlp("reader", "reader", (char *) NULL);
}
else
{
close(fd[0]);
close(fd[1]);
int status;
wait(&status);
}
return(0);
}
Reader.c
int main()
{
int count; /* number of characters in the line */
int c; /* input read */
count = 0;
while ((c = getchar())!= EOF)
{
putchar(c); count++;
if (count == LINELENGTH)
{
putchar('\n'); count = 0;
}
}
if (count > 0)
putchar('\n');
return 0;
}
Writer.c
int main(int argc, char *argv[])
{
int count; /* number of repetitions */
int i; /* loop control variable */
if (argc != 2)
{
printf("usage: writer count\n");
return -1;
}
else count = atoi(argv[1]);
for (i = 0; i < count; i++)
{
printf("Hello");
printf("hello");
}
return 0;
}
Correct the code to exec writer this way:
if(childpid == 0)
{
close(1);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
execlp("writer", "writer", argv[1], (char *) NULL);
}
I want to know that is this possible to code this program with using write(), read() functions. It takes 2 initial arguments with argv[] then fork() and after that child process' stdout passes to parents stdin and result will be showed on screen.
when I execute the program like this ---> ./program date wc
It must show a result as same as date | wc does in shell programming.
I coded this program with dup(). it works fine but I want to other way around. Thank you and sorry for my english.
int main(int argc, char* argv[]){
char* argument1[]={argv[1], NULL};
char* argument2[]={argv[2], NULL};
int fd[2];
int d;
pid_t pid;
char buffer[30];
if(argc < 3){
printf("No parameter");
return 1;
}
if(pipe(fd)==-1){
perror("pipe failed");
exit(1);
}
else{
pid=fork();
if(pid==0){
/*child process*/
close(1);
dup(fd[1]);
close(fd[0]);
//close(fd[1]);
execvp(argument1[0], argument1);
}
else if(pid>0){
/*Parent process*/
close(0);
dup(fd[0]);
close(fd[1]);
//close(fd[0]);
execvp(argument2[0], argument2);
}
}
return 0;
}
Same code with dup2: (I let you make your m_exec function)
int m_pipe(char *cmd1, char *cmd2)
{
int fd[2];
if (pipe(fd) == -1)
{
perror("Pipe failed ");
return (-1);
}
if (fork() == 0)
{
/*Child process*/
dup2(fd[0], 0);
close(fd[1]);
m_exec(cmd2);
}
else
{
/*Parent process*/
dup2(fd[1], 1);
close(fd[0]);
m_exec(cmd1);
}
return (0);
}
int main(int argc, char* argv[])
{
if(argc != 3)
{
write(2, "Usage ./a.out cmd1 cmd2\n", strlen("Usage ./a.out cmd1 cmd2\n"));
return EXIT_FAILURE;
}
if (m_pipe(argv[1], argv[2]) == -1)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}