xref: /minix3/lib/libc/nls/catopen.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: catopen.c,v 1.33 2014/09/16 01:30:28 christos Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*-
42fe8fb19SBen Gras  * Copyright (c) 1996 The NetBSD Foundation, Inc.
52fe8fb19SBen Gras  * All rights reserved.
62fe8fb19SBen Gras  *
72fe8fb19SBen Gras  * This code is derived from software contributed to The NetBSD Foundation
82fe8fb19SBen Gras  * by J.T. Conklin.
92fe8fb19SBen Gras  *
102fe8fb19SBen Gras  * Redistribution and use in source and binary forms, with or without
112fe8fb19SBen Gras  * modification, are permitted provided that the following conditions
122fe8fb19SBen Gras  * are met:
132fe8fb19SBen Gras  * 1. Redistributions of source code must retain the above copyright
142fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer.
152fe8fb19SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
162fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer in the
172fe8fb19SBen Gras  *    documentation and/or other materials provided with the distribution.
182fe8fb19SBen Gras  *
192fe8fb19SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
202fe8fb19SBen Gras  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
212fe8fb19SBen Gras  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
222fe8fb19SBen Gras  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
232fe8fb19SBen Gras  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
242fe8fb19SBen Gras  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
252fe8fb19SBen Gras  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
262fe8fb19SBen Gras  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
272fe8fb19SBen Gras  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
282fe8fb19SBen Gras  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
292fe8fb19SBen Gras  * POSSIBILITY OF SUCH DAMAGE.
302fe8fb19SBen Gras  */
312fe8fb19SBen Gras 
322fe8fb19SBen Gras #include <sys/cdefs.h>
33*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: catopen.c,v 1.33 2014/09/16 01:30:28 christos Exp $");
342fe8fb19SBen Gras 
352fe8fb19SBen Gras #define _NLS_PRIVATE
3684d9c625SLionel Sambuc #define __SETLOCALE_SOURCE__
372fe8fb19SBen Gras 
382fe8fb19SBen Gras #include "namespace.h"
392fe8fb19SBen Gras #include <sys/param.h>
402fe8fb19SBen Gras #include <sys/stat.h>
412fe8fb19SBen Gras #include <sys/mman.h>
422fe8fb19SBen Gras 
432fe8fb19SBen Gras #include <assert.h>
442fe8fb19SBen Gras #include <fcntl.h>
452fe8fb19SBen Gras #include <limits.h>
462fe8fb19SBen Gras #include <locale.h>
472fe8fb19SBen Gras #include <nl_types.h>
482fe8fb19SBen Gras #include <stdlib.h>
492fe8fb19SBen Gras #include <string.h>
502fe8fb19SBen Gras #include <unistd.h>
512fe8fb19SBen Gras 
522fe8fb19SBen Gras #include "citrus_namespace.h"
532fe8fb19SBen Gras #include "citrus_bcs.h"
542fe8fb19SBen Gras #include "citrus_region.h"
552fe8fb19SBen Gras #include "citrus_lookup.h"
562fe8fb19SBen Gras #include "citrus_aliasname_local.h"
5784d9c625SLionel Sambuc #include "setlocale_local.h"
582fe8fb19SBen Gras 
592fe8fb19SBen Gras #define NLS_ALIAS_DB "/usr/share/nls/nls.alias"
602fe8fb19SBen Gras 
612fe8fb19SBen Gras #define NLS_DEFAULT_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L"
622fe8fb19SBen Gras #define NLS_DEFAULT_LANG "C"
632fe8fb19SBen Gras 
642fe8fb19SBen Gras __weak_alias(catopen, _catopen)
6584d9c625SLionel Sambuc __weak_alias(catopen_l, _catopen_l)
662fe8fb19SBen Gras 
67f14fb602SLionel Sambuc static nl_catd load_msgcat(const char *);
682fe8fb19SBen Gras 
692fe8fb19SBen Gras nl_catd
catopen(const char * name,int oflag)7084d9c625SLionel Sambuc catopen(const char *name, int oflag)
7184d9c625SLionel Sambuc {
7284d9c625SLionel Sambuc 
7384d9c625SLionel Sambuc 	return catopen_l(name, oflag, _current_locale());
7484d9c625SLionel Sambuc }
7584d9c625SLionel Sambuc 
7684d9c625SLionel Sambuc nl_catd
catopen_l(const char * name,int oflag,locale_t loc)7784d9c625SLionel Sambuc catopen_l(const char *name, int oflag, locale_t loc)
782fe8fb19SBen Gras {
792fe8fb19SBen Gras 	char tmppath[PATH_MAX+1];
802fe8fb19SBen Gras 	const char *nlspath;
812fe8fb19SBen Gras 	const char *lang, *reallang;
822fe8fb19SBen Gras 	char *t;
832fe8fb19SBen Gras 	const char *s, *u;
842fe8fb19SBen Gras 	nl_catd catd;
852fe8fb19SBen Gras 	char langbuf[PATH_MAX];
862fe8fb19SBen Gras 
872fe8fb19SBen Gras 	if (name == NULL || *name == '\0')
882fe8fb19SBen Gras 		return (nl_catd)-1;
892fe8fb19SBen Gras 
902fe8fb19SBen Gras 	/* absolute or relative path? */
912fe8fb19SBen Gras 	if (strchr(name, '/'))
922fe8fb19SBen Gras 		return load_msgcat(name);
932fe8fb19SBen Gras 
942fe8fb19SBen Gras 	if (issetugid() || (nlspath = getenv("NLSPATH")) == NULL)
952fe8fb19SBen Gras 		nlspath = NLS_DEFAULT_PATH;
96f14fb602SLionel Sambuc 	/*
9784d9c625SLionel Sambuc 	 * Historical note:
98f14fb602SLionel Sambuc 	 * http://www.hauN.org/ml/b-l-j/a/800/828.html (in japanese)
99f14fb602SLionel Sambuc 	 */
1002fe8fb19SBen Gras 	if (oflag == NL_CAT_LOCALE) {
10184d9c625SLionel Sambuc 		lang = loc->part_name[LC_MESSAGES];
102f14fb602SLionel Sambuc 	} else {
1032fe8fb19SBen Gras 		lang = getenv("LANG");
1042fe8fb19SBen Gras 	}
1052fe8fb19SBen Gras 	if (lang == NULL || strchr(lang, '/'))
1062fe8fb19SBen Gras 		lang = NLS_DEFAULT_LANG;
1072fe8fb19SBen Gras 
1082fe8fb19SBen Gras 	reallang = __unaliasname(NLS_ALIAS_DB, lang, langbuf, sizeof(langbuf));
1092fe8fb19SBen Gras 	if (reallang == NULL)
1102fe8fb19SBen Gras 		reallang = lang;
1112fe8fb19SBen Gras 
1122fe8fb19SBen Gras 	s = nlspath;
1132fe8fb19SBen Gras 	t = tmppath;
1142fe8fb19SBen Gras 	do {
1152fe8fb19SBen Gras 		while (*s && *s != ':') {
1162fe8fb19SBen Gras 			if (*s == '%') {
1172fe8fb19SBen Gras 				switch (*(++s)) {
1182fe8fb19SBen Gras 				case 'L':	/* locale */
1192fe8fb19SBen Gras 					u = reallang;
1202fe8fb19SBen Gras 					while (*u && t < tmppath + PATH_MAX)
1212fe8fb19SBen Gras 						*t++ = *u++;
1222fe8fb19SBen Gras 					break;
1232fe8fb19SBen Gras 				case 'N':	/* name */
1242fe8fb19SBen Gras 					u = name;
1252fe8fb19SBen Gras 					while (*u && t < tmppath + PATH_MAX)
1262fe8fb19SBen Gras 						*t++ = *u++;
1272fe8fb19SBen Gras 					break;
1282fe8fb19SBen Gras 				case 'l':	/* lang */
1292fe8fb19SBen Gras 				case 't':	/* territory */
1302fe8fb19SBen Gras 				case 'c':	/* codeset */
1312fe8fb19SBen Gras 					break;
1322fe8fb19SBen Gras 				default:
1332fe8fb19SBen Gras 					if (t < tmppath + PATH_MAX)
1342fe8fb19SBen Gras 						*t++ = *s;
1352fe8fb19SBen Gras 				}
1362fe8fb19SBen Gras 			} else {
1372fe8fb19SBen Gras 				if (t < tmppath + PATH_MAX)
1382fe8fb19SBen Gras 					*t++ = *s;
1392fe8fb19SBen Gras 			}
1402fe8fb19SBen Gras 			s++;
1412fe8fb19SBen Gras 		}
1422fe8fb19SBen Gras 
1432fe8fb19SBen Gras 		*t = '\0';
1442fe8fb19SBen Gras 		catd = load_msgcat(tmppath);
1452fe8fb19SBen Gras 		if (catd != (nl_catd)-1)
1462fe8fb19SBen Gras 			return catd;
1472fe8fb19SBen Gras 
1482fe8fb19SBen Gras 		if (*s)
1492fe8fb19SBen Gras 			s++;
1502fe8fb19SBen Gras 		t = tmppath;
1512fe8fb19SBen Gras 	} while (*s);
1522fe8fb19SBen Gras 
1532fe8fb19SBen Gras 	return (nl_catd)-1;
1542fe8fb19SBen Gras }
1552fe8fb19SBen Gras 
1562fe8fb19SBen Gras static nl_catd
load_msgcat(const char * path)157f14fb602SLionel Sambuc load_msgcat(const char *path)
1582fe8fb19SBen Gras {
1592fe8fb19SBen Gras 	struct stat st;
1602fe8fb19SBen Gras 	nl_catd catd;
1612fe8fb19SBen Gras 	void *data;
1622fe8fb19SBen Gras 	int fd;
1632fe8fb19SBen Gras 
1642fe8fb19SBen Gras 	_DIAGASSERT(path != NULL);
1652fe8fb19SBen Gras 
166*0a6a1f1dSLionel Sambuc 	if ((fd = open(path, O_RDONLY|O_CLOEXEC)) == -1)
1672fe8fb19SBen Gras 		return (nl_catd)-1;
1682fe8fb19SBen Gras 
1692fe8fb19SBen Gras 	if (fstat(fd, &st) != 0) {
1702fe8fb19SBen Gras 		close (fd);
1712fe8fb19SBen Gras 		return (nl_catd)-1;
1722fe8fb19SBen Gras 	}
1732fe8fb19SBen Gras 
1742fe8fb19SBen Gras 	data = mmap(0, (size_t)st.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd,
1752fe8fb19SBen Gras 	    (off_t)0);
1762fe8fb19SBen Gras 	close (fd);
1772fe8fb19SBen Gras 
1782fe8fb19SBen Gras 	if (data == MAP_FAILED) {
1792fe8fb19SBen Gras 		return (nl_catd)-1;
1802fe8fb19SBen Gras 	}
1812fe8fb19SBen Gras 
1822fe8fb19SBen Gras 	if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) !=
1832fe8fb19SBen Gras 	    _NLS_MAGIC) {
1842fe8fb19SBen Gras 		munmap(data, (size_t)st.st_size);
1852fe8fb19SBen Gras 		return (nl_catd)-1;
1862fe8fb19SBen Gras 	}
1872fe8fb19SBen Gras 
1882fe8fb19SBen Gras 	if ((catd = malloc(sizeof (*catd))) == NULL) {
1892fe8fb19SBen Gras 		munmap(data, (size_t)st.st_size);
1902fe8fb19SBen Gras 		return (nl_catd)-1;
1912fe8fb19SBen Gras 	}
1922fe8fb19SBen Gras 
1932fe8fb19SBen Gras 	catd->__data = data;
1942fe8fb19SBen Gras 	catd->__size = (int)st.st_size;
1952fe8fb19SBen Gras 	return catd;
1962fe8fb19SBen Gras }
197