<Chapter id="sec-posix"><Title>The <literal>posix</literal> package: POSIX support</Title>

<Para>
<IndexTerm><Primary>Posix library</Primary></IndexTerm>
<IndexTerm><Primary>libraries, Posix</Primary></IndexTerm>
</Para>

<Para>
The <Literal>Posix</Literal> interface gives you access to the set of OS
services standardised by POSIX 1003.1b (or the <Emphasis>IEEE Portable
Operating System Interface for Computing Environments</Emphasis> - IEEE Std.
1003.1). The interface is accessed by <Literal>import Posix</Literal> and
adding <Option>-package posix</Option> on your command-line.
</Para>

<para>
The Posix package is <emphasis>not</emphasis> supported under
Windows. We've looked into various ways of providing support, and
other than using Cygwin, none is particularly attractive. If you want
Posix support under Windows, try building GHC for Cygwin; we don't
currently do this, but it is mostly supported.
</para>
  
<Sect1 id="Posix-data-types">
<Title>Posix data types
</Title>

<Para>
<IndexTerm><Primary>Posix, data types</Primary></IndexTerm>
</Para>

<Para>

<ProgramListing>
data ByteCount  -- instances of : Eq Ord Num Real Integral Ix Enum Show
</ProgramListing>

</Para>

<Para>
A <Literal>ByteCount</Literal> is a primitive of type <Literal>unsigned</Literal>. At a minimum,
an conforming implementation must support values in the range
<Literal>[0, UINT&lowbar;MAX]</Literal>.
</Para>

<Para>

<ProgramListing>
data ClockTick  -- instances of : Eq Ord Num Real Integral Ix Enum Show
</ProgramListing>

</Para>

<Para>
A <Literal>ClockTick</Literal> is a primitive of type <Literal>clock&lowbar;t</Literal>, which
is used to measure intervals of time in fractions of a second.  The 
resolution is determined by <Literal>getSysVar ClockTick</Literal>.
</Para>

<Para>

<ProgramListing>
data DeviceID  -- instances of : Eq Ord Num Real Integral Ix Enum Show
</ProgramListing>

</Para>

<Para>
A <Literal>DeviceID</Literal> is a primitive of type <Literal>dev&lowbar;t</Literal>.  It must
be an arithmetic type.
</Para>

<Para>

<ProgramListing>
data EpochTime -- instances of : Eq Ord Num Real Integral Ix Enum Show
</ProgramListing>

</Para>

<Para>
A <Literal>EpochTime</Literal> is a primitive of type <Literal>time&lowbar;t</Literal>, which is
used to measure seconds since the Epoch.  At a minimum, the implementation 
must support values in the range <Literal>[0, INT&lowbar;MAX]</Literal>.
</Para>

<Para>

<ProgramListing>
data FileID -- instances of : Eq Ord Num Real Integral Ix Enum Show
</ProgramListing>

</Para>

<Para>
A <Literal>FileID</Literal> is a primitive of type <Literal>ino&lowbar;t</Literal>.  It must
be an arithmetic type.
</Para>

<Para>

<ProgramListing>
data FileMode -- instance of : Eq
</ProgramListing>

</Para>

<Para>
A <Literal>FileMode</Literal> is a primitive of type <Literal>mode&lowbar;t</Literal>.
It must be an arithmetic type.
</Para>

<Para>

<ProgramListing>
data FileOffset -- instances of : Eq Ord Num Real Integral Ix Enum Show
</ProgramListing>

</Para>

<Para>
A <Literal>FileOffset</Literal> is a primitive of type <Literal>off&lowbar;t</Literal>.  It must
be an arithmetic type.
</Para>

<Para>

<ProgramListing>
data GroupID -- instances of : Eq Ord Num Real Integral Ix Enum Show
</ProgramListing>

</Para>

<Para>
A <Literal>GroupID</Literal> is a primitive of type <Literal>gid&lowbar;t</Literal>.  It must
be an arithmetic type.

<ProgramListing>
data Limit -- instances of : Eq Ord Num Real Integral Ix Enum Show
</ProgramListing>

</Para>

<Para>
A <Literal>Limit</Literal> is a primitive of type <Literal>long</Literal>.
At a minimum, the implementation must support values in the range 
<Literal>[LONG&lowbar;MIN, LONG&lowbar;MAX]</Literal>.
</Para>

<Para>

<ProgramListing>
data LinkCount -- instances of : Eq Ord Num Real Integral Ix Enum Show
</ProgramListing>

</Para>

<Para>
A <Literal>LinkCount</Literal> is a primitive of type <Literal>nlink&lowbar;t</Literal>.  It must
be an arithmetic type.
</Para>

<Para>

<ProgramListing>
data ProcessID -- instances of : Eq Ord Num Real Integral Ix Enum Show
type ProcessGroupID = ProcessID
</ProgramListing>

</Para>

<Para>
A <Literal>ProcessID</Literal> is a primitive of type <Literal>pid&lowbar;t</Literal>.  It
must be a signed arithmetic type.

<ProgramListing>
data UserID -- instances of : Eq Ord Num Real Integral Ix Enum Show
</ProgramListing>

</Para>

<Para>
A <Literal>UserID</Literal> is a primitive of type <Literal>uid&lowbar;t</Literal>.  It
must be an arithmetic type.
</Para>

<Para>

<ProgramListing>
data DirStream
</ProgramListing>

A <Literal>DirStream</Literal> is a primitive of type <Literal>DIR *</Literal>.
</Para>

<Para>

<ProgramListing>
data FileStatus
</ProgramListing>

A <Literal>FileStatus</Literal> is a primitive of type <Literal>struct stat</Literal>.
</Para>

<Para>

<ProgramListing>
data GroupEntry
</ProgramListing>

</Para>

<Para>
A <Literal>GroupEntry</Literal> is a primitive of type <Literal>struct group</Literal>.

<ProgramListing>
data ProcessTimes
</ProgramListing>

</Para>

<Para>
<Literal>ProcessTimes</Literal> is a primitive structure containing a
<Literal>clock&lowbar;t</Literal> and a <Literal>struct tms</Literal>.
</Para>

<Para>

<ProgramListing>
data SignalSet
</ProgramListing>

</Para>

<Para>
An <Literal>SignalSet</Literal> is a primitive of type <Literal>sigset&lowbar;t</Literal>.
</Para>

<Para>

<ProgramListing>
data SystemID
</ProgramListing>

</Para>

<Para>
A <Literal>SystemID</Literal> is a primitive of type <Literal>struct utsname</Literal>.
</Para>

<Para>

<ProgramListing>
data TerminalAttributes
</ProgramListing>

<Literal>TerminalAttributes</Literal> is a primitive of type <Literal>struct termios</Literal>.
</Para>

<Para>

<ProgramListing>
data UserEntry
</ProgramListing>

</Para>

<Para>
A <Literal>UserEntry</Literal> is a primitive of type <Literal>struct passwd</Literal>.
</Para>

<Para>

<ProgramListing>
data BaudRate = B0 | B50 | B75 | B110 | B134 | B150 | B200 | B300 | B600
              | B1200 | B1800 | B2400 | B4800 | B9600 | B19200 | B38400
              deriving (Eq, Show)

data Fd 

instance Eq Fd 
instance Show Fd

intToFd :: Int -&#62; Fd -- use with care.
fdToInt :: Fd -> Int     -- ditto.

data FdOption = AppendOnWrite
              | CloseOnExec
              | NonBlockingRead

data ControlCharacter = EndOfFile
                      | EndOfLine
                      | Erase
                      | Interrupt
                      | Kill
                      | Quit
                      | Suspend
                      | Start
                      | Stop

type ErrorCode = Int

type FileLock = (LockRequest, SeekMode, FileOffset, FileOffset)
--                            whence    start       length

data FlowAction = SuspendOutput | RestartOutput | TransmitStop | TransmitStart

data Handler = Default | Ignore | Catch (IO ())

data LockRequest = ReadLock | WriteLock | Unlock
                 deriving (Eq, Show)

data OpenMode = ReadOnly | WriteOnly | ReadWrite

data PathVar = LinkLimit
             | InputLineLimit
             | InputQueueLimit
             | FileNameLimit
             | PathNameLimit
             | PipeBufferLimit
             | SetOwnerAndGroupIsRestricted
             | FileNamesAreNotTruncated

data QueueSelector = InputQueue | OutputQueue | BothQueues

type Signal = Int

data SysVar = ArgumentLimit
            | ChildLimit
            | ClockTick
            | GroupLimit
            | OpenFileLimit
            | PosixVersion
            | HasSavedIDs
            | HasJobControl

data TerminalMode = InterruptOnBreak       -- BRKINT
                | MapCRtoLF                -- ICRNL
                | IgnoreBreak              -- IGNBRK
                | IgnoreCR                 -- IGNCR
                | IgnoreParityErrors       -- IGNPAR
                | MapLFtoCR                -- INLCR
                | CheckParity              -- INPCK
                | StripHighBit             -- ISTRIP
                | StartStopInput           -- IXOFF
                | StartStopOutput          -- IXON
                | MarkParityErrors         -- PARMRK
                | ProcessOutput            -- OPOST
                | LocalMode                -- CLOCAL
                | ReadEnable               -- CREAD
                | TwoStopBits              -- CSTOPB
                | HangupOnClose            -- HUPCL
                | EnableParity             -- PARENB
                | OddParity                -- PARODD
                | EnableEcho               -- ECHO
                | EchoErase                -- ECHOE
                | EchoKill                 -- ECHOK
                | EchoLF                   -- ECHONL
                | ProcessInput             -- ICANON
                | ExtendedFunctions        -- IEXTEN
                | KeyboardInterrupts       -- ISIG
                | NoFlushOnInterrupt       -- NOFLSH
                | BackgroundWriteInterrupt -- TOSTOP

data TerminalState = Immediately | WhenDrained | WhenFlushed

data ProcessStatus = Exited ExitCode 
                   | Terminated Signal 
                   | Stopped Signal
                   deriving (Eq, Show)
</ProgramListing>

</Para>

</Sect1>

<Sect1 id="Process-Primitives">
<Title>Posix Process Primitives
</Title>

<Para>

<ProgramListing>
forkProcess :: IO (Maybe ProcessID)
</ProgramListing>

</Para>

<Para>
<Function>forkProcess</Function> calls <Function>fork</Function>, returning
<Literal>Just pid</Literal> to the parent, where <VarName>pid</VarName> is the
ProcessID of the child, and returning <Literal>Nothing</Literal> to the
child.
</Para>

<Para>

<ProgramListing>
executeFile :: FilePath                   -- Command
            -&#62; Bool                       -- Search PATH?
            -&#62; [String]                   -- Arguments
            -&#62; Maybe [(String, String)]   -- Environment
            -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>executeFile cmd args env</Literal> calls one of the
<Function>execv*</Function> family, depending on whether or not the current
PATH is to be searched for the command, and whether or not an
environment is provided to supersede the process's current
environment.  The basename (leading directory names suppressed) of
the command is passed to <Function>execv*</Function> as <VarName>arg[0]</VarName>;
the argument list passed to <Function>executeFile</Function> therefore begins with <VarName>arg[1]</VarName>.
</Para>

<Para>

<Screen>
Search PATH?    Supersede environ?      Call
~~~~~~~~~~~~    ~~~~~~~~~~~~~~~~~~      ~~~~~~~
False           False                   execv
False           True                    execve
True            False                   execvp
True            True                    execvpe*
</Screen>

</Para>

<Para>
Note that <Function>execvpe</Function> is not provided by the POSIX standard, and must
be written by hand.  Care must be taken to ensure that the search path
is extracted from the original environment, and not from the
environment to be passed on to the new image.
</Para>

<Para>
NOTE: In general, sharing open files between parent and child
processes is potential bug farm, and should be avoided unless you
really depend on this `feature' of POSIX' <Function>fork()</Function> semantics. Using
Haskell, there's the extra complication that arguments to
<Function>executeFile</Function> might come from files that are read lazily (using
<Function>hGetContents</Function>, or some such.) If this is the case, then for your own
sanity, please ensure that the arguments to <Function>executeFile</Function> have been
fully evaluated before calling <Function>forkProcess</Function> (followed by
<Function>executeFile</Function>.) Consider yourself warned :-)
</Para>

<Para>
A successful <Function>executeFile</Function> overlays the current process image with 
a new one, so it only returns on failure.
</Para>

<Para>

<ProgramListing>
runProcess :: FilePath                    -- Command
           -&#62; [String]                    -- Arguments
           -&#62; Maybe [(String, String)]    -- Environment (Nothing -&#62; Inherited)
           -&#62; Maybe FilePath              -- Working directory (Nothing -&#62; inherited)
           -&#62; Maybe Handle                -- stdin  (Nothing -&#62; inherited)
           -&#62; Maybe Handle                -- stdout (Nothing -&#62; inherited)
           -&#62; Maybe Handle                -- stderr (Nothing -&#62; inherited)
           -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Function>runProcess</Function> is our candidate for the high-level OS-independent
primitive.
</Para>

<Para>
<Literal>runProcess cmd args env wd inhdl outhdl errhdl</Literal> runs <Command>cmd</Command>
(searching the current <Literal>PATH</Literal>) with arguments <Literal>args</Literal>.  If
<Literal>env</Literal> is <Literal>Just pairs</Literal>, the command is executed with the
environment specified by <Literal>pairs</Literal> of variables and values;
otherwise, the command is executed with the current environment.  If
<Literal>wd</Literal> is <Literal>Just dir</Literal>, the command is executed with working
directory <Literal>dir</Literal>; otherwise, the command is executed in the current
working directory.  If <Literal>&lcub;in,out,err</Literal>hdl&rcub; is <Literal>Just handle</Literal>, the
command is executed with the <Literal>Fd</Literal> for <Literal>std&lcub;in,out,err</Literal>&rcub;
attached to the specified <Literal>handle</Literal>; otherwise, the <Literal>Fd</Literal> for
<Literal>std&lcub;in,out,err</Literal>&rcub; is left unchanged.
</Para>

<Para>

<ProgramListing>
getProcessStatus :: Bool              -- Block?
                 -&#62; Bool              -- Stopped processes?
                 -&#62; ProcessID 
                 -&#62; IO (Maybe ProcessStatus)
</ProgramListing>

</Para>

<Para>
<Literal>getProcessStatus blk stopped pid</Literal> calls <Function>waitpid</Function>, returning
<Literal>Just tc</Literal>, the <Literal>ProcessStatus</Literal> for process <Literal>pid</Literal> if it is
available, <Literal>Nothing</Literal> otherwise.  If <Literal>blk</Literal> is <Literal>False</Literal>, then
<Literal>WNOHANG</Literal> is set in the options for <Function>waitpid</Function>, otherwise not.
If <Literal>stopped</Literal> is <Literal>True</Literal>, then <Literal>WUNTRACED</Literal> is set in the
options for <Function>waitpid</Function>, otherwise not.
</Para>

<Para>

<ProgramListing>
getGroupProcessStatus :: Bool         -- Block?
                      -&#62; Bool         -- Stopped processes?
                      -&#62; ProcessGroupID 
                      -&#62; IO (Maybe (ProcessID, ProcessStatus))
</ProgramListing>

</Para>

<Para>
<Literal>getGroupProcessStatus blk stopped pgid</Literal> calls <Function>waitpid</Function>,
returning <Literal>Just (pid, tc)</Literal>, the <Literal>ProcessID</Literal> and
<Literal>ProcessStatus</Literal> for any process in group <Literal>pgid</Literal> if one is
available, <Literal>Nothing</Literal> otherwise.  If <Literal>blk</Literal> is <Literal>False</Literal>, then
<Literal>WNOHANG</Literal> is set in the options for <Function>waitpid</Function>, otherwise not.
If <Literal>stopped</Literal> is <Literal>True</Literal>, then <Literal>WUNTRACED</Literal> is set in the
options for <Function>waitpid</Function>, otherwise not.
</Para>

<Para>

<ProgramListing>
getAnyProcessStatus :: Bool           -- Block?
                    -&#62; Bool           -- Stopped processes?
                    -&#62; IO (Maybe (ProcessID, ProcessStatus))
</ProgramListing>

</Para>

<Para>
<Literal>getAnyProcessStatus blk stopped</Literal> calls <Function>waitpid</Function>, returning
<Literal>Just (pid, tc)</Literal>, the <Literal>ProcessID</Literal> and <Literal>ProcessStatus</Literal> for any
child process if one is available, <Literal>Nothing</Literal> otherwise.  If
<Literal>blk</Literal> is <Literal>False</Literal>, then <Literal>WNOHANG</Literal> is set in the options for
<Function>waitpid</Function>, otherwise not.  If <Literal>stopped</Literal> is <Literal>True</Literal>, then
<Literal>WUNTRACED</Literal> is set in the options for <Function>waitpid</Function>, otherwise not.
</Para>

<Para>

<ProgramListing>
exitImmediately :: ExitCode -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>exitImmediately status</Literal> calls <Function>&lowbar;exit</Function> to terminate the process
with the indicated exit <Literal>status</Literal>.
The operation never returns.
</Para>

<Para>

<ProgramListing>
getEnvironment :: IO [(String, String)]
</ProgramListing>

</Para>

<Para>
<Function>getEnvironment</Function> parses the environment variable mapping provided by
<Literal>environ</Literal>, returning <Literal>(variable, value)</Literal> pairs. 
The operation never fails.
</Para>

<Para>

<ProgramListing>
setEnvironment :: [(String, String)] -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Function>setEnvironment</Function> replaces the process environment with the provided
mapping of <Literal>(variable, value)</Literal> pairs. 
</Para>

<Para>

<ProgramListing>
getEnvVar :: String -&#62; IO String
</ProgramListing>

</Para>

<Para>
<Literal>getEnvVar var</Literal> returns the value associated with variable <VarName>var</VarName> 
in the current environment (identical functionality provided through
standard Haskell library function <Function>System.getEnv</Function>).
</Para>

<Para>
The operation may fail with:
</Para>

<Para>
<VariableList>

<VarListEntry>
<Term><Literal>NoSuchThing</Literal></Term>
<ListItem>
<Para>
The variable has no mapping in the current environment.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>

<Para>

<ProgramListing>
setEnvVar :: String -&#62; String -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>setEnvVar var val</Literal> sets the value associated with variable <VarName>var</VarName> 
in the current environment to be <Literal>val</Literal>.  Any previous mapping is 
superseded.
</Para>

<Para>

<ProgramListing>
removeEnvVar :: String -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>removeEnvVar var</Literal> removes any value associated with variable <VarName>var</VarName> 
in the current environment.  Deleting a variable for which there is no mapping
does not generate an error.
</Para>

<Para>

<ProgramListing>
nullSignal :: Signal
nullSignal = 0

backgroundRead, sigTTIN        :: Signal
backgroundWrite, sigTTOU       :: Signal
continueProcess, sigCONT       :: Signal
floatingPointException, sigFPE :: Signal
illegalInstruction, sigILL     :: Signal
internalAbort, sigABRT         :: Signal
keyboardSignal, sigINT         :: Signal
keyboardStop, sigTSTP          :: Signal
keyboardTermination, sigQUIT   :: Signal
killProcess, sigKILL           :: Signal
lostConnection, sigHUP         :: Signal
openEndedPipe, sigPIPE         :: Signal
processStatusChanged, sigCHLD  :: Signal
realTimeAlarm, sigALRM         :: Signal
segmentationViolation, sigSEGV :: Signal
softwareStop, sigSTOP          :: Signal
softwareTermination, sigTERM   :: Signal
userDefinedSignal1, sigUSR1    :: Signal
userDefinedSignal2, sigUSR2    :: Signal

signalProcess :: Signal -&#62; ProcessID -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>signalProcess int pid</Literal> calls <Function>kill</Function> to signal 
process <Literal>pid</Literal> with interrupt signal <Literal>int</Literal>.
</Para>

<Para>

<ProgramListing>
raiseSignal :: Signal -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>raiseSignal int</Literal> calls <Function>kill</Function> to signal the current process
with interrupt signal <Literal>int</Literal>. 
</Para>

<Para>

<ProgramListing>
signalProcessGroup :: Signal -&#62; ProcessGroupID -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>signalProcessGroup int pgid</Literal> calls <Function>kill</Function> to signal 
all processes in group <Literal>pgid</Literal> with interrupt signal <Literal>int</Literal>.
</Para>

<Para>

<ProgramListing>
setStoppedChildFlag :: Bool -&#62; IO Bool
</ProgramListing>

</Para>

<Para>
<Literal>setStoppedChildFlag bool</Literal> sets a flag which controls whether or
not the <Constant>NOCLDSTOP</Constant> option will be used the next time a signal
handler is installed for <Constant>SIGCHLD</Constant>.  If <Literal>bool</Literal> is <Literal>True</Literal> (the
default), <Constant>NOCLDSTOP</Constant> will not be used; otherwise it will be.  The
operation never fails.
</Para>

<Para>

<ProgramListing>
queryStoppedChildFlag :: IO Bool
</ProgramListing>

</Para>

<Para>
<Function>queryStoppedChildFlag</Function> queries the flag which
controls whether or not the <Constant>NOCLDSTOP</Constant> option will be used
the next time a signal handler is installed for <Constant>SIGCHLD</Constant>.
If <Constant>NOCLDSTOP</Constant> will be used, it returns <Literal>False</Literal>; 
otherwise (the default) it returns <Literal>True</Literal>.  
The operation never fails.
</Para>

<Para>

<ProgramListing>
emptySignalSet :: SignalSet
fullSignalSet  :: SignalSet
addSignal      :: Signal -&#62; SignalSet -&#62; SignalSet
deleteSignal   :: Signal -&#62; SignalSet -&#62; SignalSet
inSignalSet    :: Signal -&#62; SignalSet -&#62; Bool

installHandler :: Signal
               -&#62; Handler 
               -&#62; Maybe SignalSet       -- other signals to block
               -&#62; IO Handler            -- old handler
</ProgramListing>

</Para>

<Para>
<Literal>installHandler int handler iset</Literal> calls <Constant>sigaction</Constant> to install an
interrupt handler for signal <Literal>int</Literal>.  If <Literal>handler</Literal> is <Literal>Default</Literal>,
<Constant>SIG&lowbar;DFL</Constant> is installed; if <Literal>handler</Literal> is <Literal>Ignore</Literal>, <Constant>SIG&lowbar;IGN</Constant> is
installed; if <Literal>handler</Literal> is <Literal>Catch action</Literal>, a handler is installed
which will invoke <Literal>action</Literal> in a new thread when (or shortly after) the
signal is received.  See <XRef LinkEnd="sec-Concurrent"> for details on how to communicate between
threads.
</Para>

<Para>
If <Literal>iset</Literal> is <Literal>Just s</Literal>, then the <VarName>sa&lowbar;mask</VarName> of the <Literal>sigaction</Literal> structure
is set to <Literal>s</Literal>; otherwise it is cleared.  The previously installed
signal handler for <Literal>int</Literal> is returned.
</Para>

<Para>

<ProgramListing>
getSignalMask :: IO SignalSet
</ProgramListing>

</Para>

<Para>
<Function>getSignalMask</Function> calls <Function>sigprocmask</Function> to determine the
set of interrupts which are currently being blocked.
</Para>

<Para>

<ProgramListing>
setSignalMask :: SignalSet -&#62; IO SignalSet
</ProgramListing>

</Para>

<Para>
<Literal>setSignalMask mask</Literal> calls <Function>sigprocmask</Function> with
<Constant>SIG&lowbar;SETMASK</Constant> to block all interrupts in <Literal>mask</Literal>.  The
previous set of blocked interrupts is returned.
</Para>

<Para>

<ProgramListing>
blockSignals :: SignalSet -&#62; IO SignalSet
</ProgramListing>

</Para>

<Para>
<Literal>setSignalMask mask</Literal> calls <Function>sigprocmask</Function> with
<Constant>SIG&lowbar;BLOCK</Constant> to add all interrupts in <Literal>mask</Literal> to the
set of blocked interrupts.  The previous set of blocked interrupts is returned.
</Para>

<Para>

<ProgramListing>
unBlockSignals :: SignalSet -&#62; IO SignalSet
</ProgramListing>

</Para>

<Para>
<Literal>setSignalMask mask</Literal> calls <Function>sigprocmask</Function> with
<Constant>SIG&lowbar;UNBLOCK</Constant> to remove all interrupts in <Literal>mask</Literal> from the
set of blocked interrupts.  The previous set of blocked interrupts is returned.
</Para>

<Para>

<ProgramListing>
getPendingSignals :: IO SignalSet
</ProgramListing>

</Para>

<Para>
<Function>getPendingSignals</Function> calls <Function>sigpending</Function> to obtain
the set of interrupts which have been received but are currently blocked.
</Para>

<Para>

<ProgramListing>
awaitSignal :: Maybe SignalSet -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>awaitSignal iset</Literal> suspends execution until an interrupt is received.
If <Literal>iset</Literal> is <Literal>Just s</Literal>, <Function>awaitSignal</Function> calls <Function>sigsuspend</Function>, installing
<Literal>s</Literal> as the new signal mask before suspending execution; otherwise, it
calls <Function>pause</Function>.  <Function>awaitSignal</Function> returns on receipt of a signal.  If you
have installed any signal handlers with <Function>installHandler</Function>, it may be
wise to call <Function>yield</Function> directly after <Function>awaitSignal</Function> to ensure that the
signal handler runs as promptly.
</Para>

<Para>

<ProgramListing>
scheduleAlarm :: Int -&#62; IO Int
</ProgramListing>

</Para>

<Para>
<Literal>scheduleAlarm i</Literal> calls <Function>alarm</Function> to schedule a real time
alarm at least <Literal>i</Literal> seconds in the future.
</Para>

<Para>

<ProgramListing>
sleep :: Int -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>sleep i</Literal> calls <Function>sleep</Function> to suspend execution of the
program until at least <Literal>i</Literal> seconds have elapsed or a signal is
received.
</Para>

</Sect1>

<Sect1 id="Process-Environment">
<Title>Posix Process Environment
</Title>

<Para>
<IndexTerm><Primary>Posix, process environment</Primary></IndexTerm>
</Para>

<Para>

<ProgramListing>
getProcessID :: IO ProcessID
</ProgramListing>

</Para>

<Para>
<Function>getProcessID</Function> calls <Function>getpid</Function> to obtain the <Literal>ProcessID</Literal> for
the current process.
</Para>

<Para>

<ProgramListing>
getParentProcessID :: IO ProcessID
</ProgramListing>

</Para>

<Para>
<Function>getProcessID</Function> calls <Function>getppid</Function> to obtain the <Literal>ProcessID</Literal> for
the parent of the current process.
</Para>

<Para>

<ProgramListing>
getRealUserID :: IO UserID
</ProgramListing>

</Para>

<Para>
<Function>getRealUserID</Function> calls <Function>getuid</Function> to obtain the real <Literal>UserID</Literal>
associated with the current process.
</Para>

<Para>

<ProgramListing>
getEffectiveUserID :: IO UserID
</ProgramListing>

</Para>

<Para>
<Function>getEffectiveUserID</Function> calls <Function>geteuid</Function> to obtain the effective
<Literal>UserID</Literal> associated with the current process.
</Para>

<Para>

<ProgramListing>
setUserID :: UserID -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>setUserID uid</Literal> calls <Function>setuid</Function> to set the real, effective, and
saved set-user-id associated with the current process to <Literal>uid</Literal>.
</Para>

<Para>

<ProgramListing>
getLoginName :: IO String
</ProgramListing>

</Para>

<Para>
<Function>getLoginName</Function> calls <Function>getlogin</Function> to obtain the login name
associated with the current process.
</Para>

<Para>

<ProgramListing>
getRealGroupID :: IO GroupID
</ProgramListing>

</Para>

<Para>
<Function>getRealGroupID</Function> calls <Function>getgid</Function> to obtain the real <Literal>GroupID</Literal>
associated with the current process.
</Para>

<Para>

<ProgramListing>
getEffectiveGroupID :: IO GroupID
</ProgramListing>

</Para>

<Para>
<Function>getEffectiveGroupID</Function> calls <Function>getegid</Function> to obtain the effective
<Literal>GroupID</Literal> associated with the current process.
</Para>

<Para>

<ProgramListing>
setGroupID :: GroupID -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>setGroupID gid</Literal> calls <Function>setgid</Function> to set the real, effective, and
saved set-group-id associated with the current process to <Literal>gid</Literal>.
</Para>

<Para>

<ProgramListing>
getGroups :: IO [GroupID]
</ProgramListing>

</Para>

<Para>
<Function>getGroups</Function> calls <Function>getgroups</Function> to obtain the list of
supplementary <Literal>GroupID</Literal>s associated with the current process.
</Para>

<Para>

<ProgramListing>
getEffectiveUserName :: IO String
</ProgramListing>

</Para>

<Para>
<Function>getEffectiveUserName</Function> calls <Function>cuserid</Function> to obtain a name
associated with the effective <Literal>UserID</Literal> of the process.
</Para>

<Para>

<ProgramListing>
getProcessGroupID :: IO ProcessGroupID
</ProgramListing>

</Para>

<Para>
<Function>getProcessGroupID</Function> calls <Function>getpgrp</Function> to obtain the
<Literal>ProcessGroupID</Literal> for the current process.
</Para>

<Para>

<ProgramListing>
createProcessGroup :: ProcessID -&#62; IO ProcessGroupID
</ProgramListing>

</Para>

<Para>
<Literal>createProcessGroup pid</Literal> calls <Function>setpgid</Function> to make
process <Literal>pid</Literal> a new process group leader.
</Para>

<Para>

<ProgramListing>
joinProcessGroup :: ProcessGroupID -&#62; IO ProcessGroupID
</ProgramListing>

</Para>

<Para>
<Literal>joinProcessGroup pgid</Literal> calls <Function>setpgid</Function> to set the
<Literal>ProcessGroupID</Literal> of the current process to <Literal>pgid</Literal>.
</Para>

<Para>

<ProgramListing>
setProcessGroupID :: ProcessID -&#62; ProcessGroupID -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>setProcessGroupID pid pgid</Literal> calls <Function>setpgid</Function> to set the
<Literal>ProcessGroupID</Literal> for process <Literal>pid</Literal> to <Literal>pgid</Literal>.
</Para>

<Para>

<ProgramListing>
createSession :: IO ProcessGroupID
</ProgramListing>

</Para>

<Para>
<Function>createSession</Function> calls <Function>setsid</Function> to create a new session
with the current process as session leader.
</Para>

<Para>

<ProgramListing>
systemName :: SystemID -&#62; String
nodeName :: SystemID -&#62; String
release :: SystemID -&#62; String
version :: SystemID -&#62; String
machine :: SystemID -&#62; String

getSystemID :: IO SystemID
</ProgramListing>

</Para>

<Para>
<Function>getSystemID</Function> calls <Function>uname</Function> to obtain information
about the current operating system.
</Para>

<Para>

<ProgramListing>
&#62; epochTime :: IO EpochTime
</ProgramListing>

</Para>

<Para>
<Function>epochTime</Function> calls <Function>time</Function> to obtain the number of 
seconds that have elapsed since the epoch (Jan 01 00:00:00 GMT 1970).
</Para>

<Para>

<ProgramListing>
elapsedTime     :: ProcessTimes -&#62; ClockTick
userTime        :: ProcessTimes -&#62; ClockTick
systemTime      :: ProcessTimes -&#62; ClockTick
childUserTime   :: ProcessTimes -&#62; ClockTick
childSystemTime :: ProcessTimes -&#62; ClockTick

getProcessTimes :: IO ProcessTimes
</ProgramListing>

</Para>

<Para>
<Function>getProcessTimes</Function> calls <Function>times</Function> to obtain time-accounting
information for the current process and its children.
</Para>

<Para>

<ProgramListing>
getControllingTerminalName :: IO FilePath
</ProgramListing>

</Para>

<Para>
<Function>getControllingTerminalName</Function> calls <Function>ctermid</Function> to obtain
a name associated with the controlling terminal for the process.  If a
controlling terminal exists,
<Function>getControllingTerminalName</Function> returns the name of the
controlling terminal.
</Para>

<Para>
The operation may fail with:
</Para>

<Para>
<VariableList>

<VarListEntry>
<Term><Literal>NoSuchThing</Literal></Term>
<ListItem>
<Para>
There is no controlling terminal, or its name cannot be determined.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term><Literal>SystemError</Literal></Term>
<ListItem>
<Para>
Various other causes.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>

<Para>

<ProgramListing>
getTerminalName :: Fd -&#62; IO FilePath
</ProgramListing>

</Para>

<Para>
<Literal>getTerminalName fd</Literal> calls <Function>ttyname</Function> to obtain a name associated
with the terminal for <Literal>Fd</Literal> <Literal>fd</Literal>. If <Literal>fd</Literal> is associated
with a terminal, <Function>getTerminalName</Function> returns the name of the
terminal.
</Para>

<Para>
The operation may fail with:
</Para>

<Para>
<VariableList>

<VarListEntry>
<Term><Literal>InappropriateType</Literal></Term>
<ListItem>
<Para>
The channel is not associated with a terminal.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term><Literal>NoSuchThing</Literal></Term>
<ListItem>
<Para>
The channel is associated with a terminal, but it has no name.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term><Literal>SystemError</Literal></Term>
<ListItem>
<Para>
Various other causes.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>

<Para>

<ProgramListing>
queryTerminal :: Fd -&#62; IO Bool
</ProgramListing>

</Para>

<Para>
<Literal>queryTerminal fd</Literal> calls <Function>isatty</Function> to determine whether or
not <Literal>Fd</Literal> <Literal>fd</Literal> is associated with a terminal.
</Para>

<Para>

<ProgramListing>
getSysVar :: SysVar -&#62; IO Limit
</ProgramListing>

</Para>

<Para>
<Literal>getSysVar var</Literal> calls <Function>sysconf</Function> to obtain the
dynamic value of the requested configurable system limit or option.
For defined system limits, <Function>getSysVar</Function> returns the associated
value.  For defined system options, the result of <Function>getSysVar</Function>
is undefined, but not failure.
</Para>

<Para>
The operation may fail with:
</Para>

<Para>
<VariableList>

<VarListEntry>
<Term><Literal>NoSuchThing</Literal></Term>
<ListItem>
<Para>
The requested system limit or option is undefined.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>

</Sect1>

<Sect1 id="Files-and-Directories">
<Title>Posix operations on files and directories
</Title>

<Para>
<IndexTerm><Primary>Posix, files and directories</Primary></IndexTerm>
</Para>

<Para>

<ProgramListing>
openDirStream :: FilePath -&#62; IO DirStream
</ProgramListing>

</Para>

<Para>
<Literal>openDirStream dir</Literal> calls <Function>opendir</Function> to obtain a
directory stream for <Literal>dir</Literal>.
</Para>

<Para>

<ProgramListing>
readDirStream :: DirStream -&#62; IO String
</ProgramListing>

</Para>

<Para>
<Literal>readDirStream dp</Literal> calls <Function>readdir</Function> to obtain the
next directory entry (<Literal>struct dirent</Literal>) for the open directory
stream <Literal>dp</Literal>, and returns the <VarName>d&lowbar;name</VarName> member of that
structure.
</Para>

<Para>
The operation may fail with:
</Para>

<Para>
<VariableList>

<VarListEntry>
<Term><Literal>EOF</Literal></Term>
<ListItem>
<Para>
End of file has been reached.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term><Literal>SystemError</Literal></Term>
<ListItem>
<Para>
Various other causes.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>

<Para>

<ProgramListing>
rewindDirStream :: DirStream -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>rewindDirStream dp</Literal> calls <Function>rewinddir</Function> to reposition
the directory stream <Literal>dp</Literal> at the beginning of the directory.
</Para>

<Para>

<ProgramListing>
closeDirStream :: DirStream -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>closeDirStream dp</Literal> calls <Function>closedir</Function> to close
the directory stream <Literal>dp</Literal>.
</Para>

<Para>

<ProgramListing>
getWorkingDirectory :: IO FilePath
</ProgramListing>

</Para>

<Para>
<Function>getWorkingDirectory</Function> calls <Function>getcwd</Function> to obtain the name
of the current working directory.
</Para>

<Para>

<ProgramListing>
changeWorkingDirectory :: FilePath -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>changeWorkingDirectory dir</Literal> calls <Function>chdir</Function> to change
the current working directory to <Literal>dir</Literal>.
</Para>

<Para>
<ProgramListing>
nullFileMode       :: FileMode       -- ---------
ownerReadMode      :: FileMode       -- r--------
ownerWriteMode     :: FileMode       -- -w-------
ownerExecuteMode   :: FileMode       -- --x------
groupReadMode      :: FileMode       -- ---r-----
groupWriteMode     :: FileMode       -- ----w----
groupExecuteMode   :: FileMode       -- -----x---
otherReadMode      :: FileMode       -- ------r--
otherWriteMode     :: FileMode       -- -------w-
otherExecuteMode   :: FileMode       -- --------x
setUserIDMode      :: FileMode       -- --S------
setGroupIDMode     :: FileMode       -- -----S---
                               
stdFileMode        :: FileMode       -- rw-rw-rw-
                               
ownerModes         :: FileMode       -- rwx------
groupModes         :: FileMode       -- ---rwx---
otherModes         :: FileMode       -- ------rwx
accessModes        :: FileMode       -- rwxrwxrwx

unionFileModes     :: FileMode -&#62; FileMode -&#62; FileMode
intersectFileModes :: FileMode -&#62; FileMode -&#62; FileMode

stdInput  :: Fd
stdInput  = intToFd 0

stdOutput :: Fd
stdOutput = intToFd 1

stdError  :: Fd
stdError  = intToFd 2

data OpenFileFlags =
 OpenFileFlags {
    append    :: Bool,
    exclusive :: Bool,
    noctty    :: Bool,
    nonBlock  :: Bool,
    trunc     :: Bool
 }

openFd :: FilePath
       -&#62; OpenMode
       -&#62; Maybe FileMode  -- Just x =&#62; O_CREAT, Nothing =&#62; must exist
       -&#62; OpenFileFlags
       -&#62; IO Fd
</ProgramListing>
</Para>

<Para>
<Literal>openFd path acc mode (OpenFileFlags app excl noctty nonblock trunc)</Literal> calls
<Function>open</Function> to obtain a <Literal>Fd</Literal> for the file <Literal>path</Literal> with access
mode <Literal>acc</Literal>.  If <Literal>mode</Literal> is <Literal>Just m</Literal>, the <Constant>O&lowbar;CREAT</Constant> flag is
set and the file's permissions will be based on <Literal>m</Literal> if it does not
already exist; otherwise, the <Constant>O&lowbar;CREAT</Constant> flag is not set.  The
arguments <Literal>app</Literal>, <Literal>excl</Literal>, <Literal>noctty</Literal>, <Literal>nonblock</Literal>, and
<Literal>trunc</Literal> control whether or not the flags <Constant>O&lowbar;APPEND</Constant>,
<Constant>O&lowbar;EXCL</Constant>, <Constant>O&lowbar;NOCTTY</Constant>, <Constant>O&lowbar;NONBLOCK</Constant>, and <Constant>O&lowbar;TRUNC</Constant> are set,
respectively.
</Para>

<Para>

<ProgramListing>
createFile :: FilePath -&#62; FileMode -&#62; IO Fd
</ProgramListing>

</Para>

<Para>
<Literal>createFile path mode</Literal> calls <Function>creat</Function> to obtain a <Literal>Fd</Literal>
for file <Literal>path</Literal>, which will be created with permissions based on
<Literal>mode</Literal> if it does not already exist.
</Para>

<Para>

<ProgramListing>
setFileCreationMask :: FileMode -&#62; IO FileMode
</ProgramListing>

</Para>

<Para>
<Literal>setFileCreationMask mode</Literal> calls <Function>umask</Function> to set
the process's file creation mask to <Literal>mode</Literal>.  The previous file
creation mask is returned.
</Para>

<Para>

<ProgramListing>
createLink :: FilePath -&#62; FilePath -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>createLink old new</Literal> calls <Function>link</Function> to create a 
new path, <Literal>new</Literal>, linked to an existing file, <Literal>old</Literal>.

<ProgramListing>
createDirectory :: FilePath -&#62; FileMode -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>createDirectory dir mode</Literal> calls <Function>mkdir</Function> to 
create a new directory, <Literal>dir</Literal>, with permissions based on
<Literal>mode</Literal>.
</Para>

<Para>

<ProgramListing>
createNamedPipe :: FilePath -&#62; FileMode -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>createNamedPipe fifo mode</Literal> calls <Function>mkfifo</Function> to 
create a new named pipe, <Literal>fifo</Literal>, with permissions based on
<Literal>mode</Literal>.
</Para>

<Para>

<ProgramListing>
removeLink :: FilePath -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>removeLink path</Literal> calls <Function>unlink</Function> to remove the link
named <Literal>path</Literal>.
</Para>

<Para>

<ProgramListing>
removeDirectory :: FilePath -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>removeDirectory dir</Literal> calls <Function>rmdir</Function> to remove the 
directory named <Literal>dir</Literal>.
</Para>

<Para>

<ProgramListing>
rename :: FilePath -&#62; FilePath -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>rename old new</Literal> calls <Function>rename</Function> to rename a 
file or directory from <Literal>old</Literal> to <Literal>new</Literal>.
</Para>

<Para>

<ProgramListing>
fileMode          :: FileStatus -&#62; FileMode
                   
fileID            :: FileStatus -&#62; FileID
deviceID          :: FileStatus -&#62; DeviceID
                   
linkCount         :: FileStatus -&#62; LinkCount
                   
fileOwner         :: FileStatus -&#62; UserID
fileGroup         :: FileStatus -&#62; GroupID
fileSize          :: FileStatus -&#62; FileOffset

accessTime        :: FileStatus -&#62; EpochTime
modificationTime  :: FileStatus -&#62; EpochTime
statusChangeTime  :: FileStatus -&#62; EpochTime

isDirectory       :: FileStatus -&#62; Bool
isCharacterDevice :: FileStatus -&#62; Bool
isBlockDevice     :: FileStatus -&#62; Bool
isRegularFile     :: FileStatus -&#62; Bool
isNamedPipe       :: FileStatus -&#62; Bool

getFileStatus     :: FilePath -&#62; IO FileStatus
</ProgramListing>

</Para>

<Para>
<Literal>getFileStatus path</Literal> calls <Function>stat</Function> to get the
<Literal>FileStatus</Literal> information for the file <Literal>path</Literal>.
</Para>

<Para>

<ProgramListing>
getFdStatus :: Fd -&#62; IO FileStatus
</ProgramListing>

</Para>

<Para>
<Literal>getFdStatus fd</Literal> calls <Function>fstat</Function> to get the
<Literal>FileStatus</Literal> information for the file associated with
<Literal>Fd</Literal> <Literal>fd</Literal>.
</Para>

<Para>

<ProgramListing>
queryAccess :: FilePath -&#62; Bool -&#62; Bool -&#62; Bool -&#62; IO Bool
</ProgramListing>

</Para>

<Para>
<Literal>queryAccess path r w x</Literal> calls <Function>access</Function> to test the access
permissions for file <Literal>path</Literal>.  The three arguments, <Literal>r</Literal>, <Literal>w</Literal>,
and <Literal>x</Literal> control whether or not <Function>access</Function> is called with
<Constant>R&lowbar;OK</Constant>, <Constant>W&lowbar;OK</Constant>, and <Constant>X&lowbar;OK</Constant> respectively.
</Para>

<Para>

<ProgramListing>
queryFile :: FilePath -&#62; IO Bool
</ProgramListing>

</Para>

<Para>
<Literal>queryFile path</Literal> calls <Function>access</Function> with <Constant>F&lowbar;OK</Constant> to test for the
existence for file <Literal>path</Literal>.
</Para>

<Para>

<ProgramListing>
setFileMode :: FilePath -&#62; FileMode -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>setFileMode path mode</Literal> calls <Function>chmod</Function> to set the
permission bits associated with file <Literal>path</Literal> to <Literal>mode</Literal>.
</Para>

<Para>

<ProgramListing>
setOwnerAndGroup :: FilePath -&#62; UserID -&#62; GroupID -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>setOwnerAndGroup path uid gid</Literal> calls <Function>chown</Function> to
set the <Literal>UserID</Literal> and <Literal>GroupID</Literal> associated with file
<Literal>path</Literal> to <Literal>uid</Literal> and <Literal>gid</Literal>, respectively.
</Para>

<Para>

<ProgramListing>
setFileTimes :: FilePath -&#62; EpochTime -&#62; EpochTime -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>setFileTimes path atime mtime</Literal> calls <Function>utime</Function> to
set the access and modification times associated with file
<Literal>path</Literal> to <Literal>atime</Literal> and <Literal>mtime</Literal>, respectively.
</Para>

<Para>

<ProgramListing>
touchFile :: FilePath -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>touchFile path</Literal> calls <Function>utime</Function> to
set the access and modification times associated with file
<Literal>path</Literal> to the current time.
</Para>

<Para>

<ProgramListing>
getPathVar :: PathVar -&#62; FilePath -&#62; IO Limit
</ProgramListing>

</Para>

<Para>
<Literal>getPathVar var path</Literal> calls <Function>pathconf</Function> to obtain the
dynamic value of the requested configurable file limit or option associated
with file or directory <Literal>path</Literal>.  For
defined file limits, <Function>getPathVar</Function> returns the associated
value.  For defined file options, the result of <Function>getPathVar</Function>
is undefined, but not failure.
The operation may fail with:
<VariableList>

<VarListEntry>
<Term><Literal>NoSuchThing</Literal></Term>
<ListItem>
<Para>
The requested file limit or option is undefined.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term><Literal>SystemError</Literal></Term>
<ListItem>
<Para>
Various other causes.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>

<Para>

<ProgramListing>
getFdVar :: PathVar -&#62; Fd -&#62; IO Limit
</ProgramListing>

</Para>

<Para>
<Literal>getFdVar var fd</Literal> calls <Function>fpathconf</Function> to obtain the
dynamic value of the requested configurable file limit or option associated
with the file or directory attached to the open channel <Literal>fd</Literal>.
For defined file limits, <Function>getFdVar</Function> returns the associated
value.  For defined file options, the result of <Function>getFdVar</Function>
is undefined, but not failure.
</Para>

<Para>
The operation may fail with:
</Para>

<Para>
<VariableList>

<VarListEntry>
<Term><Literal>NoSuchThing</Literal></Term>
<ListItem>
<Para>
The requested file limit or option is undefined.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term><Literal>SystemError</Literal></Term>
<ListItem>
<Para>
Various other causes.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>

</Sect1>

<Sect1 id="Input-Output">
<Title>Posix Input and Output Primitives
</Title>

<Para>
<IndexTerm><Primary>Posix, input/output</Primary></IndexTerm>
</Para>

<Para>

<ProgramListing>
createPipe :: IO (Fd, Fd)
</ProgramListing>

</Para>

<Para>
<Function>createPipe</Function> calls <Function>pipe</Function> to create a pipe and returns a pair of
<Literal>Fd</Literal>s, the first for reading and the second for writing.
</Para>

<Para>

<ProgramListing>
dup :: Fd -&#62; IO Fd
</ProgramListing>

</Para>

<Para>
<Literal>dup fd</Literal> calls <Function>dup</Function> to duplicate <Literal>Fd</Literal> <Literal>fd</Literal> to
another <Literal>Fd</Literal>.
</Para>

<Para>

<ProgramListing>
dupTo :: Fd -&#62; Fd -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>dupTo src dst</Literal> calls <Function>dup2</Function> to duplicate <Literal>Fd</Literal>
<Literal>src</Literal> to <Literal>Fd</Literal> <Literal>dst</Literal>.
</Para>

<Para>

<ProgramListing>
fdClose :: Fd -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>fdClose fd</Literal> calls <Function>close</Function> to close <Literal>Fd</Literal> <Literal>fd</Literal>.
</Para>

<Para>

<ProgramListing>
fdRead :: Fd -&#62; ByteCount -&#62; IO (String, ByteCount)
</ProgramListing>

</Para>

<Para>
<Literal>fdRead fd nbytes</Literal> calls <Function>read</Function> to read at most <Literal>nbytes</Literal>
bytes from <Literal>Fd</Literal> <Literal>fd</Literal>, and returns the result as a string
paired with the number of bytes actually read.
</Para>

<Para>
The operation may fail with:
</Para>

<Para>
<VariableList>

<VarListEntry>
<Term><Literal>EOF</Literal></Term>
<ListItem>
<Para>
End of file has been reached.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term><Literal>SystemError</Literal></Term>
<ListItem>
<Para>
Various other causes.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>

<Para>

<ProgramListing>
fdWrite :: Fd -&#62; String -&#62; IO ByteCount
</ProgramListing>

</Para>

<Para>
<Literal>fdWrite fd s</Literal> calls <Function>write</Function> to write
the string <Literal>s</Literal> to <Literal>Fd</Literal> <Literal>fd</Literal> as a
contiguous sequence of bytes.  It returns the number of bytes successfully
written.
</Para>

<Para>

<ProgramListing>
queryFdOption :: FdOption -&#62; Fd -&#62; IO Bool
</ProgramListing>

</Para>

<Para>
<Literal>getFdOption opt fd</Literal> calls <Function>fcntl</Function> to determine whether or
not the flag associated with <Literal>FdOption</Literal> <Literal>opt</Literal> is set for
<Literal>Fd</Literal> <Literal>fd</Literal>.
</Para>

<Para>

<ProgramListing>
setFdOption :: Fd -&#62; FdOption -&#62; Bool -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>setFdOption fd opt val</Literal> calls <Function>fcntl</Function> to set the flag
associated with <Literal>FdOption</Literal> <Literal>opt</Literal> on <Literal>Fd</Literal> <Literal>fd</Literal> to
<Literal>val</Literal>.
</Para>

<Para>

<ProgramListing>
getLock :: Fd -&#62; FileLock -&#62; IO (Maybe (ProcessID, FileLock))
</ProgramListing>

</Para>

<Para>
<Literal>getLock fd lock</Literal> calls <Function>fcntl</Function> to get the first <Literal>FileLock</Literal>
for <Literal>Fd</Literal> <Literal>fd</Literal> which blocks the <Literal>FileLock</Literal> <Literal>lock</Literal>.  If
no such <Literal>FileLock</Literal> exists, <Function>getLock</Function> returns <Literal>Nothing</Literal>.
Otherwise, it returns <Literal>Just (pid, block)</Literal>, where <Literal>block</Literal> is the
blocking <Literal>FileLock</Literal> and <Literal>pid</Literal> is the <Literal>ProcessID</Literal> of the
process holding the blocking <Literal>FileLock</Literal>.
</Para>

<Para>

<ProgramListing>
setLock :: Fd -&#62; FileLock -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>setLock fd lock</Literal> calls <Function>fcntl</Function> with <Constant>F&lowbar;SETLK</Constant> to set or
clear a lock segment for <Literal>Fd</Literal> <Literal>fd</Literal> as indicated by the
<Literal>FileLock</Literal> <Literal>lock</Literal>.  <Function>setLock</Function> does not block, but fails with
<Literal>SystemError</Literal> if the request cannot be satisfied immediately.
</Para>

<Para>

<ProgramListing>
waitToSetLock :: Fd -&#62; FileLock -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>waitToSetLock fd lock</Literal> calls <Function>fcntl</Function> with <Constant>F&lowbar;SETLKW</Constant> to set
or clear a lock segment for <Literal>Fd</Literal> <Literal>fd</Literal> as indicated by the
<Literal>FileLock</Literal> <Literal>lock</Literal>. If the request cannot be satisfied
immediately, <Function>waitToSetLock</Function> blocks until the request can be
satisfied.
</Para>

<Para>

<ProgramListing>
fdSeek :: Fd -&#62; SeekMode -&#62; FileOffset -&#62; IO FileOffset
</ProgramListing>

</Para>

<Para>
<Literal>fdSeek fd whence offset</Literal> calls <Function>lseek</Function> to position the
<Literal>Fd</Literal> <Literal>fd</Literal> at the given <Literal>offset</Literal> from the starting location
indicated by <Literal>whence</Literal>.  It returns the resulting offset from the
start of the file in bytes.
</Para>

</Sect1>

<Sect1 id="Device-Specific-Functions">
<Title>Posix, Device- and Class-Specific Functions
</Title>

<Para>
<IndexTerm><Primary>Posix, device and class-specific functions</Primary></IndexTerm>
</Para>

<Para>

<ProgramListing>
terminalMode    :: TerminalMode -&#62; TerminalAttributes -&#62; Bool
withMode        :: TerminalAttributes -&#62; TerminalMode -&#62; TerminalAttributes
withoutMode     :: TerminalAttributes -&#62; TerminalMode -&#62; TerminalAttributes

bitsPerByte     :: TerminalAttributes -&#62; Int
withBits        :: TerminalAttributes -&#62; Int -&#62; TerminalAttributes

controlChar     :: TerminalAttributes -&#62; ControlCharacter -&#62; Maybe Char
withCC          :: TerminalAttributes
                -&#62; (ControlCharacter, Char)
                -&#62; TerminalAttributes 
withoutCC       :: TerminalAttributes 
                -&#62; ControlCharacter 
                -&#62; TerminalAttributes
                  
inputTime       :: TerminalAttributes -&#62; Int
withTime        :: TerminalAttributes -&#62; Int -&#62; TerminalAttributes
                  
minInput        :: TerminalAttributes -&#62; Int
withMinInput    :: TerminalAttributes -&#62; Int -&#62; TerminalAttributes
                  
inputSpeed      :: TerminalAttributes -&#62; BaudRate
withInputSpeed  :: TerminalAttributes -&#62; BaudRate -&#62; TerminalAttributes
                  
outputSpeed     :: TerminalAttributes -&#62; BaudRate
withOutputSpeed :: TerminalAttributes -&#62; BaudRate -&#62; TerminalAttributes

getTerminalAttributes :: Fd -&#62; IO TerminalAttributes
</ProgramListing>

</Para>

<Para>
<Literal>getTerminalAttributes fd</Literal> calls <Function>tcgetattr</Function> to obtain
the <Literal>TerminalAttributes</Literal> associated with <Literal>Fd</Literal> <Literal>fd</Literal>.
</Para>

<Para>

<ProgramListing>
setTerminalAttributes :: Fd
                      -&#62; TerminalAttributes 
                      -&#62; TerminalState
                      -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>setTerminalAttributes fd attr ts</Literal> calls <Function>tcsetattr</Function> to change
the <Literal>TerminalAttributes</Literal> associated with <Literal>Fd</Literal> <Literal>fd</Literal> to
<Literal>attr</Literal>, when the terminal is in the state indicated by <Literal>ts</Literal>.
</Para>

<Para>

<ProgramListing>
sendBreak :: Fd -&#62; Int -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>sendBreak fd duration</Literal> calls <Function>tcsendbreak</Function> to transmit a
continuous stream of zero-valued bits on <Literal>Fd</Literal> <Literal>fd</Literal> for the
specified implementation-dependent <Literal>duration</Literal>.
</Para>

<Para>

<ProgramListing>
drainOutput :: Fd -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>drainOutput fd</Literal> calls <Function>tcdrain</Function> to block until all output
written to <Literal>Fd</Literal> <Literal>fd</Literal> has been transmitted.
</Para>

<Para>

<ProgramListing>
discardData :: Fd -&#62; QueueSelector -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>discardData fd queues</Literal> calls <Function>tcflush</Function> to discard
pending input and/or output for <Literal>Fd</Literal> <Literal>fd</Literal>,
as indicated by the <Literal>QueueSelector</Literal> <Literal>queues</Literal>.
</Para>

<Para>

<ProgramListing>
controlFlow :: Fd -&#62; FlowAction -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>controlFlow fd action</Literal> calls <Function>tcflow</Function> to control the 
flow of data on <Literal>Fd</Literal> <Literal>fd</Literal>, as indicated by
<Literal>action</Literal>.
</Para>

<Para>

<ProgramListing>
getTerminalProcessGroupID :: Fd -&#62; IO ProcessGroupID
</ProgramListing>

</Para>

<Para>
<Literal>getTerminalProcessGroupID fd</Literal> calls <Function>tcgetpgrp</Function> to
obtain the <Literal>ProcessGroupID</Literal> of the foreground process group 
associated with the terminal attached to <Literal>Fd</Literal> <Literal>fd</Literal>.
</Para>

<Para>

<ProgramListing>
setTerminalProcessGroupID :: Fd -&#62; ProcessGroupID -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>setTerminalProcessGroupID fd pgid</Literal> calls <Function>tcsetpgrp</Function> to
set the <Literal>ProcessGroupID</Literal> of the foreground process group 
associated with the terminal attached to <Literal>Fd</Literal> 
<Literal>fd</Literal> to <Literal>pgid</Literal>.
</Para>

</Sect1>

<Sect1 id="System-Database">
<Title>Posix System Databases
</Title>

<Para>
<IndexTerm><Primary>Posix, system databases</Primary></IndexTerm>
</Para>

<Para>

<ProgramListing>
groupName    :: GroupEntry -&#62; String
groupID      :: GroupEntry -&#62; GroupID
groupMembers :: GroupEntry -&#62; [String]

getGroupEntryForID :: GroupID -&#62; IO GroupEntry
</ProgramListing>

</Para>

<Para>
<Literal>getGroupEntryForID gid</Literal> calls <Function>getgrgid</Function> to obtain
the <Literal>GroupEntry</Literal> information associated with <Literal>GroupID</Literal>
<Literal>gid</Literal>.
</Para>

<Para>
The operation may fail with:
</Para>

<Para>
<VariableList>

<VarListEntry>
<Term><Literal>NoSuchThing</Literal></Term>
<ListItem>
<Para>
There is no group entry for the GroupID.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>

<Para>

<ProgramListing>
getGroupEntryForName :: String -&#62; IO GroupEntry
</ProgramListing>

</Para>

<Para>
<Literal>getGroupEntryForName name</Literal> calls <Function>getgrnam</Function> to obtain
the <Literal>GroupEntry</Literal> information associated with the group called
<Literal>name</Literal>.
</Para>

<Para>
The operation may fail with:
</Para>

<Para>
<VariableList>

<VarListEntry>
<Term><Literal>NoSuchThing</Literal></Term>
<ListItem>
<Para>
There is no group entry for the name.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>

<Para>

<ProgramListing>
userName      :: UserEntry -&#62; String
userID        :: UserEntry -&#62; UserID
userGroupID   :: UserEntry -&#62; GroupID
homeDirectory :: UserEntry -&#62; String
userShell     :: UserEntry -&#62; String

getUserEntryForID :: UserID -&#62; IO UserEntry
</ProgramListing>

</Para>

<Para>
<Literal>getUserEntryForID gid</Literal> calls <Function>getpwuid</Function> to obtain
the <Literal>UserEntry</Literal> information associated with <Literal>UserID</Literal>
<Literal>uid</Literal>.
The operation may fail with:
</Para>

<Para>
<VariableList>

<VarListEntry>
<Term><Literal>NoSuchThing</Literal></Term>
<ListItem>
<Para>
There is no user entry for the UserID.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>

<Para>

<ProgramListing>
getUserEntryForName :: String -&#62; IO UserEntry
</ProgramListing>

</Para>

<Para>
<Literal>getUserEntryForName name</Literal> calls <Function>getpwnam</Function> to obtain
the <Literal>UserEntry</Literal> information associated with the user login
<Literal>name</Literal>.
</Para>

<Para>
The operation may fail with:
</Para>

<Para>
<VariableList>

<VarListEntry>
<Term><Literal>NoSuchThing</Literal></Term>
<ListItem>
<Para>
There is no user entry for the name.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>

</Sect1>

<Sect1 id="Error-reporting-and-handling">
<Title>POSIX Errors
</Title>

<Para>
<IndexTerm><Primary>Posix, errors</Primary></IndexTerm>
</Para>

<Para>

<ProgramListing>
getErrorCode :: IO ErrorCode
</ProgramListing>

</Para>

<Para>
<Function>getErrorCode</Function> returns the current value of the external
variable <Function>errno</Function>.  It never fails.
</Para>

<Para>

<ProgramListing>
setErrorCode :: ErrorCode -&#62; IO ()
</ProgramListing>

</Para>

<Para>
<Literal>setErrorCode err</Literal> sets the external
variable <Function>errno</Function> to <Literal>err</Literal>.  It never fails.
</Para>

<Para>

<ProgramListing>
noError :: ErrorCode
noError = 0

argumentListTooLong, e2BIG              :: ErrorCode
badFd, eBADF                            :: ErrorCode
brokenPipe, ePIPE                       :: ErrorCode
directoryNotEmpty, eNOTEMPTY            :: ErrorCode
execFormatError, eNOEXEC                :: ErrorCode
fileAlreadyExists, eEXIST               :: ErrorCode
fileTooLarge, eFBIG                     :: ErrorCode
filenameTooLong, eNAMETOOLONG           :: ErrorCode
improperLink, eXDEV                     :: ErrorCode
inappropriateIOControlOperation, eNOTTY :: ErrorCode
inputOutputError, eIO                   :: ErrorCode
interruptedOperation, eINTR             :: ErrorCode
invalidArgument, eINVAL                 :: ErrorCode
invalidSeek, eSPIPE                     :: ErrorCode
isADirectory, eISDIR                    :: ErrorCode
noChildProcess, eCHILD                  :: ErrorCode
noLocksAvailable, eNOLCK                :: ErrorCode
noSpaceLeftOnDevice, eNOSPC             :: ErrorCode
noSuchOperationOnDevice, eNODEV         :: ErrorCode
noSuchDeviceOrAddress, eNXIO            :: ErrorCode
noSuchFileOrDirectory, eNOENT           :: ErrorCode
noSuchProcess, eSRCH                    :: ErrorCode
notADirectory, eNOTDIR                  :: ErrorCode
notEnoughMemory, eNOMEM                 :: ErrorCode
operationNotImplemented, eNOSYS         :: ErrorCode
operationNotPermitted, ePERM            :: ErrorCode
permissionDenied, eACCES                :: ErrorCode
readOnlyFileSystem, eROFS               :: ErrorCode
resourceBusy, eBUSY                     :: ErrorCode
resourceDeadlockAvoided, eDEADLK        :: ErrorCode
resourceTemporarilyUnavailable, eAGAIN  :: ErrorCode
tooManyLinks, eMLINK                    :: ErrorCode
tooManyOpenFiles, eMFILE                :: ErrorCode
tooManyOpenFilesInSystem, eNFILE        :: ErrorCode
</ProgramListing>

</Para>

</Sect1>

<Sect1 id="POpen">
<Title>POpen
</Title>

<Para>
<IndexTerm><Primary>POpen</Primary></IndexTerm>
POpen provides a convenient way of sending string input to a
subprocess and reading output from it lazily.
</Para>

<Para>

<ProgramListing>
popen :: FilePath			-- Command
      -> [String]			-- Arguments
      -> Maybe String			-- Input
      -> IO (String, String, ProcessID)	-- (stdout, stderr, pid)
</ProgramListing>

</Para>

<Para>
<literal>popen cmd args inp</literal> executes
<literal>cmd</literal> with <literal>args</literal> in a
forked process.  If <literal>inp</literal> is
<literal>Just str</literal> then str in sent in a pipe to
the standard input of the process. The output and error
streams from the process are returned, together with the
process id.
</Para>

<Para>

<ProgramListing>
popenEnvDir :: FilePath				-- Command
	    -> [String]				-- Arguments
	    -> Maybe String			-- Input
	    -> Maybe [(String, String)]		-- Environment
	    -> Maybe FilePath 			-- Working directory    
	    -> IO (String, String, ProcessID)	-- (stdout, stderr, pid)
</ProgramListing>

</Para>

<Para>
<literal>popenEnvDir cmd args inp env dir</literal> like
<literal>popen</literal> executes
<literal>cmd</literal> with <literal>args</literal> in a
forked process.  If <literal>inp</literal> is
<literal>Just str</literal> then str in sent in a pipe to
the standard input of the process. If <literal>env</literal>
is <literal>Just pairs</literal>, the command in executed in
the environment specified by <literal>pairs</literal>,
instead of the current one.  If <literal>dir</literal> is
<literal>Just d</literal> the command is executed in
directory <literal>d</literal> instead of the current
directory.  The output and error streams from the process
are returned, together with the process id.
</Para>

</Sect1>

</Chapter>
