xref: /openbsd-src/lib/libc/nls/catopen.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*-
2  * Copyright (c) 1996 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by J.T. Conklin.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *        This product includes software developed by the NetBSD
19  *        Foundation, Inc. and its contributors.
20  * 4. Neither the name of The NetBSD Foundation nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
28  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char rcsid[] = "$OpenBSD: catopen.c,v 1.9 2001/05/11 15:30:14 art Exp $";
39 #endif /* LIBC_SCCS and not lint */
40 
41 #define _NLS_PRIVATE
42 
43 #include <limits.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <sys/types.h>
47 #include <sys/param.h>
48 #include <sys/stat.h>
49 #include <sys/mman.h>
50 #include <unistd.h>
51 #include <fcntl.h>
52 #include <nl_types.h>
53 
54 #define NLS_DEFAULT_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L"
55 #define NLS_DEFAULT_LANG "C"
56 
57 static nl_catd load_msgcat __P((const char *));
58 
59 /* ARGSUSED */
60 nl_catd
61 _catopen(name, oflag)
62 	const char *name;
63 	int oflag;
64 {
65 	char tmppath[PATH_MAX];
66 	char *nlspath;
67 	char *lang;
68 	char *s, *t;
69 	const char *u;
70 	nl_catd catd;
71 
72 	if (name == NULL || *name == '\0')
73 		return (nl_catd) -1;
74 
75 	/* absolute or relative path? */
76 	if (strchr(name, '/'))
77 		return load_msgcat(name);
78 
79 	if (issetugid() != 0 || (nlspath = getenv("NLSPATH")) == NULL)
80 		nlspath = NLS_DEFAULT_PATH;
81 	if ((lang = getenv("LANG")) == NULL)
82 		lang = NLS_DEFAULT_LANG;
83 
84 	s = nlspath;
85 	t = tmppath;
86 	do {
87 		while (*s && *s != ':') {
88 			if (*s == '%') {
89 				switch (*(++s)) {
90 				case 'L':	/* locale */
91 					u = lang;
92 					while (*u && t < tmppath + PATH_MAX-1)
93 						*t++ = *u++;
94 					break;
95 				case 'N':	/* name */
96 					u = name;
97 					while (*u && t < tmppath + PATH_MAX-1)
98 						*t++ = *u++;
99 					break;
100 				case 'l':	/* lang */
101 				case 't':	/* territory */
102 				case 'c':	/* codeset */
103 					break;
104 				default:
105 					if (t < tmppath + PATH_MAX-1)
106 						*t++ = *s;
107 				}
108 			} else {
109 				if (t < tmppath + PATH_MAX-1)
110 					*t++ = *s;
111 			}
112 			s++;
113 		}
114 
115 		*t = '\0';
116 		catd = load_msgcat(tmppath);
117 		if (catd != (nl_catd) -1)
118 			return catd;
119 
120 		if (*s)
121 			s++;
122 		t = tmppath;
123 	} while (*s);
124 
125 	return (nl_catd) -1;
126 }
127 
128 static nl_catd
129 load_msgcat(path)
130 	const char *path;
131 {
132 	struct stat st;
133 	nl_catd catd;
134 	void *data;
135 	int fd;
136 
137 	if ((fd = open(path, O_RDONLY)) == -1)
138 		return (nl_catd) -1;
139 
140 	if (fstat(fd, &st) != 0) {
141 		close (fd);
142 		return (nl_catd) -1;
143 	}
144 
145 	data = mmap(0, (size_t) st.st_size, PROT_READ, MAP_SHARED, fd, (off_t)0);
146 	close (fd);
147 
148 	if (data == MAP_FAILED) {
149 		munmap(data, (size_t) st.st_size);
150 		return (nl_catd) -1;
151 	}
152 
153 	if (ntohl(((struct _nls_cat_hdr *) data)->__magic) != _NLS_MAGIC) {
154 		munmap(data, (size_t) st.st_size);
155 		return (nl_catd) -1;
156 	}
157 
158 	if ((catd = malloc(sizeof (*catd))) == 0) {
159 		munmap(data, (size_t) st.st_size);
160 		return (nl_catd) -1;
161 	}
162 
163 	catd->__data = data;
164 	catd->__size = st.st_size;
165 	return catd;
166 }
167