XlcDL.c revision 5a473929
1/*
2Copyright 1985, 1986, 1987, 1991, 1998  The Open Group
3
4Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the
6"Software"), to deal in the Software without restriction, including
7without limitation the rights to use, copy, modify, merge, publish,
8distribute, sublicense, and/or sell copies of the Software, and to
9permit persons to whom the Software is furnished to do so, subject to
10the following conditions: The above copyright notice and this
11permission notice shall be included in all copies or substantial
12portions of the Software.
13
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
21EVEN IF ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.
22
23
24Except as contained in this notice, the name of The Open Group shall not be
25used in advertising or otherwise to promote the sale, use or other dealings
26in this Software without prior written authorization from The Open Group.
27
28
29X Window System is a trademark of The Open Group
30
31OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
32logo, LBX, X Window System, and Xinerama are trademarks of the Open
33Group. All other trademarks and registered trademarks mentioned herein
34are the property of their respective owners. No right, title or
35interest in or to any trademark, service mark, logo or trade name of
36Sun Microsystems, Inc. or its licensors is granted.
37
38*/
39/*
40 * Copyright 2000 Sun Microsystems, Inc.  All rights reserved.
41 *
42 * Permission is hereby granted, free of charge, to any person obtaining a
43 * copy of this software and associated documentation files (the "Software"),
44 * to deal in the Software without restriction, including without limitation
45 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
46 * and/or sell copies of the Software, and to permit persons to whom the
47 * Software is furnished to do so, subject to the following conditions:
48 *
49 * The above copyright notice and this permission notice (including the next
50 * paragraph) shall be included in all copies or substantial portions of the
51 * Software.
52 *
53 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
56 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
58 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
59 * DEALINGS IN THE SOFTWARE.
60 */
61
62
63#ifdef HAVE_CONFIG_H
64# include <config.h>
65#else
66# if defined(hpux)
67#  define HAVE_DL_H
68# else
69#  define HAVE_DLFCN_H
70# endif
71#endif
72
73#include <stdio.h>
74
75#ifdef HAVE_DL_H
76#include <dl.h>
77#endif
78
79#ifdef HAVE_DLFCN_H
80#include <dlfcn.h>
81#endif
82
83#include <ctype.h>
84
85#include "Xlibint.h"
86#include "XlcPublic.h"
87#include "XlcPubI.h"
88
89#if !defined(__NetBSD__) && defined(_LP64)  && defined(__sparcv9)
90# define	_MACH64_NAME		"sparcv9"
91#else
92# undef _MACH64_NAME
93#endif /* defined(_LP64)  && defined(__sparcv9) */
94
95#ifdef _MACH64_NAME
96#  define	_MACH64_NAME_LEN	(sizeof (_MACH64_NAME) - 1)
97#endif
98
99#define XI18N_DLREL		2
100
101#define	iscomment(ch)	((ch) == '\0' || (ch) == '#')
102
103typedef enum {
104  XLC_OBJECT,
105  XIM_OBJECT,
106  XOM_OBJECT
107} XI18NDLType;
108
109typedef struct {
110  XI18NDLType type;
111  int	locale_name_len;
112  char *locale_name;
113  char *dl_name;
114  char *open;
115  char *im_register;
116  char *im_unregister;
117  int dl_release;
118  unsigned int refcount;
119#if defined(hpux)
120  shl_t dl_module;
121#else
122  void *dl_module;
123#endif
124} XI18NObjectsListRec, *XI18NObjectsList;
125
126#define OBJECT_INIT_LEN 8
127#define OBJECT_INC_LEN 4
128static int lc_len = 0;
129static XI18NObjectsListRec *xi18n_objects_list = NULL;
130static int lc_count = 0;
131
132static int
133parse_line(char *line, char **argv, int argsize)
134{
135    int argc = 0;
136    char *p = line;
137
138    while (argc < argsize) {
139	while (isspace(*p)) {
140	    ++p;
141	}
142	if (iscomment(*p)){
143	    break;
144	}
145	argv[argc++] = p;
146	while (!isspace(*p)) {
147	    ++p;
148	}
149	if (iscomment(*p)) {
150	    break;
151	}
152	*p++ = '\0';
153    }
154    return argc;
155}
156
157static char *
158strdup_with_underscore(const char *symbol)
159{
160	char *result;
161
162	if ((result = malloc(strlen(symbol) + 2)) == NULL)
163		return NULL;
164	result[0] = '_';
165	strcpy(result + 1, symbol);
166	return result;
167}
168
169#ifndef hpux
170static void *
171try_both_dlsym (void *handle, char *name)
172{
173    void    *ret;
174
175    ret = dlsym (handle, name);
176    if (!ret)
177    {
178	 name = strdup_with_underscore (name);
179	 if (name)
180	 {
181	     ret = dlsym (handle, name);
182	     free (name);
183	 }
184    }
185    return ret;
186}
187#endif
188
189static void
190resolve_object(char *path, const char *lc_name)
191{
192    char filename[BUFSIZ];
193    FILE *fp;
194    char buf[BUFSIZ];
195
196    if (lc_len == 0) { /* True only for the 1st time */
197      lc_len = OBJECT_INIT_LEN;
198      xi18n_objects_list = (XI18NObjectsList)
199	  Xmalloc(sizeof(XI18NObjectsListRec) * lc_len);
200      if (!xi18n_objects_list) return;
201    }
202/*
2031266793
204Limit the length of path to prevent stack buffer corruption.
205    sprintf(filename, "%s/%s", path, "XI18N_OBJS");
206*/
207    sprintf(filename, "%.*s/%s", BUFSIZ - 12, path, "XI18N_OBJS");
208    fp = fopen(filename, "r");
209    if (fp == (FILE *)NULL){
210	return;
211    }
212
213    while (fgets(buf, BUFSIZ, fp) != NULL){
214	char *p = buf;
215	int n;
216	char *args[6];
217	while (isspace(*p)){
218	    ++p;
219	}
220	if (iscomment(*p)){
221	    continue;
222	}
223
224	if (lc_count == lc_len) {
225	  lc_len += OBJECT_INC_LEN;
226	  xi18n_objects_list = (XI18NObjectsList)
227	    Xrealloc(xi18n_objects_list,
228		     sizeof(XI18NObjectsListRec) * lc_len);
229	  if (!xi18n_objects_list) return;
230	}
231	n = parse_line(p, args, 6);
232
233	if (n == 3 || n == 5) {
234	  if (!strcmp(args[0], "XLC")){
235	    xi18n_objects_list[lc_count].type = XLC_OBJECT;
236	  } else if (!strcmp(args[0], "XOM")){
237	    xi18n_objects_list[lc_count].type = XOM_OBJECT;
238	  } else if (!strcmp(args[0], "XIM")){
239	    xi18n_objects_list[lc_count].type = XIM_OBJECT;
240	  }
241	  xi18n_objects_list[lc_count].dl_name = strdup(args[1]);
242	  xi18n_objects_list[lc_count].open = strdup(args[2]);
243	  xi18n_objects_list[lc_count].dl_release = XI18N_DLREL;
244	  xi18n_objects_list[lc_count].locale_name = strdup(lc_name);
245	  xi18n_objects_list[lc_count].refcount = 0;
246	  xi18n_objects_list[lc_count].dl_module = (void*)NULL;
247	  if (n == 5) {
248	    xi18n_objects_list[lc_count].im_register = strdup(args[3]);
249	    xi18n_objects_list[lc_count].im_unregister = strdup(args[4]);
250	  } else {
251	    xi18n_objects_list[lc_count].im_register = NULL;
252	    xi18n_objects_list[lc_count].im_unregister = NULL;
253	  }
254	  lc_count++;
255	}
256    }
257    fclose(fp);
258}
259
260static char*
261__lc_path(const char *dl_name, const char *lc_dir)
262{
263    char *path;
264    size_t len;
265
266    /*
267     * reject this for possible security issue
268     */
269    if (strstr (dl_name, "../"))
270	return NULL;
271
272#if defined (_LP64) && defined (_MACH64_NAME)
273    len = (lc_dir ? strlen(lc_dir) : 0 ) +
274	(dl_name ? strlen(dl_name) : 0) + _MACH64_NAME_LEN + 10;
275    path = Xmalloc(len + 1);
276
277    if (strchr(dl_name, '/') != NULL) {
278	char *tmp = strdup(dl_name);
279	char *dl_dir, *dl_file;
280	char *slash_p;
281	slash_p = strchr(tmp, '/');
282	*slash_p = '\0';
283	dl_dir = tmp;
284	dl_file = ++slash_p;
285
286	slash_p = strrchr(lc_dir, '/');
287	*slash_p = '\0';
288	strcpy(path, lc_dir); strcat(path, "/");
289	strcat(path, dl_dir); strcat(path, "/");
290	strcat(path, _MACH64_NAME); strcat(path, "/");
291	strcat(path, dl_file); strcat(path, ".so.2");
292
293	*slash_p = '/';
294	Xfree(tmp);
295    } else {
296	strcpy(path, lc_dir); strcat(path, "/");
297	strcat(path, _MACH64_NAME); strcat(path, "/");
298	strcat(path, dl_name); strcat(path, ".so.2");
299    }
300#else
301    len = (lc_dir ? strlen(lc_dir) : 0 ) +
302	(dl_name ? strlen(dl_name) : 0) + 10;
303#if defined POSTLOCALELIBDIR
304    len += (strlen(POSTLOCALELIBDIR) + 1);
305#endif
306    path = Xmalloc(len + 1);
307
308    if (strchr(dl_name, '/') != NULL) {
309	char *slash_p;
310	slash_p = strrchr(lc_dir, '/');
311	*slash_p = '\0';
312	strcpy(path, lc_dir); strcat(path, "/");
313#if defined POSTLOCALELIBDIR
314	strcat(path, POSTLOCALELIBDIR); strcat(path, "/");
315#endif
316	strcat(path, dl_name); strcat(path, ".so.2");
317	*slash_p = '/';
318    } else {
319	strcpy(path, lc_dir); strcat(path, "/");
320#if defined POSTLOCALELIBDIR
321	strcat(path, POSTLOCALELIBDIR); strcat(path, "/");
322#endif
323	strcat(path, dl_name); strcat(path, ".so.2");
324    }
325#endif
326    return path;
327}
328
329/* We reference count dlopen() and dlclose() of modules; unfortunately,
330 * since XCloseIM, XCloseOM, XlcClose aren't wrapped, but directly
331 * call the close method of the object, we leak a reference count every
332 * time we open then close a module. Fixing this would require
333 * either creating proxy objects or hooks for close_im/close_om
334 * in XLCd
335 */
336static Bool
337open_object(
338     XI18NObjectsList object,
339     char *lc_dir)
340{
341  char *path;
342
343  if (object->refcount == 0) {
344      path = __lc_path(object->dl_name, lc_dir);
345      if (!path)
346	  return False;
347#if defined(hpux)
348      object->dl_module = shl_load(path, BIND_DEFERRED, 0L);
349#else
350      object->dl_module = dlopen(path, RTLD_LAZY);
351#endif
352      Xfree(path);
353
354      if (!object->dl_module)
355	  return False;
356    }
357
358  object->refcount++;
359  return True;
360}
361
362static void *
363fetch_symbol(
364     XI18NObjectsList object,
365     char *symbol)
366{
367    void *result = NULL;
368#if defined(hpux)
369    int getsyms_cnt, i;
370    struct shl_symbol *symbols;
371#endif
372
373    if (symbol == NULL)
374    	return NULL;
375
376#if defined(hpux)
377    getsyms_cnt = shl_getsymbols(object->dl_module, TYPE_PROCEDURE,
378				 EXPORT_SYMBOLS, malloc, &symbols);
379
380    for(i=0; i<getsyms_cnt; i++) {
381        if(!strcmp(symbols[i].name, symbol)) {
382	    result = symbols[i].value;
383	    break;
384         }
385    }
386
387    if(getsyms_cnt > 0) {
388        free(symbols);
389    }
390#else
391    result = try_both_dlsym(object->dl_module, symbol);
392#endif
393
394    return result;
395}
396
397static void
398close_object(XI18NObjectsList object)
399{
400  object->refcount--;
401  if (object->refcount == 0)
402    {
403#if defined(hpux)
404        shl_unload(object->dl_module);
405#else
406        dlclose(object->dl_module);
407#endif
408        object->dl_module = NULL;
409    }
410}
411
412
413typedef XLCd (*dynamicLoadProc)(const char *);
414
415XLCd
416_XlcDynamicLoad(const char *lc_name)
417{
418    XLCd lcd = (XLCd)NULL;
419    dynamicLoadProc lc_loader = (dynamicLoadProc)NULL;
420    int count;
421    XI18NObjectsList objects_list;
422    char lc_dir[BUFSIZE], lc_lib_dir[BUFSIZE];
423
424    if (lc_name == NULL) return (XLCd)NULL;
425
426    if (_XlcLocaleDirName(lc_dir, BUFSIZE, (char *)lc_name) == (char *)NULL)
427        return (XLCd)NULL;
428    if (_XlcLocaleLibDirName(lc_lib_dir, BUFSIZE, (char *)lc_name) == (char*)NULL)
429	return (XLCd)NULL;
430
431    resolve_object(lc_dir, lc_name);
432    resolve_object(lc_lib_dir, lc_name);
433
434    objects_list = xi18n_objects_list;
435    count = lc_count;
436    for (; count-- > 0; objects_list++) {
437        if (objects_list->type != XLC_OBJECT ||
438	    strcmp(objects_list->locale_name, lc_name)) continue;
439	if (!open_object (objects_list, lc_dir) && \
440            !open_object (objects_list, lc_lib_dir))
441	    continue;
442
443	lc_loader = (dynamicLoadProc)fetch_symbol (objects_list, objects_list->open);
444	if (!lc_loader) continue;
445	lcd = (*lc_loader)(lc_name);
446	if (lcd != (XLCd)NULL) {
447	    break;
448	}
449
450	close_object (objects_list);
451    }
452    return (XLCd)lcd;
453}
454
455
456typedef XIM (*dynamicOpenProcp)(XLCd, Display *, XrmDatabase, char *, char *);
457
458static XIM
459_XDynamicOpenIM(XLCd lcd, Display *display, XrmDatabase rdb,
460		char *res_name, char *res_class)
461{
462  XIM im = (XIM)NULL;
463  char lc_dir[BUFSIZE];
464  char *lc_name;
465  dynamicOpenProcp im_openIM = (dynamicOpenProcp)NULL;
466  int count;
467  XI18NObjectsList objects_list = xi18n_objects_list;
468
469  lc_name = lcd->core->name;
470
471  if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return (XIM)0;
472
473  count = lc_count;
474  for (; count-- > 0; objects_list++) {
475    if (objects_list->type != XIM_OBJECT ||
476	strcmp(objects_list->locale_name, lc_name)) continue;
477
478    if (!open_object (objects_list, lc_dir))
479        continue;
480
481    im_openIM = (dynamicOpenProcp)fetch_symbol(objects_list, objects_list->open);
482    if (!im_openIM) continue;
483    im = (*im_openIM)(lcd, display, rdb, res_name, res_class);
484    if (im != (XIM)NULL) {
485        break;
486    }
487
488    close_object (objects_list);
489  }
490  return (XIM)im;
491}
492
493typedef Bool (*dynamicRegisterCBProcp)(
494    XLCd, Display *, XrmDatabase, char *, char *, XIDProc, XPointer);
495
496static Bool
497_XDynamicRegisterIMInstantiateCallback(
498    XLCd	 lcd,
499    Display	*display,
500    XrmDatabase	 rdb,
501    char	*res_name,
502    char        *res_class,
503    XIDProc	 callback,
504    XPointer	 client_data)
505{
506  char lc_dir[BUFSIZE];
507  char *lc_name;
508  dynamicRegisterCBProcp im_registerIM = (dynamicRegisterCBProcp)NULL;
509  Bool ret_flag = False;
510  int count;
511  XI18NObjectsList objects_list = xi18n_objects_list;
512#if defined(hpux)
513  int getsyms_cnt, i;
514  struct shl_symbol *symbols;
515#endif
516
517  lc_name = lcd->core->name;
518
519  if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return False;
520
521  count = lc_count;
522  for (; count-- > 0; objects_list++) {
523    if (objects_list->type != XIM_OBJECT ||
524	strcmp(objects_list->locale_name, lc_name)) continue;
525
526    if (!open_object (objects_list, lc_dir))
527        continue;
528    im_registerIM = (dynamicRegisterCBProcp)fetch_symbol(objects_list,
529					    objects_list->im_register);
530    if (!im_registerIM) continue;
531    ret_flag = (*im_registerIM)(lcd, display, rdb,
532				res_name, res_class,
533				callback, client_data);
534    if (ret_flag) break;
535
536    close_object (objects_list);
537  }
538  return (Bool)ret_flag;
539}
540
541typedef Bool (*dynamicUnregisterProcp)(
542    XLCd, Display *, XrmDatabase, char *, char *, XIDProc, XPointer);
543
544static Bool
545_XDynamicUnRegisterIMInstantiateCallback(
546    XLCd	 lcd,
547    Display	*display,
548    XrmDatabase	 rdb,
549    char	*res_name,
550    char        *res_class,
551    XIDProc	 callback,
552    XPointer	 client_data)
553{
554  char lc_dir[BUFSIZE];
555  char *lc_name;
556  dynamicUnregisterProcp im_unregisterIM = (dynamicUnregisterProcp)NULL;
557  Bool ret_flag = False;
558  int count;
559  XI18NObjectsList objects_list = xi18n_objects_list;
560#if defined(hpux)
561  int getsyms_cnt, i;
562  struct shl_symbol *symbols;
563#endif
564
565  lc_name = lcd->core->name;
566  if (_XlcLocaleDirName(lc_dir, BUFSIZE, lc_name) == NULL) return False;
567
568  count = lc_count;
569  for (; count-- > 0; objects_list++) {
570    if (objects_list->type != XIM_OBJECT ||
571	strcmp(objects_list->locale_name, lc_name)) continue;
572
573    if (!objects_list->refcount) /* Must already be opened */
574        continue;
575
576    im_unregisterIM = (dynamicUnregisterProcp)fetch_symbol(objects_list,
577					      objects_list->im_unregister);
578
579    if (!im_unregisterIM) continue;
580    ret_flag = (*im_unregisterIM)(lcd, display, rdb,
581				  res_name, res_class,
582				  callback, client_data);
583    if (ret_flag) {
584        close_object (objects_list); /* opened in RegisterIMInstantiateCallback */
585	break;
586    }
587  }
588  return (Bool)ret_flag;
589}
590
591Bool
592_XInitDynamicIM(XLCd lcd)
593{
594    if(lcd == (XLCd)NULL)
595	return False;
596    lcd->methods->open_im = _XDynamicOpenIM;
597    lcd->methods->register_callback = _XDynamicRegisterIMInstantiateCallback;
598    lcd->methods->unregister_callback = _XDynamicUnRegisterIMInstantiateCallback;
599    return True;
600}
601
602
603typedef XOM (*dynamicIOpenProcp)(
604        XLCd, Display *, XrmDatabase, _Xconst char *, _Xconst char *);
605
606static XOM
607_XDynamicOpenOM(XLCd lcd, Display *display, XrmDatabase rdb,
608		_Xconst char *res_name, _Xconst char *res_class)
609{
610  XOM om = (XOM)NULL;
611  int count;
612  char lc_dir[BUFSIZE];
613  char *lc_name;
614  dynamicIOpenProcp om_openOM = (dynamicIOpenProcp)NULL;
615  XI18NObjectsList objects_list = xi18n_objects_list;
616#if defined(hpux)
617  int getsyms_cnt, i;
618  struct shl_symbol *symbols;
619#endif
620
621  lc_name = lcd->core->name;
622
623  if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return (XOM)0;
624
625  count = lc_count;
626  for (; count-- > 0; objects_list++) {
627    if (objects_list->type != XOM_OBJECT ||
628	strcmp(objects_list->locale_name, lc_name)) continue;
629    if (!open_object (objects_list, lc_dir))
630        continue;
631
632    om_openOM = (dynamicIOpenProcp)fetch_symbol(objects_list, objects_list->open);
633    if (!om_openOM) continue;
634    om = (*om_openOM)(lcd, display, rdb, res_name, res_class);
635    if (om != (XOM)NULL) {
636        break;
637    }
638    close_object(objects_list);
639  }
640  return (XOM)om;
641}
642
643Bool
644_XInitDynamicOM(XLCd lcd)
645{
646    if(lcd == (XLCd)NULL)
647	return False;
648
649    lcd->methods->open_om = _XDynamicOpenOM;
650
651    return True;
652}
653