I have the following code:
pid_t childProcessID;
childProcessID = fork();
if (childProcessID == -1) {
printf("fork failed");
exit(EXIT_FAILURE);
}
if (childProcessID == 0) {
printf("reached child\n");
close(STDOUT_FILENO);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
close(fd[0]);
printf("about to execute child command\n");
if (fork() == 0) {
execve(argv1[0], argv1, NULL);
printf("Command not found.");
exit(1);
}
else {
wait(NULL);
}
}
else {
printf("reached parent, but wait for child to finish\n");
waitpid(childProcessID, &child_status, NULL);
printf("child finished\n");
close(STDIN_FILENO);
dup2(fd[0], 0);
close(fd[1]);
printf("About to executed piped command\n");
if (fork() == 0) {
execve(argv2[0], argv2, NULL);
printf("Command not found");
exit(1);
}
else {
wait(NULL);
}
}
When I run my minishell and give it the input nl parse.c | wc -l, My minishell prints out:
reached parent, but wait for child to finish
reached child
And nothing underneath. The program is clearly still running but nothing is being printed. Why is my child not executing the rest of the code? argv1[] and argv[2] are initialized and work fine.
When you do :
dup2(fd[1], STDOUT_FILENO)
This code tells the process to redirect its STDOUT: Standard Output, i.e. the print commands and everything that gets printed on terminal to file descriptor fd[1].
So your child process executes and prints everything as it is supposed to,but not on the terminal. To see the output on terminal, comment the line :
//dup2(fd[1], STDOUT_FILENO)
Related
For my piping function, I am creating two child processes with fork() and attempting to pipe the contents of the first over to the second child process before calling execvp(). I am doing something wrong, as if I do ls -la | more, the output is a vertical list of the files in the directory. I am very new to piping in c (and c) so chances are that it is an overlooked mistake. Any help is appreciated!
void handle_pipe_cmds(char **args1, char **args2){
char ** word1 = parse_space(*args1);
char ** word2 = parse_space(*args2);
int p[2];
pipe(p);
pid_t pid = fork();
if (pid == -1) {
printf("CANNOT FORK!");
} else if (pid == 0) {
dup2(p[1], STDOUT_FILENO);
close(p[1]);
int status = execvp(word1[0], word1);
if (status != 0) {
printf("%s failed\n", word1[0]);
exit(1);
}
exit(0);
} else {
close(p[1]);
wait(NULL);
}
pid = fork();
if (pid == -1) {
printf("CANNOT FORK!");
} else if (pid == 0) {
dup2(p[0], STDIN_FILENO);
close(p[1]);
close(p[0]);
int status = execvp(word2[0], word2);
if (status != 0) {
printf("%s failed\n", word2[0]);
exit(1);
}
exit(0);
} else {
close(p[1]);
close(p[0]);
wait(NULL);
}
}
If I do ls -la | more, the output is a vertical list of the files in the directory.
That is because the ls program is aware of whether its output stream is a terminal or not, and acts different in both cases. On a terminal, it (may) print colorized entries, and multiple items per line; to a pipe, or a file, it will print just one entry per line with no color. See man ls for details.
For some unknown reason, when I'm executing piped commands in my shell program, they're only outputting once I exit the program, anyone see why?
Code:
int execCmdsPiped(char **cmds, char **pipedCmds){
// 0 is read end, 1 is write end
int pipefd[2];
pid_t pid1, pid2;
if (pipe(pipefd) == -1) {
fprintf(stderr,"Pipe failed");
return 1;
}
pid1 = fork();
if (pid1 < 0) {
fprintf(stderr, "Fork Failure");
}
if (pid1 == 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(pipedCmds[0], pipedCmds) < 0) {
printf("\nCouldn't execute command 1: %s\n", *pipedCmds);
exit(0);
}
} else {
// Parent executing
pid2 = fork();
if (pid2 < 0) {
fprintf(stderr, "Fork Failure");
exit(0);
}
// Child 2 executing..
// It only needs to read at the read end
if (pid2 == 0) {
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
if (execvp(cmds[0], cmds) < 0) {
//printf("\nCouldn't execute command 2...");
printf("\nCouldn't execute command 2: %s\n", *cmds);
exit(0);
}
} else {
// parent executing, waiting for two children
wait(NULL);
}
}
}
Output:
In this example of the output, I have used "ls | sort -r" as the example, another important note is that my program is designed to only handle one pipe, I'm not supporting multi-piped commands. But with all that in mind, where am I going wrong, and what should I do to fix it so that it's outputting within the shell, not outside it. Many thanks in advance for any and all advice and help given.
The reason would be your parent process file descriptors are not closed yet. When you wait for the second command to terminate, it hangs because the writing end is not closed so it wait until either the writing end is closed, or new data is available to read.
Try closing both pipefd[0] and pipefd[1] before waiting for process to terminate.
Also note that wait(NULL); will immediately return when one process has terminated, you would need a second one as to not generate zombies if your process still runs after that.
i am trying to create a shell program to execute piped command. When i call ls from forked child & wc from parent it works fine. but if i call wc also from forked child parent keeps on waiting (i don't know why this is happening).
void execPiped(char** Args,char** pipedArgs)
{
int pfds[2];
pipe(pfds);
pid_t pid1 = fork();
if (pid1 == -1)
{
printf("\nFailed forking child..");
return;
}
else if (pid1 == 0) //CHILD 1 EXECUTING
{
close(1); //close STDOUT
dup(pfds[1]); //set pfds as STDOUT
close(pfds[0]); //we don't need this
if (execvp(Args[0], Args) < 0)
{
printf("\nCould not execute command..");
exit(1);
}
}
else {
pid_t pid2 = fork();
if (pid2 == -1)
{
printf("\nFailed forking child..");
return;
}
else if (pid2 == 0) //CHILD 2 EXECUTING
{
close(0); //close STDIN
dup(pfds[0]); //set pfds as STDIN
close(pfds[1]); //we don't need this
if (execvp(pipedArgs[0], pipedArgs) < 0)
{
printf("\nCould not execute command..");
exit(1);
}
}
else { //Parent Executing
//Wating for Children to exit
wait(NULL);
wait(NULL);
}
return;
}
}
I am using pipe fork and exec, to implement a generic pipe for any two shell programs. I am specifically using ls | grep to test it. It works, the data gets copied over to grep, grep searches for matches and then outputs them to stdout. However after that the program just hangs.
This is my code that is executed when a pipe is detected. I fork, and then fork again because I wish to have the parent process of the first fork continue to run after the exec calls. I believe due to debug code that after the exec() call that executes grep is made that nothing is happening.
if(pipeFlag == 1){
pipe(fd);
PID = fork();
if (PID == 0){//child process
fPID = fork();
if(fPID == 0){//child of child
printf("in child of child\n");
dup2(fd[1], 1);
execvp(command, argv);//needs error checking
printf("mysh: %s: command not found\n", argv[0]);
exit(EXIT_FAILURE);
}
if(fPID > 0){//parent of 2nd child
printf("in parent of 2nd child\n");
dup2(fd[0], 0);
execvp(command1, argv1);//needs error checking
printf("mysh: %s: command not found\n", argv[0]);
exit(EXIT_FAILURE);
}
if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
}
if(PID > 0){//parent
wait(PID, 0, 0);
printf("in outer parent\n");
}
if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
}
Below is my solution to the problem. I'm not sure if it's a permanent solution. I'm not even 100% sure if my reasoning for why this works and the previous code did not isn't. All I did was switch the command that is waiting for input from the pipe(grep) to the parent process, and the command writing output to the pipe(ls) to the child process.
My reasoning for why this works is thus: I was testing with ls | grep, ls was finished writing to the pipe before grep's child process ever got set up, and therefore never closed the pipe and grep never received EOF. By changing their position grep was ready and waiting for ls to write by the time the process running ls is set up. I believe that this is a very imperfect fix, so for anyone who reads this in the future, I hope you can provide a better answer. There are a number of conditions I can think of where this could still mess up, if my reasoning for why it works is correct.
if(pipeFlag == 1){
pipe(fd);
PID = fork();
if (PID == 0){//child process
fPID = fork();
if(fPID == 0){//child of child
printf("in child of child\n");
dup2(fd[0], 0);
execvp(command1, argv1);//needs error checking
printf("mysh: %s: command not found\n", argv[0]);
exit(EXIT_FAILURE);
}
if(fPID > 0){//parent of 2nd child
printf("in parent of 2nd child\n");
dup2(fd[1], 1);
execvp(command, argv);//needs error checking
printf("mysh: %s: command not found\n", argv[0]);
exit(EXIT_FAILURE);
}
if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
}
if(PID > 0){//parent
wait(PID, 0, 0);
printf("in outer parent\n");
}
if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
}
I am implementing a shell in C. This is the function i use for piping. When i put "ls | a" in the code (i.e. pipe a valid command with invalid one),It doesnt exit the child process like it should. How do i make it go back to main function?
same thing happens when i do ps | ls or ps | pwd etc. but ls | ps works the same as in bash. i know ls | ps or ps | ls dont make sense but atleast they should give same output as bash.
void exec3(char **args, char **args2){
int fd[2];
pid_t pid,pid1;
int status;
pipe(fd);
int e=0;
if ((pid = fork()) < 0) {
printf("*** ERROR: forking child process failed\n");
exit(1);
}
else if ((pid1 = fork()) < 0) {
printf("*** ERROR: forking child process failed\n");
exit(1);
}
else if (pid == 0 && pid1!=0){
printf("in 1\n");
close(1);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
if(execvp(args[0],args)<0){
printf("**error in exec");
close(fd[0]);
close(fd[1]);
exit(1);
}
//printf("exiting 1\n");
exit(0);
}
else if (pid1 == 0 && pid!=0) {
printf("in 2\n");
close(0);
dup(fd[0]);
close(fd[1]);
close(fd[0]);
if((e=execvp(args2[0],args2))<0){
printf("**error in exec2 ");
close(fd[0]);
close(fd[1]);
exit(1);
}
exit(0);
}
else {
close(fd[0]);
close(fd[1]);
fflush(stdout) ;
while (wait(&status) != pid);
while (wait(&status) != pid1);
}
}
You are close to the solution. Look at how popen() is implemented, that is what you are trying to do.