blob: 5768469dedfedb6fe5b796ef68d3169f139a9f51 [file] [log] [blame]
/*
* 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.
* -Wine has a "process.h" which is not the same as any crt version.
* 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 <errno.h>
#include "process.h"
#include <stdlib.h>
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, LPSTR exe, LPSTR args, LPSTR env);
static int __CRTDLL__spawn(INT flags, LPSTR 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(LPSTR *arg, CHAR delim);
static LPSTR __CRTDLL__argvtos(LPSTR *arg, CHAR delim)
{
LPSTR *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;
}
/*********************************************************************
* _spawnve (CRTDLL.274)
*
* Spawn a process.
*
*/
HANDLE __cdecl CRTDLL__spawnve(INT flags, LPSTR name, LPSTR *argv, LPSTR *envv)
{
LPSTR args = __CRTDLL__argvtos(argv,' ');
LPSTR envs = __CRTDLL__argvtos(envv,0);
LPSTR fullname = name;
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)
{
HANDLE ret = __CRTDLL__spawn(flags, fullname, args, envs);
CRTDLL_free(args);
CRTDLL_free(envs);
return ret;
}
if (envs)
CRTDLL_free(envs);
WARN(":No argv[0] passed - process will not be executed");
return -1;
}
/*********************************************************************
* system (CRTDLL.485)
*/
INT __cdecl CRTDLL_system(LPSTR x)
{
/* FIXME: should probably launch cmd interpreter in COMSPEC */
return __CRTDLL__spawn(_P_WAIT, NULL, x, NULL);
}