loadmod.c revision 05b261ec
1/* 2 * Copyright 1995-1998 by Metro Link, Inc. 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Metro Link, Inc. not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. Metro Link, Inc. makes no 11 * representations about the suitability of this software for any purpose. 12 * It is provided "as is" without express or implied warranty. 13 * 14 * METRO LINK, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL METRO LINK, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22/* 23 * Copyright (c) 1997-2002 by The XFree86 Project, Inc. 24 * 25 * Permission is hereby granted, free of charge, to any person obtaining a 26 * copy of this software and associated documentation files (the "Software"), 27 * to deal in the Software without restriction, including without limitation 28 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 29 * and/or sell copies of the Software, and to permit persons to whom the 30 * Software is furnished to do so, subject to the following conditions: 31 * 32 * The above copyright notice and this permission notice shall be included in 33 * all copies or substantial portions of the Software. 34 * 35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 36 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 38 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 39 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 40 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 41 * OTHER DEALINGS IN THE SOFTWARE. 42 * 43 * Except as contained in this notice, the name of the copyright holder(s) 44 * and author(s) shall not be used in advertising or otherwise to promote 45 * the sale, use or other dealings in this Software without prior written 46 * authorization from the copyright holder(s) and author(s). 47 */ 48 49#ifdef HAVE_XORG_CONFIG_H 50#include <xorg-config.h> 51#endif 52 53#include "os.h" 54/* For stat() and related stuff */ 55#define NO_OSLIB_PROTOTYPES 56#include "xf86_OSlib.h" 57#define LOADERDECLARATIONS 58#include "loaderProcs.h" 59#include "misc.h" 60#include "xf86.h" 61#include "xf86Priv.h" 62#ifdef XINPUT 63#include "xf86Xinput.h" 64#endif 65#include "loader.h" 66#include "xf86Optrec.h" 67 68#include <sys/types.h> 69#include <regex.h> 70#include <dirent.h> 71#include <limits.h> 72 73#define TestFree(a) if (a) { xfree (a); a = NULL; } 74 75typedef struct _pattern { 76 const char *pattern; 77 regex_t rex; 78} PatternRec, *PatternPtr; 79 80/* Prototypes for static functions */ 81static char *FindModule(const char *, const char *, const char **, 82 PatternPtr); 83static Bool CheckVersion(const char *, XF86ModuleVersionInfo *, 84 const XF86ModReqInfo *); 85static void UnloadModuleOrDriver(ModuleDescPtr mod); 86static char *LoaderGetCanonicalName(const char *, PatternPtr); 87static void RemoveChild(ModuleDescPtr); 88static ModuleDescPtr doLoadModule(const char *, const char *, const char **, 89 const char **, pointer, 90 const XF86ModReqInfo *, int *, int *, 91 int flags); 92 93const ModuleVersions LoaderVersionInfo = { 94 XORG_VERSION_CURRENT, 95 ABI_ANSIC_VERSION, 96 ABI_VIDEODRV_VERSION, 97 ABI_XINPUT_VERSION, 98 ABI_EXTENSION_VERSION, 99 ABI_FONT_VERSION 100}; 101 102static void 103FreeStringList(char **paths) 104{ 105 char **p; 106 107 if (!paths) 108 return; 109 110 for (p = paths; *p; p++) 111 xfree(*p); 112 113 xfree(paths); 114} 115 116static char **defaultPathList = NULL; 117 118static Bool 119PathIsAbsolute(const char *path) 120{ 121 return (*path == '/'); 122} 123 124/* 125 * Convert a comma-separated path into a NULL-terminated array of path 126 * elements, rejecting any that are not full absolute paths, and appending 127 * a '/' when it isn't already present. 128 */ 129static char ** 130InitPathList(const char *path) 131{ 132 char *fullpath = NULL; 133 char *elem = NULL; 134 char **list = NULL, **save = NULL; 135 int len; 136 int addslash; 137 int n = 0; 138 139 if (!path) 140 return defaultPathList; 141 142 fullpath = xstrdup(path); 143 if (!fullpath) 144 return NULL; 145 elem = strtok(fullpath, ","); 146 while (elem) { 147 if (PathIsAbsolute(elem)) 148 { 149 len = strlen(elem); 150 addslash = (elem[len - 1] != '/'); 151 if (addslash) 152 len++; 153 save = list; 154 list = xrealloc(list, (n + 2) * sizeof(char *)); 155 if (!list) { 156 if (save) { 157 save[n] = NULL; 158 FreeStringList(save); 159 } 160 xfree(fullpath); 161 return NULL; 162 } 163 list[n] = xalloc(len + 1); 164 if (!list[n]) { 165 FreeStringList(list); 166 xfree(fullpath); 167 return NULL; 168 } 169 strcpy(list[n], elem); 170 if (addslash) { 171 list[n][len - 1] = '/'; 172 list[n][len] = '\0'; 173 } 174 n++; 175 } 176 elem = strtok(NULL, ","); 177 } 178 if (list) 179 list[n] = NULL; 180 return list; 181} 182 183static void 184FreePathList(char **pathlist) 185{ 186 if (pathlist && pathlist != defaultPathList) 187 FreeStringList(pathlist); 188} 189 190void 191LoaderSetPath(const char *path) 192{ 193 if (!path) 194 return; 195 196 defaultPathList = InitPathList(path); 197} 198 199/* Standard set of module subdirectories to search, in order of preference */ 200static const char *stdSubdirs[] = { 201 "", 202 "fonts/", 203 "input/", 204 "drivers/", 205 "multimedia/", 206 "extensions/", 207 "internal/", 208 NULL 209}; 210 211/* 212 * Standard set of module name patterns to check, in order of preference 213 * These are regular expressions (suitable for use with POSIX regex(3)). 214 * 215 * This list assumes that you're an ELFish platform and therefore your 216 * shared libraries are named something.so. If we're ever nuts enough 217 * to port this DDX to, say, Darwin, we'll need to fix this. 218 */ 219static PatternRec stdPatterns[] = { 220 {"^lib(.*)\\.so$",}, 221 {"(.*)_drv\\.so$",}, 222 {"(.*)\\.so$",}, 223 {NULL,} 224}; 225 226static PatternPtr 227InitPatterns(const char **patternlist) 228{ 229 char errmsg[80]; 230 int i, e; 231 PatternPtr patterns = NULL; 232 PatternPtr p = NULL; 233 static int firstTime = 1; 234 const char **s; 235 236 if (firstTime) { 237 /* precompile stdPatterns */ 238 firstTime = 0; 239 for (p = stdPatterns; p->pattern; p++) 240 if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { 241 regerror(e, &p->rex, errmsg, sizeof(errmsg)); 242 FatalError("InitPatterns: regcomp error for `%s': %s\n", 243 p->pattern, errmsg); 244 } 245 } 246 247 if (patternlist) { 248 for (i = 0, s = patternlist; *s; i++, s++) 249 if (*s == DEFAULT_LIST) 250 i += sizeof(stdPatterns) / sizeof(stdPatterns[0]) - 1 - 1; 251 patterns = xalloc((i + 1) * sizeof(PatternRec)); 252 if (!patterns) { 253 return NULL; 254 } 255 for (i = 0, s = patternlist; *s; i++, s++) 256 if (*s != DEFAULT_LIST) { 257 p = patterns + i; 258 p->pattern = *s; 259 if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { 260 regerror(e, &p->rex, errmsg, sizeof(errmsg)); 261 ErrorF("InitPatterns: regcomp error for `%s': %s\n", 262 p->pattern, errmsg); 263 i--; 264 } 265 } else { 266 for (p = stdPatterns; p->pattern; p++, i++) 267 patterns[i] = *p; 268 if (p != stdPatterns) 269 i--; 270 } 271 patterns[i].pattern = NULL; 272 } else 273 patterns = stdPatterns; 274 return patterns; 275} 276 277static void 278FreePatterns(PatternPtr patterns) 279{ 280 if (patterns && patterns != stdPatterns) 281 xfree(patterns); 282} 283 284static const char ** 285InitSubdirs(const char **subdirlist) 286{ 287 int i; 288 const char **tmp_subdirlist = NULL; 289 char **subdirs = NULL; 290 const char **s, **stmp = NULL; 291 const char *osname; 292 const char *slash; 293 int oslen = 0, len; 294 Bool indefault; 295 296 if (subdirlist == NULL) { 297 subdirlist = tmp_subdirlist = xalloc(2 * sizeof(char *)); 298 if (subdirlist == NULL) 299 return NULL; 300 subdirlist[0] = DEFAULT_LIST; 301 subdirlist[1] = NULL; 302 } 303 304 LoaderGetOS(&osname, NULL, NULL, NULL); 305 oslen = strlen(osname); 306 307 { 308 /* Count number of entries and check for invalid paths */ 309 for (i = 0, s = subdirlist; *s; i++, s++) { 310 if (*s == DEFAULT_LIST) { 311 i += sizeof(stdSubdirs) / sizeof(stdSubdirs[0]) - 1 - 1; 312 } else { 313 /* 314 * Path validity check. Don't allow absolute paths, or 315 * paths containing "..". To catch absolute paths on 316 * platforms that use driver letters, don't allow the ':' 317 * character to appear at all. 318 */ 319 if (**s == '/' || **s == '\\' || strchr(*s, ':') || 320 strstr(*s, "..")) { 321 xf86Msg(X_ERROR, "InitSubdirs: Bad subdir: \"%s\"\n", *s); 322 if (tmp_subdirlist) 323 xfree(tmp_subdirlist); 324 return NULL; 325 } 326 } 327 } 328 subdirs = xalloc((i * 2 + 1) * sizeof(char *)); 329 if (!subdirs) { 330 if (tmp_subdirlist) 331 xfree(tmp_subdirlist); 332 return NULL; 333 } 334 i = 0; 335 s = subdirlist; 336 indefault = FALSE; 337 while (*s) { 338 if (*s == DEFAULT_LIST) { 339 /* Divert to the default list */ 340 indefault = TRUE; 341 stmp = ++s; 342 s = stdSubdirs; 343 } 344 len = strlen(*s); 345 if (**s && (*s)[len - 1] != '/') { 346 slash = "/"; 347 len++; 348 } else 349 slash = ""; 350 len += oslen + 2; 351 if (!(subdirs[i] = xalloc(len))) { 352 while (--i >= 0) 353 xfree(subdirs[i]); 354 xfree(subdirs); 355 if (tmp_subdirlist) 356 xfree(tmp_subdirlist); 357 return NULL; 358 } 359 /* tack on the OS name */ 360 sprintf(subdirs[i], "%s%s%s/", *s, slash, osname); 361 i++; 362 /* path as given */ 363 subdirs[i] = xstrdup(*s); 364 i++; 365 s++; 366 if (indefault && !s) { 367 /* revert back to the main list */ 368 indefault = FALSE; 369 s = stmp; 370 } 371 } 372 subdirs[i] = NULL; 373 } 374 if (tmp_subdirlist) 375 xfree(tmp_subdirlist); 376 return (const char **)subdirs; 377} 378 379static void 380FreeSubdirs(const char **subdirs) 381{ 382 const char **s; 383 384 if (subdirs) { 385 for (s = subdirs; *s; s++) 386 xfree(*s); 387 xfree(subdirs); 388 } 389} 390 391static char * 392FindModuleInSubdir(const char *dirpath, const char *module) 393{ 394 struct dirent *direntry = NULL; 395 DIR *dir = NULL; 396 char *ret = NULL, tmpBuf[PATH_MAX]; 397 struct stat stat_buf; 398 399 dir = opendir(dirpath); 400 if (!dir) 401 return NULL; 402 403 while ((direntry = readdir(dir))) { 404 if (direntry->d_name[0] == '.') 405 continue; 406 if ((stat(direntry->d_name, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode)) { 407 snprintf(tmpBuf, PATH_MAX, "%s/%s", dirpath, direntry->d_name); 408 if ((ret = FindModuleInSubdir(tmpBuf, module))) 409 break; 410 continue; 411 } 412 413 snprintf(tmpBuf, PATH_MAX, "lib%s.so", module); 414 if (strcmp(direntry->d_name, tmpBuf) == 0) { 415 ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); 416 sprintf(ret, "%s/%s", dirpath, tmpBuf); 417 break; 418 } 419 420 snprintf(tmpBuf, PATH_MAX, "%s_drv.so", module); 421 if (strcmp(direntry->d_name, tmpBuf) == 0) { 422 ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); 423 sprintf(ret, "%s/%s", dirpath, tmpBuf); 424 break; 425 } 426 427 snprintf(tmpBuf, PATH_MAX, "%s.so", module); 428 if (strcmp(direntry->d_name, tmpBuf) == 0) { 429 ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); 430 sprintf(ret, "%s/%s", dirpath, tmpBuf); 431 break; 432 } 433 } 434 435 closedir(dir); 436 return ret; 437} 438 439static char * 440FindModule(const char *module, const char *dirname, const char **subdirlist, 441 PatternPtr patterns) 442{ 443 char buf[PATH_MAX + 1]; 444 char *dirpath = NULL; 445 char *name = NULL; 446 int dirlen; 447 const char **subdirs = NULL; 448 const char **s; 449 450 dirpath = (char *)dirname; 451 if (strlen(dirpath) > PATH_MAX) 452 return NULL; 453 454 subdirs = InitSubdirs(subdirlist); 455 if (!subdirs) 456 return NULL; 457 458 for (s = subdirs; *s; s++) { 459 if ((dirlen = strlen(dirpath) + strlen(*s)) > PATH_MAX) 460 continue; 461 strcpy(buf, dirpath); 462 strcat(buf, *s); 463 if ((name = FindModuleInSubdir(buf, module))) 464 break; 465 } 466 467 FreeSubdirs(subdirs); 468 if (dirpath != dirname) 469 xfree(dirpath); 470 471 return name; 472} 473 474_X_EXPORT char ** 475LoaderListDirs(const char **subdirlist, const char **patternlist) 476{ 477 char buf[PATH_MAX + 1]; 478 char **pathlist; 479 char **elem; 480 const char **subdirs; 481 const char **s; 482 PatternPtr patterns; 483 PatternPtr p; 484 DIR *d; 485 struct dirent *dp; 486 regmatch_t match[2]; 487 struct stat stat_buf; 488 int len, dirlen; 489 char *fp; 490 char **listing = NULL; 491 char **save; 492 int n = 0; 493 494 if (!(pathlist = InitPathList(NULL))) 495 return NULL; 496 if (!(subdirs = InitSubdirs(subdirlist))) { 497 FreePathList(pathlist); 498 return NULL; 499 } 500 if (!(patterns = InitPatterns(patternlist))) { 501 FreePathList(pathlist); 502 FreeSubdirs(subdirs); 503 return NULL; 504 } 505 506 for (elem = pathlist; *elem; elem++) { 507 for (s = subdirs; *s; s++) { 508 if ((dirlen = strlen(*elem) + strlen(*s)) > PATH_MAX) 509 continue; 510 strcpy(buf, *elem); 511 strcat(buf, *s); 512 fp = buf + dirlen; 513 if (stat(buf, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode) && 514 (d = opendir(buf))) { 515 if (buf[dirlen - 1] != '/') { 516 buf[dirlen++] = '/'; 517 fp++; 518 } 519 while ((dp = readdir(d))) { 520 if (dirlen + strlen(dp->d_name) > PATH_MAX) 521 continue; 522 strcpy(fp, dp->d_name); 523 if (!(stat(buf, &stat_buf) == 0 && 524 S_ISREG(stat_buf.st_mode))) 525 continue; 526 for (p = patterns; p->pattern; p++) { 527 if (regexec(&p->rex, dp->d_name, 2, match, 0) == 0 && 528 match[1].rm_so != -1) { 529 len = match[1].rm_eo - match[1].rm_so; 530 save = listing; 531 listing = xrealloc(listing, 532 (n + 2) * sizeof(char *)); 533 if (!listing) { 534 if (save) { 535 save[n] = NULL; 536 FreeStringList(save); 537 } 538 FreePathList(pathlist); 539 FreeSubdirs(subdirs); 540 FreePatterns(patterns); 541 return NULL; 542 } 543 listing[n] = xalloc(len + 1); 544 if (!listing[n]) { 545 FreeStringList(listing); 546 FreePathList(pathlist); 547 FreeSubdirs(subdirs); 548 FreePatterns(patterns); 549 return NULL; 550 } 551 strncpy(listing[n], dp->d_name + match[1].rm_so, 552 len); 553 listing[n][len] = '\0'; 554 n++; 555 break; 556 } 557 } 558 } 559 closedir(d); 560 } 561 } 562 } 563 if (listing) 564 listing[n] = NULL; 565 return listing; 566} 567 568_X_EXPORT void 569LoaderFreeDirList(char **list) 570{ 571 FreeStringList(list); 572} 573 574static Bool 575CheckVersion(const char *module, XF86ModuleVersionInfo * data, 576 const XF86ModReqInfo * req) 577{ 578 int vercode[4]; 579 char verstr[4]; 580 long ver = data->xf86version; 581 MessageType errtype; 582 583 xf86Msg(X_INFO, "Module %s: vendor=\"%s\"\n", 584 data->modname ? data->modname : "UNKNOWN!", 585 data->vendor ? data->vendor : "UNKNOWN!"); 586 587 /* Check for the different scheme used in XFree86 4.0.x releases: 588 * ((((((((major << 7) | minor) << 7) | subminor) << 5) | beta) << 5) | alpha) 589 * Since it wasn't used in 4.1.0 or later, limit to versions in the 4.0.x 590 * range, which limits the overlap with the new version scheme to conflicts 591 * with 6.71.8.764 through 6.72.39.934. 592 */ 593 if ((ver > (4 << 24)) && (ver < ( (4 << 24) + (1 << 17)))) { 594 /* 4.0.x and earlier */ 595 verstr[1] = verstr[3] = 0; 596 verstr[2] = (ver & 0x1f) ? (ver & 0x1f) + 'a' - 1 : 0; 597 ver >>= 5; 598 verstr[0] = (ver & 0x1f) ? (ver & 0x1f) + 'A' - 1 : 0; 599 ver >>= 5; 600 vercode[2] = ver & 0x7f; 601 ver >>= 7; 602 vercode[1] = ver & 0x7f; 603 ver >>= 7; 604 vercode[0] = ver; 605 xf86ErrorF("\tcompiled for %d.%d", vercode[0], vercode[1]); 606 if (vercode[2] != 0) 607 xf86ErrorF(".%d", vercode[2]); 608 xf86ErrorF("%s%s, module version = %d.%d.%d\n", verstr, verstr + 2, 609 data->majorversion, data->minorversion, data->patchlevel); 610 } else { 611 vercode[0] = ver / 10000000; 612 vercode[1] = (ver / 100000) % 100; 613 vercode[2] = (ver / 1000) % 100; 614 vercode[3] = ver % 1000; 615 xf86ErrorF("\tcompiled for %d.%d.%d", vercode[0], vercode[1], 616 vercode[2]); 617 if (vercode[3] != 0) 618 xf86ErrorF(".%d", vercode[3]); 619 xf86ErrorF(", module version = %d.%d.%d\n", data->majorversion, 620 data->minorversion, data->patchlevel); 621 } 622 623 if (data->moduleclass) 624 xf86ErrorFVerb(2, "\tModule class: %s\n", data->moduleclass); 625 626 ver = -1; 627 if (data->abiclass) { 628 int abimaj, abimin; 629 int vermaj, vermin; 630 631 if (!strcmp(data->abiclass, ABI_CLASS_ANSIC)) 632 ver = LoaderVersionInfo.ansicVersion; 633 else if (!strcmp(data->abiclass, ABI_CLASS_VIDEODRV)) 634 ver = LoaderVersionInfo.videodrvVersion; 635 else if (!strcmp(data->abiclass, ABI_CLASS_XINPUT)) 636 ver = LoaderVersionInfo.xinputVersion; 637 else if (!strcmp(data->abiclass, ABI_CLASS_EXTENSION)) 638 ver = LoaderVersionInfo.extensionVersion; 639 else if (!strcmp(data->abiclass, ABI_CLASS_FONT)) 640 ver = LoaderVersionInfo.fontVersion; 641 642 abimaj = GET_ABI_MAJOR(data->abiversion); 643 abimin = GET_ABI_MINOR(data->abiversion); 644 xf86ErrorFVerb(2, "\tABI class: %s, version %d.%d\n", 645 data->abiclass, abimaj, abimin); 646 if (ver != -1) { 647 vermaj = GET_ABI_MAJOR(ver); 648 vermin = GET_ABI_MINOR(ver); 649 if (abimaj != vermaj) { 650 if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) 651 errtype = X_WARNING; 652 else 653 errtype = X_ERROR; 654 xf86MsgVerb(errtype, 0, 655 "module ABI major version (%d) doesn't" 656 " match the server's version (%d)\n", 657 abimaj, vermaj); 658 if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) 659 return FALSE; 660 } else if (abimin > vermin) { 661 if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) 662 errtype = X_WARNING; 663 else 664 errtype = X_ERROR; 665 xf86MsgVerb(errtype, 0, 666 "module ABI minor version (%d) is " 667 "newer than the server's version " 668 "(%d)\n", abimin, vermin); 669 if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) 670 return FALSE; 671 } 672 } 673 } 674 675 /* Check against requirements that the caller has specified */ 676 if (req) { 677 if (req->majorversion != MAJOR_UNSPEC) { 678 if (data->majorversion != req->majorversion) { 679 xf86MsgVerb(X_WARNING, 2, "module major version (%d) " 680 "doesn't match required major version (%d)\n", 681 data->majorversion, req->majorversion); 682 return FALSE; 683 } else if (req->minorversion != MINOR_UNSPEC) { 684 if (data->minorversion < req->minorversion) { 685 xf86MsgVerb(X_WARNING, 2, "module minor version (%d) " 686 "is less than the required minor version (%d)\n", 687 data->minorversion, req->minorversion); 688 return FALSE; 689 } else if (data->minorversion == req->minorversion && 690 req->patchlevel != PATCH_UNSPEC) { 691 if (data->patchlevel < req->patchlevel) { 692 xf86MsgVerb(X_WARNING, 2, "module patch level (%d) " 693 "is less than the required patch level (%d)\n", 694 data->patchlevel, req->patchlevel); 695 return FALSE; 696 } 697 } 698 } 699 } 700 if (req->moduleclass) { 701 if (!data->moduleclass || 702 strcmp(req->moduleclass, data->moduleclass)) { 703 xf86MsgVerb(X_WARNING, 2, "Module class (%s) doesn't match " 704 "the required class (%s)\n", 705 data->moduleclass ? data->moduleclass : "<NONE>", 706 req->moduleclass); 707 return FALSE; 708 } 709 } else if (req->abiclass != ABI_CLASS_NONE) { 710 if (!data->abiclass || strcmp(req->abiclass, data->abiclass)) { 711 xf86MsgVerb(X_WARNING, 2, "ABI class (%s) doesn't match the " 712 "required ABI class (%s)\n", 713 data->abiclass ? data->abiclass : "<NONE>", 714 req->abiclass); 715 return FALSE; 716 } 717 } 718 if ((req->abiclass != ABI_CLASS_NONE) && 719 req->abiversion != ABI_VERS_UNSPEC) { 720 int reqmaj, reqmin, maj, min; 721 722 reqmaj = GET_ABI_MAJOR(req->abiversion); 723 reqmin = GET_ABI_MINOR(req->abiversion); 724 maj = GET_ABI_MAJOR(data->abiversion); 725 min = GET_ABI_MINOR(data->abiversion); 726 if (maj != reqmaj) { 727 xf86MsgVerb(X_WARNING, 2, "ABI major version (%d) doesn't " 728 "match the required ABI major version (%d)\n", 729 maj, reqmaj); 730 return FALSE; 731 } 732 /* XXX Maybe this should be the other way around? */ 733 if (min > reqmin) { 734 xf86MsgVerb(X_WARNING, 2, "module ABI minor version (%d) " 735 "is newer than that available (%d)\n", min, reqmin); 736 return FALSE; 737 } 738 } 739 } 740 return TRUE; 741} 742 743static ModuleDescPtr 744AddSibling(ModuleDescPtr head, ModuleDescPtr new) 745{ 746 new->sib = head; 747 return (new); 748} 749 750_X_EXPORT ModuleDescPtr 751LoadSubModule(ModuleDescPtr parent, const char *module, 752 const char **subdirlist, const char **patternlist, 753 pointer options, const XF86ModReqInfo * modreq, 754 int *errmaj, int *errmin) 755{ 756 ModuleDescPtr submod; 757 758 xf86MsgVerb(X_INFO, 3, "Loading sub module \"%s\"\n", module); 759 760 if (PathIsAbsolute(module)) { 761 xf86Msg(X_ERROR, 762 "LoadSubModule: Absolute module path not permitted: \"%s\"\n", 763 module); 764 if (errmaj) 765 *errmaj = LDR_BADUSAGE; 766 if (errmin) 767 *errmin = 0; 768 return NULL; 769 } 770 771 submod = doLoadModule(module, NULL, subdirlist, patternlist, options, 772 modreq, errmaj, errmin, LD_FLAG_GLOBAL); 773 if (submod && submod != (ModuleDescPtr) 1) { 774 parent->child = AddSibling(parent->child, submod); 775 submod->parent = parent; 776 } 777 return submod; 778} 779 780static ModuleDescPtr 781NewModuleDesc(const char *name) 782{ 783 ModuleDescPtr mdp = xalloc(sizeof(ModuleDesc)); 784 785 if (mdp) { 786 mdp->child = NULL; 787 mdp->sib = NULL; 788 mdp->parent = NULL; 789 mdp->demand_next = NULL; 790 mdp->name = xstrdup(name); 791 mdp->filename = NULL; 792 mdp->identifier = NULL; 793 mdp->client_id = 0; 794 mdp->in_use = 0; 795 mdp->handle = -1; 796 mdp->SetupProc = NULL; 797 mdp->TearDownProc = NULL; 798 mdp->TearDownData = NULL; 799 } 800 801 return (mdp); 802} 803 804_X_EXPORT ModuleDescPtr 805DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent) 806{ 807 ModuleDescPtr ret; 808 809 if (!mod) 810 return NULL; 811 812 ret = NewModuleDesc(mod->name); 813 if (ret == NULL) 814 return NULL; 815 816 if (LoaderHandleOpen(mod->handle) == -1) 817 return NULL; 818 819 ret->filename = xstrdup(mod->filename); 820 ret->identifier = mod->identifier; 821 ret->client_id = mod->client_id; 822 ret->in_use = mod->in_use; 823 ret->handle = mod->handle; 824 ret->SetupProc = mod->SetupProc; 825 ret->TearDownProc = mod->TearDownProc; 826 ret->TearDownData = NULL; 827 ret->path = mod->path; 828 ret->child = DuplicateModule(mod->child, ret); 829 ret->sib = DuplicateModule(mod->sib, parent); 830 ret->parent = parent; 831 ret->VersionInfo = mod->VersionInfo; 832 833 return ret; 834} 835 836static const char *compiled_in_modules[] = { 837 "ddc", 838 "i2c", 839 "ramdac", 840 NULL 841}; 842 843static ModuleDescPtr 844doLoadModule(const char *module, const char *path, const char **subdirlist, 845 const char **patternlist, pointer options, 846 const XF86ModReqInfo * modreq, 847 int *errmaj, int *errmin, int flags) 848{ 849 XF86ModuleData *initdata = NULL; 850 char **pathlist = NULL; 851 char *found = NULL; 852 char *name = NULL; 853 char **path_elem = NULL; 854 char *p = NULL; 855 ModuleDescPtr ret = NULL; 856 int wasLoaded = 0; 857 PatternPtr patterns = NULL; 858 int noncanonical = 0; 859 char *m = NULL; 860 const char **cim; 861 862 xf86MsgVerb(X_INFO, 3, "LoadModule: \"%s\"", module); 863 864 for (cim = compiled_in_modules; *cim; cim++) 865 if (!strcmp (module, *cim)) 866 { 867 xf86MsgVerb(X_INFO, 0, "Module \"%s\" already built-in\n", module); 868 return (ModuleDescPtr) 1; 869 } 870 871 patterns = InitPatterns(patternlist); 872 name = LoaderGetCanonicalName(module, patterns); 873 noncanonical = (name && strcmp(module, name) != 0); 874 if (noncanonical) { 875 xf86ErrorFVerb(3, " (%s)\n", name); 876 xf86MsgVerb(X_WARNING, 1, 877 "LoadModule: given non-canonical module name \"%s\"\n", 878 module); 879 m = name; 880 } else { 881 xf86ErrorFVerb(3, "\n"); 882 m = (char *)module; 883 } 884 if (!name) { 885 if (errmaj) 886 *errmaj = LDR_BADUSAGE; 887 if (errmin) 888 *errmin = 0; 889 goto LoadModule_fail; 890 } 891 ret = NewModuleDesc(name); 892 if (!ret) { 893 if (errmaj) 894 *errmaj = LDR_NOMEM; 895 if (errmin) 896 *errmin = 0; 897 goto LoadModule_fail; 898 } 899 900 pathlist = InitPathList(path); 901 if (!pathlist) { 902 /* This could be a malloc failure too */ 903 if (errmaj) 904 *errmaj = LDR_BADUSAGE; 905 if (errmin) 906 *errmin = 1; 907 goto LoadModule_fail; 908 } 909 910 /* 911 * if the module name is not a full pathname, we need to 912 * check the elements in the path 913 */ 914 if (PathIsAbsolute(module)) 915 found = xstrdup(module); 916 path_elem = pathlist; 917 while (!found && *path_elem != NULL) { 918 found = FindModule(m, *path_elem, subdirlist, patterns); 919 path_elem++; 920 /* 921 * When the module name isn't the canonical name, search for the 922 * former if no match was found for the latter. 923 */ 924 if (!*path_elem && m == name) { 925 path_elem = pathlist; 926 m = (char *)module; 927 } 928 } 929 930 /* 931 * did we find the module? 932 */ 933 if (!found) { 934 xf86Msg(X_WARNING, "Warning, couldn't open module %s\n", module); 935 if (errmaj) 936 *errmaj = LDR_NOENT; 937 if (errmin) 938 *errmin = 0; 939 goto LoadModule_fail; 940 } 941 ret->handle = LoaderOpen(found, name, 0, 942 errmaj, errmin, &wasLoaded, flags); 943 if (ret->handle < 0) 944 goto LoadModule_fail; 945 946 ret->filename = xstrdup(found); 947 948 /* drop any explicit suffix from the module name */ 949 p = strchr(name, '.'); 950 if (p) 951 *p = '\0'; 952 953 /* 954 * now check if the special data object <modulename>ModuleData is 955 * present. 956 */ 957 p = xalloc(strlen(name) + strlen("ModuleData") + 1); 958 if (!p) { 959 if (errmaj) 960 *errmaj = LDR_NOMEM; 961 if (errmin) 962 *errmin = 0; 963 goto LoadModule_fail; 964 } 965 strcpy(p, name); 966 strcat(p, "ModuleData"); 967 initdata = LoaderSymbol(p); 968 if (initdata) { 969 ModuleSetupProc setup; 970 ModuleTearDownProc teardown; 971 XF86ModuleVersionInfo *vers; 972 973 vers = initdata->vers; 974 setup = initdata->setup; 975 teardown = initdata->teardown; 976 977 if (!wasLoaded) { 978 if (vers) { 979 if (!CheckVersion(module, vers, modreq)) { 980 if (errmaj) 981 *errmaj = LDR_MISMATCH; 982 if (errmin) 983 *errmin = 0; 984 goto LoadModule_fail; 985 } 986 } else { 987 xf86Msg(X_ERROR, 988 "LoadModule: Module %s does not supply" 989 " version information\n", module); 990 if (errmaj) 991 *errmaj = LDR_INVALID; 992 if (errmin) 993 *errmin = 0; 994 goto LoadModule_fail; 995 } 996 } 997 if (setup) 998 ret->SetupProc = setup; 999 if (teardown) 1000 ret->TearDownProc = teardown; 1001 ret->path = path; 1002 ret->VersionInfo = vers; 1003 } else { 1004 /* No initdata is OK for external modules */ 1005 if (options == EXTERN_MODULE) 1006 goto LoadModule_exit; 1007 1008 /* no initdata, fail the load */ 1009 xf86Msg(X_ERROR, "LoadModule: Module %s does not have a %s " 1010 "data object.\n", module, p); 1011 if (errmaj) 1012 *errmaj = LDR_INVALID; 1013 if (errmin) 1014 *errmin = 0; 1015 goto LoadModule_fail; 1016 } 1017 if (ret->SetupProc) { 1018 ret->TearDownData = ret->SetupProc(ret, options, errmaj, errmin); 1019 if (!ret->TearDownData) { 1020 goto LoadModule_fail; 1021 } 1022 } else if (options) { 1023 xf86Msg(X_WARNING, "Module Options present, but no SetupProc " 1024 "available for %s\n", module); 1025 } 1026 goto LoadModule_exit; 1027 1028 LoadModule_fail: 1029 UnloadModule(ret); 1030 ret = NULL; 1031 1032 LoadModule_exit: 1033 FreePathList(pathlist); 1034 FreePatterns(patterns); 1035 TestFree(found); 1036 TestFree(name); 1037 TestFree(p); 1038 1039 /* 1040 * If you need to do something to keep the 1041 * instruction cache in sync with the main 1042 * memory before jumping to that code, you may 1043 * do it here. 1044 */ 1045#ifdef __alpha__ 1046 istream_mem_barrier(); 1047#endif 1048 return ret; 1049} 1050 1051/* 1052 * LoadModule: load a module 1053 * 1054 * module The module name. Normally this is not a filename but the 1055 * module's "canonical name. A full pathname is, however, 1056 * also accepted. 1057 * path A comma separated list of module directories. 1058 * subdirlist A NULL terminated list of subdirectories to search. When 1059 * NULL, the default "stdSubdirs" list is used. The default 1060 * list is also substituted for entries with value DEFAULT_LIST. 1061 * patternlist A NULL terminated list of regular expressions used to find 1062 * module filenames. Each regex should contain exactly one 1063 * subexpression that corresponds to the canonical module name. 1064 * When NULL, the default "stdPatterns" list is used. The 1065 * default list is also substituted for entries with value 1066 * DEFAULT_LIST. 1067 * options A NULL terminated list of Options that are passed to the 1068 * module's SetupProc function. 1069 * modreq An optional XF86ModReqInfo* containing 1070 * version/ABI/vendor-ABI requirements to check for when 1071 * loading the module. The following fields of the 1072 * XF86ModReqInfo struct are checked: 1073 * majorversion - must match the module's majorversion exactly 1074 * minorversion - the module's minorversion must be >= this 1075 * patchlevel - the module's minorversion.patchlevel must be 1076 * >= this. Patchlevel is ignored when 1077 * minorversion is not set. 1078 * abiclass - (string) must match the module's abiclass 1079 * abiversion - must be consistent with the module's 1080 * abiversion (major equal, minor no older) 1081 * moduleclass - string must match the module's moduleclass 1082 * string 1083 * "don't care" values are ~0 for numbers, and NULL for strings 1084 * errmaj Major error return. 1085 * errmin Minor error return. 1086 * 1087 */ 1088ModuleDescPtr 1089LoadModule(const char *module, const char *path, const char **subdirlist, 1090 const char **patternlist, pointer options, 1091 const XF86ModReqInfo * modreq, int *errmaj, int *errmin) 1092{ 1093 return doLoadModule(module, path, subdirlist, patternlist, options, 1094 modreq, errmaj, errmin, LD_FLAG_GLOBAL); 1095} 1096 1097void 1098UnloadModule(ModuleDescPtr mod) 1099{ 1100 UnloadModuleOrDriver(mod); 1101} 1102 1103static void 1104UnloadModuleOrDriver(ModuleDescPtr mod) 1105{ 1106 if (mod == (ModuleDescPtr) 1) 1107 return; 1108 1109 if (mod == NULL || mod->name == NULL) 1110 return; 1111 1112 xf86MsgVerb(X_INFO, 3, "UnloadModule: \"%s\"\n", mod->name); 1113 1114 if ((mod->TearDownProc) && (mod->TearDownData)) 1115 mod->TearDownProc(mod->TearDownData); 1116 LoaderUnload(mod->handle); 1117 1118 if (mod->child) 1119 UnloadModuleOrDriver(mod->child); 1120 if (mod->sib) 1121 UnloadModuleOrDriver(mod->sib); 1122 TestFree(mod->name); 1123 TestFree(mod->filename); 1124 xfree(mod); 1125#ifdef __alpha__ 1126 istream_mem_barrier(); 1127#endif 1128} 1129 1130_X_EXPORT void 1131UnloadSubModule(ModuleDescPtr mod) 1132{ 1133 if (mod == NULL || mod->name == NULL) 1134 return; 1135 1136 xf86MsgVerb(X_INFO, 3, "UnloadSubModule: \"%s\"\n", mod->name); 1137 1138 if ((mod->TearDownProc) && (mod->TearDownData)) 1139 mod->TearDownProc(mod->TearDownData); 1140 LoaderUnload(mod->handle); 1141 1142 RemoveChild(mod); 1143 1144 if (mod->child) 1145 UnloadModuleOrDriver(mod->child); 1146 1147 TestFree(mod->name); 1148 TestFree(mod->filename); 1149 xfree(mod); 1150} 1151 1152static void 1153FreeModuleDesc(ModuleDescPtr head) 1154{ 1155 ModuleDescPtr sibs, prev; 1156 1157 if (head == (ModuleDescPtr) 1) 1158 return; 1159 /* 1160 * only free it if it's not marked as in use. In use means that it may 1161 * be unloaded someday, and UnloadModule will free it 1162 */ 1163 if (head->in_use) 1164 return; 1165 if (head->child) 1166 FreeModuleDesc(head->child); 1167 sibs = head; 1168 while (sibs) { 1169 prev = sibs; 1170 sibs = sibs->sib; 1171 TestFree(prev->name); 1172 xfree(prev); 1173 } 1174} 1175 1176static void 1177RemoveChild(ModuleDescPtr child) 1178{ 1179 ModuleDescPtr mdp; 1180 ModuleDescPtr prevsib; 1181 ModuleDescPtr parent; 1182 1183 if (!child->parent) 1184 return; 1185 1186 parent = child->parent; 1187 if (parent->child == child) { 1188 parent->child = child->sib; 1189 return; 1190 } 1191 1192 prevsib = parent->child; 1193 mdp = prevsib->sib; 1194 while (mdp && mdp != child) { 1195 prevsib = mdp; 1196 mdp = mdp->sib; 1197 } 1198 if (mdp == child) 1199 prevsib->sib = child->sib; 1200 return; 1201} 1202 1203_X_EXPORT void 1204LoaderErrorMsg(const char *name, const char *modname, int errmaj, int errmin) 1205{ 1206 const char *msg; 1207 MessageType type = X_ERROR; 1208 1209 switch (errmaj) { 1210 case LDR_NOERROR: 1211 msg = "no error"; 1212 break; 1213 case LDR_NOMEM: 1214 msg = "out of memory"; 1215 break; 1216 case LDR_NOENT: 1217 msg = "module does not exist"; 1218 break; 1219 case LDR_NOSUBENT: 1220 msg = "a required submodule could not be loaded"; 1221 break; 1222 case LDR_NOSPACE: 1223 msg = "too many modules"; 1224 break; 1225 case LDR_NOMODOPEN: 1226 msg = "open failed"; 1227 break; 1228 case LDR_UNKTYPE: 1229 msg = "unknown module type"; 1230 break; 1231 case LDR_NOLOAD: 1232 msg = "loader failed"; 1233 break; 1234 case LDR_ONCEONLY: 1235 msg = "already loaded"; 1236 type = X_INFO; 1237 break; 1238 case LDR_NOPORTOPEN: 1239 msg = "port open failed"; 1240 break; 1241 case LDR_NOHARDWARE: 1242 msg = "no hardware found"; 1243 break; 1244 case LDR_MISMATCH: 1245 msg = "module requirement mismatch"; 1246 break; 1247 case LDR_BADUSAGE: 1248 msg = "invalid argument(s) to LoadModule()"; 1249 break; 1250 case LDR_INVALID: 1251 msg = "invalid module"; 1252 break; 1253 case LDR_BADOS: 1254 msg = "module doesn't support this OS"; 1255 break; 1256 case LDR_MODSPECIFIC: 1257 msg = "module-specific error"; 1258 break; 1259 default: 1260 msg = "unknown error"; 1261 } 1262 if (name) 1263 xf86Msg(type, "%s: Failed to load module \"%s\" (%s, %d)\n", 1264 name, modname, msg, errmin); 1265 else 1266 xf86Msg(type, "Failed to load module \"%s\" (%s, %d)\n", 1267 modname, msg, errmin); 1268} 1269 1270/* Given a module path or file name, return the module's canonical name */ 1271static char * 1272LoaderGetCanonicalName(const char *modname, PatternPtr patterns) 1273{ 1274 char *str; 1275 const char *s; 1276 int len; 1277 PatternPtr p; 1278 regmatch_t match[2]; 1279 1280 /* Strip off any leading path */ 1281 s = strrchr(modname, '/'); 1282 if (s == NULL) 1283 s = modname; 1284 else 1285 s++; 1286 1287 /* Find the first regex that is matched */ 1288 for (p = patterns; p->pattern; p++) 1289 if (regexec(&p->rex, s, 2, match, 0) == 0 && match[1].rm_so != -1) { 1290 len = match[1].rm_eo - match[1].rm_so; 1291 str = xalloc(len + 1); 1292 if (!str) 1293 return NULL; 1294 strncpy(str, s + match[1].rm_so, len); 1295 str[len] = '\0'; 1296 return str; 1297 } 1298 1299 /* If there is no match, return the whole name minus the leading path */ 1300 return xstrdup(s); 1301} 1302 1303/* 1304 * Return the module version information. 1305 */ 1306unsigned long 1307LoaderGetModuleVersion(ModuleDescPtr mod) 1308{ 1309 if (!mod || mod == (ModuleDescPtr) 1 || !mod->VersionInfo) 1310 return 0; 1311 1312 return MODULE_VERSION_NUMERIC(mod->VersionInfo->majorversion, 1313 mod->VersionInfo->minorversion, 1314 mod->VersionInfo->patchlevel); 1315} 1316