I have some troubles with a library function.
I have to write some C code that uses a library function which prints on the screen its internal steps.
I am not interested to its return value, but only to printed steps.
So, I think I have to read from standard output and to copy read strings in a buffer.
I already tried fscanf and dup2 but I can't read from standard output. Please, could anyone help me?
An expanded version of the previous answer, without using files, and capturing stdout in a pipe, instead:
#include <stdio.h>
#include <unistd.h>
main()
{
int stdout_bk; //is fd for stdout backup
printf("this is before redirection\n");
stdout_bk = dup(fileno(stdout));
int pipefd[2];
pipe2(pipefd, 0); // O_NONBLOCK);
// What used to be stdout will now go to the pipe.
dup2(pipefd[1], fileno(stdout));
printf("this is printed much later!\n");
fflush(stdout);//flushall();
write(pipefd[1], "good-bye", 9); // null-terminated string!
close(pipefd[1]);
dup2(stdout_bk, fileno(stdout));//restore
printf("this is now\n");
char buf[101];
read(pipefd[0], buf, 100);
printf("got this from the pipe >>>%s<<<\n", buf);
}
Generates the following output:
this is before redirection
this is now
got this from the pipe >>>this is printed much later!
good-bye<<<
You should be able to open a pipe, dup the write end into stdout and then read from the read-end of the pipe, something like the following, with error checking:
int fds[2];
pipe(fds);
dup2(fds[1], stdout);
read(fds[0], buf, buf_sz);
FILE *fp;
int stdout_bk;//is fd for stdout backup
stdout_bk = dup(fileno(stdout));
fp=fopen("temp.txt","w");//file out, after read from file
dup2(fileno(fp), fileno(stdout));
/* ... */
fflush(stdout);//flushall();
fclose(fp);
dup2(stdout_bk, fileno(stdout));//restore
I'm assuming you meant the standard input. Another possible function is gets, use man gets to understand how it works (pretty simple). Please show your code and explain where you failed for a better answer.
Related
I am trying to use a pipe to rederect stdout into a pipe and read it later. I will use this later with fork(), where the child process starts a different program that I need to comunicate with. This is my Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
int main(){
printf("Starting Test\n");
int myPipe[2], nbytes;
char readbuffer[80];
pipe(myPipe);
int backup = dup(1); //store stdout
if (dup2(1,myPipe[1])< 1){printf("error");} //copy stdout in the input end of my pipe
printf("in pipe\n"); //print something in stdout -> in my pipe
nbytes = read(myPipe[0],readbuffer,sizeof(readbuffer)); //read output of my pipe
dup2(myPipe[1],backup); // restore stdout
printf("recived: %s",readbuffer); //prit out what I recived
return 0;
}
I expected it to print out:
Starting Test
recived: in pipe
But the output that I get is:
Starting Test
in pipe
recived: #����U
So I assume that stdout was not copied properly, as I get the "in pipe" before the "recived: ..." But the dup2() call throws no errors.
I read some tutorials, mostly this one https://tldp.org/LDP/lpg/node11.html but I can't find my error... Thank you for your help!
The code has a couple of problems:
In dup2(1,myPipe[1]) the parameters are back to front. That makes mypipe[1] be the same as 1. But instead you need it to be the other way around: dup2(myPipe[1],1)
dup2(myPipe[1],backup) is also wrong. That makes backup be the same as mypipe[1]. What you want instead is to make 1 the same as backup: dup2(backup, 1).
Smaller problem but printf does not output a NUL character. So the read will not result in a valid NUL terminated string. Solve that by initialising: char readbuffer[80] = "";
I am currently trying to understand combincation of dup2 and C pipes, but not even the simplest program seems to work. Already when reading example codes I am pretty confused on when they close ends of the pipe and where the output should be printed.
Sometimes the write end is closed, even though one line later output should be generated which should go into the pipe. In other examples, the unused end is closed (which makes more sense to me).
Then, I do not understand when dup2 should be executed. I guess it should become before the output I want to redirect, but I have the feeling I also saw that differently today.
So in the end I came up with this little test with printf and fflush in each line, where nothing gets redirected through the pipe. Why's that? What am I doing wrong?
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int out_pipe[2];
char *output[101];
if (pipe(out_pipe) != 0) {
perror("pipe()");
exit(1);
}
printf("Hello");
fflush(stdout);
dup2(out_pipe[1], STDOUT_FILENO);
printf("Hello");
fflush(stdout);
close(out_pipe[1]);
printf("Hello");
fflush(stdout);
read(out_pipe[0], output, 100);
close(out_pipe[0]);
printf("PIPE: %s", output);
fflush(stdout);
return 0;
}
End your printf() messages with newlines; the fflush() is still a good idea as you're about to change where standard output goes, though it's not usually necessary if the standard output of the program is going to a terminal. If the standard output was going to a file and the fflush() was not in place, then you'd get three copies of "Hello\n" written to the pipe.
When you change standard output to the pipe, your message is indeed written to the pipe.
When you close the write file descriptor, you don't run into any issues. You then write a second Hello to the pipe. You need this fflush() to ensure that the standard I/O package has actually written its buffered data to the pipe.
You then read from the pipe into the output buffer. You should check how many bytes you read since the string is not going to be null terminated. You should get 10 bytes read (when you don't have any newlines in the messages).
You then write to the pipe again with the PIPE: prefix.
To fix, write messages to standard error.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int out_pipe[2];
char output[101];
if (pipe(out_pipe) != 0) {
perror("pipe()");
exit(1);
}
printf("Hello\n");
fflush(stdout);
dup2(out_pipe[1], STDOUT_FILENO);
printf("Hello\n");
fflush(stdout);
close(out_pipe[1]);
printf("Hello\n");
fflush(stdout);
int n = read(out_pipe[0], output, sizeof(output));
close(out_pipe[0]);
fprintf(stderr, "PIPE: %.*s\n", n, output);
return 0;
}
Note that I changed the definition of output from an array of char * to a simple array of char. With the changes, I got the output:
$ ./pipe3
Hello
PIPE: Hello
Hello
$
That's because I included newlines in the messages written to the pipe, as well as in the format string that ends up on standard error.
Is there a possibility to "reenable" stdout?
Yes; simply preserve a copy of the original file descriptor for standard output before using dup2(), and then reinstate the copy once you've done with the pipe.
I've removed the two leading fflush() calls, and the sample output demonstrates the difference between terminal and file output:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int out_pipe[2];
char output[101];
int old_stdout;
if (pipe(out_pipe) != 0) {
perror("pipe()");
exit(1);
}
printf("Hello\n");
old_stdout = dup(STDOUT_FILENO);
dup2(out_pipe[1], STDOUT_FILENO);
printf("Hello\n");
close(out_pipe[1]);
printf("Hello\n");
fflush(stdout);
int n = read(out_pipe[0], output, sizeof(output));
close(out_pipe[0]);
dup2(old_stdout, STDOUT_FILENO);
printf("PIPE: %d <<%.*s>>\n", n, n, output);
return 0;
}
Sample outputs:
$ ./pipe3Hello
PIPE: 12 <<Hello
Hello
>>
$./pipe3 > output
'pipe3' is up to date.
$ cat output
PIPE: 18 <<Hello
Hello
Hello
>>
$
If you remove the remaining fflush(), the program hangs. There is nothing in the pipe (because standard I/O hasn't flushed its buffer because it isn't full and the output isn't a terminal any more), but the pipe is open for writing, so the kernel considers that input could appear on it — if only the program that has the pipe open for writing wasn't waiting on the read end of the pipe for the input to appear. The program has deadlocked on itself.
i have the following code
it prints to the screen: haha
to the file :
haha
hello
Father finished
if i remove line 6 and 7 , I get different results
why?
int main()
{
// creates a new file having full read/write permissions
int fd = open("myfile", O_RDWR|O_CREAT, 0666);
write(fd, "haha\n", 5);
close(fd); // line 6
fd = open("myfile", O_RDWR); // line 7
close(0);
close(1);
dup(fd);
dup(fd);
if (fork() == 0)
{
char s[100];
dup(fd);
scanf("%s", s);
printf("hello\n");
write(2, s, strlen(s));
return 0;
}
wait(NULL);
printf("Father finished\n");
close(fd);
return 0;
}
Try to comment out the scanf(), recompile and rerun. The scanf() trying to read beyond EOF might be doing something in the stdio library internal buffers that is causing this issue in printf() buffer not being flushed at the time of process _exit. Just a guess...
A file descriptor has only one position which is used both for writing and reading. When you write to the file in line 4 the position is advanced past what was just written, so the descriptor's position is at the end of the file. Calling close and open has the effect of resetting the position to the beginning of file (among other things).
You could replace the calls to close and open with lseek(fd, 0, SEEK_SET) to have the same effect, without closing and reopening the file.
Also, you should not mix the stdio functions scanf, printf and low level functions such as write. The results of the program will be unpredictable because of buffering in the stdio functions.
I need help to understand the file descriptors
So here is my code:
int main()
{
char ch;
close(1);
//now opening a file so that it gets the lowest possible fd i.e. 1
int fd=open("txt",O_RDWR);
//check..
printf("first printtf is executed\n");
scanf("%c",&ch);
printf("ur value is %c\n",ch);
printf("second printf is executed\n");
return 0;
}
in the above program, I tried to redirect the output of printf to the txt file rather than the standard output, i.e. the terminal.
But how to restore the standard output file descriptor so that the printf again works as normal for the second case, i.e the second printtf should give output to the terminal only..
The simplest way to do this would be to duplicate the output descriptor before closing it. You must look at dup.
Before you close it I think you want to dup() it.
When you need it back, you can dup() the dup.
dup will always use the lowest descriptor
int out = dup(1);
close(1);
int fd = open();
...
close(fd);
dup(out);
close(out);
Warning: this is from memory and untested ;-)
I'm writing a little program, and here is what it should do.
In the main process I have to create a new one and that one should execute another program which only does a printf("text"). I want to redirect the pipe write end on stdout and the main process should read from its pipe read and and print it on stdout. I wrote the code but again and again I get a segmentation fault when the parent process tries to read from the pipe.
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void write_to(FILE *f){
char buf[50];
fprintf(f,"KOMA");
}
int main(){
int cpPipe[2];
int child1_fd;
int child2_fd;
if(pipe(cpPipe) == -1){
fprintf(stderr,"ERROR PIPE creation");
exit(1);
}else{printf("pipe couldn't be created\n");}
child1_fd = fork();
if(child1_fd < 0){
fprintf(stderr, " CHILD creation error");
exit(1);
}
if(child1_fd == 0){
printf("*CHILD*\n");
char program[] = "./Damn";
int dupK;
printf("stdout %d \n", STDOUT_FILENO);
printf("stdin %d \n", STDIN_FILENO);
printf("pipe1 %d \n", cpPipe[1]);
printf("pipe0 %d \n", cpPipe[0]);
// closing pipe write
close(cpPipe[0]);
close(1);
dup(cpPipe[1]);
printf("and");
close(cpPipe[1]);
exit(0);
}else{
printf("*Parent*\n");
char *p;
char *buf;
FILE *pipe_read;
close(cpPipe[1]);
pipe_read = fdopen(cpPipe[0],"r");
while((buf = fgets(p,30,pipe_read)) != NULL){
printf("buf %s \n", buf);
}
wait();
printf("Child is done\n");
fclose(pipe_read);
exit(0);
}
}
Do I have to close the pipe write end when I redirect stdout to it?
Uhm,... the reason for your segmentation fault is here:
buf = fgets(p,30,pipe_read);
p is a pointer to essentially nowhere of importance. It's content is whatever is in the stack at the time of execution, you never initialize it. You need it to point to a chunk of memory you can use! Assign the return of a malloc() call to it, or declare it as char p[LEN].
Edit: you are also reopening already open file descriptors. Check the documentation on fgets and pipe, I think you are confused as to how they work.
Now, that said, the flow of your function is kinda confusing. Try working on clarifying it! Remember, code is meant to express intentions, ideas of functionality. Try using pencil and paper to organize your program, and then write it as actual code :).
Cheers!
Do I have to close the pipe write end when I redirect stdout to it?
In general, yes, because while there is a process with the write end of the pipe open, the processes reading the pipe will not get EOF and will hang. It is also tidy to close file descriptors you aren't going to use, of course.
Your code also says "pipe could not be created" in the success path.