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