6.3 FIFOs
Pipes are temporary in the sense that they disappear when no process has them open. POSIX represents FIFOs or named pipes by special files that persist even after all processes have closed them. A FIFO has a name and permissions just like an ordinary file and appears in the directory listing given by ls. Any process with the appropriate permissions can access a FIFO. Create a FIFO by executing the mkfifo command from a shell or by calling the mkfifo function from a program.
The mkfifo function creates a new FIFO special file corresponding to the pathname specified by path. The mode argument specifies the permissions for the newly created FIFO.
SYNOPSIS
#include <sys/stat.h>
int mkfifo(const char *path, mode_t mode); POSIX
If successful, mkfifo returns 0. If unsuccessful, mkfifo returns �1 and sets errno. A return value of �1 means that the FIFO was not created. The following table lists the mandatory errors for mkfifo.
|
EACCES | search permission on a component of path prefix denied, or write permission on parent directory of FIFO denied | EEXIST | named file already exists | ELOOP | a loop exists in resolution of path | ENAMETOOLONG | length of path exceeds PATH_MAX, or a pathname component is longer than NAME_MAX | ENOENT | component of path prefix specified by path does not name existing file, or path is an empty string | ENOSPC | directory to contain new file cannot be extended, or the file system is out of resources | ENOTDIR | component of path prefix is not a directory | EROFS | the named file would reside on a read-only file system |
Unlike many other I/O functions, mkfifo does not set errno to EINTR.
Example 6.8
The following code segment creates a FIFO, myfifo, in the current working directory. This FIFO can be read by everybody but is writable only by the owner.
#define FIFO_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
if (mkfifo("myfifo", FIFO_PERMS) == -1) perror("Failed to create myfifo");
Remove a FIFO the same way you remove a file. Either execute the rm command from a shell or call unlink from a program. Example 6.9 shows a code segment that removes the FIFO that Example 6.8 created. The code assumes that the current working directory of the calling program contains myfifo.
Example 6.9
The following code segment removes myfifo from the current working directory.
if (unlink("myfifo") == -1) perror("Failed to remove myfifo");
Program 6.4 creates a named pipe from a path specified on the command line. It then forks a child. The child process writes to the named pipe, and the parent reads what the child has written. Program 6.4 includes error checking, identifying each message with the process ID. This identification of messages is important because the parent and child share standard error.
Program 6.4 parentchildfifo.c
The parent reads what its child has written to a named pipe.
#include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #define BUFSIZE 256 #define FIFO_PERM (S_IRUSR | S_IWUSR)
int dofifochild(const char *fifoname, const char *idstring); int dofifoparent(const char *fifoname);
int main (int argc, char *argv[]) { pid_t childpid;
if (argc != 2) { /* command line has pipe name */ fprintf(stderr, "Usage: %s pipename\n", argv[0]); return 1; } if (mkfifo(argv[1], FIFO_PERM) == -1) { /* create a named pipe */ if (errno != EEXIST) { fprintf(stderr, "[%ld]:failed to create named pipe %s: %s\n", (long)getpid(), argv[1], strerror(errno)); return 1; } } if ((childpid = fork()) == -1){ perror("Failed to fork"); return 1; } if (childpid == 0) /* The child writes */ return dofifochild(argv[1], "this was written by the child"); else return dofifoparent(argv[1]); }
The dofifochild function of Program 6.5 shows the actions taken by the child to write to the pipe. Notice that Program 6.5 uses snprintf rather than sprintf to construct the message. The first three parameters to snprintf are the buffer address, the buffer size and the format string. The snprintf does not write beyond the specified size and always inserts a null character to terminate what it has inserted. Program 6.5 also uses r_write instead of write to make sure that the child writes the entire message.
Program 6.5 dofifochild.c
The child writes to the pipe and returns.
#include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/stat.h> #include "restart.h" #define BUFSIZE 256
int dofifochild(const char *fifoname, const char *idstring) { char buf[BUFSIZE]; int fd; int rval; ssize_t strsize;
fprintf(stderr, "[%ld]:(child) about to open FIFO %s...\n", (long)getpid(), fifoname); while (((fd = open(fifoname, O_WRONLY)) == -1) && (errno == EINTR)) ; if (fd == -1) { fprintf(stderr, "[%ld]:failed to open named pipe %s for write: %s\n", (long)getpid(), fifoname, strerror(errno)); return 1; } rval = snprintf(buf, BUFSIZE, "[%ld]:%s\n", (long)getpid(), idstring); if (rval < 0) { fprintf(stderr, "[%ld]:failed to make the string:\n", (long)getpid()); return 1; } strsize = strlen(buf) + 1; fprintf(stderr, "[%ld]:about to write...\n", (long)getpid()); rval = r_write(fd, buf, strsize); if (rval != strsize) { fprintf(stderr, "[%ld]:failed to write to pipe: %s\n", (long)getpid(), strerror(errno)); return 1; } fprintf(stderr, "[%ld]:finishing...\n", (long)getpid()); return 0; }
The dofifoparent function of Program 6.6 shows the actions taken by the parent to read from the pipe.
Exercise 6.10
What happens to the named pipe after the processes of Program 6.4 exit?
Answer:
Since neither process called unlink for the FIFO, it still exists and appears in the directory listing of its path.
Program 6.6 dofifoparent.c
The parent reads what was written to a named pipe.
#include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/stat.h> #include "restart.h" #define BUFSIZE 256 #define FIFO_MODES O_RDONLY
int dofifoparent(const char *fifoname) { char buf[BUFSIZE]; int fd; int rval;
fprintf(stderr, "[%ld]:(parent) about to open FIFO %s...\n", (long)getpid(), fifoname); while (((fd = open(fifoname, FIFO_MODES)) == -1) && (errno == EINTR)) ; if (fd == -1) { fprintf(stderr, "[%ld]:failed to open named pipe %s for read: %s\n", (long)getpid(), fifoname, strerror(errno)); return 1; } fprintf(stderr, "[%ld]:about to read...\n", (long)getpid()); rval = r_read(fd, buf, BUFSIZE); if (rval == -1) { fprintf(stderr, "[%ld]:failed to read from pipe: %s\n", (long)getpid(), strerror(errno)); return 1; } fprintf(stderr, "[%ld]:read %.*s\n", (long)getpid(), rval, buf); return 0; }
|
No comments:
Post a Comment