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 */
4 
5 /* this file contains the source for opening addresses of exec type */
6 
7 #include "xiosysincludes.h"
8 #include "xioopen.h"
9 #include "nestlex.h"
10 
11 #include "xio-progcall.h"
12 #include "xio-exec.h"
13 
14 #if WITH_EXEC
15 
16 static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
17 		int xioflags,	/* XIO_RDONLY etc. */
18 		xiofile_t *fd,
19 		unsigned groups,
20 		int dummy1, int dummy2, int dummy3
21 		);
22 
23 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>") };
24 
25 const struct optdesc opt_dash = { "dash", "login", OPT_DASH, GROUP_EXEC, PH_PREEXEC, TYPE_BOOL, OFUNC_SPEC };
26 
27 static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
28 		int xioflags,	/* XIO_RDONLY, XIO_MAYCHILD etc. */
29 		xiofile_t *fd,
30 		unsigned groups,
31 		int dummy1, int dummy2, int dummy3
32 		) {
33    int status;
34    bool dash = false;
35    int duptostderr;
36 
37    if (argc != 2) {
38       Error3("\"%s:%s\": wrong number of parameters (%d instead of 1)", argv[0], argv[1], argc-1);
39    }
40 
41    retropt_bool(opts, OPT_DASH, &dash);
42 
43    status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts, &duptostderr);
44    if (status < 0)  return status;
45    if (status == 0) {	/* child */
46       const char *ends[] = { " ", NULL };
47       const char *hquotes[] = { "'", NULL };
48       const char *squotes[] = { "\"", NULL };
49       const char *nests[] = {
50 	 "'", "'",
51 	 "(", ")",
52 	 "[", "]",
53 	 "{", "}",
54 	 NULL
55       } ;
56       char **pargv = NULL;
57       int pargc;
58       size_t len;
59       const char *strp;
60       char *token; /*! */
61       char *tokp;
62       char *path = NULL;
63       char *tmp;
64       int numleft;
65 
66       /*! Close(something) */
67       /* parse command line */
68       Debug1("child: args = \"%s\"", argv[1]);
69       pargv = Malloc(8*sizeof(char *));
70       if (pargv == NULL)  return STAT_RETRYLATER;
71       len = strlen(argv[1])+1;
72       strp = argv[1];
73       token = Malloc(len); /*! */
74       tokp = token;
75       if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
76 		  true, true, false) < 0) {
77 	 Error("internal: miscalculated string lengths");
78       }
79       *tokp++ = '\0';
80       pargv[0] = strrchr(tokp-1, '/');
81       if (pargv[0] == NULL)  pargv[0] = token;  else  ++pargv[0];
82       pargc = 1;
83       while (*strp == ' ') {
84 	 while (*++strp == ' ')  ;
85 	 if ((pargc & 0x07) == 0) {
86 	    pargv = Realloc(pargv, (pargc+8)*sizeof(char *));
87 	    if (pargv == NULL)  return STAT_RETRYLATER;
88 	 }
89 	 pargv[pargc++] = tokp;
90 	 if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
91 		     true, true, false) < 0) {
92 	    Error("internal: miscalculated string lengths");
93 	 }
94 	 *tokp++ = '\0';
95       }
96       pargv[pargc] = NULL;
97 
98       if ((tmp = Malloc(strlen(pargv[0])+2)) == NULL) {
99 	 return STAT_RETRYLATER;
100       }
101       if (dash) {
102 	 tmp[0] = '-';
103 	 strcpy(tmp+1, pargv[0]);
104       } else {
105 	 strcpy(tmp, pargv[0]);
106       }
107       pargv[0] = tmp;
108 
109       if (setopt_path(opts, &path) < 0) {
110 	 /* this could be dangerous, so let us abort this child... */
111 	 Exit(1);
112       }
113 
114       if ((numleft = leftopts(opts)) > 0) {
115 	 Error1("%d option(s) could not be used", numleft);
116 	 showleft(opts);
117 	 return STAT_NORETRY;
118       }
119 
120       /* only now redirect stderr */
121       if (duptostderr >= 0) {
122 	 diag_dup();
123 	 Dup2(duptostderr, 2);
124       }
125       Notice1("execvp'ing \"%s\"", token);
126       Execvp(token, pargv);
127       /* here we come only if execvp() failed */
128       switch (pargc) {
129       case 1: Error3("execvp(\"%s\", \"%s\"): %s", token, pargv[0], strerror(errno)); break;
130       case 2: Error4("execvp(\"%s\", \"%s\", \"%s\"): %s", token, pargv[0], pargv[1], strerror(errno)); break;
131       case 3:
132       default:
133 	 Error5("execvp(\"%s\", \"%s\", \"%s\", \"%s\", ...): %s", token, pargv[0], pargv[1], pargv[2], strerror(errno)); break;
134       }
135       Exit(1);	/* this child process */
136    }
137 
138    /* parent */
139    return 0;
140 }
141 #endif /* WITH_EXEC */
142