[project @ 2001-07-03 11:37:49 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.2 2001/07/03 11:37:50 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 --
122 foreign import "ghcErrno" unsafe _errno :: Ptr CInt
123
124 -- Haskell representation for "errno" values
125 --
126 newtype Errno = Errno CInt
127
128 instance Eq Errno where
129   errno1@(Errno no1) == errno2@(Errno no2) 
130     | isValidErrno errno1 && isValidErrno errno2 = no1 == no2
131     | otherwise                                  = False
132
133 -- common "errno" symbols
134 --
135 eOK, e2BIG, eACCES, eADDRINUSE, eADDRNOTAVAIL, eADV, eAFNOSUPPORT, eAGAIN, 
136   eALREADY, eBADF, eBADMSG, eBADRPC, eBUSY, eCHILD, eCOMM, eCONNABORTED, 
137   eCONNREFUSED, eCONNRESET, eDEADLK, eDESTADDRREQ, eDIRTY, eDOM, eDQUOT, 
138   eEXIST, eFAULT, eFBIG, eFTYPE, eHOSTDOWN, eHOSTUNREACH, eIDRM, eILSEQ, 
139   eINPROGRESS, eINTR, eINVAL, eIO, eISCONN, eISDIR, eLOOP, eMFILE, eMLINK, 
140   eMSGSIZE, eMULTIHOP, eNAMETOOLONG, eNETDOWN, eNETRESET, eNETUNREACH, 
141   eNFILE, eNOBUFS, eNODATA, eNODEV, eNOENT, eNOEXEC, eNOLCK, eNOLINK, 
142   eNOMEM, eNOMSG, eNONET, eNOPROTOOPT, eNOSPC, eNOSR, eNOSTR, eNOSYS, 
143   eNOTBLK, eNOTCONN, eNOTDIR, eNOTEMPTY, eNOTSOCK, eNOTTY, eNXIO, 
144   eOPNOTSUPP, ePERM, ePFNOSUPPORT, ePIPE, ePROCLIM, ePROCUNAVAIL, 
145   ePROGMISMATCH, ePROGUNAVAIL, ePROTO, ePROTONOSUPPORT, ePROTOTYPE, 
146   eRANGE, eREMCHG, eREMOTE, eROFS, eRPCMISMATCH, eRREMOTE, eSHUTDOWN, 
147   eSOCKTNOSUPPORT, eSPIPE, eSRCH, eSRMNT, eSTALE, eTIME, eTIMEDOUT, 
148   eTOOMANYREFS, eTXTBSY, eUSERS, eWOULDBLOCK, eXDEV                    :: Errno
149 --
150 -- the CCONST_XXX identifiers are cpp symbols whose value is computed by
151 -- configure 
152 --
153 eOK             = Errno 0
154 e2BIG           = Errno (CCONST_E2BIG)
155 eACCES          = Errno (CCONST_EACCES)
156 eADDRINUSE      = Errno (CCONST_EADDRINUSE)
157 eADDRNOTAVAIL   = Errno (CCONST_EADDRNOTAVAIL)
158 eADV            = Errno (CCONST_EADV)
159 eAFNOSUPPORT    = Errno (CCONST_EAFNOSUPPORT)
160 eAGAIN          = Errno (CCONST_EAGAIN)
161 eALREADY        = Errno (CCONST_EALREADY)
162 eBADF           = Errno (CCONST_EBADF)
163 eBADMSG         = Errno (CCONST_EBADMSG)
164 eBADRPC         = Errno (CCONST_EBADRPC)
165 eBUSY           = Errno (CCONST_EBUSY)
166 eCHILD          = Errno (CCONST_ECHILD)
167 eCOMM           = Errno (CCONST_ECOMM)
168 eCONNABORTED    = Errno (CCONST_ECONNABORTED)
169 eCONNREFUSED    = Errno (CCONST_ECONNREFUSED)
170 eCONNRESET      = Errno (CCONST_ECONNRESET)
171 eDEADLK         = Errno (CCONST_EDEADLK)
172 eDESTADDRREQ    = Errno (CCONST_EDESTADDRREQ)
173 eDIRTY          = Errno (CCONST_EDIRTY)
174 eDOM            = Errno (CCONST_EDOM)
175 eDQUOT          = Errno (CCONST_EDQUOT)
176 eEXIST          = Errno (CCONST_EEXIST)
177 eFAULT          = Errno (CCONST_EFAULT)
178 eFBIG           = Errno (CCONST_EFBIG)
179 eFTYPE          = Errno (CCONST_EFTYPE)
180 eHOSTDOWN       = Errno (CCONST_EHOSTDOWN)
181 eHOSTUNREACH    = Errno (CCONST_EHOSTUNREACH)
182 eIDRM           = Errno (CCONST_EIDRM)
183 eILSEQ          = Errno (CCONST_EILSEQ)
184 eINPROGRESS     = Errno (CCONST_EINPROGRESS)
185 eINTR           = Errno (CCONST_EINTR)
186 eINVAL          = Errno (CCONST_EINVAL)
187 eIO             = Errno (CCONST_EIO)
188 eISCONN         = Errno (CCONST_EISCONN)
189 eISDIR          = Errno (CCONST_EISDIR)
190 eLOOP           = Errno (CCONST_ELOOP)
191 eMFILE          = Errno (CCONST_EMFILE)
192 eMLINK          = Errno (CCONST_EMLINK)
193 eMSGSIZE        = Errno (CCONST_EMSGSIZE)
194 eMULTIHOP       = Errno (CCONST_EMULTIHOP)
195 eNAMETOOLONG    = Errno (CCONST_ENAMETOOLONG)
196 eNETDOWN        = Errno (CCONST_ENETDOWN)
197 eNETRESET       = Errno (CCONST_ENETRESET)
198 eNETUNREACH     = Errno (CCONST_ENETUNREACH)
199 eNFILE          = Errno (CCONST_ENFILE)
200 eNOBUFS         = Errno (CCONST_ENOBUFS)
201 eNODATA         = Errno (CCONST_ENODATA)
202 eNODEV          = Errno (CCONST_ENODEV)
203 eNOENT          = Errno (CCONST_ENOENT)
204 eNOEXEC         = Errno (CCONST_ENOEXEC)
205 eNOLCK          = Errno (CCONST_ENOLCK)
206 eNOLINK         = Errno (CCONST_ENOLINK)
207 eNOMEM          = Errno (CCONST_ENOMEM)
208 eNOMSG          = Errno (CCONST_ENOMSG)
209 eNONET          = Errno (CCONST_ENONET)
210 eNOPROTOOPT     = Errno (CCONST_ENOPROTOOPT)
211 eNOSPC          = Errno (CCONST_ENOSPC)
212 eNOSR           = Errno (CCONST_ENOSR)
213 eNOSTR          = Errno (CCONST_ENOSTR)
214 eNOSYS          = Errno (CCONST_ENOSYS)
215 eNOTBLK         = Errno (CCONST_ENOTBLK)
216 eNOTCONN        = Errno (CCONST_ENOTCONN)
217 eNOTDIR         = Errno (CCONST_ENOTDIR)
218 eNOTEMPTY       = Errno (CCONST_ENOTEMPTY)
219 eNOTSOCK        = Errno (CCONST_ENOTSOCK)
220 eNOTTY          = Errno (CCONST_ENOTTY)
221 eNXIO           = Errno (CCONST_ENXIO)
222 eOPNOTSUPP      = Errno (CCONST_EOPNOTSUPP)
223 ePERM           = Errno (CCONST_EPERM)
224 ePFNOSUPPORT    = Errno (CCONST_EPFNOSUPPORT)
225 ePIPE           = Errno (CCONST_EPIPE)
226 ePROCLIM        = Errno (CCONST_EPROCLIM)
227 ePROCUNAVAIL    = Errno (CCONST_EPROCUNAVAIL)
228 ePROGMISMATCH   = Errno (CCONST_EPROGMISMATCH)
229 ePROGUNAVAIL    = Errno (CCONST_EPROGUNAVAIL)
230 ePROTO          = Errno (CCONST_EPROTO)
231 ePROTONOSUPPORT = Errno (CCONST_EPROTONOSUPPORT)
232 ePROTOTYPE      = Errno (CCONST_EPROTOTYPE)
233 eRANGE          = Errno (CCONST_ERANGE)
234 eREMCHG         = Errno (CCONST_EREMCHG)
235 eREMOTE         = Errno (CCONST_EREMOTE)
236 eROFS           = Errno (CCONST_EROFS)
237 eRPCMISMATCH    = Errno (CCONST_ERPCMISMATCH)
238 eRREMOTE        = Errno (CCONST_ERREMOTE)
239 eSHUTDOWN       = Errno (CCONST_ESHUTDOWN)
240 eSOCKTNOSUPPORT = Errno (CCONST_ESOCKTNOSUPPORT)
241 eSPIPE          = Errno (CCONST_ESPIPE)
242 eSRCH           = Errno (CCONST_ESRCH)
243 eSRMNT          = Errno (CCONST_ESRMNT)
244 eSTALE          = Errno (CCONST_ESTALE)
245 eTIME           = Errno (CCONST_ETIME)
246 eTIMEDOUT       = Errno (CCONST_ETIMEDOUT)
247 eTOOMANYREFS    = Errno (CCONST_ETOOMANYREFS)
248 eTXTBSY         = Errno (CCONST_ETXTBSY)
249 eUSERS          = Errno (CCONST_EUSERS)
250 eWOULDBLOCK     = Errno (CCONST_EWOULDBLOCK)
251 eXDEV           = Errno (CCONST_EXDEV)
252
253 -- checks whether the given errno value is supported on the current
254 -- architecture
255 --
256 isValidErrno               :: Errno -> Bool
257 --
258 -- the configure script sets all invalid "errno"s to -1
259 --
260 isValidErrno (Errno errno)  = errno /= -1
261
262
263 -- access to the current thread's "errno" value
264 -- --------------------------------------------
265
266 -- yield the current thread's "errno" value
267 --
268 getErrno :: IO Errno
269 getErrno  = do e <- peek _errno; return (Errno e)
270
271 -- set the current thread's "errno" value to 0
272 --
273 resetErrno :: IO ()
274 resetErrno  = poke _errno 0
275
276
277 -- throw current "errno" value
278 -- ---------------------------
279
280 -- the common case: throw an IO error based on a textual description
281 -- of the error location and the current thread's "errno" value
282 --
283 throwErrno     :: String -> IO a
284 throwErrno loc  =
285   do
286     errno <- getErrno
287     ioError (errnoToIOError loc errno Nothing Nothing)
288
289
290 -- guards for IO operations that may fail
291 -- --------------------------------------
292
293 -- guard an IO operation and throw an "errno" based exception of the result
294 -- value of the IO operation meets the given predicate
295 --
296 throwErrnoIf            :: (a -> Bool) -> String -> IO a -> IO a
297 throwErrnoIf pred loc f  = 
298   do
299     res <- f
300     if pred res then throwErrno loc else return res
301
302 -- as `throwErrnoIf', but discards the result
303 --
304 throwErrnoIf_            :: (a -> Bool) -> String -> IO a -> IO ()
305 throwErrnoIf_ pred loc f  = void $ throwErrnoIf pred loc f
306
307 -- as `throwErrnoIf', but retries interrupted IO operations (ie, those whose
308 -- flag `EINTR')
309 --
310 throwErrnoIfRetry            :: (a -> Bool) -> String -> IO a -> IO a
311 throwErrnoIfRetry pred loc f  = 
312   do
313     res <- f
314     if pred res
315       then do
316         err <- getErrno
317         if err == eINTR
318           then throwErrnoIfRetry pred loc f
319           else throwErrno loc
320       else return res
321
322 -- as `throwErrnoIfRetry', but checks for operations that would block and
323 -- executes an alternative action in that case.
324
325 throwErrnoIfRetryMayBlock  :: (a -> Bool) -> String -> IO a -> IO b -> IO a
326 throwErrnoIfRetryMayBlock pred loc f on_block  = 
327   do
328     res <- f
329     if pred res
330       then do
331         err <- getErrno
332         if err == eINTR
333           then throwErrnoIfRetryMayBlock pred loc f on_block
334           else if err == eWOULDBLOCK || err == eAGAIN
335                  then do on_block; throwErrnoIfRetryMayBlock pred loc f on_block
336                  else throwErrno loc
337       else return res
338
339 -- as `throwErrnoIfRetry', but discards the result
340 --
341 throwErrnoIfRetry_            :: (a -> Bool) -> String -> IO a -> IO ()
342 throwErrnoIfRetry_ pred loc f  = void $ throwErrnoIfRetry pred loc f
343
344 -- as `throwErrnoIfRetryMayBlock', but discards the result
345 --
346 throwErrnoIfRetryMayBlock_ :: (a -> Bool) -> String -> IO a -> IO b -> IO ()
347 throwErrnoIfRetryMayBlock_ pred loc f on_block 
348   = void $ throwErrnoIfRetryMayBlock pred loc f on_block
349
350 -- throws "errno" if a result of "-1" is returned
351 --
352 throwErrnoIfMinus1 :: Num a => String -> IO a -> IO a
353 throwErrnoIfMinus1  = throwErrnoIf (== -1)
354
355 -- as `throwErrnoIfMinus1', but discards the result
356 --
357 throwErrnoIfMinus1_ :: Num a => String -> IO a -> IO ()
358 throwErrnoIfMinus1_  = throwErrnoIf_ (== -1)
359
360 -- throws "errno" if a result of "-1" is returned, but retries in case of an
361 -- interrupted operation
362 --
363 throwErrnoIfMinus1Retry :: Num a => String -> IO a -> IO a
364 throwErrnoIfMinus1Retry  = throwErrnoIfRetry (== -1)
365
366 -- as `throwErrnoIfMinus1', but discards the result
367 --
368 throwErrnoIfMinus1Retry_ :: Num a => String -> IO a -> IO ()
369 throwErrnoIfMinus1Retry_  = throwErrnoIfRetry_ (== -1)
370
371 -- as throwErrnoIfMinus1Retry, but checks for operations that would block
372 --
373 throwErrnoIfMinus1RetryMayBlock :: Num a => String -> IO a -> IO b -> IO a
374 throwErrnoIfMinus1RetryMayBlock  = throwErrnoIfRetryMayBlock (== -1)
375
376 -- as `throwErrnoIfMinus1RetryMayBlock', but discards the result
377 --
378 throwErrnoIfMinus1RetryMayBlock_ :: Num a => String -> IO a -> IO b -> IO ()
379 throwErrnoIfMinus1RetryMayBlock_  = throwErrnoIfRetryMayBlock_ (== -1)
380
381 -- throws "errno" if a result of a NULL pointer is returned
382 --
383 throwErrnoIfNull :: String -> IO (Ptr a) -> IO (Ptr a)
384 throwErrnoIfNull  = throwErrnoIf (== nullPtr)
385
386 -- throws "errno" if a result of a NULL pointer is returned, but retries in
387 -- case of an interrupted operation
388 --
389 throwErrnoIfNullRetry :: String -> IO (Ptr a) -> IO (Ptr a)
390 throwErrnoIfNullRetry  = throwErrnoIfRetry (== nullPtr)
391
392 -- as throwErrnoIfNullRetry, but checks for operations that would block
393 --
394 throwErrnoIfNullRetryMayBlock :: String -> IO (Ptr a) -> IO b -> IO (Ptr a)
395 throwErrnoIfNullRetryMayBlock  = throwErrnoIfRetryMayBlock (== nullPtr)
396
397 -- conversion of an "errno" value into IO error
398 -- --------------------------------------------
399
400 -- convert a location string, an "errno" value, an optional handle,
401 -- and an optional filename into a matching IO error
402 --
403 errnoToIOError :: String -> Errno -> Maybe Handle -> Maybe String -> IOError
404 errnoToIOError loc errno maybeHdl maybeName = unsafePerformIO $ do
405     str <- strerror errno >>= peekCString
406 #if __GLASGOW_HASKELL__
407     return (IOException (IOError maybeHdl errType loc str maybeName))
408     where
409     errType
410         | errno == eOK             = OtherError
411         | errno == e2BIG           = ResourceExhausted
412         | errno == eACCES          = PermissionDenied
413         | errno == eADDRINUSE      = ResourceBusy
414         | errno == eADDRNOTAVAIL   = UnsupportedOperation
415         | errno == eADV            = OtherError
416         | errno == eAFNOSUPPORT    = UnsupportedOperation
417         | errno == eAGAIN          = ResourceExhausted
418         | errno == eALREADY        = AlreadyExists
419         | errno == eBADF           = OtherError
420         | errno == eBADMSG         = InappropriateType
421         | errno == eBADRPC         = OtherError
422         | errno == eBUSY           = ResourceBusy
423         | errno == eCHILD          = NoSuchThing
424         | errno == eCOMM           = ResourceVanished
425         | errno == eCONNABORTED    = OtherError
426         | errno == eCONNREFUSED    = NoSuchThing
427         | errno == eCONNRESET      = ResourceVanished
428         | errno == eDEADLK         = ResourceBusy
429         | errno == eDESTADDRREQ    = InvalidArgument
430         | errno == eDIRTY          = UnsatisfiedConstraints
431         | errno == eDOM            = InvalidArgument
432         | errno == eDQUOT          = PermissionDenied
433         | errno == eEXIST          = AlreadyExists
434         | errno == eFAULT          = OtherError
435         | errno == eFBIG           = PermissionDenied
436         | errno == eFTYPE          = InappropriateType
437         | errno == eHOSTDOWN       = NoSuchThing
438         | errno == eHOSTUNREACH    = NoSuchThing
439         | errno == eIDRM           = ResourceVanished
440         | errno == eILSEQ          = InvalidArgument
441         | errno == eINPROGRESS     = AlreadyExists
442         | errno == eINTR           = Interrupted
443         | errno == eINVAL          = InvalidArgument
444         | errno == eIO             = HardwareFault
445         | errno == eISCONN         = AlreadyExists
446         | errno == eISDIR          = InappropriateType
447         | errno == eLOOP           = InvalidArgument
448         | errno == eMFILE          = ResourceExhausted
449         | errno == eMLINK          = ResourceExhausted
450         | errno == eMSGSIZE        = ResourceExhausted
451         | errno == eMULTIHOP       = UnsupportedOperation
452         | errno == eNAMETOOLONG    = InvalidArgument
453         | errno == eNETDOWN        = ResourceVanished
454         | errno == eNETRESET       = ResourceVanished
455         | errno == eNETUNREACH     = NoSuchThing
456         | errno == eNFILE          = ResourceExhausted
457         | errno == eNOBUFS         = ResourceExhausted
458         | errno == eNODATA         = NoSuchThing
459         | errno == eNODEV          = NoSuchThing
460         | errno == eNOENT          = NoSuchThing
461         | errno == eNOEXEC         = InvalidArgument
462         | errno == eNOLCK          = ResourceExhausted
463         | errno == eNOLINK         = ResourceVanished
464         | errno == eNOMEM          = ResourceExhausted
465         | errno == eNOMSG          = NoSuchThing
466         | errno == eNONET          = NoSuchThing
467         | errno == eNOPROTOOPT     = UnsupportedOperation
468         | errno == eNOSPC          = ResourceExhausted
469         | errno == eNOSR           = ResourceExhausted
470         | errno == eNOSTR          = InvalidArgument
471         | errno == eNOSYS          = UnsupportedOperation
472         | errno == eNOTBLK         = InvalidArgument
473         | errno == eNOTCONN        = InvalidArgument
474         | errno == eNOTDIR         = InappropriateType
475         | errno == eNOTEMPTY       = UnsatisfiedConstraints
476         | errno == eNOTSOCK        = InvalidArgument
477         | errno == eNOTTY          = IllegalOperation
478         | errno == eNXIO           = NoSuchThing
479         | errno == eOPNOTSUPP      = UnsupportedOperation
480         | errno == ePERM           = PermissionDenied
481         | errno == ePFNOSUPPORT    = UnsupportedOperation
482         | errno == ePIPE           = ResourceVanished
483         | errno == ePROCLIM        = PermissionDenied
484         | errno == ePROCUNAVAIL    = UnsupportedOperation
485         | errno == ePROGMISMATCH   = ProtocolError
486         | errno == ePROGUNAVAIL    = UnsupportedOperation
487         | errno == ePROTO          = ProtocolError
488         | errno == ePROTONOSUPPORT = ProtocolError
489         | errno == ePROTOTYPE      = ProtocolError
490         | errno == eRANGE          = UnsupportedOperation
491         | errno == eREMCHG         = ResourceVanished
492         | errno == eREMOTE         = IllegalOperation
493         | errno == eROFS           = PermissionDenied
494         | errno == eRPCMISMATCH    = ProtocolError
495         | errno == eRREMOTE        = IllegalOperation
496         | errno == eSHUTDOWN       = IllegalOperation
497         | errno == eSOCKTNOSUPPORT = UnsupportedOperation
498         | errno == eSPIPE          = UnsupportedOperation
499         | errno == eSRCH           = NoSuchThing
500         | errno == eSRMNT          = UnsatisfiedConstraints
501         | errno == eSTALE          = ResourceVanished
502         | errno == eTIME           = TimeExpired
503         | errno == eTIMEDOUT       = TimeExpired
504         | errno == eTOOMANYREFS    = ResourceExhausted
505         | errno == eTXTBSY         = ResourceBusy
506         | errno == eUSERS          = ResourceExhausted
507         | errno == eWOULDBLOCK     = OtherError
508         | errno == eXDEV           = UnsupportedOperation
509         | otherwise                = OtherError
510 #else
511     return (userError (loc ++ ": " ++ str ++ maybe "" (": "++) maybeName))
512 #endif
513
514 foreign import unsafe strerror :: Errno -> IO (Ptr CChar)