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