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 *
gettxt(const char * msg_id,const char * dflt_str)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