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