XlcDL.c revision d8e76104
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 Oracle and/or its affiliates. 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#define XI18N_DLREL		2
90
91#define	iscomment(ch)	((ch) == '\0' || (ch) == '#')
92
93typedef enum {
94  XLC_OBJECT,
95  XIM_OBJECT,
96  XOM_OBJECT
97} XI18NDLType;
98
99typedef struct {
100  XI18NDLType type;
101  int	locale_name_len;
102  char *locale_name;
103  char *dl_name;
104  char *open;
105  char *im_register;
106  char *im_unregister;
107  int dl_release;
108  unsigned int refcount;
109#if defined(hpux)
110  shl_t dl_module;
111#else
112  void *dl_module;
113#endif
114} XI18NObjectsListRec, *XI18NObjectsList;
115
116#define OBJECT_INIT_LEN 8
117#define OBJECT_INC_LEN 4
118static int lc_len = 0;
119static XI18NObjectsListRec *xi18n_objects_list = NULL;
120static int lc_count = 0;
121
122static int
123parse_line(char *line, char **argv, int argsize)
124{
125    int argc = 0;
126    char *p = line;
127
128    while (argc < argsize) {
129	while (isspace(*p)) {
130	    ++p;
131	}
132	if (iscomment(*p)){
133	    break;
134	}
135	argv[argc++] = p;
136	while (!isspace(*p)) {
137	    ++p;
138	}
139	if (iscomment(*p)) {
140	    break;
141	}
142	*p++ = '\0';
143    }
144    return argc;
145}
146
147static char *
148strdup_with_underscore(const char *symbol)
149{
150	char *result;
151
152	if ((result = malloc(strlen(symbol) + 2)) == NULL)
153		return NULL;
154	result[0] = '_';
155	strcpy(result + 1, symbol);
156	return result;
157}
158
159#ifndef hpux
160static void *
161try_both_dlsym (void *handle, char *name)
162{
163    void    *ret;
164
165    ret = dlsym (handle, name);
166    if (!ret)
167    {
168	 name = strdup_with_underscore (name);
169	 if (name)
170	 {
171	     ret = dlsym (handle, name);
172	     free (name);
173	 }
174    }
175    return ret;
176}
177#endif
178
179static void
180resolve_object(char *path, const char *lc_name)
181{
182    char filename[BUFSIZ];
183    FILE *fp;
184    char buf[BUFSIZ];
185
186    if (lc_len == 0) { /* True only for the 1st time */
187      lc_len = OBJECT_INIT_LEN;
188      xi18n_objects_list = (XI18NObjectsList)
189	  Xmalloc(sizeof(XI18NObjectsListRec) * lc_len);
190      if (!xi18n_objects_list) return;
191    }
192/*
1931266793
194Limit the length of path to prevent stack buffer corruption.
195    sprintf(filename, "%s/%s", path, "XI18N_OBJS");
196*/
197    sprintf(filename, "%.*s/%s", BUFSIZ - 12, path, "XI18N_OBJS");
198    fp = fopen(filename, "r");
199    if (fp == (FILE *)NULL){
200	return;
201    }
202
203    while (fgets(buf, BUFSIZ, fp) != NULL){
204	char *p = buf;
205	int n;
206	char *args[6];
207	while (isspace(*p)){
208	    ++p;
209	}
210	if (iscomment(*p)){
211	    continue;
212	}
213
214	if (lc_count == lc_len) {
215	  lc_len += OBJECT_INC_LEN;
216	  xi18n_objects_list = (XI18NObjectsList)
217	    Xrealloc(xi18n_objects_list,
218		     sizeof(XI18NObjectsListRec) * lc_len);
219	  if (!xi18n_objects_list) return;
220	}
221	n = parse_line(p, args, 6);
222
223	if (n == 3 || n == 5) {
224	  if (!strcmp(args[0], "XLC")){
225	    xi18n_objects_list[lc_count].type = XLC_OBJECT;
226	  } else if (!strcmp(args[0], "XOM")){
227	    xi18n_objects_list[lc_count].type = XOM_OBJECT;
228	  } else if (!strcmp(args[0], "XIM")){
229	    xi18n_objects_list[lc_count].type = XIM_OBJECT;
230	  }
231	  xi18n_objects_list[lc_count].dl_name = strdup(args[1]);
232	  xi18n_objects_list[lc_count].open = strdup(args[2]);
233	  xi18n_objects_list[lc_count].dl_release = XI18N_DLREL;
234	  xi18n_objects_list[lc_count].locale_name = strdup(lc_name);
235	  xi18n_objects_list[lc_count].refcount = 0;
236	  xi18n_objects_list[lc_count].dl_module = (void*)NULL;
237	  if (n == 5) {
238	    xi18n_objects_list[lc_count].im_register = strdup(args[3]);
239	    xi18n_objects_list[lc_count].im_unregister = strdup(args[4]);
240	  } else {
241	    xi18n_objects_list[lc_count].im_register = NULL;
242	    xi18n_objects_list[lc_count].im_unregister = NULL;
243	  }
244	  lc_count++;
245	}
246    }
247    fclose(fp);
248}
249
250static char*
251__lc_path(const char *dl_name, const char *lc_dir)
252{
253    char *path;
254    size_t len;
255
256    /*
257     * reject this for possible security issue
258     */
259    if (strstr (dl_name, "../"))
260	return NULL;
261
262    len = (lc_dir ? strlen(lc_dir) : 0 ) +
263	(dl_name ? strlen(dl_name) : 0) + 10;
264#if defined POSTLOCALELIBDIR
265    len += (strlen(POSTLOCALELIBDIR) + 1);
266#endif
267    path = Xmalloc(len + 1);
268
269    if (strchr(dl_name, '/') != NULL) {
270	char *slash_p;
271	slash_p = strrchr(lc_dir, '/');
272	*slash_p = '\0';
273	strcpy(path, lc_dir); strcat(path, "/");
274#if defined POSTLOCALELIBDIR
275	strcat(path, POSTLOCALELIBDIR); strcat(path, "/");
276#endif
277	strcat(path, dl_name); strcat(path, ".so.2");
278	*slash_p = '/';
279    } else {
280	strcpy(path, lc_dir); strcat(path, "/");
281#if defined POSTLOCALELIBDIR
282	strcat(path, POSTLOCALELIBDIR); strcat(path, "/");
283#endif
284	strcat(path, dl_name); strcat(path, ".so.2");
285    }
286    return path;
287}
288
289/* We reference count dlopen() and dlclose() of modules; unfortunately,
290 * since XCloseIM, XCloseOM, XlcClose aren't wrapped, but directly
291 * call the close method of the object, we leak a reference count every
292 * time we open then close a module. Fixing this would require
293 * either creating proxy objects or hooks for close_im/close_om
294 * in XLCd
295 */
296static Bool
297open_object(
298     XI18NObjectsList object,
299     char *lc_dir)
300{
301  char *path;
302
303  if (object->refcount == 0) {
304      path = __lc_path(object->dl_name, lc_dir);
305      if (!path)
306	  return False;
307#if defined(hpux)
308      object->dl_module = shl_load(path, BIND_DEFERRED, 0L);
309#else
310      object->dl_module = dlopen(path, RTLD_LAZY);
311#endif
312      Xfree(path);
313
314      if (!object->dl_module)
315	  return False;
316    }
317
318  object->refcount++;
319  return True;
320}
321
322static void *
323fetch_symbol(
324     XI18NObjectsList object,
325     char *symbol)
326{
327    void *result = NULL;
328#if defined(hpux)
329    int getsyms_cnt, i;
330    struct shl_symbol *symbols;
331#endif
332
333    if (symbol == NULL)
334    	return NULL;
335
336#if defined(hpux)
337    getsyms_cnt = shl_getsymbols(object->dl_module, TYPE_PROCEDURE,
338				 EXPORT_SYMBOLS, malloc, &symbols);
339
340    for(i=0; i<getsyms_cnt; i++) {
341        if(!strcmp(symbols[i].name, symbol)) {
342	    result = symbols[i].value;
343	    break;
344         }
345    }
346
347    if(getsyms_cnt > 0) {
348        free(symbols);
349    }
350#else
351    result = try_both_dlsym(object->dl_module, symbol);
352#endif
353
354    return result;
355}
356
357static void
358close_object(XI18NObjectsList object)
359{
360  object->refcount--;
361  if (object->refcount == 0)
362    {
363#if defined(hpux)
364        shl_unload(object->dl_module);
365#else
366        dlclose(object->dl_module);
367#endif
368        object->dl_module = NULL;
369    }
370}
371
372
373typedef XLCd (*dynamicLoadProc)(const char *);
374
375XLCd
376_XlcDynamicLoad(const char *lc_name)
377{
378    XLCd lcd = (XLCd)NULL;
379    dynamicLoadProc lc_loader = (dynamicLoadProc)NULL;
380    int count;
381    XI18NObjectsList objects_list;
382    char lc_dir[BUFSIZE], lc_lib_dir[BUFSIZE];
383
384    if (lc_name == NULL) return (XLCd)NULL;
385
386    if (_XlcLocaleDirName(lc_dir, BUFSIZE, (char *)lc_name) == (char *)NULL)
387        return (XLCd)NULL;
388    if (_XlcLocaleLibDirName(lc_lib_dir, BUFSIZE, (char *)lc_name) == (char*)NULL)
389	return (XLCd)NULL;
390
391    resolve_object(lc_dir, lc_name);
392    resolve_object(lc_lib_dir, lc_name);
393
394    objects_list = xi18n_objects_list;
395    count = lc_count;
396    for (; count-- > 0; objects_list++) {
397        if (objects_list->type != XLC_OBJECT ||
398	    strcmp(objects_list->locale_name, lc_name)) continue;
399	if (!open_object (objects_list, lc_dir) && \
400            !open_object (objects_list, lc_lib_dir))
401	    continue;
402
403	lc_loader = (dynamicLoadProc)fetch_symbol (objects_list, objects_list->open);
404	if (!lc_loader) continue;
405	lcd = (*lc_loader)(lc_name);
406	if (lcd != (XLCd)NULL) {
407	    break;
408	}
409
410	close_object (objects_list);
411    }
412    return (XLCd)lcd;
413}
414
415
416typedef XIM (*dynamicOpenProcp)(XLCd, Display *, XrmDatabase, char *, char *);
417
418static XIM
419_XDynamicOpenIM(XLCd lcd, Display *display, XrmDatabase rdb,
420		char *res_name, char *res_class)
421{
422  XIM im = (XIM)NULL;
423  char lc_dir[BUFSIZE];
424  char *lc_name;
425  dynamicOpenProcp im_openIM = (dynamicOpenProcp)NULL;
426  int count;
427  XI18NObjectsList objects_list = xi18n_objects_list;
428
429  lc_name = lcd->core->name;
430
431  if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return (XIM)0;
432
433  count = lc_count;
434  for (; count-- > 0; objects_list++) {
435    if (objects_list->type != XIM_OBJECT ||
436	strcmp(objects_list->locale_name, lc_name)) continue;
437
438    if (!open_object (objects_list, lc_dir))
439        continue;
440
441    im_openIM = (dynamicOpenProcp)fetch_symbol(objects_list, objects_list->open);
442    if (!im_openIM) continue;
443    im = (*im_openIM)(lcd, display, rdb, res_name, res_class);
444    if (im != (XIM)NULL) {
445        break;
446    }
447
448    close_object (objects_list);
449  }
450  return (XIM)im;
451}
452
453typedef Bool (*dynamicRegisterCBProcp)(
454    XLCd, Display *, XrmDatabase, char *, char *, XIDProc, XPointer);
455
456static Bool
457_XDynamicRegisterIMInstantiateCallback(
458    XLCd	 lcd,
459    Display	*display,
460    XrmDatabase	 rdb,
461    char	*res_name,
462    char        *res_class,
463    XIDProc	 callback,
464    XPointer	 client_data)
465{
466  char lc_dir[BUFSIZE];
467  char *lc_name;
468  dynamicRegisterCBProcp im_registerIM = (dynamicRegisterCBProcp)NULL;
469  Bool ret_flag = False;
470  int count;
471  XI18NObjectsList objects_list = xi18n_objects_list;
472#if defined(hpux)
473  int getsyms_cnt, i;
474  struct shl_symbol *symbols;
475#endif
476
477  lc_name = lcd->core->name;
478
479  if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return False;
480
481  count = lc_count;
482  for (; count-- > 0; objects_list++) {
483    if (objects_list->type != XIM_OBJECT ||
484	strcmp(objects_list->locale_name, lc_name)) continue;
485
486    if (!open_object (objects_list, lc_dir))
487        continue;
488    im_registerIM = (dynamicRegisterCBProcp)fetch_symbol(objects_list,
489					    objects_list->im_register);
490    if (!im_registerIM) continue;
491    ret_flag = (*im_registerIM)(lcd, display, rdb,
492				res_name, res_class,
493				callback, client_data);
494    if (ret_flag) break;
495
496    close_object (objects_list);
497  }
498  return (Bool)ret_flag;
499}
500
501typedef Bool (*dynamicUnregisterProcp)(
502    XLCd, Display *, XrmDatabase, char *, char *, XIDProc, XPointer);
503
504static Bool
505_XDynamicUnRegisterIMInstantiateCallback(
506    XLCd	 lcd,
507    Display	*display,
508    XrmDatabase	 rdb,
509    char	*res_name,
510    char        *res_class,
511    XIDProc	 callback,
512    XPointer	 client_data)
513{
514  char lc_dir[BUFSIZE];
515  char *lc_name;
516  dynamicUnregisterProcp im_unregisterIM = (dynamicUnregisterProcp)NULL;
517  Bool ret_flag = False;
518  int count;
519  XI18NObjectsList objects_list = xi18n_objects_list;
520#if defined(hpux)
521  int getsyms_cnt, i;
522  struct shl_symbol *symbols;
523#endif
524
525  lc_name = lcd->core->name;
526  if (_XlcLocaleDirName(lc_dir, BUFSIZE, lc_name) == NULL) return False;
527
528  count = lc_count;
529  for (; count-- > 0; objects_list++) {
530    if (objects_list->type != XIM_OBJECT ||
531	strcmp(objects_list->locale_name, lc_name)) continue;
532
533    if (!objects_list->refcount) /* Must already be opened */
534        continue;
535
536    im_unregisterIM = (dynamicUnregisterProcp)fetch_symbol(objects_list,
537					      objects_list->im_unregister);
538
539    if (!im_unregisterIM) continue;
540    ret_flag = (*im_unregisterIM)(lcd, display, rdb,
541				  res_name, res_class,
542				  callback, client_data);
543    if (ret_flag) {
544        close_object (objects_list); /* opened in RegisterIMInstantiateCallback */
545	break;
546    }
547  }
548  return (Bool)ret_flag;
549}
550
551Bool
552_XInitDynamicIM(XLCd lcd)
553{
554    if(lcd == (XLCd)NULL)
555	return False;
556    lcd->methods->open_im = _XDynamicOpenIM;
557    lcd->methods->register_callback = _XDynamicRegisterIMInstantiateCallback;
558    lcd->methods->unregister_callback = _XDynamicUnRegisterIMInstantiateCallback;
559    return True;
560}
561
562
563typedef XOM (*dynamicIOpenProcp)(
564        XLCd, Display *, XrmDatabase, _Xconst char *, _Xconst char *);
565
566static XOM
567_XDynamicOpenOM(XLCd lcd, Display *display, XrmDatabase rdb,
568		_Xconst char *res_name, _Xconst char *res_class)
569{
570  XOM om = (XOM)NULL;
571  int count;
572  char lc_dir[BUFSIZE];
573  char *lc_name;
574  dynamicIOpenProcp om_openOM = (dynamicIOpenProcp)NULL;
575  XI18NObjectsList objects_list = xi18n_objects_list;
576#if defined(hpux)
577  int getsyms_cnt, i;
578  struct shl_symbol *symbols;
579#endif
580
581  lc_name = lcd->core->name;
582
583  if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return (XOM)0;
584
585  count = lc_count;
586  for (; count-- > 0; objects_list++) {
587    if (objects_list->type != XOM_OBJECT ||
588	strcmp(objects_list->locale_name, lc_name)) continue;
589    if (!open_object (objects_list, lc_dir))
590        continue;
591
592    om_openOM = (dynamicIOpenProcp)fetch_symbol(objects_list, objects_list->open);
593    if (!om_openOM) continue;
594    om = (*om_openOM)(lcd, display, rdb, res_name, res_class);
595    if (om != (XOM)NULL) {
596        break;
597    }
598    close_object(objects_list);
599  }
600  return (XOM)om;
601}
602
603Bool
604_XInitDynamicOM(XLCd lcd)
605{
606    if(lcd == (XLCd)NULL)
607	return False;
608
609    lcd->methods->open_om = _XDynamicOpenOM;
610
611    return True;
612}
613