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