Team-FLY |
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 .
Unlike many other I/O functions, mkfifo does not set errno to EINTR . Example 6.8The 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.9The 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.cThe 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.cThe 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.10What 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.cThe 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; } |
Team-FLY |