Restoring stdout after using dup

南楼画角 提交于 2020-07-23 03:04:13

问题


Using fork I created a child and in the child I'm executing the ls command using execl. To send the output to parent,I used pipe and dup. The parent then prints the output. The code gives the expected output, but when I tried to restore back the stdout which I saved initially in stdout_holder, nothing is printed on terminal (when I used printf("hello") or the execl statement below it). However after few observations, it is observed that hello is printed only when nothing is done after redirecting "1" for the first time. (If I don't do anything after dup(fd[1],1) and simply do dup(stdout_holder,1) ) Why is this happening?

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<string.h>
int main()
 {int fd[2],stdout_holder;
 char str;
 pid_t pid;
 pipe(fd);
 pid=fork();
 if(pid==0)
  { stdout_holder=dup(1);
    close(fd[0]);
   printf("stdout_holder=%d\n",stdout_holder); 
   fd[1]=dup2(fd[1],1);
   execl("/bin/ls","ls","-l",NULL);
   stdout_holder=dup2(stdout_holder,1);
   printf("hello\n"); //Terminal doesnt show output.
   execl("/bin/ls","ls","-l",NULL); //Terminal doesnt show output

 }
else
 { close(fd[1]);
   wait(&pid);
   while(read(fd[0],&str,1)>0)
   printf("%c",str);
  } 
}

回答1:


There are multiple issues:

  1. execl() does not return (except if there is an error), you need to fork() again or use e.g. system(). On execl the buffers are not emptied automatically, so the printf output does (at least for me) not reach stdout.

  2. The first output of printf("stdout_holder= ... and ls goes directly to stdout, not through the pipe (stdout is not replaced). You would need to use dup2() at the first place or close(1) before the dup() call..




回答2:


Whenever you place a call to the execl(execv, execlp, etc.), it starts the execution of a new program (creates a new process image). The execution of this new program causes the process to forget all about its previous process image. The execl function does not return to the same process image unless it encounters some error.

if(pid==0)
  { stdout_holder=dup(1);
    close(fd[0]);
   printf("stdout_holder=%d\n",stdout_holder); 
   fd[1]=dup2(fd[1],1);
   execl("/bin/ls","ls","-l",NULL); //creates a new process image
   //will never reach here unless there is an error in the execl call
   stdout_holder=dup2(stdout_holder,1);//Line 7
   printf("hello\n");
   execl("/bin/ls","ls","-l",NULL);// Line 9
 }

After the child process finishes the first execl call, it will terminate, and hence will never reach the remaining code (from line 7 to line 9). Executing a new process image completely changes the contents of the memory, copying only the argument and environment strings to the new locations.

Hope this answers your question.




回答3:


As in line 63 of this file you should save stdout file descriptor before changing it:

int moutfd = dup(STDOUT_FILENO);
dup2(fd, STDOUT_FILENO);

// Do the going-to-be-buffered jobs

dup2(moutfd, STDOUT_FILENO);
close(moutfd);
close(fd);


来源:https://stackoverflow.com/questions/34945049/restoring-stdout-after-using-dup

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!