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