mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 07:22:34 +00:00
230 lines
6.2 KiB
C
230 lines
6.2 KiB
C
/* source: xio-pipe.c */
|
|
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
|
|
/* Published under the GNU General Public License V.2, see file COPYING */
|
|
|
|
/* this file contains the source for opening addresses of pipe type */
|
|
|
|
#include "xiosysincludes.h"
|
|
#include "xioopen.h"
|
|
|
|
#include "xio-named.h"
|
|
|
|
#include "xio-pipe.h"
|
|
|
|
|
|
#if WITH_PIPE
|
|
|
|
static int xioopen_fifo(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc);
|
|
static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts);
|
|
|
|
|
|
const struct addrdesc xioaddr_pipe = { "PIPE", 3, xioopen_fifo, GROUP_FD|GROUP_NAMED|GROUP_OPEN|GROUP_FIFO, 0, 0, 0 HELP("[:<filename>]") };
|
|
|
|
#if defined(F_SETPIPE_SZ)
|
|
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 };
|
|
#endif
|
|
|
|
/* process an unnamed bidirectional "pipe" or "fifo" or "echo" argument with
|
|
options */
|
|
static int xioopen_fifo_unnamed(xiofile_t *sock, struct opt *opts) {
|
|
struct single *sfd = &sock->stream;
|
|
struct opt *opts2;
|
|
int filedes[2];
|
|
int numleft;
|
|
int result;
|
|
|
|
if (applyopts_single(sfd, opts, PH_INIT) < 0) return -1;
|
|
applyopts(sfd, -1, opts, PH_INIT);
|
|
|
|
if (Pipe(filedes) != 0) {
|
|
Error2("pipe(%p): %s", filedes, strerror(errno));
|
|
return -1;
|
|
}
|
|
/*0 Info2("pipe({%d,%d})", filedes[0], filedes[1]);*/
|
|
|
|
sock->common.tag = XIO_TAG_RDWR;
|
|
sfd->dtype = XIODATA_PIPE;
|
|
sfd->fd = filedes[0];
|
|
sfd->para.bipipe.fdout = filedes[1];
|
|
sfd->para.bipipe.socktype = SOCK_STREAM; /* due to socketpair reuse */
|
|
applyopts_cloexec(sfd->fd, opts);
|
|
applyopts_cloexec(sfd->para.bipipe.fdout, opts);
|
|
|
|
/* one-time and input-direction options, no second application */
|
|
retropt_bool(opts, OPT_IGNOREEOF, &sfd->ignoreeof);
|
|
|
|
/* here we copy opts! */
|
|
if ((opts2 = copyopts(opts, GROUP_FIFO)) == NULL) {
|
|
return STAT_NORETRY;
|
|
}
|
|
|
|
/* apply options to first FD */
|
|
if ((result = applyopts(sfd, -1, opts, PH_ALL)) < 0) {
|
|
return result;
|
|
}
|
|
if ((result = applyopts_single(sfd, opts, PH_ALL)) < 0) {
|
|
return result;
|
|
}
|
|
|
|
/* apply options to second FD */
|
|
if (applyopts(&sock->stream, sfd->para.bipipe.fdout, opts2, PH_ALL) < 0)
|
|
return -1;
|
|
|
|
if ((numleft = leftopts(opts)) > 0) {
|
|
showleft(opts);
|
|
Error1("INTERNAL: %d option(s) remained unused", numleft);
|
|
}
|
|
|
|
xio_chk_pipesz(sfd->fd);
|
|
|
|
Notice("writing to and reading from unnamed pipe");
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* open a named or unnamed pipe/fifo */
|
|
static int xioopen_fifo(
|
|
int argc,
|
|
const char *argv[],
|
|
struct opt *opts,
|
|
int xioflags,
|
|
xiofile_t *xfd,
|
|
const struct addrdesc *addrdesc)
|
|
{
|
|
struct single *sfd = &xfd->stream;
|
|
const char *pipename = argv[1];
|
|
int rw = (xioflags & XIO_ACCMODE);
|
|
#if HAVE_STAT64
|
|
struct stat64 pipstat;
|
|
#else
|
|
struct stat pipstat;
|
|
#endif /* !HAVE_STAT64 */
|
|
bool opt_unlink_early = false;
|
|
bool opt_unlink_close = true;
|
|
mode_t mode = 0666;
|
|
int result;
|
|
|
|
if (argc == 1) {
|
|
return xioopen_fifo_unnamed(xfd, sfd->opts);
|
|
}
|
|
|
|
if (argc != 2) {
|
|
xio_syntax(argv[0], 1, argc-1,addrdesc->syntax);
|
|
return STAT_NORETRY;
|
|
}
|
|
|
|
if (applyopts_single(sfd, opts, PH_INIT) < 0)
|
|
return -1;
|
|
applyopts(sfd, -1, opts, PH_INIT);
|
|
|
|
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
|
|
applyopts_named(pipename, opts, PH_EARLY); /* umask! */
|
|
applyopts(sfd, -1, opts, PH_EARLY);
|
|
|
|
if (opt_unlink_early) {
|
|
if (Unlink(pipename) < 0) {
|
|
return STAT_RETRYLATER;
|
|
}
|
|
}
|
|
|
|
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
|
|
retropt_modet(opts, OPT_PERM, &mode);
|
|
if (applyopts_named(pipename, opts, PH_EARLY) < 0) {
|
|
return STAT_RETRYLATER;
|
|
}
|
|
if (applyopts_named(pipename, opts, PH_PREOPEN) < 0) {
|
|
return STAT_RETRYLATER;
|
|
}
|
|
if (
|
|
#if HAVE_STAT64
|
|
Stat64(pipename, &pipstat) < 0
|
|
#else
|
|
Stat(pipename, &pipstat) < 0
|
|
#endif /* !HAVE_STAT64 */
|
|
) {
|
|
if (errno != ENOENT) {
|
|
Error3("stat(\"%s\", %p): %s", pipename, &pipstat, strerror(errno));
|
|
} else {
|
|
Debug1("xioopen_fifo(\"%s\"): does not exist, creating fifo", pipename);
|
|
#if 0
|
|
result = Mknod(pipename, S_IFIFO|mode, 0);
|
|
if (result < 0) {
|
|
Error3("mknod(%s, %d, 0): %s", pipename, mode, strerror(errno));
|
|
return STAT_RETRYLATER;
|
|
}
|
|
#else
|
|
result = Mkfifo(pipename, mode);
|
|
if (result < 0) {
|
|
Error3("mkfifo(%s, %d): %s", pipename, mode, strerror(errno));
|
|
return STAT_RETRYLATER;
|
|
}
|
|
#endif
|
|
Notice2("created named pipe \"%s\" for %s", pipename, ddirection[rw]);
|
|
applyopts_named(pipename, opts, PH_ALL);
|
|
|
|
}
|
|
if (opt_unlink_close) {
|
|
if ((sfd->unlink_close = strdup(pipename)) == NULL) {
|
|
Error1("strdup(\"%s\"): out of memory", pipename);
|
|
}
|
|
sfd->opt_unlink_close = true;
|
|
}
|
|
} else {
|
|
/* exists */
|
|
Info1("xioopen_fifo(\"%s\"): already exist, opening it", pipename);
|
|
Notice3("opening %s \"%s\" for %s",
|
|
filetypenames[(pipstat.st_mode&S_IFMT)>>12],
|
|
pipename, ddirection[rw]);
|
|
applyopts_named(pipename, opts, PH_EARLY);
|
|
}
|
|
|
|
if ((result = _xioopen_open(pipename, rw, opts)) < 0) {
|
|
return result;
|
|
}
|
|
sfd->fd = result;
|
|
|
|
applyopts_named(pipename, opts, PH_FD);
|
|
applyopts(sfd, -1, opts, PH_FD);
|
|
applyopts_cloexec(sfd->fd, opts);
|
|
xio_chk_pipesz(sfd->fd);
|
|
|
|
return _xio_openlate(sfd, opts);
|
|
}
|
|
|
|
|
|
/* Checks if fd is a pipe and if its buffer is at least the blksiz.
|
|
returns 0 if ok;
|
|
returns 1 if unknown;
|
|
returns -1 if not */
|
|
int xio_chk_pipesz(
|
|
int fd)
|
|
{
|
|
struct stat st;
|
|
int pipesz;
|
|
|
|
if (fstat(fd, &st) < 0) {
|
|
Warn2("fstat(%d, ...): %s", fd, strerror(errno));
|
|
return 1;
|
|
}
|
|
if ((st.st_mode&S_IFMT) != S_IFIFO) {
|
|
return 0;
|
|
}
|
|
|
|
#if defined(F_GETPIPE_SZ)
|
|
if ((pipesz = Fcntl(fd, F_GETPIPE_SZ)) < 0) {
|
|
Warn2("fcntl(%d, F_GETPIPE_SZ): %s", fd, strerror(errno));
|
|
return 1;
|
|
}
|
|
|
|
if (pipesz >= xioparms.bufsiz)
|
|
return 0;
|
|
|
|
Warn3("xio_chk_pipesz(%d, ...): Socat block size "F_Zu" is larger than pipe size %d, might block; use option f-setpipe-sz!",
|
|
fd, xioparms.bufsiz, pipesz);
|
|
return -1;
|
|
#else /* !defined(F_GETPIPE_SZ) */
|
|
return 1;
|
|
#endif /* !defined(F_GETPIPE_SZ) */
|
|
}
|
|
|
|
#endif /* WITH_PIPE */
|