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