forked from erluko/socat
-
Notifications
You must be signed in to change notification settings - Fork 0
/
xio-exec.c
141 lines (124 loc) · 4.01 KB
/
xio-exec.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* source: xio-exec.c */
/* Copyright Gerhard Rieger 2001-2011 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of exec type */
#include "xiosysincludes.h"
#include "xioopen.h"
#include "nestlex.h"
#include "xio-progcall.h"
#include "xio-exec.h"
#if WITH_EXEC
static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
int xioflags, /* XIO_RDONLY etc. */
xiofile_t *fd,
unsigned groups,
int dummy1, int dummy2, int dummy3
);
const struct addrdesc addr_exec = { "exec", 3, xioopen_exec, GROUP_FD|GROUP_FORK|GROUP_EXEC|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_TERMIOS|GROUP_FIFO|GROUP_PTY|GROUP_PARENT, 0, 0, 0 HELP(":<command-line>") };
const struct optdesc opt_dash = { "dash", "login", OPT_DASH, GROUP_EXEC, PH_PREEXEC, TYPE_BOOL, OFUNC_SPEC };
static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
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;
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);
status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts, &duptostderr);
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;
size_t len;
const char *strp;
char *token; /*! */
char *tokp;
char *path = NULL;
char *tmp;
int numleft;
/*! Close(something) */
/* parse command line */
Debug1("child: args = \"%s\"", argv[1]);
pargv = Malloc(8*sizeof(char *));
if (pargv == NULL) return STAT_RETRYLATER;
len = strlen(argv[1])+1;
strp = argv[1];
token = Malloc(len); /*! */
tokp = token;
if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
true, true, false) < 0) {
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 == ' ') ;
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,
true, true, false) < 0) {
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);
}
Notice1("execvp'ing \"%s\"", token);
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;
}
#endif /* WITH_EXEC */