// See the file "COPYING" in the main distribution directory for copyright. #include "zeek/Pipe.h" #include #include #include #include #include "zeek/Reporter.h" namespace zeek::detail { static void pipe_fail(int eno) { char tmp[256]; zeek::util::zeek_strerror_r(eno, tmp, sizeof(tmp)); if ( reporter ) reporter->FatalError("Pipe failure: %s", tmp); else fprintf(stderr, "Pipe failure: %s", tmp); } static int set_flags(int fd, int flags) { auto rval = fcntl(fd, F_GETFD); if ( rval == -1 ) pipe_fail(errno); if ( flags ) { rval |= flags; if ( fcntl(fd, F_SETFD, rval) == -1 ) pipe_fail(errno); } return rval; } static int unset_flags(int fd, int flags) { auto rval = fcntl(fd, F_GETFD); if ( rval == -1 ) pipe_fail(errno); if ( flags ) { rval &= ~flags; if ( fcntl(fd, F_SETFD, rval) == -1 ) pipe_fail(errno); } return rval; } static int set_status_flags(int fd, int flags) { auto rval = fcntl(fd, F_GETFL); if ( rval == -1 ) pipe_fail(errno); if ( flags ) { rval |= flags; if ( fcntl(fd, F_SETFL, rval) == -1 ) pipe_fail(errno); } return rval; } static int dup_or_fail(int fd, int flags, int status_flags) { int rval = dup(fd); if ( rval < 0 ) pipe_fail(errno); set_flags(fd, flags); set_status_flags(fd, status_flags); return rval; } Pipe::Pipe(int flags0, int flags1, int status_flags0, int status_flags1, int* arg_fds) { if ( arg_fds ) { fds[0] = arg_fds[0]; fds[1] = arg_fds[1]; } else { // pipe2 can set flags atomically, but not yet available everywhere. if ( ::pipe(fds) ) pipe_fail(errno); } flags[0] = set_flags(fds[0], flags0); flags[1] = set_flags(fds[1], flags1); status_flags[0] = set_status_flags(fds[0], status_flags0); status_flags[1] = set_status_flags(fds[1], status_flags1); } void Pipe::SetFlags(int arg_flags) { flags[0] = set_flags(fds[0], arg_flags); flags[1] = set_flags(fds[1], arg_flags); } void Pipe::UnsetFlags(int arg_flags) { flags[0] = unset_flags(fds[0], arg_flags); flags[1] = unset_flags(fds[1], arg_flags); } Pipe::~Pipe() { close(fds[0]); close(fds[1]); } Pipe::Pipe(const Pipe& other) { fds[0] = dup_or_fail(other.fds[0], other.flags[0], other.status_flags[0]); fds[1] = dup_or_fail(other.fds[1], other.flags[1], other.status_flags[1]); flags[0] = other.flags[0]; flags[1] = other.flags[1]; status_flags[0] = other.status_flags[0]; status_flags[1] = other.status_flags[1]; } Pipe& Pipe::operator=(const Pipe& other) { if ( this == &other ) return *this; close(fds[0]); close(fds[1]); fds[0] = dup_or_fail(other.fds[0], other.flags[0], other.status_flags[0]); fds[1] = dup_or_fail(other.fds[1], other.flags[1], other.status_flags[1]); flags[0] = other.flags[0]; flags[1] = other.flags[1]; status_flags[0] = other.status_flags[0]; status_flags[1] = other.status_flags[1]; return *this; } PipePair::PipePair(int flags, int status_flags, int* fds) : pipes{Pipe(flags, flags, status_flags, status_flags, fds ? fds + 0 : nullptr), Pipe(flags, flags, status_flags, status_flags, fds ? fds + 2 : nullptr)} { } } // namespace zeek::detail