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