1b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea/* $OpenBSD: strerror_r.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
2b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea/* Public Domain <marc@snafu.org> */
3b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea
4416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes// G++ automatically defines _GNU_SOURCE, which then means that <string.h>
5416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes// gives us the GNU variant.
6416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes#undef _GNU_SOURCE
7416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes
8416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes#include <string.h>
9416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes
10b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea#include <errno.h>
11b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea#include <limits.h>
12b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea#include <signal.h>
13b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea#include <stdio.h>
14b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea
153e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes#include "private/ErrnoRestorer.h"
1691570ce987ef93f9ba2fa663a5fee1bd2525a2baElliott Hughes#include "private/libc_logging.h"
173e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes
18b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdeastruct Pair {
19b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  int code;
20b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  const char* msg;
21b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea};
22b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea
23b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdeastatic const char* __code_string_lookup(const Pair* strings, int code) {
24b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  for (size_t i = 0; strings[i].msg != NULL; ++i) {
25b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea    if (strings[i].code == code) {
26b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea      return strings[i].msg;
27b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea    }
28b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  }
29b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  return NULL;
30b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea}
31b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea
32b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdeastatic const Pair _sys_error_strings[] = {
33b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea#define  __BIONIC_ERRDEF(x,y,z)  { x, z },
3426bc9c64d5b0cad921e3070a4f94fa04e1077d90Josh Gao#include "private/bionic_errdefs.h"
35b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  { 0, NULL }
36b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea};
37b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea
3895a7a64ac8b242f278f515b06bdb6057ecca4396Elliott Hughesextern "C" __LIBC_HIDDEN__ const char* __strerror_lookup(int error_number) {
394198fa4c23fc8a1895808a597bb153530f6ea515Elliott Hughes  return __code_string_lookup(_sys_error_strings, error_number);
404198fa4c23fc8a1895808a597bb153530f6ea515Elliott Hughes}
414198fa4c23fc8a1895808a597bb153530f6ea515Elliott Hughes
424198fa4c23fc8a1895808a597bb153530f6ea515Elliott Hughesstatic const Pair _sys_signal_strings[] = {
43aa0ebdafc71e1ceac78e0929b94f3bb117d0c8e9Elliott Hughes#define  __BIONIC_SIGDEF(signal_number, signal_description)  { signal_number, signal_description },
4426bc9c64d5b0cad921e3070a4f94fa04e1077d90Josh Gao#include "private/bionic_sigdefs.h"
454198fa4c23fc8a1895808a597bb153530f6ea515Elliott Hughes  { 0, NULL }
464198fa4c23fc8a1895808a597bb153530f6ea515Elliott Hughes};
474198fa4c23fc8a1895808a597bb153530f6ea515Elliott Hughes
4895a7a64ac8b242f278f515b06bdb6057ecca4396Elliott Hughesextern "C" __LIBC_HIDDEN__ const char* __strsignal_lookup(int signal_number) {
494198fa4c23fc8a1895808a597bb153530f6ea515Elliott Hughes  return __code_string_lookup(_sys_signal_strings, signal_number);
504198fa4c23fc8a1895808a597bb153530f6ea515Elliott Hughes}
514198fa4c23fc8a1895808a597bb153530f6ea515Elliott Hughes
52b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdeaint strerror_r(int error_number, char* buf, size_t buf_len) {
533e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes  ErrnoRestorer errno_restorer;
54b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  size_t length;
55b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea
564198fa4c23fc8a1895808a597bb153530f6ea515Elliott Hughes  const char* error_name = __strerror_lookup(error_number);
57b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  if (error_name != NULL) {
5891570ce987ef93f9ba2fa663a5fee1bd2525a2baElliott Hughes    length = strlcpy(buf, error_name, buf_len);
59b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  } else {
6091570ce987ef93f9ba2fa663a5fee1bd2525a2baElliott Hughes    length = __libc_format_buffer(buf, buf_len, "Unknown error %d", error_number);
61b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  }
62b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  if (length >= buf_len) {
633e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes    errno_restorer.override(ERANGE);
64b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea    return -1;
65b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  }
66b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea
67b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  return 0;
68b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea}
69b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea
70416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughesextern "C" char* __gnu_strerror_r(int error_number, char* buf, size_t buf_len) {
71416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes  ErrnoRestorer errno_restorer; // The glibc strerror_r doesn't set errno if it truncates...
72416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes  strerror_r(error_number, buf, buf_len);
73416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes  return buf; // ...and just returns whatever fit.
74416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes}
75416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes
7695a7a64ac8b242f278f515b06bdb6057ecca4396Elliott Hughesextern "C" __LIBC_HIDDEN__ const char* __strsignal(int signal_number, char* buf, size_t buf_len) {
774198fa4c23fc8a1895808a597bb153530f6ea515Elliott Hughes  const char* signal_name = __strsignal_lookup(signal_number);
78b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  if (signal_name != NULL) {
79b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea    return signal_name;
80b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  }
81b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea
82b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  const char* prefix = "Unknown";
83b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  if (signal_number >= SIGRTMIN && signal_number <= SIGRTMAX) {
84b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea    prefix = "Real-time";
85b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea    signal_number -= SIGRTMIN;
86b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  }
87b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  size_t length = snprintf(buf, buf_len, "%s signal %d", prefix, signal_number);
88b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  if (length >= buf_len) {
89b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea    return NULL;
90b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  }
91b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea  return buf;
92b5f053b5a7deb084e7a052d527e0aa41339ae05cIrina Tirdea}
93