1 {-# OPTIONS_GHC -fno-implicit-prelude #-}
3 -----------------------------------------------------------------------------
5 -- Module : System.Posix.Internals
6 -- Copyright : (c) The University of Glasgow, 1992-2002
7 -- License : see libraries/base/LICENSE
9 -- Maintainer : cvs-ghc@haskell.org
10 -- Stability : internal
11 -- Portability : non-portable (requires POSIX)
13 -- POSIX support layer for the standard libraries.
14 -- This library is built on *every* platform, including Win32.
16 -- Non-posix compliant in order to support the following features:
17 -- * S_ISSOCK (no sockets in POSIX)
19 -----------------------------------------------------------------------------
22 module System
.Posix
.Internals
where
24 #include
"HsBaseConfig.h"
27 import System
.Posix
.Types
35 #if __GLASGOW_HASKELL__
41 import Hugs
.Prelude
(IOException
(..), IOErrorType
(..))
42 import Hugs
.IO (IOMode(..))
48 {-# CFILES cbits/PrelIOUtils.c cbits/dirUtils.c cbits/consUtils.c #-}
51 -- ---------------------------------------------------------------------------
69 #ifndef __GLASGOW_HASKELL__
73 -- ---------------------------------------------------------------------------
74 -- stat()-related stuff
76 fdFileSize
:: FD
-> IO Integer
78 allocaBytes sizeof_stat
$ \ p_stat
-> do
79 throwErrnoIfMinus1Retry
"fileSize" $
81 c_mode
<- st_mode p_stat
:: IO CMode
82 if not (s_isreg c_mode
)
85 c_size
<- st_size p_stat
:: IO COff
86 return (fromIntegral c_size
)
88 data FDType
= Directory | Stream | RegularFile | RawDevice
91 fileType
:: FilePath -> IO FDType
93 allocaBytes sizeof_stat
$ \ p_stat
-> do
94 withCString file
$ \p_file
-> do
95 throwErrnoIfMinus1Retry
"fileType" $
99 -- NOTE: On Win32 platforms, this will only work with file descriptors
100 -- referring to file handles. i.e., it'll fail for socket FDs.
101 fdType
:: FD
-> IO FDType
103 allocaBytes sizeof_stat
$ \ p_stat
-> do
104 throwErrnoIfMinus1Retry
"fdType" $
108 statGetType p_stat
= do
109 c_mode
<- st_mode p_stat
:: IO CMode
111 _ | s_isdir c_mode
-> return Directory
112 | s_isfifo c_mode || s_issock c_mode || s_ischr c_mode
114 | s_isreg c_mode
-> return RegularFile
115 -- Q: map char devices to RawDevice too?
116 | s_isblk c_mode
-> return RawDevice
117 |
otherwise -> ioError ioe_unknownfiletype
120 ioe_unknownfiletype
= IOError Nothing UnsupportedOperation
"fdType"
121 "unknown file type" Nothing
123 #if __GLASGOW_HASKELL__
&& (defined
(mingw32_HOST_OS
) || defined
(__MINGW32__
))
124 closeFd
:: Bool -> CInt
-> IO CInt
126 | isStream
= c_closesocket fd
127 |
otherwise = c_close fd
129 foreign import stdcall unsafe
"HsBase.h closesocket"
130 c_closesocket
:: CInt
-> IO CInt
133 fdGetMode
:: FD
-> IO IOMode
135 #if defined
(mingw32_HOST_OS
) || defined
(__MINGW32__
)
136 -- We don't have a way of finding out which flags are set on FDs
137 -- on Windows, so make a handle that thinks that anything goes.
140 flags
<- throwErrnoIfMinus1Retry
"fdGetMode"
141 (c_fcntl_read fd const_f_getfl
)
144 wH
= (flags
.&. o_WRONLY
) /= 0
145 aH
= (flags
.&. o_APPEND
) /= 0
146 rwH
= (flags
.&. o_RDWR
) /= 0
149 | wH
&& aH
= AppendMode
151 | rwH
= ReadWriteMode
152 |
otherwise = ReadMode
156 -- ---------------------------------------------------------------------------
157 -- Terminal-related stuff
159 fdIsTTY
:: FD
-> IO Bool
160 fdIsTTY fd
= c_isatty fd
>>= return.toBool
162 #if defined
(HTYPE_TCFLAG_T
)
164 setEcho
:: FD
-> Bool -> IO ()
166 tcSetAttr fd
$ \ p_tios
-> do
167 c_lflag
<- c_lflag p_tios
:: IO CTcflag
169 | on
= c_lflag
.|
. fromIntegral const_echo
170 |
otherwise = c_lflag
.&. complement
(fromIntegral const_echo
)
171 poke_c_lflag p_tios
(new_c_lflag
:: CTcflag
)
173 getEcho
:: FD
-> IO Bool
175 tcSetAttr fd
$ \ p_tios
-> do
176 c_lflag
<- c_lflag p_tios
:: IO CTcflag
177 return ((c_lflag
.&. fromIntegral const_echo
) /= 0)
179 setCooked
:: FD
-> Bool -> IO ()
180 setCooked fd cooked
=
181 tcSetAttr fd
$ \ p_tios
-> do
183 -- turn on/off ICANON
184 c_lflag
<- c_lflag p_tios
:: IO CTcflag
185 let new_c_lflag | cooked
= c_lflag
.|
. (fromIntegral const_icanon
)
186 |
otherwise = c_lflag
.&. complement
(fromIntegral const_icanon
)
187 poke_c_lflag p_tios
(new_c_lflag
:: CTcflag
)
189 -- set VMIN & VTIME to 1/0 respectively
190 when (not cooked
) $ do
191 c_cc
<- ptr_c_cc p_tios
192 let vmin
= (c_cc `plusPtr`
(fromIntegral const_vmin
)) :: Ptr Word8
193 vtime
= (c_cc `plusPtr`
(fromIntegral const_vtime
)) :: Ptr Word8
197 tcSetAttr
:: FD
-> (Ptr CTermios
-> IO a
) -> IO a
198 tcSetAttr fd fun
= do
199 allocaBytes sizeof_termios
$ \p_tios
-> do
200 throwErrnoIfMinus1Retry
"tcSetAttr"
201 (c_tcgetattr fd p_tios
)
203 #ifdef __GLASGOW_HASKELL__
204 -- Save a copy of termios, if this is a standard file descriptor.
205 -- These terminal settings are restored in hs_exit().
207 p
<- get_saved_termios fd
208 when (p
== nullPtr
) $ do
209 saved_tios
<- mallocBytes sizeof_termios
210 copyBytes saved_tios p_tios sizeof_termios
211 set_saved_termios fd saved_tios
214 -- tcsetattr() when invoked by a background process causes the process
215 -- to be sent SIGTTOU regardless of whether the process has TOSTOP set
216 -- in its terminal flags (try it...). This function provides a
217 -- wrapper which temporarily blocks SIGTTOU around the call, making it
219 allocaBytes sizeof_sigset_t
$ \ p_sigset
-> do
220 allocaBytes sizeof_sigset_t
$ \ p_old_sigset
-> do
221 c_sigemptyset p_sigset
222 c_sigaddset p_sigset const_sigttou
223 c_sigprocmask const_sig_block p_sigset p_old_sigset
224 r
<- fun p_tios
-- do the business
225 throwErrnoIfMinus1Retry_
"tcSetAttr" $
226 c_tcsetattr fd const_tcsanow p_tios
227 c_sigprocmask const_sig_setmask p_old_sigset nullPtr
230 #ifdef __GLASGOW_HASKELL__
231 foreign import ccall unsafe
"HsBase.h __hscore_get_saved_termios"
232 get_saved_termios
:: CInt
-> IO (Ptr CTermios
)
234 foreign import ccall unsafe
"HsBase.h __hscore_set_saved_termios"
235 set_saved_termios
:: CInt
-> (Ptr CTermios
) -> IO ()
240 -- 'raw' mode for Win32 means turn off 'line input' (=> buffering and
241 -- character translation for the console.) The Win32 API for doing
242 -- this is GetConsoleMode(), which also requires echoing to be disabled
243 -- when turning off 'line input' processing. Notice that turning off
244 -- 'line input' implies enter/return is reported as '\r' (and it won't
245 -- report that character until another character is input..odd.) This
246 -- latter feature doesn't sit too well with IO actions like IO.hGetLine..
247 -- consider yourself warned.
248 setCooked
:: FD
-> Bool -> IO ()
249 setCooked fd cooked
= do
250 x
<- set_console_buffering fd
(if cooked
then 1 else 0)
252 then ioError (ioe_unk_error
"setCooked" "failed to set buffering")
255 ioe_unk_error loc msg
256 = IOError Nothing OtherError loc msg Nothing
258 -- Note: echoing goes hand in hand with enabling 'line input' / raw-ness
259 -- for Win32 consoles, hence setEcho ends up being the inverse of setCooked.
260 setEcho
:: FD
-> Bool -> IO ()
262 x
<- set_console_echo fd
(if on
then 1 else 0)
264 then ioError (ioe_unk_error
"setEcho" "failed to set echoing")
267 getEcho
:: FD
-> IO Bool
269 r
<- get_console_echo fd
271 then ioError (ioe_unk_error
"getEcho" "failed to get echoing")
274 foreign import ccall unsafe
"consUtils.h set_console_buffering__"
275 set_console_buffering
:: CInt
-> CInt
-> IO CInt
277 foreign import ccall unsafe
"consUtils.h set_console_echo__"
278 set_console_echo
:: CInt
-> CInt
-> IO CInt
280 foreign import ccall unsafe
"consUtils.h get_console_echo__"
281 get_console_echo
:: CInt
-> IO CInt
285 -- ---------------------------------------------------------------------------
286 -- Turning on non-blocking for a file descriptor
288 #if !defined
(mingw32_HOST_OS
) && !defined
(__MINGW32__
)
290 setNonBlockingFD fd
= do
291 flags
<- throwErrnoIfMinus1Retry
"setNonBlockingFD"
292 (c_fcntl_read fd const_f_getfl
)
293 -- An error when setting O_NONBLOCK isn't fatal: on some systems
294 -- there are certain file handles on which this will fail (eg. /dev/null
295 -- on FreeBSD) so we throw away the return code from fcntl_write.
296 unless (testBit flags
(fromIntegral o_NONBLOCK
)) $ do
297 c_fcntl_write fd const_f_setfl
(fromIntegral (flags
.|
. o_NONBLOCK
))
301 -- bogus defns for win32
302 setNonBlockingFD fd
= return ()
306 -- -----------------------------------------------------------------------------
309 foreign import ccall unsafe
"HsBase.h access"
310 c_access
:: CString
-> CInt
-> IO CInt
312 foreign import ccall unsafe
"HsBase.h chmod"
313 c_chmod
:: CString
-> CMode
-> IO CInt
315 foreign import ccall unsafe
"HsBase.h chdir"
316 c_chdir
:: CString
-> IO CInt
318 foreign import ccall unsafe
"HsBase.h close"
319 c_close
:: CInt
-> IO CInt
321 foreign import ccall unsafe
"HsBase.h closedir"
322 c_closedir
:: Ptr CDir
-> IO CInt
324 foreign import ccall unsafe
"HsBase.h creat"
325 c_creat
:: CString
-> CMode
-> IO CInt
327 foreign import ccall unsafe
"HsBase.h dup"
328 c_dup
:: CInt
-> IO CInt
330 foreign import ccall unsafe
"HsBase.h dup2"
331 c_dup2
:: CInt
-> CInt
-> IO CInt
333 foreign import ccall unsafe
"HsBase.h __hscore_fstat"
334 c_fstat
:: CInt
-> Ptr CStat
-> IO CInt
336 foreign import ccall unsafe
"HsBase.h getcwd"
337 c_getcwd
:: Ptr CChar
-> CSize
-> IO (Ptr CChar
)
339 foreign import ccall unsafe
"HsBase.h isatty"
340 c_isatty
:: CInt
-> IO CInt
342 foreign import ccall unsafe
"HsBase.h __hscore_lseek"
343 c_lseek
:: CInt
-> COff
-> CInt
-> IO COff
345 foreign import ccall unsafe
"HsBase.h __hscore_lstat"
346 lstat
:: CString
-> Ptr CStat
-> IO CInt
348 foreign import ccall unsafe
"HsBase.h __hscore_open"
349 c_open
:: CString
-> CInt
-> CMode
-> IO CInt
351 foreign import ccall unsafe
"HsBase.h opendir"
352 c_opendir
:: CString
-> IO (Ptr CDir
)
354 foreign import ccall unsafe
"HsBase.h __hscore_mkdir"
355 mkdir
:: CString
-> CInt
-> IO CInt
357 foreign import ccall unsafe
"HsBase.h read"
358 c_read
:: CInt
-> Ptr CChar
-> CSize
-> IO CSsize
360 foreign import ccall unsafe
"dirUtils.h __hscore_renameFile"
361 c_rename
:: CString
-> CString
-> IO CInt
363 foreign import ccall unsafe
"HsBase.h rewinddir"
364 c_rewinddir
:: Ptr CDir
-> IO ()
366 foreign import ccall unsafe
"HsBase.h rmdir"
367 c_rmdir
:: CString
-> IO CInt
369 foreign import ccall unsafe
"HsBase.h __hscore_stat"
370 c_stat
:: CString
-> Ptr CStat
-> IO CInt
372 foreign import ccall unsafe
"HsBase.h umask"
373 c_umask
:: CMode
-> IO CMode
375 foreign import ccall unsafe
"HsBase.h write"
376 c_write
:: CInt
-> Ptr CChar
-> CSize
-> IO CSsize
378 foreign import ccall unsafe
"HsBase.h __hscore_ftruncate"
379 c_ftruncate
:: CInt
-> COff
-> IO CInt
381 foreign import ccall unsafe
"HsBase.h unlink"
382 c_unlink
:: CString
-> IO CInt
384 foreign import ccall unsafe
"HsBase.h getpid"
387 #if !defined
(mingw32_HOST_OS
) && !defined
(__MINGW32__
)
388 foreign import ccall unsafe
"HsBase.h fcntl"
389 c_fcntl_read
:: CInt
-> CInt
-> IO CInt
391 foreign import ccall unsafe
"HsBase.h fcntl"
392 c_fcntl_write
:: CInt
-> CInt
-> CLong
-> IO CInt
394 foreign import ccall unsafe
"HsBase.h fcntl"
395 c_fcntl_lock
:: CInt
-> CInt
-> Ptr CFLock
-> IO CInt
397 foreign import ccall unsafe
"HsBase.h fork"
400 foreign import ccall unsafe
"HsBase.h link"
401 c_link
:: CString
-> CString
-> IO CInt
403 foreign import ccall unsafe
"HsBase.h mkfifo"
404 c_mkfifo
:: CString
-> CMode
-> IO CInt
406 foreign import ccall unsafe
"HsBase.h pipe"
407 c_pipe
:: Ptr CInt
-> IO CInt
409 foreign import ccall unsafe
"HsBase.h __hscore_sigemptyset"
410 c_sigemptyset
:: Ptr CSigset
-> IO CInt
412 foreign import ccall unsafe
"HsBase.h __hscore_sigaddset"
413 c_sigaddset
:: Ptr CSigset
-> CInt
-> IO CInt
415 foreign import ccall unsafe
"HsBase.h sigprocmask"
416 c_sigprocmask
:: CInt
-> Ptr CSigset
-> Ptr CSigset
-> IO CInt
418 foreign import ccall unsafe
"HsBase.h tcgetattr"
419 c_tcgetattr
:: CInt
-> Ptr CTermios
-> IO CInt
421 foreign import ccall unsafe
"HsBase.h tcsetattr"
422 c_tcsetattr
:: CInt
-> CInt
-> Ptr CTermios
-> IO CInt
424 foreign import ccall unsafe
"HsBase.h utime"
425 c_utime
:: CString
-> Ptr CUtimbuf
-> IO CInt
427 foreign import ccall unsafe
"HsBase.h waitpid"
428 c_waitpid
:: CPid
-> Ptr CInt
-> CInt
-> IO CPid
431 -- traversing directories
432 foreign import ccall unsafe
"dirUtils.h __hscore_readdir"
433 readdir
:: Ptr CDir
-> Ptr
(Ptr CDirent
) -> IO CInt
435 foreign import ccall unsafe
"HsBase.h __hscore_free_dirent"
436 freeDirEnt
:: Ptr CDirent
-> IO ()
438 foreign import ccall unsafe
"HsBase.h __hscore_end_of_dir"
441 foreign import ccall unsafe
"HsBase.h __hscore_d_name"
442 d_name
:: Ptr CDirent
-> IO CString
445 foreign import ccall unsafe
"HsBase.h __hscore_o_rdonly" o_RDONLY
:: CInt
446 foreign import ccall unsafe
"HsBase.h __hscore_o_wronly" o_WRONLY
:: CInt
447 foreign import ccall unsafe
"HsBase.h __hscore_o_rdwr" o_RDWR
:: CInt
448 foreign import ccall unsafe
"HsBase.h __hscore_o_append" o_APPEND
:: CInt
449 foreign import ccall unsafe
"HsBase.h __hscore_o_creat" o_CREAT
:: CInt
450 foreign import ccall unsafe
"HsBase.h __hscore_o_excl" o_EXCL
:: CInt
451 foreign import ccall unsafe
"HsBase.h __hscore_o_trunc" o_TRUNC
:: CInt
454 foreign import ccall unsafe
"HsBase.h __hscore_o_noctty" o_NOCTTY
:: CInt
455 foreign import ccall unsafe
"HsBase.h __hscore_o_nonblock" o_NONBLOCK
:: CInt
456 foreign import ccall unsafe
"HsBase.h __hscore_o_binary" o_BINARY
:: CInt
458 foreign import ccall unsafe
"HsBase.h __hscore_s_isreg" c_s_isreg
:: CMode
-> CInt
459 foreign import ccall unsafe
"HsBase.h __hscore_s_ischr" c_s_ischr
:: CMode
-> CInt
460 foreign import ccall unsafe
"HsBase.h __hscore_s_isblk" c_s_isblk
:: CMode
-> CInt
461 foreign import ccall unsafe
"HsBase.h __hscore_s_isdir" c_s_isdir
:: CMode
-> CInt
462 foreign import ccall unsafe
"HsBase.h __hscore_s_isfifo" c_s_isfifo
:: CMode
-> CInt
464 s_isreg
:: CMode
-> Bool
465 s_isreg cm
= c_s_isreg cm
/= 0
466 s_ischr
:: CMode
-> Bool
467 s_ischr cm
= c_s_ischr cm
/= 0
468 s_isblk
:: CMode
-> Bool
469 s_isblk cm
= c_s_isblk cm
/= 0
470 s_isdir
:: CMode
-> Bool
471 s_isdir cm
= c_s_isdir cm
/= 0
472 s_isfifo
:: CMode
-> Bool
473 s_isfifo cm
= c_s_isfifo cm
/= 0
475 foreign import ccall unsafe
"HsBase.h __hscore_sizeof_stat" sizeof_stat
:: Int
476 foreign import ccall unsafe
"HsBase.h __hscore_st_mtime" st_mtime
:: Ptr CStat
-> IO CTime
477 foreign import ccall unsafe
"HsBase.h __hscore_st_size" st_size
:: Ptr CStat
-> IO COff
478 foreign import ccall unsafe
"HsBase.h __hscore_st_mode" st_mode
:: Ptr CStat
-> IO CMode
480 foreign import ccall unsafe
"HsBase.h __hscore_echo" const_echo
:: CInt
481 foreign import ccall unsafe
"HsBase.h __hscore_tcsanow" const_tcsanow
:: CInt
482 foreign import ccall unsafe
"HsBase.h __hscore_icanon" const_icanon
:: CInt
483 foreign import ccall unsafe
"HsBase.h __hscore_vmin" const_vmin
:: CInt
484 foreign import ccall unsafe
"HsBase.h __hscore_vtime" const_vtime
:: CInt
485 foreign import ccall unsafe
"HsBase.h __hscore_sigttou" const_sigttou
:: CInt
486 foreign import ccall unsafe
"HsBase.h __hscore_sig_block" const_sig_block
:: CInt
487 foreign import ccall unsafe
"HsBase.h __hscore_sig_setmask" const_sig_setmask
:: CInt
488 foreign import ccall unsafe
"HsBase.h __hscore_f_getfl" const_f_getfl
:: CInt
489 foreign import ccall unsafe
"HsBase.h __hscore_f_setfl" const_f_setfl
:: CInt
491 #if defined
(HTYPE_TCFLAG_T
)
492 foreign import ccall unsafe
"HsBase.h __hscore_sizeof_termios" sizeof_termios
:: Int
493 foreign import ccall unsafe
"HsBase.h __hscore_sizeof_sigset_t" sizeof_sigset_t
:: Int
495 foreign import ccall unsafe
"HsBase.h __hscore_lflag" c_lflag
:: Ptr CTermios
-> IO CTcflag
496 foreign import ccall unsafe
"HsBase.h __hscore_poke_lflag" poke_c_lflag
:: Ptr CTermios
-> CTcflag
-> IO ()
497 foreign import ccall unsafe
"HsBase.h __hscore_ptr_c_cc" ptr_c_cc
:: Ptr CTermios
-> IO (Ptr Word8
)
500 #if !defined
(mingw32_HOST_OS
) && !defined
(__MINGW32__
)
501 foreign import ccall unsafe
"HsBase.h __hscore_s_issock" c_s_issock
:: CMode
-> CInt
502 s_issock
:: CMode
-> Bool
503 s_issock cmode
= c_s_issock cmode
/= 0
505 s_issock
:: CMode
-> Bool
506 s_issock cmode
= False