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