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