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