When my program starts, it just creates a fifo and opens it, after that I just want to output some information to the screen, however, nothing gets printed out. Here's a snippet of my code:
void listen(const server_config_t* server_conf)
{
// Create FIFO
if (mkfifo(SERVER_FIFO_PATH, 0660) == -1) {
fprintf(stdout, "server FIFO not created as it already exists. continuing...\n");
}
// Open FIFO (for reading)
int fd;
if ((fd = open(SERVER_FIFO_PATH, O_RDONLY)) == -1) {
// fprintf(stderr, "error: could not open server FIFO\n");
perror("FIFO");
exit(1);
}
// Open dummy FIFO (for writing, prevent busy waiting)
// TODO: find way to wait without another file descriptor?
int fd_dummy;
if ((fd_dummy = open(SERVER_FIFO_PATH, O_WRONLY)) == -1) {
perror("DUMMY FIFO");
exit(1);
}
// TODO: this should print immediately after starting,
// but doesn't for some reason
fprintf(stdout, "server listening... %d %s\n", server_conf->num_threads,
server_conf->password);
fflush(stdout);
.
.
.
}
Here's my output:
I've tried commenting out the fifo creation and opening, and when I do that the message gets printed correctly to the screen.
Opening a FIFO normally blocks until the other end is opened as well, see http://man7.org/linux/man-pages/man7/fifo.7.html. So your program probably waits in open(SERVER_FIFO_PATH, O_RDONLY) and does not reach any other fprintf or perror.
Your attempt to open the FIFO for reading first and then for writing does not work because the first open does not return.
You should be able to see this when you step through your program using a debugger.
BTW: When mkfifo returns -1 you should check if errno is EEXIST. There could be other errors that would also result in return value -1, see https://linux.die.net/man/3/mkfifo
As you can see from your output, there is blocking. That is, your current process cannot go on until the other end of the FIFO is opened for write. You should glance at the man page.
As to your error, there are two cases maybe the directory into which you want to place the FIFO doesn't permit to do that. Second case may be due to a system error. To overcome the issue, you need to change your fprintf as following.
#include <string.h>
#include <stdlib.h>
..
..
fprintf(stderr, "server FIFO not created as it already exists. Error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
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 am currently writing a piece of code whose intended usage is this:
program input.txt output.txt
or
program input.txt
in which case it defaults to stdout.
This is the code I have now (within main()):
FILE *outFile;
if (argc < 3) {
outFile = stdout;
} else {
fprintf(stdout, "Will output to file %s\n", argv[2]);
outFile = fopen(argv[2], "w");
if (outFile == NULL) {
fprintf(stderr, "ERR: Could not open file %s. Defaulting to stdout\n", argv[2]);
outFile = stdout;
}
}
/* ... write stuff to outFile... */
if (argc < 3 && outFile != stdout) {
fclose(outFile);
}
These are my concerns: first of all, will this successfully open and close outFile when provided? Also, will this successfully not close stdout? Can anything bad happen if I close stdout?
Also, is this portable? I compile with gcc but this project will be evaluated by a professor using Windows.
Apologies if this is a bit of a mess of a question. I come from Python and am not a CS major (I'm studying mathematics).
Yes, it's portable and it's okay.
Yes, it's portable. You assigned outfile = stdout, so they will be equal as long as you don't reassign either of them elsewhere in the program.
You don't really need the argc < 3 test as well -- the two conditions should always be the same, since you only do the assignment when that's true.
In any program that writes significant data to stdout, you should close stdout immediately before exiting, so that you can check for and report delayed write errors. (Delayed write errors are a design mistake; it ought to be impossible for fclose or close to fail. But we are stuck with them.)
The usual construct is, at the very end of main,
if (ferror(stdout) || fclose(stdout)) {
perror("stdout: write error");
return 1;
}
return 0;
Some programs stick an fflush in there too, but ISO C requires fclose to perform a fflush, so it shouldn't be necessary. This construct is entirely portable.
It's important for this to be the very last thing you do before exiting. It is relatively common for libraries to assume that stdout is never closed, so they may malfunction if you call into them after closing stdout. stdin and stderr are also troublesome that way, but I've yet to encounter a situation where one wanted to close those.
It does sometimes happen that you want to close stdout before your program is completely done. In that case you should actually leave the FILE open but close the underlying "file descriptor" and replace it with a dummy.
int rfd = open("/dev/null", O_WRONLY);
if (rfd == -1) perror_exit("/dev/null");
if (fflush(stdout) || close(1)) perror_exit("stdout: write error");
dup2(rfd, 1);
close(rfd);
This construct is NOT portable to Windows. There is an equivalent, but I don't know what it is. It's also not thread-safe: another thread could call open in between the close and dup2 operations and be assigned fd 1, or it could attempt to write something to stdout in that window and get a spurious write error. For thread safety you have to duplicate the old fd 1 and close it via that handle:
// These allocate new fds, which can always fail, e.g. because
// the program already has too many files open.
int new_stdout = open("/dev/null", O_WRONLY);
if (new_stdout == -1) perror_exit("/dev/null");
int old_stdout = dup(1);
if (old_stdout == -1) perror_exit("dup(1)");
flockfile(stdout);
if (fflush(stdout)) perror_exit("stdout: write error");
dup2 (new_stdout, 1); // cannot fail, atomically replaces fd 1
funlockfile(stdout);
// this close may receive delayed write errors from previous writes
// to stdout
if (close (old_stdout)) perror_exit("stdout: write error");
// this close cannot fail, because it only drops an alternative
// reference to the open file description now installed as fd 1
close (new_stdout);
Order of operations is critical: the open, dup and fflush calls must happen before the dup2 call, both close calls must happen after the dup2 call, and stdout must be locked from before the fflush call until after the dup2 call.
Additional possible complications, dealing with which is left as an exercise:
Cleaning up temporary fds and locks on error, when you don't want to stop the whole program on error
If the thread might be canceled mid-operation
If a concurrent thread might call fork and execve mid-operation
I'm having some trouble using dup2 in trying to redirect both stdout and stderr into the same output file.
I'm using this explanatory code sample: (gcc 4.8.2, Ubuntu 14.04)
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#define USE2FILES
int main()
{
int f1, f2, status;
f1 = open("test.out", O_CREAT | O_WRONLY, 0644);
if (f1 == -1) {
perror("open(): ");
}
status = dup2(f1, STDOUT_FILENO);
if (status == -1) {
perror("dup2(): ");
}
#ifdef USE2FILES
close(f1);
#endif
#ifdef USE2FILES
f2 = open("test.out", O_CREAT | O_WRONLY, 0644);
if (f2 == -1) {
perror("dup2(): ");
}
#else
f2 = f1;
#endif
status = dup2(f2, STDERR_FILENO);
if (status == -1) {
perror("dup2(): ");
}
close(f2);
fprintf(stderr, "test_stderr1\n");
fprintf(stdout, "test_stdout1\n");
fprintf(stderr, "test_stderr2\n");
fprintf(stdout, "test_stdout2\n");
fprintf(stderr, "test_stderr3\n");
fprintf(stdout, "test_stdout3\n");
fflush(stdout);
fflush(stderr);
return 0;
}
USE2FILES macro is supposed to switch between using either 2 file descriptors (to the same file) which get duped to stdout and stderr respectivly or 1 file descriptor which gets duplicated both to stdout and stderr.
I was under the impression that using 2 distinct file descriptors for redirection should work. However running this piece of code with USE2FILES on issues the following output in test.out:
test_stdout1
test_stdout2
test_stdout3
If I then disable USE2FILES I get:
test_stderr1
test_stderr2
test_stderr3
test_stdout1
test_stdout2
test_stdout3
Seems like in the first case no output towards stderr gets through. Is this behavior to be expected (am I missing something)?
EDIT: After accepted Chris Dodd's answer:
That's indeed a poor example. Changing the fprintf sequence to something like this:
fprintf(stderr, "test_stderr+++++++++++++++++++++++++++++++++++++++++++++++++1\n");
fprintf(stdout, "test_stdout----------------------------------------1\n");
fprintf(stderr, "test_stderr++++++++++++++++++++++++++++++++++2\n");
fprintf(stdout, "test_stdout----------------2\n");
fprintf(stderr, "test_stderr++++++++++++++++++++++++++++3\n");
fprintf(stdout, "test_stdout----------------------3\n");
gets me this test.out output:
test_stdout----------------------------------------1
test_stdout----------------2
test_stdout----------------------3
err++++++++++++++++++++++++++++3
showing pretty clearly stdout & stderr are competing with their writes over the same file.
If you do two open calls, you get two distinct kernel filehandles, each with its own I/O cursor (file offset), so writes to the two file descriptors will overwrite each other. If you use a single open call, you only get a single filehandle that both file descriptors refer to, so each write (to each descriptor) will advance the output offset so the next write (with the other file descriptor) will write after it.
In your example, the strings written are the exact same length, so the write to stdout exactly overwrites the preceeding write to stderr. Note that the file write only occurs when the FILE object is flushed, not (necessarily) when fprintf is called.
You could also get the effect you seem to be trying to get by opening the files in O_APPEND mode. This will cause every write to reposition the write offset to the current end of the file just before actually writing.
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.