xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

loadmod.c (30462B)


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