Add a stub implementation of msi.MsiSetMode.
[wine] / dlls / msvcrt / process.c
1 /*
2  * msvcrt.dll spawn/exec functions
3  *
4  * Copyright 1996,1998 Marcus Meissner
5  * Copyright 1996 Jukka Iivonen
6  * Copyright 1997,2000 Uwe Bonnes
7  * Copyright 2000 Jon Griffiths
8  *
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.
13  *
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.
18  *
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
22  *
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
27  */
28 #include "config.h"
29
30 #include <stdarg.h>
31
32 #include "msvcrt.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
36
37 /* INTERNAL: Spawn a child process */
38 static int msvcrt_spawn(int flags, const char* exe, char* cmdline, char* env)
39 {
40   STARTUPINFOA si;
41   PROCESS_INFORMATION pi;
42
43   if (sizeof(HANDLE) != sizeof(int))
44     WARN("This call is unsuitable for your architecture\n");
45
46   if ((unsigned)flags > MSVCRT__P_DETACH)
47   {
48     *MSVCRT__errno() = MSVCRT_EINVAL;
49     return -1;
50   }
51
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))
58   {
59     msvcrt_set_errno(GetLastError());
60     MSVCRT_free(si.lpReserved2);
61     return -1;
62   }
63
64   MSVCRT_free(si.lpReserved2);
65   switch(flags)
66   {
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);
83   }
84   return -1; /* can't reach here */
85 }
86
87 /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
88  * extra '\0' to terminate it
89  */
90 static char* msvcrt_argvtos(const char* const* arg, char delim)
91 {
92   const char* const* a;
93   long size;
94   char* p;
95   char* ret;
96
97   if (!arg && !delim)
98   {
99       /* Return NULL for an empty environment list */
100       return NULL;
101   }
102
103   /* get length */
104   a = arg;
105   size = 0;
106   while (*a)
107   {
108     size += strlen(*a) + 1;
109     a++;
110   }
111
112   ret = (char*)MSVCRT_malloc(size + 1);
113   if (!ret)
114     return NULL;
115
116   /* fill string */
117   a = arg;
118   p = ret;
119   while (*a)
120   {
121     int len = strlen(*a);
122     memcpy(p,*a,len);
123     p += len;
124     *p++ = delim;
125     a++;
126   }
127   if (delim && p > ret) p[-1] = 0;
128   else *p = 0;
129   return ret;
130 }
131
132 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
133  * extra '\0' to terminate it
134  */
135 static char* msvcrt_valisttos(const char* arg0, va_list alist, char delim)
136 {
137   va_list alist2;
138   long size;
139   const char *arg;
140   char* p;
141   char *ret;
142
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
152
153   if (!arg0 && !delim)
154   {
155       /* Return NULL for an empty environment list */
156       return NULL;
157   }
158
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);
166
167   ret = (char*)MSVCRT_malloc(size + 1);
168   if (!ret)
169     return NULL;
170
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;
184 }
185
186 /*********************************************************************
187  *              _cwait (MSVCRT.@)
188  */
189 int _cwait(int *status, int pid, int action)
190 {
191   HANDLE hPid = (HANDLE)pid;
192   int doserrno;
193
194   action = action; /* Remove warning */
195
196   if (!WaitForSingleObject(hPid, INFINITE))
197   {
198     if (status)
199     {
200       DWORD stat;
201       GetExitCodeProcess(hPid, &stat);
202       *status = (int)stat;
203     }
204     return (int)pid;
205   }
206   doserrno = GetLastError();
207
208   if (doserrno == ERROR_INVALID_HANDLE)
209   {
210     *MSVCRT__errno() =  MSVCRT_ECHILD;
211     *MSVCRT___doserrno() = doserrno;
212   }
213   else
214     msvcrt_set_errno(doserrno);
215
216   return status ? *status = -1 : -1;
217 }
218
219 /*********************************************************************
220  *              _execl (MSVCRT.@)
221  *
222  * Like on Windows, this function does not handle arguments with spaces
223  * or double-quotes.
224  */
225 int _execl(const char* name, const char* arg0, ...)
226 {
227   va_list ap;
228   char * args;
229   int ret;
230
231   va_start(ap, arg0);
232   args = msvcrt_valisttos(arg0, ap, ' ');
233   va_end(ap);
234
235   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL);
236   MSVCRT_free(args);
237
238   return ret;
239 }
240
241 /*********************************************************************
242  *              _execle (MSVCRT.@)
243  */
244 int _execle(const char* name, const char* arg0, ...)
245 {
246     FIXME("stub\n");
247     return -1;
248 }
249
250 /*********************************************************************
251  *              _execlp (MSVCRT.@)
252  *
253  * Like on Windows, this function does not handle arguments with spaces
254  * or double-quotes.
255  */
256 int _execlp(const char* name, const char* arg0, ...)
257 {
258   va_list ap;
259   char * args;
260   int ret;
261   char fullname[MAX_PATH];
262
263   _searchenv(name, "PATH", fullname);
264
265   va_start(ap, arg0);
266   args = msvcrt_valisttos(arg0, ap, ' ');
267   va_end(ap);
268
269   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
270   MSVCRT_free(args);
271
272   return ret;
273 }
274
275 /*********************************************************************
276  *              _execlpe (MSVCRT.@)
277  */
278 int _execlpe(const char* name, const char* arg0, ...)
279 {
280     FIXME("stub\n");
281     return -1;
282 }
283
284 /*********************************************************************
285  *              _execv (MSVCRT.@)
286  *
287  * Like on Windows, this function does not handle arguments with spaces
288  * or double-quotes.
289  */
290 int _execv(const char* name, char* const* argv)
291 {
292   return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, NULL);
293 }
294
295 /*********************************************************************
296  *              _execve (MSVCRT.@)
297  *
298  * Like on Windows, this function does not handle arguments with spaces
299  * or double-quotes.
300  */
301 int _execve(const char* name, char* const* argv, const char* const* envv)
302 {
303   return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
304 }
305
306 /*********************************************************************
307  *              _execvpe (MSVCRT.@)
308  *
309  * Like on Windows, this function does not handle arguments with spaces
310  * or double-quotes.
311  */
312 int _execvpe(const char* name, char* const* argv, const char* const* envv)
313 {
314   char fullname[MAX_PATH];
315
316   _searchenv(name, "PATH", fullname);
317   return _spawnve(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name,
318                   (const char* const*) argv, envv);
319 }
320
321 /*********************************************************************
322  *              _execvp (MSVCRT.@)
323  *
324  * Like on Windows, this function does not handle arguments with spaces
325  * or double-quotes.
326  */
327 int _execvp(const char* name, char* const* argv)
328 {
329   return _execvpe(name, argv, NULL);
330 }
331
332 /*********************************************************************
333  *              _spawnl (MSVCRT.@)
334  *
335  * Like on Windows, this function does not handle arguments with spaces
336  * or double-quotes.
337  */
338 int _spawnl(int flags, const char* name, const char* arg0, ...)
339 {
340   va_list ap;
341   char * args;
342   int ret;
343
344   va_start(ap, arg0);
345   args = msvcrt_valisttos(arg0, ap, ' ');
346   va_end(ap);
347
348   ret = msvcrt_spawn(flags, name, args, NULL);
349   MSVCRT_free(args);
350
351   return ret;
352 }
353
354 /*********************************************************************
355  *              _spawnle (MSVCRT.@)
356  */
357 int _spawnle(int flags, const char* name, const char* arg0, ...)
358 {
359     va_list ap;
360     char *args, *envs = NULL;
361     const char * const *envp;
362     int ret;
363
364     va_start(ap, arg0);
365     args = msvcrt_valisttos(arg0, ap, ' ');
366     va_end(ap);
367
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);
373
374     ret = msvcrt_spawn(flags, name, args, envs);
375
376     MSVCRT_free(args);
377     if (envs) MSVCRT_free(envs);
378     return ret;
379 }
380
381
382 /*********************************************************************
383  *              _spawnlp (MSVCRT.@)
384  *
385  * Like on Windows, this function does not handle arguments with spaces
386  * or double-quotes.
387  */
388 int _spawnlp(int flags, const char* name, const char* arg0, ...)
389 {
390   va_list ap;
391   char * args;
392   int ret;
393   char fullname[MAX_PATH];
394
395   _searchenv(name, "PATH", fullname);
396
397   va_start(ap, arg0);
398   args = msvcrt_valisttos(arg0, ap, ' ');
399   va_end(ap);
400
401   ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
402   MSVCRT_free(args);
403
404   return ret;
405 }
406
407 /*********************************************************************
408  *              _spawnlpe (MSVCRT.@)
409  */
410 int _spawnlpe(int flags, const char* name, const char* arg0, ...)
411 {
412     va_list ap;
413     char *args, *envs = NULL;
414     const char * const *envp;
415     int ret;
416     char fullname[MAX_PATH];
417
418     _searchenv(name, "PATH", fullname);
419
420     va_start(ap, arg0);
421     args = msvcrt_valisttos(arg0, ap, ' ');
422     va_end(ap);
423
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);
429
430     ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, envs);
431
432     MSVCRT_free(args);
433     if (envs) MSVCRT_free(envs);
434     return ret;
435 }
436
437 /*********************************************************************
438  *              _spawnve (MSVCRT.@)
439  *
440  * Like on Windows, this function does not handle arguments with spaces
441  * or double-quotes.
442  */
443 int _spawnve(int flags, const char* name, const char* const* argv,
444                             const char* const* envv)
445 {
446   char * args = msvcrt_argvtos(argv,' ');
447   char * envs = msvcrt_argvtos(envv,0);
448   const char *fullname = name;
449   int ret = -1;
450
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");
454
455   if (args)
456   {
457     ret = msvcrt_spawn(flags, fullname, args, envs);
458     MSVCRT_free(args);
459   }
460   if (envs)
461     MSVCRT_free(envs);
462
463   return ret;
464 }
465
466 /*********************************************************************
467  *              _spawnv (MSVCRT.@)
468  *
469  * Like on Windows, this function does not handle arguments with spaces
470  * or double-quotes.
471  */
472 int _spawnv(int flags, const char* name, const char* const* argv)
473 {
474   return _spawnve(flags, name, argv, NULL);
475 }
476
477 /*********************************************************************
478  *              _spawnvpe (MSVCRT.@)
479  *
480  * Like on Windows, this function does not handle arguments with spaces
481  * or double-quotes.
482  */
483 int _spawnvpe(int flags, const char* name, const char* const* argv,
484                             const char* const* envv)
485 {
486   char fullname[MAX_PATH];
487   _searchenv(name, "PATH", fullname);
488   return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
489 }
490
491 /*********************************************************************
492  *              _spawnvp (MSVCRT.@)
493  *
494  * Like on Windows, this function does not handle arguments with spaces
495  * or double-quotes.
496  */
497 int _spawnvp(int flags, const char* name, const char* const* argv)
498 {
499   return _spawnvpe(flags, name, argv, NULL);
500 }
501
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.
507  */
508 MSVCRT_FILE* MSVCRT__popen(const char* command, const char* mode)
509 {
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;
517
518   TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode));
519
520   if (!command || !mode)
521     return NULL;
522
523   textmode = *__p__fmode() & (MSVCRT__O_BINARY | MSVCRT__O_TEXT);
524   for (p = mode; *p; p++)
525   {
526     switch (*p)
527     {
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;
542     }
543   }
544   if (_pipe(fds, 0, textmode) == -1)
545     return NULL;
546
547   fdToDup = readPipe ? 1 : 0;
548   fdToOpen = readPipe ? 0 : 1;
549
550   if ((fdStdHandle = _dup(fdToDup)) == -1)
551     goto error;
552   if (_dup2(fds[fdToDup], fdToDup) != 0)
553     goto error;
554   if (readPipe)
555   {
556     if ((fdStdErr = _dup(MSVCRT_STDERR_FILENO)) == -1)
557       goto error;
558     if (_dup2(fds[fdToDup], MSVCRT_STDERR_FILENO) != 0)
559       goto error;
560   }
561
562   _close(fds[fdToDup]);
563
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)
574   {
575     _close(fds[fdToOpen]);
576     ret = NULL;
577   }
578   else
579   {
580     ret = MSVCRT__fdopen(fds[fdToOpen], mode);
581     if (!ret)
582       _close(fds[fdToOpen]);
583   }
584   HeapFree(GetProcessHeap(), 0, cmdcopy);
585   _dup2(fdStdHandle, fdToDup);
586   _close(fdStdHandle);
587   if (readPipe)
588   {
589     _dup2(fdStdErr, MSVCRT_STDERR_FILENO);
590     _close(fdStdErr);
591   }
592   return ret;
593
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;
600 }
601
602 /*********************************************************************
603  *              _wpopen (MSVCRT.@)
604  */
605 MSVCRT_FILE* MSVCRT__wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
606 {
607   FIXME("(command=%s, mode=%s): stub\n", debugstr_w(command), debugstr_w(mode));
608   return NULL;
609 }
610
611 /*********************************************************************
612  *              _pclose (MSVCRT.@)
613  */
614 int MSVCRT__pclose(MSVCRT_FILE* file)
615 {
616   return MSVCRT_fclose(file);
617 }
618
619 /*********************************************************************
620  *              system (MSVCRT.@)
621  */
622 int MSVCRT_system(const char* cmd)
623 {
624     char* cmdcopy;
625     int res;
626
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;
633 }
634
635 /*********************************************************************
636  *              _loaddll (MSVCRT.@)
637  */
638 int _loaddll(const char* dllname)
639 {
640   return (int)LoadLibraryA(dllname);
641 }
642
643 /*********************************************************************
644  *              _unloaddll (MSVCRT.@)
645  */
646 int _unloaddll(int dll)
647 {
648   if (FreeLibrary((HMODULE)dll))
649     return 0;
650   else
651   {
652     int err = GetLastError();
653     msvcrt_set_errno(err);
654     return err;
655   }
656 }
657
658 /*********************************************************************
659  *              _getdllprocaddr (MSVCRT.@)
660  */
661 void *_getdllprocaddr(int dll, const char *name, int ordinal)
662 {
663     if (name)
664     {
665         if (ordinal != -1) return NULL;
666         return GetProcAddress( (HMODULE)dll, name );
667     }
668     if (HIWORD(ordinal)) return NULL;
669     return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );
670 }