1 /*
2  * Copyright (C) 2002     Manuel Novoa III
3  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
4  *
5  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
6  */
7 
8 /* get rid of REDIRECT */
9 #define strerror_r __hide_strerror_r
10 
11 #include <features.h>
12 #include <errno.h>
13 #include <string.h>
14 #include "_syserrmsg.h"
15 
16 #undef strerror_r
17 
18 #ifdef __UCLIBC_HAS_ERRNO_MESSAGES__
19 
20 extern const char _string_syserrmsgs[] attribute_hidden;
21 
22 #if defined(__alpha__) || defined(__mips__) || defined(__sparc__)
23 
24 static const unsigned char estridx[] = {
25 	0,							/* success is always 0 */
26 	EPERM,
27 	ENOENT,
28 	ESRCH,
29 	EINTR,
30 	EIO,
31 	ENXIO,
32 	E2BIG,
33 	ENOEXEC,
34 	EBADF,
35 	ECHILD,
36 	EAGAIN,
37 	ENOMEM,
38 	EACCES,
39 	EFAULT,
40 	ENOTBLK,
41 	EBUSY,
42 	EEXIST,
43 	EXDEV,
44 	ENODEV,
45 	ENOTDIR,
46 	EISDIR,
47 	EINVAL,
48 	ENFILE,
49 	EMFILE,
50 	ENOTTY,
51 	ETXTBSY,
52 	EFBIG,
53 	ENOSPC,
54 	ESPIPE,
55 	EROFS,
56 	EMLINK,
57 	EPIPE,
58 	EDOM,
59 	ERANGE,
60 	EDEADLK,
61 	ENAMETOOLONG,
62 	ENOLCK,
63 	ENOSYS,
64 	ENOTEMPTY,
65 	ELOOP,
66 	0,
67 	ENOMSG,
68 	EIDRM,
69 	ECHRNG,
70 	EL2NSYNC,
71 	EL3HLT,
72 	EL3RST,
73 	ELNRNG,
74 	EUNATCH,
75 	ENOCSI,
76 	EL2HLT,
77 	EBADE,
78 	EBADR,
79 	EXFULL,
80 	ENOANO,
81 	EBADRQC,
82 	EBADSLT,
83 	0,
84 	EBFONT,
85 	ENOSTR,
86 	ENODATA,
87 	ETIME,
88 	ENOSR,
89 	ENONET,
90 	ENOPKG,
91 	EREMOTE,
92 	ENOLINK,
93 	EADV,
94 	ESRMNT,
95 	ECOMM,
96 	EPROTO,
97 	EMULTIHOP,
98 	EDOTDOT,
99 	EBADMSG,
100 	EOVERFLOW,
101 	ENOTUNIQ,
102 	EBADFD,
103 	EREMCHG,
104 	ELIBACC,
105 	ELIBBAD,
106 	ELIBSCN,
107 	ELIBMAX,
108 	ELIBEXEC,
109 	EILSEQ,
110 	ERESTART,
111 	ESTRPIPE,
112 	EUSERS,
113 	ENOTSOCK,
114 	EDESTADDRREQ,
115 	EMSGSIZE,
116 	EPROTOTYPE,
117 	ENOPROTOOPT,
118 	EPROTONOSUPPORT,
119 	ESOCKTNOSUPPORT,
120 	EOPNOTSUPP,
121 	EPFNOSUPPORT,
122 	EAFNOSUPPORT,
123 	EADDRINUSE,
124 	EADDRNOTAVAIL,
125 	ENETDOWN,
126 	ENETUNREACH,
127 	ENETRESET,
128 	ECONNABORTED,
129 	ECONNRESET,
130 	ENOBUFS,
131 	EISCONN,
132 	ENOTCONN,
133 	ESHUTDOWN,
134 	ETOOMANYREFS,
135 	ETIMEDOUT,
136 	ECONNREFUSED,
137 	EHOSTDOWN,
138 	EHOSTUNREACH,
139 	EALREADY,
140 	EINPROGRESS,
141 	ESTALE,
142 	EUCLEAN,
143 	ENOTNAM,
144 	ENAVAIL,
145 	EISNAM,
146 	EREMOTEIO,
147 #if EDQUOT > 200			/* mips has an outrageous value for this... */
148 	0,
149 #else
150 	EDQUOT,
151 #endif
152 	ENOMEDIUM,
153 	EMEDIUMTYPE,
154 #if EDEADLOCK != EDEADLK
155 	EDEADLOCK,
156 #endif
157 };
158 
159 #endif
160 
__xpg_strerror_r(int errnum,char * strerrbuf,size_t buflen)161 int __xpg_strerror_r(int errnum, char *strerrbuf, size_t buflen)
162 {
163     register char *s;
164     int i, retval;
165     char buf[_STRERROR_BUFSIZE];
166     static const char unknown[] = {
167 		'U', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 'e', 'r', 'r', 'o', 'r', ' '
168     };
169 
170     retval = EINVAL;
171 
172 
173 #ifdef __UCLIBC_HAS_ERRNO_MESSAGES__
174 
175 #if defined(__alpha__) || defined(__mips__) || defined(__sparc__)
176 	/* Need to translate errno to string index. */
177 	for (i = 0 ; i < sizeof(estridx)/sizeof(estridx[0]) ; i++) {
178 		if (estridx[i] == errnum) {
179 			goto GOT_ESTRIDX;
180 		}
181 	}
182 	i = INT_MAX;	/* Failed, but may need to check mips special case. */
183 #if EDQUOT > 200	/* Deal with large EDQUOT value on mips */
184 	if (errnum == EDQUOT)
185 		i = 122;
186 #endif
187  GOT_ESTRIDX:
188 #else
189 	/* No errno to string index translation needed. */
190 	i = errnum;
191 #endif
192 
193     if (((unsigned int) i) < _SYS_NERR) {
194 		/* Trade time for space.  This function should rarely be called
195 		 * so rather than keeping an array of pointers for the different
196 		 * messages, just run through the buffer until we find the
197 		 * correct string. */
198 		for (s = (char *) _string_syserrmsgs ; i ; ++s) {
199 			if (!*s) {
200 				--i;
201 			}
202 		}
203 		if (*s) {		/* Make sure we have an actual message. */
204 			retval = 0;
205 			goto GOT_MESG;
206 		}
207     }
208 
209 #endif /* __UCLIBC_HAS_ERRNO_MESSAGES__ */
210 
211     s = _int10tostr(buf+sizeof(buf)-1, errnum) - sizeof(unknown);
212     memcpy(s, unknown, sizeof(unknown));
213 
214  GOT_MESG:
215     if (!strerrbuf) {		/* SUSv3  */
216 		buflen = 0;
217     }
218     i = strlen(s) + 1;
219     if (i > buflen) {
220 		i = buflen;
221 		retval = ERANGE;
222     }
223 
224     if (i) {
225 		memcpy(strerrbuf, s, i);
226 		strerrbuf[i-1] = 0;	/* In case buf was too small. */
227     }
228 
229     if (retval) {
230 		__set_errno(retval);
231     }
232 
233     return retval;
234 }
235 
236 #else  /* __UCLIBC_HAS_ERRNO_MESSAGES__ */
237 
__xpg_strerror_r(int errnum,char * strerrbuf,size_t buflen)238 int __xpg_strerror_r(int errnum, char *strerrbuf, size_t buflen)
239 {
240     register char *s;
241     int i, retval;
242     char buf[_STRERROR_BUFSIZE];
243     static const char unknown[] = {
244 		'U', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 'e', 'r', 'r', 'o', 'r', ' '
245     };
246 
247     s = _int10tostr(buf+sizeof(buf)-1, errnum) - sizeof(unknown);
248     memcpy(s, unknown, sizeof(unknown));
249 
250     if (!strerrbuf) {		/* SUSv3  */
251 		buflen = 0;
252     }
253 
254     retval = EINVAL;
255 
256 	i = buf + sizeof(buf) - s;
257 
258     if (i > buflen) {
259 		i = buflen;
260 		retval = ERANGE;
261     }
262 
263     if (i) {
264 		memcpy(strerrbuf, s, i);
265 		strerrbuf[i-1] = 0;	/* In case buf was too small. */
266     }
267 
268 	__set_errno(retval);
269 
270     return retval;
271 }
272 
273 #endif /* __UCLIBC_HAS_ERRNO_MESSAGES__ */
274 libc_hidden_def(__xpg_strerror_r)
275 #if defined __USE_XOPEN2K && !defined __USE_GNU
276 strong_alias(__xpg_strerror_r,strerror_r)
277 #endif
278