| /* | 
 |  * 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 <string.h> | 
 | // gives us the GNU variant. | 
 | #undef _GNU_SOURCE | 
 |  | 
 | #include <string.h> | 
 |  | 
 | #include <errno.h> | 
 | #include <limits.h> | 
 |  | 
 | #include <async_safe/log.h> | 
 |  | 
 | #include "private/ErrnoRestorer.h" | 
 |  | 
 | #include <string.h> | 
 |  | 
 | #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] = "Inappropriate ioctl for device", | 
 |     [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<int>(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) { | 
 |     return ERANGE; | 
 |   } | 
 |  | 
 |   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<char*>(__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; | 
 | } |