mirror of
https://github.com/uselessd/alcove.git
synced 2026-04-15 01:04:41 +00:00
WIP: proxy
Convert alcove to a select loop. Each process can call the commands. fork(2) and clone(2) are now just commands.
This commit is contained in:
@@ -23,14 +23,14 @@ OIFS=$IFS
|
||||
while read line; do
|
||||
IFS=/
|
||||
set -- $line
|
||||
printf "static ETERM *alcove_%s(ETERM *);\n" $1
|
||||
printf "static ETERM *alcove_%s(alcove_state_t *, ETERM *);\n" $1
|
||||
done < $PROTO
|
||||
|
||||
cat<< 'EOF'
|
||||
|
||||
/* commands */
|
||||
typedef struct {
|
||||
ETERM *(*fp)(ETERM *);
|
||||
ETERM *(*fp)(alcove_state_t *, ETERM *);
|
||||
u_int8_t narg;
|
||||
} alcove_cmd_t;
|
||||
|
||||
|
||||
317
c_src/alcove.c
317
c_src/alcove.c
@@ -32,32 +32,21 @@
|
||||
#pragma message "Support for namespaces using clone(2) disabled"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int ctl[2];
|
||||
int in[2];
|
||||
int out[2];
|
||||
int err[2];
|
||||
} alcove_fd_t;
|
||||
static int alcove_call(alcove_state_t *ap, int fd, u_int16_t len);
|
||||
static alcove_msg_t * alcove_msg(int fd, u_int16_t len);
|
||||
|
||||
static int alcove_fork(alcove_state_t *);
|
||||
|
||||
static void alcove_ctl(int fd);
|
||||
static void alcove_select(alcove_state_t *);
|
||||
static alcove_msg_t *alcove_msg(int);
|
||||
static void usage(alcove_state_t *);
|
||||
|
||||
static int alcove_fork_child(void *arg);
|
||||
static ssize_t alcove_child_proxy(int, int, u_int16_t);
|
||||
static int alcove_write(int fd, u_int16_t, ETERM *);
|
||||
static ssize_t alcove_child_proxy(int fdin, u_int16_t type);
|
||||
static int alcove_write(u_int16_t, ETERM *);
|
||||
static ssize_t alcove_read(int, void *, ssize_t);
|
||||
|
||||
static void alcove_stats(alcove_state_t *ap);
|
||||
static void usage(alcove_state_t *);
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
static int child_exited = 0;
|
||||
|
||||
static void
|
||||
void
|
||||
gotsig(int sig)
|
||||
{
|
||||
switch (sig) {
|
||||
@@ -81,29 +70,14 @@ main(int argc, char *argv[])
|
||||
if (!ap)
|
||||
erl_err_sys("calloc");
|
||||
|
||||
ap->pid = -1;
|
||||
ap->ctl = -1;
|
||||
ap->fdin = -1;
|
||||
ap->fdout = -1;
|
||||
ap->fderr = -1;
|
||||
|
||||
signal(SIGCHLD, gotsig);
|
||||
|
||||
while ( (ch = getopt(argc, argv, "n:hv")) != -1) {
|
||||
while ( (ch = getopt(argc, argv, "hv")) != -1) {
|
||||
switch (ch) {
|
||||
case 'n':
|
||||
#ifdef CLONE_NEWNS
|
||||
if (!strncmp("ipc", optarg, 3)) ap->ns |= CLONE_NEWIPC;
|
||||
else if (!strncmp("net", optarg, 3)) ap->ns |= CLONE_NEWNET;
|
||||
else if (!strncmp("ns", optarg, 2)) ap->ns |= CLONE_NEWNS;
|
||||
else if (!strncmp("pid", optarg, 3)) ap->ns |= CLONE_NEWPID;
|
||||
else if (!strncmp("uts", optarg, 3)) ap->ns |= CLONE_NEWUTS;
|
||||
else if (!strncmp("user", optarg, 4)) ap->ns |= CLONE_NEWUSER;
|
||||
else usage(ap);
|
||||
#else
|
||||
usage(ap);
|
||||
#endif
|
||||
break;
|
||||
case 'v':
|
||||
ap->verbose++;
|
||||
break;
|
||||
@@ -113,121 +87,12 @@ main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (alcove_fork(ap) < 0)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
alcove_select(ap);
|
||||
alcove_ctl(ap);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int
|
||||
alcove_fork(alcove_state_t *ap)
|
||||
{
|
||||
alcove_fd_t fd = {{0}};
|
||||
|
||||
#ifdef CLONE_NEWNS
|
||||
const size_t stack_size = 65536;
|
||||
char *child_stack = NULL;
|
||||
|
||||
child_stack = calloc(stack_size, 1);
|
||||
if (!child_stack)
|
||||
erl_err_sys("calloc");
|
||||
#endif
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd.ctl) < 0)
|
||||
erl_err_sys("socketpair");
|
||||
|
||||
if ( (pipe(fd.in) < 0)
|
||||
|| (pipe(fd.out) < 0)
|
||||
|| (pipe(fd.err) < 0))
|
||||
erl_err_sys("pipe");
|
||||
|
||||
#ifdef CLONE_NEWNS
|
||||
ap->pid = clone(alcove_fork_child, child_stack + stack_size, ap->ns | SIGCHLD, &fd);
|
||||
if (ap->pid < 0)
|
||||
erl_err_sys("clone");
|
||||
#else
|
||||
ap->pid = fork();
|
||||
|
||||
switch (ap->pid) {
|
||||
case -1:
|
||||
erl_err_sys("fork");
|
||||
case 0:
|
||||
return alcove_fork_child(ap);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( (close(fd.ctl[PIPE_READ]) < 0)
|
||||
|| (close(fd.in[PIPE_READ]) < 0)
|
||||
|| (close(fd.out[PIPE_WRITE]) < 0)
|
||||
|| (close(fd.err[PIPE_WRITE]) < 0))
|
||||
erl_err_sys("close");
|
||||
|
||||
ap->ctl = fd.ctl[PIPE_WRITE];
|
||||
ap->fdin = fd.in[PIPE_WRITE];
|
||||
ap->fdout = fd.out[PIPE_READ];
|
||||
ap->fderr = fd.err[PIPE_READ];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
alcove_fork_child(void *arg)
|
||||
{
|
||||
alcove_fd_t *fd = arg;
|
||||
|
||||
if ( (close(fd->ctl[PIPE_WRITE]) < 0)
|
||||
|| (close(fd->in[PIPE_WRITE]) < 0)
|
||||
|| (close(fd->out[PIPE_READ]) < 0)
|
||||
|| (close(fd->err[PIPE_READ]) < 0))
|
||||
erl_err_sys("close");
|
||||
|
||||
if ( (dup2(fd->in[PIPE_READ], STDIN_FILENO) < 0)
|
||||
|| (dup2(fd->out[PIPE_WRITE], STDOUT_FILENO) < 0)
|
||||
|| (dup2(fd->err[PIPE_WRITE], STDERR_FILENO) < 0))
|
||||
erl_err_sys("dup2");
|
||||
|
||||
alcove_ctl(fd->ctl[PIPE_READ]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
alcove_ctl(int fd)
|
||||
{
|
||||
alcove_msg_t *msg = NULL;
|
||||
ETERM *arg = NULL;
|
||||
ETERM *reply = NULL;
|
||||
|
||||
for ( ; ; ) {
|
||||
msg = alcove_msg(fd);
|
||||
if (!msg)
|
||||
break;
|
||||
|
||||
arg = erl_decode(msg->arg);
|
||||
if (!arg)
|
||||
erl_err_quit("invalid message");
|
||||
|
||||
reply = alcove_cmd(msg->cmd, arg);
|
||||
if (!reply)
|
||||
erl_err_quit("unrecoverable error");
|
||||
|
||||
free(msg->arg);
|
||||
free(msg);
|
||||
erl_free_compound(arg);
|
||||
|
||||
if (alcove_write(fd, ALCOVE_MSG_CALL, reply) < 0)
|
||||
erl_err_sys("alcove_write");
|
||||
|
||||
erl_free_compound(reply);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
alcove_select(alcove_state_t *ap)
|
||||
void
|
||||
alcove_ctl(alcove_state_t *ap)
|
||||
{
|
||||
fd_set rfds;
|
||||
int fdmax = 0;
|
||||
@@ -238,9 +103,7 @@ alcove_select(alcove_state_t *ap)
|
||||
return;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
|
||||
FD_SET(STDIN_FILENO, &rfds);
|
||||
|
||||
fdmax = STDIN_FILENO;
|
||||
|
||||
if (ap->fdout > -1) {
|
||||
@@ -253,11 +116,6 @@ alcove_select(alcove_state_t *ap)
|
||||
fdmax = MAX(fdmax, ap->fderr);
|
||||
}
|
||||
|
||||
if (ap->ctl > -1) {
|
||||
FD_SET(ap->ctl, &rfds);
|
||||
fdmax = MAX(fdmax, ap->ctl);
|
||||
}
|
||||
|
||||
rv = select(fdmax+1, &rfds, NULL, NULL, NULL);
|
||||
|
||||
if (rv < 0) {
|
||||
@@ -270,24 +128,6 @@ alcove_select(alcove_state_t *ap)
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(ap->ctl, &rfds)) {
|
||||
ssize_t n = 0;
|
||||
char buf[65535] = {0};
|
||||
|
||||
n = read(ap->ctl, buf, sizeof(buf));
|
||||
|
||||
if (n == 0) {
|
||||
ap->ctl = -1;
|
||||
}
|
||||
else if (n < 0) {
|
||||
erl_err_quit("eof");
|
||||
}
|
||||
|
||||
/* XXX lock stdout */
|
||||
if (write(STDOUT_FILENO, buf, n) != n)
|
||||
erl_err_sys("write:ctl->stdout");
|
||||
}
|
||||
|
||||
if (FD_ISSET(STDIN_FILENO, &rfds)) {
|
||||
u_int16_t bufsz = 0;
|
||||
u_int16_t type = 0;
|
||||
@@ -303,23 +143,21 @@ alcove_select(alcove_state_t *ap)
|
||||
erl_err_sys("read:stdin");
|
||||
}
|
||||
|
||||
bufsz = ntohs(bufsz);
|
||||
bufsz -= sizeof(type);
|
||||
|
||||
/* message type */
|
||||
if (alcove_read(STDIN_FILENO, &type, sizeof(type)) != sizeof(type))
|
||||
erl_err_sys("read:stdin");
|
||||
|
||||
bufsz = ntohs(bufsz);
|
||||
bufsz -= sizeof(type);
|
||||
|
||||
if (alcove_read(STDIN_FILENO, buf, bufsz) != bufsz)
|
||||
erl_err_sys("read:stdin");
|
||||
|
||||
if (type == ALCOVE_MSG_CALL) {
|
||||
u_int16_t size = htons(bufsz);
|
||||
if ( (write(ap->ctl, &size, 2) != 2)
|
||||
|| (write(ap->ctl, buf, bufsz) != bufsz))
|
||||
erl_err_sys("write:stdin->ctl");
|
||||
if (alcove_call(ap, STDIN_FILENO, bufsz) < 0)
|
||||
erl_err_quit("call");
|
||||
}
|
||||
else if (type == ALCOVE_MSG_CHILDIN) {
|
||||
if (alcove_read(STDIN_FILENO, buf, bufsz) != bufsz)
|
||||
erl_err_sys("read:stdin");
|
||||
|
||||
if (write(ap->fdin, buf, bufsz) != bufsz)
|
||||
erl_err_sys("write:stdin->childin");
|
||||
}
|
||||
@@ -330,7 +168,7 @@ alcove_select(alcove_state_t *ap)
|
||||
}
|
||||
|
||||
if (FD_ISSET(ap->fdout, &rfds)) {
|
||||
switch (alcove_child_proxy(ap->fdout, STDOUT_FILENO, ALCOVE_MSG_CHILDOUT)) {
|
||||
switch (alcove_child_proxy(ap->fdout, ALCOVE_MSG_CHILDOUT)) {
|
||||
case -1:
|
||||
erl_err_sys("alcove_child_proxy");
|
||||
case 0:
|
||||
@@ -341,7 +179,7 @@ alcove_select(alcove_state_t *ap)
|
||||
}
|
||||
|
||||
if (FD_ISSET(ap->fderr, &rfds)) {
|
||||
switch (alcove_child_proxy(ap->fderr, STDOUT_FILENO, ALCOVE_MSG_CHILDERR)) {
|
||||
switch (alcove_child_proxy(ap->fderr, ALCOVE_MSG_CHILDERR)) {
|
||||
case -1:
|
||||
erl_err_sys("alcove_child_proxy");
|
||||
case 0:
|
||||
@@ -353,56 +191,76 @@ alcove_select(alcove_state_t *ap)
|
||||
}
|
||||
}
|
||||
|
||||
static alcove_msg_t *
|
||||
alcove_msg(int fd)
|
||||
static int
|
||||
alcove_call(alcove_state_t *ap, int fd, u_int16_t len)
|
||||
{
|
||||
ssize_t n = 0;
|
||||
u_int16_t buf = 0;
|
||||
u_int16_t len = 0;
|
||||
alcove_msg_t *msg = NULL;
|
||||
ETERM *arg = NULL;
|
||||
ETERM *reply = NULL;
|
||||
int rv = -1;
|
||||
|
||||
msg = alcove_msg(fd, len);
|
||||
if (!msg)
|
||||
return -1;
|
||||
|
||||
arg = erl_decode(msg->arg);
|
||||
if (!arg)
|
||||
goto DONE;
|
||||
|
||||
reply = alcove_cmd(ap, msg->cmd, arg);
|
||||
if (!reply)
|
||||
goto DONE;
|
||||
|
||||
rv = alcove_write(ALCOVE_MSG_CALL, reply);
|
||||
|
||||
DONE:
|
||||
free(msg->arg);
|
||||
free(msg);
|
||||
erl_free_compound(arg);
|
||||
erl_free_compound(reply);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static alcove_msg_t *
|
||||
alcove_msg(int fd, u_int16_t len)
|
||||
{
|
||||
u_int16_t cmd = 0;
|
||||
alcove_msg_t *msg = NULL;
|
||||
|
||||
errno = 0;
|
||||
n = alcove_read(fd, &buf, sizeof(buf));
|
||||
if (len <= sizeof(cmd))
|
||||
return NULL;
|
||||
|
||||
if (n != sizeof(buf)) {
|
||||
if (errno == 0)
|
||||
return NULL;
|
||||
|
||||
erl_err_sys("alcove_msg: expected=%lu, got=%lu",
|
||||
(unsigned long)sizeof(buf),
|
||||
(unsigned long)n);
|
||||
}
|
||||
|
||||
len = ntohs(buf);
|
||||
|
||||
if (len >= UINT16_MAX || len < sizeof(buf))
|
||||
erl_err_quit("alcove_msg: invalid len=%d (max=%d)", len, UINT16_MAX);
|
||||
|
||||
len -= sizeof(buf);
|
||||
|
||||
msg = alcove_malloc(sizeof(alcove_msg_t));
|
||||
msg->arg = alcove_malloc(len);
|
||||
len -= sizeof(cmd);
|
||||
|
||||
/* cmd */
|
||||
n = alcove_read(fd, &buf, sizeof(buf));
|
||||
if (n != sizeof(buf))
|
||||
erl_err_sys("alcove_msg: expected=%lu, got=%lu",
|
||||
(unsigned long)sizeof(buf),
|
||||
(unsigned long)n);
|
||||
if (alcove_read(fd, &cmd, sizeof(cmd)) != sizeof(cmd))
|
||||
return NULL;
|
||||
|
||||
msg->cmd = ntohs(buf);
|
||||
msg = alcove_malloc(sizeof(alcove_msg_t));
|
||||
msg->cmd = ntohs(cmd);
|
||||
|
||||
/* arg */
|
||||
n = alcove_read(fd, msg->arg, len);
|
||||
if (n != len)
|
||||
erl_err_sys("alcove_msg: expected=%u, got=%lu",
|
||||
len, (unsigned long)n);
|
||||
msg->arg = alcove_malloc(len);
|
||||
|
||||
if (alcove_read(fd, msg->arg, len) != len)
|
||||
goto BADARG;
|
||||
|
||||
return msg;
|
||||
|
||||
BADARG:
|
||||
if (msg) {
|
||||
if (msg->arg)
|
||||
free(msg->arg);
|
||||
|
||||
free(msg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
alcove_child_proxy(int fdin, int fdout, u_int16_t type)
|
||||
alcove_child_proxy(int fdin, u_int16_t type)
|
||||
{
|
||||
ssize_t n = 0;
|
||||
char buf[65535] = {0};
|
||||
@@ -417,20 +275,14 @@ alcove_child_proxy(int fdin, int fdout, u_int16_t type)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (alcove_write(fdout, type, erl_mk_binary(buf,n)) < 0)
|
||||
if (alcove_write(type, erl_mk_binary(buf,n)) < 0)
|
||||
erl_err_sys("alcove_write");
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
alcove_send(ETERM *t)
|
||||
{
|
||||
return alcove_write(STDOUT_FILENO, ALCOVE_MSG_CAST, t);
|
||||
}
|
||||
|
||||
static int
|
||||
alcove_write(int fd, u_int16_t type, ETERM *t)
|
||||
alcove_write(u_int16_t type, ETERM *t)
|
||||
{
|
||||
int tlen = 0;
|
||||
u_int16_t hlen = 0;
|
||||
@@ -447,14 +299,14 @@ alcove_write(int fd, u_int16_t type, ETERM *t)
|
||||
if (erl_encode(t, buf) < 1)
|
||||
goto ERR;
|
||||
|
||||
// flockfile(stdout);
|
||||
flockfile(stdout);
|
||||
|
||||
if ( (write(fd, &hlen, 2) != 2) ||
|
||||
(write(fd, &type, 2) != 2) ||
|
||||
(write(fd, buf, tlen) != tlen))
|
||||
if ( (write(STDOUT_FILENO, &hlen, 2) != 2) ||
|
||||
(write(STDOUT_FILENO, &type, 2) != 2) ||
|
||||
(write(STDOUT_FILENO, buf, tlen) != tlen))
|
||||
goto ERR;
|
||||
|
||||
// funlockfile(stdout);
|
||||
funlockfile(stdout);
|
||||
|
||||
erl_free(buf);
|
||||
return 0;
|
||||
@@ -497,9 +349,6 @@ usage(alcove_state_t *ap)
|
||||
__progname, ALCOVE_VERSION);
|
||||
(void)fprintf(stderr,
|
||||
"usage: %s <options>\n"
|
||||
#ifdef CLONE_NEWNS
|
||||
" -n <namespace> new namespace: ipc, net, ns, pid, user, uts\n"
|
||||
#endif
|
||||
" -v verbose mode\n",
|
||||
__progname
|
||||
);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <erl_driver.h>
|
||||
#include <erl_interface.h>
|
||||
@@ -39,12 +40,9 @@ enum {
|
||||
typedef struct {
|
||||
u_int32_t opt;
|
||||
u_int8_t verbose;
|
||||
pid_t pid;
|
||||
int ctl;
|
||||
int fdin;
|
||||
int fdout;
|
||||
int fderr;
|
||||
int ns;
|
||||
} alcove_state_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -52,7 +50,9 @@ typedef struct {
|
||||
unsigned char *arg;
|
||||
} alcove_msg_t;
|
||||
|
||||
int alcove_send(ETERM *t);
|
||||
void gotsig(int sig);
|
||||
|
||||
void alcove_ctl(alcove_state_t *ap);
|
||||
|
||||
void *alcove_malloc(ssize_t size);
|
||||
|
||||
@@ -65,7 +65,7 @@ ETERM *alcove_ok(ETERM *);
|
||||
ETERM *alcove_bool(bool);
|
||||
ETERM *alcove_bin(const char *);
|
||||
|
||||
ETERM *alcove_cmd(u_int32_t, ETERM *);
|
||||
ETERM *alcove_cmd(alcove_state_t *, u_int32_t, ETERM *);
|
||||
|
||||
#define VERBOSE(x, ...) do { \
|
||||
if (ap->verbose >= x) { \
|
||||
|
||||
@@ -25,13 +25,32 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#define PIPE_READ 0
|
||||
#define PIPE_WRITE 1
|
||||
|
||||
typedef struct {
|
||||
int ctl[2];
|
||||
int in[2];
|
||||
int out[2];
|
||||
int err[2];
|
||||
} alcove_fd_t;
|
||||
|
||||
typedef struct {
|
||||
alcove_state_t *ap;
|
||||
alcove_fd_t *fd;
|
||||
} alcove_child_t;
|
||||
|
||||
static char **alcove_list_to_argv(ETERM *);
|
||||
static void alcove_free_argv(char **);
|
||||
|
||||
static int alcove_stdio(alcove_fd_t *fd);
|
||||
static int alcove_child_fun(void *arg);
|
||||
static int alcove_parent_fd(alcove_state_t *ap, alcove_fd_t *fd);
|
||||
|
||||
#define ALCOVE_IS_IOLIST(_t) (ERL_IS_BINARY(_t) || ERL_IS_LIST(_t))
|
||||
|
||||
ETERM *
|
||||
alcove_cmd(u_int32_t cmd, ETERM *arg)
|
||||
alcove_cmd(alcove_state_t *ap, u_int32_t cmd, ETERM *arg)
|
||||
{
|
||||
alcove_cmd_t *fun = NULL;
|
||||
|
||||
@@ -43,11 +62,11 @@ alcove_cmd(u_int32_t cmd, ETERM *arg)
|
||||
if (!ERL_IS_LIST(arg) || erl_length(arg) != fun->narg)
|
||||
return erl_mk_atom("badarg");
|
||||
|
||||
return (*fun->fp)(arg);
|
||||
return (*fun->fp)(ap, arg);
|
||||
}
|
||||
|
||||
static ETERM *
|
||||
alcove_version(ETERM *arg)
|
||||
alcove_version(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
return alcove_bin(ALCOVE_VERSION);
|
||||
}
|
||||
@@ -57,7 +76,7 @@ alcove_version(ETERM *arg)
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_chdir(ETERM *arg)
|
||||
alcove_chdir(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
ETERM *hd = NULL;
|
||||
char *path = NULL;
|
||||
@@ -90,7 +109,7 @@ BADARG:
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_chroot(ETERM *arg)
|
||||
alcove_chroot(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
ETERM *hd = NULL;
|
||||
char *path = NULL;
|
||||
@@ -118,12 +137,58 @@ BADARG:
|
||||
return erl_mk_atom("badarg");
|
||||
}
|
||||
|
||||
/*
|
||||
* clone(2)
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_clone(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
ETERM *hd = NULL;
|
||||
alcove_child_t child_arg = {0};
|
||||
alcove_fd_t fd = {{0}};
|
||||
const size_t stack_size = 65536;
|
||||
char *child_stack = NULL;
|
||||
int flags = 0;
|
||||
pid_t pid = 0;
|
||||
|
||||
/* flags */
|
||||
arg = alcove_list_head(&hd, arg);
|
||||
if (!hd || !ERL_IS_INTEGER(hd))
|
||||
goto BADARG;
|
||||
|
||||
flags = ERL_INT_UVALUE(hd);
|
||||
|
||||
child_stack = calloc(stack_size, 1);
|
||||
if (!child_stack)
|
||||
return alcove_errno(errno);
|
||||
|
||||
if (alcove_stdio(&fd) < 0)
|
||||
return alcove_errno(errno);
|
||||
|
||||
child_arg.ap = ap;
|
||||
child_arg.fd = &fd;
|
||||
|
||||
pid = clone(alcove_child_fun, child_stack + stack_size, flags | SIGCHLD, &child_arg);
|
||||
|
||||
if (pid < 0)
|
||||
return alcove_errno(errno);
|
||||
|
||||
if (alcove_parent_fd(ap, &fd) < 0)
|
||||
return alcove_errno(errno);
|
||||
|
||||
return alcove_ok(erl_mk_int(pid));
|
||||
|
||||
BADARG:
|
||||
return erl_mk_atom("badarg");
|
||||
}
|
||||
|
||||
/*
|
||||
* execvp(3)
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_execvp(ETERM *arg)
|
||||
alcove_execvp(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
ETERM *hd = NULL;
|
||||
char *progname = NULL;
|
||||
@@ -167,12 +232,42 @@ BADARG:
|
||||
return erl_mk_atom("badarg");
|
||||
}
|
||||
|
||||
/*
|
||||
* fork(2)
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_fork(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
alcove_fd_t fd = {{0}};
|
||||
pid_t pid = 0;
|
||||
|
||||
if (alcove_stdio(&fd) < 0)
|
||||
return alcove_errno(errno);
|
||||
|
||||
pid = fork();
|
||||
|
||||
switch (pid) {
|
||||
case -1:
|
||||
return alcove_errno(errno);
|
||||
case 0:
|
||||
alcove_ctl(ap);
|
||||
erl_err_sys("fork");
|
||||
default:
|
||||
if (alcove_parent_fd(ap, &fd) < 0)
|
||||
return alcove_errno(errno);
|
||||
|
||||
return alcove_ok(erl_mk_int(pid));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* getcwd(3)
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_getcwd(ETERM *arg)
|
||||
alcove_getcwd(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
char buf[PATH_MAX] = {0};
|
||||
|
||||
@@ -187,7 +282,7 @@ alcove_getcwd(ETERM *arg)
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_getgid(ETERM *arg)
|
||||
alcove_getgid(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
return erl_mk_uint(getgid());
|
||||
}
|
||||
@@ -197,7 +292,7 @@ alcove_getgid(ETERM *arg)
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_getpid(ETERM *arg)
|
||||
alcove_getpid(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
return erl_mk_uint(getpid());
|
||||
}
|
||||
@@ -207,7 +302,7 @@ alcove_getpid(ETERM *arg)
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_getuid(ETERM *arg)
|
||||
alcove_getuid(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
return erl_mk_uint(getuid());
|
||||
}
|
||||
@@ -217,7 +312,7 @@ alcove_getuid(ETERM *arg)
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_setgid(ETERM *arg)
|
||||
alcove_setgid(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
ETERM *hd = NULL;
|
||||
gid_t gid = {0};
|
||||
@@ -243,7 +338,7 @@ BADARG:
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_setuid(ETERM *arg)
|
||||
alcove_setuid(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
ETERM *hd = NULL;
|
||||
uid_t uid = {0};
|
||||
@@ -269,7 +364,7 @@ BADARG:
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_gethostname(ETERM *arg)
|
||||
alcove_gethostname(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
char name[HOST_NAME_MAX] = {0};
|
||||
int rv = 0;
|
||||
@@ -286,7 +381,7 @@ alcove_gethostname(ETERM *arg)
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_sethostname(ETERM *arg)
|
||||
alcove_sethostname(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
ETERM *hd = NULL;
|
||||
char *name = NULL;
|
||||
@@ -319,7 +414,7 @@ BADARG:
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_getrlimit(ETERM *arg)
|
||||
alcove_getrlimit(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
ETERM *hd = NULL;
|
||||
int resource = 0;
|
||||
@@ -353,7 +448,7 @@ BADARG:
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_setrlimit(ETERM *arg)
|
||||
alcove_setrlimit(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
ETERM *hd = NULL;
|
||||
int resource = 0;
|
||||
@@ -400,7 +495,7 @@ BADARG:
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_setns(ETERM *arg)
|
||||
alcove_setns(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
ETERM *hd = NULL;
|
||||
char *path = NULL;
|
||||
@@ -437,7 +532,7 @@ BADARG:
|
||||
*
|
||||
*/
|
||||
static ETERM *
|
||||
alcove_unshare(ETERM *arg)
|
||||
alcove_unshare(alcove_state_t *ap, ETERM *arg)
|
||||
{
|
||||
ETERM *hd = NULL;
|
||||
int flags = 0;
|
||||
@@ -512,3 +607,55 @@ alcove_free_argv(char **argv)
|
||||
|
||||
free(argv);
|
||||
}
|
||||
|
||||
static int
|
||||
alcove_stdio(alcove_fd_t *fd)
|
||||
{
|
||||
if ( (pipe(fd->in) < 0)
|
||||
|| (pipe(fd->out) < 0)
|
||||
|| (pipe(fd->err) < 0))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
alcove_child_fun(void *arg)
|
||||
{
|
||||
alcove_child_t *child_arg = arg;
|
||||
alcove_state_t *ap = child_arg->ap;
|
||||
alcove_fd_t *fd = child_arg->fd;
|
||||
|
||||
if ( (close(fd->in[PIPE_WRITE]) < 0)
|
||||
|| (close(fd->out[PIPE_READ]) < 0)
|
||||
|| (close(fd->err[PIPE_READ]) < 0))
|
||||
return -1;
|
||||
|
||||
if ( (dup2(fd->in[PIPE_READ], STDIN_FILENO) < 0)
|
||||
|| (dup2(fd->out[PIPE_WRITE], STDOUT_FILENO) < 0)
|
||||
|| (dup2(fd->err[PIPE_WRITE], STDERR_FILENO) < 0))
|
||||
return -1;
|
||||
|
||||
ap->fdin = fd->in[PIPE_READ];
|
||||
ap->fdout = fd->out[PIPE_WRITE];
|
||||
ap->fderr = fd->err[PIPE_WRITE];
|
||||
|
||||
alcove_ctl(ap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
alcove_parent_fd(alcove_state_t *ap, alcove_fd_t *fd)
|
||||
{
|
||||
if ( (close(fd->in[PIPE_READ]) < 0)
|
||||
|| (close(fd->out[PIPE_WRITE]) < 0)
|
||||
|| (close(fd->err[PIPE_WRITE]) < 0))
|
||||
return -1;
|
||||
|
||||
ap->fdin = fd->in[PIPE_WRITE];
|
||||
ap->fdout = fd->out[PIPE_READ];
|
||||
ap->fderr = fd->err[PIPE_READ];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
chdir/1
|
||||
clone/1
|
||||
chroot/1
|
||||
execvp/2
|
||||
fork/0
|
||||
getcwd/0
|
||||
getgid/0
|
||||
gethostname/0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{application, alcove,
|
||||
[
|
||||
{description, "Erlang sandbox for ports"},
|
||||
{vsn, "0.1.0"},
|
||||
{vsn, "0.2.0"},
|
||||
{registered, []},
|
||||
{applications, [
|
||||
kernel,
|
||||
|
||||
Reference in New Issue
Block a user