[libvirt] [PATCH] Use XDG Base Directories instead of storing in home directory

William Jon McCann william.jon.mccann at gmail.com
Wed May 2 17:53:36 UTC 2012


As defined in:
http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html

This offers a number of advantages:
 * Allows sharing a home directory between different machines, or
sessions (eg. using NFS)
 * Cleanly separates cache, runtime (eg. sockets), or app data from
user settings
 * Supports performing smart or selective migration of settings
between different OS versions
 * Supports reseting settings without breaking things
 * Makes it possible to clear cache data to make room when the disk
is filling up
 * Allows us to write a robust and efficient backup solution
 * Allows an admin flexibility to change where data and settings are stored
 * Dramatically reduces the complexity and incoherence of the
system for administrators
---
 AUTHORS                        |    1 +
 daemon/libvirtd-config.c       |   10 +--
 daemon/libvirtd.c              |  143 +++++++++++++++++++++++++++++++++-------
 daemon/libvirtd.pod.in         |    2 +-
 docs/auth.html.in              |    2 +-
 docs/uri.html.in               |    2 +-
 src/libvirt.c                  |    4 +-
 src/libvirt_private.syms       |    4 ++
 src/network/bridge_driver.c    |    8 ++-
 src/nwfilter/nwfilter_driver.c |   11 +---
 src/qemu/qemu_driver.c         |   32 +++++----
 src/remote/remote_driver.c     |    4 +-
 src/remote/remote_driver.h     |    2 +-
 src/secret/secret_driver.c     |   11 +---
 src/storage/storage_driver.c   |   13 +---
 src/uml/uml_driver.c           |   10 +--
 src/util/util.c                |   67 +++++++++++++++++++
 src/util/util.h                |    4 ++
 src/util/virauth.c             |    4 +-
 tools/virsh.c                  |    6 +-
 20 files changed, 251 insertions(+), 89 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 06b830a..668eca1 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -234,6 +234,7 @@ Patches have also been contributed by:
   Jan Kiszka           <jan.kiszka at siemens.com>
   Ryan Woodsmall       <rwoodsmall at gmail.com>
   Wido den Hollander   <wido at widodh.nl>
+  William Jon McCann   <jmccann at redhat.com>
 
   [....send patches to get your name here....]
 
diff --git a/daemon/libvirtd-config.c b/daemon/libvirtd-config.c
index 471236c..8b95969 100644
--- a/daemon/libvirtd-config.c
+++ b/daemon/libvirtd-config.c
@@ -205,16 +205,16 @@ daemonConfigFilePath(bool privileged, char **configfile)
         if (!(*configfile = strdup(SYSCONFDIR "/libvirt/libvirtd.conf")))
             goto no_memory;
     } else {
-        char *userdir = NULL;
+        char *configdir = NULL;
 
-        if (!(userdir = virGetUserDirectory(geteuid())))
+        if (!(configdir = virGetUserConfigDirectory(geteuid())))
             goto error;
 
-        if (virAsprintf(configfile, "%s/.libvirt/libvirtd.conf", userdir) < 0) {
-            VIR_FREE(userdir);
+        if (virAsprintf(configfile, "%s/libvirtd.conf", configdir) < 0) {
+            VIR_FREE(configdir);
             goto no_memory;
         }
-        VIR_FREE(userdir);
+        VIR_FREE(configdir);
     }
 
     return 0;
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index b098f6a..bb25678 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -239,17 +239,25 @@ daemonPidFilePath(bool privileged,
         if (!(*pidfile = strdup(LOCALSTATEDIR "/run/libvirtd.pid")))
             goto no_memory;
     } else {
-        char *userdir = NULL;
+        char *rundir = NULL;
+        mode_t old_umask;
 
-        if (!(userdir = virGetUserDirectory(geteuid())))
+        if (!(rundir = virGetUserRuntimeDirectory(geteuid())))
             goto error;
 
-        if (virAsprintf(pidfile, "%s/.libvirt/libvirtd.pid", userdir) < 0) {
-            VIR_FREE(userdir);
+        old_umask = umask(077);
+        if (virFileMakePath(rundir) < 0) {
+            umask(old_umask);
+            goto error;
+        }
+        umask(old_umask);
+
+        if (virAsprintf(pidfile, "%s/libvirtd.pid", rundir) < 0) {
+            VIR_FREE(rundir);
             goto no_memory;
         }
 
-        VIR_FREE(userdir);
+        VIR_FREE(rundir);
     }
 
     return 0;
@@ -279,17 +287,25 @@ daemonUnixSocketPaths(struct daemonConfig *config,
             if (!(*rosockfile = strdup(LOCALSTATEDIR "/run/libvirt/libvirt-sock-ro")))
                 goto no_memory;
         } else {
-            char *userdir = NULL;
+            char *rundir = NULL;
+            mode_t old_umask;
 
-            if (!(userdir = virGetUserDirectory(geteuid())))
+            if (!(rundir = virGetUserRuntimeDirectory(geteuid())))
                 goto error;
 
-            if (virAsprintf(sockfile, "@%s/.libvirt/libvirt-sock", userdir) < 0) {
-                VIR_FREE(userdir);
+            old_umask = umask(077);
+            if (virFileMakePath(rundir) < 0) {
+                umask(old_umask);
+                goto error;
+            }
+            umask(old_umask);
+
+            if (virAsprintf(sockfile, "@%s/libvirt-sock", rundir) < 0) {
+                VIR_FREE(rundir);
                 goto no_memory;
             }
 
-            VIR_FREE(userdir);
+            VIR_FREE(rundir);
         }
     }
     return 0;
@@ -593,16 +609,25 @@ daemonSetupLogging(struct daemonConfig *config,
                                 LOCALSTATEDIR) == -1)
                     goto no_memory;
             } else {
-                char *userdir = virGetUserDirectory(geteuid());
-                if (!userdir)
+                char *logdir = virGetUserCacheDirectory(geteuid());
+                mode_t old_umask;
+
+                if (!logdir)
+                    goto error;
+
+                old_umask = umask(077);
+                if (virFileMakePath(logdir) < 0) {
+                    umask(old_umask);
                     goto error;
+                }
+                umask(old_umask);
 
-                if (virAsprintf(&tmp, "%d:file:%s/.libvirt/libvirtd.log",
-                                virLogGetDefaultPriority(), userdir) == -1) {
-                    VIR_FREE(userdir);
+                if (virAsprintf(&tmp, "%d:file:%s/libvirtd.log",
+                                virLogGetDefaultPriority(), logdir) == -1) {
+                    VIR_FREE(logdir);
                     goto no_memory;
                 }
-                VIR_FREE(userdir);
+                VIR_FREE(logdir);
             }
         } else {
             if (virAsprintf(&tmp, "%d:stderr", virLogGetDefaultPriority()) < 0)
@@ -722,6 +747,75 @@ static int daemonStateInit(virNetServerPtr srv)
     return 0;
 }
 
+static int migrateProfile(void)
+{
+    char *old_base = NULL;
+    char *updated = NULL;
+    char *home = NULL;
+    char *xdg_dir = NULL;
+    char *config_dir = NULL;
+    const char *config_home;
+    int ret = -1;
+    mode_t old_umask;
+
+    if (!(home = virGetUserDirectory(geteuid())))
+        goto cleanup;
+
+    if (virAsprintf(&old_base, "%s/.libvirt", home) < 0) {
+        goto cleanup;
+    }
+
+    /* if the new directory is there or the old one is not: do nothing */
+    if (!(config_dir = virGetUserConfigDirectory(geteuid())))
+        goto cleanup;
+
+    if (!virFileIsDir(old_base) || virFileExists(config_dir)) {
+        goto cleanup;
+    }
+
+    /* test if we already attempted to migrate first */
+    if (virAsprintf(&updated, "%s/DEPRECATED-DIRECTORY", old_base) < 0) {
+        goto cleanup;
+    }
+    if (virFileExists(updated)) {
+        goto cleanup;
+    }
+
+    config_home = getenv("XDG_CONFIG_HOME");
+    if (config_home && config_home[0] != '\0') {
+        xdg_dir = strdup(config_home);
+    } else {
+        if (virAsprintf(&xdg_dir, "%s/.config", home) < 0) {
+            goto cleanup;
+        }
+    }
+
+    old_umask = umask(077);
+    if (virFileMakePath(xdg_dir) < 0) {
+        umask(old_umask);
+        goto cleanup;
+    }
+    umask(old_umask);
+
+    if (rename(old_base, config_dir) < 0) {
+        int fd = creat(updated, 0600);
+        VIR_FORCE_CLOSE(fd);
+        VIR_ERROR(_("Unable to migrate %s to %s"), old_base, config_dir);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(home);
+    VIR_FREE(old_base);
+    VIR_FREE(xdg_dir);
+    VIR_FREE(config_dir);
+    VIR_FREE(updated);
+
+    return ret;
+}
+
 /* Print command-line usage. */
 static void
 daemonUsage(const char *argv0, bool privileged)
@@ -775,10 +869,10 @@ libvirt management daemon:\n"), argv0);
   Default paths:\n\
 \n\
     Configuration file (unless overridden by -f):\n\
-      $HOME/.libvirt/libvirtd.conf\n\
+      $XDG_CONFIG_HOME/libvirt/libvirtd.conf\n\
 \n\
     Sockets:\n\
-      $HOME/.libvirt/libvirt-sock (in UNIX abstract namespace)\n\
+      $XDG_RUNTIME_HOME/libvirt/libvirt-sock (in UNIX abstract namespace)\n\
 \n\
     TLS:\n\
       CA certificate:     $HOME/.pki/libvirt/cacert.pem\n\
@@ -786,7 +880,7 @@ libvirt management daemon:\n"), argv0);
       Server private key: $HOME/.pki/libvirt/serverkey.pem\n\
 \n\
     PID file:\n\
-      $HOME/.libvirt/libvirtd.pid\n\
+      $XDG_RUNTIME_HOME/libvirt/libvirtd.pid\n\
 \n"));
     }
 }
@@ -931,6 +1025,9 @@ int main(int argc, char **argv) {
         exit(EXIT_FAILURE);
     }
 
+    if (migrateProfile() < 0)
+        exit(EXIT_FAILURE);
+
     if (config->host_uuid &&
         virSetHostUUIDStr(config->host_uuid) < 0) {
         VIR_ERROR(_("invalid host UUID: %s"), config->host_uuid);
@@ -977,21 +1074,19 @@ int main(int argc, char **argv) {
     if (privileged) {
         run_dir = strdup(LOCALSTATEDIR "/run/libvirt");
     } else {
-        char *user_dir = virGetUserDirectory(geteuid());
+        run_dir = virGetUserRuntimeDirectory(geteuid());
 
-        if (!user_dir) {
+        if (!run_dir) {
             VIR_ERROR(_("Can't determine user directory"));
             goto cleanup;
         }
-        ignore_value(virAsprintf(&run_dir, "%s/.libvirt/", user_dir));
-        VIR_FREE(user_dir);
     }
     if (!run_dir) {
         virReportOOMError();
         goto cleanup;
     }
 
-    old_umask = umask(022);
+    old_umask = umask(077);
     if (virFileMakePath(run_dir) < 0) {
         char ebuf[1024];
         VIR_ERROR(_("unable to create rundir %s: %s"), run_dir,
diff --git a/daemon/libvirtd.pod.in b/daemon/libvirtd.pod.in
index 6e699b8..ea6c37d 100644
--- a/daemon/libvirtd.pod.in
+++ b/daemon/libvirtd.pod.in
@@ -85,7 +85,7 @@ command line using the B<-f>|B<--config> option.
 
 The sockets libvirtd will use when B<run as root>.
 
-=item F<$HOME/.libvirt/libvirt-sock>
+=item F<$XDG_RUNTIME_DIR/libvirt/libvirt-sock>
 
 The socket libvirtd will use when run as a B<non-root> user.
 
diff --git a/docs/auth.html.in b/docs/auth.html.in
index ecff0fc..60e4f11 100644
--- a/docs/auth.html.in
+++ b/docs/auth.html.in
@@ -25,7 +25,7 @@ for the authentication file using the following sequence:
         variable.</li>
       <li>The file path specified by the "authfile=/some/file" URI
         query parameter</li>
-      <li>The file $HOME/.libvirt/auth.conf</li>
+      <li>The file $XDG_CONFIG_DIR/libvirt/auth.conf</li>
       <li>The file /etc/libvirt/auth.conf</li>
     </ol>
 
diff --git a/docs/uri.html.in b/docs/uri.html.in
index 2f76e8f..5812ca9 100644
--- a/docs/uri.html.in
+++ b/docs/uri.html.in
@@ -30,7 +30,7 @@ virConnectPtr conn = virConnectOpenReadOnly (<b>"test:///default"</b>);
     <p>
 To simplify life for administrators, it is possible to setup URI aliases in a
 libvirt client configuration file. The configuration file is <code>/etc/libvirt/libvirt.conf</code>
-for the root user, or <code>$HOME/.libvirt/libvirt.conf</code> for any unprivileged user.
+for the root user, or <code>$XDG_CONFIG_DIR/libvirt/libvirt.conf</code> for any unprivileged user.
 In this file, the following syntax can be used to setup aliases
     </p>
 
diff --git a/src/libvirt.c b/src/libvirt.c
index cfd7711..22fc863 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -969,11 +969,11 @@ virConnectGetConfigFilePath(void)
                         SYSCONFDIR) < 0)
             goto no_memory;
     } else {
-        char *userdir = virGetUserDirectory(geteuid());
+        char *userdir = virGetUserConfigDirectory(geteuid());
         if (!userdir)
             goto error;
 
-        if (virAsprintf(&path, "%s/.libvirt/libvirt.conf",
+        if (virAsprintf(&path, "%s/libvirt.conf",
                         userdir) < 0) {
             VIR_FREE(userdir);
             goto no_memory;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d4038b2..06d5823 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1109,6 +1109,7 @@ virFileFindMountPoint;
 virFileHasSuffix;
 virFileIsExecutable;
 virFileIsLink;
+virFileIsDir;
 virFileLinkPointsTo;
 virFileLock;
 virFileMakePath;
@@ -1129,6 +1130,9 @@ virGetGroupID;
 virGetGroupName;
 virGetHostname;
 virGetUserDirectory;
+virGetUserConfigDirectory;
+virGetUserCacheDirectory;
+virGetUserRuntimeDirectory;
 virGetUserID;
 virGetUserName;
 virHexToBin;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index d82212f..cea87c2 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -280,18 +280,20 @@ networkStartup(int privileged) {
         if ((base = strdup (SYSCONFDIR "/libvirt")) == NULL)
             goto out_of_memory;
     } else {
-        char *userdir = virGetUserDirectory(uid);
+        char *userdir = virGetUserCacheDirectory(uid);
 
         if (!userdir)
             goto error;
 
         if (virAsprintf(&driverState->logDir,
-                        "%s/.libvirt/qemu/log", userdir) == -1) {
+                        "%s/qemu/log", userdir) == -1) {
             VIR_FREE(userdir);
             goto out_of_memory;
         }
+        VIR_FREE(userdir);
 
-        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
+        userdir = virGetUserConfigDirectory(uid);
+        if (virAsprintf(&base, "%s", userdir) == -1) {
             VIR_FREE(userdir);
             goto out_of_memory;
         }
diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c
index ffb4b5d..3d732ab 100644
--- a/src/nwfilter/nwfilter_driver.c
+++ b/src/nwfilter/nwfilter_driver.c
@@ -87,16 +87,9 @@ nwfilterDriverStartup(int privileged) {
             goto out_of_memory;
     } else {
         uid_t uid = geteuid();
-        char *userdir = virGetUserDirectory(uid);
-
-        if (!userdir)
+        base = virGetUserConfigDirectory(uid);
+        if (!base)
             goto error;
-
-        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
-            VIR_FREE(userdir);
-            goto out_of_memory;
-        }
-        VIR_FREE(userdir);
     }
 
     if (virAsprintf(&driverState->configDir,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 86e82d6..6d98abd 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -520,28 +520,38 @@ qemudStartup(int privileged) {
             goto out_of_memory;
     } else {
         uid_t uid = geteuid();
-        char *userdir = virGetUserDirectory(uid);
-        if (!userdir)
+        char *rundir;
+        char *cachedir;
+
+        cachedir = virGetUserCacheDirectory(uid);
+        if (!cachedir)
             goto error;
 
         if (virAsprintf(&qemu_driver->logDir,
-                        "%s/.libvirt/qemu/log", userdir) == -1) {
-            VIR_FREE(userdir);
+                        "%s/qemu/log", cachedir) == -1) {
+            VIR_FREE(cachedir);
             goto out_of_memory;
         }
-
-        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
-            VIR_FREE(userdir);
+        if (virAsprintf(&qemu_driver->cacheDir, "%s/qemu/cache", cachedir) == -1) {
+            VIR_FREE(cachedir);
             goto out_of_memory;
         }
-        VIR_FREE(userdir);
+        VIR_FREE(cachedir);
 
-        if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", base) == -1)
+        rundir = virGetUserRuntimeDirectory(uid);
+        if (!rundir)
+            goto error;
+        if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", rundir) == -1) {
+            VIR_FREE(rundir);
             goto out_of_memory;
+        }
+        VIR_FREE(rundir);
+
+        base = virGetUserConfigDirectory(uid);
+        if (!base)
+            goto error;
         if (virAsprintf(&qemu_driver->libDir, "%s/qemu/lib", base) == -1)
             goto out_of_memory;
-        if (virAsprintf(&qemu_driver->cacheDir, "%s/qemu/cache", base) == -1)
-            goto out_of_memory;
         if (virAsprintf(&qemu_driver->saveDir, "%s/qemu/save", base) == -1)
             goto out_of_memory;
         if (virAsprintf(&qemu_driver->snapshotDir, "%s/qemu/snapshot", base) == -1)
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 7863b73..4a9299a 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -578,12 +578,12 @@ doRemoteOpen (virConnectPtr conn,
     case trans_unix:
         if (!sockname) {
             if (flags & VIR_DRV_OPEN_REMOTE_USER) {
-                char *userdir = virGetUserDirectory(getuid());
+                char *userdir = virGetUserRuntimeDirectory(getuid());
 
                 if (!userdir)
                     goto failed;
 
-                if (virAsprintf(&sockname, "@%s" LIBVIRTD_USER_UNIX_SOCKET, userdir) < 0) {
+                if (virAsprintf(&sockname, "@%s/" LIBVIRTD_USER_UNIX_SOCKET, userdir) < 0) {
                     VIR_FREE(userdir);
                     goto out_of_memory;
                 }
diff --git a/src/remote/remote_driver.h b/src/remote/remote_driver.h
index 1504eec..aca9412 100644
--- a/src/remote/remote_driver.h
+++ b/src/remote/remote_driver.h
@@ -37,7 +37,7 @@ unsigned long remoteVersion(void);
 # define LIBVIRTD_TCP_PORT "16509"
 # define LIBVIRTD_PRIV_UNIX_SOCKET LOCALSTATEDIR "/run/libvirt/libvirt-sock"
 # define LIBVIRTD_PRIV_UNIX_SOCKET_RO LOCALSTATEDIR "/run/libvirt/libvirt-sock-ro"
-# define LIBVIRTD_USER_UNIX_SOCKET "/.libvirt/libvirt-sock"
+# define LIBVIRTD_USER_UNIX_SOCKET "libvirt-sock"
 # define LIBVIRTD_CONFIGURATION_FILE SYSCONFDIR "/libvirtd.conf"
 
 /* Defaults for PKI directory. */
diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c
index 088a243..f3fcce2 100644
--- a/src/secret/secret_driver.c
+++ b/src/secret/secret_driver.c
@@ -1013,16 +1013,9 @@ secretDriverStartup(int privileged)
             goto out_of_memory;
     } else {
         uid_t uid = geteuid();
-        char *userdir = virGetUserDirectory(uid);
-
-        if (!userdir)
+        base = virGetUserConfigDirectory(uid);
+        if (!base)
             goto error;
-
-        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
-            VIR_FREE(userdir);
-            goto out_of_memory;
-        }
-        VIR_FREE(userdir);
     }
     if (virAsprintf(&driverState->directory, "%s/secrets", base) == -1)
         goto out_of_memory;
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c
index f23ec7e..fd762c0 100644
--- a/src/storage/storage_driver.c
+++ b/src/storage/storage_driver.c
@@ -146,19 +146,12 @@ storageDriverStartup(int privileged)
             goto out_of_memory;
     } else {
         uid_t uid = geteuid();
-        char *userdir = virGetUserDirectory(uid);
-
-        if (!userdir)
+        base = virGetUserConfigDirectory(uid);
+        if (!base)
             goto error;
-
-        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
-            VIR_FREE(userdir);
-            goto out_of_memory;
-        }
-        VIR_FREE(userdir);
     }
 
-    /* Configuration paths are either ~/.libvirt/storage/... (session) or
+    /* Configuration paths are either $USER_CONFIG_HOME/libvirt/storage/... (session) or
      * /etc/libvirt/storage/... (system).
      */
     if (virAsprintf(&driverState->configDir,
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index 4e640ff..8a39d73 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -434,12 +434,12 @@ umlStartup(int privileged)
                         "%s/run/libvirt/uml-guest", LOCALSTATEDIR) == -1)
             goto out_of_memory;
     } else {
+        base = virGetUserConfigDirectory(uid);
+        if (!base)
+            goto error;
 
         if (virAsprintf(&uml_driver->logDir,
-                        "%s/.libvirt/uml/log", userdir) == -1)
-            goto out_of_memory;
-
-        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1)
+                        "%s/uml/log", base) == -1)
             goto out_of_memory;
 
         if (virAsprintf(&uml_driver->monitorDir,
@@ -447,7 +447,7 @@ umlStartup(int privileged)
             goto out_of_memory;
     }
 
-    /* Configuration paths are either ~/.libvirt/uml/... (session) or
+    /* Configuration paths are either $XDG_CONFIG_HOME/libvirt/uml/... (session) or
      * /etc/libvirt/uml/... (system).
      */
     if (virAsprintf(&uml_driver->configDir, "%s/uml", base) == -1)
diff --git a/src/util/util.c b/src/util/util.c
index 48358b2..447b7b7 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -665,6 +665,12 @@ char *virFindFileInPath(const char *file)
     return fullpath;
 }
 
+bool virFileIsDir(const char *path)
+{
+    struct stat s;
+    return (stat (path, &s) == 0) && S_ISDIR (s.st_mode);
+}
+
 bool virFileExists(const char *path)
 {
     return access(path, F_OK) == 0;
@@ -2304,6 +2310,67 @@ char *virGetUserDirectory(uid_t uid)
     return virGetUserEnt(uid, VIR_USER_ENT_DIRECTORY);
 }
 
+static char *virGetXDGDirectory(uid_t uid, const char *xdgenvname, const char *xdgdefdir)
+{
+    char *path = NULL;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    if (uid == getuid ())
+        path = getenv(xdgenvname);
+
+    if (path && path[0]) {
+        virBufferAsprintf(&buf, "%s/libvirt/", path);
+    } else {
+        char *home;
+        home = virGetUserEnt(uid, VIR_USER_ENT_DIRECTORY);
+        virBufferAsprintf(&buf, "%s/%s/libvirt/", home, xdgdefdir);
+        VIR_FREE(home);
+    }
+    VIR_FREE(path);
+
+    if (virBufferError(&buf)) {
+        virBufferFreeAndReset(&buf);
+        virReportOOMError();
+        return NULL;
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
+char *virGetUserConfigDirectory(uid_t uid)
+{
+    return virGetXDGDirectory(uid, "XDG_CONFIG_HOME", ".config");
+}
+
+char *virGetUserCacheDirectory(uid_t uid)
+{
+     return virGetXDGDirectory(uid, "XDG_CACHE_HOME", ".cache");
+}
+
+char *virGetUserRuntimeDirectory(uid_t uid)
+{
+    char *path = NULL;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    if (uid == getuid ())
+        path = getenv("XDG_RUNTIME_DIR");
+
+    if (!path || !path[0]) {
+        return virGetUserCacheDirectory(uid);
+    } else {
+        virBufferAsprintf(&buf, "%s/libvirt/", path);
+        VIR_FREE(path);
+
+        if (virBufferError(&buf)) {
+            virBufferFreeAndReset(&buf);
+            virReportOOMError();
+            return NULL;
+        }
+
+        return virBufferContentAndReset(&buf);
+    }
+}
+
 char *virGetUserName(uid_t uid)
 {
     return virGetUserEnt(uid, VIR_USER_ENT_NAME);
diff --git a/src/util/util.h b/src/util/util.h
index 85e8bd6..f5fa876 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -85,6 +85,7 @@ int virFileIsLink(const char *linkpath)
 
 char *virFindFileInPath(const char *file);
 
+bool virFileIsDir (const char *file) ATTRIBUTE_NONNULL(1);
 bool virFileExists(const char *file) ATTRIBUTE_NONNULL(1);
 bool virFileIsExecutable(const char *file) ATTRIBUTE_NONNULL(1);
 
@@ -228,6 +229,9 @@ char *virGetHostname(virConnectPtr conn);
 int virKillProcess(pid_t pid, int sig);
 
 char *virGetUserDirectory(uid_t uid);
+char *virGetUserConfigDirectory(uid_t uid);
+char *virGetUserCacheDirectory(uid_t uid);
+char *virGetUserRuntimeDirectory(uid_t uid);
 char *virGetUserName(uid_t uid);
 char *virGetGroupName(gid_t gid);
 int virGetUserID(const char *name,
diff --git a/src/util/virauth.c b/src/util/virauth.c
index c59c55a..92ecb7c 100644
--- a/src/util/virauth.c
+++ b/src/util/virauth.c
@@ -65,10 +65,10 @@ int virAuthGetConfigFilePath(virConnectPtr conn,
         }
     }
 
-    if (!(userdir = virGetUserDirectory(geteuid())))
+    if (!(userdir = virGetUserConfigDirectory(geteuid())))
         goto cleanup;
 
-    if (virAsprintf(path, "%s/.libvirt/auth.conf", userdir) < 0)
+    if (virAsprintf(path, "%s/auth.conf", userdir) < 0)
         goto no_memory;
 
     VIR_DEBUG("Checking for readability of '%s'", *path);
diff --git a/tools/virsh.c b/tools/virsh.c
index 1207ac9..2ae9b71 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -19864,15 +19864,15 @@ vshReadlineInit(vshControl *ctl)
     /* Limit the total size of the history buffer */
     stifle_history(500);
 
-    /* Prepare to read/write history from/to the ~/.virsh/history file */
-    userdir = virGetUserDirectory(getuid());
+    /* Prepare to read/write history from/to the $XDG_CACHE_HOME/virsh/history file */
+    userdir = virGetUserCacheDirectory(getuid());
 
     if (userdir == NULL) {
         vshError(ctl, "%s", _("Could not determine home directory"));
         return -1;
     }
 
-    if (virAsprintf(&ctl->historydir, "%s/.virsh", userdir) < 0) {
+    if (virAsprintf(&ctl->historydir, "%s/virsh", userdir) < 0) {
         vshError(ctl, "%s", _("Out of memory"));
         VIR_FREE(userdir);
         return -1;
-- 
1.7.10




More information about the libvir-list mailing list