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