[libvirt] [PATCH] xml: print uuids or shell-escaped names in the warning
by Ján Tomko
In the XML warning, this prints uuids for domain names with special
characters in them and shell-escaped names for other elements (like
snapshosts and networks) with special names.
---
When saving snapshots, the domain name is appended to the
"snapshot-edit" command, so using a domain name that needs escaping
would lead to something that can't be just fed to the shell.
diff to v1: xml: shell-escape domain name in comment
The function was changed to shell-escape ']>' instead of '--' as the
latter is more likely to happen.
Domain names don't get escaped, UUIDs are preferred.
---
src/conf/domain_conf.c | 6 +++-
src/libvirt_private.syms | 2 +
src/qemu/qemu_domain.c | 3 +-
src/util/buf.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/buf.h | 1 +
src/util/xml.c | 61 +++++++++++++++++++++---------------------
src/util/xml.h | 1 +
7 files changed, 108 insertions(+), 32 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 0933c08..342bf2c 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -14252,6 +14252,7 @@ int virDomainSaveXML(const char *configDir,
virDomainDefPtr def,
const char *xml)
{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
char *configFile = NULL;
int ret = -1;
@@ -14265,7 +14266,10 @@ int virDomainSaveXML(const char *configDir,
goto cleanup;
}
- ret = virXMLSaveFile(configFile, def->name, "edit", xml);
+ virUUIDFormat(def->uuid, uuidstr);
+ ret = virXMLSaveFile(configFile,
+ virXMLPickShellSafeCDATA(def->name,uuidstr), "edit",
+ xml);
cleanup:
VIR_FREE(configFile);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 699c9a3..4c0b8ca 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -37,6 +37,7 @@ virBufferError;
virBufferEscape;
virBufferEscapeSexpr;
virBufferEscapeShell;
+virBufferEscapeShellXMLCDATA;
virBufferEscapeString;
virBufferFreeAndReset;
virBufferGetIndent;
@@ -1816,6 +1817,7 @@ virURIParse;
# xml.h
virXMLChildElementCount;
virXMLParseHelper;
+virXMLPickShellSafeCDATA;
virXMLPropString;
virXMLSaveFile;
virXPathBoolean;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 4e6a5e9..1522dec 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1622,7 +1622,8 @@ qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm,
goto cleanup;
}
- if (virAsprintf(&tmp, "snapshot-edit %s", vm->def->name) < 0) {
+ if (virAsprintf(&tmp, "snapshot-edit %s",
+ virXMLPickShellSafeCDATA(vm->def->name, uuidstr)) < 0) {
virReportOOMError();
goto cleanup;
}
diff --git a/src/util/buf.c b/src/util/buf.c
index 030dc97..7ae52f2 100644
--- a/src/util/buf.c
+++ b/src/util/buf.c
@@ -623,6 +623,72 @@ virBufferEscapeShell(virBufferPtr buf, const char *str)
}
/**
+ * virBufferEscapeShellXMLCDATA:
+ * @buf: the buffer to append to
+ * @str: an unquoted string
+ *
+ * Quotes a string so that the shell (/bin/sh) will interpret the
+ * quoted string to mean str. Auto indentation may be applied.
+ * It also escapes any "]]>" so that the string can be used in XML CDATA.
+ */
+void virBufferEscapeShellXMLCDATA(virBufferPtr buf, const char *str)
+{
+ int len;
+ char *escaped, *out;
+ const char *cur;
+ char prev = '\0';
+
+ if ((buf == NULL) || (str == NULL))
+ return;
+
+ if (buf->error)
+ return;
+
+ /* Only quote if str includes shell metacharacters.
+ * This also catches ]]> */
+ if (*str && !strpbrk(str, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~")) {
+ virBufferAdd(buf, str, -1);
+ return;
+ }
+
+ if (*str) {
+ len = strlen(str);
+ if (xalloc_oversized(4, len) ||
+ VIR_ALLOC_N(escaped, 4 * len + 3) < 0) {
+ virBufferSetError(buf, errno);
+ return;
+ }
+ } else {
+ virBufferAddChar(buf, '\'');
+ return;
+ }
+
+ cur = str;
+ out = escaped;
+
+ *out++ = '\'';
+ while (*cur != 0) {
+ if (*cur == '\'') {
+ *out++ = '\'';
+ /* Replace literal ' with a close ', a \', and a open ' */
+ *out++ = '\\';
+ *out++ = '\'';
+ } else if (prev == ']' && *cur == '>') {
+ /* Replace ]> with ]''> */
+ *out++ = '\'';
+ *out++ = '\'';
+ }
+ prev = *cur;
+ *out++ = *cur++;
+ }
+ *out++ = '\'';
+ *out = 0;
+
+ virBufferAdd(buf, escaped, -1);
+ VIR_FREE(escaped);
+}
+
+/**
* virBufferStrcat:
* @buf: the buffer to append to
* @...: the variable list of strings, the last argument must be NULL
diff --git a/src/util/buf.h b/src/util/buf.h
index c3a498d..d20b37f 100644
--- a/src/util/buf.h
+++ b/src/util/buf.h
@@ -69,6 +69,7 @@ void virBufferEscapeString(virBufferPtr buf, const char *format,
void virBufferEscapeSexpr(virBufferPtr buf, const char *format,
const char *str);
void virBufferEscapeShell(virBufferPtr buf, const char *str);
+void virBufferEscapeShellXMLCDATA(virBufferPtr buf, const char *str);
void virBufferURIEncodeString(virBufferPtr buf, const char *str);
# define virBufferAddLit(buf_, literal_string_) \
diff --git a/src/util/xml.c b/src/util/xml.c
index f3dc256..1cfc15e 100644
--- a/src/util/xml.c
+++ b/src/util/xml.c
@@ -780,49 +780,50 @@ error:
goto cleanup;
}
+const char *virXMLPickShellSafeCDATA(const char *str1, const char *str2)
+{
+ /* this catches shell metacharacters as well as ]]> */
+ if(str1 && !strpbrk(str1, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~"))
+ return str1;
+ if(str2 && !strpbrk(str2, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~"))
+ return str2;
+ return NULL;
+}
static int virXMLEmitWarning(int fd,
const char *name,
const char *cmd)
{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char *str = NULL;
size_t len;
- const char *prologue = "<!--\n\
-WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE \n\
-OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:\n\
- virsh ";
- const char *epilogue = "\n\
-or other application using the libvirt API.\n\
--->\n\n";
if (fd < 0 || !name || !cmd) {
errno = EINVAL;
return -1;
}
- len = strlen(prologue);
- if (safewrite(fd, prologue, len) != len)
- return -1;
-
- len = strlen(cmd);
- if (safewrite(fd, cmd, len) != len)
- return -1;
-
- /* Omit the domain name if it contains a double hyphen
- * because they aren't allowed in XML comments */
- if (!strstr(name, "--")) {
- if (safewrite(fd, " ", 1) != 1)
- return -1;
-
- len = strlen(name);
- if (safewrite(fd, name, len) != len)
- return -1;
- }
-
- len = strlen(epilogue);
- if (safewrite(fd, epilogue, len) != len)
- return -1;
+ virBufferAddLit(&buf, "<!-- <![CDATA[\n"
+"WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE\n"
+"OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:\n"
+" virsh ");
+ virBufferEscapeShellXMLCDATA(&buf, cmd);
+ virBufferAddChar(&buf,' ');
+ virBufferEscapeShellXMLCDATA(&buf, name);
+ virBufferAddLit(&buf, "\n"
+"or other application using the libvirt API.\n"
+"]]> -->\n\n");
+
+ str = virBufferContentAndReset(&buf);
+ len = strlen(str);
+ if (str)
+ if (safewrite(fd, str, len) == len) {
+ VIR_FREE(str);
+ return 0;
+ }
- return 0;
+ VIR_FREE(str);
+ return -1;
}
diff --git a/src/util/xml.h b/src/util/xml.h
index a3750fa..cb6789b 100644
--- a/src/util/xml.h
+++ b/src/util/xml.h
@@ -61,6 +61,7 @@ xmlDocPtr virXMLParseHelper(int domcode,
const char *url,
xmlXPathContextPtr *pctxt);
+const char *virXMLPickShellSafeCDATA(const char *str1, const char *str2);
/**
* virXMLParse:
* @filename: file to parse, or NULL for string parsing
--
1.7.8.6
12 years, 1 month
[libvirt] [PATCH] Fix build with apparmor
by Jiri Denemark
Recent storage patches changed signature of virStorageFileGetMetadata
and replaced chain with backingChain in virDomainDiskDef.
---
src/security/virt-aa-helper.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index 263fc92..c3a9265 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -924,10 +924,12 @@ get_files(vahControl * ctl)
/* XXX - if we knew the qemu user:group here we could send it in
* so that the open could be re-tried as that user:group.
*/
- disk->chain = virStorageFileGetMetadata(disk->src, disk->format,
- -1, -1,
- ctl->allowDiskFormatProbing,
- NULL);
+ if (!disk->backingChain) {
+ bool probe = ctl->allowDiskFormatProbing;
+ disk->backingChain = virStorageFileGetMetadata(disk->src,
+ disk->format,
+ -1, -1, probe);
+ }
/* XXX passing ignoreOpenFailure = true to get back to the behavior
* from before using virDomainDiskDefForeachPath. actually we should
--
1.7.12.4
12 years, 1 month
[libvirt] [PATCH 0/3] apparmor: bug and typo fix and add tapFD relabeling
by Guannan Ren
These three patches are generated when trying to make use of
libvirt apparmor security driver in openSUSU 11.4.
Patches fix some typoes and bugs and rename AppArmorSetImageFDLabel
to AppArmorSetFDLabel as the common labeling function that could
be used by domainSetSecurityImageFDLabel and domainSetSecurityTapFDLabel.
tapfd could be seen in the last line in specific profile named
/etc/apparmor.d/libvirt/libvirt-cdbebdfa-1d6d-65c3-be0f-fd74b978a773.files
# DO NOT EDIT THIS FILE DIRECTLY. IT IS MANAGED BY LIBVIRT.
"/var/log/libvirt/**/rhel6qcow2.log" w,
"/var/lib/libvirt/**/rhel6qcow2.monitor" rw,
"/var/run/libvirt/**/rhel6qcow2.pid" rwk,
"/run/libvirt/**/rhel6qcow2.pid" rwk,
"/var/run/libvirt/**/*.tunnelmigrate.dest.rhel6qcow2" rw,
"/run/libvirt/**/*.tunnelmigrate.dest.rhel6qcow2" rw,
"/var/lib/libvirt/images/rhel6u3qcow2.img" rw,
"/dev/tap45" rw,
Guannan Ren(3)
[PATCH 1/3] apparmor: fix typoes in virt-aa-helper
[PATCH 2/3] apparmor: no need to check security model
[PATCH 3/3] apparmor: use AppArmorSetFDLabel for both imageFD and tapFD
src/security/security_apparmor.c | 22 ++++++----------------
src/security/virt-aa-helper.c | 7 +++----
2 files changed, 9 insertions(+), 20 deletions(-)
12 years, 1 month
[libvirt] [PATCH 1/2] include: declare typed parameter handling earlier
by Eric Blake
Commit 12ad7435 added new functions (virNodeGetMemoryParameters,
virNodeSetMemoryParameters) into the section of the file reserved
for deprecated names. Fix this by moving things earlier; split
into two patches to make git diff easier to read.
* include/libvirt/libvirt.h.in: Move virTypedParameter earlier.
---
include/libvirt/libvirt.h.in | 174 ++++++++++++++++++++++---------------------
1 file changed, 88 insertions(+), 86 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 52555f8..7d6a064 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -432,6 +432,94 @@ typedef struct _virSecurityModel {
*/
typedef virSecurityModel *virSecurityModelPtr;
+/* Common data types shared among interfaces with name/type/value lists. */
+
+/**
+ * virTypedParameterType:
+ *
+ * Express the type of a virTypedParameter
+ */
+typedef enum {
+ VIR_TYPED_PARAM_INT = 1, /* integer case */
+ VIR_TYPED_PARAM_UINT = 2, /* unsigned integer case */
+ VIR_TYPED_PARAM_LLONG = 3, /* long long case */
+ VIR_TYPED_PARAM_ULLONG = 4, /* unsigned long long case */
+ VIR_TYPED_PARAM_DOUBLE = 5, /* double case */
+ VIR_TYPED_PARAM_BOOLEAN = 6, /* boolean(character) case */
+ VIR_TYPED_PARAM_STRING = 7, /* string case */
+
+#ifdef VIR_ENUM_SENTINELS
+ VIR_TYPED_PARAM_LAST
+#endif
+} virTypedParameterType;
+
+/**
+ * virTypedParameterFlags:
+ *
+ * Flags related to libvirt APIs that use virTypedParameter.
+ *
+ * These enums should not conflict with those of virDomainModificationImpact.
+ */
+typedef enum {
+ /* 1 << 0 is reserved for virDomainModificationImpact */
+ /* 1 << 1 is reserved for virDomainModificationImpact */
+
+ /* Older servers lacked the ability to handle string typed
+ * parameters. Attempts to set a string parameter with an older
+ * server will fail at the client, but attempts to retrieve
+ * parameters must not return strings from a new server to an
+ * older client, so this flag exists to identify newer clients to
+ * newer servers. This flag is automatically set when needed, so
+ * the user does not have to worry about it; however, manually
+ * setting the flag can be used to reject servers that cannot
+ * return typed strings, even if no strings would be returned.
+ */
+ VIR_TYPED_PARAM_STRING_OKAY = 1 << 2,
+
+} virTypedParameterFlags;
+
+/**
+ * VIR_TYPED_PARAM_FIELD_LENGTH:
+ *
+ * Macro providing the field length of virTypedParameter name
+ */
+#define VIR_TYPED_PARAM_FIELD_LENGTH 80
+
+/**
+ * virTypedParameter:
+ *
+ * A named parameter, including a type and value.
+ *
+ * The types virSchedParameter, virBlkioParameter, and
+ * virMemoryParameter are aliases of this type, for use when
+ * targetting libvirt earlier than 0.9.2.
+ */
+typedef struct _virTypedParameter virTypedParameter;
+
+struct _virTypedParameter {
+ char field[VIR_TYPED_PARAM_FIELD_LENGTH]; /* parameter name */
+ int type; /* parameter type, virTypedParameterType */
+ union {
+ int i; /* type is INT */
+ unsigned int ui; /* type is UINT */
+ long long int l; /* type is LLONG */
+ unsigned long long int ul; /* type is ULLONG */
+ double d; /* type is DOUBLE */
+ char b; /* type is BOOLEAN */
+ char *s; /* type is STRING, may not be NULL */
+ } value; /* parameter value */
+};
+
+/**
+ * virTypedParameterPtr:
+ *
+ * a pointer to a virTypedParameter structure.
+ */
+typedef virTypedParameter *virTypedParameterPtr;
+
+
+/* data types relate to virNodePtr */
+
/**
* virNodeInfoPtr:
*
@@ -587,92 +675,6 @@ struct _virNodeMemoryStats {
unsigned long long value;
};
-/* Common data types shared among interfaces with name/type/value lists. */
-
-/**
- * virTypedParameterType:
- *
- * Express the type of a virTypedParameter
- */
-typedef enum {
- VIR_TYPED_PARAM_INT = 1, /* integer case */
- VIR_TYPED_PARAM_UINT = 2, /* unsigned integer case */
- VIR_TYPED_PARAM_LLONG = 3, /* long long case */
- VIR_TYPED_PARAM_ULLONG = 4, /* unsigned long long case */
- VIR_TYPED_PARAM_DOUBLE = 5, /* double case */
- VIR_TYPED_PARAM_BOOLEAN = 6, /* boolean(character) case */
- VIR_TYPED_PARAM_STRING = 7, /* string case */
-
-#ifdef VIR_ENUM_SENTINELS
- VIR_TYPED_PARAM_LAST
-#endif
-} virTypedParameterType;
-
-/**
- * virTypedParameterFlags:
- *
- * Flags related to libvirt APIs that use virTypedParameter.
- *
- * These enums should not conflict with those of virDomainModificationImpact.
- */
-typedef enum {
- /* 1 << 0 is reserved for virDomainModificationImpact */
- /* 1 << 1 is reserved for virDomainModificationImpact */
-
- /* Older servers lacked the ability to handle string typed
- * parameters. Attempts to set a string parameter with an older
- * server will fail at the client, but attempts to retrieve
- * parameters must not return strings from a new server to an
- * older client, so this flag exists to identify newer clients to
- * newer servers. This flag is automatically set when needed, so
- * the user does not have to worry about it; however, manually
- * setting the flag can be used to reject servers that cannot
- * return typed strings, even if no strings would be returned.
- */
- VIR_TYPED_PARAM_STRING_OKAY = 1 << 2,
-
-} virTypedParameterFlags;
-
-/**
- * VIR_TYPED_PARAM_FIELD_LENGTH:
- *
- * Macro providing the field length of virTypedParameter name
- */
-#define VIR_TYPED_PARAM_FIELD_LENGTH 80
-
-/**
- * virTypedParameter:
- *
- * A named parameter, including a type and value.
- *
- * The types virSchedParameter, virBlkioParameter, and
- * virMemoryParameter are aliases of this type, for use when
- * targetting libvirt earlier than 0.9.2.
- */
-typedef struct _virTypedParameter virTypedParameter;
-
-struct _virTypedParameter {
- char field[VIR_TYPED_PARAM_FIELD_LENGTH]; /* parameter name */
- int type; /* parameter type, virTypedParameterType */
- union {
- int i; /* type is INT */
- unsigned int ui; /* type is UINT */
- long long int l; /* type is LLONG */
- unsigned long long int ul; /* type is ULLONG */
- double d; /* type is DOUBLE */
- char b; /* type is BOOLEAN */
- char *s; /* type is STRING, may not be NULL */
- } value; /* parameter value */
-};
-
-/**
- * virTypedParameterPtr:
- *
- * a pointer to a virTypedParameter structure.
- */
-typedef virTypedParameter *virTypedParameterPtr;
-
-
/* Management of scheduler parameters */
/**
--
1.7.11.7
12 years, 1 month
[libvirt] [PATCH] sanlock: Introduce 'user' and 'group' conf variables
by Michal Privoznik
through which user set under what permissions does sanlock
daemon run so libvirt will set the same permissions for
files exposed to it.
---
docs/locking.html.in | 22 +++++++++
src/locking/libvirt_sanlock.aug | 2 +
src/locking/lock_driver_sanlock.c | 76 ++++++++++++++++++++++++++++++-
src/locking/sanlock.conf | 11 ++++-
src/locking/test_libvirt_sanlock.aug.in | 2 +
5 files changed, 111 insertions(+), 2 deletions(-)
diff --git a/docs/locking.html.in b/docs/locking.html.in
index 6d7b517..19dd6a3 100644
--- a/docs/locking.html.in
+++ b/docs/locking.html.in
@@ -121,6 +121,28 @@
</pre>
<p>
+ If your sanlock daemon happen to run under non-root
+ privileges, you need to tell this to libvirt so it
+ chowns created files correctly. This can be done by
+ setting <code>user</code> and/or <code>group</code>
+ variables in the configuration file. Accepted values
+ range is specified in description to the same
+ variables in <code>/etc/libvirt/qemu.conf</code>. For
+ example:
+ </p>
+
+ <pre>
+ augtool -s set /files/etc/libvirt/qemu-sanlock.conf/user sanlock
+ augtool -s set /files/etc/libvirt/qemu-sanlock.conf/group sanlock
+ </pre>
+
+ <p>
+ But remember, that if this is NFS share, you need a
+ no_root_squash-ed one for chown (and chmod possibly)
+ to succeed.
+ </p>
+
+ <p>
In terms of storage requirements, if the filesystem
uses 512 byte sectors, you need to allow for <code>1MB</code>
of storage for each guest disk. So if you have a network
diff --git a/src/locking/libvirt_sanlock.aug b/src/locking/libvirt_sanlock.aug
index d65b002..a78a444 100644
--- a/src/locking/libvirt_sanlock.aug
+++ b/src/locking/libvirt_sanlock.aug
@@ -22,6 +22,8 @@ module Libvirt_sanlock =
| int_entry "host_id"
| bool_entry "require_lease_for_disks"
| bool_entry "ignore_readonly_and_shared_disks"
+ | str_entry "user"
+ | str_entry "group"
let comment = [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
let empty = [ label "#empty" . eol ]
diff --git a/src/locking/lock_driver_sanlock.c b/src/locking/lock_driver_sanlock.c
index 4682701..d988a6d 100644
--- a/src/locking/lock_driver_sanlock.c
+++ b/src/locking/lock_driver_sanlock.c
@@ -71,6 +71,10 @@ struct _virLockManagerSanlockDriver {
int hostID;
bool autoDiskLease;
char *autoDiskLeasePath;
+
+ /* under which permissions does sanlock run */
+ uid_t user;
+ gid_t group;
};
static virLockManagerSanlockDriver *driver = NULL;
@@ -94,6 +98,7 @@ static int virLockManagerSanlockLoadConfig(const char *configFile)
{
virConfPtr conf;
virConfValuePtr p;
+ char *tmp;
if (access(configFile, R_OK) == -1) {
if (errno != ENOENT) {
@@ -142,6 +147,39 @@ static int virLockManagerSanlockLoadConfig(const char *configFile)
else
driver->requireLeaseForDisks = !driver->autoDiskLease;
+ p = virConfGetValue(conf, "user");
+ CHECK_TYPE("user", VIR_CONF_STRING);
+ if (p) {
+ if (!(tmp = strdup(p->str))) {
+ virReportOOMError();
+ virConfFree(conf);
+ return -1;
+ }
+
+ if (virGetUserID(tmp, &driver->user) < 0) {
+ VIR_FREE(tmp);
+ virConfFree(conf);
+ return -1;
+ }
+ VIR_FREE(tmp);
+ }
+
+ p = virConfGetValue (conf, "group");
+ CHECK_TYPE ("group", VIR_CONF_STRING);
+ if (p) {
+ if (!(tmp = strdup(p->str))) {
+ virReportOOMError();
+ virConfFree(conf);
+ return -1;
+ }
+ if (virGetGroupID(tmp, &driver->group) < 0) {
+ VIR_FREE(tmp);
+ virConfFree(conf);
+ return -1;
+ }
+ VIR_FREE(tmp);
+ }
+
virConfFree(conf);
return 0;
}
@@ -177,6 +215,7 @@ static int virLockManagerSanlockSetupLockspace(void)
* space allocated for it and is initialized with lease
*/
if (stat(path, &st) < 0) {
+ int perms = 0600;
VIR_DEBUG("Lockspace %s does not yet exist", path);
if (!(dir = mdir_name(path))) {
@@ -191,7 +230,10 @@ static int virLockManagerSanlockSetupLockspace(void)
goto error;
}
- if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) {
+ if (driver->group != -1)
+ perms |= 0060;
+
+ if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, perms)) < 0) {
if (errno != EEXIST) {
virReportSystemError(errno,
_("Unable to create lockspace %s"),
@@ -200,6 +242,17 @@ static int virLockManagerSanlockSetupLockspace(void)
}
VIR_DEBUG("Someone else just created lockspace %s", path);
} else {
+ /* chown() the path to make sure sanlock can access it */
+ if ((driver->user != -1 || driver->group != -1) &&
+ (fchown(fd, driver->user, driver->group) < 0)) {
+ virReportSystemError(errno,
+ _("cannot chown '%s' to (%u, %u)"),
+ path,
+ (unsigned int) driver->user,
+ (unsigned int) driver->group);
+ goto error_unlink;
+ }
+
if ((rv = sanlock_align(&ls.host_id_disk)) < 0) {
if (rv <= -200)
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -242,6 +295,26 @@ static int virLockManagerSanlockSetupLockspace(void)
}
VIR_DEBUG("Lockspace %s has been initialized", path);
}
+ } else if (S_ISREG(st.st_mode)) {
+ /* okay, the lease file exists. Check the permissions */
+ if (((driver->user != -1 && driver->user != st.st_uid) ||
+ (driver->group != -1 && driver->group != st.st_gid)) &&
+ (chown(path, driver->user, driver->group) < 0)) {
+ virReportSystemError(errno,
+ _("cannot chown '%s' to (%u, %u)"),
+ path,
+ (unsigned int) driver->user,
+ (unsigned int) driver->group);
+ goto error;
+ }
+
+ if ((driver->group != -1 && (st.st_mode & 0060) != 0060) &&
+ chmod(path, 0660) < 0) {
+ virReportSystemError(errno,
+ _("cannot chmod '%s' to 0660"),
+ path);
+ goto error;
+ }
}
ls.host_id = driver->hostID;
@@ -299,6 +372,7 @@ static int virLockManagerSanlockInit(unsigned int version,
driver->requireLeaseForDisks = true;
driver->hostID = 0;
driver->autoDiskLease = false;
+ driver->user = driver->group = -1;
if (!(driver->autoDiskLeasePath = strdup(LOCALSTATEDIR "/lib/libvirt/sanlock"))) {
VIR_FREE(driver);
virReportOOMError();
diff --git a/src/locking/sanlock.conf b/src/locking/sanlock.conf
index efc35ee..40ece65 100644
--- a/src/locking/sanlock.conf
+++ b/src/locking/sanlock.conf
@@ -29,7 +29,8 @@
#
# Recommendation is to just mount this default location as
# an NFS volume. Uncomment this, if you would prefer the mount
-# point to be somewhere else.
+# point to be somewhere else. Moreover, please make sure
+# sanlock daemon can access the specified path.
#
#disk_lease_dir = "/var/lib/libvirt/sanlock"
@@ -52,3 +53,11 @@
# to enabled, otherwise it defaults to disabled.
#
#require_lease_for_disks = 1
+
+#
+# The combination of user and group under which the sanlock
+# daemon runs. Libvirt will chown created files (like
+# content of disk_lease_dir) to make sure sanlock daemon can
+# access them. Accepted values are described in qemu.conf.
+#user = "root"
+#group = "root"
diff --git a/src/locking/test_libvirt_sanlock.aug.in b/src/locking/test_libvirt_sanlock.aug.in
index 288f329..ef98ea6 100644
--- a/src/locking/test_libvirt_sanlock.aug.in
+++ b/src/locking/test_libvirt_sanlock.aug.in
@@ -6,3 +6,5 @@ module Test_libvirt_sanlock =
{ "disk_lease_dir" = "/var/lib/libvirt/sanlock" }
{ "host_id" = "1" }
{ "require_lease_for_disks" = "1" }
+{ "user" = "root" }
+{ "group" = "root" }
--
1.7.8.6
12 years, 1 month
[libvirt] [PATCH] esx: Update version checks for vSphere 5.1
by Matthias Bolte
Also remove warnings for upcoming versions. There hadn't been any
compatibility problems with new ESX version over the whole lifetime
of the ESX driver, so I don't expect any in the future.
Update documentation to mention vSphere 5.x support.
---
docs/drvesx.html.in | 4 ++--
src/esx/esx_vi.c | 24 ++++++------------------
src/esx/esx_vi.h | 9 ++++++---
3 files changed, 14 insertions(+), 23 deletions(-)
diff --git a/docs/drvesx.html.in b/docs/drvesx.html.in
index 7d323b3..11df124 100644
--- a/docs/drvesx.html.in
+++ b/docs/drvesx.html.in
@@ -2,10 +2,10 @@
<h1>VMware ESX hypervisor driver</h1>
<ul id="toc"></ul>
<p>
- The libvirt VMware ESX driver can manage VMware ESX/ESXi 3.5/4.x and
+ The libvirt VMware ESX driver can manage VMware ESX/ESXi 3.5/4.x/5.x and
VMware GSX 2.0, also called VMware Server 2.0, and possibly later
versions. <span class="since">Since 0.8.3</span> the driver can also
- connect to a VMware vCenter 2.5/4.x (VPX).
+ connect to a VMware vCenter 2.5/4.x/5.x (VPX).
</p>
<h2><a name="project">Project Links</a></h2>
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 125eaee..0d2b970 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -833,16 +833,12 @@ esxVI_Context_Connect(esxVI_Context *ctx, const char *url,
ctx->apiVersion = esxVI_APIVersion_41;
} else if (STRPREFIX(ctx->service->about->apiVersion, "4.")) {
ctx->apiVersion = esxVI_APIVersion_4x;
-
- VIR_WARN("Found untested VI API major/minor version '%s'",
- ctx->service->about->apiVersion);
} else if (STRPREFIX(ctx->service->about->apiVersion, "5.0")) {
ctx->apiVersion = esxVI_APIVersion_50;
+ } else if (STRPREFIX(ctx->service->about->apiVersion, "5.1")) {
+ ctx->apiVersion = esxVI_APIVersion_51;
} else if (STRPREFIX(ctx->service->about->apiVersion, "5.")) {
ctx->apiVersion = esxVI_APIVersion_5x;
-
- VIR_WARN("Found untested VI API major/minor version '%s'",
- ctx->service->about->apiVersion);
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Expecting VI API major/minor version '2.5', '4.x' or "
@@ -869,16 +865,12 @@ esxVI_Context_Connect(esxVI_Context *ctx, const char *url,
ctx->productVersion = esxVI_ProductVersion_ESX41;
} else if (STRPREFIX(ctx->service->about->version, "4.")) {
ctx->productVersion = esxVI_ProductVersion_ESX4x;
-
- VIR_WARN("Found untested ESX major/minor version '%s'",
- ctx->service->about->version);
} else if (STRPREFIX(ctx->service->about->version, "5.0")) {
ctx->productVersion = esxVI_ProductVersion_ESX50;
+ } else if (STRPREFIX(ctx->service->about->version, "5.1")) {
+ ctx->productVersion = esxVI_ProductVersion_ESX51;
} else if (STRPREFIX(ctx->service->about->version, "5.")) {
ctx->productVersion = esxVI_ProductVersion_ESX5x;
-
- VIR_WARN("Found untested ESX major/minor version '%s'",
- ctx->service->about->version);
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Expecting ESX major/minor version '3.5', "
@@ -895,16 +887,12 @@ esxVI_Context_Connect(esxVI_Context *ctx, const char *url,
ctx->productVersion = esxVI_ProductVersion_VPX41;
} else if (STRPREFIX(ctx->service->about->version, "4.")) {
ctx->productVersion = esxVI_ProductVersion_VPX4x;
-
- VIR_WARN("Found untested VPX major/minor version '%s'",
- ctx->service->about->version);
} else if (STRPREFIX(ctx->service->about->version, "5.0")) {
ctx->productVersion = esxVI_ProductVersion_VPX50;
+ } else if (STRPREFIX(ctx->service->about->version, "5.1")) {
+ ctx->productVersion = esxVI_ProductVersion_VPX51;
} else if (STRPREFIX(ctx->service->about->version, "5.")) {
ctx->productVersion = esxVI_ProductVersion_VPX5x;
-
- VIR_WARN("Found untested VPX major/minor version '%s'",
- ctx->service->about->version);
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Expecting VPX major/minor version '2.5', '4.x' "
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 3471fea..a9c12c8 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -95,7 +95,8 @@ enum _esxVI_APIVersion {
esxVI_APIVersion_41,
esxVI_APIVersion_4x, /* > 4.1 */
esxVI_APIVersion_50,
- esxVI_APIVersion_5x /* > 5.0 */
+ esxVI_APIVersion_51,
+ esxVI_APIVersion_5x /* > 5.1 */
};
/*
@@ -114,7 +115,8 @@ enum _esxVI_ProductVersion {
esxVI_ProductVersion_ESX41 = esxVI_ProductVersion_ESX | 3,
esxVI_ProductVersion_ESX4x = esxVI_ProductVersion_ESX | 4, /* > 4.1 */
esxVI_ProductVersion_ESX50 = esxVI_ProductVersion_ESX | 5,
- esxVI_ProductVersion_ESX5x = esxVI_ProductVersion_ESX | 6, /* > 5.0 */
+ esxVI_ProductVersion_ESX51 = esxVI_ProductVersion_ESX | 6,
+ esxVI_ProductVersion_ESX5x = esxVI_ProductVersion_ESX | 7, /* > 5.1 */
esxVI_ProductVersion_VPX = (1 << 2) << 16,
esxVI_ProductVersion_VPX25 = esxVI_ProductVersion_VPX | 1,
@@ -122,7 +124,8 @@ enum _esxVI_ProductVersion {
esxVI_ProductVersion_VPX41 = esxVI_ProductVersion_VPX | 3,
esxVI_ProductVersion_VPX4x = esxVI_ProductVersion_VPX | 4, /* > 4.1 */
esxVI_ProductVersion_VPX50 = esxVI_ProductVersion_VPX | 5,
- esxVI_ProductVersion_VPX5x = esxVI_ProductVersion_VPX | 6 /* > 5.0 */
+ esxVI_ProductVersion_VPX51 = esxVI_ProductVersion_VPX | 6,
+ esxVI_ProductVersion_VPX5x = esxVI_ProductVersion_VPX | 7 /* > 5.1 */
};
enum _esxVI_Occurrence {
--
1.7.4.1
12 years, 1 month
[libvirt] [PATCHv2 0/9] Resend: New API to retrieve host node CPU map
by Viktor Mihajlovski
Resending the otherwise unmodified V2 series, as the cover letter didn't
show up on the mailing list (at least not in the archive).
Sorry for the extra traffic, but I have no clue what went wrong.
V2 Changes:
Added python binding for virNodeGetCPUMapFlags.
Removed RFC stanza.
Rationale:
In order to use the APIs listed below it is necessary for a client
to know the maximum number of node CPUs which is passed via the
maplen argument.
virDomainGetEmulatorPinInfo
virDomainGetVcpuPinInfo
virDomainGetVcpus
virDomainPinEmulator
virDomainPinVcpu
virDomainPinVcpuFlags
The current approach uses virNodeGetInfo to determine the maximum CPU number.
This can lead to incorrect results if not all node CPUs are online.
The maximum CPU number should always be the number of CPUs present on the
host, regardless of their online/offline state.
The following example illustrates the issue:
Host has 3 logical CPUs, 1 socket, 3 cores, 1 thread.
Guest has 1 virtual CPU and is started while all 3 host CPUs are
online.
$ virsh vcpuinfo guest
VCPU: 0
CPU: 0
State: running
CPU time: 35.4s
CPU Affinity: yyy
$ echo 0 > /sys/devices/system/cpu/cpu1/online
$ virsh vcpuinfo guest
VCPU: 0
CPU: 0
State: running
CPU time: 35.5s
CPU Affinity: y-
The correct display for CPU affinity would have been y-y, as the guest
continues to use CPUs 0 and 2.
This is not a display problem only, because it is also not possible to
explicitly pin the virtual CPU to host CPUs 0 and 2, due to the
truncated CPU mask.
PROPOSAL:
To help solve the issue above I suggest a new public API:
int virNodeGetCPUMapFlags(virConnectPtr conn,
unsigned char **cpumap,
unsigned int *online,
unsigned int flags);
The function will return the number of CPUs present on the host
or -1 on failure;
If cpumap is non-NULL virNodeGetCPUMapFlags will allocate an array
containing a bit map representation of the online CPUs. It's
the callers responsibility to deallocate cpumap using free().
If online is non-NULL, the variable pointed to will contain
the number of online host node CPUs.
The variable flags has been added to support future extensions
and must be set to 0.
Clients can use virNodeGetCPUMapFlags to properly determine the maximum
number of node CPUs and their online/offline state.
Remarks:
This series implements the QEMU and test drivers.
This series doesn't introduce changes to the existing vcpu pinning,
which I would submit as a succeeding patch set.
Viktor Mihajlovski (9):
virNodeGetCPUMapFlags: Define public API.
virNodeGetCPUMapFlags: Define driver API.
virNodeGetCPUMapFlags: Implement public API.
virNodeGetCPUMapFlags: Implement wire protocol.
libvirt.h.in: Add new cpumap macro VIR_CPU_USED
virNodeGetCPUMapFlags: Implement virsh support.
virNodeGetCPUMapFlags: Implement support function in nodeinfo
virNodeGetCPUMapFlags: Implement driver support
virNodeGetCPUMapFlags: Add python binding
daemon/remote.c | 44 ++++++++++++++++++++++++++++++
include/libvirt/libvirt.h.in | 28 ++++++++++++++++---
python/generator.py | 1 +
python/libvirt-override-api.xml | 6 ++++
python/libvirt-override.c | 56 +++++++++++++++++++++++++++++++++++++++
src/driver.h | 7 +++++
src/libvirt.c | 56 +++++++++++++++++++++++++++++++++++++++
src/libvirt_private.syms | 1 +
src/libvirt_public.syms | 5 +++
src/nodeinfo.c | 49 ++++++++++++++++++++++++++++++++++
src/nodeinfo.h | 6 ++++
src/qemu/qemu_driver.c | 1 +
src/remote/remote_driver.c | 49 ++++++++++++++++++++++++++++++++++
src/remote/remote_protocol.x | 13 ++++++++-
src/remote_protocol-structs | 12 ++++++++
src/test/test_driver.c | 30 +++++++++++++++++++++
tools/virsh-host.c | 41 ++++++++++++++++++++++++++++
tools/virsh.pod | 5 +++
18 files changed, 405 insertions(+), 5 deletions(-)
12 years, 1 month
[libvirt] [PATCH] cpu: Add recently added cpu feature flags.
by Peter Krempa
Qemu has added some new feature flags. This patch adds them to libvirt.
The new features are for the cpuid function 0x7 that takes an argument
in the ecx register. Currently only 0x0 is used as the argument so I was
lazy and I just clear the registers to 0 before calling cpuid. In future
when there maybe will be some other possible arguments, we will need to
improve the cpu detection code to take this into account.
---
The qemu flag definiton can be found at:
http://git.qemu.org/?p=qemu.git;a=blob;f=target-i386/cpu.c;h=f3708e63b765...
---
src/cpu/cpu_map.xml | 12 ++++++++++++
src/cpu/cpu_x86.c | 8 +++++++-
2 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/cpu/cpu_map.xml b/src/cpu/cpu_map.xml
index affcce3..d059e20 100644
--- a/src/cpu/cpu_map.xml
+++ b/src/cpu/cpu_map.xml
@@ -142,6 +142,9 @@
<feature name='pdcm'>
<cpuid function='0x00000001' ecx='0x00008000'/>
</feature>
+ <feature name='pcid'>
+ <cpuid function='0x00000001' ecx='0x00020000'/>
+ </feature>
<feature name='dca'> <!-- CPUID_EXT_DCA -->
<cpuid function='0x00000001' ecx='0x00040000'/>
</feature>
@@ -261,6 +264,15 @@
<cpuid function='0x80000001' ecx='0x00080000'/>
</feature>
+ <!-- cpuid function 0x7 ecx 0x0 features -->
+ <!-- We support only ecx 0x0 now as it's done by a workaround -->
+ <feature name='smep'>
+ <cpuid function='0x00000007' ebx='0x00000080'/>
+ </feature>
+ <feature name='smap'>
+ <cpuid function='0x00000007' ebx='0x00080000'/>
+ </feature>
+
<!-- models -->
<model name='486'>
<feature name='fpu'/>
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index 7cd67b8..f54c3df 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -1539,7 +1539,10 @@ static inline void
cpuidCall(struct cpuX86cpuid *cpuid)
{
# if __x86_64__
- asm("cpuid"
+ asm("xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */
+ "xor %%ecx, %%ecx;" /* functions may use them as additional */
+ "xor %%edx, %%edx;" /* arguments */
+ "cpuid"
: "=a" (cpuid->eax),
"=b" (cpuid->ebx),
"=c" (cpuid->ecx),
@@ -1550,6 +1553,9 @@ cpuidCall(struct cpuX86cpuid *cpuid)
* for global offset table on i386 with -fPIC
*/
asm("push %%ebx;"
+ "xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */
+ "xor %%ecx, %%ecx;" /* functions may use them as additional */
+ "xor %%edx, %%edx;" /* arguments */
"cpuid;"
"mov %%ebx, %1;"
"pop %%ebx;"
--
1.7.12.4
12 years, 1 month
[libvirt] [PATCH 0/3] Do not override affinity set by auto placement
by Osier Yang
Creating cgroup for emulator thread will override the affinity
set by "auto" placement with all available pCPUs. 1/3 is just to
add a helper to for later use. 2/3 to keep the affinity set by
'auto' placement. 3/3 to prohibit changing the affinity for
emulator thread dynamically if placement == "auto".
Osier Yang (3):
qemu: Add helper to prepare cpumap for affinity setting
qemu: Keep the affinity when creating cgroup for emulator thread
qemu: Prohibit chaning affinity of domain process if placement is
'auto'
src/qemu/qemu_cgroup.c | 17 ++++++++++--
src/qemu/qemu_cgroup.h | 3 +-
src/qemu/qemu_driver.c | 7 +++++
src/qemu/qemu_process.c | 64 ++++++++++++++++++++++++++++++----------------
src/qemu/qemu_process.h | 2 +
5 files changed, 67 insertions(+), 26 deletions(-)
--
1.7.7.6
12 years, 1 month
[libvirt] [PATCH] xml: shell-escape domain name in comment
by Ján Tomko
Add virBufferEscapeShellXMLComment function that both quotes a string so
shell deosn't interpert any special characters in it and makes sure that
there's no "--" in it, to avoid clashes with XML comments.
virXMLEmitWarning is changed to use virBuffer and use the above function
on the domain name.
---
src/libvirt_private.syms | 1 +
src/util/buf.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/buf.h | 1 +
src/util/xml.c | 52 +++++++++++++++---------------------
4 files changed, 90 insertions(+), 30 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 699c9a3..a49d5dc 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -37,6 +37,7 @@ virBufferError;
virBufferEscape;
virBufferEscapeSexpr;
virBufferEscapeShell;
+virBufferEscapeShellXML;
virBufferEscapeString;
virBufferFreeAndReset;
virBufferGetIndent;
diff --git a/src/util/buf.c b/src/util/buf.c
index 030dc97..839b663 100644
--- a/src/util/buf.c
+++ b/src/util/buf.c
@@ -623,6 +623,72 @@ virBufferEscapeShell(virBufferPtr buf, const char *str)
}
/**
+ * virBufferEscapeShellXMLComment:
+ * @buf: the buffer to append to
+ * @str: an unquoted string
+ *
+ * Quotes a string so that the shell (/bin/sh) will interpret the
+ * quoted string to mean str. Auto indentation may be applied.
+ * It also escapes any "--" so that the string can be used in XML comments.
+ */
+void virBufferEscapeShellXMLComment(virBufferPtr buf, const char *str)
+{
+ int len;
+ char *escaped, *out;
+ const char *cur;
+ char prev = '\0';
+
+ if ((buf == NULL) || (str == NULL))
+ return;
+
+ if (buf->error)
+ return;
+
+ /* Only quote if str includes shell metacharacters. */
+ if (*str && !strpbrk(str, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~") &&
+ !strstr(str,"--")) {
+ virBufferAdd(buf, str, -1);
+ return;
+ }
+
+ if (*str) {
+ len = strlen(str);
+ if (xalloc_oversized(4, len) ||
+ VIR_ALLOC_N(escaped, 4 * len + 3) < 0) {
+ virBufferSetError(buf, errno);
+ return;
+ }
+ } else {
+ virBufferAddLit(buf, "''");
+ return;
+ }
+
+ cur = str;
+ out = escaped;
+
+ *out++ = '\'';
+ while (*cur != 0) {
+ if (*cur == '\'') {
+ *out++ = '\'';
+ /* Replace literal ' with a close ', a \', and a open ' */
+ *out++ = '\\';
+ *out++ = '\'';
+ } else if (*cur == '-' && prev == '-') {
+ /* Replace -- with -''- */
+ *out++ = '\'';
+ *out++ = '\'';
+ }
+ prev = *cur;
+ *out++ = *cur++;
+ }
+ *out++ = '\'';
+ *out = 0;
+
+ virBufferAdd(buf, escaped, -1);
+ VIR_FREE(escaped);
+}
+
+/**
* virBufferStrcat:
* @buf: the buffer to append to
* @...: the variable list of strings, the last argument must be NULL
diff --git a/src/util/buf.h b/src/util/buf.h
index c3a498d..25e31fd 100644
--- a/src/util/buf.h
+++ b/src/util/buf.h
@@ -69,6 +69,7 @@ void virBufferEscapeString(virBufferPtr buf, const char *format,
void virBufferEscapeSexpr(virBufferPtr buf, const char *format,
const char *str);
void virBufferEscapeShell(virBufferPtr buf, const char *str);
+void virBufferEscapeShellXMLComment(virBufferPtr buf, const char *str);
void virBufferURIEncodeString(virBufferPtr buf, const char *str);
# define virBufferAddLit(buf_, literal_string_) \
diff --git a/src/util/xml.c b/src/util/xml.c
index f3dc256..685f903 100644
--- a/src/util/xml.c
+++ b/src/util/xml.c
@@ -780,49 +780,41 @@ error:
goto cleanup;
}
-
static int virXMLEmitWarning(int fd,
const char *name,
const char *cmd)
{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char *str = NULL;
size_t len;
- const char *prologue = "<!--\n\
-WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE \n\
-OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:\n\
- virsh ";
- const char *epilogue = "\n\
-or other application using the libvirt API.\n\
--->\n\n";
if (fd < 0 || !name || !cmd) {
errno = EINVAL;
return -1;
}
- len = strlen(prologue);
- if (safewrite(fd, prologue, len) != len)
- return -1;
-
- len = strlen(cmd);
- if (safewrite(fd, cmd, len) != len)
- return -1;
-
- /* Omit the domain name if it contains a double hyphen
- * because they aren't allowed in XML comments */
- if (!strstr(name, "--")) {
- if (safewrite(fd, " ", 1) != 1)
- return -1;
-
- len = strlen(name);
- if (safewrite(fd, name, len) != len)
- return -1;
+ virBufferAddLit(&buf, "<!--\n"
+"WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE\n"
+"OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:\n"
+" virsh ");
+ virBufferAdd(&buf, cmd, -1);
+ virBufferAddLit(&buf," ");
+ virBufferEscapeShellXMLComment(&buf, name);
+ virBufferAddLit(&buf, "\n"
+"or other application using the libvirt API.\n"
+"-->\n\n");
+
+ str = virBufferContentAndReset(&buf);
+ if (str) {
+ len = strlen(str);
+ if (safewrite(fd, str, len) == len) {
+ VIR_FREE(str);
+ return 0;
+ }
}
- len = strlen(epilogue);
- if (safewrite(fd, epilogue, len) != len)
- return -1;
-
- return 0;
+ VIR_FREE(str);
+ return -1;
}
--
1.7.8.6
12 years, 1 month