Currently there is a single file, xorg.conf, for configuring the server. This works fine most of the time, but it becomes a problem when packages or system services need to adjust the configuration. Instead, allow multiple configuration files to live in a directory. Typically this will be /etc/X11/xorg.conf.d.
Right now this uses the same matching templates as the config file but with a different default name. The matching code was refactored a bit to make this more coherent. It also won't fall back to using the auto configuration unless both the config file and config directory don't exist. Signed-off-by: Dan Nicholson <[email protected]> --- hw/xfree86/common/xf86Config.c | 29 +++-- hw/xfree86/parser/scan.c | 229 +++++++++++++++++++++++++++------------- hw/xfree86/parser/xf86Parser.h | 12 ++- hw/xwin/winconfig.c | 34 ++++-- 4 files changed, 208 insertions(+), 96 deletions(-) diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c index 40f65bd..04c4e01 100644 --- a/hw/xfree86/common/xf86Config.c +++ b/hw/xfree86/common/xf86Config.c @@ -2437,7 +2437,7 @@ checkInput(serverLayoutPtr layout, Bool implicit_layout) { ConfigStatus xf86HandleConfigFile(Bool autoconfig) { - const char *filename; + XF86ConfPathsPtr paths; char *searchpath; MessageType from = X_DEFAULT; char *scanptr; @@ -2453,18 +2453,25 @@ xf86HandleConfigFile(Bool autoconfig) if (xf86ConfigFile) from = X_CMDLINE; - filename = xf86openConfigFile(searchpath, xf86ConfigFile, PROJECTROOT); - if (filename) { - xf86MsgVerb(from, 0, "Using config file: \"%s\"\n", filename); - xf86ConfigFile = xnfstrdup(filename); - } else { - if (xf86ConfigFile) - xf86Msg(X_ERROR, "Unable to locate/open config file: \"%s\"\n", - xf86ConfigFile); + paths = xf86openConfigFile(searchpath, xf86ConfigFile, PROJECTROOT); + if (paths && (paths->file || paths->dir)) { + if (paths->file) { + xf86MsgVerb(from, 0, "Using config file: \"%s\"\n", + paths->file); + xf86ConfigFile = xnfstrdup(paths->file); + } else { + if (xf86ConfigFile) + xf86Msg(X_ERROR, + "Unable to locate/open config file: \"%s\"\n", + xf86ConfigFile); + } + if (paths && paths->dir) + xf86MsgVerb(X_DEFAULT, 0, "Using config directory: \"%s\"\n", + paths->dir); + } else return CONFIG_NOFILE; - } } - + if ((xf86configptr = xf86readConfigFile ()) == NULL) { xf86Msg(X_ERROR, "Problem parsing the config file\n"); return CONFIG_PARSE_ERROR; diff --git a/hw/xfree86/parser/scan.c b/hw/xfree86/parser/scan.c index 270dbd5..659b9d0 100644 --- a/hw/xfree86/parser/scan.c +++ b/hw/xfree86/parser/scan.c @@ -62,6 +62,8 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/types.h> +#include <dirent.h> #include <unistd.h> #include <stdarg.h> #include <X11/Xfuncproto.h> @@ -90,17 +92,23 @@ #include "xf86tokens.h" #define CONFIG_BUF_LEN 1024 +#define CONFIG_MAX_FILES 64 static int StringToToken (char *, xf86ConfigSymTabRec *); -static FILE *configFile = NULL; +static struct { + FILE *file; + char *path; +} configFiles[CONFIG_MAX_FILES]; static const char **builtinConfig = NULL; static int builtinIndex = 0; static int configPos = 0; /* current readers position */ static int configLineNo = 0; /* linenumber */ static char *configBuf, *configRBuf; /* buffer for lines */ -static char *configPath; /* path to config file */ +static XF86ConfPathsRec configPaths = { NULL }; /* paths to configuration */ static char *configSection = NULL; /* name of current section being parsed */ +static int numFiles = 0; /* number of config files */ +static int curFileIndex = 0; /* index of current config file */ static int pushToken = LOCK_TOKEN; static int eol_seen = 0; /* private state to handle comments */ LexRec val; @@ -155,7 +163,7 @@ xf86strToUL (char *str) /* * xf86getNextLine -- * - * read from the configFile FILE stream until we encounter a new + * read from the configFiles FILE stream until we encounter a new * line; this is effectively just a big wrapper for fgets(3). * * xf86getToken() assumes that we will read up to the next @@ -213,9 +221,18 @@ xf86getNextLine(void) /* read in another block of chars */ do { - ret = fgets(configBuf + pos, configBufLen - pos - 1, configFile); + ret = fgets(configBuf + pos, configBufLen - pos - 1, + configFiles[curFileIndex].file); - if (!ret) break; + if (!ret) { + /* stop if there are no more files */ + if (++curFileIndex >= numFiles) { + curFileIndex = 0; + break; + } + configLineNo = 0; + continue; + } /* search for EOL in the new block of chars */ @@ -306,7 +323,7 @@ again: if (!c) { char *ret; - if (configFile) + if (numFiles > 0) ret = xf86getNextLine(); else { if (builtinConfig[builtinIndex] == NULL) @@ -575,6 +592,9 @@ xf86pathIsSafe(const char *path) #ifndef XCONFIGFILE #define XCONFIGFILE "xorg.conf" #endif +#ifndef XCONFIGDIR +#define XCONFIGDIR "xorg.conf.d" +#endif #ifndef PROJECTROOT #define PROJECTROOT "/usr/X11R6" #endif @@ -616,7 +636,8 @@ xf86pathIsSafe(const char *path) static char * DoSubstitution(const char *template, const char *cmdline, const char *projroot, - int *cmdlineUsed, int *envUsed, char *XConfigFile) + int *cmdlineUsed, int *envUsed, + const char *XConfigFile) { char *result; int i, l; @@ -745,6 +766,102 @@ DoSubstitution(const char *template, const char *cmdline, const char *projroot, return result; } +static char * +DoConfigFile(const char *path, const char *cmdline, const char *projroot, + const char *confname) +{ + char *filepath = NULL; + char *pathcopy; + const char *template; + int cmdlineUsed = 0; + FILE *file = NULL; + + pathcopy = strdup(path); + template = strtok(pathcopy, ","); + while (template && !file) { + if ((filepath = DoSubstitution(template, cmdline, + projroot, &cmdlineUsed, + NULL, confname))) { + if ((file = fopen(filepath, "r")) != 0) { + if (cmdline && !cmdlineUsed) { + fclose(file); + file = NULL; + } + } + } + if (filepath && !file) { + free(filepath); + filepath = NULL; + } + template = strtok(NULL, ","); + } + + if (file) { + configFiles[numFiles].file = file; + configFiles[numFiles].path = strdup(filepath); + numFiles++; + } + return filepath; +} + +static char * +DoConfigDir(const char *path, const char *projroot, const char *confname) +{ + char *dirpath, *pathcopy; + const char *template; + DIR *dir = NULL; + + pathcopy = strdup(path); + template = strtok(pathcopy, ","); + while (template && !dir) { + if ((dirpath = DoSubstitution(template, NULL, projroot, + NULL, NULL, confname))) { + if ((dir = opendir(dirpath))) { + struct dirent *de; + char *name, *path; + size_t len; + + /* match files named *.conf */ + while ((de = readdir(dir))) { + name = de->d_name; + len = strlen(name); + if (name[0] == '.') + continue; + if (len <= 5) + continue; + if (strcmp(&name[len-5], ".conf") != 0) + continue; + path = malloc(PATH_MAX + 1); + snprintf(path, PATH_MAX + 1, "%s/%s", + dirpath, name); + configFiles[numFiles].file = + fopen(path, "r"); + if (configFiles[numFiles].file) + configFiles[numFiles++].path = + path; + else + free(path); + if (numFiles >= CONFIG_MAX_FILES) { + ErrorF("Maximum number of " + "configuration files " + "opened\n"); + break; + } + } + } + } + if (dirpath && !dir) { + free(dirpath); + dirpath = NULL; + } + template = strtok(NULL, ","); + } + + if (dir) + closedir(dir); + return dirpath; +} + /* * xf86openConfigFile -- * @@ -777,107 +894,69 @@ DoSubstitution(const char *template, const char *cmdline, const char *projroot, "%P/lib/X11/%X" #endif -const char * +const XF86ConfPathsPtr xf86openConfigFile(const char *path, const char *cmdline, const char *projroot) { - char *pathcopy; - const char *template; - int cmdlineUsed = 0; - - configFile = NULL; + memset(configFiles, 0, sizeof(configFiles)); + numFiles = 0; + curFileIndex = 0; configPos = 0; /* current readers position */ configLineNo = 0; /* linenumber */ pushToken = LOCK_TOKEN; if (!path || !path[0]) path = DEFAULT_CONF_PATH; - pathcopy = malloc(strlen(path) + 1); - strcpy(pathcopy, path); if (!projroot || !projroot[0]) projroot = PROJECTROOT; - template = strtok(pathcopy, ","); - /* First, search for a config file. */ - while (template && !configFile) { - if ((configPath = DoSubstitution(template, cmdline, projroot, - &cmdlineUsed, NULL, - XCONFIGFILE))) { - if ((configFile = fopen(configPath, "r")) != 0) { - if (cmdline && !cmdlineUsed) { - fclose(configFile); - configFile = NULL; - } - } - } - if (configPath && !configFile) { - free(configPath); - configPath = NULL; - } - template = strtok(NULL, ","); - } - - /* Then search for fallback */ - if (!configFile) { - strcpy(pathcopy, path); - template = strtok(pathcopy, ","); - - while (template && !configFile) { - if ((configPath = DoSubstitution(template, cmdline, projroot, - &cmdlineUsed, NULL, - XFREE86CFGFILE))) { - if ((configFile = fopen(configPath, "r")) != 0) { - if (cmdline && !cmdlineUsed) { - fclose(configFile); - configFile = NULL; - } - } - } - if (configPath && !configFile) { - free(configPath); - configPath = NULL; - } - template = strtok(NULL, ","); - } - } - - free(pathcopy); - if (!configFile) { + configPaths.file = DoConfigFile(path, cmdline, projroot, XCONFIGFILE); - return NULL; - } + /* Then search for fallback */ + if (!configPaths.file) + configPaths.file = DoConfigFile(path, cmdline, projroot, + XFREE86CFGFILE); + /* Search for the multiconf directory */ + configPaths.dir = DoConfigDir(path, projroot, XCONFIGDIR); configBuf = malloc (CONFIG_BUF_LEN); configRBuf = malloc (CONFIG_BUF_LEN); configBuf[0] = '\0'; /* sanity ... */ - return configPath; + return &configPaths; } void xf86closeConfigFile (void) { - free (configPath); - configPath = NULL; + int i; + + free (configPaths.file); + configPaths.file = NULL; + free (configPaths.dir); + configPaths.dir = NULL; free (configRBuf); configRBuf = NULL; free (configBuf); configBuf = NULL; - if (configFile) { - fclose (configFile); - configFile = NULL; - } else { + if (numFiles == 0) { builtinConfig = NULL; builtinIndex = 0; } + for (i = 0; i < numFiles; i++) { + fclose(configFiles[i].file); + configFiles[i].file = NULL; + free(configFiles[i].path); + configFiles[i].path = NULL; + } + numFiles = 0; } void xf86setBuiltinConfig(const char *config[]) { builtinConfig = config; - configPath = strdup("<builtin configuration>"); configBuf = malloc (CONFIG_BUF_LEN); configRBuf = malloc (CONFIG_BUF_LEN); configBuf[0] = '\0'; /* sanity ... */ @@ -888,9 +967,11 @@ void xf86parseError (char *format,...) { va_list ap; + char *filename = numFiles ? configFiles[curFileIndex].path : + "<builtin configuration>"; ErrorF ("Parse error on line %d of section %s in file %s\n\t", - configLineNo, configSection, configPath); + configLineNo, configSection, filename); va_start (ap, format); VErrorF (format, ap); va_end (ap); @@ -902,8 +983,10 @@ void xf86validationError (char *format,...) { va_list ap; + char *filename = numFiles ? configFiles[curFileIndex].path : + "<builtin configuration>"; - ErrorF ("Data incomplete in file %s\n\t", configPath); + ErrorF ("Data incomplete in file %s\n\t", filename); va_start (ap, format); VErrorF (format, ap); va_end (ap); diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h index b4837d5..16b841a 100644 --- a/hw/xfree86/parser/xf86Parser.h +++ b/hw/xfree86/parser/xf86Parser.h @@ -476,11 +476,19 @@ typedef struct } xf86ConfigSymTabRec, *xf86ConfigSymTabPtr; +typedef struct +{ + char *file; /* config file */ + char *dir; /* multiconf directory */ +} +XF86ConfPathsRec, *XF86ConfPathsPtr; + /* * prototypes for public functions */ -extern _X_EXPORT const char *xf86openConfigFile (const char *, const char *, - const char *); +extern _X_EXPORT const XF86ConfPathsPtr xf86openConfigFile(const char *path, + const char *cmdline, + const char *projroot); extern _X_EXPORT void xf86setBuiltinConfig(const char *config[]); extern _X_EXPORT XF86ConfigPtr xf86readConfigFile (void); extern _X_EXPORT void xf86closeConfigFile (void); diff --git a/hw/xwin/winconfig.c b/hw/xwin/winconfig.c index 3e1908c..63ead08 100644 --- a/hw/xwin/winconfig.c +++ b/hw/xwin/winconfig.c @@ -109,7 +109,9 @@ Bool winReadConfigfile () { Bool retval = TRUE; + XF86ConfPathsPtr paths; const char *filename; + const char *dirname; MessageType from = X_DEFAULT; char *xf86ConfigFile = NULL; @@ -121,24 +123,36 @@ winReadConfigfile () /* Parse config file into data structure */ - filename = xf86openConfigFile (CONFIGPATH, xf86ConfigFile, PROJECTROOT); - + paths = xf86openConfigFile (CONFIGPATH, xf86ConfigFile, PROJECTROOT); + /* Hack for backward compatibility */ - if (!filename && from == X_DEFAULT) - filename = xf86openConfigFile (CONFIGPATH, "XF86Config", PROJECTROOT); + if (!(paths && paths->file) && from == X_DEFAULT) + paths = xf86openConfigFile (CONFIGPATH, "XF86Config", PROJECTROOT); - if (filename) + if (paths && (paths->file || paths->dir)) { - winMsg (from, "Using config file: \"%s\"\n", filename); + if (paths && paths->file) + { + winMsg (from, "Using config file: \"%s\"\n", paths->file); + } + else + { + winMsg (X_ERROR, "Unable to locate/open config file"); + if (xf86ConfigFile) + ErrorF (": \"%s\"", xf86ConfigFile); + ErrorF ("\n"); + } + + if (paths && paths->dir) + { + winMsg (X_DEFAULT, "Using config directory \"%s\"\n", paths->dir); + } } else { - winMsg (X_ERROR, "Unable to locate/open config file"); - if (xf86ConfigFile) - ErrorF (": \"%s\"", xf86ConfigFile); - ErrorF ("\n"); return FALSE; } + if ((g_xf86configptr = xf86readConfigFile ()) == NULL) { winMsg (X_ERROR, "Problem parsing the config file\n"); -- 1.6.2.5 _______________________________________________ xorg-devel mailing list [email protected] http://lists.x.org/mailman/listinfo/xorg-devel
