/* * Copyright (C) 2012 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // G++ automatically defines _GNU_SOURCE, which then means that // gives us the GNU variant. #undef _GNU_SOURCE #include #include #include #include #include "private/ErrnoRestorer.h" #include #include "bionic/pthread_internal.h" static const char* __sys_error_strings[] = { [0] = "Success", [EPERM] = "Operation not permitted", [ENOENT] = "No such file or directory", [ESRCH] = "No such process", [EINTR] = "Interrupted system call", [EIO] = "I/O error", [ENXIO] = "No such device or address", [E2BIG] = "Argument list too long", [ENOEXEC] = "Exec format error", [EBADF] = "Bad file descriptor", [ECHILD] = "No child processes", [EAGAIN] = "Try again", [ENOMEM] = "Out of memory", [EACCES] = "Permission denied", [EFAULT] = "Bad address", [ENOTBLK] = "Block device required", [EBUSY] = "Device or resource busy", [EEXIST] = "File exists", [EXDEV] = "Cross-device link", [ENODEV] = "No such device", [ENOTDIR] = "Not a directory", [EISDIR] = "Is a directory", [EINVAL] = "Invalid argument", [ENFILE] = "File table overflow", [EMFILE] = "Too many open files", [ENOTTY] = "Not a typewriter", [ETXTBSY] = "Text file busy", [EFBIG] = "File too large", [ENOSPC] = "No space left on device", [ESPIPE] = "Illegal seek", [EROFS] = "Read-only file system", [EMLINK] = "Too many links", [EPIPE] = "Broken pipe", [EDOM] = "Math argument out of domain of func", [ERANGE] = "Math result not representable", [EDEADLK] = "Resource deadlock would occur", [ENAMETOOLONG] = "File name too long", [ENOLCK] = "No record locks available", [ENOSYS] = "Function not implemented", [ENOTEMPTY] = "Directory not empty", [ELOOP] = "Too many symbolic links encountered", [ENOMSG] = "No message of desired type", [EIDRM] = "Identifier removed", [ECHRNG] = "Channel number out of range", [EL2NSYNC] = "Level 2 not synchronized", [EL3HLT] = "Level 3 halted", [EL3RST] = "Level 3 reset", [ELNRNG] = "Link number out of range", [EUNATCH] = "Protocol driver not attached", [ENOCSI] = "No CSI structure available", [EL2HLT] = "Level 2 halted", [EBADE] = "Invalid exchange", [EBADR] = "Invalid request descriptor", [EXFULL] = "Exchange full", [ENOANO] = "No anode", [EBADRQC] = "Invalid request code", [EBADSLT] = "Invalid slot", [EBFONT] = "Bad font file format", [ENOSTR] = "Device not a stream", [ENODATA] = "No data available", [ETIME] = "Timer expired", [ENOSR] = "Out of streams resources", [ENONET] = "Machine is not on the network", [ENOPKG] = "Package not installed", [EREMOTE] = "Object is remote", [ENOLINK] = "Link has been severed", [EADV] = "Advertise error", [ESRMNT] = "Srmount error", [ECOMM] = "Communication error on send", [EPROTO] = "Protocol error", [EMULTIHOP] = "Multihop attempted", [EDOTDOT] = "RFS specific error", [EBADMSG] = "Not a data message", [EOVERFLOW] = "Value too large for defined data type", [ENOTUNIQ] = "Name not unique on network", [EBADFD] = "File descriptor in bad state", [EREMCHG] = "Remote address changed", [ELIBACC] = "Can not access a needed shared library", [ELIBBAD] = "Accessing a corrupted shared library", [ELIBSCN] = ".lib section in a.out corrupted", [ELIBMAX] = "Attempting to link in too many shared libraries", [ELIBEXEC] = "Cannot exec a shared library directly", [EILSEQ] = "Illegal byte sequence", [ERESTART] = "Interrupted system call should be restarted", [ESTRPIPE] = "Streams pipe error", [EUSERS] = "Too many users", [ENOTSOCK] = "Socket operation on non-socket", [EDESTADDRREQ] = "Destination address required", [EMSGSIZE] = "Message too long", [EPROTOTYPE] = "Protocol wrong type for socket", [ENOPROTOOPT] = "Protocol not available", [EPROTONOSUPPORT] = "Protocol not supported", [ESOCKTNOSUPPORT] = "Socket type not supported", [EOPNOTSUPP] = "Operation not supported on transport endpoint", [EPFNOSUPPORT] = "Protocol family not supported", [EAFNOSUPPORT] = "Address family not supported by protocol", [EADDRINUSE] = "Address already in use", [EADDRNOTAVAIL] = "Cannot assign requested address", [ENETDOWN] = "Network is down", [ENETUNREACH] = "Network is unreachable", [ENETRESET] = "Network dropped connection because of reset", [ECONNABORTED] = "Software caused connection abort", [ECONNRESET] = "Connection reset by peer", [ENOBUFS] = "No buffer space available", [EISCONN] = "Transport endpoint is already connected", [ENOTCONN] = "Transport endpoint is not connected", [ESHUTDOWN] = "Cannot send after transport endpoint shutdown", [ETOOMANYREFS] = "Too many references: cannot splice", [ETIMEDOUT] = "Connection timed out", [ECONNREFUSED] = "Connection refused", [EHOSTDOWN] = "Host is down", [EHOSTUNREACH] = "No route to host", [EALREADY] = "Operation already in progress", [EINPROGRESS] = "Operation now in progress", [ESTALE] = "Stale NFS file handle", [EUCLEAN] = "Structure needs cleaning", [ENOTNAM] = "Not a XENIX named type file", [ENAVAIL] = "No XENIX semaphores available", [EISNAM] = "Is a named type file", [EREMOTEIO] = "Remote I/O error", [EDQUOT] = "Quota exceeded", [ENOMEDIUM] = "No medium found", [EMEDIUMTYPE] = "Wrong medium type", [ECANCELED] = "Operation Canceled", [ENOKEY] = "Required key not available", [EKEYEXPIRED] = "Key has expired", [EKEYREVOKED] = "Key has been revoked", [EKEYREJECTED] = "Key was rejected by service", [EOWNERDEAD] = "Owner died", [ENOTRECOVERABLE] = "State not recoverable", [ERFKILL] = "Operation not possible due to RF-kill", [EHWPOISON] = "Memory page has hardware error", }; static inline const char* __strerror_lookup(int error_number) { if (error_number < 0 || error_number >= static_cast(arraysize(__sys_error_strings))) { return nullptr; } return __sys_error_strings[error_number]; } int strerror_r(int error_number, char* buf, size_t buf_len) { ErrnoRestorer errno_restorer; size_t length; const char* error_name = __strerror_lookup(error_number); if (error_name != nullptr) { length = strlcpy(buf, error_name, buf_len); } else { length = async_safe_format_buffer(buf, buf_len, "Unknown error %d", error_number); } if (length >= buf_len) { errno_restorer.override(ERANGE); return -1; } return 0; } extern "C" char* __gnu_strerror_r(int error_number, char* buf, size_t buf_len) { ErrnoRestorer errno_restorer; // The glibc strerror_r doesn't set errno if it truncates... strerror_r(error_number, buf, buf_len); return buf; // ...and just returns whatever fit. } char* strerror(int error_number) { // Just return the original constant in the easy cases. char* result = const_cast(__strerror_lookup(error_number)); if (result != nullptr) { return result; } bionic_tls& tls = __get_bionic_tls(); result = tls.strerror_buf; strerror_r(error_number, result, sizeof(tls.strerror_buf)); return result; }