--- 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.