160405Selan /* Extended support for using errno values.
260405Selan    Copyright (C) 1992 Free Software Foundation, Inc.
360405Selan    Written by Fred Fish.  fnf@cygnus.com
460405Selan 
560405Selan This file is part of the libiberty library.
660405Selan Libiberty is free software; you can redistribute it and/or
760405Selan modify it under the terms of the GNU Library General Public
860405Selan License as published by the Free Software Foundation; either
960405Selan version 2 of the License, or (at your option) any later version.
1060405Selan 
1160405Selan Libiberty is distributed in the hope that it will be useful,
1260405Selan but WITHOUT ANY WARRANTY; without even the implied warranty of
1360405Selan MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1460405Selan Library General Public License for more details.
1560405Selan 
1660405Selan You should have received a copy of the GNU Library General Public
1760405Selan License along with libiberty; see the file COPYING.LIB.  If
1860405Selan not, write to the Free Software Foundation, Inc., 675 Mass Ave,
1960405Selan Cambridge, MA 02139, USA.  */
2060405Selan 
2160405Selan #include "config.h"
2260405Selan 
2360405Selan #include <stdio.h>
2460405Selan #ifndef NEED_sys_errlist
2560405Selan /* Note that errno.h might declare sys_errlist in a way that the
2660405Selan  * compiler might consider incompatible with our later declaration,
2760405Selan  * perhaps by using const attributes.  So we hide the declaration
2860405Selan  * in errno.h (if any) using a macro. */
2960405Selan #define sys_errlist sys_errlist__
3060405Selan #endif
3160405Selan #include <errno.h>
3260405Selan #ifndef NEED_sys_errlist
3360405Selan #undef sys_errlist
3460405Selan #endif
3560405Selan 
3660405Selan /*  Routines imported from standard C runtime libraries. */
3760405Selan 
3860405Selan #ifdef __STDC__
3960405Selan #include <stddef.h>
4060405Selan extern void *malloc (size_t size);				/* 4.10.3.3 */
4160405Selan extern void *memset (void *s, int c, size_t n);			/* 4.11.6.1 */
4260405Selan #else	/* !__STDC__ */
4360405Selan extern char *malloc ();		/* Standard memory allocater */
4460405Selan extern char *memset ();
4560405Selan #endif	/* __STDC__ */
4660405Selan 
4760405Selan #ifndef NULL
4860405Selan #  ifdef __STDC__
4960405Selan #    define NULL (void *) 0
5060405Selan #  else
5160405Selan #    define NULL 0
5260405Selan #  endif
5360405Selan #endif
5460405Selan 
5560405Selan #ifndef MAX
5660405Selan #  define MAX(a,b) ((a) > (b) ? (a) : (b))
5760405Selan #endif
5860405Selan 
5960405Selan /* Translation table for errno values.  See intro(2) in most UNIX systems
6060405Selan    Programmers Reference Manuals.
6160405Selan 
6260405Selan    Note that this table is generally only accessed when it is used at runtime
6360405Selan    to initialize errno name and message tables that are indexed by errno
6460405Selan    value.
6560405Selan 
6660405Selan    Not all of these errnos will exist on all systems.  This table is the only
6760405Selan    thing that should have to be updated as new error numbers are introduced.
6860405Selan    It's sort of ugly, but at least its portable. */
6960405Selan 
7060405Selan static struct error_info
7160405Selan {
7260405Selan   int value;		/* The numeric value from <errno.h> */
7360405Selan   char *name;		/* The equivalent symbolic value */
7460405Selan   char *msg;		/* Short message about this value */
7560405Selan } error_table[] =
7660405Selan {
7760405Selan #if defined (EPERM)
7860405Selan   EPERM, "EPERM", "Not owner",
7960405Selan #endif
8060405Selan #if defined (ENOENT)
8160405Selan   ENOENT, "ENOENT", "No such file or directory",
8260405Selan #endif
8360405Selan #if defined (ESRCH)
8460405Selan   ESRCH, "ESRCH", "No such process",
8560405Selan #endif
8660405Selan #if defined (EINTR)
8760405Selan   EINTR, "EINTR", "Interrupted system call",
8860405Selan #endif
8960405Selan #if defined (EIO)
9060405Selan   EIO, "EIO", "I/O error",
9160405Selan #endif
9260405Selan #if defined (ENXIO)
9360405Selan   ENXIO, "ENXIO", "No such device or address",
9460405Selan #endif
9560405Selan #if defined (E2BIG)
9660405Selan   E2BIG, "E2BIG", "Arg list too long",
9760405Selan #endif
9860405Selan #if defined (ENOEXEC)
9960405Selan   ENOEXEC, "ENOEXEC", "Exec format error",
10060405Selan #endif
10160405Selan #if defined (EBADF)
10260405Selan   EBADF, "EBADF", "Bad file number",
10360405Selan #endif
10460405Selan #if defined (ECHILD)
10560405Selan   ECHILD, "ECHILD", "No child processes",
10660405Selan #endif
10760405Selan #if defined (EWOULDBLOCK)	/* Put before EAGAIN, sometimes aliased */
10860405Selan   EWOULDBLOCK, "EWOULDBLOCK", "Operation would block",
10960405Selan #endif
11060405Selan #if defined (EAGAIN)
11160405Selan   EAGAIN, "EAGAIN", "No more processes",
11260405Selan #endif
11360405Selan #if defined (ENOMEM)
11460405Selan   ENOMEM, "ENOMEM", "Not enough space",
11560405Selan #endif
11660405Selan #if defined (EACCES)
11760405Selan   EACCES, "EACCES", "Permission denied",
11860405Selan #endif
11960405Selan #if defined (EFAULT)
12060405Selan   EFAULT, "EFAULT", "Bad address",
12160405Selan #endif
12260405Selan #if defined (ENOTBLK)
12360405Selan   ENOTBLK, "ENOTBLK", "Block device required",
12460405Selan #endif
12560405Selan #if defined (EBUSY)
12660405Selan   EBUSY, "EBUSY", "Device busy",
12760405Selan #endif
12860405Selan #if defined (EEXIST)
12960405Selan   EEXIST, "EEXIST", "File exists",
13060405Selan #endif
13160405Selan #if defined (EXDEV)
13260405Selan   EXDEV, "EXDEV", "Cross-device link",
13360405Selan #endif
13460405Selan #if defined (ENODEV)
13560405Selan   ENODEV, "ENODEV", "No such device",
13660405Selan #endif
13760405Selan #if defined (ENOTDIR)
13860405Selan   ENOTDIR, "ENOTDIR", "Not a directory",
13960405Selan #endif
14060405Selan #if defined (EISDIR)
14160405Selan   EISDIR, "EISDIR", "Is a directory",
14260405Selan #endif
14360405Selan #if defined (EINVAL)
14460405Selan   EINVAL, "EINVAL", "Invalid argument",
14560405Selan #endif
14660405Selan #if defined (ENFILE)
14760405Selan   ENFILE, "ENFILE", "File table overflow",
14860405Selan #endif
14960405Selan #if defined (EMFILE)
15060405Selan   EMFILE, "EMFILE", "Too many open files",
15160405Selan #endif
15260405Selan #if defined (ENOTTY)
15360405Selan   ENOTTY, "ENOTTY", "Not a typewriter",
15460405Selan #endif
15560405Selan #if defined (ETXTBSY)
15660405Selan   ETXTBSY, "ETXTBSY", "Text file busy",
15760405Selan #endif
15860405Selan #if defined (EFBIG)
15960405Selan   EFBIG, "EFBIG", "File too large",
16060405Selan #endif
16160405Selan #if defined (ENOSPC)
16260405Selan   ENOSPC, "ENOSPC", "No space left on device",
16360405Selan #endif
16460405Selan #if defined (ESPIPE)
16560405Selan   ESPIPE, "ESPIPE", "Illegal seek",
16660405Selan #endif
16760405Selan #if defined (EROFS)
16860405Selan   EROFS, "EROFS", "Read-only file system",
16960405Selan #endif
17060405Selan #if defined (EMLINK)
17160405Selan   EMLINK, "EMLINK", "Too many links",
17260405Selan #endif
17360405Selan #if defined (EPIPE)
17460405Selan   EPIPE, "EPIPE", "Broken pipe",
17560405Selan #endif
17660405Selan #if defined (EDOM)
17760405Selan   EDOM, "EDOM", "Math argument out of domain of func",
17860405Selan #endif
17960405Selan #if defined (ERANGE)
18060405Selan   ERANGE, "ERANGE", "Math result not representable",
18160405Selan #endif
18260405Selan #if defined (ENOMSG)
18360405Selan   ENOMSG, "ENOMSG", "No message of desired type",
18460405Selan #endif
18560405Selan #if defined (EIDRM)
18660405Selan   EIDRM, "EIDRM", "Identifier removed",
18760405Selan #endif
18860405Selan #if defined (ECHRNG)
18960405Selan   ECHRNG, "ECHRNG", "Channel number out of range",
19060405Selan #endif
19160405Selan #if defined (EL2NSYNC)
19260405Selan   EL2NSYNC, "EL2NSYNC", "Level 2 not synchronized",
19360405Selan #endif
19460405Selan #if defined (EL3HLT)
19560405Selan   EL3HLT, "EL3HLT", "Level 3 halted",
19660405Selan #endif
19760405Selan #if defined (EL3RST)
19860405Selan   EL3RST, "EL3RST", "Level 3 reset",
19960405Selan #endif
20060405Selan #if defined (ELNRNG)
20160405Selan   ELNRNG, "ELNRNG", "Link number out of range",
20260405Selan #endif
20360405Selan #if defined (EUNATCH)
20460405Selan   EUNATCH, "EUNATCH", "Protocol driver not attached",
20560405Selan #endif
20660405Selan #if defined (ENOCSI)
20760405Selan   ENOCSI, "ENOCSI", "No CSI structure available",
20860405Selan #endif
20960405Selan #if defined (EL2HLT)
21060405Selan   EL2HLT, "EL2HLT", "Level 2 halted",
21160405Selan #endif
21260405Selan #if defined (EDEADLK)
21360405Selan   EDEADLK, "EDEADLK", "Deadlock condition",
21460405Selan #endif
21560405Selan #if defined (ENOLCK)
21660405Selan   ENOLCK, "ENOLCK", "No record locks available",
21760405Selan #endif
21860405Selan #if defined (EBADE)
21960405Selan   EBADE, "EBADE", "Invalid exchange",
22060405Selan #endif
22160405Selan #if defined (EBADR)
22260405Selan   EBADR, "EBADR", "Invalid request descriptor",
22360405Selan #endif
22460405Selan #if defined (EXFULL)
22560405Selan   EXFULL, "EXFULL", "Exchange full",
22660405Selan #endif
22760405Selan #if defined (ENOANO)
22860405Selan   ENOANO, "ENOANO", "No anode",
22960405Selan #endif
23060405Selan #if defined (EBADRQC)
23160405Selan   EBADRQC, "EBADRQC", "Invalid request code",
23260405Selan #endif
23360405Selan #if defined (EBADSLT)
23460405Selan   EBADSLT, "EBADSLT", "Invalid slot",
23560405Selan #endif
23660405Selan #if defined (EDEADLOCK)
23760405Selan   EDEADLOCK, "EDEADLOCK", "File locking deadlock error",
23860405Selan #endif
23960405Selan #if defined (EBFONT)
24060405Selan   EBFONT, "EBFONT", "Bad font file format",
24160405Selan #endif
24260405Selan #if defined (ENOSTR)
24360405Selan   ENOSTR, "ENOSTR", "Device not a stream",
24460405Selan #endif
24560405Selan #if defined (ENODATA)
24660405Selan   ENODATA, "ENODATA", "No data available",
24760405Selan #endif
24860405Selan #if defined (ETIME)
24960405Selan   ETIME, "ETIME", "Timer expired",
25060405Selan #endif
25160405Selan #if defined (ENOSR)
25260405Selan   ENOSR, "ENOSR", "Out of streams resources",
25360405Selan #endif
25460405Selan #if defined (ENONET)
25560405Selan   ENONET, "ENONET", "Machine is not on the network",
25660405Selan #endif
25760405Selan #if defined (ENOPKG)
25860405Selan   ENOPKG, "ENOPKG", "Package not installed",
25960405Selan #endif
26060405Selan #if defined (EREMOTE)
26160405Selan   EREMOTE, "EREMOTE", "Object is remote",
26260405Selan #endif
26360405Selan #if defined (ENOLINK)
26460405Selan   ENOLINK, "ENOLINK", "Link has been severed",
26560405Selan #endif
26660405Selan #if defined (EADV)
26760405Selan   EADV, "EADV", "Advertise error",
26860405Selan #endif
26960405Selan #if defined (ESRMNT)
27060405Selan   ESRMNT, "ESRMNT", "Srmount error",
27160405Selan #endif
27260405Selan #if defined (ECOMM)
27360405Selan   ECOMM, "ECOMM", "Communication error on send",
27460405Selan #endif
27560405Selan #if defined (EPROTO)
27660405Selan   EPROTO, "EPROTO", "Protocol error",
27760405Selan #endif
27860405Selan #if defined (EMULTIHOP)
27960405Selan   EMULTIHOP, "EMULTIHOP", "Multihop attempted",
28060405Selan #endif
28160405Selan #if defined (EDOTDOT)
28260405Selan   EDOTDOT, "EDOTDOT", "RFS specific error",
28360405Selan #endif
28460405Selan #if defined (EBADMSG)
28560405Selan   EBADMSG, "EBADMSG", "Not a data message",
28660405Selan #endif
28760405Selan #if defined (ENAMETOOLONG)
28860405Selan   ENAMETOOLONG, "ENAMETOOLONG", "File name too long",
28960405Selan #endif
29060405Selan #if defined (EOVERFLOW)
29160405Selan   EOVERFLOW, "EOVERFLOW", "Value too large for defined data type",
29260405Selan #endif
29360405Selan #if defined (ENOTUNIQ)
29460405Selan   ENOTUNIQ, "ENOTUNIQ", "Name not unique on network",
29560405Selan #endif
29660405Selan #if defined (EBADFD)
29760405Selan   EBADFD, "EBADFD", "File descriptor in bad state",
29860405Selan #endif
29960405Selan #if defined (EREMCHG)
30060405Selan   EREMCHG, "EREMCHG", "Remote address changed",
30160405Selan #endif
30260405Selan #if defined (ELIBACC)
30360405Selan   ELIBACC, "ELIBACC", "Can not access a needed shared library",
30460405Selan #endif
30560405Selan #if defined (ELIBBAD)
30660405Selan   ELIBBAD, "ELIBBAD", "Accessing a corrupted shared library",
30760405Selan #endif
30860405Selan #if defined (ELIBSCN)
30960405Selan   ELIBSCN, "ELIBSCN", ".lib section in a.out corrupted",
31060405Selan #endif
31160405Selan #if defined (ELIBMAX)
31260405Selan   ELIBMAX, "ELIBMAX", "Attempting to link in too many shared libraries",
31360405Selan #endif
31460405Selan #if defined (ELIBEXEC)
31560405Selan   ELIBEXEC, "ELIBEXEC", "Cannot exec a shared library directly",
31660405Selan #endif
31760405Selan #if defined (EILSEQ)
31860405Selan   EILSEQ, "EILSEQ", "Illegal byte sequence",
31960405Selan #endif
32060405Selan #if defined (ENOSYS)
32160405Selan   ENOSYS, "ENOSYS", "Operation not applicable",
32260405Selan #endif
32360405Selan #if defined (ELOOP)
32460405Selan   ELOOP, "ELOOP", "Too many symbolic links encountered",
32560405Selan #endif
32660405Selan #if defined (ERESTART)
32760405Selan   ERESTART, "ERESTART", "Interrupted system call should be restarted",
32860405Selan #endif
32960405Selan #if defined (ESTRPIPE)
33060405Selan   ESTRPIPE, "ESTRPIPE", "Streams pipe error",
33160405Selan #endif
33260405Selan #if defined (ENOTEMPTY)
33360405Selan   ENOTEMPTY, "ENOTEMPTY", "Directory not empty",
33460405Selan #endif
33560405Selan #if defined (EUSERS)
33660405Selan   EUSERS, "EUSERS", "Too many users",
33760405Selan #endif
33860405Selan #if defined (ENOTSOCK)
33960405Selan   ENOTSOCK, "ENOTSOCK", "Socket operation on non-socket",
34060405Selan #endif
34160405Selan #if defined (EDESTADDRREQ)
34260405Selan   EDESTADDRREQ, "EDESTADDRREQ", "Destination address required",
34360405Selan #endif
34460405Selan #if defined (EMSGSIZE)
34560405Selan   EMSGSIZE, "EMSGSIZE", "Message too long",
34660405Selan #endif
34760405Selan #if defined (EPROTOTYPE)
34860405Selan   EPROTOTYPE, "EPROTOTYPE", "Protocol wrong type for socket",
34960405Selan #endif
35060405Selan #if defined (ENOPROTOOPT)
35160405Selan   ENOPROTOOPT, "ENOPROTOOPT", "Protocol not available",
35260405Selan #endif
35360405Selan #if defined (EPROTONOSUPPORT)
35460405Selan   EPROTONOSUPPORT, "EPROTONOSUPPORT", "Protocol not supported",
35560405Selan #endif
35660405Selan #if defined (ESOCKTNOSUPPORT)
35760405Selan   ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "Socket type not supported",
35860405Selan #endif
35960405Selan #if defined (EOPNOTSUPP)
36060405Selan   EOPNOTSUPP, "EOPNOTSUPP", "Operation not supported on transport endpoint",
36160405Selan #endif
36260405Selan #if defined (EPFNOSUPPORT)
36360405Selan   EPFNOSUPPORT, "EPFNOSUPPORT", "Protocol family not supported",
36460405Selan #endif
36560405Selan #if defined (EAFNOSUPPORT)
36660405Selan   EAFNOSUPPORT, "EAFNOSUPPORT", "Address family not supported by protocol",
36760405Selan #endif
36860405Selan #if defined (EADDRINUSE)
36960405Selan   EADDRINUSE, "EADDRINUSE", "Address already in use",
37060405Selan #endif
37160405Selan #if defined (EADDRNOTAVAIL)
37260405Selan   EADDRNOTAVAIL, "EADDRNOTAVAIL","Cannot assign requested address",
37360405Selan #endif
37460405Selan #if defined (ENETDOWN)
37560405Selan   ENETDOWN, "ENETDOWN", "Network is down",
37660405Selan #endif
37760405Selan #if defined (ENETUNREACH)
37860405Selan   ENETUNREACH, "ENETUNREACH", "Network is unreachable",
37960405Selan #endif
38060405Selan #if defined (ENETRESET)
38160405Selan   ENETRESET, "ENETRESET", "Network dropped connection because of reset",
38260405Selan #endif
38360405Selan #if defined (ECONNABORTED)
38460405Selan   ECONNABORTED, "ECONNABORTED", "Software caused connection abort",
38560405Selan #endif
38660405Selan #if defined (ECONNRESET)
38760405Selan   ECONNRESET, "ECONNRESET", "Connection reset by peer",
38860405Selan #endif
38960405Selan #if defined (ENOBUFS)
39060405Selan   ENOBUFS, "ENOBUFS", "No buffer space available",
39160405Selan #endif
39260405Selan #if defined (EISCONN)
39360405Selan   EISCONN, "EISCONN", "Transport endpoint is already connected",
39460405Selan #endif
39560405Selan #if defined (ENOTCONN)
39660405Selan   ENOTCONN, "ENOTCONN", "Transport endpoint is not connected",
39760405Selan #endif
39860405Selan #if defined (ESHUTDOWN)
39960405Selan   ESHUTDOWN, "ESHUTDOWN", "Cannot send after transport endpoint shutdown",
40060405Selan #endif
40160405Selan #if defined (ETOOMANYREFS)
40260405Selan   ETOOMANYREFS, "ETOOMANYREFS", "Too many references: cannot splice",
40360405Selan #endif
40460405Selan #if defined (ETIMEDOUT)
40560405Selan   ETIMEDOUT, "ETIMEDOUT", "Connection timed out",
40660405Selan #endif
40760405Selan #if defined (ECONNREFUSED)
40860405Selan   ECONNREFUSED, "ECONNREFUSED", "Connection refused",
40960405Selan #endif
41060405Selan #if defined (EHOSTDOWN)
41160405Selan   EHOSTDOWN, "EHOSTDOWN", "Host is down",
41260405Selan #endif
41360405Selan #if defined (EHOSTUNREACH)
41460405Selan   EHOSTUNREACH, "EHOSTUNREACH", "No route to host",
41560405Selan #endif
41660405Selan #if defined (EALREADY)
41760405Selan   EALREADY, "EALREADY", "Operation already in progress",
41860405Selan #endif
41960405Selan #if defined (EINPROGRESS)
42060405Selan   EINPROGRESS, "EINPROGRESS", "Operation now in progress",
42160405Selan #endif
42260405Selan #if defined (ESTALE)
42360405Selan   ESTALE, "ESTALE", "Stale NFS file handle",
42460405Selan #endif
42560405Selan #if defined (EUCLEAN)
42660405Selan   EUCLEAN, "EUCLEAN", "Structure needs cleaning",
42760405Selan #endif
42860405Selan #if defined (ENOTNAM)
42960405Selan   ENOTNAM, "ENOTNAM", "Not a XENIX named type file",
43060405Selan #endif
43160405Selan #if defined (ENAVAIL)
43260405Selan   ENAVAIL, "ENAVAIL", "No XENIX semaphores available",
43360405Selan #endif
43460405Selan #if defined (EISNAM)
43560405Selan   EISNAM, "EISNAM", "Is a named type file",
43660405Selan #endif
43760405Selan #if defined (EREMOTEIO)
43860405Selan   EREMOTEIO, "EREMOTEIO", "Remote I/O error",
43960405Selan #endif
44060405Selan   0, NULL, NULL
44160405Selan };
44260405Selan 
44360405Selan /* Translation table allocated and initialized at runtime.  Indexed by the
44460405Selan    errno value to find the equivalent symbolic value. */
44560405Selan 
44660405Selan static char **error_names;
44760405Selan static int num_error_names = 0;
44860405Selan 
44960405Selan /* Translation table allocated and initialized at runtime, if it does not
45060405Selan    already exist in the host environment.  Indexed by the errno value to find
45160405Selan    the descriptive string.
45260405Selan 
45360405Selan    We don't export it for use in other modules because even though it has the
45460405Selan    same name, it differs from other implementations in that it is dynamically
45560405Selan    initialized rather than statically initialized. */
45660405Selan 
457*60406Selan #ifdef notdef
45860405Selan #ifdef NEED_sys_errlist
45960405Selan 
46060405Selan static int sys_nerr;
46160405Selan static char **sys_errlist;
46260405Selan 
46360405Selan #else
46460405Selan 
46560405Selan extern int sys_nerr;
46660405Selan extern char *sys_errlist[];
46760405Selan 
46860405Selan #endif
469*60406Selan #endif
47060405Selan 
47160405Selan 
47260405Selan /*
47360405Selan 
47460405Selan NAME
47560405Selan 
47660405Selan 	init_error_tables -- initialize the name and message tables
47760405Selan 
47860405Selan SYNOPSIS
47960405Selan 
48060405Selan 	static void init_error_tables ();
48160405Selan 
48260405Selan DESCRIPTION
48360405Selan 
48460405Selan 	Using the error_table, which is initialized at compile time, generate
48560405Selan 	the error_names and the sys_errlist (if needed) tables, which are
48660405Selan 	indexed at runtime by a specific errno value.
48760405Selan 
48860405Selan BUGS
48960405Selan 
49060405Selan 	The initialization of the tables may fail under low memory conditions,
49160405Selan 	in which case we don't do anything particularly useful, but we don't
49260405Selan 	bomb either.  Who knows, it might succeed at a later point if we free
49360405Selan 	some memory in the meantime.  In any case, the other routines know
49460405Selan 	how to deal with lack of a table after trying to initialize it.  This
49560405Selan 	may or may not be considered to be a bug, that we don't specifically
49660405Selan 	warn about this particular failure mode.
49760405Selan 
49860405Selan */
49960405Selan 
50060405Selan static void
init_error_tables()50160405Selan init_error_tables ()
50260405Selan {
50360405Selan   struct error_info *eip;
50460405Selan   int nbytes;
50560405Selan 
50660405Selan   /* If we haven't already scanned the error_table once to find the maximum
50760405Selan      errno value, then go find it now. */
50860405Selan 
50960405Selan   if (num_error_names == 0)
51060405Selan     {
51160405Selan       for (eip = error_table; eip -> name != NULL; eip++)
51260405Selan 	{
51360405Selan 	  if (eip -> value >= num_error_names)
51460405Selan 	    {
51560405Selan 	      num_error_names = eip -> value + 1;
51660405Selan 	    }
51760405Selan 	}
51860405Selan     }
51960405Selan 
52060405Selan   /* Now attempt to allocate the error_names table, zero it out, and then
52160405Selan      initialize it from the statically initialized error_table. */
52260405Selan 
52360405Selan   if (error_names == NULL)
52460405Selan     {
52560405Selan       nbytes = num_error_names * sizeof (char *);
52660405Selan       if ((error_names = (char **) malloc (nbytes)) != NULL)
52760405Selan 	{
52860405Selan 	  memset (error_names, 0, nbytes);
52960405Selan 	  for (eip = error_table; eip -> name != NULL; eip++)
53060405Selan 	    {
53160405Selan 	      error_names[eip -> value] = eip -> name;
53260405Selan 	    }
53360405Selan 	}
53460405Selan     }
53560405Selan 
53660405Selan #ifdef NEED_sys_errlist
53760405Selan 
53860405Selan   /* Now attempt to allocate the sys_errlist table, zero it out, and then
53960405Selan      initialize it from the statically initialized error_table. */
54060405Selan 
54160405Selan   if (sys_errlist == NULL)
54260405Selan     {
54360405Selan       nbytes = num_error_names * sizeof (char *);
54460405Selan       if ((sys_errlist = (char **) malloc (nbytes)) != NULL)
54560405Selan 	{
54660405Selan 	  memset (sys_errlist, 0, nbytes);
54760405Selan 	  sys_nerr = num_error_names;
54860405Selan 	  for (eip = error_table; eip -> name != NULL; eip++)
54960405Selan 	    {
55060405Selan 	      sys_errlist[eip -> value] = eip -> msg;
55160405Selan 	    }
55260405Selan 	}
55360405Selan     }
55460405Selan 
55560405Selan #endif
55660405Selan 
55760405Selan }
55860405Selan 
55960405Selan /*
56060405Selan 
56160405Selan NAME
56260405Selan 
56360405Selan 	errno_max -- return the max errno value
56460405Selan 
56560405Selan SYNOPSIS
56660405Selan 
56760405Selan 	int errno_max ();
56860405Selan 
56960405Selan DESCRIPTION
57060405Selan 
57160405Selan 	Returns the maximum errno value for which a corresponding symbolic
57260405Selan 	name or message is available.  Note that in the case where
57360405Selan 	we use the sys_errlist supplied by the system, it is possible for
57460405Selan 	there to be more symbolic names than messages, or vice versa.
57560405Selan 	In fact, the manual page for perror(3C) explicitly warns that one
57660405Selan 	should check the size of the table (sys_nerr) before indexing it,
57760405Selan 	since new error codes may be added to the system before they are
57860405Selan 	added to the table.  Thus sys_nerr might be smaller than value
57960405Selan 	implied by the largest errno value defined in <errno.h>.
58060405Selan 
58160405Selan 	We return the maximum value that can be used to obtain a meaningful
58260405Selan 	symbolic name or message.
58360405Selan 
58460405Selan */
58560405Selan 
58660405Selan int
errno_max()58760405Selan errno_max ()
58860405Selan {
58960405Selan   int maxsize;
59060405Selan 
59160405Selan   if (error_names == NULL)
59260405Selan     {
59360405Selan       init_error_tables ();
59460405Selan     }
59560405Selan   maxsize = MAX (sys_nerr, num_error_names);
59660405Selan   return (maxsize - 1);
59760405Selan }
59860405Selan 
59960405Selan #ifdef NEED_strerror
60060405Selan 
60160405Selan /*
60260405Selan 
60360405Selan NAME
60460405Selan 
60560405Selan 	strerror -- map an error number to an error message string
60660405Selan 
60760405Selan SYNOPSIS
60860405Selan 
60960405Selan 	char *strerror (int errnoval)
61060405Selan 
61160405Selan DESCRIPTION
61260405Selan 
61360405Selan 	Maps an errno number to an error message string, the contents of
61460405Selan 	which are implementation defined.  On systems which have the external
61560405Selan 	variables sys_nerr and sys_errlist, these strings will be the same
61660405Selan 	as the ones used by perror().
61760405Selan 
61860405Selan 	If the supplied error number is within the valid range of indices
61960405Selan 	for the sys_errlist, but no message is available for the particular
62060405Selan 	error number, then returns the string "Error NUM", where NUM is the
62160405Selan 	error number.
62260405Selan 
62360405Selan 	If the supplied error number is not a valid index into sys_errlist,
62460405Selan 	returns NULL.
62560405Selan 
62660405Selan 	The returned string is only guaranteed to be valid only until the
62760405Selan 	next call to strerror.
62860405Selan 
62960405Selan */
63060405Selan 
63160405Selan char *
strerror(errnoval)63260405Selan strerror (errnoval)
63360405Selan   int errnoval;
63460405Selan {
63560405Selan   char *msg;
63660405Selan   static char buf[32];
63760405Selan 
63860405Selan #ifdef NEED_sys_errlist
63960405Selan 
64060405Selan   if (error_names == NULL)
64160405Selan     {
64260405Selan       init_error_tables ();
64360405Selan     }
64460405Selan 
64560405Selan #endif
64660405Selan 
64760405Selan   if ((errnoval < 0) || (errnoval >= sys_nerr))
64860405Selan     {
64960405Selan       /* Out of range, just return NULL */
65060405Selan       msg = NULL;
65160405Selan     }
65260405Selan   else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL))
65360405Selan     {
65460405Selan       /* In range, but no sys_errlist or no entry at this index. */
65560405Selan       sprintf (buf, "Error %d", errnoval);
65660405Selan       msg = buf;
65760405Selan     }
65860405Selan   else
65960405Selan     {
66060405Selan       /* In range, and a valid message.  Just return the message. */
66160405Selan       msg = sys_errlist[errnoval];
66260405Selan     }
66360405Selan 
66460405Selan   return (msg);
66560405Selan }
66660405Selan 
66760405Selan #endif	/* NEED_strerror */
66860405Selan 
66960405Selan 
67060405Selan /*
67160405Selan 
67260405Selan NAME
67360405Selan 
67460405Selan 	strerrno -- map an error number to a symbolic name string
67560405Selan 
67660405Selan SYNOPSIS
67760405Selan 
67860405Selan 	char *strerrno (int errnoval)
67960405Selan 
68060405Selan DESCRIPTION
68160405Selan 
68260405Selan 	Given an error number returned from a system call (typically
68360405Selan 	returned in errno), returns a pointer to a string containing the
68460405Selan 	symbolic name of that error number, as found in <errno.h>.
68560405Selan 
68660405Selan 	If the supplied error number is within the valid range of indices
68760405Selan 	for symbolic names, but no name is available for the particular
68860405Selan 	error number, then returns the string "Error NUM", where NUM is
68960405Selan 	the error number.
69060405Selan 
69160405Selan 	If the supplied error number is not within the range of valid
69260405Selan 	indices, then returns NULL.
69360405Selan 
69460405Selan BUGS
69560405Selan 
69660405Selan 	The contents of the location pointed to are only guaranteed to be
69760405Selan 	valid until the next call to strerrno.
69860405Selan 
69960405Selan */
70060405Selan 
70160405Selan char *
strerrno(errnoval)70260405Selan strerrno (errnoval)
70360405Selan   int errnoval;
70460405Selan {
70560405Selan   char *name;
70660405Selan   static char buf[32];
70760405Selan 
70860405Selan   if (error_names == NULL)
70960405Selan     {
71060405Selan       init_error_tables ();
71160405Selan     }
71260405Selan 
71360405Selan   if ((errnoval < 0) || (errnoval >= num_error_names))
71460405Selan     {
71560405Selan       /* Out of range, just return NULL */
71660405Selan       name = NULL;
71760405Selan     }
71860405Selan   else if ((error_names == NULL) || (error_names[errnoval] == NULL))
71960405Selan     {
72060405Selan       /* In range, but no error_names or no entry at this index. */
72160405Selan       sprintf (buf, "Error %d", errnoval);
72260405Selan       name = buf;
72360405Selan     }
72460405Selan   else
72560405Selan     {
72660405Selan       /* In range, and a valid name.  Just return the name. */
72760405Selan       name = error_names[errnoval];
72860405Selan     }
72960405Selan 
73060405Selan   return (name);
73160405Selan }
73260405Selan 
73360405Selan /*
73460405Selan 
73560405Selan NAME
73660405Selan 
73760405Selan 	strtoerrno -- map a symbolic errno name to a numeric value
73860405Selan 
73960405Selan SYNOPSIS
74060405Selan 
74160405Selan 	int strtoerrno (char *name)
74260405Selan 
74360405Selan DESCRIPTION
74460405Selan 
74560405Selan 	Given the symbolic name of a error number, map it to an errno value.
74660405Selan 	If no translation is found, returns 0.
74760405Selan 
74860405Selan */
74960405Selan 
75060405Selan int
strtoerrno(name)75160405Selan strtoerrno (name)
75260405Selan   char *name;
75360405Selan {
75460405Selan   int errnoval = 0;
75560405Selan 
75660405Selan   if (name != NULL)
75760405Selan     {
75860405Selan       if (error_names == NULL)
75960405Selan 	{
76060405Selan 	  init_error_tables ();
76160405Selan 	}
76260405Selan       for (errnoval = 0; errnoval < num_error_names; errnoval++)
76360405Selan 	{
76460405Selan 	  if ((error_names[errnoval] != NULL) &&
76560405Selan 	      (strcmp (name, error_names[errnoval]) == 0))
76660405Selan 	    {
76760405Selan 	      break;
76860405Selan 	    }
76960405Selan 	}
77060405Selan       if (errnoval == num_error_names)
77160405Selan 	{
77260405Selan 	  errnoval = 0;
77360405Selan 	}
77460405Selan     }
77560405Selan   return (errnoval);
77660405Selan }
77760405Selan 
77860405Selan 
77960405Selan /* A simple little main that does nothing but print all the errno translations
78060405Selan    if MAIN is defined and this file is compiled and linked. */
78160405Selan 
78260405Selan #ifdef MAIN
78360405Selan 
main()78460405Selan main ()
78560405Selan {
78660405Selan   int errn;
78760405Selan   int errnmax;
78860405Selan   char *name;
78960405Selan   char *msg;
79060405Selan   char *strerrno ();
79160405Selan   char *strerror ();
79260405Selan 
79360405Selan   errnmax = errno_max ();
79460405Selan   printf ("%d entries in names table.\n", num_error_names);
79560405Selan   printf ("%d entries in messages table.\n", sys_nerr);
79660405Selan   printf ("%d is max useful index.\n", errnmax);
79760405Selan 
79860405Selan   /* Keep printing values until we get to the end of *both* tables, not
79960405Selan      *either* table.  Note that knowing the maximum useful index does *not*
80060405Selan      relieve us of the responsibility of testing the return pointer for
80160405Selan      NULL. */
80260405Selan 
80360405Selan   for (errn = 0; errn <= errnmax; errn++)
80460405Selan     {
80560405Selan       name = strerrno (errn);
80660405Selan       name = (name == NULL) ? "<NULL>" : name;
80760405Selan       msg = strerror (errn);
80860405Selan       msg = (msg == NULL) ? "<NULL>" : msg;
80960405Selan       printf ("%-4d%-18s%s\n", errn, name, msg);
81060405Selan     }
81160405Selan }
81260405Selan 
81360405Selan #endif
814