/* * 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 #include "process.h" #include "options.h" #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, 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); }