# HG changeset patch # User Claus Gittinger # Date 1551608832 -3600 # Node ID 21bbe07f943599e14af58b5de6121d0572c0775b # Parent c713774adb3277f22387951ec46bceaba377ebdb oops diff -r c713774adb32 -r 21bbe07f9435 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 +# define _NET_IF_H_INCLUDED_ +# endif + +# ifndef _SYS_IOCTL_H_INCLUDED_ +# include +# 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 +# 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 " @@ -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