Fork/exec in Haskell

Here’s some simple code I put together. I’m mostly posting it so I won’t have any problems finding it in the future.

module Main where
 
import Control.Monad
import System.Exit
import System.Posix.IO
import System.Posix.Process
 
executeChild = do
    mapM_ closeFd [stdInput, stdOutput, stdError]
    devnull <- openFd "/dev/null" ReadWrite Nothing defaultFileFlags
    dup devnull; dup devnull
    executeFile "./Child" False [] Nothing
 
main = do
    child <- forkProcess executeChild
    putStrLn "ForkExec: main - forked, going to wait"
    s <- getProcessStatus True True child
    case s of
        Nothing -> -- this shouldn't happen, ever
            print s >>  exitFailure
        Just s -> do
            print s
            case s of
                Exited _ -> putStrLn "Child exited properly, though possibly unsuccessfully"
                Terminated _ -> putStrLn "Terminated!"
                Stopped _ -> putStrLn "Stopped (only SIGSTOP?)"
            exitSuccess
    exitFailure

It’d be really nice to be able to, after the fork, close all open file descriptors in the child. But how can I find all the open file descriptors in a process? Ideally it should be fairly portable, though portability to major Unix/Linux systems is enough for me.

Share

8 Comments

  1. The classic Unix way to do this is to find out the maximum valid file descriptor and then close all of them in a for loop (e.g., see bash). Looking over System.Posix.IO, it seems that it is lacking a function of the sort

    unsafeMakeFd :: Int -> Fd

    to replicate that strategy.

  2. a. Just try to close all FDs up to getdtablesize() or sysconf(_SC_OPEN_MAX). Slow but mostly portable.

    b. Look at /proc/self/fd/. Faster but not as portable.

  3. @Twan, For this example there isn’t much reason, but in many cases it is nice to separate fork and exec.

    @ephemient, Yes, it was getdtablesize() I was looking for, but couldn’t find.

    @Blame, Huh?

  4. I’d better use /dev/fd/* instead of /proc/self/*, it’s much more portable.

  5. @bbb, It seems rather silly to iterate over all valid file descriptors, it’d be much nicer to only iterate over all open file descriptors. I’ll have to take a look at the bash code though, for educational purposes.

    @ifp5, Yes, that sounds like a good way to go.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>