[project @ 2001-07-31 12:59:30 by simonmar]
[ghc-base.git] / Foreign / C / Error.hs
1 {-# OPTIONS -fno-implicit-prelude -#include "HsCore.h" #-}
2 -----------------------------------------------------------------------------
3 -- 
4 -- Module      :  Foreign.C.Error
5 -- Copyright   :  (c) The FFI task force 2001
6 -- License     :  BSD-style (see the file libraries/core/LICENSE)
7 -- 
8 -- Maintainer  :  ffi@haskell.org
9 -- Stability   :  provisional
10 -- Portability :  portable
11 --
12 -- $Id: Error.hs,v 1.3 2001/07/31 12:59:30 simonmar Exp $
13 --
14 -- C-specific Marshalling support: Handling of C "errno" error codes
15 --
16 -----------------------------------------------------------------------------
17
18 module Foreign.C.Error (
19
20   -- Haskell representation for "errno" values
21   --
22   Errno(..),            -- instance: Eq
23   eOK, e2BIG, eACCES, eADDRINUSE, eADDRNOTAVAIL, eADV, eAFNOSUPPORT, eAGAIN, 
24   eALREADY, eBADF, eBADMSG, eBADRPC, eBUSY, eCHILD, eCOMM, eCONNABORTED, 
25   eCONNREFUSED, eCONNRESET, eDEADLK, eDESTADDRREQ, eDIRTY, eDOM, eDQUOT, 
26   eEXIST, eFAULT, eFBIG, eFTYPE, eHOSTDOWN, eHOSTUNREACH, eIDRM, eILSEQ, 
27   eINPROGRESS, eINTR, eINVAL, eIO, eISCONN, eISDIR, eLOOP, eMFILE, eMLINK, 
28   eMSGSIZE, eMULTIHOP, eNAMETOOLONG, eNETDOWN, eNETRESET, eNETUNREACH, 
29   eNFILE, eNOBUFS, eNODATA, eNODEV, eNOENT, eNOEXEC, eNOLCK, eNOLINK, 
30   eNOMEM, eNOMSG, eNONET, eNOPROTOOPT, eNOSPC, eNOSR, eNOSTR, eNOSYS, 
31   eNOTBLK, eNOTCONN, eNOTDIR, eNOTEMPTY, eNOTSOCK, eNOTTY, eNXIO, 
32   eOPNOTSUPP, ePERM, ePFNOSUPPORT, ePIPE, ePROCLIM, ePROCUNAVAIL, 
33   ePROGMISMATCH, ePROGUNAVAIL, ePROTO, ePROTONOSUPPORT, ePROTOTYPE, 
34   eRANGE, eREMCHG, eREMOTE, eROFS, eRPCMISMATCH, eRREMOTE, eSHUTDOWN, 
35   eSOCKTNOSUPPORT, eSPIPE, eSRCH, eSRMNT, eSTALE, eTIME, eTIMEDOUT, 
36   eTOOMANYREFS, eTXTBSY, eUSERS, eWOULDBLOCK, eXDEV,
37                         -- :: Errno
38   isValidErrno,         -- :: Errno -> Bool
39
40   -- access to the current thread's "errno" value
41   --
42   getErrno,             -- :: IO Errno
43   resetErrno,           -- :: IO ()
44
45   -- conversion of an "errno" value into IO error
46   --
47   errnoToIOError,       -- :: String       -- location
48                         -- -> Errno        -- errno
49                         -- -> Maybe Handle -- handle
50                         -- -> Maybe String -- filename
51                         -- -> IOError
52
53   -- throw current "errno" value
54   --
55   throwErrno,           -- ::                String               -> IO a
56
57   -- guards for IO operations that may fail
58   --
59   throwErrnoIf,         -- :: (a -> Bool) -> String -> IO a       -> IO a
60   throwErrnoIf_,        -- :: (a -> Bool) -> String -> IO a       -> IO ()
61   throwErrnoIfRetry,    -- :: (a -> Bool) -> String -> IO a       -> IO a
62   throwErrnoIfRetry_,   -- :: (a -> Bool) -> String -> IO a       -> IO ()
63   throwErrnoIfMinus1,   -- :: Num a 
64                         -- =>                String -> IO a       -> IO a
65   throwErrnoIfMinus1_,  -- :: Num a 
66                         -- =>                String -> IO a       -> IO ()
67   throwErrnoIfMinus1Retry,  
68                         -- :: Num a 
69                         -- =>                String -> IO a       -> IO a
70   throwErrnoIfMinus1Retry_,  
71                         -- :: Num a 
72                         -- =>                String -> IO a       -> IO ()
73   throwErrnoIfNull,     -- ::                String -> IO (Ptr a) -> IO (Ptr a)
74   throwErrnoIfNullRetry,-- ::                String -> IO (Ptr a) -> IO (Ptr a)
75
76   throwErrnoIfRetryMayBlock, 
77   throwErrnoIfRetryMayBlock_,
78   throwErrnoIfMinus1RetryMayBlock,
79   throwErrnoIfMinus1RetryMayBlock_,  
80   throwErrnoIfNullRetryMayBlock
81 ) where
82
83
84 -- this is were we get the CCONST_XXX definitions from that configure
85 -- calculated for us
86 --
87 #include "config.h"
88
89 -- system dependent imports
90 -- ------------------------
91
92 -- GHC allows us to get at the guts inside IO errors/exceptions
93 --
94 #if __GLASGOW_HASKELL__
95 import GHC.IOBase (Exception(..), IOException(..), IOErrorType(..))
96 #endif /* __GLASGOW_HASKELL__ */
97
98
99 -- regular imports
100 -- ---------------
101
102 import Foreign.Ptr
103 import Foreign.C.Types
104 import Foreign.C.String
105 import Foreign.Marshal.Error    ( void )
106 import Data.Maybe
107
108 #if __GLASGOW_HASKELL__
109 import GHC.Storable
110 import GHC.IOBase
111 import GHC.Num
112 import GHC.Base
113 #else
114 import System.IO                ( IOError, Handle, ioError )
115 #endif
116
117 -- "errno" type
118 -- ------------
119
120 -- import of C function that gives address of errno
121 -- This function exists because errno is a variable on some systems, but on
122 -- Windows it is a macro for a function...
123 foreign import "ghcErrno" unsafe _errno :: Ptr CInt
124
125 -- Haskell representation for "errno" values
126 --
127 newtype Errno = Errno CInt
128
129 instance Eq Errno where
130   errno1@(Errno no1) == errno2@(Errno no2) 
131     | isValidErrno errno1 && isValidErrno errno2 = no1 == no2
132     | otherwise                                  = False
133
134 -- common "errno" symbols
135 --
136 eOK, e2BIG, eACCES, eADDRINUSE, eADDRNOTAVAIL, eADV, eAFNOSUPPORT, eAGAIN, 
137   eALREADY, eBADF, eBADMSG, eBADRPC, eBUSY, eCHILD, eCOMM, eCONNABORTED, 
138   eCONNREFUSED, eCONNRESET, eDEADLK, eDESTADDRREQ, eDIRTY, eDOM, eDQUOT, 
139   eEXIST, eFAULT, eFBIG, eFTYPE, eHOSTDOWN, eHOSTUNREACH, eIDRM, eILSEQ, 
140   eINPROGRESS, eINTR, eINVAL, eIO, eISCONN, eISDIR, eLOOP, eMFILE, eMLINK, 
141   eMSGSIZE, eMULTIHOP, eNAMETOOLONG, eNETDOWN, eNETRESET, eNETUNREACH, 
142   eNFILE, eNOBUFS, eNODATA, eNODEV, eNOENT, eNOEXEC, eNOLCK, eNOLINK, 
143   eNOMEM, eNOMSG, eNONET, eNOPROTOOPT, eNOSPC, eNOSR, eNOSTR, eNOSYS, 
144   eNOTBLK, eNOTCONN, eNOTDIR, eNOTEMPTY, eNOTSOCK, eNOTTY, eNXIO, 
145   eOPNOTSUPP, ePERM, ePFNOSUPPORT, ePIPE, ePROCLIM, ePROCUNAVAIL, 
146   ePROGMISMATCH, ePROGUNAVAIL, ePROTO, ePROTONOSUPPORT, ePROTOTYPE, 
147   eRANGE, eREMCHG, eREMOTE, eROFS, eRPCMISMATCH, eRREMOTE, eSHUTDOWN, 
148   eSOCKTNOSUPPORT, eSPIPE, eSRCH, eSRMNT, eSTALE, eTIME, eTIMEDOUT, 
149   eTOOMANYREFS, eTXTBSY, eUSERS, eWOULDBLOCK, eXDEV                    :: Errno
150 --
151 -- the CCONST_XXX identifiers are cpp symbols whose value is computed by
152 -- configure 
153 --
154 eOK             = Errno 0
155 e2BIG           = Errno (CCONST_E2BIG)
156 eACCES          = Errno (CCONST_EACCES)
157 eADDRINUSE      = Errno (CCONST_EADDRINUSE)
158 eADDRNOTAVAIL   = Errno (CCONST_EADDRNOTAVAIL)
159 eADV            = Errno (CCONST_EADV)
160 eAFNOSUPPORT    = Errno (CCONST_EAFNOSUPPORT)
161 eAGAIN          = Errno (CCONST_EAGAIN)
162 eALREADY        = Errno (CCONST_EALREADY)
163 eBADF           = Errno (CCONST_EBADF)
164 eBADMSG         = Errno (CCONST_EBADMSG)
165 eBADRPC         = Errno (CCONST_EBADRPC)
166 eBUSY           = Errno (CCONST_EBUSY)
167 eCHILD          = Errno (CCONST_ECHILD)
168 eCOMM           = Errno (CCONST_ECOMM)
169 eCONNABORTED    = Errno (CCONST_ECONNABORTED)
170 eCONNREFUSED    = Errno (CCONST_ECONNREFUSED)
171 eCONNRESET      = Errno (CCONST_ECONNRESET)
172 eDEADLK         = Errno (CCONST_EDEADLK)
173 eDESTADDRREQ    = Errno (CCONST_EDESTADDRREQ)
174 eDIRTY          = Errno (CCONST_EDIRTY)
175 eDOM            = Errno (CCONST_EDOM)
176 eDQUOT          = Errno (CCONST_EDQUOT)
177 eEXIST          = Errno (CCONST_EEXIST)
178 eFAULT          = Errno (CCONST_EFAULT)
179 eFBIG           = Errno (CCONST_EFBIG)
180 eFTYPE          = Errno (CCONST_EFTYPE)
181 eHOSTDOWN       = Errno (CCONST_EHOSTDOWN)
182 eHOSTUNREACH    = Errno (CCONST_EHOSTUNREACH)
183 eIDRM           = Errno (CCONST_EIDRM)
184 eILSEQ          = Errno (CCONST_EILSEQ)
185 eINPROGRESS     = Errno (CCONST_EINPROGRESS)
186 eINTR           = Errno (CCONST_EINTR)
187 eINVAL          = Errno (CCONST_EINVAL)
188 eIO             = Errno (CCONST_EIO)
189 eISCONN         = Errno (CCONST_EISCONN)
190 eISDIR          = Errno (CCONST_EISDIR)
191 eLOOP           = Errno (CCONST_ELOOP)
192 eMFILE          = Errno (CCONST_EMFILE)
193 eMLINK          = Errno (CCONST_EMLINK)
194 eMSGSIZE        = Errno (CCONST_EMSGSIZE)
195 eMULTIHOP       = Errno (CCONST_EMULTIHOP)
196 eNAMETOOLONG    = Errno (CCONST_ENAMETOOLONG)
197 eNETDOWN        = Errno (CCONST_ENETDOWN)
198 eNETRESET       = Errno (CCONST_ENETRESET)
199 eNETUNREACH     = Errno (CCONST_ENETUNREACH)
200 eNFILE          = Errno (CCONST_ENFILE)
201 eNOBUFS         = Errno (CCONST_ENOBUFS)
202 eNODATA         = Errno (CCONST_ENODATA)
203 eNODEV          = Errno (CCONST_ENODEV)
204 eNOENT          = Errno (CCONST_ENOENT)
205 eNOEXEC         = Errno (CCONST_ENOEXEC)
206 eNOLCK          = Errno (CCONST_ENOLCK)
207 eNOLINK         = Errno (CCONST_ENOLINK)
208 eNOMEM          = Errno (CCONST_ENOMEM)
209 eNOMSG          = Errno (CCONST_ENOMSG)
210 eNONET          = Errno (CCONST_ENONET)
211 eNOPROTOOPT     = Errno (CCONST_ENOPROTOOPT)
212 eNOSPC          = Errno (CCONST_ENOSPC)
213 eNOSR           = Errno (CCONST_ENOSR)
214 eNOSTR          = Errno (CCONST_ENOSTR)
215 eNOSYS          = Errno (CCONST_ENOSYS)
216 eNOTBLK         = Errno (CCONST_ENOTBLK)
217 eNOTCONN        = Errno (CCONST_ENOTCONN)
218 eNOTDIR         = Errno (CCONST_ENOTDIR)
219 eNOTEMPTY       = Errno (CCONST_ENOTEMPTY)
220 eNOTSOCK        = Errno (CCONST_ENOTSOCK)
221 eNOTTY          = Errno (CCONST_ENOTTY)
222 eNXIO           = Errno (CCONST_ENXIO)
223 eOPNOTSUPP      = Errno (CCONST_EOPNOTSUPP)
224 ePERM           = Errno (CCONST_EPERM)
225 ePFNOSUPPORT    = Errno (CCONST_EPFNOSUPPORT)
226 ePIPE           = Errno (CCONST_EPIPE)
227 ePROCLIM        = Errno (CCONST_EPROCLIM)
228 ePROCUNAVAIL    = Errno (CCONST_EPROCUNAVAIL)
229 ePROGMISMATCH   = Errno (CCONST_EPROGMISMATCH)
230 ePROGUNAVAIL    = Errno (CCONST_EPROGUNAVAIL)
231 ePROTO          = Errno (CCONST_EPROTO)
232 ePROTONOSUPPORT = Errno (CCONST_EPROTONOSUPPORT)
233 ePROTOTYPE      = Errno (CCONST_EPROTOTYPE)
234 eRANGE          = Errno (CCONST_ERANGE)
235 eREMCHG         = Errno (CCONST_EREMCHG)
236 eREMOTE         = Errno (CCONST_EREMOTE)
237 eROFS           = Errno (CCONST_EROFS)
238 eRPCMISMATCH    = Errno (CCONST_ERPCMISMATCH)
239 eRREMOTE        = Errno (CCONST_ERREMOTE)
240 eSHUTDOWN       = Errno (CCONST_ESHUTDOWN)
241 eSOCKTNOSUPPORT = Errno (CCONST_ESOCKTNOSUPPORT)
242 eSPIPE          = Errno (CCONST_ESPIPE)
243 eSRCH           = Errno (CCONST_ESRCH)
244 eSRMNT          = Errno (CCONST_ESRMNT)
245 eSTALE          = Errno (CCONST_ESTALE)
246 eTIME           = Errno (CCONST_ETIME)
247 eTIMEDOUT       = Errno (CCONST_ETIMEDOUT)
248 eTOOMANYREFS    = Errno (CCONST_ETOOMANYREFS)
249 eTXTBSY         = Errno (CCONST_ETXTBSY)
250 eUSERS          = Errno (CCONST_EUSERS)
251 eWOULDBLOCK     = Errno (CCONST_EWOULDBLOCK)
252 eXDEV           = Errno (CCONST_EXDEV)
253
254 -- checks whether the given errno value is supported on the current
255 -- architecture
256 --
257 isValidErrno               :: Errno -> Bool
258 --
259 -- the configure script sets all invalid "errno"s to -1
260 --
261 isValidErrno (Errno errno)  = errno /= -1
262
263
264 -- access to the current thread's "errno" value
265 -- --------------------------------------------
266
267 -- yield the current thread's "errno" value
268 --
269 getErrno :: IO Errno
270 getErrno  = do e <- peek _errno; return (Errno e)
271
272 -- set the current thread's "errno" value to 0
273 --
274 resetErrno :: IO ()
275 resetErrno  = poke _errno 0
276
277
278 -- throw current "errno" value
279 -- ---------------------------
280
281 -- the common case: throw an IO error based on a textual description
282 -- of the error location and the current thread's "errno" value
283 --
284 throwErrno     :: String -> IO a
285 throwErrno loc  =
286   do
287     errno <- getErrno
288     ioError (errnoToIOError loc errno Nothing Nothing)
289
290
291 -- guards for IO operations that may fail
292 -- --------------------------------------
293
294 -- guard an IO operation and throw an "errno" based exception of the result
295 -- value of the IO operation meets the given predicate
296 --
297 throwErrnoIf            :: (a -> Bool) -> String -> IO a -> IO a
298 throwErrnoIf pred loc f  = 
299   do
300     res <- f
301     if pred res then throwErrno loc else return res
302
303 -- as `throwErrnoIf', but discards the result
304 --
305 throwErrnoIf_            :: (a -> Bool) -> String -> IO a -> IO ()
306 throwErrnoIf_ pred loc f  = void $ throwErrnoIf pred loc f
307
308 -- as `throwErrnoIf', but retries interrupted IO operations (ie, those whose
309 -- flag `EINTR')
310 --
311 throwErrnoIfRetry            :: (a -> Bool) -> String -> IO a -> IO a
312 throwErrnoIfRetry pred loc f  = 
313   do
314     res <- f
315     if pred res
316       then do
317         err <- getErrno
318         if err == eINTR
319           then throwErrnoIfRetry pred loc f
320           else throwErrno loc
321       else return res
322
323 -- as `throwErrnoIfRetry', but checks for operations that would block and
324 -- executes an alternative action in that case.
325
326 throwErrnoIfRetryMayBlock  :: (a -> Bool) -> String -> IO a -> IO b -> IO a
327 throwErrnoIfRetryMayBlock pred loc f on_block  = 
328   do
329     res <- f
330     if pred res
331       then do
332         err <- getErrno
333         if err == eINTR
334           then throwErrnoIfRetryMayBlock pred loc f on_block
335           else if err == eWOULDBLOCK || err == eAGAIN
336                  then do on_block; throwErrnoIfRetryMayBlock pred loc f on_block
337                  else throwErrno loc
338       else return res
339
340 -- as `throwErrnoIfRetry', but discards the result
341 --
342 throwErrnoIfRetry_            :: (a -> Bool) -> String -> IO a -> IO ()
343 throwErrnoIfRetry_ pred loc f  = void $ throwErrnoIfRetry pred loc f
344
345 -- as `throwErrnoIfRetryMayBlock', but discards the result
346 --
347 throwErrnoIfRetryMayBlock_ :: (a -> Bool) -> String -> IO a -> IO b -> IO ()
348 throwErrnoIfRetryMayBlock_ pred loc f on_block 
349   = void $ throwErrnoIfRetryMayBlock pred loc f on_block
350
351 -- throws "errno" if a result of "-1" is returned
352 --
353 throwErrnoIfMinus1 :: Num a => String -> IO a -> IO a
354 throwErrnoIfMinus1  = throwErrnoIf (== -1)
355
356 -- as `throwErrnoIfMinus1', but discards the result
357 --
358 throwErrnoIfMinus1_ :: Num a => String -> IO a -> IO ()
359 throwErrnoIfMinus1_  = throwErrnoIf_ (== -1)
360
361 -- throws "errno" if a result of "-1" is returned, but retries in case of an
362 -- interrupted operation
363 --
364 throwErrnoIfMinus1Retry :: Num a => String -> IO a -> IO a
365 throwErrnoIfMinus1Retry  = throwErrnoIfRetry (== -1)
366
367 -- as `throwErrnoIfMinus1', but discards the result
368 --
369 throwErrnoIfMinus1Retry_ :: Num a => String -> IO a -> IO ()
370 throwErrnoIfMinus1Retry_  = throwErrnoIfRetry_ (== -1)
371
372 -- as throwErrnoIfMinus1Retry, but checks for operations that would block
373 --
374 throwErrnoIfMinus1RetryMayBlock :: Num a => String -> IO a -> IO b -> IO a
375 throwErrnoIfMinus1RetryMayBlock  = throwErrnoIfRetryMayBlock (== -1)
376
377 -- as `throwErrnoIfMinus1RetryMayBlock', but discards the result
378 --
379 throwErrnoIfMinus1RetryMayBlock_ :: Num a => String -> IO a -> IO b -> IO ()
380 throwErrnoIfMinus1RetryMayBlock_  = throwErrnoIfRetryMayBlock_ (== -1)
381
382 -- throws "errno" if a result of a NULL pointer is returned
383 --
384 throwErrnoIfNull :: String -> IO (Ptr a) -> IO (Ptr a)
385 throwErrnoIfNull  = throwErrnoIf (== nullPtr)
386
387 -- throws "errno" if a result of a NULL pointer is returned, but retries in
388 -- case of an interrupted operation
389 --
390 throwErrnoIfNullRetry :: String -> IO (Ptr a) -> IO (Ptr a)
391 throwErrnoIfNullRetry  = throwErrnoIfRetry (== nullPtr)
392
393 -- as throwErrnoIfNullRetry, but checks for operations that would block
394 --
395 throwErrnoIfNullRetryMayBlock :: String -> IO (Ptr a) -> IO b -> IO (Ptr a)
396 throwErrnoIfNullRetryMayBlock  = throwErrnoIfRetryMayBlock (== nullPtr)
397
398 -- conversion of an "errno" value into IO error
399 -- --------------------------------------------
400
401 -- convert a location string, an "errno" value, an optional handle,
402 -- and an optional filename into a matching IO error
403 --
404 errnoToIOError :: String -> Errno -> Maybe Handle -> Maybe String -> IOError
405 errnoToIOError loc errno maybeHdl maybeName = unsafePerformIO $ do
406     str <- strerror errno >>= peekCString
407 #if __GLASGOW_HASKELL__
408     return (IOException (IOError maybeHdl errType loc str maybeName))
409     where
410     errType
411         | errno == eOK             = OtherError
412         | errno == e2BIG           = ResourceExhausted
413         | errno == eACCES          = PermissionDenied
414         | errno == eADDRINUSE      = ResourceBusy
415         | errno == eADDRNOTAVAIL   = UnsupportedOperation
416         | errno == eADV            = OtherError
417         | errno == eAFNOSUPPORT    = UnsupportedOperation
418         | errno == eAGAIN          = ResourceExhausted
419         | errno == eALREADY        = AlreadyExists
420         | errno == eBADF           = OtherError
421         | errno == eBADMSG         = InappropriateType
422         | errno == eBADRPC         = OtherError
423         | errno == eBUSY           = ResourceBusy
424         | errno == eCHILD          = NoSuchThing
425         | errno == eCOMM           = ResourceVanished
426         | errno == eCONNABORTED    = OtherError
427         | errno == eCONNREFUSED    = NoSuchThing
428         | errno == eCONNRESET      = ResourceVanished
429         | errno == eDEADLK         = ResourceBusy
430         | errno == eDESTADDRREQ    = InvalidArgument
431         | errno == eDIRTY          = UnsatisfiedConstraints
432         | errno == eDOM            = InvalidArgument
433         | errno == eDQUOT          = PermissionDenied
434         | errno == eEXIST          = AlreadyExists
435         | errno == eFAULT          = OtherError
436         | errno == eFBIG           = PermissionDenied
437         | errno == eFTYPE          = InappropriateType
438         | errno == eHOSTDOWN       = NoSuchThing
439         | errno == eHOSTUNREACH    = NoSuchThing
440         | errno == eIDRM           = ResourceVanished
441         | errno == eILSEQ          = InvalidArgument
442         | errno == eINPROGRESS     = AlreadyExists
443         | errno == eINTR           = Interrupted
444         | errno == eINVAL          = InvalidArgument
445         | errno == eIO             = HardwareFault
446         | errno == eISCONN         = AlreadyExists
447         | errno == eISDIR          = InappropriateType
448         | errno == eLOOP           = InvalidArgument
449         | errno == eMFILE          = ResourceExhausted
450         | errno == eMLINK          = ResourceExhausted
451         | errno == eMSGSIZE        = ResourceExhausted
452         | errno == eMULTIHOP       = UnsupportedOperation
453         | errno == eNAMETOOLONG    = InvalidArgument
454         | errno == eNETDOWN        = ResourceVanished
455         | errno == eNETRESET       = ResourceVanished
456         | errno == eNETUNREACH     = NoSuchThing
457         | errno == eNFILE          = ResourceExhausted
458         | errno == eNOBUFS         = ResourceExhausted
459         | errno == eNODATA         = NoSuchThing
460         | errno == eNODEV          = NoSuchThing
461         | errno == eNOENT          = NoSuchThing
462         | errno == eNOEXEC         = InvalidArgument
463         | errno == eNOLCK          = ResourceExhausted
464         | errno == eNOLINK         = ResourceVanished
465         | errno == eNOMEM          = ResourceExhausted
466         | errno == eNOMSG          = NoSuchThing
467         | errno == eNONET          = NoSuchThing
468         | errno == eNOPROTOOPT     = UnsupportedOperation
469         | errno == eNOSPC          = ResourceExhausted
470         | errno == eNOSR           = ResourceExhausted
471         | errno == eNOSTR          = InvalidArgument
472         | errno == eNOSYS          = UnsupportedOperation
473         | errno == eNOTBLK         = InvalidArgument
474         | errno == eNOTCONN        = InvalidArgument
475         | errno == eNOTDIR         = InappropriateType
476         | errno == eNOTEMPTY       = UnsatisfiedConstraints
477         | errno == eNOTSOCK        = InvalidArgument
478         | errno == eNOTTY          = IllegalOperation
479         | errno == eNXIO           = NoSuchThing
480         | errno == eOPNOTSUPP      = UnsupportedOperation
481         | errno == ePERM           = PermissionDenied
482         | errno == ePFNOSUPPORT    = UnsupportedOperation
483         | errno == ePIPE           = ResourceVanished
484         | errno == ePROCLIM        = PermissionDenied
485         | errno == ePROCUNAVAIL    = UnsupportedOperation
486         | errno == ePROGMISMATCH   = ProtocolError
487         | errno == ePROGUNAVAIL    = UnsupportedOperation
488         | errno == ePROTO          = ProtocolError
489         | errno == ePROTONOSUPPORT = ProtocolError
490         | errno == ePROTOTYPE      = ProtocolError
491         | errno == eRANGE          = UnsupportedOperation
492         | errno == eREMCHG         = ResourceVanished
493         | errno == eREMOTE         = IllegalOperation
494         | errno == eROFS           = PermissionDenied
495         | errno == eRPCMISMATCH    = ProtocolError
496         | errno == eRREMOTE        = IllegalOperation
497         | errno == eSHUTDOWN       = IllegalOperation
498         | errno == eSOCKTNOSUPPORT = UnsupportedOperation
499         | errno == eSPIPE          = UnsupportedOperation
500         | errno == eSRCH           = NoSuchThing
501         | errno == eSRMNT          = UnsatisfiedConstraints
502         | errno == eSTALE          = ResourceVanished
503         | errno == eTIME           = TimeExpired
504         | errno == eTIMEDOUT       = TimeExpired
505         | errno == eTOOMANYREFS    = ResourceExhausted
506         | errno == eTXTBSY         = ResourceBusy
507         | errno == eUSERS          = ResourceExhausted
508         | errno == eWOULDBLOCK     = OtherError
509         | errno == eXDEV           = UnsupportedOperation
510         | otherwise                = OtherError
511 #else
512     return (userError (loc ++ ": " ++ str ++ maybe "" (": "++) maybeName))
513 #endif
514
515 foreign import unsafe strerror :: Errno -> IO (Ptr CChar)