[PATCH] xfree86: Allow a config directory for multiple config files
Dan Nicholson
dbn.lists at gmail.com
Fri Nov 27 09:34:00 PST 2009
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 <dbn.lists at gmail.com>
---
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
More information about the xorg-devel
mailing list