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 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma weak _gettxt = gettxt 31 32 #include "lint.h" 33 #include "libc.h" 34 #include <mtlib.h> 35 #include <ctype.h> 36 #include <string.h> 37 #include <locale.h> 38 #include <fcntl.h> 39 #include <sys/types.h> 40 #include <sys/file.h> 41 #include <sys/mman.h> 42 #include <sys/stat.h> 43 #include <pfmt.h> 44 #include <stdlib.h> 45 #include <unistd.h> 46 #include <limits.h> 47 #include <thread.h> 48 #include "../i18n/_locale.h" 49 #include "../i18n/_loc_path.h" 50 51 #define MESSAGES "/LC_MESSAGES/" 52 #define DB_NAME_LEN 15 53 54 #define handle_return(s) \ 55 ((char *)((s) != NULL && *(s) != '\0' ? (s) : not_found)) 56 57 extern char cur_cat[]; 58 extern rwlock_t _rw_cur_cat; 59 60 static mutex_t gettxt_lock = DEFAULTMUTEX; 61 static const char *not_found = "Message not found!!\n"; 62 static const char *loc_C = "C"; 63 64 struct db_list { 65 char db_name[DB_NAME_LEN]; /* name of the message file */ 66 uintptr_t addr; /* virtual memory address */ 67 struct db_list *next; 68 }; 69 70 struct db_cache { 71 char *loc; 72 struct db_list *info; 73 struct db_cache *next; 74 }; 75 76 static struct db_cache *db_cache; 77 78 char * 79 gettxt(const char *msg_id, const char *dflt_str) 80 { 81 struct db_cache *dbc; 82 struct db_list *dbl; 83 char msgfile[DB_NAME_LEN]; /* name of static shared library */ 84 int msgnum; /* message number */ 85 char pathname[PATH_MAX]; /* full pathname to message file */ 86 int fd; 87 struct stat64 sb; 88 void *addr; 89 char *tokp; 90 size_t name_len; 91 char *curloc; 92 locale_t loc; 93 94 if ((msg_id == NULL) || (*msg_id == '\0')) { 95 return (handle_return(dflt_str)); 96 } 97 98 /* parse msg_id */ 99 if (((tokp = strchr(msg_id, ':')) == NULL) || *(tokp+1) == '\0') 100 return (handle_return(dflt_str)); 101 if ((name_len = (tokp - msg_id)) >= DB_NAME_LEN) 102 return (handle_return(dflt_str)); 103 if (name_len > 0) { 104 (void) strncpy(msgfile, msg_id, name_len); 105 msgfile[name_len] = '\0'; 106 } else { 107 lrw_rdlock(&_rw_cur_cat); 108 if (cur_cat == NULL || *cur_cat == '\0') { 109 lrw_unlock(&_rw_cur_cat); 110 return (handle_return(dflt_str)); 111 } 112 /* 113 * We know the following strcpy is safe. 114 */ 115 (void) strcpy(msgfile, cur_cat); 116 lrw_unlock(&_rw_cur_cat); 117 } 118 while (*++tokp) { 119 if (!isdigit((unsigned char)*tokp)) 120 return (handle_return(dflt_str)); 121 } 122 msgnum = atoi(msg_id + name_len + 1); 123 loc = uselocale(NULL); 124 curloc = current_locale(loc, LC_MESSAGES); 125 126 lmutex_lock(&gettxt_lock); 127 128 try_C: 129 dbc = db_cache; 130 while (dbc) { 131 if (strcmp(curloc, dbc->loc) == 0) { 132 dbl = dbc->info; 133 while (dbl) { 134 if (strcmp(msgfile, dbl->db_name) == 0) { 135 /* msgfile found */ 136 lmutex_unlock(&gettxt_lock); 137 goto msgfile_found; 138 } 139 dbl = dbl->next; 140 } 141 /* not found */ 142 break; 143 } 144 dbc = dbc->next; 145 } 146 if (dbc == NULL) { 147 /* new locale */ 148 if ((dbc = lmalloc(sizeof (struct db_cache))) == NULL) { 149 lmutex_unlock(&gettxt_lock); 150 return (handle_return(dflt_str)); 151 } 152 if ((dbc->loc = lmalloc(strlen(curloc) + 1)) == NULL) { 153 lfree(dbc, sizeof (struct db_cache)); 154 lmutex_unlock(&gettxt_lock); 155 return (handle_return(dflt_str)); 156 } 157 dbc->info = NULL; 158 (void) strcpy(dbc->loc, curloc); 159 /* connect dbc to the dbc list */ 160 dbc->next = db_cache; 161 db_cache = dbc; 162 } 163 if ((dbl = lmalloc(sizeof (struct db_list))) == NULL) { 164 lmutex_unlock(&gettxt_lock); 165 return (handle_return(dflt_str)); 166 } 167 168 if (snprintf(pathname, sizeof (pathname), 169 _DFLT_LOC_PATH "%s" MESSAGES "%s", dbc->loc, msgfile) >= 170 sizeof (pathname)) { 171 lfree(dbl, sizeof (struct db_list)); 172 lmutex_unlock(&gettxt_lock); 173 return (handle_return(dflt_str)); 174 } 175 if ((fd = open(pathname, O_RDONLY)) == -1 || 176 fstat64(fd, &sb) == -1 || 177 (addr = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_SHARED, 178 fd, 0L)) == MAP_FAILED) { 179 if (fd != -1) 180 (void) close(fd); 181 lfree(dbl, sizeof (struct db_list)); 182 183 if (strcmp(dbc->loc, "C") == 0) { 184 lmutex_unlock(&gettxt_lock); 185 return (handle_return(dflt_str)); 186 } 187 /* Change locale to C */ 188 curloc = (char *)loc_C; 189 goto try_C; 190 } 191 (void) close(fd); 192 193 /* save file name, memory address, fd and size */ 194 (void) strcpy(dbl->db_name, msgfile); 195 dbl->addr = (uintptr_t)addr; 196 197 /* connect dbl to the dbc->info list */ 198 dbl->next = dbc->info; 199 dbc->info = dbl; 200 201 lmutex_unlock(&gettxt_lock); 202 203 msgfile_found: 204 /* check if msgnum out of domain */ 205 if (msgnum <= 0 || msgnum > *(int *)dbl->addr) 206 return (handle_return(dflt_str)); 207 /* return pointer to message */ 208 return ((char *)(dbl->addr + 209 *(int *)(dbl->addr + msgnum * sizeof (int)))); 210 } 211