    module Mueval.Resources (limitResources) where

    import Control.Monad (when)
    import System.Posix.Process (nice)
    import System.Posix.Resource -- (Resource(..), ResourceLimits, setResourceLimit)

    {- | Pull together several methods of reducing priority and easy access to resources:
      'nice', and the rlimit bindings,
      If called with False, 'limitResources' will not use POSIX rlimits.
    -}
    limitResources :: Bool -> IO ()
    limitResources :: Bool -> IO ()
    limitResources Bool
    rlimit = do
        Int -> IO ()
    nice Int
    20 -- Set our process priority way down
        Bool -> IO () -> IO ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when Bool
    rlimit (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ ((Resource, ResourceLimits) -> IO ())
    -> [(Resource, ResourceLimits)] -> IO ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ ((Resource -> ResourceLimits -> IO ())
    -> (Resource, ResourceLimits) -> IO ()
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry Resource -> ResourceLimits -> IO ()
    setResourceLimit) [(Resource, ResourceLimits)]
    limits

    {- | Set all the available rlimits.
       These values have been determined through trial-and-error
    -}
    stackSizeLimitSoft
        , stackSizeLimitHard
        , totalMemoryLimitSoft
        , totalMemoryLimitHard
        , dataSizeLimitSoft
        , openFilesLimitSoft
        , openFilesLimitHard
        , fileSizeLimitSoft
        , fileSizeLimitHard
        , dataSizeLimitHard
        , cpuTimeLimitSoft
        , cpuTimeLimitHard
        , coreSizeLimitSoft
        , coreSizeLimitHard
        , zero ::
            ResourceLimit
    totalMemoryLimitSoft :: ResourceLimit
    totalMemoryLimitSoft = ResourceLimit
    dataSizeLimitSoft
    totalMemoryLimitHard :: ResourceLimit
    totalMemoryLimitHard = ResourceLimit
    dataSizeLimitHard
    -- These limits seem to be useless?
    stackSizeLimitSoft :: ResourceLimit
    stackSizeLimitSoft = ResourceLimit
    zero
    stackSizeLimitHard :: ResourceLimit
    stackSizeLimitHard = ResourceLimit
    zero
    -- We allow a few files to be opened, such as package.conf, because they are necessary. This
    -- doesn't seem to be security problem because it'll be opened at the module
    -- stage, before code ever evaluates. I hope.
    openFilesLimitSoft :: ResourceLimit
    openFilesLimitSoft = ResourceLimit
    openFilesLimitHard
    openFilesLimitHard :: ResourceLimit
    openFilesLimitHard = Integer -> ResourceLimit
    ResourceLimit Integer
    7
    -- TODO: It would be nice to set these to zero, but right now Hint gets around the
    -- insecurity of the GHC API by writing stuff out to a file in /tmp, so we need
    -- to allow our compiled binary to do file I/O... :( But at least we can still limit
    -- how much we write out!
    fileSizeLimitSoft :: ResourceLimit
    fileSizeLimitSoft = ResourceLimit
    fileSizeLimitHard
    fileSizeLimitHard :: ResourceLimit
    fileSizeLimitHard = Integer -> ResourceLimit
    ResourceLimit Integer
    10800
    dataSizeLimitSoft :: ResourceLimit
    dataSizeLimitSoft = ResourceLimit
    dataSizeLimitHard
    dataSizeLimitHard :: ResourceLimit
    dataSizeLimitHard = Integer -> ResourceLimit
    ResourceLimit (Integer -> ResourceLimit) -> Integer -> ResourceLimit
    forall a b. (a -> b) -> a -> b
    $ Integer
    6 Integer -> Int -> Integer
    forall a b. (Num a, Integral b) => a -> b -> a
    ^ (Int
    12 :: Int)
    -- These should not be identical, to give the XCPU handler time to trigger
    cpuTimeLimitSoft :: ResourceLimit
    cpuTimeLimitSoft = Integer -> ResourceLimit
    ResourceLimit Integer
    4
    cpuTimeLimitHard :: ResourceLimit
    cpuTimeLimitHard = Integer -> ResourceLimit
    ResourceLimit Integer
    5
    coreSizeLimitSoft :: ResourceLimit
    coreSizeLimitSoft = ResourceLimit
    coreSizeLimitHard
    coreSizeLimitHard :: ResourceLimit
    coreSizeLimitHard = ResourceLimit
    zero
    -- convenience
    zero :: ResourceLimit
    zero = Integer -> ResourceLimit
    ResourceLimit Integer
    0

    limits :: [(Resource, ResourceLimits)]
    limits :: [(Resource, ResourceLimits)]
    limits =
        [ (Resource
    ResourceStackSize, ResourceLimit -> ResourceLimit -> ResourceLimits
    ResourceLimits ResourceLimit
    stackSizeLimitSoft ResourceLimit
    stackSizeLimitHard)
        , (Resource
    ResourceTotalMemory, ResourceLimit -> ResourceLimit -> ResourceLimits
    ResourceLimits ResourceLimit
    totalMemoryLimitSoft ResourceLimit
    totalMemoryLimitHard)
        , (Resource
    ResourceOpenFiles, ResourceLimit -> ResourceLimit -> ResourceLimits
    ResourceLimits ResourceLimit
    openFilesLimitSoft ResourceLimit
    openFilesLimitHard)
        , (Resource
    ResourceFileSize, ResourceLimit -> ResourceLimit -> ResourceLimits
    ResourceLimits ResourceLimit
    fileSizeLimitSoft ResourceLimit
    fileSizeLimitHard)
        , (Resource
    ResourceDataSize, ResourceLimit -> ResourceLimit -> ResourceLimits
    ResourceLimits ResourceLimit
    dataSizeLimitSoft ResourceLimit
    dataSizeLimitHard)
        , (Resource
    ResourceCoreFileSize, ResourceLimit -> ResourceLimit -> ResourceLimits
    ResourceLimits ResourceLimit
    coreSizeLimitSoft ResourceLimit
    coreSizeLimitHard)
        , (Resource
    ResourceCPUTime, ResourceLimit -> ResourceLimit -> ResourceLimits
    ResourceLimits ResourceLimit
    cpuTimeLimitSoft ResourceLimit
    cpuTimeLimitHard)
        ]