#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
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);
}
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
};
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
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';
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;
}
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) {
ErrorF(" ERROR No module_options!?!\n");
error_level += 50;
}
else {
ErrorF(" CHECK CHIPSETS\n");
CheckChipsets(module_options, &error_level);
}
}
if (module_type == FontRendererModule) {
if (strcmp(*ploaderList, font_module->name)) {
ErrorF(" NOTICE FontModule->name specification mismatch: \"%s\" \"%s\"\n",
*ploaderList, font_module->name);
}
if (nfont_modules + 1 != numFontModules) {
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