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