packages feed

Unixutils 1.50 → 1.54.3

raw patch · 12 files changed

Files

Setup.hs view
@@ -1,7 +1,7 @@ #!/usr/bin/runhaskell  import Distribution.Simple-import System.Cmd+import System.Process import System.Exit  main = defaultMainWithHooks simpleUserHooks
System/Unix/Chroot.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE CPP #-} -- | This module, except for useEnv, is copied from the build-env package. module System.Unix.Chroot     ( fchroot@@ -7,8 +8,9 @@     -- , forceList'     ) where -import Control.Exception (finally, evaluate)-+import Control.Exception (evaluate)+import Control.Monad.Catch (MonadMask, finally)+import Control.Monad.Trans (MonadIO, liftIO) import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as L import Foreign.C.Error@@ -41,13 +43,17 @@ -- chroot and working directory of all the threads in the process, -- so... -- NOTE: will throw IOError if internal chroot fails-fchroot :: FilePath -> IO a -> IO a+fchroot :: (MonadIO m, MonadMask m) => FilePath -> m a -> m a fchroot path action =-    do origWd <- getWorkingDirectory-       rootFd <- openFd "/" ReadOnly Nothing defaultFileFlags-       chroot path-       changeWorkingDirectory "/"-       action `finally` (breakFree origWd rootFd)+    do origWd <- liftIO $ getWorkingDirectory+#if MIN_VERSION_unix(2,8,0)+       rootFd <- liftIO $ openFd "/" ReadOnly defaultFileFlags+#else+       rootFd <- liftIO $ openFd "/" ReadOnly Nothing defaultFileFlags+#endif+       liftIO $ chroot path+       liftIO $ changeWorkingDirectory "/"+       action `finally` (liftIO $ breakFree origWd rootFd)     where       breakFree origWd rootFd =           do changeWorkingDirectoryFd rootFd@@ -58,15 +64,15 @@ -- |The ssh inside of the chroot needs to be able to talk to the -- running ssh-agent.  Therefore we mount --bind the ssh agent socket -- dir inside the chroot (and umount it when we exit the chroot.-useEnv :: FilePath -> (a -> IO a) -> IO a -> IO a+useEnv :: (MonadIO m, MonadMask m) => FilePath -> (a -> m a) -> m a -> m a useEnv rootPath force action =     do -- In order to minimize confusion, this QIO message is output        -- at default quietness.  If you want to suppress it while seeing        -- the output from your action, you need to say something like        -- quieter (+ 1) (useEnv (quieter (\x->x-1) action))-       sockPath <- getEnv "SSH_AUTH_SOCK"-       home <- getEnv "HOME"-       copySSH home+       sockPath <- liftIO $ getEnv "SSH_AUTH_SOCK"+       home <- liftIO $ getEnv "HOME"+       liftIO $ copySSH home        -- We need to force the output before we exit the changeroot.        -- Otherwise we lose our ability to communicate with the ssh        -- agent and we get errors.@@ -75,18 +81,19 @@       copySSH Nothing = return ()       copySSH (Just home) =           -- Do NOT preserve ownership, files must be owned by root.+          createDirectoryIfMissing True (rootPath ++ "/root") >>           run "/usr/bin/rsync" ["-rlptgDHxS", "--delete", home ++ "/.ssh/", rootPath ++ "/root/.ssh"]+      withSock :: (MonadIO m, MonadMask m) => Maybe FilePath -> m a -> m a       withSock Nothing action = action       withSock (Just sockPath) action =           withMountBind dir (rootPath ++ dir) action           where dir = dropTrailingPathSeparator (dropFileName sockPath)+      withMountBind :: (MonadIO m, MonadMask m) => FilePath -> FilePath -> m a -> m a       withMountBind toMount mountPoint action =-          do createDirectoryIfMissing True mountPoint-             run "/bin/mount" ["--bind", escapePathForMount toMount, escapePathForMount mountPoint]-             result <- action-             run "/bin/umount" [escapePathForMount mountPoint]-             return result-      escapePathForMount = id	-- FIXME - Path arguments should be escaped+          (do liftIO $ createDirectoryIfMissing True mountPoint+              liftIO $ run "/bin/mount" ["--bind", escapePathForMount toMount, escapePathForMount mountPoint]+              action) `finally` (liftIO $ run "/bin/umount" [escapePathForMount mountPoint])+      escapePathForMount = id   -- FIXME - Path arguments should be escaped        run cmd args =           do (code, out, err) <- readProcessWithExitCode cmd args ""
System/Unix/Crypt.hs view
@@ -4,7 +4,7 @@ -- Module      :  System.Unix.Crypt -- Copyright   :  (c) 2010 -- License     :  BSD3--- +-- -- Maintainer  :  jeremy@seereason.com -- Stability   :  provisional -- Portability :  non-portable (requires POSIX)@@ -13,7 +13,7 @@ -- ----------------------------------------------------------------------------- -module System.Unix.Crypt +module System.Unix.Crypt     ( crypt     )     where@@ -23,7 +23,7 @@ foreign import ccall unsafe "unistd.h crypt"   c_crypt :: CString -> CString -> IO CString --- | calls crypt(3) +-- | calls crypt(3) crypt :: String -- ^ key       -> String -- ^ salt       -> IO String -- ^ encrypted password
System/Unix/Directory.hs view
@@ -12,7 +12,7 @@  import Control.Exception import Data.List (isSuffixOf)-import System.Cmd+import System.Process import System.Directory import System.Exit import System.FilePath@@ -28,7 +28,7 @@     do       status <- getSymbolicLinkStatus path       case isDirectory status of-        True -> +        True ->             do               subs <- getDirectoryContents path >>=                       return . map (path </>) . filter (not . flip elem [".", ".."]) >>=@@ -84,7 +84,7 @@ --	when you are inside a chroot. removeRecursiveSafely :: FilePath -> IO () removeRecursiveSafely path =-    traverse path removeFile removeDirectory umount+    System.Unix.Directory.traverse path removeFile removeDirectory umount     where       umount path =           do@@ -102,7 +102,7 @@ -- unmounts anything it finds mounted.  Note that this can be much -- slower than Mount.umountBelow, use that instead. unmountRecursiveSafely path =-    traverse path noOp noOp umount+    System.Unix.Directory.traverse path noOp noOp umount     where       noOp _ = return ()       umount path =@@ -134,7 +134,7 @@  -- |temporarily change the working directory to |dir| while running |action| withWorkingDirectory :: FilePath -> IO a -> IO a-withWorkingDirectory dir action = +withWorkingDirectory dir action =     bracket getCurrentDirectory setCurrentDirectory (\ _ -> setCurrentDirectory dir >> action)  -- |create a temporary directory, run the action, remove the temporary directory@@ -153,7 +153,7 @@   c_mkdtemp :: CString -> IO CString  mkdtemp :: FilePath -> IO FilePath-mkdtemp template = +mkdtemp template =       withCString (if "XXXXXX" `isSuffixOf` template then template else (template ++ "XXXXXX")) $ \ ptr -> do         cname <- throwErrnoIfNull "mkdtemp" (c_mkdtemp ptr)         name <- peekCString cname
System/Unix/FilePath.hsc view
@@ -3,7 +3,7 @@ -- | The function splitFileName is taken from missingh, at the moment -- missingh will not build under sid. -module System.Unix.FilePath +module System.Unix.FilePath     (dirName,      baseName,      realpath,
System/Unix/Files.hs view
@@ -10,7 +10,7 @@ forceSymbolicLink :: FilePath -> FilePath -> IO () forceSymbolicLink target linkName =     createSymbolicLink target linkName `catch`-      (\e -> if isAlreadyExistsError e +      (\e -> if isAlreadyExistsError e              then do removeLink linkName                      createSymbolicLink target linkName              else ioError e)
+ System/Unix/KillByCwd.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE ScopedTypeVariables #-}+-- |A place to collect and hopefully retire all the random ways of+-- running shell commands that have accumulated over the years.+module System.Unix.KillByCwd+    ( killByCwd+    ) where++import Control.Exception (catch)+import Control.Monad (liftM, filterM)+import Data.Char (isDigit)+import Data.List (isPrefixOf)+import Prelude hiding (catch)+import System.Directory (getDirectoryContents)+import System.Posix.Files (readSymbolicLink)+import System.Posix.Signals (signalProcess, sigTERM)++{-+NOTE:+++ We should make sure this works if we are inside a chroot.+++ path needs to be absolute or we might kill processes living in+  similarly named, but different directories.+++ path is an canoncialised, absolute path, such as what realpath returns++-}+-- | Kill the processes whose working directory is in or under the+-- given directory.+killByCwd :: FilePath -> IO [(String, Maybe String)]+killByCwd path =+    do pids <- liftM (filter (all isDigit)) (getDirectoryContents "/proc")+       cwdPids <- filterM (isCwd path) pids+       exePaths <- mapM exePath cwdPids+       mapM_ kill cwdPids+       return (zip cwdPids exePaths)+    where+      isCwd :: FilePath -> String -> IO Bool+      isCwd cwd pid =+          (liftM (isPrefixOf cwd) (readSymbolicLink ("/proc/" ++ pid ++"/cwd"))) `catch` (\ (_ :: IOError) -> return False)+      exePath :: String -> IO (Maybe String)+      exePath pid = (readSymbolicLink ("/proc/" ++ pid ++"/exe") >>= return . Just) `catch` (\ (_ :: IOError) -> return Nothing)+      kill :: String -> IO ()+      kill pidStr = signalProcess sigTERM (read pidStr)
System/Unix/Misc.hs view
@@ -11,13 +11,14 @@ import Data.ByteString.Lazy.Char8 (empty, readFile, writeFile) import Data.Digest.Pure.MD5 (md5) import Data.Maybe-import System.Cmd+import System.Process import System.Directory import System.Exit import System.IO import System.Posix.Files import System.Process +-- | Deprecated: Use @Data.ByteString.Lazy.Char8.readFile path >>= return . show . Data.Digest.Pure.MD5.md5@ {-# DEPRECATED md5sum "Use Data.ByteString.Lazy.Char8.readFile path >>= return . show . Data.Digest.Pure.MD5.md5" #-} md5sum :: FilePath -> IO String md5sum path = Data.ByteString.Lazy.Char8.readFile path >>= return . show . md5@@ -33,6 +34,7 @@         _ -> error ("Error running 'md5sum " ++ path ++ "'") -} +-- | Deprecated: Use @Data.ByteString.Lazy.Char8.readFile path >>= Data.ByteString.Lazy.Char8.writeFile (path ++ \".gz\")@ {-# DEPRECATED gzip "Use Data.ByteString.Lazy.Char8.readFile path >>= Data.ByteString.Lazy.Char8.writeFile (path ++ \".gz\")" #-} gzip :: FilePath -> IO () gzip path = Data.ByteString.Lazy.Char8.readFile path >>= Data.ByteString.Lazy.Char8.writeFile (path ++ ".gz")
System/Unix/Mount.hs view
@@ -1,10 +1,16 @@+{-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables #-} -- |functions for mounting, umounting, parsing \/proc\/mounts, etc-module System.Unix.Mount -    (umountBelow,	-- FilePath -> IO [(FilePath, (String, String, ExitCode))]-     umount,		-- [String] -> IO (String, String, ExitCode)-     isMountPoint)	-- FilePath -> IO Bool-    where+module System.Unix.Mount+    ( umountBelow       -- FilePath -> IO [(FilePath, (String, String, ExitCode))]+    , umount            -- [String] -> IO (String, String, ExitCode)+    , isMountPoint      -- FilePath -> IO Bool +    , withMount+    , WithProcAndSys(runWithProcAndSys)+    , withProcAndSys+    , withTmp+    ) where+ -- Standard GHC modules  import Control.Monad@@ -16,6 +22,21 @@ import System.Posix.Files import System.Process (readProcessWithExitCode) +import Control.Applicative (Applicative)+import Control.Exception (catch)+import Control.Monad.Catch (bracket, MonadCatch, MonadMask)+import Control.Monad.Trans (MonadTrans, lift, liftIO, MonadIO)+-- import Control.Monad.Trans.Except ({- ExceptT instances -})+import Data.ByteString.Lazy as L (ByteString, empty)+import GHC.IO.Exception (IOErrorType(OtherError))+import System.Directory (createDirectoryIfMissing)+import System.Exit (ExitCode(ExitFailure, ExitSuccess))+import System.FilePath ((</>))+import System.IO (hPutStrLn, stderr)+import System.IO.Error+import System.Process (CreateProcess, proc)+import System.Process.ListLike (readCreateProcess, showCreateProcessForUser)+ -- Local Modules  -- In ghc610 readFile "/proc/mounts" hangs.  Use this instead.@@ -78,7 +99,7 @@ unescape ('\\':'1':'3':'4':rest) = '\\' : (unescape rest) unescape (c:rest) = c : (unescape rest) --- |'escape' - \/proc\/mount stytle string escaper+-- |'escape' - \/proc\/mount style string escaper escape :: String -> String escape [] = [] escape (' ':rest)  = ('\\':'0':'4':'0':escape rest)@@ -115,3 +136,57 @@             -- It is hard to know what is going on if . or .. don't exist.             -- Assume we are seeing some sort of mount point.             return True++readProcess :: CreateProcess -> L.ByteString -> IO L.ByteString+readProcess p input = do+  (code, out, _err) <- readCreateProcess p input :: IO (ExitCode, L.ByteString, L.ByteString)+  case code of+    ExitFailure n -> ioError (mkIOError OtherError (showCreateProcessForUser p ++ " -> " ++ show n) Nothing Nothing)+    ExitSuccess -> return out++-- | Do an IO task with a file system remounted using mount --bind.+-- This was written to set up a build environment.+withMount :: (MonadIO m, MonadMask m) => FilePath -> FilePath -> m a -> m a+withMount directory mountpoint task =+    bracket pre (\ _ -> post) (\ _ -> task)+    where+      mount = proc "mount" ["--bind", directory, mountpoint]+      umount = proc "umount" [mountpoint]+      umountLazy = proc "umount" ["-l", mountpoint]++      pre = liftIO $ do -- hPutStrLn stderr $ "mounting /proc at " ++ show mountpoint+                        createDirectoryIfMissing True mountpoint+                        readProcess mount L.empty++      post = liftIO $ do -- hPutStrLn stderr $ "unmounting /proc at " ++ show mountpoint+                         readProcess umount L.empty+                           `catch` (\ (e :: IOError) ->+                                        do hPutStrLn stderr ("Exception unmounting " ++ mountpoint ++ ", trying -l: " ++ show e)+                                           readProcess umountLazy L.empty)++-- | Monad transformer to ensure that /proc and /sys are mounted+-- during a computation.+newtype WithProcAndSys m a = WithProcAndSys { runWithProcAndSys :: m a } deriving (Functor, Monad, Applicative)++instance MonadTrans WithProcAndSys where+    lift = WithProcAndSys++instance MonadIO m => MonadIO (WithProcAndSys m) where+    liftIO task = WithProcAndSys (liftIO task)++-- | Mount /proc and /sys in the specified build root and execute a+-- task.  Typically, the task would start with a chroot into the build+-- root.  If the build root given is "/" it is assumed that the file+-- systems are already mounted, no mounting or unmounting is done.+withProcAndSys :: (MonadIO m, MonadMask m) => FilePath -> WithProcAndSys m a -> m a+withProcAndSys "/" task = runWithProcAndSys task+withProcAndSys root task = do+  exists <- liftIO $ doesDirectoryExist root+  case exists of+    True -> withMount "/proc" (root </> "proc") $ withMount "/sys" (root </> "sys") $ runWithProcAndSys task+    False -> liftIO $ ioError $ mkIOError doesNotExistErrorType "chroot directory does not exist" Nothing (Just root)++-- | Do an IO task with /tmp remounted.  This could be used+-- to share /tmp with a build root.+withTmp :: (MonadIO m, MonadMask m) => FilePath -> m a -> m a+withTmp root task = withMount "/tmp" (root </> "tmp") task
− System/Unix/Process.hs
@@ -1,89 +0,0 @@--- | Variations of the readProcess and readProcessWithExitCode functions--- from System.Process which read and write ByteStrings and have an--- extra argument to modify the CreateProcess value before the process--- is started.-module System.Unix.Process-    ( readProcess-    , readProcessWithExitCode-    ) where--import Control.Concurrent (newEmptyMVar, forkIO, putMVar, takeMVar)-import qualified Control.Exception as C-import Control.Monad (when)-import qualified Data.ByteString.Lazy.Char8 as B-import GHC.IO.Exception (IOErrorType(OtherError))-import System.Exit (ExitCode(..))-import System.IO (hFlush, hClose)-import System.IO.Error (mkIOError)-import System.Process (CreateProcess(std_in, std_out, std_err, cwd), createProcess, waitForProcess, proc, StdStream(CreatePipe, Inherit), showCommandForUser)--readProcessWithExitCode-    :: FilePath                         -- ^ command to run-    -> [String]                         -- ^ any arguments-    -> (CreateProcess -> CreateProcess) -- ^ Modify process with this - use id for System.Process.readProcessWithExitCode behavior-    -> B.ByteString                     -- ^ standard input-    -> IO (ExitCode, B.ByteString, B.ByteString) -- ^ exitcode, stdout, stderr-readProcessWithExitCode cmd args modify input = do-    let modify' p = modify (p {std_in  = CreatePipe, std_out = CreatePipe, std_err = CreatePipe })--    (Just inh, Just outh, Just errh, pid) <--        createProcess (modify' (proc cmd args))--    outMVar <- newEmptyMVar--    -- fork off a thread to start consuming stdout-    out  <- B.hGetContents outh-    _ <- forkIO $ C.evaluate (B.length out) >> putMVar outMVar ()--    -- fork off a thread to start consuming stderr-    err  <- B.hGetContents errh-    _ <- forkIO $ C.evaluate (B.length err) >> putMVar outMVar ()--    -- now write and flush any input-    when (not (B.null input)) $ do B.hPutStr inh input; hFlush inh-    hClose inh -- done with stdin--    -- wait on the output-    takeMVar outMVar-    takeMVar outMVar-    hClose outh-    hClose errh--    -- wait on the process-    ex <- waitForProcess pid--    return (ex, out, err)--readProcess-    :: FilePath		-- ^ command to run-    -> [String]		-- ^ any arguments-    -> (CreateProcess -> CreateProcess) -- ^ modifies CreateProcess before passing to createProcess-    -> B.ByteString	-- ^ standard input-    -> IO B.ByteString	-- ^ stdout-readProcess cmd args modify input = do-    let modify' p = modify (p {std_in  = CreatePipe, std_out = CreatePipe, std_err = Inherit })-    (Just inh, Just outh, _, pid) <--        createProcess (modify' (proc cmd args))--    -- fork off a thread to start consuming the output-    output  <- B.hGetContents outh-    outMVar <- newEmptyMVar-    _ <- forkIO $ C.evaluate (B.length output) >> putMVar outMVar ()--    -- now write and flush any input-    when (not (B.null input)) $ do B.hPutStr inh input; hFlush inh-    hClose inh -- done with stdin--    -- wait on the output-    takeMVar outMVar-    hClose outh--    -- wait on the process-    ex <- waitForProcess pid--    case ex of-      ExitSuccess   -> return output-      ExitFailure r ->-          ioError (mkIOError OtherError ("readProcess: " ++ showCommandForUser cmd args ++-                                                             " (exit " ++ show r ++ ")")-                   Nothing Nothing)
System/Unix/SpecialDevice.hs view
@@ -2,30 +2,30 @@ -- | Construct an ADT representing block and character devices -- (but mostly block devices) by interpreting the contents of -- the Linux sysfs filesystem.-module System.Unix.SpecialDevice +module System.Unix.SpecialDevice     (SpecialDevice,-     sysMountPoint,	-- IO String-     ofNode,		-- FilePath -> IO (Maybe SpecialDevice)-     ofNodeStatus,	-- FileStatus -> Maybe SpecialDevice-     ofPath,		-- FilePath -> IO (Maybe SpecialDevice)-     rootPart,		-- IO (Maybe SpecialDevice)-     ofDevNo,		-- (DeviceID -> SpecialDevice) -> Int -> SpecialDevice-     ofSysName,		-- String -> IO (Maybe SpecialDevice)-     ofSysPath,		-- (DeviceID -> SpecialDevice) -> FilePath -> IO (Maybe SpecialDevice)-     toDevno,		-- SpecialDevice -> Int-     --major,		-- SpecialDevice -> Int-     --minor,		-- SpecialDevice -> Int-     ofMajorMinor,	-- (DeviceID -> SpecialDevice) -> Int -> Int -> SpecialDevice-     node,		-- SpecialDevice -> IO (Maybe FilePath)-     nodes,		-- SpecialDevice -> IO [FilePath]-     sysName,		-- SpecialDevice -> IO (Maybe String)-     splitPart,		-- String -> (String, Int)-     sysDir,		-- SpecialDevice -> IO (Maybe FilePath)-     diskOfPart,	-- SpecialDevice -> IO (Maybe SpecialDevice)-     getAllDisks,	-- IO [SpecialDevice]-     getAllPartitions,	-- IO [SpecialDevice]-     getAllCdroms,	-- IO [SpecialDevice]-     getAllRemovable,	-- IO [SpecialDevice]+     sysMountPoint,     -- IO String+     ofNode,            -- FilePath -> IO (Maybe SpecialDevice)+     ofNodeStatus,      -- FileStatus -> Maybe SpecialDevice+     ofPath,            -- FilePath -> IO (Maybe SpecialDevice)+     rootPart,          -- IO (Maybe SpecialDevice)+     ofDevNo,           -- (DeviceID -> SpecialDevice) -> Int -> SpecialDevice+     ofSysName,         -- String -> IO (Maybe SpecialDevice)+     ofSysPath,         -- (DeviceID -> SpecialDevice) -> FilePath -> IO (Maybe SpecialDevice)+     toDevno,           -- SpecialDevice -> Int+     --major,           -- SpecialDevice -> Int+     --minor,           -- SpecialDevice -> Int+     ofMajorMinor,      -- (DeviceID -> SpecialDevice) -> Int -> Int -> SpecialDevice+     node,              -- SpecialDevice -> IO (Maybe FilePath)+     nodes,             -- SpecialDevice -> IO [FilePath]+     sysName,           -- SpecialDevice -> IO (Maybe String)+     splitPart,         -- String -> (String, Int)+     sysDir,            -- SpecialDevice -> IO (Maybe FilePath)+     diskOfPart,        -- SpecialDevice -> IO (Maybe SpecialDevice)+     getAllDisks,       -- IO [SpecialDevice]+     getAllPartitions,  -- IO [SpecialDevice]+     getAllCdroms,      -- IO [SpecialDevice]+     getAllRemovable,   -- IO [SpecialDevice] --     toDevName, --     getBlkidAlist, --     getBlkidInfo,@@ -78,7 +78,7 @@         (Just . BlockDevice . specialDeviceID $ status) else         if isCharacterDevice status then             (Just . CharacterDevice . specialDeviceID $ status) else-            Nothing    +            Nothing  ofSysName :: String -> IO (Maybe SpecialDevice) ofSysName name =@@ -144,7 +144,7 @@ sysName dev = sysDir dev >>= return . maybe Nothing (Just . basename)  sysDir :: SpecialDevice -> IO (Maybe FilePath)-sysDir dev@(BlockDevice _) = +sysDir dev@(BlockDevice _) =     do       (pairs' :: [(FilePath, FileStatus)]) <- directory_find False (sysMountPoint ++ "/block")       let (paths :: [FilePath]) = map fst . filter isDev $ pairs'@@ -194,10 +194,10 @@       x -> True  getAllCdroms :: IO [SpecialDevice]-getAllCdroms = cdromGroup >>= getDisksInGroup +getAllCdroms = cdromGroup >>= getDisksInGroup  getAllRemovable :: IO [SpecialDevice]-getAllRemovable = floppyGroup >>= getDisksInGroup +getAllRemovable = floppyGroup >>= getDisksInGroup  -- ofNode "/dev/sda1" >>= maybe (return Nothing) sysDir >>= putStrLn . show -- -> Just "/sys/block/sda/sda1/dev"
Unixutils.cabal view
@@ -1,29 +1,41 @@ Name:           Unixutils-Version:        1.50+Version:        1.54.3 License:        BSD3 License-File:	COPYING Author:         Jeremy Shaw, David Fox-Homepage:       http://src.seereason.com/haskell-unixutils+Homepage:       https://github.com/seereason/haskell-unixutils.git Category:	System Synopsis:       A crude interface between Haskell and Unix-like operating systems-Maintainer:     jeremy@n-heptane.com+Maintainer:     David Fox <ddssff@gmail.com> Description:  A collection of useful and mildly useful functions that you might  expect to find in System.* which a heavy bias towards Unix-type operating systems. Build-type:	Simple-Cabal-Version: >= 1.2+Cabal-Version: >= 1.10 -Library -    Build-Depends:  base >= 4 && <5, bytestring, directory, filepath, process, pureMD5, regex-tdfa, unix, zlib-    ghc-options:	-O2+Library+    Default-Language: Haskell2010+    Build-Depends:+      base >= 4.6 && <5,+      bytestring,+      directory,+      exceptions,+      filepath,+      mtl,+      process,+      process-extras >= 0.3,+      pureMD5,+      regex-tdfa,+      unix,+      zlib     Exposed-modules:         System.Unix.Chroot,         System.Unix.Crypt,         System.Unix.Directory,         System.Unix.FilePath,+        System.Unix.KillByCwd,         System.Unix.Misc,         System.Unix.Mount,-        System.Unix.Process,         System.Unix.SpecialDevice,         System.Unix.Files     if !os(darwin)