"Fossies" - the Fresh Open Source Software Archive 
Member "seed7/src/pcs_win.c" (31 Dec 2020, 35925 Bytes) of package /linux/misc/seed7_05_20210223.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "pcs_win.c" see the
Fossies "Dox" file reference documentation.
1 /********************************************************************/
2 /* */
3 /* pcs_win.c Process functions which use the Windows API. */
4 /* Copyright (C) 1989 - 2014 Thomas Mertes */
5 /* */
6 /* This file is part of the Seed7 Runtime Library. */
7 /* */
8 /* The Seed7 Runtime Library is free software; you can */
9 /* redistribute it and/or modify it under the terms of the GNU */
10 /* Lesser General Public License as published by the Free Software */
11 /* Foundation; either version 2.1 of the License, or (at your */
12 /* option) any later version. */
13 /* */
14 /* The Seed7 Runtime Library is distributed in the hope that it */
15 /* will be useful, but WITHOUT ANY WARRANTY; without even the */
16 /* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /* PURPOSE. See the GNU Lesser General Public License for more */
18 /* details. */
19 /* */
20 /* You should have received a copy of the GNU Lesser General */
21 /* Public License along with this program; if not, write to the */
22 /* Free Software Foundation, Inc., 51 Franklin Street, */
23 /* Fifth Floor, Boston, MA 02110-1301, USA. */
24 /* */
25 /* Module: Seed7 Runtime Library */
26 /* File: seed7/src/pcs_win.c */
27 /* Changes: 2010, 2012 - 2014 Thomas Mertes */
28 /* Content: Process functions which use the Windows API. */
29 /* */
30 /********************************************************************/
31
32 #define LOG_FUNCTIONS 0
33 #define VERBOSE_EXCEPTIONS 0
34
35 #include "version.h"
36
37 #include "stdlib.h"
38 #include "stdio.h"
39 #include "string.h"
40 #include "windows.h"
41 #include "io.h"
42 #include "fcntl.h"
43 #include "wchar.h"
44 #include "ctype.h"
45 #include "errno.h"
46
47 #include "common.h"
48 #include "data_rtl.h"
49 #include "os_decls.h"
50 #include "heaputl.h"
51 #include "striutl.h"
52 #include "int_rtl.h"
53 #include "rtl_err.h"
54
55
56 #define MAXIMUM_COMMAND_LINE_LENGTH 32768
57
58 typedef struct {
59 uintType usage_count;
60 fileType stdIn;
61 fileType stdOut;
62 fileType stdErr;
63 /* Up to here the structure is identical to struct processStruct */
64 HANDLE hProcess;
65 HANDLE hThread;
66 DWORD pid;
67 boolType isTerminated;
68 DWORD exitValue;
69 } win_processRecord, *win_processType;
70
71 typedef const win_processRecord *const_win_processType;
72
73 #if DO_HEAP_STATISTIC
74 size_t sizeof_processRecord = sizeof(win_processRecord);
75 #endif
76
77 #define to_hProcess(process) (((const_win_processType) process)->hProcess)
78 #define to_hThread(process) (((const_win_processType) process)->hThread)
79 #define to_pid(process) (((const_win_processType) process)->pid)
80 #define to_isTerminated(process) (((const_win_processType) process)->isTerminated)
81 #define to_exitValue(process) (((const_win_processType) process)->exitValue)
82
83 #define to_var_hProcess(process) (((win_processType) process)->hProcess)
84 #define to_var_hThread(process) (((win_processType) process)->hThread)
85 #define to_var_pid(process) (((win_processType) process)->pid)
86 #define to_var_isTerminated(process) (((win_processType) process)->isTerminated)
87 #define to_var_exitValue(process) (((win_processType) process)->exitValue)
88
89 #if POINTER_SIZE == 32
90 typedef int32Type intPtrType;
91 #elif POINTER_SIZE == 64
92 typedef int64Type intPtrType;
93 #endif
94
95
96
97 #if ANY_LOG_ACTIVE
98 static void printParameters (const const_rtlArrayType parameters)
99
100 {
101 memSizeType paramSize;
102 memSizeType pos;
103
104 /* printParameters */
105 paramSize = arraySize(parameters);
106 for (pos = 0; pos < paramSize; pos++) {
107 printf(", \"%s\"",
108 striAsUnquotedCStri(parameters->arr[pos].value.striValue));
109 } /* for */
110 } /* printParameters */
111 #endif
112
113
114
115 /**
116 * Fill the contents of a quoted part to be used by prepareCommandLine.
117 * This function does not create the surrounding quotations (").
118 * A string with the backslash logic of Windows commandline parameters
119 * is produced. 2 * N backslashes followed by a quotation (") means
120 * N backslashes and the end of the parameter. Note that in this case
121 * the quotation is written by prepareCommandLine. 2 * N + 1 backslashes
122 * followed by a quotation (") means N backslashes and the quotation
123 * is part of the parameter. N backslashes not followed by a quotation
124 * means just N backslashes.
125 */
126 static os_charType *copyQuotedPart (os_charType *sourceChar, os_charType *destChar,
127 os_charType *beyondDest)
128
129 {
130 memSizeType countBackslash;
131
132 /* copyQuotedPart */
133 for (; *sourceChar != '\0' && destChar < beyondDest;
134 sourceChar++, destChar++) {
135 if (*sourceChar == '"') {
136 if (&destChar[2] > beyondDest) {
137 destChar = beyondDest;
138 } else {
139 *(destChar++) = '\\';
140 *destChar = *sourceChar;
141 } /* if */
142 } else if (*sourceChar == '\\') {
143 sourceChar++;
144 countBackslash = 1;
145 while (*sourceChar == '\\') {
146 sourceChar++;
147 countBackslash++;
148 } /* while */
149 /* fprintf(stderr, "countBackslash=" FMT_U_MEM "\n", countBackslash);
150 fprintf(stderr, "sourceChar=%c\n", *sourceChar); */
151 if (*sourceChar == '"' || *sourceChar == '\0') {
152 countBackslash *= 2;
153 } /* if */
154 sourceChar--;
155 if (countBackslash > MAXIMUM_COMMAND_LINE_LENGTH ||
156 &destChar[countBackslash] > beyondDest) {
157 destChar = beyondDest;
158 } else {
159 do {
160 *(destChar++) = '\\';
161 countBackslash--;
162 } while (countBackslash != 0);
163 destChar--;
164 } /* if */
165 } else {
166 *destChar = *sourceChar;
167 } /* if */
168 } /* for */
169 return destChar;
170 } /* copyQuotedPart */
171
172
173
174 /**
175 * Create a command line string that can be used by CreateProcessW().
176 * All parameters that contain a space or a quotation (") or a control
177 * character or a character byond ASCII are quoted. All other parameters
178 * are not quoted. The command line string must be freed with os_stri_free().
179 * @param err_info Unchanged if the function succeeds, and
180 * MEMORY_ERROR if a memory allocation failed, and
181 * RANGE_ERROR if the conversion of a parameter failed.
182 * @return a null terminated os_striType command line, or
183 * NULL if an error occurred.
184 */
185 static os_striType prepareCommandLine (const const_os_striType os_command_stri,
186 const const_rtlArrayType parameters, errInfoType *err_info)
187
188 {
189 const_os_striType command_stri;
190 memSizeType arraySize;
191 memSizeType striSize;
192 memSizeType pos;
193 os_striType argument;
194 os_charType *sourceChar;
195 os_charType *destChar;
196 os_charType *beyondDest;
197 boolType quoteArgument;
198 os_striType command_line;
199
200 /* prepareCommandLine */
201 logFunction(printf("prepareCommandLine(\"" FMT_S_OS "\"",
202 os_command_stri);
203 printParameters(parameters);
204 printf(", %d)\n", *err_info););
205 arraySize = arraySize(parameters);
206 if (unlikely(!os_stri_alloc(command_line, MAXIMUM_COMMAND_LINE_LENGTH - 1))) {
207 *err_info = MEMORY_ERROR;
208 } else {
209 beyondDest = &command_line[MAXIMUM_COMMAND_LINE_LENGTH];
210 if (USE_EXTENDED_LENGTH_PATH &&
211 memcmp(os_command_stri, PATH_PREFIX, PREFIX_LEN * sizeof(os_charType)) == 0) {
212 /* For extended path omit the prefix. */
213 command_stri = &os_command_stri[PREFIX_LEN];
214 } else {
215 command_stri = os_command_stri;
216 } /* if */
217 /* fprintf(stderr, "\ncommand_stri=\"%ls\"\n", command_stri); */
218 #ifdef USE_MODULE_NAME_FOR_CREATE_PROCESS
219 /* Pelles C cannot start the compiler (POCC.EXE) without this fix. */
220 {
221 os_charType *lastPathDelimiter;
222
223 lastPathDelimiter = os_stri_strrchr(command_stri, OS_PATH_DELIMITER);
224 if (lastPathDelimiter != NULL) {
225 command_stri = &lastPathDelimiter[1];
226 } /* if */
227 }
228 #endif
229 striSize = os_stri_strlen(command_stri);
230 if (striSize > MAXIMUM_COMMAND_LINE_LENGTH - 2 ||
231 &command_line[striSize] > beyondDest) {
232 *err_info = MEMORY_ERROR;
233 destChar = beyondDest;
234 } else {
235 command_line[0] = '\"';
236 memcpy(&command_line[1], command_stri, sizeof(os_charType) * striSize);
237 command_line[striSize + 1] = '\"';
238 destChar = &command_line[striSize + 2];
239 } /* if */
240 for (pos = 0; pos < arraySize && *err_info == OKAY_NO_ERROR; pos++) {
241 argument = stri_to_os_stri(parameters->arr[pos].value.striValue, err_info);
242 if (argument != NULL) {
243 /* fprintf(stderr, "argument[%d]=%ls\n", pos + 1, argument); */
244 quoteArgument = FALSE;
245 for (sourceChar = argument; *sourceChar != '\0'; sourceChar++) {
246 if (*sourceChar <= ' ' || *sourceChar > '~' || *sourceChar == '"') {
247 quoteArgument = TRUE;
248 } /* if */
249 } /* for */
250 if (quoteArgument) {
251 if (&destChar[2] > beyondDest) {
252 destChar = beyondDest;
253 } else {
254 *(destChar++) = ' ';
255 *(destChar++) = '"';
256 } /* if */
257 destChar = copyQuotedPart(argument, destChar, beyondDest);
258 if (destChar >= beyondDest) {
259 *err_info = MEMORY_ERROR;
260 } else {
261 *(destChar++) = '"';
262 } /* if */
263 } else {
264 if (destChar < beyondDest) {
265 *(destChar++) = ' ';
266 } /* if */
267 for (sourceChar = argument; *sourceChar != '\0' && destChar < beyondDest;
268 sourceChar++, destChar++) {
269 *destChar = *sourceChar;
270 } /* for */
271 } /* if */
272 os_stri_free(argument);
273 } /* if */
274 } /* for */
275 if (destChar >= beyondDest) {
276 *err_info = MEMORY_ERROR;
277 } else {
278 *destChar = '\0';
279 } /* if */
280 if (unlikely(*err_info != OKAY_NO_ERROR)) {
281 os_stri_free(command_line);
282 command_line = NULL;
283 } else {
284 /* fprintf(stderr, "command_line=%ls\n", command_line); */
285 } /* if */
286 } /* if */
287 logFunction(printf("prepareCommandLine --> \"" FMT_S_OS "\"\n",
288 command_line););
289 return command_line;
290 } /* prepareCommandLine */
291
292
293
294 /**
295 * Compare two processes.
296 * @return -1, 0 or 1 if the first argument is considered to be
297 * respectively less than, equal to, or greater than the
298 * second.
299 */
300 intType pcsCmp (const const_processType process1, const const_processType process2)
301
302 {
303 intType signumValue;
304
305 /* pcsCmp */
306 if (process1 == NULL) {
307 if (process2 != NULL) {
308 signumValue = -1;
309 } else {
310 signumValue = 0;
311 } /* if */
312 } else if (process2 == NULL) {
313 signumValue = 1;
314 } else if (to_pid(process1) < to_pid(process2)) {
315 signumValue = -1;
316 } else {
317 signumValue = to_pid(process1) > to_pid(process2);
318 } /* if */
319 return signumValue;
320 } /* pcsCmp */
321
322
323
324 /**
325 * Check if two processes are equal.
326 * @return TRUE if both processes are equal,
327 * FALSE otherwise.
328 */
329 boolType pcsEq (const const_processType process1, const const_processType process2)
330
331 { /* pcsEq */
332 if (process1 == NULL) {
333 return process2 == NULL;
334 } else if (process2 == NULL) {
335 return FALSE;
336 } else {
337 return to_pid(process1) == to_pid(process2);
338 } /* if */
339 } /* pcsEq */
340
341
342
343 /**
344 * Return the exit value of the specified process.
345 * By convention, the value 0 indicates normal termination.
346 * @return the exit value of the specified process.
347 */
348 intType pcsExitValue (const const_processType process)
349
350 {
351 intType exitValue;
352
353 /* pcsExitValue */
354 if (unlikely(!to_isTerminated(process))) {
355 raise_error(FILE_ERROR);
356 exitValue = -1;
357 } else {
358 exitValue = (intType) to_exitValue(process);
359 } /* if */
360 return exitValue;
361 } /* pcsExitValue */
362
363
364
365 /**
366 * Free the memory referred by 'oldProcess'.
367 * After pcsFree is left 'oldProcess' refers to not existing memory.
368 * The memory where 'oldProcess' is stored can be freed afterwards.
369 */
370 void pcsFree (processType oldProcess)
371
372 { /* pcsFree */
373 logFunction(printf("pcsFree(" FMT_U32 ") (usage=" FMT_U ")\n",
374 (uint32Type) (oldProcess != NULL ? to_pid(oldProcess) : 0),
375 oldProcess != NULL ? oldProcess->usage_count : (uintType) 0););
376 CloseHandle(to_hProcess(oldProcess));
377 CloseHandle(to_hThread(oldProcess));
378 FREE_RECORD(oldProcess, win_processRecord, count.process);
379 } /* pcsFree */
380
381
382
383 /**
384 * Compute the hash value of a process.
385 * @return the hash value.
386 */
387 intType pcsHashCode (const const_processType process)
388
389 {
390 intType hashCode;
391
392 /* pcsHashCode */
393 if (process == NULL) {
394 hashCode = 0;
395 } else {
396 hashCode = to_pid(process);
397 } /* if */
398 return hashCode;
399 } /* pcsHashCode */
400
401
402
403 /**
404 * Test whether the specified process is alive.
405 * @return TRUE if the specified process has not yet terminated,
406 * FALSE otherwise.
407 */
408 boolType pcsIsAlive (const processType process)
409
410 {
411 DWORD exitCode = 0;
412 boolType isAlive;
413
414 /* pcsIsAlive */
415 logFunction(printf("pcsIsAlive(" FMT_U32 ") (hProcess=" FMT_U_MEM ")\n",
416 (uint32Type) (process != NULL ? to_pid(process) : 0),
417 process != NULL ? (memSizeType) to_hProcess(process) : (memSizeType) 0););
418 if (to_isTerminated(process)) {
419 isAlive = FALSE;
420 } else {
421 if (GetExitCodeProcess(to_hProcess(process), &exitCode) != 0) {
422 if (exitCode == STILL_ACTIVE) {
423 if (WaitForSingleObject(to_hProcess(process), 0) == WAIT_OBJECT_0) {
424 to_var_isTerminated(process) = TRUE;
425 } /* if */
426 } else {
427 to_var_isTerminated(process) = TRUE;
428 } /* if */
429 isAlive = !to_isTerminated(process);
430 if (!isAlive) {
431 to_var_exitValue(process) = exitCode;
432 } /* if */
433 } else {
434 logError(printf("pcsIsAlive: GetExitCodeProcess(" FMT_U_MEM ", 0) failed:\n"
435 "GetLastError=" FMT_U32 "\n",
436 (memSizeType) to_hProcess(process), (uint32Type) GetLastError());
437 printf("PID=" FMT_U32 "\n", (uint32Type) to_pid(process)););
438 raise_error(FILE_ERROR);
439 isAlive = TRUE;
440 } /* if */
441 } /* if */
442 return isAlive;
443 } /* pcsIsAlive */
444
445
446
447 /**
448 * Kill the specified process.
449 * @exception FILE_ERROR It was not possible to kill the process.
450 */
451 void pcsKill (const processType process)
452
453 { /* pcsKill */
454 logFunction(printf("pcsKill(" FMT_U32 ") (hProcess=" FMT_U_MEM ")\n",
455 (uint32Type) (process != NULL ? to_pid(process) : 0),
456 process != NULL ? (memSizeType) to_hProcess(process) : (memSizeType) 0););
457 if (unlikely(process == NULL)) {
458 logError(printf("pcsKill: process == NULL\n"););
459 raise_error(FILE_ERROR);
460 } else if (unlikely(TerminateProcess(to_hProcess(process), 0) == 0)) {
461 logError(printf("pcsKill: TerminateProcess(" FMT_U_MEM ", 0) failed:\n"
462 "GetLastError=" FMT_U32 "\n",
463 (memSizeType) to_hProcess(process), (uint32Type) GetLastError());
464 printf("PID=" FMT_U32 "\n", (uint32Type) to_pid(process)););
465 raise_error(FILE_ERROR);
466 } /* if */
467 } /* pcsKill */
468
469
470
471 void pcsPipe2 (const const_striType command, const const_rtlArrayType parameters,
472 fileType *childStdin, fileType *childStdout)
473
474 {
475 os_striType os_command_stri;
476 os_striType command_line;
477 SECURITY_ATTRIBUTES saAttr;
478 HANDLE childInputRead = INVALID_HANDLE_VALUE;
479 HANDLE childInputWrite = INVALID_HANDLE_VALUE;
480 HANDLE childOutputRead = INVALID_HANDLE_VALUE;
481 HANDLE childOutputWrite = INVALID_HANDLE_VALUE;
482 STARTUPINFOW startupInfo;
483 PROCESS_INFORMATION processInformation;
484 int path_info = PATH_IS_NORMAL;
485 errInfoType err_info = OKAY_NO_ERROR;
486
487 /* pcsPipe2 */
488 logFunction(printf("pcsPipe2(\"%s\"", striAsUnquotedCStri(command));
489 printParameters(parameters);
490 printf(")\n"););
491 os_command_stri = cp_to_os_path(command, &path_info, &err_info);
492 if (likely(os_command_stri != NULL)) {
493 command_line = prepareCommandLine(os_command_stri, parameters, &err_info);
494 if (likely(command_line != NULL)) {
495 /* printf("pcsPipe2(%ls, %ls)\n", os_command_stri, command_line); */
496 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
497 saAttr.bInheritHandle = TRUE;
498 saAttr.lpSecurityDescriptor = NULL;
499 if (unlikely(CreatePipe(&childInputRead,
500 &childInputWrite, &saAttr, 0) == 0 ||
501 CreatePipe(&childOutputRead,
502 &childOutputWrite, &saAttr, 0) == 0)) {
503 logError(printf("pcsPipe2(\"%s\", ...): CreatePipe() failed.\n",
504 striAsUnquotedCStri(command)););
505 err_info = FILE_ERROR;
506 } else if (unlikely(SetHandleInformation(childInputWrite,
507 HANDLE_FLAG_INHERIT, 0) == 0 ||
508 SetHandleInformation(childOutputRead,
509 HANDLE_FLAG_INHERIT, 0) == 0)) {
510 logError(printf("pcsPipe2(\"%s\", ...): SetHandleInformation() failed.\n",
511 striAsUnquotedCStri(command)););
512 err_info = FILE_ERROR;
513 } else {
514 memset(&startupInfo, 0, sizeof(startupInfo));
515 /* memset(&processInformation, 0, sizeof(processInformation)); */
516 startupInfo.cb = sizeof(startupInfo);
517 startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
518 startupInfo.wShowWindow = SW_HIDE;
519 startupInfo.hStdInput = childInputRead;
520 startupInfo.hStdOutput = childOutputWrite;
521 startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);;
522 logMessage(printf("before CreateProcessW(\"" FMT_S_OS "\", \"" FMT_S_OS "\", ...)\n",
523 os_command_stri, command_line););
524 if (CreateProcessW(os_command_stri,
525 command_line /* lpCommandLine */,
526 NULL /* lpProcessAttributes */,
527 NULL /* lpThreadAttributes */,
528 1 /* bInheritHandles */,
529 CREATE_UNICODE_ENVIRONMENT /* dwCreationFlags */,
530 NULL /* lpEnvironment */,
531 NULL /* lpCurrentDirectory */,
532 &startupInfo,
533 &processInformation) != 0) {
534 CloseHandle(childInputRead);
535 CloseHandle(childOutputWrite);
536 *childStdin = fdopen(_open_osfhandle((intPtrType) (childInputWrite), _O_TEXT), "w");
537 *childStdout = fdopen(_open_osfhandle((intPtrType) (childOutputRead), _O_TEXT), "r");
538 CloseHandle(processInformation.hProcess);
539 CloseHandle(processInformation.hThread);
540 } else {
541 logError(printf("pcsPipe2: CreateProcessW(\"" FMT_S_OS "\", \"" FMT_S_OS "\", ...) failed.\n"
542 "GetLastError=" FMT_U32 "\n",
543 os_command_stri, command_line, (uint32Type) GetLastError());
544 printf("ERROR_FILE_NOT_FOUND=%d\n", (int) ERROR_FILE_NOT_FOUND););
545 err_info = FILE_ERROR;
546 } /* if */
547 /* printf("after CreateProcessW\n"); */
548 } /* if */
549 os_stri_free(command_line);
550 } /* if */
551 os_stri_free(os_command_stri);
552 } /* if */
553 if (unlikely(err_info != OKAY_NO_ERROR)) {
554 if (childInputRead != INVALID_HANDLE_VALUE) {
555 CloseHandle(childInputRead);
556 } /* if */
557 if (childInputWrite != INVALID_HANDLE_VALUE) {
558 CloseHandle(childInputWrite);
559 } /* if */
560 if (childOutputRead != INVALID_HANDLE_VALUE) {
561 CloseHandle(childOutputRead);
562 } /* if */
563 if (childOutputWrite != INVALID_HANDLE_VALUE) {
564 CloseHandle(childOutputWrite);
565 } /* if */
566 raise_error(err_info);
567 } /* if */
568 logFunction(printf("pcsPipe2 ->\n"););
569 } /* pcsPipe2 */
570
571
572
573 void pcsPty (const const_striType command, const const_rtlArrayType parameters,
574 fileType *childStdin, fileType *childStdout)
575
576 { /* pcsPty */
577 pcsPipe2(command, parameters, childStdin, childStdout);
578 } /* pcsPty */
579
580
581
582 static HANDLE getHandleFromFile (fileType aFile, errInfoType *err_info)
583
584 {
585 int file_no;
586 HANDLE fileHandle;
587
588 /* getHandleFromFile */
589 if (aFile == NULL) {
590 fileHandle = CreateFile(NULL_DEVICE, GENERIC_READ | GENERIC_WRITE,
591 FILE_SHARE_READ | FILE_SHARE_WRITE,
592 NULL, OPEN_EXISTING, 0, NULL);
593 if (unlikely(fileHandle == INVALID_HANDLE_VALUE)) {
594 logError(printf("CreateFile(\"nul:\", ...) failed.\n"););
595 } /* if */
596 } else {
597 file_no = fileno(aFile);
598 if (unlikely(file_no == -1)) {
599 logError(printf("getHandleFromFile(%d): fileno(%d) failed:\n"
600 "errno=%d\nerror: %s\n",
601 safe_fileno(aFile), safe_fileno(aFile),
602 errno, strerror(errno)););
603 *err_info = FILE_ERROR;
604 fileHandle = INVALID_HANDLE_VALUE;
605 } else {
606 fileHandle = (HANDLE) _get_osfhandle(file_no);
607 if (unlikely(fileHandle == INVALID_HANDLE_VALUE)) {
608 logError(printf("getHandleFromFile(%d): _get_osfhandle(%d) failed:\n"
609 "errno=%d\nerror: %s\n",
610 safe_fileno(aFile), safe_fileno(aFile),
611 errno, strerror(errno)););
612 *err_info = FILE_ERROR;
613 } /* if */
614 } /* if */
615 } /* if */
616 return fileHandle;
617 } /* getHandleFromFile */
618
619
620
621 processType pcsStart (const const_striType command, const const_rtlArrayType parameters,
622 fileType childStdin, fileType childStdout, fileType childStderr)
623
624 {
625 os_striType os_command_stri;
626 os_striType command_line;
627 STARTUPINFOW startupInfo;
628 PROCESS_INFORMATION processInformation;
629 int path_info = PATH_IS_NORMAL;
630 HANDLE stdinFileHandle;
631 HANDLE stdoutFileHandle;
632 HANDLE stderrFileHandle;
633 errInfoType err_info = OKAY_NO_ERROR;
634 win_processType process = NULL;
635
636 /* pcsStart */
637 logFunction(printf("pcsStart(\"%s\"", striAsUnquotedCStri(command));
638 printParameters(parameters);
639 printf(", %d, %d, %d)\n",
640 safe_fileno(childStdin), safe_fileno(childStdout),
641 safe_fileno(childStderr)););
642 stdinFileHandle = getHandleFromFile(childStdin, &err_info);
643 stdoutFileHandle = getHandleFromFile(childStdout, &err_info);
644 stderrFileHandle = getHandleFromFile(childStderr, &err_info);
645 if (likely(err_info == OKAY_NO_ERROR)) {
646 os_command_stri = cp_to_os_path(command, &path_info, &err_info);
647 if (likely(os_command_stri != NULL)) {
648 command_line = prepareCommandLine(os_command_stri, parameters, &err_info);
649 if (likely(command_line != NULL)) {
650 if (!ALLOC_RECORD(process, win_processRecord, count.process)) {
651 err_info = MEMORY_ERROR;
652 } else {
653 memset(&startupInfo, 0, sizeof(startupInfo));
654 /* memset(&processInformation, 0, sizeof(processInformation)); */
655 startupInfo.cb = sizeof(startupInfo);
656 startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
657 startupInfo.wShowWindow = SW_SHOWNORMAL;
658 startupInfo.hStdInput = stdinFileHandle;
659 startupInfo.hStdOutput = stdoutFileHandle;
660 startupInfo.hStdError = stderrFileHandle;
661 logMessage(printf("before CreateProcessW(\"" FMT_S_OS "\", \"" FMT_S_OS "\", ...)\n",
662 os_command_stri, command_line););
663 if (CreateProcessW(os_command_stri,
664 command_line /* lpCommandLine */,
665 NULL /* lpProcessAttributes */,
666 NULL /* lpThreadAttributes */,
667 1 /* bInheritHandles */,
668 CREATE_UNICODE_ENVIRONMENT /* dwCreationFlags */,
669 NULL /* lpEnvironment */,
670 NULL /* lpCurrentDirectory */,
671 &startupInfo,
672 &processInformation) != 0) {
673 /* printf("pcsStart: pProcess=" FMT_U_MEM "\n",
674 (memSizeType) (processInformation.hProcess)); */
675 /* printf("pcsStart: PID=" FMT_U32 "\n", processInformation.dwProcessId); */
676 memset(process, 0, sizeof(win_processRecord));
677 process->usage_count = 1;
678 process->hProcess = processInformation.hProcess;
679 process->hThread = processInformation.hThread;
680 process->pid = processInformation.dwProcessId;
681 process->isTerminated = FALSE;
682 } else {
683 logError(printf("pcsStart: CreateProcessW(\"" FMT_S_OS "\", \"" FMT_S_OS "\", ...) failed.\n"
684 "GetLastError=" FMT_U32 "\n",
685 os_command_stri, command_line, (uint32Type) GetLastError());
686 printf("ERROR_FILE_NOT_FOUND=%d\n", (int) ERROR_FILE_NOT_FOUND););
687 FREE_RECORD(process, win_processRecord, count.process);
688 process = NULL;
689 err_info = FILE_ERROR;
690 } /* if */
691 /* printf("after CreateProcessW\n"); */
692 } /* if */
693 os_stri_free(command_line);
694 } /* if */
695 os_stri_free(os_command_stri);
696 } /* if */
697 } /* if */
698 if (childStdin == NULL && stdinFileHandle != INVALID_HANDLE_VALUE) {
699 CloseHandle(stdinFileHandle);
700 } /* if */
701 if (childStdout == NULL && stdoutFileHandle != INVALID_HANDLE_VALUE) {
702 CloseHandle(stdoutFileHandle);
703 } /* if */
704 if (childStderr == NULL && stderrFileHandle != INVALID_HANDLE_VALUE) {
705 CloseHandle(stderrFileHandle);
706 } /* if */
707 if (unlikely(err_info != OKAY_NO_ERROR)) {
708 raise_error(err_info);
709 } /* if */
710 logFunction(printf("pcsStart -> " FMT_U32 "\n",
711 (uint32Type) (process != NULL ? process->pid : 0)););
712 return (processType) process;
713 } /* pcsStart */
714
715
716
717 processType pcsStartPipe (const const_striType command, const const_rtlArrayType parameters)
718
719 {
720 os_striType os_command_stri;
721 os_striType command_line;
722 SECURITY_ATTRIBUTES saAttr;
723 HANDLE childInputRead = INVALID_HANDLE_VALUE;
724 HANDLE childInputWrite = INVALID_HANDLE_VALUE;
725 HANDLE childOutputRead = INVALID_HANDLE_VALUE;
726 HANDLE childOutputWrite = INVALID_HANDLE_VALUE;
727 HANDLE childErrorRead = INVALID_HANDLE_VALUE;
728 HANDLE childErrorWrite = INVALID_HANDLE_VALUE;
729 STARTUPINFOW startupInfo;
730 PROCESS_INFORMATION processInformation;
731 int path_info = PATH_IS_NORMAL;
732 errInfoType err_info = OKAY_NO_ERROR;
733 win_processType process = NULL;
734
735 /* pcsStartPipe */
736 logFunction(printf("pcsStartPipe(\"%s\"", striAsUnquotedCStri(command));
737 printParameters(parameters);
738 printf(")\n"););
739 os_command_stri = cp_to_os_path(command, &path_info, &err_info);
740 if (likely(os_command_stri != NULL)) {
741 command_line = prepareCommandLine(os_command_stri, parameters, &err_info);
742 if (likely(command_line != NULL)) {
743 if (!ALLOC_RECORD(process, win_processRecord, count.process)) {
744 err_info = MEMORY_ERROR;
745 } else {
746 /* printf("pcsStartPipe(%ls, %ls)\n", os_command_stri, command_line); */
747 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
748 saAttr.bInheritHandle = TRUE;
749 saAttr.lpSecurityDescriptor = NULL;
750 if (unlikely(CreatePipe(&childInputRead,
751 &childInputWrite, &saAttr, 0) == 0 ||
752 CreatePipe(&childOutputRead,
753 &childOutputWrite, &saAttr, 0) == 0 ||
754 CreatePipe(&childErrorRead,
755 &childErrorWrite, &saAttr, 0) == 0)) {
756 logError(printf("pcsPipe2(\"%s\", ...): CreatePipe() failed.\n",
757 striAsUnquotedCStri(command)););
758 err_info = FILE_ERROR;
759 } else if (unlikely(SetHandleInformation(childInputWrite,
760 HANDLE_FLAG_INHERIT, 0) == 0 ||
761 SetHandleInformation(childOutputRead,
762 HANDLE_FLAG_INHERIT, 0) == 0 ||
763 SetHandleInformation(childErrorRead,
764 HANDLE_FLAG_INHERIT, 0) == 0)) {
765 logError(printf("pcsPipe2(\"%s\", ...): SetHandleInformation() failed.\n",
766 striAsUnquotedCStri(command)););
767 err_info = FILE_ERROR;
768 } else {
769 memset(&startupInfo, 0, sizeof(startupInfo));
770 /* memset(&processInformation, 0, sizeof(processInformation)); */
771 startupInfo.cb = sizeof(startupInfo);
772 startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
773 startupInfo.wShowWindow = SW_HIDE;
774 startupInfo.hStdInput = childInputRead;
775 startupInfo.hStdOutput = childOutputWrite;
776 startupInfo.hStdError = childErrorWrite;
777 logMessage(printf("before CreateProcessW(\"" FMT_S_OS "\", \"" FMT_S_OS "\", ...)\n",
778 os_command_stri, command_line););
779 if (CreateProcessW(os_command_stri,
780 command_line /* lpCommandLine */,
781 NULL /* lpProcessAttributes */,
782 NULL /* lpThreadAttributes */,
783 1 /* bInheritHandles */,
784 CREATE_UNICODE_ENVIRONMENT /* dwCreationFlags */,
785 NULL /* lpEnvironment */,
786 NULL /* lpCurrentDirectory */,
787 &startupInfo,
788 &processInformation) != 0) {
789 CloseHandle(childInputRead);
790 CloseHandle(childOutputWrite);
791 CloseHandle(childErrorWrite);
792 memset(process, 0, sizeof(win_processRecord));
793 process->usage_count = 1;
794 process->hProcess = processInformation.hProcess;
795 process->hThread = processInformation.hThread;
796 process->pid = processInformation.dwProcessId;
797 process->isTerminated = FALSE;
798 process->stdIn = fdopen(_open_osfhandle((intPtrType) (childInputWrite), _O_TEXT), "w");
799 process->stdOut = fdopen(_open_osfhandle((intPtrType) (childOutputRead), _O_TEXT), "r");
800 process->stdErr = fdopen(_open_osfhandle((intPtrType) (childErrorRead), _O_TEXT), "r");
801 } else {
802 logError(printf("pcsStartPipe: CreateProcessW(\"" FMT_S_OS "\", \"" FMT_S_OS "\", ...) failed.\n"
803 "GetLastError=" FMT_U32 "\n",
804 os_command_stri, command_line, (uint32Type) GetLastError());
805 printf("ERROR_FILE_NOT_FOUND=%d\n", (int) ERROR_FILE_NOT_FOUND););
806 FREE_RECORD(process, win_processRecord, count.process);
807 process = NULL;
808 err_info = FILE_ERROR;
809 } /* if */
810 /* printf("after CreateProcessW\n"); */
811 } /* if */
812 } /* if */
813 os_stri_free(command_line);
814 } /* if */
815 os_stri_free(os_command_stri);
816 } /* if */
817 if (unlikely(err_info != OKAY_NO_ERROR)) {
818 if (childInputRead != INVALID_HANDLE_VALUE) {
819 CloseHandle(childInputRead);
820 } /* if */
821 if (childInputWrite != INVALID_HANDLE_VALUE) {
822 CloseHandle(childInputWrite);
823 } /* if */
824 if (childOutputRead != INVALID_HANDLE_VALUE) {
825 CloseHandle(childOutputRead);
826 } /* if */
827 if (childOutputWrite != INVALID_HANDLE_VALUE) {
828 CloseHandle(childOutputWrite);
829 } /* if */
830 if (childErrorRead != INVALID_HANDLE_VALUE) {
831 CloseHandle(childErrorRead);
832 } /* if */
833 if (childErrorWrite != INVALID_HANDLE_VALUE) {
834 CloseHandle(childErrorWrite);
835 } /* if */
836 if (process != NULL) {
837 FREE_RECORD(process, win_processRecord, count.process);
838 process = NULL;
839 } /* if */
840 raise_error(err_info);
841 } /* if */
842 logFunction(printf("pcsStartPipe -> " FMT_U32 "\n",
843 (uint32Type) (process != NULL ? process->pid : 0)););
844 return (processType) process;
845 } /* pcsStartPipe */
846
847
848
849 /**
850 * Convert a 'process' to a string.
851 * The process is converted to a string with the process identifier (PID).
852 * @return the string result of the conversion.
853 * @exception MEMORY_ERROR Not enough memory to represent the result.
854 */
855 striType pcsStr (const const_processType process)
856
857 {
858 striType result;
859
860 /* pcsStr */
861 if (process == NULL) {
862 result = CSTRI_LITERAL_TO_STRI("NULL");
863 if (unlikely(result == NULL)) {
864 raise_error(MEMORY_ERROR);
865 } /* if */
866 } else {
867 result = intStr((intType) to_pid(process));
868 } /* if */
869 return result;
870 } /* pcsStr */
871
872
873
874 /**
875 * Wait until the specified child process has terminated.
876 * Suspend the execution of the calling process until the
877 * specified child has terminated.
878 */
879 void pcsWaitFor (const processType process)
880
881 {
882 DWORD exitCode = 0;
883
884 /* pcsWaitFor */
885 logFunction(printf("pcsWaitFor(" FMT_U32 ") (hProcess=" FMT_U_MEM ")\n",
886 (uint32Type) (process != NULL ? to_pid(process) : 0),
887 process != NULL ? (memSizeType) to_hProcess(process) : (memSizeType) 0););
888 if (!to_isTerminated(process)) {
889 if (WaitForSingleObject(to_hProcess(process), INFINITE) == WAIT_OBJECT_0) {
890 if (GetExitCodeProcess(to_hProcess(process), &exitCode) != 0) {
891 to_var_isTerminated(process) = TRUE;
892 to_var_exitValue(process) = exitCode;
893 } else {
894 logError(printf("pcsWaitFor: GetExitCodeProcess(" FMT_U_MEM ", *) failed:\n"
895 "GetLastError=" FMT_U32 "\n",
896 (memSizeType) to_hProcess(process), (uint32Type) GetLastError());
897 printf("PID=" FMT_U32 "\n", (uint32Type) to_pid(process)););
898 raise_error(FILE_ERROR);
899 } /* if */
900 } else {
901 logError(printf("pcsWaitFor: WaitForSingleObject(" FMT_U_MEM ", INFINITE) failed:\n"
902 "GetLastError=" FMT_U32 "\n",
903 (memSizeType) to_hProcess(process), (uint32Type) GetLastError());
904 printf("PID=" FMT_U32 "\n", (uint32Type) to_pid(process)););
905 raise_error(FILE_ERROR);
906 } /* if */
907 } /* if */
908 logFunction(printf("pcsWaitFor -->\n"););
909 } /* pcsWaitFor */