summaryrefslogtreecommitdiff
path: root/m4/strerror_r.m4
blob: d790ba877575c21803137e277d6f206bf0233811 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# strerror_r.m4 serial 26
dnl Copyright (C) 2002, 2007-2023 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.

AC_DEFUN([gl_FUNC_STRERROR_R],
[
  AC_REQUIRE([gl_STRING_H_DEFAULTS])
  AC_REQUIRE([gl_FUNC_STRERROR_R_WORKS])

  dnl Some systems don't declare strerror_r() if _THREAD_SAFE and _REENTRANT
  dnl are not defined.
  AC_CHECK_DECLS_ONCE([strerror_r])
  if test $ac_cv_have_decl_strerror_r = no; then
    HAVE_DECL_STRERROR_R=0
  fi

  if test $ac_cv_func_strerror_r = yes; then
    if test "$GL_GENERATE_ERRNO_H:$REPLACE_STRERROR_0" = false:0; then
      if test $gl_cv_func_strerror_r_posix_signature = yes; then
        case "$gl_cv_func_strerror_r_works" in
          dnl The system's strerror_r has bugs.  Replace it.
          *no) REPLACE_STRERROR_R=1 ;;
        esac
      else
        dnl The system's strerror_r() has a wrong signature. Replace it.
        REPLACE_STRERROR_R=1
      fi
    else
      dnl The system's strerror_r() cannot know about the new errno values we
      dnl add to <errno.h>, or any fix for strerror(0). Replace it.
      REPLACE_STRERROR_R=1
    fi
  fi
])

# Prerequisites of lib/strerror_r.c.
AC_DEFUN([gl_PREREQ_STRERROR_R], [
  AC_REQUIRE([AC_FUNC_STRERROR_R])
  dnl glibc >= 2.3.4 and cygwin 1.7.9 have a function __xpg_strerror_r.
  AC_CHECK_FUNCS_ONCE([__xpg_strerror_r])
  gl_CHECK_FUNCS_ANDROID([catgets], [[#include <nl_types.h>]])
  AC_CHECK_FUNCS_ONCE([snprintf])
])

# Detect if strerror_r works, but without affecting whether a replacement
# strerror_r will be used.
AC_DEFUN([gl_FUNC_STRERROR_R_WORKS],
[
  AC_REQUIRE([gl_HEADER_ERRNO_H])
  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles

  dnl Persuade Android <string.h> to use the GNU strerror_r API,
  dnl and Solaris <string.h> to declare strerror_r.
  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])

  AC_REQUIRE([gl_FUNC_STRERROR_0])

  gl_CHECK_FUNCS_ANDROID([strerror_r], [[#include <string.h>]])
  if test $ac_cv_func_strerror_r = yes; then
    if test "$GL_GENERATE_ERRNO_H:$REPLACE_STRERROR_0" = false:0; then
      dnl The POSIX prototype is:  int strerror_r (int, char *, size_t);
      dnl glibc, Cygwin:           char *strerror_r (int, char *, size_t);
      dnl AIX 5.1, OSF/1 5.1:      int strerror_r (int, char *, int);
      AC_CACHE_CHECK([for strerror_r with POSIX signature],
        [gl_cv_func_strerror_r_posix_signature],
        [AC_COMPILE_IFELSE(
           [AC_LANG_PROGRAM(
              [[#include <string.h>
                int strerror_r (int, char *, size_t);
              ]],
              [])],
           [gl_cv_func_strerror_r_posix_signature=yes],
           [gl_cv_func_strerror_r_posix_signature=no])
        ])
      if test $gl_cv_func_strerror_r_posix_signature = yes; then
        dnl AIX 6.1 strerror_r fails by returning -1, not an error number.
        dnl HP-UX 11.31 strerror_r always fails when the buffer length argument
        dnl is less than 80.
        dnl FreeBSD 8.s strerror_r claims failure on 0
        dnl Mac OS X 10.5 strerror_r treats 0 like -1
        dnl Solaris 10 strerror_r corrupts errno on failure
        AC_CACHE_CHECK([whether strerror_r works],
          [gl_cv_func_strerror_r_works],
          [AC_RUN_IFELSE(
             [AC_LANG_PROGRAM(
                [[#include <errno.h>
                  #include <string.h>
                ]],
                [[int result = 0;
                  char buf[79];
                  if (strerror_r (EACCES, buf, 0) < 0)
                    result |= 1;
                  errno = 0;
                  if (strerror_r (EACCES, buf, sizeof buf) != 0)
                    result |= 2;
                  strcpy (buf, "Unknown");
                  if (strerror_r (0, buf, sizeof buf) != 0)
                    result |= 4;
                  if (errno)
                    result |= 8;
                  if (strstr (buf, "nknown") || strstr (buf, "ndefined"))
                    result |= 0x10;
                  errno = 0;
                  *buf = 0;
                  if (strerror_r (-3, buf, sizeof buf) < 0)
                    result |= 0x20;
                  if (errno)
                    result |= 0x40;
                  if (!*buf)
                    result |= 0x80;
                  return result;
                ]])],
             [gl_cv_func_strerror_r_works=yes],
             [gl_cv_func_strerror_r_works=no],
             [
changequote(,)dnl
              case "$host_os" in
                       # Guess no on AIX.
                aix*)  gl_cv_func_strerror_r_works="guessing no";;
                       # Guess no on HP-UX.
                hpux*) gl_cv_func_strerror_r_works="guessing no";;
                       # Guess no on BSD variants.
                *bsd*)  gl_cv_func_strerror_r_works="guessing no";;
                       # Guess yes otherwise.
                *)     gl_cv_func_strerror_r_works="guessing yes";;
              esac
changequote([,])dnl
             ])
          ])
      else
        dnl The system's strerror() has a wrong signature.
        dnl glibc >= 2.3.4 and cygwin 1.7.9 have a function __xpg_strerror_r.
        AC_CHECK_FUNCS_ONCE([__xpg_strerror_r])
        dnl In glibc < 2.14, __xpg_strerror_r does not populate buf on failure.
        dnl In cygwin < 1.7.10, __xpg_strerror_r clobbers strerror's buffer.
        if test $ac_cv_func___xpg_strerror_r = yes; then
          AC_CACHE_CHECK([whether __xpg_strerror_r works],
            [gl_cv_func_strerror_r_works],
            [AC_RUN_IFELSE(
               [AC_LANG_PROGRAM(
                  [[#include <errno.h>
                    #include <string.h>
                    extern
                    #ifdef __cplusplus
                    "C"
                    #endif
                    int __xpg_strerror_r(int, char *, size_t);
                  ]],
                  [[int result = 0;
                    char buf[256] = "^";
                    char copy[256];
                    char *str = strerror (-1);
                    strcpy (copy, str);
                    if (__xpg_strerror_r (-2, buf, 1) == 0)
                      result |= 1;
                    if (*buf)
                      result |= 2;
                    __xpg_strerror_r (-2, buf, 256);
                    if (strcmp (str, copy))
                      result |= 4;
                    return result;
                  ]])],
               [gl_cv_func_strerror_r_works=yes],
               [gl_cv_func_strerror_r_works=no],
               [dnl Guess no on all platforms that have __xpg_strerror_r,
                dnl at least until fixed glibc and cygwin are more common.
                gl_cv_func_strerror_r_works="$gl_cross_guess_normal"
               ])
            ])
        fi
      fi
    fi
  else
    case "$gl_cv_onwards_func_strerror_r" in
      future*) REPLACE_STRERROR_R=1 ;;
    esac
  fi
])