Fixed erroneous file flag in _popen.
[wine/wine-kai.git] / dlls / msvcrt / process.c
blobc33f1e24dbaac405377b719473294785037e5cc0
1 /*
2 * msvcrt.dll spawn/exec functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * FIXME:
24 * -File handles need some special handling. Sometimes children get
25 * open file handles, sometimes not. The docs are confusing
26 * -No check for maximum path/argument/environment size is done
28 #include "config.h"
30 #include <stdarg.h>
32 #include "msvcrt.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
37 /* INTERNAL: Spawn a child process */
38 static int msvcrt_spawn(int flags, const char* exe, char* cmdline, char* env)
40 STARTUPINFOA si;
41 PROCESS_INFORMATION pi;
43 if (sizeof(HANDLE) != sizeof(int))
44 WARN("This call is unsuitable for your architecture\n");
46 if ((unsigned)flags > MSVCRT__P_DETACH)
48 *MSVCRT__errno() = MSVCRT_EINVAL;
49 return -1;
52 memset(&si, 0, sizeof(si));
53 si.cb = sizeof(si);
54 msvcrt_create_io_inherit_block(&si);
55 if (!CreateProcessA(exe, cmdline, NULL, NULL, TRUE,
56 flags == MSVCRT__P_DETACH ? DETACHED_PROCESS : 0,
57 env, NULL, &si, &pi))
59 msvcrt_set_errno(GetLastError());
60 MSVCRT_free(si.lpReserved2);
61 return -1;
64 MSVCRT_free(si.lpReserved2);
65 switch(flags)
67 case MSVCRT__P_WAIT:
68 WaitForSingleObject(pi.hProcess, INFINITE);
69 GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
70 CloseHandle(pi.hProcess);
71 CloseHandle(pi.hThread);
72 return (int)pi.dwProcessId;
73 case MSVCRT__P_DETACH:
74 CloseHandle(pi.hProcess);
75 pi.hProcess = 0;
76 /* fall through */
77 case MSVCRT__P_NOWAIT:
78 case MSVCRT__P_NOWAITO:
79 CloseHandle(pi.hThread);
80 return (int)pi.hProcess;
81 case MSVCRT__P_OVERLAY:
82 MSVCRT__exit(0);
84 return -1; /* can't reach here */
87 /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
88 * extra '\0' to terminate it
90 static char* msvcrt_argvtos(const char* const* arg, char delim)
92 const char* const* a;
93 long size;
94 char* p;
95 char* ret;
97 if (!arg && !delim)
99 /* Return NULL for an empty environment list */
100 return NULL;
103 /* get length */
104 a = arg;
105 size = 0;
106 while (*a)
108 size += strlen(*a) + 1;
109 a++;
112 ret = (char*)MSVCRT_malloc(size + 1);
113 if (!ret)
114 return NULL;
116 /* fill string */
117 a = arg;
118 p = ret;
119 while (*a)
121 int len = strlen(*a);
122 memcpy(p,*a,len);
123 p += len;
124 *p++ = delim;
125 a++;
127 if (delim && p > ret) p[-1] = 0;
128 else *p = 0;
129 return ret;
132 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
133 * extra '\0' to terminate it
135 static char* msvcrt_valisttos(const char* arg0, va_list alist, char delim)
137 va_list alist2;
138 long size;
139 const char *arg;
140 char* p;
141 char *ret;
143 #ifdef HAVE_VA_COPY
144 va_copy(alist2,alist);
145 #else
146 # ifdef HAVE___VA_COPY
147 __va_copy(alist2,alist);
148 # else
149 alist2 = alist;
150 # endif
151 #endif
153 if (!arg0 && !delim)
155 /* Return NULL for an empty environment list */
156 return NULL;
159 /* get length */
160 arg = arg0;
161 size = 0;
162 do {
163 size += strlen(arg) + 1;
164 arg = va_arg(alist, char*);
165 } while (arg != NULL);
167 ret = (char*)MSVCRT_malloc(size + 1);
168 if (!ret)
169 return NULL;
171 /* fill string */
172 arg = arg0;
173 p = ret;
174 do {
175 int len = strlen(arg);
176 memcpy(p,arg,len);
177 p += len;
178 *p++ = delim;
179 arg = va_arg(alist2, char*);
180 } while (arg != NULL);
181 if (delim && p > ret) p[-1] = 0;
182 else *p = 0;
183 return ret;
186 /*********************************************************************
187 * _cwait (MSVCRT.@)
189 int _cwait(int *status, int pid, int action)
191 HANDLE hPid = (HANDLE)pid;
192 int doserrno;
194 action = action; /* Remove warning */
196 if (!WaitForSingleObject(hPid, INFINITE))
198 if (status)
200 DWORD stat;
201 GetExitCodeProcess(hPid, &stat);
202 *status = (int)stat;
204 return (int)pid;
206 doserrno = GetLastError();
208 if (doserrno == ERROR_INVALID_HANDLE)
210 *MSVCRT__errno() = MSVCRT_ECHILD;
211 *MSVCRT___doserrno() = doserrno;
213 else
214 msvcrt_set_errno(doserrno);
216 return status ? *status = -1 : -1;
219 /*********************************************************************
220 * _execl (MSVCRT.@)
222 * Like on Windows, this function does not handle arguments with spaces
223 * or double-quotes.
225 int _execl(const char* name, const char* arg0, ...)
227 va_list ap;
228 char * args;
229 int ret;
231 va_start(ap, arg0);
232 args = msvcrt_valisttos(arg0, ap, ' ');
233 va_end(ap);
235 ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL);
236 MSVCRT_free(args);
238 return ret;
241 /*********************************************************************
242 * _execle (MSVCRT.@)
244 int _execle(const char* name, const char* arg0, ...)
246 FIXME("stub\n");
247 return -1;
250 /*********************************************************************
251 * _execlp (MSVCRT.@)
253 * Like on Windows, this function does not handle arguments with spaces
254 * or double-quotes.
256 int _execlp(const char* name, const char* arg0, ...)
258 va_list ap;
259 char * args;
260 int ret;
261 char fullname[MAX_PATH];
263 _searchenv(name, "PATH", fullname);
265 va_start(ap, arg0);
266 args = msvcrt_valisttos(arg0, ap, ' ');
267 va_end(ap);
269 ret = msvcrt_spawn(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
270 MSVCRT_free(args);
272 return ret;
275 /*********************************************************************
276 * _execlpe (MSVCRT.@)
278 int _execlpe(const char* name, const char* arg0, ...)
280 FIXME("stub\n");
281 return -1;
284 /*********************************************************************
285 * _execv (MSVCRT.@)
287 * Like on Windows, this function does not handle arguments with spaces
288 * or double-quotes.
290 int _execv(const char* name, char* const* argv)
292 return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, NULL);
295 /*********************************************************************
296 * _execve (MSVCRT.@)
298 * Like on Windows, this function does not handle arguments with spaces
299 * or double-quotes.
301 int _execve(const char* name, char* const* argv, const char* const* envv)
303 return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
306 /*********************************************************************
307 * _execvpe (MSVCRT.@)
309 * Like on Windows, this function does not handle arguments with spaces
310 * or double-quotes.
312 int _execvpe(const char* name, char* const* argv, const char* const* envv)
314 char fullname[MAX_PATH];
316 _searchenv(name, "PATH", fullname);
317 return _spawnve(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name,
318 (const char* const*) argv, envv);
321 /*********************************************************************
322 * _execvp (MSVCRT.@)
324 * Like on Windows, this function does not handle arguments with spaces
325 * or double-quotes.
327 int _execvp(const char* name, char* const* argv)
329 return _execvpe(name, argv, NULL);
332 /*********************************************************************
333 * _spawnl (MSVCRT.@)
335 * Like on Windows, this function does not handle arguments with spaces
336 * or double-quotes.
338 int _spawnl(int flags, const char* name, const char* arg0, ...)
340 va_list ap;
341 char * args;
342 int ret;
344 va_start(ap, arg0);
345 args = msvcrt_valisttos(arg0, ap, ' ');
346 va_end(ap);
348 ret = msvcrt_spawn(flags, name, args, NULL);
349 MSVCRT_free(args);
351 return ret;
354 /*********************************************************************
355 * _spawnle (MSVCRT.@)
357 int _spawnle(int flags, const char* name, const char* arg0, ...)
359 va_list ap;
360 char *args, *envs = NULL;
361 const char * const *envp;
362 int ret;
364 va_start(ap, arg0);
365 args = msvcrt_valisttos(arg0, ap, ' ');
366 va_end(ap);
368 va_start(ap, arg0);
369 while (va_arg( ap, char * ) != NULL) /*nothing*/;
370 envp = va_arg( ap, const char * const * );
371 if (envp) envs = msvcrt_argvtos(envp, 0);
372 va_end(ap);
374 ret = msvcrt_spawn(flags, name, args, envs);
376 MSVCRT_free(args);
377 if (envs) MSVCRT_free(envs);
378 return ret;
382 /*********************************************************************
383 * _spawnlp (MSVCRT.@)
385 * Like on Windows, this function does not handle arguments with spaces
386 * or double-quotes.
388 int _spawnlp(int flags, const char* name, const char* arg0, ...)
390 va_list ap;
391 char * args;
392 int ret;
393 char fullname[MAX_PATH];
395 _searchenv(name, "PATH", fullname);
397 va_start(ap, arg0);
398 args = msvcrt_valisttos(arg0, ap, ' ');
399 va_end(ap);
401 ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
402 MSVCRT_free(args);
404 return ret;
407 /*********************************************************************
408 * _spawnlpe (MSVCRT.@)
410 int _spawnlpe(int flags, const char* name, const char* arg0, ...)
412 va_list ap;
413 char *args, *envs = NULL;
414 const char * const *envp;
415 int ret;
416 char fullname[MAX_PATH];
418 _searchenv(name, "PATH", fullname);
420 va_start(ap, arg0);
421 args = msvcrt_valisttos(arg0, ap, ' ');
422 va_end(ap);
424 va_start(ap, arg0);
425 while (va_arg( ap, char * ) != NULL) /*nothing*/;
426 envp = va_arg( ap, const char * const * );
427 if (envp) envs = msvcrt_argvtos(envp, 0);
428 va_end(ap);
430 ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, envs);
432 MSVCRT_free(args);
433 if (envs) MSVCRT_free(envs);
434 return ret;
437 /*********************************************************************
438 * _spawnve (MSVCRT.@)
440 * Like on Windows, this function does not handle arguments with spaces
441 * or double-quotes.
443 int _spawnve(int flags, const char* name, const char* const* argv,
444 const char* const* envv)
446 char * args = msvcrt_argvtos(argv,' ');
447 char * envs = msvcrt_argvtos(envv,0);
448 const char *fullname = name;
449 int ret = -1;
451 FIXME(":not translating name %s to locate program\n",fullname);
452 TRACE(":call (%s), params (%s), env (%s)\n",debugstr_a(name),debugstr_a(args),
453 envs?"Custom":"Null");
455 if (args)
457 ret = msvcrt_spawn(flags, fullname, args, envs);
458 MSVCRT_free(args);
460 if (envs)
461 MSVCRT_free(envs);
463 return ret;
466 /*********************************************************************
467 * _spawnv (MSVCRT.@)
469 * Like on Windows, this function does not handle arguments with spaces
470 * or double-quotes.
472 int _spawnv(int flags, const char* name, const char* const* argv)
474 return _spawnve(flags, name, argv, NULL);
477 /*********************************************************************
478 * _spawnvpe (MSVCRT.@)
480 * Like on Windows, this function does not handle arguments with spaces
481 * or double-quotes.
483 int _spawnvpe(int flags, const char* name, const char* const* argv,
484 const char* const* envv)
486 char fullname[MAX_PATH];
487 _searchenv(name, "PATH", fullname);
488 return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
491 /*********************************************************************
492 * _spawnvp (MSVCRT.@)
494 * Like on Windows, this function does not handle arguments with spaces
495 * or double-quotes.
497 int _spawnvp(int flags, const char* name, const char* const* argv)
499 return _spawnvpe(flags, name, argv, NULL);
502 /*********************************************************************
503 * _popen (MSVCRT.@)
504 * FIXME: convert to _wpopen and call that from here instead? But it
505 * would have to convert the command back to ANSI to call msvcrt_spawn,
506 * less than ideal.
508 MSVCRT_FILE* MSVCRT__popen(const char* command, const char* mode)
510 static const char wcmd[] = "wcmd", cmdFlag[] = " /C ", comSpec[] = "COMSPEC";
511 MSVCRT_FILE *ret;
512 BOOL readPipe = TRUE;
513 int textmode, fds[2], fdToDup, fdToOpen, fdStdHandle = -1, fdStdErr = -1;
514 const char *p;
515 char *cmdcopy;
516 DWORD comSpecLen;
518 TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode));
520 if (!command || !mode)
521 return NULL;
523 textmode = *__p__fmode() & (MSVCRT__O_BINARY | MSVCRT__O_TEXT);
524 for (p = mode; *p; p++)
526 switch (*p)
528 case 'W':
529 case 'w':
530 readPipe = FALSE;
531 break;
532 case 'B':
533 case 'b':
534 textmode |= MSVCRT__O_BINARY;
535 textmode &= ~MSVCRT__O_TEXT;
536 break;
537 case 'T':
538 case 't':
539 textmode |= MSVCRT__O_TEXT;
540 textmode &= ~MSVCRT__O_BINARY;
541 break;
544 if (_pipe(fds, 0, textmode) == -1)
545 return NULL;
547 fdToDup = readPipe ? 1 : 0;
548 fdToOpen = readPipe ? 0 : 1;
550 if ((fdStdHandle = _dup(fdToDup)) == -1)
551 goto error;
552 if (_dup2(fds[fdToDup], fdToDup) != 0)
553 goto error;
554 if (readPipe)
556 if ((fdStdErr = _dup(MSVCRT_STDERR_FILENO)) == -1)
557 goto error;
558 if (_dup2(fds[fdToDup], MSVCRT_STDERR_FILENO) != 0)
559 goto error;
562 _close(fds[fdToDup]);
564 comSpecLen = GetEnvironmentVariableA(comSpec, NULL, 0);
565 if (!comSpecLen)
566 comSpecLen = strlen(wcmd) + 1;
567 cmdcopy = HeapAlloc(GetProcessHeap(), 0, comSpecLen + strlen(cmdFlag)
568 + strlen(command));
569 if (!GetEnvironmentVariableA(comSpec, cmdcopy, comSpecLen))
570 strcpy(cmdcopy, wcmd);
571 strcat(cmdcopy, cmdFlag);
572 strcat(cmdcopy, command);
573 if (msvcrt_spawn(MSVCRT__P_NOWAIT, NULL, cmdcopy, NULL) == -1)
575 _close(fds[fdToOpen]);
576 ret = NULL;
578 else
580 ret = MSVCRT__fdopen(fds[fdToOpen], mode);
581 if (!ret)
582 _close(fds[fdToOpen]);
584 HeapFree(GetProcessHeap(), 0, cmdcopy);
585 _dup2(fdStdHandle, fdToDup);
586 _close(fdStdHandle);
587 if (readPipe)
589 _dup2(fdStdErr, MSVCRT_STDERR_FILENO);
590 _close(fdStdErr);
592 return ret;
594 error:
595 if (fdStdHandle != -1) _close(fdStdHandle);
596 if (fdStdErr != -1) _close(fdStdErr);
597 _close(fds[0]);
598 _close(fds[1]);
599 return NULL;
602 /*********************************************************************
603 * _wpopen (MSVCRT.@)
605 MSVCRT_FILE* MSVCRT__wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
607 FIXME("(command=%s, mode=%s): stub\n", debugstr_w(command), debugstr_w(mode));
608 return NULL;
611 /*********************************************************************
612 * _pclose (MSVCRT.@)
614 int MSVCRT__pclose(MSVCRT_FILE* file)
616 return MSVCRT_fclose(file);
619 /*********************************************************************
620 * system (MSVCRT.@)
622 int MSVCRT_system(const char* cmd)
624 char* cmdcopy;
625 int res;
627 /* Make a writable copy for CreateProcess */
628 cmdcopy=_strdup(cmd);
629 /* FIXME: should probably launch cmd interpreter in COMSPEC */
630 res=msvcrt_spawn(MSVCRT__P_WAIT, NULL, cmdcopy, NULL);
631 MSVCRT_free(cmdcopy);
632 return res;
635 /*********************************************************************
636 * _loaddll (MSVCRT.@)
638 int _loaddll(const char* dllname)
640 return (int)LoadLibraryA(dllname);
643 /*********************************************************************
644 * _unloaddll (MSVCRT.@)
646 int _unloaddll(int dll)
648 if (FreeLibrary((HMODULE)dll))
649 return 0;
650 else
652 int err = GetLastError();
653 msvcrt_set_errno(err);
654 return err;
658 /*********************************************************************
659 * _getdllprocaddr (MSVCRT.@)
661 void *_getdllprocaddr(int dll, const char *name, int ordinal)
663 if (name)
665 if (ordinal != -1) return NULL;
666 return GetProcAddress( (HMODULE)dll, name );
668 if (HIWORD(ordinal)) return NULL;
669 return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );