Initial commit

This commit is contained in:
styan 2020-05-24 01:42:33 +00:00
commit 28fe4e659f
3 changed files with 263 additions and 0 deletions

6
Makefile Normal file
View File

@ -0,0 +1,6 @@
.POSIX:
default: all
all: fdwrap
fdwrap: fdwrap.c
clean:
rm -f fdwrap

16
example-gemini.sh Normal file
View File

@ -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

241
fdwrap.c Normal file
View File

@ -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);
}