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