1/*++ 2/* NAME 3/* fifo_listen 3 4/* SUMMARY 5/* start fifo listener 6/* SYNOPSIS 7/* #include <listen.h> 8/* 9/* int fifo_listen(path, permissions, block_mode) 10/* const char *path; 11/* int permissions; 12/* int block_mode; 13/* DESCRIPTION 14/* The \fBfifo_listen\fR routine creates the specified named pipe with 15/* the specified permissions, opens the FIFO read-write or read-only, 16/* depending on the host operating system, and returns the resulting 17/* file descriptor. 18/* The \fIblock_mode\fR argument is either NON_BLOCKING for 19/* a non-blocking socket, or BLOCKING for blocking mode. 20/* DIAGNOSTICS 21/* Fatal errors: all system call failures. 22/* LICENSE 23/* .ad 24/* .fi 25/* The Secure Mailer license must be distributed with this software. 26/* AUTHOR(S) 27/* Wietse Venema 28/* IBM T.J. Watson Research 29/* P.O. Box 704 30/* Yorktown Heights, NY 10598, USA 31/*--*/ 32 33/* System interfaces. */ 34 35#include <sys_defs.h> 36#include <sys/stat.h> 37#include <errno.h> 38#include <fcntl.h> 39#include <unistd.h> 40 41/* Utility library. */ 42 43#include "msg.h" 44#include "iostuff.h" 45#include "listen.h" 46#include "warn_stat.h" 47 48#define BUF_LEN 100 49 50/* fifo_listen - create fifo listener */ 51 52int fifo_listen(const char *path, int permissions, int block_mode) 53{ 54 char buf[BUF_LEN]; 55 static int open_mode = 0; 56 const char *myname = "fifo_listen"; 57 struct stat st; 58 int fd; 59 int count; 60 61 /* 62 * Create a named pipe (fifo). Do whatever we can so we don't run into 63 * trouble when this process is restarted after crash. Make sure that we 64 * open a fifo and not something else, then change permissions to what we 65 * wanted them to be, because mkfifo() is subject to umask settings. 66 * Instead we could zero the umask temporarily before creating the FIFO, 67 * but that would cost even more system calls. Figure out if the fifo 68 * needs to be opened O_RDWR or O_RDONLY. Some systems need one, some 69 * need the other. If we choose the wrong mode, the fifo will stay 70 * readable, causing the program to go into a loop. 71 */ 72 if (unlink(path) && errno != ENOENT) 73 msg_fatal("%s: remove %s: %m", myname, path); 74 if (mkfifo(path, permissions) < 0) 75 msg_fatal("%s: create fifo %s: %m", myname, path); 76 switch (open_mode) { 77 case 0: 78 if ((fd = open(path, O_RDWR | O_NONBLOCK, 0)) < 0) 79 msg_fatal("%s: open %s: %m", myname, path); 80 if (readable(fd) == 0) { 81 open_mode = O_RDWR | O_NONBLOCK; 82 break; 83 } else { 84 open_mode = O_RDONLY | O_NONBLOCK; 85 if (msg_verbose) 86 msg_info("open O_RDWR makes fifo readable - trying O_RDONLY"); 87 (void) close(fd); 88 /* FALLTRHOUGH */ 89 } 90 default: 91 if ((fd = open(path, open_mode, 0)) < 0) 92 msg_fatal("%s: open %s: %m", myname, path); 93 break; 94 } 95 96 /* 97 * Make sure we opened a FIFO and skip any cruft that might have 98 * accumulated before we opened it. 99 */ 100 if (fstat(fd, &st) < 0) 101 msg_fatal("%s: fstat %s: %m", myname, path); 102 if (S_ISFIFO(st.st_mode) == 0) 103 msg_fatal("%s: not a fifo: %s", myname, path); 104 if (fchmod(fd, permissions) < 0) 105 msg_fatal("%s: fchmod %s: %m", myname, path); 106 non_blocking(fd, block_mode); 107 while ((count = peekfd(fd)) > 0 108 && read(fd, buf, BUF_LEN < count ? BUF_LEN : count) > 0) 109 /* void */ ; 110 return (fd); 111} 112