[Libvir] PATCH: Support serial & parallel devices in QEMU driver
Jim Meyering
jim at meyering.net
Thu Apr 17 09:47:44 UTC 2008
"Daniel P. Berrange" <berrange at redhat.com> wrote:
> A long time ago I proposed a syntax for serial / parallel port handling
> in libvirt XML.
Nice.
And it looks correct, too, but that's not too
surprising, especially with all of those tests.
I confirmed that it passes a valgrind-enabled "make check"
with no errors or leaks.
So ACK.
The only suggestions I can make are for maintainability/readability,
and one place where it'd be good to add an additional check.
> Index: src/qemu_conf.c
> ===================================================================
...
> + case QEMUD_CHR_SRC_TYPE_DEV:
> + case QEMUD_CHR_SRC_TYPE_FILE:
> + case QEMUD_CHR_SRC_TYPE_PIPE:
> + if (path == NULL) {
> + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> + "%s", _("Missing source path attribute for char device"));
> + goto cleanup;
> + }
> +
> + strncpy(chr->srcData.file.path, (const char *)path,
> + sizeof(chr->srcData.file.path));
> + chr->srcData.file.path[sizeof(chr->srcData.file.path)-1] = '\0';
Since there are so many lines like the one above, how about using a
macro instead? Otherwise, it's too hard/risky (as reviewer/maintainer)
to ensure that the long index expression always matches the array name. E.g.,
#define NUL_TERMINATE(buf) do { (buf)[sizeof(buf)-1] = '\0'; } while (0)
Then you can do this, here and in the 9 other cases below:
(this also shortens several >80 lines)
NUL_TERMINATE(chr->srcData.file.path);
> + break;
> +
> + case QEMUD_CHR_SRC_TYPE_STDIO:
> + /* Nada */
> + break;
> +
> + case QEMUD_CHR_SRC_TYPE_TCP:
> + if (mode == NULL ||
> + STREQ((const char *)mode, "connect")) {
> + if (connectHost == NULL) {
> + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> + "%s", _("Missing source host attribute for char device"));
> + goto cleanup;
> + }
> + if (connectService == NULL) {
> + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> + "%s", _("Missing source service attribute for char device"));
> + goto cleanup;
> + }
> +
> + strncpy(chr->srcData.tcp.host, (const char *)connectHost,
> + sizeof(chr->srcData.tcp.host));
> + chr->srcData.tcp.host[sizeof(chr->srcData.tcp.host)-1] = '\0';
> + strncpy(chr->srcData.tcp.service, (const char *)connectService,
> + sizeof(chr->srcData.tcp.service));
> + chr->srcData.tcp.service[sizeof(chr->srcData.tcp.service)-1] = '\0';
> +
> + chr->srcData.tcp.listen = 0;
> + } else {
> + if (bindHost == NULL) {
> + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> + "%s", _("Missing source host attribute for char device"));
> + goto cleanup;
> + }
> + if (bindService == NULL) {
> + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> + "%s", _("Missing source service attribute for char device"));
> + goto cleanup;
> + }
> +
> + strncpy(chr->srcData.tcp.host, (const char *)bindHost,
> + sizeof(chr->srcData.tcp.host));
> + chr->srcData.tcp.host[sizeof(chr->srcData.tcp.host)-1] = '\0';
> + strncpy(chr->srcData.tcp.service, (const char *)bindService,
> + sizeof(chr->srcData.tcp.service));
> + chr->srcData.tcp.service[sizeof(chr->srcData.tcp.service)-1] = '\0';
...
> +static int qemudParseCharXMLDevices(virConnectPtr conn,
> + xmlXPathContextPtr ctxt,
> + const char *xpath,
> + int *ndevs,
Maybe better to make this "unsigned int". See below.
> + struct qemud_vm_chr_def **devs)
> +{
> + xmlXPathObjectPtr obj;
> + int i;
> +
> + obj = xmlXPathEval(BAD_CAST xpath, ctxt);
> + if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
> + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
> + struct qemud_vm_chr_def *prev = *devs;
> + if (ndevs == NULL &&
> + obj->nodesetval->nodeNr > 1) {
> + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> + "%s", _("too many character devices"));
> + goto error;
> + }
> +
> + for (i = 0; i < obj->nodesetval->nodeNr; i++) {
> + struct qemud_vm_chr_def *chr = calloc(1, sizeof(*chr));
> + if (!chr) {
> + qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
> + "%s",
> + _("failed to allocate space for char device"));
> + goto error;
> + }
> +
> + if (qemudParseCharXML(conn, chr, i, obj->nodesetval->nodeTab[i]) < 0) {
> + free(chr);
> + goto error;
> + }
> + if (ndevs)
> + (*ndevs)++;
> + chr->next = NULL;
> + if (i == 0) {
> + *devs = chr;
> + } else {
> + prev->next = chr;
> + }
> + prev = chr;
> + }
> + }
> + xmlXPathFreeObject(obj);
> +
> + return 0;
> +
> +error:
> + xmlXPathFreeObject(obj);
> + return -1;
> +}
Barely worth mentioning, but it's slightly better to avoid the
duplicate xmlXPathFreeObject above -- esp. since it's easy.
Having a single point of "return" is a good feature, too.
...
> +static int qemudGenerateXMLChar(virBufferPtr buf,
> + struct qemud_vm_chr_def *dev,
Looks like dev can be const, too.
> + const char *type)
> +{
> + const char *types[] = {
You can make it so the array is const as well as each string:
const char *const types[] = {
Actually, this list of strings should be tied to the declaration
of the corresponding QEMUD_* enum values, so if you ever add one
there, you are forced to add the new one here, too.
E.g., with this:
(assuming you add QEMUD_CHR_SRC_TYPE_LAST as an enum member):
#include "verify.h" /* from gnulib */
#define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
verify (ARRAY_CARDINALITY (types) == QEMUD_CHR_SRC_TYPE_LAST);
or this with existing:
verify (ARRAY_CARDINALITY (types) == QEMUD_CHR_SRC_TYPE_UNIX + 1);
That gives you a *compile-time* check to ensure that
the set of enum members and size of the array match.
gnulib's verify.h is pretty cool, but it's LGPL, not v2+.
I'll see about changing that. The part we need is so small
(but surprisingly dense) that maybe it doesn't matter...
# define verify_true(R) \
(!!sizeof \
(struct { unsigned int verify_error_if_negative_size__: (R) ? 1 : -1; }))
#define verify(R) extern int (* verify_function__ (void)) [verify_true (R)]
> + "null",
> + "vc",
> + "pty",
> + "dev",
> + "file",
> + "pipe",
> + "stdio",
> + "udp",
> + "tcp",
> + "unix"
> + };
It'd be nice to make sure dev->srcType is in range
before using it as an index... just in case.
> + if (virBufferVSprintf(buf, " <%s type='%s'>\n",
> + type, types[dev->srcType]) < 0)
> + return -1;
> +
...
> /* Generate an XML document describing the guest's configuration */
> char *qemudGenerateXML(virConnectPtr conn,
> struct qemud_driver *driver ATTRIBUTE_UNUSED,
> @@ -2850,6 +3447,7 @@ char *qemudGenerateXML(virConnectPtr con
> struct qemud_vm_disk_def *disk;
> struct qemud_vm_net_def *net;
> struct qemud_vm_input_def *input;
> + struct qemud_vm_chr_def *chr;
The above can all be const.
> const char *type = NULL;
> int n;
...
> Index: src/qemu_conf.h
> ===================================================================
...
> enum qemu_vm_input_type {
> QEMU_INPUT_TYPE_MOUSE,
> @@ -223,6 +269,12 @@ struct qemud_vm_def {
>
> int ninputs;
> struct qemud_vm_input_def *inputs;
> +
> + int nserials;
This never has a negative value.
(it's initialized to 0 by the calloc in qemudParseCharXMLDevices,
and every other use is a read or increment)
If you intend to keep it that way,
it's slightly better to declare it to be an unsigned type.
Same goes for qemudParseCharXMLDevices's matching "ndev" parameter.
> + struct qemud_vm_chr_def *serials;
> +
> + int nparallels;
Likewise.
More information about the libvir-list
mailing list