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