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