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 ident "%Z%%M% %I% %E% SMI" 31 32 #pragma weak _gettxt = gettxt 33 34 #include "lint.h" 35 #include "libc.h" 36 #include <mtlib.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 <thread.h> 50 #include "../i18n/_locale.h" 51 #include "../i18n/_loc_path.h" 52 53 #define MESSAGES "/LC_MESSAGES/" 54 #define DB_NAME_LEN 15 55 56 #define handle_return(s) \ 57 ((char *)((s) != NULL && *(s) != '\0' ? (s) : not_found)) 58 59 extern char cur_cat[]; 60 extern rwlock_t _rw_cur_cat; 61 62 static mutex_t gettxt_lock = DEFAULTMUTEX; 63 static const char *not_found = "Message not found!!\n"; 64 static const char *loc_C = "C"; 65 66 struct db_list { 67 char db_name[DB_NAME_LEN]; /* name of the message file */ 68 uintptr_t addr; /* virtual memory address */ 69 struct db_list *next; 70 }; 71 72 struct db_cache { 73 char *loc; 74 struct db_list *info; 75 struct db_cache *next; 76 }; 77 78 static struct db_cache *db_cache; 79 80 char * 81 gettxt(const char *msg_id, const char *dflt_str) 82 { 83 struct db_cache *dbc; 84 struct db_list *dbl; 85 char msgfile[DB_NAME_LEN]; /* name of static shared library */ 86 int msgnum; /* message number */ 87 char pathname[PATH_MAX]; /* full pathname to message file */ 88 int fd; 89 struct stat64 sb; 90 void *addr; 91 char *tokp; 92 size_t name_len; 93 char *curloc; 94 95 if ((msg_id == NULL) || (*msg_id == '\0')) { 96 return (handle_return(dflt_str)); 97 } 98 99 /* parse msg_id */ 100 if (((tokp = strchr(msg_id, ':')) == NULL) || *(tokp+1) == '\0') 101 return (handle_return(dflt_str)); 102 if ((name_len = (tokp - msg_id)) >= DB_NAME_LEN) 103 return (handle_return(dflt_str)); 104 if (name_len > 0) { 105 (void) strncpy(msgfile, msg_id, name_len); 106 msgfile[name_len] = '\0'; 107 } else { 108 lrw_rdlock(&_rw_cur_cat); 109 if (cur_cat == NULL || *cur_cat == '\0') { 110 lrw_unlock(&_rw_cur_cat); 111 return (handle_return(dflt_str)); 112 } 113 /* 114 * We know the following strcpy is safe. 115 */ 116 (void) strcpy(msgfile, cur_cat); 117 lrw_unlock(&_rw_cur_cat); 118 } 119 while (*++tokp) { 120 if (!isdigit((unsigned char)*tokp)) 121 return (handle_return(dflt_str)); 122 } 123 msgnum = atoi(msg_id + name_len + 1); 124 curloc = setlocale(LC_MESSAGES, NULL); 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