1 /*
2 * Copyright (C) 2010, 2013, 2014, 2016, the Free Software Foundation, Inc.
3 *
4 * This file is part of GAWK, the GNU implementation of the
5 * AWK Programming Language.
6 *
7 * GAWK is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * GAWK is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <io.h>
25 #include <string.h>
26 #include <process.h>
27 #include <errno.h>
28 #include "popen.h"
29 #undef popen
30 #undef pclose
31 #undef system
32
33 #ifndef _NFILE
34 #define _NFILE 40
35 #endif
36
37 static struct {
38 char *command;
39 char *name;
40 char pmode[4];
41 } pipes[_NFILE];
42
43
44 /*
45 * For systems where system() and popen() do not follow SHELL:
46 * 1. Write command to temp file. Temp filename must have slashes
47 * compatible with SHELL (if set) or COMSPEC.
48 * 2. Convert slashes in SHELL (if present) to be compatible with COMSPEC.
49 * Currently, only MSC (running under DOS) and MINGW versions are managed.
50 */
51
52 #if defined(__MINGW32__)
53
54 #define WIN32_LEAN_AND_MEAN
55 #include <windows.h>
56
57 #if 0
58 static int
59 unixshell(char *p)
60 {
61 static char *shell[] = {"sh", "bash", "csh", "tcsh", "sh32", "sh16", "ksh", NULL};
62 char **shellp = shell, *s, *q;
63
64 if (p == NULL) return (0);
65 s = p = strdup(p);
66 if ((q = strrchr(p, '\\')) != NULL)
67 p = q + 1;
68 if ((q = strrchr(p, '/')) != NULL)
69 p = q + 1;
70 if ((q = strchr(p, '.')) != NULL)
71 *q = '\0';
72 strlwr(p);
73 do {
74 if (strcmp(*shellp, p) == 0) break;
75 } while (*++shellp);
76 free(s);
77 return(*shellp ? 1 : 0);
78 }
79
80 static char *
81 slashify(char *p, char *s)
82 {
83 if (unixshell(s))
84 while (s = strchr(p, '\\')) *s = '/';
85 else
86 while (s = strchr(p, '/')) *s = '\\';
87 return(p);
88 }
89
90 static char *
91 scriptify(const char *command)
92 {
93 FILE *fp;
94 char *cmd, *name, *s, *p;
95 int i;
96
97 if((name = tempnam(".", "pip")) == NULL) return(NULL);
98 p = getenv("COMSPEC"); s = getenv("SHELL");
99 cmd = malloc(strlen(name) + (s ? strlen(s) : 0) + 9); *cmd = '\0';
100 if (s) {
101 slashify(strcpy(cmd, s), p);
102 p = s;
103 }
104 slashify(name, p);
105 if (! (i = unixshell(p))) {
106 char *p = (char *) realloc(name, strlen(name) + 5);
107 if (p == NULL) {
108 free(cmd);
109 return NULL;
110 }
111 name = p;
112 strcat(name, ".bat");
113 }
114 if (s) sprintf(cmd + strlen(cmd), " %cc ", unixshell(s) ? '-' : '/');
115 strcpy(p = cmd + strlen(cmd), name); free(name);
116
117 if ((fp = fopen(p, i ? "wb" : "w")) != NULL) {
118 if (! i) fputs("@echo off\n", fp);
119 i = strlen(command);
120 if ((fwrite(command, 1, i, fp) < i) || (fputc('\n', fp) == EOF)) {
121 free(cmd);
122 cmd = NULL;
123 }
124 } else {
125 free(cmd);
126 cmd = NULL;
127 }
128 if (fp) fclose(fp);
129 return(cmd);
130 }
131
132 static void
133 unlink_and_free(char *cmd)
134 {
135 char *s;
136
137 if (s = strrchr(cmd, ' '))
138 s++;
139 else
140 s = cmd;
141 unlink(s); free(cmd);
142 }
143 #endif
144
145 int
146 os_system(const char *cmd)
147 {
148 char *cmdexe = getenv("ComSpec");
149 char *cmd1 = quote_cmd(cmd);
150 int i = spawnl(P_WAIT, cmdexe, "cmd.exe", "/c", cmd1, NULL);
151
152 free(cmd1);
153 return(i);
154 }
155
156 #ifndef PIPES_SIMULATED
157 int
158 kill (int pid, int sig)
159 {
160 HANDLE ph;
161 int retval = 0;
162
163 /* We only support SIGKILL. */
164 if (sig != SIGKILL)
165 {
166 errno = ENOSYS;
167 return -1;
168 }
169
170 ph = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
171 if (ph)
172 {
173 BOOL status = TerminateProcess(ph, -1);
174
175 if (!status)
176 {
177 errno = EPERM;
178 retval = -1;
179 }
180 }
181 else
182 {
183 /* If we cannot open the process, it means we eaither aren't
184 allowed to (e.g., a process of another user), or such a
185 process doesn't exist. */
186 switch (GetLastError ())
187 {
188 case ERROR_ACCESS_DENIED:
189 errno = EPERM;
190 break;
191 default:
192 errno = ESRCH;
193 break;
194 }
195 retval = -1;
196 }
197 CloseHandle (ph);
198 return retval;
199 }
200
201 char *
202 quote_cmd(const char *cmd)
203 {
204 char *quoted;
205
206 /* The command will be invoked via cmd.exe, whose behavior wrt
207 quoted commands is to remove the first and the last quote
208 characters, and leave the rest (including any quote characters
209 inside the outer pair) intact. */
210 quoted = malloc(strlen (cmd) + 2 + 1);
211 sprintf(quoted, "\"%s\"", cmd);
212
213 return quoted;
214 }
215 #endif
216
217 #else /* !__MINGW32__ */
218 #define os_system(cmd) system(cmd)
219 #endif
220
221
222 FILE *
223 os_popen(const char *command, const char *mode )
224 {
225 FILE *current;
226 char *name;
227 int cur;
228 char curmode[4];
229
230 if (*mode != 'r' && *mode != 'w')
231 return NULL;
232 strncpy(curmode, mode, 3); curmode[3] = '\0';
233
234 #if defined(__MINGW32__)
235 current = popen(command, mode);
236 cur = fileno(current);
237 strcpy(pipes[cur].pmode, curmode);
238 return(current);
239 #endif
240
241 /*
242 ** get a name to use.
243 */
244 if((name = tempnam(".","pip"))==NULL)
245 return NULL;
246 /*
247 ** If we're reading, just call system to get a file filled with
248 ** output.
249 */
250 if (*curmode == 'r') {
251 FILE *fp;
252 if ((cur = dup(fileno(stdout))) == -1)
253 return NULL;
254 *curmode = 'w';
255 if ((current = freopen(name, curmode, stdout)) == NULL)
256 return NULL;
257 os_system(command);
258 if (dup2(cur, fileno(stdout)) == -1)
259 return NULL;
260 close(cur);
261 *curmode = 'r';
262 if ((current = fopen(name, curmode)) == NULL)
263 return NULL;
264 } else {
265 if ((current = fopen(name, curmode)) == NULL)
266 return NULL;
267 }
268 cur = fileno(current);
269 pipes[cur].name = name;
270 strcpy(pipes[cur].pmode, curmode);
271 pipes[cur].command = strdup(command);
272 return current;
273 }
274
275 int
276 os_pclose( FILE * current)
277 {
278 int cur = fileno(current);
279 int fd, rval;
280
281 #if defined(__MINGW32__)
282 rval = pclose(current);
283 *pipes[cur].pmode = '\0';
284 return rval;
285 #endif
286
287 /*
288 ** check for an open file.
289 */
290 switch (*pipes[cur].pmode) {
291 case 'r':
292 /*
293 ** input pipes are just files we're done with.
294 */
295 rval = fclose(current);
296 unlink(pipes[cur].name);
297 break;
298 case 'w':
299 /*
300 ** output pipes are temporary files we have
301 ** to cram down the throats of programs.
302 */
303 fclose(current);
304 rval = -1;
305 if ((fd = dup(fileno(stdin))) != -1) {
306 char *mode = pipes[cur].pmode; *mode = 'r';
307 if (current = freopen(pipes[cur].name, mode, stdin)) {
308 rval = os_system(pipes[cur].command);
309 fclose(current);
310 if (dup2(fd, fileno(stdin)) == -1) rval = -1;
311 close(fd);
312 }
313 }
314 unlink(pipes[cur].name);
315 break;
316 default:
317 return -1;
318 }
319 /*
320 ** clean up current pipe.
321 */
322 *pipes[cur].pmode = '\0';
323 free(pipes[cur].name);
324 free(pipes[cur].command);
325 return rval;
326 }