[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libvir] [patch 7/9] Add autostart QEMU implementation



Actually implement the autostart API in qemud by creating
symlinks in the autostart directories.

Signed-off-by: Mark McLoughlin <markmc redhat com>

Index: libvirt/qemud/internal.h
===================================================================
--- libvirt.orig/qemud/internal.h
+++ libvirt/qemud/internal.h
@@ -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: libvirt/qemud/conf.c
===================================================================
--- libvirt.orig/qemud/conf.c
+++ libvirt/qemud/conf.c
@@ -137,7 +137,7 @@ qemudMakeConfigPath(const char *configDi
     return 0;
 }
 
-static int
+int
 qemudEnsureDir(const char *path)
 {
     struct stat st;
@@ -1287,6 +1287,14 @@ qemudSaveVMDef(struct qemud_server *serv
                              "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 
                              "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);
@@ -1735,11 +1751,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;
 
@@ -1765,6 +1875,11 @@ qemudLoadConfig(struct qemud_server *ser
     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;
 }
 
@@ -1772,7 +1887,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;
 
@@ -1798,12 +1914,18 @@ qemudLoadNetworkConfig(struct qemud_serv
     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;
@@ -1819,6 +1941,7 @@ int qemudScanConfigDir(struct qemud_serv
     while ((entry = readdir(dir))) {
         char xml[QEMUD_MAX_XML_LEN];
         char path[PATH_MAX];
+        char autostartLink[PATH_MAX];
 
         if (entry->d_name[0] == '.')
             continue;
@@ -1829,13 +1952,19 @@ int qemudScanConfigDir(struct qemud_serv
             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);
@@ -1845,9 +1974,9 @@ int qemudScanConfigDir(struct qemud_serv
 
 /* 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: libvirt/qemud/driver.c
===================================================================
--- libvirt.orig/qemud/driver.c
+++ libvirt/qemud/driver.c
@@ -502,7 +502,12 @@ int qemudDomainUndefine(struct qemud_ser
     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
     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_se
     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 qemu
     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: libvirt/qemud/qemud.c
===================================================================
--- libvirt.orig/qemud/qemud.c
+++ libvirt/qemud/qemud.c
@@ -357,6 +357,8 @@ static int qemudListenUnix(struct qemud_
 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 *qemudInitial
     roSockname[0] = '\0';
 
     if (qemudInitPaths(sys, server->configDir, server->networkConfigDir,
+                       server->autostartDir, server->networkAutostartDir,
                        sockname, roSockname, PATH_MAX) < 0)
         goto cleanup;
 
Index: libvirt/qemud/conf.h
===================================================================
--- libvirt.orig/qemud/conf.h
+++ libvirt/qemud/conf.h
@@ -34,6 +34,7 @@ int         qemudScanConfigs            
 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);

-- 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]