[libvirt] [PATCH] virsh edit, virsh net-edit, virsh pool-edit
Jim Meyering
jim at meyering.net
Fri Aug 1 08:02:50 UTC 2008
"Richard W.M. Jones" <rjones at redhat.com> wrote:
> This implements 'virsh edit', 'virsh net-edit' and 'virsh pool-edit'
> commands.
Hi Rich,
> Index: src/virsh.c
> ===================================================================
> RCS file: /data/cvs/libvirt/src/virsh.c,v
> retrieving revision 1.157
> diff -u -r1.157 virsh.c
> --- src/virsh.c 22 Jul 2008 16:12:01 -0000 1.157
> +++ src/virsh.c 30 Jul 2008 09:54:46 -0000
> @@ -5070,6 +5070,424 @@
> }
>
> /*
> + * "edit" command
> + */
These declarations can go farther down, right above the definition
of cmdEdit.
> +static vshCmdInfo info_edit[] = {
> + {"syntax", "edit <domain>"},
> + {"help", gettext_noop("edit XML configuration for a domain")},
> + {"desc", gettext_noop("Edit the XML configuration for a domain.")},
> + {NULL, NULL}
> +};
> +
> +static vshCmdOptDef opts_edit[] = {
You can mark entries as "const":
static const vshCmdOptDef opts_edit[] = {
> + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")},
> + {NULL, 0, 0, NULL}
> +};
> +
> +static char *
> +editWriteToTempFile (vshControl *ctl, const char *doc)
> +{
> + char *ret;
> + int fd;
> +
> + ret = tempnam (NULL, "virsh");
Don't use tempnam.
It poses a security risk (symlink attack in a race to open).
Use mkstemp instead, but you'll have to form the concatenation
of $TMPDIR (if defined, else /tmp) with a template like /virshXXXXXX.
> + if (!ret) {
> + vshError(ctl, FALSE,
> + _("tempnam: failed to create temporary file: %s"),
> + strerror (errno));
> + return NULL;
> + }
> +
> + fd = open (ret, O_EXCL|O_CREAT|O_WRONLY, 0600);
> + if (fd == -1) {
> + vshError(ctl, FALSE,
> + _("open: %s: failed to create temporary file: %s"),
> + ret, strerror (errno));
> + free (ret);
> + return NULL;
> + }
> +
> + if (safewrite (fd, doc, strlen (doc)) == -1) {
> + vshError(ctl, FALSE,
> + _("write: %s: failed to create temporary file: %s"),
s/create/write/
> + ret, strerror (errno));
> + close (fd);
> + unlink (ret);
> + free (ret);
> + return NULL;
> + }
> + if (close (fd) == -1) {
> + vshError(ctl, FALSE,
> + _("close: %s: failed to create temporary file: %s"),
s/create/write/
> + ret, strerror (errno));
> + unlink (ret);
> + free (ret);
> + return NULL;
> + }
> +
> + /* Temporary filename: caller frees. */
> + return ret;
> +}
> +
> +static int
> +editFile (vshControl *ctl, const char *filename)
> +{
> + const char *editor;
> + char command[100];
> + int command_ret;
> +
> + editor = getenv ("EDITOR");
> + if (!editor) editor = "vi"; /* could be cruel & default to ed(1) here */
> +
> + snprintf (command, sizeof command, "%s %s", editor, filename);
Use asprintf rather than a fixed-sized buffer.
Otherwise, if EDITOR and/or TMPDIR are long enough, the result won't fit.
What if either contains shell meta-characters?
To accommodate you'd have to shell-quote as needed, or (as I prefer)
simply detect the bogosity and refuse to run the command.
> + command_ret = system (command);
> +
> + if (command_ret == -1) {
> + vshError(ctl, FALSE,
> + "%s: %s",
> + command, strerror (errno));
> + return -1;
> + }
> + if (command_ret != WEXITSTATUS (0)) {
> + vshError(ctl, FALSE,
> + _("%s: command exited with non-zero status"), command);
> + return -1;
> + }
> + return 0;
> +}
> +
> +static char *
> +editReadBackFile (vshControl *ctl, const char *filename)
> +{
...
How about using virFileReadAll here?
Or at least fread_file_lim, if virFileReadAll's error-handling
isn't exactly what you want.
> +}
> +static int
> +cmdEdit (vshControl *ctl, vshCmd *cmd)
> +{
...
> +static int
> +cmdNetworkEdit (vshControl *ctl, vshCmd *cmd)
> +{
...
> +static int
> +cmdPoolEdit (vshControl *ctl, vshCmd *cmd)
> +{
Have you considered factoring these three?
At 70-80 lines each, with so much common code, it's begging for it.
Two approaches:
Pure C would require lots of ugly casts and would end up
worse than the duplication.
However, consider putting this into a new file, say virsh-dom-edit.c
(or better, just extracting it from virsh.c)
static vshCmdInfo info_edit[] = { ...
static vshCmdOptDef opts_edit[] = { ...
static int
cmdEdit (vshControl *ctl, vshCmd *cmd)
{
...
}
With that, we could use a few sed substitutions to automatically derive
virsh-net-edit.c and virsh-pool-edit.c, and then replace the two +80-line
blocks of duplicate code with these two lines:
#include "virsh-net-edit.c"
#include "virsh-pool-edit.c"
If you do that, you'll have to add both new file names to the
list of built sources in src/Makefile.am:
BUILT_SOURCES += virsh-net-edit.c virsh-pool-edit.c
More information about the libvir-list
mailing list