strerror_r.c revision 1.5.6.1 1 1.5.6.1 martin /* $NetBSD: strerror_r.c,v 1.5.6.1 2024/10/13 16:08:53 martin Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.1 christos * Copyright (c) 1988 Regents of the University of California.
5 1.1 christos * All rights reserved.
6 1.1 christos *
7 1.1 christos * Redistribution and use in source and binary forms, with or without
8 1.1 christos * modification, are permitted provided that the following conditions
9 1.1 christos * are met:
10 1.1 christos * 1. Redistributions of source code must retain the above copyright
11 1.1 christos * notice, this list of conditions and the following disclaimer.
12 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 christos * notice, this list of conditions and the following disclaimer in the
14 1.1 christos * documentation and/or other materials provided with the distribution.
15 1.1 christos * 3. Neither the name of the University nor the names of its contributors
16 1.1 christos * may be used to endorse or promote products derived from this software
17 1.1 christos * without specific prior written permission.
18 1.1 christos *
19 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 1.1 christos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 1.1 christos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.1 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 1.1 christos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.1 christos * SUCH DAMAGE.
30 1.1 christos */
31 1.1 christos
32 1.1 christos #include <sys/cdefs.h>
33 1.5.6.1 martin __RCSID("$NetBSD: strerror_r.c,v 1.5.6.1 2024/10/13 16:08:53 martin Exp $");
34 1.1 christos
35 1.1 christos #include "namespace.h"
36 1.3 joerg #include <assert.h>
37 1.5.6.1 martin #include <atomic.h>
38 1.3 joerg #include <errno.h>
39 1.3 joerg #include <stdio.h>
40 1.5.6.1 martin #include <stdlib.h>
41 1.3 joerg #include <string.h>
42 1.4 christos #include <stdio.h> /* for sys_nerr on FreeBSD */
43 1.1 christos #ifdef NLS
44 1.1 christos #include <limits.h>
45 1.1 christos #include <nl_types.h>
46 1.3 joerg #define __SETLOCALE_SOURCE__
47 1.3 joerg #include <locale.h>
48 1.3 joerg #include "setlocale_local.h"
49 1.1 christos #endif
50 1.1 christos
51 1.1 christos #include "extern.h"
52 1.1 christos
53 1.5.6.1 martin #define UPREFIX "Unknown error: %d"
54 1.5.6.1 martin
55 1.2 christos __weak_alias(strerror_r, _strerror_r)
56 1.2 christos
57 1.5.6.1 martin #ifdef NLS
58 1.5.6.1 martin static void
59 1.5.6.1 martin load_errlist(locale_t loc)
60 1.5.6.1 martin {
61 1.5.6.1 martin const char **errlist;
62 1.5.6.1 martin char *errlist_prefix;
63 1.5.6.1 martin int i;
64 1.5.6.1 martin nl_catd catd;
65 1.5.6.1 martin catd = catopen_l("libc", NL_CAT_LOCALE, loc);
66 1.5.6.1 martin
67 1.5.6.1 martin if (loc->cache->errlist_prefix == NULL) {
68 1.5.6.1 martin errlist_prefix = strdup(catgets(catd, 1, 0xffff, UPREFIX));
69 1.5.6.1 martin if (errlist_prefix == NULL)
70 1.5.6.1 martin goto cleanup2;
71 1.5.6.1 martin
72 1.5.6.1 martin membar_release();
73 1.5.6.1 martin if (atomic_cas_ptr(__UNCONST(&loc->cache->errlist_prefix),
74 1.5.6.1 martin NULL, errlist_prefix) != NULL)
75 1.5.6.1 martin free(errlist_prefix);
76 1.5.6.1 martin }
77 1.5.6.1 martin
78 1.5.6.1 martin if (loc->cache->errlist)
79 1.5.6.1 martin goto cleanup2;
80 1.5.6.1 martin
81 1.5.6.1 martin errlist = calloc(sys_nerr, sizeof(*errlist));
82 1.5.6.1 martin if (errlist == NULL)
83 1.5.6.1 martin goto cleanup2;
84 1.5.6.1 martin for (i = 0; i < sys_nerr; ++i) {
85 1.5.6.1 martin errlist[i] = strdup(catgets(catd, 1, i, sys_errlist[i]));
86 1.5.6.1 martin if (errlist[i] == NULL)
87 1.5.6.1 martin goto cleanup;
88 1.5.6.1 martin }
89 1.5.6.1 martin membar_release();
90 1.5.6.1 martin if (atomic_cas_ptr(__UNCONST(&loc->cache->errlist), NULL, errlist) != NULL)
91 1.5.6.1 martin goto cleanup;
92 1.5.6.1 martin goto cleanup2;
93 1.5.6.1 martin
94 1.5.6.1 martin cleanup:
95 1.5.6.1 martin for (i = 0; i < sys_nerr; ++i)
96 1.5.6.1 martin free(__UNCONST(errlist[i]));
97 1.5.6.1 martin free(errlist);
98 1.5.6.1 martin cleanup2:
99 1.5.6.1 martin catclose(catd);
100 1.5.6.1 martin }
101 1.5.6.1 martin #endif
102 1.5.6.1 martin
103 1.1 christos int
104 1.3 joerg _strerror_lr(int num, char *buf, size_t buflen, locale_t loc)
105 1.1 christos {
106 1.1 christos unsigned int errnum = num;
107 1.1 christos int retval = 0;
108 1.1 christos size_t slen;
109 1.5 kre int saved_errno = errno;
110 1.1 christos #ifdef NLS
111 1.5.6.1 martin const char * const *errlist;
112 1.5.6.1 martin const char *errlist_prefix;
113 1.1 christos #endif
114 1.5.6.1 martin
115 1.1 christos _DIAGASSERT(buf != NULL);
116 1.1 christos
117 1.1 christos if (errnum < (unsigned int) sys_nerr) {
118 1.1 christos #ifdef NLS
119 1.5.6.1 martin errlist = *loc->cache->errlistp;
120 1.5.6.1 martin membar_datadep_consumer();
121 1.5.6.1 martin if (errlist == NULL) {
122 1.5.6.1 martin load_errlist(loc);
123 1.5.6.1 martin errlist = *loc->cache->errlistp;
124 1.5.6.1 martin membar_datadep_consumer();
125 1.5.6.1 martin if (errlist == NULL)
126 1.5.6.1 martin errlist = *LC_C_LOCALE->cache->errlistp;
127 1.5.6.1 martin }
128 1.5.6.1 martin slen = strlcpy(buf, errlist[errnum], buflen);
129 1.1 christos #else
130 1.5.6.1 martin slen = strlcpy(buf, sys_errlist[errnum], buflen);
131 1.1 christos #endif
132 1.1 christos } else {
133 1.1 christos #ifdef NLS
134 1.5.6.1 martin errlist_prefix = loc->cache->errlist_prefix;
135 1.5.6.1 martin membar_datadep_consumer();
136 1.5.6.1 martin if (errlist_prefix == NULL) {
137 1.5.6.1 martin load_errlist(loc);
138 1.5.6.1 martin errlist_prefix = loc->cache->errlist_prefix;
139 1.5.6.1 martin membar_datadep_consumer();
140 1.5.6.1 martin if (errlist_prefix == NULL)
141 1.5.6.1 martin errlist_prefix = LC_C_LOCALE->cache->errlist_prefix;
142 1.5.6.1 martin }
143 1.5.6.1 martin slen = snprintf_l(buf, buflen, loc, errlist_prefix, num);
144 1.1 christos #else
145 1.5 kre slen = snprintf(buf, buflen, UPREFIX, num);
146 1.1 christos #endif
147 1.1 christos retval = EINVAL;
148 1.1 christos }
149 1.1 christos
150 1.1 christos if (slen >= buflen)
151 1.1 christos retval = ERANGE;
152 1.1 christos
153 1.1 christos errno = saved_errno;
154 1.1 christos
155 1.1 christos return retval;
156 1.1 christos }
157 1.3 joerg
158 1.3 joerg int
159 1.3 joerg strerror_r(int num, char *buf, size_t buflen)
160 1.3 joerg {
161 1.3 joerg #ifdef NLS
162 1.3 joerg return _strerror_lr(num, buf, buflen, _current_locale());
163 1.3 joerg #else
164 1.3 joerg return _strerror_lr(num, buf, buflen, NULL);
165 1.3 joerg #endif
166 1.3 joerg }
167