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