summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--w32/compat/dirent.c376
-rw-r--r--w32/include/dirent.h74
-rw-r--r--w32/include/pathstuff.h20
-rw-r--r--w32/include/sub_proc.h108
-rw-r--r--w32/include/w32err.h20
-rw-r--r--w32/pathstuff.c438
-rw-r--r--w32/subproc/NMakefile118
-rw-r--r--w32/subproc/build.bat20
-rw-r--r--w32/subproc/misc.c126
-rw-r--r--w32/subproc/proc.h26
-rw-r--r--w32/subproc/sub_proc.c2200
-rw-r--r--w32/subproc/w32err.c102
13 files changed, 1822 insertions, 1814 deletions
diff --git a/ChangeLog b/ChangeLog
index d57aa7c..90f690c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Fri Jul 19 16:57:27 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+
+ * GNUmakefile (win32files): New variable.
+ (distfiles): Add it.
+ * w32: Updated by Rob Tulloh.
+
+ * makefile.vms (LOADLIBES): Fix typo.
+
Sun Jul 14 12:59:27 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
* job.c (construct_command_argv_internal): Fix up #else, #endifs.
diff --git a/w32/compat/dirent.c b/w32/compat/dirent.c
index f516eb9..25a7b74 100644
--- a/w32/compat/dirent.c
+++ b/w32/compat/dirent.c
@@ -1,188 +1,188 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include "dirent.h"
-
-
-DIR*
-opendir(const char* pDirName)
-{
- struct stat sb;
- DIR* pDir;
- char* pEndDirName;
- int nBufferLen;
-
- /* sanity checks */
- if (!pDirName) {
- errno = EINVAL;
- return NULL;
- }
- if (stat(pDirName, &sb) != 0) {
- errno = ENOENT;
- return NULL;
- }
- if ((sb.st_mode & S_IFMT) != S_IFDIR) {
- errno = ENOTDIR;
- return NULL;
- }
-
- /* allocate a DIR structure to return */
- pDir = (DIR *) malloc(sizeof (DIR));
-
- if (!pDir)
- return NULL;
-
- /* input directory name length */
- nBufferLen = strlen(pDirName);
-
- /* copy input directory name to DIR buffer */
- strcpy(pDir->dir_pDirectoryName, pDirName);
-
- /* point to end of the copied directory name */
- pEndDirName = &pDir->dir_pDirectoryName[nBufferLen - 1];
-
- /* if directory name did not end in '/' or '\', add '/' */
- if ((*pEndDirName != '/') && (*pEndDirName != '\\')) {
- pEndDirName++;
- *pEndDirName = '/';
- }
-
- /* now append the wildcard character to the buffer */
- pEndDirName++;
- *pEndDirName = '*';
- pEndDirName++;
- *pEndDirName = '\0';
-
- /* other values defaulted */
- pDir->dir_nNumFiles = 0;
- pDir->dir_hDirHandle = INVALID_HANDLE_VALUE;
- pDir->dir_ulCookie = __DIRENT_COOKIE;
-
- return pDir;
-}
-
-void
-closedir(DIR *pDir)
-{
- /* got a valid pointer? */
- if (!pDir) {
- errno = EINVAL;
- return;
- }
-
- /* sanity check that this is a DIR pointer */
- if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
- errno = EINVAL;
- return;
- }
-
- /* close the WIN32 directory handle */
- if (pDir->dir_hDirHandle != INVALID_HANDLE_VALUE)
- FindClose(pDir->dir_hDirHandle);
-
- free(pDir);
-
- return;
-}
-
-struct dirent *
-readdir(DIR* pDir)
-{
- WIN32_FIND_DATA wfdFindData;
-
- if (!pDir) {
- errno = EINVAL;
- return NULL;
- }
-
- /* sanity check that this is a DIR pointer */
- if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
- errno = EINVAL;
- return NULL;
- }
-
- if (pDir->dir_nNumFiles == 0) {
- pDir->dir_hDirHandle = FindFirstFile(pDir->dir_pDirectoryName, &wfdFindData);
- if (pDir->dir_hDirHandle == INVALID_HANDLE_VALUE)
- return NULL;
- } else if (!FindNextFile(pDir->dir_hDirHandle, &wfdFindData))
- return NULL;
-
- /* bump count for next call to readdir() or telldir() */
- pDir->dir_nNumFiles++;
-
- /* fill in struct dirent values */
- pDir->dir_sdReturn.d_ino = -1;
- strcpy(pDir->dir_sdReturn.d_name, wfdFindData.cFileName);
-
- return &pDir->dir_sdReturn;
-}
-
-void
-rewinddir(DIR* pDir)
-{
- if (!pDir) {
- errno = EINVAL;
- return;
- }
-
- /* sanity check that this is a DIR pointer */
- if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
- errno = EINVAL;
- return;
- }
-
- /* close the WIN32 directory handle */
- if (pDir->dir_hDirHandle != INVALID_HANDLE_VALUE)
- if (!FindClose(pDir->dir_hDirHandle))
- errno = EBADF;
-
- /* reset members which control readdir() */
- pDir->dir_hDirHandle = INVALID_HANDLE_VALUE;
- pDir->dir_nNumFiles = 0;
-
- return;
-}
-
-int
-telldir(DIR* pDir)
-{
- if (!pDir) {
- errno = EINVAL;
- return -1;
- }
-
- /* sanity check that this is a DIR pointer */
- if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
- errno = EINVAL;
- return -1;
- }
-
- /* return number of times readdir() called */
- return pDir->dir_nNumFiles;
-}
-
-void
-seekdir(DIR* pDir, long nPosition)
-{
- if (!pDir)
- return;
-
- /* sanity check that this is a DIR pointer */
- if (pDir->dir_ulCookie != __DIRENT_COOKIE)
- return;
-
- /* go back to beginning of directory */
- rewinddir(pDir);
-
- /* loop until we have found position we care about */
- for (--nPosition; nPosition && readdir(pDir); nPosition--);
-
- /* flag invalid nPosition value */
- if (nPosition)
- errno = EINVAL;
-
- return;
-}
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "dirent.h"
+
+
+DIR*
+opendir(const char* pDirName)
+{
+ struct stat sb;
+ DIR* pDir;
+ char* pEndDirName;
+ int nBufferLen;
+
+ /* sanity checks */
+ if (!pDirName) {
+ errno = EINVAL;
+ return NULL;
+ }
+ if (stat(pDirName, &sb) != 0) {
+ errno = ENOENT;
+ return NULL;
+ }
+ if ((sb.st_mode & S_IFMT) != S_IFDIR) {
+ errno = ENOTDIR;
+ return NULL;
+ }
+
+ /* allocate a DIR structure to return */
+ pDir = (DIR *) malloc(sizeof (DIR));
+
+ if (!pDir)
+ return NULL;
+
+ /* input directory name length */
+ nBufferLen = strlen(pDirName);
+
+ /* copy input directory name to DIR buffer */
+ strcpy(pDir->dir_pDirectoryName, pDirName);
+
+ /* point to end of the copied directory name */
+ pEndDirName = &pDir->dir_pDirectoryName[nBufferLen - 1];
+
+ /* if directory name did not end in '/' or '\', add '/' */
+ if ((*pEndDirName != '/') && (*pEndDirName != '\\')) {
+ pEndDirName++;
+ *pEndDirName = '/';
+ }
+
+ /* now append the wildcard character to the buffer */
+ pEndDirName++;
+ *pEndDirName = '*';
+ pEndDirName++;
+ *pEndDirName = '\0';
+
+ /* other values defaulted */
+ pDir->dir_nNumFiles = 0;
+ pDir->dir_hDirHandle = INVALID_HANDLE_VALUE;
+ pDir->dir_ulCookie = __DIRENT_COOKIE;
+
+ return pDir;
+}
+
+void
+closedir(DIR *pDir)
+{
+ /* got a valid pointer? */
+ if (!pDir) {
+ errno = EINVAL;
+ return;
+ }
+
+ /* sanity check that this is a DIR pointer */
+ if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
+ errno = EINVAL;
+ return;
+ }
+
+ /* close the WIN32 directory handle */
+ if (pDir->dir_hDirHandle != INVALID_HANDLE_VALUE)
+ FindClose(pDir->dir_hDirHandle);
+
+ free(pDir);
+
+ return;
+}
+
+struct dirent *
+readdir(DIR* pDir)
+{
+ WIN32_FIND_DATA wfdFindData;
+
+ if (!pDir) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* sanity check that this is a DIR pointer */
+ if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (pDir->dir_nNumFiles == 0) {
+ pDir->dir_hDirHandle = FindFirstFile(pDir->dir_pDirectoryName, &wfdFindData);
+ if (pDir->dir_hDirHandle == INVALID_HANDLE_VALUE)
+ return NULL;
+ } else if (!FindNextFile(pDir->dir_hDirHandle, &wfdFindData))
+ return NULL;
+
+ /* bump count for next call to readdir() or telldir() */
+ pDir->dir_nNumFiles++;
+
+ /* fill in struct dirent values */
+ pDir->dir_sdReturn.d_ino = -1;
+ strcpy(pDir->dir_sdReturn.d_name, wfdFindData.cFileName);
+
+ return &pDir->dir_sdReturn;
+}
+
+void
+rewinddir(DIR* pDir)
+{
+ if (!pDir) {
+ errno = EINVAL;
+ return;
+ }
+
+ /* sanity check that this is a DIR pointer */
+ if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
+ errno = EINVAL;
+ return;
+ }
+
+ /* close the WIN32 directory handle */
+ if (pDir->dir_hDirHandle != INVALID_HANDLE_VALUE)
+ if (!FindClose(pDir->dir_hDirHandle))
+ errno = EBADF;
+
+ /* reset members which control readdir() */
+ pDir->dir_hDirHandle = INVALID_HANDLE_VALUE;
+ pDir->dir_nNumFiles = 0;
+
+ return;
+}
+
+int
+telldir(DIR* pDir)
+{
+ if (!pDir) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* sanity check that this is a DIR pointer */
+ if (pDir->dir_ulCookie != __DIRENT_COOKIE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* return number of times readdir() called */
+ return pDir->dir_nNumFiles;
+}
+
+void
+seekdir(DIR* pDir, long nPosition)
+{
+ if (!pDir)
+ return;
+
+ /* sanity check that this is a DIR pointer */
+ if (pDir->dir_ulCookie != __DIRENT_COOKIE)
+ return;
+
+ /* go back to beginning of directory */
+ rewinddir(pDir);
+
+ /* loop until we have found position we care about */
+ for (--nPosition; nPosition && readdir(pDir); nPosition--);
+
+ /* flag invalid nPosition value */
+ if (nPosition)
+ errno = EINVAL;
+
+ return;
+}
diff --git a/w32/include/dirent.h b/w32/include/dirent.h
index 6bb7fbd..ccc1800 100644
--- a/w32/include/dirent.h
+++ b/w32/include/dirent.h
@@ -1,37 +1,37 @@
-#ifndef _DIRENT_H
-#define _DIRENT_H
-
-#include <stdlib.h>
-#include <windows.h>
-#include <limits.h>
-#include <sys/types.h>
-
-#ifndef NAME_MAX
-#define NAME_MAX 255
-#endif
-
-#define __DIRENT_COOKIE 0xfefeabab
-
-
-struct dirent
-{
- ino_t d_ino; /* unused - no equivalent on WIN32 */
- char d_name[NAME_MAX+1];
-};
-
-typedef struct dir_struct {
- ULONG dir_ulCookie;
- HANDLE dir_hDirHandle;
- DWORD dir_nNumFiles;
- char dir_pDirectoryName[NAME_MAX+1];
- struct dirent dir_sdReturn;
-} DIR;
-
-DIR *opendir(const char *);
-struct dirent *readdir(DIR *);
-void rewinddir(DIR *);
-void closedir(DIR *);
-int telldir(DIR *);
-void seekdir(DIR *, long);
-
-#endif
+#ifndef _DIRENT_H
+#define _DIRENT_H
+
+#include <stdlib.h>
+#include <windows.h>
+#include <limits.h>
+#include <sys/types.h>
+
+#ifndef NAME_MAX
+#define NAME_MAX 255
+#endif
+
+#define __DIRENT_COOKIE 0xfefeabab
+
+
+struct dirent
+{
+ ino_t d_ino; /* unused - no equivalent on WIN32 */
+ char d_name[NAME_MAX+1];
+};
+
+typedef struct dir_struct {
+ ULONG dir_ulCookie;
+ HANDLE dir_hDirHandle;
+ DWORD dir_nNumFiles;
+ char dir_pDirectoryName[NAME_MAX+1];
+ struct dirent dir_sdReturn;
+} DIR;
+
+DIR *opendir(const char *);
+struct dirent *readdir(DIR *);
+void rewinddir(DIR *);
+void closedir(DIR *);
+int telldir(DIR *);
+void seekdir(DIR *, long);
+
+#endif
diff --git a/w32/include/pathstuff.h b/w32/include/pathstuff.h
index 285ed04..63e7fb0 100644
--- a/w32/include/pathstuff.h
+++ b/w32/include/pathstuff.h
@@ -1,10 +1,10 @@
-#ifndef _PATHSTUFF_H
-#define _PATHSTUFF_H
-
-extern char * convert_Path_to_win32(char *Path, char to_delim);
-extern char * w32ify(char *file, int resolve);
-extern char * getcwd_fs(char *buf, int len);
-
-#define convert_vpath_to_win32(vpath, delim) convert_Path_to_win32(vpath, delim)
-
-#endif
+#ifndef _PATHSTUFF_H
+#define _PATHSTUFF_H
+
+extern char * convert_Path_to_win32(char *Path, char to_delim);
+extern char * w32ify(char *file, int resolve);
+extern char * getcwd_fs(char *buf, int len);
+
+#define convert_vpath_to_win32(vpath, delim) convert_Path_to_win32(vpath, delim)
+
+#endif
diff --git a/w32/include/sub_proc.h b/w32/include/sub_proc.h
index 12e9cf3..4f1f312 100644
--- a/w32/include/sub_proc.h
+++ b/w32/include/sub_proc.h
@@ -1,54 +1,54 @@
-#ifndef SUB_PROC_H
-#define SUB_PROC_H
-
-/*
- * Component Name:
- *
- * $Date$
- *
- * $Source$
- *
- * $Revision$
- *
- * Description:
- *
- * (C) COPYRIGHT TIVOLI Systems, Inc. 1991-1994
- * Unpublished Work
- * All Rights Reserved
- * Licensed Material - Property of TIVOLI Systems, Inc.
- */
-
-/* $Id$ */
-
-#ifdef WIN32
-
-#define EXTERN_DECL(entry, args) extern entry args
-#define VOID_DECL void
-
-EXTERN_DECL(HANDLE process_init, (VOID_DECL));
-EXTERN_DECL(HANDLE process_init_fd, (HANDLE stdinh, HANDLE stdouth,
- HANDLE stderrh));
-EXTERN_DECL(long process_begin, (HANDLE proc, char **argv, char **envp,
- char *exec_path, char *as_user));
-EXTERN_DECL(long process_pipe_io, (HANDLE proc, char *stdin_data,
- int stdin_data_len));
-EXTERN_DECL(long process_file_io, (HANDLE proc));
-EXTERN_DECL(void process_cleanup, (HANDLE proc));
-EXTERN_DECL(HANDLE process_wait_for_any, (VOID_DECL));
-EXTERN_DECL(void process_register, (HANDLE proc));
-EXTERN_DECL(HANDLE process_easy, (char** argv, char** env));
-EXTERN_DECL(BOOL process_kill, (HANDLE proc, int signal));
-
-/* support routines */
-EXTERN_DECL(long process_errno, (HANDLE proc));
-EXTERN_DECL(long process_last_err, (HANDLE proc));
-EXTERN_DECL(long process_exit_code, (HANDLE proc));
-EXTERN_DECL(long process_signal, (HANDLE proc));
-EXTERN_DECL(char * process_outbuf, (HANDLE proc));
-EXTERN_DECL(char * process_errbuf, (HANDLE proc));
-EXTERN_DECL(int process_outcnt, (HANDLE proc));
-EXTERN_DECL(int process_errcnt, (HANDLE proc));
-EXTERN_DECL(void process_pipes, (HANDLE proc, int pipes[3]));
-
-#endif
-#endif
+#ifndef SUB_PROC_H
+#define SUB_PROC_H
+
+/*
+ * Component Name:
+ *
+ * $Date$
+ *
+ * $Source$
+ *
+ * $Revision$
+ *
+ * Description:
+ *
+ * (C) COPYRIGHT TIVOLI Systems, Inc. 1991-1994
+ * Unpublished Work
+ * All Rights Reserved
+ * Licensed Material - Property of TIVOLI Systems, Inc.
+ */
+
+/* $Id$ */
+
+#ifdef WIN32
+
+#define EXTERN_DECL(entry, args) extern entry args
+#define VOID_DECL void
+
+EXTERN_DECL(HANDLE process_init, (VOID_DECL));
+EXTERN_DECL(HANDLE process_init_fd, (HANDLE stdinh, HANDLE stdouth,
+ HANDLE stderrh));
+EXTERN_DECL(long process_begin, (HANDLE proc, char **argv, char **envp,
+ char *exec_path, char *as_user));
+EXTERN_DECL(long process_pipe_io, (HANDLE proc, char *stdin_data,
+ int stdin_data_len));
+EXTERN_DECL(long process_file_io, (HANDLE proc));
+EXTERN_DECL(void process_cleanup, (HANDLE proc));
+EXTERN_DECL(HANDLE process_wait_for_any, (VOID_DECL));
+EXTERN_DECL(void process_register, (HANDLE proc));
+EXTERN_DECL(HANDLE process_easy, (char** argv, char** env));
+EXTERN_DECL(BOOL process_kill, (HANDLE proc, int signal));
+
+/* support routines */
+EXTERN_DECL(long process_errno, (HANDLE proc));
+EXTERN_DECL(long process_last_err, (HANDLE proc));
+EXTERN_DECL(long process_exit_code, (HANDLE proc));
+EXTERN_DECL(long process_signal, (HANDLE proc));
+EXTERN_DECL(char * process_outbuf, (HANDLE proc));
+EXTERN_DECL(char * process_errbuf, (HANDLE proc));
+EXTERN_DECL(int process_outcnt, (HANDLE proc));
+EXTERN_DECL(int process_errcnt, (HANDLE proc));
+EXTERN_DECL(void process_pipes, (HANDLE proc, int pipes[3]));
+
+#endif
+#endif
diff --git a/w32/include/w32err.h b/w32/include/w32err.h
index 7e9df78..b48dbbe 100644
--- a/w32/include/w32err.h
+++ b/w32/include/w32err.h
@@ -1,10 +1,10 @@
-#ifndef _W32ERR_H_
-#define _W32ERR_H_
-
-#ifndef EXTERN_DECL
-#define EXTERN_DECL(entry, args) entry args
-#endif
-
-EXTERN_DECL(char * map_win32_error_to_string, (DWORD error));
-
-#endif /* !_W32ERR_H */
+#ifndef _W32ERR_H_
+#define _W32ERR_H_
+
+#ifndef EXTERN_DECL
+#define EXTERN_DECL(entry, args) entry args
+#endif
+
+EXTERN_DECL(char * map_win32_error_to_string, (DWORD error));
+
+#endif /* !_W32ERR_H */
diff --git a/w32/pathstuff.c b/w32/pathstuff.c
index e5011f8..c6e8cfe 100644
--- a/w32/pathstuff.c
+++ b/w32/pathstuff.c
@@ -1,219 +1,219 @@
-#include <string.h>
-#include <stdlib.h>
-#include "make.h"
-
-/*
- * Convert delimiter separated path to Canonical format.
- */
-char *
-convert_Path_to_win32(char *Path, char to_delim)
-{
- char *etok; /* token separator for old Path */
- char *p; /* points to element of old Path */
-
- /* is this a multi-element Path ? */
- for (p = Path, etok = strpbrk(p, ":;");
- etok;
- etok = strpbrk(p, ":;"))
- if ((etok - p) == 1) {
- if (*(etok - 1) == ';' ||
- *(etok - 1) == ':') {
- etok[-1] = to_delim;
- etok[0] = to_delim;
- p = ++etok;
- continue; /* ignore empty bucket */
- } else if (etok = strpbrk(etok+1, ":;")) {
- /* found one to count, handle drive letter */
- *etok = to_delim;
- p = ++etok;
- } else
- /* all finished, force abort */
- p += strlen(p);
- } else {
- /* found another one, no drive letter */
- *etok = to_delim;
- p = ++etok;
- }
-
-#if 0
- /* convert to backward slashes */
- for (p = Path, p = strchr(p, '/'); p; p = strchr(p, '/'))
- *p = '\\';
-#endif
- return Path;
-}
-
-/*
- * Convert to forward slashes. Resolve to full pathname optionally
- */
-char *
-w32ify(char *filename, int resolve)
-{
- static char w32_path[FILENAME_MAX];
- char *p;
-
- if (resolve)
- _fullpath(w32_path, filename, sizeof (w32_path));
- else
- strncpy(w32_path, filename, sizeof (w32_path));
-
- for (p = w32_path; p && *p; p++)
- if (*p == '\\')
- *p = '/';
-
- return w32_path;
-}
-
-char *
-getcwd_fs(char* buf, int len)
-{
- char *p;
-
- if (p = getcwd(buf, len)) {
- char *q = w32ify(buf, 0);
- strncpy(buf, q, len);
- }
-
- return p;
-}
-
-#ifdef unused
-/*
- * Convert delimiter separated pathnames (e.g. PATH) or single file pathname
- * (e.g. c:/foo, c:\bar) to NutC format. If we are handed a string that
- * _NutPathToNutc() fails to convert, just return the path we were handed
- * and assume the caller will know what to do with it (It was probably
- * a mistake to try and convert it anyway due to some of the bizarre things
- * that might look like pathnames in makefiles).
- */
-char *
-convert_path_to_nutc(char *path)
-{
- int count; /* count of path elements */
- char *nutc_path; /* new NutC path */
- int nutc_path_len; /* length of buffer to allocate for new path */
- char *pathp; /* pointer to nutc_path used to build it */
- char *etok; /* token separator for old path */
- char *p; /* points to element of old path */
- char sep; /* what flavor of separator used in old path */
- char *rval;
-
- /* is this a multi-element path ? */
- for (p = path, etok = strpbrk(p, ":;"), count = 0;
- etok;
- etok = strpbrk(p, ":;"))
- if ((etok - p) == 1) {
- if (*(etok - 1) == ';' ||
- *(etok - 1) == ':') {
- p = ++etok;
- continue; /* ignore empty bucket */
- } else if (etok = strpbrk(etok+1, ":;"))
- /* found one to count, handle drive letter */
- p = ++etok, count++;
- else
- /* all finished, force abort */
- p += strlen(p);
- } else
- /* found another one, no drive letter */
- p = ++etok, count++;
-
- if (count) {
- count++; /* x1;x2;x3 <- need to count x3 */
-
- /*
- * Hazard a guess on how big the buffer needs to be.
- * We have to convert things like c:/foo to /c=/foo.
- */
- nutc_path_len = strlen(path) + (count*2) + 1;
- nutc_path = xmalloc(nutc_path_len);
- pathp = nutc_path;
- *pathp = '\0';
-
- /*
- * Loop through PATH and convert one elemnt of the path at at
- * a time. Single file pathnames will fail this and fall
- * to the logic below loop.
- */
- for (p = path, etok = strpbrk(p, ":;");
- etok;
- etok = strpbrk(p, ":;")) {
-
- /* don't trip up on device specifiers or empty path slots */
- if ((etok - p) == 1)
- if (*(etok - 1) == ';' ||
- *(etok - 1) == ':') {
- p = ++etok;
- continue;
- } else if ((etok = strpbrk(etok+1, ":;")) == NULL)
- break; /* thing found was a WIN32 pathname */
-
- /* save separator */
- sep = *etok;
-
- /* terminate the current path element -- temporarily */
- *etok = '\0';
-
-#ifdef __NUTC__
- /* convert to NutC format */
- if (_NutPathToNutc(p, pathp, 0) == FALSE) {
- free(nutc_path);
- rval = savestring(path, strlen(path));
- return rval;
- }
-#else
- *pathp++ = '/';
- *pathp++ = p[0];
- *pathp++ = '=';
- *pathp++ = '/';
- strcpy(pathp, &p[2]);
-#endif
-
- pathp += strlen(pathp);
- *pathp++ = ':'; /* use Unix style path separtor for new path */
- *pathp = '\0'; /* make sure we are null terminaed */
-
- /* restore path separator */
- *etok = sep;
-
- /* point p to first char of next path element */
- p = ++etok;
-
- }
- } else {
- nutc_path_len = strlen(path) + 3;
- nutc_path = xmalloc(nutc_path_len);
- pathp = nutc_path;
- *pathp = '\0';
- p = path;
- }
-
- /*
- * OK, here we handle the last element in PATH (e.g. c of a;b;c)
- * or the path was a single filename and will be converted
- * here. Note, testing p here assures that we don't trip up
- * on paths like a;b; which have trailing delimiter followed by
- * nothing.
- */
- if (*p != '\0') {
-#ifdef __NUTC__
- if (_NutPathToNutc(p, pathp, 0) == FALSE) {
- free(nutc_path);
- rval = savestring(path, strlen(path));
- return rval;
- }
-#else
- *pathp++ = '/';
- *pathp++ = p[0];
- *pathp++ = '=';
- *pathp++ = '/';
- strcpy(pathp, &p[2]);
-#endif
- } else
- *(pathp-1) = '\0'; /* we're already done, don't leave trailing : */
-
- rval = savestring(nutc_path, strlen(nutc_path));
- free(nutc_path);
- return rval;
-}
-
-#endif
+#include <string.h>
+#include <stdlib.h>
+#include "make.h"
+
+/*
+ * Convert delimiter separated path to Canonical format.
+ */
+char *
+convert_Path_to_win32(char *Path, char to_delim)
+{
+ char *etok; /* token separator for old Path */
+ char *p; /* points to element of old Path */
+
+ /* is this a multi-element Path ? */
+ for (p = Path, etok = strpbrk(p, ":;");
+ etok;
+ etok = strpbrk(p, ":;"))
+ if ((etok - p) == 1) {
+ if (*(etok - 1) == ';' ||
+ *(etok - 1) == ':') {
+ etok[-1] = to_delim;
+ etok[0] = to_delim;
+ p = ++etok;
+ continue; /* ignore empty bucket */
+ } else if (etok = strpbrk(etok+1, ":;")) {
+ /* found one to count, handle drive letter */
+ *etok = to_delim;
+ p = ++etok;
+ } else
+ /* all finished, force abort */
+ p += strlen(p);
+ } else {
+ /* found another one, no drive letter */
+ *etok = to_delim;
+ p = ++etok;
+ }
+
+#if 0
+ /* convert to backward slashes */
+ for (p = Path, p = strchr(p, '/'); p; p = strchr(p, '/'))
+ *p = '\\';
+#endif
+ return Path;
+}
+
+/*
+ * Convert to forward slashes. Resolve to full pathname optionally
+ */
+char *
+w32ify(char *filename, int resolve)
+{
+ static char w32_path[FILENAME_MAX];
+ char *p;
+
+ if (resolve)
+ _fullpath(w32_path, filename, sizeof (w32_path));
+ else
+ strncpy(w32_path, filename, sizeof (w32_path));
+
+ for (p = w32_path; p && *p; p++)
+ if (*p == '\\')
+ *p = '/';
+
+ return w32_path;
+}
+
+char *
+getcwd_fs(char* buf, int len)
+{
+ char *p;
+
+ if (p = getcwd(buf, len)) {
+ char *q = w32ify(buf, 0);
+ strncpy(buf, q, len);
+ }
+
+ return p;
+}
+
+#ifdef unused
+/*
+ * Convert delimiter separated pathnames (e.g. PATH) or single file pathname
+ * (e.g. c:/foo, c:\bar) to NutC format. If we are handed a string that
+ * _NutPathToNutc() fails to convert, just return the path we were handed
+ * and assume the caller will know what to do with it (It was probably
+ * a mistake to try and convert it anyway due to some of the bizarre things
+ * that might look like pathnames in makefiles).
+ */
+char *
+convert_path_to_nutc(char *path)
+{
+ int count; /* count of path elements */
+ char *nutc_path; /* new NutC path */
+ int nutc_path_len; /* length of buffer to allocate for new path */
+ char *pathp; /* pointer to nutc_path used to build it */
+ char *etok; /* token separator for old path */
+ char *p; /* points to element of old path */
+ char sep; /* what flavor of separator used in old path */
+ char *rval;
+
+ /* is this a multi-element path ? */
+ for (p = path, etok = strpbrk(p, ":;"), count = 0;
+ etok;
+ etok = strpbrk(p, ":;"))
+ if ((etok - p) == 1) {
+ if (*(etok - 1) == ';' ||
+ *(etok - 1) == ':') {
+ p = ++etok;
+ continue; /* ignore empty bucket */
+ } else if (etok = strpbrk(etok+1, ":;"))
+ /* found one to count, handle drive letter */
+ p = ++etok, count++;
+ else
+ /* all finished, force abort */
+ p += strlen(p);
+ } else
+ /* found another one, no drive letter */
+ p = ++etok, count++;
+
+ if (count) {
+ count++; /* x1;x2;x3 <- need to count x3 */
+
+ /*
+ * Hazard a guess on how big the buffer needs to be.
+ * We have to convert things like c:/foo to /c=/foo.
+ */
+ nutc_path_len = strlen(path) + (count*2) + 1;
+ nutc_path = xmalloc(nutc_path_len);
+ pathp = nutc_path;
+ *pathp = '\0';
+
+ /*
+ * Loop through PATH and convert one elemnt of the path at at
+ * a time. Single file pathnames will fail this and fall
+ * to the logic below loop.
+ */
+ for (p = path, etok = strpbrk(p, ":;");
+ etok;
+ etok = strpbrk(p, ":;")) {
+
+ /* don't trip up on device specifiers or empty path slots */
+ if ((etok - p) == 1)
+ if (*(etok - 1) == ';' ||
+ *(etok - 1) == ':') {
+ p = ++etok;
+ continue;
+ } else if ((etok = strpbrk(etok+1, ":;")) == NULL)
+ break; /* thing found was a WIN32 pathname */
+
+ /* save separator */
+ sep = *etok;
+
+ /* terminate the current path element -- temporarily */
+ *etok = '\0';
+
+#ifdef __NUTC__
+ /* convert to NutC format */
+ if (_NutPathToNutc(p, pathp, 0) == FALSE) {
+ free(nutc_path);
+ rval = savestring(path, strlen(path));
+ return rval;
+ }
+#else
+ *pathp++ = '/';
+ *pathp++ = p[0];
+ *pathp++ = '=';
+ *pathp++ = '/';
+ strcpy(pathp, &p[2]);
+#endif
+
+ pathp += strlen(pathp);
+ *pathp++ = ':'; /* use Unix style path separtor for new path */
+ *pathp = '\0'; /* make sure we are null terminaed */
+
+ /* restore path separator */
+ *etok = sep;
+
+ /* point p to first char of next path element */
+ p = ++etok;
+
+ }
+ } else {
+ nutc_path_len = strlen(path) + 3;
+ nutc_path = xmalloc(nutc_path_len);
+ pathp = nutc_path;
+ *pathp = '\0';
+ p = path;
+ }
+
+ /*
+ * OK, here we handle the last element in PATH (e.g. c of a;b;c)
+ * or the path was a single filename and will be converted
+ * here. Note, testing p here assures that we don't trip up
+ * on paths like a;b; which have trailing delimiter followed by
+ * nothing.
+ */
+ if (*p != '\0') {
+#ifdef __NUTC__
+ if (_NutPathToNutc(p, pathp, 0) == FALSE) {
+ free(nutc_path);
+ rval = savestring(path, strlen(path));
+ return rval;
+ }
+#else
+ *pathp++ = '/';
+ *pathp++ = p[0];
+ *pathp++ = '=';
+ *pathp++ = '/';
+ strcpy(pathp, &p[2]);
+#endif
+ } else
+ *(pathp-1) = '\0'; /* we're already done, don't leave trailing : */
+
+ rval = savestring(nutc_path, strlen(nutc_path));
+ free(nutc_path);
+ return rval;
+}
+
+#endif
diff --git a/w32/subproc/NMakefile b/w32/subproc/NMakefile
index 3d44b82..0d2ca89 100644
--- a/w32/subproc/NMakefile
+++ b/w32/subproc/NMakefile
@@ -1,59 +1,59 @@
-# NOTE: If you have no `make' program at all to process this makefile, run
-# `build.bat' instead.
-#
-# Copyright (C) 1988, 89, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc
-# This file is part of GNU Make.
-#
-# GNU Make is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# GNU Make 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Make; see the file COPYING. If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-#
-# NMakefile for GNU Make (subproc library)
-#
-LIB = lib
-CC = cl
-
-OUTDIR=.
-MAKEFILE=NMakefile
-
-CFLAGS_any = /nologo /MT /W3 /GX /Z7 /YX /D WIN32 /D _WINDOWS -I. -I../include
-CFLAGS_debug = $(CFLAGS_any) /Od /D _DEBUG /FR.\WinDebug\ /Fp.\WinDebug\subproc.pch /Fo.\WinDebug/
-CFLAGS_release = $(CFLAGS_any) /O2 /FR.\WinRel\ /Fp.\WinRel\subproc.pch /Fo.\WinRel/
-
-all: Release Debug
-
-Release:
- $(MAKE) /f $(MAKEFILE) OUTDIR=WinRel CFLAGS="$(CFLAGS_release)" WinRel/subproc.lib
-Debug:
- $(MAKE) /f $(MAKEFILE) OUTDIR=WinDebug CFLAGS="$(CFLAGS_debug)" WinDebug/subproc.lib
-
-clean:
- rmdir /s /q WinRel WinDebug
-
-$(OUTDIR):
- if not exist .\$@\nul mkdir .\$@
-
-OBJS = $(OUTDIR)/misc.obj $(OUTDIR)/w32err.obj $(OUTDIR)/sub_proc.obj
-
-$(OUTDIR)/subproc.lib: $(OUTDIR) $(OBJS)
- $(LIB) -out:$@ @<<
- $(OBJS)
-<<
-
-.c{$(OUTDIR)}.obj:
- $(CC) $(CFLAGS) /c $<
-
-$(OUTDIR)/misc.obj: misc.c proc.h
-$(OUTDIR)/sub_proc.obj: sub_proc.c ../include/sub_proc.h ../include/w32err.h proc.h
-$(OUTDIR)/w32err.obj: w32err.c ../include/w32err.h
+# NOTE: If you have no `make' program at all to process this makefile, run
+# `build.bat' instead.
+#
+# Copyright (C) 1988, 89, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc
+# This file is part of GNU Make.
+#
+# GNU Make is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Make 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Make; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+#
+# NMakefile for GNU Make (subproc library)
+#
+LIB = lib
+CC = cl
+
+OUTDIR=.
+MAKEFILE=NMakefile
+
+CFLAGS_any = /nologo /MT /W3 /GX /Z7 /YX /D WIN32 /D _WINDOWS -I. -I../include
+CFLAGS_debug = $(CFLAGS_any) /Od /D _DEBUG /FR.\WinDebug\ /Fp.\WinDebug\subproc.pch /Fo.\WinDebug/
+CFLAGS_release = $(CFLAGS_any) /O2 /FR.\WinRel\ /Fp.\WinRel\subproc.pch /Fo.\WinRel/
+
+all: Release Debug
+
+Release:
+ $(MAKE) /f $(MAKEFILE) OUTDIR=WinRel CFLAGS="$(CFLAGS_release)" WinRel/subproc.lib
+Debug:
+ $(MAKE) /f $(MAKEFILE) OUTDIR=WinDebug CFLAGS="$(CFLAGS_debug)" WinDebug/subproc.lib
+
+clean:
+ rmdir /s /q WinRel WinDebug
+
+$(OUTDIR):
+ if not exist .\$@\nul mkdir .\$@
+
+OBJS = $(OUTDIR)/misc.obj $(OUTDIR)/w32err.obj $(OUTDIR)/sub_proc.obj
+
+$(OUTDIR)/subproc.lib: $(OUTDIR) $(OBJS)
+ $(LIB) -out:$@ @<<
+ $(OBJS)
+<<
+
+.c{$(OUTDIR)}.obj:
+ $(CC) $(CFLAGS) /c $<
+
+$(OUTDIR)/misc.obj: misc.c proc.h
+$(OUTDIR)/sub_proc.obj: sub_proc.c ../include/sub_proc.h ../include/w32err.h proc.h
+$(OUTDIR)/w32err.obj: w32err.c ../include/w32err.h
diff --git a/w32/subproc/build.bat b/w32/subproc/build.bat
index 45231bf..bb35615 100644
--- a/w32/subproc/build.bat
+++ b/w32/subproc/build.bat
@@ -1,10 +1,10 @@
-if not exist .\WinDebug\nul mkdir .\WinDebug
-cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /D WIN32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c misc.c
-cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /D WIN32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c sub_proc.c
-cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /D WIN32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c w32err.c
-lib.exe /NOLOGO /OUT:.\WinDebug\subproc.lib .\WinDebug/misc.obj .\WinDebug/sub_proc.obj .\WinDebug/w32err.obj
-if not exist .\WinRel\nul mkdir .\WinRel
-cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /D WIN32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c misc.c
-cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /D WIN32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c sub_proc.c
-cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /D WIN32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c w32err.c
-lib.exe /NOLOGO /OUT:.\WinRel\subproc.lib .\WinRel/misc.obj .\WinRel/sub_proc.obj .\WinRel/w32err.obj
+if not exist .\WinDebug\nul mkdir .\WinDebug
+cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /D WIN32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c misc.c
+cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /D WIN32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c sub_proc.c
+cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /D WIN32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c w32err.c
+lib.exe /NOLOGO /OUT:.\WinDebug\subproc.lib .\WinDebug/misc.obj .\WinDebug/sub_proc.obj .\WinDebug/w32err.obj
+if not exist .\WinRel\nul mkdir .\WinRel
+cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /D WIN32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c misc.c
+cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /D WIN32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c sub_proc.c
+cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /D WIN32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c w32err.c
+lib.exe /NOLOGO /OUT:.\WinRel\subproc.lib .\WinRel/misc.obj .\WinRel/sub_proc.obj .\WinRel/w32err.obj
diff --git a/w32/subproc/misc.c b/w32/subproc/misc.c
index 23b6124..2fd66ab 100644
--- a/w32/subproc/misc.c
+++ b/w32/subproc/misc.c
@@ -1,63 +1,63 @@
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <windows.h>
-#include "proc.h"
-
-
-/*
- * Description: Convert a NULL string terminated UNIX environment block to
- * an environment block suitable for a win32 system call
- *
- * Returns: TRUE= success, FALSE=fail
- *
- * Notes/Dependencies: the environment block is sorted in case-insensitive
- * order, is double-null terminated, and is a char *, not a char **
- */
-int _cdecl compare(const void *a1, const void *a2)
-{
- return _stricoll(*((char**)a1),*((char**)a2));
-}
-bool_t
-arr2envblk(char **arr, char **envblk_out)
-{
- char **tmp;
- int size_needed;
- int arrcnt;
- char *ptr;
-
- arrcnt = 0;
- while (arr[arrcnt]) {
- arrcnt++;
- }
-
- tmp = (char**) calloc(arrcnt + 1, sizeof(char *));
- if (!tmp) {
- return FALSE;
- }
-
- arrcnt = 0;
- size_needed = 0;
- while (arr[arrcnt]) {
- tmp[arrcnt] = arr[arrcnt];
- size_needed += strlen(arr[arrcnt]) + 1;
- arrcnt++;
- }
- size_needed++;
-
- qsort((void *) tmp, (size_t) arrcnt, sizeof (char*), compare);
-
- ptr = *envblk_out = calloc(size_needed, 1);
- if (!ptr) {
- free(tmp);
- return FALSE;
- }
-
- arrcnt = 0;
- while (tmp[arrcnt]) {
- strcpy(ptr, tmp[arrcnt]);
- ptr += strlen(tmp[arrcnt]) + 1;
- arrcnt++;
- }
- return TRUE;
-}
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+#include "proc.h"
+
+
+/*
+ * Description: Convert a NULL string terminated UNIX environment block to
+ * an environment block suitable for a win32 system call
+ *
+ * Returns: TRUE= success, FALSE=fail
+ *
+ * Notes/Dependencies: the environment block is sorted in case-insensitive
+ * order, is double-null terminated, and is a char *, not a char **
+ */
+int _cdecl compare(const void *a1, const void *a2)
+{
+ return _stricoll(*((char**)a1),*((char**)a2));
+}
+bool_t
+arr2envblk(char **arr, char **envblk_out)
+{
+ char **tmp;
+ int size_needed;
+ int arrcnt;
+ char *ptr;
+
+ arrcnt = 0;
+ while (arr[arrcnt]) {
+ arrcnt++;
+ }
+
+ tmp = (char**) calloc(arrcnt + 1, sizeof(char *));
+ if (!tmp) {
+ return FALSE;
+ }
+
+ arrcnt = 0;
+ size_needed = 0;
+ while (arr[arrcnt]) {
+ tmp[arrcnt] = arr[arrcnt];
+ size_needed += strlen(arr[arrcnt]) + 1;
+ arrcnt++;
+ }
+ size_needed++;
+
+ qsort((void *) tmp, (size_t) arrcnt, sizeof (char*), compare);
+
+ ptr = *envblk_out = calloc(size_needed, 1);
+ if (!ptr) {
+ free(tmp);
+ return FALSE;
+ }
+
+ arrcnt = 0;
+ while (tmp[arrcnt]) {
+ strcpy(ptr, tmp[arrcnt]);
+ ptr += strlen(tmp[arrcnt]) + 1;
+ arrcnt++;
+ }
+ return TRUE;
+}
diff --git a/w32/subproc/proc.h b/w32/subproc/proc.h
index ce7a14f..249ffd8 100644
--- a/w32/subproc/proc.h
+++ b/w32/subproc/proc.h
@@ -1,13 +1,13 @@
-#ifndef _PROC_H
-#define _PROC_H
-
-typedef int bool_t;
-
-#define E_SCALL 101
-#define E_IO 102
-#define E_NO_MEM 103
-#define E_FORK 104
-
-extern bool_t arr2envblk(char **arr, char **envblk_out);
-
-#endif
+#ifndef _PROC_H
+#define _PROC_H
+
+typedef int bool_t;
+
+#define E_SCALL 101
+#define E_IO 102
+#define E_NO_MEM 103
+#define E_FORK 104
+
+extern bool_t arr2envblk(char **arr, char **envblk_out);
+
+#endif
diff --git a/w32/subproc/sub_proc.c b/w32/subproc/sub_proc.c
index 52cd9d7..4f1ded9 100644
--- a/w32/subproc/sub_proc.c
+++ b/w32/subproc/sub_proc.c
@@ -1,1100 +1,1100 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <process.h> /* for msvc _beginthreadex, _endthreadex */
-#include <windows.h>
-
-#include "sub_proc.h"
-#include "proc.h"
-#include "w32err.h"
-
-static char *make_command_line( char *shell_name, char *exec_path, char **argv);
-
-typedef struct sub_process_t {
- int sv_stdin[2];
- int sv_stdout[2];
- int sv_stderr[2];
- int using_pipes;
- char *inp;
- DWORD incnt;
- char * volatile outp;
- volatile DWORD outcnt;
- char * volatile errp;
- volatile DWORD errcnt;
- int pid;
- int exit_code;
- int signal;
- long last_err;
- long lerrno;
-} sub_process;
-
-/* keep track of children so we can implement a waitpid-like routine */
-static sub_process *proc_array[256];
-static int proc_index = 0;
-static int fake_exits_pending = 0;
-
-/*
- * When a process has been waited for, adjust the wait state
- * array so that we don't wait for it again
- */
-static void
-process_adjust_wait_state(sub_process* pproc)
-{
- int i;
-
- if (!proc_index)
- return;
-
- for (i = 0; i < proc_index; i++)
- if (proc_array[i]->pid == pproc->pid)
- break;
-
- if (i < proc_index) {
- proc_index--;
- if (i != proc_index)
- memmove(&proc_array[i], &proc_array[i+1],
- (proc_index-i) * sizeof(sub_process*));
- proc_array[proc_index] = NULL;
- }
-}
-
-/*
- * Waits for any of the registered child processes to finish.
- */
-static sub_process *
-process_wait_for_any_private(void)
-{
- HANDLE handles[256];
- DWORD retval, which;
- int i;
-
- if (!proc_index)
- return NULL;
-
- /* build array of handles to wait for */
- for (i = 0; i < proc_index; i++) {
- handles[i] = (HANDLE) proc_array[i]->pid;
-
- if (fake_exits_pending && proc_array[i]->exit_code)
- break;
- }
-
- /* wait for someone to exit */
- if (!fake_exits_pending) {
- retval = WaitForMultipleObjects(proc_index, handles, FALSE, INFINITE);
- which = retval - WAIT_OBJECT_0;
- } else {
- fake_exits_pending--;
- retval = !WAIT_FAILED;
- which = i;
- }
-
- /* return pointer to process */
- if (retval != WAIT_FAILED) {
- sub_process* pproc = proc_array[which];
- process_adjust_wait_state(pproc);
- return pproc;
- } else
- return NULL;
-}
-
-/*
- * Terminate a process.
- */
-BOOL
-process_kill(HANDLE proc, int signal)
-{
- sub_process* pproc = (sub_process*) proc;
- pproc->signal = signal;
- return (TerminateProcess((HANDLE) pproc->pid, signal));
-}
-
-/*
- * Use this function to register processes you wish to wait for by
- * calling process_file_io(NULL) or process_wait_any(). This must be done
- * because it is possible for callers of this library to reuse the same
- * handle for multiple processes launches :-(
- */
-void
-process_register(HANDLE proc)
-{
- proc_array[proc_index++] = (sub_process *) proc;
-}
-
-/*
- * Public function which works kind of like waitpid(). Wait for any
- * of the children to die and return results. To call this function,
- * you must do 1 of things:
- *
- * x = process_easy(...);
- *
- * or
- *
- * x = process_init_fd();
- * process_register(x);
- *
- * or
- *
- * x = process_init();
- * process_register(x);
- *
- * You must NOT then call process_pipe_io() because this function is
- * not capable of handling automatic notification of any child
- * death.
- */
-
-HANDLE
-process_wait_for_any(void)
-{
- sub_process* pproc = process_wait_for_any_private();
-
- if (!pproc)
- return NULL;
- else {
- /*
- * Ouch! can't tell caller if this fails directly. Caller
- * will have to use process_last_err()
- */
- (void) process_file_io(pproc);
- return ((HANDLE) pproc);
- }
-}
-
-long
-process_errno(HANDLE proc)
-{
- return (((sub_process *)proc)->lerrno);
-}
-
-long
-process_signal(HANDLE proc)
-{
- return (((sub_process *)proc)->signal);
-}
-
- long
-process_last_err(HANDLE proc)
-{
- return (((sub_process *)proc)->last_err);
-}
-
- long
-process_exit_code(HANDLE proc)
-{
- return (((sub_process *)proc)->exit_code);
-}
-
- char *
-process_outbuf(HANDLE proc)
-{
- return (((sub_process *)proc)->outp);
-}
-
- char *
-process_errbuf(HANDLE proc)
-{
- return (((sub_process *)proc)->errp);
-}
-
- int
-process_outcnt(HANDLE proc)
-{
- return (((sub_process *)proc)->outcnt);
-}
-
- int
-process_errcnt(HANDLE proc)
-{
- return (((sub_process *)proc)->errcnt);
-}
-
- void
-process_pipes(HANDLE proc, int pipes[3])
-{
- pipes[0] = ((sub_process *)proc)->sv_stdin[0];
- pipes[1] = ((sub_process *)proc)->sv_stdout[0];
- pipes[2] = ((sub_process *)proc)->sv_stderr[0];
- return;
-}
-
-
- HANDLE
-process_init()
-{
- sub_process *pproc;
- /*
- * open file descriptors for attaching stdin/stdout/sterr
- */
- HANDLE stdin_pipes[2];
- HANDLE stdout_pipes[2];
- HANDLE stderr_pipes[2];
- SECURITY_ATTRIBUTES inherit;
- BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
-
- pproc = malloc(sizeof(*pproc));
- memset(pproc, 0, sizeof(*pproc));
-
- /* We can't use NULL for lpSecurityDescriptor because that
- uses the default security descriptor of the calling process.
- Instead we use a security descriptor with no DACL. This
- allows nonrestricted access to the associated objects. */
-
- if (!InitializeSecurityDescriptor((PSECURITY_DESCRIPTOR)(&sd),
- SECURITY_DESCRIPTOR_REVISION)) {
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- return((HANDLE)pproc);
- }
-
- inherit.nLength = sizeof(inherit);
- inherit.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(&sd);
- inherit.bInheritHandle = TRUE;
-
- // By convention, parent gets pipe[0], and child gets pipe[1]
- // This means the READ side of stdin pipe goes into pipe[1]
- // and the WRITE side of the stdout and stderr pipes go into pipe[1]
- if (CreatePipe( &stdin_pipes[1], &stdin_pipes[0], &inherit, 0) == FALSE ||
- CreatePipe( &stdout_pipes[0], &stdout_pipes[1], &inherit, 0) == FALSE ||
- CreatePipe( &stderr_pipes[0], &stderr_pipes[1], &inherit, 0) == FALSE) {
-
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- return((HANDLE)pproc);
- }
-
- //
- // Mark the parent sides of the pipes as non-inheritable
- //
- if (SetHandleInformation(stdin_pipes[0],
- HANDLE_FLAG_INHERIT, 0) == FALSE ||
- SetHandleInformation(stdout_pipes[0],
- HANDLE_FLAG_INHERIT, 0) == FALSE ||
- SetHandleInformation(stderr_pipes[0],
- HANDLE_FLAG_INHERIT, 0) == FALSE) {
-
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- return((HANDLE)pproc);
- }
- pproc->sv_stdin[0] = (int) stdin_pipes[0];
- pproc->sv_stdin[1] = (int) stdin_pipes[1];
- pproc->sv_stdout[0] = (int) stdout_pipes[0];
- pproc->sv_stdout[1] = (int) stdout_pipes[1];
- pproc->sv_stderr[0] = (int) stderr_pipes[0];
- pproc->sv_stderr[1] = (int) stderr_pipes[1];
-
- pproc->using_pipes = 1;
-
- pproc->lerrno = 0;
-
- return((HANDLE)pproc);
-}
-
-
- HANDLE
-process_init_fd(HANDLE stdinh, HANDLE stdouth, HANDLE stderrh)
-{
- sub_process *pproc;
-
- pproc = malloc(sizeof(*pproc));
- memset(pproc, 0, sizeof(*pproc));
-
- /*
- * Just pass the provided file handles to the 'child side' of the
- * pipe, bypassing pipes altogether.
- */
- pproc->sv_stdin[1] = (int) stdinh;
- pproc->sv_stdout[1] = (int) stdouth;
- pproc->sv_stderr[1] = (int) stderrh;
-
- pproc->last_err = pproc->lerrno = 0;
-
- return((HANDLE)pproc);
-}
-
-
-static HANDLE
-find_file(char *exec_path, LPOFSTRUCT file_info)
-{
- HANDLE exec_handle;
- char *fname;
- char *ext;
-
- if ((exec_handle = (HANDLE)OpenFile(exec_path, file_info,
- OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
- return(exec_handle);
- }
-
- fname = malloc(strlen(exec_path) + 5);
- strcpy(fname, exec_path);
- ext = fname + strlen(fname);
- strcpy(ext, ".exe");
- if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
- OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
- free(fname);
- return(exec_handle);
- }
-
- strcpy(ext, ".bat");
- if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
- OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
- free(fname);
- return(exec_handle);
- }
-
- strcpy(ext, ".com");
- if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
- OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
- free(fname);
- return(exec_handle);
- }
-
- free(fname);
- return(exec_handle);
-}
-
-
-/*
- * Description: Create the child process to be helped
- *
- * Returns:
- *
- * Notes/Dependencies:
- */
-long
-process_begin(
- HANDLE proc,
- char **argv,
- char **envp,
- char *exec_path,
- char *as_user)
-{
- sub_process *pproc = (sub_process *)proc;
- char *shell_name = 0;
- int file_not_found=0;
- HANDLE exec_handle;
- char buf[256];
- DWORD bytes_returned;
- DWORD flags;
- char *command_line;
- STARTUPINFO startInfo;
- PROCESS_INFORMATION procInfo;
- char *envblk=NULL;
- OFSTRUCT file_info;
-
-
- /*
- * Shell script detection... if the exec_path starts with #! then
- * we want to exec shell-script-name exec-path, not just exec-path
- * NT doesn't recognize #!/bin/sh or #!/etc/Tivoli/bin/perl. We do not
- * hard-code the path to the shell or perl or whatever: Instead, we
- * assume it's in the path somewhere (generally, the NT tools
- * bin directory)
- * We use OpenFile here because it is capable of searching the Path.
- */
-
- exec_handle = find_file(exec_path, &file_info);
-
- /*
- * If we couldn't open the file, just assume that Win32 will be able
- * to find and execute it.
- */
- if (exec_handle == (HANDLE)HFILE_ERROR) {
- file_not_found++;
- }
- else {
- /* Attempt to read the first line of the file */
- if (ReadFile( exec_handle,
- buf, sizeof(buf) - 1, /* leave room for trailing NULL */
- &bytes_returned, 0) == FALSE || bytes_returned < 2) {
-
- pproc->last_err = GetLastError();
- pproc->lerrno = E_IO;
- CloseHandle(exec_handle);
- return(-1);
- }
- if (buf[0] == '#' && buf[1] == '!') {
- /*
- * This is a shell script... Change the command line from
- * exec_path args to shell_name exec_path args
- */
- char *p;
-
- /* Make sure buf is NULL terminated */
- buf[bytes_returned] = 0;
- /*
- * Depending on the file system type, etc. the first line
- * of the shell script may end with newline or newline-carriage-return
- * Whatever it ends with, cut it off.
- */
- p= strchr(buf, '\n');
- if (p)
- *p = 0;
- p = strchr(buf, '\r');
- if (p)
- *p = 0;
-
- /*
- * Find base name of shell
- */
- shell_name = strrchr( buf, '/');
- if (shell_name) {
- shell_name++;
- } else {
- shell_name = &buf[2];/* skipping "#!" */
- }
-
- }
- CloseHandle(exec_handle);
- }
-
- flags = 0;
-
- if (file_not_found)
- command_line = make_command_line( shell_name, exec_path, argv);
- else
- command_line = make_command_line( shell_name, file_info.szPathName,
- argv);
-
- if ( command_line == NULL ) {
- pproc->last_err = 0;
- pproc->lerrno = E_NO_MEM;
- return(-1);
- }
-
- if (envp) {
- if (arr2envblk(envp, &envblk) ==FALSE) {
- pproc->last_err = 0;
- pproc->lerrno = E_NO_MEM;
- free( command_line );
- return(-1);
- }
- }
-
- if ((shell_name) || (file_not_found)) {
- exec_path = 0; /* Search for the program in %Path% */
- } else {
- exec_path = file_info.szPathName;
- }
-
- /*
- * Set up inherited stdin, stdout, stderr for child
- */
- GetStartupInfo(&startInfo);
- startInfo.dwFlags = STARTF_USESTDHANDLES;
- startInfo.lpReserved = 0;
- startInfo.cbReserved2 = 0;
- startInfo.lpReserved2 = 0;
- startInfo.lpTitle = shell_name ? shell_name : exec_path;
- startInfo.hStdInput = (HANDLE)pproc->sv_stdin[1];
- startInfo.hStdOutput = (HANDLE)pproc->sv_stdout[1];
- startInfo.hStdError = (HANDLE)pproc->sv_stderr[1];
-
- /*
- * See if we need to setuid to a different user.
- */
- if (as_user) {
- return -1;
- }
-
- if (as_user) {
- return -1;
- } else {
- if (CreateProcess(
- exec_path,
- command_line,
- NULL,
- 0, /* default security attributes for thread */
- TRUE, /* inherit handles (e.g. helper pipes, oserv socket) */
- flags,
- envblk,
- 0, /* default starting directory */
- &startInfo,
- &procInfo) == FALSE) {
-
- pproc->last_err = GetLastError();
- pproc->lerrno = E_FORK;
- fprintf(stderr, "process_begin: CreateProcess(%s, %s, ...) failed.\n", exec_path, command_line);
- free( command_line );
- return(-1);
- }
- }
-
- pproc->pid = (int)procInfo.hProcess;
- /* Close the thread handle -- we'll just watch the process */
- CloseHandle(procInfo.hThread);
-
- /* Close the halves of the pipes we don't need */
- if (pproc->sv_stdin) {
- CloseHandle((HANDLE)pproc->sv_stdin[1]);
- (HANDLE)pproc->sv_stdin[1] = 0;
- }
- if (pproc->sv_stdout) {
- CloseHandle((HANDLE)pproc->sv_stdout[1]);
- (HANDLE)pproc->sv_stdout[1] = 0;
- }
- if (pproc->sv_stderr) {
- CloseHandle((HANDLE)pproc->sv_stderr[1]);
- (HANDLE)pproc->sv_stderr[1] = 0;
- }
-
- free( command_line );
- pproc->lerrno=0;
- return 0;
-}
-
-
-
-static DWORD
-proc_stdin_thread(sub_process *pproc)
-{
- DWORD in_done;
- for (;;) {
- if (WriteFile( (HANDLE) pproc->sv_stdin[0], pproc->inp, pproc->incnt,
- &in_done, NULL) == FALSE)
- _endthreadex(0);
- // This if should never be true for anonymous pipes, but gives
- // us a chance to change I/O mechanisms later
- if (in_done < pproc->incnt) {
- pproc->incnt -= in_done;
- pproc->inp += in_done;
- } else {
- _endthreadex(0);
- }
- }
- return 0; // for compiler warnings only.. not reached
-}
-
-static DWORD
-proc_stdout_thread(sub_process *pproc)
-{
- DWORD bufsize = 1024;
- char c;
- DWORD nread;
- pproc->outp = malloc(bufsize);
- if (pproc->outp == NULL)
- _endthreadex(0);
- pproc->outcnt = 0;
-
- for (;;) {
- if (ReadFile( (HANDLE)pproc->sv_stdout[0], &c, 1, &nread, NULL)
- == FALSE) {
-/* map_win32_error_to_string(GetLastError());*/
- _endthreadex(0);
- }
- if (nread == 0)
- _endthreadex(0);
- if (pproc->outcnt + nread > bufsize) {
- bufsize += nread + 512;
- pproc->outp = realloc(pproc->outp, bufsize);
- if (pproc->outp == NULL) {
- pproc->outcnt = 0;
- _endthreadex(0);
- }
- }
- pproc->outp[pproc->outcnt++] = c;
- }
- return 0;
-}
-
-static DWORD
-proc_stderr_thread(sub_process *pproc)
-{
- DWORD bufsize = 1024;
- char c;
- DWORD nread;
- pproc->errp = malloc(bufsize);
- if (pproc->errp == NULL)
- _endthreadex(0);
- pproc->errcnt = 0;
-
- for (;;) {
- if (ReadFile( (HANDLE)pproc->sv_stderr[0], &c, 1, &nread, NULL) == FALSE) {
- map_win32_error_to_string(GetLastError());
- _endthreadex(0);
- }
- if (nread == 0)
- _endthreadex(0);
- if (pproc->errcnt + nread > bufsize) {
- bufsize += nread + 512;
- pproc->errp = realloc(pproc->errp, bufsize);
- if (pproc->errp == NULL) {
- pproc->errcnt = 0;
- _endthreadex(0);
- }
- }
- pproc->errp[pproc->errcnt++] = c;
- }
- return 0;
-}
-
-
-/*
- * Purpose: collects output from child process and returns results
- *
- * Description:
- *
- * Returns:
- *
- * Notes/Dependencies:
- */
- long
-process_pipe_io(
- HANDLE proc,
- char *stdin_data,
- int stdin_data_len)
-{
- sub_process *pproc = (sub_process *)proc;
- bool_t stdin_eof = FALSE, stdout_eof = FALSE, stderr_eof = FALSE;
- HANDLE childhand = (HANDLE) pproc->pid;
- HANDLE tStdin, tStdout, tStderr;
- DWORD dwStdin, dwStdout, dwStderr;
- HANDLE wait_list[4];
- DWORD wait_count;
- DWORD wait_return;
- HANDLE ready_hand;
- bool_t child_dead = FALSE;
-
-
- /*
- * Create stdin thread, if needed
- */
- pproc->inp = stdin_data;
- pproc->incnt = stdin_data_len;
- if (!pproc->inp) {
- stdin_eof = TRUE;
- CloseHandle((HANDLE)pproc->sv_stdin[0]);
- (HANDLE)pproc->sv_stdin[0] = 0;
- } else {
- tStdin = (HANDLE) _beginthreadex( 0, 1024,
- (unsigned (__stdcall *) (void *))proc_stdin_thread, pproc, 0,
- (unsigned int *) &dwStdin);
- if (tStdin == 0) {
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- goto done;
- }
- }
-
- /*
- * Assume child will produce stdout and stderr
- */
- tStdout = (HANDLE) _beginthreadex( 0, 1024,
- (unsigned (__stdcall *) (void *))proc_stdout_thread, pproc, 0,
- (unsigned int *) &dwStdout);
- tStderr = (HANDLE) _beginthreadex( 0, 1024,
- (unsigned (__stdcall *) (void *))proc_stderr_thread, pproc, 0,
- (unsigned int *) &dwStderr);
-
- if (tStdout == 0 || tStderr == 0) {
-
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- goto done;
- }
-
-
- /*
- * Wait for all I/O to finish and for the child process to exit
- */
-
- while (!stdin_eof || !stdout_eof || !stderr_eof || !child_dead) {
- wait_count = 0;
- if (!stdin_eof) {
- wait_list[wait_count++] = tStdin;
- }
- if (!stdout_eof) {
- wait_list[wait_count++] = tStdout;
- }
- if (!stderr_eof) {
- wait_list[wait_count++] = tStderr;
- }
- if (!child_dead) {
- wait_list[wait_count++] = childhand;
- }
-
- wait_return = WaitForMultipleObjects(wait_count, wait_list,
- FALSE, /* don't wait for all: one ready will do */
- child_dead? 1000 :INFINITE); /* after the child dies, subthreads have
- one second to collect all remaining output */
-
- if (wait_return == WAIT_FAILED) {
-/* map_win32_error_to_string(GetLastError());*/
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- goto done;
- }
-
- ready_hand = wait_list[wait_return - WAIT_OBJECT_0];
-
- if (ready_hand == tStdin) {
- CloseHandle((HANDLE)pproc->sv_stdin[0]);
- (HANDLE)pproc->sv_stdin[0] = 0;
- CloseHandle(tStdin);
- tStdin = 0;
- stdin_eof = TRUE;
-
- } else if (ready_hand == tStdout) {
-
- CloseHandle((HANDLE)pproc->sv_stdout[0]);
- (HANDLE)pproc->sv_stdout[0] = 0;
- CloseHandle(tStdout);
- tStdout = 0;
- stdout_eof = TRUE;
-
- } else if (ready_hand == tStderr) {
-
- CloseHandle((HANDLE)pproc->sv_stderr[0]);
- (HANDLE)pproc->sv_stderr[0] = 0;
- CloseHandle(tStderr);
- tStderr = 0;
- stderr_eof = TRUE;
-
- } else if (ready_hand == childhand) {
-
- if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) {
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- goto done;
- }
- child_dead = TRUE;
-
- } else {
-
- /* ?? Got back a handle we didn't query ?? */
- pproc->last_err = 0;
- pproc->lerrno = E_FAIL;
- goto done;
- }
- }
-
- done:
- if (tStdin != 0)
- CloseHandle(tStdin);
- if (tStdout != 0)
- CloseHandle(tStdout);
- if (tStderr != 0)
- CloseHandle(tStderr);
-
- if (pproc->lerrno)
- return(-1);
- else
- return(0);
-
-}
-
-/*
- * Purpose: collects output from child process and returns results
- *
- * Description:
- *
- * Returns:
- *
- * Notes/Dependencies:
- */
- long
-process_file_io(
- HANDLE proc)
-{
- sub_process *pproc;
- HANDLE childhand;
- DWORD wait_return;
-
- if (proc == NULL)
- pproc = process_wait_for_any_private();
- else
- pproc = (sub_process *)proc;
-
- /* some sort of internal error */
- if (!pproc)
- return -1;
-
- childhand = (HANDLE) pproc->pid;
-
- /*
- * This function is poorly named, and could also be used just to wait
- * for child death if you're doing your own pipe I/O. If that is
- * the case, close the pipe handles here.
- */
- if (pproc->sv_stdin[0]) {
- CloseHandle((HANDLE)pproc->sv_stdin[0]);
- pproc->sv_stdin[0] = 0;
- }
- if (pproc->sv_stdout[0]) {
- CloseHandle((HANDLE)pproc->sv_stdout[0]);
- pproc->sv_stdout[0] = 0;
- }
- if (pproc->sv_stderr[0]) {
- CloseHandle((HANDLE)pproc->sv_stderr[0]);
- pproc->sv_stderr[0] = 0;
- }
-
- /*
- * Wait for the child process to exit
- */
-
- wait_return = WaitForSingleObject(childhand, INFINITE);
-
- if (wait_return != WAIT_OBJECT_0) {
-/* map_win32_error_to_string(GetLastError());*/
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- goto done2;
- }
-
- if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) {
- pproc->last_err = GetLastError();
- pproc->lerrno = E_SCALL;
- }
-
-done2:
- if (pproc->lerrno)
- return(-1);
- else
- return(0);
-
-}
-
-/*
- * Description: Clean up any leftover handles, etc. It is up to the
- * caller to manage and free the input, ouput, and stderr buffers.
- */
- void
-process_cleanup(
- HANDLE proc)
-{
- sub_process *pproc = (sub_process *)proc;
- int i;
-
- if (pproc->using_pipes) {
- for (i= 0; i <= 1; i++) {
- if ((HANDLE)pproc->sv_stdin[i])
- CloseHandle((HANDLE)pproc->sv_stdin[i]);
- if ((HANDLE)pproc->sv_stdout[i])
- CloseHandle((HANDLE)pproc->sv_stdout[i]);
- if ((HANDLE)pproc->sv_stderr[i])
- CloseHandle((HANDLE)pproc->sv_stderr[i]);
- }
- }
- if ((HANDLE)pproc->pid)
- CloseHandle((HANDLE)pproc->pid);
-
- free(pproc);
-}
-
-
-/*
- * Try to protect against WIN32 argument munging. This function takes
- * an argv vector and outputs a 'protected' string as a return
- * value. The return code can be safely passed to CreateProcess().
- *
- * The caller should free the return value.
- */
-
-#define TRACE(x)
-static char *fix_command_line(char *args[])
-{
- int i;
- char *narg;
- char *nargp;
- char *p;
- char *q;
- int alloc_len = 0;
-
- for (i = 0; args[i]; i++)
- alloc_len += ((strlen(args[i]) * 2) + 1);
- /* account for possible enclosing quotes and null termination */
- alloc_len += 3;
-
- nargp = narg = malloc(alloc_len);
-
- for (i = 0; args[i]; i++) {
- p = args[i];
- TRACE(("original arg: %s\n", p));
-
- if (*p == '\0') {
- *nargp++ = '"';
- *nargp++ = '"';
- *nargp = '\0';
- TRACE(("empty string arg: %s\n", nargp-2));
- } else if (strpbrk(p, "\" \t")) {
- /* point to end of copy buffer */
- q = narg;
- q += (alloc_len-1);
- *q-- = '\0'; /* ensure null terminated string */
- *q-- = '"'; /* terminating quote of argument */
-
- /* point to end of the input string */
- p = args[i];
- p += strlen(args[i]);
- p--;
-
- /*
- * Because arg is quoted, escape any backslashes
- * that might occur at the end of the string which
- * proceed the closing quote.
- * Example:
- * foo c:\
- * Becomes:
- * "foo c:\\"
- */
- while (*p == '\\')
- *q-- = *p--, *q-- = '\\';
-
- /* copy the string in reverse */
- while (p >= args[i]) {
- /* copy the character */
- *q-- = *p--;
-
- /*
- * Escape any double quote found. Also escape
- * each backslash preceding the double quote.
- */
- if (*(p+1) == '"') {
- *q-- = '\\';
- if (p >= args[i] && *p == '\\')
- while (p >= args[i] && *p == '\\')
- *q-- = *p--, *q-- = '\\';
- }
- }
-
- /* finish quoting arg, q now points to complete arg */
- *q = '"';
-
- /* rejustify */
- memmove(nargp, q, strlen(q) + 1);
- TRACE(("arg with white space or doublequotes: %s\n", nargp));
- nargp += strlen(nargp);
- } else {
- /* just copy the argument, no protection needed */
- strcpy(nargp, args[i]);
- TRACE(("plain arg: %s\n", nargp));
- nargp += strlen(nargp);
- }
-
- /* separate arguments with spaces (if more args to gather) */
- if (args[i+1])
- *nargp++ = ' ';
- *nargp = '\0';
- } /* end for */
-
- /* NULL terminate the arg list */
- *nargp = '\0';
-
- return (narg);
-}
-#undef TRACE
-
-/*
- * Description:
- * Create a command line buffer to pass to CreateProcess
- *
- * Returns: the buffer or NULL for failure
- * Shell case: sh_name a:/full/path/to/script argv[1] argv[2] ...
- * Otherwise: argv[0] argv[1] argv[2] ...
- *
- * Notes/Dependencies:
- * CreateProcess does not take an argv, so this command creates a
- * command line for the executable.
- */
-
-static char *
-make_command_line( char *shell_name, char *exec_path, char **argv)
-{
- char** nargv;
- char* buf;
- int i;
-
- if (shell_name) {
- for (i = 0; argv[i]; i++);
- i += 2;
- nargv = (char **) malloc(i * sizeof (char *));
- nargv[0] = shell_name;
- for (i = 1; argv[i-1]; i++)
- nargv[i] = argv[i-1];
- nargv[i] = NULL;
- } else
- nargv = argv;
-
- /* create string suitable for CreateProcess() */
- buf = fix_command_line(nargv);
-
- if (shell_name)
- free(nargv);
-
- return buf;
-}
-
-/*
- * Description: Given an argv and optional envp, launch the process
- * using the default stdin, stdout, and stderr handles.
- * Also, register process so that process_wait_for_any_private()
- * can be used via process_file_io(NULL) or
- * process_wait_for_any().
- *
- * Returns:
- *
- * Notes/Dependencies:
- */
-HANDLE
-process_easy(
- char **argv,
- char **envp)
-{
- HANDLE hIn;
- HANDLE hOut;
- HANDLE hErr;
- HANDLE hProcess;
-
- if (DuplicateHandle(GetCurrentProcess(),
- GetStdHandle(STD_INPUT_HANDLE),
- GetCurrentProcess(),
- &hIn,
- 0,
- TRUE,
- DUPLICATE_SAME_ACCESS) == FALSE) {
- fprintf(stderr,
- "process_easy: DuplicateHandle(In) failed (e=%d)\n",
- GetLastError());
- return INVALID_HANDLE_VALUE;
- }
- if (DuplicateHandle(GetCurrentProcess(),
- GetStdHandle(STD_OUTPUT_HANDLE),
- GetCurrentProcess(),
- &hOut,
- 0,
- TRUE,
- DUPLICATE_SAME_ACCESS) == FALSE) {
- fprintf(stderr,
- "process_easy: DuplicateHandle(Out) failed (e=%d)\n",
- GetLastError());
- return INVALID_HANDLE_VALUE;
- }
- if (DuplicateHandle(GetCurrentProcess(),
- GetStdHandle(STD_ERROR_HANDLE),
- GetCurrentProcess(),
- &hErr,
- 0,
- TRUE,
- DUPLICATE_SAME_ACCESS) == FALSE) {
- fprintf(stderr,
- "process_easy: DuplicateHandle(Err) failed (e=%d)\n",
- GetLastError());
- return INVALID_HANDLE_VALUE;
- }
-
- hProcess = process_init_fd(hIn, hOut, hErr);
-
- if (process_begin(hProcess, argv, envp, argv[0], NULL)) {
- fake_exits_pending++;
- ((sub_process*) hProcess)->exit_code = process_last_err(hProcess);
-
- /* close up unused handles */
- CloseHandle(hIn);
- CloseHandle(hOut);
- CloseHandle(hErr);
- }
-
- process_register(hProcess);
-
- return hProcess;
-}
+#include <stdlib.h>
+#include <stdio.h>
+#include <process.h> /* for msvc _beginthreadex, _endthreadex */
+#include <windows.h>
+
+#include "sub_proc.h"
+#include "proc.h"
+#include "w32err.h"
+
+static char *make_command_line( char *shell_name, char *exec_path, char **argv);
+
+typedef struct sub_process_t {
+ int sv_stdin[2];
+ int sv_stdout[2];
+ int sv_stderr[2];
+ int using_pipes;
+ char *inp;
+ DWORD incnt;
+ char * volatile outp;
+ volatile DWORD outcnt;
+ char * volatile errp;
+ volatile DWORD errcnt;
+ int pid;
+ int exit_code;
+ int signal;
+ long last_err;
+ long lerrno;
+} sub_process;
+
+/* keep track of children so we can implement a waitpid-like routine */
+static sub_process *proc_array[256];
+static int proc_index = 0;
+static int fake_exits_pending = 0;
+
+/*
+ * When a process has been waited for, adjust the wait state
+ * array so that we don't wait for it again
+ */
+static void
+process_adjust_wait_state(sub_process* pproc)
+{
+ int i;
+
+ if (!proc_index)
+ return;
+
+ for (i = 0; i < proc_index; i++)
+ if (proc_array[i]->pid == pproc->pid)
+ break;
+
+ if (i < proc_index) {
+ proc_index--;
+ if (i != proc_index)
+ memmove(&proc_array[i], &proc_array[i+1],
+ (proc_index-i) * sizeof(sub_process*));
+ proc_array[proc_index] = NULL;
+ }
+}
+
+/*
+ * Waits for any of the registered child processes to finish.
+ */
+static sub_process *
+process_wait_for_any_private(void)
+{
+ HANDLE handles[256];
+ DWORD retval, which;
+ int i;
+
+ if (!proc_index)
+ return NULL;
+
+ /* build array of handles to wait for */
+ for (i = 0; i < proc_index; i++) {
+ handles[i] = (HANDLE) proc_array[i]->pid;
+
+ if (fake_exits_pending && proc_array[i]->exit_code)
+ break;
+ }
+
+ /* wait for someone to exit */
+ if (!fake_exits_pending) {
+ retval = WaitForMultipleObjects(proc_index, handles, FALSE, INFINITE);
+ which = retval - WAIT_OBJECT_0;
+ } else {
+ fake_exits_pending--;
+ retval = !WAIT_FAILED;
+ which = i;
+ }
+
+ /* return pointer to process */
+ if (retval != WAIT_FAILED) {
+ sub_process* pproc = proc_array[which];
+ process_adjust_wait_state(pproc);
+ return pproc;
+ } else
+ return NULL;
+}
+
+/*
+ * Terminate a process.
+ */
+BOOL
+process_kill(HANDLE proc, int signal)
+{
+ sub_process* pproc = (sub_process*) proc;
+ pproc->signal = signal;
+ return (TerminateProcess((HANDLE) pproc->pid, signal));
+}
+
+/*
+ * Use this function to register processes you wish to wait for by
+ * calling process_file_io(NULL) or process_wait_any(). This must be done
+ * because it is possible for callers of this library to reuse the same
+ * handle for multiple processes launches :-(
+ */
+void
+process_register(HANDLE proc)
+{
+ proc_array[proc_index++] = (sub_process *) proc;
+}
+
+/*
+ * Public function which works kind of like waitpid(). Wait for any
+ * of the children to die and return results. To call this function,
+ * you must do 1 of things:
+ *
+ * x = process_easy(...);
+ *
+ * or
+ *
+ * x = process_init_fd();
+ * process_register(x);
+ *
+ * or
+ *
+ * x = process_init();
+ * process_register(x);
+ *
+ * You must NOT then call process_pipe_io() because this function is
+ * not capable of handling automatic notification of any child
+ * death.
+ */
+
+HANDLE
+process_wait_for_any(void)
+{
+ sub_process* pproc = process_wait_for_any_private();
+
+ if (!pproc)
+ return NULL;
+ else {
+ /*
+ * Ouch! can't tell caller if this fails directly. Caller
+ * will have to use process_last_err()
+ */
+ (void) process_file_io(pproc);
+ return ((HANDLE) pproc);
+ }
+}
+
+long
+process_errno(HANDLE proc)
+{
+ return (((sub_process *)proc)->lerrno);
+}
+
+long
+process_signal(HANDLE proc)
+{
+ return (((sub_process *)proc)->signal);
+}
+
+ long
+process_last_err(HANDLE proc)
+{
+ return (((sub_process *)proc)->last_err);
+}
+
+ long
+process_exit_code(HANDLE proc)
+{
+ return (((sub_process *)proc)->exit_code);
+}
+
+ char *
+process_outbuf(HANDLE proc)
+{
+ return (((sub_process *)proc)->outp);
+}
+
+ char *
+process_errbuf(HANDLE proc)
+{
+ return (((sub_process *)proc)->errp);
+}
+
+ int
+process_outcnt(HANDLE proc)
+{
+ return (((sub_process *)proc)->outcnt);
+}
+
+ int
+process_errcnt(HANDLE proc)
+{
+ return (((sub_process *)proc)->errcnt);
+}
+
+ void
+process_pipes(HANDLE proc, int pipes[3])
+{
+ pipes[0] = ((sub_process *)proc)->sv_stdin[0];
+ pipes[1] = ((sub_process *)proc)->sv_stdout[0];
+ pipes[2] = ((sub_process *)proc)->sv_stderr[0];
+ return;
+}
+
+
+ HANDLE
+process_init()
+{
+ sub_process *pproc;
+ /*
+ * open file descriptors for attaching stdin/stdout/sterr
+ */
+ HANDLE stdin_pipes[2];
+ HANDLE stdout_pipes[2];
+ HANDLE stderr_pipes[2];
+ SECURITY_ATTRIBUTES inherit;
+ BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
+
+ pproc = malloc(sizeof(*pproc));
+ memset(pproc, 0, sizeof(*pproc));
+
+ /* We can't use NULL for lpSecurityDescriptor because that
+ uses the default security descriptor of the calling process.
+ Instead we use a security descriptor with no DACL. This
+ allows nonrestricted access to the associated objects. */
+
+ if (!InitializeSecurityDescriptor((PSECURITY_DESCRIPTOR)(&sd),
+ SECURITY_DESCRIPTOR_REVISION)) {
+ pproc->last_err = GetLastError();
+ pproc->lerrno = E_SCALL;
+ return((HANDLE)pproc);
+ }
+
+ inherit.nLength = sizeof(inherit);
+ inherit.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(&sd);
+ inherit.bInheritHandle = TRUE;
+
+ // By convention, parent gets pipe[0], and child gets pipe[1]
+ // This means the READ side of stdin pipe goes into pipe[1]
+ // and the WRITE side of the stdout and stderr pipes go into pipe[1]
+ if (CreatePipe( &stdin_pipes[1], &stdin_pipes[0], &inherit, 0) == FALSE ||
+ CreatePipe( &stdout_pipes[0], &stdout_pipes[1], &inherit, 0) == FALSE ||
+ CreatePipe( &stderr_pipes[0], &stderr_pipes[1], &inherit, 0) == FALSE) {
+
+ pproc->last_err = GetLastError();
+ pproc->lerrno = E_SCALL;
+ return((HANDLE)pproc);
+ }
+
+ //
+ // Mark the parent sides of the pipes as non-inheritable
+ //
+ if (SetHandleInformation(stdin_pipes[0],
+ HANDLE_FLAG_INHERIT, 0) == FALSE ||
+ SetHandleInformation(stdout_pipes[0],
+ HANDLE_FLAG_INHERIT, 0) == FALSE ||
+ SetHandleInformation(stderr_pipes[0],
+ HANDLE_FLAG_INHERIT, 0) == FALSE) {
+
+ pproc->last_err = GetLastError();
+ pproc->lerrno = E_SCALL;
+ return((HANDLE)pproc);
+ }
+ pproc->sv_stdin[0] = (int) stdin_pipes[0];
+ pproc->sv_stdin[1] = (int) stdin_pipes[1];
+ pproc->sv_stdout[0] = (int) stdout_pipes[0];
+ pproc->sv_stdout[1] = (int) stdout_pipes[1];
+ pproc->sv_stderr[0] = (int) stderr_pipes[0];
+ pproc->sv_stderr[1] = (int) stderr_pipes[1];
+
+ pproc->using_pipes = 1;
+
+ pproc->lerrno = 0;
+
+ return((HANDLE)pproc);
+}
+
+
+ HANDLE
+process_init_fd(HANDLE stdinh, HANDLE stdouth, HANDLE stderrh)
+{
+ sub_process *pproc;
+
+ pproc = malloc(sizeof(*pproc));
+ memset(pproc, 0, sizeof(*pproc));
+
+ /*
+ * Just pass the provided file handles to the 'child side' of the
+ * pipe, bypassing pipes altogether.
+ */
+ pproc->sv_stdin[1] = (int) stdinh;
+ pproc->sv_stdout[1] = (int) stdouth;
+ pproc->sv_stderr[1] = (int) stderrh;
+
+ pproc->last_err = pproc->lerrno = 0;
+
+ return((HANDLE)pproc);
+}
+
+
+static HANDLE
+find_file(char *exec_path, LPOFSTRUCT file_info)
+{
+ HANDLE exec_handle;
+ char *fname;
+ char *ext;
+
+ if ((exec_handle = (HANDLE)OpenFile(exec_path, file_info,
+ OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
+ return(exec_handle);
+ }
+
+ fname = malloc(strlen(exec_path) + 5);
+ strcpy(fname, exec_path);
+ ext = fname + strlen(fname);
+ strcpy(ext, ".exe");
+ if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
+ OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
+ free(fname);
+ return(exec_handle);
+ }
+
+ strcpy(ext, ".bat");
+ if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
+ OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
+ free(fname);
+ return(exec_handle);
+ }
+
+ strcpy(ext, ".com");
+ if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
+ OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
+ free(fname);
+ return(exec_handle);
+ }
+
+ free(fname);
+ return(exec_handle);
+}
+
+
+/*
+ * Description: Create the child process to be helped
+ *
+ * Returns:
+ *
+ * Notes/Dependencies:
+ */
+long
+process_begin(
+ HANDLE proc,
+ char **argv,
+ char **envp,
+ char *exec_path,
+ char *as_user)
+{
+ sub_process *pproc = (sub_process *)proc;
+ char *shell_name = 0;
+ int file_not_found=0;
+ HANDLE exec_handle;
+ char buf[256];
+ DWORD bytes_returned;
+ DWORD flags;
+ char *command_line;
+ STARTUPINFO startInfo;
+ PROCESS_INFORMATION procInfo;
+ char *envblk=NULL;
+ OFSTRUCT file_info;
+
+
+ /*
+ * Shell script detection... if the exec_path starts with #! then
+ * we want to exec shell-script-name exec-path, not just exec-path
+ * NT doesn't recognize #!/bin/sh or #!/etc/Tivoli/bin/perl. We do not
+ * hard-code the path to the shell or perl or whatever: Instead, we
+ * assume it's in the path somewhere (generally, the NT tools
+ * bin directory)
+ * We use OpenFile here because it is capable of searching the Path.
+ */
+
+ exec_handle = find_file(exec_path, &file_info);
+
+ /*
+ * If we couldn't open the file, just assume that Win32 will be able
+ * to find and execute it.
+ */
+ if (exec_handle == (HANDLE)HFILE_ERROR) {
+ file_not_found++;
+ }
+ else {
+ /* Attempt to read the first line of the file */
+ if (ReadFile( exec_handle,
+ buf, sizeof(buf) - 1, /* leave room for trailing NULL */
+ &bytes_returned, 0) == FALSE || bytes_returned < 2) {
+
+ pproc->last_err = GetLastError();
+ pproc->lerrno = E_IO;
+ CloseHandle(exec_handle);
+ return(-1);
+ }
+ if (buf[0] == '#' && buf[1] == '!') {
+ /*
+ * This is a shell script... Change the command line from
+ * exec_path args to shell_name exec_path args
+ */
+ char *p;
+
+ /* Make sure buf is NULL terminated */
+ buf[bytes_returned] = 0;
+ /*
+ * Depending on the file system type, etc. the first line
+ * of the shell script may end with newline or newline-carriage-return
+ * Whatever it ends with, cut it off.
+ */
+ p= strchr(buf, '\n');
+ if (p)
+ *p = 0;
+ p = strchr(buf, '\r');
+ if (p)
+ *p = 0;
+
+ /*
+ * Find base name of shell
+ */
+ shell_name = strrchr( buf, '/');
+ if (shell_name) {
+ shell_name++;
+ } else {
+ shell_name = &buf[2];/* skipping "#!" */
+ }
+
+ }
+ CloseHandle(exec_handle);
+ }
+
+ flags = 0;
+
+ if (file_not_found)
+ command_line = make_command_line( shell_name, exec_path, argv);
+ else
+ command_line = make_command_line( shell_name, file_info.szPathName,
+ argv);
+
+ if ( command_line == NULL ) {
+ pproc->last_err = 0;
+ pproc->lerrno = E_NO_MEM;
+ return(-1);
+ }
+
+ if (envp) {
+ if (arr2envblk(envp, &envblk) ==FALSE) {
+ pproc->last_err = 0;
+ pproc->lerrno = E_NO_MEM;
+ free( command_line );
+ return(-1);
+ }
+ }
+
+ if ((shell_name) || (file_not_found)) {
+ exec_path = 0; /* Search for the program in %Path% */
+ } else {
+ exec_path = file_info.szPathName;
+ }
+
+ /*
+ * Set up inherited stdin, stdout, stderr for child
+ */
+ GetStartupInfo(&startInfo);
+ startInfo.dwFlags = STARTF_USESTDHANDLES;
+ startInfo.lpReserved = 0;
+ startInfo.cbReserved2 = 0;
+ startInfo.lpReserved2 = 0;
+ startInfo.lpTitle = shell_name ? shell_name : exec_path;
+ startInfo.hStdInput = (HANDLE)pproc->sv_stdin[1];
+ startInfo.hStdOutput = (HANDLE)pproc->sv_stdout[1];
+ startInfo.hStdError = (HANDLE)pproc->sv_stderr[1];
+
+ /*
+ * See if we need to setuid to a different user.
+ */
+ if (as_user) {
+ return -1;
+ }
+
+ if (as_user) {
+ return -1;
+ } else {
+ if (CreateProcess(
+ exec_path,
+ command_line,
+ NULL,
+ 0, /* default security attributes for thread */
+ TRUE, /* inherit handles (e.g. helper pipes, oserv socket) */
+ flags,
+ envblk,
+ 0, /* default starting directory */
+ &startInfo,
+ &procInfo) == FALSE) {
+
+ pproc->last_err = GetLastError();
+ pproc->lerrno = E_FORK;
+ fprintf(stderr, "process_begin: CreateProcess(%s, %s, ...) failed.\n", exec_path, command_line);
+ free( command_line );
+ return(-1);
+ }
+ }
+
+ pproc->pid = (int)procInfo.hProcess;
+ /* Close the thread handle -- we'll just watch the process */
+ CloseHandle(procInfo.hThread);
+
+ /* Close the halves of the pipes we don't need */
+ if (pproc->sv_stdin) {
+ CloseHandle((HANDLE)pproc->sv_stdin[1]);
+ (HANDLE)pproc->sv_stdin[1] = 0;
+ }
+ if (pproc->sv_stdout) {
+ CloseHandle((HANDLE)pproc->sv_stdout[1]);
+ (HANDLE)pproc->sv_stdout[1] = 0;
+ }
+ if (pproc->sv_stderr) {
+ CloseHandle((HANDLE)pproc->sv_stderr[1]);
+ (HANDLE)pproc->sv_stderr[1] = 0;
+ }
+
+ free( command_line );
+ pproc->lerrno=0;
+ return 0;
+}
+
+
+
+static DWORD
+proc_stdin_thread(sub_process *pproc)
+{
+ DWORD in_done;
+ for (;;) {
+ if (WriteFile( (HANDLE) pproc->sv_stdin[0], pproc->inp, pproc->incnt,
+ &in_done, NULL) == FALSE)
+ _endthreadex(0);
+ // This if should never be true for anonymous pipes, but gives
+ // us a chance to change I/O mechanisms later
+ if (in_done < pproc->incnt) {
+ pproc->incnt -= in_done;
+ pproc->inp += in_done;
+ } else {
+ _endthreadex(0);
+ }
+ }
+ return 0; // for compiler warnings only.. not reached
+}
+
+static DWORD
+proc_stdout_thread(sub_process *pproc)
+{
+ DWORD bufsize = 1024;
+ char c;
+ DWORD nread;
+ pproc->outp = malloc(bufsize);
+ if (pproc->outp == NULL)
+ _endthreadex(0);
+ pproc->outcnt = 0;
+
+ for (;;) {
+ if (ReadFile( (HANDLE)pproc->sv_stdout[0], &c, 1, &nread, NULL)
+ == FALSE) {
+/* map_win32_error_to_string(GetLastError());*/
+ _endthreadex(0);
+ }
+ if (nread == 0)
+ _endthreadex(0);
+ if (pproc->outcnt + nread > bufsize) {
+ bufsize += nread + 512;
+ pproc->outp = realloc(pproc->outp, bufsize);
+ if (pproc->outp == NULL) {
+ pproc->outcnt = 0;
+ _endthreadex(0);
+ }
+ }
+ pproc->outp[pproc->outcnt++] = c;
+ }
+ return 0;
+}
+
+static DWORD
+proc_stderr_thread(sub_process *pproc)
+{
+ DWORD bufsize = 1024;
+ char c;
+ DWORD nread;
+ pproc->errp = malloc(bufsize);
+ if (pproc->errp == NULL)
+ _endthreadex(0);
+ pproc->errcnt = 0;
+
+ for (;;) {
+ if (ReadFile( (HANDLE)pproc->sv_stderr[0], &c, 1, &nread, NULL) == FALSE) {
+ map_win32_error_to_string(GetLastError());
+ _endthreadex(0);
+ }
+ if (nread == 0)
+ _endthreadex(0);
+ if (pproc->errcnt + nread > bufsize) {
+ bufsize += nread + 512;
+ pproc->errp = realloc(pproc->errp, bufsize);
+ if (pproc->errp == NULL) {
+ pproc->errcnt = 0;
+ _endthreadex(0);
+ }
+ }
+ pproc->errp[pproc->errcnt++] = c;
+ }
+ return 0;
+}
+
+
+/*
+ * Purpose: collects output from child process and returns results
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ * Notes/Dependencies:
+ */
+ long
+process_pipe_io(
+ HANDLE proc,
+ char *stdin_data,
+ int stdin_data_len)
+{
+ sub_process *pproc = (sub_process *)proc;
+ bool_t stdin_eof = FALSE, stdout_eof = FALSE, stderr_eof = FALSE;
+ HANDLE childhand = (HANDLE) pproc->pid;
+ HANDLE tStdin, tStdout, tStderr;
+ DWORD dwStdin, dwStdout, dwStderr;
+ HANDLE wait_list[4];
+ DWORD wait_count;
+ DWORD wait_return;
+ HANDLE ready_hand;
+ bool_t child_dead = FALSE;
+
+
+ /*
+ * Create stdin thread, if needed
+ */
+ pproc->inp = stdin_data;
+ pproc->incnt = stdin_data_len;
+ if (!pproc->inp) {
+ stdin_eof = TRUE;
+ CloseHandle((HANDLE)pproc->sv_stdin[0]);
+ (HANDLE)pproc->sv_stdin[0] = 0;
+ } else {
+ tStdin = (HANDLE) _beginthreadex( 0, 1024,
+ (unsigned (__stdcall *) (void *))proc_stdin_thread, pproc, 0,
+ (unsigned int *) &dwStdin);
+ if (tStdin == 0) {
+ pproc->last_err = GetLastError();
+ pproc->lerrno = E_SCALL;
+ goto done;
+ }
+ }
+
+ /*
+ * Assume child will produce stdout and stderr
+ */
+ tStdout = (HANDLE) _beginthreadex( 0, 1024,
+ (unsigned (__stdcall *) (void *))proc_stdout_thread, pproc, 0,
+ (unsigned int *) &dwStdout);
+ tStderr = (HANDLE) _beginthreadex( 0, 1024,
+ (unsigned (__stdcall *) (void *))proc_stderr_thread, pproc, 0,
+ (unsigned int *) &dwStderr);
+
+ if (tStdout == 0 || tStderr == 0) {
+
+ pproc->last_err = GetLastError();
+ pproc->lerrno = E_SCALL;
+ goto done;
+ }
+
+
+ /*
+ * Wait for all I/O to finish and for the child process to exit
+ */
+
+ while (!stdin_eof || !stdout_eof || !stderr_eof || !child_dead) {
+ wait_count = 0;
+ if (!stdin_eof) {
+ wait_list[wait_count++] = tStdin;
+ }
+ if (!stdout_eof) {
+ wait_list[wait_count++] = tStdout;
+ }
+ if (!stderr_eof) {
+ wait_list[wait_count++] = tStderr;
+ }
+ if (!child_dead) {
+ wait_list[wait_count++] = childhand;
+ }
+
+ wait_return = WaitForMultipleObjects(wait_count, wait_list,
+ FALSE, /* don't wait for all: one ready will do */
+ child_dead? 1000 :INFINITE); /* after the child dies, subthreads have
+ one second to collect all remaining output */
+
+ if (wait_return == WAIT_FAILED) {
+/* map_win32_error_to_string(GetLastError());*/
+ pproc->last_err = GetLastError();
+ pproc->lerrno = E_SCALL;
+ goto done;
+ }
+
+ ready_hand = wait_list[wait_return - WAIT_OBJECT_0];
+
+ if (ready_hand == tStdin) {
+ CloseHandle((HANDLE)pproc->sv_stdin[0]);
+ (HANDLE)pproc->sv_stdin[0] = 0;
+ CloseHandle(tStdin);
+ tStdin = 0;
+ stdin_eof = TRUE;
+
+ } else if (ready_hand == tStdout) {
+
+ CloseHandle((HANDLE)pproc->sv_stdout[0]);
+ (HANDLE)pproc->sv_stdout[0] = 0;
+ CloseHandle(tStdout);
+ tStdout = 0;
+ stdout_eof = TRUE;
+
+ } else if (ready_hand == tStderr) {
+
+ CloseHandle((HANDLE)pproc->sv_stderr[0]);
+ (HANDLE)pproc->sv_stderr[0] = 0;
+ CloseHandle(tStderr);
+ tStderr = 0;
+ stderr_eof = TRUE;
+
+ } else if (ready_hand == childhand) {
+
+ if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) {
+ pproc->last_err = GetLastError();
+ pproc->lerrno = E_SCALL;
+ goto done;
+ }
+ child_dead = TRUE;
+
+ } else {
+
+ /* ?? Got back a handle we didn't query ?? */
+ pproc->last_err = 0;
+ pproc->lerrno = E_FAIL;
+ goto done;
+ }
+ }
+
+ done:
+ if (tStdin != 0)
+ CloseHandle(tStdin);
+ if (tStdout != 0)
+ CloseHandle(tStdout);
+ if (tStderr != 0)
+ CloseHandle(tStderr);
+
+ if (pproc->lerrno)
+ return(-1);
+ else
+ return(0);
+
+}
+
+/*
+ * Purpose: collects output from child process and returns results
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ * Notes/Dependencies:
+ */
+ long
+process_file_io(
+ HANDLE proc)
+{
+ sub_process *pproc;
+ HANDLE childhand;
+ DWORD wait_return;
+
+ if (proc == NULL)
+ pproc = process_wait_for_any_private();
+ else
+ pproc = (sub_process *)proc;
+
+ /* some sort of internal error */
+ if (!pproc)
+ return -1;
+
+ childhand = (HANDLE) pproc->pid;
+
+ /*
+ * This function is poorly named, and could also be used just to wait
+ * for child death if you're doing your own pipe I/O. If that is
+ * the case, close the pipe handles here.
+ */
+ if (pproc->sv_stdin[0]) {
+ CloseHandle((HANDLE)pproc->sv_stdin[0]);
+ pproc->sv_stdin[0] = 0;
+ }
+ if (pproc->sv_stdout[0]) {
+ CloseHandle((HANDLE)pproc->sv_stdout[0]);
+ pproc->sv_stdout[0] = 0;
+ }
+ if (pproc->sv_stderr[0]) {
+ CloseHandle((HANDLE)pproc->sv_stderr[0]);
+ pproc->sv_stderr[0] = 0;
+ }
+
+ /*
+ * Wait for the child process to exit
+ */
+
+ wait_return = WaitForSingleObject(childhand, INFINITE);
+
+ if (wait_return != WAIT_OBJECT_0) {
+/* map_win32_error_to_string(GetLastError());*/
+ pproc->last_err = GetLastError();
+ pproc->lerrno = E_SCALL;
+ goto done2;
+ }
+
+ if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) {
+ pproc->last_err = GetLastError();
+ pproc->lerrno = E_SCALL;
+ }
+
+done2:
+ if (pproc->lerrno)
+ return(-1);
+ else
+ return(0);
+
+}
+
+/*
+ * Description: Clean up any leftover handles, etc. It is up to the
+ * caller to manage and free the input, ouput, and stderr buffers.
+ */
+ void
+process_cleanup(
+ HANDLE proc)
+{
+ sub_process *pproc = (sub_process *)proc;
+ int i;
+
+ if (pproc->using_pipes) {
+ for (i= 0; i <= 1; i++) {
+ if ((HANDLE)pproc->sv_stdin[i])
+ CloseHandle((HANDLE)pproc->sv_stdin[i]);
+ if ((HANDLE)pproc->sv_stdout[i])
+ CloseHandle((HANDLE)pproc->sv_stdout[i]);
+ if ((HANDLE)pproc->sv_stderr[i])
+ CloseHandle((HANDLE)pproc->sv_stderr[i]);
+ }
+ }
+ if ((HANDLE)pproc->pid)
+ CloseHandle((HANDLE)pproc->pid);
+
+ free(pproc);
+}
+
+
+/*
+ * Try to protect against WIN32 argument munging. This function takes
+ * an argv vector and outputs a 'protected' string as a return
+ * value. The return code can be safely passed to CreateProcess().
+ *
+ * The caller should free the return value.
+ */
+
+#define TRACE(x)
+static char *fix_command_line(char *args[])
+{
+ int i;
+ char *narg;
+ char *nargp;
+ char *p;
+ char *q;
+ int alloc_len = 0;
+
+ for (i = 0; args[i]; i++)
+ alloc_len += ((strlen(args[i]) * 2) + 1);
+ /* account for possible enclosing quotes and null termination */
+ alloc_len += 3;
+
+ nargp = narg = malloc(alloc_len);
+
+ for (i = 0; args[i]; i++) {
+ p = args[i];
+ TRACE(("original arg: %s\n", p));
+
+ if (*p == '\0') {
+ *nargp++ = '"';
+ *nargp++ = '"';
+ *nargp = '\0';
+ TRACE(("empty string arg: %s\n", nargp-2));
+ } else if (strpbrk(p, "\" \t")) {
+ /* point to end of copy buffer */
+ q = narg;
+ q += (alloc_len-1);
+ *q-- = '\0'; /* ensure null terminated string */
+ *q-- = '"'; /* terminating quote of argument */
+
+ /* point to end of the input string */
+ p = args[i];
+ p += strlen(args[i]);
+ p--;
+
+ /*
+ * Because arg is quoted, escape any backslashes
+ * that might occur at the end of the string which
+ * proceed the closing quote.
+ * Example:
+ * foo c:\
+ * Becomes:
+ * "foo c:\\"
+ */
+ while (*p == '\\')
+ *q-- = *p--, *q-- = '\\';
+
+ /* copy the string in reverse */
+ while (p >= args[i]) {
+ /* copy the character */
+ *q-- = *p--;
+
+ /*
+ * Escape any double quote found. Also escape
+ * each backslash preceding the double quote.
+ */
+ if (*(p+1) == '"') {
+ *q-- = '\\';
+ if (p >= args[i] && *p == '\\')
+ while (p >= args[i] && *p == '\\')
+ *q-- = *p--, *q-- = '\\';
+ }
+ }
+
+ /* finish quoting arg, q now points to complete arg */
+ *q = '"';
+
+ /* rejustify */
+ memmove(nargp, q, strlen(q) + 1);
+ TRACE(("arg with white space or doublequotes: %s\n", nargp));
+ nargp += strlen(nargp);
+ } else {
+ /* just copy the argument, no protection needed */
+ strcpy(nargp, args[i]);
+ TRACE(("plain arg: %s\n", nargp));
+ nargp += strlen(nargp);
+ }
+
+ /* separate arguments with spaces (if more args to gather) */
+ if (args[i+1])
+ *nargp++ = ' ';
+ *nargp = '\0';
+ } /* end for */
+
+ /* NULL terminate the arg list */
+ *nargp = '\0';
+
+ return (narg);
+}
+#undef TRACE
+
+/*
+ * Description:
+ * Create a command line buffer to pass to CreateProcess
+ *
+ * Returns: the buffer or NULL for failure
+ * Shell case: sh_name a:/full/path/to/script argv[1] argv[2] ...
+ * Otherwise: argv[0] argv[1] argv[2] ...
+ *
+ * Notes/Dependencies:
+ * CreateProcess does not take an argv, so this command creates a
+ * command line for the executable.
+ */
+
+static char *
+make_command_line( char *shell_name, char *exec_path, char **argv)
+{
+ char** nargv;
+ char* buf;
+ int i;
+
+ if (shell_name) {
+ for (i = 0; argv[i]; i++);
+ i += 2;
+ nargv = (char **) malloc(i * sizeof (char *));
+ nargv[0] = shell_name;
+ for (i = 1; argv[i-1]; i++)
+ nargv[i] = argv[i-1];
+ nargv[i] = NULL;
+ } else
+ nargv = argv;
+
+ /* create string suitable for CreateProcess() */
+ buf = fix_command_line(nargv);
+
+ if (shell_name)
+ free(nargv);
+
+ return buf;
+}
+
+/*
+ * Description: Given an argv and optional envp, launch the process
+ * using the default stdin, stdout, and stderr handles.
+ * Also, register process so that process_wait_for_any_private()
+ * can be used via process_file_io(NULL) or
+ * process_wait_for_any().
+ *
+ * Returns:
+ *
+ * Notes/Dependencies:
+ */
+HANDLE
+process_easy(
+ char **argv,
+ char **envp)
+{
+ HANDLE hIn;
+ HANDLE hOut;
+ HANDLE hErr;
+ HANDLE hProcess;
+
+ if (DuplicateHandle(GetCurrentProcess(),
+ GetStdHandle(STD_INPUT_HANDLE),
+ GetCurrentProcess(),
+ &hIn,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS) == FALSE) {
+ fprintf(stderr,
+ "process_easy: DuplicateHandle(In) failed (e=%d)\n",
+ GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ if (DuplicateHandle(GetCurrentProcess(),
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ GetCurrentProcess(),
+ &hOut,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS) == FALSE) {
+ fprintf(stderr,
+ "process_easy: DuplicateHandle(Out) failed (e=%d)\n",
+ GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ if (DuplicateHandle(GetCurrentProcess(),
+ GetStdHandle(STD_ERROR_HANDLE),
+ GetCurrentProcess(),
+ &hErr,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS) == FALSE) {
+ fprintf(stderr,
+ "process_easy: DuplicateHandle(Err) failed (e=%d)\n",
+ GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+
+ hProcess = process_init_fd(hIn, hOut, hErr);
+
+ if (process_begin(hProcess, argv, envp, argv[0], NULL)) {
+ fake_exits_pending++;
+ ((sub_process*) hProcess)->exit_code = process_last_err(hProcess);
+
+ /* close up unused handles */
+ CloseHandle(hIn);
+ CloseHandle(hOut);
+ CloseHandle(hErr);
+ }
+
+ process_register(hProcess);
+
+ return hProcess;
+}
diff --git a/w32/subproc/w32err.c b/w32/subproc/w32err.c
index e4e8835..8abd75b 100644
--- a/w32/subproc/w32err.c
+++ b/w32/subproc/w32err.c
@@ -1,51 +1,51 @@
-#include <windows.h>
-#include "w32err.h"
-
-/*
- * Description: the win32 version of perror()
- *
- * Returns: a pointer to a static error
- *
- * Notes/Dependencies: I got this from
- * comp.os.ms-windows.programmer.win32
- */
-char *
-map_win32_error_to_string (DWORD ercode) {
-/* __declspec (thread) necessary if you will use multiple threads */
-__declspec (thread) static char szMessageBuffer[128];
-
- /* Fill message buffer with a default message in
- * case FormatMessage fails
- */
- wsprintf (szMessageBuffer, "Error %ld", ercode);
-
- /*
- * Special code for winsock error handling.
- */
- if (ercode > WSABASEERR) {
- HMODULE hModule = GetModuleHandle("wsock32");
- if (hModule != NULL) {
- FormatMessage(FORMAT_MESSAGE_FROM_HMODULE,
- hModule,
- ercode,
- LANG_NEUTRAL,
- szMessageBuffer,
- sizeof(szMessageBuffer),
- NULL);
- FreeLibrary(hModule);
- }
- } else {
- /*
- * Default system message handling
- */
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- ercode,
- LANG_NEUTRAL,
- szMessageBuffer,
- sizeof(szMessageBuffer),
- NULL);
- }
- return szMessageBuffer;
-}
-
+#include <windows.h>
+#include "w32err.h"
+
+/*
+ * Description: the win32 version of perror()
+ *
+ * Returns: a pointer to a static error
+ *
+ * Notes/Dependencies: I got this from
+ * comp.os.ms-windows.programmer.win32
+ */
+char *
+map_win32_error_to_string (DWORD ercode) {
+/* __declspec (thread) necessary if you will use multiple threads */
+__declspec (thread) static char szMessageBuffer[128];
+
+ /* Fill message buffer with a default message in
+ * case FormatMessage fails
+ */
+ wsprintf (szMessageBuffer, "Error %ld", ercode);
+
+ /*
+ * Special code for winsock error handling.
+ */
+ if (ercode > WSABASEERR) {
+ HMODULE hModule = GetModuleHandle("wsock32");
+ if (hModule != NULL) {
+ FormatMessage(FORMAT_MESSAGE_FROM_HMODULE,
+ hModule,
+ ercode,
+ LANG_NEUTRAL,
+ szMessageBuffer,
+ sizeof(szMessageBuffer),
+ NULL);
+ FreeLibrary(hModule);
+ }
+ } else {
+ /*
+ * Default system message handling
+ */
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ ercode,
+ LANG_NEUTRAL,
+ szMessageBuffer,
+ sizeof(szMessageBuffer),
+ NULL);
+ }
+ return szMessageBuffer;
+}
+