ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/win_process.c
Revision: 3.14
Committed: Fri Feb 28 05:18:49 2020 UTC (4 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R3, HEAD
Changes since 3.13: +12 -8 lines
Log Message:
Added filtering capabilities to Unix version of open_process()

File Contents

# Content
1 #ifndef lint
2 static char RCSid[]="$Id: win_process.c,v 3.13 2016/03/28 16:59:38 schorsch Exp $";
3 #endif
4 /*
5 * Routines to communicate with separate process via dual pipes.
6 * Windows version.
7 *
8 * External symbols declared in standard.h
9 */
10
11 #include "copyright.h"
12
13 #include <stdio.h>
14 #define STRICT
15 #include <windows.h> /* typedefs */
16 #include <io.h> /* _open_osfhandle */
17 #include <fcntl.h> /* _O_XXX */
18
19 #include "rterror.h"
20 #include "rtio.h"
21 #include "rtprocess.h"
22
23
24 SUBPROC sp_inactive; /* zero initialization is fine */
25
26
27 int
28 win_nice(int inc) /* simple nice(2) replacement for Windows */
29 {
30 /* We don't have much granularity available: IDLE_PRIORITY_CLASS
31 will run whenever no other higher priority process is running */
32 if (inc > 0) {
33 return (int)!SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
34 }
35 return 0;
36 }
37
38
39 /*
40 Safely terminate a process by creating a remote thread
41 in the process that calls ExitProcess.
42 As presented by Andrew Tucker in Windows Developer Magazine.
43 */
44 BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode)
45 {
46 DWORD dwTID, dwCode, dwErr = 0;
47 HANDLE hProcessDup = INVALID_HANDLE_VALUE;
48 HANDLE hRT = NULL;
49 HINSTANCE hKernel = GetModuleHandle("Kernel32");
50 BOOL bSuccess = FALSE;
51
52 BOOL bDup = DuplicateHandle(GetCurrentProcess(),
53 hProcess,
54 GetCurrentProcess(),
55 &hProcessDup,
56 PROCESS_ALL_ACCESS,
57 FALSE,
58 0);
59 /* Detect the special case where the process is already dead... */
60 if ( GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) &&
61 (dwCode == STILL_ACTIVE) ) {
62 FARPROC pfnExitProc;
63 pfnExitProc = GetProcAddress(hKernel, "ExitProcess");
64 hRT = CreateRemoteThread((bDup) ? hProcessDup : hProcess,
65 NULL,
66 0,
67 (LPTHREAD_START_ROUTINE)pfnExitProc,
68 (PVOID)uExitCode, 0, &dwTID);
69 if ( hRT == NULL ) dwErr = GetLastError();
70 } else {
71 dwErr = ERROR_PROCESS_ABORTED;
72 }
73 if ( hRT ) {
74 /* Must wait process to terminate to guarantee that it has exited... */
75 WaitForSingleObject((bDup) ? hProcessDup : hProcess, INFINITE);
76 CloseHandle(hRT);
77 bSuccess = TRUE;
78 }
79 if ( bDup ) CloseHandle(hProcessDup);
80 if ( !bSuccess ) SetLastError(dwErr);
81 return bSuccess;
82 }
83
84
85 static int
86 start_process(SUBPROC *proc, char *cmdstr)
87 {
88 BOOL res;
89 int Pflags = 0;
90 SECURITY_ATTRIBUTES SAttrs;
91 STARTUPINFO SInfo;
92 PROCESS_INFORMATION PInfo;
93 /* welcome to the world of resource handles */
94 HANDLE hToChildRead = NULL;
95 HANDLE hToChildWrite = NULL;
96 HANDLE hFromChildRead = NULL;
97 HANDLE hFromChildWrite = NULL;
98 HANDLE hRead = NULL, hWrite = NULL;
99 HANDLE hStdIn, hStdOut, hStdErr;
100 HANDLE hCurProc;
101
102 /* get process and standard stream handles */
103 hCurProc = GetCurrentProcess();
104 hStdIn = GetStdHandle(STD_INPUT_HANDLE);
105 hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
106 hStdErr = GetStdHandle(STD_ERROR_HANDLE);
107
108 /* the remote pipe handles must be inheritable */
109 SAttrs.bInheritHandle = 1;
110 SAttrs.lpSecurityDescriptor = NULL;
111 SAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);
112
113 /* make pipe, assign to stdout */
114 /* we'll check for errors after CreateProcess()...*/
115 res = CreatePipe(&hFromChildRead, &hFromChildWrite, &SAttrs, 0);
116 res = SetStdHandle(STD_OUTPUT_HANDLE, hFromChildWrite);
117 /* create non-inheritable dup of local end */
118 res = DuplicateHandle(hCurProc, hFromChildRead, hCurProc, &hRead,
119 0, FALSE, DUPLICATE_SAME_ACCESS);
120 CloseHandle(hFromChildRead); hFromChildRead = NULL;
121
122 res = CreatePipe(&hToChildRead, &hToChildWrite, &SAttrs, 0);
123 res = SetStdHandle(STD_INPUT_HANDLE, hToChildRead);
124 res = DuplicateHandle(hCurProc, hToChildWrite, hCurProc, &hWrite,
125 0, FALSE, DUPLICATE_SAME_ACCESS);
126 CloseHandle(hToChildWrite); hToChildWrite = NULL;
127
128 CloseHandle(hCurProc); hCurProc = NULL;
129
130 /* do some bookkeeping for Windows... */
131 SInfo.cb = sizeof(STARTUPINFO);
132 SInfo.lpReserved = NULL;
133 SInfo.lpDesktop = NULL;
134 SInfo.lpTitle = NULL;
135 SInfo.cbReserved2 = 0;
136 SInfo.lpReserved2 = NULL;
137 /* don't open a console automatically, pass handles */
138 SInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
139 SInfo.wShowWindow = SW_HIDE;
140 SInfo.hStdInput = hToChildRead;
141 SInfo.hStdOutput = hFromChildWrite;
142 SInfo.hStdError = hStdErr; /* reuse original stderr */
143
144 res = CreateProcess(NULL, /* command name */
145 cmdstr, /* full command line */
146 NULL, /* default process attributes */
147 NULL, /* default security attributes */
148 1, /* inherit handles (pass doesn't work reliably) */
149 Pflags, /* process flags */
150 NULL, /* no new environment */
151 NULL, /* stay in current directory */
152 &SInfo,
153 &PInfo
154 );
155 /* reset stdin/stdout in any case */
156 SetStdHandle(STD_OUTPUT_HANDLE, hStdOut);
157 SetStdHandle(STD_INPUT_HANDLE, hStdIn);
158 /* Oops... */
159 if(res == 0) {
160 char es[128];
161 _snprintf(es, sizeof(es),
162 "Error creating process (%d)\n", GetLastError());
163 eputs(es);
164 goto error;
165 }
166 /* close stuff we don't need */
167 CloseHandle(PInfo.hThread);
168 CloseHandle(hFromChildWrite); hFromChildWrite = NULL;
169 CloseHandle(hToChildRead); hToChildRead = NULL;
170 /* get the file descriptors */
171 proc->r = _open_osfhandle((long)hRead, _O_RDONLY|_O_BINARY);
172 proc->w = _open_osfhandle((long)hWrite, _O_APPEND|_O_BINARY);
173 proc->pid = PInfo.dwProcessId;
174 proc->flags = PF_RUNNING;
175 CloseHandle(hCurProc);
176 /* Windows doesn't tell us the actual buffer size */
177 return PIPE_BUF;
178
179 error: /* cleanup */
180 if(PInfo.hThread) CloseHandle(PInfo.hThread);
181 if(hToChildRead) CloseHandle(hToChildRead);
182 if(hToChildWrite) CloseHandle(hToChildWrite);
183 if(hFromChildRead) CloseHandle(hFromChildRead);
184 if(hFromChildWrite) CloseHandle(hFromChildWrite);
185 if(hRead) CloseHandle(hRead);
186 if(hWrite) CloseHandle(hWrite);
187 if(hCurProc) CloseHandle(hCurProc);
188 proc->flags = 0;
189 return -1;
190 /* There... Are we happy now? */
191 }
192
193
194 static size_t /* copied size or -1 on error */
195 wordncopy( /* copy (quoted) src to dest. */
196
197 char * dest,
198 char * src,
199 size_t dlen,
200 int insert_space, /* prepend a space */
201 int force_dq /* turn 'src' into "dest" (for Win command line) */
202 )
203 {
204 size_t slen;
205 size_t pos = 0;
206
207 slen = strlen(src);
208 if (insert_space) {
209 if (1 >= dlen) return -1;
210 dest[pos++] = ' ';
211 }
212 if (strpbrk(src, " \f\n\r\t\v")) {
213 if (force_dq && src[0] == '\'' && src[slen-1] == '\'') {
214 if (slen + pos + 1 > dlen) return -1;
215 dest[pos++] = '"';
216 strncpy(dest + pos, src + 1, slen -2);
217 pos += slen - 2;
218 dest[pos++] = '"';
219 } else if (src[0] == '"' && src[slen-1] == '"') {
220 if (slen + pos + 1 > dlen) return -1;
221 strncpy(dest + pos, src, slen);
222 pos += slen;
223 } else {
224 if (slen + pos + 3 > dlen) return -1;
225 dest[pos++] = '"';
226 strncpy(dest + pos, src, slen);
227 pos += slen;
228 dest[pos++] = '"';
229 }
230 } else {
231 if (slen + pos + 1 > dlen) return -1;
232 strncpy(dest + pos, src, slen);
233 pos += slen;
234 }
235 dest[pos] = '\0';
236 return pos;
237 }
238
239
240
241 static char *
242 quoted_cmdline( /* compose command line for StartProcess() as static string */
243
244 char *cmdpath, /* full path to executable */
245 char *sl[] /* list of arguments */
246 )
247 {
248 static char *cmdstr;
249 static size_t clen;
250 char *newcs;
251 size_t newlen, pos, i, res;
252
253 newlen = strlen(cmdpath) + 3; /* allow two quotes plus the final \0 */
254 for (i = 0; sl[i] != NULL; i++) {
255 newlen += strlen(sl[i]) + 3; /* allow two quotes and a space */
256 }
257 if (cmdstr == NULL) {
258 cmdstr = (char *) malloc(newlen);
259 if (cmdstr == NULL) return NULL;
260 } else if (newlen > clen) {
261 newcs = (char *) realloc(cmdstr, newlen);
262 if (newcs == NULL) return NULL;
263 cmdstr = newcs;
264 }
265 clen = newlen;
266 pos = wordncopy(cmdstr, cmdpath, clen, 0, 1);
267 if (pos < 0) return NULL;
268 for (i = 0; sl[i] != NULL; i++) {
269 res = wordncopy(cmdstr + pos, sl[i], clen - pos, 1, 1);
270 if (res < 0) return NULL;
271 pos += res;
272 }
273 return cmdstr;
274 }
275
276
277 int
278 open_process(SUBPROC *proc, char *av[])
279 {
280 char *cmdpath;
281 char *cmdstr;
282
283 if (av == NULL || av[0] == NULL || proc->flags) {
284 fputs("Illegal call to open_process()!\n", stderr);
285 return -1;
286 }
287 proc->pid = 0;
288 if (av == NULL) { return -1; }
289 cmdpath = getpath(av[0], getenv("PATH"), X_OK);
290 cmdstr = quoted_cmdline(cmdpath, av+1);
291 if (cmdstr == NULL) { return 0; }
292 return start_process(proc, cmdstr);
293 }
294
295
296 int win_kill(RT_PID pid, int sig) /* we ignore sig... */
297 {
298 HANDLE hProc;
299
300 hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, pid);
301 /* it looks like we want to ignore errors here */
302 if(hProc != NULL) {
303 SafeTerminateProcess(hProc, 0);
304 CloseHandle(hProc);
305 }
306 return 0; /* XXX we need to figure out more here... */
307 }
308
309
310 int
311 close_processes(SUBPROC pd[], int nproc) {
312 int i, icres, ocres;
313 DWORD pid;
314
315 for (i = 0; i < nproc; i++) {
316 if (pd[i].flags & PF_RUNNING) {
317 ocres = close(pd[i].w);
318 icres = close(pd[i].r);
319 pd[i].flags = 0;
320 if(ocres != 0 || icres != 0) {
321 /* something went wrong: enforce infanticide */
322 /* other than that, it looks like we want to ignore errors */
323 win_kill(pd[i].pid, 0);
324 }
325 }
326 pd[i].pid = 0;
327 }
328 return 0; /* XXX we need to figure out more here... */
329 }
330
331
332 #ifdef TEST_MODULE
333 int
334 main( int argc, char **argv )
335 {
336 SUBPROC proc;
337 FILE *inf, *outf;
338 int res;
339 char ret[1024];
340 char *command[]= {"word", "gappy word", "\"quoted words\"", "'squoted words'", NULL};
341
342 proc.flags = 0;
343 proc.pid = 0;
344 res = open_process(&proc, command)
345 if (res == 0) {
346 printf("open_process() failed with return value 0\n");
347 return -1;
348 }
349 printf("process opened with return value: %d, pid: %d, r: %d, w: %d\n",
350 res, proc.pid, proc.r, proc.w);
351 inf = fdopen(proc.r, "rb");
352 outf = fdopen(proc.w, "wb");
353 fprintf(outf,"0 0 0 0 1 0\n");
354 fflush(outf);
355 fgets(ret, sizeof(ret), inf);
356 printf("%s\n",ret);
357 close_process(&proc);
358 }
359 #endif
360