I got this problem where i want to read from file using read function, but i cant't.
My code does that. I have a parent proccess and a child process. The child does an exec command and i have redirected the stdout to a file f. The parent waits the child and after that is reads from the file it's content and stores it to a buffer. Then i'm sending this output to a client through socket,using send, but that's not the problem. The problem is that even though the txt has content inside from the exec command, read function won't read anything and from my testing it always reads 0 bytes.
//parent
if (wait(&status2)== -1){ // Wait for child
perror("wait");
}
check_child_exit(status2);
n = read(f, buffer, MAX_BUFF-1);
if (n < 0){
error("ERROR reading from File");
}
printf("\n%d\n",n);
n = send(newsockfd,buffer, MAX_BUFF-1,0);
if (n < 0){
perror("ERROR writing to socket");
break;
}
//child
dup2(f,1);
dup2(f,2);
.
.
.
execvp(words[0],words); // Execute date
perror("execvp");
exit(EXIT_FAILURE)
So as you can see these are the 2 processes. I heard from another article that the problem might be on the opening of the file. But im not sure which options to use or not. I even tried to open with open function and fopen function just to try new things.
Here are the open and fopen call:
f = open("temp133",O_RDWR|O_CREAT|O_TRUNC,0755);
if (f==-1){
error_exit("Error Exit");
}
FILE *fd=fopen("tmp","w+");
thanks in advance
Related
Will EXECVP system call supports IO redirections
That means is this give desired output
char *args[]={"cat","A.txt","B.txt",">","C.txt",NULL};
execvp(args[0],args);
I mean will the data in A.txt and B.txt goes to C.txt
If no why ?
UPD : I have asked two doubts in comment please clarify it
This is technically not an answer to your question, that has been answered in the comments. But an explanation to how you can do redirection with execvp
When starting a new program with execvp, it will inherit the current file descriptor. So if you setup file descriptor 1 (which is used for stdout)
to be redirected to "C.txt" before calling execvp, the new program will
write to "C.txt":
// Open "C.txt" for writing, creating it if it doesn't exist, or
// clearing its content if it does exist.
// `mode` should be set as appropriate
//
int fd = creat("C.txt", mode);
if (fd == -1)
{
// Swap out error handling to suit your needs
perror("open failed");
exit(EXIT_FAILURE);
}
// We want new process to have "C.txt" on file descriptor 1
if (dup2(fd, 1) == -1)
{
perror("dup failed");
exit(EXIT_FAILURE);
}
// "C.txt" is now writable on file descriptor 1, so we don't need the
// old one. Actually, the old one could confuse the new executable.
close(fd);
// We can now execute new program. It will inherit current open
// file descriptors and it will see "C.txt" on file descriptor 1
char *args[]={"cat","A.txt","B.txt",NULL};
execvp(args[0],args);
// If we reach this point, `execvp` failed.
perror("execvp failed");
exit(EXIT_FAILURE);
I want to make a simple program that uses fifo. I compiled this code and when I run it the console is waiting for an input. I tried to put a printf on first line and it doesn t appear on console.
int main(){
char* fifo = "./f";
int x = mkfifo(fifo, 0700);
if ( x == -1){
perror("error open");
exit(EXIT_FAILURE);
}
int f = open (fifo, O_WRONLY);
if ( f == -1){
perror("error open");
exit(EXIT_FAILURE);
}
close(f);
unlink(fifo);
return 0;
}
In console I run it like this
./x
and nothing happens, just the cursor is going next line and is waiting for input.
Why is my program not running?
From the mkfifo() man page:
Opening a FIFO for reading normally blocks until some other process opens the same FIFO for writing, and vice versa. See fifo(7) for nonblocking handling of FIFO special files.
So after your call to open(), your process is put on hold until another process opens the fifo with read access. Which in your case never happens.
i want to redirect the output of an unnamed pipe to an opened log file in c but i can't seem to make it happen, my code looks like this:
close(fildes[1]);
FILE * file = fopen(logfile, "w");
int fd = fileno(file);
if (fd == -1) {
bail_out(EXIT_FAILURE, strerror(errno));
}
/* if (dup2(fd, fildes[0]) == -1) {
bail_out(EXIT_FAILURE, strerror(errno));
} */
/* for testing purposes */
char reading_buf[3];
while(read(fildes[0], reading_buf, 3) > 0) {
write(fd, reading_buf, 1);
}
(void)wait(&status);
close(fildes[0]);
break;
the pipe gets filled, i've tested that with the while loop at the bottom. but when i comment out the dup2 call nothing gets redirected to the file. i think i don't fully understand dup2 and pipes.
Also: if i dup2 the reading end of the pipe and then close the original fildes[0], does the pipe get closed? or is it simply the FD that gets closed. not entirely should about that either..
To redirect output from a pipe to a file, somebody needs to read from the read end of the pipe and write to the file's file descriptor. It can't be done merely by duping the file descriptors.
For instance, say you have a pipe
int filedes[2];
pipe (filedes);
and a file
FILE *logfile = fopen (logfile_path, "w");
int logfd = fileno (logfile);
you could launch a child process to do the redirection using the cat command
int child = fork ();
if (child == 0) {
// close the write end of the pipe
close (filedes[1]);
// make STDOUT point to the log file
dup2 (logfd, STDOUT_FILENO);
// make STDIN point to the read end of the pipe
dup2 (filedes[0], STDIN_FILENO);
// launch cat
execlp ("cat", "cat", (char*) NULL);
// in case of error
exit (1);
}
Now, whatever is written to the write end of the pipe in the parent will be read by the child executing cat and written to the file.
// close the read end of the pipe, it's not needed in the parent
close (filedes[0]);
// write something
const char *msg = "Hello World!\n";
write (filedes[1], msg, strlen (msg));
// close the write end of the pipe, this will make the child read EOF
close (filedes[1]);
Don't forget to collect the zombie
wait (&status);
and close the file
fclose (logfile);
About your last question, when a file descriptor is duped there will be two of them pointing to the same underlying open file. So, when one of them is closed the file remains open for it can be accessed through other descriptor.
This is explained in the close man page:
If fd is the last file descriptor referring to the underlying open file
description (see open(2)), the resources associated with the open file
description are freed;
This is just a small part of a bigger program but Im trying to get the output from execvp
I have execvp set up correctly with dup2 that directs it into a pipe.
My problem comes when it comes to using read to read the full length of the pipe I don't know how large the output of execvp is each time cause it can be different depending on the input.
int fd[2];
pipe(fd);
pid_t pid = fork();
if (pid == 0) {
close(fd[0]);
dup2(fd[1], 1);
execvp(msg.v,(char *[]){msg.v,NULL});
} else if (pid > 0) {
close(fd[1]);
read(fd[0],msg.v,....);
}
I have tried a few different sizes for read but its either not enough or I end up getting random junk at the end I know you can use popen and a few other things from stdio but its required for the assignment that we do not use them Im blanking on other ways to go about getting the output.
A little more useless info the whole program is part of a server. Im making a server and a client.. start the server give the client a terminal command it sends it over to the server over a INET stream and sending the output back to the client to display output all without stdio.
You have to pay attention to how much data read returns into your buffer. While read is returning positive numbers, you have more data. When the program is done, it will close its end of the pipe, and your read will return 0.
} else if (pid > 0) {
close(fd[1]);
ssize_t r = read(fd[0],buf,bufsz);
if (r > 0) do {
/* ... do something with r bytes in buf */
r = read(fd[0],buf,bufsz);
} while (r > 0);
if (r < 0) {
perror("read");
/*...*/
}
}
If you see read give an "Interrupted system call" error, then you have encountered the EINTR case that caf mentioned. You restart your read again in that case.
for (;;) {
r = read(fd[0],buf,bufsz);
if (r != -1 || errno != EINTR) break;
}
I am assuming you are not doing non-blocking I/O, so you will not encounter the "Resource temporarily unavailable" message.
You keep reading until read() returns 0, which indicates EOF (or -1 with errno set to a permanent error, which is anything other than EAGAIN or EINTR).
You must not ignore the return value of read() - it tells you how many bytes it has returned. That's why you're seeing "junk" at the end of the buffer - in those cases read() was not filling the whole buffer, and you ignored the return value so you don't know how much it actually returned.
I've run into a problem while trying to send data through pipes, to be more exact: i do not get non-null file descriptors for pipe.
Here is the code for creation of the pipe:
//PIPE is defined as a "/tmp/my.fifo"
umask(0);
...
mknod(PIPE,S_IFIFO,0);
...
p=fopen(PIPE,"w");
if (p)
{
//fprintf(p,"some message");
fclose(p);
}
else
printf("Could not open the pipe\n");
Here is the code for reading from the pipe:
cos_pipe = fopen(PIPE,"r");
if (cos_pipe)
{
fgets(buffer,80,cos_pipe);
...
fclose(cos_pipe);
}
else
{
printf("Couldn't open the pipe\n");
usleep(300000);
}
Code is compiled into two different bineries that i launch separately. All the output i get is "Couldn't open the pipe".
On somewhat related note: should the program that created pipe delete it later?
The mode argument requires permissions too. Use S_IFIFO|S_IRUSR|S_IWUSR.
Consider using the mkfifo function instead:
mkfifo(PIPE,S_IRUSR|S_IWUSR)
You should remove the pipe when you are done using it. Also, what happens if more than one instance of your program is running at once - you're using a fixed name for the pipe.