oops
authorClaus Gittinger <cg@exept.de>
Sun, 03 Mar 2019 11:27:12 +0100
changeset 23818 21bbe07f9435
parent 23817 c713774adb32
child 23819 8803cc371eca
oops
UnixOperatingSystem.st
--- a/UnixOperatingSystem.st	Sun Mar 03 11:23:52 2019 +0100
+++ b/UnixOperatingSystem.st	Sun Mar 03 11:27:12 2019 +0100
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
  COPYRIGHT (c) 1988 by Claus Gittinger
 	      All Rights Reserved
@@ -102,7 +104,9 @@
 !
 
 !UnixOperatingSystem primitiveDefinitions!
-fs.h"
+%{
+
+#include "stxOSDefs.h"
 
 #if defined(_AIX)
 # ifndef WANT_REALPATH
@@ -554,10 +558,94 @@
 /*
  * some (old ?) systems do not define this ...
  */
-#if ! !
+#if !defined(R_OK) && !defined(_AIX)
+# define R_OK    4       /* Test for Read permission */
+# define W_OK    2       /* Test for Write permission */
+# define X_OK    1       /* Test for eXecute permission */
+# define F_OK    0       /* Test for existence of File */
+#endif
+
+#define SIGHANDLER_ARG
+
+/*
+ * where is the timezone info ?
+ */
+#ifdef HAS_TM_GMTOFF
+# define TIMEZONE(tmPtr)       (-((tmPtr)->tm_gmtoff))
+#else
+# if defined(HAS_NO_TIMEZONE)
+#  if defined(HAS_NO_TM_GMTOFF)
+#   define TIMEZONE(tmPtr)       0
+#  else
+#   define TIMEZONE(tmPtr)       (-((tmPtr)->tm_gmtoff))
+#  endif
+# else
+#  if defined(HAS_ALTZONE)
+#   define TIMEZONE(tmPtr)       ((tmPtr)->tm_isdst == 0 ? timezone : altzone)
+#  else  /*!HAS_ALTZONE*/
+#   define TIMEZONE(tmPtr)       ((tmPtr)->tm_isdst == 0 ? timezone : timezone-3600)
+#  endif /*!HAS_ALTZONE*/
+# endif
+#endif
+#ifndef CONST
+# ifdef __GNUC__
+#  define CONST const
+# else
+#  define CONST /* nothing */
+# endif
+#endif
+
+#ifndef        FORK
+# if defined(HAS_VFORK)
+#  define     FORK            vfork
+# else
+#  define     FORK            fork
+# endif
+#endif
+
+/*
+ * Socket defines
+ */
+#include "stxOSDefs.h"
+
+#ifdef NET_IF_SUPPORT  /* for mac address of interfaces */
+
+# ifndef _NET_IF_H_INCLUDED_
+#  include <net/if.h>
+#  define _NET_IF_H_INCLUDED_
+# endif
+
+# ifndef _SYS_IOCTL_H_INCLUDED_
+#  include <sys/ioctl.h>
+#  define _SYS_IOCTL_H_INCLUDED_
+# endif
+
+#endif /* NET_IF_SUPPORT */
+
+#if defined(TRY_AGAIN) || defined(HOST_NOT_FOUND)
+# define USE_H_ERRNO
+#endif
+
+#ifdef USE_H_ERRNO
+# ifndef h_errno
+ extern h_errno;
+# endif
+#endif
+
+#if (defined(__ELD__) || defined (ELF))
+# ifndef ELFMAG1
+#  include <elf.h>
+# endif
+#endif
+
+%}
+! !
 
 !UnixOperatingSystem primitiveFunctions!
-s' system() is broken in that it does not correctly
+%{
+
+/*
+ * some systems' system() is broken in that it does not correctly
  * handle EINTR and returns failure even though it actually succeeded.
  * (LINUX is one of them)
  * Here is a fixed version. If you encounter EINTR returns from
@@ -604,7 +692,297 @@
 #  define _SYS_TYPES_H_INCLUDED_
 # endif
 
-# if (! !
+# if (!defined(HAVE_GNU_LD) && !defined (__ELF__)) || !defined(LINUX)
+#  define       __environ       environ
+    extern char **environ;
+# endif
+
+# if !defined (__sigemptyset)
+#  define      __sigemptyset   sigemptyset
+# endif
+# if !defined (__sigaction)
+#  define      __sigaction     sigaction
+#  define      __sigaddset     sigaddset
+#  define      __sigprocmask   sigprocmask
+#  define      __execve        execve
+#  define      __wait          wait
+#  define      __waitpid       waitpid
+# endif /* ! LINUX */
+
+# define      __sigprocmask   sigprocmask
+# define      __execve        execve
+
+# define        SHELL_PATH      "/bin/sh"       /* Path of the shell.  */
+# define        SHELL_NAME      "sh"            /* Name to give it.  */
+
+
+static int
+mySystem(const char *line)
+{
+    int status, save;
+    pid_t pid;
+    struct sigaction sa, intr, quit;
+    sigset_t block, omask;
+
+    if (line == NULL)
+	return -1;
+
+    sa.sa_handler = SIG_IGN;
+    sa.sa_flags = 0;
+    __sigemptyset (&sa.sa_mask);
+
+    if (__sigaction (SIGINT, &sa, &intr) < 0) {
+	DPRINTF(("1: errno=%d\n", errno));
+	return -1;
+    }
+    if (__sigaction (SIGQUIT, &sa, &quit) < 0) {
+	save = errno;
+	(void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+	errno = save;
+	DPRINTF(("2: errno=%d\n", errno));
+	return -1;
+    }
+
+    __sigemptyset (&block);
+    __sigaddset (&block, SIGCHLD);
+    save = errno;
+    if (__sigprocmask(SIG_BLOCK, &block, &omask) < 0) {
+	if (errno == ENOSYS)
+	    errno = save;
+	else {
+	    save = errno;
+	    (void) __sigaction(SIGINT, &intr, (struct sigaction *) NULL);
+	    (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+	    errno = save;
+	    DPRINTF(("3: errno=%d\n", errno));
+	    return -1;
+	}
+    }
+
+    pid = FORK();
+    if (pid == (pid_t) 0) {
+	/* Child side.  */
+	CONST char *new_argv[4];
+	new_argv[0] = SHELL_NAME;
+	new_argv[1] = "-c";
+	new_argv[2] = line;
+	new_argv[3] = NULL;
+
+	/* Restore the signals.  */
+	(void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+	(void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+	(void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
+
+	/* Exec the shell.  */
+	(void) __execve (SHELL_PATH, (char *CONST *) new_argv, __environ);
+	_exit (127);
+    } else {
+	if (pid < (pid_t) 0) {
+	    /* The fork failed.  */
+	    DPRINTF(("4: errno=%d\n", errno));
+	    status = -1;
+	} else {
+	    /* Parent side.  */
+#ifdef  NO_WAITPID
+	    pid_t child;
+
+	    do {
+		__BEGIN_INTERRUPTABLE__
+		child = __wait (&status);
+		__END_INTERRUPTABLE__
+		if (child < 0 && errno != EINTR) {
+		    DPRINTF(("5: errno=%d\n", errno));
+		    status = -1;
+		    break;
+		}
+	    } while (child != pid);
+#else
+	    pid_t child;
+
+	    /* claus: the original did not care for EINTR here ... */
+	    do {
+		__BEGIN_INTERRUPTABLE__
+		child = __waitpid (pid, &status, 0);
+		__END_INTERRUPTABLE__
+	    } while ((child != pid) && (errno == EINTR));
+	    if (child != pid) {
+		DPRINTF(("6: errno=%d\n", errno));
+		status = -1;
+	    }
+#endif /* NO_WAITPID */
+	}
+    }
+    save = errno;
+    if ((__sigaction (SIGINT, &intr, (struct sigaction *) NULL)
+     | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)
+     | __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL)) != 0) {
+	if (errno == ENOSYS) {
+	    errno = save;
+	} else {
+	    status = -1;
+	    DPRINTF(("7: errno=%d\n", errno));
+	}
+    }
+
+    return status;
+}
+#else
+# define __wait wait
+#endif /* WANT_SYSTEM */
+
+
+/*
+ * some systems do not have realpath();
+ * the alternative of reading from a 'pwd'-pipe
+ * is way too slow. Here is a realpath for the rest of us.
+ * define WANT_REALPATH in the xxxIntern-file to get it.
+ */
+
+#if defined(HAS_REALPATH)
+# undef WANT_REALPATH
+#endif
+#if !defined(HAS_GETWD) && !defined(HAS_GETCWD)
+# undef WANT_REALPATH
+#endif
+
+#if defined(WANT_REALPATH)
+
+# ifndef NULL
+#  define NULL (char *)0
+# endif
+
+# define MAX_READLINKS 32
+
+# ifndef MAXPATHLEN
+#  define MAXPATHLEN     1024
+# endif
+
+static char *
+realpath(const char *path, char *resolved_path)
+{
+	char copy_path[MAXPATHLEN];
+	char link_path[MAXPATHLEN];
+	char *new_path, *max_path, *mallocedPath;
+	int readlinks = 0;
+	int n;
+
+	if (resolved_path == NULL) {
+	    mallocedPath = resolved_path = malloc(MAXPATHLEN+1);
+	}
+	new_path = resolved_path;
+
+	/* Make a copy of the source path since we may need to modify it. */
+	strcpy(copy_path, path);
+	path = copy_path;
+	max_path = copy_path + MAXPATHLEN - 2;
+	/* If it's a relative pathname use getwd for starters. */
+	if (*path != '/') {
+#ifdef HAS_GETCWD
+		new_path = getcwd(new_path, MAXPATHLEN - 1);
+#else
+		new_path = getwd(new_path);
+#endif
+		if (new_path == NULL) {
+		    if (mallocedPath) free(mallocedPath);
+		    return(NULL);
+		}
+
+		new_path += strlen(new_path);
+		if (new_path[-1] != '/')
+			*new_path++ = '/';
+	}
+	else {
+		*new_path++ = '/';
+		path++;
+	}
+	/* Expand each slash-separated pathname component. */
+	while (*path != '\0') {
+		/* Ignore stray "/". */
+		if (*path == '/') {
+			path++;
+			continue;
+		}
+		if (*path == '.') {
+			/* Ignore ".". */
+			if (path[1] == '\0' || path[1] == '/') {
+				path++;
+				continue;
+			}
+			if (path[1] == '.') {
+				if (path[2] == '\0' || path[2] == '/') {
+					path += 2;
+					/* Ignore ".." at root. */
+					if (new_path == resolved_path + 1)
+						continue;
+					/* Handle ".." by backing up. */
+					while ((--new_path)[-1] != '/')
+						;
+					continue;
+				}
+			}
+		}
+		/* Safely copy the next pathname component. */
+		while (*path != '\0' && *path != '/') {
+			if (path > max_path) {
+			    if (mallocedPath) free(mallocedPath);
+			    errno = ENAMETOOLONG;
+			    return NULL;
+			}
+			*new_path++ = *path++;
+		}
+#ifdef S_IFLNK
+		/* Protect against infinite loops. */
+		if (readlinks++ > MAX_READLINKS) {
+		    if (mallocedPath) free(mallocedPath);
+		    errno = ELOOP;
+		    return NULL;
+		}
+		/* See if latest pathname component is a symlink. */
+		*new_path = '\0';
+		n = readlink(resolved_path, link_path, MAXPATHLEN - 1);
+		if (n < 0) {
+			/* EINVAL means the file exists but isn't a symlink. */
+			if (errno != EINVAL) {
+			    if (mallocedPath) free(mallocedPath);
+			    return NULL;
+			}
+		}
+		else {
+			/* Note: readlink doesn't add the null byte. */
+			link_path[n] = '\0';
+			if (*link_path == '/')
+				/* Start over for an absolute symlink. */
+				new_path = resolved_path;
+			else
+				/* Otherwise back up over this component. */
+				while (*(--new_path) != '/')
+					;
+			/* Safe sex check. */
+			if (strlen(path) + n >= MAXPATHLEN) {
+			    if (mallocedPath) free(mallocedPath);
+			    errno = ENAMETOOLONG;
+			    return NULL;
+			}
+			/* Insert symlink contents into path. */
+			strcat(link_path, path);
+			strcpy(copy_path, link_path);
+			path = copy_path;
+		}
+#endif /* S_IFLNK */
+		*new_path++ = '/';
+	}
+	/* Delete trailing slash but don't whomp a lone slash. */
+	if (new_path != resolved_path + 1 && new_path[-1] == '/')
+		new_path--;
+	/* Make sure it's null terminated. */
+	*new_path = '\0';
+	return resolved_path;
+}
+# define HAS_REALPATH
+#endif /* WANT_REALPATH && not HAS_REALPATH */
+
+%}
+! !
 
 !UnixOperatingSystem class methodsFor:'documentation'!
 
@@ -9316,7 +9694,7 @@
      Codeset := #'utf8-mac'.
      CodesetEncoder := nil.
      OperatingSystem getCodesetEncoder
-     OperatingSystem encodePath:'äöü'
+     OperatingSystem encodePath:'äöü'
     "
 
     "Modified: / 23-01-2013 / 10:00:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
@@ -13078,106 +13456,102 @@
     |result domain type proto encodedHostName|
 
     domainArg notNil ifTrue:[
-        domain := OperatingSystem domainCodeOf:domainArg.
+	domain := OperatingSystem domainCodeOf:domainArg.
     ].
     typeArg notNil ifTrue:[
-        type := OperatingSystem socketTypeCodeOf:typeArg.
+	type := OperatingSystem socketTypeCodeOf:typeArg.
     ].
     protoArg notNil ifTrue:[
-        proto := self protocolCodeOf:protoArg.
+	proto := self protocolCodeOf:protoArg.
     ].
 
     hostName isNil ifTrue:[
-        encodedHostName := nil.
+	encodedHostName := nil.
     ] ifFalse:[
-        encodedHostName := hostName utf8Encoded.
+	encodedHostName := hostName utf8Encoded.
     ].
     (encodedHostName ~~ hostName and:[OperatingSystem getCodeset ~~ #utf8]) ifTrue:[
-        "hostName is not plain ASCII - so this is an IDN domain name. Have to ensure, that the locale is UTF-8.
-         Block interrupt to not affect other ST/X processes while the locale is changed."
-        |interruptsBlocked oldLocale|
-
-        interruptsBlocked := OperatingSystem blockInterrupts.
-        oldLocale := OperatingSystem setLocale:#'LC_CTYPE' to:nil.
-        OperatingSystem setLocale:#'LC_CTYPE' to:'en_US.UTF-8'.
-        result := self primGetAddressInfo:encodedHostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags.
-        OperatingSystem setLocale:#'LC_CTYPE' to:oldLocale.
-        interruptsBlocked ifFalse:[
-            OperatingSystem unblockInterrupts.
-        ].
+	"hostName is not plain ASCII - so this is an IDN domain name. Have to ensure, that the locale is UTF-8.
+	 Block interrupt to not affect other ST/X processes while the locale is changed."
+	|interruptsBlocked oldLocale|
+
+	interruptsBlocked := OperatingSystem blockInterrupts.
+	oldLocale := OperatingSystem setLocale:#'LC_CTYPE' to:nil.
+	OperatingSystem setLocale:#'LC_CTYPE' to:'en_US.UTF-8'.
+	result := self primGetAddressInfo:encodedHostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags.
+	OperatingSystem setLocale:#'LC_CTYPE' to:oldLocale.
+	interruptsBlocked ifFalse:[
+	    OperatingSystem unblockInterrupts.
+	].
     ] ifFalse:[
-        result := self primGetAddressInfo:encodedHostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags.
+	result := self primGetAddressInfo:encodedHostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags.
     ].
     result isArray ifFalse:[
-        |request|
-        request := SocketAddressInfo new
-            domain:domainArg;
-            type:typeArg;
-            protocol:protoArg;
-            canonicalName:hostName;
-            serviceName:serviceName.
-        ^ (HostNameLookupError new
-                parameter:result;
-                messageText:' - ', (result printString);
-                request:request) raiseRequest.
+	|request|
+	request := SocketAddressInfo new
+	    domain:domainArg;
+	    type:typeArg;
+	    protocol:protoArg;
+	    canonicalName:hostName;
+	    serviceName:serviceName.
+	^ (HostNameLookupError new
+		parameter:result;
+		messageText:' - ', (result printString);
+		request:request) raiseRequest.
     ].
     1 to:result size do:[:i |
-        |entry dom info|
-
-        entry := result at:i.
-
-        info := SocketAddressInfo new.
-        info
-            flags:(entry at:1);
-            domain:(dom := OperatingSystem domainSymbolOf:(entry at:2));
-            type:(OperatingSystem socketTypeSymbolOf:(entry at:3));
-            protocol:(self protocolSymbolOf:(entry at:4));
-            socketAddress:((SocketAddress newDomain:dom) fromBytes:(entry at:5));
-            canonicalName:(entry at:6).
-
-        result at:i put:info.
+	|entry dom info|
+
+	entry := result at:i.
+
+	info := SocketAddressInfo new.
+	info
+	    flags:(entry at:1);
+	    domain:(dom := OperatingSystem domainSymbolOf:(entry at:2));
+	    type:(OperatingSystem socketTypeSymbolOf:(entry at:3));
+	    protocol:(self protocolSymbolOf:(entry at:4));
+	    socketAddress:((SocketAddress newDomain:dom) fromBytes:(entry at:5));
+	    canonicalName:(entry at:6).
+
+	result at:i put:info.
     ].
     ^ result.
 
 
     "
      self getAddressInfo:'localhost' serviceName:nil
-            domain:nil type:nil protocol:nil flags:nil
+	    domain:nil type:nil protocol:nil flags:nil
      self getAddressInfo:nil serviceName:22
-            domain:nil type:nil protocol:nil flags:nil
+	    domain:nil type:nil protocol:nil flags:nil
      self getAddressInfo:'' serviceName:22
-            domain:nil type:nil protocol:nil flags:nil
+	    domain:nil type:nil protocol:nil flags:nil
      self getAddressInfo:'localhost' serviceName:nil
-            domain:nil type:#stream protocol:nil flags:nil
+	    domain:nil type:#stream protocol:nil flags:nil
      self getAddressInfo:'localhost' serviceName:nil
-            domain:#inet type:#stream protocol:#tcp flags:nil
+	    domain:#inet type:#stream protocol:#tcp flags:nil
      self getAddressInfo:'blurb.exept.de' serviceName:nil
-            domain:#inet type:nil protocol:nil flags:nil
+	    domain:#inet type:nil protocol:nil flags:nil
      self getAddressInfo:'1.2.3.4' serviceName:'bla'
-            domain:#inet type:nil protocol:nil flags:nil
+	    domain:#inet type:nil protocol:nil flags:nil
      self getAddressInfo:'localhost' serviceName:'echo'
-            domain:#inet type:nil protocol:nil flags:nil
+	    domain:#inet type:nil protocol:nil flags:nil
      self getAddressInfo:nil serviceName:'echo'
-            domain:#inet type:nil protocol:nil flags:nil
+	    domain:#inet type:nil protocol:nil flags:nil
      self getAddressInfo:nil serviceName:nil
-            domain:#inet type:nil protocol:nil flags:nil
+	    domain:#inet type:nil protocol:nil flags:nil
      self getAddressInfo:'www.google.de' serviceName:80
-            domain:nil type:nil protocol:nil flags:nil
+	    domain:nil type:nil protocol:nil flags:nil
      self getAddressInfo:'www.exept.de' serviceName:nil
-            domain:nil type:nil protocol:nil flags:nil
-     self getAddressInfo:'www.exept.de' serviceName:'https'
-            domain:#'AF_INET' type:nil protocol:nil flags:nil
+	    domain:nil type:nil protocol:nil flags:nil
      self getAddressInfo:'www.exept.de' serviceName:'https'
-            domain:#'AF_UNSPEC' type:nil protocol:nil flags:nil
+	    domain:#'AF_INET' type:nil protocol:nil flags:nil
      self getAddressInfo:'www.exept.de' serviceName:nil
-            domain:#'AF_INET6' type:nil protocol:nil flags:nil
-     self getAddressInfo:'www.baden-württemberg.de' serviceName:nil
-            domain:#'AF_INET' type:#stream protocol:nil flags:nil
-     self getAddressInfo:'www.baden-württemberg.de' serviceName:nil
-            domain:#'AF_INET6' type:#stream protocol:nil flags:nil
-    "
-
-    "Modified: / 03-03-2019 / 11:23:38 / Claus Gittinger"
+	    domain:#'AF_INET6' type:nil protocol:nil flags:nil
+     self getAddressInfo:'www.baden-württemberg.de' serviceName:nil
+	    domain:#'AF_INET' type:#stream protocol:nil flags:nil
+     self getAddressInfo:'www.baden-württemberg.de' serviceName:nil
+	    domain:#'AF_INET6' type:#stream protocol:nil flags:nil
+    "
 !
 
 getNameInfo:socketAddress wantHostName:wantHostName wantServiceName:wantServiceName datagram:useDatagram flags:flags