diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,123 @@
+License Agreement
+
+Preamble
+
+The aim of this licence agreement is to enable the free use of the
+software that is described in the sequel by anyone. In order to
+guarantee this, it is necessary to set up rules for the use of the
+software that hold for any user.
+
+Provider of this licence is the University of Bremen, represented by
+its principal (called "licence provider" in the sequel). The provider
+of the licence has developed the "Uniform Workbench" (just
+called "software" in the sequel). The software includes a
+graphical tool for accessing documents stored in a versioned repository,
+but also contains libraries and some other tools.
+
+Following the ideas of open source software, the licence provider
+gives access to the software without fee for anyone (called "licence
+taker" in the sequel) under the following conditions which are similar
+to the Lesser Gnu Public License (LGPL). Each licence taker obligates
+himself to follow the terms of use below.
+
+
+
+1 Principle
+
+Each licence taker appreciating these terms of use receives a simple
+right, not resctricted in time and space and without any fee, to use
+the software, in particular, to copy, distribute and process
+it. Exclusively the following terms of use do hold.  The licence
+provider explicitly contradicts any conflicting terms of business. By
+making use of the rights described below, in particular by copying or
+distributing it, a licence treaty between the licence provider and the
+licence takes is concluded.
+
+
+
+2 Copying
+
+The licence taker has the right to make and distribute unmodified
+copies of the software on any media. Prerequisite for this is that the
+licence provider and this licence agreement is clearly recognizable,
+and that the sources are distributed together with the software.
+
+
+
+3 Modification and Distribution
+
+The licence taker has the right to modify copies of the software (or
+parts thereof) and to distribute these modifications under the terms
+of 2 above and the following conditions:
+
+1. The modified software has to carry a clear mark that points to the
+original licence provider, the modification that has been made, and
+the date of the modification.
+
+2. The licence taker has to ensure that the software as a whole or
+parts of it are accessible to third parties under the terms of this
+licence agreement without fee.
+
+3. If during the modification a copyright of the licence taker
+emerges, then this copyright must be put under the terms of this
+licence if the modified software is distributed.
+
+
+4 Other duties
+
+1. Reference to the validity of this licence agreement must not be
+modified or deleted by the licence taker.
+
+2. The use of the software by third parties must not be conditioned by
+the fulfilment of duties that are not mentioned in this licence
+agreement.
+
+3. The use of the software must not be prevented or complicated by
+means fo technical protection, in particular copy protection means.
+
+
+
+5 Liability, Update
+
+1. Liability of the licence provider is restriced to fraudulent
+withheld factual or legal errors. The licence provider does not give
+any warranty, and neither ensures any properties of the
+software. Furthermore, he is liable only for those damages that are
+caused by willful or grossly negligent violation of duty.
+
+2. The licence provider has the right to update these terms of use at
+any time.
+
+
+
+
+6 Forum for users
+
+The licence provider does provide neither support nor
+consultation. Without acknowledgement of any legal duty, the licence
+provider will care about the installation of a user forum for
+discussions about the software and its further development.
+
+
+7 Legal domicile
+
+It is agreed that the law of the Federal Republic of Germany is valid
+for this licence agreement. For any lawsuits or legal actions emerging
+from this licence agreement, it is agreed that exclusively German
+courts are competent. Legal domicile is Bremen.
+
+
+8 Termination through Offence
+
+Any violation of a duty of this agreement automatically terminates the
+rights of use of the offender.
+
+
+
+9 Salvatorian Clause
+
+If any rule of this agreement should be or become inoperative,
+validity of the other rules is not affected. The parties will care
+about replacing the invalid rule by some valid rule that comes close
+to the purpose of this agreement.
+
diff --git a/Posixutil/BlockSigPIPE.hs b/Posixutil/BlockSigPIPE.hs
new file mode 100644
--- /dev/null
+++ b/Posixutil/BlockSigPIPE.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE CPP #-}
+-- | Module that should also compile on Windows for blocking sigPIPE on
+-- Unix, something you need to do to avoid the entire system crashing when
+-- a pipe is closed.
+module Posixutil.BlockSigPIPE(
+   blockSigPIPE, -- :: IO ()
+   ) where
+
+import Util.Computation
+
+#ifndef WINDOWS
+import System.Posix.Signals
+#endif
+
+blockSigPIPE :: IO ()
+blockSigPIPE = do
+#ifndef WINDOWS
+  installHandler sigPIPE Ignore Nothing
+#endif
+  done
diff --git a/Posixutil/ChildProcess.hs b/Posixutil/ChildProcess.hs
new file mode 100644
--- /dev/null
+++ b/Posixutil/ChildProcess.hs
@@ -0,0 +1,370 @@
+-- |
+-- Description: Calling other programs.
+--
+-- Calling other programs.
+--
+-- This module now serves basically as an interface to GHC's new
+-- System.Process module.
+module Posixutil.ChildProcess (
+   ChildProcess,
+   PosixProcess, -- holds information about a process to be created
+
+   ChildProcessStatus(ChildExited,ChildTerminated),
+
+   -- linemode, arguments, &c encode configuration options for
+   -- a process to be created.  Various functions for creating new
+   -- processes take a [Config PosixProcess] as an argument.
+   -- In particular newChildProcess does.
+   linemode,       -- :: Bool -> Config PosixProcess
+   -- for meaning of linemode see readMsg.
+   arguments,      -- :: [String] -> Config PosixProcess
+   appendArguments,-- :: [String] -> Config PosixProcess
+   environment,    -- :: [(String,String)] -> Config PosixProcess
+   standarderrors, -- :: Bool -> Config PosixProcess
+   -- if standarderrors is true, we send stderr to the childprocesses
+   -- out channel (of which there is only one).  Otherwise we
+   -- display them, with the name of the responsible process,
+   -- on our stderr.
+   challengeResponse, -- :: (String,String) -> Config PosixProcess
+   -- Set a "challenge" and "response".  Each is given as a String.
+   -- The challenge (first String) will have newline appended if in line-mode.
+   -- However the response will always be expected exactly as is.
+   toolName, -- :: String -> Config PosixProcess
+   -- The name of the tool, used in error messages and in the debug file.
+
+   newChildProcess, -- :: FilePath -> [Config PosixProcess] -> IO ChildProcess
+
+
+   sendMsg, -- :: ChildProcess -> String -> IO ()
+   -- sendMsg sends a String to the ChildProcess, adding a new line
+   -- for line mode.
+
+   sendMsgRaw, -- :: ChildProcess -> CStringLen -> IO ()
+   -- sendMsgRaw writes a CStringLen
+   -- to the child process.  It does not append a newline.
+
+   readMsg, -- :: ChildProcess -> IO String
+
+   waitForChildProcess, -- :: ChildProcess -> IO ChildProcessStatus
+    -- waits until the ChildProcess exits or is terminated
+   )
+where
+
+import System.IO
+import System.IO.Error as IO
+
+import Foreign.C.String
+import System.Exit
+import System.Process
+import Control.Concurrent
+import qualified Control.Exception as Exception
+
+import Util.Computation
+import Util.CompileFlags
+import Util.Object
+import Util.IOExtras
+import Util.Debug
+import Util.FileNames
+
+import Events.Destructible
+
+import Posixutil.BlockSigPIPE
+import Posixutil.ProcessClasses
+
+-- --------------------------------------------------------------------------
+--  Tool Parameters
+-- --------------------------------------------------------------------------
+
+-- | Describes configuration options for the process.
+data PosixProcess =
+   PosixProcess {
+      args            :: [String],
+      ppenv           :: Maybe [(String, String)],
+      lmode           :: Bool, -- line mode
+      includestderr   :: Bool, -- include stderr
+      cresponse       :: Maybe (String,String),
+      toolname        :: Maybe String
+     }
+
+-- | Initial configuration options.
+defaultPosixProcess :: PosixProcess
+defaultPosixProcess =
+   PosixProcess {
+      args = [],
+      ppenv = Nothing,
+      lmode = True,
+      includestderr = True,
+      cresponse = Nothing,
+      toolname = Nothing
+      }
+
+
+-- | If 'True', 'readMsg' returns lines, otherwise it returs the first input
+-- that's available
+linemode :: Bool -> Config PosixProcess
+linemode lm' parms = return parms{lmode = lm'}
+
+-- | Set command arguments
+arguments :: [String] -> Config PosixProcess
+arguments args' parms = return parms{args = args'}
+
+-- | Append command arguments
+appendArguments :: [String] -> Config PosixProcess
+appendArguments args' parms = return parms{args = (args parms) ++ args'}
+
+-- | Set the process' environment.
+environment :: [(String,String)] -> Config PosixProcess
+environment env' parms = return parms{ppenv = Just env'}
+
+-- if 'True', we send stderr to the childprocesses
+-- out channel (of which there is only one).  Otherwise we
+-- display them, with the name of the responsible process,
+-- on our stderr.
+standarderrors :: Bool -> Config PosixProcess
+standarderrors err' parms = return parms{includestderr = err'}
+
+-- | Set a "challenge" and "response".  This is used as a test
+-- when the tool starts up, to make sure that everything is
+-- working properly.
+---
+-- The challenge (first String) will have newline appended if in line-mode.
+-- However the response will always be expected exactly as is.
+challengeResponse :: (String,String) -> Config PosixProcess
+challengeResponse cr parms = return parms {cresponse = Just cr}
+
+-- | The name of the tool, used in error messages and in the debug file.
+toolName :: String -> Config PosixProcess
+toolName n parms = return parms {toolname = Just n}
+
+
+-- -------------------------------------------------------------------------
+-- Data Declaration
+-- -------------------------------------------------------------------------
+
+-- | A running process
+data ChildProcess = ChildProcess {
+   processHandle :: ProcessHandle,
+      -- | GHC's handle to the process.
+
+   processIn :: Handle,
+   processOutput :: Chan String,
+
+   childObjectID :: ObjectID,
+   lineMode :: Bool,
+      -- | if True readMsg returns lines, otherwise
+      -- it returns the first input that's available.
+   toolTitle :: String
+      -- Title of the tool, derived from the file name or
+      -- supplied by the toolName function,
+      -- used in the debugging file.
+   }
+
+-- | Status if a process
+data ChildProcessStatus = ChildExited ExitCode
+                        | ChildTerminated
+   deriving (Eq, Ord, Show)
+
+-- -------------------------------------------------------------------------
+-- Initialising
+-- -------------------------------------------------------------------------
+
+-- | Starting a new 'ChildProcess'
+newChildProcess :: FilePath -> [Config PosixProcess] -> IO ChildProcess
+newChildProcess filePath configurations =
+   do
+      parms <- configure defaultPosixProcess configurations
+
+      debug("newChildProcess:")
+      debug(filePath:(args parms))
+
+      blockSigPIPE
+
+      -- run the process.
+      (processIn,processOut,processErr,processHandle) <- runInteractiveProcess
+         filePath (args parms) Nothing (ppenv parms)
+
+      childObjectID <- newObject
+
+      processOutput <- newChan
+
+      let
+         toolTitle :: String
+         toolTitle =
+            case (toolname parms,splitName filePath) of
+               (Just toolTitle,_) -> toolTitle
+               (Nothing,(dir,toolTitle)) -> toolTitle
+
+         lineMode :: Bool
+         lineMode = lmode parms
+
+         getFn :: Handle -> IO String
+         getFn = if lineMode then hGetLine else getAvail
+
+         -- Worker thread which reads input from the tool and sends it to
+         -- processOutput
+         monitorHandle :: Handle -> IO ()
+         monitorHandle handle =
+            foreverUntil (
+               do
+                  nextOrEOF <- catchEOF (getFn handle)
+                  case nextOrEOF of
+                     Nothing -> return True
+                     Just line ->
+                        do
+                           debugRead childProcess (line ++ "\n")
+                           writeChan processOutput line
+                           return False
+               )
+
+         -- Worker thread which reads input from the tool (in fact, stderr)
+         -- and reports it.
+         reportErrors :: IO ()
+         reportErrors =
+            foreverUntil (
+               do
+                  nextOrEOF <- catchEOF (getFn processErr)
+                  case nextOrEOF of
+                     Nothing -> return True
+                     Just line ->
+                        do
+                           hPutStrLn stderr ("Error from " ++ toolTitle
+                              ++ ": " ++ line)
+                           hFlush stderr
+                           return False
+               )
+
+         getAvail :: Handle -> IO String
+         getAvail handle =
+            do
+               c0 <- hGetChar handle -- force a wait if necessary
+               getAvail0 [c0] handle
+
+         getAvail0 :: String -> Handle -> IO String
+         getAvail0 acc handle =
+            do
+               ready <- hReady handle
+               if ready
+                  then
+                     do
+                        c <- hGetChar handle
+                        getAvail0 (c : acc) handle
+                  else
+                     return (reverse acc)
+
+         childProcess = ChildProcess {
+            processHandle = processHandle,
+            processIn = processIn,
+            processOutput = processOutput,
+            childObjectID = childObjectID,
+            lineMode = lineMode,
+            toolTitle = toolTitle
+            }
+
+      -- Do challenge-response
+      case cresponse parms of
+         Nothing -> done
+         Just (challenge,response) ->
+            do
+               sendMsg childProcess challenge
+               responseLineOrError
+                  <- IO.try (mapM (const (hGetChar processOut))
+                     [1..length response])
+               case responseLineOrError of
+                  Left excep -> error (
+                     "Starting " ++ toolTitle ++ " got IO error "
+                     ++ show excep)
+                  Right line -> if line == response
+                     then
+                        done
+                     else
+                        do
+                           remainder <- getAvail0 [] processOut
+                           error (
+                              "Starting " ++ toolTitle
+                              ++ " got unexpected response "
+                              ++ line ++ remainder
+                              )
+
+      forkIO (monitorHandle processOut)
+      if includestderr parms
+         then
+            forkIO (monitorHandle processErr)
+         else
+            forkIO (reportErrors)
+
+      return childProcess
+
+-- -------------------------------------------------------------------------
+-- Communicating with the process
+-- -------------------------------------------------------------------------
+
+-- | Sends a String to the ChildProcess, adding a new line
+-- for line mode.
+sendMsg :: ChildProcess -> String -> IO ()
+sendMsg childProcess line =
+   do
+      debugWrite childProcess line
+      let
+         lineToWrite =
+            if lineMode childProcess then line ++ recordSep else line
+      hPutStr (processIn childProcess) lineToWrite
+      hFlush (processIn childProcess)
+
+
+
+-- | Writes a CStringLen
+-- to the child process.  It does not append a newline.
+sendMsgRaw :: ChildProcess -> CStringLen -> IO ()
+sendMsgRaw childProcess (cStrLn@(ptr,len)) =
+   do
+      if isDebug
+         then
+            do
+               str <- peekCStringLen cStrLn
+               debugWrite childProcess str
+         else
+            done
+      hPutBuf (processIn childProcess) ptr len
+      hFlush (processIn childProcess)
+
+-- | Reads a string from the ChildProcess
+readMsg :: ChildProcess -> IO String
+readMsg childProcess = readChan (processOutput childProcess)
+
+-- -------------------------------------------------------------------------
+-- Waiting for a process
+-- -------------------------------------------------------------------------
+
+-- | Waits for the ChildProcess to exit or be terminated
+waitForChildProcess :: ChildProcess -> IO ChildProcessStatus
+waitForChildProcess p =
+  Exception.catch (waitForChild p) (\_ -> return ChildTerminated)
+  where
+    waitForChild p = do
+      exitCode <- waitForProcess (processHandle p)
+      return (ChildExited exitCode)
+
+-- -------------------------------------------------------------------------
+-- Writing debugging information to a file
+-- -------------------------------------------------------------------------
+
+debugWrite :: ChildProcess -> String -> IO ()
+debugWrite childProcess str =
+   debugString (toolTitle childProcess++">"++str++"\n")
+
+debugRead :: ChildProcess -> String -> IO ()
+debugRead childProcess str =
+   debugString (toolTitle childProcess++"<"++str++"\n")
+
+-- -------------------------------------------------------------------------
+-- Instances
+-- -------------------------------------------------------------------------
+
+instance Object ChildProcess where
+   objectID = childObjectID
+
+instance Destroyable ChildProcess where
+   destroy childProcess = terminateProcess (processHandle childProcess)
+
+instance Tool ChildProcess where
+   getToolStatus childProcess = getProcessExitCode (processHandle childProcess)
diff --git a/Posixutil/CopyFile.hs b/Posixutil/CopyFile.hs
new file mode 100644
--- /dev/null
+++ b/Posixutil/CopyFile.hs
@@ -0,0 +1,186 @@
+-- | This contains functions for copying to and from files
+module Posixutil.CopyFile(
+   copyFile,
+   copyFileWE,
+   copyStringToFile,
+   copyStringToFileCheck,
+   copyFileToString,
+   copyFileToStringCheck,
+   copyICStringLenToFile,
+   copyFileToICStringLenCheck,
+
+   copyCStringLenToFile,
+   copyFileToCStringLen,
+   copyFileToICStringLen,
+   ) where
+
+import System.IO as IO
+import System.IO.Error as IO
+import qualified System.IO.Error as IOErr
+
+import Foreign.C
+import Control.Exception
+import qualified System.Directory as Dir
+
+import Util.Computation
+import Util.ICStringLen
+import Util.DeepSeq
+
+-- amahnke: Supplemented C-Code by System.Directory.CopyFile:
+--
+-- foreign import ccall unsafe "copy_file.h copy_file" copyFilePrim
+--   :: CString -> CString -> IO Int
+
+copyFile :: String -> String -> IO ()
+copyFile source destination =
+   do
+      unitWE <- copyFileWE source destination
+      coerceWithErrorIO unitWE
+
+copyFileWE :: String -> String -> IO (WithError ())
+copyFileWE source destination =
+   if source == destination
+      then
+         return (hasValue ())
+      else
+             IOErr.catch (do
+                            Dir.copyFile source destination
+                            return(hasValue()))
+              (\ioErr ->
+                  let
+                     codeStr = if IOErr.isAlreadyExistsError ioErr
+                                 then  ("Can't write to " ++ destination ++ ". File already exists!")
+                                 else if IOErr.isDoesNotExistError ioErr
+                                        then ("Can't read from " ++ source ++ ". File doesn't exists!")
+                                        else if IOErr.isPermissionError ioErr
+                                               then ("Can't write to " ++ destination ++ ". Insufficient permissions!")
+                                               else if IOErr.isFullError ioErr
+                                                      then ("Can't write to " ++ destination ++ ". Disk full!")
+                                                      else ("Something went wrong within copyFile.")
+                  in
+                    return(hasError codeStr)
+              )
+ {--
+           code <-
+               withCString source (\ sourcePrim ->
+                  withCString destination (\ destinationPrim ->
+                     copyFilePrim sourcePrim destinationPrim
+                     )
+                  )
+            if (code<0)
+               then
+                  let
+                     codeStr = case code of
+                        -- see includes/copy_file.h
+                        -1 -> "Can't read from "++source
+                        -2 -> "Can't write to "++destination
+                        -3 -> "Not enough memory to allocate buffer"
+                        _ -> "Unknown error!!"
+                  in
+                     return(hasError codeStr)
+               else
+                  return(hasValue ())
+--}
+
+-- | Reads in a file to a String.  NB - differs from readFile in that this
+-- is done instantly, so we don\'t have to worry about semi-closed handles
+-- hanging around.
+copyFileToString :: FilePath -> IO String
+copyFileToString filePath =
+   do
+      s <- IO.readFile filePath
+
+--      (cString,len) <- copyFileToCStringLen filePath
+--      string <- peekCStringLen (cString,len)
+--      free cString
+      s `deepSeq` (return s)
+
+-- | Read in a file, catching certain errors
+copyFileToStringCheck :: FilePath -> IO (WithError String)
+copyFileToStringCheck filePath =
+   exceptionToError
+      (\ exception ->
+         case ioErrors exception of
+         Nothing -> Nothing
+         Just ioError ->
+            if IO.isDoesNotExistError ioError
+            then
+               Just "File does not exist"
+            else if IO.isAlreadyInUseError ioError
+            then
+               Just "File is already in use"
+            else if IO.isPermissionError ioError
+            then
+               Just "No read access to file"
+            else
+               Nothing
+         )
+      (copyFileToString filePath)
+
+copyFileToCStringLen :: FilePath -> IO CStringLen
+copyFileToCStringLen file =
+   do
+      str <- readFile file
+      newCStringLen $!! str
+
+copyFileToICStringLenCheck :: FilePath -> IO (WithError ICStringLen)
+copyFileToICStringLenCheck filePath =
+   exceptionToError
+      (\ exception ->
+         case ioErrors exception of
+            Nothing -> Nothing
+            Just ioError -> Just (show ioError)
+         )
+      (copyFileToICStringLen filePath)
+
+copyFileToICStringLen :: FilePath -> IO ICStringLen
+copyFileToICStringLen filePath =
+   do
+      -- shamelessly pirated from GHC's slurpFile function.
+      handle <- IO.openFile filePath IO.ReadMode
+      len <- IO.hFileSize handle
+      if len > fromIntegral (maxBound::Int)
+         then
+            error "CopyFile.copyFileToICStringLen: file too big"
+         else
+            do
+               let
+                  len_i = fromIntegral len
+               mkICStringLen len_i
+                  (\ cString ->
+                     do
+                        lenRead <- hGetBuf handle cString len_i
+                        when (lenRead < len_i)
+                           (error"EOF within CopyFile.copyFileToICStringLen")
+                     )
+
+copyICStringLenToFile :: ICStringLen -> FilePath -> IO ()
+copyICStringLenToFile icsl filePath =
+   withICStringLen icsl (\ i cstr ->
+      copyCStringLenToFile (cstr,i) filePath
+      )
+
+-- | Write to a file, catching certain errors.
+-- (At the moment this is not very helpful, returning messages like
+-- \"system error\").
+copyStringToFileCheck :: String -> FilePath -> IO (WithError ())
+copyStringToFileCheck str filePath =
+   exceptionToError
+      (\ exception ->
+         case ioErrors exception of
+            Nothing -> Nothing
+            Just ioError -> Just (show ioError)
+         )
+      (copyStringToFile str filePath)
+
+copyStringToFile :: String -> FilePath -> IO ()
+copyStringToFile str filePath =
+   withCStringLen str
+      (\ cStringLen -> copyCStringLenToFile cStringLen filePath)
+
+copyCStringLenToFile :: CStringLen -> FilePath -> IO ()
+copyCStringLenToFile (ptr,len) filePath =
+   do
+      handle <- IO.openFile filePath IO.WriteMode
+      hPutBuf handle ptr len
+      IO.hFlush handle
diff --git a/Posixutil/ProcessClasses.hs b/Posixutil/ProcessClasses.hs
new file mode 100644
--- /dev/null
+++ b/Posixutil/ProcessClasses.hs
@@ -0,0 +1,46 @@
+-- | ProcessClasses describes some classes which tools encapsulating
+-- processes may instance.
+module Posixutil.ProcessClasses(
+   ToolStatus, -- encodes status of process
+   Tool(..), -- can get tool status
+   SingleInstanceTool(..), -- this tool has at most one instance
+   CommandTool(..), -- can send commands.
+   ) where
+
+import System.Exit
+
+-- --------------------------------------------------------------------------
+--  Can get status
+-- --------------------------------------------------------------------------
+
+type ToolStatus = Maybe ExitCode
+
+class Tool t where
+    getToolStatus   :: t -> IO ToolStatus
+
+-- --------------------------------------------------------------------------
+-- Tool has at most one instance, which this gets.
+-- --------------------------------------------------------------------------
+
+class SingleInstanceTool t where
+    getToolInstance :: IO t
+
+-- --------------------------------------------------------------------------
+-- Command tools, IE tools where you can send a message and (maybe)
+-- get a response.
+-- --------------------------------------------------------------------------
+
+class Tool t => CommandTool t where
+   -- Tools have two sorts of output.  One is what comes out of their
+   -- stdout channel (and if the appropriate mode in ChildProcess is set
+   -- their stderr channel as well).
+   -- execOneWayCmd is used when that's all there is.
+   -- execCmd is used when there's also a string from somewhere else as well.
+   evalCmd         :: String -> t -> IO String
+   execCmd         :: String -> t -> IO ()
+   execOneWayCmd   :: String -> t -> IO ()
+   execCmd cmd t   =
+      do
+         _ <- evalCmd cmd t
+         return ()
+   -- only overrridden by Expect, in which all commands are one-way.
diff --git a/Posixutil/SafeSystem.hs b/Posixutil/SafeSystem.hs
new file mode 100644
--- /dev/null
+++ b/Posixutil/SafeSystem.hs
@@ -0,0 +1,64 @@
+-- | SafeSystem.safeSystem executes a command (supplied as a String) and
+-- returns its exit code.  It differs from System.system in that it does
+-- NOT stop the world while doing this, so that other threads can run.
+-- How it works: we use ChildProcess to run the runCommand C program,
+-- and feed it the command over stdin.  Ugly, but is there a better way?
+module Posixutil.SafeSystem(
+   safeSystemGeneral,
+   safeSystem,
+   ) where
+
+import System.Exit
+
+import Util.WBFiles
+import Util.FileNames
+import Util.Computation
+
+import Posixutil.ChildProcess
+
+safeSystem :: String -> IO ExitCode
+safeSystem command =
+   let
+      -- We ignore blank output lines.
+      outputSink "" = done
+      outputSink str = putStrLn ("SafeSystem output: "++str)
+   in
+      safeSystemGeneral command outputSink
+
+-- | Run \"command\", displaying any output using the supplied
+-- outputSink function.  (This output had better not include
+-- \"EXITCODE [number]\".)
+--
+-- outputSink is fed output line by line, and without the newlines.
+safeSystemGeneral :: String -> (String -> IO ()) -> IO ExitCode
+safeSystemGeneral command outputSink =
+   do
+      -- Get location of runCommand
+      top <- getTOP
+      let
+         fullName = (trimDir top) `combineNames`
+            ("posixutil" `combineNames` "runCommand")
+      childProcess <- newChildProcess fullName [
+         linemode True,
+         standarderrors True
+         ]
+      sendMsg childProcess (command++"\n")
+      let
+         readOutput =
+            do
+               let
+                  -- we ignore blank input lines.
+                  notExit str =
+                     do
+                        outputSink str
+                        readOutput
+               nextLine <- readMsg childProcess
+               case nextLine of
+                  'E':'X':'I':'T':'C':'O':'D':'E':' ':numberStr ->
+                     case readsPrec 0 numberStr of
+                        [(0,"")] -> return ExitSuccess
+                        [(n,"")] -> return (ExitFailure n)
+                        _ -> notExit nextLine
+                  _ -> notExit nextLine
+      readOutput
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/uni-posixutil.cabal b/uni-posixutil.cabal
new file mode 100644
--- /dev/null
+++ b/uni-posixutil.cabal
@@ -0,0 +1,36 @@
+name:           uni-posixutil
+version:        2.2.0.0
+build-type:     Simple
+license:        LGPL
+license-file:   LICENSE
+author:         uniform@informatik.uni-bremen.de
+maintainer:     Christian.Maeder@dfki.de
+homepage:       http://www.informatik.uni-bremen.de/uniform/wb/
+category:       Uniform
+synopsis:       Posix utilities for the uniform workbench
+description:    posix utilities
+cabal-version:  >= 1.4
+tested-with:    GHC==6.8.3, GHC==6.10.4, GHC==6.12.3
+
+library
+  exposed-modules:
+    Posixutil.CopyFile,
+    Posixutil.SafeSystem,
+    Posixutil.ProcessClasses,
+    Posixutil.ChildProcess,
+    Posixutil.BlockSigPIPE
+
+  build-depends:
+        base >=3 && < 4,
+        directory,
+        process,
+        uni-util,
+        uni-events
+
+  if os(windows)
+     cpp-options: -DWINDOWS
+  else
+     build-Depends: unix
+
+  if impl(ghc > 6.10)
+    ghc-options: -fwarn-unused-imports -fno-warn-warnings-deprecations
