|  | /* | 
|  | * 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] = "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<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) { | 
|  | 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<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; | 
|  | } |