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