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 510a4fa49Srie * Common Development and Distribution License (the "License"). 610a4fa49Srie * 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 */ 2110a4fa49Srie 227c478bd9Sstevel@tonic-gate /* 2356deab07SRod Evans * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267257d1b4Sraf 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * Messaging support. To minimize ld.so.1's overhead, messaging support isn't 297c478bd9Sstevel@tonic-gate * enabled until we need to contruct a message - Note that we don't rely on the 307c478bd9Sstevel@tonic-gate * application to signify whether messaging is applicable, as many message 317c478bd9Sstevel@tonic-gate * conditions (such as relocations) are generated before the application gains 327c478bd9Sstevel@tonic-gate * control. 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * This code implements a very trimmed down version of the capabilities found 357c478bd9Sstevel@tonic-gate * via setlocale(3c), textdomain(3i) and gettext(3i). Dragging in the original 367c478bd9Sstevel@tonic-gate * routines from libc/libintl isn't possible as they cause all i18n support to 377c478bd9Sstevel@tonic-gate * be included which is far too expensive for ld.so.1. 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #include <sys/types.h> 417c478bd9Sstevel@tonic-gate #include <sys/mman.h> 427c478bd9Sstevel@tonic-gate #include <sys/stat.h> 437c478bd9Sstevel@tonic-gate #include <string.h> 447c478bd9Sstevel@tonic-gate #include <stdio.h> 457c478bd9Sstevel@tonic-gate #include <stdlib.h> 467c478bd9Sstevel@tonic-gate #include <unistd.h> 477c478bd9Sstevel@tonic-gate #include <fcntl.h> 487c478bd9Sstevel@tonic-gate #include <limits.h> 497257d1b4Sraf #include <libintl.h> 507c478bd9Sstevel@tonic-gate #include "_rtld.h" 517c478bd9Sstevel@tonic-gate #include "msg.h" 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* 547c478bd9Sstevel@tonic-gate * A message object file (as generated by msgfmt(1)) consists of a message 557c478bd9Sstevel@tonic-gate * header, followed by a message list, followed by the msgid strings and then 567c478bd9Sstevel@tonic-gate * the msgstr strings. None of this is defined in any OSNET available headers 577c478bd9Sstevel@tonic-gate * so we have our own local definitions :-( 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate typedef struct { 607c478bd9Sstevel@tonic-gate int hdr_midlst; /* middle message no. */ 617c478bd9Sstevel@tonic-gate int hdr_lstcnt; /* total no. of message in the file */ 627c478bd9Sstevel@tonic-gate int hdr_msgidsz; /* size of msgids (in bytes) */ 637c478bd9Sstevel@tonic-gate int hdr_msgstrsz; /* size of msgstrs (in bytes) */ 647c478bd9Sstevel@tonic-gate int hdr_lstsz; /* size of message list (in bytes) */ 657c478bd9Sstevel@tonic-gate } Msghdr; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate typedef struct { 687c478bd9Sstevel@tonic-gate int lst_less; 697c478bd9Sstevel@tonic-gate int lst_more; 707c478bd9Sstevel@tonic-gate int lst_idoff; 717c478bd9Sstevel@tonic-gate int lst_stroff; 727c478bd9Sstevel@tonic-gate } Msglst; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate #define LEAFINDICATOR -99 757c478bd9Sstevel@tonic-gate #define OLD_MSG_STRUCT_SIZE 20 767c478bd9Sstevel@tonic-gate #define NEW_MSG_STRUCT_SIZE (sizeof (Msglst)) 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * Define a local structure for maintaining the domains we care about. 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate typedef struct { 827c478bd9Sstevel@tonic-gate const char *dom_name; 837c478bd9Sstevel@tonic-gate const Msghdr *dom_msghdr; 847c478bd9Sstevel@tonic-gate size_t dom_msgsz; 857c478bd9Sstevel@tonic-gate } Domain; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 897c478bd9Sstevel@tonic-gate * Perform a binary search of a message file (described by the Msghdr) for a 907c478bd9Sstevel@tonic-gate * msgid (string). Given a match return the associated msgstr, otherwise 917c478bd9Sstevel@tonic-gate * return the original msgid. 927c478bd9Sstevel@tonic-gate */ 937c478bd9Sstevel@tonic-gate static const char * 947c478bd9Sstevel@tonic-gate msgid_to_msgstr(const Msghdr *msghdr, const char *msgid) 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate const Msglst *list, *_list; 977c478bd9Sstevel@tonic-gate const char *ids, *strs, *_msgid; 987c478bd9Sstevel@tonic-gate int off, var; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* 1017c478bd9Sstevel@tonic-gate * Establish pointers to the message list (we actually start the search 1027c478bd9Sstevel@tonic-gate * in the middle of this list (hdr->midlst), the msgid strings (ids) 1037c478bd9Sstevel@tonic-gate * and the msgstr strings (strs). 1047c478bd9Sstevel@tonic-gate */ 1057c478bd9Sstevel@tonic-gate list = (const Msglst *)&msghdr[1]; 1067c478bd9Sstevel@tonic-gate ids = (const char *)&list[msghdr->hdr_lstcnt]; 1077c478bd9Sstevel@tonic-gate strs = (const char *)&ids[msghdr->hdr_msgidsz]; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate off = msghdr->hdr_midlst; 1107c478bd9Sstevel@tonic-gate 111*9ac6ca4dSRod Evans for (;;) { 1127c478bd9Sstevel@tonic-gate _list = list + off; 1137c478bd9Sstevel@tonic-gate _msgid = ids + _list->lst_idoff; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate if ((var = strcmp(_msgid, msgid)) == 0) 1167c478bd9Sstevel@tonic-gate return (strs + _list->lst_stroff); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate if (var < 0) { 1197c478bd9Sstevel@tonic-gate if ((off = _list->lst_less) == LEAFINDICATOR) 1207c478bd9Sstevel@tonic-gate return (msgid); 1217c478bd9Sstevel@tonic-gate } else { 1227c478bd9Sstevel@tonic-gate if ((off = _list->lst_more) == LEAFINDICATOR) 1237c478bd9Sstevel@tonic-gate return (msgid); 1247c478bd9Sstevel@tonic-gate } 125*9ac6ca4dSRod Evans } 1267c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1277c478bd9Sstevel@tonic-gate return (NULL); /* keep gcc happy */ 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate * Open a message file. Following the model of setlocale(3c) we obtain the 1327c478bd9Sstevel@tonic-gate * message file for the specified locale. Normally this is: 1337c478bd9Sstevel@tonic-gate * 1347c478bd9Sstevel@tonic-gate * /usr/lib/locale/`locale'/LC_MESSAGES/`domain'.mo 1357c478bd9Sstevel@tonic-gate * 1367c478bd9Sstevel@tonic-gate * The locale was determined during initial environment processing (see 1377c478bd9Sstevel@tonic-gate * readenv()), which was determined from an LC_ALL, LC_MESSAGES or LANG 1387c478bd9Sstevel@tonic-gate * setting. If no locale has been specified, or any file processing errors 1397c478bd9Sstevel@tonic-gate * occur, internationalization is basically disabled. 1407c478bd9Sstevel@tonic-gate */ 1417c478bd9Sstevel@tonic-gate static void 1427c478bd9Sstevel@tonic-gate open_mofile(Domain * dom) 1437c478bd9Sstevel@tonic-gate { 1447c478bd9Sstevel@tonic-gate const char *domain = dom->dom_name; 1457c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 1467c478bd9Sstevel@tonic-gate int fd; 147cb511613SAli Bahrami rtld_stat_t status; 1487c478bd9Sstevel@tonic-gate const Msghdr *msghdr; 1497c478bd9Sstevel@tonic-gate int count; 1507c478bd9Sstevel@tonic-gate size_t size_tot, size_old, size_new; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate dom->dom_msghdr = (Msghdr *)-1; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate (void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_FMT_MSGFILE), 15510a4fa49Srie glcs[CI_LCMESSAGES].lc_un.lc_ptr, domain); 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate if ((fd = open(path, O_RDONLY, 0)) == -1) 1587c478bd9Sstevel@tonic-gate return; 1597c478bd9Sstevel@tonic-gate 160cb511613SAli Bahrami if ((rtld_fstat(fd, &status) == -1) || 1617c478bd9Sstevel@tonic-gate (status.st_size < sizeof (Msghdr))) { 1627c478bd9Sstevel@tonic-gate (void) close(fd); 1637c478bd9Sstevel@tonic-gate return; 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate /* LINTED */ 1677c478bd9Sstevel@tonic-gate if ((msghdr = (Msghdr *)mmap(0, status.st_size, PROT_READ, MAP_SHARED, 1687c478bd9Sstevel@tonic-gate fd, 0)) == (Msghdr *)-1) { 1697c478bd9Sstevel@tonic-gate (void) close(fd); 1707c478bd9Sstevel@tonic-gate return; 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate (void) close(fd); 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate /* checks if opened file is msg file */ 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate count = msghdr->hdr_lstcnt; 1777c478bd9Sstevel@tonic-gate if (((count - 1) / 2) != msghdr->hdr_midlst) { 1787c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)msghdr, status.st_size); 1797c478bd9Sstevel@tonic-gate return; 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate size_tot = msghdr->hdr_lstsz; 1837c478bd9Sstevel@tonic-gate size_old = OLD_MSG_STRUCT_SIZE * count; 1847c478bd9Sstevel@tonic-gate size_new = (int)NEW_MSG_STRUCT_SIZE * count; 1857c478bd9Sstevel@tonic-gate if ((size_tot != size_old) && (size_tot != size_new)) { 1867c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)msghdr, status.st_size); 1877c478bd9Sstevel@tonic-gate return; 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate size_tot = msghdr->hdr_msgidsz + msghdr->hdr_msgstrsz + 1917c478bd9Sstevel@tonic-gate (int)sizeof (Msghdr); 1927c478bd9Sstevel@tonic-gate if ((size_tot + size_old < status.st_size) && 1937c478bd9Sstevel@tonic-gate (size_tot + size_new < status.st_size)) { 1947c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)msghdr, status.st_size); 1957c478bd9Sstevel@tonic-gate return; 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * We have a good message file, initialize the Domain information. 2007c478bd9Sstevel@tonic-gate */ 2017c478bd9Sstevel@tonic-gate dom->dom_msghdr = msghdr; 2027c478bd9Sstevel@tonic-gate dom->dom_msgsz = status.st_size; 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate /* 2077c478bd9Sstevel@tonic-gate * Two interfaces are established to support our internationalization. 2087c478bd9Sstevel@tonic-gate * gettext(3i) calls originate from all link-editor libraries, and thus the 2097257d1b4Sraf * SUNW_OST_SGS domain is assumed. dgettext() calls originate from 2107c478bd9Sstevel@tonic-gate * dependencies such as libelf and libc. 2117c478bd9Sstevel@tonic-gate * 2127c478bd9Sstevel@tonic-gate * Presently we support two domains (libc's strerror() uses SUNW_OST_OSLIB). 2137c478bd9Sstevel@tonic-gate * If ld.so.1's dependencies evolve to require more then the `domain' array 2147c478bd9Sstevel@tonic-gate * maintained below can be enlarged or made more dynamic in nature. 2157c478bd9Sstevel@tonic-gate */ 2167257d1b4Sraf char * 2177257d1b4Sraf dgettext(const char *domain, const char *msgid) 2187c478bd9Sstevel@tonic-gate { 2197c478bd9Sstevel@tonic-gate static int domaincnt = 0; 2207c478bd9Sstevel@tonic-gate static Domain *domains; 2217c478bd9Sstevel@tonic-gate Domain *_domain; 2227c478bd9Sstevel@tonic-gate int cnt; 2237c478bd9Sstevel@tonic-gate 22410a4fa49Srie if (glcs[CI_LCMESSAGES].lc_un.lc_val == 0) 2257257d1b4Sraf return ((char *)msgid); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* 2287c478bd9Sstevel@tonic-gate * Determine if we've initialized any domains yet. 2297c478bd9Sstevel@tonic-gate */ 2307c478bd9Sstevel@tonic-gate if (domaincnt == 0) { 23156deab07SRod Evans if ((domains = calloc(sizeof (Domain), 2)) == NULL) 2327257d1b4Sraf return ((char *)msgid); 2337c478bd9Sstevel@tonic-gate domains[0].dom_name = MSG_ORIG(MSG_SUNW_OST_SGS); 2347c478bd9Sstevel@tonic-gate domains[1].dom_name = MSG_ORIG(MSG_SUNW_OST_OSLIB); 2357c478bd9Sstevel@tonic-gate domaincnt = 2; 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* 2397c478bd9Sstevel@tonic-gate * If this is a new locale make sure we clean up any old ones. 2407c478bd9Sstevel@tonic-gate */ 2417c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_NEWLOCALE) { 2427c478bd9Sstevel@tonic-gate cnt = 0; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate for (_domain = domains; cnt < domaincnt; _domain++, cnt++) { 2457c478bd9Sstevel@tonic-gate if (_domain->dom_msghdr == 0) 2467c478bd9Sstevel@tonic-gate continue; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate if (_domain->dom_msghdr != (Msghdr *)-1) 2497c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)_domain->dom_msghdr, 2507c478bd9Sstevel@tonic-gate _domain->dom_msgsz); 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate _domain->dom_msghdr = 0; 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate rtld_flags &= ~RT_FL_NEWLOCALE; 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * Determine which domain we need. 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate for (cnt = 0, _domain = domains; cnt < domaincnt; _domain++, cnt++) { 2617c478bd9Sstevel@tonic-gate if (_domain->dom_name == domain) 2627c478bd9Sstevel@tonic-gate break; 2637c478bd9Sstevel@tonic-gate if (strcmp(_domain->dom_name, domain) == 0) 2647c478bd9Sstevel@tonic-gate break; 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate if (cnt == domaincnt) 2677257d1b4Sraf return ((char *)msgid); 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate /* 2707c478bd9Sstevel@tonic-gate * Determine if the domain has been initialized yet. 2717c478bd9Sstevel@tonic-gate */ 2727c478bd9Sstevel@tonic-gate if (_domain->dom_msghdr == 0) 2737c478bd9Sstevel@tonic-gate open_mofile(_domain); 2747c478bd9Sstevel@tonic-gate if (_domain->dom_msghdr == (Msghdr *)-1) 2757257d1b4Sraf return ((char *)msgid); 2767c478bd9Sstevel@tonic-gate 2777257d1b4Sraf return ((char *)msgid_to_msgstr(_domain->dom_msghdr, msgid)); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate /* 2817c478bd9Sstevel@tonic-gate * This satisfies any dependencies of code dragged in from libc, as we don't 2827c478bd9Sstevel@tonic-gate * want libc's gettext implementation in ld.so.1. This routine may not be 2837c478bd9Sstevel@tonic-gate * referenced, in which case -zignore will discard it. 2847c478bd9Sstevel@tonic-gate */ 2857c478bd9Sstevel@tonic-gate char * 2867c478bd9Sstevel@tonic-gate gettext(const char *msgid) 2877c478bd9Sstevel@tonic-gate { 2887257d1b4Sraf return ((char *)dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), msgid)); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /* 2927c478bd9Sstevel@tonic-gate * The sgsmsg.1l use requires the following interface. 2937c478bd9Sstevel@tonic-gate */ 2947c478bd9Sstevel@tonic-gate const char * 2957c478bd9Sstevel@tonic-gate _rtld_msg(Msg mid) 2967c478bd9Sstevel@tonic-gate { 2977257d1b4Sraf return ((char *)dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid))); 2987c478bd9Sstevel@tonic-gate } 299