XlcDL.c revision dac667f7
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 = Xmalloc(sizeof(XI18NObjectsListRec) * lc_len); 189 if (!xi18n_objects_list) return; 190 } 191 snprintf(filename, sizeof(filename), "%s/%s", 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 int new_len = lc_len + OBJECT_INC_LEN; 210 XI18NObjectsListRec *tmp = Xrealloc(xi18n_objects_list, 211 sizeof(XI18NObjectsListRec) * new_len); 212 if (tmp == NULL) 213 goto done; 214 xi18n_objects_list = tmp; 215 lc_len = new_len; 216 } 217 n = parse_line(p, args, 6); 218 219 if (n == 3 || n == 5) { 220 if (!strcmp(args[0], "XLC")){ 221 xi18n_objects_list[lc_count].type = XLC_OBJECT; 222 } else if (!strcmp(args[0], "XOM")){ 223 xi18n_objects_list[lc_count].type = XOM_OBJECT; 224 } else if (!strcmp(args[0], "XIM")){ 225 xi18n_objects_list[lc_count].type = XIM_OBJECT; 226 } 227 xi18n_objects_list[lc_count].dl_name = strdup(args[1]); 228 xi18n_objects_list[lc_count].open = strdup(args[2]); 229 xi18n_objects_list[lc_count].dl_release = XI18N_DLREL; 230 xi18n_objects_list[lc_count].locale_name = strdup(lc_name); 231 xi18n_objects_list[lc_count].refcount = 0; 232 xi18n_objects_list[lc_count].dl_module = (void*)NULL; 233 if (n == 5) { 234 xi18n_objects_list[lc_count].im_register = strdup(args[3]); 235 xi18n_objects_list[lc_count].im_unregister = strdup(args[4]); 236 } else { 237 xi18n_objects_list[lc_count].im_register = NULL; 238 xi18n_objects_list[lc_count].im_unregister = NULL; 239 } 240 lc_count++; 241 } 242 } 243 done: 244 fclose(fp); 245} 246 247static char* 248__lc_path(const char *dl_name, const char *lc_dir) 249{ 250 char *path; 251 size_t len; 252 char *slash_p; 253 254 /* 255 * reject this for possible security issue 256 */ 257 if (strstr (dl_name, "../")) 258 return NULL; 259 260 len = (lc_dir ? strlen(lc_dir) : 0 ) + 261 (dl_name ? strlen(dl_name) : 0) + 10; 262#if defined POSTLOCALELIBDIR 263 len += (strlen(POSTLOCALELIBDIR) + 1); 264#endif 265 path = Xmalloc(len + 1); 266 267 if (strchr(dl_name, '/') != NULL) { 268 slash_p = strrchr(lc_dir, '/'); 269 *slash_p = '\0'; 270 } else 271 slash_p = NULL; 272 273#if defined POSTLOCALELIBDIR 274 snprintf(path, len + 1, "%s/%s/%s.so.2", 275 lc_dir, POSTLOCALELIBDIR, dl_name); 276#else 277 snprintf(path, len + 1, "%s/%s.so.2", lc_dir, dl_name); 278#endif 279 280 if (slash_p != NULL) 281 *slash_p = '/'; 282 283 return path; 284} 285 286/* We reference count dlopen() and dlclose() of modules; unfortunately, 287 * since XCloseIM, XCloseOM, XlcClose aren't wrapped, but directly 288 * call the close method of the object, we leak a reference count every 289 * time we open then close a module. Fixing this would require 290 * either creating proxy objects or hooks for close_im/close_om 291 * in XLCd 292 */ 293static Bool 294open_object( 295 XI18NObjectsList object, 296 char *lc_dir) 297{ 298 char *path; 299 300 if (object->refcount == 0) { 301 path = __lc_path(object->dl_name, lc_dir); 302 if (!path) 303 return False; 304#if defined(hpux) 305 object->dl_module = shl_load(path, BIND_DEFERRED, 0L); 306#else 307 object->dl_module = dlopen(path, RTLD_LAZY); 308#endif 309 Xfree(path); 310 311 if (!object->dl_module) 312 return False; 313 } 314 315 object->refcount++; 316 return True; 317} 318 319static void * 320fetch_symbol( 321 XI18NObjectsList object, 322 char *symbol) 323{ 324 void *result = NULL; 325#if defined(hpux) 326 int getsyms_cnt, i; 327 struct shl_symbol *symbols; 328#endif 329 330 if (symbol == NULL) 331 return NULL; 332 333#if defined(hpux) 334 getsyms_cnt = shl_getsymbols(object->dl_module, TYPE_PROCEDURE, 335 EXPORT_SYMBOLS, malloc, &symbols); 336 337 for(i=0; i<getsyms_cnt; i++) { 338 if(!strcmp(symbols[i].name, symbol)) { 339 result = symbols[i].value; 340 break; 341 } 342 } 343 344 if(getsyms_cnt > 0) { 345 free(symbols); 346 } 347#else 348 result = try_both_dlsym(object->dl_module, symbol); 349#endif 350 351 return result; 352} 353 354static void 355close_object(XI18NObjectsList object) 356{ 357 object->refcount--; 358 if (object->refcount == 0) 359 { 360#if defined(hpux) 361 shl_unload(object->dl_module); 362#else 363 dlclose(object->dl_module); 364#endif 365 object->dl_module = NULL; 366 } 367} 368 369 370typedef XLCd (*dynamicLoadProc)(const char *); 371 372XLCd 373_XlcDynamicLoad(const char *lc_name) 374{ 375 XLCd lcd = (XLCd)NULL; 376 dynamicLoadProc lc_loader = (dynamicLoadProc)NULL; 377 int count; 378 XI18NObjectsList objects_list; 379 char lc_dir[BUFSIZE], lc_lib_dir[BUFSIZE]; 380 381 if (lc_name == NULL) return (XLCd)NULL; 382 383 if (_XlcLocaleDirName(lc_dir, BUFSIZE, lc_name) == NULL) 384 return (XLCd)NULL; 385 if (_XlcLocaleLibDirName(lc_lib_dir, BUFSIZE, lc_name) == NULL) 386 return (XLCd)NULL; 387 388 resolve_object(lc_dir, lc_name); 389 resolve_object(lc_lib_dir, lc_name); 390 391 objects_list = xi18n_objects_list; 392 count = lc_count; 393 for (; count-- > 0; objects_list++) { 394 if (objects_list->type != XLC_OBJECT || 395 strcmp(objects_list->locale_name, lc_name)) continue; 396 if (!open_object (objects_list, lc_dir) && \ 397 !open_object (objects_list, lc_lib_dir)) 398 continue; 399 400 lc_loader = (dynamicLoadProc)fetch_symbol (objects_list, objects_list->open); 401 if (!lc_loader) continue; 402 lcd = (*lc_loader)(lc_name); 403 if (lcd != (XLCd)NULL) { 404 break; 405 } 406 407 close_object (objects_list); 408 } 409 return (XLCd)lcd; 410} 411 412 413typedef XIM (*dynamicOpenProcp)(XLCd, Display *, XrmDatabase, char *, char *); 414 415static XIM 416_XDynamicOpenIM(XLCd lcd, Display *display, XrmDatabase rdb, 417 char *res_name, char *res_class) 418{ 419 XIM im = (XIM)NULL; 420 char lc_dir[BUFSIZE]; 421 char *lc_name; 422 dynamicOpenProcp im_openIM = (dynamicOpenProcp)NULL; 423 int count; 424 XI18NObjectsList objects_list = xi18n_objects_list; 425 426 lc_name = lcd->core->name; 427 428 if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return (XIM)0; 429 430 count = lc_count; 431 for (; count-- > 0; objects_list++) { 432 if (objects_list->type != XIM_OBJECT || 433 strcmp(objects_list->locale_name, lc_name)) continue; 434 435 if (!open_object (objects_list, lc_dir)) 436 continue; 437 438 im_openIM = (dynamicOpenProcp)fetch_symbol(objects_list, objects_list->open); 439 if (!im_openIM) continue; 440 im = (*im_openIM)(lcd, display, rdb, res_name, res_class); 441 if (im != (XIM)NULL) { 442 break; 443 } 444 445 close_object (objects_list); 446 } 447 return (XIM)im; 448} 449 450typedef Bool (*dynamicRegisterCBProcp)( 451 XLCd, Display *, XrmDatabase, char *, char *, XIDProc, XPointer); 452 453static Bool 454_XDynamicRegisterIMInstantiateCallback( 455 XLCd lcd, 456 Display *display, 457 XrmDatabase rdb, 458 char *res_name, 459 char *res_class, 460 XIDProc callback, 461 XPointer client_data) 462{ 463 char lc_dir[BUFSIZE]; 464 char *lc_name; 465 dynamicRegisterCBProcp im_registerIM = (dynamicRegisterCBProcp)NULL; 466 Bool ret_flag = False; 467 int count; 468 XI18NObjectsList objects_list = xi18n_objects_list; 469#if defined(hpux) 470 int getsyms_cnt, i; 471 struct shl_symbol *symbols; 472#endif 473 474 lc_name = lcd->core->name; 475 476 if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return False; 477 478 count = lc_count; 479 for (; count-- > 0; objects_list++) { 480 if (objects_list->type != XIM_OBJECT || 481 strcmp(objects_list->locale_name, lc_name)) continue; 482 483 if (!open_object (objects_list, lc_dir)) 484 continue; 485 im_registerIM = (dynamicRegisterCBProcp)fetch_symbol(objects_list, 486 objects_list->im_register); 487 if (!im_registerIM) continue; 488 ret_flag = (*im_registerIM)(lcd, display, rdb, 489 res_name, res_class, 490 callback, client_data); 491 if (ret_flag) break; 492 493 close_object (objects_list); 494 } 495 return (Bool)ret_flag; 496} 497 498typedef Bool (*dynamicUnregisterProcp)( 499 XLCd, Display *, XrmDatabase, char *, char *, XIDProc, XPointer); 500 501static Bool 502_XDynamicUnRegisterIMInstantiateCallback( 503 XLCd lcd, 504 Display *display, 505 XrmDatabase rdb, 506 char *res_name, 507 char *res_class, 508 XIDProc callback, 509 XPointer client_data) 510{ 511 char lc_dir[BUFSIZE]; 512 const char *lc_name; 513 dynamicUnregisterProcp im_unregisterIM = (dynamicUnregisterProcp)NULL; 514 Bool ret_flag = False; 515 int count; 516 XI18NObjectsList objects_list = xi18n_objects_list; 517#if defined(hpux) 518 int getsyms_cnt, i; 519 struct shl_symbol *symbols; 520#endif 521 522 lc_name = lcd->core->name; 523 if (_XlcLocaleDirName(lc_dir, BUFSIZE, lc_name) == NULL) return False; 524 525 count = lc_count; 526 for (; count-- > 0; objects_list++) { 527 if (objects_list->type != XIM_OBJECT || 528 strcmp(objects_list->locale_name, lc_name)) continue; 529 530 if (!objects_list->refcount) /* Must already be opened */ 531 continue; 532 533 im_unregisterIM = (dynamicUnregisterProcp)fetch_symbol(objects_list, 534 objects_list->im_unregister); 535 536 if (!im_unregisterIM) continue; 537 ret_flag = (*im_unregisterIM)(lcd, display, rdb, 538 res_name, res_class, 539 callback, client_data); 540 if (ret_flag) { 541 close_object (objects_list); /* opened in RegisterIMInstantiateCallback */ 542 break; 543 } 544 } 545 return (Bool)ret_flag; 546} 547 548Bool 549_XInitDynamicIM(XLCd lcd) 550{ 551 if(lcd == (XLCd)NULL) 552 return False; 553 lcd->methods->open_im = _XDynamicOpenIM; 554 lcd->methods->register_callback = _XDynamicRegisterIMInstantiateCallback; 555 lcd->methods->unregister_callback = _XDynamicUnRegisterIMInstantiateCallback; 556 return True; 557} 558 559 560typedef XOM (*dynamicIOpenProcp)( 561 XLCd, Display *, XrmDatabase, _Xconst char *, _Xconst char *); 562 563static XOM 564_XDynamicOpenOM(XLCd lcd, Display *display, XrmDatabase rdb, 565 _Xconst char *res_name, _Xconst char *res_class) 566{ 567 XOM om = (XOM)NULL; 568 int count; 569 char lc_dir[BUFSIZE]; 570 char *lc_name; 571 dynamicIOpenProcp om_openOM = (dynamicIOpenProcp)NULL; 572 XI18NObjectsList objects_list = xi18n_objects_list; 573#if defined(hpux) 574 int getsyms_cnt, i; 575 struct shl_symbol *symbols; 576#endif 577 578 lc_name = lcd->core->name; 579 580 if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return (XOM)0; 581 582 count = lc_count; 583 for (; count-- > 0; objects_list++) { 584 if (objects_list->type != XOM_OBJECT || 585 strcmp(objects_list->locale_name, lc_name)) continue; 586 if (!open_object (objects_list, lc_dir)) 587 continue; 588 589 om_openOM = (dynamicIOpenProcp)fetch_symbol(objects_list, objects_list->open); 590 if (!om_openOM) continue; 591 om = (*om_openOM)(lcd, display, rdb, res_name, res_class); 592 if (om != (XOM)NULL) { 593 break; 594 } 595 close_object(objects_list); 596 } 597 return (XOM)om; 598} 599 600Bool 601_XInitDynamicOM(XLCd lcd) 602{ 603 if(lcd == (XLCd)NULL) 604 return False; 605 606 lcd->methods->open_om = _XDynamicOpenOM; 607 608 return True; 609} 610