]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Fri Feb 23 09:03:19 IST 2007 Mark McLoughlin <markmc@redhat.com>
authorMark McLoughlin <markmc@redhat.com>
Fri, 23 Feb 2007 09:07:41 +0000 (09:07 +0000)
committerMark McLoughlin <markmc@redhat.com>
Fri, 23 Feb 2007 09:07:41 +0000 (09:07 +0000)
        * qemud/driver.c: maintain the autostart flag on disk
        using symlinks from the "autostart" directories to
        the corresponding config files.

        * qemud/internal.h: add paths to the autostart links
        to the vm/network structures and paths to the autostart
        dirs to the server struct.

        * qemud/qemud.c: initialize the server autostart dir
        patches.

        * qemud/conf.h: expose qemudEnsureDir()

        * qemud/conf.c: check the autostart symlinks when
        loading config files at startup.

ChangeLog
qemud/conf.c
qemud/conf.h
qemud/driver.c
qemud/internal.h
qemud/qemud.c

index ed0057ac21d863e72aef206009d65f21aff195f9..449f04ae8a6961276e12329b12621a7108042210 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+Fri Feb 23 09:03:19 IST 2007 Mark McLoughlin <markmc@redhat.com>
+
+       * qemud/driver.c: maintain the autostart flag on disk
+       using symlinks from the "autostart" directories to
+       the corresponding config files.
+
+       * qemud/internal.h: add paths to the autostart links
+       to the vm/network structures and paths to the autostart
+       dirs to the server struct.
+
+       * qemud/qemud.c: initialize the server autostart dir
+       patches.
+
+       * qemud/conf.h: expose qemudEnsureDir()
+
+       * qemud/conf.c: check the autostart symlinks when
+       loading config files at startup.
+       
 Fri Feb 23 09:00:13 IST 2007 Mark McLoughlin <markmc@redhat.com>
 
        * qemud/protocol.h: add the (domain/network)(Get/Set)Autostart
index 3f9a6a77e3495883831baa4f894bb5a14de21a55..d662c58f815e1ec152e4246298ed100ce97b3908 100644 (file)
@@ -137,7 +137,7 @@ qemudMakeConfigPath(const char *configDir,
     return 0;
 }
 
-static int
+int
 qemudEnsureDir(const char *path)
 {
     struct stat st;
@@ -1287,6 +1287,14 @@ qemudSaveVMDef(struct qemud_server *server,
                              "cannot construct config file path");
             return -1;
         }
+
+        if (qemudMakeConfigPath(server->autostartDir, def->name, ".xml",
+                                vm->autostartLink, PATH_MAX) < 0) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "cannot construct autostart link path");
+            vm->configFile[0] = '\0';
+            return -1;
+        }
     }
 
     return qemudSaveConfig(server, vm, def);
@@ -1666,6 +1674,14 @@ qemudSaveNetworkDef(struct qemud_server *server,
                              "cannot construct config file path");
             return -1;
         }
+
+        if (qemudMakeConfigPath(server->networkAutostartDir, def->name, ".xml",
+                                network->autostartLink, PATH_MAX) < 0) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "cannot construct autostart link path");
+            network->configFile[0] = '\0';
+            return -1;
+        }
     }
 
     return qemudSaveNetworkConfig(server, network, def);
@@ -1734,11 +1750,105 @@ compareFileToNameSuffix(const char *file,
         return 0;
 }
 
+static int
+checkLinkPointsTo(const char *checkLink,
+                  const char *checkDest)
+{
+    char dest[PATH_MAX];
+    char real[PATH_MAX];
+    char checkReal[PATH_MAX];
+    int n;
+    int passed = 0;
+
+    /* read the link destination */
+    if ((n = readlink(checkLink, dest, PATH_MAX)) < 0) {
+        switch (errno) {
+        case ENOENT:
+        case ENOTDIR:
+            break;
+
+        case EINVAL:
+            qemudLog(QEMUD_WARN, "Autostart file '%s' is not a symlink",
+                     checkLink);
+            break;
+
+        default:
+            qemudLog(QEMUD_WARN, "Failed to read autostart symlink '%s': %s",
+                     checkLink, strerror(errno));
+            break;
+        }
+
+        goto failed;
+    } else if (n >= PATH_MAX) {
+        qemudLog(QEMUD_WARN, "Symlink '%s' contents too long to fit in buffer",
+                 checkLink);
+        goto failed;
+    }
+
+    dest[n] = '\0';
+
+    /* make absolute */
+    if (dest[0] != '/') {
+        char dir[PATH_MAX];
+        char tmp[PATH_MAX];
+        char *p;
+
+        strncpy(dir, checkLink, PATH_MAX);
+        dir[PATH_MAX] = '\0';
+
+        if (!(p = strrchr(dir, '/'))) {
+            qemudLog(QEMUD_WARN, "Symlink path '%s' is not absolute", checkLink);
+            goto failed;
+        }
+
+        if (p == dir) /* handle unlikely root dir case */
+            p++;
+
+        *p = '\0';
+
+        if (qemudMakeConfigPath(dir, dest, NULL, tmp, PATH_MAX) < 0) {
+            qemudLog(QEMUD_WARN, "Path '%s/%s' is too long", dir, dest);
+            goto failed;
+        }
+
+        strncpy(dest, tmp, PATH_MAX);
+        dest[PATH_MAX] = '\0';
+    }
+
+    /* canonicalize both paths */
+    if (!realpath(dest, real)) {
+        qemudLog(QEMUD_WARN, "Failed to expand path '%s' :%s",
+                 dest, strerror(errno));
+        strncpy(real, dest, PATH_MAX);
+        real[PATH_MAX] = '\0';
+    }
+
+    if (!realpath(checkDest, checkReal)) {
+        qemudLog(QEMUD_WARN, "Failed to expand path '%s' :%s",
+                 checkDest, strerror(errno));
+        strncpy(checkReal, checkDest, PATH_MAX);
+        checkReal[PATH_MAX] = '\0';
+    }
+
+    /* compare */
+    if (strcmp(checkReal, real) != 0) {
+        qemudLog(QEMUD_WARN, "Autostart link '%s' is not a symlink to '%s', ignoring",
+                 checkLink, checkReal);
+        goto failed;
+    }
+
+    passed = 1;
+
+ failed:
+    return passed;
+}
+
 static struct qemud_vm *
 qemudLoadConfig(struct qemud_server *server,
                 const char *file,
                 const char *path,
-                const char *xml) {
+                const char *xml,
+                const char *autostartLink) {
     struct qemud_vm_def *def;
     struct qemud_vm *vm;
 
@@ -1764,6 +1874,11 @@ qemudLoadConfig(struct qemud_server *server,
     strncpy(vm->configFile, path, PATH_MAX);
     vm->configFile[PATH_MAX-1] = '\0';
 
+    strncpy(vm->autostartLink, autostartLink, PATH_MAX);
+    vm->autostartLink[PATH_MAX-1] = '\0';
+
+    vm->autostart = checkLinkPointsTo(vm->autostartLink, vm->configFile);
+
     return vm;
 }
 
@@ -1771,7 +1886,8 @@ static struct qemud_network *
 qemudLoadNetworkConfig(struct qemud_server *server,
                        const char *file,
                        const char *path,
-                       const char *xml) {
+                       const char *xml,
+                       const char *autostartLink) {
     struct qemud_network_def *def;
     struct qemud_network *network;
 
@@ -1797,12 +1913,18 @@ qemudLoadNetworkConfig(struct qemud_server *server,
     strncpy(network->configFile, path, PATH_MAX);
     network->configFile[PATH_MAX-1] = '\0';
 
+    strncpy(network->autostartLink, autostartLink, PATH_MAX);
+    network->autostartLink[PATH_MAX-1] = '\0';
+
+    network->autostart = checkLinkPointsTo(network->autostartLink, network->configFile);
+
     return network;
 }
 
 static
 int qemudScanConfigDir(struct qemud_server *server,
                        const char *configDir,
+                       const char *autostartDir,
                        int isGuest) {
     DIR *dir;
     struct dirent *entry;
@@ -1818,6 +1940,7 @@ int qemudScanConfigDir(struct qemud_server *server,
     while ((entry = readdir(dir))) {
         char xml[QEMUD_MAX_XML_LEN];
         char path[PATH_MAX];
+        char autostartLink[PATH_MAX];
 
         if (entry->d_name[0] == '.')
             continue;
@@ -1828,13 +1951,19 @@ int qemudScanConfigDir(struct qemud_server *server,
             continue;
         }
 
+        if (qemudMakeConfigPath(autostartDir, entry->d_name, NULL, autostartLink, PATH_MAX) < 0) {
+            qemudLog(QEMUD_WARN, "Autostart link path '%s/%s' is too long",
+                     autostartDir, entry->d_name);
+            continue;
+        }
+
         if (!qemudReadFile(path, xml, QEMUD_MAX_XML_LEN))
             continue;
 
         if (isGuest)
-            qemudLoadConfig(server, entry->d_name, path, xml);
+            qemudLoadConfig(server, entry->d_name, path, xml, autostartLink);
         else
-            qemudLoadNetworkConfig(server, entry->d_name, path, xml);
+            qemudLoadNetworkConfig(server, entry->d_name, path, xml, autostartLink);
     }
 
     closedir(dir);
@@ -1844,9 +1973,9 @@ int qemudScanConfigDir(struct qemud_server *server,
 
 /* Scan for all guest and network config files */
 int qemudScanConfigs(struct qemud_server *server) {
-    if (qemudScanConfigDir(server, server->configDir, 1) < 0)
+    if (qemudScanConfigDir(server, server->configDir, server->autostartDir, 1) < 0)
         return -1;
-    return qemudScanConfigDir(server, server->networkConfigDir, 0);
+    return qemudScanConfigDir(server, server->networkConfigDir, server->networkAutostartDir, 0);
 }
 
 /* Simple grow-on-demand string buffer */
index 548484cc20c7f90aab1039289a1a157ec7d40247..9069ee684203085ce1bd8460d482cc633381c357 100644 (file)
@@ -34,6 +34,7 @@ int         qemudScanConfigs            (struct qemud_server *server);
 int         qemudDeleteConfig           (struct qemud_server *server,
                                          const char *configFile,
                                          const char *name);
+int         qemudEnsureDir              (const char *path);
 
 void        qemudFreeVMDef              (struct qemud_vm_def *vm);
 void        qemudFreeVM                 (struct qemud_vm *vm);
index 8aa049f0265ec3f15435953e338fdfbdad3c3175..1aa3b396a4b07215a32d020e1c26260dce0a353b 100644 (file)
@@ -502,7 +502,12 @@ int qemudDomainUndefine(struct qemud_server *server, const unsigned char *uuid)
     if (qemudDeleteConfig(server, vm->configFile, vm->def->name) < 0)
         return -1;
 
+    if (unlink(vm->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR)
+        qemudLog(QEMUD_WARN, "Failed to delete autostart link '%s': %s",
+                 vm->autostartLink, strerror(errno));
+
     vm->configFile[0] = '\0';
+    vm->autostartLink[0] = '\0';
 
     qemudRemoveInactiveVM(server, vm);
 
@@ -539,6 +544,31 @@ int qemudDomainSetAutostart(struct qemud_server *server,
     if (vm->autostart == autostart)
         return 0;
 
+    if (autostart) {
+        int err;
+
+        if ((err = qemudEnsureDir(server->autostartDir))) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "cannot create autostart directory %s: %s",
+                             server->autostartDir, strerror(err));
+            return -1;
+        }
+
+        if (symlink(vm->configFile, vm->autostartLink) < 0) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "Failed to create symlink '%s' to '%s': %s",
+                             vm->autostartLink, vm->configFile, strerror(errno));
+            return -1;
+        }
+    } else {
+        if (unlink(vm->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "Failed to delete symlink '%s': %s",
+                             vm->autostartLink, strerror(errno));
+            return -1;
+        }
+    }
+
     vm->autostart = autostart;
 
     return 0;
@@ -657,7 +687,12 @@ int qemudNetworkUndefine(struct qemud_server *server, const unsigned char *uuid)
     if (qemudDeleteConfig(server, network->configFile, network->def->name) < 0)
         return -1;
 
+    if (unlink(network->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR)
+        qemudLog(QEMUD_WARN, "Failed to delete autostart link '%s': %s",
+                 network->autostartLink, strerror(errno));
+
     network->configFile[0] = '\0';
+    network->autostartLink[0] = '\0';
 
     qemudRemoveInactiveNetwork(server, network);
 
@@ -750,6 +785,31 @@ int qemudNetworkSetAutostart(struct qemud_server *server,
     if (network->autostart == autostart)
         return 0;
 
+    if (autostart) {
+        int err;
+
+        if ((err = qemudEnsureDir(server->networkAutostartDir))) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "cannot create autostart directory %s: %s",
+                             server->networkAutostartDir, strerror(err));
+            return -1;
+        }
+
+        if (symlink(network->configFile, network->autostartLink) < 0) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "Failed to create symlink '%s' to '%s': %s",
+                             network->autostartLink, network->configFile, strerror(errno));
+            return -1;
+        }
+    } else {
+        if (unlink(network->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "Failed to delete symlink '%s': %s",
+                             network->autostartLink, strerror(errno));
+            return -1;
+        }
+    }
+
     network->autostart = autostart;
 
     return 0;
index e575d5bb7ca7daf1b61164a6b89a3ebc8e12d28f..e43222fff53aced87d428a5712530382e3c5f464 100644 (file)
@@ -205,6 +205,7 @@ struct qemud_vm {
     int ntapfds;
 
     char configFile[PATH_MAX];
+    char autostartLink[PATH_MAX];
 
     struct qemud_vm_def *def; /* The current definition */
     struct qemud_vm_def *newDef; /* New definition to activate at shutdown */
@@ -241,6 +242,7 @@ struct qemud_network_def {
 /* Virtual Network runtime state */
 struct qemud_network {
     char configFile[PATH_MAX];
+    char autostartLink[PATH_MAX];
 
     struct qemud_network_def *def; /* The current definition */
     struct qemud_network_def *newDef; /* New definition to activate at shutdown */
@@ -293,6 +295,8 @@ struct qemud_server {
     iptablesContext *iptables;
     char configDir[PATH_MAX];
     char networkConfigDir[PATH_MAX];
+    char autostartDir[PATH_MAX];
+    char networkAutostartDir[PATH_MAX];
     char errorMessage[QEMUD_MAX_ERROR_LEN];
     int errorCode;
     unsigned int shutdown : 1;
index 36ad1616af62b3b5979c61bc4eab414158f45f44..3961c6415e0df83f8fa25f5cd05d27c8cebe5aec 100644 (file)
@@ -357,6 +357,8 @@ static int qemudListenUnix(struct qemud_server *server,
 static int qemudInitPaths(int sys,
                           char *configDir,
                           char *networkConfigDir,
+                          char *autostartDir,
+                          char *networkAutostartDir,
                           char *sockname,
                           char *roSockname,
                           int maxlen) {
@@ -376,6 +378,12 @@ static int qemudInitPaths(int sys,
         if (snprintf(networkConfigDir, maxlen, "%s/libvirt/qemu/networks", SYSCONF_DIR) >= maxlen)
             goto snprintf_error;
 
+        if (snprintf(autostartDir, maxlen, "%s/libvirt/qemu/autostart", SYSCONF_DIR) >= maxlen)
+            goto snprintf_error;
+
+        if (snprintf(networkAutostartDir, maxlen, "%s/libvirt/qemu/networks/autostart", SYSCONF_DIR) >= maxlen)
+            goto snprintf_error;
+
         if (snprintf(sockname, maxlen, "%s/run/libvirt/qemud-sock", LOCAL_STATE_DIR) >= maxlen)
             goto snprintf_error;
 
@@ -400,6 +408,12 @@ static int qemudInitPaths(int sys,
         if (snprintf(networkConfigDir, maxlen, "%s/.libvirt/qemu/networks", pw->pw_dir) >= maxlen)
             goto snprintf_error;
 
+        if (snprintf(autostartDir, maxlen, "%s/.libvirt/qemu/autostart", pw->pw_dir) >= maxlen)
+            goto snprintf_error;
+
+        if (snprintf(networkAutostartDir, maxlen, "%s/.libvirt/qemu/networks/autostart", pw->pw_dir) >= maxlen)
+            goto snprintf_error;
+
         if (snprintf(sockname, maxlen, "@%s/.libvirt/qemud-sock", pw->pw_dir) >= maxlen)
             goto snprintf_error;
     }
@@ -430,6 +444,7 @@ static struct qemud_server *qemudInitialize(int sys, int sigread) {
     roSockname[0] = '\0';
 
     if (qemudInitPaths(sys, server->configDir, server->networkConfigDir,
+                       server->autostartDir, server->networkAutostartDir,
                        sockname, roSockname, PATH_MAX) < 0)
         goto cleanup;