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