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