UnixOperatingSystem.st
changeset 20327 e70f8895a3cb
parent 20296 3a064b47bacf
child 20328 d27372774fc9
--- a/UnixOperatingSystem.st	Thu Sep 01 18:28:45 2016 +0200
+++ b/UnixOperatingSystem.st	Thu Sep 01 18:58:06 2016 +0200
@@ -3143,32 +3143,68 @@
 exec:aCommandPathArg withArguments:argColl environment:environmentDictionary
     fileDescriptors:fdColl fork:doFork newPgrp:newPgrp inDirectory:aDirectory
 
+    ^ self
+        exec:aCommandPathArg withArguments:argColl environment:environmentDictionary
+        fileDescriptors:fdColl fork:doFork newPgrp:newPgrp inDirectory:aDirectory showWindow:nil
+
+    "
+     |id|
+
+     id := OperatingSystem fork.
+     id == 0 ifTrue:[
+        'I am the child'.
+        OperatingSystem exec:'/bin/ls' withArguments:#('ls' '/tmp').
+        'not reached'.
+     ]
+    "
+    "
+     |id|
+
+     id := OperatingSystem fork.
+     id == 0 ifTrue:[
+        'I am the child'.
+        OperatingSystem
+           exec:'/bin/sh'
+           withArguments:#('sh' '-c' 'sleep 2;echo 1;sleep 2;echo 2').
+        'not reached'.
+     ].
+     id printNL.
+     (Delay forSeconds:3.5) wait.
+     'killing ...' printNL.
+     OperatingSystem sendSignal:(OperatingSystem sigTERM) to:id.
+     OperatingSystem sendSignal:(OperatingSystem sigKILL) to:id
+    "
+!
+
+exec:aCommandPathArg withArguments:argColl environment:environmentDictionary
+    fileDescriptors:fdColl fork:doFork newPgrp:newPgrp inDirectory:aDirectory showWindow:ignoredHere
+
     "Internal lowLevel entry for combined fork & exec;
 
      If fork is false (chain a command):
-	 execute the OS command specified by the argument, aCommandPath, with
-	 arguments in argArray (no arguments, if nil).
-	 If successful, this method does not return and smalltalk is gone.
-	 If not successful, it does return.
-	 Normal use is with forkForCommand.
+         execute the OS command specified by the argument, aCommandPath, with
+         arguments in argArray (no arguments, if nil).
+         If successful, this method does not return and smalltalk is gone.
+         If not successful, it does return.
+         Normal use is with forkForCommand.
 
      If fork is true (subprocess command execution):
-	fork a child to do the above.
-	The process id of the child process is returned; nil if the fork failed.
+        fork a child to do the above.
+        The process id of the child process is returned; nil if the fork failed.
 
      fdColl contains the filedescriptors, to be used for the child (if fork is true).
-	fdArray[1] = 15 -> use fd 15 as stdin.
-	If an element of the array is set to nil, the corresponding filedescriptor
-	will be closed for the child.
-	fdArray[1] == StdIn for child
-	fdArray[2] == StdOut for child
-	fdArray[3] == StdErr for child
-	on VMS, these must be channels as returned by createMailBox.
-	All filedescriptors not present in fdColl will be closed for the child.
+        fdArray[1] = 15 -> use fd 15 as stdin.
+        If an element of the array is set to nil, the corresponding filedescriptor
+        will be closed for the child.
+        fdArray[1] == StdIn for child
+        fdArray[2] == StdOut for child
+        fdArray[3] == StdErr for child
+        on VMS, these must be channels as returned by createMailBox.
+        All filedescriptors not present in fdColl will be closed for the child.
 
      If newPgrp is true, the subprocess will be established in a new process group.
-	The processgroup will be equal to id.
-	newPgrp is not used on WIN32 and VMS systems.
+        The processgroup will be equal to id.
+        newPgrp is not used on WIN32 and VMS systems.
 
      environmentDictionary specifies environment variables which are passed differently from
      the current environment. If non-nil, it must be a dictionary providing
@@ -3176,33 +3212,33 @@
      To pass a variable as empty (i.e. unset), pass a nil value.
 
      Notice: this used to be two separate ST-methods; however, in order to use
-	    vfork on some machines, it had to be merged into one, to avoid write
-	    accesses to ST/X memory from the vforked-child.
-	    The code below only does read accesses."
+            vfork on some machines, it had to be merged into one, to avoid write
+            accesses to ST/X memory from the vforked-child.
+            The code below only does read accesses."
 
     |envArray argArray fdArray dirName cnt aCommandPath|
 
     environmentDictionary notEmptyOrNil ifTrue:[
-	envArray := Array new:environmentDictionary size.
-	cnt := 1.
-	environmentDictionary keysAndValuesDo:[:key :val |
-	    val isNil ifTrue:[
-		envArray at:cnt put:((self encodePath:key), '=')
-	    ] ifFalse:[
-		envArray at:cnt put:((self encodePath:key), '=', (self encodePath:val))
-	    ].
-	    cnt := cnt + 1.
-	].
+        envArray := Array new:environmentDictionary size.
+        cnt := 1.
+        environmentDictionary keysAndValuesDo:[:key :val |
+            val isNil ifTrue:[
+                envArray at:cnt put:((self encodePath:key), '=')
+            ] ifFalse:[
+                envArray at:cnt put:((self encodePath:key), '=', (self encodePath:val))
+            ].
+            cnt := cnt + 1.
+        ].
     ].
     argColl notNil ifTrue:[
-	argArray := argColl asArray collect:[:eachArg| self encodePath:eachArg].
+        argArray := argColl asArray collect:[:eachArg| self encodePath:eachArg].
     ].
     fdColl notNil ifTrue:[
-	fdArray := fdColl asArray
+        fdArray := fdColl asArray
     ].
     aDirectory notNil ifTrue:[
-	dirName := aDirectory asFilename osNameForFile.
-	dirName := self encodePath:dirName.
+        dirName := aDirectory asFilename osNameForFile.
+        dirName := self encodePath:dirName.
     ].
     aCommandPath := self encodePath:aCommandPathArg.
 
@@ -3218,210 +3254,210 @@
     char **_env, **_nEnv;
 
     if (__isStringLike(aCommandPath) &&
-	((argArray == nil) || __isArrayLike(argArray)) &&
-	((fdArray == nil) || __isArrayLike(fdArray))
+        ((argArray == nil) || __isArrayLike(argArray)) &&
+        ((fdArray == nil) || __isArrayLike(fdArray))
     ) {
-	nargs = argArray == nil ? 0 : __arraySize(argArray);
-	argv = (char **) malloc(sizeof(char *) * (nargs + 1));
-	if (argv) {
-	    int nOldEnv, nNewEnv;
-
-	    for (i=0; i < nargs; i++) {
-		arg = __ArrayInstPtr(argArray)->a_element[i];
-		if (__isStringLike(arg)) {
-		    argv[i] = (char *) __stringVal(arg);
-		} else {
-		    argv[i] = "";
-		}
-	    }
-	    argv[i] = NULL;
-
-	    /*
-	     * number of new items in environment ..
-	     */
-	    nNewEnv = 0;
-	    if ((envArray != nil) && __isArrayLike(envArray)) {
-		nNewEnv = __arraySize(envArray);
-	    }
-
-	    if (nNewEnv == 0) {
-		_nEnv = environ;
-	    } else {
-		_env = environ;
-		/*
-		 * get size of environment
-		 */
-		nOldEnv = 0;
-		if (_env) {
-		    while (*_env) {
-			nOldEnv++;
-			_env++;
-		    }
-		}
-
-		/*
-		 * generate a new environment
-		 * I have not found a spec which defines if
-		 * items at the end overwrite previous definitions,
-		 * or if the first encountered definition is valid.
-		 * To be prepared for any case, simply add the new definitions
-		 * at both ends - that should do it in any case.
-		 * Someone with more know-how may want to fix this.
-		 * getenv() searches for the first entry.
-		 * But maybe someone creates a Dictionary from the environment.
-		 * In this case the last entry would overwrite previous entries.
-		 */
-		_nEnv = (char **)malloc(sizeof(char *) * (nNewEnv + nOldEnv + nNewEnv + 1));
-		if (_nEnv) {
-		    char **eO, **eN;
-
-		    eN = _nEnv;
-		    if (nNewEnv) {
-			/*
-			 * add new items at the front ...
-			 */
-			int i;
-			OBJ *t;
-
-			for (i=0, t = __arrayVal(envArray);
-			     i < __arraySize(envArray);
-			     i++, t++) {
-
-			    if (__isStringLike(*t)) {
-				*eN++ = (char *)__stringVal(*t);
-			    }
-			}
-		    }
-
-		    if (nOldEnv) {
-			/*
-			 * append old environment
-			 */
-			for (eO = environ; *eO; *eN++ = *eO++)
-			    continue;
-		    }
-
-		    if (nNewEnv) {
-			/*
-			 * append new items again at the end
-			 */
-			for (eO = _nEnv, i=0; i<nNewEnv; i++) {
-			    *eN++ = *eO++;
-			}
-		    }
-		    *eN = NULL;
-		}
-	    }
-
-	    if (doFork == true) {
-		/*
-		 * fork a subprocess.
-		 */
-		int nfd;
-
-		nfd = fdArray == nil ? 0 : __arraySize(fdArray);
-		id = FORK ();
-		if (id == 0) {
-		    /*
-		    ** In child.
-		    ** first: dup filedescriptors.
-		    */
-		    for (i = 0; i < nfd; i++) {
-			OBJ fd;
-			int rslt;
-
-			fd = __arrayVal(fdArray)[i];
-			if (__isSmallInteger(fd) && (__intVal(fd) != i)) {
-			    do {
-				rslt = dup2(__intVal(fd), i);
-			    } while ((rslt < 0) && (errno == EINTR));
-			}
-		    }
-		    /*
-		    ** Second: close descriptors
-		    **         marked as unwanted
-		    ** (extra loop to allow duping of low filedescriptor numbers to
-		    **  higher fd numbers)
-		    */
-		    for (i = 0; i < nfd; i++) {
-			if (__arrayVal(fdArray)[i] == nil) {
-			    close(i);
-			}
-		    }
-
-		    /*
-		    ** third: close all filedescriptors larger
-		    ** then the explicitely closed or duped
-		    ** filedescriptors
-		    */
+        nargs = argArray == nil ? 0 : __arraySize(argArray);
+        argv = (char **) malloc(sizeof(char *) * (nargs + 1));
+        if (argv) {
+            int nOldEnv, nNewEnv;
+
+            for (i=0; i < nargs; i++) {
+                arg = __ArrayInstPtr(argArray)->a_element[i];
+                if (__isStringLike(arg)) {
+                    argv[i] = (char *) __stringVal(arg);
+                } else {
+                    argv[i] = "";
+                }
+            }
+            argv[i] = NULL;
+
+            /*
+             * number of new items in environment ..
+             */
+            nNewEnv = 0;
+            if ((envArray != nil) && __isArrayLike(envArray)) {
+                nNewEnv = __arraySize(envArray);
+            }
+
+            if (nNewEnv == 0) {
+                _nEnv = environ;
+            } else {
+                _env = environ;
+                /*
+                 * get size of environment
+                 */
+                nOldEnv = 0;
+                if (_env) {
+                    while (*_env) {
+                        nOldEnv++;
+                        _env++;
+                    }
+                }
+
+                /*
+                 * generate a new environment
+                 * I have not found a spec which defines if
+                 * items at the end overwrite previous definitions,
+                 * or if the first encountered definition is valid.
+                 * To be prepared for any case, simply add the new definitions
+                 * at both ends - that should do it in any case.
+                 * Someone with more know-how may want to fix this.
+                 * getenv() searches for the first entry.
+                 * But maybe someone creates a Dictionary from the environment.
+                 * In this case the last entry would overwrite previous entries.
+                 */
+                _nEnv = (char **)malloc(sizeof(char *) * (nNewEnv + nOldEnv + nNewEnv + 1));
+                if (_nEnv) {
+                    char **eO, **eN;
+
+                    eN = _nEnv;
+                    if (nNewEnv) {
+                        /*
+                         * add new items at the front ...
+                         */
+                        int i;
+                        OBJ *t;
+
+                        for (i=0, t = __arrayVal(envArray);
+                             i < __arraySize(envArray);
+                             i++, t++) {
+
+                            if (__isStringLike(*t)) {
+                                *eN++ = (char *)__stringVal(*t);
+                            }
+                        }
+                    }
+
+                    if (nOldEnv) {
+                        /*
+                         * append old environment
+                         */
+                        for (eO = environ; *eO; *eN++ = *eO++)
+                            continue;
+                    }
+
+                    if (nNewEnv) {
+                        /*
+                         * append new items again at the end
+                         */
+                        for (eO = _nEnv, i=0; i<nNewEnv; i++) {
+                            *eN++ = *eO++;
+                        }
+                    }
+                    *eN = NULL;
+                }
+            }
+
+            if (doFork == true) {
+                /*
+                 * fork a subprocess.
+                 */
+                int nfd;
+
+                nfd = fdArray == nil ? 0 : __arraySize(fdArray);
+                id = FORK ();
+                if (id == 0) {
+                    /*
+                    ** In child.
+                    ** first: dup filedescriptors.
+                    */
+                    for (i = 0; i < nfd; i++) {
+                        OBJ fd;
+                        int rslt;
+
+                        fd = __arrayVal(fdArray)[i];
+                        if (__isSmallInteger(fd) && (__intVal(fd) != i)) {
+                            do {
+                                rslt = dup2(__intVal(fd), i);
+                            } while ((rslt < 0) && (errno == EINTR));
+                        }
+                    }
+                    /*
+                    ** Second: close descriptors
+                    **         marked as unwanted
+                    ** (extra loop to allow duping of low filedescriptor numbers to
+                    **  higher fd numbers)
+                    */
+                    for (i = 0; i < nfd; i++) {
+                        if (__arrayVal(fdArray)[i] == nil) {
+                            close(i);
+                        }
+                    }
+
+                    /*
+                    ** third: close all filedescriptors larger
+                    ** then the explicitely closed or duped
+                    ** filedescriptors
+                    */
 #ifndef OPEN_MAX
 # define OPEN_MAX       256
 #endif
-		    for ( ;i < OPEN_MAX; i++) {
-			close(i);
-		    }
-
-		    if (newPgrp == true) {
+                    for ( ;i < OPEN_MAX; i++) {
+                        close(i);
+                    }
+
+                    if (newPgrp == true) {
 #ifndef NEXT
-			setsid();
+                        setsid();
 #endif
 #if defined(TIOCSCTTY)
-			ioctl(0, TIOCSCTTY, 0) ;
+                        ioctl(0, TIOCSCTTY, 0) ;
 #endif
 
 #if defined(TIOCSPGRP)
-			{
-			    int pgrp = getpid();
-
-			    ioctl(0, TIOCSPGRP, (char *)&pgrp);
-			}
+                        {
+                            int pgrp = getpid();
+
+                            ioctl(0, TIOCSPGRP, (char *)&pgrp);
+                        }
 #endif
 #if defined(_POSIX_JOB_CONTROL) || defined(__osx__)
-			(void) setpgid(0, 0);
+                        (void) setpgid(0, 0);
 #else
 # if defined(BSD) || defined(LINUX) || defined(__osx__)
-			(void) setpgrp(0);
-# endif
-#endif
-		    }
-
-		    if (dirName == nil || chdir((char *)__stringVal(dirName)) == 0) {
-			execve((char *)__stringVal(aCommandPath), argv, _nEnv);
-		    }
-		    /* reached if chdir failed or aCommandPathh cannot be executed */
-		    _exit(127);                 /* POSIX 2 compatible exit value */
-		}
-	    } else {
-		/*
-		 * no subprocess (i.e. transfer to another program)
-		 */
-		if (dirName == nil || chdir((char *)__stringVal(dirName)) == 0) {
-		    execve((char *)__stringVal(aCommandPath), argv, _nEnv);
-		}
-		/*
-		 * reached if chdir failed or command-path cannot be executed
-		 */
-		id = -1;
-	    }
-
-	    if (nNewEnv && (_nEnv != NULL)) {
-		/*
-		 * free new environment stuff
-		 */
-		free(_nEnv);
-	    }
-
-	    free(argv);
-
-	    /*
-	     * In parent: succes or failure
-	     */
-	    if (id == -1) {
-		RETURN (nil);
-	    } else {
-		RETURN (__mkSmallInteger(id));
-	    }
-	}
+                        (void) setpgrp(0);
+# endif
+#endif
+                    }
+
+                    if (dirName == nil || chdir((char *)__stringVal(dirName)) == 0) {
+                        execve((char *)__stringVal(aCommandPath), argv, _nEnv);
+                    }
+                    /* reached if chdir failed or aCommandPathh cannot be executed */
+                    _exit(127);                 /* POSIX 2 compatible exit value */
+                }
+            } else {
+                /*
+                 * no subprocess (i.e. transfer to another program)
+                 */
+                if (dirName == nil || chdir((char *)__stringVal(dirName)) == 0) {
+                    execve((char *)__stringVal(aCommandPath), argv, _nEnv);
+                }
+                /*
+                 * reached if chdir failed or command-path cannot be executed
+                 */
+                id = -1;
+            }
+
+            if (nNewEnv && (_nEnv != NULL)) {
+                /*
+                 * free new environment stuff
+                 */
+                free(_nEnv);
+            }
+
+            free(argv);
+
+            /*
+             * In parent: succes or failure
+             */
+            if (id == -1) {
+                RETURN (nil);
+            } else {
+                RETURN (__mkSmallInteger(id));
+            }
+        }
     }
 %}.
     "
@@ -3437,9 +3473,9 @@
 
      id := OperatingSystem fork.
      id == 0 ifTrue:[
-	'I am the child'.
-	OperatingSystem exec:'/bin/ls' withArguments:#('ls' '/tmp').
-	'not reached'.
+        'I am the child'.
+        OperatingSystem exec:'/bin/ls' withArguments:#('ls' '/tmp').
+        'not reached'.
      ]
     "
     "
@@ -3447,11 +3483,11 @@
 
      id := OperatingSystem fork.
      id == 0 ifTrue:[
-	'I am the child'.
-	OperatingSystem
-	   exec:'/bin/sh'
-	   withArguments:#('sh' '-c' 'sleep 2;echo 1;sleep 2;echo 2').
-	'not reached'.
+        'I am the child'.
+        OperatingSystem
+           exec:'/bin/sh'
+           withArguments:#('sh' '-c' 'sleep 2;echo 1;sleep 2;echo 2').
+        'not reached'.
      ].
      id printNL.
      (Delay forSeconds:3.5) wait.