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