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