xref: /illumos-gate/usr/src/lib/libc/port/gen/gettxt.c (revision 7257d1b4)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5e53d4db1Ssp  * Common Development and Distribution License (the "License").
6e53d4db1Ssp  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21e8031f0aSraf 
227c478bd9Sstevel@tonic-gate /*
23*7257d1b4Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
30*7257d1b4Sraf #pragma ident	"%Z%%M%	%I%	%E% SMI"
317c478bd9Sstevel@tonic-gate 
32*7257d1b4Sraf #pragma weak _gettxt = gettxt
337c478bd9Sstevel@tonic-gate 
34*7257d1b4Sraf #include "lint.h"
35e53d4db1Ssp #include "libc.h"
36e53d4db1Ssp #include <mtlib.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #include <string.h>
397c478bd9Sstevel@tonic-gate #include <locale.h>
407c478bd9Sstevel@tonic-gate #include <fcntl.h>
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
427c478bd9Sstevel@tonic-gate #include <sys/file.h>
437c478bd9Sstevel@tonic-gate #include <sys/mman.h>
447c478bd9Sstevel@tonic-gate #include <sys/stat.h>
457c478bd9Sstevel@tonic-gate #include <pfmt.h>
467c478bd9Sstevel@tonic-gate #include <stdlib.h>
477c478bd9Sstevel@tonic-gate #include <unistd.h>
487c478bd9Sstevel@tonic-gate #include <limits.h>
49e53d4db1Ssp #include <thread.h>
507c478bd9Sstevel@tonic-gate #include "../i18n/_locale.h"
517c478bd9Sstevel@tonic-gate #include "../i18n/_loc_path.h"
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #define	MESSAGES 	"/LC_MESSAGES/"
547c478bd9Sstevel@tonic-gate #define	DB_NAME_LEN	15
557c478bd9Sstevel@tonic-gate 
56e53d4db1Ssp #define	handle_return(s)	\
57e53d4db1Ssp 	((char *)((s) != NULL && *(s) != '\0' ? (s) : not_found))
587c478bd9Sstevel@tonic-gate 
59e53d4db1Ssp extern char cur_cat[];
60e53d4db1Ssp extern rwlock_t _rw_cur_cat;
617c478bd9Sstevel@tonic-gate 
62e53d4db1Ssp static mutex_t	gettxt_lock = DEFAULTMUTEX;
63e53d4db1Ssp static const char	*not_found = "Message not found!!\n";
64e53d4db1Ssp static const char	*loc_C = "C";
657c478bd9Sstevel@tonic-gate 
66e53d4db1Ssp struct db_list {
677c478bd9Sstevel@tonic-gate 	char	db_name[DB_NAME_LEN];	/* name of the message file */
687c478bd9Sstevel@tonic-gate 	uintptr_t	addr;		/* virtual memory address */
69e53d4db1Ssp 	struct db_list	*next;
70e53d4db1Ssp };
71e53d4db1Ssp 
72e53d4db1Ssp struct db_cache {
73e53d4db1Ssp 	char	*loc;
74e53d4db1Ssp 	struct db_list	*info;
75e53d4db1Ssp 	struct db_cache	*next;
76e53d4db1Ssp };
777c478bd9Sstevel@tonic-gate 
78e53d4db1Ssp static struct db_cache	*db_cache;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate char *
817c478bd9Sstevel@tonic-gate gettxt(const char *msg_id, const char *dflt_str)
827c478bd9Sstevel@tonic-gate {
83e53d4db1Ssp 	struct db_cache	*dbc;
84e53d4db1Ssp 	struct db_list	*dbl;
85e53d4db1Ssp 	char 	msgfile[DB_NAME_LEN];	/* name of static shared library */
86e53d4db1Ssp 	int	msgnum;			/* message number */
87e53d4db1Ssp 	char	pathname[PATH_MAX];	/* full pathname to message file */
88e53d4db1Ssp 	int	fd;
89e53d4db1Ssp 	struct stat64	sb;
907c478bd9Sstevel@tonic-gate 	void	*addr;
91e53d4db1Ssp 	char	*tokp;
92e53d4db1Ssp 	size_t	name_len;
937c478bd9Sstevel@tonic-gate 	char	*curloc;
947c478bd9Sstevel@tonic-gate 
95e53d4db1Ssp 	if ((msg_id == NULL) || (*msg_id == '\0')) {
967c478bd9Sstevel@tonic-gate 		return (handle_return(dflt_str));
977c478bd9Sstevel@tonic-gate 	}
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	/* parse msg_id */
1007c478bd9Sstevel@tonic-gate 	if (((tokp = strchr(msg_id, ':')) == NULL) || *(tokp+1) == '\0')
1017c478bd9Sstevel@tonic-gate 		return (handle_return(dflt_str));
1027c478bd9Sstevel@tonic-gate 	if ((name_len = (tokp - msg_id)) >= DB_NAME_LEN)
1037c478bd9Sstevel@tonic-gate 		return (handle_return(dflt_str));
104e53d4db1Ssp 	if (name_len > 0) {
1057c478bd9Sstevel@tonic-gate 		(void) strncpy(msgfile, msg_id, name_len);
1067c478bd9Sstevel@tonic-gate 		msgfile[name_len] = '\0';
1077c478bd9Sstevel@tonic-gate 	} else {
108e53d4db1Ssp 		lrw_rdlock(&_rw_cur_cat);
109e53d4db1Ssp 		if (cur_cat == NULL || *cur_cat == '\0') {
110e53d4db1Ssp 			lrw_unlock(&_rw_cur_cat);
111e53d4db1Ssp 			return (handle_return(dflt_str));
1127c478bd9Sstevel@tonic-gate 		}
113e53d4db1Ssp 		/*
114e53d4db1Ssp 		 * We know the following strcpy is safe.
115e53d4db1Ssp 		 */
116e53d4db1Ssp 		(void) strcpy(msgfile, cur_cat);
117e53d4db1Ssp 		lrw_unlock(&_rw_cur_cat);
1187c478bd9Sstevel@tonic-gate 	}
119e53d4db1Ssp 	while (*++tokp) {
120e53d4db1Ssp 		if (!isdigit((unsigned char)*tokp))
1217c478bd9Sstevel@tonic-gate 			return (handle_return(dflt_str));
122e53d4db1Ssp 	}
1237c478bd9Sstevel@tonic-gate 	msgnum = atoi(msg_id + name_len + 1);
1247c478bd9Sstevel@tonic-gate 	curloc = setlocale(LC_MESSAGES, NULL);
125e53d4db1Ssp 
126e53d4db1Ssp 	lmutex_lock(&gettxt_lock);
127e53d4db1Ssp 
128e53d4db1Ssp try_C:
129e53d4db1Ssp 	dbc = db_cache;
130e53d4db1Ssp 	while (dbc) {
131e53d4db1Ssp 		if (strcmp(curloc, dbc->loc) == 0) {
132e53d4db1Ssp 			dbl = dbc->info;
133e53d4db1Ssp 			while (dbl) {
134e53d4db1Ssp 				if (strcmp(msgfile, dbl->db_name) == 0) {
135e53d4db1Ssp 					/* msgfile found */
136e53d4db1Ssp 					lmutex_unlock(&gettxt_lock);
137e53d4db1Ssp 					goto msgfile_found;
138e53d4db1Ssp 				}
139e53d4db1Ssp 				dbl = dbl->next;
140e53d4db1Ssp 			}
141e53d4db1Ssp 			/* not found */
142e53d4db1Ssp 			break;
1437c478bd9Sstevel@tonic-gate 		}
144e53d4db1Ssp 		dbc = dbc->next;
1457c478bd9Sstevel@tonic-gate 	}
146e53d4db1Ssp 	if (dbc == NULL) {
147e53d4db1Ssp 		/* new locale */
148e53d4db1Ssp 		if ((dbc = lmalloc(sizeof (struct db_cache))) == NULL) {
149e53d4db1Ssp 			lmutex_unlock(&gettxt_lock);
1507c478bd9Sstevel@tonic-gate 			return (handle_return(dflt_str));
151e53d4db1Ssp 		}
152e53d4db1Ssp 		if ((dbc->loc = lmalloc(strlen(curloc) + 1)) == NULL) {
153e53d4db1Ssp 			lfree(dbc, sizeof (struct db_cache));
154e53d4db1Ssp 			lmutex_unlock(&gettxt_lock);
1557c478bd9Sstevel@tonic-gate 			return (handle_return(dflt_str));
1567c478bd9Sstevel@tonic-gate 		}
157e53d4db1Ssp 		dbc->info = NULL;
158e53d4db1Ssp 		(void) strcpy(dbc->loc, curloc);
159e53d4db1Ssp 		/* connect dbc to the dbc list */
160e53d4db1Ssp 		dbc->next = db_cache;
161e53d4db1Ssp 		db_cache = dbc;
162e53d4db1Ssp 	}
163e53d4db1Ssp 	if ((dbl = lmalloc(sizeof (struct db_list))) == NULL) {
164e53d4db1Ssp 		lmutex_unlock(&gettxt_lock);
165e53d4db1Ssp 		return (handle_return(dflt_str));
166e53d4db1Ssp 	}
1677c478bd9Sstevel@tonic-gate 
168e53d4db1Ssp 	if (snprintf(pathname, sizeof (pathname),
169e53d4db1Ssp 	    _DFLT_LOC_PATH "%s" MESSAGES "%s", dbc->loc, msgfile) >=
170e53d4db1Ssp 	    sizeof (pathname)) {
171e53d4db1Ssp 		lfree(dbl, sizeof (struct db_list));
172e53d4db1Ssp 		lmutex_unlock(&gettxt_lock);
173e53d4db1Ssp 		return (handle_return(dflt_str));
174e53d4db1Ssp 	}
175e53d4db1Ssp 	if ((fd = open(pathname, O_RDONLY)) == -1 ||
176e53d4db1Ssp 	    fstat64(fd, &sb) == -1 ||
177e53d4db1Ssp 	    (addr = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_SHARED,
178e53d4db1Ssp 	    fd, 0L)) == MAP_FAILED) {
1797c478bd9Sstevel@tonic-gate 		if (fd != -1)
1807c478bd9Sstevel@tonic-gate 			(void) close(fd);
181e53d4db1Ssp 		lfree(dbl, sizeof (struct db_list));
1827c478bd9Sstevel@tonic-gate 
183e53d4db1Ssp 		if (strcmp(dbc->loc, "C") == 0) {
184e53d4db1Ssp 			lmutex_unlock(&gettxt_lock);
185e53d4db1Ssp 			return (handle_return(dflt_str));
186e53d4db1Ssp 		}
187e53d4db1Ssp 		/* Change locale to C */
188e53d4db1Ssp 		curloc = (char *)loc_C;
189e53d4db1Ssp 		goto try_C;
1907c478bd9Sstevel@tonic-gate 	}
191e53d4db1Ssp 	(void) close(fd);
192e53d4db1Ssp 
193e53d4db1Ssp 	/* save file name, memory address, fd and size */
194e53d4db1Ssp 	(void) strcpy(dbl->db_name, msgfile);
195e53d4db1Ssp 	dbl->addr = (uintptr_t)addr;
196e53d4db1Ssp 
197e53d4db1Ssp 	/* connect dbl to the dbc->info list */
198e53d4db1Ssp 	dbl->next = dbc->info;
199e53d4db1Ssp 	dbc->info = dbl;
200e53d4db1Ssp 
201e53d4db1Ssp 	lmutex_unlock(&gettxt_lock);
202e53d4db1Ssp 
203e53d4db1Ssp msgfile_found:
2047c478bd9Sstevel@tonic-gate 	/* check if msgnum out of domain */
205e53d4db1Ssp 	if (msgnum <= 0 || msgnum > *(int *)dbl->addr)
2067c478bd9Sstevel@tonic-gate 		return (handle_return(dflt_str));
2077c478bd9Sstevel@tonic-gate 	/* return pointer to message */
208e53d4db1Ssp 	return ((char *)(dbl->addr +
209e53d4db1Ssp 	    *(int *)(dbl->addr + msgnum * sizeof (int))));
2107c478bd9Sstevel@tonic-gate }
211