511 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			511 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* errno.cc: errno-related functions
 | |
| 
 | |
| This file is part of Cygwin.
 | |
| 
 | |
| This software is a copyrighted work licensed under the terms of the
 | |
| Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 | |
| details. */
 | |
| 
 | |
| #define _sys_nerr FOO_sys_nerr
 | |
| #define sys_nerr FOOsys_nerr
 | |
| #define _sys_errlist FOO_sys_errlist
 | |
| #define strerror_r FOO_strerror_r
 | |
| #define __INSIDE_CYGWIN__
 | |
| #include <errno.h>
 | |
| #include <error.h>
 | |
| #include <stdarg.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include "winsup.h"
 | |
| #include "cygtls.h"
 | |
| #include "ntdll.h"
 | |
| #undef _sys_nerr
 | |
| #undef sys_nerr
 | |
| #undef _sys_errlist
 | |
| #undef strerror_r
 | |
| 
 | |
| /* Table to map Windows error codes to Errno values.  */
 | |
| /* FIXME: Doing things this way is a little slow.  It's trivial to change
 | |
|    this into a big case statement if necessary.  Left as is for now. */
 | |
| 
 | |
| #define X(w, e) {ERROR_##w, #w, e}
 | |
| 
 | |
| static const errmap_t errmap[] =
 | |
| {
 | |
|   /* FIXME: Some of these choices are arbitrary! */
 | |
|   X (ACCESS_DENIED,		EACCES),
 | |
|   X (ACTIVE_CONNECTIONS,	EAGAIN),
 | |
|   X (ALREADY_EXISTS,		EEXIST),
 | |
|   X (BAD_DEVICE,		ENODEV),
 | |
|   X (BAD_EXE_FORMAT,		ENOEXEC),
 | |
|   X (BAD_NETPATH,		ENOENT),
 | |
|   X (BAD_NET_NAME,		ENOENT),
 | |
|   X (BAD_NET_RESP,		ENOSYS),
 | |
|   X (BAD_PATHNAME,		ENOENT),
 | |
|   X (BAD_PIPE,			EINVAL),
 | |
|   X (BAD_UNIT,			ENODEV),
 | |
|   X (BAD_USERNAME,		EINVAL),
 | |
|   X (BEGINNING_OF_MEDIA,	EIO),
 | |
|   X (BROKEN_PIPE,		EPIPE),
 | |
|   X (BUSY,			EBUSY),
 | |
|   X (BUS_RESET,			EIO),
 | |
|   X (CALL_NOT_IMPLEMENTED,	ENOSYS),
 | |
|   X (CANCELLED,			EINTR),
 | |
|   X (CANNOT_MAKE,		EPERM),
 | |
|   X (CASE_DIFFERING_NAMES_IN_DIR, EINVAL),
 | |
|   X (CHILD_NOT_COMPLETE,	EBUSY),
 | |
|   X (COMMITMENT_LIMIT,		EAGAIN),
 | |
|   X (CONNECTION_REFUSED,	ECONNREFUSED),
 | |
|   X (CRC,			EIO),
 | |
|   X (DEVICE_DOOR_OPEN,		EIO),
 | |
|   X (DEVICE_IN_USE,		EAGAIN),
 | |
|   X (DEVICE_REQUIRES_CLEANING,	EIO),
 | |
|   X (DEV_NOT_EXIST,		ENOENT),
 | |
|   X (DIRECTORY,			ENOTDIR),
 | |
|   X (DIR_NOT_EMPTY,		ENOTEMPTY),
 | |
|   X (DISK_CORRUPT,		EIO),
 | |
|   X (DISK_FULL,			ENOSPC),
 | |
|   X (DS_GENERIC_ERROR,		EIO),
 | |
|   X (DUP_NAME,			ENOTUNIQ),
 | |
|   X (EAS_DIDNT_FIT,		ENOSPC),
 | |
|   X (EAS_NOT_SUPPORTED,		ENOTSUP),
 | |
|   X (EA_LIST_INCONSISTENT,	EINVAL),
 | |
|   X (EA_TABLE_FULL,		ENOSPC),
 | |
|   X (END_OF_MEDIA,		ENOSPC),
 | |
|   X (EOM_OVERFLOW,		EIO),
 | |
|   X (EXE_MACHINE_TYPE_MISMATCH,	ENOEXEC),
 | |
|   X (EXE_MARKED_INVALID,	ENOEXEC),
 | |
|   X (FILEMARK_DETECTED,		EIO),
 | |
|   X (FILENAME_EXCED_RANGE,	ENAMETOOLONG),
 | |
|   X (FILE_CORRUPT,		EEXIST),
 | |
|   X (FILE_EXISTS,		EEXIST),
 | |
|   X (FILE_INVALID,		ENXIO),
 | |
|   X (FILE_NOT_FOUND,		ENOENT),
 | |
|   X (HANDLE_DISK_FULL,		ENOSPC),
 | |
|   X (HANDLE_EOF,		ENODATA),
 | |
|   X (INVALID_ADDRESS,		EINVAL),
 | |
|   X (INVALID_AT_INTERRUPT_TIME,	EINTR),
 | |
|   X (INVALID_BLOCK_LENGTH,	EIO),
 | |
|   X (INVALID_DATA,		EINVAL),
 | |
|   X (INVALID_DRIVE,		ENODEV),
 | |
|   X (INVALID_EA_NAME,		EINVAL),
 | |
|   X (INVALID_EXE_SIGNATURE,	ENOEXEC),
 | |
|   X (INVALID_FUNCTION,		EBADRQC),
 | |
|   X (INVALID_HANDLE,		EBADF),
 | |
|   X (INVALID_NAME,		ENOENT),
 | |
|   X (INVALID_PARAMETER,		EINVAL),
 | |
|   X (INVALID_SIGNAL_NUMBER,	EINVAL),
 | |
|   X (IOPL_NOT_ENABLED,		ENOEXEC),
 | |
|   X (IO_DEVICE,			EIO),
 | |
|   X (IO_INCOMPLETE,		EAGAIN),
 | |
|   X (IO_PENDING,		EAGAIN),
 | |
|   X (LOCK_VIOLATION,		EBUSY),
 | |
|   X (MAX_THRDS_REACHED,		EAGAIN),
 | |
|   X (META_EXPANSION_TOO_LONG,	EINVAL),
 | |
|   X (MOD_NOT_FOUND,		ENOENT),
 | |
|   X (MORE_DATA,			EMSGSIZE),
 | |
|   X (NEGATIVE_SEEK,		EINVAL),
 | |
|   X (NETNAME_DELETED,		ENOENT),
 | |
|   X (NOACCESS,			EFAULT),
 | |
|   X (NONE_MAPPED,		EINVAL),
 | |
|   X (NONPAGED_SYSTEM_RESOURCES,	EAGAIN),
 | |
|   X (NOT_CONNECTED,		ENOLINK),
 | |
|   X (NOT_ENOUGH_MEMORY,		ENOMEM),
 | |
|   X (NOT_ENOUGH_QUOTA,		EIO),
 | |
|   X (NOT_OWNER,			EPERM),
 | |
|   X (NOT_READY,			ENOMEDIUM),
 | |
|   X (NOT_SAME_DEVICE,		EXDEV),
 | |
|   X (NOT_SUPPORTED,		ENOSYS),
 | |
|   X (NO_DATA,			EPIPE),
 | |
|   X (NO_DATA_DETECTED,		EIO),
 | |
|   X (NO_MEDIA_IN_DRIVE,		ENOMEDIUM),
 | |
|   X (NO_MORE_FILES,		ENMFILE),
 | |
|   X (NO_MORE_ITEMS,		ENMFILE),
 | |
|   X (NO_MORE_SEARCH_HANDLES,	ENFILE),
 | |
|   X (NO_PROC_SLOTS,		EAGAIN),
 | |
|   X (NO_SIGNAL_SENT,		EIO),
 | |
|   X (NO_SYSTEM_RESOURCES,	EFBIG),
 | |
|   X (NO_TOKEN,			EINVAL),
 | |
|   X (OPEN_FAILED,		EIO),
 | |
|   X (OPEN_FILES,		EAGAIN),
 | |
|   X (OUTOFMEMORY,		ENOMEM),
 | |
|   X (PAGED_SYSTEM_RESOURCES,	EAGAIN),
 | |
|   X (PAGEFILE_QUOTA,		EAGAIN),
 | |
|   X (PATH_NOT_FOUND,		ENOENT),
 | |
|   X (PIPE_BUSY,			EBUSY),
 | |
|   X (PIPE_CONNECTED,		EBUSY),
 | |
|   X (PIPE_LISTENING,		ECOMM),
 | |
|   X (PIPE_NOT_CONNECTED,	ECOMM),
 | |
|   X (POSSIBLE_DEADLOCK,		EDEADLOCK),
 | |
|   X (PRIVILEGE_NOT_HELD,	EPERM),
 | |
|   X (PROCESS_ABORTED,		EFAULT),
 | |
|   X (PROC_NOT_FOUND,		ESRCH),
 | |
|   X (REM_NOT_LIST,		ENONET),
 | |
|   X (SECTOR_NOT_FOUND,		EINVAL),
 | |
|   X (SEEK,			EINVAL),
 | |
|   X (SERVICE_REQUEST_TIMEOUT,	EBUSY),
 | |
|   X (SETMARK_DETECTED,		EIO),
 | |
|   X (SHARING_BUFFER_EXCEEDED,	ENOLCK),
 | |
|   X (SHARING_VIOLATION,		EBUSY),
 | |
|   X (SIGNAL_PENDING,		EBUSY),
 | |
|   X (SIGNAL_REFUSED,		EIO),
 | |
|   X (SXS_CANT_GEN_ACTCTX,	ELIBBAD),
 | |
|   X (THREAD_1_INACTIVE,		EINVAL),
 | |
|   X (TIMEOUT,			EBUSY),
 | |
|   X (TOO_MANY_LINKS,		EMLINK),
 | |
|   X (TOO_MANY_OPEN_FILES,	EMFILE),
 | |
|   X (UNEXP_NET_ERR,		EIO),
 | |
|   X (WAIT_NO_CHILDREN,		ECHILD),
 | |
|   X (WORKING_SET_QUOTA,		EAGAIN),
 | |
|   X (WRITE_PROTECT,		EROFS),
 | |
|   { 0, NULL, 0}
 | |
| };
 | |
| 
 | |
| extern "C" {
 | |
| const char *_sys_errlist[] =
 | |
| {
 | |
| /* NOERROR 0 */		  "No error",
 | |
| /* EPERM 1 */		  "Operation not permitted",
 | |
| /* ENOENT 2 */		  "No such file or directory",
 | |
| /* ESRCH 3 */		  "No such process",
 | |
| /* EINTR 4 */		  "Interrupted system call",
 | |
| /* EIO 5 */		  "Input/output error",
 | |
| /* ENXIO 6 */		  "No such device or address",
 | |
| /* E2BIG 7 */		  "Argument list too long",
 | |
| /* ENOEXEC 8 */		  "Exec format error",
 | |
| /* EBADF 9 */		  "Bad file descriptor",
 | |
| /* ECHILD 10 */		  "No child processes",
 | |
| /* EAGAIN 11 */		  "Resource temporarily unavailable",
 | |
| /* ENOMEM 12 */		  "Cannot allocate memory",
 | |
| /* EACCES 13 */		  "Permission denied",
 | |
| /* EFAULT 14 */		  "Bad address",
 | |
| /* ENOTBLK 15 */	  "Block device required",
 | |
| /* EBUSY 16 */		  "Device or resource busy",
 | |
| /* EEXIST 17 */		  "File exists",
 | |
| /* EXDEV 18 */		  "Invalid cross-device link",
 | |
| /* ENODEV 19 */		  "No such device",
 | |
| /* ENOTDIR 20 */	  "Not a directory",
 | |
| /* EISDIR 21 */		  "Is a directory",
 | |
| /* EINVAL 22 */		  "Invalid argument",
 | |
| /* ENFILE 23 */		  "Too many open files in system",
 | |
| /* EMFILE 24 */		  "Too many open files",
 | |
| /* ENOTTY 25 */		  "Inappropriate ioctl for device",
 | |
| /* ETXTBSY 26 */	  "Text file busy",
 | |
| /* EFBIG 27 */		  "File too large",
 | |
| /* ENOSPC 28 */		  "No space left on device",
 | |
| /* ESPIPE 29 */		  "Illegal seek",
 | |
| /* EROFS 30 */		  "Read-only file system",
 | |
| /* EMLINK 31 */		  "Too many links",
 | |
| /* EPIPE 32 */		  "Broken pipe",
 | |
| /* EDOM 33 */		  "Numerical argument out of domain",
 | |
| /* ERANGE 34 */		  "Numerical result out of range",
 | |
| /* ENOMSG 35 */		  "No message of desired type",
 | |
| /* EIDRM 36 */		  "Identifier removed",
 | |
| /* ECHRNG 37 */		  "Channel number out of range",
 | |
| /* EL2NSYNC 38 */	  "Level 2 not synchronized",
 | |
| /* EL3HLT 39 */		  "Level 3 halted",
 | |
| /* EL3RST 40 */		  "Level 3 reset",
 | |
| /* ELNRNG 41 */		  "Link number out of range",
 | |
| /* EUNATCH 42 */	  "Protocol driver not attached",
 | |
| /* ENOCSI 43 */		  "No CSI structure available",
 | |
| /* EL2HLT 44 */		  "Level 2 halted",
 | |
| /* EDEADLK 45 */	  "Resource deadlock avoided",
 | |
| /* ENOLCK 46 */		  "No locks available",
 | |
| 			  NULL,
 | |
| 			  NULL,
 | |
| 			  NULL,
 | |
| /* EBADE 50 */		  "Invalid exchange",
 | |
| /* EBADR 51 */		  "Invalid request descriptor",
 | |
| /* EXFULL 52 */		  "Exchange full",
 | |
| /* ENOANO 53 */		  "No anode",
 | |
| /* EBADRQC 54 */	  "Invalid request code",
 | |
| /* EBADSLT 55 */	  "Invalid slot",
 | |
| /* EDEADLOCK 56 */	  "File locking deadlock error",
 | |
| /* EBFONT 57 */		  "Bad font file format",
 | |
| 			  NULL,
 | |
| 			  NULL,
 | |
| /* ENOSTR 60 */		  "Device not a stream",
 | |
| /* ENODATA 61 */	  "No data available",
 | |
| /* ETIME 62 */		  "Timer expired",
 | |
| /* ENOSR 63 */		  "Out of streams resources",
 | |
| /* ENONET 64 */		  "Machine is not on the network",
 | |
| /* ENOPKG 65 */		  "Package not installed",
 | |
| /* EREMOTE 66 */	  "Object is remote",
 | |
| /* ENOLINK 67 */	  "Link has been severed",
 | |
| /* EADV 68 */		  "Advertise error",
 | |
| /* ESRMNT 69 */		  "Srmount error",
 | |
| /* ECOMM 70 */		  "Communication error on send",
 | |
| /* EPROTO 71 */		  "Protocol error",
 | |
| 			  NULL,
 | |
| 			  NULL,
 | |
| /* EMULTIHOP 74 */	  "Multihop attempted",
 | |
| /* ELBIN 75 */		  "Inode is remote (not really error)",
 | |
| /* EDOTDOT 76 */	  "RFS specific error",
 | |
| /* EBADMSG 77 */	  "Bad message",
 | |
| 			  NULL,
 | |
| /* EFTYPE 79 */		  "Inappropriate file type or format",
 | |
| /* ENOTUNIQ 80 */	  "Name not unique on network",
 | |
| /* EBADFD 81 */		  "File descriptor in bad state",
 | |
| /* EREMCHG 82 */	  "Remote address changed",
 | |
| /* ELIBACC 83 */	  "Can not access a needed shared library",
 | |
| /* ELIBBAD 84 */	  "Accessing a corrupted shared library",
 | |
| /* ELIBSCN 85 */	  ".lib section in a.out corrupted",
 | |
| /* ELIBMAX 86 */	  "Attempting to link in too many shared libraries",
 | |
| /* ELIBEXEC 87 */	  "Cannot exec a shared library directly",
 | |
| /* ENOSYS 88 */		  "Function not implemented",
 | |
| /* ENMFILE 89 */	  "No more files",
 | |
| /* ENOTEMPTY 90	*/	  "Directory not empty",
 | |
| /* ENAMETOOLONG 91 */	  "File name too long",
 | |
| /* ELOOP 92 */		  "Too many levels of symbolic links",
 | |
| 			  NULL,
 | |
| 			  NULL,
 | |
| /* EOPNOTSUPP 95 */	  "Operation not supported",
 | |
| /* EPFNOSUPPORT 96 */	  "Protocol family not supported",
 | |
| 			  NULL,
 | |
| 			  NULL,
 | |
| 			  NULL,
 | |
| 			  NULL,
 | |
| 			  NULL,
 | |
| 			  NULL,
 | |
| 			  NULL,
 | |
| /* ECONNRESET 104 */	  "Connection reset by peer",
 | |
| /* ENOBUFS 105 */	  "No buffer space available",
 | |
| /* EAFNOSUPPORT 106 */	  "Address family not supported by protocol",
 | |
| /* EPROTOTYPE 107 */	  "Protocol wrong type for socket",
 | |
| /* ENOTSOCK 108 */	  "Socket operation on non-socket",
 | |
| /* ENOPROTOOPT 109 */	  "Protocol not available",
 | |
| /* ESHUTDOWN 110 */	  "Cannot send after transport endpoint shutdown",
 | |
| /* ECONNREFUSED 111 */	  "Connection refused",
 | |
| /* EADDRINUSE 112 */	  "Address already in use",
 | |
| /* ECONNABORTED 113 */	  "Software caused connection abort",
 | |
| /* ENETUNREACH 114 */	  "Network is unreachable",
 | |
| /* ENETDOWN 115 */	  "Network is down",
 | |
| /* ETIMEDOUT 116 */	  "Connection timed out",
 | |
| /* EHOSTDOWN 117 */	  "Host is down",
 | |
| /* EHOSTUNREACH 118 */	  "No route to host",
 | |
| /* EINPROGRESS 119 */	  "Operation now in progress",
 | |
| /* EALREADY 120 */	  "Operation already in progress",
 | |
| /* EDESTADDRREQ 121 */	  "Destination address required",
 | |
| /* EMSGSIZE 122 */	  "Message too long",
 | |
| /* EPROTONOSUPPORT 123 */ "Protocol not supported",
 | |
| /* ESOCKTNOSUPPORT 124 */ "Socket type not supported",
 | |
| /* EADDRNOTAVAIL 125 */	  "Cannot assign requested address",
 | |
| /* ENETRESET 126 */	  "Network dropped connection on reset",
 | |
| /* EISCONN 127 */	  "Transport endpoint is already connected",
 | |
| /* ENOTCONN 128 */	  "Transport endpoint is not connected",
 | |
| /* ETOOMANYREFS 129 */	  "Too many references: cannot splice",
 | |
| /* EPROCLIM 130 */	  "Too many processes",
 | |
| /* EUSERS 131 */	  "Too many users",
 | |
| /* EDQUOT 132 */	  "Disk quota exceeded",
 | |
| /* ESTALE 133 */	  "Stale NFS file handle",
 | |
| /* ENOTSUP 134 */	  "Not supported",
 | |
| /* ENOMEDIUM 135 */	  "No medium found",
 | |
| /* ENOSHARE 136 */	  "No such host or network path",
 | |
| /* ECASECLASH 137 */	  "Filename exists with different case",
 | |
| /* EILSEQ 138 */	  "Invalid or incomplete multibyte or wide character",
 | |
| /* EOVERFLOW 139 */	  "Value too large for defined data type",
 | |
| /* ECANCELED 140 */	  "Operation canceled",
 | |
| /* ENOTRECOVERABLE 141 */ "State not recoverable",
 | |
| /* EOWNERDEAD 142 */	  "Previous owner died",
 | |
| /* ESTRPIPE 143 */	  "Streams pipe error"
 | |
| };
 | |
| 
 | |
| int NO_COPY_INIT _sys_nerr = sizeof (_sys_errlist) / sizeof (_sys_errlist[0]);
 | |
| };
 | |
| 
 | |
| int __reg2
 | |
| geterrno_from_win_error (DWORD code, int deferrno)
 | |
| {
 | |
|   for (int i = 0; errmap[i].w != 0; ++i)
 | |
|     if (code == errmap[i].w)
 | |
|       {
 | |
| 	syscall_printf ("windows error %u == errno %d", code, errmap[i].e);
 | |
| 	return errmap[i].e;
 | |
|       }
 | |
| 
 | |
|   syscall_printf ("unknown windows error %u, setting errno to %d", code,
 | |
| 		  deferrno);
 | |
|   return deferrno;	/* FIXME: what's so special about EACCESS? */
 | |
| }
 | |
| 
 | |
| /* seterrno_from_win_error: Given a Windows error code, set errno
 | |
|    as appropriate. */
 | |
| void __reg3
 | |
| seterrno_from_win_error (const char *file, int line, DWORD code)
 | |
| {
 | |
|   syscall_printf ("%s:%d windows error %u", file, line, code);
 | |
|   errno = _impure_ptr->_errno =  geterrno_from_win_error (code, EACCES);
 | |
| }
 | |
| 
 | |
| int __reg2
 | |
| geterrno_from_nt_status (NTSTATUS status, int deferrno)
 | |
| {
 | |
|   return geterrno_from_win_error (RtlNtStatusToDosError (status));
 | |
| }
 | |
| 
 | |
| /* seterrno_from_nt_status: Given a NT status code, set errno
 | |
|    as appropriate. */
 | |
| void __reg3
 | |
| seterrno_from_nt_status (const char *file, int line, NTSTATUS status)
 | |
| {
 | |
|   DWORD code = RtlNtStatusToDosError (status);
 | |
|   SetLastError (code);
 | |
|   syscall_printf ("%s:%d status %y -> windows error %u",
 | |
| 		  file, line, status, code);
 | |
|   errno = _impure_ptr->_errno =  geterrno_from_win_error (code, EACCES);
 | |
| }
 | |
| 
 | |
| static char *
 | |
| strerror_worker (int errnum)
 | |
| {
 | |
|   char *res;
 | |
|   if (errnum >= 0 && errnum < _sys_nerr)
 | |
|     res = (char *) _sys_errlist [errnum];
 | |
|   else
 | |
|     res = NULL;
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| /* Newlib requires this override for perror and friends to avoid
 | |
|    clobbering strerror() buffer, without having to differentiate
 | |
|    between strerror_r signatures.  This function is intentionally not
 | |
|    exported, so that only newlib can use it.  */
 | |
| extern "C" char *
 | |
| _strerror_r (struct _reent *, int errnum, int internal, int *errptr)
 | |
| {
 | |
|   char *errstr = strerror_worker (errnum);
 | |
|   if (!errstr)
 | |
|     {
 | |
|       errstr = internal ? _my_tls.locals.strerror_r_buf
 | |
| 	: _my_tls.locals.strerror_buf;
 | |
|       __small_sprintf (errstr, "Unknown error %d", errnum);
 | |
|       if (errptr)
 | |
| 	*errptr = EINVAL;
 | |
|     }
 | |
|   return errstr;
 | |
| }
 | |
| 
 | |
| /* strerror: convert from errno values to error strings.  Newlib's
 | |
|    strerror_r returns "" for unknown values, so we override it to
 | |
|    provide a nicer thread-safe result string and set errno.  */
 | |
| extern "C" char *
 | |
| strerror (int errnum)
 | |
| {
 | |
|   int error = 0;
 | |
|   char *result = _strerror_r (NULL, errnum, 0, &error);
 | |
|   if (error)
 | |
|     set_errno (error);
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| extern "C" char *
 | |
| strerror_l (int errnum, locale_t locale)
 | |
| {
 | |
|   /* We don't provide localized system error messages (yet?). */
 | |
|   return strerror (errnum);
 | |
| }
 | |
| 
 | |
| /* Newlib's <string.h> provides declarations for two strerror_r
 | |
|    variants, according to preprocessor feature macros.  However, it
 | |
|    returns "" instead of "Unknown error ...", so we override both
 | |
|    versions.  */
 | |
| extern "C" char *
 | |
| strerror_r (int errnum, char *buf, size_t n)
 | |
| {
 | |
|   int error = 0;
 | |
|   char *errstr = _strerror_r (NULL, errnum, 1, &error);
 | |
|   if (error)
 | |
|     set_errno (error);
 | |
|   if (strlen (errstr) >= n)
 | |
|     return errstr;
 | |
|   return strcpy (buf, errstr);
 | |
| }
 | |
| 
 | |
| extern "C" int
 | |
| __xpg_strerror_r (int errnum, char *buf, size_t n)
 | |
| {
 | |
|   if (!n)
 | |
|     return ERANGE;
 | |
|   int result = 0;
 | |
|   char *error = strerror_worker (errnum);
 | |
|   char tmp[sizeof "Unknown error -2147483648"];
 | |
|   if (!error)
 | |
|     {
 | |
|       __small_sprintf (error = tmp, "Unknown error %d", errnum);
 | |
|       result = EINVAL;
 | |
|     }
 | |
|   if (strlen (error) >= n)
 | |
|     {
 | |
|       memcpy (buf, error, n - 1);
 | |
|       buf[n - 1] = '\0';
 | |
|       return ERANGE;
 | |
|     }
 | |
|   strcpy (buf, error);
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| unsigned int error_message_count = 0;
 | |
| int error_one_per_line = 0;
 | |
| void (*error_print_progname) (void) = NULL;
 | |
| 
 | |
| static void
 | |
| _verror (int status, int errnum, const char *filename, unsigned int lineno, const char *fmt, va_list ap)
 | |
| {
 | |
|   error_message_count++;
 | |
| 
 | |
|   fflush (stdout);
 | |
| 
 | |
|   if (error_print_progname)
 | |
|     (*error_print_progname) ();
 | |
|   else
 | |
|     fprintf (stderr, "%s:%s", program_invocation_name, filename ? "" : " ");
 | |
| 
 | |
|   if (filename)
 | |
|     fprintf (stderr, "%s:%d: ", filename, lineno);
 | |
| 
 | |
|   vfprintf (stderr, fmt, ap);
 | |
| 
 | |
|   if (errnum != 0)
 | |
|     fprintf (stderr, ": %s", strerror (errnum));
 | |
| 
 | |
|   fprintf (stderr, "\n");
 | |
| 
 | |
|   if (status != 0)
 | |
|     exit (status);
 | |
| }
 | |
| 
 | |
| extern "C" void
 | |
| error (int status, int errnum, const char *fmt, ...)
 | |
| {
 | |
|   va_list ap;
 | |
|   va_start (ap, fmt);
 | |
|   _verror (status, errnum, NULL, 0, fmt, ap);
 | |
|   va_end (ap);
 | |
| }
 | |
| 
 | |
| extern "C" void
 | |
| error_at_line (int status, int errnum, const char *filename, unsigned int lineno, const char *fmt, ...)
 | |
| {
 | |
|   va_list ap;
 | |
| 
 | |
|   if (error_one_per_line != 0)
 | |
|     {
 | |
|       static const char *last_filename;
 | |
|       static unsigned int last_lineno;
 | |
| 
 | |
|       /* strcmp(3) will SEGV if filename or last_filename are NULL */
 | |
|       if (lineno == last_lineno
 | |
| 	  && ((!filename && !last_filename)
 | |
| 	      || (filename && last_filename && strcmp (filename, last_filename) == 0)))
 | |
| 	return;
 | |
| 
 | |
|       last_filename = filename;
 | |
|       last_lineno = lineno;
 | |
|     }
 | |
| 
 | |
|   va_start (ap, fmt);
 | |
|   _verror (status, errnum, filename, lineno, fmt, ap);
 | |
|   va_end (ap);
 | |
| }
 |