8eeb0f7b4856d34e7ddf2ac34001adcba3f5b1c2
[ghc-hetmet.git] / ghc / lib / posix / Posix.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1995-1996
3 %
4 \section[Posix]{Haskell 1.3 POSIX bindings}
5
6 \begin{code}
7 module Posix  (
8     module PosixDB,
9     module PosixErr,
10     module PosixFiles,
11     module PosixIO,
12     module PosixProcEnv,
13     module PosixProcPrim,
14     module PosixTTY,
15
16     runProcess,
17     exec,
18
19     ByteCount,
20     Fd, intToFd,
21     ClockTick,
22     EpochTime,
23     FileOffset,
24     GroupID,
25     Limit,
26     LinkCount,
27     ProcessID,
28     ProcessGroupID,
29     UserID,
30     
31     ExitCode
32
33     )  where
34
35 import PrelBase
36 import PrelIOBase
37 import IO
38 import PrelHandle
39
40 import PosixDB
41 import PosixErr
42 import PosixFiles
43 import PosixIO
44 import PosixProcEnv
45 import PosixProcPrim
46 import PosixTTY
47 import PosixUtil
48
49 -- [OLD COMMENT:]
50 -- runProcess is our candidate for the high-level OS-independent primitive 
51 -- If accepted, it will be moved out of Posix into LibSystem.
52 --
53 -- ***NOTE***: make sure you completely force the evaluation of the path
54 -- and arguments to the child before calling runProcess. If you don't do
55 -- this *and* the arguments from runProcess are read in from a file lazily,
56 -- be prepared for some rather weird parent-child file I/O behaviour.
57 --
58 -- [If you don't force the args, consider the case where the
59 --  arguments emanate from a file that is read lazily, using hGetContents
60 --  or some such. Since a child of a fork() inherits the opened files of
61 --  the parent, the child can force the evaluation of the arguments and
62 --  read them off the file without any problems.  The problem is that
63 --  while the child share a file table with the parent, it has
64 --  separate buffers, so a child may fill up its (copy of) the buffer, but
65 --  only read it partially. When the *parent* tries to read from the shared file again,
66 --  the (shared) file offset will have been stepped on by whatever number of chars
67 --  that was copied into the file buffer of the child. i.e., the unused parts of the
68 --  buffer will *not* be seen, resulting in random/unpredicatable results.
69 --
70 --  Based on a true (, debugged :-) story.
71 -- ]
72
73 import Directory        ( setCurrentDirectory )
74
75
76 runProcess :: FilePath                      -- Command
77            -> [String]                      -- Arguments
78            -> Maybe [(String, String)]      -- Environment
79            -> Maybe FilePath                -- Working directory    
80            -> Maybe Handle                  -- stdin
81            -> Maybe Handle                  -- stdout
82            -> Maybe Handle                  -- stderr
83            -> IO ()
84 runProcess path args env dir stdin stdout stderr = do
85     pid <- forkProcess
86     case pid of
87       Nothing -> doTheBusiness
88       Just x  -> return ()
89   where
90     doTheBusiness :: IO ()
91     doTheBusiness = do
92         maybeChangeWorkingDirectory
93         maybeDup2 0 stdin
94         maybeDup2 1 stdout
95         maybeDup2 2 stderr
96         executeFile path True args env
97         syserr "runProcess"
98
99     maybeChangeWorkingDirectory :: IO ()
100     maybeChangeWorkingDirectory =
101         case dir of
102           Nothing -> return ()
103           Just x  -> setCurrentDirectory x
104
105     maybeDup2 :: Int -> Maybe Handle -> IO ()
106     maybeDup2 dest h =
107         case h of Nothing -> return ()
108                   Just x  -> do
109                     src <- handleToFd x
110                     dupTo src (intToFd dest)
111                     return ()
112
113 \end{code}