Version 1.8.0.0
[socat.git] / xio-pipe.c
blobda17b8a8c8a8656411d677bd4e43cf998f5fa006
1 /* source: xio-pipe.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for opening addresses of pipe type */
7 #include "xiosysincludes.h"
8 #include "xioopen.h"
10 #include "xio-named.h"
12 #include "xio-pipe.h"
15 #if WITH_PIPE
17 static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc);
18 static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts);
21 const struct addrdesc xioaddr_pipe = { "PIPE", 3, xioopen_fifo, GROUP_FD|GROUP_NAMED|GROUP_OPEN|GROUP_FIFO, 0, 0, 0 HELP("[:<filename>]") };
23 #if defined(F_SETPIPE_SZ)
24 const struct optdesc opt_f_setpipe_sz = { "f-setpipe-sz", "pipesz", OPT_F_SETPIPE_SZ, GROUP_FD, PH_FD, TYPE_INT, OFUNC_FCNTL, F_SETPIPE_SZ, 0 };
25 #endif
27 /* process an unnamed bidirectional "pipe" or "fifo" or "echo" argument with
28 options */
29 static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) {
30 struct single *sfd = &sock->stream;
31 struct opt *opts2;
32 int filedes[2];
33 int numleft;
34 int result;
36 if (applyopts_single(sfd, opts, PH_INIT) < 0) return -1;
37 applyopts(sfd, -1, opts, PH_INIT);
39 if (Pipe(filedes) != 0) {
40 Error2("pipe(%p): %s", filedes, strerror(errno));
41 return -1;
43 /*0 Info2("pipe({%d,%d})", filedes[0], filedes[1]);*/
45 sock->common.tag = XIO_TAG_RDWR;
46 sfd->dtype = XIODATA_PIPE;
47 sfd->fd = filedes[0];
48 sfd->para.bipipe.fdout = filedes[1];
49 sfd->para.bipipe.socktype = SOCK_STREAM; /* due to socketpair reuse */
50 applyopts_cloexec(sfd->fd, opts);
51 applyopts_cloexec(sfd->para.bipipe.fdout, opts);
53 /* one-time and input-direction options, no second application */
54 retropt_bool(opts, OPT_IGNOREEOF, &sfd->ignoreeof);
56 /* here we copy opts! */
57 if ((opts2 = copyopts(opts, GROUP_FIFO)) == NULL) {
58 return STAT_NORETRY;
61 /* apply options to first FD */
62 if ((result = applyopts(sfd, -1, opts, PH_ALL)) < 0) {
63 return result;
65 if ((result = applyopts_single(sfd, opts, PH_ALL)) < 0) {
66 return result;
69 /* apply options to second FD */
70 if (applyopts(&sock->stream, sfd->para.bipipe.fdout, opts2, PH_ALL) < 0)
71 return -1;
73 if ((numleft = leftopts(opts)) > 0) {
74 showleft(opts);
75 Error1("INTERNAL: %d option(s) remained unused", numleft);
78 xio_chk_pipesz(sfd->fd);
80 Notice("writing to and reading from unnamed pipe");
81 return 0;
85 /* open a named or unnamed pipe/fifo */
86 static int xioopen_fifo(
87 int argc,
88 const char *argv[],
89 struct opt *opts,
90 int xioflags,
91 xiofile_t *xfd,
92 const struct addrdesc *addrdesc)
94 struct single *sfd = &xfd->stream;
95 const char *pipename = argv[1];
96 int rw = (xioflags & XIO_ACCMODE);
97 #if HAVE_STAT64
98 struct stat64 pipstat;
99 #else
100 struct stat pipstat;
101 #endif /* !HAVE_STAT64 */
102 bool opt_unlink_early = false;
103 bool opt_unlink_close = true;
104 mode_t mode = 0666;
105 int result;
107 if (argc == 1) {
108 return xioopen_fifo_unnamed(xfd, sfd->opts);
111 if (argc != 2) {
112 xio_syntax(argv[0], 1, argc-1,addrdesc->syntax);
113 return STAT_NORETRY;
116 if (applyopts_single(sfd, opts, PH_INIT) < 0)
117 return -1;
118 applyopts(sfd, -1, opts, PH_INIT);
120 retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
121 applyopts_named(pipename, opts, PH_EARLY); /* umask! */
122 applyopts(sfd, -1, opts, PH_EARLY);
124 if (opt_unlink_early) {
125 if (Unlink(pipename) < 0) {
126 return STAT_RETRYLATER;
130 retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
131 retropt_modet(opts, OPT_PERM, &mode);
132 if (applyopts_named(pipename, opts, PH_EARLY) < 0) {
133 return STAT_RETRYLATER;
135 if (applyopts_named(pipename, opts, PH_PREOPEN) < 0) {
136 return STAT_RETRYLATER;
138 if (
139 #if HAVE_STAT64
140 Stat64(pipename, &pipstat) < 0
141 #else
142 Stat(pipename, &pipstat) < 0
143 #endif /* !HAVE_STAT64 */
145 if (errno != ENOENT) {
146 Error3("stat(\"%s\", %p): %s", pipename, &pipstat, strerror(errno));
147 } else {
148 Debug1("xioopen_fifo(\"%s\"): does not exist, creating fifo", pipename);
149 #if 0
150 result = Mknod(pipename, S_IFIFO|mode, 0);
151 if (result < 0) {
152 Error3("mknod(%s, %d, 0): %s", pipename, mode, strerror(errno));
153 return STAT_RETRYLATER;
155 #else
156 result = Mkfifo(pipename, mode);
157 if (result < 0) {
158 Error3("mkfifo(%s, %d): %s", pipename, mode, strerror(errno));
159 return STAT_RETRYLATER;
161 #endif
162 Notice2("created named pipe \"%s\" for %s", pipename, ddirection[rw]);
163 applyopts_named(pipename, opts, PH_ALL);
166 if (opt_unlink_close) {
167 if ((sfd->unlink_close = strdup(pipename)) == NULL) {
168 Error1("strdup(\"%s\"): out of memory", pipename);
170 sfd->opt_unlink_close = true;
172 } else {
173 /* exists */
174 Info1("xioopen_fifo(\"%s\"): already exist, opening it", pipename);
175 Notice3("opening %s \"%s\" for %s",
176 filetypenames[(pipstat.st_mode&S_IFMT)>>12],
177 pipename, ddirection[rw]);
178 applyopts_named(pipename, opts, PH_EARLY);
181 if ((result = _xioopen_open(pipename, rw, opts)) < 0) {
182 return result;
184 sfd->fd = result;
186 applyopts_named(pipename, opts, PH_FD);
187 applyopts(sfd, -1, opts, PH_FD);
188 applyopts_cloexec(sfd->fd, opts);
189 xio_chk_pipesz(sfd->fd);
191 return _xio_openlate(sfd, opts);
195 /* Checks if fd is a pipe and if its buffer is at least the blksiz.
196 returns 0 if ok;
197 returns 1 if unknown;
198 returns -1 if not */
199 int xio_chk_pipesz(
200 int fd)
202 struct stat st;
203 int pipesz;
205 if (fstat(fd, &st) < 0) {
206 Warn2("fstat(%d, ...): %s", fd, strerror(errno));
207 return 1;
209 if ((st.st_mode&S_IFMT) != S_IFIFO) {
210 return 0;
213 #if defined(F_GETPIPE_SZ)
214 if ((pipesz = Fcntl(fd, F_GETPIPE_SZ)) < 0) {
215 Warn2("fcntl(%d, F_GETPIPE_SZ): %s", fd, strerror(errno));
216 return 1;
219 if (pipesz >= xioparms.bufsiz)
220 return 0;
222 Warn3("xio_chk_pipesz(%d, ...): Socat block size "F_Zu" is larger than pipe size %d, might block; use option f-setpipe-sz!",
223 fd, xioparms.bufsiz, pipesz);
224 return -1;
225 #else /* !defined(F_GETPIPE_SZ) */
226 return 1;
227 #endif /* !defined(F_GETPIPE_SZ) */
230 #endif /* WITH_PIPE */