1 /* $OpenBSD: strerror_r.c,v 1.8 2013/06/01 21:26:18 stsp Exp $ */ 2 /* Public Domain <marc@snafu.org> */ 3 4 #ifdef NLS 5 #define catclose _catclose 6 #define catgets _catgets 7 #define catopen _catopen 8 #include <nl_types.h> 9 #endif 10 11 #define sys_errlist _sys_errlist 12 #define sys_nerr _sys_nerr 13 #define sys_siglist _sys_siglist 14 15 #include <errno.h> 16 #include <limits.h> 17 #include <signal.h> 18 #include <string.h> 19 20 static size_t 21 __digits10(unsigned int num) 22 { 23 size_t i = 0; 24 25 do { 26 num /= 10; 27 i++; 28 } while (num != 0); 29 30 return i; 31 } 32 33 static int 34 __itoa(int num, int sign, char *buffer, size_t start, size_t end) 35 { 36 size_t pos; 37 unsigned int a; 38 int neg; 39 40 if (sign && num < 0) { 41 a = -num; 42 neg = 1; 43 } 44 else { 45 a = num; 46 neg = 0; 47 } 48 49 pos = start + __digits10(a); 50 if (neg) 51 pos++; 52 53 if (pos < end) 54 buffer[pos] = '\0'; 55 else 56 return ERANGE; 57 pos--; 58 do { 59 buffer[pos] = (a % 10) + '0'; 60 pos--; 61 a /= 10; 62 } while (a != 0); 63 if (neg) 64 buffer[pos] = '-'; 65 return 0; 66 } 67 68 69 static int 70 __num2string(int num, int sign, int setid, char *buf, size_t buflen, 71 char * list[], size_t max, const char *def) 72 { 73 int ret = 0; 74 size_t len; 75 76 #ifdef NLS 77 nl_catd catd; 78 catd = catopen("libc", NL_CAT_LOCALE); 79 #endif 80 81 if (0 <= num && num < max) { 82 #ifdef NLS 83 len = strlcpy(buf, catgets(catd, setid, num, list[num]), 84 buflen); 85 #else 86 len = strlcpy(buf, list[num], buflen); 87 #endif 88 if (len >= buflen) 89 ret = ERANGE; 90 } else { 91 #ifdef NLS 92 len = strlcpy(buf, catgets(catd, setid, 0xffff, def), buflen); 93 #else 94 len = strlcpy(buf, def, buflen); 95 #endif 96 if (len >= buflen) 97 ret = ERANGE; 98 else { 99 ret = __itoa(num, sign, buf, len, buflen); 100 if (ret == 0) 101 ret = EINVAL; 102 } 103 } 104 105 #ifdef NLS 106 catclose(catd); 107 #endif 108 109 return ret; 110 } 111 112 #define UPREFIX "Unknown error: " 113 114 int 115 strerror_r(int errnum, char *strerrbuf, size_t buflen) 116 { 117 int save_errno; 118 int ret_errno; 119 120 save_errno = errno; 121 122 ret_errno = __num2string(errnum, 1, 1, strerrbuf, buflen, 123 sys_errlist, sys_nerr, UPREFIX); 124 125 errno = ret_errno ? ret_errno : save_errno; 126 return (ret_errno); 127 } 128 129 #define USIGPREFIX "Unknown signal: " 130 131 char * 132 __strsignal(int num, char *buf) 133 { 134 __num2string(num, 0, 2, buf, NL_TEXTMAX, (char **)sys_siglist, NSIG, 135 USIGPREFIX); 136 return buf; 137 } 138