From c38dead3ea7e177728d90cd815cf4eead0c9f534 Mon Sep 17 00:00:00 2001 From: marha Date: Sat, 15 May 2010 16:28:11 +0000 Subject: xserver git update 15/5/2010 --- xorg-server/hw/xfree86/loader/loadext.c | 884 +++++------ xorg-server/hw/xfree86/loader/loadmod.c | 2536 +++++++++++++++---------------- 2 files changed, 1710 insertions(+), 1710 deletions(-) (limited to 'xorg-server/hw/xfree86/loader') diff --git a/xorg-server/hw/xfree86/loader/loadext.c b/xorg-server/hw/xfree86/loader/loadext.c index 29cdaf1ac..26066856d 100644 --- a/xorg-server/hw/xfree86/loader/loadext.c +++ b/xorg-server/hw/xfree86/loader/loadext.c @@ -1,442 +1,442 @@ -/* - * Copyright (c) 2000 by The XFree86 Project, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the name of the copyright holder(s) - * and author(s) shall not be used in advertising or otherwise to promote - * the sale, use or other dealings in this Software without prior written - * authorization from the copyright holder(s) and author(s). - */ - -/* Maybe this file belongs elsewhere? */ - -#define LOADERDECLARATIONS -#ifdef HAVE_XORG_CONFIG_H -#include -#endif - -#include "loaderProcs.h" -#include "misc.h" -#include "xf86.h" - -/* - * This should be static, but miinitext wants it. FIXME: make extension - * initialization not completely terrible. - */ -ExtensionModule *ExtensionModuleList = NULL; -static int numExtensionModules = 0; - -static ExtensionModule * -NewExtensionModule(void) -{ - ExtensionModule *save = ExtensionModuleList; - int n; - - /* Sanity check */ - if (!ExtensionModuleList) - numExtensionModules = 0; - - n = numExtensionModules + 1; - ExtensionModuleList = xrealloc(ExtensionModuleList, - (n + 1) * sizeof(ExtensionModule)); - if (ExtensionModuleList == NULL) { - ExtensionModuleList = save; - return NULL; - } else { - numExtensionModules++; - ExtensionModuleList[numExtensionModules].name = NULL; - return ExtensionModuleList + (numExtensionModules - 1); - } -} - -void -LoadExtension(ExtensionModule * e, Bool builtin) -{ - ExtensionModule *newext; - - if (e == NULL || e->name == NULL) - return; - - if (!(newext = NewExtensionModule())) - return; - - if (builtin) - xf86MsgVerb(X_INFO, 2, "Initializing built-in extension %s\n", - e->name); - else - xf86MsgVerb(X_INFO, 2, "Loading extension %s\n", e->name); - - newext->name = e->name; - newext->initFunc = e->initFunc; - newext->disablePtr = e->disablePtr; - newext->setupFunc = e->setupFunc; - newext->initDependencies = e->initDependencies; - - if (e->setupFunc != NULL) - e->setupFunc(); -} - -/* - * Sort ExtensionModuleList according to the initialisation order - * dependencies. The code for this is taken from BSD's tsort, - * and carries the following copyright/license: - * - * - * Copyright (c) 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Michael Rendell of Memorial University of Newfoundland. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#define NF_MARK 0x1 /* marker for cycle detection */ -#define NF_ACYCLIC 0x2 /* this node is cycle free */ -#define NF_NODEST 0x4 /* Unreachable */ - -typedef struct node_str NODE; -struct node_str { - NODE **n_prevp; /* pointer to previous node's n_next */ - NODE *n_next; /* next node in graph */ - NODE **n_arcs; /* array of arcs to other nodes */ - int n_narcs; /* number of arcs in n_arcs[] */ - int n_arcsize; /* size of n_arcs[] array */ - int n_refcnt; /* # of arcs pointing to this node */ - int n_flags; /* NF_* */ - const char *n_name; /* name of this node */ -}; - -static NODE *graph = NULL, **cycle_buf = NULL, **longest_cycle = NULL; -static int longest = 0; -static NODE *sorted = NULL, *last = NULL; - -/* Find a node in the graph (insert if not found) and return a pointer to it. */ -static NODE * -get_node(const char *name) -{ - NODE *n; - - for (n = graph; n && n->n_name && strcmp(n->n_name, name); - n = n->n_next) ; - if (n) - return (n); - - n = xnfalloc(sizeof(NODE)); - - n->n_narcs = 0; - n->n_arcsize = 0; - n->n_arcs = NULL; - n->n_refcnt = 0; - n->n_flags = 0; - n->n_name = name; - - /* Add to linked list. */ - if ((n->n_next = graph) != NULL) - graph->n_prevp = &n->n_next; - n->n_prevp = &graph; - graph = n; - - return (n); -} - -/* - * add an arc from node s1 to node s2 in the graph. If s1 or s2 are not in - * the graph, then add them. - */ -static void -add_arc(const char *s1, const char *s2) -{ - NODE *n1; - NODE *n2; - int bsize, i; - - n1 = get_node(s1); - - if (!strcmp(s1, s2)) - return; - - n2 = get_node(s2); - - /* - * Check if this arc is already here. - */ - for (i = 0; i < n1->n_narcs; i++) - if (n1->n_arcs[i] == n2) - return; - /* - * Add it. - */ - if (n1->n_narcs == n1->n_arcsize) { - if (!n1->n_arcsize) - n1->n_arcsize = 10; - bsize = n1->n_arcsize * sizeof(*n1->n_arcs) * 2; - n1->n_arcs = xnfrealloc(n1->n_arcs, bsize); - n1->n_arcsize = bsize / sizeof(*n1->n_arcs); - } - n1->n_arcs[n1->n_narcs++] = n2; - ++n2->n_refcnt; -} - -/* - * Clear the NODEST flag from all nodes. - */ -static void -clear_cycle(void) -{ - NODE *n; - - for (n = graph; n != NULL; n = n->n_next) - n->n_flags &= ~NF_NODEST; -} - -/* print node and remove from graph (does not actually free node) */ -static void -remove_node(NODE * n) -{ - NODE **np; - NODE *newnode; - int i; - -#ifdef DEBUG - ErrorF("%s\n", n->n_name); -#endif - newnode = xnfalloc(sizeof(NODE)); - memcpy(newnode, n, sizeof(NODE)); - if (last) - last->n_next = newnode; - else - sorted = newnode; - last = newnode; - newnode->n_next = NULL; - - for (np = n->n_arcs, i = n->n_narcs; --i >= 0; np++) - --(*np)->n_refcnt; - n->n_narcs = 0; - *n->n_prevp = n->n_next; - if (n->n_next) - n->n_next->n_prevp = n->n_prevp; -} - -static void -free_nodes(NODE * nodelist) -{ - NODE *n, *nextnode; - - for (n = nodelist; n;) { - nextnode = n->n_next; - xfree(n); - n = nextnode; - } -} - -/* look for the longest? cycle from node from to node to. */ -static int -find_cycle(NODE * from, NODE * to, int longest_len, int depth) -{ - NODE **np; - int i, len; - - /* - * avoid infinite loops and ignore portions of the graph known - * to be acyclic - */ - if (from->n_flags & (NF_NODEST | NF_MARK | NF_ACYCLIC)) - return (0); - from->n_flags |= NF_MARK; - - for (np = from->n_arcs, i = from->n_narcs; --i >= 0; np++) { - cycle_buf[depth] = *np; - if (*np == to) { - if (depth + 1 > longest_len) { - longest_len = depth + 1; - memcpy((char *)longest_cycle, - (char *)cycle_buf, longest_len * sizeof(NODE *)); - } - } else { - if ((*np)->n_flags & (NF_MARK | NF_ACYCLIC | NF_NODEST)) - continue; - len = find_cycle(*np, to, longest_len, depth + 1); - -#ifdef DEBUG - ErrorF("%*s %s->%s %d\n", depth, "", - from->n_name, to->n_name, len); -#endif - - if (len == 0) - (*np)->n_flags |= NF_NODEST; - - if (len > longest_len) - longest_len = len; - - if (len > 0 && !longest) - break; - } - } - from->n_flags &= ~NF_MARK; - return (longest_len); -} - -/* do topological sort on graph */ -static void -tsort(void) -{ - NODE *n, *next; - int cnt, i; - - while (graph != NULL) { - /* - * Keep getting rid of simple cases until there are none left, - * if there are any nodes still in the graph, then there is - * a cycle in it. - */ - do { - for (cnt = 0, n = graph; n != NULL; n = next) { - next = n->n_next; - if (n->n_refcnt == 0) { - remove_node(n); - ++cnt; - } - } - } while (graph != NULL && cnt); - - if (graph == NULL) - break; - - if (!cycle_buf) { - /* - * Allocate space for two cycle logs - one to be used - * as scratch space, the other to save the longest - * cycle. - */ - for (cnt = 0, n = graph; n != NULL; n = n->n_next) - ++cnt; - cycle_buf = xnfalloc(sizeof(NODE *) * cnt); - longest_cycle = xnfalloc(sizeof(NODE *) * cnt); - if (cycle_buf == NULL || longest_cycle == NULL) - return; - } - for (n = graph; n != NULL; n = n->n_next) - if (!(n->n_flags & NF_ACYCLIC)) { - if ((cnt = find_cycle(n, n, 0, 0))) { - ErrorF("tsort: cycle in data"); - for (i = 0; i < cnt; i++) - ErrorF("%s", longest_cycle[i]->n_name); - remove_node(n); - clear_cycle(); - break; - } else { - /* to avoid further checks */ - n->n_flags |= NF_ACYCLIC; - clear_cycle(); - } - } - - if (n == NULL) - ErrorF("tsort: internal error -- could not find cycle"); - } - if (cycle_buf) - xfree(cycle_buf); - if (longest_cycle) - xfree(longest_cycle); - if (graph) - free_nodes(graph); -} - -void -LoaderSortExtensions(void) -{ - int i, j; - ExtensionModule *ext, *newList; - NODE *node; - - graph = NULL; - longest = 0; - sorted = NULL; - last = NULL; - cycle_buf = NULL; - longest_cycle = NULL; - - /* - * Parse list and build the graph. Enter them in reverse order - * because tsort() will reverse those that have no depedencies. - */ - for (i = numExtensionModules - 1; i >= 0; i--) { - ext = &ExtensionModuleList[i]; - add_arc(ext->name, ext->name); -#ifdef DEBUG - ErrorF("Extension %s:\n", ext->name); -#endif - if (ext->initDependencies) - for (j = 0; ext->initDependencies[j]; j++) { - add_arc(ext->initDependencies[j], ext->name); -#ifdef DEBUG - ErrorF("\t%s\n", ext->initDependencies[j]); -#endif - } - } - tsort(); - newList = xnfalloc((numExtensionModules + 1) * sizeof(ExtensionModule)); - i = 0; - for (node = sorted; node; node = node->n_next) { - for (j = 0; j < numExtensionModules; j++) - if (!strcmp(node->n_name, ExtensionModuleList[j].name)) - break; - if (j != numExtensionModules) - newList[i++] = ExtensionModuleList[j]; - } - if (sorted) - free_nodes(sorted); - if (graph) - free_nodes(graph); - newList[i].name = NULL; - xfree(ExtensionModuleList); - ExtensionModuleList = newList; -#ifdef DEBUG - for (i = 0; ExtensionModuleList[i].name; i++) - ErrorF("Extension %s\n", ExtensionModuleList[i].name); -#endif -} +/* + * Copyright (c) 2000 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +/* Maybe this file belongs elsewhere? */ + +#define LOADERDECLARATIONS +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#include "loaderProcs.h" +#include "misc.h" +#include "xf86.h" + +/* + * This should be static, but miinitext wants it. FIXME: make extension + * initialization not completely terrible. + */ +ExtensionModule *ExtensionModuleList = NULL; +static int numExtensionModules = 0; + +static ExtensionModule * +NewExtensionModule(void) +{ + ExtensionModule *save = ExtensionModuleList; + int n; + + /* Sanity check */ + if (!ExtensionModuleList) + numExtensionModules = 0; + + n = numExtensionModules + 1; + ExtensionModuleList = realloc(ExtensionModuleList, + (n + 1) * sizeof(ExtensionModule)); + if (ExtensionModuleList == NULL) { + ExtensionModuleList = save; + return NULL; + } else { + numExtensionModules++; + ExtensionModuleList[numExtensionModules].name = NULL; + return ExtensionModuleList + (numExtensionModules - 1); + } +} + +void +LoadExtension(ExtensionModule * e, Bool builtin) +{ + ExtensionModule *newext; + + if (e == NULL || e->name == NULL) + return; + + if (!(newext = NewExtensionModule())) + return; + + if (builtin) + xf86MsgVerb(X_INFO, 2, "Initializing built-in extension %s\n", + e->name); + else + xf86MsgVerb(X_INFO, 2, "Loading extension %s\n", e->name); + + newext->name = e->name; + newext->initFunc = e->initFunc; + newext->disablePtr = e->disablePtr; + newext->setupFunc = e->setupFunc; + newext->initDependencies = e->initDependencies; + + if (e->setupFunc != NULL) + e->setupFunc(); +} + +/* + * Sort ExtensionModuleList according to the initialisation order + * dependencies. The code for this is taken from BSD's tsort, + * and carries the following copyright/license: + * + * + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Rendell of Memorial University of Newfoundland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define NF_MARK 0x1 /* marker for cycle detection */ +#define NF_ACYCLIC 0x2 /* this node is cycle free */ +#define NF_NODEST 0x4 /* Unreachable */ + +typedef struct node_str NODE; +struct node_str { + NODE **n_prevp; /* pointer to previous node's n_next */ + NODE *n_next; /* next node in graph */ + NODE **n_arcs; /* array of arcs to other nodes */ + int n_narcs; /* number of arcs in n_arcs[] */ + int n_arcsize; /* size of n_arcs[] array */ + int n_refcnt; /* # of arcs pointing to this node */ + int n_flags; /* NF_* */ + const char *n_name; /* name of this node */ +}; + +static NODE *graph = NULL, **cycle_buf = NULL, **longest_cycle = NULL; +static int longest = 0; +static NODE *sorted = NULL, *last = NULL; + +/* Find a node in the graph (insert if not found) and return a pointer to it. */ +static NODE * +get_node(const char *name) +{ + NODE *n; + + for (n = graph; n && n->n_name && strcmp(n->n_name, name); + n = n->n_next) ; + if (n) + return (n); + + n = xnfalloc(sizeof(NODE)); + + n->n_narcs = 0; + n->n_arcsize = 0; + n->n_arcs = NULL; + n->n_refcnt = 0; + n->n_flags = 0; + n->n_name = name; + + /* Add to linked list. */ + if ((n->n_next = graph) != NULL) + graph->n_prevp = &n->n_next; + n->n_prevp = &graph; + graph = n; + + return (n); +} + +/* + * add an arc from node s1 to node s2 in the graph. If s1 or s2 are not in + * the graph, then add them. + */ +static void +add_arc(const char *s1, const char *s2) +{ + NODE *n1; + NODE *n2; + int bsize, i; + + n1 = get_node(s1); + + if (!strcmp(s1, s2)) + return; + + n2 = get_node(s2); + + /* + * Check if this arc is already here. + */ + for (i = 0; i < n1->n_narcs; i++) + if (n1->n_arcs[i] == n2) + return; + /* + * Add it. + */ + if (n1->n_narcs == n1->n_arcsize) { + if (!n1->n_arcsize) + n1->n_arcsize = 10; + bsize = n1->n_arcsize * sizeof(*n1->n_arcs) * 2; + n1->n_arcs = xnfrealloc(n1->n_arcs, bsize); + n1->n_arcsize = bsize / sizeof(*n1->n_arcs); + } + n1->n_arcs[n1->n_narcs++] = n2; + ++n2->n_refcnt; +} + +/* + * Clear the NODEST flag from all nodes. + */ +static void +clear_cycle(void) +{ + NODE *n; + + for (n = graph; n != NULL; n = n->n_next) + n->n_flags &= ~NF_NODEST; +} + +/* print node and remove from graph (does not actually free node) */ +static void +remove_node(NODE * n) +{ + NODE **np; + NODE *newnode; + int i; + +#ifdef DEBUG + ErrorF("%s\n", n->n_name); +#endif + newnode = xnfalloc(sizeof(NODE)); + memcpy(newnode, n, sizeof(NODE)); + if (last) + last->n_next = newnode; + else + sorted = newnode; + last = newnode; + newnode->n_next = NULL; + + for (np = n->n_arcs, i = n->n_narcs; --i >= 0; np++) + --(*np)->n_refcnt; + n->n_narcs = 0; + *n->n_prevp = n->n_next; + if (n->n_next) + n->n_next->n_prevp = n->n_prevp; +} + +static void +free_nodes(NODE * nodelist) +{ + NODE *n, *nextnode; + + for (n = nodelist; n;) { + nextnode = n->n_next; + free(n); + n = nextnode; + } +} + +/* look for the longest? cycle from node from to node to. */ +static int +find_cycle(NODE * from, NODE * to, int longest_len, int depth) +{ + NODE **np; + int i, len; + + /* + * avoid infinite loops and ignore portions of the graph known + * to be acyclic + */ + if (from->n_flags & (NF_NODEST | NF_MARK | NF_ACYCLIC)) + return (0); + from->n_flags |= NF_MARK; + + for (np = from->n_arcs, i = from->n_narcs; --i >= 0; np++) { + cycle_buf[depth] = *np; + if (*np == to) { + if (depth + 1 > longest_len) { + longest_len = depth + 1; + memcpy((char *)longest_cycle, + (char *)cycle_buf, longest_len * sizeof(NODE *)); + } + } else { + if ((*np)->n_flags & (NF_MARK | NF_ACYCLIC | NF_NODEST)) + continue; + len = find_cycle(*np, to, longest_len, depth + 1); + +#ifdef DEBUG + ErrorF("%*s %s->%s %d\n", depth, "", + from->n_name, to->n_name, len); +#endif + + if (len == 0) + (*np)->n_flags |= NF_NODEST; + + if (len > longest_len) + longest_len = len; + + if (len > 0 && !longest) + break; + } + } + from->n_flags &= ~NF_MARK; + return (longest_len); +} + +/* do topological sort on graph */ +static void +tsort(void) +{ + NODE *n, *next; + int cnt, i; + + while (graph != NULL) { + /* + * Keep getting rid of simple cases until there are none left, + * if there are any nodes still in the graph, then there is + * a cycle in it. + */ + do { + for (cnt = 0, n = graph; n != NULL; n = next) { + next = n->n_next; + if (n->n_refcnt == 0) { + remove_node(n); + ++cnt; + } + } + } while (graph != NULL && cnt); + + if (graph == NULL) + break; + + if (!cycle_buf) { + /* + * Allocate space for two cycle logs - one to be used + * as scratch space, the other to save the longest + * cycle. + */ + for (cnt = 0, n = graph; n != NULL; n = n->n_next) + ++cnt; + cycle_buf = xnfalloc(sizeof(NODE *) * cnt); + longest_cycle = xnfalloc(sizeof(NODE *) * cnt); + if (cycle_buf == NULL || longest_cycle == NULL) + return; + } + for (n = graph; n != NULL; n = n->n_next) + if (!(n->n_flags & NF_ACYCLIC)) { + if ((cnt = find_cycle(n, n, 0, 0))) { + ErrorF("tsort: cycle in data"); + for (i = 0; i < cnt; i++) + ErrorF("%s", longest_cycle[i]->n_name); + remove_node(n); + clear_cycle(); + break; + } else { + /* to avoid further checks */ + n->n_flags |= NF_ACYCLIC; + clear_cycle(); + } + } + + if (n == NULL) + ErrorF("tsort: internal error -- could not find cycle"); + } + if (cycle_buf) + free(cycle_buf); + if (longest_cycle) + free(longest_cycle); + if (graph) + free_nodes(graph); +} + +void +LoaderSortExtensions(void) +{ + int i, j; + ExtensionModule *ext, *newList; + NODE *node; + + graph = NULL; + longest = 0; + sorted = NULL; + last = NULL; + cycle_buf = NULL; + longest_cycle = NULL; + + /* + * Parse list and build the graph. Enter them in reverse order + * because tsort() will reverse those that have no depedencies. + */ + for (i = numExtensionModules - 1; i >= 0; i--) { + ext = &ExtensionModuleList[i]; + add_arc(ext->name, ext->name); +#ifdef DEBUG + ErrorF("Extension %s:\n", ext->name); +#endif + if (ext->initDependencies) + for (j = 0; ext->initDependencies[j]; j++) { + add_arc(ext->initDependencies[j], ext->name); +#ifdef DEBUG + ErrorF("\t%s\n", ext->initDependencies[j]); +#endif + } + } + tsort(); + newList = xnfalloc((numExtensionModules + 1) * sizeof(ExtensionModule)); + i = 0; + for (node = sorted; node; node = node->n_next) { + for (j = 0; j < numExtensionModules; j++) + if (!strcmp(node->n_name, ExtensionModuleList[j].name)) + break; + if (j != numExtensionModules) + newList[i++] = ExtensionModuleList[j]; + } + if (sorted) + free_nodes(sorted); + if (graph) + free_nodes(graph); + newList[i].name = NULL; + free(ExtensionModuleList); + ExtensionModuleList = newList; +#ifdef DEBUG + for (i = 0; ExtensionModuleList[i].name; i++) + ErrorF("Extension %s\n", ExtensionModuleList[i].name); +#endif +} diff --git a/xorg-server/hw/xfree86/loader/loadmod.c b/xorg-server/hw/xfree86/loader/loadmod.c index 5b175a546..e75ec8f69 100644 --- a/xorg-server/hw/xfree86/loader/loadmod.c +++ b/xorg-server/hw/xfree86/loader/loadmod.c @@ -1,1268 +1,1268 @@ -/* - * Copyright 1995-1998 by Metro Link, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Metro Link, Inc. not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Metro Link, Inc. makes no - * representations about the suitability of this software for any purpose. - * It is provided "as is" without express or implied warranty. - * - * METRO LINK, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL METRO LINK, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ -/* - * Copyright (c) 1997-2002 by The XFree86 Project, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the name of the copyright holder(s) - * and author(s) shall not be used in advertising or otherwise to promote - * the sale, use or other dealings in this Software without prior written - * authorization from the copyright holder(s) and author(s). - */ - -#ifdef HAVE_XORG_CONFIG_H -#include -#endif - -#include "os.h" -/* For stat() and related stuff */ -#define NO_OSLIB_PROTOTYPES -#include "xf86_OSlib.h" -#define LOADERDECLARATIONS -#include "loaderProcs.h" -#include "misc.h" -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86Xinput.h" -#include "loader.h" -#include "xf86Optrec.h" - -#include -#include -#include -#include - -typedef struct _pattern { - const char *pattern; - regex_t rex; -} PatternRec, *PatternPtr; - -/* Prototypes for static functions */ -static char *FindModule(const char *, const char *, const char **, - PatternPtr); -static Bool CheckVersion(const char *, XF86ModuleVersionInfo *, - const XF86ModReqInfo *); -static void UnloadModuleOrDriver(ModuleDescPtr mod); -static char *LoaderGetCanonicalName(const char *, PatternPtr); -static void RemoveChild(ModuleDescPtr); -static ModuleDescPtr doLoadModule(const char *, const char *, const char **, - const char **, pointer, - const XF86ModReqInfo *, int *, int *, - int flags); - -const ModuleVersions LoaderVersionInfo = { - XORG_VERSION_CURRENT, - ABI_ANSIC_VERSION, - ABI_VIDEODRV_VERSION, - ABI_XINPUT_VERSION, - ABI_EXTENSION_VERSION, - ABI_FONT_VERSION -}; - -static void -FreeStringList(char **paths) -{ - char **p; - - if (!paths) - return; - - for (p = paths; *p; p++) - xfree(*p); - - xfree(paths); -} - -static char **defaultPathList = NULL; - -static Bool -PathIsAbsolute(const char *path) -{ - return (*path == '/'); -} - -/* - * Convert a comma-separated path into a NULL-terminated array of path - * elements, rejecting any that are not full absolute paths, and appending - * a '/' when it isn't already present. - */ -static char ** -InitPathList(const char *path) -{ - char *fullpath = NULL; - char *elem = NULL; - char **list = NULL, **save = NULL; - int len; - int addslash; - int n = 0; - - if (!path) - return defaultPathList; - - fullpath = xstrdup(path); - if (!fullpath) - return NULL; - elem = strtok(fullpath, ","); - while (elem) { - if (PathIsAbsolute(elem)) - { - len = strlen(elem); - addslash = (elem[len - 1] != '/'); - if (addslash) - len++; - save = list; - list = xrealloc(list, (n + 2) * sizeof(char *)); - if (!list) { - if (save) { - save[n] = NULL; - FreeStringList(save); - } - xfree(fullpath); - return NULL; - } - list[n] = xalloc(len + 1); - if (!list[n]) { - FreeStringList(list); - xfree(fullpath); - return NULL; - } - strcpy(list[n], elem); - if (addslash) { - list[n][len - 1] = '/'; - list[n][len] = '\0'; - } - n++; - } - elem = strtok(NULL, ","); - } - if (list) - list[n] = NULL; - xfree(fullpath); - return list; -} - -static void -FreePathList(char **pathlist) -{ - if (pathlist && pathlist != defaultPathList) - FreeStringList(pathlist); -} - -void -LoaderSetPath(const char *path) -{ - if (!path) - return; - - defaultPathList = InitPathList(path); -} - -/* Standard set of module subdirectories to search, in order of preference */ -static const char *stdSubdirs[] = { - "", - "input/", - "drivers/", - "multimedia/", - "extensions/", - "internal/", - NULL -}; - -/* - * Standard set of module name patterns to check, in order of preference - * These are regular expressions (suitable for use with POSIX regex(3)). - * - * This list assumes that you're an ELFish platform and therefore your - * shared libraries are named something.so. If we're ever nuts enough - * to port this DDX to, say, Darwin, we'll need to fix this. - */ -static PatternRec stdPatterns[] = { - {"^lib(.*)\\.so$",}, - {"(.*)_drv\\.so$",}, - {"(.*)\\.so$",}, - {NULL,} -}; - -static PatternPtr -InitPatterns(const char **patternlist) -{ - char errmsg[80]; - int i, e; - PatternPtr patterns = NULL; - PatternPtr p = NULL; - static int firstTime = 1; - const char **s; - - if (firstTime) { - /* precompile stdPatterns */ - firstTime = 0; - for (p = stdPatterns; p->pattern; p++) - if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { - regerror(e, &p->rex, errmsg, sizeof(errmsg)); - FatalError("InitPatterns: regcomp error for `%s': %s\n", - p->pattern, errmsg); - } - } - - if (patternlist) { - for (i = 0, s = patternlist; *s; i++, s++) - if (*s == DEFAULT_LIST) - i += sizeof(stdPatterns) / sizeof(stdPatterns[0]) - 1 - 1; - patterns = xalloc((i + 1) * sizeof(PatternRec)); - if (!patterns) { - return NULL; - } - for (i = 0, s = patternlist; *s; i++, s++) - if (*s != DEFAULT_LIST) { - p = patterns + i; - p->pattern = *s; - if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { - regerror(e, &p->rex, errmsg, sizeof(errmsg)); - ErrorF("InitPatterns: regcomp error for `%s': %s\n", - p->pattern, errmsg); - i--; - } - } else { - for (p = stdPatterns; p->pattern; p++, i++) - patterns[i] = *p; - if (p != stdPatterns) - i--; - } - patterns[i].pattern = NULL; - } else - patterns = stdPatterns; - return patterns; -} - -static void -FreePatterns(PatternPtr patterns) -{ - if (patterns && patterns != stdPatterns) - xfree(patterns); -} - -static const char ** -InitSubdirs(const char **subdirlist) -{ - int i; - const char **tmp_subdirlist = NULL; - char **subdirs = NULL; - const char **s, **stmp = NULL; - const char *osname; - const char *slash; - int oslen = 0, len; - Bool indefault; - - if (subdirlist == NULL) { - subdirlist = tmp_subdirlist = xalloc(2 * sizeof(char *)); - if (subdirlist == NULL) - return NULL; - subdirlist[0] = DEFAULT_LIST; - subdirlist[1] = NULL; - } - - LoaderGetOS(&osname, NULL, NULL, NULL); - oslen = strlen(osname); - - { - /* Count number of entries and check for invalid paths */ - for (i = 0, s = subdirlist; *s; i++, s++) { - if (*s == DEFAULT_LIST) { - i += sizeof(stdSubdirs) / sizeof(stdSubdirs[0]) - 1 - 1; - } else { - /* - * Path validity check. Don't allow absolute paths, or - * paths containing "..". To catch absolute paths on - * platforms that use driver letters, don't allow the ':' - * character to appear at all. - */ - if (**s == '/' || **s == '\\' || strchr(*s, ':') || - strstr(*s, "..")) { - xf86Msg(X_ERROR, "InitSubdirs: Bad subdir: \"%s\"\n", *s); - if (tmp_subdirlist) - xfree(tmp_subdirlist); - return NULL; - } - } - } - subdirs = xalloc((i * 2 + 1) * sizeof(char *)); - if (!subdirs) { - if (tmp_subdirlist) - xfree(tmp_subdirlist); - return NULL; - } - i = 0; - s = subdirlist; - indefault = FALSE; - while (*s) { - if (*s == DEFAULT_LIST) { - /* Divert to the default list */ - indefault = TRUE; - stmp = ++s; - s = stdSubdirs; - } - len = strlen(*s); - if (**s && (*s)[len - 1] != '/') { - slash = "/"; - len++; - } else - slash = ""; - len += oslen + 2; - if (!(subdirs[i] = xalloc(len))) { - while (--i >= 0) - xfree(subdirs[i]); - xfree(subdirs); - if (tmp_subdirlist) - xfree(tmp_subdirlist); - return NULL; - } - /* tack on the OS name */ - sprintf(subdirs[i], "%s%s%s/", *s, slash, osname); - i++; - /* path as given */ - subdirs[i] = xstrdup(*s); - i++; - s++; - if (indefault && !s) { - /* revert back to the main list */ - indefault = FALSE; - s = stmp; - } - } - subdirs[i] = NULL; - } - if (tmp_subdirlist) - xfree(tmp_subdirlist); - return (const char **)subdirs; -} - -static void -FreeSubdirs(const char **subdirs) -{ - const char **s; - - if (subdirs) { - for (s = subdirs; *s; s++) - xfree(*s); - xfree(subdirs); - } -} - -static char * -FindModuleInSubdir(const char *dirpath, const char *module) -{ - struct dirent *direntry = NULL; - DIR *dir = NULL; - char *ret = NULL, tmpBuf[PATH_MAX]; - struct stat stat_buf; - - dir = opendir(dirpath); - if (!dir) - return NULL; - - while ((direntry = readdir(dir))) { - if (direntry->d_name[0] == '.') - continue; - snprintf(tmpBuf, PATH_MAX, "%s%s/", dirpath, direntry->d_name); - /* the stat with the appended / fails for normal files, - and works for sub dirs fine, looks a bit strange in strace - but does seem to work */ - if ((stat(tmpBuf, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode)) { - if ((ret = FindModuleInSubdir(tmpBuf, module))) - break; - continue; - } - - snprintf(tmpBuf, PATH_MAX, "lib%s.so", module); - if (strcmp(direntry->d_name, tmpBuf) == 0) { - ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); - sprintf(ret, "%s%s", dirpath, tmpBuf); - break; - } - - snprintf(tmpBuf, PATH_MAX, "%s_drv.so", module); - if (strcmp(direntry->d_name, tmpBuf) == 0) { - ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); - sprintf(ret, "%s%s", dirpath, tmpBuf); - break; - } - - snprintf(tmpBuf, PATH_MAX, "%s.so", module); - if (strcmp(direntry->d_name, tmpBuf) == 0) { - ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); - sprintf(ret, "%s%s", dirpath, tmpBuf); - break; - } - } - - closedir(dir); - return ret; -} - -static char * -FindModule(const char *module, const char *dirname, const char **subdirlist, - PatternPtr patterns) -{ - char buf[PATH_MAX + 1]; - char *dirpath = NULL; - char *name = NULL; - int dirlen; - const char **subdirs = NULL; - const char **s; - - dirpath = (char *)dirname; - if (strlen(dirpath) > PATH_MAX) - return NULL; - - subdirs = InitSubdirs(subdirlist); - if (!subdirs) - return NULL; - - for (s = subdirs; *s; s++) { - if ((dirlen = strlen(dirpath) + strlen(*s)) > PATH_MAX) - continue; - strcpy(buf, dirpath); - strcat(buf, *s); - if ((name = FindModuleInSubdir(buf, module))) - break; - } - - FreeSubdirs(subdirs); - if (dirpath != dirname) - xfree(dirpath); - - return name; -} - -char ** -LoaderListDirs(const char **subdirlist, const char **patternlist) -{ - char buf[PATH_MAX + 1]; - char **pathlist; - char **elem; - const char **subdirs; - const char **s; - PatternPtr patterns; - PatternPtr p; - DIR *d; - struct dirent *dp; - regmatch_t match[2]; - struct stat stat_buf; - int len, dirlen; - char *fp; - char **listing = NULL; - char **save; - int n = 0; - - if (!(pathlist = InitPathList(NULL))) - return NULL; - if (!(subdirs = InitSubdirs(subdirlist))) { - FreePathList(pathlist); - return NULL; - } - if (!(patterns = InitPatterns(patternlist))) { - FreePathList(pathlist); - FreeSubdirs(subdirs); - return NULL; - } - - for (elem = pathlist; *elem; elem++) { - for (s = subdirs; *s; s++) { - if ((dirlen = strlen(*elem) + strlen(*s)) > PATH_MAX) - continue; - strcpy(buf, *elem); - strcat(buf, *s); - fp = buf + dirlen; - if (stat(buf, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode) && - (d = opendir(buf))) { - if (buf[dirlen - 1] != '/') { - buf[dirlen++] = '/'; - fp++; - } - while ((dp = readdir(d))) { - if (dirlen + strlen(dp->d_name) > PATH_MAX) - continue; - strcpy(fp, dp->d_name); - if (!(stat(buf, &stat_buf) == 0 && - S_ISREG(stat_buf.st_mode))) - continue; - for (p = patterns; p->pattern; p++) { - if (regexec(&p->rex, dp->d_name, 2, match, 0) == 0 && - match[1].rm_so != -1) { - len = match[1].rm_eo - match[1].rm_so; - save = listing; - listing = xrealloc(listing, - (n + 2) * sizeof(char *)); - if (!listing) { - if (save) { - save[n] = NULL; - FreeStringList(save); - } - FreePathList(pathlist); - FreeSubdirs(subdirs); - FreePatterns(patterns); - return NULL; - } - listing[n] = xalloc(len + 1); - if (!listing[n]) { - FreeStringList(listing); - FreePathList(pathlist); - FreeSubdirs(subdirs); - FreePatterns(patterns); - return NULL; - } - strncpy(listing[n], dp->d_name + match[1].rm_so, - len); - listing[n][len] = '\0'; - n++; - break; - } - } - } - closedir(d); - } - } - } - if (listing) - listing[n] = NULL; - return listing; -} - -void -LoaderFreeDirList(char **list) -{ - FreeStringList(list); -} - -static Bool -CheckVersion(const char *module, XF86ModuleVersionInfo * data, - const XF86ModReqInfo * req) -{ - int vercode[4]; - char verstr[4]; - long ver = data->xf86version; - MessageType errtype; - - xf86Msg(X_INFO, "Module %s: vendor=\"%s\"\n", - data->modname ? data->modname : "UNKNOWN!", - data->vendor ? data->vendor : "UNKNOWN!"); - - /* Check for the different scheme used in XFree86 4.0.x releases: - * ((((((((major << 7) | minor) << 7) | subminor) << 5) | beta) << 5) | alpha) - * Since it wasn't used in 4.1.0 or later, limit to versions in the 4.0.x - * range, which limits the overlap with the new version scheme to conflicts - * with 6.71.8.764 through 6.72.39.934. - */ - if ((ver > (4 << 24)) && (ver < ( (4 << 24) + (1 << 17)))) { - /* 4.0.x and earlier */ - verstr[1] = verstr[3] = 0; - verstr[2] = (ver & 0x1f) ? (ver & 0x1f) + 'a' - 1 : 0; - ver >>= 5; - verstr[0] = (ver & 0x1f) ? (ver & 0x1f) + 'A' - 1 : 0; - ver >>= 5; - vercode[2] = ver & 0x7f; - ver >>= 7; - vercode[1] = ver & 0x7f; - ver >>= 7; - vercode[0] = ver; - xf86ErrorF("\tcompiled for %d.%d", vercode[0], vercode[1]); - if (vercode[2] != 0) - xf86ErrorF(".%d", vercode[2]); - xf86ErrorF("%s%s, module version = %d.%d.%d\n", verstr, verstr + 2, - data->majorversion, data->minorversion, data->patchlevel); - } else { - vercode[0] = ver / 10000000; - vercode[1] = (ver / 100000) % 100; - vercode[2] = (ver / 1000) % 100; - vercode[3] = ver % 1000; - xf86ErrorF("\tcompiled for %d.%d.%d", vercode[0], vercode[1], - vercode[2]); - if (vercode[3] != 0) - xf86ErrorF(".%d", vercode[3]); - xf86ErrorF(", module version = %d.%d.%d\n", data->majorversion, - data->minorversion, data->patchlevel); - } - - if (data->moduleclass) - xf86ErrorFVerb(2, "\tModule class: %s\n", data->moduleclass); - - ver = -1; - if (data->abiclass) { - int abimaj, abimin; - int vermaj, vermin; - - if (!strcmp(data->abiclass, ABI_CLASS_ANSIC)) - ver = LoaderVersionInfo.ansicVersion; - else if (!strcmp(data->abiclass, ABI_CLASS_VIDEODRV)) - ver = LoaderVersionInfo.videodrvVersion; - else if (!strcmp(data->abiclass, ABI_CLASS_XINPUT)) - ver = LoaderVersionInfo.xinputVersion; - else if (!strcmp(data->abiclass, ABI_CLASS_EXTENSION)) - ver = LoaderVersionInfo.extensionVersion; - else if (!strcmp(data->abiclass, ABI_CLASS_FONT)) - ver = LoaderVersionInfo.fontVersion; - - abimaj = GET_ABI_MAJOR(data->abiversion); - abimin = GET_ABI_MINOR(data->abiversion); - xf86ErrorFVerb(2, "\tABI class: %s, version %d.%d\n", - data->abiclass, abimaj, abimin); - if (ver != -1) { - vermaj = GET_ABI_MAJOR(ver); - vermin = GET_ABI_MINOR(ver); - if (abimaj != vermaj) { - if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) - errtype = X_WARNING; - else - errtype = X_ERROR; - xf86MsgVerb(errtype, 0, - "module ABI major version (%d) doesn't" - " match the server's version (%d)\n", - abimaj, vermaj); - if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) - return FALSE; - } else if (abimin > vermin) { - if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) - errtype = X_WARNING; - else - errtype = X_ERROR; - xf86MsgVerb(errtype, 0, - "module ABI minor version (%d) is " - "newer than the server's version " - "(%d)\n", abimin, vermin); - if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) - return FALSE; - } - } - } - - /* Check against requirements that the caller has specified */ - if (req) { - if (req->majorversion != MAJOR_UNSPEC) { - if (data->majorversion != req->majorversion) { - xf86MsgVerb(X_WARNING, 2, "module major version (%d) " - "doesn't match required major version (%d)\n", - data->majorversion, req->majorversion); - return FALSE; - } else if (req->minorversion != MINOR_UNSPEC) { - if (data->minorversion < req->minorversion) { - xf86MsgVerb(X_WARNING, 2, "module minor version (%d) " - "is less than the required minor version (%d)\n", - data->minorversion, req->minorversion); - return FALSE; - } else if (data->minorversion == req->minorversion && - req->patchlevel != PATCH_UNSPEC) { - if (data->patchlevel < req->patchlevel) { - xf86MsgVerb(X_WARNING, 2, "module patch level (%d) " - "is less than the required patch level (%d)\n", - data->patchlevel, req->patchlevel); - return FALSE; - } - } - } - } - if (req->moduleclass) { - if (!data->moduleclass || - strcmp(req->moduleclass, data->moduleclass)) { - xf86MsgVerb(X_WARNING, 2, "Module class (%s) doesn't match " - "the required class (%s)\n", - data->moduleclass ? data->moduleclass : "", - req->moduleclass); - return FALSE; - } - } else if (req->abiclass != ABI_CLASS_NONE) { - if (!data->abiclass || strcmp(req->abiclass, data->abiclass)) { - xf86MsgVerb(X_WARNING, 2, "ABI class (%s) doesn't match the " - "required ABI class (%s)\n", - data->abiclass ? data->abiclass : "", - req->abiclass); - return FALSE; - } - } - if ((req->abiclass != ABI_CLASS_NONE) && - req->abiversion != ABI_VERS_UNSPEC) { - int reqmaj, reqmin, maj, min; - - reqmaj = GET_ABI_MAJOR(req->abiversion); - reqmin = GET_ABI_MINOR(req->abiversion); - maj = GET_ABI_MAJOR(data->abiversion); - min = GET_ABI_MINOR(data->abiversion); - if (maj != reqmaj) { - xf86MsgVerb(X_WARNING, 2, "ABI major version (%d) doesn't " - "match the required ABI major version (%d)\n", - maj, reqmaj); - return FALSE; - } - /* XXX Maybe this should be the other way around? */ - if (min > reqmin) { - xf86MsgVerb(X_WARNING, 2, "module ABI minor version (%d) " - "is newer than that available (%d)\n", min, reqmin); - return FALSE; - } - } - } - return TRUE; -} - -static ModuleDescPtr -AddSibling(ModuleDescPtr head, ModuleDescPtr new) -{ - new->sib = head; - return (new); -} - -pointer -LoadSubModule(pointer _parent, const char *module, - const char **subdirlist, const char **patternlist, - pointer options, const XF86ModReqInfo * modreq, - int *errmaj, int *errmin) -{ - ModuleDescPtr submod; - ModuleDescPtr parent = (ModuleDescPtr)_parent; - - xf86MsgVerb(X_INFO, 3, "Loading sub module \"%s\"\n", module); - - if (PathIsAbsolute(module)) { - xf86Msg(X_ERROR, - "LoadSubModule: Absolute module path not permitted: \"%s\"\n", - module); - if (errmaj) - *errmaj = LDR_BADUSAGE; - if (errmin) - *errmin = 0; - return NULL; - } - - submod = doLoadModule(module, NULL, subdirlist, patternlist, options, - modreq, errmaj, errmin, LD_FLAG_GLOBAL); - if (submod && submod != (ModuleDescPtr) 1) { - parent->child = AddSibling(parent->child, submod); - submod->parent = parent; - } - return submod; -} - -static ModuleDescPtr -NewModuleDesc(const char *name) -{ - ModuleDescPtr mdp = xalloc(sizeof(ModuleDesc)); - - if (mdp) { - mdp->child = NULL; - mdp->sib = NULL; - mdp->parent = NULL; - mdp->name = xstrdup(name); - mdp->handle = -1; - mdp->SetupProc = NULL; - mdp->TearDownProc = NULL; - mdp->TearDownData = NULL; - } - - return (mdp); -} - -ModuleDescPtr -DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent) -{ - ModuleDescPtr ret; - - if (!mod) - return NULL; - - ret = NewModuleDesc(mod->name); - if (ret == NULL) - return NULL; - - if (LoaderHandleOpen(mod->handle) == -1) - return NULL; - - ret->handle = mod->handle; - ret->SetupProc = mod->SetupProc; - ret->TearDownProc = mod->TearDownProc; - ret->TearDownData = NULL; - ret->child = DuplicateModule(mod->child, ret); - ret->sib = DuplicateModule(mod->sib, parent); - ret->parent = parent; - ret->VersionInfo = mod->VersionInfo; - - return ret; -} - -static const char *compiled_in_modules[] = { - "ddc", - "i2c", - "ramdac", - NULL -}; - -static ModuleDescPtr -doLoadModule(const char *module, const char *path, const char **subdirlist, - const char **patternlist, pointer options, - const XF86ModReqInfo * modreq, - int *errmaj, int *errmin, int flags) -{ - XF86ModuleData *initdata = NULL; - char **pathlist = NULL; - char *found = NULL; - char *name = NULL; - char **path_elem = NULL; - char *p = NULL; - ModuleDescPtr ret = NULL; - int wasLoaded = 0; - PatternPtr patterns = NULL; - int noncanonical = 0; - char *m = NULL; - const char **cim; - - xf86MsgVerb(X_INFO, 3, "LoadModule: \"%s\"", module); - - patterns = InitPatterns(patternlist); - name = LoaderGetCanonicalName(module, patterns); - noncanonical = (name && strcmp(module, name) != 0); - if (noncanonical) { - xf86ErrorFVerb(3, " (%s)\n", name); - xf86MsgVerb(X_WARNING, 1, - "LoadModule: given non-canonical module name \"%s\"\n", - module); - m = name; - } else { - xf86ErrorFVerb(3, "\n"); - m = (char *)module; - } - - for (cim = compiled_in_modules; *cim; cim++) - if (!strcmp (m, *cim)) - { - xf86MsgVerb(X_INFO, 3, "Module \"%s\" already built-in\n", m); - ret = (ModuleDescPtr) 1; - goto LoadModule_exit; - } - - if (!name) { - if (errmaj) - *errmaj = LDR_BADUSAGE; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - ret = NewModuleDesc(name); - if (!ret) { - if (errmaj) - *errmaj = LDR_NOMEM; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - - pathlist = InitPathList(path); - if (!pathlist) { - /* This could be a malloc failure too */ - if (errmaj) - *errmaj = LDR_BADUSAGE; - if (errmin) - *errmin = 1; - goto LoadModule_fail; - } - - /* - * if the module name is not a full pathname, we need to - * check the elements in the path - */ - if (PathIsAbsolute(module)) - found = xstrdup(module); - path_elem = pathlist; - while (!found && *path_elem != NULL) { - found = FindModule(m, *path_elem, subdirlist, patterns); - path_elem++; - /* - * When the module name isn't the canonical name, search for the - * former if no match was found for the latter. - */ - if (!*path_elem && m == name) { - path_elem = pathlist; - m = (char *)module; - } - } - - /* - * did we find the module? - */ - if (!found) { - xf86Msg(X_WARNING, "Warning, couldn't open module %s\n", module); - if (errmaj) - *errmaj = LDR_NOENT; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - ret->handle = LoaderOpen(found, name, 0, - errmaj, errmin, &wasLoaded, flags); - if (ret->handle < 0) - goto LoadModule_fail; - - /* drop any explicit suffix from the module name */ - p = strchr(name, '.'); - if (p) - *p = '\0'; - - /* - * now check if the special data object ModuleData is - * present. - */ - p = xalloc(strlen(name) + strlen("ModuleData") + 1); - if (!p) { - if (errmaj) - *errmaj = LDR_NOMEM; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - strcpy(p, name); - strcat(p, "ModuleData"); - initdata = LoaderSymbol(p); - if (initdata) { - ModuleSetupProc setup; - ModuleTearDownProc teardown; - XF86ModuleVersionInfo *vers; - - vers = initdata->vers; - setup = initdata->setup; - teardown = initdata->teardown; - - if (!wasLoaded) { - if (vers) { - if (!CheckVersion(module, vers, modreq)) { - if (errmaj) - *errmaj = LDR_MISMATCH; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - } else { - xf86Msg(X_ERROR, - "LoadModule: Module %s does not supply" - " version information\n", module); - if (errmaj) - *errmaj = LDR_INVALID; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - } - if (setup) - ret->SetupProc = setup; - if (teardown) - ret->TearDownProc = teardown; - ret->VersionInfo = vers; - } else { - /* No initdata is OK for external modules */ - if (options == EXTERN_MODULE) - goto LoadModule_exit; - - /* no initdata, fail the load */ - xf86Msg(X_ERROR, "LoadModule: Module %s does not have a %s " - "data object.\n", module, p); - if (errmaj) - *errmaj = LDR_INVALID; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - if (ret->SetupProc) { - ret->TearDownData = ret->SetupProc(ret, options, errmaj, errmin); - if (!ret->TearDownData) { - goto LoadModule_fail; - } - } else if (options) { - xf86Msg(X_WARNING, "Module Options present, but no SetupProc " - "available for %s\n", module); - } - goto LoadModule_exit; - - LoadModule_fail: - UnloadModule(ret); - ret = NULL; - - LoadModule_exit: - FreePathList(pathlist); - FreePatterns(patterns); - xfree(found); - xfree(name); - xfree(p); - - return ret; -} - -/* - * LoadModule: load a module - * - * module The module name. Normally this is not a filename but the - * module's "canonical name. A full pathname is, however, - * also accepted. - * path A comma separated list of module directories. - * subdirlist A NULL terminated list of subdirectories to search. When - * NULL, the default "stdSubdirs" list is used. The default - * list is also substituted for entries with value DEFAULT_LIST. - * patternlist A NULL terminated list of regular expressions used to find - * module filenames. Each regex should contain exactly one - * subexpression that corresponds to the canonical module name. - * When NULL, the default "stdPatterns" list is used. The - * default list is also substituted for entries with value - * DEFAULT_LIST. - * options A NULL terminated list of Options that are passed to the - * module's SetupProc function. - * modreq An optional XF86ModReqInfo* containing - * version/ABI/vendor-ABI requirements to check for when - * loading the module. The following fields of the - * XF86ModReqInfo struct are checked: - * majorversion - must match the module's majorversion exactly - * minorversion - the module's minorversion must be >= this - * patchlevel - the module's minorversion.patchlevel must be - * >= this. Patchlevel is ignored when - * minorversion is not set. - * abiclass - (string) must match the module's abiclass - * abiversion - must be consistent with the module's - * abiversion (major equal, minor no older) - * moduleclass - string must match the module's moduleclass - * string - * "don't care" values are ~0 for numbers, and NULL for strings - * errmaj Major error return. - * errmin Minor error return. - * - */ -ModuleDescPtr -LoadModule(const char *module, const char *path, const char **subdirlist, - const char **patternlist, pointer options, - const XF86ModReqInfo * modreq, int *errmaj, int *errmin) -{ - return doLoadModule(module, path, subdirlist, patternlist, options, - modreq, errmaj, errmin, LD_FLAG_GLOBAL); -} - -void -UnloadModule(pointer mod) -{ - UnloadModuleOrDriver((ModuleDescPtr)mod); -} - -static void -UnloadModuleOrDriver(ModuleDescPtr mod) -{ - if (mod == (ModuleDescPtr) 1) - return; - - if (mod == NULL || mod->name == NULL) - return; - - xf86MsgVerb(X_INFO, 3, "UnloadModule: \"%s\"\n", mod->name); - - if ((mod->TearDownProc) && (mod->TearDownData)) - mod->TearDownProc(mod->TearDownData); - LoaderUnload(mod->handle); - - if (mod->child) - UnloadModuleOrDriver(mod->child); - if (mod->sib) - UnloadModuleOrDriver(mod->sib); - xfree(mod->name); - xfree(mod); -} - -void -UnloadSubModule(pointer _mod) -{ - ModuleDescPtr mod = (ModuleDescPtr)_mod; - - if (mod == NULL || mod->name == NULL) - return; - - xf86MsgVerb(X_INFO, 3, "UnloadSubModule: \"%s\"\n", mod->name); - - if ((mod->TearDownProc) && (mod->TearDownData)) - mod->TearDownProc(mod->TearDownData); - LoaderUnload(mod->handle); - - RemoveChild(mod); - - if (mod->child) - UnloadModuleOrDriver(mod->child); - - xfree(mod->name); - xfree(mod); -} - -static void -RemoveChild(ModuleDescPtr child) -{ - ModuleDescPtr mdp; - ModuleDescPtr prevsib; - ModuleDescPtr parent; - - if (!child->parent) - return; - - parent = child->parent; - if (parent->child == child) { - parent->child = child->sib; - return; - } - - prevsib = parent->child; - mdp = prevsib->sib; - while (mdp && mdp != child) { - prevsib = mdp; - mdp = mdp->sib; - } - if (mdp == child) - prevsib->sib = child->sib; - return; -} - -void -LoaderErrorMsg(const char *name, const char *modname, int errmaj, int errmin) -{ - const char *msg; - MessageType type = X_ERROR; - - switch (errmaj) { - case LDR_NOERROR: - msg = "no error"; - break; - case LDR_NOMEM: - msg = "out of memory"; - break; - case LDR_NOENT: - msg = "module does not exist"; - break; - case LDR_NOSUBENT: - msg = "a required submodule could not be loaded"; - break; - case LDR_NOSPACE: - msg = "too many modules"; - break; - case LDR_NOMODOPEN: - msg = "open failed"; - break; - case LDR_UNKTYPE: - msg = "unknown module type"; - break; - case LDR_NOLOAD: - msg = "loader failed"; - break; - case LDR_ONCEONLY: - msg = "already loaded"; - type = X_INFO; - break; - case LDR_NOPORTOPEN: - msg = "port open failed"; - break; - case LDR_NOHARDWARE: - msg = "no hardware found"; - break; - case LDR_MISMATCH: - msg = "module requirement mismatch"; - break; - case LDR_BADUSAGE: - msg = "invalid argument(s) to LoadModule()"; - break; - case LDR_INVALID: - msg = "invalid module"; - break; - case LDR_BADOS: - msg = "module doesn't support this OS"; - break; - case LDR_MODSPECIFIC: - msg = "module-specific error"; - break; - default: - msg = "unknown error"; - } - if (name) - xf86Msg(type, "%s: Failed to load module \"%s\" (%s, %d)\n", - name, modname, msg, errmin); - else - xf86Msg(type, "Failed to load module \"%s\" (%s, %d)\n", - modname, msg, errmin); -} - -/* Given a module path or file name, return the module's canonical name */ -static char * -LoaderGetCanonicalName(const char *modname, PatternPtr patterns) -{ - char *str; - const char *s; - int len; - PatternPtr p; - regmatch_t match[2]; - - /* Strip off any leading path */ - s = strrchr(modname, '/'); - if (s == NULL) - s = modname; - else - s++; - - /* Find the first regex that is matched */ - for (p = patterns; p->pattern; p++) - if (regexec(&p->rex, s, 2, match, 0) == 0 && match[1].rm_so != -1) { - len = match[1].rm_eo - match[1].rm_so; - str = xalloc(len + 1); - if (!str) - return NULL; - strncpy(str, s + match[1].rm_so, len); - str[len] = '\0'; - return str; - } - - /* If there is no match, return the whole name minus the leading path */ - return xstrdup(s); -} - -/* - * Return the module version information. - */ -unsigned long -LoaderGetModuleVersion(ModuleDescPtr mod) -{ - if (!mod || mod == (ModuleDescPtr) 1 || !mod->VersionInfo) - return 0; - - return MODULE_VERSION_NUMERIC(mod->VersionInfo->majorversion, - mod->VersionInfo->minorversion, - mod->VersionInfo->patchlevel); -} +/* + * Copyright 1995-1998 by Metro Link, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Metro Link, Inc. not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Metro Link, Inc. makes no + * representations about the suitability of this software for any purpose. + * It is provided "as is" without express or implied warranty. + * + * METRO LINK, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL METRO LINK, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Copyright (c) 1997-2002 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#include "os.h" +/* For stat() and related stuff */ +#define NO_OSLIB_PROTOTYPES +#include "xf86_OSlib.h" +#define LOADERDECLARATIONS +#include "loaderProcs.h" +#include "misc.h" +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86Xinput.h" +#include "loader.h" +#include "xf86Optrec.h" + +#include +#include +#include +#include + +typedef struct _pattern { + const char *pattern; + regex_t rex; +} PatternRec, *PatternPtr; + +/* Prototypes for static functions */ +static char *FindModule(const char *, const char *, const char **, + PatternPtr); +static Bool CheckVersion(const char *, XF86ModuleVersionInfo *, + const XF86ModReqInfo *); +static void UnloadModuleOrDriver(ModuleDescPtr mod); +static char *LoaderGetCanonicalName(const char *, PatternPtr); +static void RemoveChild(ModuleDescPtr); +static ModuleDescPtr doLoadModule(const char *, const char *, const char **, + const char **, pointer, + const XF86ModReqInfo *, int *, int *, + int flags); + +const ModuleVersions LoaderVersionInfo = { + XORG_VERSION_CURRENT, + ABI_ANSIC_VERSION, + ABI_VIDEODRV_VERSION, + ABI_XINPUT_VERSION, + ABI_EXTENSION_VERSION, + ABI_FONT_VERSION +}; + +static void +FreeStringList(char **paths) +{ + char **p; + + if (!paths) + return; + + for (p = paths; *p; p++) + free(*p); + + free(paths); +} + +static char **defaultPathList = NULL; + +static Bool +PathIsAbsolute(const char *path) +{ + return (*path == '/'); +} + +/* + * Convert a comma-separated path into a NULL-terminated array of path + * elements, rejecting any that are not full absolute paths, and appending + * a '/' when it isn't already present. + */ +static char ** +InitPathList(const char *path) +{ + char *fullpath = NULL; + char *elem = NULL; + char **list = NULL, **save = NULL; + int len; + int addslash; + int n = 0; + + if (!path) + return defaultPathList; + + fullpath = xstrdup(path); + if (!fullpath) + return NULL; + elem = strtok(fullpath, ","); + while (elem) { + if (PathIsAbsolute(elem)) + { + len = strlen(elem); + addslash = (elem[len - 1] != '/'); + if (addslash) + len++; + save = list; + list = realloc(list, (n + 2) * sizeof(char *)); + if (!list) { + if (save) { + save[n] = NULL; + FreeStringList(save); + } + free(fullpath); + return NULL; + } + list[n] = malloc(len + 1); + if (!list[n]) { + FreeStringList(list); + free(fullpath); + return NULL; + } + strcpy(list[n], elem); + if (addslash) { + list[n][len - 1] = '/'; + list[n][len] = '\0'; + } + n++; + } + elem = strtok(NULL, ","); + } + if (list) + list[n] = NULL; + free(fullpath); + return list; +} + +static void +FreePathList(char **pathlist) +{ + if (pathlist && pathlist != defaultPathList) + FreeStringList(pathlist); +} + +void +LoaderSetPath(const char *path) +{ + if (!path) + return; + + defaultPathList = InitPathList(path); +} + +/* Standard set of module subdirectories to search, in order of preference */ +static const char *stdSubdirs[] = { + "", + "input/", + "drivers/", + "multimedia/", + "extensions/", + "internal/", + NULL +}; + +/* + * Standard set of module name patterns to check, in order of preference + * These are regular expressions (suitable for use with POSIX regex(3)). + * + * This list assumes that you're an ELFish platform and therefore your + * shared libraries are named something.so. If we're ever nuts enough + * to port this DDX to, say, Darwin, we'll need to fix this. + */ +static PatternRec stdPatterns[] = { + {"^lib(.*)\\.so$",}, + {"(.*)_drv\\.so$",}, + {"(.*)\\.so$",}, + {NULL,} +}; + +static PatternPtr +InitPatterns(const char **patternlist) +{ + char errmsg[80]; + int i, e; + PatternPtr patterns = NULL; + PatternPtr p = NULL; + static int firstTime = 1; + const char **s; + + if (firstTime) { + /* precompile stdPatterns */ + firstTime = 0; + for (p = stdPatterns; p->pattern; p++) + if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { + regerror(e, &p->rex, errmsg, sizeof(errmsg)); + FatalError("InitPatterns: regcomp error for `%s': %s\n", + p->pattern, errmsg); + } + } + + if (patternlist) { + for (i = 0, s = patternlist; *s; i++, s++) + if (*s == DEFAULT_LIST) + i += sizeof(stdPatterns) / sizeof(stdPatterns[0]) - 1 - 1; + patterns = malloc((i + 1) * sizeof(PatternRec)); + if (!patterns) { + return NULL; + } + for (i = 0, s = patternlist; *s; i++, s++) + if (*s != DEFAULT_LIST) { + p = patterns + i; + p->pattern = *s; + if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { + regerror(e, &p->rex, errmsg, sizeof(errmsg)); + ErrorF("InitPatterns: regcomp error for `%s': %s\n", + p->pattern, errmsg); + i--; + } + } else { + for (p = stdPatterns; p->pattern; p++, i++) + patterns[i] = *p; + if (p != stdPatterns) + i--; + } + patterns[i].pattern = NULL; + } else + patterns = stdPatterns; + return patterns; +} + +static void +FreePatterns(PatternPtr patterns) +{ + if (patterns && patterns != stdPatterns) + free(patterns); +} + +static const char ** +InitSubdirs(const char **subdirlist) +{ + int i; + const char **tmp_subdirlist = NULL; + char **subdirs = NULL; + const char **s, **stmp = NULL; + const char *osname; + const char *slash; + int oslen = 0, len; + Bool indefault; + + if (subdirlist == NULL) { + subdirlist = tmp_subdirlist = malloc(2 * sizeof(char *)); + if (subdirlist == NULL) + return NULL; + subdirlist[0] = DEFAULT_LIST; + subdirlist[1] = NULL; + } + + LoaderGetOS(&osname, NULL, NULL, NULL); + oslen = strlen(osname); + + { + /* Count number of entries and check for invalid paths */ + for (i = 0, s = subdirlist; *s; i++, s++) { + if (*s == DEFAULT_LIST) { + i += sizeof(stdSubdirs) / sizeof(stdSubdirs[0]) - 1 - 1; + } else { + /* + * Path validity check. Don't allow absolute paths, or + * paths containing "..". To catch absolute paths on + * platforms that use driver letters, don't allow the ':' + * character to appear at all. + */ + if (**s == '/' || **s == '\\' || strchr(*s, ':') || + strstr(*s, "..")) { + xf86Msg(X_ERROR, "InitSubdirs: Bad subdir: \"%s\"\n", *s); + if (tmp_subdirlist) + free(tmp_subdirlist); + return NULL; + } + } + } + subdirs = malloc((i * 2 + 1) * sizeof(char *)); + if (!subdirs) { + if (tmp_subdirlist) + free(tmp_subdirlist); + return NULL; + } + i = 0; + s = subdirlist; + indefault = FALSE; + while (*s) { + if (*s == DEFAULT_LIST) { + /* Divert to the default list */ + indefault = TRUE; + stmp = ++s; + s = stdSubdirs; + } + len = strlen(*s); + if (**s && (*s)[len - 1] != '/') { + slash = "/"; + len++; + } else + slash = ""; + len += oslen + 2; + if (!(subdirs[i] = malloc(len))) { + while (--i >= 0) + free(subdirs[i]); + free(subdirs); + if (tmp_subdirlist) + free(tmp_subdirlist); + return NULL; + } + /* tack on the OS name */ + sprintf(subdirs[i], "%s%s%s/", *s, slash, osname); + i++; + /* path as given */ + subdirs[i] = xstrdup(*s); + i++; + s++; + if (indefault && !s) { + /* revert back to the main list */ + indefault = FALSE; + s = stmp; + } + } + subdirs[i] = NULL; + } + if (tmp_subdirlist) + free(tmp_subdirlist); + return (const char **)subdirs; +} + +static void +FreeSubdirs(const char **subdirs) +{ + const char **s; + + if (subdirs) { + for (s = subdirs; *s; s++) + free(*s); + free(subdirs); + } +} + +static char * +FindModuleInSubdir(const char *dirpath, const char *module) +{ + struct dirent *direntry = NULL; + DIR *dir = NULL; + char *ret = NULL, tmpBuf[PATH_MAX]; + struct stat stat_buf; + + dir = opendir(dirpath); + if (!dir) + return NULL; + + while ((direntry = readdir(dir))) { + if (direntry->d_name[0] == '.') + continue; + snprintf(tmpBuf, PATH_MAX, "%s%s/", dirpath, direntry->d_name); + /* the stat with the appended / fails for normal files, + and works for sub dirs fine, looks a bit strange in strace + but does seem to work */ + if ((stat(tmpBuf, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode)) { + if ((ret = FindModuleInSubdir(tmpBuf, module))) + break; + continue; + } + + snprintf(tmpBuf, PATH_MAX, "lib%s.so", module); + if (strcmp(direntry->d_name, tmpBuf) == 0) { + ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); + sprintf(ret, "%s%s", dirpath, tmpBuf); + break; + } + + snprintf(tmpBuf, PATH_MAX, "%s_drv.so", module); + if (strcmp(direntry->d_name, tmpBuf) == 0) { + ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); + sprintf(ret, "%s%s", dirpath, tmpBuf); + break; + } + + snprintf(tmpBuf, PATH_MAX, "%s.so", module); + if (strcmp(direntry->d_name, tmpBuf) == 0) { + ret = malloc(strlen(tmpBuf) + strlen(dirpath) + 2); + sprintf(ret, "%s%s", dirpath, tmpBuf); + break; + } + } + + closedir(dir); + return ret; +} + +static char * +FindModule(const char *module, const char *dirname, const char **subdirlist, + PatternPtr patterns) +{ + char buf[PATH_MAX + 1]; + char *dirpath = NULL; + char *name = NULL; + int dirlen; + const char **subdirs = NULL; + const char **s; + + dirpath = (char *)dirname; + if (strlen(dirpath) > PATH_MAX) + return NULL; + + subdirs = InitSubdirs(subdirlist); + if (!subdirs) + return NULL; + + for (s = subdirs; *s; s++) { + if ((dirlen = strlen(dirpath) + strlen(*s)) > PATH_MAX) + continue; + strcpy(buf, dirpath); + strcat(buf, *s); + if ((name = FindModuleInSubdir(buf, module))) + break; + } + + FreeSubdirs(subdirs); + if (dirpath != dirname) + free(dirpath); + + return name; +} + +char ** +LoaderListDirs(const char **subdirlist, const char **patternlist) +{ + char buf[PATH_MAX + 1]; + char **pathlist; + char **elem; + const char **subdirs; + const char **s; + PatternPtr patterns; + PatternPtr p; + DIR *d; + struct dirent *dp; + regmatch_t match[2]; + struct stat stat_buf; + int len, dirlen; + char *fp; + char **listing = NULL; + char **save; + int n = 0; + + if (!(pathlist = InitPathList(NULL))) + return NULL; + if (!(subdirs = InitSubdirs(subdirlist))) { + FreePathList(pathlist); + return NULL; + } + if (!(patterns = InitPatterns(patternlist))) { + FreePathList(pathlist); + FreeSubdirs(subdirs); + return NULL; + } + + for (elem = pathlist; *elem; elem++) { + for (s = subdirs; *s; s++) { + if ((dirlen = strlen(*elem) + strlen(*s)) > PATH_MAX) + continue; + strcpy(buf, *elem); + strcat(buf, *s); + fp = buf + dirlen; + if (stat(buf, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode) && + (d = opendir(buf))) { + if (buf[dirlen - 1] != '/') { + buf[dirlen++] = '/'; + fp++; + } + while ((dp = readdir(d))) { + if (dirlen + strlen(dp->d_name) > PATH_MAX) + continue; + strcpy(fp, dp->d_name); + if (!(stat(buf, &stat_buf) == 0 && + S_ISREG(stat_buf.st_mode))) + continue; + for (p = patterns; p->pattern; p++) { + if (regexec(&p->rex, dp->d_name, 2, match, 0) == 0 && + match[1].rm_so != -1) { + len = match[1].rm_eo - match[1].rm_so; + save = listing; + listing = realloc(listing, + (n + 2) * sizeof(char *)); + if (!listing) { + if (save) { + save[n] = NULL; + FreeStringList(save); + } + FreePathList(pathlist); + FreeSubdirs(subdirs); + FreePatterns(patterns); + return NULL; + } + listing[n] = malloc(len + 1); + if (!listing[n]) { + FreeStringList(listing); + FreePathList(pathlist); + FreeSubdirs(subdirs); + FreePatterns(patterns); + return NULL; + } + strncpy(listing[n], dp->d_name + match[1].rm_so, + len); + listing[n][len] = '\0'; + n++; + break; + } + } + } + closedir(d); + } + } + } + if (listing) + listing[n] = NULL; + return listing; +} + +void +LoaderFreeDirList(char **list) +{ + FreeStringList(list); +} + +static Bool +CheckVersion(const char *module, XF86ModuleVersionInfo * data, + const XF86ModReqInfo * req) +{ + int vercode[4]; + char verstr[4]; + long ver = data->xf86version; + MessageType errtype; + + xf86Msg(X_INFO, "Module %s: vendor=\"%s\"\n", + data->modname ? data->modname : "UNKNOWN!", + data->vendor ? data->vendor : "UNKNOWN!"); + + /* Check for the different scheme used in XFree86 4.0.x releases: + * ((((((((major << 7) | minor) << 7) | subminor) << 5) | beta) << 5) | alpha) + * Since it wasn't used in 4.1.0 or later, limit to versions in the 4.0.x + * range, which limits the overlap with the new version scheme to conflicts + * with 6.71.8.764 through 6.72.39.934. + */ + if ((ver > (4 << 24)) && (ver < ( (4 << 24) + (1 << 17)))) { + /* 4.0.x and earlier */ + verstr[1] = verstr[3] = 0; + verstr[2] = (ver & 0x1f) ? (ver & 0x1f) + 'a' - 1 : 0; + ver >>= 5; + verstr[0] = (ver & 0x1f) ? (ver & 0x1f) + 'A' - 1 : 0; + ver >>= 5; + vercode[2] = ver & 0x7f; + ver >>= 7; + vercode[1] = ver & 0x7f; + ver >>= 7; + vercode[0] = ver; + xf86ErrorF("\tcompiled for %d.%d", vercode[0], vercode[1]); + if (vercode[2] != 0) + xf86ErrorF(".%d", vercode[2]); + xf86ErrorF("%s%s, module version = %d.%d.%d\n", verstr, verstr + 2, + data->majorversion, data->minorversion, data->patchlevel); + } else { + vercode[0] = ver / 10000000; + vercode[1] = (ver / 100000) % 100; + vercode[2] = (ver / 1000) % 100; + vercode[3] = ver % 1000; + xf86ErrorF("\tcompiled for %d.%d.%d", vercode[0], vercode[1], + vercode[2]); + if (vercode[3] != 0) + xf86ErrorF(".%d", vercode[3]); + xf86ErrorF(", module version = %d.%d.%d\n", data->majorversion, + data->minorversion, data->patchlevel); + } + + if (data->moduleclass) + xf86ErrorFVerb(2, "\tModule class: %s\n", data->moduleclass); + + ver = -1; + if (data->abiclass) { + int abimaj, abimin; + int vermaj, vermin; + + if (!strcmp(data->abiclass, ABI_CLASS_ANSIC)) + ver = LoaderVersionInfo.ansicVersion; + else if (!strcmp(data->abiclass, ABI_CLASS_VIDEODRV)) + ver = LoaderVersionInfo.videodrvVersion; + else if (!strcmp(data->abiclass, ABI_CLASS_XINPUT)) + ver = LoaderVersionInfo.xinputVersion; + else if (!strcmp(data->abiclass, ABI_CLASS_EXTENSION)) + ver = LoaderVersionInfo.extensionVersion; + else if (!strcmp(data->abiclass, ABI_CLASS_FONT)) + ver = LoaderVersionInfo.fontVersion; + + abimaj = GET_ABI_MAJOR(data->abiversion); + abimin = GET_ABI_MINOR(data->abiversion); + xf86ErrorFVerb(2, "\tABI class: %s, version %d.%d\n", + data->abiclass, abimaj, abimin); + if (ver != -1) { + vermaj = GET_ABI_MAJOR(ver); + vermin = GET_ABI_MINOR(ver); + if (abimaj != vermaj) { + if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) + errtype = X_WARNING; + else + errtype = X_ERROR; + xf86MsgVerb(errtype, 0, + "module ABI major version (%d) doesn't" + " match the server's version (%d)\n", + abimaj, vermaj); + if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) + return FALSE; + } else if (abimin > vermin) { + if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) + errtype = X_WARNING; + else + errtype = X_ERROR; + xf86MsgVerb(errtype, 0, + "module ABI minor version (%d) is " + "newer than the server's version " + "(%d)\n", abimin, vermin); + if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) + return FALSE; + } + } + } + + /* Check against requirements that the caller has specified */ + if (req) { + if (req->majorversion != MAJOR_UNSPEC) { + if (data->majorversion != req->majorversion) { + xf86MsgVerb(X_WARNING, 2, "module major version (%d) " + "doesn't match required major version (%d)\n", + data->majorversion, req->majorversion); + return FALSE; + } else if (req->minorversion != MINOR_UNSPEC) { + if (data->minorversion < req->minorversion) { + xf86MsgVerb(X_WARNING, 2, "module minor version (%d) " + "is less than the required minor version (%d)\n", + data->minorversion, req->minorversion); + return FALSE; + } else if (data->minorversion == req->minorversion && + req->patchlevel != PATCH_UNSPEC) { + if (data->patchlevel < req->patchlevel) { + xf86MsgVerb(X_WARNING, 2, "module patch level (%d) " + "is less than the required patch level (%d)\n", + data->patchlevel, req->patchlevel); + return FALSE; + } + } + } + } + if (req->moduleclass) { + if (!data->moduleclass || + strcmp(req->moduleclass, data->moduleclass)) { + xf86MsgVerb(X_WARNING, 2, "Module class (%s) doesn't match " + "the required class (%s)\n", + data->moduleclass ? data->moduleclass : "", + req->moduleclass); + return FALSE; + } + } else if (req->abiclass != ABI_CLASS_NONE) { + if (!data->abiclass || strcmp(req->abiclass, data->abiclass)) { + xf86MsgVerb(X_WARNING, 2, "ABI class (%s) doesn't match the " + "required ABI class (%s)\n", + data->abiclass ? data->abiclass : "", + req->abiclass); + return FALSE; + } + } + if ((req->abiclass != ABI_CLASS_NONE) && + req->abiversion != ABI_VERS_UNSPEC) { + int reqmaj, reqmin, maj, min; + + reqmaj = GET_ABI_MAJOR(req->abiversion); + reqmin = GET_ABI_MINOR(req->abiversion); + maj = GET_ABI_MAJOR(data->abiversion); + min = GET_ABI_MINOR(data->abiversion); + if (maj != reqmaj) { + xf86MsgVerb(X_WARNING, 2, "ABI major version (%d) doesn't " + "match the required ABI major version (%d)\n", + maj, reqmaj); + return FALSE; + } + /* XXX Maybe this should be the other way around? */ + if (min > reqmin) { + xf86MsgVerb(X_WARNING, 2, "module ABI minor version (%d) " + "is newer than that available (%d)\n", min, reqmin); + return FALSE; + } + } + } + return TRUE; +} + +static ModuleDescPtr +AddSibling(ModuleDescPtr head, ModuleDescPtr new) +{ + new->sib = head; + return (new); +} + +pointer +LoadSubModule(pointer _parent, const char *module, + const char **subdirlist, const char **patternlist, + pointer options, const XF86ModReqInfo * modreq, + int *errmaj, int *errmin) +{ + ModuleDescPtr submod; + ModuleDescPtr parent = (ModuleDescPtr)_parent; + + xf86MsgVerb(X_INFO, 3, "Loading sub module \"%s\"\n", module); + + if (PathIsAbsolute(module)) { + xf86Msg(X_ERROR, + "LoadSubModule: Absolute module path not permitted: \"%s\"\n", + module); + if (errmaj) + *errmaj = LDR_BADUSAGE; + if (errmin) + *errmin = 0; + return NULL; + } + + submod = doLoadModule(module, NULL, subdirlist, patternlist, options, + modreq, errmaj, errmin, LD_FLAG_GLOBAL); + if (submod && submod != (ModuleDescPtr) 1) { + parent->child = AddSibling(parent->child, submod); + submod->parent = parent; + } + return submod; +} + +static ModuleDescPtr +NewModuleDesc(const char *name) +{ + ModuleDescPtr mdp = malloc(sizeof(ModuleDesc)); + + if (mdp) { + mdp->child = NULL; + mdp->sib = NULL; + mdp->parent = NULL; + mdp->name = xstrdup(name); + mdp->handle = -1; + mdp->SetupProc = NULL; + mdp->TearDownProc = NULL; + mdp->TearDownData = NULL; + } + + return (mdp); +} + +ModuleDescPtr +DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent) +{ + ModuleDescPtr ret; + + if (!mod) + return NULL; + + ret = NewModuleDesc(mod->name); + if (ret == NULL) + return NULL; + + if (LoaderHandleOpen(mod->handle) == -1) + return NULL; + + ret->handle = mod->handle; + ret->SetupProc = mod->SetupProc; + ret->TearDownProc = mod->TearDownProc; + ret->TearDownData = NULL; + ret->child = DuplicateModule(mod->child, ret); + ret->sib = DuplicateModule(mod->sib, parent); + ret->parent = parent; + ret->VersionInfo = mod->VersionInfo; + + return ret; +} + +static const char *compiled_in_modules[] = { + "ddc", + "i2c", + "ramdac", + NULL +}; + +static ModuleDescPtr +doLoadModule(const char *module, const char *path, const char **subdirlist, + const char **patternlist, pointer options, + const XF86ModReqInfo * modreq, + int *errmaj, int *errmin, int flags) +{ + XF86ModuleData *initdata = NULL; + char **pathlist = NULL; + char *found = NULL; + char *name = NULL; + char **path_elem = NULL; + char *p = NULL; + ModuleDescPtr ret = NULL; + int wasLoaded = 0; + PatternPtr patterns = NULL; + int noncanonical = 0; + char *m = NULL; + const char **cim; + + xf86MsgVerb(X_INFO, 3, "LoadModule: \"%s\"", module); + + patterns = InitPatterns(patternlist); + name = LoaderGetCanonicalName(module, patterns); + noncanonical = (name && strcmp(module, name) != 0); + if (noncanonical) { + xf86ErrorFVerb(3, " (%s)\n", name); + xf86MsgVerb(X_WARNING, 1, + "LoadModule: given non-canonical module name \"%s\"\n", + module); + m = name; + } else { + xf86ErrorFVerb(3, "\n"); + m = (char *)module; + } + + for (cim = compiled_in_modules; *cim; cim++) + if (!strcmp (m, *cim)) + { + xf86MsgVerb(X_INFO, 3, "Module \"%s\" already built-in\n", m); + ret = (ModuleDescPtr) 1; + goto LoadModule_exit; + } + + if (!name) { + if (errmaj) + *errmaj = LDR_BADUSAGE; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + ret = NewModuleDesc(name); + if (!ret) { + if (errmaj) + *errmaj = LDR_NOMEM; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + + pathlist = InitPathList(path); + if (!pathlist) { + /* This could be a malloc failure too */ + if (errmaj) + *errmaj = LDR_BADUSAGE; + if (errmin) + *errmin = 1; + goto LoadModule_fail; + } + + /* + * if the module name is not a full pathname, we need to + * check the elements in the path + */ + if (PathIsAbsolute(module)) + found = xstrdup(module); + path_elem = pathlist; + while (!found && *path_elem != NULL) { + found = FindModule(m, *path_elem, subdirlist, patterns); + path_elem++; + /* + * When the module name isn't the canonical name, search for the + * former if no match was found for the latter. + */ + if (!*path_elem && m == name) { + path_elem = pathlist; + m = (char *)module; + } + } + + /* + * did we find the module? + */ + if (!found) { + xf86Msg(X_WARNING, "Warning, couldn't open module %s\n", module); + if (errmaj) + *errmaj = LDR_NOENT; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + ret->handle = LoaderOpen(found, name, 0, + errmaj, errmin, &wasLoaded, flags); + if (ret->handle < 0) + goto LoadModule_fail; + + /* drop any explicit suffix from the module name */ + p = strchr(name, '.'); + if (p) + *p = '\0'; + + /* + * now check if the special data object ModuleData is + * present. + */ + p = malloc(strlen(name) + strlen("ModuleData") + 1); + if (!p) { + if (errmaj) + *errmaj = LDR_NOMEM; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + strcpy(p, name); + strcat(p, "ModuleData"); + initdata = LoaderSymbol(p); + if (initdata) { + ModuleSetupProc setup; + ModuleTearDownProc teardown; + XF86ModuleVersionInfo *vers; + + vers = initdata->vers; + setup = initdata->setup; + teardown = initdata->teardown; + + if (!wasLoaded) { + if (vers) { + if (!CheckVersion(module, vers, modreq)) { + if (errmaj) + *errmaj = LDR_MISMATCH; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + } else { + xf86Msg(X_ERROR, + "LoadModule: Module %s does not supply" + " version information\n", module); + if (errmaj) + *errmaj = LDR_INVALID; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + } + if (setup) + ret->SetupProc = setup; + if (teardown) + ret->TearDownProc = teardown; + ret->VersionInfo = vers; + } else { + /* No initdata is OK for external modules */ + if (options == EXTERN_MODULE) + goto LoadModule_exit; + + /* no initdata, fail the load */ + xf86Msg(X_ERROR, "LoadModule: Module %s does not have a %s " + "data object.\n", module, p); + if (errmaj) + *errmaj = LDR_INVALID; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + if (ret->SetupProc) { + ret->TearDownData = ret->SetupProc(ret, options, errmaj, errmin); + if (!ret->TearDownData) { + goto LoadModule_fail; + } + } else if (options) { + xf86Msg(X_WARNING, "Module Options present, but no SetupProc " + "available for %s\n", module); + } + goto LoadModule_exit; + + LoadModule_fail: + UnloadModule(ret); + ret = NULL; + + LoadModule_exit: + FreePathList(pathlist); + FreePatterns(patterns); + free(found); + free(name); + free(p); + + return ret; +} + +/* + * LoadModule: load a module + * + * module The module name. Normally this is not a filename but the + * module's "canonical name. A full pathname is, however, + * also accepted. + * path A comma separated list of module directories. + * subdirlist A NULL terminated list of subdirectories to search. When + * NULL, the default "stdSubdirs" list is used. The default + * list is also substituted for entries with value DEFAULT_LIST. + * patternlist A NULL terminated list of regular expressions used to find + * module filenames. Each regex should contain exactly one + * subexpression that corresponds to the canonical module name. + * When NULL, the default "stdPatterns" list is used. The + * default list is also substituted for entries with value + * DEFAULT_LIST. + * options A NULL terminated list of Options that are passed to the + * module's SetupProc function. + * modreq An optional XF86ModReqInfo* containing + * version/ABI/vendor-ABI requirements to check for when + * loading the module. The following fields of the + * XF86ModReqInfo struct are checked: + * majorversion - must match the module's majorversion exactly + * minorversion - the module's minorversion must be >= this + * patchlevel - the module's minorversion.patchlevel must be + * >= this. Patchlevel is ignored when + * minorversion is not set. + * abiclass - (string) must match the module's abiclass + * abiversion - must be consistent with the module's + * abiversion (major equal, minor no older) + * moduleclass - string must match the module's moduleclass + * string + * "don't care" values are ~0 for numbers, and NULL for strings + * errmaj Major error return. + * errmin Minor error return. + * + */ +ModuleDescPtr +LoadModule(const char *module, const char *path, const char **subdirlist, + const char **patternlist, pointer options, + const XF86ModReqInfo * modreq, int *errmaj, int *errmin) +{ + return doLoadModule(module, path, subdirlist, patternlist, options, + modreq, errmaj, errmin, LD_FLAG_GLOBAL); +} + +void +UnloadModule(pointer mod) +{ + UnloadModuleOrDriver((ModuleDescPtr)mod); +} + +static void +UnloadModuleOrDriver(ModuleDescPtr mod) +{ + if (mod == (ModuleDescPtr) 1) + return; + + if (mod == NULL || mod->name == NULL) + return; + + xf86MsgVerb(X_INFO, 3, "UnloadModule: \"%s\"\n", mod->name); + + if ((mod->TearDownProc) && (mod->TearDownData)) + mod->TearDownProc(mod->TearDownData); + LoaderUnload(mod->handle); + + if (mod->child) + UnloadModuleOrDriver(mod->child); + if (mod->sib) + UnloadModuleOrDriver(mod->sib); + free(mod->name); + free(mod); +} + +void +UnloadSubModule(pointer _mod) +{ + ModuleDescPtr mod = (ModuleDescPtr)_mod; + + if (mod == NULL || mod->name == NULL) + return; + + xf86MsgVerb(X_INFO, 3, "UnloadSubModule: \"%s\"\n", mod->name); + + if ((mod->TearDownProc) && (mod->TearDownData)) + mod->TearDownProc(mod->TearDownData); + LoaderUnload(mod->handle); + + RemoveChild(mod); + + if (mod->child) + UnloadModuleOrDriver(mod->child); + + free(mod->name); + free(mod); +} + +static void +RemoveChild(ModuleDescPtr child) +{ + ModuleDescPtr mdp; + ModuleDescPtr prevsib; + ModuleDescPtr parent; + + if (!child->parent) + return; + + parent = child->parent; + if (parent->child == child) { + parent->child = child->sib; + return; + } + + prevsib = parent->child; + mdp = prevsib->sib; + while (mdp && mdp != child) { + prevsib = mdp; + mdp = mdp->sib; + } + if (mdp == child) + prevsib->sib = child->sib; + return; +} + +void +LoaderErrorMsg(const char *name, const char *modname, int errmaj, int errmin) +{ + const char *msg; + MessageType type = X_ERROR; + + switch (errmaj) { + case LDR_NOERROR: + msg = "no error"; + break; + case LDR_NOMEM: + msg = "out of memory"; + break; + case LDR_NOENT: + msg = "module does not exist"; + break; + case LDR_NOSUBENT: + msg = "a required submodule could not be loaded"; + break; + case LDR_NOSPACE: + msg = "too many modules"; + break; + case LDR_NOMODOPEN: + msg = "open failed"; + break; + case LDR_UNKTYPE: + msg = "unknown module type"; + break; + case LDR_NOLOAD: + msg = "loader failed"; + break; + case LDR_ONCEONLY: + msg = "already loaded"; + type = X_INFO; + break; + case LDR_NOPORTOPEN: + msg = "port open failed"; + break; + case LDR_NOHARDWARE: + msg = "no hardware found"; + break; + case LDR_MISMATCH: + msg = "module requirement mismatch"; + break; + case LDR_BADUSAGE: + msg = "invalid argument(s) to LoadModule()"; + break; + case LDR_INVALID: + msg = "invalid module"; + break; + case LDR_BADOS: + msg = "module doesn't support this OS"; + break; + case LDR_MODSPECIFIC: + msg = "module-specific error"; + break; + default: + msg = "unknown error"; + } + if (name) + xf86Msg(type, "%s: Failed to load module \"%s\" (%s, %d)\n", + name, modname, msg, errmin); + else + xf86Msg(type, "Failed to load module \"%s\" (%s, %d)\n", + modname, msg, errmin); +} + +/* Given a module path or file name, return the module's canonical name */ +static char * +LoaderGetCanonicalName(const char *modname, PatternPtr patterns) +{ + char *str; + const char *s; + int len; + PatternPtr p; + regmatch_t match[2]; + + /* Strip off any leading path */ + s = strrchr(modname, '/'); + if (s == NULL) + s = modname; + else + s++; + + /* Find the first regex that is matched */ + for (p = patterns; p->pattern; p++) + if (regexec(&p->rex, s, 2, match, 0) == 0 && match[1].rm_so != -1) { + len = match[1].rm_eo - match[1].rm_so; + str = malloc(len + 1); + if (!str) + return NULL; + strncpy(str, s + match[1].rm_so, len); + str[len] = '\0'; + return str; + } + + /* If there is no match, return the whole name minus the leading path */ + return xstrdup(s); +} + +/* + * Return the module version information. + */ +unsigned long +LoaderGetModuleVersion(ModuleDescPtr mod) +{ + if (!mod || mod == (ModuleDescPtr) 1 || !mod->VersionInfo) + return 0; + + return MODULE_VERSION_NUMERIC(mod->VersionInfo->majorversion, + mod->VersionInfo->minorversion, + mod->VersionInfo->patchlevel); +} -- cgit v1.2.3