PageRenderTime 59ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/hw/xfree86/loader/loadmod.c

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