diff --git a/System/Posix/Directory.hsc b/System/Posix/Directory.hsc
--- a/System/Posix/Directory.hsc
+++ b/System/Posix/Directory.hsc
@@ -37,8 +37,6 @@
 import System.IO.Error
 import System.Posix.Error
 import System.Posix.Types
-import System.Posix.Internals
---import System.Directory hiding (createDirectory)
 import Foreign
 import Foreign.C
 
@@ -63,6 +61,9 @@
     dirp <- throwErrnoPathIfNull "openDirStream" name $ c_opendir s
     return (DirStream dirp)
 
+foreign import ccall unsafe "__hsunix_opendir"
+   c_opendir :: CString  -> IO (Ptr CDir)
+
 -- | @readDirStream dp@ calls @readdir@ to obtain the
 --   next directory entry (@struct dirent@) for the open directory
 --   stream @dp@, and returns the @d_name@ member of that
@@ -73,32 +74,51 @@
  where
   loop ptr_dEnt = do
     resetErrno
-    r <- readdir dirp ptr_dEnt
+    r <- c_readdir dirp ptr_dEnt
     if (r == 0)
 	 then do dEnt <- peek ptr_dEnt
 		 if (dEnt == nullPtr)
 		    then return []
 		    else do
 	 	     entry <- (d_name dEnt >>= peekCString)
-		     freeDirEnt dEnt
+		     c_freeDirEnt dEnt
 		     return entry
 	 else do errno <- getErrno
 		 if (errno == eINTR) then loop ptr_dEnt else do
 		 let (Errno eo) = errno
-		 if (eo == end_of_dir)
+		 if (eo == 0)
 		    then return []
 		    else throwErrno "readDirStream"
 
+type CDir       = ()
+type CDirent    = ()
+
+-- traversing directories
+foreign import ccall unsafe "__hscore_readdir"
+  c_readdir  :: Ptr CDir -> Ptr (Ptr CDirent) -> IO CInt
+
+foreign import ccall unsafe "__hscore_free_dirent"
+  c_freeDirEnt  :: Ptr CDirent -> IO ()
+
+foreign import ccall unsafe "__hscore_d_name"
+  d_name :: Ptr CDirent -> IO CString
+
 -- | @rewindDirStream dp@ calls @rewinddir@ to reposition
 --   the directory stream @dp@ at the beginning of the directory.
 rewindDirStream :: DirStream -> IO ()
 rewindDirStream (DirStream dirp) = c_rewinddir dirp
 
+foreign import ccall unsafe "rewinddir"
+   c_rewinddir :: Ptr CDir -> IO ()
+
 -- | @closeDirStream dp@ calls @closedir@ to close
 --   the directory stream @dp@.
 closeDirStream :: DirStream -> IO ()
 closeDirStream (DirStream dirp) = do
   throwErrnoIfMinus1_ "closeDirStream" (c_closedir dirp)
+
+foreign import ccall unsafe "closedir"
+   c_closedir :: Ptr CDir -> IO CInt
 
 newtype DirStreamOffset = DirStreamOffset COff
 
diff --git a/System/Posix/IO.hsc b/System/Posix/IO.hsc
--- a/System/Posix/IO.hsc
+++ b/System/Posix/IO.hsc
@@ -1,5 +1,6 @@
 {-# LANGUAGE ForeignFunctionInterface #-}
 {-# OPTIONS_GHC -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -XRecordWildCards #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  System.Posix.IO
@@ -34,6 +35,7 @@
     -- EAGAIN exceptions may occur for non-blocking IO!
 
     fdRead, fdWrite,
+    fdReadBuf, fdWriteBuf,
 
     -- ** Seeking
     fdSeek,
@@ -65,17 +67,27 @@
 import System.IO.Error
 import System.Posix.Types
 import System.Posix.Error
-import System.Posix.Internals
+import qualified System.Posix.Internals as Base
 
 import Foreign
 import Foreign.C
 import Data.Bits
 
 #ifdef __GLASGOW_HASKELL__
+#if __GLASGOW_HASKELL__ >= 611
+import GHC.IO.Handle
+import GHC.IO.Handle.Internals
+import GHC.IO.Handle.Types
+import qualified GHC.IO.FD as FD
+import qualified GHC.IO.Handle.FD as FD
+import GHC.IO.Exception
+import Data.Typeable (cast)
+#else
 import GHC.IOBase
 import GHC.Handle hiding (fdToHandle)
 import qualified GHC.Handle
 #endif
+#endif
 
 #ifdef __HUGS__
 import Hugs.Prelude (IOException(..), IOErrorType(..))
@@ -101,6 +113,9 @@
     wfd <- peekElemOff p_fd 1
     return (Fd rfd, Fd wfd)
 
+foreign import ccall unsafe "pipe"
+   c_pipe :: Ptr CInt -> IO CInt
+
 -- -----------------------------------------------------------------------------
 -- Duplicating file descriptors
 
@@ -114,6 +129,12 @@
   r <- throwErrnoIfMinus1 "dupTo" (c_dup2 fd1 fd2)
   return (Fd r)
 
+foreign import ccall unsafe "dup"
+   c_dup :: CInt -> IO CInt
+
+foreign import ccall unsafe "dup2"
+   c_dup2 :: CInt -> CInt -> IO CInt
+
 -- -----------------------------------------------------------------------------
 -- Opening and closing files
 
@@ -179,6 +200,9 @@
 		   WriteOnly -> (#const O_WRONLY)
 		   ReadWrite -> (#const O_RDWR)
 
+foreign import ccall unsafe "__hscore_open"
+   c_open :: CString -> CInt -> CMode -> IO CInt
+
 -- |Create and open this file in WriteOnly mode.  A special case of
 -- 'openFd'.  See 'System.Posix.Files' for information on how to use
 -- the 'FileMode' type.
@@ -193,6 +217,9 @@
 closeFd :: Fd -> IO ()
 closeFd (Fd fd) = throwErrnoIfMinus1_ "closeFd" (c_close fd)
 
+foreign import ccall unsafe "HsBase.h close"
+   c_close :: CInt -> IO CInt
+
 -- -----------------------------------------------------------------------------
 -- Converting file descriptors to/from Handles
 
@@ -210,6 +237,24 @@
 fdToHandle :: Fd -> IO Handle
 
 #ifdef __GLASGOW_HASKELL__
+#if __GLASGOW_HASKELL__ >= 611
+handleToFd h = withHandle "handleToFd" h $ \ h_@Handle__{haType=_,..} -> do
+  case cast haDevice of
+    Nothing -> ioError (ioeSetErrorString (mkIOError IllegalOperation
+                                           "handleToFd" (Just h) Nothing) 
+                        "handle is not a file descriptor")
+    Just fd -> do
+     -- converting a Handle into an Fd effectively means
+     -- letting go of the Handle; it is put into a closed
+     -- state as a result. 
+     flushWriteBuffer h_
+     FD.release fd
+     return (Handle__{haType=ClosedHandle,..}, Fd (fromIntegral (FD.fdFD fd)))
+
+fdToHandle fd = FD.fdToHandle (fromIntegral fd)
+
+#else
+
 handleToFd h = withHandle "handleToFd" h $ \ h_ -> do
   -- converting a Handle into an Fd effectively means
   -- letting go of the Handle; it is put into a closed
@@ -224,6 +269,7 @@
 
 fdToHandle fd = GHC.Handle.fdToHandle (fromIntegral fd)
 #endif
+#endif
 
 #ifdef __HUGS__
 handleToFd h = do
@@ -273,6 +319,12 @@
 	      _    		-> ((#const F_GETFL),(#const F_SETFL))
   opt_val = fdOption2Int opt
 
+foreign import ccall unsafe "HsBase.h fcntl_read"
+   c_fcntl_read  :: CInt -> CInt -> IO CInt
+
+foreign import ccall unsafe "HsBase.h fcntl_write"
+   c_fcntl_write :: CInt -> CInt -> CLong -> IO CInt
+
 -- -----------------------------------------------------------------------------
 -- Seeking 
 
@@ -284,7 +336,7 @@
 -- | May throw an exception if this is an invalid descriptor.
 fdSeek :: Fd -> SeekMode -> FileOffset -> IO FileOffset
 fdSeek (Fd fd) mode off =
-  throwErrnoIfMinus1 "fdSeek" (c_lseek fd off (mode2Int mode))
+  throwErrnoIfMinus1 "fdSeek" (Base.c_lseek fd off (mode2Int mode))
 
 -- -----------------------------------------------------------------------------
 -- Locking
@@ -306,6 +358,11 @@
     maybeResult (_, (Unlock, _, _, _)) = Nothing
     maybeResult x = Just x
 
+type CFLock     = ()
+
+foreign import ccall unsafe "HsBase.h fcntl_lock"
+   c_fcntl_lock  :: CInt -> CInt -> Ptr CFLock -> IO CInt
+
 allocaLock :: FileLock -> (Ptr CFLock -> IO a) -> IO a
 allocaLock (lockreq, mode, start, len) io = 
   allocaBytes (#const sizeof(struct flock)) $ \p -> do
@@ -357,22 +414,55 @@
 -- -----------------------------------------------------------------------------
 -- fd{Read,Write}
 
--- | May throw an exception if this is an invalid descriptor.
+-- | Read data from an 'Fd' and convert it to a 'String'.  Throws an
+-- exception if this is an invalid descriptor, or EOF has been
+-- reached.
 fdRead :: Fd
        -> ByteCount -- ^How many bytes to read
        -> IO (String, ByteCount) -- ^The bytes read, how many bytes were read.
 fdRead _fd 0 = return ("", 0)
-fdRead (Fd fd) nbytes = do
-    allocaBytes (fromIntegral nbytes) $ \ bytes -> do
-    rc    <-  throwErrnoIfMinus1Retry "fdRead" (c_read fd bytes nbytes)
+fdRead fd nbytes = do
+    allocaBytes (fromIntegral nbytes) $ \ buf -> do
+    rc <- fdReadBuf fd buf nbytes
     case fromIntegral rc of
-      0 -> ioError (IOError Nothing EOF "fdRead" "EOF" Nothing)
+      0 -> ioError (ioeSetErrorString (mkIOError EOF "fdRead" Nothing Nothing) "EOF")
       n -> do
-       s <- peekCStringLen (bytes, fromIntegral n)
+       s <- peekCStringLen (castPtr buf, fromIntegral n)
        return (s, n)
 
--- | May throw an exception if this is an invalid descriptor.
+-- | Read data from an 'Fd' into memory.  This is exactly equivalent
+-- to the POSIX @read@ function.
+fdReadBuf :: Fd
+          -> Ptr Word8 -- ^ Memory in which to put the data
+          -> ByteCount -- ^ Maximum number of bytes to read
+          -> IO ByteCount -- ^ Number of bytes read (zero for EOF)
+fdReadBuf _fd _buf 0 = return 0
+fdReadBuf fd buf nbytes = 
+  fmap fromIntegral $
+    throwErrnoIfMinus1Retry "fdReadBuf" $ 
+      c_safe_read (fromIntegral fd) (castPtr buf) (fromIntegral nbytes)
+
+foreign import ccall safe "read"
+   c_safe_read :: CInt -> Ptr CChar -> CSize -> IO CSsize
+
+-- | Write a 'String' to an 'Fd' (no character conversion is done,
+-- the least-significant 8 bits of each character are written).
 fdWrite :: Fd -> String -> IO ByteCount
-fdWrite (Fd fd) str = withCStringLen str $ \ (strPtr,len) -> do
-    rc <- throwErrnoIfMinus1Retry "fdWrite" (c_write fd strPtr (fromIntegral len))
+fdWrite fd str = 
+  withCStringLen str $ \ (buf,len) -> do
+    rc <- fdWriteBuf fd (castPtr buf) (fromIntegral len)
     return (fromIntegral rc)
+
+-- | Write data from memory to an 'Fd'.  This is exactly equivalent
+-- to the POSIX @write@ function.
+fdWriteBuf :: Fd
+           -> Ptr Word8    -- ^ Memory containing the data to write
+           -> ByteCount    -- ^ Maximum number of bytes to write
+           -> IO ByteCount -- ^ Number of bytes written
+fdWriteBuf fd buf len =
+  fmap fromIntegral $
+    throwErrnoIfMinus1Retry "fdWriteBuf" $ 
+      c_safe_write (fromIntegral fd) (castPtr buf) (fromIntegral len)
+
+foreign import ccall safe "write" 
+   c_safe_write :: CInt -> Ptr CChar -> CSize -> IO CSsize
diff --git a/System/Posix/Process.hsc b/System/Posix/Process.hsc
--- a/System/Posix/Process.hsc
+++ b/System/Posix/Process.hsc
@@ -71,9 +71,7 @@
 import Foreign.Ptr ( Ptr, nullPtr )
 import Foreign.StablePtr ( StablePtr, newStablePtr, freeStablePtr )
 import Foreign.Storable ( Storable(..) )
-import System.IO
 import System.Exit
-import System.Posix.Error
 import System.Posix.Process.Internals
 import System.Posix.Types
 import Control.Monad
@@ -175,7 +173,7 @@
 
 type CTms = ()
 
-foreign import ccall unsafe "times"
+foreign import ccall unsafe "__hsunix_times"
   c_times :: Ptr CTms -> IO CClock
 
 -- -----------------------------------------------------------------------------
@@ -276,7 +274,7 @@
             -> Bool			    -- ^ Search PATH?
             -> [String]			    -- ^ Arguments
             -> Maybe [(String, String)]	    -- ^ Environment
-            -> IO ()
+            -> IO a
 executeFile path search args Nothing = do
   withCString path $ \s ->
     withMany withCString (path:args) $ \cstrs ->
@@ -285,6 +283,7 @@
 	if search 
 	   then throwErrnoPathIfMinus1_ "executeFile" path (c_execvp s arr)
 	   else throwErrnoPathIfMinus1_ "executeFile" path (c_execv s arr)
+        return undefined -- never reached
 
 executeFile path search args (Just env) = do
   withCString path $ \s ->
@@ -299,6 +298,7 @@
 		   (c_execvpe s arg_arr env_arr)
 	   else throwErrnoPathIfMinus1_ "executeFile" path
 		   (c_execve s arg_arr env_arr)
+        return undefined -- never reached
 
 foreign import ccall unsafe "execvp"
   c_execvp :: CString -> Ptr CString -> IO CInt
diff --git a/System/Posix/Process/Internals.hs b/System/Posix/Process/Internals.hs
--- a/System/Posix/Process/Internals.hs
+++ b/System/Posix/Process/Internals.hs
@@ -9,8 +9,6 @@
 import System.IO.Error
 import GHC.Conc (Signal)
 
--- we had to move this into GHC.Conc in GHC to avoid recursive dependencies.
--- it can be moved back when the signal handling stuff in base is moved out.
 data ProcessStatus = Exited ExitCode
                    | Terminated Signal
                    | Stopped Signal
diff --git a/System/Posix/Semaphore.hsc b/System/Posix/Semaphore.hsc
--- a/System/Posix/Semaphore.hsc
+++ b/System/Posix/Semaphore.hsc
@@ -24,12 +24,12 @@
 #include <fcntl.h>
 
 import Foreign.C
-import Foreign.ForeignPtr
+import Foreign.ForeignPtr hiding (newForeignPtr)
+import Foreign.Concurrent
 import Foreign.Marshal
 import Foreign.Ptr
 import Foreign.Storable
 import System.Posix.Types
-import System.Posix.Error
 import Control.Concurrent
 import Data.Bits
 
@@ -52,11 +52,10 @@
         semOpen' cname =
             do sem <- throwErrnoPathIfNull "semOpen" name $ 
                       sem_open cname (toEnum cflags) mode (toEnum value)
-               finalizer <- mkCallback (finalize sem)
-               fptr <- newForeignPtr finalizer sem
+               fptr <- newForeignPtr sem (finalize sem)
                return $ Semaphore fptr
-        finalize sem _ = throwErrnoPathIfMinus1_ "semOpen" name $
-                         sem_close sem in
+        finalize sem = throwErrnoPathIfMinus1_ "semOpen" name $
+                       sem_close sem in
     withCAString name semOpen'
 
 -- | Delete the semaphore with the given name.
@@ -112,9 +111,6 @@
                           cint <- peek ptr
                           return $ fromEnum cint
 
-foreign import ccall safe "wrapper"
-        mkCallback :: (Ptr () -> IO ()) -> IO (FunPtr (Ptr () -> IO ()))
-        
 foreign import ccall safe "sem_open"
         sem_open :: CString -> CInt -> CMode -> CUInt -> IO (Ptr ())
 foreign import ccall safe "sem_close"
diff --git a/System/Posix/Signals.hsc b/System/Posix/Signals.hsc
--- a/System/Posix/Signals.hsc
+++ b/System/Posix/Signals.hsc
@@ -103,14 +103,17 @@
 import Foreign.C
 import System.Posix.Types
 import System.Posix.Internals
-import System.Posix.Process.Internals
 import System.Posix.Process
-import Control.Monad
+import System.Posix.Process.Internals
 import Data.Dynamic
 
 #ifdef __GLASGOW_HASKELL__
+#if __GLASGOW_HASKELL__ >= 611
+##include "rts/Signals.h"
+#else
 ##include "Signals.h"
-import GHC.IOBase
+#endif
+
 import GHC.Conc hiding (Signal)
 #endif
 
@@ -571,10 +574,12 @@
     	  Nothing -> do SignalSet fp <- getSignalMask; return fp
     	  Just (SignalSet fp) -> return fp
   withForeignPtr fp $ \p -> do
-  c_sigsuspend p
+  _ <- c_sigsuspend p
   return ()
   -- ignore the return value; according to the docs it can only ever be
   -- (-1) with errno set to EINTR.
+  -- XXX My manpage says it can also return EFAULT. And why is ignoring
+  -- EINTR the right thing to do?
  
 foreign import ccall unsafe "sigsuspend"
   c_sigsuspend :: Ptr CSigset -> IO CInt
diff --git a/System/Posix/Terminal.hsc b/System/Posix/Terminal.hsc
--- a/System/Posix/Terminal.hsc
+++ b/System/Posix/Terminal.hsc
@@ -801,5 +801,6 @@
   withForeignPtr fp1 $ \p1 -> do
    withTerminalAttributes termios $ \p2 -> do
     copyBytes p1 p2 (#const sizeof(struct termios))
-    action p1
+    _ <- action p1
+    return ()
   return $ makeTerminalAttributes fp1
diff --git a/System/Posix/Time.hsc b/System/Posix/Time.hsc
--- a/System/Posix/Time.hsc
+++ b/System/Posix/Time.hsc
@@ -33,5 +33,5 @@
 epochTime :: IO EpochTime
 epochTime = throwErrnoIfMinus1 "epochTime" (c_time nullPtr)
 
-foreign import ccall unsafe "time"
+foreign import ccall unsafe "__hsunix_time"
   c_time :: Ptr CTime -> IO CTime
diff --git a/System/Posix/Unistd.hsc b/System/Posix/Unistd.hsc
--- a/System/Posix/Unistd.hsc
+++ b/System/Posix/Unistd.hsc
@@ -158,7 +158,7 @@
 
 data CTimeSpec
 
-foreign import ccall safe "nanosleep" 
+foreign import ccall safe "__hsunix_nanosleep" 
   c_nanosleep :: Ptr CTimeSpec -> Ptr CTimeSpec -> IO CInt
 #endif
 
diff --git a/System/Posix/User.hsc b/System/Posix/User.hsc
--- a/System/Posix/User.hsc
+++ b/System/Posix/User.hsc
@@ -167,13 +167,13 @@
 #ifdef HAVE_GETGRGID_R
 getGroupEntryForID gid = do
   allocaBytes (#const sizeof(struct group)) $ \pgr ->
-    allocaBytes grBufSize $ \pbuf ->
-      alloca $ \ ppgr -> do
-        throwErrorIfNonZero_ "getGroupEntryForID" $
-	     c_getgrgid_r gid pgr pbuf (fromIntegral grBufSize) ppgr
-	throwErrnoIfNull "getGroupEntryForID" $
-	     peekElemOff ppgr 0
-	unpackGroupEntry pgr
+    alloca $ \ ppgr -> do
+      throwErrorIfNonZero_ "getGroupEntryForID" $
+	   doubleAllocWhile isERANGE grBufSize $ \s b ->
+	     c_getgrgid_r gid pgr b (fromIntegral s) ppgr
+      _ <- throwErrnoIfNull "getGroupEntryForID" $
+	   peekElemOff ppgr 0
+      unpackGroupEntry pgr
 
 
 foreign import ccall unsafe "getgrgid_r"
@@ -190,19 +190,19 @@
 #ifdef HAVE_GETGRNAM_R
 getGroupEntryForName name = do
   allocaBytes (#const sizeof(struct group)) $ \pgr ->
-    allocaBytes grBufSize $ \pbuf ->
-      alloca $ \ ppgr ->
-        withCString name $ \ pstr -> do
-          throwErrorIfNonZero_ "getGroupEntryForName" $
-            c_getgrnam_r pstr pgr pbuf (fromIntegral grBufSize) ppgr
-          r <- peekElemOff ppgr 0
-          when (r == nullPtr) $
-            ioError $ flip ioeSetErrorString "no group name"
-                    $ mkIOError doesNotExistErrorType
-                                "getGroupEntryForName"
-                                Nothing
-                                (Just name)
-          unpackGroupEntry pgr
+    alloca $ \ ppgr ->
+      withCString name $ \ pstr -> do
+	throwErrorIfNonZero_ "getGroupEntryForName" $
+	  doubleAllocWhile isERANGE grBufSize $ \s b ->
+	    c_getgrnam_r pstr pgr b (fromIntegral s) ppgr
+	r <- peekElemOff ppgr 0
+	when (r == nullPtr) $
+	  ioError $ flip ioeSetErrorString "no group name"
+		  $ mkIOError doesNotExistErrorType
+			      "getGroupEntryForName"
+			      Nothing
+			      (Just name)
+	unpackGroupEntry pgr
 
 foreign import ccall unsafe "getgrnam_r"
   c_getgrnam_r :: CString -> Ptr CGroup -> CString
@@ -213,6 +213,12 @@
 
 -- | @getAllGroupEntries@ returns all group entries on the system by
 --   repeatedly calling @getgrent@
+
+--
+-- getAllGroupEntries may fail with isDoesNotExistError on Linux due to
+-- this bug in glibc:
+--   http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=466647
+--
 getAllGroupEntries :: IO [GroupEntry]
 #ifdef HAVE_GETGRENT
 getAllGroupEntries =
@@ -235,9 +241,9 @@
 #if defined(HAVE_GETGRGID_R) || defined(HAVE_GETGRNAM_R)
 grBufSize :: Int
 #if defined(HAVE_SYSCONF) && defined(HAVE_SC_GETGR_R_SIZE_MAX)
-grBufSize = sysconfWithDefault 2048 (#const _SC_GETGR_R_SIZE_MAX)
+grBufSize = sysconfWithDefault 1024 (#const _SC_GETGR_R_SIZE_MAX)
 #else
-grBufSize = 2048	-- just assume some value (1024 is too small on OpenBSD)
+grBufSize = 1024
 #endif
 #endif
 
@@ -284,15 +290,15 @@
 #ifdef HAVE_GETPWUID_R
 getUserEntryForID uid = do
   allocaBytes (#const sizeof(struct passwd)) $ \ppw ->
-    allocaBytes pwBufSize $ \pbuf ->
-      alloca $ \ pppw -> do
-        throwErrorIfNonZero_ "getUserEntryForID" $
-	     c_getpwuid_r uid ppw pbuf (fromIntegral pwBufSize) pppw
-	throwErrnoIfNull "getUserEntryForID" $
-	     peekElemOff pppw 0
-	unpackUserEntry ppw
+    alloca $ \ pppw -> do
+      throwErrorIfNonZero_ "getUserEntryForID" $
+	   doubleAllocWhile isERANGE pwBufSize $ \s b ->
+	     c_getpwuid_r uid ppw b (fromIntegral s) pppw
+      _ <- throwErrnoIfNull "getUserEntryForID" $
+	   peekElemOff pppw 0
+      unpackUserEntry ppw
 
-foreign import ccall unsafe "getpwuid_r"
+foreign import ccall unsafe "__hsunix_getpwuid_r"
   c_getpwuid_r :: CUid -> Ptr CPasswd -> 
 			CString -> CSize -> Ptr (Ptr CPasswd) -> IO CInt
 #elif HAVE_GETPWUID
@@ -314,21 +320,21 @@
 #if HAVE_GETPWNAM_R
 getUserEntryForName name = do
   allocaBytes (#const sizeof(struct passwd)) $ \ppw ->
-    allocaBytes pwBufSize $ \pbuf ->
-      alloca $ \ pppw ->
-        withCString name $ \ pstr -> do
-          throwErrorIfNonZero_ "getUserEntryForName" $
-            c_getpwnam_r pstr ppw pbuf (fromIntegral pwBufSize) pppw
-          r <- peekElemOff pppw 0
-          when (r == nullPtr) $
-            ioError $ flip ioeSetErrorString "no user name"
-                    $ mkIOError doesNotExistErrorType
-                                "getUserEntryForName"
-                                Nothing
-                                (Just name)
-          unpackUserEntry ppw
+    alloca $ \ pppw ->
+      withCString name $ \ pstr -> do
+	throwErrorIfNonZero_ "getUserEntryForName" $
+	  doubleAllocWhile isERANGE pwBufSize $ \s b ->
+	    c_getpwnam_r pstr ppw b (fromIntegral s) pppw
+	r <- peekElemOff pppw 0
+	when (r == nullPtr) $
+	  ioError $ flip ioeSetErrorString "no user name"
+		  $ mkIOError doesNotExistErrorType
+			      "getUserEntryForName"
+			      Nothing
+			      (Just name)
+	unpackUserEntry ppw
 
-foreign import ccall unsafe "getpwnam_r"
+foreign import ccall unsafe "__hsunix_getpwnam_r"
   c_getpwnam_r :: CString -> Ptr CPasswd
                -> CString -> CSize -> Ptr (Ptr CPasswd) -> IO CInt
 #elif HAVE_GETPWNAM
@@ -359,7 +365,7 @@
                      else do thisentry <- unpackUserEntry ppw
                              worker (thisentry : accum)
 
-foreign import ccall unsafe "getpwent"
+foreign import ccall unsafe "__hsunix_getpwent"
   c_getpwent :: IO (Ptr CPasswd)
 foreign import ccall unsafe "setpwent"
   c_setpwent :: IO ()
@@ -391,6 +397,14 @@
     unsafePerformIO $ do v <- fmap fromIntegral $ c_sysconf sc
                          return $ if v == (-1) then def else v
 #endif
+
+isERANGE :: Integral a => a -> Bool
+isERANGE = (== eRANGE) . Errno . fromIntegral
+
+doubleAllocWhile :: (a -> Bool) -> Int -> (Int -> Ptr b -> IO a) -> IO a
+doubleAllocWhile p s m = do
+  r <- allocaBytes s (m s)
+  if p r then doubleAllocWhile p (2 * s) m else return r
 
 unpackUserEntry :: Ptr CPasswd -> IO UserEntry
 unpackUserEntry ptr = do
diff --git a/cbits/HsUnix.c b/cbits/HsUnix.c
--- a/cbits/HsUnix.c
+++ b/cbits/HsUnix.c
@@ -42,6 +42,58 @@
     return mknod(pathname,mode,dev);
 }
 
+#ifdef HAVE_GETPWENT
+// getpwent is a macro on some platforms, so we need a wrapper:
+struct passwd *__hsunix_getpwent(void)
+{
+    return getpwent();
+}
+#endif
+
+#if HAVE_GETPWNAM_R
+// getpwnam_r is a macro on some platforms, so we need a wrapper:
+int __hsunix_getpwnam_r(const char *name, struct passwd *pw, char *buffer,
+                        size_t buflen, struct passwd **result)
+{
+    return getpwnam_r(name, pw, buffer, buflen, result);
+}
+#endif
+
+#ifdef HAVE_GETPWUID_R
+// getpwuid_r is a macro on some platforms, so we need a wrapper:
+int __hsunix_getpwuid_r(uid_t uid, struct passwd *pw, char *buffer,
+                        size_t buflen, struct passwd **result)
+{
+    return getpwuid_r(uid, pw, buffer, buflen, result);
+}
+#endif
+
+#ifdef HAVE_NANOSLEEP
+// nanosleep is a macro on some platforms, so we need a wrapper:
+int __hsunix_nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+    return nanosleep(rqtp, rmtp);
+}
+#endif
+
+// opendir is a macro on some platforms, so we need a wrapper:
+DIR *__hsunix_opendir(const char *filename)
+{
+    return opendir(filename);
+}
+
+// time is a macro on some platforms, so we need a wrapper:
+time_t __hsunix_time(time_t *tloc)
+{
+    return time(tloc);
+}
+
+// times is a macro on some platforms, so we need a wrapper:
+clock_t __hsunix_times(struct tms *tp)
+{
+    return times(tp);
+}
+
 #ifdef HAVE_PTSNAME
 // I cannot figure out how to make the definitions of the following
 // functions visible in <stdlib.h> on Linux.  But these definitions
diff --git a/cbits/dirUtils.c b/cbits/dirUtils.c
new file mode 100644
--- /dev/null
+++ b/cbits/dirUtils.c
@@ -0,0 +1,83 @@
+/* 
+ * (c) The University of Glasgow 2002
+ *
+ * Directory Runtime Support
+ */
+
+/* needed only for solaris2_HOST_OS */
+#ifdef __GLASGOW_HASKELL__
+#include "ghcconfig.h"
+#endif
+
+// The following is required on Solaris to force the POSIX versions of
+// the various _r functions instead of the Solaris versions.
+#ifdef solaris2_HOST_OS
+#define _POSIX_PTHREAD_SEMANTICS
+#endif
+
+#include "HsUnix.h"
+
+/*
+ * read an entry from the directory stream; opt for the
+ * re-entrant friendly way of doing this, if available.
+ */
+int
+__hscore_readdir( DIR *dirPtr, struct dirent **pDirEnt )
+{
+#if HAVE_READDIR_R
+  struct dirent* p;
+  int res;
+  static unsigned int nm_max = (unsigned int)-1;
+  
+  if (pDirEnt == NULL) {
+    return -1;
+  }
+  if (nm_max == (unsigned int)-1) {
+#ifdef NAME_MAX
+    nm_max = NAME_MAX + 1;
+#else
+    nm_max = pathconf(".", _PC_NAME_MAX);
+    if (nm_max == -1) { nm_max = 255; }
+    nm_max++;
+#endif
+  }
+  p = (struct dirent*)malloc(sizeof(struct dirent) + nm_max);
+  if (p == NULL) return -1;
+  res = readdir_r(dirPtr, p, pDirEnt);
+  if (res != 0) {
+      *pDirEnt = NULL;
+      free(p);
+  }
+  else if (*pDirEnt == NULL) {
+    // end of stream
+    free(p);
+  }
+  return res;
+#else
+
+  if (pDirEnt == NULL) {
+    return -1;
+  }
+
+  *pDirEnt = readdir(dirPtr);
+  if (*pDirEnt == NULL) {
+    return -1;
+  } else {
+    return 0;
+  }  
+#endif
+}
+
+char *
+__hscore_d_name( struct dirent* d )
+{
+  return (d->d_name);
+}
+
+void
+__hscore_free_dirent(struct dirent *dEnt)
+{
+#if HAVE_READDIR_R
+  free(dEnt);
+#endif
+}
diff --git a/configure b/configure
--- a/configure
+++ b/configure
@@ -5185,6 +5185,100 @@
 done
 
 
+for ac_func in readdir_r
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
 # Avoid adding rt if absent or unneeded
 { echo "$as_me:$LINENO: checking for shm_open in -lrt" >&5
 echo $ECHO_N "checking for shm_open in -lrt... $ECHO_C" >&6; }
@@ -5801,7 +5895,7 @@
 ### we'd like to return it; otherwise, we'll fake it.
 { echo "$as_me:$LINENO: checking return type of usleep" >&5
 echo $ECHO_N "checking return type of usleep... $ECHO_C" >&6; }
-if test "${cv_func_usleep_return_type+set}" = set; then
+if test "${fptools_cv_func_usleep_return_type+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat >conftest.$ac_ext <<_ACEOF
@@ -5815,16 +5909,16 @@
 _ACEOF
 if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
   $EGREP "void[      ]+usleep" >/dev/null 2>&1; then
-  cv_func_usleep_return_type=void
+  fptools_cv_func_usleep_return_type=void
 else
-  cv_func_usleep_return_type=int
+  fptools_cv_func_usleep_return_type=int
 fi
 rm -f conftest*
 
 fi
-{ echo "$as_me:$LINENO: result: $cv_func_usleep_return_type" >&5
-echo "${ECHO_T}$cv_func_usleep_return_type" >&6; }
-case "$cv_func_usleep_return_type" in
+{ echo "$as_me:$LINENO: result: $fptools_cv_func_usleep_return_type" >&5
+echo "${ECHO_T}$fptools_cv_func_usleep_return_type" >&6; }
+case "$fptools_cv_func_usleep_return_type" in
   "void" )
 
 cat >>confdefs.h <<\_ACEOF
@@ -5838,7 +5932,7 @@
 ###  in common use return void.
 { echo "$as_me:$LINENO: checking return type of unsetenv" >&5
 echo $ECHO_N "checking return type of unsetenv... $ECHO_C" >&6; }
-if test "${cv_func_unsetenv_return_type+set}" = set; then
+if test "${fptools_cv_func_unsetenv_return_type+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat >conftest.$ac_ext <<_ACEOF
@@ -5852,16 +5946,16 @@
 _ACEOF
 if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
   $EGREP "void[      ]+unsetenv" >/dev/null 2>&1; then
-  cv_func_unsetenv_return_type=void
+  fptools_cv_func_unsetenv_return_type=void
 else
-  cv_func_unsetenv_return_type=int
+  fptools_cv_func_unsetenv_return_type=int
 fi
 rm -f conftest*
 
 fi
-{ echo "$as_me:$LINENO: result: $cv_func_unsetenv_return_type" >&5
-echo "${ECHO_T}$cv_func_unsetenv_return_type" >&6; }
-case "$cv_func_unsetenv_return_type" in
+{ echo "$as_me:$LINENO: result: $fptools_cv_func_unsetenv_return_type" >&5
+echo "${ECHO_T}$fptools_cv_func_unsetenv_return_type" >&6; }
+case "$fptools_cv_func_unsetenv_return_type" in
   "void" )
 
 cat >>confdefs.h <<\_ACEOF
diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -27,6 +27,7 @@
 AC_CHECK_FUNCS([nanosleep])
 AC_CHECK_FUNCS([ptsname])
 AC_CHECK_FUNCS([setitimer])
+AC_CHECK_FUNCS([readdir_r])
 
 # Avoid adding rt if absent or unneeded
 AC_CHECK_LIB(rt, shm_open, [EXTRA_LIBS="$EXTRA_LIBS rt" CFLAGS="$CFLAGS -lrt"])
@@ -69,12 +70,12 @@
 
 ### On some systems usleep has no return value.  If it does have one,
 ### we'd like to return it; otherwise, we'll fake it.
-AC_CACHE_CHECK([return type of usleep], cv_func_usleep_return_type,
+AC_CACHE_CHECK([return type of usleep], fptools_cv_func_usleep_return_type,
   [AC_EGREP_HEADER(changequote(<, >)<void[      ]+usleep>changequote([, ]),
                    /usr/include/unistd.h,
-                   [cv_func_usleep_return_type=void],
-                   [cv_func_usleep_return_type=int])])
-case "$cv_func_usleep_return_type" in
+                   [fptools_cv_func_usleep_return_type=void],
+                   [fptools_cv_func_usleep_return_type=int])])
+case "$fptools_cv_func_usleep_return_type" in
   "void" )
     AC_DEFINE([USLEEP_RETURNS_VOID], [1], [Define if the system headers declare usleep to return void.])
   ;;
@@ -82,12 +83,12 @@
 
 ###  POSIX.1003.1 unsetenv returns 0 or -1 (EINVAL), but older implementations
 ###  in common use return void.
-AC_CACHE_CHECK([return type of unsetenv], cv_func_unsetenv_return_type,
+AC_CACHE_CHECK([return type of unsetenv], fptools_cv_func_unsetenv_return_type,
   [AC_EGREP_HEADER(changequote(<, >)<void[      ]+unsetenv>changequote([, ]),
                    /usr/include/stdlib.h,
-                   [cv_func_unsetenv_return_type=void],
-                   [cv_func_unsetenv_return_type=int])])
-case "$cv_func_unsetenv_return_type" in
+                   [fptools_cv_func_unsetenv_return_type=void],
+                   [fptools_cv_func_unsetenv_return_type=int])])
+case "$fptools_cv_func_unsetenv_return_type" in
   "void" )
     AC_DEFINE([UNSETENV_RETURNS_VOID], [1], [Define if stdlib.h declares unsetenv to return void.])
   ;;
diff --git a/include/HsUnix.h b/include/HsUnix.h
--- a/include/HsUnix.h
+++ b/include/HsUnix.h
@@ -127,6 +127,37 @@
 // lstat is a macro on some platforms, so we need a wrapper:
 int __hsunix_mknod(const char *pathname, mode_t mode, dev_t dev);
 
+#ifdef HAVE_GETPWENT
+// getpwent is a macro on some platforms, so we need a wrapper:
+struct passwd *__hsunix_getpwent(void);
+#endif
+
+#if HAVE_GETPWNAM_R
+// getpwnam_r is a macro on some platforms, so we need a wrapper:
+int __hsunix_getpwnam_r(const char *, struct passwd *, char *, size_t,
+                        struct passwd **);
+#endif
+
+#ifdef HAVE_GETPWUID_R
+// getpwuid_r is a macro on some platforms, so we need a wrapper:
+int __hsunix_getpwuid_r(uid_t, struct passwd *, char *, size_t,
+                        struct passwd **);
+#endif
+
+#ifdef HAVE_NANOSLEEP
+// nanosleep is a macro on some platforms, so we need a wrapper:
+int __hsunix_nanosleep(const struct timespec *, struct timespec *);
+#endif
+
+// opendir is a macro on some platforms, so we need a wrapper:
+DIR *__hsunix_opendir(const char *);
+
+// time is a macro on some platforms, so we need a wrapper:
+time_t __hsunix_time(time_t *);
+
+// times is a macro on some platforms, so we need a wrapper:
+clock_t __hsunix_times(struct tms *);
+
 #ifdef HAVE_PTSNAME
 // I cannot figure out how to make the definitions of the following
 // functions visible in <stdlib.h> on Linux.  But these definitions
diff --git a/include/HsUnixConfig.h b/include/HsUnixConfig.h
--- a/include/HsUnixConfig.h
+++ b/include/HsUnixConfig.h
@@ -163,6 +163,9 @@
 /* Define to 1 if you have the <pwd.h> header file. */
 #define HAVE_PWD_H 1
 
+/* Define to 1 if you have the `readdir_r' function. */
+#define HAVE_READDIR_R 1
+
 /* Define to 1 if RTLD_DEFAULT is available. */
 /* #undef HAVE_RTLDDEFAULT */
 
diff --git a/include/HsUnixConfig.h.in b/include/HsUnixConfig.h.in
--- a/include/HsUnixConfig.h.in
+++ b/include/HsUnixConfig.h.in
@@ -162,6 +162,9 @@
 /* Define to 1 if you have the <pwd.h> header file. */
 #undef HAVE_PWD_H
 
+/* Define to 1 if you have the `readdir_r' function. */
+#undef HAVE_READDIR_R
+
 /* Define to 1 if RTLD_DEFAULT is available. */
 #undef HAVE_RTLDDEFAULT
 
diff --git a/unix.cabal b/unix.cabal
--- a/unix.cabal
+++ b/unix.cabal
@@ -1,8 +1,9 @@
 name:		unix
-version:	2.3.2.0
+version:	2.4.0.0
 license:	BSD3
 license-file:	LICENSE
 maintainer:	libraries@haskell.org
+bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries/unix
 synopsis:	POSIX functionality
 category:       System
 description:
@@ -12,29 +13,6 @@
 	IEEE Std. 1003.1).
 	.
 	The package is not supported under Windows (except under Cygwin).
-build-type: Configure
-exposed-modules:
-		System.Posix
-		System.Posix.DynamicLinker.Module
-		System.Posix.DynamicLinker.Prim
-		System.Posix.Directory
-		System.Posix.DynamicLinker
-		System.Posix.Env
-		System.Posix.Error
-		System.Posix.Files
-		System.Posix.IO
-		System.Posix.Process
-		System.Posix.Process.Internals
-		System.Posix.Resource
-		System.Posix.Temp
-		System.Posix.Terminal
-		System.Posix.Time
-		System.Posix.Unistd
-		System.Posix.User
-        System.Posix.Signals
-		System.Posix.Signals.Exts
-                System.Posix.Semaphore
-                System.Posix.SharedMem
 extra-source-files:
         config.guess config.sub install-sh
 		configure.ac configure
@@ -43,10 +21,41 @@
 extra-tmp-files:
 		config.log config.status autom4te.cache
 		unix.buildinfo include/HsUnixConfig.h
-build-depends:	base
-extensions:	CPP, ForeignFunctionInterface, EmptyDataDecls
-include-dirs: 	include
-includes:       HsUnix.h execvpe.h
-install-includes:
-		HsUnix.h HsUnixConfig.h execvpe.h
-c-sources:	cbits/HsUnix.c cbits/execvpe.c
+build-type: Configure
+Cabal-Version: >= 1.6
+
+Library
+    exposed-modules:
+        System.Posix
+        System.Posix.DynamicLinker.Module
+        System.Posix.DynamicLinker.Prim
+        System.Posix.Directory
+        System.Posix.DynamicLinker
+        System.Posix.Env
+        System.Posix.Error
+        System.Posix.Files
+        System.Posix.IO
+        System.Posix.Process
+        System.Posix.Process.Internals
+        System.Posix.Resource
+        System.Posix.Temp
+        System.Posix.Terminal
+        System.Posix.Time
+        System.Posix.Unistd
+        System.Posix.User
+        System.Posix.Signals
+        System.Posix.Signals.Exts
+        System.Posix.Semaphore
+        System.Posix.SharedMem
+    build-depends:	base >= 4.1 && < 4.3
+    extensions:	CPP, ForeignFunctionInterface, EmptyDataDecls
+    include-dirs: 	include
+    includes:       HsUnix.h execvpe.h
+    install-includes:
+        HsUnix.h HsUnixConfig.h execvpe.h
+    c-sources:	cbits/HsUnix.c cbits/execvpe.c cbits/dirUtils.c
+
+source-repository head
+    type:     darcs
+    location: http://darcs.haskell.org/packages/unix/
+
