1 {-# OPTIONS -fno-implicit-prelude #-}
3 -- ---------------------------------------------------------------------------
5 -- POSIX support layer for the standard libraries
7 -- Non-posix compliant in order to support the following features:
8 -- * S_ISSOCK (no sockets in POSIX)
10 module PrelPosix where
12 -- See above comment for non-Posixness reasons.
13 -- #include "PosixSource.h"
29 import PrelMarshalAlloc
30 import PrelMarshalUtils
36 -- ---------------------------------------------------------------------------
42 type CDev = #type dev_t
43 type CIno = #type ino_t
44 type CMode = #type mode_t
45 type COff = #type off_t
46 type CPid = #type pid_t
48 #ifdef mingw32_TARGET_OS
49 type CSsize = #type size_t
51 type CGid = #type gid_t
52 type CNlink = #type nlink_t
53 type CSsize = #type ssize_t
54 type CUid = #type uid_t
56 type CSpeed = #type speed_t
57 type CTcflag = #type tcflag_t
60 -- ---------------------------------------------------------------------------
61 -- stat()-related stuff
65 fdFileSize :: Int -> IO Integer
67 allocaBytes (#const sizeof(struct stat)) $ \ p_stat -> do
68 throwErrnoIfMinus1Retry "fileSize" $
69 c_fstat (fromIntegral fd) p_stat
70 c_mode <- (#peek struct stat, st_mode) p_stat :: IO CMode
71 if not (s_isreg c_mode)
74 c_size <- (#peek struct stat, st_size) p_stat :: IO COff
75 return (fromIntegral c_size)
77 data FDType = Directory | Stream | RegularFile
80 -- NOTE: On Win32 platforms, this will only work with file descriptors
81 -- referring to file handles. i.e., it'll fail for socket FDs.
82 fdType :: Int -> IO FDType
84 allocaBytes (#const sizeof(struct stat)) $ \ p_stat -> do
85 throwErrnoIfMinus1Retry "fdType" $
86 c_fstat (fromIntegral fd) p_stat
87 c_mode <- (#peek struct stat, st_mode) p_stat :: IO CMode
89 _ | s_isdir c_mode -> return Directory
90 | s_isfifo c_mode -> return Stream
91 | s_issock c_mode -> return Stream
92 | s_ischr c_mode -> return Stream
93 | s_isreg c_mode -> return RegularFile
94 | s_isblk c_mode -> return RegularFile
95 | otherwise -> ioException ioe_unknownfiletype
96 -- we consider character devices to be streams (eg. ttys),
97 -- whereas block devices are more like regular files because they
100 ioe_unknownfiletype = IOError Nothing UnsupportedOperation "fdType"
101 "unknown file type" Nothing
103 foreign import "s_isreg_PrelPosix_wrap" unsafe s_isreg :: CMode -> Bool
104 #def inline int s_isreg_PrelPosix_wrap(m) { return S_ISREG(m); }
106 foreign import "s_isdir_PrelPosix_wrap" unsafe s_isdir :: CMode -> Bool
107 #def inline int s_isdir_PrelPosix_wrap(m) { return S_ISDIR(m); }
109 foreign import "s_isfifo_PrelPosix_wrap" unsafe s_isfifo :: CMode -> Bool
110 #def inline int s_isfifo_PrelPosix_wrap(m) { return S_ISFIFO(m); }
112 foreign import "s_ischr_PrelPosix_wrap" unsafe s_ischr :: CMode -> Bool
113 #def inline int s_ischr_PrelPosix_wrap(m) { return S_ISCHR(m); }
115 foreign import "s_isblk_PrelPosix_wrap" unsafe s_isblk :: CMode -> Bool
116 #def inline int s_isblk_PrelPosix_wrap(m) { return S_ISBLK(m); }
118 #ifndef mingw32_TARGET_OS
119 foreign import "s_issock_PrelPosix_wrap" unsafe s_issock :: CMode -> Bool
120 #def inline int s_issock_PrelPosix_wrap(m) { return S_ISSOCK(m); }
122 s_issock :: CMode -> Bool
123 s_issock cmode = False
126 -- It isn't clear whether ftruncate is POSIX or not (I've read several
127 -- manpages and they seem to conflict), so we truncate using open/2.
128 fileTruncate :: FilePath -> IO ()
129 fileTruncate file = do
130 let flags = o_WRONLY .|. o_TRUNC
131 withCString file $ \file_cstr -> do
132 fd <- fromIntegral `liftM`
133 throwErrnoIfMinus1Retry "fileTruncate"
134 (c_open file_cstr (fromIntegral flags) 0o666)
138 -- ---------------------------------------------------------------------------
139 -- Terminal-related stuff
141 fdIsTTY :: Int -> IO Bool
142 fdIsTTY fd = c_isatty (fromIntegral fd) >>= return.toBool
144 #ifndef mingw32_TARGET_OS
148 setEcho :: Int -> Bool -> IO ()
150 allocaBytes (#const sizeof(struct termios)) $ \p_tios -> do
151 throwErrnoIfMinus1Retry "setEcho"
152 (c_tcgetattr (fromIntegral fd) p_tios)
153 c_lflag <- (#peek struct termios, c_lflag) p_tios :: IO CTcflag
154 let new_c_lflag | on = c_lflag .|. (#const ECHO)
155 | otherwise = c_lflag .&. complement (#const ECHO)
156 (#poke struct termios, c_lflag) p_tios (new_c_lflag :: CTcflag)
157 tcSetAttr fd (#const TCSANOW) p_tios
159 getEcho :: Int -> IO Bool
161 allocaBytes (#const sizeof(struct termios)) $ \p_tios -> do
162 throwErrnoIfMinus1Retry "setEcho"
163 (c_tcgetattr (fromIntegral fd) p_tios)
164 c_lflag <- (#peek struct termios, c_lflag) p_tios :: IO CTcflag
165 return ((c_lflag .&. (#const ECHO)) /= 0)
167 setCooked :: Int -> Bool -> IO ()
168 setCooked fd cooked =
169 allocaBytes (#const sizeof(struct termios)) $ \p_tios -> do
170 throwErrnoIfMinus1Retry "setCooked"
171 (c_tcgetattr (fromIntegral fd) p_tios)
173 -- turn on/off ICANON
174 c_lflag <- (#peek struct termios, c_lflag) p_tios :: IO CTcflag
175 let new_c_lflag | cooked = c_lflag .|. (#const ICANON)
176 | otherwise = c_lflag .&. complement (#const ICANON)
177 (#poke struct termios, c_lflag) p_tios (new_c_lflag :: CTcflag)
179 -- set VMIN & VTIME to 1/0 respectively
181 let c_cc = (#ptr struct termios, c_cc) p_tios
182 vmin = c_cc `plusPtr` (#const VMIN) :: Ptr Word8
183 vtime = c_cc `plusPtr` (#const VTIME) :: Ptr Word8
187 tcSetAttr fd (#const TCSANOW) p_tios
189 -- tcsetattr() when invoked by a background process causes the process
190 -- to be sent SIGTTOU regardless of whether the process has TOSTOP set
191 -- in its terminal flags (try it...). This function provides a
192 -- wrapper which temporarily blocks SIGTTOU around the call, making it
195 tcSetAttr :: FD -> CInt -> Ptr Termios -> IO ()
196 tcSetAttr fd options p_tios = do
197 allocaBytes (#const sizeof(sigset_t)) $ \ p_sigset -> do
198 allocaBytes (#const sizeof(sigset_t)) $ \ p_old_sigset -> do
199 c_sigemptyset p_sigset
200 c_sigaddset p_sigset (#const SIGTTOU)
201 c_sigprocmask (#const SIG_BLOCK) p_sigset p_old_sigset
202 throwErrnoIfMinus1Retry_ "tcSetAttr" $
203 c_tcsetattr (fromIntegral fd) options p_tios
204 c_sigprocmask (#const SIG_SETMASK) p_old_sigset nullPtr
208 -- bogus defns for win32
209 setCooked :: Int -> Bool -> IO ()
210 setCooked fd cooked = return ()
212 setEcho :: Int -> Bool -> IO ()
213 setEcho fd on = return ()
215 getEcho :: Int -> IO Bool
216 getEcho fd = return False
220 -- ---------------------------------------------------------------------------
221 -- Turning on non-blocking for a file descriptor
223 #ifndef mingw32_TARGET_OS
225 setNonBlockingFD fd = do
226 flags <- throwErrnoIfMinus1Retry "setNonBlockingFD"
227 (fcntl_read (fromIntegral fd) (#const F_GETFL))
228 -- An error when setting O_NONBLOCK isn't fatal: on some systems
229 -- there are certain file handles on which this will fail (eg. /dev/null
230 -- on FreeBSD) so we throw away the return code from fcntl_write.
231 fcntl_write (fromIntegral fd)
232 (#const F_SETFL) (flags .|. #const O_NONBLOCK)
235 -- bogus defns for win32
236 setNonBlockingFD fd = return ()
240 -- -----------------------------------------------------------------------------
243 foreign import "stat" unsafe
244 c_stat :: CString -> Ptr CStat -> IO CInt
246 foreign import "fstat" unsafe
247 c_fstat :: CInt -> Ptr CStat -> IO CInt
250 foreign import "lstat" unsafe
251 c_lstat :: CString -> Ptr CStat -> IO CInt
254 foreign import "open" unsafe
255 c_open :: CString -> CInt -> CMode -> IO CInt
258 o_RDONLY = (#const O_RDONLY) :: CInt
259 o_WRONLY = (#const O_WRONLY) :: CInt
260 o_RDWR = (#const O_RDWR) :: CInt
261 o_APPEND = (#const O_APPEND) :: CInt
262 o_CREAT = (#const O_CREAT) :: CInt
263 o_EXCL = (#const O_EXCL) :: CInt
264 o_TRUNC = (#const O_TRUNC) :: CInt
266 #ifdef mingw32_TARGET_OS
268 o_NONBLOCK = 0 :: CInt
270 o_NOCTTY = (#const O_NOCTTY) :: CInt
271 o_NONBLOCK = (#const O_NONBLOCK) :: CInt
275 o_BINARY = (#const O_BINARY) :: CInt
278 foreign import "isatty" unsafe
279 c_isatty :: CInt -> IO CInt
281 foreign import "close" unsafe
282 c_close :: CInt -> IO CInt
284 #ifdef mingw32_TARGET_OS
285 closeFd :: Bool -> CInt -> IO CInt
287 | isStream = c_closesocket fd
288 | otherwise = c_close fd
290 foreign import "closesocket" unsafe
291 c_closesocket :: CInt -> IO CInt
294 foreign import "lseek" unsafe
295 c_lseek :: CInt -> COff -> CInt -> IO COff
297 foreign import "write" unsafe
298 c_write :: CInt -> Ptr CChar -> CSize -> IO CSsize
300 foreign import "read" unsafe
301 c_read :: CInt -> Ptr CChar -> CSize -> IO CSsize
303 #ifndef mingw32_TARGET_OS
304 foreign import "fcntl" unsafe
305 fcntl_read :: CInt -> CInt -> IO CInt
307 foreign import "fcntl" unsafe
308 fcntl_write :: CInt -> CInt -> CInt -> IO CInt
310 foreign import "fork" unsafe
313 foreign import "sigemptyset_PrelPosix_wrap" unsafe
314 c_sigemptyset :: Ptr CSigset -> IO ()
315 #def inline void sigemptyset_PrelPosix_wrap(sigset_t *set) { sigemptyset(set); }
317 foreign import "sigaddset" unsafe
318 c_sigaddset :: Ptr CSigset -> CInt -> IO ()
320 foreign import "sigprocmask" unsafe
321 c_sigprocmask :: CInt -> Ptr CSigset -> Ptr CSigset -> IO ()
323 foreign import "tcgetattr" unsafe
324 c_tcgetattr :: CInt -> Ptr Termios -> IO CInt
326 foreign import "tcsetattr" unsafe
327 c_tcsetattr :: CInt -> CInt -> Ptr Termios -> IO CInt
329 foreign import "unlink" unsafe
330 c_unlink :: CString -> IO CInt
332 foreign import "waitpid" unsafe
333 c_waitpid :: CPid -> Ptr CInt -> CInt -> IO CPid