xref: /netbsd-src/lib/libc/string/strerror_r.c (revision d1f43e70cb5544bfeaa3cb4776119ec76b02d3f5)
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