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