Version 1.8.0.0
[socat.git] / xio-exec.c
blobbed513cf76005eca1b3f3747074d9dcfba6aa513
1 /* source: xio-exec.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for opening addresses of exec type */
7 #include "xiosysincludes.h"
8 #include "xioopen.h"
9 #include "nestlex.h"
11 #include "xio-progcall.h"
12 #include "xio-exec.h"
14 #if WITH_EXEC
16 static int xioopen_exec(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
18 const struct addrdesc xioaddr_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>") };
20 const struct optdesc opt_dash = { "dash", "login", OPT_DASH, GROUP_EXEC, PH_PREEXEC, TYPE_BOOL, OFUNC_SPEC };
22 static int xioopen_exec(
23 int argc,
24 const char *argv[],
25 struct opt *opts,
26 int xioflags, /* XIO_RDONLY, XIO_MAYCHILD etc. */
27 xiofile_t *xfd,
28 const struct addrdesc *addrdesc)
30 struct single *sfd = &xfd->stream;
31 int status;
32 bool dash = false;
33 int duptostderr;
34 int numleft;
36 if (argc != 2) {
37 xio_syntax(argv[0], 1, argc-1, addrdesc->syntax);
38 return STAT_NORETRY;
41 retropt_bool(opts, OPT_DASH, &dash);
43 status =
44 _xioopen_foxec(xioflags, sfd, addrdesc->groups, &opts, &duptostderr);
45 if (status < 0)
46 return status;
47 if (status == 0) { /* child */
48 const char *ends[] = { " ", NULL };
49 const char *hquotes[] = { "'", NULL };
50 const char *squotes[] = { "\"", NULL };
51 const char *nests[] = {
52 "'", "'",
53 "(", ")",
54 "[", "]",
55 "{", "}",
56 NULL
57 } ;
58 char **pargv = NULL;
59 int pargc;
60 size_t len;
61 const char *strp;
62 char *token; /*! */
63 char *tokp;
64 char *path = NULL;
65 char *tmp;
67 /*! Close(something) */
68 /* parse command line */
69 Debug1("child: args = \"%s\"", argv[1]);
70 pargv = Malloc(8*sizeof(char *));
71 if (pargv == NULL) return STAT_RETRYLATER;
72 len = strlen(argv[1])+1;
73 strp = argv[1];
74 token = Malloc(len); /*! */
75 tokp = token;
76 if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
77 true, true, false) < 0) {
78 Error("internal: miscalculated string lengths");
80 *tokp++ = '\0';
81 pargv[0] = strrchr(tokp-1, '/');
82 if (pargv[0] == NULL) pargv[0] = token; else ++pargv[0];
83 pargc = 1;
84 while (*strp == ' ') {
85 while (*++strp == ' ') ;
86 if ((pargc & 0x07) == 0) {
87 pargv = Realloc(pargv, (pargc+8)*sizeof(char *));
88 if (pargv == NULL) return STAT_RETRYLATER;
90 pargv[pargc++] = tokp;
91 if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
92 true, true, false) < 0) {
93 Error("internal: miscalculated string lengths");
95 *tokp++ = '\0';
97 pargv[pargc] = NULL;
99 if ((tmp = Malloc(strlen(pargv[0])+2)) == NULL) {
100 return STAT_RETRYLATER;
102 if (dash) {
103 tmp[0] = '-';
104 strcpy(tmp+1, pargv[0]);
105 } else {
106 strcpy(tmp, pargv[0]);
108 pargv[0] = tmp;
110 if (setopt_path(opts, &path) < 0) {
111 /* this could be dangerous, so let us abort this child... */
112 Exit(1);
115 dropopts(opts, PH_PASTEXEC);
116 if ((numleft = leftopts(opts)) > 0) {
117 showleft(opts);
118 Error1("INTERNAL: %d option(s) remained unused", numleft);
119 return STAT_NORETRY;
122 /* only now redirect stderr */
123 if (duptostderr >= 0) {
124 diag_dup();
125 Dup2(duptostderr, 2);
127 Notice1("execvp'ing \"%s\"", token);
128 Execvp(token, pargv);
129 /* here we come only if execvp() failed */
130 switch (pargc) {
131 case 1:
132 Error3("execvp(\"%s\", \"%s\"): %s",
133 token, pargv[0], strerror(errno)); break;
134 case 2:
135 Error4("execvp(\"%s\", \"%s\", \"%s\"): %s",
136 token, pargv[0], pargv[1], strerror(errno)); break;
137 case 3:
138 default:
139 Error5("execvp(\"%s\", \"%s\", \"%s\", \"%s\", ...): %s", token,
140 pargv[0], pargv[1], pargv[2], strerror(errno));
141 break;
143 Exit(1); /* this child process */
146 /* parent */
147 _xio_openlate(sfd, opts);
148 return 0;
150 #endif /* WITH_EXEC */