xref: /onnv-gate/usr/src/lib/libc/port/gen/gettxt.c (revision 6812:febeba71273d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54447Ssp149894  * Common Development and Distribution License (the "License").
64447Ssp149894  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211219Sraf 
220Sstevel@tonic-gate /*
23*6812Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
30*6812Sraf #pragma ident	"%Z%%M%	%I%	%E% SMI"
310Sstevel@tonic-gate 
32*6812Sraf #pragma weak _gettxt = gettxt
330Sstevel@tonic-gate 
34*6812Sraf #include "lint.h"
354447Ssp149894 #include "libc.h"
364447Ssp149894 #include <mtlib.h>
370Sstevel@tonic-gate #include <ctype.h>
380Sstevel@tonic-gate #include <string.h>
390Sstevel@tonic-gate #include <locale.h>
400Sstevel@tonic-gate #include <fcntl.h>
410Sstevel@tonic-gate #include <sys/types.h>
420Sstevel@tonic-gate #include <sys/file.h>
430Sstevel@tonic-gate #include <sys/mman.h>
440Sstevel@tonic-gate #include <sys/stat.h>
450Sstevel@tonic-gate #include <pfmt.h>
460Sstevel@tonic-gate #include <stdlib.h>
470Sstevel@tonic-gate #include <unistd.h>
480Sstevel@tonic-gate #include <limits.h>
494447Ssp149894 #include <thread.h>
500Sstevel@tonic-gate #include "../i18n/_locale.h"
510Sstevel@tonic-gate #include "../i18n/_loc_path.h"
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #define	MESSAGES 	"/LC_MESSAGES/"
540Sstevel@tonic-gate #define	DB_NAME_LEN	15
550Sstevel@tonic-gate 
564447Ssp149894 #define	handle_return(s)	\
574447Ssp149894 	((char *)((s) != NULL && *(s) != '\0' ? (s) : not_found))
580Sstevel@tonic-gate 
594447Ssp149894 extern char cur_cat[];
604447Ssp149894 extern rwlock_t _rw_cur_cat;
610Sstevel@tonic-gate 
624447Ssp149894 static mutex_t	gettxt_lock = DEFAULTMUTEX;
634447Ssp149894 static const char	*not_found = "Message not found!!\n";
644447Ssp149894 static const char	*loc_C = "C";
650Sstevel@tonic-gate 
664447Ssp149894 struct db_list {
670Sstevel@tonic-gate 	char	db_name[DB_NAME_LEN];	/* name of the message file */
680Sstevel@tonic-gate 	uintptr_t	addr;		/* virtual memory address */
694447Ssp149894 	struct db_list	*next;
704447Ssp149894 };
710Sstevel@tonic-gate 
724447Ssp149894 struct db_cache {
734447Ssp149894 	char	*loc;
744447Ssp149894 	struct db_list	*info;
754447Ssp149894 	struct db_cache	*next;
764447Ssp149894 };
774447Ssp149894 
784447Ssp149894 static struct db_cache	*db_cache;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate char *
gettxt(const char * msg_id,const char * dflt_str)810Sstevel@tonic-gate gettxt(const char *msg_id, const char *dflt_str)
820Sstevel@tonic-gate {
834447Ssp149894 	struct db_cache	*dbc;
844447Ssp149894 	struct db_list	*dbl;
854447Ssp149894 	char 	msgfile[DB_NAME_LEN];	/* name of static shared library */
864447Ssp149894 	int	msgnum;			/* message number */
874447Ssp149894 	char	pathname[PATH_MAX];	/* full pathname to message file */
884447Ssp149894 	int	fd;
894447Ssp149894 	struct stat64	sb;
900Sstevel@tonic-gate 	void	*addr;
914447Ssp149894 	char	*tokp;
924447Ssp149894 	size_t	name_len;
930Sstevel@tonic-gate 	char	*curloc;
940Sstevel@tonic-gate 
954447Ssp149894 	if ((msg_id == NULL) || (*msg_id == '\0')) {
960Sstevel@tonic-gate 		return (handle_return(dflt_str));
970Sstevel@tonic-gate 	}
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	/* parse msg_id */
1000Sstevel@tonic-gate 	if (((tokp = strchr(msg_id, ':')) == NULL) || *(tokp+1) == '\0')
1010Sstevel@tonic-gate 		return (handle_return(dflt_str));
1020Sstevel@tonic-gate 	if ((name_len = (tokp - msg_id)) >= DB_NAME_LEN)
1030Sstevel@tonic-gate 		return (handle_return(dflt_str));
1044447Ssp149894 	if (name_len > 0) {
1050Sstevel@tonic-gate 		(void) strncpy(msgfile, msg_id, name_len);
1060Sstevel@tonic-gate 		msgfile[name_len] = '\0';
1070Sstevel@tonic-gate 	} else {
1084447Ssp149894 		lrw_rdlock(&_rw_cur_cat);
1094447Ssp149894 		if (cur_cat == NULL || *cur_cat == '\0') {
1104447Ssp149894 			lrw_unlock(&_rw_cur_cat);
1114447Ssp149894 			return (handle_return(dflt_str));
1120Sstevel@tonic-gate 		}
1134447Ssp149894 		/*
1144447Ssp149894 		 * We know the following strcpy is safe.
1154447Ssp149894 		 */
1164447Ssp149894 		(void) strcpy(msgfile, cur_cat);
1174447Ssp149894 		lrw_unlock(&_rw_cur_cat);
1180Sstevel@tonic-gate 	}
1194447Ssp149894 	while (*++tokp) {
1204447Ssp149894 		if (!isdigit((unsigned char)*tokp))
1210Sstevel@tonic-gate 			return (handle_return(dflt_str));
1224447Ssp149894 	}
1230Sstevel@tonic-gate 	msgnum = atoi(msg_id + name_len + 1);
1240Sstevel@tonic-gate 	curloc = setlocale(LC_MESSAGES, NULL);
1254447Ssp149894 
1264447Ssp149894 	lmutex_lock(&gettxt_lock);
1274447Ssp149894 
1284447Ssp149894 try_C:
1294447Ssp149894 	dbc = db_cache;
1304447Ssp149894 	while (dbc) {
1314447Ssp149894 		if (strcmp(curloc, dbc->loc) == 0) {
1324447Ssp149894 			dbl = dbc->info;
1334447Ssp149894 			while (dbl) {
1344447Ssp149894 				if (strcmp(msgfile, dbl->db_name) == 0) {
1354447Ssp149894 					/* msgfile found */
1364447Ssp149894 					lmutex_unlock(&gettxt_lock);
1374447Ssp149894 					goto msgfile_found;
1384447Ssp149894 				}
1394447Ssp149894 				dbl = dbl->next;
1404447Ssp149894 			}
1414447Ssp149894 			/* not found */
1424447Ssp149894 			break;
1434447Ssp149894 		}
1444447Ssp149894 		dbc = dbc->next;
1454447Ssp149894 	}
1464447Ssp149894 	if (dbc == NULL) {
1474447Ssp149894 		/* new locale */
1484447Ssp149894 		if ((dbc = lmalloc(sizeof (struct db_cache))) == NULL) {
1494447Ssp149894 			lmutex_unlock(&gettxt_lock);
1500Sstevel@tonic-gate 			return (handle_return(dflt_str));
1510Sstevel@tonic-gate 		}
1524447Ssp149894 		if ((dbc->loc = lmalloc(strlen(curloc) + 1)) == NULL) {
1534447Ssp149894 			lfree(dbc, sizeof (struct db_cache));
1544447Ssp149894 			lmutex_unlock(&gettxt_lock);
1550Sstevel@tonic-gate 			return (handle_return(dflt_str));
1560Sstevel@tonic-gate 		}
1574447Ssp149894 		dbc->info = NULL;
1584447Ssp149894 		(void) strcpy(dbc->loc, curloc);
1594447Ssp149894 		/* connect dbc to the dbc list */
1604447Ssp149894 		dbc->next = db_cache;
1614447Ssp149894 		db_cache = dbc;
1624447Ssp149894 	}
1634447Ssp149894 	if ((dbl = lmalloc(sizeof (struct db_list))) == NULL) {
1644447Ssp149894 		lmutex_unlock(&gettxt_lock);
1654447Ssp149894 		return (handle_return(dflt_str));
1664447Ssp149894 	}
1670Sstevel@tonic-gate 
1684447Ssp149894 	if (snprintf(pathname, sizeof (pathname),
1694447Ssp149894 	    _DFLT_LOC_PATH "%s" MESSAGES "%s", dbc->loc, msgfile) >=
1704447Ssp149894 	    sizeof (pathname)) {
1714447Ssp149894 		lfree(dbl, sizeof (struct db_list));
1724447Ssp149894 		lmutex_unlock(&gettxt_lock);
1734447Ssp149894 		return (handle_return(dflt_str));
1744447Ssp149894 	}
1754447Ssp149894 	if ((fd = open(pathname, O_RDONLY)) == -1 ||
1764447Ssp149894 	    fstat64(fd, &sb) == -1 ||
1774447Ssp149894 	    (addr = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_SHARED,
1784447Ssp149894 	    fd, 0L)) == MAP_FAILED) {
1790Sstevel@tonic-gate 		if (fd != -1)
1800Sstevel@tonic-gate 			(void) close(fd);
1814447Ssp149894 		lfree(dbl, sizeof (struct db_list));
1820Sstevel@tonic-gate 
1834447Ssp149894 		if (strcmp(dbc->loc, "C") == 0) {
1844447Ssp149894 			lmutex_unlock(&gettxt_lock);
1854447Ssp149894 			return (handle_return(dflt_str));
1864447Ssp149894 		}
1874447Ssp149894 		/* Change locale to C */
1884447Ssp149894 		curloc = (char *)loc_C;
1894447Ssp149894 		goto try_C;
1904447Ssp149894 	}
1914447Ssp149894 	(void) close(fd);
1920Sstevel@tonic-gate 
1934447Ssp149894 	/* save file name, memory address, fd and size */
1944447Ssp149894 	(void) strcpy(dbl->db_name, msgfile);
1954447Ssp149894 	dbl->addr = (uintptr_t)addr;
1964447Ssp149894 
1974447Ssp149894 	/* connect dbl to the dbc->info list */
1984447Ssp149894 	dbl->next = dbc->info;
1994447Ssp149894 	dbc->info = dbl;
2004447Ssp149894 
2014447Ssp149894 	lmutex_unlock(&gettxt_lock);
2024447Ssp149894 
2034447Ssp149894 msgfile_found:
2040Sstevel@tonic-gate 	/* check if msgnum out of domain */
2054447Ssp149894 	if (msgnum <= 0 || msgnum > *(int *)dbl->addr)
2060Sstevel@tonic-gate 		return (handle_return(dflt_str));
2070Sstevel@tonic-gate 	/* return pointer to message */
2084447Ssp149894 	return ((char *)(dbl->addr +
2094447Ssp149894 	    *(int *)(dbl->addr + msgnum * sizeof (int))));
2100Sstevel@tonic-gate }
211