/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * catopen.c * */ #pragma weak _catopen = catopen #pragma weak _catclose = catclose #include "lint.h" #include "libc.h" #include #include #include #include #include #include #include #include #include #include #include "../i18n/_loc_path.h" #include "nlspath_checks.h" #define SAFE_F 1 #define UNSAFE_F 0 static char * replace_nls_option(char *, char *, char *, char *, char *, char *, char *); static nl_catd file_open(const char *, int); static nl_catd process_nls_path(char *, int); nl_catd catopen(const char *name, int oflag) { nl_catd p; if (!name) { /* Null pointer */ errno = EFAULT; return ((nl_catd)-1); } else if (!*name) { /* Empty string */ errno = ENOENT; return ((nl_catd)-1); } else if (strchr(name, '/') != NULL) { /* If name contains '/', then it is complete file name */ p = file_open(name, SAFE_F); } else { /* Normal case */ p = process_nls_path((char *)name, oflag); } if (p == NULL) { /* Opening catalog file failed */ return ((nl_catd)-1); } else { return (p); } } /* * This routine will process NLSPATH environment variable. * It will return catd id whenever it finds valid catalog. */ static nl_catd process_nls_path(char *name, int oflag) { char *s, *s1, *s2, *t; char *nlspath, *lang, *territory, *codeset, *locale; char pathname[PATH_MAX + 1]; nl_catd p; /* * locale=language_territory.codeset * XPG4 uses LC_MESSAGES. * XPG3 uses LANG. * From the following two lines, choose one depending on XPG3 or 4. * * Chose XPG4. If oflag == NL_CAT_LOCALE, use LC_MESSAGES. */ if (oflag == NL_CAT_LOCALE) { locale_t loc = uselocale(NULL); locale = current_locale(loc, LC_MESSAGES); } else { locale = getenv("LANG"); } nlspath = getenv("NLSPATH"); lang = NULL; if (nlspath) { territory = NULL; codeset = NULL; /* * extract lang, territory and codeset from locale name */ if (locale) { lang = s = libc_strdup(locale); if (!lang) { /* strdup failed */ return (NULL); } s1 = s2 = NULL; while (s && *s) { if (*s == '_') { s1 = s; *s1++ = '\0'; } else if (*s == '.') { s2 = s; *s2++ = '\0'; } s++; } territory = s1; codeset = s2; } /* if (locale) */ /* * March through NLSPATH until finds valid cat file */ s = nlspath; while (*s) { if (*s == ':') { /* unqualified pathname is unsafe */ p = file_open(name, UNSAFE_F); if (p != NULL) { if (lang) libc_free(lang); return (p); } ++s; continue; } /* replace Substitution field */ s = replace_nls_option(s, name, pathname, locale, lang, territory, codeset); p = file_open(pathname, UNSAFE_F); if (p != NULL) { if (lang) libc_free(lang); return (p); } if (*s) ++s; } /* while */ } /* if (nlspath) */ /* lang is not used any more, free it */ if (lang) libc_free(lang); /* * Implementation dependent default location of XPG3. * We use /usr/lib/locale//LC_MESSAGES/%N. * If C locale, do not translate message. */ if (locale == NULL) { return (NULL); } else if (locale[0] == 'C' && locale[1] == '\0') { p = libc_malloc(sizeof (struct _nl_catd_struct)); if (p == NULL) { /* malloc failed */ return (NULL); } p->__content = NULL; p->__size = 0; p->__trust = 1; return (p); } s = _DFLT_LOC_PATH; t = pathname; while (*t++ = *s++) continue; t--; s = locale; while (*s && t < pathname + PATH_MAX) *t++ = *s++; s = "/LC_MESSAGES/"; while (*s && t < pathname + PATH_MAX) *t++ = *s++; s = name; while (*s && t < pathname + PATH_MAX) *t++ = *s++; *t = '\0'; return (file_open(pathname, SAFE_F)); } /* * This routine will replace substitution parameters in NLSPATH * with appropiate values. Returns expanded pathname. */ static char * replace_nls_option(char *s, char *name, char *pathname, char *locale, char *lang, char *territory, char *codeset) { char *t, *u; t = pathname; while (*s && *s != ':') { if (t < pathname + PATH_MAX) { /* * %% is considered a single % character (XPG). * %L : LC_MESSAGES (XPG4) LANG(XPG3) * %l : The language element from the current locale. * (XPG3, XPG4) */ if (*s != '%') *t++ = *s; else if (*++s == 'N') { u = name; while (*u && t < pathname + PATH_MAX) *t++ = *u++; } else if (*s == 'L') { if (locale) { u = locale; while (*u && t < pathname + PATH_MAX) *t++ = *u++; } } else if (*s == 'l') { if (lang) { u = lang; while (*u && *u != '_' && t < pathname + PATH_MAX) *t++ = *u++; } } else if (*s == 't') { if (territory) { u = territory; while (*u && *u != '.' && t < pathname + PATH_MAX) *t++ = *u++; } } else if (*s == 'c') { if (codeset) { u = codeset; while (*u && t < pathname + PATH_MAX) *t++ = *u++; } } else { if (t < pathname + PATH_MAX) *t++ = *s; } } ++s; } *t = '\0'; return (s); } /* * This routine will open file, mmap it, and return catd id. */ static nl_catd file_open(const char *name, int safe) { int fd; struct stat64 statbuf; void *addr; struct _cat_hdr *tmp; nl_catd tmp_catd; int trust; fd = nls_safe_open(name, &statbuf, &trust, safe); if (fd == -1) { return (NULL); } addr = mmap(0, (size_t)statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); (void) close(fd); if (addr == MAP_FAILED) { return (NULL); } /* check MAGIC number of catalogue file */ tmp = (struct _cat_hdr *)addr; if (tmp->__hdr_magic != _CAT_MAGIC) { (void) munmap(addr, (size_t)statbuf.st_size); return (NULL); } tmp_catd = libc_malloc(sizeof (struct _nl_catd_struct)); if (tmp_catd == NULL) { /* malloc failed */ (void) munmap(addr, statbuf.st_size); return (NULL); } tmp_catd->__content = addr; tmp_catd->__size = (int)statbuf.st_size; tmp_catd->__trust = trust; return (tmp_catd); } int catclose(nl_catd catd) { if (catd && catd != (nl_catd)-1) { if (catd->__content) { (void) munmap(catd->__content, catd->__size); catd->__content = NULL; } catd->__size = 0; catd->__trust = 0; libc_free(catd); } return (0); }