Updated.
[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  * FIXME:
10  * -File handles need some special handling. Sometimes children get
11  *  open file handles, sometimes not. The docs are confusing
12  * -No check for maximum path/argument/environment size is done
13  */
14 #include "msvcrt.h"
15 #include "ms_errno.h"
16
17 DEFAULT_DEBUG_CHANNEL(msvcrt);
18
19 /* Process creation flags */
20 #define _P_WAIT    0
21 #define _P_NOWAIT  1
22 #define _P_OVERLAY 2
23 #define _P_NOWAITO 3
24 #define _P_DETACH  4
25
26 void __cdecl MSVCRT__exit(int);
27 void __cdecl MSVCRT__searchenv(const char* file, const char* env, char *buf);
28
29 /* FIXME: Check file extenstions for app to run */
30 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
31 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
32 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
33 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
34
35 /* INTERNAL: Spawn a child process */
36 static int __MSVCRT__spawn(int flags, const char *exe, char * args, char *env)
37 {
38   STARTUPINFOA si;
39   PROCESS_INFORMATION pi;
40
41   if (sizeof(HANDLE) != sizeof(int))
42     WARN("This call is unsuitable for your architecture\n");
43
44   if ((unsigned)flags > _P_DETACH)
45   {
46     SET_THREAD_VAR(errno,MSVCRT_EINVAL);
47     return -1;
48   }
49
50   FIXME(":must dup/kill streams for child process\n");
51
52   memset(&si, 0, sizeof(si));
53   si.cb = sizeof(si);
54
55   if (!CreateProcessA(exe, args, NULL, NULL, TRUE,
56                      flags == _P_DETACH ? DETACHED_PROCESS : 0,
57                      env, NULL, &si, &pi))
58   {
59     MSVCRT__set_errno(GetLastError());
60     return -1;
61   }
62
63   switch(flags)
64   {
65   case _P_WAIT:
66     WaitForSingleObject(pi.hProcess,-1); /* wait forvever */
67     GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
68     CloseHandle(pi.hProcess);
69     CloseHandle(pi.hThread);
70     return (int)pi.dwProcessId;
71   case _P_DETACH:
72     CloseHandle(pi.hProcess);
73     pi.hProcess = 0;
74     /* fall through */
75   case _P_NOWAIT:
76   case _P_NOWAITO:
77     CloseHandle(pi.hThread);
78     return (int)pi.hProcess;
79   case  _P_OVERLAY:
80     MSVCRT__exit(0);
81   }
82   return -1; /* can't reach here */
83 }
84
85 /* INTERNAL: Convert argv list to a single 'delim'-separated string */
86 static char * __MSVCRT__argvtos(const char * *arg, char delim)
87 {
88   const char **search = arg;
89   long size = 0;
90   char *ret;
91
92   if (!arg && !delim)
93     return NULL;
94
95   /* get length */
96   while(*search)
97   {
98     size += strlen(*search) + 1;
99     search++;
100   }
101
102   if (!(ret = (char *)MSVCRT_calloc(size + 1, 1)))
103     return NULL;
104
105   /* fill string */
106   search = arg;
107   size = 0;
108   while(*search)
109   {
110     int strsize = strlen(*search);
111     memcpy(ret+size,*search,strsize);
112     ret[size+strsize] = delim;
113     size += strsize + 1;
114     search++;
115   }
116   return ret;
117 }
118
119 /*********************************************************************
120  *              _cwait (MSVCRT.@)
121  */
122 int __cdecl MSVCRT__cwait(int *status, int pid, int action)
123 {
124   HANDLE hPid = (HANDLE)pid;
125   int doserrno;
126
127   action = action; /* Remove warning */
128
129   if (!WaitForSingleObject(hPid, -1)) /* wait forever */
130   {
131     if (status)
132     {
133       DWORD stat;
134       GetExitCodeProcess(hPid, &stat);
135       *status = (int)stat;
136     }
137     return (int)pid;
138   }
139   doserrno = GetLastError();
140
141   if (doserrno == ERROR_INVALID_HANDLE)
142   {
143     SET_THREAD_VAR(errno, MSVCRT_ECHILD);
144     SET_THREAD_VAR(doserrno,doserrno);
145   }
146   else
147     MSVCRT__set_errno(doserrno);
148
149   return status ? *status = -1 : -1;
150 }
151
152 /*********************************************************************
153  *              _spawnve (MSVCRT.@)
154  */
155 int __cdecl MSVCRT__spawnve(int flags, const char *name, const char **argv,
156                             const char **envv)
157 {
158   char * args = __MSVCRT__argvtos(argv,' ');
159   char * envs = __MSVCRT__argvtos(envv,0);
160   const char *fullname = name;
161   int ret = -1;
162
163   FIXME(":not translating name %s to locate program\n",fullname);
164   TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null");
165
166   if (args)
167   {
168     ret = __MSVCRT__spawn(flags, fullname, args, envs);
169     MSVCRT_free(args);
170   }
171   if (envs)
172     MSVCRT_free(envs);
173
174   return ret;
175 }
176
177 /*********************************************************************
178  *              _spawnv (MSVCRT.@)
179  */
180 int __cdecl MSVCRT__spawnv(int flags, const char *name, const char **argv)
181 {
182   return MSVCRT__spawnve(flags, name, argv, NULL);
183 }
184
185 /*********************************************************************
186  *              _spawnvpe (MSVCRT.@)
187  */
188 int __cdecl MSVCRT__spawnvpe(int flags, const char *name, const char **argv,
189                             const char **envv)
190 {
191   char fullname[MAX_PATH];
192   MSVCRT__searchenv(name, "PATH", fullname);
193   return MSVCRT__spawnve(flags, fullname[0] ? fullname : name, argv, envv);
194 }
195
196 /*********************************************************************
197  *              _spawnvp (MSVCRT.@)
198  */
199 int __cdecl MSVCRT__spawnvp(int flags, const char *name, const char **argv)
200 {
201   return MSVCRT__spawnvpe(flags, name, argv, NULL);
202 }
203
204 /*********************************************************************
205  *              system (MSVCRT.@)
206  */
207 int __cdecl MSVCRT_system(const char *cmd)
208 {
209   /* FIXME: should probably launch cmd interpreter in COMSPEC */
210   return __MSVCRT__spawn(_P_WAIT, cmd, NULL, NULL);
211 }
212
213 /*********************************************************************
214  *              _loaddll (MSVCRT.@)
215  */
216 int __cdecl MSVCRT__loaddll(const char *dllname)
217 {
218   return LoadLibraryA(dllname);
219 }
220
221 /*********************************************************************
222  *              _unloaddll (MSVCRT.@)
223  */
224 int __cdecl MSVCRT__unloaddll(int dll)
225 {
226   if (FreeLibrary((HANDLE)dll))
227     return 0;
228   else
229   {
230     int err = GetLastError();
231     MSVCRT__set_errno(err);
232     return err;
233   }
234 }
235