Initial commit
This commit is contained in:
commit
28fe4e659f
|
@ -0,0 +1,6 @@
|
|||
.POSIX:
|
||||
default: all
|
||||
all: fdwrap
|
||||
fdwrap: fdwrap.c
|
||||
clean:
|
||||
rm -f fdwrap
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/sh
|
||||
HOST="${HOST:-localhost}"
|
||||
PORT="${PORT:-1965}"
|
||||
while getopts h:p: opt; do
|
||||
case "$opt" in
|
||||
h) HOST="$OPTARG";;
|
||||
p) PORT="$OPTARG";;
|
||||
*) usage;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
for x in "$@"; do
|
||||
fdwrap -f '3>stdin,stdin<stdout' -w \
|
||||
"openssl s_client -quiet -connect $HOST:$PORT 2>/dev/null" \
|
||||
sh -c 'printf %s\\r\\n "$1" >&3; cat' sh-gemini "$x"
|
||||
done
|
|
@ -0,0 +1,241 @@
|
|||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sysexits.h>
|
||||
#include <err.h>
|
||||
|
||||
#define FDPAIR_INITIALIZER { NULL, 0, { -1, -1 }, { -1, -1 } }
|
||||
struct fdpair {
|
||||
struct fdpair *next;
|
||||
int direction;
|
||||
int pipe[2];
|
||||
int fd[2];
|
||||
};
|
||||
|
||||
static int plumbfdpairs(struct fdpair *);
|
||||
static ssize_t strtofdpairs(const char *, struct fdpair **);
|
||||
static ssize_t strtofdpair(const char *, struct fdpair *);
|
||||
static ssize_t strtofd(const char *, int *);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const char *wargv[] = { "sh", "-c", NULL, NULL };
|
||||
const char *wrapper = "exec cat";
|
||||
struct fdpair *pairs = NULL;
|
||||
struct fdpair *p;
|
||||
ssize_t r;
|
||||
pid_t pid;
|
||||
int nullfd;
|
||||
int c;
|
||||
|
||||
if (strtofdpairs("stdin<-stdout,stdout->stdin", &pairs) < 0)
|
||||
err(EX_OSERR, "strtofdpairs");
|
||||
while ((c = getopt(argc, argv, "f:w:")) != -1)
|
||||
switch (c) {
|
||||
case 'w':
|
||||
wrapper = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
r = strtofdpairs(optarg, &pairs);
|
||||
if (r >= 0 && optarg[r] != '\0') {
|
||||
errno = EINVAL;
|
||||
r = -1;
|
||||
}
|
||||
if (r < 0)
|
||||
err(EX_USAGE, "%s", optarg);
|
||||
break;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
wargv[2] = wrapper;
|
||||
if ((nullfd = open("/dev/null", O_RDWR)) < 0)
|
||||
err(EX_OSERR, "/dev/null");
|
||||
/*
|
||||
* Reserve the desired descriptors so
|
||||
* that socketpair(2) does not take them.
|
||||
*/
|
||||
for (p = pairs; p != NULL; p = p->next)
|
||||
if ((p->fd[0] != STDIN_FILENO &&
|
||||
p->fd[0] != STDOUT_FILENO &&
|
||||
p->fd[0] != STDERR_FILENO &&
|
||||
dup2(nullfd, p->fd[0]) < 0) ||
|
||||
(p->fd[1] != STDIN_FILENO &&
|
||||
p->fd[1] != STDOUT_FILENO &&
|
||||
p->fd[1] != STDERR_FILENO &&
|
||||
dup2(nullfd, p->fd[1]) < 0))
|
||||
err(EX_OSERR, "dup2");
|
||||
(void)close(nullfd);
|
||||
for (p = pairs; p != NULL; p = p->next)
|
||||
if (socketpair(PF_LOCAL, SOCK_STREAM, 0, p->pipe) != 0)
|
||||
err(EX_OSERR, "pipe");
|
||||
switch (pid = fork()) {
|
||||
case -1:
|
||||
err(EX_OSERR, "fork");
|
||||
case 0:
|
||||
for (p = pairs; p != NULL; p = p->next)
|
||||
if (p->direction) {
|
||||
if (close(p->pipe[1]) != 0)
|
||||
err(EX_OSERR, "close");
|
||||
if (dup2(p->pipe[0], p->fd[1]) < 0)
|
||||
err(EX_OSERR, "dup2");
|
||||
if (close(p->pipe[0]) != 0)
|
||||
err(EX_OSERR, "close");
|
||||
} else {
|
||||
if (close(p->pipe[0]) != 0)
|
||||
err(EX_OSERR, "close");
|
||||
if (dup2(p->pipe[1], p->fd[1]) < 0)
|
||||
err(EX_OSERR, "dup2");
|
||||
if (close(p->pipe[1]) != 0)
|
||||
err(EX_OSERR, "close");
|
||||
}
|
||||
(void)execvp("sh", (char * const *)wargv);
|
||||
err(EX_SOFTWARE, "execvp: sh -c %s", wrapper);
|
||||
default:
|
||||
for (p = pairs; p != NULL; p = p->next)
|
||||
if (p->direction) {
|
||||
if (close(p->pipe[0]) != 0)
|
||||
err(EX_OSERR, "close");
|
||||
if (dup2(p->pipe[1], p->fd[0]) < 0)
|
||||
err(EX_OSERR, "dup2");
|
||||
if (close(p->pipe[1]) != 0)
|
||||
err(EX_OSERR, "close");
|
||||
} else {
|
||||
if (close(p->pipe[1]) != 0)
|
||||
err(EX_OSERR, "close");
|
||||
if (dup2(p->pipe[0], p->fd[0]) < 0)
|
||||
err(EX_OSERR, "dup2");
|
||||
if (close(p->pipe[0]) != 0)
|
||||
err(EX_OSERR, "close");
|
||||
}
|
||||
(void)execvp(*argv, argv);
|
||||
err(EX_SOFTWARE, "execvp: %s ...", *argv);
|
||||
}
|
||||
abort(); /* unreachable */
|
||||
usage:
|
||||
(void)fprintf(stderr,
|
||||
"usage: fdwrap [-f fd-pairs] [-w wrapper-command] "
|
||||
"command [argument ...]\n");
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
strtofdpairs(const char *s, struct fdpair **fdp)
|
||||
{
|
||||
struct fdpair *p;
|
||||
struct fdpair *n;
|
||||
struct fdpair t = FDPAIR_INITIALIZER;
|
||||
ssize_t r;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; s[i] != '\0'; i += r + (s[i + r] == ',')) {
|
||||
if ((r = strtofdpair(s + i, &t)) < 0)
|
||||
return (-1);
|
||||
for (p = NULL, n = *fdp; n != NULL;
|
||||
p = n, n = n == NULL ? *fdp : n->next)
|
||||
if (n->fd[0] == t.fd[0] ||
|
||||
n->fd[1] == t.fd[1]) {
|
||||
if (p == NULL)
|
||||
*fdp = n->next;
|
||||
else
|
||||
p->next = n->next;
|
||||
free(n);
|
||||
n = p;
|
||||
}
|
||||
if ((n = malloc(sizeof(*n))) == NULL)
|
||||
return (-1);
|
||||
*n = t;
|
||||
if (p == NULL)
|
||||
*fdp = n;
|
||||
else
|
||||
p->next = n;
|
||||
}
|
||||
if (i == 0) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
strtofdpair(const char *s, struct fdpair *fdp)
|
||||
{
|
||||
int fd[2];
|
||||
ssize_t r;
|
||||
size_t i;
|
||||
int d = -1;
|
||||
|
||||
if ((r = strtofd(s, &fd[0])) < 0)
|
||||
return (-1);
|
||||
i = r;
|
||||
if (s[i] == '-' && s[i + 1] == '>') {
|
||||
d = 1;
|
||||
i += 2;
|
||||
} else if (s[i] == '<' && s[i + 1] == '-') {
|
||||
d = 0;
|
||||
i += 2;
|
||||
} else if (s[i] == '>') {
|
||||
d = 1;
|
||||
i++;
|
||||
} else if (s[i] == '<') {
|
||||
d = 0;
|
||||
i++;
|
||||
}
|
||||
if (d == -1) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if ((r = strtofd(s + i, &fd[1])) < 0)
|
||||
return (-1);
|
||||
i += r;
|
||||
if (fdp != NULL) {
|
||||
fdp->direction = d;
|
||||
fdp->fd[0] = fd[0];
|
||||
fdp->fd[1] = fd[1];
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
strtofd(const char *s, int *fdp)
|
||||
{
|
||||
size_t i;
|
||||
int fd = 0;
|
||||
|
||||
if (strncasecmp(s, "stdin", 5) == 0) {
|
||||
i = 5;
|
||||
fd = STDIN_FILENO;
|
||||
} else if (strncasecmp(s, "stdout", 6) == 0) {
|
||||
i = 6;
|
||||
fd = STDOUT_FILENO;
|
||||
} else if (strncasecmp(s, "stderr", 6) == 0) {
|
||||
i = 6;
|
||||
fd = STDERR_FILENO;
|
||||
} else {
|
||||
for (i = 0; s[i] >= '0' && s[i] <= '9';
|
||||
fd = fd * 10 + (s[i] - '0'), i++)
|
||||
if (fd > (INT_MAX - (s[i] - '0')) / 10) {
|
||||
errno = ERANGE;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
if (i == 0) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (fdp != NULL)
|
||||
*fdp = fd;
|
||||
return (i);
|
||||
}
|
Loading…
Reference in New Issue