ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/win_process.c
Revision: 3.13
Committed: Mon Mar 28 16:59:38 2016 UTC (8 years, 1 month ago) by schorsch
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R2, rad5R1
Changes since 3.12: +2 -16 lines
Log Message:
Remove code for obsolete systems.

File Contents

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