diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/libc/locale/ldpart.c | 35 | ||||
| -rw-r--r-- | lib/libc/locale/rune.3 | 7 | ||||
| -rw-r--r-- | lib/libc/locale/setlocale.3 | 2 | ||||
| -rw-r--r-- | lib/libc/locale/setlocale.c | 176 | ||||
| -rw-r--r-- | lib/libc/locale/setrunelocale.c | 47 | 
5 files changed, 169 insertions, 98 deletions
diff --git a/lib/libc/locale/ldpart.c b/lib/libc/locale/ldpart.c index 7f9fa2944e40..345812003755 100644 --- a/lib/libc/locale/ldpart.c +++ b/lib/libc/locale/ldpart.c @@ -22,13 +22,15 @@   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   * SUCH DAMAGE. - * - * $FreeBSD$   */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +  #include <sys/types.h>  #include <sys/stat.h>  #include <sys/syslimits.h> +#include <errno.h>  #include <fcntl.h>  #include <stdlib.h>  #include <string.h> @@ -47,11 +49,11 @@ __part_load_locale(const char *name,  		const char *category_filename,  		int locale_buf_size_max,  		int locale_buf_size_min, -		const char **dst_localebuf) { - +		const char **dst_localebuf) +{  	static char		locale_buf_C[] = "C";  	static int		num_lines; - +	int                     saverr;  	int			 fd;  	char			*lbuf;  	char			*p; @@ -65,8 +67,7 @@ __part_load_locale(const char *name,  	save_using_locale = *using_locale;  	*using_locale = 0; -	if (name == NULL) -		goto no_locale; +	/* 'name' must be already checked. */  	if (!strcmp(name, "C") || !strcmp(name, "POSIX"))  		return 0; @@ -86,8 +87,8 @@ __part_load_locale(const char *name,  	 */  	namesize = strlen(name) + 1; -	if (!_PathLocale) -		goto no_locale; +	/* 'PathLocale' must be already set & checked. */ +  	/* Range checking not needed, 'name' size is limited */  	strcpy(filename, _PathLocale);  	strcat(filename, "/"); @@ -99,8 +100,10 @@ __part_load_locale(const char *name,  		goto no_locale;  	if (_fstat(fd, &st) != 0)  		goto bad_locale; -	if (st.st_size <= 0) +	if (st.st_size <= 0) { +		errno = EFTYPE;  		goto bad_locale; +	}  	bufsize = namesize + st.st_size;  	locale_buf = NULL;  	lbuf = (lbuf == NULL || lbuf == locale_buf_C) ? @@ -117,15 +120,19 @@ __part_load_locale(const char *name,  	/*  	 * Parse the locale file into localebuf.  	 */ -	if (plim[-1] != '\n') +	if (plim[-1] != '\n') { +		errno = EFTYPE;  		goto bad_lbuf; +	}  	num_lines = split_lines(p, plim);  	if (num_lines >= locale_buf_size_max)  		num_lines = locale_buf_size_max;  	else if (num_lines >= locale_buf_size_min)  		num_lines = locale_buf_size_min; -	else +	else { +		errno = EFTYPE;  		goto reset_locale; +	}  	set_from_buf(lbuf, num_lines, dst_localebuf);  	/*  	 * Record the successful parse in the cache. @@ -139,9 +146,9 @@ reset_locale:  	locale_buf = locale_buf_C;  	save_using_locale = 0;  bad_lbuf: -	free(lbuf); +	saverr = errno; free(lbuf); errno = saverr;  bad_locale: -	(void)_close(fd); +	saverr = errno; (void)_close(fd); errno = saverr;  no_locale:  	*using_locale = save_using_locale;  	return -1; diff --git a/lib/libc/locale/rune.3 b/lib/libc/locale/rune.3 index 7c83ebc619c2..7c37c40b91ff 100644 --- a/lib/libc/locale/rune.3 +++ b/lib/libc/locale/rune.3 @@ -217,16 +217,13 @@ function returns one of the following values:  .It Er 0  .Fn setrunelocale  was successful. -.It Bq Er EFAULT +.It Bq Er EINVAL  .Fa locale -was -.Dv NULL . +name was incorrect.  .It Bq Er ENOENT  The locale could not be found.  .It Bq Er EFTYPE  The file found was not a valid file. -.It Bq Er EINVAL -The encoding indicated by the locale was unknown.  .El  .Pp  The diff --git a/lib/libc/locale/setlocale.3 b/lib/libc/locale/setlocale.3 index 77628b84b674..a1bb367bd7b1 100644 --- a/lib/libc/locale/setlocale.3 +++ b/lib/libc/locale/setlocale.3 @@ -282,6 +282,8 @@ which may be altered by later calls to  .Fn setlocale  or  .Fn localeconv . +.Sh ERRORS +No errors are defined.  .Sh FILES  .Bl -tag -width /usr/share/locale/locale/category -compact  .It Pa $PATH_LOCALE/ Ns Em locale/category diff --git a/lib/libc/locale/setlocale.c b/lib/libc/locale/setlocale.c index ae64d82d506a..6b249a9fa89b 100644 --- a/lib/libc/locale/setlocale.c +++ b/lib/libc/locale/setlocale.c @@ -35,17 +35,15 @@   * SUCH DAMAGE.   */ -#ifdef LIBC_RCS -static const char rcsid[] = -  "$FreeBSD$"; -#endif -  #if defined(LIBC_SCCS) && !defined(lint)  static char sccsid[] = "@(#)setlocale.c	8.1 (Berkeley) 7/4/93";  #endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$");  #include <sys/types.h>  #include <sys/stat.h> +#include <errno.h>  #include <limits.h>  #include <locale.h>  #include <rune.h> @@ -93,21 +91,24 @@ static char saved_categories[_LC_LAST][ENCODING_LEN + 1];  static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)]; -static char	*currentlocale __P((void)); -static char	*loadlocale __P((int)); +static char	*currentlocale(void); +static int      wrap_setrunelocale(char *); +static char	*loadlocale(int);  char *  setlocale(category, locale)  	int category;  	const char *locale;  { -	int i, j, len; +	int i, j, len, saverr;  	char *env, *r; -	if (category < LC_ALL || category >= _LC_LAST) +	if (category < LC_ALL || category >= _LC_LAST) { +		errno = EINVAL;  		return (NULL); +	} -	if (!locale) +	if (locale == NULL)  		return (category != LC_ALL ?  		    current_categories[category] : currentlocale()); @@ -123,47 +124,73 @@ setlocale(category, locale)  	if (!*locale) {  		env = getenv("LC_ALL"); -		if (category != LC_ALL && (!env || !*env)) +		if (category != LC_ALL && (env == NULL || !*env))  			env = getenv(categories[category]); -		if (!env || !*env) +		if (env == NULL || !*env)  			env = getenv("LANG"); -		if (!env || !*env || strchr(env, '/')) +		if (env == NULL || !*env)  			env = "C"; -		(void)strlcpy(new_categories[category], env, ENCODING_LEN + 1); +		if (strlen(env) > ENCODING_LEN) { +			errno = EINVAL; +			return (NULL); +		} +		(void)strcpy(new_categories[category], env); +  		if (category == LC_ALL) {  			for (i = 1; i < _LC_LAST; ++i) { -				if (!(env = getenv(categories[i])) || !*env) +				if ((env = getenv(categories[i])) == NULL || +				    !*env)  					env = new_categories[LC_ALL]; -				(void)strlcpy(new_categories[i], env, ENCODING_LEN + 1); +				else if (strlen(env) > ENCODING_LEN) { +					errno = EINVAL; +					return (NULL); +				} +				(void)strcpy(new_categories[i], env);  			}  		} -	} else if (category != LC_ALL) -		(void)strlcpy(new_categories[category], locale, ENCODING_LEN + 1); -	else { +	} else if (category != LC_ALL) { +		if (strlen(locale) > ENCODING_LEN) { +			errno = EINVAL; +			return (NULL); +		} +		(void)strcpy(new_categories[category], locale); +	} else {  		if ((r = strchr(locale, '/')) == NULL) { +			if (strlen(locale) > ENCODING_LEN) { +				errno = EINVAL; +				return (NULL); +			}  			for (i = 1; i < _LC_LAST; ++i) -				(void)strlcpy(new_categories[i], locale, ENCODING_LEN + 1); +				(void)strcpy(new_categories[i], locale);  		} else { -			for (i = 1; r[1] == '/'; ++r); -			if (!r[1]) +			for (i = 1; r[1] == '/'; ++r) +				; +			if (!r[1]) { +				errno = EINVAL;  				return (NULL);	/* Hmm, just slashes... */ +			}  			do {  				if (i == _LC_LAST)  					break;  /* Too many slashes... */ -				len = r - locale > ENCODING_LEN ? ENCODING_LEN : r - locale; -				(void)strlcpy(new_categories[i], locale, len + 1); +				if ((len = r - locale) > ENCODING_LEN) { +					errno = EINVAL; +					return (NULL); +				} +				(void)strlcpy(new_categories[i], locale, +					      len + 1);  				i++;  				locale = r;  				while (*locale == '/') -				    ++locale; -				while (*++r && *r != '/'); +					++locale; +				while (*++r && *r != '/') +					;  			} while (*locale);  			while (i < _LC_LAST) {  				(void)strcpy(new_categories[i], -				    new_categories[i-1]); +					     new_categories[i-1]);  				i++;  			}  		} @@ -175,12 +202,13 @@ setlocale(category, locale)  	for (i = 1; i < _LC_LAST; ++i) {  		(void)strcpy(saved_categories[i], current_categories[i]);  		if (loadlocale(i) == NULL) { +			saverr = errno;  			for (j = 1; j < i; j++) {  				(void)strcpy(new_categories[j], -				     saved_categories[j]); -				/* XXX can fail too */ +					     saved_categories[j]);  				(void)loadlocale(j);  			} +			errno = saverr;  			return (NULL);  		}  	} @@ -197,14 +225,28 @@ currentlocale()  	for (i = 2; i < _LC_LAST; ++i)  		if (strcmp(current_categories[1], current_categories[i])) {  			for (i = 2; i < _LC_LAST; ++i) { -				(void) strcat(current_locale_string, "/"); -				(void) strcat(current_locale_string, current_categories[i]); +				(void)strcat(current_locale_string, "/"); +				(void)strcat(current_locale_string, +					     current_categories[i]);  			}  			break;  		}  	return (current_locale_string);  } +static int +wrap_setrunelocale(locale) +	char *locale; +{ +	int ret = setrunelocale(locale); + +	if (ret != 0) { +		errno = ret; +		return (-1); +	} +	return (0); +} +  static char *  loadlocale(category)  	int category; @@ -212,6 +254,15 @@ loadlocale(category)  	char *ret;  	char *new = new_categories[category];  	char *old = current_categories[category]; +	int (*func)(); +	int saverr; + +	if ((new[0] == '.' && +	     (new[1] == '\0' || (new[1] == '.' && new[2] == '\0'))) || +	    strchr(new, '/') != NULL) { +		errno = EINVAL; +		return (NULL); +	}  	if (_PathLocale == NULL) {  		char *p = getenv("PATH_LOCALE"); @@ -222,8 +273,10 @@ loadlocale(category)  #endif  			) {  			if (strlen(p) + 1/*"/"*/ + ENCODING_LEN + -			    1/*"/"*/ + CATEGORY_LEN >= PATH_MAX) +			    1/*"/"*/ + CATEGORY_LEN >= PATH_MAX) { +				errno = ENAMETOOLONG;  				return (NULL); +			}  			_PathLocale = strdup(p);  			if (_PathLocale == NULL)  				return (NULL); @@ -231,35 +284,42 @@ loadlocale(category)  			_PathLocale = _PATH_LOCALE;  	} -	if (strcmp(new, old) == 0) -		return (old); - -	if (category == LC_CTYPE) { -		ret = setrunelocale(new) ? NULL : new; -		if (!ret) -			(void)setrunelocale(old); -		else -			(void)strcpy(old, new); -		return (ret); +	switch (category) { +	case LC_CTYPE: +		func = wrap_setrunelocale; +		break; +	case LC_COLLATE: +		func = __collate_load_tables; +		break; +	case LC_TIME: +		func = __time_load_locale; +		break; +	case LC_NUMERIC: +		func = __numeric_load_locale; +		break; +	case LC_MONETARY: +		func = __monetary_load_locale; +		break; +	case LC_MESSAGES: +		func = __messages_load_locale; +		break; +	default: +		errno = EINVAL; +		return (NULL);  	} -#define LOAD_CATEGORY(CAT, FUNC)			\ -	if (category == CAT) {				\ -		ret = (FUNC(new) < 0) ? NULL : new;	\ -		if (!ret)				\ -			(void)FUNC(old);		\ -		else					\ -			(void)strcpy(old, new);		\ -		return (ret);				\ -	} +	if (strcmp(new, old) == 0) +		return (old); -	LOAD_CATEGORY(LC_COLLATE, __collate_load_tables); -	LOAD_CATEGORY(LC_TIME, __time_load_locale); -	LOAD_CATEGORY(LC_NUMERIC, __numeric_load_locale); -	LOAD_CATEGORY(LC_MONETARY, __monetary_load_locale); -	LOAD_CATEGORY(LC_MESSAGES, __messages_load_locale); +	ret = func(new) != 0 ? NULL : new; +	if (ret == NULL) { +		saverr = errno; +		if (func(old) != 0 && func("C") == 0) +			(void)strcpy(old, "C"); +		errno = saverr; +	} else +		(void)strcpy(old, new); -	/* Just in case...*/ -	return (NULL); +	return (ret);  } diff --git a/lib/libc/locale/setrunelocale.c b/lib/libc/locale/setrunelocale.c index 55d6ba90b566..a42c02086836 100644 --- a/lib/libc/locale/setrunelocale.c +++ b/lib/libc/locale/setrunelocale.c @@ -32,10 +32,11 @@   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   * SUCH DAMAGE. - * - * $FreeBSD$   */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +  #include <rune.h>  #include <errno.h>  #include <limits.h> @@ -45,12 +46,12 @@  #include <unistd.h>  #include "setlocale.h" -extern int		_none_init __P((_RuneLocale *)); -extern int		_UTF2_init __P((_RuneLocale *)); -extern int		_EUC_init __P((_RuneLocale *)); -extern int		_BIG5_init __P((_RuneLocale *)); -extern int		_MSKanji_init __P((_RuneLocale *)); -extern _RuneLocale      *_Read_RuneMagi __P((FILE *)); +extern int		_none_init(_RuneLocale *); +extern int		_UTF2_init(_RuneLocale *); +extern int		_EUC_init(_RuneLocale *); +extern int		_BIG5_init(_RuneLocale *); +extern int		_MSKanji_init(_RuneLocale *); +extern _RuneLocale      *_Read_RuneMagi(FILE *);  int  setrunelocale(encoding) @@ -60,15 +61,19 @@ setrunelocale(encoding)  	char name[PATH_MAX];  	_RuneLocale *rl; -	if (!encoding || strlen(encoding) > ENCODING_LEN) -	    return(EFAULT); +	if (!encoding || !*encoding || strlen(encoding) > ENCODING_LEN || +	    (encoding[0] == '.' && +	     (encoding[1] == '\0' || +	      (encoding[1] == '.' && encoding[2] == '\0'))) || +	    strchr(encoding, '/') != NULL) +		return (EINVAL);  	/*  	 * The "C" and "POSIX" locale are always here.  	 */  	if (!strcmp(encoding, "C") || !strcmp(encoding, "POSIX")) {  		_CurrentRuneLocale = &_DefaultRuneLocale; -		return(0); +		return (0);  	}  	if (_PathLocale == NULL) { @@ -81,7 +86,7 @@ setrunelocale(encoding)  			) {  			if (strlen(p) + 1/*"/"*/ + ENCODING_LEN +  			    1/*"/"*/ + CATEGORY_LEN >= PATH_MAX) -				return(EFAULT); +				return (ENAMETOOLONG);  			_PathLocale = strdup(p);  			if (_PathLocale == NULL)  				return (errno); @@ -95,27 +100,27 @@ setrunelocale(encoding)  	(void) strcat(name, "/LC_CTYPE");  	if ((fp = fopen(name, "r")) == NULL) -		return(ENOENT); +		return (errno);  	if ((rl = _Read_RuneMagi(fp)) == 0) {  		fclose(fp); -		return(EFTYPE); +		return (EFTYPE);  	}  	fclose(fp);  	if (!rl->encoding[0]) -		return(EINVAL); +		return (EFTYPE);  	else if (!strcmp(rl->encoding, "NONE")) -		return(_none_init(rl)); +		return (_none_init(rl));  	else if (!strcmp(rl->encoding, "UTF2")) -		return(_UTF2_init(rl)); +		return (_UTF2_init(rl));  	else if (!strcmp(rl->encoding, "EUC")) -		return(_EUC_init(rl)); +		return (_EUC_init(rl));  	else if (!strcmp(rl->encoding, "BIG5")) -		return(_BIG5_init(rl)); +		return (_BIG5_init(rl));  	else if (!strcmp(rl->encoding, "MSKanji")) -		return(_MSKanji_init(rl)); +		return (_MSKanji_init(rl));  	else -		return(EINVAL); +		return (EFTYPE);  }  | 
