ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/win_process.c
Revision: 3.1
Committed: Thu Jun 26 00:58:09 2003 UTC (20 years, 10 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Log Message:
Abstracted process and path handling for Windows.
Renamed FLOAT to RREAL because of conflict on Windows.
Added conditional compiles for some signal handlers.

File Contents

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