Unix.st
changeset 77 6c38ca59927f
parent 68 59faa75185ba
child 85 1343af456e28
--- a/Unix.st	Thu May 12 04:07:15 1994 +0200
+++ b/Unix.st	Tue May 17 12:09:46 1994 +0200
@@ -22,7 +22,7 @@
 COPYRIGHT (c) 1988 by Claus Gittinger
              All Rights Reserved
 
-$Header: /cvs/stx/stx/libbasic/Attic/Unix.st,v 1.13 1994-03-30 09:34:10 claus Exp $
+$Header: /cvs/stx/stx/libbasic/Attic/Unix.st,v 1.14 1994-05-17 10:09:37 claus Exp $
 
 written 1988 by claus
 '!
@@ -77,6 +77,13 @@
 #  define S_IXOTH (S_IEXEC>>6)
 # endif
 
+# ifndef MAXPATHLEN
+#  include <sys/param.h>
+#  ifndef MAXPATHLEN
+#   define MAXPATHLEN 1024
+#  endif
+# endif
+
 #endif
 
 /*
@@ -205,105 +212,165 @@
 
     |cpu|
     
-    cpu := 'unknown'.
-
 %{  /* NOCONTEXT */
-#ifdef vax
-    cpu = _MKSTRING("vax" COMMA_CON);
-#endif
-#ifdef mips
-    cpu = _MKSTRING("mips" COMMA_CON);
-#endif
-#ifdef i386
-    cpu = _MKSTRING("i386" COMMA_CON);
-#endif
-#ifdef ns32k
-    cpu = _MKSTRING("ns32k" COMMA_CON);
-#endif
-#ifdef mc68k
-    cpu = _MKSTRING("mc68k" COMMA_CON);
-#endif
-#ifdef sparc
-    cpu = _MKSTRING("sparc" COMMA_CON);
-#endif
-#ifdef hppa
-    cpu = _MKSTRING("hppa" COMMA_CON);
-#endif
-#ifdef rs6000
-    cpu = _MKSTRING("rs6000" COMMA_CON);
-#endif
-#ifdef alpha
-    cpu = _MKSTRING("alpha" COMMA_CON);
-#endif
-#ifdef transputer
-    cpu = _MKSTRING("transputer" COMMA_CON);
-#endif
+
+#   ifdef vax
+#    define CPU_STRING "vax"
+#   endif
+#   ifdef mips
+#    define CPU_STRING "mips"
+#   endif
+#   ifdef i386
+#    define CPU_STRING "i386"
+#   endif
+#   ifdef ns32k
+#    define CPU_STRING "ns32k"
+#   endif
+#   ifdef mc68k
+#    define CPU_STRING "mc68k"
+#   endif
+#   ifdef sparc
+#    define CPU_STRING "sparc"
+#   endif
+#   ifdef hppa
+#    define CPU_STRING "hppa"
+#   endif
+#   ifdef rs6000
+#    define CPU_STRING "rs6000"
+#   endif
+#   ifdef alpha
+#    define CPU_STRING "alpha"
+#   endif
+#   ifdef powerPC
+#    define CPU_STRING "powerPC"
+#   endif
+#   ifdef transputer
+#    define CPU_STRING "transputer"
+#   endif
+
+#   ifndef CPU_STRING
+#    define CPU_STRING "unknown"
+#   endif
+
+    cpu = _MKSTRING(CPU_STRING COMMA_CON);
+#   undef CPU_STRING
 %}
 .
     ^ cpu
 
-    "OperatingSystem getCPUType"
+    "
+     OperatingSystem getCPUType
+    "
+
+    "examples: are we running on a ss-10/solaris ?"
+    "
+     (OperatingSystem getCPUType = 'sparc') 
+     and:[OperatingSystem getOSType = 'solaris']
+    "
+
+    "or on a pc/solaris ?"
+    "
+     (OperatingSystem getCPUType = 'i386')
+     and:[OperatingSystem getOSType = 'solaris']
+    "
 !
 
 getOSType
-    "return a string giving the type of OS we're running on"
+    "return a string giving the type of OS we're running on.
+     This can be used to adapt programs to certain environment
+     differences (for example: mail-lock strategy ...)"
 
     |os|
 
-    os := 'unknown'.
-
 %{  /* NOCONTEXT */
-#ifdef MSDOS
-  os = _MKSTRING("msdos" COMMA_CON);
-#endif
-
-#ifdef sinix
-  os = _MKSTRING("sinix" COMMA_CON);
-#endif
-
-#ifdef ultrix
-  os = _MKSTRING("ultrix" COMMA_CON);
-#endif
-
-#ifdef sco
-  os = _MKSTRING("sco" COMMA_CON);
-#endif
-
-#ifdef hpux
-  os = _MKSTRING("hpux" COMMA_CON);
-#endif
-
-#ifdef LINUX
-  os = _MKSTRING("linux" COMMA_CON);
-#endif
-
-#ifdef BSD
-# ifdef MACH
-  os = _MKSTRING("mach" COMMA_CON);
-# endif
-
-# ifdef sunos
-  os = _MKSTRING("sunos" COMMA_CON);
-# endif
-
-# ifdef IRIS
-  os = _MKSTRING("irix" COMMA_CON);
-# endif
-
-  if (os == nil) os = _MKSTRING("bsd" COMMA_CON);
-#endif
-
-#ifdef SYSV
-# ifdef SYSV3
-  os = _MKSTRING("sys5.3" COMMA_CON);
-# else
-#  ifdef SYSV4
-    os = _MKSTRING("sys5.4" COMMA_CON);
-#  else
-    os = _MKSTRING("sys5" COMMA_CON);
-#  endif
-# endif
-#endif
+
+#   ifdef MSDOS
+#    define OS_STRING "msdos"
+#   endif
+
+#   ifdef NT
+#    define OS_STRING "nt"
+#   endif
+
+#   ifdef sinix
+#    define OS_STRING "sinix"
+#   endif
+
+#   ifdef ultrix
+#    define OS_STRING "ultrix"
+#   endif
+
+#   ifdef sco
+#    define OS_STRING "sco"
+#   endif
+
+#   ifdef hpux
+#    define OS_STRING "hpux"
+#   endif
+
+#   ifdef LINUX
+#    define OS_STRING "linux"
+#   endif
+
+#   ifdef sunos
+#    define OS_STRING "sunos"
+#   endif
+
+#   ifdef solaris
+#    define OS_STRING "solaris"
+#   endif
+
+#   ifdef IRIS
+#    define OS_STRING "irix"
+#   endif
+
+    /*
+     * no concrete info; become somewhat vague ...
+     */
+#   ifndef OS_STRING
+#    ifdef MACH
+#     define OS_STRING "mach"
+#    endif
+#   endif
+
+#   ifndef OS_STRING
+#    ifdef BSD
+#     define OS_STRING "bsd"
+#    endif
+
+#    ifdef SYSV
+#     ifdef SYSV3
+#      define OS_STRING "sys5.3"
+#     else
+#      ifdef SYSV4
+#       define OS_STRING "sys5.4"
+#      else
+#       define OS_STRING "sys5"
+#      endif
+#     endif
+#    endif
+#   endif
+
+    /*
+     * become very vague ...
+     */
+#   ifndef OS_STRING
+#    ifdef POSIX
+#     define OS_STRING "posix"
+#    endif
+#   endif
+#   ifndef OS_STRING
+#    ifdef UNIX
+#     define OS_STRING "unix"
+#    endif
+#   endif
+
+#   ifndef OS_STRING
+#    define OS_STRING "unknown"
+#   endif
+
+    os = _MKSTRING(OS_STRING COMMA_CON);
+#   undef OS_STRING
 %}
 .
     ^ os
@@ -316,76 +383,34 @@
      This is almost the same as getOSType, but the returned string
      is slightly different for some systems (i.e. iris vs. irix).
      Dont depend on this - use getOSType. I dont really see a point
-     here ..."
+     here ... (except for slight differences between next/mach and other
+     machs)"
 
     |sys|
 
-    sys := 'unknown'.
-
-%{  /* NOCONTEXT */
-#ifdef MSDOS
-  sys = _MKSTRING("msdos" COMMA_CON);
-#endif
-
-#ifdef sinix
-  sys = _MKSTRING("sinix" COMMA_CON);
-#endif
-
-#ifdef ultrix
-  sys = _MKSTRING("ultrix" COMMA_CON);
-#endif
-
-#ifdef sco
-  sys = _MKSTRING("sco" COMMA_CON);
-#endif
-
-#ifdef sunos
-  sys = _MKSTRING("sunos" COMMA_CON);
-#endif
-
-#ifdef solaris
-  sys = _MKSTRING("solaris" COMMA_CON);
-#endif
-
-#ifdef NEXT
-  sys = _MKSTRING("next" COMMA_CON);
-#endif
-
-#ifdef IRIS
-  sys = _MKSTRING("iris" COMMA_CON);
-#endif
-
-#ifdef LINUX
-  sys = _MKSTRING("linux" COMMA_CON);
-#endif
-
-#ifdef hpux
-  sys = _MKSTRING("hpux" COMMA_CON);
-#endif
-
-#ifdef BSD
-# ifdef MACH
-  if (sys == nil) sys = _MKSTRING("mach" COMMA_CON);
-# endif
-  if (sys == nil) sys = _MKSTRING("bsd" COMMA_CON);
-#endif
-
-#ifdef SYSV
-# ifdef SYSV3
-  if (sys == nil) sys = _MKSTRING("sys5.3" COMMA_CON);
-# else
-#  ifdef SYSV4
-    if (sys == nil) sys = _MKSTRING("sys5.4" COMMA_CON);
-#  else
-    if (sys == nil) sys = _MKSTRING("sys5" COMMA_CON);
-#  endif
-# endif
-#endif
+%{
+#   ifdef NEXT
+#    define SYS_STRING "next"
+#   endif
+
+#   ifdef IRIS
+#    define SYS_STRING "iris"
+#   endif
+
+#   ifdef SYS_STRING
+     sys = _MKSTRING(SYS_STRING COMMA_CON);
+#    undef SYS_STRING
+#   endif
 %}
 .
+    sys isNil ifTrue:[
+	^ self getOSType
+    ].
     ^ sys
 
-    "OperatingSystem getSystemType"
+    "
+     OperatingSystem getSystemType
+    "
 !
 
 getHostName
@@ -398,9 +423,28 @@
         ^ HostName
     ].
     name := self getEnvironment:'HOST'.
+%{
+#if defined(HAS_GETHOSTNAME)
+    char buffer[128];
+
+    if (gethostname(buffer, sizeof(buffer)) == 0) {
+        name = _MKSTRING(buffer COMMA_CON);
+    }
+#else
+# if defined(HAS_UNAME)
+#  include <sys/utsname.h>
+
+    struct utsname ubuff;
+
+    if (uname(&ubuff) == 0) {
+	name = _MKSTRING(ubuff.nodename COMMA_CON);
+    }
+# endif
+#endif
+%}.
     name isNil ifTrue:[
         "since fork might be slow on some machines, give a warning ..."
-        'please set the HOST shell variable for faster startup' errorPrintNewline.
+        'please set the HOST shell variable for faster startup' errorPrintNL.
 
         p := PipeStream readingFrom:'hostname'.
         p notNil ifTrue:[
@@ -409,10 +453,10 @@
         ]
     ].
     name isNil ifTrue:[
-        'cannot find out hostname' errorPrintNewline.
+        'cannot find out hostname' errorPrintNL.
     ].
     HostName := name.
-    ^name
+    ^ name
 
     "
      OperatingSystem getHostName
@@ -424,10 +468,7 @@
 
 %{  /* NOCONTEXT */
 
-#ifdef BSD
-    RETURN ( true );
-#endif
-#ifdef SYSV4
+#if defined(BSD) || defined(MACH) || defined(SYSV4)
     RETURN ( true );
 #endif
 %}
@@ -437,22 +478,35 @@
 
 maxFileNameLength
     "return the max number of characters in a filename.
-     this is no problem on 'real' unixes, but those instant
-     ****-stations always make problems .."
+     This is no problem on 'real' unixes, but those 
+     'instant ****-stations' always make problems .."
 
 %{  /* NOCONTEXT */
-#if defined(BSD) || defined(SYSV4) || defined(LONGFILENAMES)
-    RETURN ( _MKSMALLINT(255) );
-#else
-# ifdef SYSV
-    RETURN ( _MKSMALLINT(14) );
-# endif
-# ifdef MSDOS
-    RETURN ( _MKSMALLINT(9) );
-# endif
-#endif
+ 
+    /*
+     * XXX: newer systems provide a query function for this ... use it
+     */
+#   if defined(BSD) || defined(SYSV4) || defined(LONGFILENAMES)
+     RETURN ( _MKSMALLINT(255) );
+#   endif
+
+#   ifdef SYSV
+      RETURN ( _MKSMALLINT(14) );
+#   endif
+
+#   ifdef MSDOS
+     RETURN ( _MKSMALLINT(9) );
+#   endif
+
+#   ifdef NT
+     /*
+      * mhmh - depends on the filesystem type
+      */
+     RETURN ( _MKSMALLINT(9) );
+#   endif
 %}
 .
+    "unix default"
     ^ 14
 !
 
@@ -465,18 +519,18 @@
 %{  /* NOCONTEXT */
 #ifdef NOTDEF
 
-#if defined(SIGPOLL) || defined(SIGIO)
-# if defined(F_GETFL) && defined(F_SETFL)
-#  if defined(FASYNC)
-/*
- * mhmh they seem to NOT work on NS2.1
- */
-#   if !defined(NEXT)
-    RETURN (true);
+#   if defined(SIGPOLL) || defined(SIGIO)
+#    if defined(F_GETFL) && defined(F_SETFL)
+#     if defined(FASYNC)
+      /*
+       * mhmh they seem to NOT work on NS2.1
+       */
+#      if !defined(NEXT)
+        RETURN (true);
+#      endif
+#     endif
+#    endif
 #   endif
-#  endif
-# endif
-#endif
 
 #endif
 %}
@@ -488,11 +542,11 @@
     "return true, if the OS supports nonblocking IO."
 
 %{  /* NOCONTEXT */
-#if defined(F_GETFL) && defined(F_SETFL)
-# if defined(FNDELAY)
-    RETURN (true);
-# endif
-#endif
+#   if defined(F_GETFL) && defined(F_SETFL)
+#    if defined(FNDELAY)
+       RETURN (true);
+#    endif
+#   endif
 %}
 .
     ^ false
@@ -552,11 +606,12 @@
 #endif
 %}
 .
-    ^ '???'
+    ^ '? (' , aNumber printString , ')'
 
     "
      OperatingSystem getUserNameFromID:0
      OperatingSystem getUserNameFromID:100
+     OperatingSystem getUserNameFromID:9991 
     "
 !
 
@@ -627,87 +682,311 @@
      (as returned by a system call). 
      Should be replaced by a resource lookup."
 
-    |msg messages|
-
-    (Language == #german) ifTrue:[
-        messages := #('keine superuser Berechtigung'
-                      'ungueltiger Datei- oder VerzeichnisName'
-                      nil "'ungueltige Prozessnummer'  "
-                      nil "'unterbrochener systemcall' "
-                      'E/A Fehler'
-                      nil "'Geraet existiert nicht' "
-                      'zu viele Argumente'
-                      'nicht ausfuehrbar'
-                      nil "'falscher FileDescriptor'"
-                      nil "'kein Kindprozess'       "
-                      'zu viele Prozesse oder zu wenig Speicher'
-                      'zu wenig Speicher'
-                      'keine ZugriffsBerechtigung'
-                      nil "'falsche Adresse'        "
-                      nil "'kein Blockgeraet'       "
-                      nil "'Platte noch im Zugriff' "
-                      'Datei existiert bereits'
-                      nil "'Link ueber Plattengrenzen hinweg' "
-                      'Geraet existiert nicht'
-                      'ist kein Verzeichnis'
-                      'ist ein Verzeichnis'
-                      nil "'ungueltiges Argument' "
-                      'zu viele Dateien offen'
-                      'zu viele Dateien offen'
-                      nil "'kein Terminalgeraet'  "
-                      'Datei wird gerade ausgefuehrt'
-                      'Datei zu gross'
-                      'Platte ist voll'
-                      'ungueltige Positionierung'
-                      'Platte ist schreibgeschuetzt'
-                      'zu viele Links'
-                      'Pipe unterbrochen'
-                      'argument nicht im gueltigen Bereich'
-                      'Ergebnis nicht im gueltigen Bereich')
-    ] ifFalse:[
-        messages := #('Not super-user'
-                      'No such file or directory'
-                      nil "'No such process'   "
-                      nil "'interrupted system call' "
-                      'I/O error'
-                      nil "'No such device or address' "
-                      'Arg list too long'
-                      'Exec format error'
-                      nil "'Bad file number'"
-                      nil "'No children'       "
-                      'No more processes'
-                      'Not enough core'
-                      'Permission denied'
-                      nil "'Bad address'        "
-                      nil "'Block device required'       "
-                      nil "'Mount device busy' "
-                      'File exists'
-                      nil "'Cross-device link' "
-                      'No such device'
-                      'Not a directory'
-                      'Is a directory'
-                      nil 'Invalid argument'
-                      'File table overflow'
-                      'Too many open files'
-                      nil "'Not a typewriter' "
-                      'Text file busy'
-                      'File too large'
-                      'No space left on device'
-                      'Illegal seek'
-                      'Read only file system'
-                      'Too many links'
-                      'Broken pipe'
-                      'Math arg out of domain of func'
-                      'Math result not representable')
-    ].
-
-    (errNr between:1 and:messages size) ifTrue:[
-        msg := messages at:errNr
-    ].
-    msg isNil ifTrue:[
-        ^ ('ErrorNr: ' , errNr printString)
-    ].
-    ^ msg
+%{
+    /* claus:
+     * I made this some primitive code, since errnos are not
+     * standard across unixes
+     */
+    char *msg = "unknown error";
+    char buffer[50];
+
+    if (_isSmallInteger(errNr)) {
+        switch (_intVal(errNr)) {
+	    /*
+	     * POSIX errnos - these should be defined
+	     */
+	    case EPERM:
+		msg = "Operation not permitted";
+		break;
+	    case ENOENT:
+                msg = "No such file or directory";
+		break;
+	    case ESRCH:
+                msg = "No such process";
+		break;
+	    case EINTR:
+                msg = "Interrupted system call";
+		break;
+	    case EIO:
+                msg = "I/O error";
+		break;
+	    case ENXIO:
+                msg = "No such device or address";
+		break;
+	    case E2BIG:
+                msg = "Arg list too long";
+		break;
+	    case ENOEXEC:
+                msg = "Exec format error";
+		break;
+	    case EBADF:
+                msg = "Bad file number";
+		break;
+	    case ECHILD:
+                msg = "No child processes";
+		break;
+#if !defined(EWOULDBLOCK) && defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
+	    case EAGAIN:
+                msg = "Try again";
+		break;
+#endif
+	    case ENOMEM:
+                msg = "Out of memory";
+		break;
+	    case EACCES:
+                msg = "Permission denied";
+		break;
+	    case EFAULT:
+                msg = "Bad address";
+		break;
+	    case EBUSY:
+                msg = "Device or resource busy";
+		break;
+	    case EEXIST:
+                msg = "File exists";
+		break;
+	    case EXDEV:
+                msg = "Cross-device link";
+		break;
+	    case ENODEV:
+                msg = "No such device";
+		break;
+	    case ENOTDIR:
+                msg = "Not a directory";
+		break;
+	    case EISDIR:
+                msg = "Is a directory";
+		break;
+	    case EINVAL:
+                msg = "Invalid argument";
+		break;
+	    case ENFILE:
+                msg = "File table overflow";
+		break;
+	    case EMFILE:
+                msg = "Too many open files";
+		break;
+	    case ENOTTY:
+                msg = "Not a typewriter";
+		break;
+	    case EFBIG:
+                msg = "File too large";
+		break;
+	    case ENOSPC:
+                msg = "No space left on device";
+		break;
+	    case ESPIPE:
+                msg = "Illegal seek";
+		break;
+	    case EROFS:
+                msg = "Read-only file system";
+		break;
+	    case EMLINK:
+                msg = "Too many links";
+		break;
+	    case EPIPE:
+                msg = "Broken pipe";
+		break;
+	    case EDOM:
+                msg = "Math argument out of domain";
+		break;
+	    case ERANGE:
+                msg = "Math result not representable";
+		break;
+#ifdef EDEADLK
+	    case EDEADLK:
+                msg = "Resource deadlock would occur";
+		break;
+#endif
+#ifdef ENAMETOOLONG
+	    case ENAMETOOLONG:
+                msg = "File name too long";
+		break;
+#endif
+#ifdef ENOLCK
+	    case ENOLCK:
+                msg = "No record locks available";
+		break;
+#endif
+#ifdef ENOSYS
+	    case ENOSYS:
+                msg = "Function not implemented";
+		break;
+#endif
+#ifdef ENOTEMPTY
+	    case ENOTEMPTY:
+                msg = "Directory not empty";
+		break;
+#endif
+#ifdef EILSEQ
+	    case EILSEQ:
+		msg = "Illegal byte sequence";
+		break;
+#endif
+	    /*
+	     * XPG3 errnos - defined on most systems
+	     */
+#ifdef ENOTBLK
+	    case ENOTBLK:
+                msg = "Block device required";
+		break;
+#endif
+#ifdef ETXTBSY
+	    case ETXTBSY:
+                msg = "Text file busy";
+		break;
+#endif
+	    /*
+	     * some others
+	     */
+#ifdef EWOULDBLOCK
+	    case EWOULDBLOCK:
+		msg = "Operation would block";
+		break;
+#endif
+#ifdef ENOMSG
+	    case ENOMSG:
+		msg = "No message of desired type";
+		break;
+#endif
+#ifdef ELOOP
+	    case ELOOP:
+		msg = "Too many levels of symbolic links";
+		break;
+#endif
+
+	    /*
+	     * some stream errors
+	     */
+#ifdef ETIME
+	    case ETIME:
+		msg = "Timer expired";
+		break;
+#endif
+#ifdef ENOSR
+	    case ENOSR:
+		msg = "Out of streams resources";
+		break;
+#endif
+#ifdef ENOSTR
+	    case ENOSTR:
+		msg = "Device not a stream";
+		break;
+#endif
+#ifdef ECOMM
+	    case ECOMM:
+		msg = "Communication error on send";
+		break;
+#endif
+#ifdef EPROTO
+	    case EPROTO:
+		msg = "Protocol error";
+		break;
+#endif
+	    /*
+	     * nfs errors
+	     */
+#ifdef ESTALE
+	    case ESTALE:
+		msg = "Stale NFS file handle";
+		break;
+#endif
+#ifdef EREMOTE
+	    case EREMOTE:
+		msg = "Too many levels of remote in path";
+		break;
+#endif
+	    /*
+	     * some networking errors
+	     */
+#ifdef EINPROGRESS
+	    case EINPROGRESS:
+		msg = "Operation now in progress";
+		break;
+#endif
+#ifdef EALREADY
+	    case EALREADY:
+		msg = "Operation already in progress";
+		break;
+#endif
+#ifdef ENOTSOCK
+	    case ENOTSOCK:
+		msg = "Socket operation on non-socket";
+		break;
+#endif
+#ifdef EDESTADDRREQ
+	    case EDESTADDRREQ:
+		msg = "Destination address required";
+		break;
+#endif
+#ifdef EMSGSIZE
+	    case EMSGSIZE:
+		msg = "Message too long";
+		break;
+#endif
+#ifdef EPROTOTYPE
+	    case EPROTOTYPE:
+		msg = "Protocol wrong type for socket";
+		break;
+#endif
+#ifdef ENOPROTOOPT
+	    case ENOPROTOOPT:
+		msg = "Protocol not available";
+		break;
+#endif
+#ifdef EPROTONOSUPPORT
+	    case EPROTONOSUPPORT:
+		msg = "Protocol not supported";
+		break;
+#endif
+#ifdef ESOCKTNOSUPPORT
+	    case ESOCKTNOSUPPORT:
+		msg = "Socket type not supported";
+		break;
+#endif
+#ifdef EOPNOTSUPP
+	    case EOPNOTSUPP:
+		msg = "Operation not supported on socket";
+		break;
+#endif
+#ifdef EPFNOSUPPORT
+	    case EPFNOSUPPORT:
+		msg = "Protocol family not supported";
+		break;
+#endif
+#ifdef EAFNOSUPPORT
+	    case EAFNOSUPPORT:
+		msg = "Address family not supported by protocol family";
+		break;
+#endif
+#ifdef EADDRINUSE
+	    case EADDRINUSE:
+		msg = "Address already in use";
+		break;
+#endif
+#ifdef EADDRNOTAVAIL
+	    case EADDRNOTAVAIL:
+		msg = "Can\'t assign requested address";
+		break;
+#endif
+#ifdef ETIMEDOUT
+	    case ETIMEDOUT:
+		msg = "Connection timed out";
+		break;
+#endif
+#ifdef ECONNREFUSED
+	    case ECONNREFUSED:
+		msg = "Connection refused";
+		break;
+#endif
+	    default:
+		sprintf(buffer, "ErrorNr: %d", _intVal(errNr));
+		msg = buffer;
+		break;
+        }
+    }
+    RETURN (_MKSTRING(msg COMMA_CON));
+%}
 ! !
 
 !OperatingSystem class methodsFor:'signal constants'!
@@ -1390,15 +1669,17 @@
     ^ self enableSignal:(self sigFP)
 !
 
-enableSignalInterrupts
-    "enable signal exception interrupts (trap, buserror & segm. violation).
+enableHardSignalInterrupts
+    "enable hard signal exception interrupts (trap, buserror & segm. violation).
      after enabling, these exceptions will send the message 
      'signalInterrupt' to the SignalInterruptHandler object."
 
 %{  /* NOCONTEXT */
 
     extern void signalPIPEInterrupt();
+#ifdef SIGBUS
     extern void signalBUSInterrupt();
+#endif
     extern void signalSEGVInterrupt();
 
     signal(SIGPIPE, signalPIPEInterrupt);
@@ -2197,7 +2478,7 @@
      (i.e. OperatingSystem baseNameOf:'/usr/lib/st/file' -> 'file'
        and OperatingSystem baseNameOf:'/usr/lib' -> lib).
      This method does not check if the path is valid 
-     (i.e. if these directories really exist)."
+     (i.e. if these directories really exist & is readable)."
 
     |prev index sep|
 
@@ -2214,9 +2495,12 @@
         prev := index + 1
     ]
 
-    "OperatingSystem baseNameOf:'/fee/foo/bar'"
-    "OperatingSystem baseNameOf:'foo/bar'"
-    "OperatingSystem baseNameOf:'../../foo/bar'"
+    "
+     OperatingSystem baseNameOf:'/fee/foo/bar'
+     OperatingSystem baseNameOf:'foo/bar'
+     OperatingSystem baseNameOf:'../../foo/bar'
+     OperatingSystem baseNameOf:'hello'
+    "
 !
 
 directoryNameOf:aPathString
@@ -2224,14 +2508,17 @@
      - thats the name of the directory where aPath is
      (i.e. OperatingSystem directoryNameOf:'/usr/lib/st/file' -> '/usr/lib/st'
        and OperatingSystem directoryNameOf:'/usr/lib' -> /usr').
-     This method does not check if the path is valid (i.e. if these directories
-     really exist)."
+     This method does not check if the path is valid
+     (i.e. if these directories really exist & are readable)."
 
     |last index sep sepString|
 
     sep := self fileSeparator.
     sepString := sep asString.
     (aPathString = sepString) ifTrue:[
+        "
+         the trivial '/' case
+        "
         ^ aPathString
     ].
     (aPathString startsWith:sepString) ifFalse:[
@@ -2243,15 +2530,75 @@
     [true] whileTrue:[
         index := aPathString indexOf:sep startingAt:(last + 1).
         index == 0 ifTrue:[
-            (last == 1) ifTrue:[^ sepString].
+            (last == 1) ifTrue:[
+                (aPathString startsWith:sepString) ifTrue:[
+                    ^ sepString
+                ].
+                ^ '.'
+            ].
+"
+            (aPathString startsWith:sepString) ifFalse:[
+                (aPathString startsWith:('..' , sepString)) ifFalse:[
+                    ^ './' , (aPathString copyTo:(last - 1))
+                ]
+            ].
+"
             ^ aPathString copyTo:(last - 1)
         ].
         last := index.
     ]
 
-    "OperatingSystem directoryNameOf:'/fee/foo/bar'"
-    "OperatingSystem directoryNameOf:'foo/bar'"
-    "OperatingSystem directoryNameOf:'../../foo/bar'"
+    "
+     OperatingSystem directoryNameOf:'/fee/foo/bar'
+     OperatingSystem directoryNameOf:'foo/bar'
+     OperatingSystem directoryNameOf:'../../foo/bar'
+     OperatingSystem directoryNameOf:'bar'
+     OperatingSystem directoryNameOf:'/bar'
+    "
+!
+
+pathNameOf:pathName
+    "return the pathName of the argument, aPathString,
+     - thats the full pathname of the directory, starting at '/'.
+     This method needs the path to be valid
+     (i.e. all directories must exist, be readable and executable).
+     Notice: if symbolic links are involved, the result may look different
+     from what you expect."
+
+    |p path|
+
+    "some have a convenient function for this ..."
+%{  /* STACK: 16000 */
+#ifdef HAS_REALPATH
+    char nameBuffer[MAXPATHLEN + 1];
+
+    if (__isString(pathName)) {
+        if (realpath(_stringVal(pathName), nameBuffer)) {
+            path = _MKSTRING(nameBuffer COMMA_CON);
+        }
+    }
+#endif
+%}
+.
+    path isNil ifTrue:[
+        "have to fall back ..."
+
+        p := PipeStream readingFrom:'cd ' , pathName , '; pwd'.
+        p isNil ifTrue:[
+            path := pathName
+        ] ifFalse:[
+            path := p nextLine.
+            p close.
+        ].
+    ].
+    ^ path.
+
+    "
+     OperatingSystem pathNameOf:'.'
+     OperatingSystem pathNameOf:'../smalltalk/../smalltalk'
+     OperatingSystem pathNameOf:'../../..'
+     OperatingSystem pathNameOf:'..'
+    "
 !
 
 isValidPath:aPathName
@@ -2365,15 +2712,6 @@
 
     |info type mode uid gid size id atimeLow atimeHi mtimeLow mtimeHi|
 
-    "{ Symbol: directory }"
-    "{ Symbol: regular }"
-    "{ Symbol: characterSpecial }"
-    "{ Symbol: blockSpecial }"
-    "{ Symbol: fifo }"
-    "{ Symbol: socket }"
-    "{ Symbol: symbolicLink }"
-    "{ Symbol: unknown }"
-
 %{
     struct stat buf;
     int ret;
@@ -2389,34 +2727,34 @@
         }
         switch (buf.st_mode & S_IFMT) {
             case S_IFDIR:
-                type = _directory;
+                type = @symbol(directory);
                 break;
             case S_IFCHR:
-                type = _characterSpecial;
+                type = @symbol(characterSpecial);
                 break;
             case S_IFBLK:
-                type = _blockSpecial;
+                type = @symbol(blockSpecial);
                 break;
             case S_IFREG:
-                type = _regular;
+                type = @symbol(regular);
                 break;
 #ifdef S_IFLNK
             case S_IFLNK:
-                type = _symbolicLink;
+                type = @symbol(symbolicLink);
                 break;
 #endif
 #ifdef S_IFSOCK
             case S_IFSOCK:
-                type = _socket;
+                type = @symbol(socket);
                 break;
 #endif
 #ifdef S_IFIFO
             case S_IFIFO:
-                type = _fifo;
+                type = @symbol(fifo);
                 break;
 #endif
             default:
-                type = _unknown;
+                type = @symbol(unknown);
                 break;
         }
         mode = _MKSMALLINT(buf.st_mode & 0777);
@@ -2726,7 +3064,7 @@
 %{  /* NOCONTEXT */
 
     if (__isString(oldPath) && __isString(newPath)) {
-#if defined(BSD)
+#if defined(HAS_RENAME)
         if (rename((char *) _stringVal(oldPath), (char *) _stringVal(newPath)) >= 0) {
             RETURN ( true );
         }