wine/dlls/msvcrt/process.c

517 lines
12 KiB
C
Raw Normal View History

/*
* msvcrt.dll spawn/exec functions
*
* Copyright 1996,1998 Marcus Meissner
* Copyright 1996 Jukka Iivonen
* Copyright 1997,2000 Uwe Bonnes
* Copyright 2000 Jon Griffiths
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* 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 "config.h"
#include <stdarg.h>
#include "msvcrt.h"
2002-09-17 18:32:53 +00:00
#include "msvcrt/errno.h"
#include "msvcrt/stdio.h"
#include "msvcrt/process.h"
#include "msvcrt/stdlib.h"
#include "msvcrt/string.h"
#include "wine/debug.h"
WINE_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)
{
*MSVCRT__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(p,*a,len);
p += len;
*p++ = delim;
a++;
}
if (delim && p > ret) p[-1] = 0;
else *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)
2001-05-18 20:58:08 +00:00
{
va_list alist2;
2001-05-18 20:58:08 +00:00
long size;
const char *arg;
char* p;
2001-05-18 20:58:08 +00:00
char *ret;
#if HAVE_VA_COPY
va_copy(alist2,alist);
#else
# if HAVE___VA_COPY
__va_copy(alist2,alist);
# else
alist2 = alist;
# endif
#endif
2001-05-18 20:58:08 +00:00
if (!arg0 && !delim)
{
/* Return NULL for an empty environment list */
return NULL;
2001-05-18 20:58:08 +00:00
}
/* 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)
2001-05-18 20:58:08 +00:00
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);
if (delim && p > ret) p[-1] = 0;
else *p = 0;
2001-05-18 20:58:08 +00:00
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)
{
*MSVCRT__errno() = MSVCRT_ECHILD;
*__doserrno() = doserrno;
}
else
MSVCRT__set_errno(doserrno);
return status ? *status = -1 : -1;
}
2001-05-22 19:18:51 +00:00
/*********************************************************************
* _execl (MSVCRT.@)
*
2002-05-31 23:06:46 +00:00
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
2001-05-22 19:18:51 +00:00
*/
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.@)
*
2002-05-31 23:06:46 +00:00
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
2001-05-22 19:18:51 +00:00
*/
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.@)
*
2002-05-31 23:06:46 +00:00
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
2001-05-22 19:18:51 +00:00
*/
int _execv(const char* name, char* const* argv)
{
return _spawnve(_P_OVERLAY, name, (const char* const*) argv, NULL);
}
/*********************************************************************
* _execve (MSVCRT.@)
*
2002-05-31 23:06:46 +00:00
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
2001-05-22 19:18:51 +00:00
*/
int _execve(const char* name, char* const* argv, const char* const* envv)
{
return _spawnve(_P_OVERLAY, name, (const char* const*) argv, envv);
}
/*********************************************************************
* _execvpe (MSVCRT.@)
*
2002-05-31 23:06:46 +00:00
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
2001-05-22 19:18:51 +00:00
*/
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.@)
*
2002-05-31 23:06:46 +00:00
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
2001-05-22 19:18:51 +00:00
*/
int _execvp(const char* name, char* const* argv)
{
return _execvpe(name, argv, NULL);
}
2001-05-18 20:58:08 +00:00
/*********************************************************************
* _spawnl (MSVCRT.@)
*
2002-05-31 23:06:46 +00:00
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
2001-05-18 20:58:08 +00:00
*/
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;
}
/*********************************************************************
2001-05-22 19:18:51 +00:00
* _spawnlp (MSVCRT.@)
*
2002-05-31 23:06:46 +00:00
* Like on Windows, this function does not handle arguments with spaces
* or double-quotes.
2001-05-18 20:58:08 +00:00
*/
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);
2001-05-22 19:18:51 +00:00
ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
2001-05-18 20:58:08 +00:00
MSVCRT_free(args);
return ret;
}
/*********************************************************************
* _spawnve (MSVCRT.@)
*
2002-05-31 23:06:46 +00:00
* 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.@)
*
2002-05-31 23:06:46 +00:00
* 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.@)
*
2002-05-31 23:06:46 +00:00
* 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.@)
*
2002-05-31 23:06:46 +00:00
* 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);
}
/*********************************************************************
* _popen (MSVCRT.@)
*/
MSVCRT_FILE* _popen(const char* command, const char* mode)
{
FIXME("(command=%s, mode=%s): stub\n", debugstr_a(command), debugstr_a(mode));
return NULL;
}
/*********************************************************************
* _wpopen (MSVCRT.@)
*/
MSVCRT_FILE* _wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
{
FIXME("(command=%s, mode=%s): stub\n", debugstr_w(command), debugstr_w(mode));
return NULL;
}
/*********************************************************************
* _pclose (MSVCRT.@)
*/
int _pclose(MSVCRT_FILE* file)
{
FIXME("(file=%p): stub\n", file);
return 0;
}
/*********************************************************************
* 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 (int)LoadLibraryA(dllname);
}
/*********************************************************************
* _unloaddll (MSVCRT.@)
*/
int _unloaddll(int dll)
{
if (FreeLibrary((HMODULE)dll))
return 0;
else
{
int err = GetLastError();
MSVCRT__set_errno(err);
return err;
}
}
/*********************************************************************
* _getdllprocaddr (MSVCRT.@)
*/
void *_getdllprocaddr(int dll, const char *name, int ordinal)
{
if (name)
{
if (ordinal != -1) return NULL;
return GetProcAddress( (HMODULE)dll, name );
}
if (HIWORD(ordinal)) return NULL;
return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );
}