1 | /* Extended support for using errno values. |
2 | Written by Fred Fish. fnf@cygnus.com |
3 | This file is in the public domain. --Per Bothner. */ |
4 | |
5 | #include "config.h" |
6 | |
7 | #ifdef HAVE_SYS_ERRLIST |
8 | /* Note that errno.h (not sure what OS) or stdio.h (BSD 4.4, at least) |
9 | might declare sys_errlist in a way that the compiler might consider |
10 | incompatible with our later declaration, perhaps by using const |
11 | attributes. So we hide the declaration in errno.h (if any) using a |
12 | macro. */ |
13 | #define sys_nerr sys_nerr__ |
14 | #define sys_errlist sys_errlist__ |
15 | #endif |
16 | |
17 | #include "ansidecl.h" |
18 | #include "libiberty.h" |
19 | |
20 | #include <stdio.h> |
21 | #include <errno.h> |
22 | |
23 | #ifdef HAVE_SYS_ERRLIST |
24 | #undef sys_nerr |
25 | #undef sys_errlist |
26 | #endif |
27 | |
28 | /* Routines imported from standard C runtime libraries. */ |
29 | |
30 | #ifdef HAVE_STDLIB_H |
31 | #include <stdlib.h> |
32 | #else |
33 | extern void *malloc (); |
34 | #endif |
35 | |
36 | #ifdef HAVE_STRING_H |
37 | #include <string.h> |
38 | #else |
39 | extern void *memset (); |
40 | #endif |
41 | |
42 | #ifndef MAX |
43 | # define MAX(a,b) ((a) > (b) ? (a) : (b)) |
44 | #endif |
45 | |
46 | static void init_error_tables (void); |
47 | |
48 | /* Translation table for errno values. See intro(2) in most UNIX systems |
49 | Programmers Reference Manuals. |
50 | |
51 | Note that this table is generally only accessed when it is used at runtime |
52 | to initialize errno name and message tables that are indexed by errno |
53 | value. |
54 | |
55 | Not all of these errnos will exist on all systems. This table is the only |
56 | thing that should have to be updated as new error numbers are introduced. |
57 | It's sort of ugly, but at least its portable. */ |
58 | |
59 | struct error_info |
60 | { |
61 | const int value; /* The numeric value from <errno.h> */ |
62 | const char *const name; /* The equivalent symbolic value */ |
63 | #ifndef HAVE_SYS_ERRLIST |
64 | const char *const msg; /* Short message about this value */ |
65 | #endif |
66 | }; |
67 | |
68 | #ifndef HAVE_SYS_ERRLIST |
69 | # define ENTRY(value, name, msg) {value, name, msg} |
70 | #else |
71 | # define ENTRY(value, name, msg) {value, name} |
72 | #endif |
73 | |
74 | static const struct error_info error_table[] = |
75 | { |
76 | #if defined (EPERM) |
77 | ENTRY(EPERM, "EPERM" , "Not owner" ), |
78 | #endif |
79 | #if defined (ENOENT) |
80 | ENTRY(ENOENT, "ENOENT" , "No such file or directory" ), |
81 | #endif |
82 | #if defined (ESRCH) |
83 | ENTRY(ESRCH, "ESRCH" , "No such process" ), |
84 | #endif |
85 | #if defined (EINTR) |
86 | ENTRY(EINTR, "EINTR" , "Interrupted system call" ), |
87 | #endif |
88 | #if defined (EIO) |
89 | ENTRY(EIO, "EIO" , "I/O error" ), |
90 | #endif |
91 | #if defined (ENXIO) |
92 | ENTRY(ENXIO, "ENXIO" , "No such device or address" ), |
93 | #endif |
94 | #if defined (E2BIG) |
95 | ENTRY(E2BIG, "E2BIG" , "Arg list too long" ), |
96 | #endif |
97 | #if defined (ENOEXEC) |
98 | ENTRY(ENOEXEC, "ENOEXEC" , "Exec format error" ), |
99 | #endif |
100 | #if defined (EBADF) |
101 | ENTRY(EBADF, "EBADF" , "Bad file number" ), |
102 | #endif |
103 | #if defined (ECHILD) |
104 | ENTRY(ECHILD, "ECHILD" , "No child processes" ), |
105 | #endif |
106 | #if defined (EWOULDBLOCK) /* Put before EAGAIN, sometimes aliased */ |
107 | ENTRY(EWOULDBLOCK, "EWOULDBLOCK" , "Operation would block" ), |
108 | #endif |
109 | #if defined (EAGAIN) |
110 | ENTRY(EAGAIN, "EAGAIN" , "No more processes" ), |
111 | #endif |
112 | #if defined (ENOMEM) |
113 | ENTRY(ENOMEM, "ENOMEM" , "Not enough space" ), |
114 | #endif |
115 | #if defined (EACCES) |
116 | ENTRY(EACCES, "EACCES" , "Permission denied" ), |
117 | #endif |
118 | #if defined (EFAULT) |
119 | ENTRY(EFAULT, "EFAULT" , "Bad address" ), |
120 | #endif |
121 | #if defined (ENOTBLK) |
122 | ENTRY(ENOTBLK, "ENOTBLK" , "Block device required" ), |
123 | #endif |
124 | #if defined (EBUSY) |
125 | ENTRY(EBUSY, "EBUSY" , "Device busy" ), |
126 | #endif |
127 | #if defined (EEXIST) |
128 | ENTRY(EEXIST, "EEXIST" , "File exists" ), |
129 | #endif |
130 | #if defined (EXDEV) |
131 | ENTRY(EXDEV, "EXDEV" , "Cross-device link" ), |
132 | #endif |
133 | #if defined (ENODEV) |
134 | ENTRY(ENODEV, "ENODEV" , "No such device" ), |
135 | #endif |
136 | #if defined (ENOTDIR) |
137 | ENTRY(ENOTDIR, "ENOTDIR" , "Not a directory" ), |
138 | #endif |
139 | #if defined (EISDIR) |
140 | ENTRY(EISDIR, "EISDIR" , "Is a directory" ), |
141 | #endif |
142 | #if defined (EINVAL) |
143 | ENTRY(EINVAL, "EINVAL" , "Invalid argument" ), |
144 | #endif |
145 | #if defined (ENFILE) |
146 | ENTRY(ENFILE, "ENFILE" , "File table overflow" ), |
147 | #endif |
148 | #if defined (EMFILE) |
149 | ENTRY(EMFILE, "EMFILE" , "Too many open files" ), |
150 | #endif |
151 | #if defined (ENOTTY) |
152 | ENTRY(ENOTTY, "ENOTTY" , "Not a typewriter" ), |
153 | #endif |
154 | #if defined (ETXTBSY) |
155 | ENTRY(ETXTBSY, "ETXTBSY" , "Text file busy" ), |
156 | #endif |
157 | #if defined (EFBIG) |
158 | ENTRY(EFBIG, "EFBIG" , "File too large" ), |
159 | #endif |
160 | #if defined (ENOSPC) |
161 | ENTRY(ENOSPC, "ENOSPC" , "No space left on device" ), |
162 | #endif |
163 | #if defined (ESPIPE) |
164 | ENTRY(ESPIPE, "ESPIPE" , "Illegal seek" ), |
165 | #endif |
166 | #if defined (EROFS) |
167 | ENTRY(EROFS, "EROFS" , "Read-only file system" ), |
168 | #endif |
169 | #if defined (EMLINK) |
170 | ENTRY(EMLINK, "EMLINK" , "Too many links" ), |
171 | #endif |
172 | #if defined (EPIPE) |
173 | ENTRY(EPIPE, "EPIPE" , "Broken pipe" ), |
174 | #endif |
175 | #if defined (EDOM) |
176 | ENTRY(EDOM, "EDOM" , "Math argument out of domain of func" ), |
177 | #endif |
178 | #if defined (ERANGE) |
179 | ENTRY(ERANGE, "ERANGE" , "Math result not representable" ), |
180 | #endif |
181 | #if defined (ENOMSG) |
182 | ENTRY(ENOMSG, "ENOMSG" , "No message of desired type" ), |
183 | #endif |
184 | #if defined (EIDRM) |
185 | ENTRY(EIDRM, "EIDRM" , "Identifier removed" ), |
186 | #endif |
187 | #if defined (ECHRNG) |
188 | ENTRY(ECHRNG, "ECHRNG" , "Channel number out of range" ), |
189 | #endif |
190 | #if defined (EL2NSYNC) |
191 | ENTRY(EL2NSYNC, "EL2NSYNC" , "Level 2 not synchronized" ), |
192 | #endif |
193 | #if defined (EL3HLT) |
194 | ENTRY(EL3HLT, "EL3HLT" , "Level 3 halted" ), |
195 | #endif |
196 | #if defined (EL3RST) |
197 | ENTRY(EL3RST, "EL3RST" , "Level 3 reset" ), |
198 | #endif |
199 | #if defined (ELNRNG) |
200 | ENTRY(ELNRNG, "ELNRNG" , "Link number out of range" ), |
201 | #endif |
202 | #if defined (EUNATCH) |
203 | ENTRY(EUNATCH, "EUNATCH" , "Protocol driver not attached" ), |
204 | #endif |
205 | #if defined (ENOCSI) |
206 | ENTRY(ENOCSI, "ENOCSI" , "No CSI structure available" ), |
207 | #endif |
208 | #if defined (EL2HLT) |
209 | ENTRY(EL2HLT, "EL2HLT" , "Level 2 halted" ), |
210 | #endif |
211 | #if defined (EDEADLK) |
212 | ENTRY(EDEADLK, "EDEADLK" , "Deadlock condition" ), |
213 | #endif |
214 | #if defined (ENOLCK) |
215 | ENTRY(ENOLCK, "ENOLCK" , "No record locks available" ), |
216 | #endif |
217 | #if defined (EBADE) |
218 | ENTRY(EBADE, "EBADE" , "Invalid exchange" ), |
219 | #endif |
220 | #if defined (EBADR) |
221 | ENTRY(EBADR, "EBADR" , "Invalid request descriptor" ), |
222 | #endif |
223 | #if defined (EXFULL) |
224 | ENTRY(EXFULL, "EXFULL" , "Exchange full" ), |
225 | #endif |
226 | #if defined (ENOANO) |
227 | ENTRY(ENOANO, "ENOANO" , "No anode" ), |
228 | #endif |
229 | #if defined (EBADRQC) |
230 | ENTRY(EBADRQC, "EBADRQC" , "Invalid request code" ), |
231 | #endif |
232 | #if defined (EBADSLT) |
233 | ENTRY(EBADSLT, "EBADSLT" , "Invalid slot" ), |
234 | #endif |
235 | #if defined (EDEADLOCK) |
236 | ENTRY(EDEADLOCK, "EDEADLOCK" , "File locking deadlock error" ), |
237 | #endif |
238 | #if defined (EBFONT) |
239 | ENTRY(EBFONT, "EBFONT" , "Bad font file format" ), |
240 | #endif |
241 | #if defined (ENOSTR) |
242 | ENTRY(ENOSTR, "ENOSTR" , "Device not a stream" ), |
243 | #endif |
244 | #if defined (ENODATA) |
245 | ENTRY(ENODATA, "ENODATA" , "No data available" ), |
246 | #endif |
247 | #if defined (ETIME) |
248 | ENTRY(ETIME, "ETIME" , "Timer expired" ), |
249 | #endif |
250 | #if defined (ENOSR) |
251 | ENTRY(ENOSR, "ENOSR" , "Out of streams resources" ), |
252 | #endif |
253 | #if defined (ENONET) |
254 | ENTRY(ENONET, "ENONET" , "Machine is not on the network" ), |
255 | #endif |
256 | #if defined (ENOPKG) |
257 | ENTRY(ENOPKG, "ENOPKG" , "Package not installed" ), |
258 | #endif |
259 | #if defined (EREMOTE) |
260 | ENTRY(EREMOTE, "EREMOTE" , "Object is remote" ), |
261 | #endif |
262 | #if defined (ENOLINK) |
263 | ENTRY(ENOLINK, "ENOLINK" , "Link has been severed" ), |
264 | #endif |
265 | #if defined (EADV) |
266 | ENTRY(EADV, "EADV" , "Advertise error" ), |
267 | #endif |
268 | #if defined (ESRMNT) |
269 | ENTRY(ESRMNT, "ESRMNT" , "Srmount error" ), |
270 | #endif |
271 | #if defined (ECOMM) |
272 | ENTRY(ECOMM, "ECOMM" , "Communication error on send" ), |
273 | #endif |
274 | #if defined (EPROTO) |
275 | ENTRY(EPROTO, "EPROTO" , "Protocol error" ), |
276 | #endif |
277 | #if defined (EMULTIHOP) |
278 | ENTRY(EMULTIHOP, "EMULTIHOP" , "Multihop attempted" ), |
279 | #endif |
280 | #if defined (EDOTDOT) |
281 | ENTRY(EDOTDOT, "EDOTDOT" , "RFS specific error" ), |
282 | #endif |
283 | #if defined (EBADMSG) |
284 | ENTRY(EBADMSG, "EBADMSG" , "Not a data message" ), |
285 | #endif |
286 | #if defined (ENAMETOOLONG) |
287 | ENTRY(ENAMETOOLONG, "ENAMETOOLONG" , "File name too long" ), |
288 | #endif |
289 | #if defined (EOVERFLOW) |
290 | ENTRY(EOVERFLOW, "EOVERFLOW" , "Value too large for defined data type" ), |
291 | #endif |
292 | #if defined (ENOTUNIQ) |
293 | ENTRY(ENOTUNIQ, "ENOTUNIQ" , "Name not unique on network" ), |
294 | #endif |
295 | #if defined (EBADFD) |
296 | ENTRY(EBADFD, "EBADFD" , "File descriptor in bad state" ), |
297 | #endif |
298 | #if defined (EREMCHG) |
299 | ENTRY(EREMCHG, "EREMCHG" , "Remote address changed" ), |
300 | #endif |
301 | #if defined (ELIBACC) |
302 | ENTRY(ELIBACC, "ELIBACC" , "Cannot access a needed shared library" ), |
303 | #endif |
304 | #if defined (ELIBBAD) |
305 | ENTRY(ELIBBAD, "ELIBBAD" , "Accessing a corrupted shared library" ), |
306 | #endif |
307 | #if defined (ELIBSCN) |
308 | ENTRY(ELIBSCN, "ELIBSCN" , ".lib section in a.out corrupted" ), |
309 | #endif |
310 | #if defined (ELIBMAX) |
311 | ENTRY(ELIBMAX, "ELIBMAX" , "Attempting to link in too many shared libraries" ), |
312 | #endif |
313 | #if defined (ELIBEXEC) |
314 | ENTRY(ELIBEXEC, "ELIBEXEC" , "Cannot exec a shared library directly" ), |
315 | #endif |
316 | #if defined (EILSEQ) |
317 | ENTRY(EILSEQ, "EILSEQ" , "Illegal byte sequence" ), |
318 | #endif |
319 | #if defined (ENOSYS) |
320 | ENTRY(ENOSYS, "ENOSYS" , "Operation not applicable" ), |
321 | #endif |
322 | #if defined (ELOOP) |
323 | ENTRY(ELOOP, "ELOOP" , "Too many symbolic links encountered" ), |
324 | #endif |
325 | #if defined (ERESTART) |
326 | ENTRY(ERESTART, "ERESTART" , "Interrupted system call should be restarted" ), |
327 | #endif |
328 | #if defined (ESTRPIPE) |
329 | ENTRY(ESTRPIPE, "ESTRPIPE" , "Streams pipe error" ), |
330 | #endif |
331 | #if defined (ENOTEMPTY) |
332 | ENTRY(ENOTEMPTY, "ENOTEMPTY" , "Directory not empty" ), |
333 | #endif |
334 | #if defined (EUSERS) |
335 | ENTRY(EUSERS, "EUSERS" , "Too many users" ), |
336 | #endif |
337 | #if defined (ENOTSOCK) |
338 | ENTRY(ENOTSOCK, "ENOTSOCK" , "Socket operation on non-socket" ), |
339 | #endif |
340 | #if defined (EDESTADDRREQ) |
341 | ENTRY(EDESTADDRREQ, "EDESTADDRREQ" , "Destination address required" ), |
342 | #endif |
343 | #if defined (EMSGSIZE) |
344 | ENTRY(EMSGSIZE, "EMSGSIZE" , "Message too long" ), |
345 | #endif |
346 | #if defined (EPROTOTYPE) |
347 | ENTRY(EPROTOTYPE, "EPROTOTYPE" , "Protocol wrong type for socket" ), |
348 | #endif |
349 | #if defined (ENOPROTOOPT) |
350 | ENTRY(ENOPROTOOPT, "ENOPROTOOPT" , "Protocol not available" ), |
351 | #endif |
352 | #if defined (EPROTONOSUPPORT) |
353 | ENTRY(EPROTONOSUPPORT, "EPROTONOSUPPORT" , "Protocol not supported" ), |
354 | #endif |
355 | #if defined (ESOCKTNOSUPPORT) |
356 | ENTRY(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT" , "Socket type not supported" ), |
357 | #endif |
358 | #if defined (EOPNOTSUPP) |
359 | ENTRY(EOPNOTSUPP, "EOPNOTSUPP" , "Operation not supported on transport endpoint" ), |
360 | #endif |
361 | #if defined (EPFNOSUPPORT) |
362 | ENTRY(EPFNOSUPPORT, "EPFNOSUPPORT" , "Protocol family not supported" ), |
363 | #endif |
364 | #if defined (EAFNOSUPPORT) |
365 | ENTRY(EAFNOSUPPORT, "EAFNOSUPPORT" , "Address family not supported by protocol" ), |
366 | #endif |
367 | #if defined (EADDRINUSE) |
368 | ENTRY(EADDRINUSE, "EADDRINUSE" , "Address already in use" ), |
369 | #endif |
370 | #if defined (EADDRNOTAVAIL) |
371 | ENTRY(EADDRNOTAVAIL, "EADDRNOTAVAIL" ,"Cannot assign requested address" ), |
372 | #endif |
373 | #if defined (ENETDOWN) |
374 | ENTRY(ENETDOWN, "ENETDOWN" , "Network is down" ), |
375 | #endif |
376 | #if defined (ENETUNREACH) |
377 | ENTRY(ENETUNREACH, "ENETUNREACH" , "Network is unreachable" ), |
378 | #endif |
379 | #if defined (ENETRESET) |
380 | ENTRY(ENETRESET, "ENETRESET" , "Network dropped connection because of reset" ), |
381 | #endif |
382 | #if defined (ECONNABORTED) |
383 | ENTRY(ECONNABORTED, "ECONNABORTED" , "Software caused connection abort" ), |
384 | #endif |
385 | #if defined (ECONNRESET) |
386 | ENTRY(ECONNRESET, "ECONNRESET" , "Connection reset by peer" ), |
387 | #endif |
388 | #if defined (ENOBUFS) |
389 | ENTRY(ENOBUFS, "ENOBUFS" , "No buffer space available" ), |
390 | #endif |
391 | #if defined (EISCONN) |
392 | ENTRY(EISCONN, "EISCONN" , "Transport endpoint is already connected" ), |
393 | #endif |
394 | #if defined (ENOTCONN) |
395 | ENTRY(ENOTCONN, "ENOTCONN" , "Transport endpoint is not connected" ), |
396 | #endif |
397 | #if defined (ESHUTDOWN) |
398 | ENTRY(ESHUTDOWN, "ESHUTDOWN" , "Cannot send after transport endpoint shutdown" ), |
399 | #endif |
400 | #if defined (ETOOMANYREFS) |
401 | ENTRY(ETOOMANYREFS, "ETOOMANYREFS" , "Too many references: cannot splice" ), |
402 | #endif |
403 | #if defined (ETIMEDOUT) |
404 | ENTRY(ETIMEDOUT, "ETIMEDOUT" , "Connection timed out" ), |
405 | #endif |
406 | #if defined (ECONNREFUSED) |
407 | ENTRY(ECONNREFUSED, "ECONNREFUSED" , "Connection refused" ), |
408 | #endif |
409 | #if defined (EHOSTDOWN) |
410 | ENTRY(EHOSTDOWN, "EHOSTDOWN" , "Host is down" ), |
411 | #endif |
412 | #if defined (EHOSTUNREACH) |
413 | ENTRY(EHOSTUNREACH, "EHOSTUNREACH" , "No route to host" ), |
414 | #endif |
415 | #if defined (EALREADY) |
416 | ENTRY(EALREADY, "EALREADY" , "Operation already in progress" ), |
417 | #endif |
418 | #if defined (EINPROGRESS) |
419 | ENTRY(EINPROGRESS, "EINPROGRESS" , "Operation now in progress" ), |
420 | #endif |
421 | #if defined (ESTALE) |
422 | ENTRY(ESTALE, "ESTALE" , "Stale NFS file handle" ), |
423 | #endif |
424 | #if defined (EUCLEAN) |
425 | ENTRY(EUCLEAN, "EUCLEAN" , "Structure needs cleaning" ), |
426 | #endif |
427 | #if defined (ENOTNAM) |
428 | ENTRY(ENOTNAM, "ENOTNAM" , "Not a XENIX named type file" ), |
429 | #endif |
430 | #if defined (ENAVAIL) |
431 | ENTRY(ENAVAIL, "ENAVAIL" , "No XENIX semaphores available" ), |
432 | #endif |
433 | #if defined (EISNAM) |
434 | ENTRY(EISNAM, "EISNAM" , "Is a named type file" ), |
435 | #endif |
436 | #if defined (EREMOTEIO) |
437 | ENTRY(EREMOTEIO, "EREMOTEIO" , "Remote I/O error" ), |
438 | #endif |
439 | ENTRY(0, NULL, NULL) |
440 | }; |
441 | |
442 | #ifdef EVMSERR |
443 | /* This is not in the table, because the numeric value of EVMSERR (32767) |
444 | lies outside the range of sys_errlist[]. */ |
445 | static struct { int value; const char *name, *msg; } |
446 | evmserr = { EVMSERR, "EVMSERR" , "VMS-specific error" }; |
447 | #endif |
448 | |
449 | /* Translation table allocated and initialized at runtime. Indexed by the |
450 | errno value to find the equivalent symbolic value. */ |
451 | |
452 | static const char **error_names; |
453 | static int num_error_names = 0; |
454 | |
455 | /* Translation table allocated and initialized at runtime, if it does not |
456 | already exist in the host environment. Indexed by the errno value to find |
457 | the descriptive string. |
458 | |
459 | We don't export it for use in other modules because even though it has the |
460 | same name, it differs from other implementations in that it is dynamically |
461 | initialized rather than statically initialized. */ |
462 | |
463 | #ifndef HAVE_SYS_ERRLIST |
464 | |
465 | #define sys_nerr sys_nerr__ |
466 | #define sys_errlist sys_errlist__ |
467 | static int sys_nerr; |
468 | static const char **sys_errlist; |
469 | |
470 | #else |
471 | |
472 | |
473 | #ifndef sys_nerr |
474 | extern int sys_nerr; |
475 | #endif |
476 | #ifndef sys_errlist |
477 | extern char *sys_errlist[]; |
478 | #endif |
479 | |
480 | #endif |
481 | |
482 | /* |
483 | |
484 | NAME |
485 | |
486 | init_error_tables -- initialize the name and message tables |
487 | |
488 | SYNOPSIS |
489 | |
490 | static void init_error_tables (); |
491 | |
492 | DESCRIPTION |
493 | |
494 | Using the error_table, which is initialized at compile time, generate |
495 | the error_names and the sys_errlist (if needed) tables, which are |
496 | indexed at runtime by a specific errno value. |
497 | |
498 | BUGS |
499 | |
500 | The initialization of the tables may fail under low memory conditions, |
501 | in which case we don't do anything particularly useful, but we don't |
502 | bomb either. Who knows, it might succeed at a later point if we free |
503 | some memory in the meantime. In any case, the other routines know |
504 | how to deal with lack of a table after trying to initialize it. This |
505 | may or may not be considered to be a bug, that we don't specifically |
506 | warn about this particular failure mode. |
507 | |
508 | */ |
509 | |
510 | static void |
511 | init_error_tables (void) |
512 | { |
513 | const struct error_info *eip; |
514 | int nbytes; |
515 | |
516 | /* If we haven't already scanned the error_table once to find the maximum |
517 | errno value, then go find it now. */ |
518 | |
519 | if (num_error_names == 0) |
520 | { |
521 | for (eip = error_table; eip -> name != NULL; eip++) |
522 | { |
523 | if (eip -> value >= num_error_names) |
524 | { |
525 | num_error_names = eip -> value + 1; |
526 | } |
527 | } |
528 | } |
529 | |
530 | /* Now attempt to allocate the error_names table, zero it out, and then |
531 | initialize it from the statically initialized error_table. */ |
532 | |
533 | if (error_names == NULL) |
534 | { |
535 | nbytes = num_error_names * sizeof (char *); |
536 | if ((error_names = (const char **) malloc (size: nbytes)) != NULL) |
537 | { |
538 | memset (s: error_names, c: 0, n: nbytes); |
539 | for (eip = error_table; eip -> name != NULL; eip++) |
540 | { |
541 | error_names[eip -> value] = eip -> name; |
542 | } |
543 | } |
544 | } |
545 | |
546 | #ifndef HAVE_SYS_ERRLIST |
547 | |
548 | /* Now attempt to allocate the sys_errlist table, zero it out, and then |
549 | initialize it from the statically initialized error_table. */ |
550 | |
551 | if (sys_errlist == NULL) |
552 | { |
553 | nbytes = num_error_names * sizeof (char *); |
554 | if ((sys_errlist = (const char **) malloc (size: nbytes)) != NULL) |
555 | { |
556 | memset (sys_errlist, c: 0, n: nbytes); |
557 | sys_nerr = num_error_names; |
558 | for (eip = error_table; eip -> name != NULL; eip++) |
559 | { |
560 | sys_errlist[eip -> value] = eip -> msg; |
561 | } |
562 | } |
563 | } |
564 | |
565 | #endif |
566 | |
567 | } |
568 | |
569 | /* |
570 | |
571 | |
572 | @deftypefn Extension int errno_max (void) |
573 | |
574 | Returns the maximum @code{errno} value for which a corresponding |
575 | symbolic name or message is available. Note that in the case where we |
576 | use the @code{sys_errlist} supplied by the system, it is possible for |
577 | there to be more symbolic names than messages, or vice versa. In |
578 | fact, the manual page for @code{perror(3C)} explicitly warns that one |
579 | should check the size of the table (@code{sys_nerr}) before indexing |
580 | it, since new error codes may be added to the system before they are |
581 | added to the table. Thus @code{sys_nerr} might be smaller than value |
582 | implied by the largest @code{errno} value defined in @code{<errno.h>}. |
583 | |
584 | We return the maximum value that can be used to obtain a meaningful |
585 | symbolic name or message. |
586 | |
587 | @end deftypefn |
588 | |
589 | */ |
590 | |
591 | int |
592 | errno_max (void) |
593 | { |
594 | int maxsize; |
595 | |
596 | if (error_names == NULL) |
597 | { |
598 | init_error_tables (); |
599 | } |
600 | maxsize = MAX (sys_nerr, num_error_names); |
601 | return (maxsize - 1); |
602 | } |
603 | |
604 | #ifndef HAVE_STRERROR |
605 | |
606 | /* |
607 | |
608 | @deftypefn Supplemental char* strerror (int @var{errnoval}) |
609 | |
610 | Maps an @code{errno} number to an error message string, the contents |
611 | of which are implementation defined. On systems which have the |
612 | external variables @code{sys_nerr} and @code{sys_errlist}, these |
613 | strings will be the same as the ones used by @code{perror}. |
614 | |
615 | If the supplied error number is within the valid range of indices for |
616 | the @code{sys_errlist}, but no message is available for the particular |
617 | error number, then returns the string @samp{Error @var{num}}, where |
618 | @var{num} is the error number. |
619 | |
620 | If the supplied error number is not a valid index into |
621 | @code{sys_errlist}, returns @code{NULL}. |
622 | |
623 | The returned string is only guaranteed to be valid only until the |
624 | next call to @code{strerror}. |
625 | |
626 | @end deftypefn |
627 | |
628 | */ |
629 | |
630 | char * |
631 | strerror (int errnoval) |
632 | { |
633 | const char *msg; |
634 | static char buf[32]; |
635 | |
636 | #ifndef HAVE_SYS_ERRLIST |
637 | |
638 | if (error_names == NULL) |
639 | { |
640 | init_error_tables (); |
641 | } |
642 | |
643 | #endif |
644 | |
645 | if ((errnoval < 0) || (errnoval >= sys_nerr)) |
646 | { |
647 | #ifdef EVMSERR |
648 | if (errnoval == evmserr.value) |
649 | msg = evmserr.msg; |
650 | else |
651 | #endif |
652 | /* Out of range, just return NULL */ |
653 | msg = NULL; |
654 | } |
655 | else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL)) |
656 | { |
657 | /* In range, but no sys_errlist or no entry at this index. */ |
658 | sprintf (buf, "Error %d" , errnoval); |
659 | msg = buf; |
660 | } |
661 | else |
662 | { |
663 | /* In range, and a valid message. Just return the message. */ |
664 | msg = (char *) sys_errlist[errnoval]; |
665 | } |
666 | |
667 | return (msg); |
668 | } |
669 | |
670 | #endif /* ! HAVE_STRERROR */ |
671 | |
672 | |
673 | /* |
674 | |
675 | @deftypefn Replacement {const char*} strerrno (int @var{errnum}) |
676 | |
677 | Given an error number returned from a system call (typically returned |
678 | in @code{errno}), returns a pointer to a string containing the |
679 | symbolic name of that error number, as found in @code{<errno.h>}. |
680 | |
681 | If the supplied error number is within the valid range of indices for |
682 | symbolic names, but no name is available for the particular error |
683 | number, then returns the string @samp{Error @var{num}}, where @var{num} |
684 | is the error number. |
685 | |
686 | If the supplied error number is not within the range of valid |
687 | indices, then returns @code{NULL}. |
688 | |
689 | The contents of the location pointed to are only guaranteed to be |
690 | valid until the next call to @code{strerrno}. |
691 | |
692 | @end deftypefn |
693 | |
694 | */ |
695 | |
696 | const char * |
697 | strerrno (int errnoval) |
698 | { |
699 | const char *name; |
700 | static char buf[32]; |
701 | |
702 | if (error_names == NULL) |
703 | { |
704 | init_error_tables (); |
705 | } |
706 | |
707 | if ((errnoval < 0) || (errnoval >= num_error_names)) |
708 | { |
709 | #ifdef EVMSERR |
710 | if (errnoval == evmserr.value) |
711 | name = evmserr.name; |
712 | else |
713 | #endif |
714 | /* Out of range, just return NULL */ |
715 | name = NULL; |
716 | } |
717 | else if ((error_names == NULL) || (error_names[errnoval] == NULL)) |
718 | { |
719 | /* In range, but no error_names or no entry at this index. */ |
720 | sprintf (s: buf, format: "Error %d" , errnoval); |
721 | name = (const char *) buf; |
722 | } |
723 | else |
724 | { |
725 | /* In range, and a valid name. Just return the name. */ |
726 | name = error_names[errnoval]; |
727 | } |
728 | |
729 | return (name); |
730 | } |
731 | |
732 | /* |
733 | |
734 | @deftypefn Extension int strtoerrno (const char *@var{name}) |
735 | |
736 | Given the symbolic name of a error number (e.g., @code{EACCES}), map it |
737 | to an errno value. If no translation is found, returns 0. |
738 | |
739 | @end deftypefn |
740 | |
741 | */ |
742 | |
743 | int |
744 | strtoerrno (const char *name) |
745 | { |
746 | int errnoval = 0; |
747 | |
748 | if (name != NULL) |
749 | { |
750 | if (error_names == NULL) |
751 | { |
752 | init_error_tables (); |
753 | } |
754 | for (errnoval = 0; errnoval < num_error_names; errnoval++) |
755 | { |
756 | if ((error_names[errnoval] != NULL) && |
757 | (strcmp (s1: name, s2: error_names[errnoval]) == 0)) |
758 | { |
759 | break; |
760 | } |
761 | } |
762 | if (errnoval == num_error_names) |
763 | { |
764 | #ifdef EVMSERR |
765 | if (strcmp (name, evmserr.name) == 0) |
766 | errnoval = evmserr.value; |
767 | else |
768 | #endif |
769 | errnoval = 0; |
770 | } |
771 | } |
772 | return (errnoval); |
773 | } |
774 | |
775 | |
776 | /* A simple little main that does nothing but print all the errno translations |
777 | if MAIN is defined and this file is compiled and linked. */ |
778 | |
779 | #ifdef MAIN |
780 | |
781 | #include <stdio.h> |
782 | |
783 | int |
784 | main (void) |
785 | { |
786 | int errn; |
787 | int errnmax; |
788 | const char *name; |
789 | const char *msg; |
790 | char *strerror (); |
791 | |
792 | errnmax = errno_max (); |
793 | printf ("%d entries in names table.\n" , num_error_names); |
794 | printf ("%d entries in messages table.\n" , sys_nerr); |
795 | printf ("%d is max useful index.\n" , errnmax); |
796 | |
797 | /* Keep printing values until we get to the end of *both* tables, not |
798 | *either* table. Note that knowing the maximum useful index does *not* |
799 | relieve us of the responsibility of testing the return pointer for |
800 | NULL. */ |
801 | |
802 | for (errn = 0; errn <= errnmax; errn++) |
803 | { |
804 | name = strerrno (errn); |
805 | name = (name == NULL) ? "<NULL>" : name; |
806 | msg = strerror (errn); |
807 | msg = (msg == NULL) ? "<NULL>" : msg; |
808 | printf ("%-4d%-18s%s\n" , errn, name, msg); |
809 | } |
810 | |
811 | return 0; |
812 | } |
813 | |
814 | #endif |
815 | |