226 lines
5.4 KiB
C
226 lines
5.4 KiB
C
![]() |
/*
|
||
|
* 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 "options.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)
|
||
|
{
|
||
|
#define SYSBUF_LENGTH 1500
|
||
|
char buffer[SYSBUF_LENGTH];
|
||
|
unsigned char *y = x;
|
||
|
unsigned char *bp;
|
||
|
int i;
|
||
|
|
||
|
strcpy(buffer, argv0);
|
||
|
bp = buffer + strlen(buffer);
|
||
|
*bp++ = ' ';
|
||
|
*bp++ = '"';
|
||
|
*bp++ = 0;
|
||
|
i = strlen(buffer) + strlen(x) +2;
|
||
|
|
||
|
/* Calculate needed buffer size to prevent overflow. */
|
||
|
while (*y) {
|
||
|
if (*y =='\\') i++;
|
||
|
y++;
|
||
|
}
|
||
|
/* If buffer too short, exit. */
|
||
|
if (i > SYSBUF_LENGTH) {
|
||
|
TRACE("_system buffer to small\n");
|
||
|
return 127;
|
||
|
}
|
||
|
|
||
|
y =x;
|
||
|
|
||
|
while (*y) {
|
||
|
*bp = *y;
|
||
|
bp++; y++;
|
||
|
if (*(y-1) =='\\') *bp++ = '\\';
|
||
|
}
|
||
|
/* Remove spaces from end of string. */
|
||
|
while (*(y-1) == ' ') {
|
||
|
bp--;y--;
|
||
|
}
|
||
|
*bp++ = '"';
|
||
|
*bp = 0;
|
||
|
TRACE("_system got '%s', executing '%s'\n",x,buffer);
|
||
|
|
||
|
return system(buffer);
|
||
|
}
|