1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate /* 29*7c478bd9Sstevel@tonic-gate * Messaging support. To minimize ld.so.1's overhead, messaging support isn't 30*7c478bd9Sstevel@tonic-gate * enabled until we need to contruct a message - Note that we don't rely on the 31*7c478bd9Sstevel@tonic-gate * application to signify whether messaging is applicable, as many message 32*7c478bd9Sstevel@tonic-gate * conditions (such as relocations) are generated before the application gains 33*7c478bd9Sstevel@tonic-gate * control. 34*7c478bd9Sstevel@tonic-gate * 35*7c478bd9Sstevel@tonic-gate * This code implements a very trimmed down version of the capabilities found 36*7c478bd9Sstevel@tonic-gate * via setlocale(3c), textdomain(3i) and gettext(3i). Dragging in the original 37*7c478bd9Sstevel@tonic-gate * routines from libc/libintl isn't possible as they cause all i18n support to 38*7c478bd9Sstevel@tonic-gate * be included which is far too expensive for ld.so.1. 39*7c478bd9Sstevel@tonic-gate */ 40*7c478bd9Sstevel@tonic-gate #include "_synonyms.h" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/mman.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 45*7c478bd9Sstevel@tonic-gate #include <string.h> 46*7c478bd9Sstevel@tonic-gate #include <stdio.h> 47*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 48*7c478bd9Sstevel@tonic-gate #include <unistd.h> 49*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 50*7c478bd9Sstevel@tonic-gate #include <limits.h> 51*7c478bd9Sstevel@tonic-gate #include "_rtld.h" 52*7c478bd9Sstevel@tonic-gate #include "msg.h" 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate /* 55*7c478bd9Sstevel@tonic-gate * A message object file (as generated by msgfmt(1)) consists of a message 56*7c478bd9Sstevel@tonic-gate * header, followed by a message list, followed by the msgid strings and then 57*7c478bd9Sstevel@tonic-gate * the msgstr strings. None of this is defined in any OSNET available headers 58*7c478bd9Sstevel@tonic-gate * so we have our own local definitions :-( 59*7c478bd9Sstevel@tonic-gate */ 60*7c478bd9Sstevel@tonic-gate typedef struct { 61*7c478bd9Sstevel@tonic-gate int hdr_midlst; /* middle message no. */ 62*7c478bd9Sstevel@tonic-gate int hdr_lstcnt; /* total no. of message in the file */ 63*7c478bd9Sstevel@tonic-gate int hdr_msgidsz; /* size of msgids (in bytes) */ 64*7c478bd9Sstevel@tonic-gate int hdr_msgstrsz; /* size of msgstrs (in bytes) */ 65*7c478bd9Sstevel@tonic-gate int hdr_lstsz; /* size of message list (in bytes) */ 66*7c478bd9Sstevel@tonic-gate } Msghdr; 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate typedef struct { 69*7c478bd9Sstevel@tonic-gate int lst_less; 70*7c478bd9Sstevel@tonic-gate int lst_more; 71*7c478bd9Sstevel@tonic-gate int lst_idoff; 72*7c478bd9Sstevel@tonic-gate int lst_stroff; 73*7c478bd9Sstevel@tonic-gate } Msglst; 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate #define LEAFINDICATOR -99 76*7c478bd9Sstevel@tonic-gate #define OLD_MSG_STRUCT_SIZE 20 77*7c478bd9Sstevel@tonic-gate #define NEW_MSG_STRUCT_SIZE (sizeof (Msglst)) 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate /* 80*7c478bd9Sstevel@tonic-gate * Define a local structure for maintaining the domains we care about. 81*7c478bd9Sstevel@tonic-gate */ 82*7c478bd9Sstevel@tonic-gate typedef struct { 83*7c478bd9Sstevel@tonic-gate const char *dom_name; 84*7c478bd9Sstevel@tonic-gate const Msghdr *dom_msghdr; 85*7c478bd9Sstevel@tonic-gate size_t dom_msgsz; 86*7c478bd9Sstevel@tonic-gate } Domain; 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate /* 90*7c478bd9Sstevel@tonic-gate * Perform a binary search of a message file (described by the Msghdr) for a 91*7c478bd9Sstevel@tonic-gate * msgid (string). Given a match return the associated msgstr, otherwise 92*7c478bd9Sstevel@tonic-gate * return the original msgid. 93*7c478bd9Sstevel@tonic-gate */ 94*7c478bd9Sstevel@tonic-gate static const char * 95*7c478bd9Sstevel@tonic-gate msgid_to_msgstr(const Msghdr *msghdr, const char *msgid) 96*7c478bd9Sstevel@tonic-gate { 97*7c478bd9Sstevel@tonic-gate const Msglst *list, *_list; 98*7c478bd9Sstevel@tonic-gate const char *ids, *strs, *_msgid; 99*7c478bd9Sstevel@tonic-gate int off, var; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate /* 102*7c478bd9Sstevel@tonic-gate * Establish pointers to the message list (we actually start the search 103*7c478bd9Sstevel@tonic-gate * in the middle of this list (hdr->midlst), the msgid strings (ids) 104*7c478bd9Sstevel@tonic-gate * and the msgstr strings (strs). 105*7c478bd9Sstevel@tonic-gate */ 106*7c478bd9Sstevel@tonic-gate list = (const Msglst *)&msghdr[1]; 107*7c478bd9Sstevel@tonic-gate ids = (const char *)&list[msghdr->hdr_lstcnt]; 108*7c478bd9Sstevel@tonic-gate strs = (const char *)&ids[msghdr->hdr_msgidsz]; 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate off = msghdr->hdr_midlst; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate do { 113*7c478bd9Sstevel@tonic-gate _list = list + off; 114*7c478bd9Sstevel@tonic-gate _msgid = ids + _list->lst_idoff; 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate if ((var = strcmp(_msgid, msgid)) == 0) 117*7c478bd9Sstevel@tonic-gate return (strs + _list->lst_stroff); 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate if (var < 0) { 120*7c478bd9Sstevel@tonic-gate if ((off = _list->lst_less) == LEAFINDICATOR) 121*7c478bd9Sstevel@tonic-gate return (msgid); 122*7c478bd9Sstevel@tonic-gate } else { 123*7c478bd9Sstevel@tonic-gate if ((off = _list->lst_more) == LEAFINDICATOR) 124*7c478bd9Sstevel@tonic-gate return (msgid); 125*7c478bd9Sstevel@tonic-gate } 126*7c478bd9Sstevel@tonic-gate } while (off); 127*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 128*7c478bd9Sstevel@tonic-gate return (NULL); /* keep gcc happy */ 129*7c478bd9Sstevel@tonic-gate } 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate /* 132*7c478bd9Sstevel@tonic-gate * Open a message file. Following the model of setlocale(3c) we obtain the 133*7c478bd9Sstevel@tonic-gate * message file for the specified locale. Normally this is: 134*7c478bd9Sstevel@tonic-gate * 135*7c478bd9Sstevel@tonic-gate * /usr/lib/locale/`locale'/LC_MESSAGES/`domain'.mo 136*7c478bd9Sstevel@tonic-gate * 137*7c478bd9Sstevel@tonic-gate * The locale was determined during initial environment processing (see 138*7c478bd9Sstevel@tonic-gate * readenv()), which was determined from an LC_ALL, LC_MESSAGES or LANG 139*7c478bd9Sstevel@tonic-gate * setting. If no locale has been specified, or any file processing errors 140*7c478bd9Sstevel@tonic-gate * occur, internationalization is basically disabled. 141*7c478bd9Sstevel@tonic-gate */ 142*7c478bd9Sstevel@tonic-gate static void 143*7c478bd9Sstevel@tonic-gate open_mofile(Domain * dom) 144*7c478bd9Sstevel@tonic-gate { 145*7c478bd9Sstevel@tonic-gate const char *domain = dom->dom_name; 146*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 147*7c478bd9Sstevel@tonic-gate int fd; 148*7c478bd9Sstevel@tonic-gate struct stat status; 149*7c478bd9Sstevel@tonic-gate const Msghdr *msghdr; 150*7c478bd9Sstevel@tonic-gate int count; 151*7c478bd9Sstevel@tonic-gate size_t size_tot, size_old, size_new; 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate dom->dom_msghdr = (Msghdr *)-1; 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate (void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_FMT_MSGFILE), 156*7c478bd9Sstevel@tonic-gate locale, domain); 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate if ((fd = open(path, O_RDONLY, 0)) == -1) 159*7c478bd9Sstevel@tonic-gate return; 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate if ((fstat(fd, &status) == -1) || 162*7c478bd9Sstevel@tonic-gate (status.st_size < sizeof (Msghdr))) { 163*7c478bd9Sstevel@tonic-gate (void) close(fd); 164*7c478bd9Sstevel@tonic-gate return; 165*7c478bd9Sstevel@tonic-gate } 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate /* LINTED */ 168*7c478bd9Sstevel@tonic-gate if ((msghdr = (Msghdr *)mmap(0, status.st_size, PROT_READ, MAP_SHARED, 169*7c478bd9Sstevel@tonic-gate fd, 0)) == (Msghdr *)-1) { 170*7c478bd9Sstevel@tonic-gate (void) close(fd); 171*7c478bd9Sstevel@tonic-gate return; 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate (void) close(fd); 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate /* checks if opened file is msg file */ 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate count = msghdr->hdr_lstcnt; 178*7c478bd9Sstevel@tonic-gate if (((count - 1) / 2) != msghdr->hdr_midlst) { 179*7c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)msghdr, status.st_size); 180*7c478bd9Sstevel@tonic-gate return; 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate size_tot = msghdr->hdr_lstsz; 184*7c478bd9Sstevel@tonic-gate size_old = OLD_MSG_STRUCT_SIZE * count; 185*7c478bd9Sstevel@tonic-gate size_new = (int)NEW_MSG_STRUCT_SIZE * count; 186*7c478bd9Sstevel@tonic-gate if ((size_tot != size_old) && (size_tot != size_new)) { 187*7c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)msghdr, status.st_size); 188*7c478bd9Sstevel@tonic-gate return; 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate size_tot = msghdr->hdr_msgidsz + msghdr->hdr_msgstrsz + 192*7c478bd9Sstevel@tonic-gate (int)sizeof (Msghdr); 193*7c478bd9Sstevel@tonic-gate if ((size_tot + size_old < status.st_size) && 194*7c478bd9Sstevel@tonic-gate (size_tot + size_new < status.st_size)) { 195*7c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)msghdr, status.st_size); 196*7c478bd9Sstevel@tonic-gate return; 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate /* 200*7c478bd9Sstevel@tonic-gate * We have a good message file, initialize the Domain information. 201*7c478bd9Sstevel@tonic-gate */ 202*7c478bd9Sstevel@tonic-gate dom->dom_msghdr = msghdr; 203*7c478bd9Sstevel@tonic-gate dom->dom_msgsz = status.st_size; 204*7c478bd9Sstevel@tonic-gate } 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate /* 208*7c478bd9Sstevel@tonic-gate * Two interfaces are established to support our internationalization. 209*7c478bd9Sstevel@tonic-gate * gettext(3i) calls originate from all link-editor libraries, and thus the 210*7c478bd9Sstevel@tonic-gate * SUNW_OST_SGS domain is assumed. _dgettext() calls originate from 211*7c478bd9Sstevel@tonic-gate * dependencies such as libelf and libc. 212*7c478bd9Sstevel@tonic-gate * 213*7c478bd9Sstevel@tonic-gate * Presently we support two domains (libc's strerror() uses SUNW_OST_OSLIB). 214*7c478bd9Sstevel@tonic-gate * If ld.so.1's dependencies evolve to require more then the `domain' array 215*7c478bd9Sstevel@tonic-gate * maintained below can be enlarged or made more dynamic in nature. 216*7c478bd9Sstevel@tonic-gate */ 217*7c478bd9Sstevel@tonic-gate const char * 218*7c478bd9Sstevel@tonic-gate _dgettext(const char *domain, const char *msgid) 219*7c478bd9Sstevel@tonic-gate { 220*7c478bd9Sstevel@tonic-gate static int domaincnt = 0; 221*7c478bd9Sstevel@tonic-gate static Domain *domains; 222*7c478bd9Sstevel@tonic-gate Domain *_domain; 223*7c478bd9Sstevel@tonic-gate int cnt; 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate if (locale == 0) 226*7c478bd9Sstevel@tonic-gate return (msgid); 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate /* 229*7c478bd9Sstevel@tonic-gate * Determine if we've initialized any domains yet. 230*7c478bd9Sstevel@tonic-gate */ 231*7c478bd9Sstevel@tonic-gate if (domaincnt == 0) { 232*7c478bd9Sstevel@tonic-gate if ((domains = (Domain *)calloc(sizeof (Domain), 2)) == 0) 233*7c478bd9Sstevel@tonic-gate return (msgid); 234*7c478bd9Sstevel@tonic-gate domains[0].dom_name = MSG_ORIG(MSG_SUNW_OST_SGS); 235*7c478bd9Sstevel@tonic-gate domains[1].dom_name = MSG_ORIG(MSG_SUNW_OST_OSLIB); 236*7c478bd9Sstevel@tonic-gate domaincnt = 2; 237*7c478bd9Sstevel@tonic-gate } 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate /* 240*7c478bd9Sstevel@tonic-gate * If this is a new locale make sure we clean up any old ones. 241*7c478bd9Sstevel@tonic-gate */ 242*7c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_NEWLOCALE) { 243*7c478bd9Sstevel@tonic-gate cnt = 0; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate for (_domain = domains; cnt < domaincnt; _domain++, cnt++) { 246*7c478bd9Sstevel@tonic-gate if (_domain->dom_msghdr == 0) 247*7c478bd9Sstevel@tonic-gate continue; 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate if (_domain->dom_msghdr != (Msghdr *)-1) 250*7c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)_domain->dom_msghdr, 251*7c478bd9Sstevel@tonic-gate _domain->dom_msgsz); 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate _domain->dom_msghdr = 0; 254*7c478bd9Sstevel@tonic-gate } 255*7c478bd9Sstevel@tonic-gate rtld_flags &= ~RT_FL_NEWLOCALE; 256*7c478bd9Sstevel@tonic-gate } 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate /* 259*7c478bd9Sstevel@tonic-gate * Determine which domain we need. 260*7c478bd9Sstevel@tonic-gate */ 261*7c478bd9Sstevel@tonic-gate for (cnt = 0, _domain = domains; cnt < domaincnt; _domain++, cnt++) { 262*7c478bd9Sstevel@tonic-gate if (_domain->dom_name == domain) 263*7c478bd9Sstevel@tonic-gate break; 264*7c478bd9Sstevel@tonic-gate if (strcmp(_domain->dom_name, domain) == 0) 265*7c478bd9Sstevel@tonic-gate break; 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate if (cnt == domaincnt) 268*7c478bd9Sstevel@tonic-gate return (msgid); 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate /* 271*7c478bd9Sstevel@tonic-gate * Determine if the domain has been initialized yet. 272*7c478bd9Sstevel@tonic-gate */ 273*7c478bd9Sstevel@tonic-gate if (_domain->dom_msghdr == 0) 274*7c478bd9Sstevel@tonic-gate open_mofile(_domain); 275*7c478bd9Sstevel@tonic-gate if (_domain->dom_msghdr == (Msghdr *)-1) 276*7c478bd9Sstevel@tonic-gate return (msgid); 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate return (msgid_to_msgstr(_domain->dom_msghdr, msgid)); 279*7c478bd9Sstevel@tonic-gate } 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate /* 282*7c478bd9Sstevel@tonic-gate * This satisfies any dependencies of code dragged in from libc, as we don't 283*7c478bd9Sstevel@tonic-gate * want libc's gettext implementation in ld.so.1. This routine may not be 284*7c478bd9Sstevel@tonic-gate * referenced, in which case -zignore will discard it. 285*7c478bd9Sstevel@tonic-gate */ 286*7c478bd9Sstevel@tonic-gate char * 287*7c478bd9Sstevel@tonic-gate gettext(const char *msgid) 288*7c478bd9Sstevel@tonic-gate { 289*7c478bd9Sstevel@tonic-gate return ((char *)_dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), msgid)); 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate /* 293*7c478bd9Sstevel@tonic-gate * The sgsmsg.1l use requires the following interface. 294*7c478bd9Sstevel@tonic-gate */ 295*7c478bd9Sstevel@tonic-gate const char * 296*7c478bd9Sstevel@tonic-gate _rtld_msg(Msg mid) 297*7c478bd9Sstevel@tonic-gate { 298*7c478bd9Sstevel@tonic-gate return ((char *)_dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid))); 299*7c478bd9Sstevel@tonic-gate } 300