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