406 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			406 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
 | |
|  * 
 | |
|  * 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
 | |
|  * CONECTIVA LINUX 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 Conectiva Linux shall
 | |
|  * not be used in advertising or otherwise to promote the sale, use or other
 | |
|  * dealings in this Software without prior written authorization from
 | |
|  * Conectiva Linux.
 | |
|  *
 | |
|  * Author: Paulo César Pereira de Andrade <pcpa@conectiva.com.br>
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include "config.h"
 | |
| #include "cards.h"
 | |
| #include "options.h"
 | |
| #include "loader.h"
 | |
| #include "stubs.h"
 | |
| #include <X11/Xresource.h>
 | |
| #include <X11/Xos.h>
 | |
| 
 | |
| #ifdef USE_MODULES
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #if defined(X_POSIX_C_SOURCE)
 | |
| #define _POSIX_C_SOURCE X_POSIX_C_SOURCE
 | |
| #include <setjmp.h>
 | |
| #undef _POSIX_C_SOURCE
 | |
| #else
 | |
| #include <setjmp.h>
 | |
| #endif
 | |
| #include <signal.h>
 | |
| #include <ctype.h>
 | |
| 
 | |
| #include <stdarg.h>
 | |
| 
 | |
| #ifndef OPTIONSPATH
 | |
| #define OPTIONSPATH "/usr/lib/X11"
 | |
| #endif
 | |
| 
 | |
| #ifndef SIGNALRETURNSINT
 | |
| void sig_handler(int);
 | |
| #else
 | |
| int sig_handler(int);
 | |
| #endif	/* SIGNALRETURNSINT */
 | |
| 
 | |
| static Bool EnumDatabase(XrmDatabase*, XrmBindingList, XrmQuarkList,
 | |
| 			 XrmRepresentation*, XrmValue*, XPointer);
 | |
| 
 | |
| static sigjmp_buf jmp;
 | |
| int signal_caught;
 | |
| int error_level;
 | |
| char *loaderPath, **loaderList, **ploaderList;
 | |
| extern XrmDatabase options_xrm;
 | |
| extern int noverify;
 | |
| extern ModuleType module_type;
 | |
| static OptionInfoPtr option;
 | |
| 
 | |
| extern FontModule *font_module;
 | |
| extern int numFontModules;
 | |
| 
 | |
| char **checkerLegend;
 | |
| int *checkerErrors;
 | |
| 
 | |
| #ifndef SIGNALRETURNSINT
 | |
| void
 | |
| #else
 | |
| int
 | |
| #endif
 | |
| sig_handler(int sig)
 | |
| {
 | |
|     char *str;
 | |
| 
 | |
|     switch (sig) {
 | |
| 	case SIGTRAP:
 | |
| 	    str = "TRAP";
 | |
| 	    break;
 | |
| 	case SIGBUS:
 | |
| 	    str = "BUS";
 | |
| 	    break;
 | |
| 	case SIGSEGV:
 | |
| 	    str = "SEGV";
 | |
| 	    break;
 | |
| 	case SIGILL:
 | |
| 	    str = "ILL";
 | |
| 	    break;
 | |
| 	case SIGFPE:
 | |
| 	    str = "FPE";
 | |
| 	    break;
 | |
| 	default:
 | |
| 	    str = "???";
 | |
| 	    break;
 | |
|     }
 | |
| 
 | |
|     if (signal_caught == 1) {
 | |
| 	ErrorF("  ERROR I am dead.\n");
 | |
| 	exit(1);
 | |
|     }
 | |
|     else if (signal_caught == 2)
 | |
| 	abort();
 | |
|     ++signal_caught;
 | |
|     ErrorF("  ERROR SIG%s caught!\n", str);
 | |
|     if (!noverify)
 | |
| 	error_level += 50;
 | |
|     siglongjmp(jmp, 1);
 | |
|     /*NOTREACHED*/
 | |
| }
 | |
| 
 | |
| void
 | |
| CheckMsg(int code, char *fmt, ...)
 | |
| {
 | |
|     va_list ap;
 | |
| 
 | |
|     ++checkerErrors[code];
 | |
|     ErrorF("%3d ", code);
 | |
| 
 | |
|     va_start(ap, fmt);
 | |
|     VErrorF(fmt, ap);
 | |
|     va_end(ap);
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| EnumDatabase(XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
 | |
| 	     XrmRepresentation *type, XrmValue *value, XPointer closure)
 | |
| {
 | |
|     char *res = XrmQuarkToString(quarks[1]);
 | |
| 
 | |
|     if (res) {
 | |
| 	option = module_options->option;
 | |
| 	while (option->name) {
 | |
| 	    if (strcasecmp(option->name, res) == 0)
 | |
| 		return (False);
 | |
| 	    ++option;
 | |
| 	}
 | |
| 	CheckMsg(CHECKER_OPTION_UNUSED,
 | |
| 		 "WARNING %s.%s is not used\n",
 | |
| 		 XrmQuarkToString(quarks[0]), res);
 | |
| 	++error_level;
 | |
|     }
 | |
| 
 | |
|     return (False);
 | |
| }
 | |
| 
 | |
| Bool
 | |
| LoaderInitializeOptions(void)
 | |
| {
 | |
|     static int first = 1;
 | |
|     static char *modules = "lib/modules";
 | |
|     volatile Bool options_ok = False;
 | |
|     char *ptr, query[256];
 | |
|     char *ptr2, query2[256];
 | |
|     char *type;
 | |
|     XrmValue value;
 | |
|     XrmQuark names[2];
 | |
|     XrmQuark classes[2];
 | |
|     volatile int i;
 | |
|     static ModuleType module_types[] = {
 | |
| 	GenericModule, FontRendererModule, InputModule, VideoModule, NullModule
 | |
|     };
 | |
| 
 | |
|     /* The offset in this vector must match loader.h:enum ModuleType values */
 | |
|     static char *module_strs[] = {
 | |
| 	"Null Module", "Video Module", "Input Module", "Generic Module", "Font Module"
 | |
|     };
 | |
| 
 | |
|     if (first) {
 | |
| 	checkerLegend = (char**)
 | |
| 	    XtCalloc(1, sizeof(char*) * (CHECKER_LAST_MESSAGE + 1));
 | |
| 	checkerErrors = (int*)
 | |
| 	    XtCalloc(1, sizeof(int) * (CHECKER_LAST_MESSAGE + 1));
 | |
| 	xf86cfgLoaderInit();
 | |
| 	first = 0;
 | |
| 
 | |
| 	checkerLegend[CHECKER_OPTIONS_FILE_MISSING] =
 | |
| 	"The Options file, normally " OPTIONSPATH "/Options was not found.\n";
 | |
| 	checkerLegend[CHECKER_OPTION_DESCRIPTION_MISSING] =
 | |
| 	"No description for the module option. The description should be in\n"
 | |
| 	"in the Options file, and using the sintax:\n"
 | |
| 	"Module.Option:	any text describing the option";
 | |
| 	checkerLegend[CHECKER_LOAD_FAILED] =
 | |
| 	"Failed to load the module. Usually the loader will print a complete\n"
 | |
| 	"description for the reason the module was not loaded. Use the -verbose\n"
 | |
| 	"command line option if it is not printing any messages.";
 | |
| 	checkerLegend[CHECKER_RECOGNIZED_AS] =
 | |
| 	"This message means the module code did not follow what was expected\n"
 | |
| 	"by the checker. For video drivers, it did not call xf86AddDriver,\n"
 | |
| 	"a input module did not call xf86AddInputDriver and a font renderer\n"
 | |
| 	"module did not call LoadFont. This message can also be printed if\n"
 | |
| 	"the module is in the incorrect directory.";
 | |
| 	checkerLegend[CHECKER_NO_OPTIONS_AVAILABLE] =
 | |
| 	"The driver does not have an AvailableOptions function, or that\n"
 | |
| 	"function is returning NULL. If the driver is returning NULL, and\n"
 | |
| 	"really does not need any options from "__XCONFIGFILE__", than the message\n"
 | |
| 	"can be ignored.";
 | |
| 	checkerLegend[CHECKER_NO_VENDOR_CHIPSET] =
 | |
| 	"The checker could not fetch the PCI chipset/vendor information from\n"
 | |
| 	"the module. The checker currently wraps xf86PrintChipsets and\n"
 | |
| 	"xf86MatchPciInstances to read the information from the module.";
 | |
| 	checkerLegend[CHECKER_CANNOT_VERIFY_CHIPSET] =
 | |
| 	"The vendor id was not found, so it is not possible to search the list\n"
 | |
| 	"of chipsets.";
 | |
| 	checkerLegend[CHECKER_OPTION_UNUSED] =
 | |
| 	"The option description is defined in the Options file, but the option\n"
 | |
| 	"was name not retrieved when calling the module AvailableOptions.";
 | |
| 	checkerLegend[CHECKER_NOMATCH_CHIPSET_STRINGS] =
 | |
| 	"The string specified in the module does not match the one in\n"
 | |
| 	"common/xf86PciInfo.h";
 | |
| 	checkerLegend[CHECKER_CHIPSET_NOT_LISTED] =
 | |
| 	"This means that common/xf86PciInfo.h does not have an entry for the\n"
 | |
| 	"given vendor and id.";
 | |
| 	checkerLegend[CHECKER_CHIPSET_NOT_SUPPORTED] =
 | |
| 	"The chipset is listed in common/xf86PciInfo.h, but the driver does\n"
 | |
| 	"not support it, or does not list it in the chipsets fetched by the checker.";
 | |
| 	checkerLegend[CHECKER_CHIPSET_NO_VENDOR] =
 | |
| 	"The vendor id specified to xf86MatchPciInstances is not defined in\n"
 | |
| 	"common/xf86PciInfo.h";
 | |
| 	checkerLegend[CHECKER_NO_CHIPSETS] =
 | |
| 	"No chipsets were passed to xf86MatchPciIntances.";
 | |
| 	checkerLegend[CHECKER_FILE_MODULE_NAME_MISMATCH] =
 | |
| 	"The module name string does not match the the modname field of the\n"
 | |
| 	"XF86ModuleVersionInfo structure. This generally is not an error, but\n"
 | |
| 	"to may be a good idea to use the same string to avoid confusion.";
 | |
|     }
 | |
| 
 | |
|     if (XF86Module_path == NULL) {
 | |
| 	XF86Module_path = malloc(strlen(XFree86Dir) + strlen(modules) + 2);
 | |
| 	sprintf(XF86Module_path, "%s/%s", XFree86Dir, modules);
 | |
|     }
 | |
| 
 | |
|     if (loaderPath == NULL || strcmp(XF86Module_path, loaderPath))
 | |
| 	loaderPath = strdup(XF86Module_path);
 | |
|     else
 | |
| 	/* nothing new */
 | |
| 	return (True);
 | |
| 
 | |
|     if (!noverify) {
 | |
| 	options_ok = InitializeOptionsDatabase();
 | |
| 	InitializePciInfo();
 | |
|     }
 | |
| 
 | |
|     for (i = 0; module_types[i] != NullModule; i++) {
 | |
| 	xf86cfgLoaderInitList(module_types[i]);
 | |
| 	if (!noverify)
 | |
| 	    ErrorF("================= Checking modules of type \"%s\" =================\n",
 | |
| 		   module_strs[module_types[i]]);
 | |
| 
 | |
| 	if (loaderList) {
 | |
| 	    for (ploaderList = loaderList; *ploaderList; ploaderList++) {
 | |
| 		signal_caught = 0;
 | |
| 		signal(SIGTRAP, sig_handler);
 | |
| 		signal(SIGBUS, sig_handler);
 | |
| 		signal(SIGSEGV, sig_handler);
 | |
| 		signal(SIGILL, sig_handler);
 | |
| 		signal(SIGFPE, sig_handler);
 | |
| 		if (sigsetjmp(jmp, 1) == 0) {
 | |
| 		    if (!noverify) {
 | |
| 			int ok, nfont_modules;
 | |
| 
 | |
| 			nfont_modules = numFontModules;
 | |
| 			error_level = 0;
 | |
| 			ErrorF("CHECK MODULE %s\n", *ploaderList);
 | |
| 			if ((ok = xf86cfgCheckModule()) == 0) {
 | |
| 			    CheckMsg(CHECKER_LOAD_FAILED,
 | |
| 				     "ERROR Failed to load module.\n");
 | |
| 			    error_level += 50;
 | |
| 			}
 | |
| 			else if (module_type != module_types[i]) {
 | |
| 			    CheckMsg(CHECKER_RECOGNIZED_AS,
 | |
| 				     "WARNING %s recognized as a \"%s\"\n", *ploaderList,
 | |
| 				     module_strs[module_type]);
 | |
| 			    ++error_level;
 | |
| 			}
 | |
| 			if (ok) {
 | |
| 			    if (options_ok) {
 | |
| 				if ((module_options == NULL || module_options->option == NULL) &&
 | |
| 				    module_type != GenericModule) {
 | |
| 				    CheckMsg(CHECKER_NO_OPTIONS_AVAILABLE,
 | |
| 					     "WARNING Not a generic module, but no options available.\n");
 | |
| 				    ++error_level;
 | |
| 				}
 | |
| 				else if (module_options && strcmp(module_options->name, *ploaderList) == 0) {
 | |
| 				    ErrorF("  CHECK OPTIONS\n");
 | |
| 				    option = module_options->option;
 | |
| 
 | |
| 				    while (option->name) {
 | |
| 					XmuSnprintf(query, sizeof(query), "%s.%s", *ploaderList, option->name);
 | |
| 					for (ptr = query, ptr2 = query2; *ptr; ptr++) {
 | |
| 					    if (*ptr != '_' && *ptr != ' ' && *ptr != '\t')
 | |
| 						*ptr2 = tolower(*ptr);
 | |
| 					}
 | |
| 					*ptr2 = '\0';
 | |
| 					/* all resources are in lowercase */
 | |
| 					if (!XrmGetResource(options_xrm, query2, "Module.Option", &type, &value) ||
 | |
| 					    value.addr == NULL) {
 | |
| 					    CheckMsg(CHECKER_OPTION_DESCRIPTION_MISSING,
 | |
| 						     "WARNING no description for %s\n", query);
 | |
| 					    ++error_level;
 | |
| 					}
 | |
| 					++option;
 | |
| 				    }
 | |
| 
 | |
| 				    /* now do a linear search for Options file entries that are not
 | |
| 				     * in the driver.
 | |
| 				     */
 | |
| 				    names[0] = XrmPermStringToQuark(module_options->name);
 | |
| 				    classes[0] = XrmPermStringToQuark("Option");
 | |
| 				    names[1] = classes[1] = NULLQUARK;
 | |
| 				    (void)XrmEnumerateDatabase(options_xrm, (XrmNameList)&names, (XrmClassList)&classes,
 | |
| 							       XrmEnumOneLevel, EnumDatabase, NULL);
 | |
| 				}
 | |
| 			    }
 | |
| 			    else {
 | |
| 				CheckMsg(CHECKER_OPTIONS_FILE_MISSING,
 | |
| 					 "ERROR Options file missing.\n");
 | |
| 				error_level += 10;
 | |
| 			    }
 | |
| 
 | |
| 			    if (module_type == VideoModule &&
 | |
| 				(module_options == NULL || module_options->vendor < 0 ||
 | |
| 				 module_options->chipsets == NULL)) {
 | |
| 				CheckMsg(CHECKER_NO_VENDOR_CHIPSET,
 | |
| 				         "WARNING No vendor/chipset information available.\n");
 | |
| 				++error_level;
 | |
| 			    }
 | |
| 			    else if (module_type == VideoModule) {
 | |
| 				if (module_options == NULL) {
 | |
| 				    /* No description for this, if this happen,
 | |
| 				     * something really strange happened. */
 | |
| 				    ErrorF("  ERROR No module_options!?!\n");
 | |
| 				    error_level += 50;
 | |
| 				}
 | |
| 				else {
 | |
| 				    ErrorF("  CHECK CHIPSETS\n");
 | |
| 				    CheckChipsets(module_options, &error_level);
 | |
| 				}
 | |
| 			    }
 | |
| 
 | |
| 			    /* font modules check */
 | |
| 			    if (module_type == FontRendererModule) {
 | |
| 				if (strcmp(*ploaderList, font_module->name)) {
 | |
| 				    /* not an error */
 | |
| 				    ErrorF("  NOTICE FontModule->name specification mismatch: \"%s\" \"%s\"\n",
 | |
| 					   *ploaderList, font_module->name);
 | |
| 				}
 | |
| 				if (nfont_modules + 1 != numFontModules) {
 | |
| 				    /* not an error */
 | |
| 				    ErrorF("  NOTICE font module \"%s\" loaded more than one font renderer.\n",
 | |
| 					   *ploaderList);
 | |
| 				}
 | |
| 			    }
 | |
| 			    else if (nfont_modules != numFontModules) {
 | |
| 				ErrorF("  WARNING number of font modules changed from %d to %d.\n",
 | |
| 				       nfont_modules, numFontModules);
 | |
| 				++error_level;
 | |
| 			    }
 | |
| 			}
 | |
| 			ErrorF("  SUMMARY error_level set to %d.\n\n", error_level);
 | |
| 		    }
 | |
| 		    else
 | |
| 			(void)xf86cfgCheckModule();
 | |
| 		}
 | |
| 		signal(SIGTRAP, SIG_DFL);
 | |
| 		signal(SIGBUS, SIG_DFL);
 | |
| 		signal(SIGSEGV, SIG_DFL);
 | |
| 		signal(SIGILL, SIG_DFL);
 | |
| 		signal(SIGFPE, SIG_DFL);
 | |
| 	    }
 | |
| 	    xf86cfgLoaderFreeList();
 | |
| 	}
 | |
| 	else
 | |
| 	    ErrorF("  ERROR Failed to initialize module list.\n");
 | |
|     }
 | |
| 
 | |
|     if (!noverify) {
 | |
| 	ErrorF("===================================== LEGEND ===============================\n");
 | |
| 	ErrorF("NOTICE lines are just informative.\n");
 | |
| 	ErrorF("WARNING lines add 1 to error_level.\n");
 | |
| 	ErrorF("ERROR lines add 2 or more (based on the severity of the error) to error_level.\n\n");
 | |
| 	for (i = 0; i <= CHECKER_LAST_MESSAGE; i++)
 | |
| 	    if (checkerErrors[i]) {
 | |
| 		ErrorF("%3d\n%s\n\n", i, checkerLegend[i]);
 | |
| 	    }
 | |
|     }
 | |
| 
 | |
|     return (True);
 | |
| }
 | |
| #endif
 |