Home | History | Annotate | Line # | Download | only in loader
      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 #include "xf86Xinput.h"
     63 #include "loader.h"
     64 #include "xf86Optrec.h"
     65 
     66 #include <sys/types.h>
     67 #include <regex.h>
     68 #include <dirent.h>
     69 #include <limits.h>
     70 
     71 typedef struct _pattern {
     72     const char *pattern;
     73     regex_t rex;
     74 } PatternRec, *PatternPtr;
     75 
     76 /* Prototypes for static functions */
     77 static char *FindModule(const char *, const char *, const char **,
     78 			PatternPtr);
     79 static Bool CheckVersion(const char *, XF86ModuleVersionInfo *,
     80 			 const XF86ModReqInfo *);
     81 static void UnloadModuleOrDriver(ModuleDescPtr mod);
     82 static char *LoaderGetCanonicalName(const char *, PatternPtr);
     83 static void RemoveChild(ModuleDescPtr);
     84 static ModuleDescPtr doLoadModule(const char *, const char *, const char **,
     85 				  const char **, pointer,
     86 				  const XF86ModReqInfo *, int *, int *);
     87 
     88 const ModuleVersions LoaderVersionInfo = {
     89     XORG_VERSION_CURRENT,
     90     ABI_ANSIC_VERSION,
     91     ABI_VIDEODRV_VERSION,
     92     ABI_XINPUT_VERSION,
     93     ABI_EXTENSION_VERSION,
     94     ABI_FONT_VERSION
     95 };
     96 
     97 static void
     98 FreeStringList(char **paths)
     99 {
    100     char **p;
    101 
    102     if (!paths)
    103 	return;
    104 
    105     for (p = paths; *p; p++)
    106 	free(*p);
    107 
    108     free(paths);
    109 }
    110 
    111 static char **defaultPathList = NULL;
    112 
    113 static Bool
    114 PathIsAbsolute(const char *path)
    115 {
    116     return *path == '/';
    117 }
    118 
    119 /*
    120  * Convert a comma-separated path into a NULL-terminated array of path
    121  * elements, rejecting any that are not full absolute paths, and appending
    122  * a '/' when it isn't already present.
    123  */
    124 static char **
    125 InitPathList(const char *path)
    126 {
    127     char *fullpath = NULL;
    128     char *elem = NULL;
    129     char **list = NULL, **save = NULL;
    130     int len;
    131     int addslash;
    132     int n = 0;
    133 
    134     if (!path)
    135 	return defaultPathList;
    136 
    137     fullpath = strdup(path);
    138     if (!fullpath)
    139 	return NULL;
    140     elem = strtok(fullpath, ",");
    141     while (elem) {
    142 	if (PathIsAbsolute(elem))
    143 	{
    144 	    len = strlen(elem);
    145 	    addslash = (elem[len - 1] != '/');
    146 	    if (addslash)
    147 		len++;
    148 	    save = list;
    149 	    list = realloc(list, (n + 2) * sizeof(char *));
    150 	    if (!list) {
    151 		if (save) {
    152 		    save[n] = NULL;
    153 		    FreeStringList(save);
    154 		}
    155 		free(fullpath);
    156 		return NULL;
    157 	    }
    158 	    list[n] = malloc(len + 1);
    159 	    if (!list[n]) {
    160 		FreeStringList(list);
    161 		free(fullpath);
    162 		return NULL;
    163 	    }
    164 	    strcpy(list[n], elem);
    165 	    if (addslash) {
    166 		list[n][len - 1] = '/';
    167 		list[n][len] = '\0';
    168 	    }
    169 	    n++;
    170 	}
    171 	elem = strtok(NULL, ",");
    172     }
    173     if (list)
    174 	list[n] = NULL;
    175     free(fullpath);
    176     return list;
    177 }
    178 
    179 static void
    180 FreePathList(char **pathlist)
    181 {
    182     if (pathlist && pathlist != defaultPathList)
    183 	FreeStringList(pathlist);
    184 }
    185 
    186 void
    187 LoaderSetPath(const char *path)
    188 {
    189     if (!path)
    190 	return;
    191 
    192     defaultPathList = InitPathList(path);
    193 }
    194 
    195 /* Standard set of module subdirectories to search, in order of preference */
    196 static const char *stdSubdirs[] = {
    197     "",
    198     "input/",
    199     "drivers/",
    200     "multimedia/",
    201     "extensions/",
    202     "internal/",
    203     NULL
    204 };
    205 
    206 /*
    207  * Standard set of module name patterns to check, in order of preference
    208  * These are regular expressions (suitable for use with POSIX regex(3)).
    209  *
    210  * This list assumes that you're an ELFish platform and therefore your
    211  * shared libraries are named something.so.  If we're ever nuts enough
    212  * to port this DDX to, say, Darwin, we'll need to fix this.
    213  */
    214 static PatternRec stdPatterns[] = {
    215     {"^lib(.*)\\.so$",},
    216     {"(.*)_drv\\.so$",},
    217     {"(.*)\\.so$",},
    218     {NULL,}
    219 };
    220 
    221 static PatternPtr
    222 InitPatterns(const char **patternlist)
    223 {
    224     char errmsg[80];
    225     int i, e;
    226     PatternPtr patterns = NULL;
    227     PatternPtr p = NULL;
    228     static int firstTime = 1;
    229     const char **s;
    230 
    231     if (firstTime) {
    232 	/* precompile stdPatterns */
    233 	firstTime = 0;
    234 	for (p = stdPatterns; p->pattern; p++)
    235 	    if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) {
    236 		regerror(e, &p->rex, errmsg, sizeof(errmsg));
    237 		FatalError("InitPatterns: regcomp error for `%s': %s\n",
    238 			   p->pattern, errmsg);
    239 	    }
    240     }
    241 
    242     if (patternlist) {
    243 	for (i = 0, s = patternlist; *s; i++, s++)
    244 	    if (*s == DEFAULT_LIST)
    245 		i += sizeof(stdPatterns) / sizeof(stdPatterns[0]) - 1 - 1;
    246 	patterns = malloc((i + 1) * sizeof(PatternRec));
    247 	if (!patterns) {
    248 	    return NULL;
    249 	}
    250 	for (i = 0, s = patternlist; *s; i++, s++)
    251 	    if (*s != DEFAULT_LIST) {
    252 		p = patterns + i;
    253 		p->pattern = *s;
    254 		if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) {
    255 		    regerror(e, &p->rex, errmsg, sizeof(errmsg));
    256 		    ErrorF("InitPatterns: regcomp error for `%s': %s\n",
    257 			   p->pattern, errmsg);
    258 		    i--;
    259 		}
    260 	    } else {
    261 		for (p = stdPatterns; p->pattern; p++, i++)
    262 		    patterns[i] = *p;
    263 		if (p != stdPatterns)
    264 		    i--;
    265 	    }
    266 	patterns[i].pattern = NULL;
    267     } else
    268 	patterns = stdPatterns;
    269     return patterns;
    270 }
    271 
    272 static void
    273 FreePatterns(PatternPtr patterns)
    274 {
    275     if (patterns && patterns != stdPatterns)
    276 	free(patterns);
    277 }
    278 
    279 static const char **
    280 InitSubdirs(const char **subdirlist)
    281 {
    282     int i;
    283     const char **tmp_subdirlist = NULL;
    284     char **subdirs = NULL;
    285     const char **s, **stmp = NULL;
    286     const char *osname;
    287     const char *slash;
    288     int oslen = 0, len;
    289     Bool indefault;
    290 
    291     if (subdirlist == NULL) {
    292 	subdirlist = tmp_subdirlist = malloc(2 * sizeof(char *));
    293 	if (subdirlist == NULL)
    294 	    return NULL;
    295 	subdirlist[0] = DEFAULT_LIST;
    296 	subdirlist[1] = NULL;
    297     }
    298 
    299     LoaderGetOS(&osname, NULL, NULL, NULL);
    300     oslen = strlen(osname);
    301 
    302     {
    303 	/* Count number of entries and check for invalid paths */
    304 	for (i = 0, s = subdirlist; *s; i++, s++) {
    305 	    if (*s == DEFAULT_LIST) {
    306 		i += sizeof(stdSubdirs) / sizeof(stdSubdirs[0]) - 1 - 1;
    307 	    } else {
    308 		/*
    309 		 * Path validity check.  Don't allow absolute paths, or
    310 		 * paths containing "..".  To catch absolute paths on
    311 		 * platforms that use driver letters, don't allow the ':'
    312 		 * character to appear at all.
    313 		 */
    314 		if (**s == '/' || **s == '\\' || strchr(*s, ':') ||
    315 		    strstr(*s, "..")) {
    316 		    xf86Msg(X_ERROR, "InitSubdirs: Bad subdir: \"%s\"\n", *s);
    317 		    free(tmp_subdirlist);
    318 		    return NULL;
    319 		}
    320 	    }
    321 	}
    322 	subdirs = malloc((i * 2 + 1) * sizeof(char *));
    323 	if (!subdirs) {
    324 	    free(tmp_subdirlist);
    325 	    return NULL;
    326 	}
    327 	i = 0;
    328 	s = subdirlist;
    329 	indefault = FALSE;
    330 	while (*s) {
    331 	    if (*s == DEFAULT_LIST) {
    332 		/* Divert to the default list */
    333 		indefault = TRUE;
    334 		stmp = ++s;
    335 		s = stdSubdirs;
    336 	    }
    337 	    len = strlen(*s);
    338 	    if (**s && (*s)[len - 1] != '/') {
    339 		slash = "/";
    340 		len++;
    341 	    } else
    342 		slash = "";
    343 	    len += oslen + 2;
    344 	    if (!(subdirs[i] = malloc(len))) {
    345 		while (--i >= 0)
    346 		    free(subdirs[i]);
    347 		free(subdirs);
    348 		free(tmp_subdirlist);
    349 		return NULL;
    350 	    }
    351 	    /* tack on the OS name */
    352 	    sprintf(subdirs[i], "%s%s%s/", *s, slash, osname);
    353 	    i++;
    354 	    /* path as given */
    355 	    subdirs[i] = strdup(*s);
    356 	    i++;
    357 	    s++;
    358 	    if (indefault && !s) {
    359 		/* revert back to the main list */
    360 		indefault = FALSE;
    361 		s = stmp;
    362 	    }
    363 	}
    364 	subdirs[i] = NULL;
    365     }
    366     free(tmp_subdirlist);
    367     return (const char **)subdirs;
    368 }
    369 
    370 static void
    371 FreeSubdirs(const char **subdirs)
    372 {
    373     const char **s;
    374 
    375     if (subdirs) {
    376 	for (s = subdirs; *s; s++)
    377 	    free((char *)*s);
    378 	free(subdirs);
    379     }
    380 }
    381 
    382 static char *
    383 FindModuleInSubdir(const char *dirpath, const char *module)
    384 {
    385     struct dirent *direntry = NULL;
    386     DIR *dir = NULL;
    387     char *ret = NULL, tmpBuf[PATH_MAX];
    388     struct stat stat_buf;
    389 
    390     dir = opendir(dirpath);
    391     if (!dir)
    392         return NULL;
    393 
    394     while ((direntry = readdir(dir))) {
    395         if (direntry->d_name[0] == '.')
    396             continue;
    397         snprintf(tmpBuf, PATH_MAX, "%s%s/", dirpath, direntry->d_name);
    398 	/* the stat with the appended / fails for normal files,
    399 	   and works for sub dirs fine, looks a bit strange in strace
    400 	   but does seem to work */
    401         if ((stat(tmpBuf, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode)) {
    402             if ((ret = FindModuleInSubdir(tmpBuf, module)))
    403                 break;
    404             continue;
    405         }
    406 
    407         snprintf(tmpBuf, PATH_MAX, "lib%s.so", module);
    408         if (strcmp(direntry->d_name, tmpBuf) == 0) {
    409             if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1)
    410 		ret = NULL;
    411             break;
    412         }
    413 
    414         snprintf(tmpBuf, PATH_MAX, "%s_drv.so", module);
    415         if (strcmp(direntry->d_name, tmpBuf) == 0) {
    416             if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1)
    417 		ret = NULL;
    418             break;
    419         }
    420 
    421         snprintf(tmpBuf, PATH_MAX, "%s.so", module);
    422         if (strcmp(direntry->d_name, tmpBuf) == 0) {
    423             if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1)
    424 		ret = NULL;
    425             break;
    426         }
    427     }
    428 
    429     closedir(dir);
    430     return ret;
    431 }
    432 
    433 static char *
    434 FindModule(const char *module, const char *dirname, const char **subdirlist,
    435 	   PatternPtr patterns)
    436 {
    437     char buf[PATH_MAX + 1];
    438     char *dirpath = NULL;
    439     char *name = NULL;
    440     int dirlen;
    441     const char **subdirs = NULL;
    442     const char **s;
    443 
    444     dirpath = (char *)dirname;
    445     if (strlen(dirpath) > PATH_MAX)
    446 	return NULL;
    447 
    448     subdirs = InitSubdirs(subdirlist);
    449     if (!subdirs)
    450 	return NULL;
    451 
    452     for (s = subdirs; *s; s++) {
    453 	if ((dirlen = strlen(dirpath) + strlen(*s)) > PATH_MAX)
    454 	    continue;
    455 	strcpy(buf, dirpath);
    456 	strcat(buf, *s);
    457         if ((name = FindModuleInSubdir(buf, module)))
    458             break;
    459     }
    460 
    461     FreeSubdirs(subdirs);
    462     if (dirpath != dirname)
    463 	free(dirpath);
    464 
    465     return name;
    466 }
    467 
    468 char **
    469 LoaderListDirs(const char **subdirlist, const char **patternlist)
    470 {
    471     char buf[PATH_MAX + 1];
    472     char **pathlist;
    473     char **elem;
    474     const char **subdirs;
    475     const char **s;
    476     PatternPtr patterns;
    477     PatternPtr p;
    478     DIR *d;
    479     struct dirent *dp;
    480     regmatch_t match[2];
    481     struct stat stat_buf;
    482     int len, dirlen;
    483     char *fp;
    484     char **listing = NULL;
    485     char **save;
    486     int n = 0;
    487 
    488     if (!(pathlist = InitPathList(NULL)))
    489 	return NULL;
    490     if (!(subdirs = InitSubdirs(subdirlist))) {
    491 	FreePathList(pathlist);
    492 	return NULL;
    493     }
    494     if (!(patterns = InitPatterns(patternlist))) {
    495 	FreePathList(pathlist);
    496 	FreeSubdirs(subdirs);
    497 	return NULL;
    498     }
    499 
    500     for (elem = pathlist; *elem; elem++) {
    501 	for (s = subdirs; *s; s++) {
    502 	    if ((dirlen = strlen(*elem) + strlen(*s)) > PATH_MAX)
    503 		continue;
    504 	    strcpy(buf, *elem);
    505 	    strcat(buf, *s);
    506 	    fp = buf + dirlen;
    507 	    if (stat(buf, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode) &&
    508 		(d = opendir(buf))) {
    509 		if (buf[dirlen - 1] != '/') {
    510 		    buf[dirlen++] = '/';
    511 		    fp++;
    512 		}
    513 		while ((dp = readdir(d))) {
    514 		    if (dirlen + strlen(dp->d_name) > PATH_MAX)
    515 			continue;
    516 		    strcpy(fp, dp->d_name);
    517 		    if (!(stat(buf, &stat_buf) == 0 &&
    518 			  S_ISREG(stat_buf.st_mode)))
    519 			continue;
    520 		    for (p = patterns; p->pattern; p++) {
    521 			if (regexec(&p->rex, dp->d_name, 2, match, 0) == 0 &&
    522 			    match[1].rm_so != -1) {
    523 			    len = match[1].rm_eo - match[1].rm_so;
    524 			    save = listing;
    525 			    listing = realloc(listing,
    526 					       (n + 2) * sizeof(char *));
    527 			    if (!listing) {
    528 				if (save) {
    529 				    save[n] = NULL;
    530 				    FreeStringList(save);
    531 				}
    532 				FreePathList(pathlist);
    533 				FreeSubdirs(subdirs);
    534 				FreePatterns(patterns);
    535 				closedir(d);
    536 				return NULL;
    537 			    }
    538 			    listing[n] = malloc(len + 1);
    539 			    if (!listing[n]) {
    540 				FreeStringList(listing);
    541 				FreePathList(pathlist);
    542 				FreeSubdirs(subdirs);
    543 				FreePatterns(patterns);
    544 				closedir(d);
    545 				return NULL;
    546 			    }
    547 			    strncpy(listing[n], dp->d_name + match[1].rm_so,
    548 				    len);
    549 			    listing[n][len] = '\0';
    550 			    n++;
    551 			    break;
    552 			}
    553 		    }
    554 		}
    555 		closedir(d);
    556 	    }
    557 	}
    558     }
    559     if (listing)
    560 	listing[n] = NULL;
    561 
    562     FreePathList(pathlist);
    563     FreeSubdirs(subdirs);
    564     FreePatterns(patterns);
    565     return listing;
    566 }
    567 
    568 void
    569 LoaderFreeDirList(char **list)
    570 {
    571     FreeStringList(list);
    572 }
    573 
    574 static Bool
    575 CheckVersion(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 
    743 static ModuleDescPtr
    744 AddSibling(ModuleDescPtr head, ModuleDescPtr new)
    745 {
    746     new->sib = head;
    747     return new;
    748 }
    749 
    750 pointer
    751 LoadSubModule(pointer _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     ModuleDescPtr parent = (ModuleDescPtr)_parent;
    758 
    759     xf86MsgVerb(X_INFO, 3, "Loading sub module \"%s\"\n", module);
    760 
    761     if (PathIsAbsolute(module)) {
    762 	xf86Msg(X_ERROR,
    763 		"LoadSubModule: Absolute module path not permitted: \"%s\"\n",
    764 		module);
    765 	if (errmaj)
    766 	    *errmaj = LDR_BADUSAGE;
    767 	if (errmin)
    768 	    *errmin = 0;
    769 	return NULL;
    770     }
    771 
    772     submod = doLoadModule(module, NULL, subdirlist, patternlist, options,
    773 			  modreq, errmaj, errmin);
    774     if (submod && submod != (ModuleDescPtr) 1) {
    775 	parent->child = AddSibling(parent->child, submod);
    776 	submod->parent = parent;
    777     }
    778     return submod;
    779 }
    780 
    781 static ModuleDescPtr
    782 NewModuleDesc(const char *name)
    783 {
    784     ModuleDescPtr mdp = calloc(1, sizeof(ModuleDesc));
    785 
    786     if (mdp)
    787 	mdp->name = xstrdup(name);
    788 
    789     return mdp;
    790 }
    791 
    792 ModuleDescPtr
    793 DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent)
    794 {
    795     ModuleDescPtr ret;
    796     int errmaj, errmin;
    797 
    798     if (!mod)
    799 	return NULL;
    800 
    801     ret = NewModuleDesc(mod->name);
    802     if (ret == NULL)
    803 	return NULL;
    804 
    805     if (!(ret->handle = LoaderOpen(mod->path, &errmaj, &errmin))) {
    806         free(ret);
    807         return NULL;
    808     }
    809 
    810     ret->SetupProc = mod->SetupProc;
    811     ret->TearDownProc = mod->TearDownProc;
    812     ret->TearDownData = NULL;
    813     ret->child = DuplicateModule(mod->child, ret);
    814     ret->sib = DuplicateModule(mod->sib, parent);
    815     ret->parent = parent;
    816     ret->VersionInfo = mod->VersionInfo;
    817     ret->path = strdup(mod->path);
    818 
    819     return ret;
    820 }
    821 
    822 static const char *compiled_in_modules[] = {
    823     "ddc",
    824     "i2c",
    825     "ramdac",
    826     NULL
    827 };
    828 
    829 static ModuleDescPtr
    830 doLoadModule(const char *module, const char *path, const char **subdirlist,
    831 	     const char **patternlist, pointer options,
    832 	     const XF86ModReqInfo * modreq,
    833 	     int *errmaj, int *errmin)
    834 {
    835     XF86ModuleData *initdata = NULL;
    836     char **pathlist = NULL;
    837     char *found = NULL;
    838     char *name = NULL;
    839     char **path_elem = NULL;
    840     char *p = NULL;
    841     ModuleDescPtr ret = NULL;
    842     PatternPtr patterns = NULL;
    843     int noncanonical = 0;
    844     char *m = NULL;
    845     const char **cim;
    846 
    847     xf86MsgVerb(X_INFO, 3, "LoadModule: \"%s\"", module);
    848 
    849     patterns = InitPatterns(patternlist);
    850     name = LoaderGetCanonicalName(module, patterns);
    851     noncanonical = (name && strcmp(module, name) != 0);
    852     if (noncanonical) {
    853 	xf86ErrorFVerb(3, " (%s)\n", name);
    854 	xf86MsgVerb(X_WARNING, 1,
    855 		    "LoadModule: given non-canonical module name \"%s\"\n",
    856 		    module);
    857 	m = name;
    858     } else {
    859 	xf86ErrorFVerb(3, "\n");
    860 	m = (char *)module;
    861     }
    862 
    863     for (cim = compiled_in_modules; *cim; cim++)
    864 	if (!strcmp (m, *cim))
    865 	{
    866 	    xf86MsgVerb(X_INFO, 3, "Module \"%s\" already built-in\n", m);
    867 	    ret = (ModuleDescPtr) 1;
    868 	    goto LoadModule_exit;
    869 	}
    870 
    871     if (!name) {
    872 	if (errmaj)
    873 	    *errmaj = LDR_BADUSAGE;
    874 	if (errmin)
    875 	    *errmin = 0;
    876 	goto LoadModule_fail;
    877     }
    878     ret = NewModuleDesc(name);
    879     if (!ret) {
    880 	if (errmaj)
    881 	    *errmaj = LDR_NOMEM;
    882 	if (errmin)
    883 	    *errmin = 0;
    884 	goto LoadModule_fail;
    885     }
    886 
    887     pathlist = InitPathList(path);
    888     if (!pathlist) {
    889 	/* This could be a malloc failure too */
    890 	if (errmaj)
    891 	    *errmaj = LDR_BADUSAGE;
    892 	if (errmin)
    893 	    *errmin = 1;
    894 	goto LoadModule_fail;
    895     }
    896 
    897     /*
    898      * if the module name is not a full pathname, we need to
    899      * check the elements in the path
    900      */
    901     if (PathIsAbsolute(module))
    902 	found = xstrdup(module);
    903     path_elem = pathlist;
    904     while (!found && *path_elem != NULL) {
    905 	found = FindModule(m, *path_elem, subdirlist, patterns);
    906 	path_elem++;
    907 	/*
    908 	 * When the module name isn't the canonical name, search for the
    909 	 * former if no match was found for the latter.
    910 	 */
    911 	if (!*path_elem && m == name) {
    912 	    path_elem = pathlist;
    913 	    m = (char *)module;
    914 	}
    915     }
    916 
    917     /*
    918      * did we find the module?
    919      */
    920     if (!found) {
    921 	xf86Msg(X_WARNING, "Warning, couldn't open module %s\n", module);
    922 	if (errmaj)
    923 	    *errmaj = LDR_NOENT;
    924 	if (errmin)
    925 	    *errmin = 0;
    926 	goto LoadModule_fail;
    927     }
    928     ret->handle = LoaderOpen(found, errmaj, errmin);
    929     if (ret->handle == NULL)
    930 	goto LoadModule_fail;
    931     ret->path = strdup(found);
    932 
    933     /* drop any explicit suffix from the module name */
    934     p = strchr(name, '.');
    935     if (p)
    936         *p = '\0';
    937 
    938     /*
    939      * now check if the special data object <modulename>ModuleData is
    940      * present.
    941      */
    942     if (asprintf(&p, "%sModuleData", name) == -1) {
    943 	p = NULL;
    944 	if (errmaj)
    945 	    *errmaj = LDR_NOMEM;
    946 	if (errmin)
    947 	    *errmin = 0;
    948 	goto LoadModule_fail;
    949     }
    950     initdata = LoaderSymbol(p);
    951     if (initdata) {
    952 	ModuleSetupProc setup;
    953 	ModuleTearDownProc teardown;
    954 	XF86ModuleVersionInfo *vers;
    955 
    956 	vers = initdata->vers;
    957 	setup = initdata->setup;
    958 	teardown = initdata->teardown;
    959 
    960         if (vers) {
    961             if (!CheckVersion(module, vers, modreq)) {
    962                 if (errmaj)
    963                     *errmaj = LDR_MISMATCH;
    964                 if (errmin)
    965                     *errmin = 0;
    966                 goto LoadModule_fail;
    967             }
    968         } else {
    969             xf86Msg(X_ERROR,
    970                     "LoadModule: Module %s does not supply"
    971                     " version information\n", module);
    972             if (errmaj)
    973                 *errmaj = LDR_INVALID;
    974             if (errmin)
    975                 *errmin = 0;
    976             goto LoadModule_fail;
    977         }
    978 	if (setup)
    979 	    ret->SetupProc = setup;
    980 	if (teardown)
    981 	    ret->TearDownProc = teardown;
    982 	ret->VersionInfo = vers;
    983     } else {
    984 	/* No initdata is OK for external modules */
    985 	if (options == EXTERN_MODULE)
    986 	    goto LoadModule_exit;
    987 
    988 	/* no initdata, fail the load */
    989 	xf86Msg(X_ERROR, "LoadModule: Module %s does not have a %s "
    990 		"data object.\n", module, p);
    991 	if (errmaj)
    992 	    *errmaj = LDR_INVALID;
    993 	if (errmin)
    994 	    *errmin = 0;
    995 	goto LoadModule_fail;
    996     }
    997     if (ret->SetupProc) {
    998 	ret->TearDownData = ret->SetupProc(ret, options, errmaj, errmin);
    999 	if (!ret->TearDownData) {
   1000 	    goto LoadModule_fail;
   1001 	}
   1002     } else if (options) {
   1003 	xf86Msg(X_WARNING, "Module Options present, but no SetupProc "
   1004 		"available for %s\n", module);
   1005     }
   1006     goto LoadModule_exit;
   1007 
   1008   LoadModule_fail:
   1009     UnloadModule(ret);
   1010     ret = NULL;
   1011 
   1012   LoadModule_exit:
   1013     FreePathList(pathlist);
   1014     FreePatterns(patterns);
   1015     free(found);
   1016     free(name);
   1017     free(p);
   1018 
   1019     return ret;
   1020 }
   1021 
   1022 /*
   1023  * LoadModule: load a module
   1024  *
   1025  * module       The module name.  Normally this is not a filename but the
   1026  *              module's "canonical name.  A full pathname is, however,
   1027  *              also accepted.
   1028  * path         A comma separated list of module directories.
   1029  * subdirlist   A NULL terminated list of subdirectories to search.  When
   1030  *              NULL, the default "stdSubdirs" list is used.  The default
   1031  *              list is also substituted for entries with value DEFAULT_LIST.
   1032  * patternlist  A NULL terminated list of regular expressions used to find
   1033  *              module filenames.  Each regex should contain exactly one
   1034  *              subexpression that corresponds to the canonical module name.
   1035  *              When NULL, the default "stdPatterns" list is used.  The
   1036  *              default list is also substituted for entries with value
   1037  *              DEFAULT_LIST.
   1038  * options      A NULL terminated list of Options that are passed to the
   1039  *              module's SetupProc function.
   1040  * modreq       An optional XF86ModReqInfo* containing
   1041  *              version/ABI/vendor-ABI requirements to check for when
   1042  *              loading the module.  The following fields of the
   1043  *              XF86ModReqInfo struct are checked:
   1044  *                majorversion - must match the module's majorversion exactly
   1045  *                minorversion - the module's minorversion must be >= this
   1046  *                patchlevel   - the module's minorversion.patchlevel must be
   1047  *                               >= this.  Patchlevel is ignored when
   1048  *                               minorversion is not set.
   1049  *                abiclass     - (string) must match the module's abiclass
   1050  *                abiversion   - must be consistent with the module's
   1051  *                               abiversion (major equal, minor no older)
   1052  *                moduleclass  - string must match the module's moduleclass
   1053  *                               string
   1054  *              "don't care" values are ~0 for numbers, and NULL for strings
   1055  * errmaj       Major error return.
   1056  * errmin       Minor error return.
   1057  *
   1058  */
   1059 ModuleDescPtr
   1060 LoadModule(const char *module, const char *path, const char **subdirlist,
   1061 	   const char **patternlist, pointer options,
   1062 	   const XF86ModReqInfo * modreq, int *errmaj, int *errmin)
   1063 {
   1064   return doLoadModule(module, path, subdirlist, patternlist, options,
   1065 		      modreq, errmaj, errmin);
   1066 }
   1067 
   1068 void
   1069 UnloadModule(pointer mod)
   1070 {
   1071     UnloadModuleOrDriver((ModuleDescPtr)mod);
   1072 }
   1073 
   1074 static void
   1075 UnloadModuleOrDriver(ModuleDescPtr mod)
   1076 {
   1077     if (mod == (ModuleDescPtr) 1)
   1078 	return;
   1079 
   1080     if (mod == NULL || mod->name == NULL)
   1081 	return;
   1082 
   1083     xf86MsgVerb(X_INFO, 3, "UnloadModule: \"%s\"\n", mod->name);
   1084 
   1085     if ((mod->TearDownProc) && (mod->TearDownData))
   1086 	mod->TearDownProc(mod->TearDownData);
   1087     LoaderUnload(mod->name, mod->handle);
   1088 
   1089     if (mod->child)
   1090 	UnloadModuleOrDriver(mod->child);
   1091     if (mod->sib)
   1092 	UnloadModuleOrDriver(mod->sib);
   1093     free(mod->path);
   1094     free(mod->name);
   1095     free(mod);
   1096 }
   1097 
   1098 void
   1099 UnloadSubModule(pointer _mod)
   1100 {
   1101     ModuleDescPtr mod = (ModuleDescPtr)_mod;
   1102 
   1103     if (mod == NULL || mod->name == NULL)
   1104 	return;
   1105 
   1106     xf86MsgVerb(X_INFO, 3, "UnloadSubModule: \"%s\"\n", mod->name);
   1107 
   1108     if ((mod->TearDownProc) && (mod->TearDownData))
   1109 	mod->TearDownProc(mod->TearDownData);
   1110     LoaderUnload(mod->name, mod->handle);
   1111 
   1112     RemoveChild(mod);
   1113 
   1114     if (mod->child)
   1115 	UnloadModuleOrDriver(mod->child);
   1116 
   1117     free(mod->path);
   1118     free(mod->name);
   1119     free(mod);
   1120 }
   1121 
   1122 static void
   1123 RemoveChild(ModuleDescPtr child)
   1124 {
   1125     ModuleDescPtr mdp;
   1126     ModuleDescPtr prevsib;
   1127     ModuleDescPtr parent;
   1128 
   1129     if (!child->parent)
   1130 	return;
   1131 
   1132     parent = child->parent;
   1133     if (parent->child == child) {
   1134 	parent->child = child->sib;
   1135 	return;
   1136     }
   1137 
   1138     prevsib = parent->child;
   1139     mdp = prevsib->sib;
   1140     while (mdp && mdp != child) {
   1141 	prevsib = mdp;
   1142 	mdp = mdp->sib;
   1143     }
   1144     if (mdp == child)
   1145 	prevsib->sib = child->sib;
   1146     return;
   1147 }
   1148 
   1149 void
   1150 LoaderErrorMsg(const char *name, const char *modname, int errmaj, int errmin)
   1151 {
   1152     const char *msg;
   1153     MessageType type = X_ERROR;
   1154 
   1155     switch (errmaj) {
   1156     case LDR_NOERROR:
   1157 	msg = "no error";
   1158 	break;
   1159     case LDR_NOMEM:
   1160 	msg = "out of memory";
   1161 	break;
   1162     case LDR_NOENT:
   1163 	msg = "module does not exist";
   1164 	break;
   1165     case LDR_NOSUBENT:
   1166 	msg = "a required submodule could not be loaded";
   1167 	break;
   1168     case LDR_NOSPACE:
   1169 	msg = "too many modules";
   1170 	break;
   1171     case LDR_NOMODOPEN:
   1172 	msg = "open failed";
   1173 	break;
   1174     case LDR_UNKTYPE:
   1175 	msg = "unknown module type";
   1176 	break;
   1177     case LDR_NOLOAD:
   1178 	msg = "loader failed";
   1179 	break;
   1180     case LDR_ONCEONLY:
   1181 	msg = "already loaded";
   1182         type = X_INFO;
   1183 	break;
   1184     case LDR_NOPORTOPEN:
   1185 	msg = "port open failed";
   1186 	break;
   1187     case LDR_NOHARDWARE:
   1188 	msg = "no hardware found";
   1189 	break;
   1190     case LDR_MISMATCH:
   1191 	msg = "module requirement mismatch";
   1192 	break;
   1193     case LDR_BADUSAGE:
   1194 	msg = "invalid argument(s) to LoadModule()";
   1195 	break;
   1196     case LDR_INVALID:
   1197 	msg = "invalid module";
   1198 	break;
   1199     case LDR_BADOS:
   1200 	msg = "module doesn't support this OS";
   1201 	break;
   1202     case LDR_MODSPECIFIC:
   1203 	msg = "module-specific error";
   1204 	break;
   1205     default:
   1206 	msg = "unknown error";
   1207     }
   1208     if (name)
   1209 	xf86Msg(type, "%s: Failed to load module \"%s\" (%s, %d)\n",
   1210 		name, modname, msg, errmin);
   1211     else
   1212 	xf86Msg(type, "Failed to load module \"%s\" (%s, %d)\n",
   1213 		modname, msg, errmin);
   1214 }
   1215 
   1216 /* Given a module path or file name, return the module's canonical name */
   1217 static char *
   1218 LoaderGetCanonicalName(const char *modname, PatternPtr patterns)
   1219 {
   1220     char *str;
   1221     const char *s;
   1222     int len;
   1223     PatternPtr p;
   1224     regmatch_t match[2];
   1225 
   1226     /* Strip off any leading path */
   1227     s = strrchr(modname, '/');
   1228     if (s == NULL)
   1229 	s = modname;
   1230     else
   1231 	s++;
   1232 
   1233     /* Find the first regex that is matched */
   1234     for (p = patterns; p->pattern; p++)
   1235 	if (regexec(&p->rex, s, 2, match, 0) == 0 && match[1].rm_so != -1) {
   1236 	    len = match[1].rm_eo - match[1].rm_so;
   1237 	    str = malloc(len + 1);
   1238 	    if (!str)
   1239 		return NULL;
   1240 	    strncpy(str, s + match[1].rm_so, len);
   1241 	    str[len] = '\0';
   1242 	    return str;
   1243 	}
   1244 
   1245     /* If there is no match, return the whole name minus the leading path */
   1246     return strdup(s);
   1247 }
   1248 
   1249 /*
   1250  * Return the module version information.
   1251  */
   1252 unsigned long
   1253 LoaderGetModuleVersion(ModuleDescPtr mod)
   1254 {
   1255     if (!mod || mod == (ModuleDescPtr) 1 || !mod->VersionInfo)
   1256 	return 0;
   1257 
   1258     return MODULE_VERSION_NUMERIC(mod->VersionInfo->majorversion,
   1259 				  mod->VersionInfo->minorversion,
   1260 				  mod->VersionInfo->patchlevel);
   1261 }
   1262