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