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