1*d1f43e70Sjoerg /* $NetBSD: strerror_r.c,v 1.6 2024/06/08 21:35:18 joerg Exp $ */
21cf13731Schristos
31cf13731Schristos /*
41cf13731Schristos * Copyright (c) 1988 Regents of the University of California.
51cf13731Schristos * All rights reserved.
61cf13731Schristos *
71cf13731Schristos * Redistribution and use in source and binary forms, with or without
81cf13731Schristos * modification, are permitted provided that the following conditions
91cf13731Schristos * are met:
101cf13731Schristos * 1. Redistributions of source code must retain the above copyright
111cf13731Schristos * notice, this list of conditions and the following disclaimer.
121cf13731Schristos * 2. Redistributions in binary form must reproduce the above copyright
131cf13731Schristos * notice, this list of conditions and the following disclaimer in the
141cf13731Schristos * documentation and/or other materials provided with the distribution.
151cf13731Schristos * 3. Neither the name of the University nor the names of its contributors
161cf13731Schristos * may be used to endorse or promote products derived from this software
171cf13731Schristos * without specific prior written permission.
181cf13731Schristos *
191cf13731Schristos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
201cf13731Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
211cf13731Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
221cf13731Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
231cf13731Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
241cf13731Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
251cf13731Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
261cf13731Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
271cf13731Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
281cf13731Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
291cf13731Schristos * SUCH DAMAGE.
301cf13731Schristos */
311cf13731Schristos
321cf13731Schristos #include <sys/cdefs.h>
33*d1f43e70Sjoerg __RCSID("$NetBSD: strerror_r.c,v 1.6 2024/06/08 21:35:18 joerg Exp $");
341cf13731Schristos
351cf13731Schristos #include "namespace.h"
361cf13731Schristos #include <assert.h>
37*d1f43e70Sjoerg #include <atomic.h>
381cf13731Schristos #include <errno.h>
391cf13731Schristos #include <stdio.h>
40*d1f43e70Sjoerg #include <stdlib.h>
411cf13731Schristos #include <string.h>
424ad16b3eSchristos #include <stdio.h> /* for sys_nerr on FreeBSD */
437efdee83Sjoerg #ifdef NLS
447efdee83Sjoerg #include <limits.h>
457efdee83Sjoerg #include <nl_types.h>
467efdee83Sjoerg #define __SETLOCALE_SOURCE__
477efdee83Sjoerg #include <locale.h>
487efdee83Sjoerg #include "setlocale_local.h"
497efdee83Sjoerg #endif
507efdee83Sjoerg
511cf13731Schristos #include "extern.h"
521cf13731Schristos
53*d1f43e70Sjoerg #define UPREFIX "Unknown error: %d"
54*d1f43e70Sjoerg
__weak_alias(strerror_r,_strerror_r)5586741d79Schristos __weak_alias(strerror_r, _strerror_r)
5686741d79Schristos
57*d1f43e70Sjoerg #ifdef NLS
58*d1f43e70Sjoerg static void
59*d1f43e70Sjoerg load_errlist(locale_t loc)
60*d1f43e70Sjoerg {
61*d1f43e70Sjoerg const char **errlist;
62*d1f43e70Sjoerg char *errlist_prefix;
63*d1f43e70Sjoerg int i;
64*d1f43e70Sjoerg nl_catd catd;
65*d1f43e70Sjoerg catd = catopen_l("libc", NL_CAT_LOCALE, loc);
66*d1f43e70Sjoerg
67*d1f43e70Sjoerg if (loc->cache->errlist_prefix == NULL) {
68*d1f43e70Sjoerg errlist_prefix = strdup(catgets(catd, 1, 0xffff, UPREFIX));
69*d1f43e70Sjoerg if (errlist_prefix == NULL)
70*d1f43e70Sjoerg goto cleanup2;
71*d1f43e70Sjoerg
72*d1f43e70Sjoerg membar_release();
73*d1f43e70Sjoerg if (atomic_cas_ptr(__UNCONST(&loc->cache->errlist_prefix),
74*d1f43e70Sjoerg NULL, errlist_prefix) != NULL)
75*d1f43e70Sjoerg free(errlist_prefix);
76*d1f43e70Sjoerg }
77*d1f43e70Sjoerg
78*d1f43e70Sjoerg if (loc->cache->errlist)
79*d1f43e70Sjoerg goto cleanup2;
80*d1f43e70Sjoerg
81*d1f43e70Sjoerg errlist = calloc(sys_nerr, sizeof(*errlist));
82*d1f43e70Sjoerg if (errlist == NULL)
83*d1f43e70Sjoerg goto cleanup2;
84*d1f43e70Sjoerg for (i = 0; i < sys_nerr; ++i) {
85*d1f43e70Sjoerg errlist[i] = strdup(catgets(catd, 1, i, sys_errlist[i]));
86*d1f43e70Sjoerg if (errlist[i] == NULL)
87*d1f43e70Sjoerg goto cleanup;
88*d1f43e70Sjoerg }
89*d1f43e70Sjoerg membar_release();
90*d1f43e70Sjoerg if (atomic_cas_ptr(__UNCONST(&loc->cache->errlist), NULL, errlist) != NULL)
91*d1f43e70Sjoerg goto cleanup;
92*d1f43e70Sjoerg goto cleanup2;
93*d1f43e70Sjoerg
94*d1f43e70Sjoerg cleanup:
95*d1f43e70Sjoerg for (i = 0; i < sys_nerr; ++i)
96*d1f43e70Sjoerg free(__UNCONST(errlist[i]));
97*d1f43e70Sjoerg free(errlist);
98*d1f43e70Sjoerg cleanup2:
99*d1f43e70Sjoerg catclose(catd);
100*d1f43e70Sjoerg }
101*d1f43e70Sjoerg #endif
102*d1f43e70Sjoerg
1031cf13731Schristos int
_strerror_lr(int num,char * buf,size_t buflen,locale_t loc)1047efdee83Sjoerg _strerror_lr(int num, char *buf, size_t buflen, locale_t loc)
1051cf13731Schristos {
1061cf13731Schristos unsigned int errnum = num;
1071cf13731Schristos int retval = 0;
1081cf13731Schristos size_t slen;
1091cf13731Schristos int saved_errno = errno;
110219987b2Skre #ifdef NLS
111*d1f43e70Sjoerg const char * const *errlist;
112*d1f43e70Sjoerg const char *errlist_prefix;
1131cf13731Schristos #endif
114*d1f43e70Sjoerg
1151cf13731Schristos _DIAGASSERT(buf != NULL);
1161cf13731Schristos
1171cf13731Schristos if (errnum < (unsigned int) sys_nerr) {
1181cf13731Schristos #ifdef NLS
119*d1f43e70Sjoerg errlist = *loc->cache->errlistp;
120*d1f43e70Sjoerg membar_datadep_consumer();
121*d1f43e70Sjoerg if (errlist == NULL) {
122*d1f43e70Sjoerg load_errlist(loc);
123*d1f43e70Sjoerg errlist = *loc->cache->errlistp;
124*d1f43e70Sjoerg membar_datadep_consumer();
125*d1f43e70Sjoerg if (errlist == NULL)
126*d1f43e70Sjoerg errlist = *LC_C_LOCALE->cache->errlistp;
127*d1f43e70Sjoerg }
128*d1f43e70Sjoerg slen = strlcpy(buf, errlist[errnum], buflen);
1291cf13731Schristos #else
1301cf13731Schristos slen = strlcpy(buf, sys_errlist[errnum], buflen);
1311cf13731Schristos #endif
1321cf13731Schristos } else {
1331cf13731Schristos #ifdef NLS
134*d1f43e70Sjoerg errlist_prefix = loc->cache->errlist_prefix;
135*d1f43e70Sjoerg membar_datadep_consumer();
136*d1f43e70Sjoerg if (errlist_prefix == NULL) {
137*d1f43e70Sjoerg load_errlist(loc);
138*d1f43e70Sjoerg errlist_prefix = loc->cache->errlist_prefix;
139*d1f43e70Sjoerg membar_datadep_consumer();
140*d1f43e70Sjoerg if (errlist_prefix == NULL)
141*d1f43e70Sjoerg errlist_prefix = LC_C_LOCALE->cache->errlist_prefix;
142*d1f43e70Sjoerg }
143*d1f43e70Sjoerg slen = snprintf_l(buf, buflen, loc, errlist_prefix, num);
1441cf13731Schristos #else
145219987b2Skre slen = snprintf(buf, buflen, UPREFIX, num);
1461cf13731Schristos #endif
1471cf13731Schristos retval = EINVAL;
1481cf13731Schristos }
1491cf13731Schristos
1501cf13731Schristos if (slen >= buflen)
1511cf13731Schristos retval = ERANGE;
1521cf13731Schristos
153219987b2Skre errno = saved_errno;
1541cf13731Schristos
1551cf13731Schristos return retval;
1561cf13731Schristos }
1577efdee83Sjoerg
1587efdee83Sjoerg int
strerror_r(int num,char * buf,size_t buflen)1597efdee83Sjoerg strerror_r(int num, char *buf, size_t buflen)
1607efdee83Sjoerg {
1617efdee83Sjoerg #ifdef NLS
1627efdee83Sjoerg return _strerror_lr(num, buf, buflen, _current_locale());
1637efdee83Sjoerg #else
1647efdee83Sjoerg return _strerror_lr(num, buf, buflen, NULL);
1657efdee83Sjoerg #endif
1667efdee83Sjoerg }
167