/ string / FreeBSD / strerror.c
strerror.c
  1  /*-
  2   * Copyright (c) 1988, 1993
  3   *	The Regents of the University of California.  All rights reserved.
  4   *
  5   * Redistribution and use in source and binary forms, with or without
  6   * modification, are permitted provided that the following conditions
  7   * are met:
  8   * 1. Redistributions of source code must retain the above copyright
  9   *    notice, this list of conditions and the following disclaimer.
 10   * 2. Redistributions in binary form must reproduce the above copyright
 11   *    notice, this list of conditions and the following disclaimer in the
 12   *    documentation and/or other materials provided with the distribution.
 13   * 4. Neither the name of the University nor the names of its contributors
 14   *    may be used to endorse or promote products derived from this software
 15   *    without specific prior written permission.
 16   *
 17   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 18   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 19   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 20   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 21   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 22   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 23   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 24   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 25   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 26   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 27   * SUCH DAMAGE.
 28   */
 29  
 30  #if defined(LIBC_SCCS) && !defined(lint)
 31  static char sccsid[] = "@(#)strerror.c	8.1 (Berkeley) 6/4/93";
 32  #endif /* LIBC_SCCS and not lint */
 33  #include <sys/cdefs.h>
 34  __FBSDID("$FreeBSD: src/lib/libc/string/strerror.c,v 1.16 2007/01/09 00:28:12 imp Exp $");
 35  
 36  #if defined(NLS)
 37  #include <nl_types.h>
 38  #endif
 39  
 40  #include <limits.h>
 41  #include <errno.h>
 42  #include <string.h>
 43  #include <stdio.h>
 44  #include <stdlib.h>
 45  
 46  #define	UPREFIX		"Unknown error"
 47  
 48  /*
 49   * Define a buffer size big enough to describe a 64-bit signed integer
 50   * converted to ASCII decimal (19 bytes), with an optional leading sign
 51   * (1 byte); finally, we get the prefix, delimiter (": ") and a trailing
 52   * NUL from UPREFIX.
 53   */
 54  #define	EBUFSIZE	(20 + 2 + sizeof(UPREFIX))
 55  
 56  #if defined(DARLING) && defined(VARIANT_LEGACY)
 57  // these can't be included in the legacy variant because they're already
 58  // included in the regular variant (and they're exactly the same in both versions,
 59  // both in terms of symbol naming and functionality)
 60  __private_extern__ void __errstr(int num, char *uprefix, char *buf, size_t len);
 61  extern int strerror_r(int errnum, char *strerrbuf, size_t buflen);
 62  #else
 63  /*
 64   * Doing this by hand instead of linking with stdio(3) avoids bloat for
 65   * statically linked binaries.
 66   */
 67  __private_extern__ void
 68  __errstr(int num, char *uprefix, char *buf, size_t len)
 69  {
 70  	char *t;
 71  	unsigned int uerr;
 72  	char tmp[EBUFSIZE];
 73  
 74  	t = tmp + sizeof(tmp);
 75  	*--t = '\0';
 76  	uerr = (num >= 0) ? num : -num;
 77  	do {
 78  		*--t = "0123456789"[uerr % 10];
 79  	} while (uerr /= 10);
 80  	if (num < 0)
 81  		*--t = '-';
 82  	*--t = ' ';
 83  	*--t = ':';
 84  	strlcpy(buf, uprefix, len);
 85  	strlcat(buf, t, len);
 86  }
 87  
 88  int
 89  strerror_r(int errnum, char *strerrbuf, size_t buflen)
 90  {
 91  	int retval = 0;
 92  #if defined(NLS)
 93  	int saved_errno = errno;
 94  	nl_catd catd;
 95  	catd = catopen("libc", NL_CAT_LOCALE);
 96  #endif
 97  
 98  	if (errnum < 0 || errnum >= sys_nerr) {
 99  		__errstr(errnum,
100  #if defined(NLS)
101  			catgets(catd, 1, 0xffff, UPREFIX),
102  #else
103  			UPREFIX,
104  #endif
105  			strerrbuf, buflen);
106  		retval = EINVAL;
107  	} else {
108  		if (strlcpy(strerrbuf,
109  #if defined(NLS)
110  			catgets(catd, 1, errnum, sys_errlist[errnum]),
111  #else
112  			sys_errlist[errnum],
113  #endif
114  			buflen) >= buflen)
115  		retval = ERANGE;
116  	}
117  
118  #if defined(NLS)
119  	catclose(catd);
120  	errno = saved_errno;
121  #endif
122  
123  	return (retval);
124  }
125  #endif
126  
127  static char *__strerror_ebuf = NULL;
128  
129  char *
130  strerror(int num)
131  {
132  #if !defined(NLS)
133  	if (num >= 0 && num < sys_nerr) {
134  		return (char*)sys_errlist[num];
135  	}
136  #endif
137  
138  	if (__strerror_ebuf == NULL) {
139  		__strerror_ebuf = calloc(1, NL_TEXTMAX);
140  		if (__strerror_ebuf == NULL) {
141  			return NULL;
142  		}
143  	}
144  
145  	if (strerror_r(num, __strerror_ebuf, NL_TEXTMAX) != 0) {
146  		errno = EINVAL;
147  	}
148  	return __strerror_ebuf;
149  }