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

Reply via email to