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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 /* Copyright (c) 1988 AT&T */ 31 /* All Rights Reserved */ 32 33 34 #pragma weak gettxt = _gettxt 35 36 #include "synonyms.h" 37 #include <ctype.h> 38 #include <string.h> 39 #include <locale.h> 40 #include <fcntl.h> 41 #include <sys/types.h> 42 #include <sys/file.h> 43 #include <sys/mman.h> 44 #include <sys/stat.h> 45 #include <pfmt.h> 46 #include <stdlib.h> 47 #include <unistd.h> 48 #include <limits.h> 49 #include "../i18n/_locale.h" 50 #include "../i18n/_loc_path.h" 51 52 #define MAXDB 10 /* maximum number of data bases per program */ 53 #define MESSAGES "/LC_MESSAGES/" 54 #define DB_NAME_LEN 15 55 56 char *handle_return(const char *); 57 58 /* support multiple versions of a package */ 59 60 char *Msgdb = (char *)NULL; 61 62 static char *saved_locale = NULL; 63 static const char *not_found = "Message not found!!\n"; 64 65 static struct db_info { 66 char db_name[DB_NAME_LEN]; /* name of the message file */ 67 uintptr_t addr; /* virtual memory address */ 68 size_t length; 69 } *db_info; 70 71 static int db_count; /* number of currently accessible data bases */ 72 73 char * 74 gettxt(const char *msg_id, const char *dflt_str) 75 { 76 char msgfile[DB_NAME_LEN]; /* name of static shared library */ 77 int msgnum; /* message number */ 78 char pathname[PATH_MAX]; /* full pathname to message file */ 79 int i; 80 int new_locale = 0; 81 int fd; 82 struct stat64 sb; 83 void *addr; 84 char *tokp; 85 size_t name_len; 86 char *curloc; 87 88 if ((msg_id == NULL) || (*msg_id == NULL)) { 89 return (handle_return(dflt_str)); 90 } 91 92 /* first time called, allocate space */ 93 if (!db_info) { 94 if ((db_info = (struct db_info *) \ 95 malloc(MAXDB * sizeof (struct db_info))) == NULL) 96 return (handle_return(dflt_str)); 97 } 98 99 /* parse msg_id */ 100 101 if (((tokp = strchr(msg_id, ':')) == NULL) || *(tokp+1) == '\0') 102 return (handle_return(dflt_str)); 103 if ((name_len = (tokp - msg_id)) >= DB_NAME_LEN) 104 return (handle_return(dflt_str)); 105 if (name_len) { 106 (void) strncpy(msgfile, msg_id, name_len); 107 msgfile[name_len] = '\0'; 108 } else { 109 if (Msgdb && strlen(Msgdb) < DB_NAME_LEN) 110 (void) strcpy(msgfile, Msgdb); 111 else { 112 char *p; 113 p = (char *)setcat((const char *)0); 114 if ((p != NULL) && strlen(p) < DB_NAME_LEN) 115 (void) strcpy(msgfile, p); 116 else 117 return (handle_return(dflt_str)); 118 } 119 } 120 while (*++tokp) 121 if (!isdigit(*tokp)) 122 return (handle_return(dflt_str)); 123 msgnum = atoi(msg_id + name_len + 1); 124 125 /* Has locale been changed? */ 126 127 curloc = setlocale(LC_MESSAGES, NULL); 128 if (saved_locale != NULL && strcmp(curloc, saved_locale) == 0) { 129 for (i = 0; i < db_count; i++) 130 if (strcmp(db_info[i].db_name, msgfile) == 0) 131 break; 132 } else { /* new locale - clear everything */ 133 if (saved_locale) 134 free(saved_locale); 135 /* 136 * allocate at least 2 bytes, so that we can copy "C" 137 * without re-allocating the saved_locale. 138 */ 139 if ((saved_locale = malloc(strlen(curloc)+2)) == NULL) 140 return (handle_return(dflt_str)); 141 (void) strcpy(saved_locale, curloc); 142 for (i = 0; i < db_count; i++) { 143 (void) munmap((void *)db_info[i].addr, 144 db_info[i].length); 145 (void) strcpy(db_info[i].db_name, ""); 146 new_locale++; 147 } 148 db_count = 0; 149 } 150 if (new_locale || i == db_count) { 151 if (db_count == MAXDB) 152 return (handle_return(dflt_str)); 153 if (snprintf(pathname, sizeof (pathname), 154 _DFLT_LOC_PATH "%s" MESSAGES "%s", 155 saved_locale, msgfile) >= sizeof (pathname)) { 156 return (handle_return(dflt_str)); 157 } 158 if ((fd = open(pathname, O_RDONLY)) == -1 || 159 fstat64(fd, &sb) == -1 || 160 (addr = mmap(0, (size_t)sb.st_size, 161 PROT_READ, MAP_SHARED, 162 fd, 0)) == MAP_FAILED) { 163 if (fd != -1) 164 (void) close(fd); 165 if (strcmp(saved_locale, "C") == 0) 166 return (handle_return(dflt_str)); 167 168 /* Change locale to C */ 169 170 if (snprintf(pathname, sizeof (pathname), 171 _DFLT_LOC_PATH "C" MESSAGES "%s", 172 msgfile) >= sizeof (pathname)) { 173 return (handle_return(dflt_str)); 174 } 175 176 for (i = 0; i < db_count; i++) { 177 (void) munmap((void *)db_info[i].addr, 178 db_info[i].length); 179 (void) strcpy(db_info[i].db_name, ""); 180 } 181 db_count = 0; 182 if ((fd = open(pathname, O_RDONLY)) != -1 && 183 fstat64(fd, &sb) != -1 && 184 (addr = mmap(0, (size_t)sb.st_size, 185 PROT_READ, MAP_SHARED, 186 fd, 0)) != MAP_FAILED) { 187 (void) strcpy(saved_locale, "C"); 188 } else { 189 if (fd != -1) 190 (void) close(fd); 191 return (handle_return(dflt_str)); 192 } 193 } 194 if (fd != -1) 195 (void) close(fd); 196 197 /* save file name, memory address, fd and size */ 198 199 (void) strcpy(db_info[db_count].db_name, msgfile); 200 db_info[db_count].addr = (uintptr_t)addr; 201 db_info[db_count].length = (size_t)sb.st_size; 202 i = db_count; 203 db_count++; 204 } 205 /* check if msgnum out of domain */ 206 if (msgnum <= 0 || msgnum > *(int *)(db_info[i].addr)) 207 return (handle_return(dflt_str)); 208 /* return pointer to message */ 209 return ((char *)(db_info[i].addr + *(int *)(db_info[i].addr 210 + msgnum * sizeof (int)))); 211 } 212 213 char * 214 handle_return(const char *dflt_str) 215 { 216 return ((char *)(dflt_str && *dflt_str ? dflt_str : not_found)); 217 } 218