695af0da30
The posix spec says strerror_r returns a positive error number, not -1 and set errno. Test: bionic-unit-tests-static Change-Id: I6a12d50d046f9caac299bf3bff63e6c9496c1b6f
222 lines
8.5 KiB
C++
222 lines
8.5 KiB
C++
/*
|
|
* 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;
|
|
}
|