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