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