socat/xio-exec.c

155 lines
4.5 KiB
C
Raw Normal View History

2008-01-28 21:37:16 +00:00
/* source: xio-exec.c */
/* Copyright Gerhard Rieger 2001-2008 */
2008-01-27 12:00:08 +00:00
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of exec type */
2008-02-17 13:59:16 +00:00
/* this file contains the source for an inter address that just invokes a
program. The program should provide its data side on FDs 0 and 1, and its
protocol side on FDs 3 and 4. */
2008-01-27 12:00:08 +00:00
#include "xiosysincludes.h"
#include "xioopen.h"
#include "nestlex.h"
#include "xio-progcall.h"
#include "xio-exec.h"
#if WITH_EXEC
2008-02-17 13:59:16 +00:00
static int xioopen_exec1end(int argc, const char *argv[], struct opt *opts,
2008-01-27 12:00:08 +00:00
int xioflags, /* XIO_RDONLY etc. */
xiofile_t *fd,
unsigned groups,
int dummy1, int dummy2, int dummy3
);
2008-02-17 13:59:16 +00:00
static const struct xioaddr_endpoint_desc xioaddr_exec1end = { XIOADDR_ENDPOINT, "exec", 1, XIOBIT_ALL, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, XIOSHUT_UNSPEC, XIOCLOSE_UNSPEC, xioopen_exec1end, 0, 0, 0 HELP(":<command-line>") };
const union xioaddr_desc *xioaddrs_exec[] = {
(union xioaddr_desc *)&xioaddr_exec1end,
NULL };
2008-01-27 12:00:08 +00:00
const struct optdesc opt_dash = { "dash", "login", OPT_DASH, GROUP_EXEC, PH_PREEXEC, TYPE_BOOL, OFUNC_SPEC };
2008-02-17 13:59:16 +00:00
static int xioopen_exec1end(int argc, const char *argv[], struct opt *opts,
2008-01-27 12:00:08 +00:00
int xioflags, /* XIO_RDONLY, XIO_MAYCHILD etc. */
xiofile_t *fd,
unsigned groups,
int dummy1, int dummy2, int dummy3
) {
int status;
bool dash = false;
int duptostderr;
2008-01-27 12:00:08 +00:00
if (argc != 2) {
Error3("\"%s:%s\": wrong number of parameters (%d instead of 1)", argv[0], argv[1], argc-1);
}
retropt_bool(opts, OPT_DASH, &dash);
2008-10-22 00:33:23 +00:00
status = _xioopen_foxec_end(xioflags, &fd->stream, groups, &opts, &duptostderr);
2008-01-27 12:00:08 +00:00
if (status < 0) return status;
if (status == 0) { /* child */
const char *ends[] = { " ", NULL };
const char *hquotes[] = { "'", NULL };
const char *squotes[] = { "\"", NULL };
const char *nests[] = {
"'", "'",
"(", ")",
"[", "]",
"{", "}",
NULL
} ;
char **pargv = NULL;
int pargc, i;
size_t len;
const char *strp;
char *token; /*! */
char *tokp;
char *path = NULL;
char *tmp;
int numleft;
int result;
/*! Close(something) */
/* parse command line */
Debug1("child: args = \"%s\"", argv[1]);
pargv = Malloc(8*sizeof(char *));
if (pargv == NULL) return STAT_RETRYLATER;
i = 0;
len = strlen(argv[1])+1;
strp = argv[1];
token = Malloc(len); /*! */
tokp = token;
if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
2008-02-17 13:59:16 +00:00
false, true, true, false) < 0) {
2008-01-27 12:00:08 +00:00
Error("internal: miscalculated string lengths");
}
*tokp++ = '\0';
pargv[0] = strrchr(tokp-1, '/');
if (pargv[0] == NULL) pargv[0] = token; else ++pargv[0];
pargc = 1;
while (*strp == ' ') {
while (*++strp == ' ') ;
2008-01-27 12:00:08 +00:00
if ((pargc & 0x07) == 0) {
pargv = Realloc(pargv, (pargc+8)*sizeof(char *));
if (pargv == NULL) return STAT_RETRYLATER;
}
pargv[pargc++] = tokp;
if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
2008-02-17 13:59:16 +00:00
false, true, true, false) < 0) {
2008-01-27 12:00:08 +00:00
Error("internal: miscalculated string lengths");
}
*tokp++ = '\0';
}
pargv[pargc] = NULL;
if ((tmp = Malloc(strlen(pargv[0])+2)) == NULL) {
return STAT_RETRYLATER;
}
if (dash) {
tmp[0] = '-';
strcpy(tmp+1, pargv[0]);
} else {
strcpy(tmp, pargv[0]);
}
pargv[0] = tmp;
if (setopt_path(opts, &path) < 0) {
/* this could be dangerous, so let us abort this child... */
Exit(1);
}
if ((numleft = leftopts(opts)) > 0) {
Error1("%d option(s) could not be used", numleft);
showleft(opts);
return STAT_NORETRY;
}
/* only now redirect stderr */
if (duptostderr >= 0) {
diag_dup();
Dup2(duptostderr, 2);
}
2008-01-27 12:00:08 +00:00
Notice1("execvp'ing \"%s\"", token);
result = Execvp(token, pargv);
/* here we come only if execvp() failed */
switch (pargc) {
case 1: Error3("execvp(\"%s\", \"%s\"): %s", token, pargv[0], strerror(errno)); break;
case 2: Error4("execvp(\"%s\", \"%s\", \"%s\"): %s", token, pargv[0], pargv[1], strerror(errno)); break;
case 3:
default:
Error5("execvp(\"%s\", \"%s\", \"%s\", \"%s\", ...): %s", token, pargv[0], pargv[1], pargv[2], strerror(errno)); break;
}
Exit(1); /* this child process */
}
/* parent */
return 0;
}
2008-02-17 13:59:16 +00:00
2008-01-27 12:00:08 +00:00
#endif /* WITH_EXEC */