15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(__ANDROID__) 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Post-L versions of bionic define the GNU-specific strerror_r if _GNU_SOURCE 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// is defined, but the symbol is renamed to __gnu_strerror_r which only exists 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// on those later versions. To preserve ABI compatibility with older versions, 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// undefine _GNU_SOURCE and use the POSIX version. 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#undef _GNU_SOURCE 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/safe_strerror_posix.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h> 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#define USE_HISTORICAL_STRERRO_R (defined(__GLIBC__) || defined(OS_NACL)) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if USE_HISTORICAL_STRERRO_R && defined(__GNUC__) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GCC will complain about the unused second wrap function unless we tell it 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that we meant for them to be potentially unused, which is exactly what this 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// attribute is for. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define POSSIBLY_UNUSED __attribute__((unused)) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define POSSIBLY_UNUSED 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if USE_HISTORICAL_STRERRO_R 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// glibc has two strerror_r functions: a historical GNU-specific one that 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// returns type char *, and a POSIX.1-2001 compliant one available since 2.3.4 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that returns int. This wraps the GNU-specific one. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void POSSIBLY_UNUSED wrap_posix_strerror_r( 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *(*strerror_r_ptr)(int, char *, size_t), 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int err, 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *buf, 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t len) { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GNU version. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *rc = (*strerror_r_ptr)(err, buf, len); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rc != buf) { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // glibc did not use buf and returned a static string instead. Copy it 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // into buf. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[0] = '\0'; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strncat(buf, rc, len - 1); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The GNU version never fails. Unknown errors get an "unknown error" message. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The result is always null terminated. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // USE_HISTORICAL_STRERRO_R 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Wrapper for strerror_r functions that implement the POSIX interface. POSIX 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// does not define the behaviour for some of the edge cases, so we wrap it to 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// guarantee that they are handled. This is compiled on all POSIX platforms, but 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it will only be used on Linux if the POSIX strerror_r implementation is 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// being used (see below). 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void POSSIBLY_UNUSED wrap_posix_strerror_r( 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int (*strerror_r_ptr)(int, char *, size_t), 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int err, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *buf, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t len) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int old_errno = errno; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Have to cast since otherwise we get an error if this is the GNU version 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (but in such a scenario this function is never called). Sadly we can't use 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // C++-style casts because the appropriate one is reinterpret_cast but it's 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // considered illegal to reinterpret_cast a type to itself, so we get an 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // error in the opposite case. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int result = (*strerror_r_ptr)(err, buf, len); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == 0) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // POSIX is vague about whether the string will be terminated, although 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it indirectly implies that typically ERANGE will be returned, instead 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of truncating the string. We play it safe by always terminating the 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // string explicitly. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[len - 1] = '\0'; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Error. POSIX is vague about whether the return value is itself a system 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // error code or something else. On Linux currently it is -1 and errno is 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // set. On BSD-derived systems it is a system error and errno is unchanged. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We try and detect which case it is so as to put as much useful info as 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we can into our message. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int strerror_error; // The error encountered in strerror 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int new_errno = errno; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_errno != old_errno) { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // errno was changed, so probably the return value is just -1 or something 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // else that doesn't provide any info, and errno is the error. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strerror_error = new_errno; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either the error from strerror_r was the same as the previous value, or 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // errno wasn't used. Assume the latter. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strerror_error = result; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // snprintf truncates and always null-terminates. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) snprintf(buf, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len, 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Error %d while retrieving error %d", 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strerror_error, 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errno = old_errno; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void safe_strerror_r(int err, char *buf, size_t len) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buf == NULL || len <= 0) { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If using glibc (i.e., Linux), the compiler will automatically select the 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // appropriate overloaded function based on the function type of strerror_r. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The other one will be elided from the translation unit since both are 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // static. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrap_posix_strerror_r(&strerror_r, err, buf, len); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string safe_strerror(int err) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int buffer_size = 256; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[buffer_size]; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) safe_strerror_r(err, buf, sizeof(buf)); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(buf); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 120