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