[libvirt] [PATCH 04/28] Rename command.{c,h} to vircommand.{c,h}

Daniel P. Berrange berrange at redhat.com
Mon Dec 17 14:57:37 UTC 2012


From: "Daniel P. Berrange" <berrange at redhat.com>

---
 cfg.mk                                    |    4 +-
 daemon/remote.c                           |    2 +-
 po/POTFILES.in                            |    2 +-
 src/Makefile.am                           |    2 +-
 src/fdstream.h                            |    2 +-
 src/libvirt.c                             |    2 +-
 src/libxl/libxl_driver.c                  |    2 +-
 src/lxc/lxc_container.c                   |    2 +-
 src/lxc/lxc_controller.c                  |    2 +-
 src/lxc/lxc_process.c                     |    2 +-
 src/network/bridge_driver.c               |    2 +-
 src/network/bridge_driver.h               |    2 +-
 src/nwfilter/nwfilter_ebiptables_driver.c |    2 +-
 src/openvz/openvz_conf.c                  |    2 +-
 src/openvz/openvz_driver.c                |    2 +-
 src/openvz/openvz_util.c                  |    2 +-
 src/parallels/parallels_driver.c          |    2 +-
 src/parallels/parallels_utils.c           |    2 +-
 src/qemu/qemu_capabilities.c              |    2 +-
 src/qemu/qemu_capabilities.h              |    2 +-
 src/qemu/qemu_command.h                   |    2 +-
 src/qemu/qemu_conf.h                      |    2 +-
 src/remote/remote_driver.c                |    2 +-
 src/rpc/virnetsocket.h                    |    2 +-
 src/security/security_apparmor.c          |    2 +-
 src/security/virt-aa-helper.c             |    2 +-
 src/storage/storage_backend.h             |    2 +-
 src/storage/storage_backend_disk.c        |    2 +-
 src/storage/storage_backend_fs.c          |    2 +-
 src/storage/storage_backend_iscsi.c       |    2 +-
 src/storage/storage_backend_logical.c     |    2 +-
 src/storage/storage_backend_scsi.c        |    2 +-
 src/storage/storage_backend_sheepdog.c    |    2 +-
 src/uml/uml_conf.c                        |    2 +-
 src/uml/uml_conf.h                        |    2 +-
 src/util/command.c                        | 2523 -----------------------------
 src/util/command.h                        |  166 --
 src/util/dnsmasq.c                        |    2 +-
 src/util/ebtables.c                       |    2 +-
 src/util/hooks.c                          |    2 +-
 src/util/iptables.c                       |    2 +-
 src/util/pci.c                            |    2 +-
 src/util/storage_file.c                   |    2 +-
 src/util/sysinfo.c                        |    2 +-
 src/util/util.c                           |    2 +-
 src/util/vircommand.c                     | 2523 +++++++++++++++++++++++++++++
 src/util/vircommand.h                     |  166 ++
 src/util/virfile.c                        |    2 +-
 src/util/virnetdev.c                      |    2 +-
 src/util/virnetdevbandwidth.c             |    2 +-
 src/util/virnetdevopenvswitch.c           |    2 +-
 src/util/virnetdevveth.c                  |    2 +-
 src/util/virnodesuspend.c                 |    2 +-
 src/vmware/vmware_conf.c                  |    2 +-
 src/vmware/vmware_driver.c                |    2 +-
 src/xen/xen_driver.c                      |    2 +-
 tests/commandtest.c                       |    2 +-
 tests/networkxml2conftest.c               |    2 +-
 tests/reconnect.c                         |    2 +-
 tests/statstest.c                         |    2 +-
 tests/testutils.c                         |    2 +-
 tests/virnettlscontexttest.c              |    2 +-
 tools/virsh.c                             |    2 +-
 63 files changed, 2749 insertions(+), 2749 deletions(-)
 delete mode 100644 src/util/command.c
 delete mode 100644 src/util/command.h
 create mode 100644 src/util/vircommand.c
 create mode 100644 src/util/vircommand.h

diff --git a/cfg.mk b/cfg.mk
index 1fe007e..9fbf799 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -745,7 +745,7 @@ $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protoco
 # List all syntax-check exemptions:
 exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.h$$
 
-_src1=libvirt|fdstream|qemu/qemu_monitor|util/(command|util)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon
+_src1=libvirt|fdstream|qemu/qemu_monitor|util/(vircommand|util)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon
 exclude_file_name_regexp--sc_avoid_write = \
   ^(src/($(_src1))|daemon/libvirtd|tools/console|tests/(shunload|virnettlscontext)test)\.c$$
 
@@ -778,7 +778,7 @@ exclude_file_name_regexp--sc_prohibit_close = \
 exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \
   (^tests/(qemuhelp|nodeinfo)data/|\.(gif|ico|png|diff)$$)
 
-_src2=src/(util/command|libvirt|lxc/lxc_controller|locking/lock_daemon)
+_src2=src/(util/vircommand|libvirt|lxc/lxc_controller|locking/lock_daemon)
 exclude_file_name_regexp--sc_prohibit_fork_wrappers = \
   (^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$)
 
diff --git a/daemon/remote.c b/daemon/remote.c
index 41b8ea8..1746280 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -39,7 +39,7 @@
 #include "stream.h"
 #include "uuid.h"
 #include "libvirt/libvirt-qemu.h"
-#include "command.h"
+#include "vircommand.h"
 #include "intprops.h"
 #include "virnetserverservice.h"
 #include "virnetserver.h"
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 19ed187..843db7c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -137,7 +137,6 @@ src/storage/storage_driver.c
 src/test/test_driver.c
 src/uml/uml_conf.c
 src/uml/uml_driver.c
-src/util/command.c
 src/util/conf.c
 src/util/dnsmasq.c
 src/util/event_poll.c
@@ -157,6 +156,7 @@ src/util/viraudit.c
 src/util/virauth.c
 src/util/virauthconfig.c
 src/util/vircgroup.c
+src/util/vircommand.c
 src/util/virdbus.c
 src/util/virfile.c
 src/util/virhash.c
diff --git a/src/Makefile.am b/src/Makefile.am
index fd21aa6..7e16d68 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -53,7 +53,6 @@ augeastest_DATA =
 # These files are not related to driver APIs. Simply generic
 # helper APIs for various purposes
 UTIL_SOURCES =							\
-		util/command.c util/command.h			\
 		util/conf.c util/conf.h				\
 		util/event.c util/event.h			\
 		util/event_poll.c util/event_poll.h		\
@@ -83,6 +82,7 @@ UTIL_SOURCES =							\
 		util/virauthconfig.c util/virauthconfig.h	\
 		util/virbitmap.c util/virbitmap.h		\
 		util/virbuffer.c util/virbuffer.h		\
+		util/vircommand.c util/vircommand.h		\
 		util/virfile.c util/virfile.h			\
 		util/virnodesuspend.c util/virnodesuspend.h	\
 		util/virobject.c util/virobject.h		\
diff --git a/src/fdstream.h b/src/fdstream.h
index 65457d8..d6f5a7a 100644
--- a/src/fdstream.h
+++ b/src/fdstream.h
@@ -24,7 +24,7 @@
 # define __VIR_FDSTREAM_H_
 
 # include "internal.h"
-# include "command.h"
+# include "vircommand.h"
 
 /* internal callback, the generic one is used up by daemon stream driver */
 /* the close callback is called with fdstream private data locked */
diff --git a/src/libvirt.c b/src/libvirt.c
index 4215971..e28ed05 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -56,7 +56,7 @@
 #include "intprops.h"
 #include "conf.h"
 #include "rpc/virnettlscontext.h"
-#include "command.h"
+#include "vircommand.h"
 #include "virrandom.h"
 #include "viruri.h"
 #include "threads.h"
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 302f81c..1423073 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -39,7 +39,7 @@
 #include "virfile.h"
 #include "memory.h"
 #include "uuid.h"
-#include "command.h"
+#include "vircommand.h"
 #include "libxl.h"
 #include "libxl_driver.h"
 #include "libxl_conf.h"
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 3014564..33ebf1f 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -61,7 +61,7 @@
 #include "virnetdevveth.h"
 #include "uuid.h"
 #include "virfile.h"
-#include "command.h"
+#include "vircommand.h"
 #include "virnetdev.h"
 #include "virprocess.h"
 
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index 5510b9a..c9cac5d 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -67,7 +67,7 @@
 #include "util.h"
 #include "virfile.h"
 #include "virpidfile.h"
-#include "command.h"
+#include "vircommand.h"
 #include "processinfo.h"
 #include "nodeinfo.h"
 #include "virrandom.h"
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index 3e7fcb8..7f66dc7 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -42,7 +42,7 @@
 #include "domain_audit.h"
 #include "virterror_internal.h"
 #include "logging.h"
-#include "command.h"
+#include "vircommand.h"
 #include "hooks.h"
 
 #define VIR_FROM_THIS VIR_FROM_LXC
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index c65f0bb..319ff8c 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -53,7 +53,7 @@
 #include "virbuffer.h"
 #include "virpidfile.h"
 #include "util.h"
-#include "command.h"
+#include "vircommand.h"
 #include "memory.h"
 #include "uuid.h"
 #include "iptables.h"
diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h
index 43fefc0..fea27e0 100644
--- a/src/network/bridge_driver.h
+++ b/src/network/bridge_driver.h
@@ -30,7 +30,7 @@
 # include "internal.h"
 # include "network_conf.h"
 # include "domain_conf.h"
-# include "command.h"
+# include "vircommand.h"
 # include "dnsmasq.h"
 
 int networkRegister(void);
diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c
index 5cfc036..6966acf 100644
--- a/src/nwfilter/nwfilter_ebiptables_driver.c
+++ b/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -40,7 +40,7 @@
 #include "nwfilter_gentech_driver.h"
 #include "nwfilter_ebiptables_driver.h"
 #include "virfile.h"
-#include "command.h"
+#include "vircommand.h"
 #include "configmake.h"
 #include "intprops.h"
 
diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c
index 3f89db3..c9189ef 100644
--- a/src/openvz/openvz_conf.c
+++ b/src/openvz/openvz_conf.c
@@ -52,7 +52,7 @@
 #include "util.h"
 #include "nodeinfo.h"
 #include "virfile.h"
-#include "command.h"
+#include "vircommand.h"
 
 #define VIR_FROM_THIS VIR_FROM_OPENVZ
 
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index 1b213c4..75d52e2 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -57,7 +57,7 @@
 #include "virfile.h"
 #include "virtypedparam.h"
 #include "logging.h"
-#include "command.h"
+#include "vircommand.h"
 #include "viruri.h"
 #include "stats_linux.h"
 
diff --git a/src/openvz/openvz_util.c b/src/openvz/openvz_util.c
index 111045f..4163e19 100644
--- a/src/openvz/openvz_util.c
+++ b/src/openvz/openvz_util.c
@@ -26,7 +26,7 @@
 #include "internal.h"
 
 #include "virterror_internal.h"
-#include "command.h"
+#include "vircommand.h"
 #include "datatypes.h"
 #include "memory.h"
 
diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c
index 60507e7..648cb48 100644
--- a/src/parallels/parallels_driver.c
+++ b/src/parallels/parallels_driver.c
@@ -46,7 +46,7 @@
 #include "memory.h"
 #include "util.h"
 #include "logging.h"
-#include "command.h"
+#include "vircommand.h"
 #include "configmake.h"
 #include "storage_file.h"
 #include "nodeinfo.h"
diff --git a/src/parallels/parallels_utils.c b/src/parallels/parallels_utils.c
index 521fd97..e47ff76 100644
--- a/src/parallels/parallels_utils.c
+++ b/src/parallels/parallels_utils.c
@@ -24,7 +24,7 @@
 
 #include <stdarg.h>
 
-#include "command.h"
+#include "vircommand.h"
 #include "virterror_internal.h"
 #include "memory.h"
 #include "json.h"
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 45962b0..f68e081 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -34,7 +34,7 @@
 #include "nodeinfo.h"
 #include "cpu/cpu.h"
 #include "domain_conf.h"
-#include "command.h"
+#include "vircommand.h"
 #include "virbitmap.h"
 #include "virnodesuspend.h"
 #include "qemu_monitor.h"
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index bf4eef8..cd7ee92 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -26,7 +26,7 @@
 
 # include "virobject.h"
 # include "capabilities.h"
-# include "command.h"
+# include "vircommand.h"
 # include "virobject.h"
 # include "qemu_monitor.h"
 
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 0dde4be..b3ac4a6 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -25,7 +25,7 @@
 # define __QEMU_COMMAND_H__
 
 # include "domain_conf.h"
-# include "command.h"
+# include "vircommand.h"
 # include "capabilities.h"
 # include "qemu_conf.h"
 # include "qemu_domain.h"
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index bcf21c3..eafaf9f 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -40,7 +40,7 @@
 # include "cpu_conf.h"
 # include "driver.h"
 # include "virbitmap.h"
-# include "command.h"
+# include "vircommand.h"
 # include "threadpool.h"
 # include "locking/lock_manager.h"
 # include "qemu_capabilities.h"
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index f32e88e..8b77e7d 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -41,7 +41,7 @@
 #include "memory.h"
 #include "util.h"
 #include "virfile.h"
-#include "command.h"
+#include "vircommand.h"
 #include "intprops.h"
 #include "virtypedparam.h"
 #include "viruri.h"
diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h
index e024640..fcd54dd 100644
--- a/src/rpc/virnetsocket.h
+++ b/src/rpc/virnetsocket.h
@@ -25,7 +25,7 @@
 # define __VIR_NET_SOCKET_H__
 
 # include "virsocketaddr.h"
-# include "command.h"
+# include "vircommand.h"
 # include "virnettlscontext.h"
 # include "virobject.h"
 # ifdef HAVE_SASL
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index b0cdb65..ff8aea1 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -47,7 +47,7 @@
 #include "hostusb.h"
 #include "virfile.h"
 #include "configmake.h"
-#include "command.h"
+#include "vircommand.h"
 #include "logging.h"
 
 #define VIR_FROM_THIS VIR_FROM_SECURITY
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index 78ebae3..bfd6305 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -43,7 +43,7 @@
 #include "virbuffer.h"
 #include "util.h"
 #include "memory.h"
-#include "command.h"
+#include "vircommand.h"
 
 #include "security_driver.h"
 #include "security_apparmor.h"
diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h
index c991015..56b6797 100644
--- a/src/storage/storage_backend.h
+++ b/src/storage/storage_backend.h
@@ -26,7 +26,7 @@
 
 # include "internal.h"
 # include "storage_conf.h"
-# include "command.h"
+# include "vircommand.h"
 
 typedef char * (*virStorageBackendFindPoolSources)(virConnectPtr conn, const char *srcSpec, unsigned int flags);
 typedef int (*virStorageBackendCheckPool)(virConnectPtr conn, virStoragePoolObjPtr pool, bool *active);
diff --git a/src/storage/storage_backend_disk.c b/src/storage/storage_backend_disk.c
index 06b5909..c6aa407 100644
--- a/src/storage/storage_backend_disk.c
+++ b/src/storage/storage_backend_disk.c
@@ -31,7 +31,7 @@
 #include "storage_backend_disk.h"
 #include "util.h"
 #include "memory.h"
-#include "command.h"
+#include "vircommand.h"
 #include "configmake.h"
 
 #define VIR_FROM_THIS VIR_FROM_STORAGE
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index fcc46b7..cdf93af 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -45,7 +45,7 @@
 #include "storage_backend_fs.h"
 #include "storage_conf.h"
 #include "storage_file.h"
-#include "command.h"
+#include "vircommand.h"
 #include "memory.h"
 #include "xml.h"
 #include "virfile.h"
diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c
index b080250..c468b1b 100644
--- a/src/storage/storage_backend_iscsi.c
+++ b/src/storage/storage_backend_iscsi.c
@@ -41,7 +41,7 @@
 #include "memory.h"
 #include "logging.h"
 #include "virfile.h"
-#include "command.h"
+#include "vircommand.h"
 #include "virrandom.h"
 
 #define VIR_FROM_THIS VIR_FROM_STORAGE
diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c
index fd5cbd1..53e6c61 100644
--- a/src/storage/storage_backend_logical.c
+++ b/src/storage/storage_backend_logical.c
@@ -34,7 +34,7 @@
 #include "virterror_internal.h"
 #include "storage_backend_logical.h"
 #include "storage_conf.h"
-#include "command.h"
+#include "vircommand.h"
 #include "memory.h"
 #include "logging.h"
 #include "virfile.h"
diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c
index 4e832eb..6515e57 100644
--- a/src/storage/storage_backend_scsi.c
+++ b/src/storage/storage_backend_scsi.c
@@ -33,7 +33,7 @@
 #include "memory.h"
 #include "logging.h"
 #include "virfile.h"
-#include "command.h"
+#include "vircommand.h"
 
 #define VIR_FROM_THIS VIR_FROM_STORAGE
 
diff --git a/src/storage/storage_backend_sheepdog.c b/src/storage/storage_backend_sheepdog.c
index 66d8fb4..ecca7a8 100644
--- a/src/storage/storage_backend_sheepdog.c
+++ b/src/storage/storage_backend_sheepdog.c
@@ -29,7 +29,7 @@
 #include "virterror_internal.h"
 #include "storage_backend_sheepdog.h"
 #include "storage_conf.h"
-#include "util/command.h"
+#include "vircommand.h"
 #include "util.h"
 #include "memory.h"
 #include "logging.h"
diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
index 11c915e..6aec8fc 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -45,7 +45,7 @@
 #include "logging.h"
 #include "domain_nwfilter.h"
 #include "virfile.h"
-#include "command.h"
+#include "vircommand.h"
 #include "virnetdevtap.h"
 #include "virnodesuspend.h"
 
diff --git a/src/uml/uml_conf.h b/src/uml/uml_conf.h
index 9bddedc..09a0305 100644
--- a/src/uml/uml_conf.h
+++ b/src/uml/uml_conf.h
@@ -31,7 +31,7 @@
 # include "domain_event.h"
 # include "virterror_internal.h"
 # include "threads.h"
-# include "command.h"
+# include "vircommand.h"
 # include "virhash.h"
 
 # define umlDebug(fmt, ...) do {} while(0)
diff --git a/src/util/command.c b/src/util/command.c
deleted file mode 100644
index fbd9ff8..0000000
--- a/src/util/command.c
+++ /dev/null
@@ -1,2523 +0,0 @@
-/*
- * command.c: Child command execution
- *
- * Copyright (C) 2010-2012 Red Hat, Inc.
- *
- * 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, see
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <config.h>
-
-#include <poll.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-
-#if HAVE_CAPNG
-# include <cap-ng.h>
-#endif
-
-#include "command.h"
-#include "memory.h"
-#include "virterror_internal.h"
-#include "util.h"
-#include "logging.h"
-#include "virfile.h"
-#include "virpidfile.h"
-#include "virprocess.h"
-#include "virbuffer.h"
-
-#define VIR_FROM_THIS VIR_FROM_NONE
-
-/* Flags for virExecWithHook */
-enum {
-    VIR_EXEC_NONE   = 0,
-    VIR_EXEC_NONBLOCK = (1 << 0),
-    VIR_EXEC_DAEMON = (1 << 1),
-    VIR_EXEC_CLEAR_CAPS = (1 << 2),
-    VIR_EXEC_RUN_SYNC = (1 << 3),
-};
-
-struct _virCommand {
-    int has_error; /* ENOMEM on allocation failure, -1 for anything else.  */
-
-    char **args;
-    size_t nargs;
-    size_t maxargs;
-
-    char **env;
-    size_t nenv;
-    size_t maxenv;
-
-    char *pwd;
-
-    int *preserve; /* FDs to pass to child. */
-    int preserve_size;
-    int *transfer; /* FDs to close in parent. */
-    int transfer_size;
-
-    unsigned int flags;
-
-    char *inbuf;
-    char **outbuf;
-    char **errbuf;
-
-    int infd;
-    int outfd;
-    int errfd;
-    int *outfdptr;
-    int *errfdptr;
-
-    bool handshake;
-    int handshakeWait[2];
-    int handshakeNotify[2];
-
-    virExecHook hook;
-    void *opaque;
-
-    pid_t pid;
-    char *pidfile;
-    bool reap;
-
-    unsigned long long capabilities;
-};
-
-/*
- * virCommandFDIsSet:
- * @fd: FD to test
- * @set: the set
- * @set_size: actual size of @set
- *
- * Check if FD is already in @set or not.
- *
- * Returns true if @set contains @fd,
- * false otherwise.
- */
-static bool
-virCommandFDIsSet(int fd,
-                  const int *set,
-                  int set_size)
-{
-    int i = 0;
-
-    while (i < set_size)
-        if (set[i++] == fd)
-            return true;
-
-    return false;
-}
-
-/*
- * virCommandFDSet:
- * @fd: FD to be put into @set
- * @set: the set
- * @set_size: actual size of @set
- *
- * This is practically generalized implementation
- * of FD_SET() as we do not want to be limited
- * by FD_SETSIZE.
- *
- * Returns: 0 on success,
- *          -1 on usage error,
- *          ENOMEM on OOM
- */
-static int
-virCommandFDSet(int fd,
-                int **set,
-                int *set_size)
-{
-    if (fd < 0 || !set || !set_size)
-        return -1;
-
-    if (virCommandFDIsSet(fd, *set, *set_size))
-        return 0;
-
-    if (VIR_REALLOC_N(*set, *set_size + 1) < 0) {
-        return ENOMEM;
-    }
-
-    (*set)[*set_size] = fd;
-    (*set_size)++;
-
-    return 0;
-}
-
-#ifndef WIN32
-
-static int virClearCapabilities(void) ATTRIBUTE_UNUSED;
-
-# if HAVE_CAPNG
-static int virClearCapabilities(void)
-{
-    int ret;
-
-    capng_clear(CAPNG_SELECT_BOTH);
-
-    if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("cannot clear process capabilities %d"), ret);
-        return -1;
-    }
-
-    return 0;
-}
-
-/**
- * virSetCapabilities:
- *  @capabilities - capability flag to set.
- *                  In case of 0, this function is identical to
- *                  virClearCapabilities()
- *
- */
-static int virSetCapabilities(unsigned long long capabilities)
-{
-    int ret, i;
-
-    capng_clear(CAPNG_SELECT_BOTH);
-
-    for (i = 0; i <= CAP_LAST_CAP; i++) {
-        if (capabilities & (1ULL << i))
-            capng_update(CAPNG_ADD, CAPNG_BOUNDING_SET, i);
-    }
-
-    if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("cannot apply process capabilities %d"), ret);
-        return -1;
-    }
-
-    return 0;
-}
-# else
-static int virClearCapabilities(void)
-{
-//    VIR_WARN("libcap-ng support not compiled in, unable to clear "
-//             "capabilities");
-    return 0;
-}
-
-static int
-virSetCapabilities(unsigned long long capabilities ATTRIBUTE_UNUSED)
-{
-    return 0;
-}
-# endif
-
-/**
- * virFork:
- * @pid - a pointer to a pid_t that will receive the return value from
- *        fork()
- *
- * fork a new process while avoiding various race/deadlock conditions
- *
- * on return from virFork(), if *pid < 0, the fork failed and there is
- * no new process. Otherwise, just like fork(), if *pid == 0, it is the
- * child process returning, and if *pid > 0, it is the parent.
- *
- * Even if *pid >= 0, if the return value from virFork() is < 0, it
- * indicates a failure that occurred in the parent or child process
- * after the fork. In this case, the child process should call
- * _exit(EXIT_FAILURE) after doing any additional error reporting.
- */
-int
-virFork(pid_t *pid)
-{
-    sigset_t oldmask, newmask;
-    struct sigaction sig_action;
-    int saved_errno, ret = -1;
-
-    *pid = -1;
-
-    /*
-     * Need to block signals now, so that child process can safely
-     * kill off caller's signal handlers without a race.
-     */
-    sigfillset(&newmask);
-    if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) {
-        saved_errno = errno;
-        virReportSystemError(errno,
-                             "%s", _("cannot block signals"));
-        goto cleanup;
-    }
-
-    /* Ensure we hold the logging lock, to protect child processes
-     * from deadlocking on another thread's inherited mutex state */
-    virLogLock();
-
-    *pid = fork();
-    saved_errno = errno; /* save for caller */
-
-    /* Unlock for both parent and child process */
-    virLogUnlock();
-
-    if (*pid < 0) {
-        /* attempt to restore signal mask, but ignore failure, to
-           avoid obscuring the fork failure */
-        ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL));
-        virReportSystemError(saved_errno,
-                             "%s", _("cannot fork child process"));
-        goto cleanup;
-    }
-
-    if (*pid) {
-
-        /* parent process */
-
-        /* Restore our original signal mask now that the child is
-           safely running */
-        if (pthread_sigmask(SIG_SETMASK, &oldmask, NULL) != 0) {
-            saved_errno = errno; /* save for caller */
-            virReportSystemError(errno, "%s", _("cannot unblock signals"));
-            goto cleanup;
-        }
-        ret = 0;
-
-    } else {
-
-        /* child process */
-
-        int logprio;
-        int i;
-
-        /* Remove any error callback so errors in child now
-           get sent to stderr where they stand a fighting chance
-           of being seen / logged */
-        virSetErrorFunc(NULL, NULL);
-        virSetErrorLogPriorityFunc(NULL);
-
-        /* Make sure any hook logging is sent to stderr, since child
-         * process may close the logfile FDs */
-        logprio = virLogGetDefaultPriority();
-        virLogReset();
-        virLogSetDefaultPriority(logprio);
-
-        /* Clear out all signal handlers from parent so nothing
-           unexpected can happen in our child once we unblock
-           signals */
-        sig_action.sa_handler = SIG_DFL;
-        sig_action.sa_flags = 0;
-        sigemptyset(&sig_action.sa_mask);
-
-        for (i = 1; i < NSIG; i++) {
-            /* Only possible errors are EFAULT or EINVAL
-               The former wont happen, the latter we
-               expect, so no need to check return value */
-
-            sigaction(i, &sig_action, NULL);
-        }
-
-        /* Unmask all signals in child, since we've no idea
-           what the caller's done with their signal mask
-           and don't want to propagate that to children */
-        sigemptyset(&newmask);
-        if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) {
-            saved_errno = errno; /* save for caller */
-            virReportSystemError(errno, "%s", _("cannot unblock signals"));
-            goto cleanup;
-        }
-        ret = 0;
-    }
-
-cleanup:
-    if (ret < 0)
-        errno = saved_errno;
-    return ret;
-}
-
-/*
- * Ensure that *null is an fd visiting /dev/null.  Return 0 on
- * success, -1 on failure.  Allows for lazy opening of shared
- * /dev/null fd only as required.
- */
-static int
-getDevNull(int *null)
-{
-    if (*null == -1 && (*null = open("/dev/null", O_RDWR|O_CLOEXEC)) < 0) {
-        virReportSystemError(errno,
-                             _("cannot open %s"),
-                             "/dev/null");
-        return -1;
-    }
-    return 0;
-}
-
-/* Ensure that STD is an inheritable copy of FD.  Return 0 on success,
- * -1 on failure.  */
-static int
-prepareStdFd(int fd, int std)
-{
-    if (fd == std)
-        return virSetInherit(fd, true);
-    if (dup2(fd, std) != std)
-        return -1;
-    return 0;
-}
-
-/*
- * @argv argv to exec
- * @envp optional environment to use for exec
- * @keepfd options fd_ret to keep open for child process
- * @retpid optional pointer to store child process pid
- * @infd optional file descriptor to use as child input, otherwise /dev/null
- * @outfd optional pointer to communicate output fd behavior
- *        outfd == NULL : Use /dev/null
- *        *outfd == -1  : Use a new fd
- *        *outfd != -1  : Use *outfd
- * @errfd optional pointer to communcate error fd behavior. See outfd
- * @flags possible combination of the following:
- *        VIR_EXEC_NONE     : Default function behavior
- *        VIR_EXEC_NONBLOCK : Set child process output fd's as non-blocking
- *        VIR_EXEC_DAEMON   : Daemonize the child process
- * @hook optional virExecHook function to call prior to exec
- * @data data to pass to the hook function
- * @pidfile path to use as pidfile for daemonized process (needs DAEMON flag)
- * @capabilities capabilities to keep
- */
-static int
-virExecWithHook(const char *const*argv,
-                const char *const*envp,
-                const int *keepfd,
-                int keepfd_size,
-                pid_t *retpid,
-                int infd, int *outfd, int *errfd,
-                unsigned int flags,
-                virExecHook hook,
-                void *data,
-                char *pidfile,
-                unsigned long long capabilities)
-{
-    pid_t pid;
-    int null = -1, i, openmax;
-    int pipeout[2] = {-1,-1};
-    int pipeerr[2] = {-1,-1};
-    int childout = -1;
-    int childerr = -1;
-    int tmpfd;
-    const char *binary = NULL;
-    int forkRet;
-
-    if (argv[0][0] != '/') {
-        if (!(binary = virFindFileInPath(argv[0]))) {
-            virReportSystemError(ENOENT,
-                                 _("Cannot find '%s' in path"),
-                                 argv[0]);
-            return -1;
-        }
-    } else {
-        binary = argv[0];
-    }
-
-    if (infd < 0) {
-        if (getDevNull(&null) < 0)
-            goto cleanup;
-        infd = null;
-    }
-
-    if (outfd != NULL) {
-        if (*outfd == -1) {
-            if (pipe2(pipeout, O_CLOEXEC) < 0) {
-                virReportSystemError(errno,
-                                     "%s", _("cannot create pipe"));
-                goto cleanup;
-            }
-
-            if ((flags & VIR_EXEC_NONBLOCK) &&
-                virSetNonBlock(pipeout[0]) == -1) {
-                virReportSystemError(errno,
-                                     "%s", _("Failed to set non-blocking file descriptor flag"));
-                goto cleanup;
-            }
-
-            childout = pipeout[1];
-        } else {
-            childout = *outfd;
-        }
-    } else {
-        if (getDevNull(&null) < 0)
-            goto cleanup;
-        childout = null;
-    }
-
-    if (errfd != NULL) {
-        if (errfd == outfd) {
-            childerr = childout;
-        } else if (*errfd == -1) {
-            if (pipe2(pipeerr, O_CLOEXEC) < 0) {
-                virReportSystemError(errno,
-                                     "%s", _("Failed to create pipe"));
-                goto cleanup;
-            }
-
-            if ((flags & VIR_EXEC_NONBLOCK) &&
-                virSetNonBlock(pipeerr[0]) == -1) {
-                virReportSystemError(errno,
-                                     "%s", _("Failed to set non-blocking file descriptor flag"));
-                goto cleanup;
-            }
-
-            childerr = pipeerr[1];
-        } else {
-            childerr = *errfd;
-        }
-    } else {
-        if (getDevNull(&null) < 0)
-            goto cleanup;
-        childerr = null;
-    }
-
-    forkRet = virFork(&pid);
-
-    if (pid < 0) {
-        goto cleanup;
-    }
-
-    if (pid) { /* parent */
-        if (forkRet < 0) {
-            goto cleanup;
-        }
-
-        VIR_FORCE_CLOSE(null);
-        if (outfd && *outfd == -1) {
-            VIR_FORCE_CLOSE(pipeout[1]);
-            *outfd = pipeout[0];
-        }
-        if (errfd && *errfd == -1) {
-            VIR_FORCE_CLOSE(pipeerr[1]);
-            *errfd = pipeerr[0];
-        }
-
-        *retpid = pid;
-
-        if (binary != argv[0])
-            VIR_FREE(binary);
-
-        return 0;
-    }
-
-    /* child */
-
-    if (forkRet < 0) {
-        /* The fork was successful, but after that there was an error
-         * in the child (which was already logged).
-        */
-        goto fork_error;
-    }
-
-    openmax = sysconf(_SC_OPEN_MAX);
-    for (i = 3; i < openmax; i++) {
-        if (i == infd || i == childout || i == childerr)
-            continue;
-        if (!keepfd || !virCommandFDIsSet(i, keepfd, keepfd_size)) {
-            tmpfd = i;
-            VIR_MASS_CLOSE(tmpfd);
-        } else if (virSetInherit(i, true) < 0) {
-            virReportSystemError(errno, _("failed to preserve fd %d"), i);
-            goto fork_error;
-        }
-    }
-
-    if (prepareStdFd(infd, STDIN_FILENO) < 0) {
-        virReportSystemError(errno,
-                             "%s", _("failed to setup stdin file handle"));
-        goto fork_error;
-    }
-    if (childout > 0 && prepareStdFd(childout, STDOUT_FILENO) < 0) {
-        virReportSystemError(errno,
-                             "%s", _("failed to setup stdout file handle"));
-        goto fork_error;
-    }
-    if (childerr > 0 && prepareStdFd(childerr, STDERR_FILENO) < 0) {
-        virReportSystemError(errno,
-                             "%s", _("failed to setup stderr file handle"));
-        goto fork_error;
-    }
-
-    if (infd != STDIN_FILENO && infd != null && infd != childerr &&
-        infd != childout)
-        VIR_FORCE_CLOSE(infd);
-    if (childout > STDERR_FILENO && childout != null && childout != childerr)
-        VIR_FORCE_CLOSE(childout);
-    if (childerr > STDERR_FILENO && childerr != null)
-        VIR_FORCE_CLOSE(childerr);
-    VIR_FORCE_CLOSE(null);
-
-    /* Initialize full logging for a while */
-    virLogSetFromEnv();
-
-    /* Daemonize as late as possible, so the parent process can detect
-     * the above errors with wait* */
-    if (flags & VIR_EXEC_DAEMON) {
-        if (setsid() < 0) {
-            virReportSystemError(errno,
-                                 "%s", _("cannot become session leader"));
-            goto fork_error;
-        }
-
-        if (chdir("/") < 0) {
-            virReportSystemError(errno,
-                                 "%s", _("cannot change to root directory"));
-            goto fork_error;
-        }
-
-        pid = fork();
-        if (pid < 0) {
-            virReportSystemError(errno,
-                                 "%s", _("cannot fork child process"));
-            goto fork_error;
-        }
-
-        if (pid > 0) {
-            if (pidfile && (virPidFileWritePath(pidfile,pid) < 0)) {
-                kill(pid, SIGTERM);
-                usleep(500*1000);
-                kill(pid, SIGTERM);
-                virReportSystemError(errno,
-                                     _("could not write pidfile %s for %d"),
-                                     pidfile, pid);
-                goto fork_error;
-            }
-            _exit(0);
-        }
-    }
-
-    if (hook) {
-        /* virFork reset all signal handlers to the defaults.
-         * This is good for the child process, but our hook
-         * risks running something that generates SIGPIPE,
-         * so we need to temporarily block that again
-         */
-        struct sigaction waxon, waxoff;
-        memset(&waxoff, 0, sizeof(waxoff));
-        waxoff.sa_handler = SIG_IGN;
-        sigemptyset(&waxoff.sa_mask);
-        memset(&waxon, 0, sizeof(waxon));
-        if (sigaction(SIGPIPE, &waxoff, &waxon) < 0) {
-            virReportSystemError(errno, "%s",
-                                 _("Could not disable SIGPIPE"));
-            goto fork_error;
-        }
-
-        if ((hook)(data) != 0) {
-            VIR_DEBUG("Hook function failed.");
-            goto fork_error;
-        }
-
-        if (sigaction(SIGPIPE, &waxon, NULL) < 0) {
-            virReportSystemError(errno, "%s",
-                                 _("Could not re-enable SIGPIPE"));
-            goto fork_error;
-        }
-    }
-
-    /* The steps above may need todo something privileged, so
-     * we delay clearing capabilities until the last minute */
-    if (capabilities || (flags & VIR_EXEC_CLEAR_CAPS))
-        if (virSetCapabilities(capabilities) < 0)
-            goto fork_error;
-
-    /* Close logging again to ensure no FDs leak to child */
-    virLogReset();
-
-    if (envp)
-        execve(binary, (char **) argv, (char**)envp);
-    else
-        execv(binary, (char **) argv);
-
-    virReportSystemError(errno,
-                         _("cannot execute binary %s"),
-                         argv[0]);
-
- fork_error:
-    virDispatchError(NULL);
-    _exit(EXIT_FAILURE);
-
- cleanup:
-    /* This is cleanup of parent process only - child
-       should never jump here on error */
-
-    if (binary != argv[0])
-        VIR_FREE(binary);
-
-    /* NB we don't virReportError() on any failures here
-       because the code which jumped here already raised
-       an error condition which we must not overwrite */
-    VIR_FORCE_CLOSE(pipeerr[0]);
-    VIR_FORCE_CLOSE(pipeerr[1]);
-    VIR_FORCE_CLOSE(pipeout[0]);
-    VIR_FORCE_CLOSE(pipeout[1]);
-    VIR_FORCE_CLOSE(null);
-    return -1;
-}
-
-/**
- * virRun:
- * @argv NULL terminated argv to run
- * @status optional variable to return exit status in
- *
- * Run a command without using the shell.
- *
- * If status is NULL, then return 0 if the command run and
- * exited with 0 status; Otherwise return -1
- *
- * If status is not-NULL, then return 0 if the command ran.
- * The status variable is filled with the command exit status
- * and should be checked by caller for success. Return -1
- * only if the command could not be run.
- */
-int
-virRun(const char *const*argv, int *status)
-{
-    int ret;
-    virCommandPtr cmd = virCommandNewArgs(argv);
-
-    ret = virCommandRun(cmd, status);
-    virCommandFree(cmd);
-    return ret;
-}
-
-#else /* WIN32 */
-
-int
-virRun(const char *const *argv ATTRIBUTE_UNUSED,
-       int *status)
-{
-    if (status)
-        *status = ENOTSUP;
-    else
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       "%s", _("virRun is not implemented for WIN32"));
-    return -1;
-}
-
-static int
-virExecWithHook(const char *const*argv ATTRIBUTE_UNUSED,
-                const char *const*envp ATTRIBUTE_UNUSED,
-                const int *keepfd ATTRIBUTE_UNUSED,
-                int keepfd_size ATTRIBUTE_UNUSED,
-                pid_t *retpid ATTRIBUTE_UNUSED,
-                int infd ATTRIBUTE_UNUSED,
-                int *outfd ATTRIBUTE_UNUSED,
-                int *errfd ATTRIBUTE_UNUSED,
-                int flags_unused ATTRIBUTE_UNUSED,
-                virExecHook hook ATTRIBUTE_UNUSED,
-                void *data ATTRIBUTE_UNUSED,
-                char *pidfile ATTRIBUTE_UNUSED,
-                unsigned long long capabilities ATTRIBUTE_UNUSED)
-{
-    /* XXX: Some day we can implement pieces of virCommand/virExec on
-     * top of _spawn() or CreateProcess(), but we can't implement
-     * everything, since mingw completely lacks fork(), so we cannot
-     * run hook code in the child.  */
-    virReportError(VIR_ERR_INTERNAL_ERROR,
-                   "%s", _("virExec is not implemented for WIN32"));
-    return -1;
-}
-
-int
-virFork(pid_t *pid)
-{
-    *pid = -1;
-    errno = ENOTSUP;
-
-    return -1;
-}
-
-#endif /* WIN32 */
-
-
-/**
- * virCommandNew:
- * @binary: program to run
- *
- * Create a new command for named binary.  If @binary is relative,
- * it will be found via a PATH search of the parent's PATH (and not
- * any altered PATH set by virCommandAddEnv* commands).
- */
-virCommandPtr
-virCommandNew(const char *binary)
-{
-    const char *const args[] = { binary, NULL };
-
-    return virCommandNewArgs(args);
-}
-
-/**
- * virCommandNewArgs:
- * @args: array of arguments
- *
- * Create a new command with a NULL terminated
- * set of args, taking binary from args[0].  More arguments can
- * be added later.  @args[0] is handled like @binary of virCommandNew.
- */
-virCommandPtr
-virCommandNewArgs(const char *const*args)
-{
-    virCommandPtr cmd;
-
-    if (VIR_ALLOC(cmd) < 0)
-        return NULL;
-
-    cmd->handshakeWait[0] = -1;
-    cmd->handshakeWait[1] = -1;
-    cmd->handshakeNotify[0] = -1;
-    cmd->handshakeNotify[1] = -1;
-
-    cmd->infd = cmd->outfd = cmd->errfd = -1;
-    cmd->pid = -1;
-
-    virCommandAddArgSet(cmd, args);
-
-    return cmd;
-}
-
-/**
- * virCommandNewArgList:
- * @binary: program to run
- * @...: additional arguments
- *
- * Create a new command with a NULL terminated
- * list of args, starting with the binary to run.  More arguments can
- * be added later.  @binary is handled as in virCommandNew.
- */
-virCommandPtr
-virCommandNewArgList(const char *binary, ...)
-{
-    virCommandPtr cmd = virCommandNew(binary);
-    va_list list;
-    const char *arg;
-
-    if (!cmd || cmd->has_error)
-        return cmd;
-
-    va_start(list, binary);
-    while ((arg = va_arg(list, const char *)) != NULL)
-        virCommandAddArg(cmd, arg);
-    va_end(list);
-    return cmd;
-}
-
-/**
- * virCommandNewVAList:
- * @binary: program to run
- * @va_list: additional arguments
- *
- * Create a new command with a NULL terminated
- * variable argument list.  @binary is handled as in virCommandNew.
- */
-virCommandPtr
-virCommandNewVAList(const char *binary, va_list list)
-{
-    virCommandPtr cmd = virCommandNew(binary);
-    const char *arg;
-
-    if (!cmd || cmd->has_error)
-        return cmd;
-
-    while ((arg = va_arg(list, const char *)) != NULL)
-        virCommandAddArg(cmd, arg);
-    return cmd;
-}
-
-
-/*
- * Preserve the specified file descriptor in the child, instead of
- * closing it.  FD must not be one of the three standard streams.  If
- * transfer is true, then fd will be closed in the parent after a call
- * to Run/RunAsync/Free, otherwise caller is still responsible for fd.
- * Returns true if a transferring caller should close FD now, and
- * false if the transfer is successfully recorded.
- */
-static bool
-virCommandKeepFD(virCommandPtr cmd, int fd, bool transfer)
-{
-    int ret = 0;
-
-    if (!cmd)
-        return fd > STDERR_FILENO;
-
-    if (fd <= STDERR_FILENO ||
-        (ret = virCommandFDSet(fd, &cmd->preserve, &cmd->preserve_size)) ||
-        (transfer && (ret = virCommandFDSet(fd, &cmd->transfer,
-                                            &cmd->transfer_size)))) {
-        if (!cmd->has_error)
-            cmd->has_error = ret ? ret : -1 ;
-        VIR_DEBUG("cannot preserve %d", fd);
-        return fd > STDERR_FILENO;
-    }
-
-    return false;
-}
-
-/**
- * virCommandPreserveFD:
- * @cmd: the command to modify
- * @fd: fd to mark for inheritance into child
- *
- * Preserve the specified file descriptor
- * in the child, instead of closing it on exec.
- * The parent is still responsible for managing fd.
- */
-void
-virCommandPreserveFD(virCommandPtr cmd, int fd)
-{
-    virCommandKeepFD(cmd, fd, false);
-}
-
-/**
- * virCommandTransferFD:
- * @cmd: the command to modify
- * @fd: fd to reassign to the child
- *
- * Transfer the specified file descriptor
- * to the child, instead of closing it on exec.
- * The parent should no longer use fd, and the parent's copy will
- * be automatically closed no later than during Run/RunAsync/Free.
- */
-void
-virCommandTransferFD(virCommandPtr cmd, int fd)
-{
-    if (virCommandKeepFD(cmd, fd, true))
-        VIR_FORCE_CLOSE(fd);
-}
-
-
-/**
- * virCommandSetPidFile:
- * @cmd: the command to modify
- * @pidfile: filename to use
- *
- * Save the child PID in a pidfile.  The pidfile will be populated
- * before the exec of the child.
- */
-void
-virCommandSetPidFile(virCommandPtr cmd, const char *pidfile)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    VIR_FREE(cmd->pidfile);
-    if (!(cmd->pidfile = strdup(pidfile))) {
-        cmd->has_error = ENOMEM;
-    }
-}
-
-
-/**
- * virCommandClearCaps:
- * @cmd: the command to modify
- *
- * Remove all capabilities from the child, after any hooks have been run.
- */
-void
-virCommandClearCaps(virCommandPtr cmd)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    cmd->flags |= VIR_EXEC_CLEAR_CAPS;
-}
-
-/**
- * virCommandAllowCap:
- * @cmd: the command to modify
- * @capability: what to allow
- *
- * Allow specific capabilities
- */
-void
-virCommandAllowCap(virCommandPtr cmd,
-                   int capability)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    cmd->capabilities |= (1ULL << capability);
-}
-
-
-
-/**
- * virCommandDaemonize:
- * @cmd: the command to modify
- *
- * Daemonize the child process.  The child will have a current working
- * directory of /, and must be started with virCommandRun, which will
- * complete as soon as the daemon grandchild has started.
- */
-void
-virCommandDaemonize(virCommandPtr cmd)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    cmd->flags |= VIR_EXEC_DAEMON;
-}
-
-/**
- * virCommandNonblockingFDs:
- * @cmd: the command to modify
- *
- * Set FDs created by virCommandSetOutputFD and virCommandSetErrorFD
- * as non-blocking in the parent.
- */
-void
-virCommandNonblockingFDs(virCommandPtr cmd)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    cmd->flags |= VIR_EXEC_NONBLOCK;
-}
-
-/* Add an environment variable to the cmd->env list.  'env' is a
- * string like "name=value".  If the named environment variable is
- * already set, then it is replaced in the list.
- */
-static inline void
-virCommandAddEnv(virCommandPtr cmd, char *env)
-{
-    size_t namelen;
-    size_t i;
-
-    /* Search for the name in the existing environment. */
-    namelen = strcspn(env, "=");
-    for (i = 0; i < cmd->nenv; ++i) {
-        /* + 1 because we want to match the '=' character too. */
-        if (STREQLEN(cmd->env[i], env, namelen + 1)) {
-            VIR_FREE(cmd->env[i]);
-            cmd->env[i] = env;
-            return;
-        }
-    }
-
-    /* Arg plus trailing NULL. */
-    if (VIR_RESIZE_N(cmd->env, cmd->maxenv, cmd->nenv, 1 + 1) < 0) {
-        VIR_FREE(env);
-        cmd->has_error = ENOMEM;
-        return;
-    }
-
-    cmd->env[cmd->nenv++] = env;
-}
-
-/**
- * virCommandAddEnvFormat:
- * @cmd: the command to modify
- * @format: format of arguments, end result must be in name=value format
- * @...: arguments to be formatted
- *
- * Add an environment variable to the child created by a printf-style format.
- */
-void
-virCommandAddEnvFormat(virCommandPtr cmd, const char *format, ...)
-{
-    char *env;
-    va_list list;
-
-    if (!cmd || cmd->has_error)
-        return;
-
-    va_start(list, format);
-    if (virVasprintf(&env, format, list) < 0) {
-        cmd->has_error = ENOMEM;
-        va_end(list);
-        return;
-    }
-    va_end(list);
-
-    virCommandAddEnv(cmd, env);
-}
-
-/**
- * virCommandAddEnvPair:
- * @cmd: the command to modify
- * @name: variable name, must not contain =
- * @value: value to assign to name
- *
- * Add an environment variable to the child
- * using separate name & value strings
- */
-void
-virCommandAddEnvPair(virCommandPtr cmd, const char *name, const char *value)
-{
-    virCommandAddEnvFormat(cmd, "%s=%s", name, value);
-}
-
-
-/**
- * virCommandAddEnvString:
- * @cmd: the command to modify
- * @str: name=value format
- *
- * Add an environment variable to the child
- * using a preformatted env string FOO=BAR
- */
-void
-virCommandAddEnvString(virCommandPtr cmd, const char *str)
-{
-    char *env;
-
-    if (!cmd || cmd->has_error)
-        return;
-
-    if (!(env = strdup(str))) {
-        cmd->has_error = ENOMEM;
-        return;
-    }
-
-    virCommandAddEnv(cmd, env);
-}
-
-
-/**
- * virCommandAddEnvBuffer:
- * @cmd: the command to modify
- * @buf: buffer that contains name=value string, which will be reset on return
- *
- * Convert a buffer containing preformatted name=value into an
- * environment variable of the child.
- * Correctly transfers memory errors or contents from buf to cmd.
- */
-void
-virCommandAddEnvBuffer(virCommandPtr cmd, virBufferPtr buf)
-{
-    if (!cmd || cmd->has_error) {
-        virBufferFreeAndReset(buf);
-        return;
-    }
-
-    if (virBufferError(buf)) {
-        cmd->has_error = ENOMEM;
-        virBufferFreeAndReset(buf);
-        return;
-    }
-    if (!virBufferUse(buf)) {
-        cmd->has_error = EINVAL;
-        return;
-    }
-
-    virCommandAddEnv(cmd, virBufferContentAndReset(buf));
-}
-
-
-/**
- * virCommandAddEnvPass:
- * @cmd: the command to modify
- * @name: the name to look up in current environment
- *
- * Pass an environment variable to the child
- * using current process' value
- */
-void
-virCommandAddEnvPass(virCommandPtr cmd, const char *name)
-{
-    char *value;
-    if (!cmd || cmd->has_error)
-        return;
-
-    value = getenv(name);
-    if (value)
-        virCommandAddEnvPair(cmd, name, value);
-}
-
-
-/**
- * virCommandAddEnvPassCommon:
- * @cmd: the command to modify
- *
- * Set LC_ALL to C, and propagate other essential environment
- * variables (such as PATH) from the parent process.
- */
-void
-virCommandAddEnvPassCommon(virCommandPtr cmd)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    /* Attempt to Pre-allocate; allocation failure will be detected
-     * later during virCommandAdd*.  */
-    ignore_value(VIR_RESIZE_N(cmd->env, cmd->maxenv, cmd->nenv, 9));
-
-    virCommandAddEnvPair(cmd, "LC_ALL", "C");
-
-    virCommandAddEnvPass(cmd, "LD_PRELOAD");
-    virCommandAddEnvPass(cmd, "LD_LIBRARY_PATH");
-    virCommandAddEnvPass(cmd, "PATH");
-    virCommandAddEnvPass(cmd, "HOME");
-    virCommandAddEnvPass(cmd, "USER");
-    virCommandAddEnvPass(cmd, "LOGNAME");
-    virCommandAddEnvPass(cmd, "TMPDIR");
-}
-
-/**
- * virCommandAddArg:
- * @cmd: the command to modify
- * @val: the argument to add
- *
- * Add a command line argument to the child
- */
-void
-virCommandAddArg(virCommandPtr cmd, const char *val)
-{
-    char *arg;
-
-    if (!cmd || cmd->has_error)
-        return;
-
-    if (!(arg = strdup(val))) {
-        cmd->has_error = ENOMEM;
-        return;
-    }
-
-    /* Arg plus trailing NULL. */
-    if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, 1 + 1) < 0) {
-        VIR_FREE(arg);
-        cmd->has_error = ENOMEM;
-        return;
-    }
-
-    cmd->args[cmd->nargs++] = arg;
-}
-
-
-/**
- * virCommandAddArgBuffer:
- * @cmd: the command to modify
- * @buf: buffer that contains argument string, which will be reset on return
- *
- * Convert a buffer into a command line argument to the child.
- * Correctly transfers memory errors or contents from buf to cmd.
- */
-void
-virCommandAddArgBuffer(virCommandPtr cmd, virBufferPtr buf)
-{
-    if (!cmd || cmd->has_error) {
-        virBufferFreeAndReset(buf);
-        return;
-    }
-
-    /* Arg plus trailing NULL. */
-    if (virBufferError(buf) ||
-        VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, 1 + 1) < 0) {
-        cmd->has_error = ENOMEM;
-        virBufferFreeAndReset(buf);
-        return;
-    }
-
-    cmd->args[cmd->nargs] = virBufferContentAndReset(buf);
-    if (!cmd->args[cmd->nargs])
-        cmd->args[cmd->nargs] = strdup("");
-    if (!cmd->args[cmd->nargs]) {
-        cmd->has_error = ENOMEM;
-        return;
-    }
-    cmd->nargs++;
-}
-
-
-/**
- * virCommandAddArgFormat:
- * @cmd: the command to modify
- * @format: format of arguments, end result must be in name=value format
- * @...: arguments to be formatted
- *
- * Add a command line argument created by a printf-style format.
- */
-void
-virCommandAddArgFormat(virCommandPtr cmd, const char *format, ...)
-{
-    char *arg;
-    va_list list;
-
-    if (!cmd || cmd->has_error)
-        return;
-
-    va_start(list, format);
-    if (virVasprintf(&arg, format, list) < 0) {
-        cmd->has_error = ENOMEM;
-        va_end(list);
-        return;
-    }
-    va_end(list);
-
-    /* Arg plus trailing NULL. */
-    if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, 1 + 1) < 0) {
-        VIR_FREE(arg);
-        cmd->has_error = ENOMEM;
-        return;
-    }
-
-    cmd->args[cmd->nargs++] = arg;
-}
-
-/**
- * virCommandAddArgPair:
- * @cmd: the command to modify
- * @name: left half of argument
- * @value: right half of argument
- *
- * Add "NAME=VAL" as a single command line argument to the child
- */
-void
-virCommandAddArgPair(virCommandPtr cmd, const char *name, const char *val)
-{
-    virCommandAddArgFormat(cmd, "%s=%s", name, val);
-}
-
-/**
- * virCommandAddArgSet:
- * @cmd: the command to modify
- * @vals: array of arguments to add
- *
- * Add a NULL terminated list of args
- */
-void
-virCommandAddArgSet(virCommandPtr cmd, const char *const*vals)
-{
-    int narg = 0;
-
-    if (!cmd || cmd->has_error)
-        return;
-
-    if (vals[0] == NULL) {
-        cmd->has_error = EINVAL;
-        return;
-    }
-
-    while (vals[narg] != NULL)
-        narg++;
-
-    /* narg plus trailing NULL. */
-    if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, narg + 1) < 0) {
-        cmd->has_error = ENOMEM;
-        return;
-    }
-
-    narg = 0;
-    while (vals[narg] != NULL) {
-        char *arg = strdup(vals[narg++]);
-        if (!arg) {
-            cmd->has_error = ENOMEM;
-            return;
-        }
-        cmd->args[cmd->nargs++] = arg;
-    }
-}
-
-/**
- * virCommandAddArgList:
- * @cmd: the command to modify
- * @...: list of arguments to add
- *
- * Add a NULL terminated list of args.
- */
-void
-virCommandAddArgList(virCommandPtr cmd, ...)
-{
-    va_list list;
-    int narg = 0;
-
-    if (!cmd || cmd->has_error)
-        return;
-
-    va_start(list, cmd);
-    while (va_arg(list, const char *) != NULL)
-        narg++;
-    va_end(list);
-
-    /* narg plus trailing NULL. */
-    if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, narg + 1) < 0) {
-        cmd->has_error = ENOMEM;
-        return;
-    }
-
-    va_start(list, cmd);
-    while (1) {
-        char *arg = va_arg(list, char *);
-        if (!arg)
-            break;
-        arg = strdup(arg);
-        if (!arg) {
-            cmd->has_error = ENOMEM;
-            va_end(list);
-            return;
-        }
-        cmd->args[cmd->nargs++] = arg;
-    }
-    va_end(list);
-}
-
-/**
- * virCommandSetWorkingDirectory:
- * @cmd: the command to modify
- * @pwd: directory to use
- *
- * Set the working directory of a non-daemon child process, rather
- * than the parent's working directory.  Daemons automatically get /
- * without using this call.
- */
-void
-virCommandSetWorkingDirectory(virCommandPtr cmd, const char *pwd)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    if (cmd->pwd) {
-        cmd->has_error = -1;
-        VIR_DEBUG("cannot set directory twice");
-    } else {
-        cmd->pwd = strdup(pwd);
-        if (!cmd->pwd)
-            cmd->has_error = ENOMEM;
-    }
-}
-
-
-/**
- * virCommandSetInputBuffer:
- * @cmd: the command to modify
- * @inbuf: string to feed to stdin
- *
- * Feed the child's stdin from a string buffer.  This requires the use
- * of virCommandRun().
- */
-void
-virCommandSetInputBuffer(virCommandPtr cmd, const char *inbuf)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    if (cmd->infd != -1 || cmd->inbuf) {
-        cmd->has_error = -1;
-        VIR_DEBUG("cannot specify input twice");
-        return;
-    }
-
-    cmd->inbuf = strdup(inbuf);
-    if (!cmd->inbuf)
-        cmd->has_error = ENOMEM;
-}
-
-
-/**
- * virCommandSetOutputBuffer:
- * @cmd: the command to modify
- * @outbuf: address of variable to store malloced result buffer
- *
- * Capture the child's stdout to a string buffer.  *outbuf is
- * guaranteed to be allocated after successful virCommandRun or
- * virCommandWait, and is best-effort allocated after failed
- * virCommandRun; caller is responsible for freeing *outbuf.
- * This requires the use of virCommandRun.
- */
-void
-virCommandSetOutputBuffer(virCommandPtr cmd, char **outbuf)
-{
-    *outbuf = NULL;
-    if (!cmd || cmd->has_error)
-        return;
-
-    if (cmd->outfdptr) {
-        cmd->has_error = -1;
-        VIR_DEBUG("cannot specify output twice");
-        return;
-    }
-
-    cmd->outbuf = outbuf;
-    cmd->outfdptr = &cmd->outfd;
-}
-
-
-/**
- * virCommandSetErrorBuffer:
- * @cmd: the command to modify
- * @errbuf: address of variable to store malloced result buffer
- *
- * Capture the child's stderr to a string buffer.  *errbuf is
- * guaranteed to be allocated after successful virCommandRun or
- * virCommandWait, and is best-effort allocated after failed
- * virCommandRun; caller is responsible for freeing *errbuf.
- * This requires the use of virCommandRun.  It is possible to
- * pass the same pointer as for virCommandSetOutputBuffer(), in
- * which case the child process will interleave all output into
- * a single string.
- */
-void
-virCommandSetErrorBuffer(virCommandPtr cmd, char **errbuf)
-{
-    *errbuf = NULL;
-    if (!cmd || cmd->has_error)
-        return;
-
-    if (cmd->errfdptr) {
-        cmd->has_error = -1;
-        VIR_DEBUG("cannot specify stderr twice");
-        return;
-    }
-
-    cmd->errbuf = errbuf;
-    cmd->errfdptr = &cmd->errfd;
-}
-
-
-/**
- * virCommandSetInputFD:
- * @cmd: the command to modify
- * @infd: the descriptor to use
- *
- * Attach a file descriptor to the child's stdin
- */
-void
-virCommandSetInputFD(virCommandPtr cmd, int infd)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    if (cmd->infd != -1 || cmd->inbuf) {
-        cmd->has_error = -1;
-        VIR_DEBUG("cannot specify input twice");
-        return;
-    }
-    if (infd < 0) {
-        cmd->has_error = -1;
-        VIR_DEBUG("cannot specify invalid input fd");
-        return;
-    }
-
-    cmd->infd = infd;
-}
-
-
-/**
- * virCommandSetOutputFD:
- * @cmd: the command to modify
- * @outfd: location of output fd
- *
- * Attach a file descriptor to the child's stdout.  If *@outfd is -1 on
- * entry, then a pipe will be created and returned in this variable when
- * the child is run.  Otherwise, *@outfd is used as the output.
- */
-void
-virCommandSetOutputFD(virCommandPtr cmd, int *outfd)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    if (cmd->outfdptr) {
-        cmd->has_error = -1;
-        VIR_DEBUG("cannot specify output twice");
-        return;
-    }
-
-    cmd->outfdptr = outfd;
-}
-
-
-/**
- * virCommandSetErrorFD:
- * @cmd: the command to modify
- * @errfd: location of error fd
- *
- * Attach a file descriptor to the child's stderr.  If *@errfd is -1 on
- * entry, then a pipe will be created and returned in this variable when
- * the child is run.  Otherwise, *@errfd is used for error collection,
- * and may be the same as outfd given to virCommandSetOutputFD().
- */
-void
-virCommandSetErrorFD(virCommandPtr cmd, int *errfd)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    if (cmd->errfdptr) {
-        cmd->has_error = -1;
-        VIR_DEBUG("cannot specify stderr twice");
-        return;
-    }
-
-    cmd->errfdptr = errfd;
-}
-
-
-/**
- * virCommandSetPreExecHook:
- * @cmd: the command to modify
- * @hook: the hook to run
- * @opaque: argument to pass to the hook
- *
- * Run HOOK(OPAQUE) in the child as the last thing before changing
- * directories, dropping capabilities, and executing the new process.
- * Force the child to fail if HOOK does not return zero.
- *
- * Since @hook runs in the child, it should be careful to avoid
- * any functions that are not async-signal-safe.
- */
-void
-virCommandSetPreExecHook(virCommandPtr cmd, virExecHook hook, void *opaque)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    if (cmd->hook) {
-        cmd->has_error = -1;
-        VIR_DEBUG("cannot specify hook twice");
-        return;
-    }
-    cmd->hook = hook;
-    cmd->opaque = opaque;
-}
-
-
-/**
- * virCommandWriteArgLog:
- * @cmd: the command to log
- * @logfd: where to log the results
- *
- * Call after adding all arguments and environment settings, but before
- * Run/RunAsync, to immediately output the environment and arguments of
- * cmd to logfd.  If virCommandRun cannot succeed (because of an
- * out-of-memory condition while building cmd), nothing will be logged.
- */
-void
-virCommandWriteArgLog(virCommandPtr cmd, int logfd)
-{
-    int ioError = 0;
-    size_t i;
-
-    /* Any errors will be reported later by virCommandRun, which means
-     * no command will be run, so there is nothing to log. */
-    if (!cmd || cmd->has_error)
-        return;
-
-    for (i = 0 ; i < cmd->nenv ; i++) {
-        if (safewrite(logfd, cmd->env[i], strlen(cmd->env[i])) < 0)
-            ioError = errno;
-        if (safewrite(logfd, " ", 1) < 0)
-            ioError = errno;
-    }
-    for (i = 0 ; i < cmd->nargs ; i++) {
-        if (safewrite(logfd, cmd->args[i], strlen(cmd->args[i])) < 0)
-            ioError = errno;
-        if (safewrite(logfd, i == cmd->nargs - 1 ? "\n" : " ", 1) < 0)
-            ioError = errno;
-    }
-
-    if (ioError) {
-        char ebuf[1024];
-        VIR_WARN("Unable to write command %s args to logfile: %s",
-                 cmd->args[0], virStrerror(ioError, ebuf, sizeof(ebuf)));
-    }
-}
-
-
-/**
- * virCommandToString:
- * @cmd: the command to convert
- *
- * Call after adding all arguments and environment settings, but
- * before Run/RunAsync, to return a string representation of the
- * environment and arguments of cmd, suitably quoted for pasting into
- * a shell.  If virCommandRun cannot succeed (because of an
- * out-of-memory condition while building cmd), NULL will be returned.
- * Caller is responsible for freeing the resulting string.
- */
-char *
-virCommandToString(virCommandPtr cmd)
-{
-    size_t i;
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    /* Cannot assume virCommandRun will be called; so report the error
-     * now.  If virCommandRun is called, it will report the same error. */
-    if (!cmd ||cmd->has_error == ENOMEM) {
-        virReportOOMError();
-        return NULL;
-    }
-    if (cmd->has_error) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("invalid use of command API"));
-        return NULL;
-    }
-
-    for (i = 0; i < cmd->nenv; i++) {
-        /* In shell, a='b c' has a different meaning than 'a=b c', so
-         * we must determine where the '=' lives.  */
-        char *eq = strchr(cmd->env[i], '=');
-
-        if (!eq) {
-            virBufferFreeAndReset(&buf);
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("invalid use of command API"));
-            return NULL;
-        }
-        eq++;
-        virBufferAdd(&buf, cmd->env[i], eq - cmd->env[i]);
-        virBufferEscapeShell(&buf, eq);
-        virBufferAddChar(&buf, ' ');
-    }
-    virBufferEscapeShell(&buf, cmd->args[0]);
-    for (i = 1; i < cmd->nargs; i++) {
-        virBufferAddChar(&buf, ' ');
-        virBufferEscapeShell(&buf, cmd->args[i]);
-    }
-
-    if (virBufferError(&buf)) {
-        virBufferFreeAndReset(&buf);
-        virReportOOMError();
-        return NULL;
-    }
-
-    return virBufferContentAndReset(&buf);
-}
-
-
-/*
- * Manage input and output to the child process.
- */
-static int
-virCommandProcessIO(virCommandPtr cmd, int *inpipe)
-{
-    int infd = -1, outfd = -1, errfd = -1;
-    size_t inlen = 0, outlen = 0, errlen = 0;
-    size_t inoff = 0;
-    int ret = 0;
-
-    /* With an input buffer, feed data to child
-     * via pipe */
-    if (cmd->inbuf) {
-        inlen = strlen(cmd->inbuf);
-        infd = *inpipe;
-    }
-
-    /* With out/err buffer, the outfd/errfd have been filled with an
-     * FD for us.  Guarantee an allocated string with partial results
-     * even if we encounter a later failure, as well as freeing any
-     * results accumulated over a prior run of the same command.  */
-    if (cmd->outbuf) {
-        outfd = cmd->outfd;
-        if (VIR_REALLOC_N(*cmd->outbuf, 1) < 0) {
-            virReportOOMError();
-            ret = -1;
-        }
-    }
-    if (cmd->errbuf) {
-        errfd = cmd->errfd;
-        if (VIR_REALLOC_N(*cmd->errbuf, 1) < 0) {
-            virReportOOMError();
-            ret = -1;
-        }
-    }
-    if (ret == -1)
-        goto cleanup;
-    ret = -1;
-
-    for (;;) {
-        int i;
-        struct pollfd fds[3];
-        int nfds = 0;
-
-        if (infd != -1) {
-            fds[nfds].fd = infd;
-            fds[nfds].events = POLLOUT;
-            fds[nfds].revents = 0;
-            nfds++;
-        }
-        if (outfd != -1) {
-            fds[nfds].fd = outfd;
-            fds[nfds].events = POLLIN;
-            fds[nfds].revents = 0;
-            nfds++;
-        }
-        if (errfd != -1) {
-            fds[nfds].fd = errfd;
-            fds[nfds].events = POLLIN;
-            fds[nfds].revents = 0;
-            nfds++;
-        }
-
-        if (nfds == 0)
-            break;
-
-        if (poll(fds, nfds, -1) < 0) {
-            if (errno == EAGAIN || errno == EINTR)
-                continue;
-            virReportSystemError(errno, "%s",
-                                 _("unable to poll on child"));
-            goto cleanup;
-        }
-
-        for (i = 0; i < nfds ; i++) {
-            if (fds[i].revents & (POLLIN | POLLHUP | POLLERR) &&
-                (fds[i].fd == errfd || fds[i].fd == outfd)) {
-                char data[1024];
-                char **buf;
-                size_t *len;
-                int done;
-                if (fds[i].fd == outfd) {
-                    buf = cmd->outbuf;
-                    len = &outlen;
-                } else {
-                    buf = cmd->errbuf;
-                    len = &errlen;
-                }
-                /* Silence a false positive from clang. */
-                sa_assert(buf);
-
-                done = read(fds[i].fd, data, sizeof(data));
-                if (done < 0) {
-                    if (errno != EINTR &&
-                        errno != EAGAIN) {
-                        virReportSystemError(errno, "%s",
-                                             (fds[i].fd == outfd) ?
-                                             _("unable to read child stdout") :
-                                             _("unable to read child stderr"));
-                        goto cleanup;
-                    }
-                } else if (done == 0) {
-                    if (fds[i].fd == outfd)
-                        outfd = -1;
-                    else
-                        errfd = -1;
-                } else {
-                    if (VIR_REALLOC_N(*buf, *len + done + 1) < 0) {
-                        virReportOOMError();
-                        goto cleanup;
-                    }
-                    memcpy(*buf + *len, data, done);
-                    *len += done;
-                }
-            }
-
-            if (fds[i].revents & (POLLOUT | POLLERR) &&
-                fds[i].fd == infd) {
-                int done;
-
-                /* Coverity 5.3.0 can't see that we only get here if
-                 * infd is in the set because it was non-negative.  */
-                sa_assert(infd != -1);
-                done = write(infd, cmd->inbuf + inoff,
-                             inlen - inoff);
-                if (done < 0) {
-                    if (errno == EPIPE) {
-                        VIR_DEBUG("child closed stdin early, ignoring EPIPE "
-                                  "on fd %d", infd);
-                        if (VIR_CLOSE(*inpipe) < 0)
-                            VIR_DEBUG("ignoring failed close on fd %d", infd);
-                        infd = -1;
-                    } else if (errno != EINTR && errno != EAGAIN) {
-                        virReportSystemError(errno, "%s",
-                                             _("unable to write to child input"));
-                        goto cleanup;
-                    }
-                } else {
-                    inoff += done;
-                    if (inoff == inlen) {
-                        if (VIR_CLOSE(*inpipe) < 0)
-                            VIR_DEBUG("ignoring failed close on fd %d", infd);
-                        infd = -1;
-                    }
-                }
-            }
-        }
-    }
-
-    ret = 0;
-cleanup:
-    if (cmd->outbuf && *cmd->outbuf)
-        (*cmd->outbuf)[outlen] = '\0';
-    if (cmd->errbuf && *cmd->errbuf)
-        (*cmd->errbuf)[errlen] = '\0';
-    return ret;
-}
-
-/**
- * virCommandExec:
- * @cmd: command to run
- *
- * Exec the command, replacing the current process. Meant to be called
- * in the hook after already forking / cloning, so does not attempt to
- * daemonize or preserve any FDs.
- *
- * Returns -1 on any error executing the command.
- * Will not return on success.
- */
-#ifndef WIN32
-int virCommandExec(virCommandPtr cmd)
-{
-    if (!cmd ||cmd->has_error == ENOMEM) {
-        virReportOOMError();
-        return -1;
-    }
-    if (cmd->has_error) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("invalid use of command API"));
-        return -1;
-    }
-
-    return execve(cmd->args[0], cmd->args, cmd->env);
-}
-#else
-int virCommandExec(virCommandPtr cmd ATTRIBUTE_UNUSED)
-{
-    /* Mingw execve() has a broken signature. Disable this
-     * function until gnulib fixes the signature, since we
-     * don't really need this on Win32 anyway.
-     */
-    virReportSystemError(ENOSYS, "%s",
-                         _("Executing new processes is not supported on Win32 platform"));
-    return -1;
-}
-#endif
-
-/**
- * virCommandRun:
- * @cmd: command to run
- * @exitstatus: optional status collection
- *
- * Run the command and wait for completion.
- * Returns -1 on any error executing the
- * command. Returns 0 if the command executed,
- * with the exit status set.  If @exitstatus is NULL, then the
- * child must exit with status 0 for this to succeed.
- */
-int
-virCommandRun(virCommandPtr cmd, int *exitstatus)
-{
-    int ret = 0;
-    char *outbuf = NULL;
-    char *errbuf = NULL;
-    int infd[2] = { -1, -1 };
-    struct stat st;
-    bool string_io;
-    bool async_io = false;
-    char *str;
-    int tmpfd;
-
-    if (!cmd ||cmd->has_error == ENOMEM) {
-        virReportOOMError();
-        return -1;
-    }
-    if (cmd->has_error) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("invalid use of command API"));
-        return -1;
-    }
-
-    /* Avoid deadlock, by requiring that any open fd not under our
-     * control must be visiting a regular file, or that we are
-     * daemonized and no string io is required.  */
-    string_io = cmd->inbuf || cmd->outbuf || cmd->errbuf;
-    if (cmd->infd != -1 &&
-        (fstat(cmd->infd, &st) < 0 || !S_ISREG(st.st_mode)))
-        async_io = true;
-    if (cmd->outfdptr && cmd->outfdptr != &cmd->outfd &&
-        (*cmd->outfdptr == -1 ||
-         fstat(*cmd->outfdptr, &st) < 0 || !S_ISREG(st.st_mode)))
-        async_io = true;
-    if (cmd->errfdptr && cmd->errfdptr != &cmd->errfd &&
-        (*cmd->errfdptr == -1 ||
-         fstat(*cmd->errfdptr, &st) < 0 || !S_ISREG(st.st_mode)))
-        async_io = true;
-    if (async_io) {
-        if (!(cmd->flags & VIR_EXEC_DAEMON) || string_io) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("cannot mix caller fds with blocking execution"));
-            return -1;
-        }
-    } else {
-        if ((cmd->flags & VIR_EXEC_DAEMON) && string_io) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("cannot mix string I/O with daemon"));
-            return -1;
-        }
-    }
-
-    /* If we have an input buffer, we need
-     * a pipe to feed the data to the child */
-    if (cmd->inbuf) {
-        if (pipe2(infd, O_CLOEXEC) < 0) {
-            virReportSystemError(errno, "%s",
-                                 _("unable to open pipe"));
-            cmd->has_error = -1;
-            return -1;
-        }
-        cmd->infd = infd[0];
-    }
-
-    /* If caller requested the same string for stdout and stderr, then
-     * merge those into one string.  */
-    if (cmd->outbuf && cmd->outbuf == cmd->errbuf) {
-        cmd->errfdptr = &cmd->outfd;
-        cmd->errbuf = NULL;
-    }
-
-    /* If caller hasn't requested capture of stdout/err, then capture
-     * it ourselves so we can log it.  But the intermediate child for
-     * a daemon has no expected output, and we don't want our
-     * capturing pipes passed on to the daemon grandchild.
-     */
-    if (!(cmd->flags & VIR_EXEC_DAEMON)) {
-        if (!cmd->outfdptr) {
-            cmd->outfdptr = &cmd->outfd;
-            cmd->outbuf = &outbuf;
-            string_io = true;
-        }
-        if (!cmd->errfdptr) {
-            cmd->errfdptr = &cmd->errfd;
-            cmd->errbuf = &errbuf;
-            string_io = true;
-        }
-    }
-
-    cmd->flags |= VIR_EXEC_RUN_SYNC;
-    if (virCommandRunAsync(cmd, NULL) < 0) {
-        if (cmd->inbuf) {
-            tmpfd = infd[0];
-            if (VIR_CLOSE(infd[0]) < 0)
-                VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
-            tmpfd = infd[1];
-            if (VIR_CLOSE(infd[1]) < 0)
-                VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
-        }
-        cmd->has_error = -1;
-        return -1;
-    }
-
-    tmpfd = infd[0];
-    if (VIR_CLOSE(infd[0]) < 0)
-        VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
-    if (string_io)
-        ret = virCommandProcessIO(cmd, &infd[1]);
-
-    if (virCommandWait(cmd, exitstatus) < 0)
-        ret = -1;
-
-    str = (exitstatus ? virProcessTranslateStatus(*exitstatus)
-           : (char *) "status 0");
-    VIR_DEBUG("Result %s, stdout: '%s' stderr: '%s'",
-              NULLSTR(str),
-              cmd->outbuf ? NULLSTR(*cmd->outbuf) : "(null)",
-              cmd->errbuf ? NULLSTR(*cmd->errbuf) : "(null)");
-    if (exitstatus)
-        VIR_FREE(str);
-
-    /* Reset any capturing, in case caller runs
-     * this identical command again */
-    if (cmd->inbuf) {
-        tmpfd = infd[1];
-        if (VIR_CLOSE(infd[1]) < 0)
-            VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
-    }
-    if (cmd->outbuf == &outbuf) {
-        tmpfd = cmd->outfd;
-        if (VIR_CLOSE(cmd->outfd) < 0)
-            VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
-        cmd->outfdptr = NULL;
-        cmd->outbuf = NULL;
-        VIR_FREE(outbuf);
-    }
-    if (cmd->errbuf == &errbuf) {
-        tmpfd = cmd->errfd;
-        if (VIR_CLOSE(cmd->errfd) < 0)
-            VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
-        cmd->errfdptr = NULL;
-        cmd->errbuf = NULL;
-        VIR_FREE(errbuf);
-    }
-
-    return ret;
-}
-
-
-/*
- * Perform all virCommand-specific actions, along with the user hook.
- */
-static int
-virCommandHook(void *data)
-{
-    virCommandPtr cmd = data;
-    int res = 0;
-
-    if (cmd->hook) {
-        VIR_DEBUG("Run hook %p %p", cmd->hook, cmd->opaque);
-        res = cmd->hook(cmd->opaque);
-        VIR_DEBUG("Done hook %d", res);
-    }
-    if (res == 0 && cmd->pwd) {
-        VIR_DEBUG("Running child in %s", cmd->pwd);
-        res = chdir(cmd->pwd);
-        if (res < 0) {
-            virReportSystemError(errno,
-                                 _("Unable to change to %s"), cmd->pwd);
-        }
-    }
-    if (cmd->handshake) {
-        char c = res < 0 ? '0' : '1';
-        int rv;
-        VIR_DEBUG("Notifying parent for handshake start on %d",
-                  cmd->handshakeWait[1]);
-        if (safewrite(cmd->handshakeWait[1], &c, sizeof(c)) != sizeof(c)) {
-            virReportSystemError(errno, "%s",
-                                 _("Unable to notify parent process"));
-            return -1;
-        }
-
-        /* On failure we pass the error message back to parent,
-         * so they don't have to dig through stderr logs
-         */
-        if (res < 0) {
-            virErrorPtr err = virGetLastError();
-            const char *msg = err ? err->message :
-                _("Unknown failure during hook execution");
-            size_t len = strlen(msg) + 1;
-            if (safewrite(cmd->handshakeWait[1], msg, len) != len) {
-                virReportSystemError(errno, "%s",
-                                     _("Unable to send error to parent"));
-                return -1;
-            }
-            return -1;
-        }
-
-        VIR_DEBUG("Waiting on parent for handshake complete on %d",
-                  cmd->handshakeNotify[0]);
-        if ((rv = saferead(cmd->handshakeNotify[0], &c,
-                           sizeof(c))) != sizeof(c)) {
-            if (rv < 0)
-                virReportSystemError(errno, "%s",
-                                     _("Unable to wait on parent process"));
-            else
-                virReportSystemError(EIO, "%s",
-                                     _("libvirtd quit during handshake"));
-            return -1;
-        }
-        if (c != '1') {
-            virReportSystemError(EINVAL,
-                                 _("Unexpected confirm code '%c' from parent"),
-                                 c);
-            return -1;
-        }
-        VIR_FORCE_CLOSE(cmd->handshakeWait[1]);
-        VIR_FORCE_CLOSE(cmd->handshakeNotify[0]);
-    }
-
-    VIR_DEBUG("Hook is done %d", res);
-
-    return res;
-}
-
-
-/**
- * virCommandRunAsync:
- * @cmd: command to start
- * @pid: optional variable to track child pid
- *
- * Run the command asynchronously
- * Returns -1 on any error executing the
- * command. Returns 0 if the command executed.
- *
- * There are two approaches to child process cleanup.
- * 1. Use auto-cleanup, by passing NULL for pid.  The child will be
- * auto-reaped by virCommandFree, unless you reap it earlier via
- * virCommandWait or virCommandAbort.  Good for where cmd is in
- * scope for the duration of the child process.
- * 2. Use manual cleanup, by passing the address of a pid_t variable
- * for pid.  While cmd is still in scope, you may reap the child via
- * virCommandWait or virCommandAbort.  But after virCommandFree, if
- * you have not yet reaped the child, then it continues to run until
- * you call virProcessWait or virProcessAbort.
- */
-int
-virCommandRunAsync(virCommandPtr cmd, pid_t *pid)
-{
-    int ret;
-    char *str;
-    int i;
-    bool synchronous = false;
-
-    if (!cmd || cmd->has_error == ENOMEM) {
-        virReportOOMError();
-        return -1;
-    }
-    if (cmd->has_error) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("invalid use of command API"));
-        return -1;
-    }
-
-    synchronous = cmd->flags & VIR_EXEC_RUN_SYNC;
-    cmd->flags &= ~VIR_EXEC_RUN_SYNC;
-
-    /* Buffer management can only be requested via virCommandRun.  */
-    if ((cmd->inbuf && cmd->infd == -1) ||
-        (cmd->outbuf && cmd->outfdptr != &cmd->outfd) ||
-        (cmd->errbuf && cmd->errfdptr != &cmd->errfd)) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("cannot mix string I/O with asynchronous command"));
-        return -1;
-    }
-
-    if (cmd->pid != -1) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("command is already running as pid %lld"),
-                       (long long) cmd->pid);
-        return -1;
-    }
-
-    if (!synchronous && (cmd->flags & VIR_EXEC_DAEMON)) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("daemonized command cannot use virCommandRunAsync"));
-        return -1;
-    }
-    if (cmd->pwd && (cmd->flags & VIR_EXEC_DAEMON)) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("daemonized command cannot set working directory %s"),
-                       cmd->pwd);
-        return -1;
-    }
-    if (cmd->pidfile && !(cmd->flags & VIR_EXEC_DAEMON)) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("creation of pid file requires daemonized command"));
-        return -1;
-    }
-
-    str = virCommandToString(cmd);
-    VIR_DEBUG("About to run %s", str ? str : cmd->args[0]);
-    VIR_FREE(str);
-
-    ret = virExecWithHook((const char *const *)cmd->args,
-                          (const char *const *)cmd->env,
-                          cmd->preserve,
-                          cmd->preserve_size,
-                          &cmd->pid,
-                          cmd->infd,
-                          cmd->outfdptr,
-                          cmd->errfdptr,
-                          cmd->flags,
-                          virCommandHook,
-                          cmd,
-                          cmd->pidfile,
-                          cmd->capabilities);
-
-    VIR_DEBUG("Command result %d, with PID %d",
-              ret, (int)cmd->pid);
-
-    for (i = 0; i < cmd->transfer_size; i++) {
-        VIR_FORCE_CLOSE(cmd->transfer[i]);
-    }
-    cmd->transfer_size = 0;
-    VIR_FREE(cmd->transfer);
-
-    if (ret == 0 && pid)
-        *pid = cmd->pid;
-    else
-        cmd->reap = true;
-
-    return ret;
-}
-
-
-/**
- * virCommandWait:
- * @cmd: command to wait on
- * @exitstatus: optional status collection
- *
- * Wait for the command previously started with virCommandRunAsync()
- * to complete. Return -1 on any error waiting for
- * completion. Returns 0 if the command
- * finished with the exit status set.  If @exitstatus is NULL, then the
- * child must exit with status 0 for this to succeed.
- */
-int
-virCommandWait(virCommandPtr cmd, int *exitstatus)
-{
-    int ret;
-    int status = 0;
-
-    if (!cmd ||cmd->has_error == ENOMEM) {
-        virReportOOMError();
-        return -1;
-    }
-    if (cmd->has_error) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("invalid use of command API"));
-        return -1;
-    }
-
-    if (cmd->pid == -1) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("command is not yet running"));
-        return -1;
-    }
-
-    /* If virProcessWait reaps pid but then returns failure because
-     * exitstatus was NULL, then a second virCommandWait would risk
-     * calling waitpid on an unrelated process.  Besides, that error
-     * message is not as detailed as what we can provide.  So, we
-     * guarantee that virProcessWait only fails due to failure to wait,
-     * and repeat the exitstatus check code ourselves.  */
-    ret = virProcessWait(cmd->pid, exitstatus ? exitstatus : &status);
-    if (ret == 0) {
-        cmd->pid = -1;
-        cmd->reap = false;
-        if (status) {
-            char *str = virCommandToString(cmd);
-            char *st = virProcessTranslateStatus(status);
-            bool haveErrMsg = cmd->errbuf && *cmd->errbuf && (*cmd->errbuf)[0];
-
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Child process (%s) unexpected %s%s%s"),
-                           str ? str : cmd->args[0], NULLSTR(st),
-                           haveErrMsg ? ": " : "",
-                           haveErrMsg ? *cmd->errbuf : "");
-            VIR_FREE(str);
-            VIR_FREE(st);
-            return -1;
-        }
-    }
-
-    return ret;
-}
-
-
-#ifndef WIN32
-/**
- * virCommandAbort:
- * @cmd: command to abort
- *
- * Abort an async command if it is running, without issuing
- * any errors or affecting errno.  Designed for error paths
- * where some but not all paths to the cleanup code might
- * have started the child process.
- */
-void
-virCommandAbort(virCommandPtr cmd)
-{
-    if (!cmd || cmd->pid == -1)
-        return;
-    virProcessAbort(cmd->pid);
-    cmd->pid = -1;
-    cmd->reap = false;
-}
-#else /* WIN32 */
-void
-virCommandAbort(virCommandPtr cmd ATTRIBUTE_UNUSED)
-{
-    /* Mingw lacks WNOHANG and kill().  But since we haven't ported
-     * virExecWithHook to mingw yet, there's no process to be killed,
-     * making this implementation trivially correct for now :)  */
-}
-#endif
-
-
-/**
- * virCommandRequireHandshake:
- * @cmd: command to modify
- *
- * Request that the child perform a handshake with
- * the parent when the hook function has completed
- * execution. The child will not exec() until the
- * parent has notified
- */
-void virCommandRequireHandshake(virCommandPtr cmd)
-{
-    if (!cmd || cmd->has_error)
-        return;
-
-    if (cmd->handshake) {
-        cmd->has_error = -1;
-        VIR_DEBUG("Cannot require handshake twice");
-        return;
-    }
-
-    if (pipe2(cmd->handshakeWait, O_CLOEXEC) < 0) {
-        cmd->has_error = errno;
-        return;
-    }
-    if (pipe2(cmd->handshakeNotify, O_CLOEXEC) < 0) {
-        VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
-        VIR_FORCE_CLOSE(cmd->handshakeWait[1]);
-        cmd->has_error = errno;
-        return;
-    }
-
-    VIR_DEBUG("Transfer handshake wait=%d notify=%d, "
-              "keep handshake wait=%d notify=%d",
-              cmd->handshakeWait[1], cmd->handshakeNotify[0],
-              cmd->handshakeWait[0], cmd->handshakeNotify[1]);
-    virCommandTransferFD(cmd, cmd->handshakeWait[1]);
-    virCommandTransferFD(cmd, cmd->handshakeNotify[0]);
-    cmd->handshake = true;
-}
-
-/**
- * virCommandHandshakeWait:
- * @cmd: command to wait on
- *
- * Wait for the child to complete execution of its
- * hook function.  To be called in the parent.
- */
-int virCommandHandshakeWait(virCommandPtr cmd)
-{
-    char c;
-    int rv;
-    if (!cmd ||cmd->has_error == ENOMEM) {
-        virReportOOMError();
-        return -1;
-    }
-    if (cmd->has_error || !cmd->handshake) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("invalid use of command API"));
-        return -1;
-    }
-
-    if (cmd->handshakeWait[0] == -1) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Handshake is already complete"));
-        return -1;
-    }
-
-    VIR_DEBUG("Wait for handshake on %d", cmd->handshakeWait[0]);
-    if ((rv = saferead(cmd->handshakeWait[0], &c, sizeof(c))) != sizeof(c)) {
-        if (rv < 0)
-            virReportSystemError(errno, "%s",
-                                 _("Unable to wait for child process"));
-        else
-            virReportSystemError(EIO, "%s",
-                                 _("Child quit during startup handshake"));
-        VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
-        return -1;
-    }
-    if (c != '1') {
-        char *msg;
-        ssize_t len;
-        if (VIR_ALLOC_N(msg, 1024) < 0) {
-            virReportOOMError();
-            VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
-            return -1;
-        }
-        /* Close the handshakeNotify fd before trying to read anything
-         * further on the handshakeWait pipe; so that a child waiting
-         * on our acknowledgment will die rather than deadlock.  */
-        VIR_FORCE_CLOSE(cmd->handshakeNotify[1]);
-
-        if ((len = saferead(cmd->handshakeWait[0], msg, 1024)) < 0) {
-            VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
-            VIR_FREE(msg);
-            virReportSystemError(errno, "%s",
-                                 _("No error message from child failure"));
-            return -1;
-        }
-        VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
-        msg[len-1] = '\0';
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", msg);
-        VIR_FREE(msg);
-        return -1;
-    }
-    VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
-    return 0;
-}
-
-/**
- * virCommandHandshakeNotify:
- * @cmd: command to resume
- *
- * Notify the child that it is OK to exec() the
- * real binary now.  To be called in the parent.
- */
-int virCommandHandshakeNotify(virCommandPtr cmd)
-{
-    char c = '1';
-    if (!cmd ||cmd->has_error == ENOMEM) {
-        virReportOOMError();
-        return -1;
-    }
-    if (cmd->has_error || !cmd->handshake) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("invalid use of command API"));
-        return -1;
-    }
-
-    if (cmd->handshakeNotify[1] == -1) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Handshake is already complete"));
-        return -1;
-    }
-
-    VIR_DEBUG("Notify handshake on %d", cmd->handshakeNotify[1]);
-    if (safewrite(cmd->handshakeNotify[1], &c, sizeof(c)) != sizeof(c)) {
-        virReportSystemError(errno, "%s", _("Unable to notify child process"));
-        VIR_FORCE_CLOSE(cmd->handshakeNotify[1]);
-        return -1;
-    }
-    VIR_FORCE_CLOSE(cmd->handshakeNotify[1]);
-    return 0;
-}
-
-
-/**
- * virCommandFree:
- * @cmd: optional command to free
- *
- * Release all resources.  The only exception is that if you called
- * virCommandRunAsync with a non-null pid, then the asynchronous child
- * is not reaped, and you must call virProcessWait() or virProcessAbort() yourself.
- */
-void
-virCommandFree(virCommandPtr cmd)
-{
-    int i;
-    if (!cmd)
-        return;
-
-    for (i = 0; i < cmd->transfer_size; i++) {
-        VIR_FORCE_CLOSE(cmd->transfer[i]);
-    }
-
-    VIR_FREE(cmd->inbuf);
-    VIR_FORCE_CLOSE(cmd->outfd);
-    VIR_FORCE_CLOSE(cmd->errfd);
-
-    for (i = 0 ; i < cmd->nargs ; i++)
-        VIR_FREE(cmd->args[i]);
-    VIR_FREE(cmd->args);
-
-    for (i = 0 ; i < cmd->nenv ; i++)
-        VIR_FREE(cmd->env[i]);
-    VIR_FREE(cmd->env);
-
-    VIR_FREE(cmd->pwd);
-
-    if (cmd->handshake) {
-        /* The other 2 fds in these arrays are closed
-         * due to use with virCommandTransferFD
-         */
-        VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
-        VIR_FORCE_CLOSE(cmd->handshakeNotify[1]);
-    }
-
-    VIR_FREE(cmd->pidfile);
-
-    if (cmd->reap)
-        virCommandAbort(cmd);
-
-    VIR_FREE(cmd->transfer);
-    VIR_FREE(cmd->preserve);
-
-    VIR_FREE(cmd);
-}
diff --git a/src/util/command.h b/src/util/command.h
deleted file mode 100644
index 6c8ab49..0000000
--- a/src/util/command.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * command.h: Child command execution
- *
- * Copyright (C) 2010-2011 Red Hat, Inc.
- *
- * 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, see
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef __VIR_COMMAND_H__
-# define __VIR_COMMAND_H__
-
-# include "internal.h"
-# include "util.h"
-# include "virbuffer.h"
-
-typedef struct _virCommand virCommand;
-typedef virCommand *virCommandPtr;
-
-/* This will execute in the context of the first child
- * after fork() but before execve().  As such, it is unsafe to
- * call any function that is not async-signal-safe.  */
-typedef int (*virExecHook)(void *data);
-
-int virFork(pid_t *pid) ATTRIBUTE_RETURN_CHECK;
-
-int virRun(const char *const*argv, int *status) ATTRIBUTE_RETURN_CHECK;
-
-virCommandPtr virCommandNew(const char *binary) ATTRIBUTE_NONNULL(1);
-
-virCommandPtr virCommandNewArgs(const char *const*args) ATTRIBUTE_NONNULL(1);
-
-virCommandPtr virCommandNewArgList(const char *binary, ...)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL;
-
-virCommandPtr virCommandNewVAList(const char *binary, va_list list)
-    ATTRIBUTE_NONNULL(1);
-
-/* All error report from these setup APIs is
- * delayed until the Run/RunAsync methods
- */
-
-void virCommandPreserveFD(virCommandPtr cmd,
-                          int fd);
-
-void virCommandTransferFD(virCommandPtr cmd,
-                          int fd);
-
-void virCommandSetPidFile(virCommandPtr cmd,
-                          const char *pidfile) ATTRIBUTE_NONNULL(2);
-
-void virCommandClearCaps(virCommandPtr cmd);
-
-void virCommandAllowCap(virCommandPtr cmd,
-                        int capability);
-
-void virCommandDaemonize(virCommandPtr cmd);
-
-void virCommandNonblockingFDs(virCommandPtr cmd);
-
-void virCommandAddEnvFormat(virCommandPtr cmd, const char *format, ...)
-    ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3);
-
-void virCommandAddEnvPair(virCommandPtr cmd,
-                          const char *name,
-                          const char *value) ATTRIBUTE_NONNULL(2);
-
-void virCommandAddEnvString(virCommandPtr cmd,
-                            const char *str) ATTRIBUTE_NONNULL(2);
-
-void virCommandAddEnvBuffer(virCommandPtr cmd,
-                            virBufferPtr buf);
-
-void virCommandAddEnvPass(virCommandPtr cmd,
-                          const char *name) ATTRIBUTE_NONNULL(2);
-
-void virCommandAddEnvPassCommon(virCommandPtr cmd);
-
-void virCommandAddArg(virCommandPtr cmd,
-                      const char *val) ATTRIBUTE_NONNULL(2);
-
-void virCommandAddArgBuffer(virCommandPtr cmd,
-                            virBufferPtr buf);
-
-void virCommandAddArgFormat(virCommandPtr cmd,
-                            const char *format, ...)
-    ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3);
-
-void virCommandAddArgPair(virCommandPtr cmd,
-                          const char *name,
-                          const char *val)
-    ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
-
-void virCommandAddArgSet(virCommandPtr cmd,
-                         const char *const*vals) ATTRIBUTE_NONNULL(2);
-
-void virCommandAddArgList(virCommandPtr cmd,
-                          ... /* const char *arg, ..., NULL */)
-    ATTRIBUTE_SENTINEL;
-
-void virCommandSetWorkingDirectory(virCommandPtr cmd,
-                                   const char *pwd) ATTRIBUTE_NONNULL(2);
-
-void virCommandSetInputBuffer(virCommandPtr cmd,
-                              const char *inbuf) ATTRIBUTE_NONNULL(2);
-
-void virCommandSetOutputBuffer(virCommandPtr cmd,
-                               char **outbuf) ATTRIBUTE_NONNULL(2);
-
-void virCommandSetErrorBuffer(virCommandPtr cmd,
-                              char **errbuf) ATTRIBUTE_NONNULL(2);
-
-void virCommandSetInputFD(virCommandPtr cmd,
-                          int infd);
-
-void virCommandSetOutputFD(virCommandPtr cmd,
-                           int *outfd) ATTRIBUTE_NONNULL(2);
-
-void virCommandSetErrorFD(virCommandPtr cmd,
-                          int *errfd) ATTRIBUTE_NONNULL(2);
-
-void virCommandSetPreExecHook(virCommandPtr cmd,
-                              virExecHook hook,
-                              void *opaque) ATTRIBUTE_NONNULL(2);
-
-void virCommandWriteArgLog(virCommandPtr cmd,
-                           int logfd);
-
-char *virCommandToString(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK;
-
-int virCommandExec(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK;
-
-int virCommandRun(virCommandPtr cmd,
-                  int *exitstatus) ATTRIBUTE_RETURN_CHECK;
-
-int virCommandRunAsync(virCommandPtr cmd,
-                       pid_t *pid) ATTRIBUTE_RETURN_CHECK;
-
-int virCommandWait(virCommandPtr cmd,
-                   int *exitstatus) ATTRIBUTE_RETURN_CHECK;
-
-void virCommandRequireHandshake(virCommandPtr cmd);
-
-int virCommandHandshakeWait(virCommandPtr cmd)
-    ATTRIBUTE_RETURN_CHECK;
-
-int virCommandHandshakeNotify(virCommandPtr cmd)
-    ATTRIBUTE_RETURN_CHECK;
-
-void virCommandAbort(virCommandPtr cmd);
-
-void virCommandFree(virCommandPtr cmd);
-
-#endif /* __VIR_COMMAND_H__ */
diff --git a/src/util/dnsmasq.c b/src/util/dnsmasq.c
index 74593c8..6e9c9dd 100644
--- a/src/util/dnsmasq.c
+++ b/src/util/dnsmasq.c
@@ -42,7 +42,7 @@
 #include "virbitmap.h"
 #include "dnsmasq.h"
 #include "util.h"
-#include "command.h"
+#include "vircommand.h"
 #include "memory.h"
 #include "virterror_internal.h"
 #include "logging.h"
diff --git a/src/util/ebtables.c b/src/util/ebtables.c
index f1b2986..4b427ee 100644
--- a/src/util/ebtables.c
+++ b/src/util/ebtables.c
@@ -41,7 +41,7 @@
 
 #include "internal.h"
 #include "ebtables.h"
-#include "command.h"
+#include "vircommand.h"
 #include "memory.h"
 #include "virterror_internal.h"
 #include "logging.h"
diff --git a/src/util/hooks.c b/src/util/hooks.c
index 8817a4e..a6c056d 100644
--- a/src/util/hooks.c
+++ b/src/util/hooks.c
@@ -37,7 +37,7 @@
 #include "memory.h"
 #include "virfile.h"
 #include "configmake.h"
-#include "command.h"
+#include "vircommand.h"
 
 #define VIR_FROM_THIS VIR_FROM_HOOK
 
diff --git a/src/util/iptables.c b/src/util/iptables.c
index 00a1c29..25253ff 100644
--- a/src/util/iptables.c
+++ b/src/util/iptables.c
@@ -39,7 +39,7 @@
 
 #include "internal.h"
 #include "iptables.h"
-#include "command.h"
+#include "vircommand.h"
 #include "memory.h"
 #include "virterror_internal.h"
 #include "logging.h"
diff --git a/src/util/pci.c b/src/util/pci.c
index 5971764..bf46fca 100644
--- a/src/util/pci.c
+++ b/src/util/pci.c
@@ -36,7 +36,7 @@
 
 #include "logging.h"
 #include "memory.h"
-#include "command.h"
+#include "vircommand.h"
 #include "virterror_internal.h"
 #include "virfile.h"
 
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
index 3f85e0e..eebf59a 100644
--- a/src/util/storage_file.c
+++ b/src/util/storage_file.c
@@ -24,7 +24,6 @@
 #include <config.h>
 #include "storage_file.h"
 
-#include <command.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -41,6 +40,7 @@
 #include "logging.h"
 #include "virfile.h"
 #include "c-ctype.h"
+#include "vircommand.h"
 #include "virhash.h"
 
 #define VIR_FROM_THIS VIR_FROM_STORAGE
diff --git a/src/util/sysinfo.c b/src/util/sysinfo.c
index bac4b23..e21cbfd 100644
--- a/src/util/sysinfo.c
+++ b/src/util/sysinfo.c
@@ -35,7 +35,7 @@
 #include "util.h"
 #include "logging.h"
 #include "memory.h"
-#include "command.h"
+#include "vircommand.h"
 
 #define VIR_FROM_THIS VIR_FROM_SYSINFO
 
diff --git a/src/util/util.c b/src/util/util.c
index 422ee75..f8ba7b4 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -84,7 +84,7 @@
 #include "threads.h"
 #include "verify.h"
 #include "virfile.h"
-#include "command.h"
+#include "vircommand.h"
 #include "nonblocking.h"
 #include "passfd.h"
 #include "virprocess.h"
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
new file mode 100644
index 0000000..3046658
--- /dev/null
+++ b/src/util/vircommand.c
@@ -0,0 +1,2523 @@
+/*
+ * vircommand.c: Child command execution
+ *
+ * Copyright (C) 2010-2012 Red Hat, Inc.
+ *
+ * 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include <poll.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+
+#if HAVE_CAPNG
+# include <cap-ng.h>
+#endif
+
+#include "vircommand.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "util.h"
+#include "logging.h"
+#include "virfile.h"
+#include "virpidfile.h"
+#include "virprocess.h"
+#include "virbuffer.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+/* Flags for virExecWithHook */
+enum {
+    VIR_EXEC_NONE   = 0,
+    VIR_EXEC_NONBLOCK = (1 << 0),
+    VIR_EXEC_DAEMON = (1 << 1),
+    VIR_EXEC_CLEAR_CAPS = (1 << 2),
+    VIR_EXEC_RUN_SYNC = (1 << 3),
+};
+
+struct _virCommand {
+    int has_error; /* ENOMEM on allocation failure, -1 for anything else.  */
+
+    char **args;
+    size_t nargs;
+    size_t maxargs;
+
+    char **env;
+    size_t nenv;
+    size_t maxenv;
+
+    char *pwd;
+
+    int *preserve; /* FDs to pass to child. */
+    int preserve_size;
+    int *transfer; /* FDs to close in parent. */
+    int transfer_size;
+
+    unsigned int flags;
+
+    char *inbuf;
+    char **outbuf;
+    char **errbuf;
+
+    int infd;
+    int outfd;
+    int errfd;
+    int *outfdptr;
+    int *errfdptr;
+
+    bool handshake;
+    int handshakeWait[2];
+    int handshakeNotify[2];
+
+    virExecHook hook;
+    void *opaque;
+
+    pid_t pid;
+    char *pidfile;
+    bool reap;
+
+    unsigned long long capabilities;
+};
+
+/*
+ * virCommandFDIsSet:
+ * @fd: FD to test
+ * @set: the set
+ * @set_size: actual size of @set
+ *
+ * Check if FD is already in @set or not.
+ *
+ * Returns true if @set contains @fd,
+ * false otherwise.
+ */
+static bool
+virCommandFDIsSet(int fd,
+                  const int *set,
+                  int set_size)
+{
+    int i = 0;
+
+    while (i < set_size)
+        if (set[i++] == fd)
+            return true;
+
+    return false;
+}
+
+/*
+ * virCommandFDSet:
+ * @fd: FD to be put into @set
+ * @set: the set
+ * @set_size: actual size of @set
+ *
+ * This is practically generalized implementation
+ * of FD_SET() as we do not want to be limited
+ * by FD_SETSIZE.
+ *
+ * Returns: 0 on success,
+ *          -1 on usage error,
+ *          ENOMEM on OOM
+ */
+static int
+virCommandFDSet(int fd,
+                int **set,
+                int *set_size)
+{
+    if (fd < 0 || !set || !set_size)
+        return -1;
+
+    if (virCommandFDIsSet(fd, *set, *set_size))
+        return 0;
+
+    if (VIR_REALLOC_N(*set, *set_size + 1) < 0) {
+        return ENOMEM;
+    }
+
+    (*set)[*set_size] = fd;
+    (*set_size)++;
+
+    return 0;
+}
+
+#ifndef WIN32
+
+static int virClearCapabilities(void) ATTRIBUTE_UNUSED;
+
+# if HAVE_CAPNG
+static int virClearCapabilities(void)
+{
+    int ret;
+
+    capng_clear(CAPNG_SELECT_BOTH);
+
+    if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot clear process capabilities %d"), ret);
+        return -1;
+    }
+
+    return 0;
+}
+
+/**
+ * virSetCapabilities:
+ *  @capabilities - capability flag to set.
+ *                  In case of 0, this function is identical to
+ *                  virClearCapabilities()
+ *
+ */
+static int virSetCapabilities(unsigned long long capabilities)
+{
+    int ret, i;
+
+    capng_clear(CAPNG_SELECT_BOTH);
+
+    for (i = 0; i <= CAP_LAST_CAP; i++) {
+        if (capabilities & (1ULL << i))
+            capng_update(CAPNG_ADD, CAPNG_BOUNDING_SET, i);
+    }
+
+    if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot apply process capabilities %d"), ret);
+        return -1;
+    }
+
+    return 0;
+}
+# else
+static int virClearCapabilities(void)
+{
+//    VIR_WARN("libcap-ng support not compiled in, unable to clear "
+//             "capabilities");
+    return 0;
+}
+
+static int
+virSetCapabilities(unsigned long long capabilities ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+# endif
+
+/**
+ * virFork:
+ * @pid - a pointer to a pid_t that will receive the return value from
+ *        fork()
+ *
+ * fork a new process while avoiding various race/deadlock conditions
+ *
+ * on return from virFork(), if *pid < 0, the fork failed and there is
+ * no new process. Otherwise, just like fork(), if *pid == 0, it is the
+ * child process returning, and if *pid > 0, it is the parent.
+ *
+ * Even if *pid >= 0, if the return value from virFork() is < 0, it
+ * indicates a failure that occurred in the parent or child process
+ * after the fork. In this case, the child process should call
+ * _exit(EXIT_FAILURE) after doing any additional error reporting.
+ */
+int
+virFork(pid_t *pid)
+{
+    sigset_t oldmask, newmask;
+    struct sigaction sig_action;
+    int saved_errno, ret = -1;
+
+    *pid = -1;
+
+    /*
+     * Need to block signals now, so that child process can safely
+     * kill off caller's signal handlers without a race.
+     */
+    sigfillset(&newmask);
+    if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) {
+        saved_errno = errno;
+        virReportSystemError(errno,
+                             "%s", _("cannot block signals"));
+        goto cleanup;
+    }
+
+    /* Ensure we hold the logging lock, to protect child processes
+     * from deadlocking on another thread's inherited mutex state */
+    virLogLock();
+
+    *pid = fork();
+    saved_errno = errno; /* save for caller */
+
+    /* Unlock for both parent and child process */
+    virLogUnlock();
+
+    if (*pid < 0) {
+        /* attempt to restore signal mask, but ignore failure, to
+           avoid obscuring the fork failure */
+        ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL));
+        virReportSystemError(saved_errno,
+                             "%s", _("cannot fork child process"));
+        goto cleanup;
+    }
+
+    if (*pid) {
+
+        /* parent process */
+
+        /* Restore our original signal mask now that the child is
+           safely running */
+        if (pthread_sigmask(SIG_SETMASK, &oldmask, NULL) != 0) {
+            saved_errno = errno; /* save for caller */
+            virReportSystemError(errno, "%s", _("cannot unblock signals"));
+            goto cleanup;
+        }
+        ret = 0;
+
+    } else {
+
+        /* child process */
+
+        int logprio;
+        int i;
+
+        /* Remove any error callback so errors in child now
+           get sent to stderr where they stand a fighting chance
+           of being seen / logged */
+        virSetErrorFunc(NULL, NULL);
+        virSetErrorLogPriorityFunc(NULL);
+
+        /* Make sure any hook logging is sent to stderr, since child
+         * process may close the logfile FDs */
+        logprio = virLogGetDefaultPriority();
+        virLogReset();
+        virLogSetDefaultPriority(logprio);
+
+        /* Clear out all signal handlers from parent so nothing
+           unexpected can happen in our child once we unblock
+           signals */
+        sig_action.sa_handler = SIG_DFL;
+        sig_action.sa_flags = 0;
+        sigemptyset(&sig_action.sa_mask);
+
+        for (i = 1; i < NSIG; i++) {
+            /* Only possible errors are EFAULT or EINVAL
+               The former wont happen, the latter we
+               expect, so no need to check return value */
+
+            sigaction(i, &sig_action, NULL);
+        }
+
+        /* Unmask all signals in child, since we've no idea
+           what the caller's done with their signal mask
+           and don't want to propagate that to children */
+        sigemptyset(&newmask);
+        if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) {
+            saved_errno = errno; /* save for caller */
+            virReportSystemError(errno, "%s", _("cannot unblock signals"));
+            goto cleanup;
+        }
+        ret = 0;
+    }
+
+cleanup:
+    if (ret < 0)
+        errno = saved_errno;
+    return ret;
+}
+
+/*
+ * Ensure that *null is an fd visiting /dev/null.  Return 0 on
+ * success, -1 on failure.  Allows for lazy opening of shared
+ * /dev/null fd only as required.
+ */
+static int
+getDevNull(int *null)
+{
+    if (*null == -1 && (*null = open("/dev/null", O_RDWR|O_CLOEXEC)) < 0) {
+        virReportSystemError(errno,
+                             _("cannot open %s"),
+                             "/dev/null");
+        return -1;
+    }
+    return 0;
+}
+
+/* Ensure that STD is an inheritable copy of FD.  Return 0 on success,
+ * -1 on failure.  */
+static int
+prepareStdFd(int fd, int std)
+{
+    if (fd == std)
+        return virSetInherit(fd, true);
+    if (dup2(fd, std) != std)
+        return -1;
+    return 0;
+}
+
+/*
+ * @argv argv to exec
+ * @envp optional environment to use for exec
+ * @keepfd options fd_ret to keep open for child process
+ * @retpid optional pointer to store child process pid
+ * @infd optional file descriptor to use as child input, otherwise /dev/null
+ * @outfd optional pointer to communicate output fd behavior
+ *        outfd == NULL : Use /dev/null
+ *        *outfd == -1  : Use a new fd
+ *        *outfd != -1  : Use *outfd
+ * @errfd optional pointer to communcate error fd behavior. See outfd
+ * @flags possible combination of the following:
+ *        VIR_EXEC_NONE     : Default function behavior
+ *        VIR_EXEC_NONBLOCK : Set child process output fd's as non-blocking
+ *        VIR_EXEC_DAEMON   : Daemonize the child process
+ * @hook optional virExecHook function to call prior to exec
+ * @data data to pass to the hook function
+ * @pidfile path to use as pidfile for daemonized process (needs DAEMON flag)
+ * @capabilities capabilities to keep
+ */
+static int
+virExecWithHook(const char *const*argv,
+                const char *const*envp,
+                const int *keepfd,
+                int keepfd_size,
+                pid_t *retpid,
+                int infd, int *outfd, int *errfd,
+                unsigned int flags,
+                virExecHook hook,
+                void *data,
+                char *pidfile,
+                unsigned long long capabilities)
+{
+    pid_t pid;
+    int null = -1, i, openmax;
+    int pipeout[2] = {-1,-1};
+    int pipeerr[2] = {-1,-1};
+    int childout = -1;
+    int childerr = -1;
+    int tmpfd;
+    const char *binary = NULL;
+    int forkRet;
+
+    if (argv[0][0] != '/') {
+        if (!(binary = virFindFileInPath(argv[0]))) {
+            virReportSystemError(ENOENT,
+                                 _("Cannot find '%s' in path"),
+                                 argv[0]);
+            return -1;
+        }
+    } else {
+        binary = argv[0];
+    }
+
+    if (infd < 0) {
+        if (getDevNull(&null) < 0)
+            goto cleanup;
+        infd = null;
+    }
+
+    if (outfd != NULL) {
+        if (*outfd == -1) {
+            if (pipe2(pipeout, O_CLOEXEC) < 0) {
+                virReportSystemError(errno,
+                                     "%s", _("cannot create pipe"));
+                goto cleanup;
+            }
+
+            if ((flags & VIR_EXEC_NONBLOCK) &&
+                virSetNonBlock(pipeout[0]) == -1) {
+                virReportSystemError(errno,
+                                     "%s", _("Failed to set non-blocking file descriptor flag"));
+                goto cleanup;
+            }
+
+            childout = pipeout[1];
+        } else {
+            childout = *outfd;
+        }
+    } else {
+        if (getDevNull(&null) < 0)
+            goto cleanup;
+        childout = null;
+    }
+
+    if (errfd != NULL) {
+        if (errfd == outfd) {
+            childerr = childout;
+        } else if (*errfd == -1) {
+            if (pipe2(pipeerr, O_CLOEXEC) < 0) {
+                virReportSystemError(errno,
+                                     "%s", _("Failed to create pipe"));
+                goto cleanup;
+            }
+
+            if ((flags & VIR_EXEC_NONBLOCK) &&
+                virSetNonBlock(pipeerr[0]) == -1) {
+                virReportSystemError(errno,
+                                     "%s", _("Failed to set non-blocking file descriptor flag"));
+                goto cleanup;
+            }
+
+            childerr = pipeerr[1];
+        } else {
+            childerr = *errfd;
+        }
+    } else {
+        if (getDevNull(&null) < 0)
+            goto cleanup;
+        childerr = null;
+    }
+
+    forkRet = virFork(&pid);
+
+    if (pid < 0) {
+        goto cleanup;
+    }
+
+    if (pid) { /* parent */
+        if (forkRet < 0) {
+            goto cleanup;
+        }
+
+        VIR_FORCE_CLOSE(null);
+        if (outfd && *outfd == -1) {
+            VIR_FORCE_CLOSE(pipeout[1]);
+            *outfd = pipeout[0];
+        }
+        if (errfd && *errfd == -1) {
+            VIR_FORCE_CLOSE(pipeerr[1]);
+            *errfd = pipeerr[0];
+        }
+
+        *retpid = pid;
+
+        if (binary != argv[0])
+            VIR_FREE(binary);
+
+        return 0;
+    }
+
+    /* child */
+
+    if (forkRet < 0) {
+        /* The fork was successful, but after that there was an error
+         * in the child (which was already logged).
+        */
+        goto fork_error;
+    }
+
+    openmax = sysconf(_SC_OPEN_MAX);
+    for (i = 3; i < openmax; i++) {
+        if (i == infd || i == childout || i == childerr)
+            continue;
+        if (!keepfd || !virCommandFDIsSet(i, keepfd, keepfd_size)) {
+            tmpfd = i;
+            VIR_MASS_CLOSE(tmpfd);
+        } else if (virSetInherit(i, true) < 0) {
+            virReportSystemError(errno, _("failed to preserve fd %d"), i);
+            goto fork_error;
+        }
+    }
+
+    if (prepareStdFd(infd, STDIN_FILENO) < 0) {
+        virReportSystemError(errno,
+                             "%s", _("failed to setup stdin file handle"));
+        goto fork_error;
+    }
+    if (childout > 0 && prepareStdFd(childout, STDOUT_FILENO) < 0) {
+        virReportSystemError(errno,
+                             "%s", _("failed to setup stdout file handle"));
+        goto fork_error;
+    }
+    if (childerr > 0 && prepareStdFd(childerr, STDERR_FILENO) < 0) {
+        virReportSystemError(errno,
+                             "%s", _("failed to setup stderr file handle"));
+        goto fork_error;
+    }
+
+    if (infd != STDIN_FILENO && infd != null && infd != childerr &&
+        infd != childout)
+        VIR_FORCE_CLOSE(infd);
+    if (childout > STDERR_FILENO && childout != null && childout != childerr)
+        VIR_FORCE_CLOSE(childout);
+    if (childerr > STDERR_FILENO && childerr != null)
+        VIR_FORCE_CLOSE(childerr);
+    VIR_FORCE_CLOSE(null);
+
+    /* Initialize full logging for a while */
+    virLogSetFromEnv();
+
+    /* Daemonize as late as possible, so the parent process can detect
+     * the above errors with wait* */
+    if (flags & VIR_EXEC_DAEMON) {
+        if (setsid() < 0) {
+            virReportSystemError(errno,
+                                 "%s", _("cannot become session leader"));
+            goto fork_error;
+        }
+
+        if (chdir("/") < 0) {
+            virReportSystemError(errno,
+                                 "%s", _("cannot change to root directory"));
+            goto fork_error;
+        }
+
+        pid = fork();
+        if (pid < 0) {
+            virReportSystemError(errno,
+                                 "%s", _("cannot fork child process"));
+            goto fork_error;
+        }
+
+        if (pid > 0) {
+            if (pidfile && (virPidFileWritePath(pidfile,pid) < 0)) {
+                kill(pid, SIGTERM);
+                usleep(500*1000);
+                kill(pid, SIGTERM);
+                virReportSystemError(errno,
+                                     _("could not write pidfile %s for %d"),
+                                     pidfile, pid);
+                goto fork_error;
+            }
+            _exit(0);
+        }
+    }
+
+    if (hook) {
+        /* virFork reset all signal handlers to the defaults.
+         * This is good for the child process, but our hook
+         * risks running something that generates SIGPIPE,
+         * so we need to temporarily block that again
+         */
+        struct sigaction waxon, waxoff;
+        memset(&waxoff, 0, sizeof(waxoff));
+        waxoff.sa_handler = SIG_IGN;
+        sigemptyset(&waxoff.sa_mask);
+        memset(&waxon, 0, sizeof(waxon));
+        if (sigaction(SIGPIPE, &waxoff, &waxon) < 0) {
+            virReportSystemError(errno, "%s",
+                                 _("Could not disable SIGPIPE"));
+            goto fork_error;
+        }
+
+        if ((hook)(data) != 0) {
+            VIR_DEBUG("Hook function failed.");
+            goto fork_error;
+        }
+
+        if (sigaction(SIGPIPE, &waxon, NULL) < 0) {
+            virReportSystemError(errno, "%s",
+                                 _("Could not re-enable SIGPIPE"));
+            goto fork_error;
+        }
+    }
+
+    /* The steps above may need todo something privileged, so
+     * we delay clearing capabilities until the last minute */
+    if (capabilities || (flags & VIR_EXEC_CLEAR_CAPS))
+        if (virSetCapabilities(capabilities) < 0)
+            goto fork_error;
+
+    /* Close logging again to ensure no FDs leak to child */
+    virLogReset();
+
+    if (envp)
+        execve(binary, (char **) argv, (char**)envp);
+    else
+        execv(binary, (char **) argv);
+
+    virReportSystemError(errno,
+                         _("cannot execute binary %s"),
+                         argv[0]);
+
+ fork_error:
+    virDispatchError(NULL);
+    _exit(EXIT_FAILURE);
+
+ cleanup:
+    /* This is cleanup of parent process only - child
+       should never jump here on error */
+
+    if (binary != argv[0])
+        VIR_FREE(binary);
+
+    /* NB we don't virReportError() on any failures here
+       because the code which jumped here already raised
+       an error condition which we must not overwrite */
+    VIR_FORCE_CLOSE(pipeerr[0]);
+    VIR_FORCE_CLOSE(pipeerr[1]);
+    VIR_FORCE_CLOSE(pipeout[0]);
+    VIR_FORCE_CLOSE(pipeout[1]);
+    VIR_FORCE_CLOSE(null);
+    return -1;
+}
+
+/**
+ * virRun:
+ * @argv NULL terminated argv to run
+ * @status optional variable to return exit status in
+ *
+ * Run a command without using the shell.
+ *
+ * If status is NULL, then return 0 if the command run and
+ * exited with 0 status; Otherwise return -1
+ *
+ * If status is not-NULL, then return 0 if the command ran.
+ * The status variable is filled with the command exit status
+ * and should be checked by caller for success. Return -1
+ * only if the command could not be run.
+ */
+int
+virRun(const char *const*argv, int *status)
+{
+    int ret;
+    virCommandPtr cmd = virCommandNewArgs(argv);
+
+    ret = virCommandRun(cmd, status);
+    virCommandFree(cmd);
+    return ret;
+}
+
+#else /* WIN32 */
+
+int
+virRun(const char *const *argv ATTRIBUTE_UNUSED,
+       int *status)
+{
+    if (status)
+        *status = ENOTSUP;
+    else
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("virRun is not implemented for WIN32"));
+    return -1;
+}
+
+static int
+virExecWithHook(const char *const*argv ATTRIBUTE_UNUSED,
+                const char *const*envp ATTRIBUTE_UNUSED,
+                const int *keepfd ATTRIBUTE_UNUSED,
+                int keepfd_size ATTRIBUTE_UNUSED,
+                pid_t *retpid ATTRIBUTE_UNUSED,
+                int infd ATTRIBUTE_UNUSED,
+                int *outfd ATTRIBUTE_UNUSED,
+                int *errfd ATTRIBUTE_UNUSED,
+                int flags_unused ATTRIBUTE_UNUSED,
+                virExecHook hook ATTRIBUTE_UNUSED,
+                void *data ATTRIBUTE_UNUSED,
+                char *pidfile ATTRIBUTE_UNUSED,
+                unsigned long long capabilities ATTRIBUTE_UNUSED)
+{
+    /* XXX: Some day we can implement pieces of virCommand/virExec on
+     * top of _spawn() or CreateProcess(), but we can't implement
+     * everything, since mingw completely lacks fork(), so we cannot
+     * run hook code in the child.  */
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                   "%s", _("virExec is not implemented for WIN32"));
+    return -1;
+}
+
+int
+virFork(pid_t *pid)
+{
+    *pid = -1;
+    errno = ENOTSUP;
+
+    return -1;
+}
+
+#endif /* WIN32 */
+
+
+/**
+ * virCommandNew:
+ * @binary: program to run
+ *
+ * Create a new command for named binary.  If @binary is relative,
+ * it will be found via a PATH search of the parent's PATH (and not
+ * any altered PATH set by virCommandAddEnv* commands).
+ */
+virCommandPtr
+virCommandNew(const char *binary)
+{
+    const char *const args[] = { binary, NULL };
+
+    return virCommandNewArgs(args);
+}
+
+/**
+ * virCommandNewArgs:
+ * @args: array of arguments
+ *
+ * Create a new command with a NULL terminated
+ * set of args, taking binary from args[0].  More arguments can
+ * be added later.  @args[0] is handled like @binary of virCommandNew.
+ */
+virCommandPtr
+virCommandNewArgs(const char *const*args)
+{
+    virCommandPtr cmd;
+
+    if (VIR_ALLOC(cmd) < 0)
+        return NULL;
+
+    cmd->handshakeWait[0] = -1;
+    cmd->handshakeWait[1] = -1;
+    cmd->handshakeNotify[0] = -1;
+    cmd->handshakeNotify[1] = -1;
+
+    cmd->infd = cmd->outfd = cmd->errfd = -1;
+    cmd->pid = -1;
+
+    virCommandAddArgSet(cmd, args);
+
+    return cmd;
+}
+
+/**
+ * virCommandNewArgList:
+ * @binary: program to run
+ * @...: additional arguments
+ *
+ * Create a new command with a NULL terminated
+ * list of args, starting with the binary to run.  More arguments can
+ * be added later.  @binary is handled as in virCommandNew.
+ */
+virCommandPtr
+virCommandNewArgList(const char *binary, ...)
+{
+    virCommandPtr cmd = virCommandNew(binary);
+    va_list list;
+    const char *arg;
+
+    if (!cmd || cmd->has_error)
+        return cmd;
+
+    va_start(list, binary);
+    while ((arg = va_arg(list, const char *)) != NULL)
+        virCommandAddArg(cmd, arg);
+    va_end(list);
+    return cmd;
+}
+
+/**
+ * virCommandNewVAList:
+ * @binary: program to run
+ * @va_list: additional arguments
+ *
+ * Create a new command with a NULL terminated
+ * variable argument list.  @binary is handled as in virCommandNew.
+ */
+virCommandPtr
+virCommandNewVAList(const char *binary, va_list list)
+{
+    virCommandPtr cmd = virCommandNew(binary);
+    const char *arg;
+
+    if (!cmd || cmd->has_error)
+        return cmd;
+
+    while ((arg = va_arg(list, const char *)) != NULL)
+        virCommandAddArg(cmd, arg);
+    return cmd;
+}
+
+
+/*
+ * Preserve the specified file descriptor in the child, instead of
+ * closing it.  FD must not be one of the three standard streams.  If
+ * transfer is true, then fd will be closed in the parent after a call
+ * to Run/RunAsync/Free, otherwise caller is still responsible for fd.
+ * Returns true if a transferring caller should close FD now, and
+ * false if the transfer is successfully recorded.
+ */
+static bool
+virCommandKeepFD(virCommandPtr cmd, int fd, bool transfer)
+{
+    int ret = 0;
+
+    if (!cmd)
+        return fd > STDERR_FILENO;
+
+    if (fd <= STDERR_FILENO ||
+        (ret = virCommandFDSet(fd, &cmd->preserve, &cmd->preserve_size)) ||
+        (transfer && (ret = virCommandFDSet(fd, &cmd->transfer,
+                                            &cmd->transfer_size)))) {
+        if (!cmd->has_error)
+            cmd->has_error = ret ? ret : -1 ;
+        VIR_DEBUG("cannot preserve %d", fd);
+        return fd > STDERR_FILENO;
+    }
+
+    return false;
+}
+
+/**
+ * virCommandPreserveFD:
+ * @cmd: the command to modify
+ * @fd: fd to mark for inheritance into child
+ *
+ * Preserve the specified file descriptor
+ * in the child, instead of closing it on exec.
+ * The parent is still responsible for managing fd.
+ */
+void
+virCommandPreserveFD(virCommandPtr cmd, int fd)
+{
+    virCommandKeepFD(cmd, fd, false);
+}
+
+/**
+ * virCommandTransferFD:
+ * @cmd: the command to modify
+ * @fd: fd to reassign to the child
+ *
+ * Transfer the specified file descriptor
+ * to the child, instead of closing it on exec.
+ * The parent should no longer use fd, and the parent's copy will
+ * be automatically closed no later than during Run/RunAsync/Free.
+ */
+void
+virCommandTransferFD(virCommandPtr cmd, int fd)
+{
+    if (virCommandKeepFD(cmd, fd, true))
+        VIR_FORCE_CLOSE(fd);
+}
+
+
+/**
+ * virCommandSetPidFile:
+ * @cmd: the command to modify
+ * @pidfile: filename to use
+ *
+ * Save the child PID in a pidfile.  The pidfile will be populated
+ * before the exec of the child.
+ */
+void
+virCommandSetPidFile(virCommandPtr cmd, const char *pidfile)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    VIR_FREE(cmd->pidfile);
+    if (!(cmd->pidfile = strdup(pidfile))) {
+        cmd->has_error = ENOMEM;
+    }
+}
+
+
+/**
+ * virCommandClearCaps:
+ * @cmd: the command to modify
+ *
+ * Remove all capabilities from the child, after any hooks have been run.
+ */
+void
+virCommandClearCaps(virCommandPtr cmd)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    cmd->flags |= VIR_EXEC_CLEAR_CAPS;
+}
+
+/**
+ * virCommandAllowCap:
+ * @cmd: the command to modify
+ * @capability: what to allow
+ *
+ * Allow specific capabilities
+ */
+void
+virCommandAllowCap(virCommandPtr cmd,
+                   int capability)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    cmd->capabilities |= (1ULL << capability);
+}
+
+
+
+/**
+ * virCommandDaemonize:
+ * @cmd: the command to modify
+ *
+ * Daemonize the child process.  The child will have a current working
+ * directory of /, and must be started with virCommandRun, which will
+ * complete as soon as the daemon grandchild has started.
+ */
+void
+virCommandDaemonize(virCommandPtr cmd)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    cmd->flags |= VIR_EXEC_DAEMON;
+}
+
+/**
+ * virCommandNonblockingFDs:
+ * @cmd: the command to modify
+ *
+ * Set FDs created by virCommandSetOutputFD and virCommandSetErrorFD
+ * as non-blocking in the parent.
+ */
+void
+virCommandNonblockingFDs(virCommandPtr cmd)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    cmd->flags |= VIR_EXEC_NONBLOCK;
+}
+
+/* Add an environment variable to the cmd->env list.  'env' is a
+ * string like "name=value".  If the named environment variable is
+ * already set, then it is replaced in the list.
+ */
+static inline void
+virCommandAddEnv(virCommandPtr cmd, char *env)
+{
+    size_t namelen;
+    size_t i;
+
+    /* Search for the name in the existing environment. */
+    namelen = strcspn(env, "=");
+    for (i = 0; i < cmd->nenv; ++i) {
+        /* + 1 because we want to match the '=' character too. */
+        if (STREQLEN(cmd->env[i], env, namelen + 1)) {
+            VIR_FREE(cmd->env[i]);
+            cmd->env[i] = env;
+            return;
+        }
+    }
+
+    /* Arg plus trailing NULL. */
+    if (VIR_RESIZE_N(cmd->env, cmd->maxenv, cmd->nenv, 1 + 1) < 0) {
+        VIR_FREE(env);
+        cmd->has_error = ENOMEM;
+        return;
+    }
+
+    cmd->env[cmd->nenv++] = env;
+}
+
+/**
+ * virCommandAddEnvFormat:
+ * @cmd: the command to modify
+ * @format: format of arguments, end result must be in name=value format
+ * @...: arguments to be formatted
+ *
+ * Add an environment variable to the child created by a printf-style format.
+ */
+void
+virCommandAddEnvFormat(virCommandPtr cmd, const char *format, ...)
+{
+    char *env;
+    va_list list;
+
+    if (!cmd || cmd->has_error)
+        return;
+
+    va_start(list, format);
+    if (virVasprintf(&env, format, list) < 0) {
+        cmd->has_error = ENOMEM;
+        va_end(list);
+        return;
+    }
+    va_end(list);
+
+    virCommandAddEnv(cmd, env);
+}
+
+/**
+ * virCommandAddEnvPair:
+ * @cmd: the command to modify
+ * @name: variable name, must not contain =
+ * @value: value to assign to name
+ *
+ * Add an environment variable to the child
+ * using separate name & value strings
+ */
+void
+virCommandAddEnvPair(virCommandPtr cmd, const char *name, const char *value)
+{
+    virCommandAddEnvFormat(cmd, "%s=%s", name, value);
+}
+
+
+/**
+ * virCommandAddEnvString:
+ * @cmd: the command to modify
+ * @str: name=value format
+ *
+ * Add an environment variable to the child
+ * using a preformatted env string FOO=BAR
+ */
+void
+virCommandAddEnvString(virCommandPtr cmd, const char *str)
+{
+    char *env;
+
+    if (!cmd || cmd->has_error)
+        return;
+
+    if (!(env = strdup(str))) {
+        cmd->has_error = ENOMEM;
+        return;
+    }
+
+    virCommandAddEnv(cmd, env);
+}
+
+
+/**
+ * virCommandAddEnvBuffer:
+ * @cmd: the command to modify
+ * @buf: buffer that contains name=value string, which will be reset on return
+ *
+ * Convert a buffer containing preformatted name=value into an
+ * environment variable of the child.
+ * Correctly transfers memory errors or contents from buf to cmd.
+ */
+void
+virCommandAddEnvBuffer(virCommandPtr cmd, virBufferPtr buf)
+{
+    if (!cmd || cmd->has_error) {
+        virBufferFreeAndReset(buf);
+        return;
+    }
+
+    if (virBufferError(buf)) {
+        cmd->has_error = ENOMEM;
+        virBufferFreeAndReset(buf);
+        return;
+    }
+    if (!virBufferUse(buf)) {
+        cmd->has_error = EINVAL;
+        return;
+    }
+
+    virCommandAddEnv(cmd, virBufferContentAndReset(buf));
+}
+
+
+/**
+ * virCommandAddEnvPass:
+ * @cmd: the command to modify
+ * @name: the name to look up in current environment
+ *
+ * Pass an environment variable to the child
+ * using current process' value
+ */
+void
+virCommandAddEnvPass(virCommandPtr cmd, const char *name)
+{
+    char *value;
+    if (!cmd || cmd->has_error)
+        return;
+
+    value = getenv(name);
+    if (value)
+        virCommandAddEnvPair(cmd, name, value);
+}
+
+
+/**
+ * virCommandAddEnvPassCommon:
+ * @cmd: the command to modify
+ *
+ * Set LC_ALL to C, and propagate other essential environment
+ * variables (such as PATH) from the parent process.
+ */
+void
+virCommandAddEnvPassCommon(virCommandPtr cmd)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    /* Attempt to Pre-allocate; allocation failure will be detected
+     * later during virCommandAdd*.  */
+    ignore_value(VIR_RESIZE_N(cmd->env, cmd->maxenv, cmd->nenv, 9));
+
+    virCommandAddEnvPair(cmd, "LC_ALL", "C");
+
+    virCommandAddEnvPass(cmd, "LD_PRELOAD");
+    virCommandAddEnvPass(cmd, "LD_LIBRARY_PATH");
+    virCommandAddEnvPass(cmd, "PATH");
+    virCommandAddEnvPass(cmd, "HOME");
+    virCommandAddEnvPass(cmd, "USER");
+    virCommandAddEnvPass(cmd, "LOGNAME");
+    virCommandAddEnvPass(cmd, "TMPDIR");
+}
+
+/**
+ * virCommandAddArg:
+ * @cmd: the command to modify
+ * @val: the argument to add
+ *
+ * Add a command line argument to the child
+ */
+void
+virCommandAddArg(virCommandPtr cmd, const char *val)
+{
+    char *arg;
+
+    if (!cmd || cmd->has_error)
+        return;
+
+    if (!(arg = strdup(val))) {
+        cmd->has_error = ENOMEM;
+        return;
+    }
+
+    /* Arg plus trailing NULL. */
+    if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, 1 + 1) < 0) {
+        VIR_FREE(arg);
+        cmd->has_error = ENOMEM;
+        return;
+    }
+
+    cmd->args[cmd->nargs++] = arg;
+}
+
+
+/**
+ * virCommandAddArgBuffer:
+ * @cmd: the command to modify
+ * @buf: buffer that contains argument string, which will be reset on return
+ *
+ * Convert a buffer into a command line argument to the child.
+ * Correctly transfers memory errors or contents from buf to cmd.
+ */
+void
+virCommandAddArgBuffer(virCommandPtr cmd, virBufferPtr buf)
+{
+    if (!cmd || cmd->has_error) {
+        virBufferFreeAndReset(buf);
+        return;
+    }
+
+    /* Arg plus trailing NULL. */
+    if (virBufferError(buf) ||
+        VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, 1 + 1) < 0) {
+        cmd->has_error = ENOMEM;
+        virBufferFreeAndReset(buf);
+        return;
+    }
+
+    cmd->args[cmd->nargs] = virBufferContentAndReset(buf);
+    if (!cmd->args[cmd->nargs])
+        cmd->args[cmd->nargs] = strdup("");
+    if (!cmd->args[cmd->nargs]) {
+        cmd->has_error = ENOMEM;
+        return;
+    }
+    cmd->nargs++;
+}
+
+
+/**
+ * virCommandAddArgFormat:
+ * @cmd: the command to modify
+ * @format: format of arguments, end result must be in name=value format
+ * @...: arguments to be formatted
+ *
+ * Add a command line argument created by a printf-style format.
+ */
+void
+virCommandAddArgFormat(virCommandPtr cmd, const char *format, ...)
+{
+    char *arg;
+    va_list list;
+
+    if (!cmd || cmd->has_error)
+        return;
+
+    va_start(list, format);
+    if (virVasprintf(&arg, format, list) < 0) {
+        cmd->has_error = ENOMEM;
+        va_end(list);
+        return;
+    }
+    va_end(list);
+
+    /* Arg plus trailing NULL. */
+    if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, 1 + 1) < 0) {
+        VIR_FREE(arg);
+        cmd->has_error = ENOMEM;
+        return;
+    }
+
+    cmd->args[cmd->nargs++] = arg;
+}
+
+/**
+ * virCommandAddArgPair:
+ * @cmd: the command to modify
+ * @name: left half of argument
+ * @value: right half of argument
+ *
+ * Add "NAME=VAL" as a single command line argument to the child
+ */
+void
+virCommandAddArgPair(virCommandPtr cmd, const char *name, const char *val)
+{
+    virCommandAddArgFormat(cmd, "%s=%s", name, val);
+}
+
+/**
+ * virCommandAddArgSet:
+ * @cmd: the command to modify
+ * @vals: array of arguments to add
+ *
+ * Add a NULL terminated list of args
+ */
+void
+virCommandAddArgSet(virCommandPtr cmd, const char *const*vals)
+{
+    int narg = 0;
+
+    if (!cmd || cmd->has_error)
+        return;
+
+    if (vals[0] == NULL) {
+        cmd->has_error = EINVAL;
+        return;
+    }
+
+    while (vals[narg] != NULL)
+        narg++;
+
+    /* narg plus trailing NULL. */
+    if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, narg + 1) < 0) {
+        cmd->has_error = ENOMEM;
+        return;
+    }
+
+    narg = 0;
+    while (vals[narg] != NULL) {
+        char *arg = strdup(vals[narg++]);
+        if (!arg) {
+            cmd->has_error = ENOMEM;
+            return;
+        }
+        cmd->args[cmd->nargs++] = arg;
+    }
+}
+
+/**
+ * virCommandAddArgList:
+ * @cmd: the command to modify
+ * @...: list of arguments to add
+ *
+ * Add a NULL terminated list of args.
+ */
+void
+virCommandAddArgList(virCommandPtr cmd, ...)
+{
+    va_list list;
+    int narg = 0;
+
+    if (!cmd || cmd->has_error)
+        return;
+
+    va_start(list, cmd);
+    while (va_arg(list, const char *) != NULL)
+        narg++;
+    va_end(list);
+
+    /* narg plus trailing NULL. */
+    if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, narg + 1) < 0) {
+        cmd->has_error = ENOMEM;
+        return;
+    }
+
+    va_start(list, cmd);
+    while (1) {
+        char *arg = va_arg(list, char *);
+        if (!arg)
+            break;
+        arg = strdup(arg);
+        if (!arg) {
+            cmd->has_error = ENOMEM;
+            va_end(list);
+            return;
+        }
+        cmd->args[cmd->nargs++] = arg;
+    }
+    va_end(list);
+}
+
+/**
+ * virCommandSetWorkingDirectory:
+ * @cmd: the command to modify
+ * @pwd: directory to use
+ *
+ * Set the working directory of a non-daemon child process, rather
+ * than the parent's working directory.  Daemons automatically get /
+ * without using this call.
+ */
+void
+virCommandSetWorkingDirectory(virCommandPtr cmd, const char *pwd)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    if (cmd->pwd) {
+        cmd->has_error = -1;
+        VIR_DEBUG("cannot set directory twice");
+    } else {
+        cmd->pwd = strdup(pwd);
+        if (!cmd->pwd)
+            cmd->has_error = ENOMEM;
+    }
+}
+
+
+/**
+ * virCommandSetInputBuffer:
+ * @cmd: the command to modify
+ * @inbuf: string to feed to stdin
+ *
+ * Feed the child's stdin from a string buffer.  This requires the use
+ * of virCommandRun().
+ */
+void
+virCommandSetInputBuffer(virCommandPtr cmd, const char *inbuf)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    if (cmd->infd != -1 || cmd->inbuf) {
+        cmd->has_error = -1;
+        VIR_DEBUG("cannot specify input twice");
+        return;
+    }
+
+    cmd->inbuf = strdup(inbuf);
+    if (!cmd->inbuf)
+        cmd->has_error = ENOMEM;
+}
+
+
+/**
+ * virCommandSetOutputBuffer:
+ * @cmd: the command to modify
+ * @outbuf: address of variable to store malloced result buffer
+ *
+ * Capture the child's stdout to a string buffer.  *outbuf is
+ * guaranteed to be allocated after successful virCommandRun or
+ * virCommandWait, and is best-effort allocated after failed
+ * virCommandRun; caller is responsible for freeing *outbuf.
+ * This requires the use of virCommandRun.
+ */
+void
+virCommandSetOutputBuffer(virCommandPtr cmd, char **outbuf)
+{
+    *outbuf = NULL;
+    if (!cmd || cmd->has_error)
+        return;
+
+    if (cmd->outfdptr) {
+        cmd->has_error = -1;
+        VIR_DEBUG("cannot specify output twice");
+        return;
+    }
+
+    cmd->outbuf = outbuf;
+    cmd->outfdptr = &cmd->outfd;
+}
+
+
+/**
+ * virCommandSetErrorBuffer:
+ * @cmd: the command to modify
+ * @errbuf: address of variable to store malloced result buffer
+ *
+ * Capture the child's stderr to a string buffer.  *errbuf is
+ * guaranteed to be allocated after successful virCommandRun or
+ * virCommandWait, and is best-effort allocated after failed
+ * virCommandRun; caller is responsible for freeing *errbuf.
+ * This requires the use of virCommandRun.  It is possible to
+ * pass the same pointer as for virCommandSetOutputBuffer(), in
+ * which case the child process will interleave all output into
+ * a single string.
+ */
+void
+virCommandSetErrorBuffer(virCommandPtr cmd, char **errbuf)
+{
+    *errbuf = NULL;
+    if (!cmd || cmd->has_error)
+        return;
+
+    if (cmd->errfdptr) {
+        cmd->has_error = -1;
+        VIR_DEBUG("cannot specify stderr twice");
+        return;
+    }
+
+    cmd->errbuf = errbuf;
+    cmd->errfdptr = &cmd->errfd;
+}
+
+
+/**
+ * virCommandSetInputFD:
+ * @cmd: the command to modify
+ * @infd: the descriptor to use
+ *
+ * Attach a file descriptor to the child's stdin
+ */
+void
+virCommandSetInputFD(virCommandPtr cmd, int infd)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    if (cmd->infd != -1 || cmd->inbuf) {
+        cmd->has_error = -1;
+        VIR_DEBUG("cannot specify input twice");
+        return;
+    }
+    if (infd < 0) {
+        cmd->has_error = -1;
+        VIR_DEBUG("cannot specify invalid input fd");
+        return;
+    }
+
+    cmd->infd = infd;
+}
+
+
+/**
+ * virCommandSetOutputFD:
+ * @cmd: the command to modify
+ * @outfd: location of output fd
+ *
+ * Attach a file descriptor to the child's stdout.  If *@outfd is -1 on
+ * entry, then a pipe will be created and returned in this variable when
+ * the child is run.  Otherwise, *@outfd is used as the output.
+ */
+void
+virCommandSetOutputFD(virCommandPtr cmd, int *outfd)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    if (cmd->outfdptr) {
+        cmd->has_error = -1;
+        VIR_DEBUG("cannot specify output twice");
+        return;
+    }
+
+    cmd->outfdptr = outfd;
+}
+
+
+/**
+ * virCommandSetErrorFD:
+ * @cmd: the command to modify
+ * @errfd: location of error fd
+ *
+ * Attach a file descriptor to the child's stderr.  If *@errfd is -1 on
+ * entry, then a pipe will be created and returned in this variable when
+ * the child is run.  Otherwise, *@errfd is used for error collection,
+ * and may be the same as outfd given to virCommandSetOutputFD().
+ */
+void
+virCommandSetErrorFD(virCommandPtr cmd, int *errfd)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    if (cmd->errfdptr) {
+        cmd->has_error = -1;
+        VIR_DEBUG("cannot specify stderr twice");
+        return;
+    }
+
+    cmd->errfdptr = errfd;
+}
+
+
+/**
+ * virCommandSetPreExecHook:
+ * @cmd: the command to modify
+ * @hook: the hook to run
+ * @opaque: argument to pass to the hook
+ *
+ * Run HOOK(OPAQUE) in the child as the last thing before changing
+ * directories, dropping capabilities, and executing the new process.
+ * Force the child to fail if HOOK does not return zero.
+ *
+ * Since @hook runs in the child, it should be careful to avoid
+ * any functions that are not async-signal-safe.
+ */
+void
+virCommandSetPreExecHook(virCommandPtr cmd, virExecHook hook, void *opaque)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    if (cmd->hook) {
+        cmd->has_error = -1;
+        VIR_DEBUG("cannot specify hook twice");
+        return;
+    }
+    cmd->hook = hook;
+    cmd->opaque = opaque;
+}
+
+
+/**
+ * virCommandWriteArgLog:
+ * @cmd: the command to log
+ * @logfd: where to log the results
+ *
+ * Call after adding all arguments and environment settings, but before
+ * Run/RunAsync, to immediately output the environment and arguments of
+ * cmd to logfd.  If virCommandRun cannot succeed (because of an
+ * out-of-memory condition while building cmd), nothing will be logged.
+ */
+void
+virCommandWriteArgLog(virCommandPtr cmd, int logfd)
+{
+    int ioError = 0;
+    size_t i;
+
+    /* Any errors will be reported later by virCommandRun, which means
+     * no command will be run, so there is nothing to log. */
+    if (!cmd || cmd->has_error)
+        return;
+
+    for (i = 0 ; i < cmd->nenv ; i++) {
+        if (safewrite(logfd, cmd->env[i], strlen(cmd->env[i])) < 0)
+            ioError = errno;
+        if (safewrite(logfd, " ", 1) < 0)
+            ioError = errno;
+    }
+    for (i = 0 ; i < cmd->nargs ; i++) {
+        if (safewrite(logfd, cmd->args[i], strlen(cmd->args[i])) < 0)
+            ioError = errno;
+        if (safewrite(logfd, i == cmd->nargs - 1 ? "\n" : " ", 1) < 0)
+            ioError = errno;
+    }
+
+    if (ioError) {
+        char ebuf[1024];
+        VIR_WARN("Unable to write command %s args to logfile: %s",
+                 cmd->args[0], virStrerror(ioError, ebuf, sizeof(ebuf)));
+    }
+}
+
+
+/**
+ * virCommandToString:
+ * @cmd: the command to convert
+ *
+ * Call after adding all arguments and environment settings, but
+ * before Run/RunAsync, to return a string representation of the
+ * environment and arguments of cmd, suitably quoted for pasting into
+ * a shell.  If virCommandRun cannot succeed (because of an
+ * out-of-memory condition while building cmd), NULL will be returned.
+ * Caller is responsible for freeing the resulting string.
+ */
+char *
+virCommandToString(virCommandPtr cmd)
+{
+    size_t i;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    /* Cannot assume virCommandRun will be called; so report the error
+     * now.  If virCommandRun is called, it will report the same error. */
+    if (!cmd ||cmd->has_error == ENOMEM) {
+        virReportOOMError();
+        return NULL;
+    }
+    if (cmd->has_error) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("invalid use of command API"));
+        return NULL;
+    }
+
+    for (i = 0; i < cmd->nenv; i++) {
+        /* In shell, a='b c' has a different meaning than 'a=b c', so
+         * we must determine where the '=' lives.  */
+        char *eq = strchr(cmd->env[i], '=');
+
+        if (!eq) {
+            virBufferFreeAndReset(&buf);
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("invalid use of command API"));
+            return NULL;
+        }
+        eq++;
+        virBufferAdd(&buf, cmd->env[i], eq - cmd->env[i]);
+        virBufferEscapeShell(&buf, eq);
+        virBufferAddChar(&buf, ' ');
+    }
+    virBufferEscapeShell(&buf, cmd->args[0]);
+    for (i = 1; i < cmd->nargs; i++) {
+        virBufferAddChar(&buf, ' ');
+        virBufferEscapeShell(&buf, cmd->args[i]);
+    }
+
+    if (virBufferError(&buf)) {
+        virBufferFreeAndReset(&buf);
+        virReportOOMError();
+        return NULL;
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
+
+/*
+ * Manage input and output to the child process.
+ */
+static int
+virCommandProcessIO(virCommandPtr cmd, int *inpipe)
+{
+    int infd = -1, outfd = -1, errfd = -1;
+    size_t inlen = 0, outlen = 0, errlen = 0;
+    size_t inoff = 0;
+    int ret = 0;
+
+    /* With an input buffer, feed data to child
+     * via pipe */
+    if (cmd->inbuf) {
+        inlen = strlen(cmd->inbuf);
+        infd = *inpipe;
+    }
+
+    /* With out/err buffer, the outfd/errfd have been filled with an
+     * FD for us.  Guarantee an allocated string with partial results
+     * even if we encounter a later failure, as well as freeing any
+     * results accumulated over a prior run of the same command.  */
+    if (cmd->outbuf) {
+        outfd = cmd->outfd;
+        if (VIR_REALLOC_N(*cmd->outbuf, 1) < 0) {
+            virReportOOMError();
+            ret = -1;
+        }
+    }
+    if (cmd->errbuf) {
+        errfd = cmd->errfd;
+        if (VIR_REALLOC_N(*cmd->errbuf, 1) < 0) {
+            virReportOOMError();
+            ret = -1;
+        }
+    }
+    if (ret == -1)
+        goto cleanup;
+    ret = -1;
+
+    for (;;) {
+        int i;
+        struct pollfd fds[3];
+        int nfds = 0;
+
+        if (infd != -1) {
+            fds[nfds].fd = infd;
+            fds[nfds].events = POLLOUT;
+            fds[nfds].revents = 0;
+            nfds++;
+        }
+        if (outfd != -1) {
+            fds[nfds].fd = outfd;
+            fds[nfds].events = POLLIN;
+            fds[nfds].revents = 0;
+            nfds++;
+        }
+        if (errfd != -1) {
+            fds[nfds].fd = errfd;
+            fds[nfds].events = POLLIN;
+            fds[nfds].revents = 0;
+            nfds++;
+        }
+
+        if (nfds == 0)
+            break;
+
+        if (poll(fds, nfds, -1) < 0) {
+            if (errno == EAGAIN || errno == EINTR)
+                continue;
+            virReportSystemError(errno, "%s",
+                                 _("unable to poll on child"));
+            goto cleanup;
+        }
+
+        for (i = 0; i < nfds ; i++) {
+            if (fds[i].revents & (POLLIN | POLLHUP | POLLERR) &&
+                (fds[i].fd == errfd || fds[i].fd == outfd)) {
+                char data[1024];
+                char **buf;
+                size_t *len;
+                int done;
+                if (fds[i].fd == outfd) {
+                    buf = cmd->outbuf;
+                    len = &outlen;
+                } else {
+                    buf = cmd->errbuf;
+                    len = &errlen;
+                }
+                /* Silence a false positive from clang. */
+                sa_assert(buf);
+
+                done = read(fds[i].fd, data, sizeof(data));
+                if (done < 0) {
+                    if (errno != EINTR &&
+                        errno != EAGAIN) {
+                        virReportSystemError(errno, "%s",
+                                             (fds[i].fd == outfd) ?
+                                             _("unable to read child stdout") :
+                                             _("unable to read child stderr"));
+                        goto cleanup;
+                    }
+                } else if (done == 0) {
+                    if (fds[i].fd == outfd)
+                        outfd = -1;
+                    else
+                        errfd = -1;
+                } else {
+                    if (VIR_REALLOC_N(*buf, *len + done + 1) < 0) {
+                        virReportOOMError();
+                        goto cleanup;
+                    }
+                    memcpy(*buf + *len, data, done);
+                    *len += done;
+                }
+            }
+
+            if (fds[i].revents & (POLLOUT | POLLERR) &&
+                fds[i].fd == infd) {
+                int done;
+
+                /* Coverity 5.3.0 can't see that we only get here if
+                 * infd is in the set because it was non-negative.  */
+                sa_assert(infd != -1);
+                done = write(infd, cmd->inbuf + inoff,
+                             inlen - inoff);
+                if (done < 0) {
+                    if (errno == EPIPE) {
+                        VIR_DEBUG("child closed stdin early, ignoring EPIPE "
+                                  "on fd %d", infd);
+                        if (VIR_CLOSE(*inpipe) < 0)
+                            VIR_DEBUG("ignoring failed close on fd %d", infd);
+                        infd = -1;
+                    } else if (errno != EINTR && errno != EAGAIN) {
+                        virReportSystemError(errno, "%s",
+                                             _("unable to write to child input"));
+                        goto cleanup;
+                    }
+                } else {
+                    inoff += done;
+                    if (inoff == inlen) {
+                        if (VIR_CLOSE(*inpipe) < 0)
+                            VIR_DEBUG("ignoring failed close on fd %d", infd);
+                        infd = -1;
+                    }
+                }
+            }
+        }
+    }
+
+    ret = 0;
+cleanup:
+    if (cmd->outbuf && *cmd->outbuf)
+        (*cmd->outbuf)[outlen] = '\0';
+    if (cmd->errbuf && *cmd->errbuf)
+        (*cmd->errbuf)[errlen] = '\0';
+    return ret;
+}
+
+/**
+ * virCommandExec:
+ * @cmd: command to run
+ *
+ * Exec the command, replacing the current process. Meant to be called
+ * in the hook after already forking / cloning, so does not attempt to
+ * daemonize or preserve any FDs.
+ *
+ * Returns -1 on any error executing the command.
+ * Will not return on success.
+ */
+#ifndef WIN32
+int virCommandExec(virCommandPtr cmd)
+{
+    if (!cmd ||cmd->has_error == ENOMEM) {
+        virReportOOMError();
+        return -1;
+    }
+    if (cmd->has_error) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("invalid use of command API"));
+        return -1;
+    }
+
+    return execve(cmd->args[0], cmd->args, cmd->env);
+}
+#else
+int virCommandExec(virCommandPtr cmd ATTRIBUTE_UNUSED)
+{
+    /* Mingw execve() has a broken signature. Disable this
+     * function until gnulib fixes the signature, since we
+     * don't really need this on Win32 anyway.
+     */
+    virReportSystemError(ENOSYS, "%s",
+                         _("Executing new processes is not supported on Win32 platform"));
+    return -1;
+}
+#endif
+
+/**
+ * virCommandRun:
+ * @cmd: command to run
+ * @exitstatus: optional status collection
+ *
+ * Run the command and wait for completion.
+ * Returns -1 on any error executing the
+ * command. Returns 0 if the command executed,
+ * with the exit status set.  If @exitstatus is NULL, then the
+ * child must exit with status 0 for this to succeed.
+ */
+int
+virCommandRun(virCommandPtr cmd, int *exitstatus)
+{
+    int ret = 0;
+    char *outbuf = NULL;
+    char *errbuf = NULL;
+    int infd[2] = { -1, -1 };
+    struct stat st;
+    bool string_io;
+    bool async_io = false;
+    char *str;
+    int tmpfd;
+
+    if (!cmd ||cmd->has_error == ENOMEM) {
+        virReportOOMError();
+        return -1;
+    }
+    if (cmd->has_error) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("invalid use of command API"));
+        return -1;
+    }
+
+    /* Avoid deadlock, by requiring that any open fd not under our
+     * control must be visiting a regular file, or that we are
+     * daemonized and no string io is required.  */
+    string_io = cmd->inbuf || cmd->outbuf || cmd->errbuf;
+    if (cmd->infd != -1 &&
+        (fstat(cmd->infd, &st) < 0 || !S_ISREG(st.st_mode)))
+        async_io = true;
+    if (cmd->outfdptr && cmd->outfdptr != &cmd->outfd &&
+        (*cmd->outfdptr == -1 ||
+         fstat(*cmd->outfdptr, &st) < 0 || !S_ISREG(st.st_mode)))
+        async_io = true;
+    if (cmd->errfdptr && cmd->errfdptr != &cmd->errfd &&
+        (*cmd->errfdptr == -1 ||
+         fstat(*cmd->errfdptr, &st) < 0 || !S_ISREG(st.st_mode)))
+        async_io = true;
+    if (async_io) {
+        if (!(cmd->flags & VIR_EXEC_DAEMON) || string_io) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("cannot mix caller fds with blocking execution"));
+            return -1;
+        }
+    } else {
+        if ((cmd->flags & VIR_EXEC_DAEMON) && string_io) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("cannot mix string I/O with daemon"));
+            return -1;
+        }
+    }
+
+    /* If we have an input buffer, we need
+     * a pipe to feed the data to the child */
+    if (cmd->inbuf) {
+        if (pipe2(infd, O_CLOEXEC) < 0) {
+            virReportSystemError(errno, "%s",
+                                 _("unable to open pipe"));
+            cmd->has_error = -1;
+            return -1;
+        }
+        cmd->infd = infd[0];
+    }
+
+    /* If caller requested the same string for stdout and stderr, then
+     * merge those into one string.  */
+    if (cmd->outbuf && cmd->outbuf == cmd->errbuf) {
+        cmd->errfdptr = &cmd->outfd;
+        cmd->errbuf = NULL;
+    }
+
+    /* If caller hasn't requested capture of stdout/err, then capture
+     * it ourselves so we can log it.  But the intermediate child for
+     * a daemon has no expected output, and we don't want our
+     * capturing pipes passed on to the daemon grandchild.
+     */
+    if (!(cmd->flags & VIR_EXEC_DAEMON)) {
+        if (!cmd->outfdptr) {
+            cmd->outfdptr = &cmd->outfd;
+            cmd->outbuf = &outbuf;
+            string_io = true;
+        }
+        if (!cmd->errfdptr) {
+            cmd->errfdptr = &cmd->errfd;
+            cmd->errbuf = &errbuf;
+            string_io = true;
+        }
+    }
+
+    cmd->flags |= VIR_EXEC_RUN_SYNC;
+    if (virCommandRunAsync(cmd, NULL) < 0) {
+        if (cmd->inbuf) {
+            tmpfd = infd[0];
+            if (VIR_CLOSE(infd[0]) < 0)
+                VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
+            tmpfd = infd[1];
+            if (VIR_CLOSE(infd[1]) < 0)
+                VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
+        }
+        cmd->has_error = -1;
+        return -1;
+    }
+
+    tmpfd = infd[0];
+    if (VIR_CLOSE(infd[0]) < 0)
+        VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
+    if (string_io)
+        ret = virCommandProcessIO(cmd, &infd[1]);
+
+    if (virCommandWait(cmd, exitstatus) < 0)
+        ret = -1;
+
+    str = (exitstatus ? virProcessTranslateStatus(*exitstatus)
+           : (char *) "status 0");
+    VIR_DEBUG("Result %s, stdout: '%s' stderr: '%s'",
+              NULLSTR(str),
+              cmd->outbuf ? NULLSTR(*cmd->outbuf) : "(null)",
+              cmd->errbuf ? NULLSTR(*cmd->errbuf) : "(null)");
+    if (exitstatus)
+        VIR_FREE(str);
+
+    /* Reset any capturing, in case caller runs
+     * this identical command again */
+    if (cmd->inbuf) {
+        tmpfd = infd[1];
+        if (VIR_CLOSE(infd[1]) < 0)
+            VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
+    }
+    if (cmd->outbuf == &outbuf) {
+        tmpfd = cmd->outfd;
+        if (VIR_CLOSE(cmd->outfd) < 0)
+            VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
+        cmd->outfdptr = NULL;
+        cmd->outbuf = NULL;
+        VIR_FREE(outbuf);
+    }
+    if (cmd->errbuf == &errbuf) {
+        tmpfd = cmd->errfd;
+        if (VIR_CLOSE(cmd->errfd) < 0)
+            VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
+        cmd->errfdptr = NULL;
+        cmd->errbuf = NULL;
+        VIR_FREE(errbuf);
+    }
+
+    return ret;
+}
+
+
+/*
+ * Perform all virCommand-specific actions, along with the user hook.
+ */
+static int
+virCommandHook(void *data)
+{
+    virCommandPtr cmd = data;
+    int res = 0;
+
+    if (cmd->hook) {
+        VIR_DEBUG("Run hook %p %p", cmd->hook, cmd->opaque);
+        res = cmd->hook(cmd->opaque);
+        VIR_DEBUG("Done hook %d", res);
+    }
+    if (res == 0 && cmd->pwd) {
+        VIR_DEBUG("Running child in %s", cmd->pwd);
+        res = chdir(cmd->pwd);
+        if (res < 0) {
+            virReportSystemError(errno,
+                                 _("Unable to change to %s"), cmd->pwd);
+        }
+    }
+    if (cmd->handshake) {
+        char c = res < 0 ? '0' : '1';
+        int rv;
+        VIR_DEBUG("Notifying parent for handshake start on %d",
+                  cmd->handshakeWait[1]);
+        if (safewrite(cmd->handshakeWait[1], &c, sizeof(c)) != sizeof(c)) {
+            virReportSystemError(errno, "%s",
+                                 _("Unable to notify parent process"));
+            return -1;
+        }
+
+        /* On failure we pass the error message back to parent,
+         * so they don't have to dig through stderr logs
+         */
+        if (res < 0) {
+            virErrorPtr err = virGetLastError();
+            const char *msg = err ? err->message :
+                _("Unknown failure during hook execution");
+            size_t len = strlen(msg) + 1;
+            if (safewrite(cmd->handshakeWait[1], msg, len) != len) {
+                virReportSystemError(errno, "%s",
+                                     _("Unable to send error to parent"));
+                return -1;
+            }
+            return -1;
+        }
+
+        VIR_DEBUG("Waiting on parent for handshake complete on %d",
+                  cmd->handshakeNotify[0]);
+        if ((rv = saferead(cmd->handshakeNotify[0], &c,
+                           sizeof(c))) != sizeof(c)) {
+            if (rv < 0)
+                virReportSystemError(errno, "%s",
+                                     _("Unable to wait on parent process"));
+            else
+                virReportSystemError(EIO, "%s",
+                                     _("libvirtd quit during handshake"));
+            return -1;
+        }
+        if (c != '1') {
+            virReportSystemError(EINVAL,
+                                 _("Unexpected confirm code '%c' from parent"),
+                                 c);
+            return -1;
+        }
+        VIR_FORCE_CLOSE(cmd->handshakeWait[1]);
+        VIR_FORCE_CLOSE(cmd->handshakeNotify[0]);
+    }
+
+    VIR_DEBUG("Hook is done %d", res);
+
+    return res;
+}
+
+
+/**
+ * virCommandRunAsync:
+ * @cmd: command to start
+ * @pid: optional variable to track child pid
+ *
+ * Run the command asynchronously
+ * Returns -1 on any error executing the
+ * command. Returns 0 if the command executed.
+ *
+ * There are two approaches to child process cleanup.
+ * 1. Use auto-cleanup, by passing NULL for pid.  The child will be
+ * auto-reaped by virCommandFree, unless you reap it earlier via
+ * virCommandWait or virCommandAbort.  Good for where cmd is in
+ * scope for the duration of the child process.
+ * 2. Use manual cleanup, by passing the address of a pid_t variable
+ * for pid.  While cmd is still in scope, you may reap the child via
+ * virCommandWait or virCommandAbort.  But after virCommandFree, if
+ * you have not yet reaped the child, then it continues to run until
+ * you call virProcessWait or virProcessAbort.
+ */
+int
+virCommandRunAsync(virCommandPtr cmd, pid_t *pid)
+{
+    int ret;
+    char *str;
+    int i;
+    bool synchronous = false;
+
+    if (!cmd || cmd->has_error == ENOMEM) {
+        virReportOOMError();
+        return -1;
+    }
+    if (cmd->has_error) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("invalid use of command API"));
+        return -1;
+    }
+
+    synchronous = cmd->flags & VIR_EXEC_RUN_SYNC;
+    cmd->flags &= ~VIR_EXEC_RUN_SYNC;
+
+    /* Buffer management can only be requested via virCommandRun.  */
+    if ((cmd->inbuf && cmd->infd == -1) ||
+        (cmd->outbuf && cmd->outfdptr != &cmd->outfd) ||
+        (cmd->errbuf && cmd->errfdptr != &cmd->errfd)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("cannot mix string I/O with asynchronous command"));
+        return -1;
+    }
+
+    if (cmd->pid != -1) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("command is already running as pid %lld"),
+                       (long long) cmd->pid);
+        return -1;
+    }
+
+    if (!synchronous && (cmd->flags & VIR_EXEC_DAEMON)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("daemonized command cannot use virCommandRunAsync"));
+        return -1;
+    }
+    if (cmd->pwd && (cmd->flags & VIR_EXEC_DAEMON)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("daemonized command cannot set working directory %s"),
+                       cmd->pwd);
+        return -1;
+    }
+    if (cmd->pidfile && !(cmd->flags & VIR_EXEC_DAEMON)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("creation of pid file requires daemonized command"));
+        return -1;
+    }
+
+    str = virCommandToString(cmd);
+    VIR_DEBUG("About to run %s", str ? str : cmd->args[0]);
+    VIR_FREE(str);
+
+    ret = virExecWithHook((const char *const *)cmd->args,
+                          (const char *const *)cmd->env,
+                          cmd->preserve,
+                          cmd->preserve_size,
+                          &cmd->pid,
+                          cmd->infd,
+                          cmd->outfdptr,
+                          cmd->errfdptr,
+                          cmd->flags,
+                          virCommandHook,
+                          cmd,
+                          cmd->pidfile,
+                          cmd->capabilities);
+
+    VIR_DEBUG("Command result %d, with PID %d",
+              ret, (int)cmd->pid);
+
+    for (i = 0; i < cmd->transfer_size; i++) {
+        VIR_FORCE_CLOSE(cmd->transfer[i]);
+    }
+    cmd->transfer_size = 0;
+    VIR_FREE(cmd->transfer);
+
+    if (ret == 0 && pid)
+        *pid = cmd->pid;
+    else
+        cmd->reap = true;
+
+    return ret;
+}
+
+
+/**
+ * virCommandWait:
+ * @cmd: command to wait on
+ * @exitstatus: optional status collection
+ *
+ * Wait for the command previously started with virCommandRunAsync()
+ * to complete. Return -1 on any error waiting for
+ * completion. Returns 0 if the command
+ * finished with the exit status set.  If @exitstatus is NULL, then the
+ * child must exit with status 0 for this to succeed.
+ */
+int
+virCommandWait(virCommandPtr cmd, int *exitstatus)
+{
+    int ret;
+    int status = 0;
+
+    if (!cmd ||cmd->has_error == ENOMEM) {
+        virReportOOMError();
+        return -1;
+    }
+    if (cmd->has_error) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("invalid use of command API"));
+        return -1;
+    }
+
+    if (cmd->pid == -1) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("command is not yet running"));
+        return -1;
+    }
+
+    /* If virProcessWait reaps pid but then returns failure because
+     * exitstatus was NULL, then a second virCommandWait would risk
+     * calling waitpid on an unrelated process.  Besides, that error
+     * message is not as detailed as what we can provide.  So, we
+     * guarantee that virProcessWait only fails due to failure to wait,
+     * and repeat the exitstatus check code ourselves.  */
+    ret = virProcessWait(cmd->pid, exitstatus ? exitstatus : &status);
+    if (ret == 0) {
+        cmd->pid = -1;
+        cmd->reap = false;
+        if (status) {
+            char *str = virCommandToString(cmd);
+            char *st = virProcessTranslateStatus(status);
+            bool haveErrMsg = cmd->errbuf && *cmd->errbuf && (*cmd->errbuf)[0];
+
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Child process (%s) unexpected %s%s%s"),
+                           str ? str : cmd->args[0], NULLSTR(st),
+                           haveErrMsg ? ": " : "",
+                           haveErrMsg ? *cmd->errbuf : "");
+            VIR_FREE(str);
+            VIR_FREE(st);
+            return -1;
+        }
+    }
+
+    return ret;
+}
+
+
+#ifndef WIN32
+/**
+ * virCommandAbort:
+ * @cmd: command to abort
+ *
+ * Abort an async command if it is running, without issuing
+ * any errors or affecting errno.  Designed for error paths
+ * where some but not all paths to the cleanup code might
+ * have started the child process.
+ */
+void
+virCommandAbort(virCommandPtr cmd)
+{
+    if (!cmd || cmd->pid == -1)
+        return;
+    virProcessAbort(cmd->pid);
+    cmd->pid = -1;
+    cmd->reap = false;
+}
+#else /* WIN32 */
+void
+virCommandAbort(virCommandPtr cmd ATTRIBUTE_UNUSED)
+{
+    /* Mingw lacks WNOHANG and kill().  But since we haven't ported
+     * virExecWithHook to mingw yet, there's no process to be killed,
+     * making this implementation trivially correct for now :)  */
+}
+#endif
+
+
+/**
+ * virCommandRequireHandshake:
+ * @cmd: command to modify
+ *
+ * Request that the child perform a handshake with
+ * the parent when the hook function has completed
+ * execution. The child will not exec() until the
+ * parent has notified
+ */
+void virCommandRequireHandshake(virCommandPtr cmd)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    if (cmd->handshake) {
+        cmd->has_error = -1;
+        VIR_DEBUG("Cannot require handshake twice");
+        return;
+    }
+
+    if (pipe2(cmd->handshakeWait, O_CLOEXEC) < 0) {
+        cmd->has_error = errno;
+        return;
+    }
+    if (pipe2(cmd->handshakeNotify, O_CLOEXEC) < 0) {
+        VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
+        VIR_FORCE_CLOSE(cmd->handshakeWait[1]);
+        cmd->has_error = errno;
+        return;
+    }
+
+    VIR_DEBUG("Transfer handshake wait=%d notify=%d, "
+              "keep handshake wait=%d notify=%d",
+              cmd->handshakeWait[1], cmd->handshakeNotify[0],
+              cmd->handshakeWait[0], cmd->handshakeNotify[1]);
+    virCommandTransferFD(cmd, cmd->handshakeWait[1]);
+    virCommandTransferFD(cmd, cmd->handshakeNotify[0]);
+    cmd->handshake = true;
+}
+
+/**
+ * virCommandHandshakeWait:
+ * @cmd: command to wait on
+ *
+ * Wait for the child to complete execution of its
+ * hook function.  To be called in the parent.
+ */
+int virCommandHandshakeWait(virCommandPtr cmd)
+{
+    char c;
+    int rv;
+    if (!cmd ||cmd->has_error == ENOMEM) {
+        virReportOOMError();
+        return -1;
+    }
+    if (cmd->has_error || !cmd->handshake) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("invalid use of command API"));
+        return -1;
+    }
+
+    if (cmd->handshakeWait[0] == -1) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Handshake is already complete"));
+        return -1;
+    }
+
+    VIR_DEBUG("Wait for handshake on %d", cmd->handshakeWait[0]);
+    if ((rv = saferead(cmd->handshakeWait[0], &c, sizeof(c))) != sizeof(c)) {
+        if (rv < 0)
+            virReportSystemError(errno, "%s",
+                                 _("Unable to wait for child process"));
+        else
+            virReportSystemError(EIO, "%s",
+                                 _("Child quit during startup handshake"));
+        VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
+        return -1;
+    }
+    if (c != '1') {
+        char *msg;
+        ssize_t len;
+        if (VIR_ALLOC_N(msg, 1024) < 0) {
+            virReportOOMError();
+            VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
+            return -1;
+        }
+        /* Close the handshakeNotify fd before trying to read anything
+         * further on the handshakeWait pipe; so that a child waiting
+         * on our acknowledgment will die rather than deadlock.  */
+        VIR_FORCE_CLOSE(cmd->handshakeNotify[1]);
+
+        if ((len = saferead(cmd->handshakeWait[0], msg, 1024)) < 0) {
+            VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
+            VIR_FREE(msg);
+            virReportSystemError(errno, "%s",
+                                 _("No error message from child failure"));
+            return -1;
+        }
+        VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
+        msg[len-1] = '\0';
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", msg);
+        VIR_FREE(msg);
+        return -1;
+    }
+    VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
+    return 0;
+}
+
+/**
+ * virCommandHandshakeNotify:
+ * @cmd: command to resume
+ *
+ * Notify the child that it is OK to exec() the
+ * real binary now.  To be called in the parent.
+ */
+int virCommandHandshakeNotify(virCommandPtr cmd)
+{
+    char c = '1';
+    if (!cmd ||cmd->has_error == ENOMEM) {
+        virReportOOMError();
+        return -1;
+    }
+    if (cmd->has_error || !cmd->handshake) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("invalid use of command API"));
+        return -1;
+    }
+
+    if (cmd->handshakeNotify[1] == -1) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Handshake is already complete"));
+        return -1;
+    }
+
+    VIR_DEBUG("Notify handshake on %d", cmd->handshakeNotify[1]);
+    if (safewrite(cmd->handshakeNotify[1], &c, sizeof(c)) != sizeof(c)) {
+        virReportSystemError(errno, "%s", _("Unable to notify child process"));
+        VIR_FORCE_CLOSE(cmd->handshakeNotify[1]);
+        return -1;
+    }
+    VIR_FORCE_CLOSE(cmd->handshakeNotify[1]);
+    return 0;
+}
+
+
+/**
+ * virCommandFree:
+ * @cmd: optional command to free
+ *
+ * Release all resources.  The only exception is that if you called
+ * virCommandRunAsync with a non-null pid, then the asynchronous child
+ * is not reaped, and you must call virProcessWait() or virProcessAbort() yourself.
+ */
+void
+virCommandFree(virCommandPtr cmd)
+{
+    int i;
+    if (!cmd)
+        return;
+
+    for (i = 0; i < cmd->transfer_size; i++) {
+        VIR_FORCE_CLOSE(cmd->transfer[i]);
+    }
+
+    VIR_FREE(cmd->inbuf);
+    VIR_FORCE_CLOSE(cmd->outfd);
+    VIR_FORCE_CLOSE(cmd->errfd);
+
+    for (i = 0 ; i < cmd->nargs ; i++)
+        VIR_FREE(cmd->args[i]);
+    VIR_FREE(cmd->args);
+
+    for (i = 0 ; i < cmd->nenv ; i++)
+        VIR_FREE(cmd->env[i]);
+    VIR_FREE(cmd->env);
+
+    VIR_FREE(cmd->pwd);
+
+    if (cmd->handshake) {
+        /* The other 2 fds in these arrays are closed
+         * due to use with virCommandTransferFD
+         */
+        VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
+        VIR_FORCE_CLOSE(cmd->handshakeNotify[1]);
+    }
+
+    VIR_FREE(cmd->pidfile);
+
+    if (cmd->reap)
+        virCommandAbort(cmd);
+
+    VIR_FREE(cmd->transfer);
+    VIR_FREE(cmd->preserve);
+
+    VIR_FREE(cmd);
+}
diff --git a/src/util/vircommand.h b/src/util/vircommand.h
new file mode 100644
index 0000000..4c88165
--- /dev/null
+++ b/src/util/vircommand.h
@@ -0,0 +1,166 @@
+/*
+ * vircommand.h: Child command execution
+ *
+ * Copyright (C) 2010-2011 Red Hat, Inc.
+ *
+ * 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VIR_COMMAND_H__
+# define __VIR_COMMAND_H__
+
+# include "internal.h"
+# include "util.h"
+# include "virbuffer.h"
+
+typedef struct _virCommand virCommand;
+typedef virCommand *virCommandPtr;
+
+/* This will execute in the context of the first child
+ * after fork() but before execve().  As such, it is unsafe to
+ * call any function that is not async-signal-safe.  */
+typedef int (*virExecHook)(void *data);
+
+int virFork(pid_t *pid) ATTRIBUTE_RETURN_CHECK;
+
+int virRun(const char *const*argv, int *status) ATTRIBUTE_RETURN_CHECK;
+
+virCommandPtr virCommandNew(const char *binary) ATTRIBUTE_NONNULL(1);
+
+virCommandPtr virCommandNewArgs(const char *const*args) ATTRIBUTE_NONNULL(1);
+
+virCommandPtr virCommandNewArgList(const char *binary, ...)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL;
+
+virCommandPtr virCommandNewVAList(const char *binary, va_list list)
+    ATTRIBUTE_NONNULL(1);
+
+/* All error report from these setup APIs is
+ * delayed until the Run/RunAsync methods
+ */
+
+void virCommandPreserveFD(virCommandPtr cmd,
+                          int fd);
+
+void virCommandTransferFD(virCommandPtr cmd,
+                          int fd);
+
+void virCommandSetPidFile(virCommandPtr cmd,
+                          const char *pidfile) ATTRIBUTE_NONNULL(2);
+
+void virCommandClearCaps(virCommandPtr cmd);
+
+void virCommandAllowCap(virCommandPtr cmd,
+                        int capability);
+
+void virCommandDaemonize(virCommandPtr cmd);
+
+void virCommandNonblockingFDs(virCommandPtr cmd);
+
+void virCommandAddEnvFormat(virCommandPtr cmd, const char *format, ...)
+    ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3);
+
+void virCommandAddEnvPair(virCommandPtr cmd,
+                          const char *name,
+                          const char *value) ATTRIBUTE_NONNULL(2);
+
+void virCommandAddEnvString(virCommandPtr cmd,
+                            const char *str) ATTRIBUTE_NONNULL(2);
+
+void virCommandAddEnvBuffer(virCommandPtr cmd,
+                            virBufferPtr buf);
+
+void virCommandAddEnvPass(virCommandPtr cmd,
+                          const char *name) ATTRIBUTE_NONNULL(2);
+
+void virCommandAddEnvPassCommon(virCommandPtr cmd);
+
+void virCommandAddArg(virCommandPtr cmd,
+                      const char *val) ATTRIBUTE_NONNULL(2);
+
+void virCommandAddArgBuffer(virCommandPtr cmd,
+                            virBufferPtr buf);
+
+void virCommandAddArgFormat(virCommandPtr cmd,
+                            const char *format, ...)
+    ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3);
+
+void virCommandAddArgPair(virCommandPtr cmd,
+                          const char *name,
+                          const char *val)
+    ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+
+void virCommandAddArgSet(virCommandPtr cmd,
+                         const char *const*vals) ATTRIBUTE_NONNULL(2);
+
+void virCommandAddArgList(virCommandPtr cmd,
+                          ... /* const char *arg, ..., NULL */)
+    ATTRIBUTE_SENTINEL;
+
+void virCommandSetWorkingDirectory(virCommandPtr cmd,
+                                   const char *pwd) ATTRIBUTE_NONNULL(2);
+
+void virCommandSetInputBuffer(virCommandPtr cmd,
+                              const char *inbuf) ATTRIBUTE_NONNULL(2);
+
+void virCommandSetOutputBuffer(virCommandPtr cmd,
+                               char **outbuf) ATTRIBUTE_NONNULL(2);
+
+void virCommandSetErrorBuffer(virCommandPtr cmd,
+                              char **errbuf) ATTRIBUTE_NONNULL(2);
+
+void virCommandSetInputFD(virCommandPtr cmd,
+                          int infd);
+
+void virCommandSetOutputFD(virCommandPtr cmd,
+                           int *outfd) ATTRIBUTE_NONNULL(2);
+
+void virCommandSetErrorFD(virCommandPtr cmd,
+                          int *errfd) ATTRIBUTE_NONNULL(2);
+
+void virCommandSetPreExecHook(virCommandPtr cmd,
+                              virExecHook hook,
+                              void *opaque) ATTRIBUTE_NONNULL(2);
+
+void virCommandWriteArgLog(virCommandPtr cmd,
+                           int logfd);
+
+char *virCommandToString(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK;
+
+int virCommandExec(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK;
+
+int virCommandRun(virCommandPtr cmd,
+                  int *exitstatus) ATTRIBUTE_RETURN_CHECK;
+
+int virCommandRunAsync(virCommandPtr cmd,
+                       pid_t *pid) ATTRIBUTE_RETURN_CHECK;
+
+int virCommandWait(virCommandPtr cmd,
+                   int *exitstatus) ATTRIBUTE_RETURN_CHECK;
+
+void virCommandRequireHandshake(virCommandPtr cmd);
+
+int virCommandHandshakeWait(virCommandPtr cmd)
+    ATTRIBUTE_RETURN_CHECK;
+
+int virCommandHandshakeNotify(virCommandPtr cmd)
+    ATTRIBUTE_RETURN_CHECK;
+
+void virCommandAbort(virCommandPtr cmd);
+
+void virCommandFree(virCommandPtr cmd);
+
+#endif /* __VIR_COMMAND_H__ */
diff --git a/src/util/virfile.c b/src/util/virfile.c
index c79ef04..d77b726 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -37,7 +37,7 @@
 # include <sys/ioctl.h>
 #endif
 
-#include "command.h"
+#include "vircommand.h"
 #include "configmake.h"
 #include "memory.h"
 #include "virterror_internal.h"
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index c345013..e98a2ca 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -26,7 +26,7 @@
 #include "virmacaddr.h"
 #include "virfile.h"
 #include "virterror_internal.h"
-#include "command.h"
+#include "vircommand.h"
 #include "memory.h"
 #include "pci.h"
 #include "logging.h"
diff --git a/src/util/virnetdevbandwidth.c b/src/util/virnetdevbandwidth.c
index 19c00b6..bd75a9d 100644
--- a/src/util/virnetdevbandwidth.c
+++ b/src/util/virnetdevbandwidth.c
@@ -23,7 +23,7 @@
 #include <config.h>
 
 #include "virnetdevbandwidth.h"
-#include "command.h"
+#include "vircommand.h"
 #include "memory.h"
 #include "virterror_internal.h"
 
diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c
index 5bce611..983a240 100644
--- a/src/util/virnetdevopenvswitch.c
+++ b/src/util/virnetdevopenvswitch.c
@@ -24,7 +24,7 @@
 #include <config.h>
 
 #include "virnetdevopenvswitch.h"
-#include "command.h"
+#include "vircommand.h"
 #include "memory.h"
 #include "virterror_internal.h"
 #include "virmacaddr.h"
diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c
index 4166ee0..3261337 100644
--- a/src/util/virnetdevveth.c
+++ b/src/util/virnetdevveth.c
@@ -28,7 +28,7 @@
 #include "virnetdevveth.h"
 #include "memory.h"
 #include "logging.h"
-#include "command.h"
+#include "vircommand.h"
 #include "virterror_internal.h"
 
 #define VIR_FROM_THIS VIR_FROM_NONE
diff --git a/src/util/virnodesuspend.c b/src/util/virnodesuspend.c
index f80920e..a34ca6a 100644
--- a/src/util/virnodesuspend.c
+++ b/src/util/virnodesuspend.c
@@ -22,7 +22,7 @@
 #include <config.h>
 #include "virnodesuspend.h"
 
-#include "command.h"
+#include "vircommand.h"
 #include "threads.h"
 #include "datatypes.h"
 
diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c
index 2eed4f8..b32de66 100644
--- a/src/vmware/vmware_conf.c
+++ b/src/vmware/vmware_conf.c
@@ -24,7 +24,7 @@
 #include <string.h>
 #include <sys/utsname.h>
 
-#include "command.h"
+#include "vircommand.h"
 #include "cpu/cpu.h"
 #include "dirname.h"
 #include "memory.h"
diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c
index 3e7397f..d9a1333 100644
--- a/src/vmware/vmware_driver.c
+++ b/src/vmware/vmware_driver.c
@@ -30,7 +30,7 @@
 #include "memory.h"
 #include "util.h"
 #include "uuid.h"
-#include "command.h"
+#include "vircommand.h"
 #include "vmx.h"
 #include "vmware_conf.h"
 #include "vmware_driver.h"
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
index d2de141..d9174b6 100644
--- a/src/xen/xen_driver.c
+++ b/src/xen/xen_driver.c
@@ -62,7 +62,7 @@
 #include "fdstream.h"
 #include "virfile.h"
 #include "viruri.h"
-#include "command.h"
+#include "vircommand.h"
 #include "virnodesuspend.h"
 #include "nodeinfo.h"
 #include "configmake.h"
diff --git a/tests/commandtest.c b/tests/commandtest.c
index 19bf9ba..f76bc54 100644
--- a/tests/commandtest.c
+++ b/tests/commandtest.c
@@ -33,7 +33,7 @@
 #include "nodeinfo.h"
 #include "util.h"
 #include "memory.h"
-#include "command.h"
+#include "vircommand.h"
 #include "virfile.h"
 #include "virpidfile.h"
 #include "virterror_internal.h"
diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c
index 1888465..dc0e064 100644
--- a/tests/networkxml2conftest.c
+++ b/tests/networkxml2conftest.c
@@ -11,7 +11,7 @@
 #include "internal.h"
 #include "testutils.h"
 #include "network_conf.h"
-#include "command.h"
+#include "vircommand.h"
 #include "memory.h"
 #include "network/bridge_driver.h"
 
diff --git a/tests/reconnect.c b/tests/reconnect.c
index 90af830..4031360 100644
--- a/tests/reconnect.c
+++ b/tests/reconnect.c
@@ -6,7 +6,7 @@
 
 #include "internal.h"
 #include "testutils.h"
-#include "command.h"
+#include "vircommand.h"
 
 static void errorHandler(void *userData ATTRIBUTE_UNUSED,
                          virErrorPtr error ATTRIBUTE_UNUSED) {
diff --git a/tests/statstest.c b/tests/statstest.c
index 8c40082..ad71bf9 100644
--- a/tests/statstest.c
+++ b/tests/statstest.c
@@ -9,7 +9,7 @@
 #include "internal.h"
 #include "xen/block_stats.h"
 #include "testutils.h"
-#include "command.h"
+#include "vircommand.h"
 
 static void testQuietError(void *userData ATTRIBUTE_UNUSED,
                            virErrorPtr error ATTRIBUTE_UNUSED)
diff --git a/tests/testutils.c b/tests/testutils.c
index e8b48e8..1315cb5 100644
--- a/tests/testutils.c
+++ b/tests/testutils.c
@@ -45,7 +45,7 @@
 #include "virterror_internal.h"
 #include "virbuffer.h"
 #include "logging.h"
-#include "command.h"
+#include "vircommand.h"
 #include "virrandom.h"
 #include "dirname.h"
 #include "virprocess.h"
diff --git a/tests/virnettlscontexttest.c b/tests/virnettlscontexttest.c
index cc260e0..d421feb 100644
--- a/tests/virnettlscontexttest.c
+++ b/tests/virnettlscontexttest.c
@@ -32,7 +32,7 @@
 #include "memory.h"
 #include "logging.h"
 #include "virfile.h"
-#include "command.h"
+#include "vircommand.h"
 #include "virsocketaddr.h"
 #include "gnutls_1_0_compat.h"
 
diff --git a/tools/virsh.c b/tools/virsh.c
index 82c03e4..07da077 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -66,7 +66,7 @@
 #include "event_poll.h"
 #include "configmake.h"
 #include "threads.h"
-#include "command.h"
+#include "vircommand.h"
 #include "virkeycode.h"
 #include "virnetdevbandwidth.h"
 #include "virbitmap.h"
-- 
1.7.11.7




More information about the libvir-list mailing list