blob: 0a860037d80216411cc5c11a6f5c3a702b8a167a [file] [log] [blame]
/*
* msvcrt.dll spawn/exec functions
*
* Copyright 1996,1998 Marcus Meissner
* Copyright 1996 Jukka Iivonen
* Copyright 1997,2000 Uwe Bonnes
* Copyright 2000 Jon Griffiths
*
* 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
*/
#include "msvcrt.h"
#include "ms_errno.h"
#include "msvcrt/process.h"
#include "msvcrt/stdlib.h"
#include "msvcrt/string.h"
DEFAULT_DEBUG_CHANNEL(msvcrt);
/* FIXME: Check file extensions for app to run */
static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
/* INTERNAL: Spawn a child process */
static int msvcrt_spawn(int flags, const char* exe, char* cmdline, char* env)
{
STARTUPINFOA si;
PROCESS_INFORMATION pi;
if (sizeof(HANDLE) != sizeof(int))
WARN("This call is unsuitable for your architecture\n");
if ((unsigned)flags > _P_DETACH)
{
SET_THREAD_VAR(errno,MSVCRT_EINVAL);
return -1;
}
FIXME(":must dup/kill streams for child process\n");
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcessA(exe, cmdline, NULL, NULL, TRUE,
flags == _P_DETACH ? DETACHED_PROCESS : 0,
env, NULL, &si, &pi))
{
MSVCRT__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 (int)pi.dwProcessId;
case _P_DETACH:
CloseHandle(pi.hProcess);
pi.hProcess = 0;
/* fall through */
case _P_NOWAIT:
case _P_NOWAITO:
CloseHandle(pi.hThread);
return (int)pi.hProcess;
case _P_OVERLAY:
MSVCRT__exit(0);
}
return -1; /* can't reach here */
}
/* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
* extra '\0' to terminate it
*/
static char* msvcrt_argvtos(const char* const* arg, char delim)
{
const char* const* a;
long size;
char* p;
char* ret;
if (!arg && !delim)
{
/* Return NULL for an empty environment list */
return NULL;
}
/* get length */
a = arg;
size = 0;
while (*a)
{
size += strlen(*a) + 1;
a++;
}
ret = (char*)MSVCRT_malloc(size + 1);
if (!ret)
return NULL;
/* fill string */
a = arg;
p = ret;
while (*a)
{
int len = strlen(*a);
memcpy(ret+size,*a,len);
p += len;
*p++ = delim;
a++;
}
*p='\0';
return ret;
}
/* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
* extra '\0' to terminate it
*/
static char* msvcrt_valisttos(const char* arg0, va_list alist, char delim)
{
va_list alist2 = alist;
long size;
const char *arg;
char* p;
char *ret;
if (!arg0 && !delim)
{
/* Return NULL for an empty environment list */
return NULL;
}
/* get length */
arg = arg0;
size = 0;
do {
size += strlen(arg) + 1;
arg = va_arg(alist, char*);
} while (arg != NULL);
ret = (char*)MSVCRT_malloc(size + 1);
if (!ret)
return NULL;
/* fill string */
arg = arg0;
p = ret;
do {
int len = strlen(arg);
memcpy(p,arg,len);
p += len;
*p++ = delim;
arg = va_arg(alist2, char*);
} while (arg != NULL);
*p = '\0';
return ret;
}
/*********************************************************************
* _cwait (MSVCRT.@)
*/
int _cwait(int *status, int pid, int action)
{
HANDLE hPid = (HANDLE)pid;
int doserrno;
action = action; /* Remove warning */
if (!WaitForSingleObject(hPid, -1)) /* wait forever */
{
if (status)
{
DWORD stat;
GetExitCodeProcess(hPid, &stat);
*status = (int)stat;
}
return (int)pid;
}
doserrno = GetLastError();
if (doserrno == ERROR_INVALID_HANDLE)
{
SET_THREAD_VAR(errno, MSVCRT_ECHILD);
SET_THREAD_VAR(doserrno,doserrno);
}
else
MSVCRT__set_errno(doserrno);
return status ? *status = -1 : -1;
}
/*********************************************************************
* _execl (MSVCRT.@)
*
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
*/
int _execl(const char* name, const char* arg0, ...)
{
va_list ap;
char * args;
int ret;
va_start(ap, arg0);
args = msvcrt_valisttos(arg0, ap, ' ');
va_end(ap);
ret = msvcrt_spawn(_P_OVERLAY, name, args, NULL);
MSVCRT_free(args);
return ret;
}
/*********************************************************************
* _execlp (MSVCRT.@)
*
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
*/
int _execlp(const char* name, const char* arg0, ...)
{
va_list ap;
char * args;
int ret;
char fullname[MAX_PATH];
_searchenv(name, "PATH", fullname);
va_start(ap, arg0);
args = msvcrt_valisttos(arg0, ap, ' ');
va_end(ap);
ret = msvcrt_spawn(_P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
MSVCRT_free(args);
return ret;
}
/*********************************************************************
* _execv (MSVCRT.@)
*
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
*/
int _execv(const char* name, char* const* argv)
{
return _spawnve(_P_OVERLAY, name, (const char* const*) argv, NULL);
}
/*********************************************************************
* _execve (MSVCRT.@)
*
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
*/
int _execve(const char* name, char* const* argv, const char* const* envv)
{
return _spawnve(_P_OVERLAY, name, (const char* const*) argv, envv);
}
/*********************************************************************
* _execvpe (MSVCRT.@)
*
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
*/
int _execvpe(const char* name, char* const* argv, const char* const* envv)
{
char fullname[MAX_PATH];
_searchenv(name, "PATH", fullname);
return _spawnve(_P_OVERLAY, fullname[0] ? fullname : name,
(const char* const*) argv, envv);
}
/*********************************************************************
* _execvp (MSVCRT.@)
*
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
*/
int _execvp(const char* name, char* const* argv)
{
return _execvpe(name, argv, NULL);
}
/*********************************************************************
* _spawnl (MSVCRT.@)
*
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
*/
int _spawnl(int flags, const char* name, const char* arg0, ...)
{
va_list ap;
char * args;
int ret;
va_start(ap, arg0);
args = msvcrt_valisttos(arg0, ap, ' ');
va_end(ap);
ret = msvcrt_spawn(flags, name, args, NULL);
MSVCRT_free(args);
return ret;
}
/*********************************************************************
* _spawnlp (MSVCRT.@)
*
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
*/
int _spawnlp(int flags, const char* name, const char* arg0, ...)
{
va_list ap;
char * args;
int ret;
char fullname[MAX_PATH];
_searchenv(name, "PATH", fullname);
va_start(ap, arg0);
args = msvcrt_valisttos(arg0, ap, ' ');
va_end(ap);
ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
MSVCRT_free(args);
return ret;
}
/*********************************************************************
* _spawnve (MSVCRT.@)
*
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
*/
int _spawnve(int flags, const char* name, const char* const* argv,
const char* const* envv)
{
char * args = msvcrt_argvtos(argv,' ');
char * envs = msvcrt_argvtos(envv,0);
const char *fullname = name;
int 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 = msvcrt_spawn(flags, fullname, args, envs);
MSVCRT_free(args);
}
if (envs)
MSVCRT_free(envs);
return ret;
}
/*********************************************************************
* _spawnv (MSVCRT.@)
*
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
*/
int _spawnv(int flags, const char* name, const char* const* argv)
{
return _spawnve(flags, name, argv, NULL);
}
/*********************************************************************
* _spawnvpe (MSVCRT.@)
*
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
*/
int _spawnvpe(int flags, const char* name, const char* const* argv,
const char* const* envv)
{
char fullname[MAX_PATH];
_searchenv(name, "PATH", fullname);
return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
}
/*********************************************************************
* _spawnvp (MSVCRT.@)
*
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
*/
int _spawnvp(int flags, const char* name, const char* const* argv)
{
return _spawnvpe(flags, name, argv, NULL);
}
/*********************************************************************
* system (MSVCRT.@)
*/
int MSVCRT_system(const char* cmd)
{
char* cmdcopy;
int res;
/* Make a writable copy for CreateProcess */
cmdcopy=_strdup(cmd);
/* FIXME: should probably launch cmd interpreter in COMSPEC */
res=msvcrt_spawn(_P_WAIT, NULL, cmdcopy, NULL);
MSVCRT_free(cmdcopy);
return res;
}
/*********************************************************************
* _loaddll (MSVCRT.@)
*/
int _loaddll(const char* dllname)
{
return LoadLibraryA(dllname);
}
/*********************************************************************
* _unloaddll (MSVCRT.@)
*/
int _unloaddll(int dll)
{
if (FreeLibrary((HANDLE)dll))
return 0;
else
{
int err = GetLastError();
MSVCRT__set_errno(err);
return err;
}
}