Home | History | Annotate | Download | only in gen
      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