
On Wed, Mar 19, 2008 at 11:14:31PM -0700, Dave Leskovec wrote:
This patch adds the lxc_conf source files. [...] +#define LXC_MAX_XML_LENGTH 4096
maybe up that a bit, or even better try to avoid a fixed size buffer but that can be done separately
+#define LXC_MAX_ERROR_LEN 1024 +#define LXC_DOMAIN_TYPE "linuxcontainer"
In general try to provide comments for types, even if it looks easy to figure out :-)
+typedef struct __lxc_mount lxc_mount_t; +struct __lxc_mount { + char source[PATH_MAX]; /* user's directory */ + char target[PATH_MAX]; + + lxc_mount_t *next; +}; + +typedef struct __lxc_vm_def lxc_vm_def_t; +struct __lxc_vm_def { + unsigned char uuid[VIR_UUID_BUFLEN]; + char* name; + int id; + + /* init command string */ + char init[PATH_MAX]; + + int maxMemory;
In kbytes I assume, maybe an unsigned long would be in order there...
+ /* mounts - list of mount structs */ + int nmounts; + lxc_mount_t *mounts; + + /* tty device */ + char tty[LXC_MAX_TTY_NAME]; +}; [...]
Index: b/src/lxc_conf.c [...] +static inline int lxcIsEmptyXPathStringObj(xmlXPathObjectPtr xpathObj) +{ + if ((xpathObj == NULL) || + (xpathObj->type != XPATH_STRING) || + (xpathObj->stringval == NULL) || + (xpathObj->stringval[0] == 0)) { + return 1; + } else { + return 0; + } +}
best made a convenience function exported from xml.h . I'm not sure inlining functions is really a net gain in a libvirt context, it's not like anything is time critical, but this can add up on the size of the library quicker than one would expect.
+static int lxcParseMountXML(virConnectPtr conn, xmlNodePtr nodePtr, + lxc_mount_t *lxcMount) +{ + xmlChar *fsType = NULL; + xmlNodePtr curNode; + xmlChar *mountSource = NULL; + xmlChar *mountTarget = NULL; + int strLen; + int rc = -1; + + if (NULL == (fsType = xmlGetProp(nodePtr, BAD_CAST "type"))) {
stylistic, separate the affectation and the test, more readable IMHO. And it makes more obvious the fact that the returned value need to be freed.
+ lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, + _("missing filesystem type")); + goto error; + } [...] +static int lxcParseDomainName(virConnectPtr conn, char **name, + xmlXPathContextPtr contextPtr) +{ + int rc = -1; + xmlXPathObjectPtr xpathObj = NULL; + + xpathObj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", contextPtr); + if (lxcIsEmptyXPathStringObj(xpathObj)) { + lxcError(conn, NULL, VIR_ERR_NO_NAME, NULL); + goto parse_complete; + }
Hum, why not use virXPathString() it hides the libxml2 XPath details,
+ *name = strdup((const char *)xpathObj->stringval); + if (NULL == *name) { + lxcError(conn, NULL, VIR_ERR_NO_MEMORY, NULL); + goto parse_complete; + } + + + rc = 0; + +parse_complete: + xmlXPathFreeObject(xpathObj); + return rc; +}
and simplifies the cleanup/exit, no strdup, no xmlXPathFreeObject, I guess each time you use the combo xmlXPathEval/lxcIsEmptyXPathStringObj a virXPathString call would be clearer and more in line with other libvirt code
+static int lxcParseDomainMounts(virConnectPtr conn, + lxc_mount_t **mounts, + xmlXPathContextPtr contextPtr) +{ + int rc = -1; + xmlXPathObjectPtr xpathObj = NULL; + int i; + lxc_mount_t *mountObj; + lxc_mount_t *prevObj = NULL; + int nmounts = 0; + + xpathObj = xmlXPathEval(BAD_CAST "/domain/devices/filesystem",
Hum, I'm sure using virXPathNodeSet() would make this code clearer
+ if ((xpathObj != NULL) && + (xpathObj->type == XPATH_NODESET) && + (xpathObj->nodesetval != NULL) && + (xpathObj->nodesetval->nodeNr >= 0)) { + for (i = 0; i < xpathObj->nodesetval->nodeNr; ++i) { + mountObj = calloc(1, sizeof(lxc_mount_t)); + if (NULL == mountObj) { + lxcError(conn, NULL, VIR_ERR_NO_MEMORY, "mount"); + goto parse_complete; + } + + rc = lxcParseMountXML(conn, xpathObj->nodesetval->nodeTab[i], + mountObj); + if (0 > rc) { + free(mountObj); + goto parse_complete; + } + + /* set the linked list pointers */ + nmounts++; + mountObj->next = NULL; + if (0 == i) { + *mounts = mountObj; + } else { + prevObj->next = mountObj; + } + prevObj = mountObj; + } + } + + rc = nmounts; + +parse_complete: + xmlXPathFreeObject(xpathObj); + + return rc; +} [...] +static int lxcParseDomainMemory(virConnectPtr conn, int* memory, xmlXPathContextPtr contextPtr) +{ + int rc = -1; + xmlXPathObjectPtr xpathObj = NULL; + char *endChar = NULL; + + xpathObj = xmlXPathEval(BAD_CAST "string(/domain/memory[1])", contextPtr); + if (lxcIsEmptyXPathStringObj(xpathObj)) { + /* not an error, default to an invalid value so it's not used */ + *memory = -1; + } else { + *memory = strtoll((const char*)xpathObj->stringval, + &endChar, 10); + if ((endChar == (const char*)xpathObj->stringval) || + (*endChar != '\0')) { + lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, + _("invalid memory value")); + goto parse_complete; + } + }
use virXPathLong() and keep as a long in the structure,
+ rc = 0; [...] +static lxc_vm_def_t * lxcParseXML(virConnectPtr conn, xmlDocPtr docPtr) +{ + xmlNodePtr rootNodePtr = NULL; + xmlXPathContextPtr contextPtr = NULL; + xmlChar *xmlProp = NULL; + lxc_vm_def_t *containerDef; + + if (!(containerDef = calloc(1, sizeof(*containerDef)))) { + lxcError(conn, NULL, VIR_ERR_NO_MEMORY, "containerDef"); + return NULL; + } + + /* Prepare parser / xpath context */ + rootNodePtr = xmlDocGetRootElement(docPtr); + if ((rootNodePtr == NULL) || + (!xmlStrEqual(rootNodePtr->name, BAD_CAST "domain"))) { + lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, + _("invalid root element")); + goto error; + } + + contextPtr = xmlXPathNewContext(docPtr); + if (contextPtr == NULL) { + lxcError(conn, NULL, VIR_ERR_NO_MEMORY, "context"); + goto error; + } + + /* Verify the domain type is linuxcontainer */ + if (!(xmlProp = xmlGetProp(rootNodePtr, BAD_CAST "type"))) { + lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, + _("missing domain type")); + goto error; + } + + if (!(xmlStrEqual(xmlProp, BAD_CAST LXC_DOMAIN_TYPE))) { + lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, + _("invalid domain type")); + goto error; + } + free(xmlProp); + xmlProp = NULL;
Hum, maybe this check could be unified as a simple type = virXPathString("/domain/@type", contextPtr); and check the returned string against LXC_DOMAIN_TYPE, smaller, simpler and would insure that the root element is named domain (without namespace)
+ if ((xmlProp = xmlGetProp(rootNodePtr, BAD_CAST "id"))) { + if (0 > virStrToLong_i((char*)xmlProp, NULL, 10, &(containerDef->id))) { + lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, + "invalid domain id"); + goto error; + } + } else { + containerDef->id = -1; + } + free(xmlProp); + xmlProp = NULL;
Same with virXPathString("/domain/@id, ...)
+ if (lxcParseDomainName(conn, &(containerDef->name), contextPtr) < 0) { [...] +int lxcLoadDriverConfig(virConnectPtr conn) +{ + lxc_driver_t *driverPtr = (lxc_driver_t*)conn->privateData; + + /* Set the container configuration directory */ + driverPtr->configDir = strdup(SYSCONF_DIR "/libvirt/lxc"); + if (NULL == driverPtr->configDir) { + lxcError(conn, NULL, VIR_ERR_NO_MEMORY, "configDir"); + return -1; + } + + return 0; +}
Hum, is there something missing in that function ? [...] [...]
+int lxcLoadContainerInfo(virConnectPtr conn) +{ + int rc = -1; + lxc_driver_t *driverPtr = (lxc_driver_t*)conn->privateData; + DIR *dir; + struct dirent *dirEntry; + + if (!(dir = opendir(driverPtr->configDir))) { + if (ENOENT == errno) { + /* no config dir => no containers */ + rc = 0; + } else { + lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to open config directory: %s"), strerror(errno)); + } + + goto load_complete; + } + + while ((dirEntry = readdir(dir))) { + if (dirEntry->d_name[0] == '.') { + continue; + } + + if (!virFileHasSuffix(dirEntry->d_name, ".xml")) { + continue; + }
so container definition files are detected by a .xml suffix, maybe using something like .lxc would be more specific, not a big deal, but once it's set it's a bit annoying to change [...]
+int lxcDeleteConfig(virConnectPtr conn, + lxc_driver_t *driver ATTRIBUTE_UNUSED, + const char *configFile, + const char *name) +{ + if (!configFile[0]) { + lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, + _("no config file for %s"), name); + return -1; + }
Hum ... can we make a little bit of checking here for the file to be an absolute path and having the right prefix ?
+ if (unlink(configFile) < 0) { + lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot remove config for %s"), name); + return -1; + } + + return 0; +}
Still look fine, I could make the XPath access cleanups in a second step. Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/