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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Messaging support. To minimize ld.so.1's overhead, messaging support isn't
29 * enabled until we need to contruct a message - Note that we don't rely on the
30 * application to signify whether messaging is applicable, as many message
31 * conditions (such as relocations) are generated before the application gains
34 * This code implements a very trimmed down version of the capabilities found
35 * via setlocale(3c), textdomain(3i) and gettext(3i). Dragging in the original
36 * routines from libc/libintl isn't possible as they cause all i18n support to
37 * be included which is far too expensive for ld.so.1.
40 #include <sys/types.h>
54 * A message object file (as generated by msgfmt(1)) consists of a message
55 * header, followed by a message list, followed by the msgid strings and then
56 * the msgstr strings. None of this is defined in any OSNET available headers
57 * so we have our own local definitions :-(
60 int hdr_midlst
; /* middle message no. */
61 int hdr_lstcnt
; /* total no. of message in the file */
62 int hdr_msgidsz
; /* size of msgids (in bytes) */
63 int hdr_msgstrsz
; /* size of msgstrs (in bytes) */
64 int hdr_lstsz
; /* size of message list (in bytes) */
74 #define LEAFINDICATOR -99
75 #define OLD_MSG_STRUCT_SIZE 20
76 #define NEW_MSG_STRUCT_SIZE (sizeof (Msglst))
79 * Define a local structure for maintaining the domains we care about.
83 const Msghdr
*dom_msghdr
;
89 * Perform a binary search of a message file (described by the Msghdr) for a
90 * msgid (string). Given a match return the associated msgstr, otherwise
91 * return the original msgid.
94 msgid_to_msgstr(const Msghdr
*msghdr
, const char *msgid
)
96 const Msglst
*list
, *_list
;
97 const char *ids
, *strs
, *_msgid
;
101 * Establish pointers to the message list (we actually start the search
102 * in the middle of this list (hdr->midlst), the msgid strings (ids)
103 * and the msgstr strings (strs).
105 list
= (const Msglst
*)&msghdr
[1];
106 ids
= (const char *)&list
[msghdr
->hdr_lstcnt
];
107 strs
= (const char *)&ids
[msghdr
->hdr_msgidsz
];
109 off
= msghdr
->hdr_midlst
;
113 _msgid
= ids
+ _list
->lst_idoff
;
115 if ((var
= strcmp(_msgid
, msgid
)) == 0)
116 return (strs
+ _list
->lst_stroff
);
119 if ((off
= _list
->lst_less
) == LEAFINDICATOR
)
122 if ((off
= _list
->lst_more
) == LEAFINDICATOR
)
127 return (NULL
); /* keep gcc happy */
131 * Open a message file. Following the model of setlocale(3c) we obtain the
132 * message file for the specified locale. Normally this is:
134 * /usr/lib/locale/`locale'/LC_MESSAGES/`domain'.mo
136 * The locale was determined during initial environment processing (see
137 * readenv()), which was determined from an LC_ALL, LC_MESSAGES or LANG
138 * setting. If no locale has been specified, or any file processing errors
139 * occur, internationalization is basically disabled.
142 open_mofile(Domain
* dom
)
144 const char *domain
= dom
->dom_name
;
148 const Msghdr
*msghdr
;
150 size_t size_tot
, size_old
, size_new
;
152 dom
->dom_msghdr
= (Msghdr
*)-1;
154 (void) snprintf(path
, PATH_MAX
, MSG_ORIG(MSG_FMT_MSGFILE
),
155 glcs
[CI_LCMESSAGES
].lc_un
.lc_ptr
, domain
);
157 if ((fd
= open(path
, O_RDONLY
, 0)) == -1)
160 if ((rtld_fstat(fd
, &status
) == -1) ||
161 (status
.st_size
< sizeof (Msghdr
))) {
167 if ((msghdr
= mmap(NULL
, status
.st_size
, PROT_READ
, MAP_SHARED
,
168 fd
, 0)) == (Msghdr
*)-1) {
174 /* checks if opened file is msg file */
176 count
= msghdr
->hdr_lstcnt
;
177 if (((count
- 1) / 2) != msghdr
->hdr_midlst
) {
178 (void) munmap((caddr_t
)msghdr
, status
.st_size
);
182 size_tot
= msghdr
->hdr_lstsz
;
183 size_old
= OLD_MSG_STRUCT_SIZE
* count
;
184 size_new
= (int)NEW_MSG_STRUCT_SIZE
* count
;
185 if ((size_tot
!= size_old
) && (size_tot
!= size_new
)) {
186 (void) munmap((caddr_t
)msghdr
, status
.st_size
);
190 size_tot
= msghdr
->hdr_msgidsz
+ msghdr
->hdr_msgstrsz
+
191 (int)sizeof (Msghdr
);
192 if ((size_tot
+ size_old
< status
.st_size
) &&
193 (size_tot
+ size_new
< status
.st_size
)) {
194 (void) munmap((caddr_t
)msghdr
, status
.st_size
);
199 * We have a good message file, initialize the Domain information.
201 dom
->dom_msghdr
= msghdr
;
202 dom
->dom_msgsz
= status
.st_size
;
207 * Two interfaces are established to support our internationalization.
208 * gettext(3i) calls originate from all link-editor libraries, and thus the
209 * SUNW_OST_SGS domain is assumed. dgettext() calls originate from
210 * dependencies such as libelf and libc.
212 * Presently we support two domains (libc's strerror() uses SUNW_OST_OSLIB).
213 * If ld.so.1's dependencies evolve to require more then the `domain' array
214 * maintained below can be enlarged or made more dynamic in nature.
217 dgettext(const char *domain
, const char *msgid
)
219 static int domaincnt
= 0;
220 static Domain
*domains
;
224 if (glcs
[CI_LCMESSAGES
].lc_un
.lc_val
== 0)
225 return ((char *)msgid
);
228 * Determine if we've initialized any domains yet.
230 if (domaincnt
== 0) {
231 if ((domains
= calloc(sizeof (Domain
), 2)) == NULL
)
232 return ((char *)msgid
);
233 domains
[0].dom_name
= MSG_ORIG(MSG_SUNW_OST_SGS
);
234 domains
[1].dom_name
= MSG_ORIG(MSG_SUNW_OST_OSLIB
);
239 * If this is a new locale make sure we clean up any old ones.
241 if (rtld_flags
& RT_FL_NEWLOCALE
) {
244 for (_domain
= domains
; cnt
< domaincnt
; _domain
++, cnt
++) {
245 if (_domain
->dom_msghdr
== 0)
248 if (_domain
->dom_msghdr
!= (Msghdr
*)-1)
249 (void) munmap((caddr_t
)_domain
->dom_msghdr
,
252 _domain
->dom_msghdr
= 0;
254 rtld_flags
&= ~RT_FL_NEWLOCALE
;
258 * Determine which domain we need.
260 for (cnt
= 0, _domain
= domains
; cnt
< domaincnt
; _domain
++, cnt
++) {
261 if (_domain
->dom_name
== domain
)
263 if (strcmp(_domain
->dom_name
, domain
) == 0)
266 if (cnt
== domaincnt
)
267 return ((char *)msgid
);
270 * Determine if the domain has been initialized yet.
272 if (_domain
->dom_msghdr
== 0)
273 open_mofile(_domain
);
274 if (_domain
->dom_msghdr
== (Msghdr
*)-1)
275 return ((char *)msgid
);
277 return ((char *)msgid_to_msgstr(_domain
->dom_msghdr
, msgid
));
281 * This satisfies any dependencies of code dragged in from libc, as we don't
282 * want libc's gettext implementation in ld.so.1. This routine may not be
283 * referenced, in which case -zignore will discard it.
286 gettext(const char *msgid
)
288 return ((char *)dgettext(MSG_ORIG(MSG_SUNW_OST_SGS
), msgid
));
292 * The sgsmsg.1l use requires the following interface.
297 return ((char *)dgettext(MSG_ORIG(MSG_SUNW_OST_SGS
), MSG_ORIG(mid
)));