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