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.
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 sortunsafeMakeFd :: Int -> Fdto replicate that strategy.
Why are you using fork/exec as opposed to System.Process?
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.
finally
@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?
I’d better use /dev/fd/* instead of /proc/self/*, it’s much more portable.
@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.
Set ‘close on exec’ on the descriptors. http://en.wikipedia.org/wiki/Fork-exec