Index: src/openvz_conf.c
===================================================================
RCS file: /data/cvs/libvirt/src/openvz_conf.c,v
retrieving revision 1.4
diff -u -r1.4 openvz_conf.c
--- src/openvz_conf.c	9 Aug 2007 20:19:12 -0000	1.4
+++ src/openvz_conf.c	23 Aug 2007 08:39:27 -0000
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2006, 2007 Binary Karma
  * Copyright (C) 2006 Shuveb Hussain
+ * Copyright (C) 2007 Anoop Joe Cyriac
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -18,7 +19,10 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
  *
- * Author: Shuveb Hussain <shuveb@binarykarma.com>
+ * Authors: 
+ * Shuveb Hussain <shuveb@binarykarma.com>
+ * Anoop Joe Cyriac <anoop@binarykarma.com>
+ *
  */
 
 #ifdef WITH_OPENVZ
@@ -31,6 +35,10 @@
 #include <dirent.h>
 #include <strings.h>
 #include <time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
 
 #include <libxml/parser.h>
 #include <libxml/tree.h>
@@ -39,11 +47,21 @@
 
 #include <libvirt/virterror.h>
 
-#include "openvz_conf.h"
 #include "openvz_driver.h"
+#include "openvz_conf.h"
 #include "uuid.h"
 #include "buf.h"
 
+#include <string.h>
+
+static char *openvzLocateConfDir(void);
+static void error (virConnectPtr conn, virErrorNumber code, const char *info);
+static struct openvz_vm_def *openvzParseXML(virConnectPtr conn, xmlDocPtr xml);
+static int openvzGetVPSUUID(int vpsid, char *uuidbuf);
+static int openvzSetUUID(int vpsid);
+static struct openvz_vm *openvzLoadConfig(struct openvz_driver *driver,
+                                          const char *path,
+                                          const char *xmlStr);
 
 /* For errors internal to this library. */
 static void
@@ -72,11 +90,11 @@
 
 struct openvz_vm 
 *openvzFindVMByUUID(const struct openvz_driver *driver,
-                                   const unsigned char *uuid) {
+                   		   const unsigned char *uuid) {
     struct openvz_vm *vm = driver->vms;
 
     while (vm) {
-        if (!memcmp(vm->vmdef->uuid, uuid, VIR_UUID_BUFLEN))
+        if (!memcmp(vm->vmdef->uuid, uuid, OPENVZ_UUID_MAX))
             return vm;
         vm = vm->next;
     }
@@ -98,30 +116,179 @@
     return NULL;
 }
 
-/* Free all memory associated with a struct openvz_vm object */
-void 
-openvzFreeVMDef(struct openvz_vm_def *def) {
-    struct ovz_quota *quota = def->fs.quota;
-    struct ovz_ip *ip = def->net.ips;
-    struct ovz_ns *ns = def->net.ns;
-
-    while (quota) {
-        struct ovz_quota *prev = quota;
-        quota = quota->next;
-        free(prev);
-    }
-    while (ip) {
-        struct ovz_ip *prev = ip;
-        ip = ip->next;
-        free(prev);
-    }
-    while (ns) {
-        struct ovz_ns *prev = ns;
-        ns = ns->next;
-        free(prev);
+int
+strtoI(char *str)
+{
+    int base = 10;
+    char *endptr;
+    int val;
+
+    val = (int) strtol(str, &endptr, base);
+
+    /* Check for various possible errors */
+    if ((endptr == str)         /* "No digits were found" */
+        ||((*endptr != '\0')
+           && (*endptr !=
+               ' ')) /*"Name contain characters other than integers" */ )
+        return 0;
+    return val;
+}
+
+void
+openvzRemoveInactiveVM(struct openvz_driver *driver, struct openvz_vm *vm)
+{
+    driver->num_inactive--;
+    openvzFreeVM(driver, vm, 1);
+}
+
+/* Free all memory associated with a openvz_vm_def structure */
+void
+openvzFreeVMDef(struct openvz_vm_def *def)
+{
+    if (def) {
+        struct ovz_quota *quota = def->fs.quota;
+        struct ovz_ip *ip = def->net.ips;
+        struct ovz_ns *ns = def->net.ns;
+
+        while (quota) {
+            struct ovz_quota *prev = quota;
+
+            quota = quota->next;
+            free(prev);
+        }
+        while (ip) {
+            struct ovz_ip *prev = ip;
+
+            ip = ip->next;
+            free(prev);
+        }
+        while (ns) {
+            struct ovz_ns *prev = ns;
+
+            ns = ns->next;
+            free(prev);
+        }
+
+        free(def);
+        def = NULL;
     }
+}
+
+/* Free all memory associated with a openvz_vm structure 
+ * @checkCallee == 0 then openvzFreeDriver() is callee else some other function
+ */
+void
+openvzFreeVM(struct openvz_driver *driver, struct openvz_vm *vm,
+             int checkCallee)
+{
+    struct openvz_vm *vms;
+
+    if (!vm && !driver)
+        return;
+    vms = driver->vms;
+    if (checkCallee) {
+        if (vms == vm)
+            driver->vms = vm->next;
+        else {
+            while (vms) {
+                struct openvz_vm *prev = vms;
 
-    free(def);
+                vms = vms->next;
+                if (vms == vm) {
+                    prev->next = vms->next;
+                    break;
+                }
+            }
+        }
+    }
+    if (vms) {
+        openvzFreeVMDef(vm->vmdef);
+        free(vm);
+        vm = NULL;
+    }
+}
+
+/* Free all memory associated with a openvz_driver structure */
+void
+openvzFreeDriver(struct openvz_driver *driver)
+{
+    struct openvz_vm *next;
+
+    if (!driver)
+        return;
+    if (driver->vms)
+        for(next = driver->vms->next; driver->vms; driver->vms = next)
+            openvzFreeVM(driver, driver->vms, 0);
+    free(driver);
+    driver = NULL;
+}
+
+struct openvz_vm *
+openvzAssignVMDef(virConnectPtr conn,
+                  struct openvz_driver *driver, struct openvz_vm_def *def)
+{
+    struct openvz_vm *vm = NULL;
+
+    if (!driver || !def)
+        return NULL;
+
+    if ((vm = openvzFindVMByName(driver, def->name))) {
+        if (!openvzIsActiveVM(vm)) {
+            openvzFreeVMDef(vm->vmdef);
+            vm->vmdef = def;
+        }
+
+        return vm;
+    }
+
+    if (!(vm = calloc(1, sizeof(struct openvz_vm)))) {
+        openvzFreeVMDef(def);    
+        error(conn, VIR_ERR_NO_MEMORY, "vm");
+        return NULL;
+    }
+
+    vm->vpsid = -1;             // -1 needed for to represent inactiveness of domain before 'start'
+    vm->status = VIR_DOMAIN_SHUTOFF;
+    vm->vmdef = def;
+    vm->next = driver->vms;
+
+    driver->vms = vm;
+    driver->num_inactive++;
+
+    return vm;
+}
+
+struct openvz_vm_def 
+*openvzParseVMDef(virConnectPtr conn,
+                 const char *xmlStr, const char *displayName)
+{
+    xmlDocPtr xml;
+    struct openvz_vm_def *def = NULL;
+
+    if (!
+        (xml =
+         xmlReadDoc(BAD_CAST xmlStr,
+                    displayName ? displayName : "domain.xml", NULL,
+                    XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOERROR |
+                    XML_PARSE_NOWARNING))) {
+        error(conn, VIR_ERR_XML_ERROR, NULL);
+        return NULL;
+    }
+    if (!(xml->name = calloc(1, PATH_MAX))) {
+        openvzLog(OPENVZ_ERR,
+                  "Error in allocating memory to store xml URI");
+        xmlFreeDoc(xml);
+        return NULL;
+    }
+    if (displayName)
+        strncpy(xml->name, displayName, PATH_MAX - 1);
+    else
+        strncpy(xml->name, "domain.xml", PATH_MAX - 1);
+
+    def = openvzParseXML(conn, xml);
+    xmlFreeDoc(xml);
+
+    return def;
 }
 
 /*
@@ -136,6 +303,8 @@
     xmlXPathContextPtr ctxt = NULL;
     xmlXPathObjectPtr obj = NULL;
     struct openvz_vm_def *def;
+    struct ovz_ip *ovzIp;
+    struct ovz_ns *ovzNs;
 
     if (!(def = calloc(1, sizeof(struct openvz_vm_def)))) {
         error(conn, VIR_ERR_NO_MEMORY, "xmlXPathContext");
@@ -155,8 +324,7 @@
         goto bail_out;
     }
 
-
-    /* Find out what type of QEMU virtualization to use */
+    /* Find out what type of OPENVZ virtualization to use */
     if (!(prop = xmlGetProp(root, BAD_CAST "type"))) {
         error(conn, VIR_ERR_INTERNAL_ERROR, "missing domain type attribute");
         goto bail_out;
@@ -171,16 +339,17 @@
 
     /* Extract domain name */
     obj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", ctxt);
-    if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
+    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
         (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
         error(conn, VIR_ERR_INTERNAL_ERROR,"invalid domain name");
         goto bail_out;
     }
-    if (0/* check if VPS ID is < 101 */) {
-        error(conn, VIR_ERR_INTERNAL_ERROR, "VPS ID is less than 101");
+    if (strtoI(BAD_CAST obj->stringval) < 101) {        /* rejecting VPS ID < 101 for they are reserved */
+        error(conn, VIR_ERR_INTERNAL_ERROR,
+              "VPS ID Error (must be an integer greater than 101");
         goto bail_out;
     }
-    strcpy(def->name, (const char *)obj->stringval);
+    strncpy(def->name, (const char *) obj->stringval, OPENVZ_NAME_MAX);
     xmlXPathFreeObject(obj);
 
     /* Extract domain uuid */
@@ -188,9 +357,10 @@
     if ((obj == NULL) || (obj->type != XPATH_STRING) ||
         (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
         int err;
+
         if ((err = virUUIDGenerate(def->uuid))) {
             error(conn, VIR_ERR_INTERNAL_ERROR,
-                             "Failed to generate UUID");
+		    	     "Failed to generate UUID");
             goto bail_out;
         }
     } else if (virUUIDParse((const char *)obj->stringval, def->uuid) < 0) {
@@ -200,19 +370,165 @@
     xmlXPathFreeObject(obj);
 
     /* Extract filesystem info */
-    obj = xmlXPathEval(BAD_CAST "string(/domain/filesystem/template[1])", ctxt);
+    obj =
+        xmlXPathEval(BAD_CAST
+                     "string(/domain/container/filesystem/template[1])",
+                     ctxt);
     if ((obj == NULL) || (obj->type != XPATH_STRING) ||
-        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+	(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
         error(conn, VIR_ERR_OS_TYPE, NULL);
         goto bail_out;
     }
-    strcpy(def->fs.tmpl, (const char *)obj->stringval);
+    strncpy(def->fs.tmpl, (const char *) obj->stringval, OPENVZ_TMPL_MAX);
     xmlXPathFreeObject(obj);
 
     /* TODO Add quota processing here */
 
     /* TODO analysis of the network devices */
 
+
+    /*          Extract network                 */
+    /*              Extract ipaddress               */
+    obj =
+        xmlXPathEval(BAD_CAST
+                     "string(/domain/container/network/ipaddress[1])",
+                     ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING)
+        || (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+
+        openvzLog(OPENVZ_WARN,
+                  "No IP address in the given xml config file '%s'",
+                  xml->name);
+    }
+    if (xmlStrlen(obj->stringval) >= (OPENVZ_IP_MAX)) {
+        char errorMessage[OPENVZ_MAX_ERROR_LEN];
+
+        snprintf(errorMessage, OPENVZ_MAX_ERROR_LEN - 1, "%s",
+                 "ipaddress length too long");
+        error(conn, VIR_ERR_INTERNAL_ERROR, errorMessage);
+        goto bail_out;
+    }
+    if (!(ovzIp = calloc(1, sizeof(struct ovz_ip)))) {
+        openvzLog(OPENVZ_ERR,
+                  "Failed to Create Memory for 'ovz_ip' structure");
+        goto bail_out;
+    }
+    strncpy(ovzIp->ip, (const char *) obj->stringval, OPENVZ_IP_MAX);
+    def->net.ips = ovzIp;
+    xmlXPathFreeObject(obj);
+
+    /*              Extract netmask                 */
+    obj =
+        xmlXPathEval(BAD_CAST
+                     "string(/domain/container/network/netmask[1])", ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING)
+        || (obj->stringval == NULL) || (obj->stringval[0] == 0))
+        openvzLog(OPENVZ_WARN,
+                  "No Netmask address in the given xml config file '%s'",
+                  xml->name);
+    if (strlen((const char *) obj->stringval) >= (OPENVZ_IP_MAX)) {
+        char errorMessage[OPENVZ_MAX_ERROR_LEN];
+
+        snprintf(errorMessage, OPENVZ_MAX_ERROR_LEN - 1, "%s",
+                 "netmask length too long");
+        error(conn, VIR_ERR_INTERNAL_ERROR, errorMessage);
+        goto bail_out;
+    }
+    strncpy(def->net.ips->netmask, (const char *) obj->stringval,
+            OPENVZ_IP_MAX);
+    xmlXPathFreeObject(obj);
+
+    /*              Extract hostname                */
+    obj =
+        xmlXPathEval(BAD_CAST
+                     "string(/domain/container/network/hostname[1])",
+                     ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING)
+        || (obj->stringval == NULL) || (obj->stringval[0] == 0))
+        openvzLog(OPENVZ_WARN,
+                  "No hostname in the given xml config file '%s'",
+                  xml->name);
+    if (strlen((const char *) obj->stringval) >= (OPENVZ_HOSTNAME_MAX - 1)) {
+        char errorMessage[OPENVZ_MAX_ERROR_LEN];
+
+        snprintf(errorMessage, OPENVZ_MAX_ERROR_LEN - 1, "%s",
+                 "hostname length too long");
+        error(conn, VIR_ERR_INTERNAL_ERROR, errorMessage);
+        goto bail_out;
+    }
+    strncpy(def->net.hostname, (const char *) obj->stringval,
+            OPENVZ_HOSTNAME_MAX - 1);
+    xmlXPathFreeObject(obj);
+
+    /*              Extract gateway         */
+    obj =
+        xmlXPathEval(BAD_CAST
+                     "string(/domain/container/network/gateway[1])", ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING)
+        || (obj->stringval == NULL) || (obj->stringval[0] == 0))
+        openvzLog(OPENVZ_WARN,
+                  "No Gateway address in the given xml config file '%s'",
+                  xml->name);
+    if (strlen((const char *) obj->stringval) >= (OPENVZ_IP_MAX)) {
+        char errorMessage[OPENVZ_MAX_ERROR_LEN];
+
+        snprintf(errorMessage, OPENVZ_MAX_ERROR_LEN - 1, "%s",
+                 "gateway length too long");
+        error(conn, VIR_ERR_INTERNAL_ERROR, errorMessage);
+        goto bail_out;
+    }
+    strncpy(def->net.def_gw, (const char *) obj->stringval, OPENVZ_IP_MAX);
+    xmlXPathFreeObject(obj);
+
+    /*              Extract nameserver      */
+    obj =
+        xmlXPathEval(BAD_CAST
+                     "string(/domain/container/network/nameserver[1])",
+                     ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING)
+        || (obj->stringval == NULL) || (obj->stringval[0] == 0))
+        openvzLog(OPENVZ_WARN,
+                  "No Nameserver address inthe given xml config file '%s'",
+                  xml->name);
+    if (strlen((const char *) obj->stringval) >= (OPENVZ_IP_MAX)) {
+        char errorMessage[OPENVZ_MAX_ERROR_LEN];
+
+        snprintf(errorMessage, OPENVZ_MAX_ERROR_LEN - 1, "%s",
+                 "nameserver length too long");
+        error(conn, VIR_ERR_INTERNAL_ERROR, errorMessage);
+        goto bail_out;
+    }
+    if (!(ovzNs = calloc(1, sizeof(struct ovz_ns)))) {
+        openvzLog(OPENVZ_ERR,
+                  "Failed to Create Memory for 'ovz_ns' structure");
+        goto bail_out;
+    }
+    strncpy(ovzNs->ip, (const char *) obj->stringval, OPENVZ_IP_MAX);
+    def->net.ns = ovzNs;
+    xmlXPathFreeObject(obj);
+
+    /*          Extract profile         */
+    obj =
+        xmlXPathEval(BAD_CAST "string(/domain/container/profile[1])",
+                     ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING)
+        || (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+        error(conn, VIR_ERR_INTERNAL_ERROR, NULL);
+        goto bail_out;
+    }
+    if (strlen((const char *) obj->stringval) >= (OPENVZ_PROFILE_MAX - 1)) {
+        char errorMessage[OPENVZ_MAX_ERROR_LEN];
+
+        snprintf(errorMessage, OPENVZ_MAX_ERROR_LEN - 1, "%s",
+                 "profile length too long");
+        error(conn, VIR_ERR_INTERNAL_ERROR, errorMessage);
+        goto bail_out;
+    }
+    strncpy(def->profile, (const char *) obj->stringval,
+            OPENVZ_PROFILE_MAX - 1);
+    xmlXPathFreeObject(obj);
+
+
     xmlXPathFreeContext(ctxt);
 
     return def;
@@ -225,28 +541,8 @@
     if (ctxt)
         xmlXPathFreeContext(ctxt);
     openvzFreeVMDef(def);
-    return NULL;
-}
 
-struct openvz_vm_def *
-openvzParseVMDef(virConnectPtr conn,
-                const char *xmlStr,
-                const char *displayName) {
-    xmlDocPtr xml;
-    struct openvz_vm_def *def = NULL;
-
-    if (!(xml = xmlReadDoc(BAD_CAST xmlStr, displayName ? displayName : "domain.xml", NULL,
-                           XML_PARSE_NOENT | XML_PARSE_NONET |
-                           XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
-        error(conn, VIR_ERR_XML_ERROR, NULL);
-        return NULL;
-    }
-
-    def = openvzParseXML(conn, xml);
-
-    xmlFreeDoc(xml);
-
-    return def;
+    return NULL;
 }
 
 struct openvz_vm *
@@ -264,19 +560,19 @@
     driver = conn->privateData;
     driver->num_active = 0;
     driver->num_inactive = 0;
-    
+
     if((fp = popen(VZLIST " -a -ovpsid,status -H 2>/dev/null", "r")) == NULL) {
         error(conn, VIR_ERR_INTERNAL_ERROR, "popen failed");
         return NULL;
     }
-    pnext = &vm; 
-    while(!feof(fp)) { 
-        *pnext = malloc(sizeof(struct openvz_vm));
-        if(!*pnext) {
+    pnext = &vm;
+    while(!feof(fp)) {
+        *pnext = calloc(1, sizeof(struct openvz_vm));
+        if (!*pnext) {
             error(conn, VIR_ERR_INTERNAL_ERROR, "malloc failed");
             return NULL;
         }
-        
+
         if(!vm)
             vm = *pnext;
 
@@ -286,19 +582,19 @@
             driver->num_active ++;
             (*pnext)->vpsid = veid;
         }
-        else {
+       	else {
             (*pnext)->status = VIR_DOMAIN_SHUTOFF;
             driver->num_inactive ++;
             (*pnext)->vpsid = -1;    /* inactive domains don't have their ID set in libvirt,
                                         thought this doesn't make sense for OpenVZ */
         }
 
-        vmdef = malloc(sizeof(struct openvz_vm_def));
+        vmdef = calloc(1, sizeof(struct openvz_vm_def));
         if(!vmdef) {
             error(conn, VIR_ERR_INTERNAL_ERROR, "malloc failed");
             return NULL;
         }
-        
+
         snprintf(vmdef->name, OPENVZ_NAME_MAX,  "%i", veid);
         openvzGetVPSUUID(veid, uuidstr);
         ret = virUUIDParse(uuidstr, vmdef->uuid);
@@ -400,8 +696,8 @@
 openvzSetUUID(int vpsid)
 {
     char conf_file[PATH_MAX];
-    char uuidstr[VIR_UUID_STRING_BUFLEN];
-    unsigned char uuid[VIR_UUID_BUFLEN];
+    char uuid[VIR_UUID_STRING_BUFLEN];
+    unsigned char new_uuid[VIR_UUID_BUFLEN];
     char *conf_dir;
     int fd, ret, i;
 
@@ -418,8 +714,10 @@
         return -1;
 
     if(uuid[0] == (int)NULL) {
-        virUUIDGenerate(uuid);
-        virUUIDFormat(uuid, uuidstr);
+        virUUIDGenerate(new_uuid);
+        bzero(uuid, VIR_UUID_STRING_BUFLEN);
+        for(i = 0; i < VIR_UUID_BUFLEN; i++)
+            sprintf(uuid + (i * 2), "%02x", (unsigned char) new_uuid[i]);
 
         lseek(fd, 0, SEEK_END);
         write(fd, "\n#UUID: ", 8);
@@ -467,4 +765,3 @@
 }
 
 #endif
-
