1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * catopen.c 29 * 30 */ 31 32 #pragma weak _catopen = catopen 33 #pragma weak _catclose = catclose 34 35 #include "lint.h" 36 #include "libc.h" 37 #include "thr_uberdata.h" 38 #include <sys/types.h> 39 #include <unistd.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <sys/stat.h> 43 #include <sys/mman.h> 44 #include <nl_types.h> 45 #include <locale.h> 46 #include <limits.h> 47 #include <errno.h> 48 #include "../i18n/_loc_path.h" 49 #include "nlspath_checks.h" 50 51 #define SAFE_F 1 52 #define UNSAFE_F 0 53 54 static char * 55 replace_nls_option(char *, char *, char *, char *, char *, char *, char *); 56 static nl_catd file_open(const char *, int); 57 static nl_catd process_nls_path(char *, int); 58 59 nl_catd 60 catopen(const char *name, int oflag) 61 { 62 nl_catd p; 63 64 if (!name) { /* Null pointer */ 65 errno = EFAULT; 66 return ((nl_catd)-1); 67 } else if (!*name) { /* Empty string */ 68 errno = ENOENT; 69 return ((nl_catd)-1); 70 } else if (strchr(name, '/') != NULL) { 71 /* If name contains '/', then it is complete file name */ 72 p = file_open(name, SAFE_F); 73 } else { /* Normal case */ 74 p = process_nls_path((char *)name, oflag); 75 } 76 77 if (p == NULL) { /* Opening catalog file failed */ 78 return ((nl_catd)-1); 79 } else { 80 return (p); 81 } 82 } 83 84 85 /* 86 * This routine will process NLSPATH environment variable. 87 * It will return catd id whenever it finds valid catalog. 88 */ 89 static nl_catd 90 process_nls_path(char *name, int oflag) 91 { 92 char *s, *s1, *s2, *t; 93 char *nlspath, *lang, *territory, *codeset, *locale; 94 char pathname[PATH_MAX + 1]; 95 nl_catd p; 96 97 /* 98 * locale=language_territory.codeset 99 * XPG4 uses LC_MESSAGES. 100 * XPG3 uses LANG. 101 * From the following two lines, choose one depending on XPG3 or 4. 102 * 103 * Chose XPG4. If oflag == NL_CAT_LOCALE, use LC_MESSAGES. 104 */ 105 if (oflag == NL_CAT_LOCALE) { 106 locale_t loc = __curlocale(); 107 locale = current_locale(loc, LC_MESSAGES); 108 } else { 109 locale = getenv("LANG"); 110 } 111 112 nlspath = getenv("NLSPATH"); 113 lang = NULL; 114 if (nlspath) { 115 territory = NULL; 116 codeset = NULL; 117 /* 118 * extract lang, territory and codeset from locale name 119 */ 120 if (locale) { 121 lang = s = libc_strdup(locale); 122 if (!lang) { 123 /* strdup failed */ 124 return (NULL); 125 } 126 s1 = s2 = NULL; 127 while (s && *s) { 128 if (*s == '_') { 129 s1 = s; 130 *s1++ = '\0'; 131 } else if (*s == '.') { 132 s2 = s; 133 *s2++ = '\0'; 134 } 135 s++; 136 } 137 territory = s1; 138 codeset = s2; 139 } /* if (locale) */ 140 141 /* 142 * March through NLSPATH until finds valid cat file 143 */ 144 s = nlspath; 145 while (*s) { 146 if (*s == ':') { 147 /* unqualified pathname is unsafe */ 148 p = file_open(name, UNSAFE_F); 149 if (p != NULL) { 150 if (lang) 151 libc_free(lang); 152 return (p); 153 } 154 ++s; 155 continue; 156 } 157 158 /* replace Substitution field */ 159 s = replace_nls_option(s, name, pathname, locale, 160 lang, territory, codeset); 161 162 p = file_open(pathname, UNSAFE_F); 163 if (p != NULL) { 164 if (lang) 165 libc_free(lang); 166 return (p); 167 } 168 if (*s) 169 ++s; 170 } /* while */ 171 } /* if (nlspath) */ 172 173 /* lang is not used any more, free it */ 174 if (lang) 175 libc_free(lang); 176 177 /* 178 * Implementation dependent default location of XPG3. 179 * We use /usr/lib/locale/<locale>/LC_MESSAGES/%N. 180 * If C locale, do not translate message. 181 */ 182 if (locale == NULL) { 183 return (NULL); 184 } else if (locale[0] == 'C' && locale[1] == '\0') { 185 p = libc_malloc(sizeof (struct _nl_catd_struct)); 186 if (p == NULL) { 187 /* malloc failed */ 188 return (NULL); 189 } 190 p->__content = NULL; 191 p->__size = 0; 192 p->__trust = 1; 193 return (p); 194 } 195 196 s = _DFLT_LOC_PATH; 197 t = pathname; 198 while ((*t++ = *s++) != '\0') 199 continue; 200 t--; 201 s = locale; 202 while (*s && t < pathname + PATH_MAX) 203 *t++ = *s++; 204 s = "/LC_MESSAGES/"; 205 while (*s && t < pathname + PATH_MAX) 206 *t++ = *s++; 207 s = name; 208 while (*s && t < pathname + PATH_MAX) 209 *t++ = *s++; 210 *t = '\0'; 211 return (file_open(pathname, SAFE_F)); 212 } 213 214 215 /* 216 * This routine will replace substitution parameters in NLSPATH 217 * with appropiate values. Returns expanded pathname. 218 */ 219 static char * 220 replace_nls_option(char *s, char *name, char *pathname, char *locale, 221 char *lang, char *territory, char *codeset) 222 { 223 char *t, *u; 224 225 t = pathname; 226 while (*s && *s != ':') { 227 if (t < pathname + PATH_MAX) { 228 /* 229 * %% is considered a single % character (XPG). 230 * %L : LC_MESSAGES (XPG4) LANG(XPG3) 231 * %l : The language element from the current locale. 232 * (XPG3, XPG4) 233 */ 234 if (*s != '%') 235 *t++ = *s; 236 else if (*++s == 'N') { 237 u = name; 238 while (*u && t < pathname + PATH_MAX) 239 *t++ = *u++; 240 } else if (*s == 'L') { 241 if (locale) { 242 u = locale; 243 while (*u && t < pathname + PATH_MAX) 244 *t++ = *u++; 245 } 246 } else if (*s == 'l') { 247 if (lang) { 248 u = lang; 249 while (*u && *u != '_' && 250 t < pathname + PATH_MAX) 251 *t++ = *u++; 252 } 253 } else if (*s == 't') { 254 if (territory) { 255 u = territory; 256 while (*u && *u != '.' && 257 t < pathname + PATH_MAX) 258 *t++ = *u++; 259 } 260 } else if (*s == 'c') { 261 if (codeset) { 262 u = codeset; 263 while (*u && t < pathname + PATH_MAX) 264 *t++ = *u++; 265 } 266 } else { 267 if (t < pathname + PATH_MAX) 268 *t++ = *s; 269 } 270 } 271 ++s; 272 } 273 *t = '\0'; 274 return (s); 275 } 276 277 /* 278 * This routine will open file, mmap it, and return catd id. 279 */ 280 static nl_catd 281 file_open(const char *name, int safe) 282 { 283 int fd; 284 struct stat64 statbuf; 285 void *addr; 286 struct _cat_hdr *tmp; 287 nl_catd tmp_catd; 288 int trust; 289 290 fd = nls_safe_open(name, &statbuf, &trust, safe); 291 292 if (fd == -1) { 293 return (NULL); 294 } 295 296 addr = mmap(0, (size_t)statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); 297 (void) close(fd); 298 299 if (addr == MAP_FAILED) { 300 return (NULL); 301 } 302 303 /* check MAGIC number of catalogue file */ 304 tmp = (struct _cat_hdr *)addr; 305 if (tmp->__hdr_magic != _CAT_MAGIC) { 306 (void) munmap(addr, (size_t)statbuf.st_size); 307 return (NULL); 308 } 309 310 tmp_catd = libc_malloc(sizeof (struct _nl_catd_struct)); 311 if (tmp_catd == NULL) { 312 /* malloc failed */ 313 (void) munmap(addr, statbuf.st_size); 314 return (NULL); 315 } 316 tmp_catd->__content = addr; 317 tmp_catd->__size = (int)statbuf.st_size; 318 tmp_catd->__trust = trust; 319 320 return (tmp_catd); 321 } 322 323 int 324 catclose(nl_catd catd) 325 { 326 if (catd && 327 catd != (nl_catd)-1) { 328 if (catd->__content) { 329 (void) munmap(catd->__content, catd->__size); 330 catd->__content = NULL; 331 } 332 catd->__size = 0; 333 catd->__trust = 0; 334 libc_free(catd); 335 } 336 return (0); 337 } 338