xref: /illumos-gate/usr/src/lib/libc/port/gen/gettxt.c (revision a07094369b21309434206d9b3601d162693466fc)
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