/* 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 #include #include #include #include #include #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 struct { DWORD w; /* windows version of error */ const char *s; /* text of windows version */ int e; /* errno version of error */ } 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 (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; } /* Newlib's 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); }