/* * CRTDLL spawn functions * * Copyright 1996,1998 Marcus Meissner * Copyright 1996 Jukka Iivonen * Copyright 1997,2000 Uwe Bonnes * Copyright 2000 Jon Griffiths * * These functions differ in whether they pass arguments as an array * (v in the name) or as varags (l in the name), whether they * seach the path (p in the name) and/or whether they take an * environment (e in the name) or pass the parents environment. * Args as Search Take * Name varargs? path? environment? * spawnl N N N * spawnle N N Y * spawnlp N Y N * spawnlpe N Y Y * spawnv Y N N * spawnve Y N Y * spawnvp Y Y N * spawnvpe Y Y Y * * Implementation Notes: * MT Safe - But only because of missing functionality. * * After translating input arguments into the required format for * CreateProcess(), the internal function __CRTDLL__spawn() is * called to perform the actual spawning. * * FIXME: * -File handles need some special handling. Sometimes children get * open file handles, sometimes not. The docs are confusing. * -No check for maximum path/argument/environment size is done. * Unresolved issues Uwe Bonnes 970904: * -system-call calls another wine process, but without debugging arguments * and uses the first wine executable in the path */ #include "crtdll.h" #include #include DEFAULT_DEBUG_CHANNEL(crtdll); /* Process creation flags */ #define _P_WAIT 0 #define _P_NOWAIT 1 #define _P_OVERLAY 2 #define _P_NOWAITO 3 #define _P_DETACH 4 extern void __CRTDLL__set_errno(ULONG err); extern LPVOID __cdecl CRTDLL_calloc(DWORD size, DWORD count); extern VOID __cdecl CRTDLL_free(void *ptr); extern VOID __cdecl CRTDLL__exit(LONG ret); extern INT CRTDLL_doserrno; /* INTERNAL: Spawn a child process */ static int __CRTDLL__spawn(INT flags, LPCSTR exe, LPSTR args, LPSTR env) { STARTUPINFOA si; PROCESS_INFORMATION pi; if ((unsigned)flags > _P_DETACH) { CRTDLL_errno = EINVAL; return -1; } FIXME(":must dup/kill streams for child process\n"); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); if (!CreateProcessA(exe, args, NULL, NULL, TRUE, flags == _P_DETACH ? DETACHED_PROCESS : 0, env, NULL, &si, &pi)) { __CRTDLL__set_errno(GetLastError()); return -1; } switch(flags) { case _P_WAIT: WaitForSingleObject(pi.hProcess,-1); /* wait forvever */ GetExitCodeProcess(pi.hProcess,&pi.dwProcessId); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return pi.dwProcessId; case _P_DETACH: CloseHandle(pi.hProcess); pi.hProcess = 0; /* fall through */ case _P_NOWAIT: case _P_NOWAITO: CloseHandle(pi.hThread); return pi.hProcess; case _P_OVERLAY: CRTDLL__exit(0); } return -1; /* cant reach here */ } /* INTERNAL: Convert argv list to a single 'delim'-seperated string */ static LPSTR __CRTDLL__argvtos(LPCSTR *arg, CHAR delim) { LPCSTR *search = arg; LONG size = 0; LPSTR ret; if (!arg && !delim) return NULL; /* get length */ while(*search) { size += strlen(*search) + 1; search++; } if (!(ret = (LPSTR)CRTDLL_calloc(size + 1, 1))) return NULL; /* fill string */ search = arg; size = 0; while(*search) { int strsize = strlen(*search); memcpy(ret+size,*search,strsize); ret[size+strsize] = delim; size += strsize + 1; search++; } return ret; } /********************************************************************* * _cwait (CRTDLL.069) * * Wait for a spawned process to finish. */ INT __cdecl CRTDLL__cwait(LPINT status, INT pid, INT action) { HANDLE hPid = (HANDLE)pid; action = action; /* Remove warning */ if (!WaitForSingleObject(hPid, -1)) /* wait forvever */ { if (status) { DWORD stat; GetExitCodeProcess(hPid, &stat); *status = (INT)stat; } return pid; } CRTDLL_doserrno = GetLastError(); if (CRTDLL_doserrno == ERROR_INVALID_HANDLE) CRTDLL_errno = ECHILD; else __CRTDLL__set_errno(CRTDLL_doserrno); return status ? *status = -1 : -1; } /********************************************************************* * _spawnv (CRTDLL.273) * * Spawn a process. */ HANDLE __cdecl CRTDLL__spawnv(INT flags, LPCSTR name, LPCSTR *argv) { return CRTDLL__spawnve(flags, name, argv, NULL); } /********************************************************************* * _spawnve (CRTDLL.274) * * Spawn a process. */ HANDLE __cdecl CRTDLL__spawnve(INT flags, LPCSTR name, LPCSTR *argv, LPCSTR *envv) { LPSTR args = __CRTDLL__argvtos(argv,' '); LPSTR envs = __CRTDLL__argvtos(envv,0); LPCSTR fullname = name; HANDLE ret = -1; FIXME(":not translating name %s to locate program\n",fullname); TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null"); if (args) { ret = __CRTDLL__spawn(flags, fullname, args, envs); CRTDLL_free(args); } if (envs) CRTDLL_free(envs); return ret; } /********************************************************************* * _spawnvp (CRTDLL.275) * * Spawn a process. */ HANDLE __cdecl CRTDLL__spawnvp(INT flags, LPCSTR name, LPCSTR *argv) { return CRTDLL__spawnvpe(flags, name, argv, NULL); } /********************************************************************* * _spawnvpe (CRTDLL.276) * * Spawn a process. */ HANDLE __cdecl CRTDLL__spawnvpe(INT flags, LPCSTR name, LPCSTR *argv, LPCSTR *envv) { char fullname[MAX_PATH]; CRTDLL__searchenv(name, "PATH", fullname); return CRTDLL__spawnve(flags, fullname[0] ? fullname : name, argv, envv); } /********************************************************************* * system (CRTDLL.485) * * Spawn an O/S process. */ INT __cdecl CRTDLL_system(LPCSTR cmd) { /* FIXME: should probably launch cmd interpreter in COMSPEC */ return __CRTDLL__spawn(_P_WAIT, cmd, NULL, NULL); }