2 * <errno.h> wrapper functions.
13 Mono_Posix_Stdlib_SetLastError (int error_number
)
18 #ifdef HAVE_STRERROR_R
21 * There are two versions of strerror_r:
22 * - the GNU version: char *strerror_r (int errnum, char *buf, size_t n);
23 * - the XPG version: int strerror_r (int errnum, char *buf, size_t n);
25 * Ideally I could stick with the XPG version, but we need to support
26 * Red Hat 9, which only supports the GNU version.
28 * Furthermore, I do NOT want to export the GNU version in Mono.Posix.dll,
29 * as that's supposed to contain *standard* function definitions (give or
30 * take a few GNU extensions). Portability trumps all.
32 * Consequently, we export the functionality of the XPG version.
33 * Internally, we se the GNU version if _GNU_SOURCE is defined, otherwise
34 * we assume that the XPG version is present.
38 #define mph_min(x,y) ((x) <= (y) ? (x) : (y))
40 /* If you pass an invalid errno value to glibc 2.3.2's strerror_r, you get
41 * back the string "Unknown error" with the error value appended. */
42 static const char mph_unknown
[] = "Unknown error ";
45 * Translate the GNU semantics to the XPG semantics.
47 * From reading the (RH9-using) GLibc 2.3.2 sysdeps/generic/_strerror.c,
48 * we can say the following:
49 * - If errnum is a valid error number, a pointer to a constant string is
50 * returned. Thus, the prototype *lies* (it's not really a char*).
51 * `buf' is unchanged (WTF?).
52 * - If errnum is an *invalid* error number, an error message is copied
53 * into `buf' and `buf' is returned. The error message returned is
54 * "Unknown error %i", where %i is the input errnum.
56 * Meanwhile, XPG always modifies `buf' if there's enough space, and either
57 * returns 0 (success) or -1 (error) with errno = EINVAL (bad errnum) or
58 * ERANGE (`buf' isn't big enough). Also, GLibc 2.3.3 (which has the XPG
59 * version) first checks the validity of errnum first, then does the copy.
61 * Assuming that the GNU implementation doesn't change much (ha!), we can
62 * check for EINVAL by comparing the strerror_r return to `buf', OR by
63 * comparing the return value to "Uknown error". (This assumes that
64 * strerror_r will always only return the input buffer for errors.)
66 * Check for ERANGE by comparing the string length returned by strerror_r to
69 * Then pray that this actually works...
72 Mono_Posix_Syscall_strerror_r (int errnum
, char *buf
, mph_size_t n
)
75 char ebuf
[sizeof(mph_unknown
)];
79 mph_return_if_size_t_overflow (n
);
81 /* first, check for valid errnum */
82 r
= strerror_r (errnum
, ebuf
, sizeof(ebuf
));
86 strncmp (r
, mph_unknown
, mph_min (len
, sizeof(mph_unknown
))) == 0) {
91 /* valid errnum (we hope); is buffer big enough? */
98 strncpy (buf
, r
, len
);
104 #else /* !def _GNU_SOURCE */
107 Mono_Posix_Syscall_strerror_r (int errnum
, char *buf
, mph_size_t n
)
109 mph_return_if_size_t_overflow (n
);
110 return strerror_r (errnum
, buf
, (size_t) n
);
113 #endif /* def _GNU_SOURCE */
115 #endif /* def HAVE_STRERROR_R */