From 68ef3443d4bfb2c1dacbd7266cc53c182302ceae Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Thu, 19 Jul 2007 16:22:40 +0000 Subject: [PATCH] * src/Makefile.am src/openvz_conf.c src/openvz_conf.h src/openvz_driver.c src/qemu_driver.c src/util.c src/util.h: cleanup patches from Shuveb Hussain, with new util module for common code shared between drivers. Daniel --- ChangeLog | 7 ++ include/libvirt/virterror.h | 1 + src/Makefile.am | 3 +- src/openvz_conf.c | 49 ++++----- src/openvz_conf.h | 8 +- src/openvz_driver.c | 42 +++++--- src/qemu_driver.c | 90 +---------------- src/util.c | 192 ++++++++++++++++++++++++++++++++++++ src/util.h | 26 +++++ 9 files changed, 289 insertions(+), 129 deletions(-) create mode 100644 src/util.c create mode 100644 src/util.h diff --git a/ChangeLog b/ChangeLog index 884f4699b5..a6a1a1d7e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Thu Jul 19 18:21:47 CEST 2007 Daniel Veillard + + * src/Makefile.am src/openvz_conf.c src/openvz_conf.h + src/openvz_driver.c src/qemu_driver.c src/util.c src/util.h: + cleanup patches from Shuveb Hussain, with new util module for + common code shared between drivers. + Thu Jul 19 16:35:00 BST 2007 Richard W.M. Jones * configure.in, src/xen_internal.c: Newer Xen uses diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index da115cbbe1..8e2701f47e 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -51,6 +51,7 @@ typedef enum { VIR_FROM_NET, /* Error when operating on a network */ VIR_FROM_TEST, /* Error from test driver */ VIR_FROM_REMOTE, /* Error from remote driver */ + VIR_FROM_OPENVZ, /* Error from OpenVZ driver */ } virErrorDomain; diff --git a/src/Makefile.am b/src/Makefile.am index c4bf4a2ac8..ff8e86d94e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -49,7 +49,8 @@ CLIENT_SOURCES = \ qemu_driver.c qemu_driver.h \ qemu_conf.c qemu_conf.h \ openvz_conf.c openvz_conf.h \ - openvz_driver.c openvz_driver.h + openvz_driver.c openvz_driver.h \ + util.c util.h SERVER_SOURCES = \ ../qemud/protocol.h ../qemud/protocol.c \ diff --git a/src/openvz_conf.c b/src/openvz_conf.c index 3f57bdb1e7..2dc3f6c0c0 100644 --- a/src/openvz_conf.c +++ b/src/openvz_conf.c @@ -57,7 +57,8 @@ error (virConnectPtr conn, virErrorNumber code, const char *info) errmsg, info); } -struct openvz_vm *openvzFindVMByID(const struct openvz_driver *driver, int id) { +struct openvz_vm +*openvzFindVMByID(const struct openvz_driver *driver, int id) { struct openvz_vm *vm = driver->vms; while (vm) { @@ -69,7 +70,8 @@ struct openvz_vm *openvzFindVMByID(const struct openvz_driver *driver, int id) { return NULL; } -struct openvz_vm *openvzFindVMByUUID(const struct openvz_driver *driver, +struct openvz_vm +*openvzFindVMByUUID(const struct openvz_driver *driver, const unsigned char *uuid) { struct openvz_vm *vm = driver->vms; @@ -82,7 +84,8 @@ struct openvz_vm *openvzFindVMByUUID(const struct openvz_driver *driver, return NULL; } -struct openvz_vm *openvzFindVMByName(const struct openvz_driver *driver, +struct openvz_vm +*openvzFindVMByName(const struct openvz_driver *driver, const char *name) { struct openvz_vm *vm = driver->vms; @@ -96,7 +99,8 @@ struct openvz_vm *openvzFindVMByName(const struct openvz_driver *driver, } /* Free all memory associated with a struct openvz_vm object */ -void openvzFreeVMDef(struct openvz_vm_def *def) { +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; @@ -124,8 +128,9 @@ void openvzFreeVMDef(struct openvz_vm_def *def) { * Parses a libvirt XML definition of a guest, and populates the * the openvz_vm struct with matching data about the guests config */ -static struct openvz_vm_def *openvzParseXML(virConnectPtr conn, - xmlDocPtr xml) { +static struct openvz_vm_def +*openvzParseXML(virConnectPtr conn, + xmlDocPtr xml) { xmlNodePtr root = NULL; xmlChar *prop = NULL; xmlXPathContextPtr ctxt = NULL; @@ -249,7 +254,7 @@ openvzGetVPSInfo(virConnectPtr conn) { FILE *fp; int veid, ret; char status[16]; - char uuidstr[(VIR_UUID_BUFLEN * 2) + 1]; + char uuidstr[VIR_UUID_STRING_BUFLEN]; struct openvz_vm *vm; struct openvz_vm **pnext; struct openvz_driver *driver; @@ -296,15 +301,9 @@ openvzGetVPSInfo(virConnectPtr conn) { snprintf(vmdef->name, OPENVZ_NAME_MAX, "%i", veid); openvzGetVPSUUID(veid, uuidstr); - ret = sscanf(uuidstr, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - (unsigned int *)&vmdef->uuid[0], (unsigned int *)&vmdef->uuid[1], (unsigned int *)&vmdef->uuid[2], - (unsigned int *)&vmdef->uuid[3], (unsigned int *)&vmdef->uuid[4], (unsigned int *)&vmdef->uuid[5], - (unsigned int *)&vmdef->uuid[6], (unsigned int *)&vmdef->uuid[7], (unsigned int *)&vmdef->uuid[8], - (unsigned int *)&vmdef->uuid[9], (unsigned int *)&vmdef->uuid[10], (unsigned int *)&vmdef->uuid[11], - (unsigned int *)&vmdef->uuid[12], (unsigned int *)&vmdef->uuid[13], (unsigned int *)&vmdef->uuid[14], - (unsigned int *)&vmdef->uuid[15]); + ret = virUUIDParse(uuidstr, vmdef->uuid); - if(ret != 16) { + if(ret == -1) { error(conn, VIR_ERR_INTERNAL_ERROR, "UUID in config file malformed"); return NULL; } @@ -315,7 +314,8 @@ openvzGetVPSInfo(virConnectPtr conn) { return vm; } -char *openvzLocateConfDir(void) +static char +*openvzLocateConfDir(void) { const char *conf_dir_list[] = {"/etc/vz/conf", "/usr/local/etc/conf", NULL}; int i=0; @@ -330,9 +330,8 @@ char *openvzLocateConfDir(void) } /* Richard Steven's classic readline() function */ - -static -int openvz_readline(int fd, char *ptr, int maxlen) +int +openvz_readline(int fd, char *ptr, int maxlen) { int n, rc; char c; @@ -356,7 +355,8 @@ int openvz_readline(int fd, char *ptr, int maxlen) return n; } -int openvzGetVPSUUID(int vpsid, char *uuidbuf) +static int +openvzGetVPSUUID(int vpsid, char *uuidbuf) { char conf_file[PATH_MAX]; char line[1024]; @@ -385,7 +385,7 @@ int openvzGetVPSUUID(int vpsid, char *uuidbuf) sscanf(line, "%s %s\n", iden, uuid); if(!strcmp(iden, "#UUID:")) { - strncpy(uuidbuf, uuid, (VIR_UUID_BUFLEN * 2) +1); + strncpy(uuidbuf, uuid, VIR_UUID_STRING_BUFLEN); break; } } @@ -396,10 +396,11 @@ int openvzGetVPSUUID(int vpsid, char *uuidbuf) * assign if not present. */ -int openvzSetUUID(int vpsid) +static int +openvzSetUUID(int vpsid) { char conf_file[PATH_MAX]; - char uuid[(VIR_UUID_BUFLEN * 2) + 1]; + char uuid[VIR_UUID_STRING_BUFLEN]; unsigned char new_uuid[VIR_UUID_BUFLEN]; char *conf_dir; int fd, ret, i; @@ -418,7 +419,7 @@ int openvzSetUUID(int vpsid) if(uuid[0] == (int)NULL) { virUUIDGenerate(new_uuid); - bzero(uuid, (VIR_UUID_BUFLEN * 2) + 1); + bzero(uuid, VIR_UUID_STRING_BUFLEN); for(i = 0; i < VIR_UUID_BUFLEN; i ++) sprintf(uuid + (i * 2), "%02x", (unsigned char)new_uuid[i]); diff --git a/src/openvz_conf.h b/src/openvz_conf.h index ffc773868c..8871dbfcbb 100644 --- a/src/openvz_conf.h +++ b/src/openvz_conf.h @@ -94,8 +94,8 @@ struct openvz_vm { struct openvz_vm *next; }; -char *openvzLocateConfDir(void); -int readline(int fd, char *ptr, int maxlen); +static char *openvzLocateConfDir(void); +int openvz_readline(int fd, char *ptr, int maxlen); static void error (virConnectPtr conn, virErrorNumber code, const char *info); struct openvz_vm *openvzFindVMByID(const struct openvz_driver *driver, int id); struct openvz_vm *openvzFindVMByUUID(const struct openvz_driver *driver, @@ -108,7 +108,7 @@ struct openvz_vm_def *openvzParseVMDef(virConnectPtr conn, const char *xmlStr, const char *displayName); struct openvz_vm *openvzGetVPSInfo(virConnectPtr conn); void openvzGenerateUUID(unsigned char *uuid); -int openvzGetVPSUUID(int vpsid, char *uuidbuf); -int openvzSetUUID(int vpsid); +static int openvzGetVPSUUID(int vpsid, char *uuidbuf); +static int openvzSetUUID(int vpsid); int openvzAssignUUIDs(void); #endif /* OPENVZ_CONF_H */ diff --git a/src/openvz_driver.c b/src/openvz_driver.c index 18afd86b39..e85aa8606f 100644 --- a/src/openvz_driver.c +++ b/src/openvz_driver.c @@ -52,6 +52,7 @@ #include "event.h" #include "buf.h" +#include "util.h" #include "openvz_driver.h" #include "openvz_conf.h" @@ -284,6 +285,11 @@ static virDrvOpenStatus openvzOpen(virConnectPtr conn, if (strcmp(name, "openvz:///system")) return VIR_DRV_OPEN_DECLINED; } + /* See if we are running an OpenVZ enabled kernel */ + if(access("/proc/vz/veinfo", F_OK) == -1 || + access("/proc/user_beancounters", F_OK) == -1) { + return VIR_DRV_OPEN_DECLINED; + } conn->privateData = &ovz_driver; @@ -323,19 +329,25 @@ static const char *openvzGetType(virConnectPtr conn ATTRIBUTE_UNUSED) { static int openvzListDomains(virConnectPtr conn, int *ids, int nids) { int got = 0; - int veid; - FILE *fp; + int veid, pid, outfd, errfd; + int ret; + char buf[32]; + const char *cmd[] = {VZLIST, "-ovpsid", "-H" , NULL}; - if((fp = popen(VZLIST " -o vpsid -H 2> /dev/null", "r")) == NULL){ - error(conn, VIR_ERR_INTERNAL_ERROR, "Could not popen " VZLIST); + ret = virExec(conn, (char **)cmd, &pid, &outfd, &errfd); + if(ret == -1) { + error(conn, VIR_ERR_INTERNAL_ERROR, "Could not exec " VZLIST); return (int)NULL; } - while(!(feof(fp)) && got < nids){ - fscanf(fp, "%d\n", &veid); + while(got < nids){ + ret = openvz_readline(outfd, buf, 32); + if(!ret) break; + sscanf(buf, "%d", &veid); ids[got] = veid; got ++; } + waitpid(pid, NULL, 0); return got; } @@ -347,23 +359,27 @@ static int openvzNumDomains(virConnectPtr conn) { static int openvzListDefinedDomains(virConnectPtr conn, char **const names, int nnames) { int got = 0; - FILE *fp; - int veid; + int veid, pid, outfd, errfd, ret; char vpsname[OPENVZ_NAME_MAX]; + char buf[32]; + const char *cmd[] = {VZLIST, "-ovpsid", "-H", NULL}; /* the -S options lists only stopped domains */ - if((fp = popen(VZLIST " -S -o vpsid -H 2> /dev/null", "r")) == NULL){ - error(conn, VIR_ERR_INTERNAL_ERROR, "Could not popen " VZLIST); + ret = virExec(conn, (char **)cmd, &pid, &outfd, &errfd); + if(ret == -1) { + error(conn, VIR_ERR_INTERNAL_ERROR, "Could not exec " VZLIST); return (int)NULL; } - while(!(feof(fp)) && got < nnames){ - fscanf(fp, "%d\n", &veid); + while(got < nnames){ + ret = openvz_readline(outfd, buf, 32); + if(!ret) break; + sscanf(buf, "%d\n", &veid); sprintf(vpsname, "%d", veid); names[got] = strdup(vpsname); got ++; } - + waitpid(pid, NULL, 0); return got; } diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 7268413389..c207516b7b 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -50,6 +50,7 @@ #include "event.h" #include "buf.h" +#include "util.h" #include "qemu_driver.h" #include "qemu_conf.h" @@ -330,91 +331,6 @@ qemudShutdown(void) { return 0; } -static int -qemudExec(virConnectPtr conn, - char **argv, - int *retpid, int *outfd, int *errfd) { - int pid, null; - int pipeout[2] = {-1,-1}; - int pipeerr[2] = {-1,-1}; - - if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot open %s : %s", - _PATH_DEVNULL, strerror(errno)); - goto cleanup; - } - - if ((outfd != NULL && pipe(pipeout) < 0) || - (errfd != NULL && pipe(pipeerr) < 0)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot create pipe : %s", - strerror(errno)); - goto cleanup; - } - - if ((pid = fork()) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot fork child process : %s", - strerror(errno)); - goto cleanup; - } - - if (pid) { /* parent */ - close(null); - if (outfd) { - close(pipeout[1]); - qemudSetNonBlock(pipeout[0]); - qemudSetCloseExec(pipeout[0]); - *outfd = pipeout[0]; - } - if (errfd) { - close(pipeerr[1]); - qemudSetNonBlock(pipeerr[0]); - qemudSetCloseExec(pipeerr[0]); - *errfd = pipeerr[0]; - } - *retpid = pid; - return 0; - } - - /* child */ - - if (pipeout[0] > 0 && close(pipeout[0]) < 0) - _exit(1); - if (pipeerr[0] > 0 && close(pipeerr[0]) < 0) - _exit(1); - - if (dup2(null, STDIN_FILENO) < 0) - _exit(1); - if (dup2(pipeout[1] > 0 ? pipeout[1] : null, STDOUT_FILENO) < 0) - _exit(1); - if (dup2(pipeerr[1] > 0 ? pipeerr[1] : null, STDERR_FILENO) < 0) - _exit(1); - - close(null); - if (pipeout[1] > 0) - close(pipeout[1]); - if (pipeerr[1] > 0) - close(pipeerr[1]); - - execvp(argv[0], argv); - - _exit(1); - - return 0; - - cleanup: - if (pipeerr[0] > 0) - close(pipeerr[0]); - if (pipeerr[1] > 0) - close(pipeerr[1]); - if (pipeout[0] > 0) - close(pipeout[0]); - if (pipeout[1] > 0) - close(pipeout[1]); - if (null > 0) - close(null); - return -1; -} - /* Return -1 for error, 1 to continue reading and 0 for success */ typedef int qemudHandlerMonitorOutput(virConnectPtr conn, struct qemud_driver *driver, @@ -722,7 +638,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, qemudLog(QEMUD_WARN, "Unable to write argv to logfile %d: %s", errno, strerror(errno)); - if (qemudExec(conn, argv, &vm->pid, &vm->stdout, &vm->stderr) == 0) { + if (virExecNonBlock(conn, argv, &vm->pid, &vm->stdout, &vm->stderr) == 0) { vm->id = driver->nextvmid++; vm->state = VIR_DOMAIN_RUNNING; @@ -981,7 +897,7 @@ dhcpStartDhcpDaemon(virConnectPtr conn, if (qemudBuildDnsmasqArgv(conn, network, &argv) < 0) return -1; - ret = qemudExec(conn, argv, &network->dnsmasqPid, NULL, NULL); + ret = virExecNonBlock(conn, argv, &network->dnsmasqPid, NULL, NULL); for (i = 0; argv[i]; i++) free(argv[i]); diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000000..6459951903 --- /dev/null +++ b/src/util.c @@ -0,0 +1,192 @@ +/* + * utils.c: common, generic utility functions + * + * Copyright (C) 2006, 2007 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * Copyright (C) 2006, 2007 Binary Karma + * Copyright (C) 2006 Shuveb Hussain + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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: Daniel P. Berrange + * File created Jul 18, 2007 - Shuveb Hussain + */ + +#include +#include +#include +#include +#include +#include +#include +#include "event.h" +#include "buf.h" + +#define MAX_ERROR_LEN 1024 + +static void +ReportError(virConnectPtr conn, + virDomainPtr dom, + virNetworkPtr net, + int code, const char *fmt, ...) { + va_list args; + char errorMessage[MAX_ERROR_LEN]; + + if (fmt) { + va_start(args, fmt); + vsnprintf(errorMessage, MAX_ERROR_LEN-1, fmt, args); + va_end(args); + } else { + errorMessage[0] = '\0'; + } + __virRaiseError(conn, dom, net, VIR_FROM_NONE, code, VIR_ERR_ERROR, + NULL, NULL, NULL, -1, -1, errorMessage); +} + +static int virSetCloseExec(int fd) { + int flags; + if ((flags = fcntl(fd, F_GETFD)) < 0) + return -1; + flags |= FD_CLOEXEC; + if ((fcntl(fd, F_SETFD, flags)) < 0) + return -1; + return 0; +} + +static int virSetNonBlock(int fd) { + int flags; + if ((flags = fcntl(fd, F_GETFL)) < 0) + return -1; + flags |= O_NONBLOCK; + if ((fcntl(fd, F_SETFL, flags)) < 0) + return -1; + return 0; +} + +static int +_virExec(virConnectPtr conn, + char **argv, + int *retpid, int *outfd, int *errfd, int non_block) { + int pid, null; + int pipeout[2] = {-1,-1}; + int pipeerr[2] = {-1,-1}; + + if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0) { + ReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot open %s : %s", + _PATH_DEVNULL, strerror(errno)); + goto cleanup; + } + + if ((outfd != NULL && pipe(pipeout) < 0) || + (errfd != NULL && pipe(pipeerr) < 0)) { + ReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot create pipe : %s", + strerror(errno)); + goto cleanup; + } + + if ((pid = fork()) < 0) { + ReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot fork child process : %s", + strerror(errno)); + goto cleanup; + } + + if (pid) { /* parent */ + close(null); + if (outfd) { + close(pipeout[1]); + if(non_block) + if(virSetNonBlock(pipeout[0]) == -1) + ReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "Failed to set non-blocking file descriptor flag"); + + if(virSetCloseExec(pipeout[0]) == -1) + ReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "Failed to set close-on-exec file descriptor flag"); + *outfd = pipeout[0]; + } + if (errfd) { + close(pipeerr[1]); + if(non_block) + if(virSetNonBlock(pipeerr[0]) == -1) + ReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "Failed to set non-blocking file descriptor flag"); + + if(virSetCloseExec(pipeerr[0]) == -1) + ReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "Failed to set close-on-exec file descriptor flag"); + *errfd = pipeerr[0]; + } + *retpid = pid; + return 0; + } + + /* child */ + + if (pipeout[0] > 0 && close(pipeout[0]) < 0) + _exit(1); + if (pipeerr[0] > 0 && close(pipeerr[0]) < 0) + _exit(1); + + if (dup2(null, STDIN_FILENO) < 0) + _exit(1); + if (dup2(pipeout[1] > 0 ? pipeout[1] : null, STDOUT_FILENO) < 0) + _exit(1); + if (dup2(pipeerr[1] > 0 ? pipeerr[1] : null, STDERR_FILENO) < 0) + _exit(1); + + close(null); + if (pipeout[1] > 0) + close(pipeout[1]); + if (pipeerr[1] > 0) + close(pipeerr[1]); + + execvp(argv[0], argv); + + _exit(1); + + return 0; + + cleanup: + if (pipeerr[0] > 0) + close(pipeerr[0]); + if (pipeerr[1] > 0) + close(pipeerr[1]); + if (pipeout[0] > 0) + close(pipeout[0]); + if (pipeout[1] > 0) + close(pipeout[1]); + if (null > 0) + close(null); + return -1; +} + +int +virExec(virConnectPtr conn, + char **argv, + int *retpid, int *outfd, int *errfd) { + + _virExec(conn, argv, retpid, outfd, errfd, 0); + +} + +int +virExecNonBlock(virConnectPtr conn, + char **argv, + int *retpid, int *outfd, int *errfd) { + + _virExec(conn, argv, retpid, outfd, errfd, 1); + +} + diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000000..5b84043599 --- /dev/null +++ b/src/util.h @@ -0,0 +1,26 @@ +/* + * utils.h: common, generic utility functions + * + * Copyright (C) 2006, 2007 Binary Karma + * Copyright (C) 2006 Shuveb Hussain + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * File created Jul 18, 2007 - Shuveb Hussain + */ + +int virExec(virConnectPtr conn, char **argv, int *retpid, int *outfd, int *errfd); +int virExecNonBlock(virConnectPtr conn, char **argv, int *retpid, int *outfd, int *errfd); +