errno.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. * <errno.h> wrapper functions.
  3. */
  4. #include <errno.h>
  5. #include <string.h>
  6. #include "map.h"
  7. #include "mph.h"
  8. #include <stdio.h>
  9. G_BEGIN_DECLS
  10. void
  11. Mono_Posix_Stdlib_SetLastError (int error_number)
  12. {
  13. errno = error_number;
  14. }
  15. #ifdef HAVE_STRERROR_R
  16. /*
  17. * There are two versions of strerror_r:
  18. * - the GNU version: char *strerror_r (int errnum, char *buf, size_t n);
  19. * - the XPG version: int strerror_r (int errnum, char *buf, size_t n);
  20. *
  21. * Ideally I could stick with the XPG version, but we need to support
  22. * Red Hat 9, which only supports the GNU version.
  23. *
  24. * Furthermore, I do NOT want to export the GNU version in Mono.Posix.dll,
  25. * as that's supposed to contain *standard* function definitions (give or
  26. * take a few GNU extensions). Portability trumps all.
  27. *
  28. * Consequently, we export the functionality of the XPG version.
  29. * Internally, we se the GNU version if _GNU_SOURCE is defined, otherwise
  30. * we assume that the XPG version is present.
  31. */
  32. #ifdef _GNU_SOURCE
  33. #define mph_min(x,y) ((x) <= (y) ? (x) : (y))
  34. /* If you pass an invalid errno value to glibc 2.3.2's strerror_r, you get
  35. * back the string "Unknown error" with the error value appended. */
  36. static const char mph_unknown[] = "Unknown error ";
  37. /*
  38. * Translate the GNU semantics to the XPG semantics.
  39. *
  40. * From reading the (RH9-using) GLibc 2.3.2 sysdeps/generic/_strerror.c,
  41. * we can say the following:
  42. * - If errnum is a valid error number, a pointer to a constant string is
  43. * returned. Thus, the prototype *lies* (it's not really a char*).
  44. * `buf' is unchanged (WTF?).
  45. * - If errnum is an *invalid* error number, an error message is copied
  46. * into `buf' and `buf' is returned. The error message returned is
  47. * "Unknown error %i", where %i is the input errnum.
  48. *
  49. * Meanwhile, XPG always modifies `buf' if there's enough space, and either
  50. * returns 0 (success) or -1 (error) with errno = EINVAL (bad errnum) or
  51. * ERANGE (`buf' isn't big enough). Also, GLibc 2.3.3 (which has the XPG
  52. * version) first checks the validity of errnum first, then does the copy.
  53. *
  54. * Assuming that the GNU implementation doesn't change much (ha!), we can
  55. * check for EINVAL by comparing the strerror_r return to `buf', OR by
  56. * comparing the return value to "Uknown error". (This assumes that
  57. * strerror_r will always only return the input buffer for errors.)
  58. *
  59. * Check for ERANGE by comparing the string length returned by strerror_r to
  60. * `n'.
  61. *
  62. * Then pray that this actually works...
  63. */
  64. gint32
  65. Mono_Posix_Syscall_strerror_r (int errnum, char *buf, mph_size_t n)
  66. {
  67. char *r;
  68. char ebuf [sizeof(mph_unknown)];
  69. size_t len;
  70. size_t blen;
  71. mph_return_if_size_t_overflow (n);
  72. /* first, check for valid errnum */
  73. r = strerror_r (errnum, ebuf, sizeof(ebuf));
  74. len = strlen (r);
  75. if (r == ebuf ||
  76. strncmp (r, mph_unknown, mph_min (len, sizeof(mph_unknown))) == 0) {
  77. errno = EINVAL;
  78. return -1;
  79. }
  80. /* valid errnum (we hope); is buffer big enough? */
  81. blen = (size_t) n;
  82. if ((len+1) > blen) {
  83. errno = ERANGE;
  84. return -1;
  85. }
  86. strncpy (buf, r, len);
  87. buf[len] = '\0';
  88. return 0;
  89. }
  90. #else /* !def _GNU_SOURCE */
  91. gint32
  92. Mono_Posix_Syscall_strerror_r (int errnum, char *buf, mph_size_t n)
  93. {
  94. mph_return_if_size_t_overflow (n);
  95. return strerror_r (errnum, buf, (size_t) n);
  96. }
  97. #endif /* def _GNU_SOURCE */
  98. #endif /* def HAVE_STRERROR_R */
  99. G_END_DECLS
  100. /*
  101. * vim: noexpandtab
  102. */