UnixOperatingSystem.st
changeset 23817 c713774adb32
parent 23816 1656c246ca09
child 23818 21bbe07f9435
equal deleted inserted replaced
23816:1656c246ca09 23817:c713774adb32
   100 	poolDictionaries:''
   100 	poolDictionaries:''
   101 	privateIn:UnixOperatingSystem
   101 	privateIn:UnixOperatingSystem
   102 !
   102 !
   103 
   103 
   104 !UnixOperatingSystem primitiveDefinitions!
   104 !UnixOperatingSystem primitiveDefinitions!
   105 %{
   105 fs.h"
   106 
       
   107 #include "stxOSDefs.h"
       
   108 
   106 
   109 #if defined(_AIX)
   107 #if defined(_AIX)
   110 # ifndef WANT_REALPATH
   108 # ifndef WANT_REALPATH
   111 #  define WANT_REALPATH
   109 #  define WANT_REALPATH
   112 # endif
   110 # endif
   554 #endif
   552 #endif
   555 
   553 
   556 /*
   554 /*
   557  * some (old ?) systems do not define this ...
   555  * some (old ?) systems do not define this ...
   558  */
   556  */
   559 #if !defined(R_OK) && !defined(_AIX)
   557 #if ! !
   560 # define R_OK    4       /* Test for Read permission */
       
   561 # define W_OK    2       /* Test for Write permission */
       
   562 # define X_OK    1       /* Test for eXecute permission */
       
   563 # define F_OK    0       /* Test for existence of File */
       
   564 #endif
       
   565 
       
   566 #define SIGHANDLER_ARG
       
   567 
       
   568 /*
       
   569  * where is the timezone info ?
       
   570  */
       
   571 #ifdef HAS_TM_GMTOFF
       
   572 # define TIMEZONE(tmPtr)       (-((tmPtr)->tm_gmtoff))
       
   573 #else
       
   574 # if defined(HAS_NO_TIMEZONE)
       
   575 #  if defined(HAS_NO_TM_GMTOFF)
       
   576 #   define TIMEZONE(tmPtr)       0
       
   577 #  else
       
   578 #   define TIMEZONE(tmPtr)       (-((tmPtr)->tm_gmtoff))
       
   579 #  endif
       
   580 # else
       
   581 #  if defined(HAS_ALTZONE)
       
   582 #   define TIMEZONE(tmPtr)       ((tmPtr)->tm_isdst == 0 ? timezone : altzone)
       
   583 #  else  /*!HAS_ALTZONE*/
       
   584 #   define TIMEZONE(tmPtr)       ((tmPtr)->tm_isdst == 0 ? timezone : timezone-3600)
       
   585 #  endif /*!HAS_ALTZONE*/
       
   586 # endif
       
   587 #endif
       
   588 #ifndef CONST
       
   589 # ifdef __GNUC__
       
   590 #  define CONST const
       
   591 # else
       
   592 #  define CONST /* nothing */
       
   593 # endif
       
   594 #endif
       
   595 
       
   596 #ifndef        FORK
       
   597 # if defined(HAS_VFORK)
       
   598 #  define     FORK            vfork
       
   599 # else
       
   600 #  define     FORK            fork
       
   601 # endif
       
   602 #endif
       
   603 
       
   604 /*
       
   605  * Socket defines
       
   606  */
       
   607 #include "stxOSDefs.h"
       
   608 
       
   609 #ifdef NET_IF_SUPPORT  /* for mac address of interfaces */
       
   610 
       
   611 # ifndef _NET_IF_H_INCLUDED_
       
   612 #  include <net/if.h>
       
   613 #  define _NET_IF_H_INCLUDED_
       
   614 # endif
       
   615 
       
   616 # ifndef _SYS_IOCTL_H_INCLUDED_
       
   617 #  include <sys/ioctl.h>
       
   618 #  define _SYS_IOCTL_H_INCLUDED_
       
   619 # endif
       
   620 
       
   621 #endif /* NET_IF_SUPPORT */
       
   622 
       
   623 #if defined(TRY_AGAIN) || defined(HOST_NOT_FOUND)
       
   624 # define USE_H_ERRNO
       
   625 #endif
       
   626 
       
   627 #ifdef USE_H_ERRNO
       
   628 # ifndef h_errno
       
   629  extern h_errno;
       
   630 # endif
       
   631 #endif
       
   632 
       
   633 #if (defined(__ELD__) || defined (ELF))
       
   634 # ifndef ELFMAG1
       
   635 #  include <elf.h>
       
   636 # endif
       
   637 #endif
       
   638 
       
   639 %}
       
   640 ! !
       
   641 
   558 
   642 !UnixOperatingSystem primitiveFunctions!
   559 !UnixOperatingSystem primitiveFunctions!
   643 %{
   560 s' system() is broken in that it does not correctly
   644 
       
   645 /*
       
   646  * some systems' system() is broken in that it does not correctly
       
   647  * handle EINTR and returns failure even though it actually succeeded.
   561  * handle EINTR and returns failure even though it actually succeeded.
   648  * (LINUX is one of them)
   562  * (LINUX is one of them)
   649  * Here is a fixed version. If you encounter EINTR returns from
   563  * Here is a fixed version. If you encounter EINTR returns from
   650  * UnixOperatingSystem>>executeCommand, you ought to define WANT_SYSTEM
   564  * UnixOperatingSystem>>executeCommand, you ought to define WANT_SYSTEM
   651  * in the xxxIntern.h file to get this fixed version.
   565  * in the xxxIntern.h file to get this fixed version.
   688 # ifndef _SYS_TYPES_H_INCLUDED_
   602 # ifndef _SYS_TYPES_H_INCLUDED_
   689 #  include <sys/types.h>
   603 #  include <sys/types.h>
   690 #  define _SYS_TYPES_H_INCLUDED_
   604 #  define _SYS_TYPES_H_INCLUDED_
   691 # endif
   605 # endif
   692 
   606 
   693 # if (!defined(HAVE_GNU_LD) && !defined (__ELF__)) || !defined(LINUX)
   607 # if (! !
   694 #  define       __environ       environ
       
   695     extern char **environ;
       
   696 # endif
       
   697 
       
   698 # if !defined (__sigemptyset)
       
   699 #  define      __sigemptyset   sigemptyset
       
   700 # endif
       
   701 # if !defined (__sigaction)
       
   702 #  define      __sigaction     sigaction
       
   703 #  define      __sigaddset     sigaddset
       
   704 #  define      __sigprocmask   sigprocmask
       
   705 #  define      __execve        execve
       
   706 #  define      __wait          wait
       
   707 #  define      __waitpid       waitpid
       
   708 # endif /* ! LINUX */
       
   709 
       
   710 # define      __sigprocmask   sigprocmask
       
   711 # define      __execve        execve
       
   712 
       
   713 # define        SHELL_PATH      "/bin/sh"       /* Path of the shell.  */
       
   714 # define        SHELL_NAME      "sh"            /* Name to give it.  */
       
   715 
       
   716 
       
   717 static int
       
   718 mySystem(const char *line)
       
   719 {
       
   720     int status, save;
       
   721     pid_t pid;
       
   722     struct sigaction sa, intr, quit;
       
   723     sigset_t block, omask;
       
   724 
       
   725     if (line == NULL)
       
   726 	return -1;
       
   727 
       
   728     sa.sa_handler = SIG_IGN;
       
   729     sa.sa_flags = 0;
       
   730     __sigemptyset (&sa.sa_mask);
       
   731 
       
   732     if (__sigaction (SIGINT, &sa, &intr) < 0) {
       
   733 	DPRINTF(("1: errno=%d\n", errno));
       
   734 	return -1;
       
   735     }
       
   736     if (__sigaction (SIGQUIT, &sa, &quit) < 0) {
       
   737 	save = errno;
       
   738 	(void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
       
   739 	errno = save;
       
   740 	DPRINTF(("2: errno=%d\n", errno));
       
   741 	return -1;
       
   742     }
       
   743 
       
   744     __sigemptyset (&block);
       
   745     __sigaddset (&block, SIGCHLD);
       
   746     save = errno;
       
   747     if (__sigprocmask(SIG_BLOCK, &block, &omask) < 0) {
       
   748 	if (errno == ENOSYS)
       
   749 	    errno = save;
       
   750 	else {
       
   751 	    save = errno;
       
   752 	    (void) __sigaction(SIGINT, &intr, (struct sigaction *) NULL);
       
   753 	    (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
       
   754 	    errno = save;
       
   755 	    DPRINTF(("3: errno=%d\n", errno));
       
   756 	    return -1;
       
   757 	}
       
   758     }
       
   759 
       
   760     pid = FORK();
       
   761     if (pid == (pid_t) 0) {
       
   762 	/* Child side.  */
       
   763 	CONST char *new_argv[4];
       
   764 	new_argv[0] = SHELL_NAME;
       
   765 	new_argv[1] = "-c";
       
   766 	new_argv[2] = line;
       
   767 	new_argv[3] = NULL;
       
   768 
       
   769 	/* Restore the signals.  */
       
   770 	(void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
       
   771 	(void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
       
   772 	(void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
       
   773 
       
   774 	/* Exec the shell.  */
       
   775 	(void) __execve (SHELL_PATH, (char *CONST *) new_argv, __environ);
       
   776 	_exit (127);
       
   777     } else {
       
   778 	if (pid < (pid_t) 0) {
       
   779 	    /* The fork failed.  */
       
   780 	    DPRINTF(("4: errno=%d\n", errno));
       
   781 	    status = -1;
       
   782 	} else {
       
   783 	    /* Parent side.  */
       
   784 #ifdef  NO_WAITPID
       
   785 	    pid_t child;
       
   786 
       
   787 	    do {
       
   788 		__BEGIN_INTERRUPTABLE__
       
   789 		child = __wait (&status);
       
   790 		__END_INTERRUPTABLE__
       
   791 		if (child < 0 && errno != EINTR) {
       
   792 		    DPRINTF(("5: errno=%d\n", errno));
       
   793 		    status = -1;
       
   794 		    break;
       
   795 		}
       
   796 	    } while (child != pid);
       
   797 #else
       
   798 	    pid_t child;
       
   799 
       
   800 	    /* claus: the original did not care for EINTR here ... */
       
   801 	    do {
       
   802 		__BEGIN_INTERRUPTABLE__
       
   803 		child = __waitpid (pid, &status, 0);
       
   804 		__END_INTERRUPTABLE__
       
   805 	    } while ((child != pid) && (errno == EINTR));
       
   806 	    if (child != pid) {
       
   807 		DPRINTF(("6: errno=%d\n", errno));
       
   808 		status = -1;
       
   809 	    }
       
   810 #endif /* NO_WAITPID */
       
   811 	}
       
   812     }
       
   813     save = errno;
       
   814     if ((__sigaction (SIGINT, &intr, (struct sigaction *) NULL)
       
   815      | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)
       
   816      | __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL)) != 0) {
       
   817 	if (errno == ENOSYS) {
       
   818 	    errno = save;
       
   819 	} else {
       
   820 	    status = -1;
       
   821 	    DPRINTF(("7: errno=%d\n", errno));
       
   822 	}
       
   823     }
       
   824 
       
   825     return status;
       
   826 }
       
   827 #else
       
   828 # define __wait wait
       
   829 #endif /* WANT_SYSTEM */
       
   830 
       
   831 
       
   832 /*
       
   833  * some systems do not have realpath();
       
   834  * the alternative of reading from a 'pwd'-pipe
       
   835  * is way too slow. Here is a realpath for the rest of us.
       
   836  * define WANT_REALPATH in the xxxIntern-file to get it.
       
   837  */
       
   838 
       
   839 #if defined(HAS_REALPATH)
       
   840 # undef WANT_REALPATH
       
   841 #endif
       
   842 #if !defined(HAS_GETWD) && !defined(HAS_GETCWD)
       
   843 # undef WANT_REALPATH
       
   844 #endif
       
   845 
       
   846 #if defined(WANT_REALPATH)
       
   847 
       
   848 # ifndef NULL
       
   849 #  define NULL (char *)0
       
   850 # endif
       
   851 
       
   852 # define MAX_READLINKS 32
       
   853 
       
   854 # ifndef MAXPATHLEN
       
   855 #  define MAXPATHLEN     1024
       
   856 # endif
       
   857 
       
   858 static char *
       
   859 realpath(const char *path, char *resolved_path)
       
   860 {
       
   861 	char copy_path[MAXPATHLEN];
       
   862 	char link_path[MAXPATHLEN];
       
   863 	char *new_path, *max_path, *mallocedPath;
       
   864 	int readlinks = 0;
       
   865 	int n;
       
   866 
       
   867 	if (resolved_path == NULL) {
       
   868 	    mallocedPath = resolved_path = malloc(MAXPATHLEN+1);
       
   869 	}
       
   870 	new_path = resolved_path;
       
   871 
       
   872 	/* Make a copy of the source path since we may need to modify it. */
       
   873 	strcpy(copy_path, path);
       
   874 	path = copy_path;
       
   875 	max_path = copy_path + MAXPATHLEN - 2;
       
   876 	/* If it's a relative pathname use getwd for starters. */
       
   877 	if (*path != '/') {
       
   878 #ifdef HAS_GETCWD
       
   879 		new_path = getcwd(new_path, MAXPATHLEN - 1);
       
   880 #else
       
   881 		new_path = getwd(new_path);
       
   882 #endif
       
   883 		if (new_path == NULL) {
       
   884 		    if (mallocedPath) free(mallocedPath);
       
   885 		    return(NULL);
       
   886 		}
       
   887 
       
   888 		new_path += strlen(new_path);
       
   889 		if (new_path[-1] != '/')
       
   890 			*new_path++ = '/';
       
   891 	}
       
   892 	else {
       
   893 		*new_path++ = '/';
       
   894 		path++;
       
   895 	}
       
   896 	/* Expand each slash-separated pathname component. */
       
   897 	while (*path != '\0') {
       
   898 		/* Ignore stray "/". */
       
   899 		if (*path == '/') {
       
   900 			path++;
       
   901 			continue;
       
   902 		}
       
   903 		if (*path == '.') {
       
   904 			/* Ignore ".". */
       
   905 			if (path[1] == '\0' || path[1] == '/') {
       
   906 				path++;
       
   907 				continue;
       
   908 			}
       
   909 			if (path[1] == '.') {
       
   910 				if (path[2] == '\0' || path[2] == '/') {
       
   911 					path += 2;
       
   912 					/* Ignore ".." at root. */
       
   913 					if (new_path == resolved_path + 1)
       
   914 						continue;
       
   915 					/* Handle ".." by backing up. */
       
   916 					while ((--new_path)[-1] != '/')
       
   917 						;
       
   918 					continue;
       
   919 				}
       
   920 			}
       
   921 		}
       
   922 		/* Safely copy the next pathname component. */
       
   923 		while (*path != '\0' && *path != '/') {
       
   924 			if (path > max_path) {
       
   925 			    if (mallocedPath) free(mallocedPath);
       
   926 			    errno = ENAMETOOLONG;
       
   927 			    return NULL;
       
   928 			}
       
   929 			*new_path++ = *path++;
       
   930 		}
       
   931 #ifdef S_IFLNK
       
   932 		/* Protect against infinite loops. */
       
   933 		if (readlinks++ > MAX_READLINKS) {
       
   934 		    if (mallocedPath) free(mallocedPath);
       
   935 		    errno = ELOOP;
       
   936 		    return NULL;
       
   937 		}
       
   938 		/* See if latest pathname component is a symlink. */
       
   939 		*new_path = '\0';
       
   940 		n = readlink(resolved_path, link_path, MAXPATHLEN - 1);
       
   941 		if (n < 0) {
       
   942 			/* EINVAL means the file exists but isn't a symlink. */
       
   943 			if (errno != EINVAL) {
       
   944 			    if (mallocedPath) free(mallocedPath);
       
   945 			    return NULL;
       
   946 			}
       
   947 		}
       
   948 		else {
       
   949 			/* Note: readlink doesn't add the null byte. */
       
   950 			link_path[n] = '\0';
       
   951 			if (*link_path == '/')
       
   952 				/* Start over for an absolute symlink. */
       
   953 				new_path = resolved_path;
       
   954 			else
       
   955 				/* Otherwise back up over this component. */
       
   956 				while (*(--new_path) != '/')
       
   957 					;
       
   958 			/* Safe sex check. */
       
   959 			if (strlen(path) + n >= MAXPATHLEN) {
       
   960 			    if (mallocedPath) free(mallocedPath);
       
   961 			    errno = ENAMETOOLONG;
       
   962 			    return NULL;
       
   963 			}
       
   964 			/* Insert symlink contents into path. */
       
   965 			strcat(link_path, path);
       
   966 			strcpy(copy_path, link_path);
       
   967 			path = copy_path;
       
   968 		}
       
   969 #endif /* S_IFLNK */
       
   970 		*new_path++ = '/';
       
   971 	}
       
   972 	/* Delete trailing slash but don't whomp a lone slash. */
       
   973 	if (new_path != resolved_path + 1 && new_path[-1] == '/')
       
   974 		new_path--;
       
   975 	/* Make sure it's null terminated. */
       
   976 	*new_path = '\0';
       
   977 	return resolved_path;
       
   978 }
       
   979 # define HAS_REALPATH
       
   980 #endif /* WANT_REALPATH && not HAS_REALPATH */
       
   981 
       
   982 %}
       
   983 ! !
       
   984 
   608 
   985 !UnixOperatingSystem class methodsFor:'documentation'!
   609 !UnixOperatingSystem class methodsFor:'documentation'!
   986 
   610 
   987 copyright
   611 copyright
   988 "
   612 "
 13449      Domain, type, protocol may be nil or specify a hint for the socket
 13073      Domain, type, protocol may be nil or specify a hint for the socket
 13450      addresses to be returned.
 13074      addresses to be returned.
 13451      The sorting function used within getaddrinfo() is defined in RFC 3484; in linux the order can be
 13075      The sorting function used within getaddrinfo() is defined in RFC 3484; in linux the order can be
 13452      tweaked for a particular system by editing /etc/gai.conf"
 13076      tweaked for a particular system by editing /etc/gai.conf"
 13453 
 13077 
 13454     |result domain type proto encodedHostName os|
 13078     |result domain type proto encodedHostName|
 13455 
 13079 
 13456     os := OperatingSystem.
       
 13457     
       
 13458     domainArg notNil ifTrue:[
 13080     domainArg notNil ifTrue:[
 13459         domain := os domainCodeOf:domainArg.
 13081         domain := OperatingSystem domainCodeOf:domainArg.
 13460     ].
 13082     ].
 13461     typeArg notNil ifTrue:[
 13083     typeArg notNil ifTrue:[
 13462         type := os socketTypeCodeOf:typeArg.
 13084         type := OperatingSystem socketTypeCodeOf:typeArg.
 13463     ].
 13085     ].
 13464     protoArg notNil ifTrue:[
 13086     protoArg notNil ifTrue:[
 13465         proto := self protocolCodeOf:protoArg.
 13087         proto := self protocolCodeOf:protoArg.
 13466     ].
 13088     ].
 13467 
 13089 
 13468     hostName isNil ifTrue:[
 13090     hostName isNil ifTrue:[
 13469         encodedHostName := nil.
 13091         encodedHostName := nil.
 13470     ] ifFalse:[
 13092     ] ifFalse:[
 13471         encodedHostName := hostName utf8Encoded.
 13093         encodedHostName := hostName utf8Encoded.
 13472     ].
 13094     ].
 13473     (encodedHostName ~~ hostName and:[os getCodeset ~~ #utf8]) ifTrue:[
 13095     (encodedHostName ~~ hostName and:[OperatingSystem getCodeset ~~ #utf8]) ifTrue:[
 13474         "hostName is not plain ASCII - so this is an IDN domain name. Have to ensure, that the locale is UTF-8.
 13096         "hostName is not plain ASCII - so this is an IDN domain name. Have to ensure, that the locale is UTF-8.
 13475          Block interrupt to not affect other ST/X processes while the locale is changed."
 13097          Block interrupt to not affect other ST/X processes while the locale is changed."
 13476         |interruptsBlocked oldLocale|
 13098         |interruptsBlocked oldLocale|
 13477 
 13099 
 13478         interruptsBlocked := os blockInterrupts.
 13100         interruptsBlocked := OperatingSystem blockInterrupts.
 13479         oldLocale := os setLocale:#'LC_CTYPE' to:nil.
 13101         oldLocale := OperatingSystem setLocale:#'LC_CTYPE' to:nil.
 13480         os setLocale:#'LC_CTYPE' to:'en_US.UTF-8'.
 13102         OperatingSystem setLocale:#'LC_CTYPE' to:'en_US.UTF-8'.
 13481         result := self primGetAddressInfo:encodedHostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags.
 13103         result := self primGetAddressInfo:encodedHostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags.
 13482         os setLocale:#'LC_CTYPE' to:oldLocale.
 13104         OperatingSystem setLocale:#'LC_CTYPE' to:oldLocale.
 13483         interruptsBlocked ifFalse:[
 13105         interruptsBlocked ifFalse:[
 13484             os unblockInterrupts.
 13106             OperatingSystem unblockInterrupts.
 13485         ].
 13107         ].
 13486     ] ifFalse:[
 13108     ] ifFalse:[
 13487         result := self primGetAddressInfo:encodedHostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags.
 13109         result := self primGetAddressInfo:encodedHostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags.
 13488     ].
 13110     ].
 13489     result isArray ifFalse:[
 13111     result isArray ifFalse:[
 13505         entry := result at:i.
 13127         entry := result at:i.
 13506 
 13128 
 13507         info := SocketAddressInfo new.
 13129         info := SocketAddressInfo new.
 13508         info
 13130         info
 13509             flags:(entry at:1);
 13131             flags:(entry at:1);
 13510             domain:(dom := os domainSymbolOf:(entry at:2));
 13132             domain:(dom := OperatingSystem domainSymbolOf:(entry at:2));
 13511             type:(os socketTypeSymbolOf:(entry at:3));
 13133             type:(OperatingSystem socketTypeSymbolOf:(entry at:3));
 13512             protocol:(self protocolSymbolOf:(entry at:4));
 13134             protocol:(self protocolSymbolOf:(entry at:4));
 13513             socketAddress:((SocketAddress newDomain:dom) fromBytes:(entry at:5));
 13135             socketAddress:((SocketAddress newDomain:dom) fromBytes:(entry at:5));
 13514             canonicalName:(entry at:6).
 13136             canonicalName:(entry at:6).
 13515 
 13137 
 13516         result at:i put:info.
 13138         result at:i put:info.
 13553             domain:#'AF_INET' type:#stream protocol:nil flags:nil
 13175             domain:#'AF_INET' type:#stream protocol:nil flags:nil
 13554      self getAddressInfo:'www.baden-württemberg.de' serviceName:nil
 13176      self getAddressInfo:'www.baden-württemberg.de' serviceName:nil
 13555             domain:#'AF_INET6' type:#stream protocol:nil flags:nil
 13177             domain:#'AF_INET6' type:#stream protocol:nil flags:nil
 13556     "
 13178     "
 13557 
 13179 
 13558     "Modified: / 03-03-2019 / 11:21:21 / Claus Gittinger"
 13180     "Modified: / 03-03-2019 / 11:23:38 / Claus Gittinger"
 13559 !
 13181 !
 13560 
 13182 
 13561 getNameInfo:socketAddress wantHostName:wantHostName wantServiceName:wantServiceName datagram:useDatagram flags:flags
 13183 getNameInfo:socketAddress wantHostName:wantHostName wantServiceName:wantServiceName datagram:useDatagram flags:flags
 13562     "answer an Array containing the hostName and serviceName
 13184     "answer an Array containing the hostName and serviceName
 13563      in socketAddress.
 13185      in socketAddress.