[libvirt] [PATCH] conf: Fix typo in error message in ABI stability check
by Peter Krempa
s/vpu/vCPU/
---
Pushed as trivial.
src/conf/domain_conf.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b7e253e..e0bd8aa 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -12596,13 +12596,13 @@ virDomainDefCheckABIStability(virDomainDefPtr src,
if (src->vcpus != dst->vcpus) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Target domain vpu count %d does not match source %d"),
+ _("Target domain vCPU count %d does not match source %d"),
dst->vcpus, src->vcpus);
return false;
}
if (src->maxvcpus != dst->maxvcpus) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Target domain vpu max %d does not match source %d"),
+ _("Target domain vCPU max %d does not match source %d"),
dst->maxvcpus, src->maxvcpus);
return false;
}
--
1.8.2.1
11 years, 6 months
[libvirt] [PATCH 1/2] util: fix virFileOpenAs return value and resulting error logs
by Laine Stump
This resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=851411
https://bugzilla.redhat.com/show_bug.cgi?id=955500
The first problem was that virFileOpenAs was returning fd (-1) in one
of the error cases rather than ret (-errno), so the caller thought
that the error was EPERM rather than ENOENT.
The second problem was that some log messages in the general purpose
qemuOpenFile() function would always say "Failed to create" even if
the caller hadn't included O_CREAT (i.e. they were trying to open an
existing file).
This fixes virFileOpenAs to jup down to the error return (which
returns ret instead of fd) in the previously incorrect failure case of
virFileOpenAs(), removes all error logging from virFileOpenAs() (since
the callers report it), and modifies qemuOpenFile to appropriately use
"open" or "create" in its log messages.
NB: I seriously considered removing logging from all callers of
virFileOpenAs(), but there is at least one case where the callers
doesn't want virFileOpenAs() to log any errors, because it's just
going to try again (qemuOpenFile(). We can't simply make a silent
variation of virFileOpenAs() though, because qemuOpenFile() can't make
the decision about whether or not it wants to retry until after
virFileOpenAs() has already returned an error code.
Likewise, I also considered changing virFileOpenAs() to return -1 with
errno set on return, and may still do that, but only as a separate
patch, as it obscures the intent of this patch too much.
---
src/libxl/libxl_driver.c | 6 ++---
src/qemu/qemu_driver.c | 55 ++++++++++++++++++++++---------------------
src/storage/storage_backend.c | 2 +-
src/util/virstoragefile.c | 4 ++--
src/util/virutil.c | 35 ++++++++-------------------
5 files changed, 44 insertions(+), 58 deletions(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 7361743..f09f7eb 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -1,5 +1,5 @@
/*---------------------------------------------------------------------------*/
-/* Copyright (C) 2006-2012 Red Hat, Inc.
+/* Copyright (C) 2006-2013 Red Hat, Inc.
* Copyright (C) 2011-2013 SUSE LINUX Products GmbH, Nuernberg, Germany.
* Copyright (C) 2011 Univention GmbH.
*
@@ -550,8 +550,8 @@ libxlSaveImageOpen(libxlDriverPrivatePtr driver, const char *from,
char *xml = NULL;
if ((fd = virFileOpenAs(from, O_RDONLY, 0, -1, -1, 0)) < 0) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("cannot read domain image"));
+ virReportSystemError(-fd,
+ _("Failed to open domain image file '%s'"), from);
goto error;
}
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0aceb17..5657abc 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2562,10 +2562,9 @@ qemuOpenFile(virQEMUDriverPtr driver, const char *path, int oflags,
/* First try creating the file as root */
if (!is_reg) {
- fd = open(path, oflags & ~O_CREAT);
- if (fd < 0) {
- virReportSystemError(errno, _("unable to open %s"), path);
- goto cleanup;
+ if ((fd = open(path, oflags & ~O_CREAT)) < 0) {
+ fd = -errno;
+ goto error;
}
} else {
if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR, uid, gid,
@@ -2576,36 +2575,30 @@ qemuOpenFile(virQEMUDriverPtr driver, const char *path, int oflags,
qemu user (cfg->user) is non-root, just set a flag to
bypass security driver shenanigans, and retry the operation
after doing setuid to qemu user */
- if ((fd != -EACCES && fd != -EPERM) ||
- cfg->user == getuid()) {
- virReportSystemError(-fd,
- _("Failed to create file '%s'"),
- path);
- goto cleanup;
- }
+ if ((fd != -EACCES && fd != -EPERM) || cfg->user == getuid())
+ goto error;
/* On Linux we can also verify the FS-type of the directory. */
switch (path_shared) {
case 1:
- /* it was on a network share, so we'll continue
- * as outlined above
- */
- break;
+ /* it was on a network share, so we'll continue
+ * as outlined above
+ */
+ break;
case -1:
- virReportSystemError(errno,
- _("Failed to create file "
- "'%s': couldn't determine fs type"),
- path);
- goto cleanup;
+ virReportSystemError(-fd, oflags & O_CREAT
+ ? _("Failed to create file "
+ "'%s': couldn't determine fs type")
+ : _("Failed to open file "
+ "'%s': couldn't determine fs type"),
+ path);
+ goto cleanup;
case 0:
default:
- /* local file - log the error returned by virFileOpenAs */
- virReportSystemError(-fd,
- _("Failed to create file '%s'"),
- path);
- goto cleanup;
+ /* local file - log the error returned by virFileOpenAs */
+ goto error;
}
/* Retry creating the file as cfg->user */
@@ -2614,8 +2607,9 @@ qemuOpenFile(virQEMUDriverPtr driver, const char *path, int oflags,
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
cfg->user, cfg->group,
vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
- virReportSystemError(-fd,
- _("Error from child process creating '%s'"),
+ virReportSystemError(-fd, oflags & O_CREAT
+ ? _("Error from child process creating '%s'")
+ : _("Error from child process opening '%s'"),
path);
goto cleanup;
}
@@ -2634,6 +2628,13 @@ cleanup:
*bypassSecurityDriver = bypass_security;
virObjectUnref(cfg);
return fd;
+
+error:
+ virReportSystemError(-fd, oflags & O_CREAT
+ ? _("Failed to create file '%s'")
+ : _("Failed to open file '%s'"),
+ path);
+ goto cleanup;
}
/* Helper function to execute a migration to file with a correct save header
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index b85a5a9..39f9a99 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -405,7 +405,7 @@ virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED,
vol->target.perms.gid,
operation_flags)) < 0) {
virReportSystemError(-fd,
- _("cannot create path '%s'"),
+ _("Failed to create file '%s'"),
vol->target.path);
goto cleanup;
}
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
index c7bb85a..0c43397 100644
--- a/src/util/virstoragefile.c
+++ b/src/util/virstoragefile.c
@@ -893,7 +893,7 @@ virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid)
int fd, ret;
if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) {
- virReportSystemError(errno, _("cannot open file '%s'"), path);
+ virReportSystemError(-fd, _("Failed to open file '%s'"), path);
return -1;
}
@@ -952,7 +952,7 @@ virStorageFileGetMetadataRecurse(const char *path, const char *directory,
return NULL;
if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) {
- virReportSystemError(-fd, _("cannot open file '%s'"), path);
+ virReportSystemError(-fd, _("Failed to open file '%s'"), path);
return NULL;
}
diff --git a/src/util/virutil.c b/src/util/virutil.c
index 982d4a3..8079b0b 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -973,9 +973,11 @@ virFileOpenForked(const char *path, int openflags, mode_t mode,
* uid:gid before returning (even if it already existed with a
* different owner). If @flags includes VIR_FILE_OPEN_FORCE_MODE,
* ensure it has those permissions before returning (again, even if
- * the file already existed with different permissions). The return
- * value (if non-negative) is the file descriptor, left open. Returns
- * -errno on failure. */
+ * the file already existed with different permissions).
+ *
+ * The return value (if non-negative) is the file descriptor, left
+ * open. Returns -errno on failure.
+ */
int
virFileOpenAs(const char *path, int openflags, mode_t mode,
uid_t uid, gid_t gid, unsigned int flags)
@@ -999,6 +1001,8 @@ virFileOpenAs(const char *path, int openflags, mode_t mode,
if ((fd = open(path, openflags, mode)) < 0) {
ret = -errno;
+ if (!(flags & VIR_FILE_OPEN_FORK))
+ goto error;
} else {
ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags);
if (ret < 0)
@@ -1024,45 +1028,26 @@ virFileOpenAs(const char *path, int openflags, mode_t mode,
/* On Linux we can also verify the FS-type of the
* directory. (this is a NOP on other platforms). */
- switch (virStorageFileIsSharedFS(path)) {
- case 1:
- /* it was on a network share, so we'll re-try */
- break;
- case -1:
- /* failure detecting fstype */
- virReportSystemError(errno, _("couldn't determine fs type "
- "of mount containing '%s'"), path);
- goto error;
- case 0:
- default:
- /* file isn't on a recognized network FS */
+ if (virStorageFileIsSharedFS(path) <= 0)
goto error;
- }
}
/* passed all prerequisites - retry the open w/fork+setuid */
if ((fd = virFileOpenForked(path, openflags, mode, uid, gid, flags)) < 0) {
ret = fd;
- fd = -1;
goto error;
}
}
/* File is successfully opened */
-
return fd;
error:
- if (fd < 0) {
- /* whoever failed the open last has already set ret = -errno */
- virReportSystemError(-ret, openflags & O_CREAT
- ? _("failed to create file '%s'")
- : _("failed to open file '%s'"),
- path);
- } else {
+ if (fd >= 0) {
/* some other failure after the open succeeded */
VIR_FORCE_CLOSE(fd);
}
+ /* whoever failed the open last has already set ret = -errno */
return ret;
}
--
1.8.1.4
11 years, 6 months
[libvirt] what does virDomainFree used for?
by yue
hi,all
i see many virDomainFree, what does it do?
thanks
----log--------------
2013-05-10 02:46:51.315+0000: 1968: debug : virDomainFree:2313 : dom=0x7fbf5c000aa0, (VM: name=longg, uuid=bad73975-ffbc-4ed7-a497-2ca0038c726a)
2013-05-10 02:46:56.319+0000: 1963: debug : virDomainInterfaceStats:7223 : dom=0x7fbf68010ad0, (VM: name=longg, uuid=bad73975-ffbc-4ed7-a497-2ca0038c726a), path=vnet0, stats=0x7fbf808f4b00, size=64
2013-05-10 02:46:56.319+0000: 1963: debug : virDomainFree:2313 : dom=0x7fbf68010ad0, (VM: name=longg, uuid=bad73975-ffbc-4ed7-a497-2ca0038c726a)
11 years, 6 months
[libvirt] [PATCH 2/2] util: move virFile* functions from virutil.c to virutil.h
by Laine Stump
These all existed before virfile.c was created, and for some reason
weren't moved.
This is mostly straightfoward, although the syntax rule prohibiting
write() had to be changed to have an exception for virfile.c instead
of virutil.c.
This movement pointed out that there is a function called
virBuildPath(), and another almost identical function called
virFileBuildPath(). They really should be a single function, which
I'll take care of as soon as I figure out what the arglist should look
like.
---
cfg.mk | 2 +-
src/esx/esx_driver.c | 5 +-
src/esx/esx_storage_backend_vmfs.c | 1 +
src/libvirt.c | 1 +
src/libvirt_private.syms | 66 +-
src/node_device/node_device_driver.c | 3 +-
src/node_device/node_device_udev.c | 1 +
src/parallels/parallels_driver.c | 1 +
src/parallels/parallels_network.c | 1 +
src/parallels/parallels_storage.c | 1 +
src/rpc/virnetsshsession.c | 3 +-
src/rpc/virnettlscontext.c | 1 +
src/security/security_dac.c | 1 +
src/storage/parthelper.c | 3 +-
src/storage/storage_backend_disk.c | 1 +
src/util/virebtables.c | 1 +
src/util/virfile.c | 1448 +++++++++++++++++++++++++++++-
src/util/virfile.h | 121 ++-
src/util/virhook.c | 2 +-
src/util/viriptables.c | 1 +
src/util/virkeyfile.c | 3 +-
src/util/virnetdevveth.c | 3 +-
src/util/virsysinfo.c | 3 +-
src/util/virusb.c | 3 +-
src/util/virutil.c | 1603 ++--------------------------------
src/util/virutil.h | 111 ---
src/vbox/vbox_XPCOMCGlue.c | 1 +
src/vmx/vmx.c | 1 +
src/xen/xm_internal.c | 1 +
tests/eventtest.c | 3 +-
tests/libvirtdconftest.c | 3 +-
tests/securityselinuxtest.c | 1 +
tests/virlockspacetest.c | 3 +-
tests/virportallocatortest.c | 1 +
tests/virstoragetest.c | 1 +
tools/virsh-interface.c | 3 +-
tools/virsh-network.c | 3 +-
tools/virsh-nodedev.c | 1 +
tools/virsh-nwfilter.c | 3 +-
tools/virsh-pool.c | 3 +-
tools/virsh-secret.c | 3 +-
tools/virsh-snapshot.c | 3 +-
42 files changed, 1746 insertions(+), 1678 deletions(-)
diff --git a/cfg.mk b/cfg.mk
index 227c18b..0bf5bfc 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -841,7 +841,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/(vircommand|virutil)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon
+_src1=libvirt|fdstream|qemu/qemu_monitor|util/(vircommand|virfile)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon
_test1=shunloadtest|virnettlscontexttest|vircgroupmock
exclude_file_name_regexp--sc_avoid_write = \
^(src/($(_src1))|daemon/libvirtd|tools/console|tests/($(_test1)))\.c$$
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index dcf64b8..eff02a0 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -2,7 +2,7 @@
/*
* esx_driver.c: core driver functions for managing VMware ESX hosts
*
- * Copyright (C) 2010-2012 Red Hat, Inc.
+ * Copyright (C) 2010-2013 Red Hat, Inc.
* Copyright (C) 2009-2013 Matthias Bolte <matthias.bolte(a)googlemail.com>
* Copyright (C) 2009 Maximilian Wilhelm <max(a)rfc2324.org>
*
@@ -29,6 +29,7 @@
#include "snapshot_conf.h"
#include "virauth.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virlog.h"
#include "viruuid.h"
#include "vmx.h"
@@ -44,8 +45,8 @@
#include "esx_vi.h"
#include "esx_vi_methods.h"
#include "esx_util.h"
-#include "viruri.h"
#include "virstring.h"
+#include "viruri.h"
#define VIR_FROM_THIS VIR_FROM_ESX
diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c
index 5d6f183..da27144 100644
--- a/src/esx/esx_storage_backend_vmfs.c
+++ b/src/esx/esx_storage_backend_vmfs.c
@@ -32,6 +32,7 @@
#include "internal.h"
#include "md5.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virlog.h"
#include "viruuid.h"
#include "storage_conf.h"
diff --git a/src/libvirt.c b/src/libvirt.c
index 33a4419..1954051 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -59,6 +59,7 @@
# include "rpc/virnettlscontext.h"
#endif
#include "vircommand.h"
+#include "virfile.h"
#include "virrandom.h"
#include "viruri.h"
#include "virthread.h"
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d4cb4a3..3dac210 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1271,18 +1271,51 @@ virEventPollUpdateTimeout;
# util/virfile.h
+saferead;
+safewrite;
+safezero;
+virBuildPathInternal;
+virDirCreate;
+virFileAbsPath;
+virFileAccessibleAs;
+virFileBuildPath;
virFileClose;
virFileDeleteTree;
virFileDirectFdFlag;
+virFileExists;
virFileFclose;
virFileFdopen;
+virFileFindMountPoint;
+virFileHasSuffix;
+virFileIsAbsPath;
+virFileIsDir;
+virFileIsExecutable;
+virFileIsLink;
+virFileLinkPointsTo;
+virFileLock;
virFileLoopDeviceAssociate;
+virFileMakePath;
+virFileMakePathWithMode;
+virFileMatchesNameSuffix;
+virFileOpenAs;
+virFileOpenTty;
+virFileReadAll;
+virFileReadLimFD;
+virFileResolveAllLinks;
+virFileResolveLink;
virFileRewrite;
+virFileSanitizePath;
+virFileSkipRoot;
+virFileStripSuffix;
virFileTouch;
+virFileUnlock;
virFileUpdatePerm;
+virFileWaitForDevices;
virFileWrapperFdClose;
virFileWrapperFdFree;
virFileWrapperFdNew;
+virFileWriteStr;
+virFindFileInPath;
# util/virhash.h
@@ -1860,44 +1893,11 @@ virUSBDeviceSetUsedBy;
# util/virutil.h
-saferead;
-safewrite;
-safezero;
-virBuildPathInternal;
virCompareLimitUlong;
-virDirCreate;
virDoubleToStr;
virEnumFromString;
virEnumToString;
-virFileAbsPath;
-virFileAccessibleAs;
-virFileBuildPath;
-virFileExists;
-virFileFindMountPoint;
-virFileHasSuffix;
-virFileIsAbsPath;
-virFileIsDir;
-virFileIsExecutable;
-virFileIsLink;
-virFileLinkPointsTo;
-virFileLock;
-virFileMakePath;
-virFileMakePathWithMode;
-virFileMatchesNameSuffix;
-virFileOpenAs;
-virFileOpenTty;
-virFileReadAll;
-virFileReadLimFD;
-virFileResolveAllLinks;
-virFileResolveLink;
-virFileSanitizePath;
-virFileSkipRoot;
-virFileStripSuffix;
-virFileUnlock;
-virFileWaitForDevices;
-virFileWriteStr;
virFindFCHostCapableVport;
-virFindFileInPath;
virFormatIntDecimal;
virGetDeviceID;
virGetDeviceUnprivSGIO;
diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c
index 05dc49c..0877bf0 100644
--- a/src/node_device/node_device_driver.c
+++ b/src/node_device/node_device_driver.c
@@ -1,7 +1,7 @@
/*
* node_device.c: node device enumeration
*
- * Copyright (C) 2010-2011 Red Hat, Inc.
+ * Copyright (C) 2010-2013 Red Hat, Inc.
* Copyright (C) 2008 Virtual Iron Software, Inc.
* Copyright (C) 2008 David F. Lively
*
@@ -32,6 +32,7 @@
#include "virerror.h"
#include "datatypes.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virlog.h"
#include "virstring.h"
#include "node_device_conf.h"
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
index c3c97d7..cdd38c5 100644
--- a/src/node_device/node_device_udev.c
+++ b/src/node_device/node_device_udev.c
@@ -37,6 +37,7 @@
#include "viralloc.h"
#include "viruuid.h"
#include "virbuffer.h"
+#include "virfile.h"
#include "virpci.h"
#include "virstring.h"
diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c
index c29a5ba..2ed2ce2 100644
--- a/src/parallels/parallels_driver.c
+++ b/src/parallels/parallels_driver.c
@@ -45,6 +45,7 @@
#include "virlog.h"
#include "vircommand.h"
#include "configmake.h"
+#include "virfile.h"
#include "virstoragefile.h"
#include "nodeinfo.h"
#include "c-ctype.h"
diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c
index 23109d3..84c7608 100644
--- a/src/parallels/parallels_network.c
+++ b/src/parallels/parallels_network.c
@@ -27,6 +27,7 @@
#include "dirname.h"
#include "viralloc.h"
#include "virerror.h"
+#include "virfile.h"
#include "md5.h"
#include "parallels_utils.h"
#include "virstring.h"
diff --git a/src/parallels/parallels_storage.c b/src/parallels/parallels_storage.c
index 4c98e43..5f714e0 100644
--- a/src/parallels/parallels_storage.c
+++ b/src/parallels/parallels_storage.c
@@ -36,6 +36,7 @@
#include "configmake.h"
#include "virstoragefile.h"
#include "virerror.h"
+#include "virfile.h"
#include "parallels_utils.h"
#include "virstring.h"
diff --git a/src/rpc/virnetsshsession.c b/src/rpc/virnetsshsession.c
index 27750fc..189d928 100644
--- a/src/rpc/virnetsshsession.c
+++ b/src/rpc/virnetsshsession.c
@@ -1,7 +1,7 @@
/*
* virnetsshsession.c: ssh network transport provider based on libssh2
*
- * Copyright (C) 2012 Red Hat, Inc.
+ * Copyright (C) 2012-2013 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
@@ -33,6 +33,7 @@
#include "virthread.h"
#include "virutil.h"
#include "virerror.h"
+#include "virfile.h"
#include "virobject.h"
#include "virstring.h"
diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c
index 7f5975d..1a7ccb8 100644
--- a/src/rpc/virnettlscontext.c
+++ b/src/rpc/virnettlscontext.c
@@ -33,6 +33,7 @@
#include "viralloc.h"
#include "virerror.h"
+#include "virfile.h"
#include "virutil.h"
#include "virlog.h"
#include "virthread.h"
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index cd214d8..16cce0e 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -25,6 +25,7 @@
#include "security_dac.h"
#include "virerror.h"
+#include "virfile.h"
#include "viralloc.h"
#include "virlog.h"
#include "virpci.h"
diff --git a/src/storage/parthelper.c b/src/storage/parthelper.c
index c4af48f..36bb196 100644
--- a/src/storage/parthelper.c
+++ b/src/storage/parthelper.c
@@ -10,7 +10,7 @@
* in a reliable fashion if merely after a list of partitions & sizes,
* though it is fine for creating partitions.
*
- * Copyright (C) 2007-2008, 2010 Red Hat, Inc.
+ * Copyright (C) 2007-2008, 2010, 2013 Red Hat, Inc.
* Copyright (C) 2007-2008 Daniel P. Berrange
*
* This library is free software; you can redistribute it and/or
@@ -42,6 +42,7 @@
#include <locale.h>
#include "virutil.h"
+#include "virfile.h"
#include "c-ctype.h"
#include "configmake.h"
diff --git a/src/storage/storage_backend_disk.c b/src/storage/storage_backend_disk.c
index 6da2d12..c0b1f38 100644
--- a/src/storage/storage_backend_disk.c
+++ b/src/storage/storage_backend_disk.c
@@ -32,6 +32,7 @@
#include "storage_backend_disk.h"
#include "viralloc.h"
#include "vircommand.h"
+#include "virfile.h"
#include "configmake.h"
#include "virstring.h"
diff --git a/src/util/virebtables.c b/src/util/virebtables.c
index 6bc6fed..3834ea8 100644
--- a/src/util/virebtables.c
+++ b/src/util/virebtables.c
@@ -46,6 +46,7 @@
#include "vircommand.h"
#include "viralloc.h"
#include "virerror.h"
+#include "virfile.h"
#include "virlog.h"
#include "virthread.h"
#include "virstring.h"
diff --git a/src/util/virfile.c b/src/util/virfile.c
index 25a0501..1491f27 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -1,7 +1,7 @@
/*
* virfile.c: safer file handling
*
- * Copyright (C) 2010-2012 Red Hat, Inc.
+ * Copyright (C) 2010-2013 Red Hat, Inc.
* Copyright (C) 2010 IBM Corporation
* Copyright (C) 2010 Stefan Berger
* Copyright (C) 2010 Eric Blake
@@ -25,24 +25,36 @@
#include <config.h>
#include "internal.h"
-#include "virfile.h"
-
+#include <passfd.h>
#include <fcntl.h>
+#include <pty.h>
#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
#include <unistd.h>
#include <dirent.h>
+#include <dirname.h>
+#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
+# include <mntent.h>
+#endif
+#include <stdlib.h>
#if defined(__linux__) && HAVE_DECL_LO_FLAGS_AUTOCLEAR
# include <linux/loop.h>
# include <sys/ioctl.h>
#endif
-#include "vircommand.h"
#include "configmake.h"
#include "viralloc.h"
+#include "vircommand.h"
#include "virerror.h"
+#include "virfile.h"
#include "virlog.h"
+#include "virprocess.h"
#include "virstring.h"
+#include "virstoragefile.h"
+#include "virutil.h"
#define VIR_FROM_THIS VIR_FROM_NONE
@@ -728,3 +740,1431 @@ cleanup:
closedir(dh);
return ret;
}
+
+int
+virFileStripSuffix(char *str, const char *suffix)
+{
+ int len = strlen(str);
+ int suffixlen = strlen(suffix);
+
+ if (len < suffixlen)
+ return 0;
+
+ if (!STREQ(str + len - suffixlen, suffix))
+ return 0;
+
+ str[len-suffixlen] = '\0';
+
+ return 1;
+}
+
+
+/* Like read(), but restarts after EINTR. Doesn't play
+ * nicely with nonblocking FD and EAGAIN, in which case
+ * you want to use bare read(). Or even use virSocket()
+ * if the FD is related to a socket rather than a plain
+ * file or pipe. */
+ssize_t
+saferead(int fd, void *buf, size_t count)
+{
+ size_t nread = 0;
+ while (count > 0) {
+ ssize_t r = read(fd, buf, count);
+ if (r < 0 && errno == EINTR)
+ continue;
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return nread;
+ buf = (char *)buf + r;
+ count -= r;
+ nread += r;
+ }
+ return nread;
+}
+
+/* Like write(), but restarts after EINTR. Doesn't play
+ * nicely with nonblocking FD and EAGAIN, in which case
+ * you want to use bare write(). Or even use virSocket()
+ * if the FD is related to a socket rather than a plain
+ * file or pipe. */
+ssize_t
+safewrite(int fd, const void *buf, size_t count)
+{
+ size_t nwritten = 0;
+ while (count > 0) {
+ ssize_t r = write(fd, buf, count);
+
+ if (r < 0 && errno == EINTR)
+ continue;
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return nwritten;
+ buf = (const char *)buf + r;
+ count -= r;
+ nwritten += r;
+ }
+ return nwritten;
+}
+
+#ifdef HAVE_POSIX_FALLOCATE
+int
+safezero(int fd, off_t offset, off_t len)
+{
+ int ret = posix_fallocate(fd, offset, len);
+ if (ret == 0)
+ return 0;
+ errno = ret;
+ return -1;
+}
+#else
+
+# ifdef HAVE_MMAP
+int
+safezero(int fd, off_t offset, off_t len)
+{
+ int r;
+ char *buf;
+
+ /* memset wants the mmap'ed file to be present on disk so create a
+ * sparse file
+ */
+ r = ftruncate(fd, offset + len);
+ if (r < 0)
+ return -1;
+
+ buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
+ if (buf == MAP_FAILED)
+ return -1;
+
+ memset(buf, 0, len);
+ munmap(buf, len);
+
+ return 0;
+}
+
+# else /* HAVE_MMAP */
+
+int
+safezero(int fd, off_t offset, off_t len)
+{
+ int r;
+ char *buf;
+ unsigned long long remain, bytes;
+
+ if (lseek(fd, offset, SEEK_SET) < 0)
+ return -1;
+
+ /* Split up the write in small chunks so as not to allocate lots of RAM */
+ remain = len;
+ bytes = 1024 * 1024;
+
+ r = VIR_ALLOC_N(buf, bytes);
+ if (r < 0) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ while (remain) {
+ if (bytes > remain)
+ bytes = remain;
+
+ r = safewrite(fd, buf, bytes);
+ if (r < 0) {
+ VIR_FREE(buf);
+ return -1;
+ }
+
+ /* safewrite() guarantees all data will be written */
+ remain -= bytes;
+ }
+ VIR_FREE(buf);
+ return 0;
+}
+# endif /* HAVE_MMAP */
+#endif /* HAVE_POSIX_FALLOCATE */
+
+
+#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
+/* search /proc/mounts for mount point of *type; return pointer to
+ * malloc'ed string of the path if found, otherwise return NULL
+ * with errno set to an appropriate value.
+ */
+char *
+virFileFindMountPoint(const char *type)
+{
+ FILE *f;
+ struct mntent mb;
+ char mntbuf[1024];
+ char *ret = NULL;
+
+ f = setmntent("/proc/mounts", "r");
+ if (!f)
+ return NULL;
+
+ while (getmntent_r(f, &mb, mntbuf, sizeof(mntbuf))) {
+ if (STREQ(mb.mnt_type, type)) {
+ ret = strdup(mb.mnt_dir);
+ goto cleanup;
+ }
+ }
+
+ if (!ret)
+ errno = ENOENT;
+
+cleanup:
+ endmntent(f);
+
+ return ret;
+}
+
+#else /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */
+
+char *
+virFileFindMountPoint(const char *type ATTRIBUTE_UNUSED)
+{
+ errno = ENOSYS;
+
+ return NULL;
+}
+
+#endif /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */
+
+int
+virBuildPathInternal(char **path, ...)
+{
+ char *path_component = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ va_list ap;
+ int ret = 0;
+
+ va_start(ap, path);
+
+ path_component = va_arg(ap, char *);
+ virBufferAdd(&buf, path_component, -1);
+
+ while ((path_component = va_arg(ap, char *)) != NULL)
+ {
+ virBufferAddChar(&buf, '/');
+ virBufferAdd(&buf, path_component, -1);
+ }
+
+ va_end(ap);
+
+ *path = virBufferContentAndReset(&buf);
+ if (*path == NULL) {
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/* Like gnulib's fread_file, but read no more than the specified maximum
+ number of bytes. If the length of the input is <= max_len, and
+ upon error while reading that data, it works just like fread_file. */
+static char *
+saferead_lim(int fd, size_t max_len, size_t *length)
+{
+ char *buf = NULL;
+ size_t alloc = 0;
+ size_t size = 0;
+ int save_errno;
+
+ for (;;) {
+ int count;
+ int requested;
+
+ if (size + BUFSIZ + 1 > alloc) {
+ alloc += alloc / 2;
+ if (alloc < size + BUFSIZ + 1)
+ alloc = size + BUFSIZ + 1;
+
+ if (VIR_REALLOC_N(buf, alloc) < 0) {
+ save_errno = errno;
+ break;
+ }
+ }
+
+ /* Ensure that (size + requested <= max_len); */
+ requested = MIN(size < max_len ? max_len - size : 0,
+ alloc - size - 1);
+ count = saferead(fd, buf + size, requested);
+ size += count;
+
+ if (count != requested || requested == 0) {
+ save_errno = errno;
+ if (count < 0)
+ break;
+ buf[size] = '\0';
+ *length = size;
+ return buf;
+ }
+ }
+
+ VIR_FREE(buf);
+ errno = save_errno;
+ return NULL;
+}
+
+/* A wrapper around saferead_lim that maps a failure due to
+ exceeding the maximum size limitation to EOVERFLOW. */
+int
+virFileReadLimFD(int fd, int maxlen, char **buf)
+{
+ size_t len;
+ char *s;
+
+ if (maxlen <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ s = saferead_lim(fd, maxlen+1, &len);
+ if (s == NULL)
+ return -1;
+ if (len > maxlen || (int)len != len) {
+ VIR_FREE(s);
+ /* There was at least one byte more than MAXLEN.
+ Set errno accordingly. */
+ errno = EOVERFLOW;
+ return -1;
+ }
+ *buf = s;
+ return len;
+}
+
+int
+virFileReadAll(const char *path, int maxlen, char **buf)
+{
+ int fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ virReportSystemError(errno, _("Failed to open file '%s'"), path);
+ return -1;
+ }
+
+ int len = virFileReadLimFD(fd, maxlen, buf);
+ VIR_FORCE_CLOSE(fd);
+ if (len < 0) {
+ virReportSystemError(errno, _("Failed to read file '%s'"), path);
+ return -1;
+ }
+
+ return len;
+}
+
+/* Truncate @path and write @str to it. If @mode is 0, ensure that
+ @path exists; otherwise, use @mode if @path must be created.
+ Return 0 for success, nonzero for failure.
+ Be careful to preserve any errno value upon failure. */
+int
+virFileWriteStr(const char *path, const char *str, mode_t mode)
+{
+ int fd;
+
+ if (mode)
+ fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, mode);
+ else
+ fd = open(path, O_WRONLY|O_TRUNC);
+ if (fd == -1)
+ return -1;
+
+ if (safewrite(fd, str, strlen(str)) < 0) {
+ VIR_FORCE_CLOSE(fd);
+ return -1;
+ }
+
+ /* Use errno from failed close only if there was no write error. */
+ if (VIR_CLOSE(fd) != 0)
+ return -1;
+
+ return 0;
+}
+
+int
+virFileMatchesNameSuffix(const char *file,
+ const char *name,
+ const char *suffix)
+{
+ int filelen = strlen(file);
+ int namelen = strlen(name);
+ int suffixlen = strlen(suffix);
+
+ if (filelen == (namelen + suffixlen) &&
+ STREQLEN(file, name, namelen) &&
+ STREQLEN(file + namelen, suffix, suffixlen))
+ return 1;
+ else
+ return 0;
+}
+
+int
+virFileHasSuffix(const char *str,
+ const char *suffix)
+{
+ int len = strlen(str);
+ int suffixlen = strlen(suffix);
+
+ if (len < suffixlen)
+ return 0;
+
+ return STRCASEEQ(str + len - suffixlen, suffix);
+}
+
+#define SAME_INODE(Stat_buf_1, Stat_buf_2) \
+ ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \
+ && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev)
+
+/* Return nonzero if checkLink and checkDest
+ refer to the same file. Otherwise, return 0. */
+int
+virFileLinkPointsTo(const char *checkLink,
+ const char *checkDest)
+{
+ struct stat src_sb;
+ struct stat dest_sb;
+
+ return (stat(checkLink, &src_sb) == 0
+ && stat(checkDest, &dest_sb) == 0
+ && SAME_INODE(src_sb, dest_sb));
+}
+
+
+static int
+virFileResolveLinkHelper(const char *linkpath,
+ bool intermediatePaths,
+ char **resultpath)
+{
+ struct stat st;
+
+ *resultpath = NULL;
+
+ /* We don't need the full canonicalization of intermediate
+ * directories, if linkpath is absolute and the basename is
+ * already a non-symlink. */
+ if (IS_ABSOLUTE_FILE_NAME(linkpath) && !intermediatePaths) {
+ if (lstat(linkpath, &st) < 0)
+ return -1;
+
+ if (!S_ISLNK(st.st_mode)) {
+ if (!(*resultpath = strdup(linkpath)))
+ return -1;
+ return 0;
+ }
+ }
+
+ *resultpath = canonicalize_file_name(linkpath);
+
+ return *resultpath == NULL ? -1 : 0;
+}
+
+/*
+ * Attempt to resolve a symbolic link, returning an
+ * absolute path where only the last component is guaranteed
+ * not to be a symlink.
+ *
+ * Return 0 if path was not a symbolic, or the link was
+ * resolved. Return -1 with errno set upon error
+ */
+int
+virFileResolveLink(const char *linkpath, char **resultpath)
+{
+ return virFileResolveLinkHelper(linkpath, false, resultpath);
+}
+
+/*
+ * Attempt to resolve a symbolic link, returning an
+ * absolute path where every component is guaranteed
+ * not to be a symlink.
+ *
+ * Return 0 if path was not a symbolic, or the link was
+ * resolved. Return -1 with errno set upon error
+ */
+int
+virFileResolveAllLinks(const char *linkpath, char **resultpath)
+{
+ return virFileResolveLinkHelper(linkpath, true, resultpath);
+}
+
+/*
+ * Check whether the given file is a link.
+ * Returns 1 in case of the file being a link, 0 in case it is not
+ * a link and the negative errno in all other cases.
+ */
+int
+virFileIsLink(const char *linkpath)
+{
+ struct stat st;
+
+ if (lstat(linkpath, &st) < 0)
+ return -errno;
+
+ return S_ISLNK(st.st_mode) != 0;
+}
+
+
+/*
+ * Finds a requested executable file in the PATH env. e.g.:
+ * "kvm-img" will return "/usr/bin/kvm-img"
+ *
+ * You must free the result
+ */
+char *
+virFindFileInPath(const char *file)
+{
+ char *path = NULL;
+ char *pathiter;
+ char *pathseg;
+ char *fullpath = NULL;
+
+ if (file == NULL)
+ return NULL;
+
+ /* if we are passed an absolute path (starting with /), return a
+ * copy of that path, after validating that it is executable
+ */
+ if (IS_ABSOLUTE_FILE_NAME(file)) {
+ if (virFileIsExecutable(file))
+ return strdup(file);
+ else
+ return NULL;
+ }
+
+ /* If we are passed an anchored path (containing a /), then there
+ * is no path search - it must exist in the current directory
+ */
+ if (strchr(file, '/')) {
+ if (virFileIsExecutable(file))
+ ignore_value(virFileAbsPath(file, &path));
+ return path;
+ }
+
+ /* copy PATH env so we can tweak it */
+ path = getenv("PATH");
+
+ if (path == NULL || (path = strdup(path)) == NULL)
+ return NULL;
+
+ /* for each path segment, append the file to search for and test for
+ * it. return it if found.
+ */
+ pathiter = path;
+ while ((pathseg = strsep(&pathiter, ":")) != NULL) {
+ if (virAsprintf(&fullpath, "%s/%s", pathseg, file) < 0 ||
+ virFileIsExecutable(fullpath))
+ break;
+ VIR_FREE(fullpath);
+ }
+
+ VIR_FREE(path);
+ return fullpath;
+}
+
+bool
+virFileIsDir(const char *path)
+{
+ struct stat s;
+ return (stat(path, &s) == 0) && S_ISDIR(s.st_mode);
+}
+
+bool
+virFileExists(const char *path)
+{
+ return access(path, F_OK) == 0;
+}
+
+/* Check that a file is regular and has executable bits. If false is
+ * returned, errno is valid.
+ *
+ * Note: In the presence of ACLs, this may return true for a file that
+ * would actually fail with EACCES for a given user, or false for a
+ * file that the user could actually execute, but setups with ACLs
+ * that weird are unusual. */
+bool
+virFileIsExecutable(const char *file)
+{
+ struct stat sb;
+
+ /* We would also want to check faccessat if we cared about ACLs,
+ * but we don't. */
+ if (stat(file, &sb) < 0)
+ return false;
+ if (S_ISREG(sb.st_mode) && (sb.st_mode & 0111) != 0)
+ return true;
+ errno = S_ISDIR(sb.st_mode) ? EISDIR : EACCES;
+ return false;
+}
+
+#ifndef WIN32
+/* Check that a file is accessible under certain
+ * user & gid.
+ * @mode can be F_OK, or a bitwise combination of R_OK, W_OK, and X_OK.
+ * see 'man access' for more details.
+ * Returns 0 on success, -1 on fail with errno set.
+ */
+int
+virFileAccessibleAs(const char *path, int mode,
+ uid_t uid, gid_t gid)
+{
+ pid_t pid = 0;
+ int status, ret = 0;
+ int forkRet = 0;
+
+ if (uid == getuid() &&
+ gid == getgid())
+ return access(path, mode);
+
+ forkRet = virFork(&pid);
+
+ if (pid < 0) {
+ return -1;
+ }
+
+ if (pid) { /* parent */
+ if (virProcessWait(pid, &status) < 0) {
+ /* virProcessWait() already
+ * reported error */
+ return -1;
+ }
+
+ if (!WIFEXITED(status)) {
+ errno = EINTR;
+ return -1;
+ }
+
+ if (status) {
+ errno = WEXITSTATUS(status);
+ return -1;
+ }
+
+ return 0;
+ }
+
+ /* child.
+ * Return positive value here. Parent
+ * will change it to negative one. */
+
+ if (forkRet < 0) {
+ ret = errno;
+ goto childerror;
+ }
+
+ if (virSetUIDGID(uid, gid) < 0) {
+ ret = errno;
+ goto childerror;
+ }
+
+ if (access(path, mode) < 0)
+ ret = errno;
+
+childerror:
+ if ((ret & 0xFF) != ret) {
+ VIR_WARN("unable to pass desired return value %d", ret);
+ ret = 0xFF;
+ }
+
+ _exit(ret);
+}
+
+/* virFileOpenForceOwnerMode() - an internal utility function called
+ * only by virFileOpenAs(). Sets the owner and mode of the file
+ * opened as "fd" if it's not correct AND the flags say it should be
+ * forced. */
+static int
+virFileOpenForceOwnerMode(const char *path, int fd, mode_t mode,
+ uid_t uid, gid_t gid, unsigned int flags)
+{
+ int ret = 0;
+ struct stat st;
+
+ if (!(flags & (VIR_FILE_OPEN_FORCE_OWNER | VIR_FILE_OPEN_FORCE_MODE)))
+ return 0;
+
+ if (fstat(fd, &st) == -1) {
+ ret = -errno;
+ virReportSystemError(errno, _("stat of '%s' failed"), path);
+ return ret;
+ }
+ /* NB: uid:gid are never "-1" (default) at this point - the caller
+ * has always changed -1 to the value of get[gu]id().
+ */
+ if ((flags & VIR_FILE_OPEN_FORCE_OWNER) &&
+ ((st.st_uid != uid) || (st.st_gid != gid)) &&
+ (fchown(fd, uid, gid) < 0)) {
+ ret = -errno;
+ virReportSystemError(errno,
+ _("cannot chown '%s' to (%u, %u)"),
+ path, (unsigned int) uid,
+ (unsigned int) gid);
+ return ret;
+ }
+ if ((flags & VIR_FILE_OPEN_FORCE_MODE) &&
+ ((mode & (S_IRWXU|S_IRWXG|S_IRWXO)) !=
+ (st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))) &&
+ (fchmod(fd, mode) < 0)) {
+ ret = -errno;
+ virReportSystemError(errno,
+ _("cannot set mode of '%s' to %04o"),
+ path, mode);
+ return ret;
+ }
+ return ret;
+}
+
+/* virFileOpenForked() - an internal utility function called only by
+ * virFileOpenAs(). It forks, then the child does setuid+setgid to
+ * given uid:gid and attempts to open the file, while the parent just
+ * calls recvfd to get the open fd back from the child. returns the
+ * fd, or -errno if there is an error. */
+static int
+virFileOpenForked(const char *path, int openflags, mode_t mode,
+ uid_t uid, gid_t gid, unsigned int flags)
+{
+ pid_t pid;
+ int waitret, status, ret = 0;
+ int fd = -1;
+ int pair[2] = { -1, -1 };
+ int forkRet;
+
+ /* parent is running as root, but caller requested that the
+ * file be opened as some other user and/or group). The
+ * following dance avoids problems caused by root-squashing
+ * NFS servers. */
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) {
+ ret = -errno;
+ virReportSystemError(errno,
+ _("failed to create socket needed for '%s'"),
+ path);
+ return ret;
+ }
+
+ forkRet = virFork(&pid);
+ if (pid < 0)
+ return -errno;
+
+ if (pid == 0) {
+
+ /* child */
+
+ VIR_FORCE_CLOSE(pair[0]); /* preserves errno */
+ if (forkRet < 0) {
+ /* error encountered and logged in virFork() after the fork. */
+ ret = -errno;
+ goto childerror;
+ }
+
+ /* set desired uid/gid, then attempt to create the file */
+
+ if (virSetUIDGID(uid, gid) < 0) {
+ ret = -errno;
+ goto childerror;
+ }
+
+ if ((fd = open(path, openflags, mode)) < 0) {
+ ret = -errno;
+ virReportSystemError(errno,
+ _("child process failed to create file '%s'"),
+ path);
+ goto childerror;
+ }
+
+ /* File is successfully open. Set permissions if requested. */
+ ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags);
+ if (ret < 0)
+ goto childerror;
+
+ do {
+ ret = sendfd(pair[1], fd);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0) {
+ ret = -errno;
+ virReportSystemError(errno, "%s",
+ _("child process failed to send fd to parent"));
+ goto childerror;
+ }
+
+ childerror:
+ /* ret tracks -errno on failure, but exit value must be positive.
+ * If the child exits with EACCES, then the parent tries again. */
+ /* XXX This makes assumptions about errno being < 255, which is
+ * not true on Hurd. */
+ VIR_FORCE_CLOSE(pair[1]);
+ if (ret < 0) {
+ VIR_FORCE_CLOSE(fd);
+ }
+ ret = -ret;
+ if ((ret & 0xff) != ret) {
+ VIR_WARN("unable to pass desired return value %d", ret);
+ ret = 0xff;
+ }
+ _exit(ret);
+ }
+
+ /* parent */
+
+ VIR_FORCE_CLOSE(pair[1]);
+
+ do {
+ fd = recvfd(pair[0], 0);
+ } while (fd < 0 && errno == EINTR);
+ VIR_FORCE_CLOSE(pair[0]); /* NB: this preserves errno */
+
+ if (fd < 0 && errno != EACCES) {
+ ret = -errno;
+ while (waitpid(pid, NULL, 0) == -1 && errno == EINTR);
+ return ret;
+ }
+
+ /* wait for child to complete, and retrieve its exit code */
+ while ((waitret = waitpid(pid, &status, 0) == -1)
+ && (errno == EINTR));
+ if (waitret == -1) {
+ ret = -errno;
+ virReportSystemError(errno,
+ _("failed to wait for child creating '%s'"),
+ path);
+ VIR_FORCE_CLOSE(fd);
+ return ret;
+ }
+ if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES ||
+ fd == -1) {
+ /* fall back to the simpler method, which works better in
+ * some cases */
+ VIR_FORCE_CLOSE(fd);
+ if (flags & VIR_FILE_OPEN_NOFORK) {
+ /* If we had already tried opening w/o fork+setuid and
+ * failed, no sense trying again. Just set return the
+ * original errno that we got at that time (by
+ * definition, always either EACCES or EPERM - EACCES
+ * is close enough).
+ */
+ return -EACCES;
+ }
+ if ((fd = open(path, openflags, mode)) < 0)
+ return -errno;
+ ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags);
+ if (ret < 0) {
+ VIR_FORCE_CLOSE(fd);
+ return ret;
+ }
+ }
+ return fd;
+}
+
+/**
+ * virFileOpenAs:
+ * @path: file to open or create
+ * @openflags: flags to pass to open
+ * @mode: mode to use on creation or when forcing permissions
+ * @uid: uid that should own file on creation
+ * @gid: gid that should own file
+ * @flags: bit-wise or of VIR_FILE_OPEN_* flags
+ *
+ * Open @path, and return an fd to the open file. @openflags contains
+ * the flags normally passed to open(2), while those in @flags are
+ * used internally. If @flags includes VIR_FILE_OPEN_NOFORK, then try
+ * opening the file while executing with the current uid:gid
+ * (i.e. don't fork+setuid+setgid before the call to open()). If
+ * @flags includes VIR_FILE_OPEN_FORK, then try opening the file while
+ * the effective user id is @uid (by forking a child process); this
+ * allows one to bypass root-squashing NFS issues; NOFORK is always
+ * tried before FORK (the absence of both flags is treated identically
+ * to (VIR_FILE_OPEN_NOFORK | VIR_FILE_OPEN_FORK)). If @flags includes
+ * VIR_FILE_OPEN_FORCE_OWNER, then ensure that @path is owned by
+ * uid:gid before returning (even if it already existed with a
+ * different owner). If @flags includes VIR_FILE_OPEN_FORCE_MODE,
+ * ensure it has those permissions before returning (again, even if
+ * the file already existed with different permissions).
+ *
+ * The return value (if non-negative) is the file descriptor, left
+ * open. Returns -errno on failure.
+ */
+int
+virFileOpenAs(const char *path, int openflags, mode_t mode,
+ uid_t uid, gid_t gid, unsigned int flags)
+{
+ int ret = 0, fd = -1;
+
+ /* allow using -1 to mean "current value" */
+ if (uid == (uid_t) -1)
+ uid = getuid();
+ if (gid == (gid_t) -1)
+ gid = getgid();
+
+ /* treat absence of both flags as presence of both for simpler
+ * calling. */
+ if (!(flags & (VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK)))
+ flags |= VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK;
+
+ if ((flags & VIR_FILE_OPEN_NOFORK)
+ || (getuid() != 0)
+ || ((uid == 0) && (gid == 0))) {
+
+ if ((fd = open(path, openflags, mode)) < 0) {
+ ret = -errno;
+ if (!(flags & VIR_FILE_OPEN_FORK))
+ goto error;
+ } else {
+ ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags);
+ if (ret < 0)
+ goto error;
+ }
+ }
+
+ /* If we either 1) didn't try opening as current user at all, or
+ * 2) failed, and errno/virStorageFileIsSharedFS indicate we might
+ * be successful if we try as a different uid, then try doing
+ * fork+setuid+setgid before opening.
+ */
+ if ((fd < 0) && (flags & VIR_FILE_OPEN_FORK)) {
+
+ if (ret < 0) {
+ /* An open(2) that failed due to insufficient permissions
+ * could return one or the other of these depending on OS
+ * version and circumstances. Any other errno indicates a
+ * problem that couldn't be remedied by fork+setuid
+ * anyway. */
+ if (ret != -EACCES && ret != -EPERM)
+ goto error;
+
+ /* On Linux we can also verify the FS-type of the
+ * directory. (this is a NOP on other platforms). */
+ if (virStorageFileIsSharedFS(path) <= 0)
+ goto error;
+ }
+
+ /* passed all prerequisites - retry the open w/fork+setuid */
+ if ((fd = virFileOpenForked(path, openflags, mode, uid, gid, flags)) < 0) {
+ ret = fd;
+ goto error;
+ }
+ }
+
+ /* File is successfully opened */
+ return fd;
+
+error:
+ if (fd >= 0) {
+ /* some other failure after the open succeeded */
+ VIR_FORCE_CLOSE(fd);
+ }
+ /* whoever failed the open last has already set ret = -errno */
+ return ret;
+}
+
+/* return -errno on failure, or 0 on success */
+static int
+virDirCreateNoFork(const char *path,
+ mode_t mode, uid_t uid, gid_t gid,
+ unsigned int flags)
+{
+ int ret = 0;
+ struct stat st;
+
+ if ((mkdir(path, mode) < 0)
+ && !((errno == EEXIST) && (flags & VIR_DIR_CREATE_ALLOW_EXIST))) {
+ ret = -errno;
+ virReportSystemError(errno, _("failed to create directory '%s'"),
+ path);
+ goto error;
+ }
+
+ if (stat(path, &st) == -1) {
+ ret = -errno;
+ virReportSystemError(errno, _("stat of '%s' failed"), path);
+ goto error;
+ }
+ if (((st.st_uid != uid) || (st.st_gid != gid))
+ && (chown(path, uid, gid) < 0)) {
+ ret = -errno;
+ virReportSystemError(errno, _("cannot chown '%s' to (%u, %u)"),
+ path, (unsigned int) uid, (unsigned int) gid);
+ goto error;
+ }
+ if ((flags & VIR_DIR_CREATE_FORCE_PERMS)
+ && (chmod(path, mode) < 0)) {
+ ret = -errno;
+ virReportSystemError(errno,
+ _("cannot set mode of '%s' to %04o"),
+ path, mode);
+ goto error;
+ }
+error:
+ return ret;
+}
+
+/* return -errno on failure, or 0 on success */
+int
+virDirCreate(const char *path,
+ mode_t mode, uid_t uid, gid_t gid,
+ unsigned int flags)
+{
+ struct stat st;
+ pid_t pid;
+ int waitret;
+ int status, ret = 0;
+
+ /* allow using -1 to mean "current value" */
+ if (uid == (uid_t) -1)
+ uid = getuid();
+ if (gid == (gid_t) -1)
+ gid = getgid();
+
+ if ((!(flags & VIR_DIR_CREATE_AS_UID))
+ || (getuid() != 0)
+ || ((uid == 0) && (gid == 0))
+ || ((flags & VIR_DIR_CREATE_ALLOW_EXIST) && (stat(path, &st) >= 0))) {
+ return virDirCreateNoFork(path, mode, uid, gid, flags);
+ }
+
+ int forkRet = virFork(&pid);
+
+ if (pid < 0) {
+ ret = -errno;
+ return ret;
+ }
+
+ if (pid) { /* parent */
+ /* wait for child to complete, and retrieve its exit code */
+ while ((waitret = waitpid(pid, &status, 0) == -1) && (errno == EINTR));
+ if (waitret == -1) {
+ ret = -errno;
+ virReportSystemError(errno,
+ _("failed to wait for child creating '%s'"),
+ path);
+ goto parenterror;
+ }
+ if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES) {
+ /* fall back to the simpler method, which works better in
+ * some cases */
+ return virDirCreateNoFork(path, mode, uid, gid, flags);
+ }
+parenterror:
+ return ret;
+ }
+
+ /* child */
+
+ if (forkRet < 0) {
+ /* error encountered and logged in virFork() after the fork. */
+ goto childerror;
+ }
+
+ /* set desired uid/gid, then attempt to create the directory */
+
+ if (virSetUIDGID(uid, gid) < 0) {
+ ret = -errno;
+ goto childerror;
+ }
+ if (mkdir(path, mode) < 0) {
+ ret = -errno;
+ if (ret != -EACCES) {
+ /* in case of EACCES, the parent will retry */
+ virReportSystemError(errno, _("child failed to create directory '%s'"),
+ path);
+ }
+ goto childerror;
+ }
+ /* check if group was set properly by creating after
+ * setgid. If not, try doing it with chown */
+ if (stat(path, &st) == -1) {
+ ret = -errno;
+ virReportSystemError(errno,
+ _("stat of '%s' failed"), path);
+ goto childerror;
+ }
+ if ((st.st_gid != gid) && (chown(path, (uid_t) -1, gid) < 0)) {
+ ret = -errno;
+ virReportSystemError(errno,
+ _("cannot chown '%s' to group %u"),
+ path, (unsigned int) gid);
+ goto childerror;
+ }
+ if ((flags & VIR_DIR_CREATE_FORCE_PERMS)
+ && chmod(path, mode) < 0) {
+ virReportSystemError(errno,
+ _("cannot set mode of '%s' to %04o"),
+ path, mode);
+ goto childerror;
+ }
+childerror:
+ _exit(ret);
+}
+
+#else /* WIN32 */
+
+int
+virFileAccessibleAs(const char *path,
+ int mode,
+ uid_t uid ATTRIBUTE_UNUSED,
+ gid_t gid ATTRIBUTE_UNUSED)
+{
+
+ VIR_WARN("Ignoring uid/gid due to WIN32");
+
+ return access(path, mode);
+}
+
+/* return -errno on failure, or 0 on success */
+int
+virFileOpenAs(const char *path ATTRIBUTE_UNUSED,
+ int openflags ATTRIBUTE_UNUSED,
+ mode_t mode ATTRIBUTE_UNUSED,
+ uid_t uid ATTRIBUTE_UNUSED,
+ gid_t gid ATTRIBUTE_UNUSED,
+ unsigned int flags_unused ATTRIBUTE_UNUSED)
+{
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("virFileOpenAs is not implemented for WIN32"));
+
+ return -ENOSYS;
+}
+
+int
+virDirCreate(const char *path ATTRIBUTE_UNUSED,
+ mode_t mode ATTRIBUTE_UNUSED,
+ uid_t uid ATTRIBUTE_UNUSED,
+ gid_t gid ATTRIBUTE_UNUSED,
+ unsigned int flags_unused ATTRIBUTE_UNUSED)
+{
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("virDirCreate is not implemented for WIN32"));
+
+ return -ENOSYS;
+}
+#endif /* WIN32 */
+
+static int
+virFileMakePathHelper(char *path, mode_t mode)
+{
+ struct stat st;
+ char *p;
+
+ VIR_DEBUG("path=%s mode=0%o", path, mode);
+
+ if (stat(path, &st) >= 0) {
+ if (S_ISDIR(st.st_mode))
+ return 0;
+
+ errno = ENOTDIR;
+ return -1;
+ }
+
+ if (errno != ENOENT)
+ return -1;
+
+ if ((p = strrchr(path, '/')) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (p != path) {
+ *p = '\0';
+
+ if (virFileMakePathHelper(path, mode) < 0)
+ return -1;
+
+ *p = '/';
+ }
+
+ if (mkdir(path, mode) < 0 && errno != EEXIST)
+ return -1;
+
+ return 0;
+}
+
+/**
+ * Creates the given directory with mode 0777 if it's not already existing.
+ *
+ * Returns 0 on success, or -1 if an error occurred (in which case, errno
+ * is set appropriately).
+ */
+int
+virFileMakePath(const char *path)
+{
+ return virFileMakePathWithMode(path, 0777);
+}
+
+int
+virFileMakePathWithMode(const char *path,
+ mode_t mode)
+{
+ int ret = -1;
+ char *tmp;
+
+ if ((tmp = strdup(path)) == NULL)
+ goto cleanup;
+
+ ret = virFileMakePathHelper(tmp, mode);
+
+cleanup:
+ VIR_FREE(tmp);
+ return ret;
+}
+
+/* Build up a fully qualified path for a config file to be
+ * associated with a persistent guest or network */
+char *
+virFileBuildPath(const char *dir, const char *name, const char *ext)
+{
+ char *path;
+
+ if (ext == NULL) {
+ if (virAsprintf(&path, "%s/%s", dir, name) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+ } else {
+ if (virAsprintf(&path, "%s/%s%s", dir, name, ext) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+ }
+
+ return path;
+}
+
+/* Open a non-blocking master side of a pty. If ttyName is not NULL,
+ * then populate it with the name of the slave. If rawmode is set,
+ * also put the master side into raw mode before returning. */
+#ifndef WIN32
+int
+virFileOpenTty(int *ttymaster, char **ttyName, int rawmode)
+{
+ /* XXX A word of caution - on some platforms (Solaris and HP-UX),
+ * additional ioctl() calls are needs after opening the slave
+ * before it will cause isatty() to return true. Should we make
+ * virFileOpenTty also return the opened slave fd, so the caller
+ * doesn't have to worry about that mess? */
+ int ret = -1;
+ int slave = -1;
+ char *name = NULL;
+
+ /* Unfortunately, we can't use the name argument of openpty, since
+ * there is no guarantee on how large the buffer has to be.
+ * Likewise, we can't use the termios argument: we have to use
+ * read-modify-write since there is no portable way to initialize
+ * a struct termios without use of tcgetattr. */
+ if (openpty(ttymaster, &slave, NULL, NULL, NULL) < 0)
+ return -1;
+
+ /* What a shame that openpty cannot atomically set FD_CLOEXEC, but
+ * that using posix_openpt/grantpt/unlockpt/ptsname is not
+ * thread-safe, and that ptsname_r is not portable. */
+ if (virSetNonBlock(*ttymaster) < 0 ||
+ virSetCloseExec(*ttymaster) < 0)
+ goto cleanup;
+
+ /* While Linux supports tcgetattr on either the master or the
+ * slave, Solaris requires it to be on the slave. */
+ if (rawmode) {
+ struct termios ttyAttr;
+ if (tcgetattr(slave, &ttyAttr) < 0)
+ goto cleanup;
+
+ cfmakeraw(&ttyAttr);
+
+ if (tcsetattr(slave, TCSADRAIN, &ttyAttr) < 0)
+ goto cleanup;
+ }
+
+ /* ttyname_r on the slave is required by POSIX, while ptsname_r on
+ * the master is a glibc extension, and the POSIX ptsname is not
+ * thread-safe. Since openpty gave us both descriptors, guess
+ * which way we will determine the name? :) */
+ if (ttyName) {
+ /* Initial guess of 64 is generally sufficient; rely on ERANGE
+ * to tell us if we need to grow. */
+ size_t len = 64;
+ int rc;
+
+ if (VIR_ALLOC_N(name, len) < 0)
+ goto cleanup;
+
+ while ((rc = ttyname_r(slave, name, len)) == ERANGE) {
+ if (VIR_RESIZE_N(name, len, len, len) < 0)
+ goto cleanup;
+ }
+ if (rc != 0) {
+ errno = rc;
+ goto cleanup;
+ }
+ *ttyName = name;
+ name = NULL;
+ }
+
+ ret = 0;
+
+cleanup:
+ if (ret != 0)
+ VIR_FORCE_CLOSE(*ttymaster);
+ VIR_FORCE_CLOSE(slave);
+ VIR_FREE(name);
+
+ return ret;
+}
+#else /* WIN32 */
+int
+virFileOpenTty(int *ttymaster ATTRIBUTE_UNUSED,
+ char **ttyName ATTRIBUTE_UNUSED,
+ int rawmode ATTRIBUTE_UNUSED)
+{
+ /* mingw completely lacks pseudo-terminals, and the gnulib
+ * replacements are not (yet) license compatible. */
+ errno = ENOSYS;
+ return -1;
+}
+#endif /* WIN32 */
+
+bool
+virFileIsAbsPath(const char *path)
+{
+ if (!path)
+ return false;
+
+ if (VIR_FILE_IS_DIR_SEPARATOR(path[0]))
+ return true;
+
+#ifdef WIN32
+ if (c_isalpha(path[0]) &&
+ path[1] == ':' &&
+ VIR_FILE_IS_DIR_SEPARATOR(path[2]))
+ return true;
+#endif
+
+ return false;
+}
+
+
+const char *
+virFileSkipRoot(const char *path)
+{
+#ifdef WIN32
+ /* Skip \\server\share or //server/share */
+ if (VIR_FILE_IS_DIR_SEPARATOR(path[0]) &&
+ VIR_FILE_IS_DIR_SEPARATOR(path[1]) &&
+ path[2] &&
+ !VIR_FILE_IS_DIR_SEPARATOR(path[2]))
+ {
+ const char *p = strchr(path + 2, VIR_FILE_DIR_SEPARATOR);
+ const char *q = strchr(path + 2, '/');
+
+ if (p == NULL || (q != NULL && q < p))
+ p = q;
+
+ if (p && p > path + 2 && p[1]) {
+ path = p + 1;
+
+ while (path[0] &&
+ !VIR_FILE_IS_DIR_SEPARATOR(path[0]))
+ path++;
+
+ /* Possibly skip a backslash after the share name */
+ if (VIR_FILE_IS_DIR_SEPARATOR(path[0]))
+ path++;
+
+ return path;
+ }
+ }
+#endif
+
+ /* Skip initial slashes */
+ if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) {
+ while (VIR_FILE_IS_DIR_SEPARATOR(path[0]))
+ path++;
+
+ return path;
+ }
+
+#ifdef WIN32
+ /* Skip X:\ */
+ if (c_isalpha(path[0]) &&
+ path[1] == ':' &&
+ VIR_FILE_IS_DIR_SEPARATOR(path[2]))
+ return path + 3;
+#endif
+
+ return path;
+}
+
+
+
+/*
+ * Creates an absolute path for a potentially relative path.
+ * Return 0 if the path was not relative, or on success.
+ * Return -1 on error.
+ *
+ * You must free the result.
+ */
+int
+virFileAbsPath(const char *path, char **abspath)
+{
+ char *buf;
+
+ if (path[0] == '/') {
+ if (!(*abspath = strdup(path)))
+ return -1;
+ } else {
+ buf = getcwd(NULL, 0);
+ if (buf == NULL)
+ return -1;
+
+ if (virAsprintf(abspath, "%s/%s", buf, path) < 0) {
+ VIR_FREE(buf);
+ return -1;
+ }
+ VIR_FREE(buf);
+ }
+
+ return 0;
+}
+
+/* Remove spurious / characters from a path. The result must be freed */
+char *
+virFileSanitizePath(const char *path)
+{
+ const char *cur = path;
+ char *cleanpath;
+ int idx = 0;
+
+ cleanpath = strdup(path);
+ if (!cleanpath) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ /* Need to sanitize:
+ * // -> //
+ * /// -> /
+ * /../foo -> /../foo
+ * /foo///bar/ -> /foo/bar
+ */
+
+ /* Starting with // is valid posix, but ///foo == /foo */
+ if (cur[0] == '/' && cur[1] == '/' && cur[2] != '/') {
+ idx = 2;
+ cur += 2;
+ }
+
+ /* Sanitize path in place */
+ while (*cur != '\0') {
+ if (*cur != '/') {
+ cleanpath[idx++] = *cur++;
+ continue;
+ }
+
+ /* Skip all extra / */
+ while (*++cur == '/')
+ continue;
+
+ /* Don't add a trailing / */
+ if (idx != 0 && *cur == '\0')
+ break;
+
+ cleanpath[idx++] = '/';
+ }
+ cleanpath[idx] = '\0';
+
+ return cleanpath;
+}
diff --git a/src/util/virfile.h b/src/util/virfile.h
index 5f0dd2b..bd35331 100644
--- a/src/util/virfile.h
+++ b/src/util/virfile.h
@@ -1,7 +1,7 @@
/*
* virfile.h: safer file handling
*
- * Copyright (C) 2010-2011 Red Hat, Inc.
+ * Copyright (C) 2010-2011, 2013 Red Hat, Inc.
* Copyright (C) 2010 IBM Corporation
* Copyright (C) 2010 Stefan Berger
* Copyright (C) 2010 Eric Blake
@@ -23,8 +23,8 @@
*/
-#ifndef __VIR_FILES_H_
-# define __VIR_FILES_H_
+#ifndef __VIR_FILE_H_
+# define __VIR_FILE_H_
# include <stdio.h>
@@ -36,6 +36,12 @@ typedef enum virFileCloseFlags {
VIR_FILE_CLOSE_DONT_LOG = 1 << 2,
} virFileCloseFlags;
+ssize_t saferead(int fd, void *buf, size_t count) ATTRIBUTE_RETURN_CHECK;
+ssize_t safewrite(int fd, const void *buf, size_t count)
+ ATTRIBUTE_RETURN_CHECK;
+int safezero(int fd, off_t offset, off_t len)
+ ATTRIBUTE_RETURN_CHECK;
+
/* Don't call these directly - use the macros below */
int virFileClose(int *fdptr, virFileCloseFlags flags)
ATTRIBUTE_RETURN_CHECK;
@@ -110,4 +116,111 @@ int virFileLoopDeviceAssociate(const char *file,
int virFileDeleteTree(const char *dir);
-#endif /* __VIR_FILES_H */
+int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK;
+
+int virFileReadAll(const char *path, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK;
+
+int virFileWriteStr(const char *path, const char *str, mode_t mode)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+
+int virFileMatchesNameSuffix(const char *file,
+ const char *name,
+ const char *suffix);
+
+int virFileHasSuffix(const char *str,
+ const char *suffix);
+
+int virFileStripSuffix(char *str,
+ const char *suffix) ATTRIBUTE_RETURN_CHECK;
+
+int virFileLinkPointsTo(const char *checkLink,
+ const char *checkDest);
+
+int virFileResolveLink(const char *linkpath,
+ char **resultpath) ATTRIBUTE_RETURN_CHECK;
+int virFileResolveAllLinks(const char *linkpath,
+ char **resultpath) ATTRIBUTE_RETURN_CHECK;
+
+int virFileIsLink(const char *linkpath)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+
+char *virFindFileInPath(const char *file);
+
+bool virFileIsDir (const char *file) ATTRIBUTE_NONNULL(1);
+bool virFileExists(const char *file) ATTRIBUTE_NONNULL(1);
+bool virFileIsExecutable(const char *file) ATTRIBUTE_NONNULL(1);
+
+char *virFileSanitizePath(const char *path);
+
+enum {
+ VIR_FILE_OPEN_NONE = 0,
+ VIR_FILE_OPEN_NOFORK = (1 << 0),
+ VIR_FILE_OPEN_FORK = (1 << 1),
+ VIR_FILE_OPEN_FORCE_MODE = (1 << 2),
+ VIR_FILE_OPEN_FORCE_OWNER = (1 << 3),
+};
+int virFileAccessibleAs(const char *path, int mode,
+ uid_t uid, gid_t gid)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+int virFileOpenAs(const char *path, int openflags, mode_t mode,
+ uid_t uid, gid_t gid,
+ unsigned int flags)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+
+enum {
+ VIR_DIR_CREATE_NONE = 0,
+ VIR_DIR_CREATE_AS_UID = (1 << 0),
+ VIR_DIR_CREATE_FORCE_PERMS = (1 << 1),
+ VIR_DIR_CREATE_ALLOW_EXIST = (1 << 2),
+};
+int virDirCreate(const char *path, mode_t mode, uid_t uid, gid_t gid,
+ unsigned int flags) ATTRIBUTE_RETURN_CHECK;
+int virFileMakePath(const char *path) ATTRIBUTE_RETURN_CHECK;
+int virFileMakePathWithMode(const char *path,
+ mode_t mode) ATTRIBUTE_RETURN_CHECK;
+
+char *virFileBuildPath(const char *dir,
+ const char *name,
+ const char *ext) ATTRIBUTE_RETURN_CHECK;
+
+
+# ifdef WIN32
+/* On Win32, the canonical directory separator is the backslash, and
+ * the search path separator is the semicolon. Note that also the
+ * (forward) slash works as directory separator.
+ */
+# define VIR_FILE_DIR_SEPARATOR '\\'
+# define VIR_FILE_DIR_SEPARATOR_S "\\"
+# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR || (c) == '/')
+# define VIR_FILE_PATH_SEPARATOR ';'
+# define VIR_FILE_PATH_SEPARATOR_S ";"
+
+# else /* !WIN32 */
+
+# define VIR_FILE_DIR_SEPARATOR '/'
+# define VIR_FILE_DIR_SEPARATOR_S "/"
+# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR)
+# define VIR_FILE_PATH_SEPARATOR ':'
+# define VIR_FILE_PATH_SEPARATOR_S ":"
+
+# endif /* !WIN32 */
+
+bool virFileIsAbsPath(const char *path);
+int virFileAbsPath(const char *path,
+ char **abspath) ATTRIBUTE_RETURN_CHECK;
+const char *virFileSkipRoot(const char *path);
+
+int virFileOpenTty(int *ttymaster,
+ char **ttyName,
+ int rawmode);
+
+char *virFileFindMountPoint(const char *type);
+
+void virFileWaitForDevices(void);
+
+/* NB: this should be combined with virFileBuildPath */
+# define virBuildPath(path, ...) \
+ virBuildPathInternal(path, __VA_ARGS__, NULL)
+int virBuildPathInternal(char **path, ...) ATTRIBUTE_SENTINEL;
+
+#endif /* __VIR_FILE_H */
diff --git a/src/util/virhook.c b/src/util/virhook.c
index 097afba..508c268 100644
--- a/src/util/virhook.c
+++ b/src/util/virhook.c
@@ -1,7 +1,7 @@
/*
* virhook.c: implementation of the synchronous hooks support
*
- * Copyright (C) 2010-2012 Red Hat, Inc.
+ * Copyright (C) 2010-2013 Red Hat, Inc.
* Copyright (C) 2010 Daniel Veillard
*
* This library is free software; you can redistribute it and/or
diff --git a/src/util/viriptables.c b/src/util/viriptables.c
index 06a1356..b0fe2b0 100644
--- a/src/util/viriptables.c
+++ b/src/util/viriptables.c
@@ -44,6 +44,7 @@
#include "vircommand.h"
#include "viralloc.h"
#include "virerror.h"
+#include "virfile.h"
#include "virlog.h"
#include "virthread.h"
#include "virstring.h"
diff --git a/src/util/virkeyfile.c b/src/util/virkeyfile.c
index d77e95d..1732d0c 100644
--- a/src/util/virkeyfile.c
+++ b/src/util/virkeyfile.c
@@ -1,7 +1,7 @@
/*
* virkeyfile.c: "ini"-style configuration file handling
*
- * Copyright (C) 2012 Red Hat, Inc.
+ * Copyright (C) 2012-2013 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
@@ -28,6 +28,7 @@
#include "c-ctype.h"
#include "virlog.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virutil.h"
#include "virhash.h"
#include "virkeyfile.h"
diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c
index 5daf21e..e73c31d 100644
--- a/src/util/virnetdevveth.c
+++ b/src/util/virnetdevveth.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2011 Red Hat, Inc.
+ * Copyright (C) 2010-2013 Red Hat, Inc.
* Copyright IBM Corp. 2008
*
* This library is free software; you can redistribute it and/or
@@ -30,6 +30,7 @@
#include "virlog.h"
#include "vircommand.h"
#include "virerror.h"
+#include "virfile.h"
#include "virstring.h"
#include "virutil.h"
diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c
index 2efe634..686cd49 100644
--- a/src/util/virsysinfo.c
+++ b/src/util/virsysinfo.c
@@ -1,7 +1,7 @@
/*
* virsysinfo.c: get SMBIOS/sysinfo information from the host
*
- * Copyright (C) 2010-2012 Red Hat, Inc.
+ * Copyright (C) 2010-2013 Red Hat, Inc.
* Copyright (C) 2010 Daniel Veillard
*
* This library is free software; you can redistribute it and/or
@@ -35,6 +35,7 @@
#include "virlog.h"
#include "viralloc.h"
#include "vircommand.h"
+#include "virfile.h"
#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_SYSINFO
diff --git a/src/util/virusb.c b/src/util/virusb.c
index 3192634..27ba9c7 100644
--- a/src/util/virusb.c
+++ b/src/util/virusb.c
@@ -1,7 +1,7 @@
/*
* virusb.c: helper APIs for managing host USB devices
*
- * Copyright (C) 2009-2012 Red Hat, Inc.
+ * Copyright (C) 2009-2013 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
@@ -38,6 +38,7 @@
#include "viralloc.h"
#include "virutil.h"
#include "virerror.h"
+#include "virfile.h"
#include "virstring.h"
#define USB_SYSFS "/sys/bus/usb"
diff --git a/src/util/virutil.c b/src/util/virutil.c
index 8079b0b..c5bc9de 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -29,7 +29,6 @@
#include <dirent.h>
#include <stdio.h>
#include <stdarg.h>
-#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
@@ -37,14 +36,11 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
-#include <sys/wait.h>
#if HAVE_MMAP
# include <sys/mman.h>
#endif
#include <string.h>
-#include <signal.h>
#include <termios.h>
-#include <pty.h>
#include <locale.h>
#if HAVE_LIBDEVMAPPER_H
@@ -63,9 +59,6 @@
# include <cap-ng.h>
# include <sys/prctl.h>
#endif
-#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
-# include <mntent.h>
-#endif
#ifdef WIN32
# ifdef HAVE_WINSOCK2_H
@@ -76,1482 +69,152 @@
#endif
#include "c-ctype.h"
-#include "dirname.h"
#include "virerror.h"
#include "virlog.h"
#include "virbuffer.h"
-#include "virstoragefile.h"
#include "viralloc.h"
#include "virthread.h"
#include "verify.h"
#include "virfile.h"
#include "vircommand.h"
#include "nonblocking.h"
-#include "passfd.h"
-#include "virprocess.h"
-#include "virstring.h"
-
-#ifndef NSIG
-# define NSIG 32
-#endif
-
-verify(sizeof(gid_t) <= sizeof(unsigned int) &&
- sizeof(uid_t) <= sizeof(unsigned int));
-
-#define VIR_FROM_THIS VIR_FROM_NONE
-
-/* Like read(), but restarts after EINTR. Doesn't play
- * nicely with nonblocking FD and EAGAIN, in which case
- * you want to use bare read(). Or even use virSocket()
- * if the FD is related to a socket rather than a plain
- * file or pipe. */
-ssize_t
-saferead(int fd, void *buf, size_t count)
-{
- size_t nread = 0;
- while (count > 0) {
- ssize_t r = read(fd, buf, count);
- if (r < 0 && errno == EINTR)
- continue;
- if (r < 0)
- return r;
- if (r == 0)
- return nread;
- buf = (char *)buf + r;
- count -= r;
- nread += r;
- }
- return nread;
-}
-
-/* Like write(), but restarts after EINTR. Doesn't play
- * nicely with nonblocking FD and EAGAIN, in which case
- * you want to use bare write(). Or even use virSocket()
- * if the FD is related to a socket rather than a plain
- * file or pipe. */
-ssize_t
-safewrite(int fd, const void *buf, size_t count)
-{
- size_t nwritten = 0;
- while (count > 0) {
- ssize_t r = write(fd, buf, count);
-
- if (r < 0 && errno == EINTR)
- continue;
- if (r < 0)
- return r;
- if (r == 0)
- return nwritten;
- buf = (const char *)buf + r;
- count -= r;
- nwritten += r;
- }
- return nwritten;
-}
-
-#ifdef HAVE_POSIX_FALLOCATE
-int safezero(int fd, off_t offset, off_t len)
-{
- int ret = posix_fallocate(fd, offset, len);
- if (ret == 0)
- return 0;
- errno = ret;
- return -1;
-}
-#else
-
-# ifdef HAVE_MMAP
-int safezero(int fd, off_t offset, off_t len)
-{
- int r;
- char *buf;
-
- /* memset wants the mmap'ed file to be present on disk so create a
- * sparse file
- */
- r = ftruncate(fd, offset + len);
- if (r < 0)
- return -1;
-
- buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
- if (buf == MAP_FAILED)
- return -1;
-
- memset(buf, 0, len);
- munmap(buf, len);
-
- return 0;
-}
-
-# else /* HAVE_MMAP */
-
-int safezero(int fd, off_t offset, off_t len)
-{
- int r;
- char *buf;
- unsigned long long remain, bytes;
-
- if (lseek(fd, offset, SEEK_SET) < 0)
- return -1;
-
- /* Split up the write in small chunks so as not to allocate lots of RAM */
- remain = len;
- bytes = 1024 * 1024;
-
- r = VIR_ALLOC_N(buf, bytes);
- if (r < 0) {
- errno = ENOMEM;
- return -1;
- }
-
- while (remain) {
- if (bytes > remain)
- bytes = remain;
-
- r = safewrite(fd, buf, bytes);
- if (r < 0) {
- VIR_FREE(buf);
- return -1;
- }
-
- /* safewrite() guarantees all data will be written */
- remain -= bytes;
- }
- VIR_FREE(buf);
- return 0;
-}
-# endif /* HAVE_MMAP */
-#endif /* HAVE_POSIX_FALLOCATE */
-
-int virFileStripSuffix(char *str,
- const char *suffix)
-{
- int len = strlen(str);
- int suffixlen = strlen(suffix);
-
- if (len < suffixlen)
- return 0;
-
- if (!STREQ(str + len - suffixlen, suffix))
- return 0;
-
- str[len-suffixlen] = '\0';
-
- return 1;
-}
-
-#ifndef WIN32
-
-int virSetInherit(int fd, bool inherit) {
- int fflags;
- if ((fflags = fcntl(fd, F_GETFD)) < 0)
- return -1;
- if (inherit)
- fflags &= ~FD_CLOEXEC;
- else
- fflags |= FD_CLOEXEC;
- if ((fcntl(fd, F_SETFD, fflags)) < 0)
- return -1;
- return 0;
-}
-
-#else /* WIN32 */
-
-int virSetInherit(int fd ATTRIBUTE_UNUSED, bool inherit ATTRIBUTE_UNUSED)
-{
- /* FIXME: Currently creating child processes is not supported on
- * Win32, so there is no point in failing calls that are only relevant
- * when creating child processes. So just pretend that we changed the
- * inheritance property of the given fd as requested. */
- return 0;
-}
-
-#endif /* WIN32 */
-
-int virSetBlocking(int fd, bool blocking) {
- return set_nonblocking_flag(fd, !blocking);
-}
-
-int virSetNonBlock(int fd) {
- return virSetBlocking(fd, false);
-}
-
-int virSetCloseExec(int fd)
-{
- return virSetInherit(fd, false);
-}
-
-int
-virPipeReadUntilEOF(int outfd, int errfd,
- char **outbuf, char **errbuf) {
-
- struct pollfd fds[2];
- int i;
- int finished[2];
-
- fds[0].fd = outfd;
- fds[0].events = POLLIN;
- fds[0].revents = 0;
- finished[0] = 0;
- fds[1].fd = errfd;
- fds[1].events = POLLIN;
- fds[1].revents = 0;
- finished[1] = 0;
-
- while (!(finished[0] && finished[1])) {
-
- if (poll(fds, ARRAY_CARDINALITY(fds), -1) < 0) {
- if ((errno == EAGAIN) || (errno == EINTR))
- continue;
- goto pollerr;
- }
-
- for (i = 0; i < ARRAY_CARDINALITY(fds); ++i) {
- char data[1024], **buf;
- int got, size;
-
- if (!(fds[i].revents))
- continue;
- else if (fds[i].revents & POLLHUP)
- finished[i] = 1;
-
- if (!(fds[i].revents & POLLIN)) {
- if (fds[i].revents & POLLHUP)
- continue;
-
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("Unknown poll response."));
- goto error;
- }
-
- got = read(fds[i].fd, data, sizeof(data));
-
- if (got == sizeof(data))
- finished[i] = 0;
-
- if (got == 0) {
- finished[i] = 1;
- continue;
- }
- if (got < 0) {
- if (errno == EINTR)
- continue;
- if (errno == EAGAIN)
- break;
- goto pollerr;
- }
-
- buf = ((fds[i].fd == outfd) ? outbuf : errbuf);
- size = (*buf ? strlen(*buf) : 0);
- if (VIR_REALLOC_N(*buf, size+got+1) < 0) {
- virReportOOMError();
- goto error;
- }
- memmove(*buf+size, data, got);
- (*buf)[size+got] = '\0';
- }
- continue;
-
- pollerr:
- virReportSystemError(errno,
- "%s", _("poll error"));
- goto error;
- }
-
- return 0;
-
-error:
- VIR_FREE(*outbuf);
- VIR_FREE(*errbuf);
- return -1;
-}
-
-/* Like gnulib's fread_file, but read no more than the specified maximum
- number of bytes. If the length of the input is <= max_len, and
- upon error while reading that data, it works just like fread_file. */
-static char *
-saferead_lim(int fd, size_t max_len, size_t *length)
-{
- char *buf = NULL;
- size_t alloc = 0;
- size_t size = 0;
- int save_errno;
-
- for (;;) {
- int count;
- int requested;
-
- if (size + BUFSIZ + 1 > alloc) {
- alloc += alloc / 2;
- if (alloc < size + BUFSIZ + 1)
- alloc = size + BUFSIZ + 1;
-
- if (VIR_REALLOC_N(buf, alloc) < 0) {
- save_errno = errno;
- break;
- }
- }
-
- /* Ensure that (size + requested <= max_len); */
- requested = MIN(size < max_len ? max_len - size : 0,
- alloc - size - 1);
- count = saferead(fd, buf + size, requested);
- size += count;
-
- if (count != requested || requested == 0) {
- save_errno = errno;
- if (count < 0)
- break;
- buf[size] = '\0';
- *length = size;
- return buf;
- }
- }
-
- VIR_FREE(buf);
- errno = save_errno;
- return NULL;
-}
-
-/* A wrapper around saferead_lim that maps a failure due to
- exceeding the maximum size limitation to EOVERFLOW. */
-int
-virFileReadLimFD(int fd, int maxlen, char **buf)
-{
- size_t len;
- char *s;
-
- if (maxlen <= 0) {
- errno = EINVAL;
- return -1;
- }
- s = saferead_lim(fd, maxlen+1, &len);
- if (s == NULL)
- return -1;
- if (len > maxlen || (int)len != len) {
- VIR_FREE(s);
- /* There was at least one byte more than MAXLEN.
- Set errno accordingly. */
- errno = EOVERFLOW;
- return -1;
- }
- *buf = s;
- return len;
-}
-
-int virFileReadAll(const char *path, int maxlen, char **buf)
-{
- int fd = open(path, O_RDONLY);
- if (fd < 0) {
- virReportSystemError(errno, _("Failed to open file '%s'"), path);
- return -1;
- }
-
- int len = virFileReadLimFD(fd, maxlen, buf);
- VIR_FORCE_CLOSE(fd);
- if (len < 0) {
- virReportSystemError(errno, _("Failed to read file '%s'"), path);
- return -1;
- }
-
- return len;
-}
-
-/* Truncate @path and write @str to it. If @mode is 0, ensure that
- @path exists; otherwise, use @mode if @path must be created.
- Return 0 for success, nonzero for failure.
- Be careful to preserve any errno value upon failure. */
-int virFileWriteStr(const char *path, const char *str, mode_t mode)
-{
- int fd;
-
- if (mode)
- fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, mode);
- else
- fd = open(path, O_WRONLY|O_TRUNC);
- if (fd == -1)
- return -1;
-
- if (safewrite(fd, str, strlen(str)) < 0) {
- VIR_FORCE_CLOSE(fd);
- return -1;
- }
-
- /* Use errno from failed close only if there was no write error. */
- if (VIR_CLOSE(fd) != 0)
- return -1;
-
- return 0;
-}
-
-int virFileMatchesNameSuffix(const char *file,
- const char *name,
- const char *suffix)
-{
- int filelen = strlen(file);
- int namelen = strlen(name);
- int suffixlen = strlen(suffix);
-
- if (filelen == (namelen + suffixlen) &&
- STREQLEN(file, name, namelen) &&
- STREQLEN(file + namelen, suffix, suffixlen))
- return 1;
- else
- return 0;
-}
-
-int virFileHasSuffix(const char *str,
- const char *suffix)
-{
- int len = strlen(str);
- int suffixlen = strlen(suffix);
-
- if (len < suffixlen)
- return 0;
-
- return STRCASEEQ(str + len - suffixlen, suffix);
-}
-
-#define SAME_INODE(Stat_buf_1, Stat_buf_2) \
- ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \
- && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev)
-
-/* Return nonzero if checkLink and checkDest
- refer to the same file. Otherwise, return 0. */
-int virFileLinkPointsTo(const char *checkLink,
- const char *checkDest)
-{
- struct stat src_sb;
- struct stat dest_sb;
-
- return (stat(checkLink, &src_sb) == 0
- && stat(checkDest, &dest_sb) == 0
- && SAME_INODE(src_sb, dest_sb));
-}
-
-
-
-static int
-virFileResolveLinkHelper(const char *linkpath,
- bool intermediatePaths,
- char **resultpath)
-{
- struct stat st;
-
- *resultpath = NULL;
-
- /* We don't need the full canonicalization of intermediate
- * directories, if linkpath is absolute and the basename is
- * already a non-symlink. */
- if (IS_ABSOLUTE_FILE_NAME(linkpath) && !intermediatePaths) {
- if (lstat(linkpath, &st) < 0)
- return -1;
-
- if (!S_ISLNK(st.st_mode)) {
- if (!(*resultpath = strdup(linkpath)))
- return -1;
- return 0;
- }
- }
-
- *resultpath = canonicalize_file_name(linkpath);
-
- return *resultpath == NULL ? -1 : 0;
-}
-
-/*
- * Attempt to resolve a symbolic link, returning an
- * absolute path where only the last component is guaranteed
- * not to be a symlink.
- *
- * Return 0 if path was not a symbolic, or the link was
- * resolved. Return -1 with errno set upon error
- */
-int virFileResolveLink(const char *linkpath,
- char **resultpath)
-{
- return virFileResolveLinkHelper(linkpath, false, resultpath);
-}
-
-/*
- * Attempt to resolve a symbolic link, returning an
- * absolute path where every component is guaranteed
- * not to be a symlink.
- *
- * Return 0 if path was not a symbolic, or the link was
- * resolved. Return -1 with errno set upon error
- */
-int virFileResolveAllLinks(const char *linkpath,
- char **resultpath)
-{
- return virFileResolveLinkHelper(linkpath, true, resultpath);
-}
-
-/*
- * Check whether the given file is a link.
- * Returns 1 in case of the file being a link, 0 in case it is not
- * a link and the negative errno in all other cases.
- */
-int virFileIsLink(const char *linkpath)
-{
- struct stat st;
-
- if (lstat(linkpath, &st) < 0)
- return -errno;
-
- return S_ISLNK(st.st_mode) != 0;
-}
-
-
-/*
- * Finds a requested executable file in the PATH env. e.g.:
- * "kvm-img" will return "/usr/bin/kvm-img"
- *
- * You must free the result
- */
-char *virFindFileInPath(const char *file)
-{
- char *path = NULL;
- char *pathiter;
- char *pathseg;
- char *fullpath = NULL;
-
- if (file == NULL)
- return NULL;
-
- /* if we are passed an absolute path (starting with /), return a
- * copy of that path, after validating that it is executable
- */
- if (IS_ABSOLUTE_FILE_NAME(file)) {
- if (virFileIsExecutable(file))
- return strdup(file);
- else
- return NULL;
- }
-
- /* If we are passed an anchored path (containing a /), then there
- * is no path search - it must exist in the current directory
- */
- if (strchr(file, '/')) {
- if (virFileIsExecutable(file))
- ignore_value(virFileAbsPath(file, &path));
- return path;
- }
-
- /* copy PATH env so we can tweak it */
- path = getenv("PATH");
-
- if (path == NULL || (path = strdup(path)) == NULL)
- return NULL;
-
- /* for each path segment, append the file to search for and test for
- * it. return it if found.
- */
- pathiter = path;
- while ((pathseg = strsep(&pathiter, ":")) != NULL) {
- if (virAsprintf(&fullpath, "%s/%s", pathseg, file) < 0 ||
- virFileIsExecutable(fullpath))
- break;
- VIR_FREE(fullpath);
- }
-
- VIR_FREE(path);
- return fullpath;
-}
-
-bool virFileIsDir(const char *path)
-{
- struct stat s;
- return (stat(path, &s) == 0) && S_ISDIR(s.st_mode);
-}
-
-bool virFileExists(const char *path)
-{
- return access(path, F_OK) == 0;
-}
-
-/* Check that a file is regular and has executable bits. If false is
- * returned, errno is valid.
- *
- * Note: In the presence of ACLs, this may return true for a file that
- * would actually fail with EACCES for a given user, or false for a
- * file that the user could actually execute, but setups with ACLs
- * that weird are unusual. */
-bool
-virFileIsExecutable(const char *file)
-{
- struct stat sb;
-
- /* We would also want to check faccessat if we cared about ACLs,
- * but we don't. */
- if (stat(file, &sb) < 0)
- return false;
- if (S_ISREG(sb.st_mode) && (sb.st_mode & 0111) != 0)
- return true;
- errno = S_ISDIR(sb.st_mode) ? EISDIR : EACCES;
- return false;
-}
-
-#ifndef WIN32
-/* Check that a file is accessible under certain
- * user & gid.
- * @mode can be F_OK, or a bitwise combination of R_OK, W_OK, and X_OK.
- * see 'man access' for more details.
- * Returns 0 on success, -1 on fail with errno set.
- */
-int
-virFileAccessibleAs(const char *path, int mode,
- uid_t uid, gid_t gid)
-{
- pid_t pid = 0;
- int status, ret = 0;
- int forkRet = 0;
-
- if (uid == getuid() &&
- gid == getgid())
- return access(path, mode);
-
- forkRet = virFork(&pid);
-
- if (pid < 0) {
- return -1;
- }
-
- if (pid) { /* parent */
- if (virProcessWait(pid, &status) < 0) {
- /* virProcessWait() already
- * reported error */
- return -1;
- }
-
- if (!WIFEXITED(status)) {
- errno = EINTR;
- return -1;
- }
-
- if (status) {
- errno = WEXITSTATUS(status);
- return -1;
- }
-
- return 0;
- }
-
- /* child.
- * Return positive value here. Parent
- * will change it to negative one. */
-
- if (forkRet < 0) {
- ret = errno;
- goto childerror;
- }
-
- if (virSetUIDGID(uid, gid) < 0) {
- ret = errno;
- goto childerror;
- }
-
- if (access(path, mode) < 0)
- ret = errno;
-
-childerror:
- if ((ret & 0xFF) != ret) {
- VIR_WARN("unable to pass desired return value %d", ret);
- ret = 0xFF;
- }
-
- _exit(ret);
-}
-
-/* virFileOpenForceOwnerMode() - an internal utility function called
- * only by virFileOpenAs(). Sets the owner and mode of the file
- * opened as "fd" if it's not correct AND the flags say it should be
- * forced. */
-static int
-virFileOpenForceOwnerMode(const char *path, int fd, mode_t mode,
- uid_t uid, gid_t gid, unsigned int flags)
-{
- int ret = 0;
- struct stat st;
-
- if (!(flags & (VIR_FILE_OPEN_FORCE_OWNER | VIR_FILE_OPEN_FORCE_MODE)))
- return 0;
-
- if (fstat(fd, &st) == -1) {
- ret = -errno;
- virReportSystemError(errno, _("stat of '%s' failed"), path);
- return ret;
- }
- /* NB: uid:gid are never "-1" (default) at this point - the caller
- * has always changed -1 to the value of get[gu]id().
- */
- if ((flags & VIR_FILE_OPEN_FORCE_OWNER) &&
- ((st.st_uid != uid) || (st.st_gid != gid)) &&
- (fchown(fd, uid, gid) < 0)) {
- ret = -errno;
- virReportSystemError(errno,
- _("cannot chown '%s' to (%u, %u)"),
- path, (unsigned int) uid,
- (unsigned int) gid);
- return ret;
- }
- if ((flags & VIR_FILE_OPEN_FORCE_MODE) &&
- ((mode & (S_IRWXU|S_IRWXG|S_IRWXO)) !=
- (st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))) &&
- (fchmod(fd, mode) < 0)) {
- ret = -errno;
- virReportSystemError(errno,
- _("cannot set mode of '%s' to %04o"),
- path, mode);
- return ret;
- }
- return ret;
-}
-
-/* virFileOpenForked() - an internal utility function called only by
- * virFileOpenAs(). It forks, then the child does setuid+setgid to
- * given uid:gid and attempts to open the file, while the parent just
- * calls recvfd to get the open fd back from the child. returns the
- * fd, or -errno if there is an error. */
-static int
-virFileOpenForked(const char *path, int openflags, mode_t mode,
- uid_t uid, gid_t gid, unsigned int flags)
-{
- pid_t pid;
- int waitret, status, ret = 0;
- int fd = -1;
- int pair[2] = { -1, -1 };
- int forkRet;
-
- /* parent is running as root, but caller requested that the
- * file be opened as some other user and/or group). The
- * following dance avoids problems caused by root-squashing
- * NFS servers. */
-
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) {
- ret = -errno;
- virReportSystemError(errno,
- _("failed to create socket needed for '%s'"),
- path);
- return ret;
- }
-
- forkRet = virFork(&pid);
- if (pid < 0)
- return -errno;
-
- if (pid == 0) {
-
- /* child */
-
- VIR_FORCE_CLOSE(pair[0]); /* preserves errno */
- if (forkRet < 0) {
- /* error encountered and logged in virFork() after the fork. */
- ret = -errno;
- goto childerror;
- }
-
- /* set desired uid/gid, then attempt to create the file */
-
- if (virSetUIDGID(uid, gid) < 0) {
- ret = -errno;
- goto childerror;
- }
-
- if ((fd = open(path, openflags, mode)) < 0) {
- ret = -errno;
- virReportSystemError(errno,
- _("child process failed to create file '%s'"),
- path);
- goto childerror;
- }
-
- /* File is successfully open. Set permissions if requested. */
- ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags);
- if (ret < 0)
- goto childerror;
-
- do {
- ret = sendfd(pair[1], fd);
- } while (ret < 0 && errno == EINTR);
-
- if (ret < 0) {
- ret = -errno;
- virReportSystemError(errno, "%s",
- _("child process failed to send fd to parent"));
- goto childerror;
- }
-
- childerror:
- /* ret tracks -errno on failure, but exit value must be positive.
- * If the child exits with EACCES, then the parent tries again. */
- /* XXX This makes assumptions about errno being < 255, which is
- * not true on Hurd. */
- VIR_FORCE_CLOSE(pair[1]);
- if (ret < 0) {
- VIR_FORCE_CLOSE(fd);
- }
- ret = -ret;
- if ((ret & 0xff) != ret) {
- VIR_WARN("unable to pass desired return value %d", ret);
- ret = 0xff;
- }
- _exit(ret);
- }
-
- /* parent */
-
- VIR_FORCE_CLOSE(pair[1]);
-
- do {
- fd = recvfd(pair[0], 0);
- } while (fd < 0 && errno == EINTR);
- VIR_FORCE_CLOSE(pair[0]); /* NB: this preserves errno */
-
- if (fd < 0 && errno != EACCES) {
- ret = -errno;
- while (waitpid(pid, NULL, 0) == -1 && errno == EINTR);
- return ret;
- }
-
- /* wait for child to complete, and retrieve its exit code */
- while ((waitret = waitpid(pid, &status, 0) == -1)
- && (errno == EINTR));
- if (waitret == -1) {
- ret = -errno;
- virReportSystemError(errno,
- _("failed to wait for child creating '%s'"),
- path);
- VIR_FORCE_CLOSE(fd);
- return ret;
- }
- if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES ||
- fd == -1) {
- /* fall back to the simpler method, which works better in
- * some cases */
- VIR_FORCE_CLOSE(fd);
- if (flags & VIR_FILE_OPEN_NOFORK) {
- /* If we had already tried opening w/o fork+setuid and
- * failed, no sense trying again. Just set return the
- * original errno that we got at that time (by
- * definition, always either EACCES or EPERM - EACCES
- * is close enough).
- */
- return -EACCES;
- }
- if ((fd = open(path, openflags, mode)) < 0)
- return -errno;
- ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags);
- if (ret < 0) {
- VIR_FORCE_CLOSE(fd);
- return ret;
- }
- }
- return fd;
-}
-
-/**
- * virFileOpenAs:
- * @path: file to open or create
- * @openflags: flags to pass to open
- * @mode: mode to use on creation or when forcing permissions
- * @uid: uid that should own file on creation
- * @gid: gid that should own file
- * @flags: bit-wise or of VIR_FILE_OPEN_* flags
- *
- * Open @path, and return an fd to the open file. @openflags contains
- * the flags normally passed to open(2), while those in @flags are
- * used internally. If @flags includes VIR_FILE_OPEN_NOFORK, then try
- * opening the file while executing with the current uid:gid
- * (i.e. don't fork+setuid+setgid before the call to open()). If
- * @flags includes VIR_FILE_OPEN_FORK, then try opening the file while
- * the effective user id is @uid (by forking a child process); this
- * allows one to bypass root-squashing NFS issues; NOFORK is always
- * tried before FORK (the absence of both flags is treated identically
- * to (VIR_FILE_OPEN_NOFORK | VIR_FILE_OPEN_FORK)). If @flags includes
- * VIR_FILE_OPEN_FORCE_OWNER, then ensure that @path is owned by
- * uid:gid before returning (even if it already existed with a
- * different owner). If @flags includes VIR_FILE_OPEN_FORCE_MODE,
- * ensure it has those permissions before returning (again, even if
- * the file already existed with different permissions).
- *
- * The return value (if non-negative) is the file descriptor, left
- * open. Returns -errno on failure.
- */
-int
-virFileOpenAs(const char *path, int openflags, mode_t mode,
- uid_t uid, gid_t gid, unsigned int flags)
-{
- int ret = 0, fd = -1;
-
- /* allow using -1 to mean "current value" */
- if (uid == (uid_t) -1)
- uid = getuid();
- if (gid == (gid_t) -1)
- gid = getgid();
-
- /* treat absence of both flags as presence of both for simpler
- * calling. */
- if (!(flags & (VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK)))
- flags |= VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK;
-
- if ((flags & VIR_FILE_OPEN_NOFORK)
- || (getuid() != 0)
- || ((uid == 0) && (gid == 0))) {
-
- if ((fd = open(path, openflags, mode)) < 0) {
- ret = -errno;
- if (!(flags & VIR_FILE_OPEN_FORK))
- goto error;
- } else {
- ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags);
- if (ret < 0)
- goto error;
- }
- }
-
- /* If we either 1) didn't try opening as current user at all, or
- * 2) failed, and errno/virStorageFileIsSharedFS indicate we might
- * be successful if we try as a different uid, then try doing
- * fork+setuid+setgid before opening.
- */
- if ((fd < 0) && (flags & VIR_FILE_OPEN_FORK)) {
-
- if (ret < 0) {
- /* An open(2) that failed due to insufficient permissions
- * could return one or the other of these depending on OS
- * version and circumstances. Any other errno indicates a
- * problem that couldn't be remedied by fork+setuid
- * anyway. */
- if (ret != -EACCES && ret != -EPERM)
- goto error;
-
- /* On Linux we can also verify the FS-type of the
- * directory. (this is a NOP on other platforms). */
- if (virStorageFileIsSharedFS(path) <= 0)
- goto error;
- }
-
- /* passed all prerequisites - retry the open w/fork+setuid */
- if ((fd = virFileOpenForked(path, openflags, mode, uid, gid, flags)) < 0) {
- ret = fd;
- goto error;
- }
- }
-
- /* File is successfully opened */
- return fd;
-
-error:
- if (fd >= 0) {
- /* some other failure after the open succeeded */
- VIR_FORCE_CLOSE(fd);
- }
- /* whoever failed the open last has already set ret = -errno */
- return ret;
-}
-
-/* return -errno on failure, or 0 on success */
-static int virDirCreateNoFork(const char *path, mode_t mode, uid_t uid, gid_t gid,
- unsigned int flags) {
- int ret = 0;
- struct stat st;
-
- if ((mkdir(path, mode) < 0)
- && !((errno == EEXIST) && (flags & VIR_DIR_CREATE_ALLOW_EXIST))) {
- ret = -errno;
- virReportSystemError(errno, _("failed to create directory '%s'"),
- path);
- goto error;
- }
-
- if (stat(path, &st) == -1) {
- ret = -errno;
- virReportSystemError(errno, _("stat of '%s' failed"), path);
- goto error;
- }
- if (((st.st_uid != uid) || (st.st_gid != gid))
- && (chown(path, uid, gid) < 0)) {
- ret = -errno;
- virReportSystemError(errno, _("cannot chown '%s' to (%u, %u)"),
- path, (unsigned int) uid, (unsigned int) gid);
- goto error;
- }
- if ((flags & VIR_DIR_CREATE_FORCE_PERMS)
- && (chmod(path, mode) < 0)) {
- ret = -errno;
- virReportSystemError(errno,
- _("cannot set mode of '%s' to %04o"),
- path, mode);
- goto error;
- }
-error:
- return ret;
-}
-
-/* return -errno on failure, or 0 on success */
-int virDirCreate(const char *path, mode_t mode,
- uid_t uid, gid_t gid, unsigned int flags) {
- struct stat st;
- pid_t pid;
- int waitret;
- int status, ret = 0;
-
- /* allow using -1 to mean "current value" */
- if (uid == (uid_t) -1)
- uid = getuid();
- if (gid == (gid_t) -1)
- gid = getgid();
-
- if ((!(flags & VIR_DIR_CREATE_AS_UID))
- || (getuid() != 0)
- || ((uid == 0) && (gid == 0))
- || ((flags & VIR_DIR_CREATE_ALLOW_EXIST) && (stat(path, &st) >= 0))) {
- return virDirCreateNoFork(path, mode, uid, gid, flags);
- }
-
- int forkRet = virFork(&pid);
-
- if (pid < 0) {
- ret = -errno;
- return ret;
- }
-
- if (pid) { /* parent */
- /* wait for child to complete, and retrieve its exit code */
- while ((waitret = waitpid(pid, &status, 0) == -1) && (errno == EINTR));
- if (waitret == -1) {
- ret = -errno;
- virReportSystemError(errno,
- _("failed to wait for child creating '%s'"),
- path);
- goto parenterror;
- }
- if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES) {
- /* fall back to the simpler method, which works better in
- * some cases */
- return virDirCreateNoFork(path, mode, uid, gid, flags);
- }
-parenterror:
- return ret;
- }
-
- /* child */
-
- if (forkRet < 0) {
- /* error encountered and logged in virFork() after the fork. */
- goto childerror;
- }
-
- /* set desired uid/gid, then attempt to create the directory */
-
- if (virSetUIDGID(uid, gid) < 0) {
- ret = -errno;
- goto childerror;
- }
- if (mkdir(path, mode) < 0) {
- ret = -errno;
- if (ret != -EACCES) {
- /* in case of EACCES, the parent will retry */
- virReportSystemError(errno, _("child failed to create directory '%s'"),
- path);
- }
- goto childerror;
- }
- /* check if group was set properly by creating after
- * setgid. If not, try doing it with chown */
- if (stat(path, &st) == -1) {
- ret = -errno;
- virReportSystemError(errno,
- _("stat of '%s' failed"), path);
- goto childerror;
- }
- if ((st.st_gid != gid) && (chown(path, (uid_t) -1, gid) < 0)) {
- ret = -errno;
- virReportSystemError(errno,
- _("cannot chown '%s' to group %u"),
- path, (unsigned int) gid);
- goto childerror;
- }
- if ((flags & VIR_DIR_CREATE_FORCE_PERMS)
- && chmod(path, mode) < 0) {
- virReportSystemError(errno,
- _("cannot set mode of '%s' to %04o"),
- path, mode);
- goto childerror;
- }
-childerror:
- _exit(ret);
-}
-
-#else /* WIN32 */
-
-int
-virFileAccessibleAs(const char *path,
- int mode,
- uid_t uid ATTRIBUTE_UNUSED,
- gid_t gid ATTRIBUTE_UNUSED)
-{
-
- VIR_WARN("Ignoring uid/gid due to WIN32");
-
- return access(path, mode);
-}
-
-/* return -errno on failure, or 0 on success */
-int virFileOpenAs(const char *path ATTRIBUTE_UNUSED,
- int openflags ATTRIBUTE_UNUSED,
- mode_t mode ATTRIBUTE_UNUSED,
- uid_t uid ATTRIBUTE_UNUSED,
- gid_t gid ATTRIBUTE_UNUSED,
- unsigned int flags_unused ATTRIBUTE_UNUSED)
-{
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("virFileOpenAs is not implemented for WIN32"));
-
- return -ENOSYS;
-}
-
-int virDirCreate(const char *path ATTRIBUTE_UNUSED,
- mode_t mode ATTRIBUTE_UNUSED,
- uid_t uid ATTRIBUTE_UNUSED,
- gid_t gid ATTRIBUTE_UNUSED,
- unsigned int flags_unused ATTRIBUTE_UNUSED)
-{
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("virDirCreate is not implemented for WIN32"));
-
- return -ENOSYS;
-}
-#endif /* WIN32 */
-
-static int virFileMakePathHelper(char *path, mode_t mode)
-{
- struct stat st;
- char *p;
+#include "virprocess.h"
+#include "virstring.h"
+#include "virutil.h"
- VIR_DEBUG("path=%s mode=0%o", path, mode);
+#ifndef NSIG
+# define NSIG 32
+#endif
- if (stat(path, &st) >= 0) {
- if (S_ISDIR(st.st_mode))
- return 0;
+verify(sizeof(gid_t) <= sizeof(unsigned int) &&
+ sizeof(uid_t) <= sizeof(unsigned int));
- errno = ENOTDIR;
- return -1;
- }
+#define VIR_FROM_THIS VIR_FROM_NONE
- if (errno != ENOENT)
- return -1;
+#ifndef WIN32
- if ((p = strrchr(path, '/')) == NULL) {
- errno = EINVAL;
+int virSetInherit(int fd, bool inherit) {
+ int fflags;
+ if ((fflags = fcntl(fd, F_GETFD)) < 0)
return -1;
- }
-
- if (p != path) {
- *p = '\0';
-
- if (virFileMakePathHelper(path, mode) < 0)
- return -1;
-
- *p = '/';
- }
-
- if (mkdir(path, mode) < 0 && errno != EEXIST)
+ if (inherit)
+ fflags &= ~FD_CLOEXEC;
+ else
+ fflags |= FD_CLOEXEC;
+ if ((fcntl(fd, F_SETFD, fflags)) < 0)
return -1;
-
return 0;
}
-/**
- * Creates the given directory with mode 0777 if it's not already existing.
- *
- * Returns 0 on success, or -1 if an error occurred (in which case, errno
- * is set appropriately).
- */
-int virFileMakePath(const char *path)
-{
- return virFileMakePathWithMode(path, 0777);
-}
+#else /* WIN32 */
-int
-virFileMakePathWithMode(const char *path,
- mode_t mode)
+int virSetInherit(int fd ATTRIBUTE_UNUSED, bool inherit ATTRIBUTE_UNUSED)
{
- int ret = -1;
- char *tmp;
-
- if ((tmp = strdup(path)) == NULL)
- goto cleanup;
-
- ret = virFileMakePathHelper(tmp, mode);
-
-cleanup:
- VIR_FREE(tmp);
- return ret;
+ /* FIXME: Currently creating child processes is not supported on
+ * Win32, so there is no point in failing calls that are only relevant
+ * when creating child processes. So just pretend that we changed the
+ * inheritance property of the given fd as requested. */
+ return 0;
}
-/* Build up a fully qualified path for a config file to be
- * associated with a persistent guest or network */
-char *
-virFileBuildPath(const char *dir, const char *name, const char *ext)
-{
- char *path;
-
- if (ext == NULL) {
- if (virAsprintf(&path, "%s/%s", dir, name) < 0) {
- virReportOOMError();
- return NULL;
- }
- } else {
- if (virAsprintf(&path, "%s/%s%s", dir, name, ext) < 0) {
- virReportOOMError();
- return NULL;
- }
- }
+#endif /* WIN32 */
- return path;
+int virSetBlocking(int fd, bool blocking) {
+ return set_nonblocking_flag(fd, !blocking);
}
-/* Open a non-blocking master side of a pty. If ttyName is not NULL,
- * then populate it with the name of the slave. If rawmode is set,
- * also put the master side into raw mode before returning. */
-#ifndef WIN32
-int virFileOpenTty(int *ttymaster,
- char **ttyName,
- int rawmode)
-{
- /* XXX A word of caution - on some platforms (Solaris and HP-UX),
- * additional ioctl() calls are needs after opening the slave
- * before it will cause isatty() to return true. Should we make
- * virFileOpenTty also return the opened slave fd, so the caller
- * doesn't have to worry about that mess? */
- int ret = -1;
- int slave = -1;
- char *name = NULL;
-
- /* Unfortunately, we can't use the name argument of openpty, since
- * there is no guarantee on how large the buffer has to be.
- * Likewise, we can't use the termios argument: we have to use
- * read-modify-write since there is no portable way to initialize
- * a struct termios without use of tcgetattr. */
- if (openpty(ttymaster, &slave, NULL, NULL, NULL) < 0)
- return -1;
-
- /* What a shame that openpty cannot atomically set FD_CLOEXEC, but
- * that using posix_openpt/grantpt/unlockpt/ptsname is not
- * thread-safe, and that ptsname_r is not portable. */
- if (virSetNonBlock(*ttymaster) < 0 ||
- virSetCloseExec(*ttymaster) < 0)
- goto cleanup;
-
- /* While Linux supports tcgetattr on either the master or the
- * slave, Solaris requires it to be on the slave. */
- if (rawmode) {
- struct termios ttyAttr;
- if (tcgetattr(slave, &ttyAttr) < 0)
- goto cleanup;
-
- cfmakeraw(&ttyAttr);
-
- if (tcsetattr(slave, TCSADRAIN, &ttyAttr) < 0)
- goto cleanup;
- }
-
- /* ttyname_r on the slave is required by POSIX, while ptsname_r on
- * the master is a glibc extension, and the POSIX ptsname is not
- * thread-safe. Since openpty gave us both descriptors, guess
- * which way we will determine the name? :) */
- if (ttyName) {
- /* Initial guess of 64 is generally sufficient; rely on ERANGE
- * to tell us if we need to grow. */
- size_t len = 64;
- int rc;
-
- if (VIR_ALLOC_N(name, len) < 0)
- goto cleanup;
-
- while ((rc = ttyname_r(slave, name, len)) == ERANGE) {
- if (VIR_RESIZE_N(name, len, len, len) < 0)
- goto cleanup;
- }
- if (rc != 0) {
- errno = rc;
- goto cleanup;
- }
- *ttyName = name;
- name = NULL;
- }
-
- ret = 0;
-
-cleanup:
- if (ret != 0)
- VIR_FORCE_CLOSE(*ttymaster);
- VIR_FORCE_CLOSE(slave);
- VIR_FREE(name);
-
- return ret;
-}
-#else /* WIN32 */
-int virFileOpenTty(int *ttymaster ATTRIBUTE_UNUSED,
- char **ttyName ATTRIBUTE_UNUSED,
- int rawmode ATTRIBUTE_UNUSED)
-{
- /* mingw completely lacks pseudo-terminals, and the gnulib
- * replacements are not (yet) license compatible. */
- errno = ENOSYS;
- return -1;
+int virSetNonBlock(int fd) {
+ return virSetBlocking(fd, false);
}
-#endif /* WIN32 */
-bool virFileIsAbsPath(const char *path)
+int virSetCloseExec(int fd)
{
- if (!path)
- return false;
-
- if (VIR_FILE_IS_DIR_SEPARATOR(path[0]))
- return true;
-
-#ifdef WIN32
- if (c_isalpha(path[0]) &&
- path[1] == ':' &&
- VIR_FILE_IS_DIR_SEPARATOR(path[2]))
- return true;
-#endif
-
- return false;
+ return virSetInherit(fd, false);
}
+int
+virPipeReadUntilEOF(int outfd, int errfd,
+ char **outbuf, char **errbuf) {
-const char *virFileSkipRoot(const char *path)
-{
-#ifdef WIN32
- /* Skip \\server\share or //server/share */
- if (VIR_FILE_IS_DIR_SEPARATOR(path[0]) &&
- VIR_FILE_IS_DIR_SEPARATOR(path[1]) &&
- path[2] &&
- !VIR_FILE_IS_DIR_SEPARATOR(path[2]))
- {
- const char *p = strchr(path + 2, VIR_FILE_DIR_SEPARATOR);
- const char *q = strchr(path + 2, '/');
-
- if (p == NULL || (q != NULL && q < p))
- p = q;
-
- if (p && p > path + 2 && p[1]) {
- path = p + 1;
+ struct pollfd fds[2];
+ int i;
+ int finished[2];
- while (path[0] &&
- !VIR_FILE_IS_DIR_SEPARATOR(path[0]))
- path++;
+ fds[0].fd = outfd;
+ fds[0].events = POLLIN;
+ fds[0].revents = 0;
+ finished[0] = 0;
+ fds[1].fd = errfd;
+ fds[1].events = POLLIN;
+ fds[1].revents = 0;
+ finished[1] = 0;
- /* Possibly skip a backslash after the share name */
- if (VIR_FILE_IS_DIR_SEPARATOR(path[0]))
- path++;
+ while (!(finished[0] && finished[1])) {
- return path;
+ if (poll(fds, ARRAY_CARDINALITY(fds), -1) < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ goto pollerr;
}
- }
-#endif
-
- /* Skip initial slashes */
- if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) {
- while (VIR_FILE_IS_DIR_SEPARATOR(path[0]))
- path++;
- return path;
- }
+ for (i = 0; i < ARRAY_CARDINALITY(fds); ++i) {
+ char data[1024], **buf;
+ int got, size;
-#ifdef WIN32
- /* Skip X:\ */
- if (c_isalpha(path[0]) &&
- path[1] == ':' &&
- VIR_FILE_IS_DIR_SEPARATOR(path[2]))
- return path + 3;
-#endif
+ if (!(fds[i].revents))
+ continue;
+ else if (fds[i].revents & POLLHUP)
+ finished[i] = 1;
- return path;
-}
+ if (!(fds[i].revents & POLLIN)) {
+ if (fds[i].revents & POLLHUP)
+ continue;
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Unknown poll response."));
+ goto error;
+ }
+ got = read(fds[i].fd, data, sizeof(data));
-/*
- * Creates an absolute path for a potentially relative path.
- * Return 0 if the path was not relative, or on success.
- * Return -1 on error.
- *
- * You must free the result.
- */
-int virFileAbsPath(const char *path, char **abspath)
-{
- char *buf;
+ if (got == sizeof(data))
+ finished[i] = 0;
- if (path[0] == '/') {
- if (!(*abspath = strdup(path)))
- return -1;
- } else {
- buf = getcwd(NULL, 0);
- if (buf == NULL)
- return -1;
+ if (got == 0) {
+ finished[i] = 1;
+ continue;
+ }
+ if (got < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EAGAIN)
+ break;
+ goto pollerr;
+ }
- if (virAsprintf(abspath, "%s/%s", buf, path) < 0) {
- VIR_FREE(buf);
- return -1;
+ buf = ((fds[i].fd == outfd) ? outbuf : errbuf);
+ size = (*buf ? strlen(*buf) : 0);
+ if (VIR_REALLOC_N(*buf, size+got+1) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+ memmove(*buf+size, data, got);
+ (*buf)[size+got] = '\0';
}
- VIR_FREE(buf);
- }
-
- return 0;
-}
-
-/* Remove spurious / characters from a path. The result must be freed */
-char *
-virFileSanitizePath(const char *path)
-{
- const char *cur = path;
- char *cleanpath;
- int idx = 0;
-
- cleanpath = strdup(path);
- if (!cleanpath) {
- virReportOOMError();
- return NULL;
- }
-
- /* Need to sanitize:
- * // -> //
- * /// -> /
- * /../foo -> /../foo
- * /foo///bar/ -> /foo/bar
- */
+ continue;
- /* Starting with // is valid posix, but ///foo == /foo */
- if (cur[0] == '/' && cur[1] == '/' && cur[2] != '/') {
- idx = 2;
- cur += 2;
+ pollerr:
+ virReportSystemError(errno,
+ "%s", _("poll error"));
+ goto error;
}
- /* Sanitize path in place */
- while (*cur != '\0') {
- if (*cur != '/') {
- cleanpath[idx++] = *cur++;
- continue;
- }
-
- /* Skip all extra / */
- while (*++cur == '/')
- continue;
-
- /* Don't add a trailing / */
- if (idx != 0 && *cur == '\0')
- break;
-
- cleanpath[idx++] = '/';
- }
- cleanpath[idx] = '\0';
+ return 0;
- return cleanpath;
+error:
+ VIR_FREE(*outbuf);
+ VIR_FREE(*errbuf);
+ return -1;
}
/* Convert C from hexadecimal character to integer. */
@@ -2777,50 +1440,6 @@ virSetUIDGIDWithCaps(uid_t uid, gid_t gid,
#endif
-#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
-/* search /proc/mounts for mount point of *type; return pointer to
- * malloc'ed string of the path if found, otherwise return NULL
- * with errno set to an appropriate value.
- */
-char *virFileFindMountPoint(const char *type)
-{
- FILE *f;
- struct mntent mb;
- char mntbuf[1024];
- char *ret = NULL;
-
- f = setmntent("/proc/mounts", "r");
- if (!f)
- return NULL;
-
- while (getmntent_r(f, &mb, mntbuf, sizeof(mntbuf))) {
- if (STREQ(mb.mnt_type, type)) {
- ret = strdup(mb.mnt_dir);
- goto cleanup;
- }
- }
-
- if (!ret)
- errno = ENOENT;
-
-cleanup:
- endmntent(f);
-
- return ret;
-}
-
-#else /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */
-
-char *
-virFileFindMountPoint(const char *type ATTRIBUTE_UNUSED)
-{
- errno = ENOSYS;
-
- return NULL;
-}
-
-#endif /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */
-
#if defined(UDEVADM) || defined(UDEVSETTLE)
void virFileWaitForDevices(void)
{
@@ -2847,34 +1466,6 @@ void virFileWaitForDevices(void)
void virFileWaitForDevices(void) {}
#endif
-int virBuildPathInternal(char **path, ...)
-{
- char *path_component = NULL;
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- va_list ap;
- int ret = 0;
-
- va_start(ap, path);
-
- path_component = va_arg(ap, char *);
- virBufferAdd(&buf, path_component, -1);
-
- while ((path_component = va_arg(ap, char *)) != NULL)
- {
- virBufferAddChar(&buf, '/');
- virBufferAdd(&buf, path_component, -1);
- }
-
- va_end(ap);
-
- *path = virBufferContentAndReset(&buf);
- if (*path == NULL) {
- ret = -1;
- }
-
- return ret;
-}
-
#if HAVE_LIBDEVMAPPER_H
bool
virIsDevMapperDevice(const char *dev_name)
diff --git a/src/util/virutil.h b/src/util/virutil.h
index 8a2d25c..5ec8869 100644
--- a/src/util/virutil.h
+++ b/src/util/virutil.h
@@ -38,12 +38,6 @@
# define MAX(a, b) ((a) > (b) ? (a) : (b))
# endif
-ssize_t saferead(int fd, void *buf, size_t count) ATTRIBUTE_RETURN_CHECK;
-ssize_t safewrite(int fd, const void *buf, size_t count)
- ATTRIBUTE_RETURN_CHECK;
-int safezero(int fd, off_t offset, off_t len)
- ATTRIBUTE_RETURN_CHECK;
-
int virSetBlocking(int fd, bool blocking) ATTRIBUTE_RETURN_CHECK;
int virSetNonBlock(int fd) ATTRIBUTE_RETURN_CHECK;
int virSetInherit(int fd, bool inherit) ATTRIBUTE_RETURN_CHECK;
@@ -56,104 +50,6 @@ int virSetUIDGID(uid_t uid, gid_t gid);
int virSetUIDGIDWithCaps(uid_t uid, gid_t gid, unsigned long long capBits,
bool clearExistingCaps);
-int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK;
-
-int virFileReadAll(const char *path, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK;
-
-int virFileWriteStr(const char *path, const char *str, mode_t mode)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
-
-int virFileMatchesNameSuffix(const char *file,
- const char *name,
- const char *suffix);
-
-int virFileHasSuffix(const char *str,
- const char *suffix);
-
-int virFileStripSuffix(char *str,
- const char *suffix) ATTRIBUTE_RETURN_CHECK;
-
-int virFileLinkPointsTo(const char *checkLink,
- const char *checkDest);
-
-int virFileResolveLink(const char *linkpath,
- char **resultpath) ATTRIBUTE_RETURN_CHECK;
-int virFileResolveAllLinks(const char *linkpath,
- char **resultpath) ATTRIBUTE_RETURN_CHECK;
-
-int virFileIsLink(const char *linkpath)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
-
-char *virFindFileInPath(const char *file);
-
-bool virFileIsDir (const char *file) ATTRIBUTE_NONNULL(1);
-bool virFileExists(const char *file) ATTRIBUTE_NONNULL(1);
-bool virFileIsExecutable(const char *file) ATTRIBUTE_NONNULL(1);
-
-char *virFileSanitizePath(const char *path);
-
-enum {
- VIR_FILE_OPEN_NONE = 0,
- VIR_FILE_OPEN_NOFORK = (1 << 0),
- VIR_FILE_OPEN_FORK = (1 << 1),
- VIR_FILE_OPEN_FORCE_MODE = (1 << 2),
- VIR_FILE_OPEN_FORCE_OWNER = (1 << 3),
-};
-int virFileAccessibleAs(const char *path, int mode,
- uid_t uid, gid_t gid)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
-int virFileOpenAs(const char *path, int openflags, mode_t mode,
- uid_t uid, gid_t gid,
- unsigned int flags)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
-
-enum {
- VIR_DIR_CREATE_NONE = 0,
- VIR_DIR_CREATE_AS_UID = (1 << 0),
- VIR_DIR_CREATE_FORCE_PERMS = (1 << 1),
- VIR_DIR_CREATE_ALLOW_EXIST = (1 << 2),
-};
-int virDirCreate(const char *path, mode_t mode, uid_t uid, gid_t gid,
- unsigned int flags) ATTRIBUTE_RETURN_CHECK;
-int virFileMakePath(const char *path) ATTRIBUTE_RETURN_CHECK;
-int virFileMakePathWithMode(const char *path,
- mode_t mode) ATTRIBUTE_RETURN_CHECK;
-
-char *virFileBuildPath(const char *dir,
- const char *name,
- const char *ext) ATTRIBUTE_RETURN_CHECK;
-
-
-# ifdef WIN32
-/* On Win32, the canonical directory separator is the backslash, and
- * the search path separator is the semicolon. Note that also the
- * (forward) slash works as directory separator.
- */
-# define VIR_FILE_DIR_SEPARATOR '\\'
-# define VIR_FILE_DIR_SEPARATOR_S "\\"
-# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR || (c) == '/')
-# define VIR_FILE_PATH_SEPARATOR ';'
-# define VIR_FILE_PATH_SEPARATOR_S ";"
-
-# else /* !WIN32 */
-
-# define VIR_FILE_DIR_SEPARATOR '/'
-# define VIR_FILE_DIR_SEPARATOR_S "/"
-# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR)
-# define VIR_FILE_PATH_SEPARATOR ':'
-# define VIR_FILE_PATH_SEPARATOR_S ":"
-
-# endif /* !WIN32 */
-
-bool virFileIsAbsPath(const char *path);
-int virFileAbsPath(const char *path,
- char **abspath) ATTRIBUTE_RETURN_CHECK;
-const char *virFileSkipRoot(const char *path);
-
-int virFileOpenTty(int *ttymaster,
- char **ttyName,
- int rawmode);
-
int virScaleInteger(unsigned long long *value, const char *suffix,
unsigned long long scale, unsigned long long limit)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
@@ -224,13 +120,6 @@ int virGetUserID(const char *name,
int virGetGroupID(const char *name,
gid_t *gid) ATTRIBUTE_RETURN_CHECK;
-char *virFileFindMountPoint(const char *type);
-
-void virFileWaitForDevices(void);
-
-# define virBuildPath(path, ...) virBuildPathInternal(path, __VA_ARGS__, NULL)
-int virBuildPathInternal(char **path, ...) ATTRIBUTE_SENTINEL;
-
bool virIsDevMapperDevice(const char *dev_name) ATTRIBUTE_NONNULL(1);
bool virValidateWWN(const char *wwn);
diff --git a/src/vbox/vbox_XPCOMCGlue.c b/src/vbox/vbox_XPCOMCGlue.c
index e0b606f..121382c 100644
--- a/src/vbox/vbox_XPCOMCGlue.c
+++ b/src/vbox/vbox_XPCOMCGlue.c
@@ -41,6 +41,7 @@
#include "virutil.h"
#include "virlog.h"
#include "virerror.h"
+#include "virfile.h"
#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_VBOX
diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c
index 2df8a83..2e96a30 100644
--- a/src/vmx/vmx.c
+++ b/src/vmx/vmx.c
@@ -26,6 +26,7 @@
#include "internal.h"
#include "virerror.h"
+#include "virfile.h"
#include "virconf.h"
#include "viralloc.h"
#include "virlog.h"
diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
index 921c66a..812072a 100644
--- a/src/xen/xm_internal.c
+++ b/src/xen/xm_internal.c
@@ -36,6 +36,7 @@
#include <xen/dom0_ops.h>
#include "virerror.h"
+#include "virfile.h"
#include "datatypes.h"
#include "xm_internal.h"
#include "xen_driver.h"
diff --git a/tests/eventtest.c b/tests/eventtest.c
index 16a693c..700ea08 100644
--- a/tests/eventtest.c
+++ b/tests/eventtest.c
@@ -1,7 +1,7 @@
/*
* eventtest.c: Test the libvirtd event loop impl
*
- * Copyright (C) 2009, 2011 Red Hat, Inc.
+ * Copyright (C) 2009, 2011-2013 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
@@ -28,6 +28,7 @@
#include "testutils.h"
#include "internal.h"
+#include "virfile.h"
#include "virthread.h"
#include "virlog.h"
#include "virutil.h"
diff --git a/tests/libvirtdconftest.c b/tests/libvirtdconftest.c
index df8d3d8..e1dd82d 100644
--- a/tests/libvirtdconftest.c
+++ b/tests/libvirtdconftest.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Red Hat, Inc.
+ * Copyright (C) 2012-2013 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
@@ -27,6 +27,7 @@
#include "virutil.h"
#include "c-ctype.h"
#include "virerror.h"
+#include "virfile.h"
#include "virlog.h"
#include "virconf.h"
#include "virstring.h"
diff --git a/tests/securityselinuxtest.c b/tests/securityselinuxtest.c
index dd4cd11..3fbc87b 100644
--- a/tests/securityselinuxtest.c
+++ b/tests/securityselinuxtest.c
@@ -33,6 +33,7 @@
#include "viralloc.h"
#include "virlog.h"
#include "virerror.h"
+#include "virfile.h"
#include "security/security_manager.h"
#include "virstring.h"
diff --git a/tests/virlockspacetest.c b/tests/virlockspacetest.c
index 7678396..b659f61 100644
--- a/tests/virlockspacetest.c
+++ b/tests/virlockspacetest.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011, 2013 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
@@ -28,6 +28,7 @@
#include "virutil.h"
#include "virerror.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virlog.h"
#include "virlockspace.h"
diff --git a/tests/virportallocatortest.c b/tests/virportallocatortest.c
index a528506..1a0cdfa 100644
--- a/tests/virportallocatortest.c
+++ b/tests/virportallocatortest.c
@@ -53,6 +53,7 @@ int bind(int sockfd ATTRIBUTE_UNUSED,
# include "virutil.h"
# include "virerror.h"
# include "viralloc.h"
+# include "virfile.h"
# include "virlog.h"
# include "virportallocator.h"
# include "virstring.h"
diff --git a/tests/virstoragetest.c b/tests/virstoragetest.c
index 0016052..fef4b37 100644
--- a/tests/virstoragetest.c
+++ b/tests/virstoragetest.c
@@ -25,6 +25,7 @@
#include "testutils.h"
#include "vircommand.h"
#include "virerror.h"
+#include "virfile.h"
#include "virlog.h"
#include "virstoragefile.h"
#include "virstring.h"
diff --git a/tools/virsh-interface.c b/tools/virsh-interface.c
index 706074f..f75c572 100644
--- a/tools/virsh-interface.c
+++ b/tools/virsh-interface.c
@@ -1,7 +1,7 @@
/*
* virsh-interface.c: Commands to manage host interface
*
- * Copyright (C) 2005, 2007-2012 Red Hat, Inc.
+ * Copyright (C) 2005, 2007-2013 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
@@ -34,6 +34,7 @@
#include "internal.h"
#include "virbuffer.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virutil.h"
#include "virxml.h"
#include "virstring.h"
diff --git a/tools/virsh-network.c b/tools/virsh-network.c
index 81267bc..a80cbb5 100644
--- a/tools/virsh-network.c
+++ b/tools/virsh-network.c
@@ -1,7 +1,7 @@
/*
* virsh-network.c: Commands to manage network
*
- * Copyright (C) 2005, 2007-2012 Red Hat, Inc.
+ * Copyright (C) 2005, 2007-2013 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
@@ -34,6 +34,7 @@
#include "internal.h"
#include "virbuffer.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virxml.h"
#include "conf/network_conf.h"
diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c
index 8fa67fc..592fa44 100644
--- a/tools/virsh-nodedev.c
+++ b/tools/virsh-nodedev.c
@@ -34,6 +34,7 @@
#include "internal.h"
#include "virbuffer.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virxml.h"
#include "conf/node_device_conf.h"
diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c
index 3b1e1e4..5a360c2 100644
--- a/tools/virsh-nwfilter.c
+++ b/tools/virsh-nwfilter.c
@@ -1,7 +1,7 @@
/*
* virsh-nwfilter.c: Commands to manage network filters
*
- * Copyright (C) 2005, 2007-2012 Red Hat, Inc.
+ * Copyright (C) 2005, 2007-2013 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
@@ -34,6 +34,7 @@
#include "internal.h"
#include "virbuffer.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virutil.h"
#include "virxml.h"
diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c
index f154366..c5944ae 100644
--- a/tools/virsh-pool.c
+++ b/tools/virsh-pool.c
@@ -1,7 +1,7 @@
/*
* virsh-pool.c: Commands to manage storage pool
*
- * Copyright (C) 2005, 2007-2012 Red Hat, Inc.
+ * Copyright (C) 2005, 2007-2013 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
@@ -34,6 +34,7 @@
#include "internal.h"
#include "virbuffer.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virxml.h"
#include "conf/storage_conf.h"
#include "virstring.h"
diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c
index 7201522..044629d 100644
--- a/tools/virsh-secret.c
+++ b/tools/virsh-secret.c
@@ -1,7 +1,7 @@
/*
* virsh-secret.c: Commands to manage secret
*
- * Copyright (C) 2005, 2007-2012 Red Hat, Inc.
+ * Copyright (C) 2005, 2007-2013 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
@@ -35,6 +35,7 @@
#include "base64.h"
#include "virbuffer.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virutil.h"
#include "virxml.h"
diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c
index 4f5fa15..7e75772 100644
--- a/tools/virsh-snapshot.c
+++ b/tools/virsh-snapshot.c
@@ -1,7 +1,7 @@
/*
* virsh-snapshot.c: Commands to manage domain snapshot
*
- * Copyright (C) 2005, 2007-2012 Red Hat, Inc.
+ * Copyright (C) 2005, 2007-2013 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
@@ -36,6 +36,7 @@
#include "internal.h"
#include "virbuffer.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virsh-domain.h"
#include "virxml.h"
#include "conf/snapshot_conf.h"
--
1.8.1.4
11 years, 6 months
[libvirt] [PATCH] Replace 'goto clean' with 'goto cleanup' in apparmor code
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
Some of the apparmor code files did not follow the normal
goto label naming pratices
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/security/security_apparmor.c | 34 ++++++++++-----------
src/security/virt-aa-helper.c | 66 ++++++++++++++++++++--------------------
2 files changed, 50 insertions(+), 50 deletions(-)
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index 5fb5db3..8123532 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -94,7 +94,7 @@ profile_status(const char *str, const int check_enforcing)
virReportSystemError(errno,
_("Failed to read AppArmor profiles list "
"\'%s\'"), APPARMOR_PROFILES_PATH);
- goto clean;
+ goto cleanup;
}
if (strstr(content, tmp) != NULL)
@@ -105,7 +105,7 @@ profile_status(const char *str, const int check_enforcing)
}
VIR_FREE(content);
- clean:
+ cleanup:
VIR_FREE(tmp);
VIR_FREE(etmp);
@@ -294,12 +294,12 @@ reload_profile(virSecurityManagerPtr mgr,
_("cannot update AppArmor profile "
"\'%s\'"),
secdef->imagelabel);
- goto clean;
+ goto cleanup;
}
}
rc = 0;
- clean:
+ cleanup:
VIR_FREE(profile_name);
return rc;
@@ -372,11 +372,11 @@ AppArmorSecurityManagerProbe(const char *virtDriver)
if (!virFileExists(template)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("template \'%s\' does not exist"), template);
- goto clean;
+ goto cleanup;
}
rc = SECURITY_DRIVER_ENABLE;
- clean:
+ cleanup:
VIR_FREE(template);
return rc;
@@ -449,7 +449,7 @@ AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
secdef->label = strndup(profile_name, strlen(profile_name));
if (!secdef->label) {
virReportOOMError();
- goto clean;
+ goto cleanup;
}
/* set imagelabel the same as label (but we won't use it) */
@@ -474,14 +474,14 @@ AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
}
rc = 0;
- goto clean;
+ goto cleanup;
err:
VIR_FREE(secdef->label);
VIR_FREE(secdef->imagelabel);
VIR_FREE(secdef->model);
- clean:
+ cleanup:
VIR_FREE(profile_name);
return rc;
@@ -526,17 +526,17 @@ AppArmorGetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
VIR_SECURITY_LABEL_BUFLEN) == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("error copying profile name"));
- goto clean;
+ goto cleanup;
}
if ((sec->enforcing = profile_status(profile_name, 1)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("error calling profile_status()"));
- goto clean;
+ goto cleanup;
}
rc = 0;
- clean:
+ cleanup:
VIR_FREE(profile_name);
return rc;
@@ -609,17 +609,17 @@ AppArmorSetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
"hypervisor driver is \'%s\'."),
secdef->model, SECURITY_APPARMOR_NAME);
if (use_apparmor() > 0)
- goto clean;
+ goto cleanup;
}
if (aa_change_profile(profile_name) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("error calling aa_change_profile()"));
- goto clean;
+ goto cleanup;
}
rc = 0;
- clean:
+ cleanup:
VIR_FREE(profile_name);
return rc;
@@ -736,13 +736,13 @@ AppArmorSetSecurityImageLabel(virSecurityManagerPtr mgr,
_("cannot update AppArmor profile "
"\'%s\'"),
secdef->imagelabel);
- goto clean;
+ goto cleanup;
}
}
}
rc = 0;
- clean:
+ cleanup:
VIR_FREE(profile_name);
return rc;
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index 0831d2f..5d48850 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -277,46 +277,46 @@ update_include_file(const char *include_file, const char *included_files,
if (append && virFileExists(include_file)) {
if (virAsprintf(&pcontent, "%s%s", existing, included_files) == -1) {
vah_error(NULL, 0, _("could not allocate memory for profile"));
- goto clean;
+ goto cleanup;
}
} else {
if (virAsprintf(&pcontent, "%s%s", warning, included_files) == -1) {
vah_error(NULL, 0, _("could not allocate memory for profile"));
- goto clean;
+ goto cleanup;
}
}
plen = strlen(pcontent);
if (plen > MAX_FILE_LEN) {
vah_error(NULL, 0, _("invalid length for new profile"));
- goto clean;
+ goto cleanup;
}
/* only update the disk profile if it is different */
if (flen > 0 && flen == plen && STREQLEN(existing, pcontent, plen)) {
rc = 0;
- goto clean;
+ goto cleanup;
}
/* write the file */
if ((fd = open(include_file, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1) {
vah_error(NULL, 0, _("failed to create include file"));
- goto clean;
+ goto cleanup;
}
if (safewrite(fd, pcontent, plen) < 0) { /* don't write the '\0' */
VIR_FORCE_CLOSE(fd);
vah_error(NULL, 0, _("failed to write to profile"));
- goto clean;
+ goto cleanup;
}
if (VIR_CLOSE(fd) != 0) {
vah_error(NULL, 0, _("failed to close or write to profile"));
- goto clean;
+ goto cleanup;
}
rc = 0;
- clean:
+ cleanup:
VIR_FREE(pcontent);
VIR_FREE(existing);
@@ -785,7 +785,7 @@ vah_add_file(virBufferPtr buf, const char *path, const char *perms)
vah_error(NULL, 0, path);
vah_error(NULL, 0, _("skipped restricted file"));
}
- goto clean;
+ goto cleanup;
}
virBufferAsprintf(buf, " \"%s\" %s,\n", tmp, perms);
@@ -794,7 +794,7 @@ vah_add_file(virBufferPtr buf, const char *path, const char *perms)
virBufferAsprintf(buf, " deny \"%s\" w,\n", tmp);
}
- clean:
+ cleanup:
VIR_FREE(tmp);
return rc;
@@ -814,7 +814,7 @@ vah_add_file_chardev(virBufferPtr buf,
/* add the pipe input */
if (virAsprintf(&pipe_in, "%s.in", path) == -1) {
vah_error(NULL, 0, _("could not allocate memory"));
- goto clean;
+ goto cleanup;
}
if (vah_add_file(buf, pipe_in, perms) != 0)
@@ -837,11 +837,11 @@ vah_add_file_chardev(virBufferPtr buf,
} else {
/* add the file */
if (vah_add_file(buf, path, perms) != 0)
- goto clean;
+ goto cleanup;
rc = 0;
}
- clean:
+ cleanup:
return rc;
}
@@ -903,7 +903,7 @@ get_files(vahControl * ctl)
if (STRNEQ(uuid, ctl->uuid)) {
vah_error(ctl, 0, _("given uuid does not match XML uuid"));
- goto clean;
+ goto cleanup;
}
for (i = 0; i < ctl->def->ndisks; i++) {
@@ -925,7 +925,7 @@ get_files(vahControl * ctl)
* careful than just ignoring them.
*/
if (virDomainDiskDefForeachPath(disk, true, add_file_path, &buf) < 0)
- goto clean;
+ goto cleanup;
}
for (i = 0; i < ctl->def->nserials; i++)
@@ -939,7 +939,7 @@ get_files(vahControl * ctl)
ctl->def->serials[i]->source.data.file.path,
"rw",
ctl->def->serials[i]->source.type) != 0)
- goto clean;
+ goto cleanup;
for (i = 0; i < ctl->def->nconsoles; i++)
if (ctl->def->consoles[i] &&
@@ -950,7 +950,7 @@ get_files(vahControl * ctl)
ctl->def->consoles[i]->source.data.file.path)
if (vah_add_file(&buf,
ctl->def->consoles[i]->source.data.file.path, "rw") != 0)
- goto clean;
+ goto cleanup;
for (i = 0 ; i < ctl->def->nparallels; i++)
if (ctl->def->parallels[i] &&
@@ -963,7 +963,7 @@ get_files(vahControl * ctl)
ctl->def->parallels[i]->source.data.file.path,
"rw",
ctl->def->parallels[i]->source.type) != 0)
- goto clean;
+ goto cleanup;
for (i = 0 ; i < ctl->def->nchannels; i++)
if (ctl->def->channels[i] &&
@@ -976,36 +976,36 @@ get_files(vahControl * ctl)
ctl->def->channels[i]->source.data.file.path,
"rw",
ctl->def->channels[i]->source.type) != 0)
- goto clean;
+ goto cleanup;
if (ctl->def->os.kernel)
if (vah_add_file(&buf, ctl->def->os.kernel, "r") != 0)
- goto clean;
+ goto cleanup;
if (ctl->def->os.initrd)
if (vah_add_file(&buf, ctl->def->os.initrd, "r") != 0)
- goto clean;
+ goto cleanup;
if (ctl->def->os.dtb)
if (vah_add_file(&buf, ctl->def->os.dtb, "r") != 0)
- goto clean;
+ goto cleanup;
if (ctl->def->os.loader && ctl->def->os.loader)
if (vah_add_file(&buf, ctl->def->os.loader, "r") != 0)
- goto clean;
+ goto cleanup;
for (i = 0; i < ctl->def->ngraphics; i++) {
if (ctl->def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
ctl->def->graphics[i]->data.vnc.socket &&
vah_add_file(&buf, ctl->def->graphics[i]->data.vnc.socket, "rw"))
- goto clean;
+ goto cleanup;
}
if (ctl->def->ngraphics == 1 &&
ctl->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL)
if (vah_add_file(&buf, ctl->def->graphics[0]->data.sdl.xauth,
"r") != 0)
- goto clean;
+ goto cleanup;
for (i = 0; i < ctl->def->nhostdevs; i++)
if (ctl->def->hostdevs[i]) {
@@ -1023,7 +1023,7 @@ get_files(vahControl * ctl)
rc = virUSBDeviceFileIterate(usb, file_iterate_hostdev_cb, &buf);
virUSBDeviceFree(usb);
if (rc != 0)
- goto clean;
+ goto cleanup;
break;
}
@@ -1051,18 +1051,18 @@ get_files(vahControl * ctl)
if (ctl->newfile)
if (vah_add_file(&buf, ctl->newfile, "rw") != 0)
- goto clean;
+ goto cleanup;
if (virBufferError(&buf)) {
virBufferFreeAndReset(&buf);
vah_error(NULL, 0, _("failed to allocate file buffer"));
- goto clean;
+ goto cleanup;
}
rc = 0;
ctl->files = virBufferContentAndReset(&buf);
- clean:
+ cleanup:
VIR_FREE(uuid);
return rc;
}
@@ -1232,7 +1232,7 @@ main(int argc, char **argv)
if (ctl->append && ctl->newfile) {
if (vah_add_file(&buf, ctl->newfile, "rw") != 0)
- goto clean;
+ goto cleanup;
} else {
virBufferAsprintf(&buf, " \"%s/log/libvirt/**/%s.log\" w,\n",
LOCALSTATEDIR, ctl->def->name);
@@ -1265,7 +1265,7 @@ main(int argc, char **argv)
} else if ((rc = update_include_file(include_file,
included_files,
ctl->append)) != 0)
- goto clean;
+ goto cleanup;
/* create the profile from TEMPLATE */
@@ -1274,7 +1274,7 @@ main(int argc, char **argv)
if (virAsprintf(&tmp, " #include <libvirt/%s.files>\n",
ctl->uuid) == -1) {
vah_error(ctl, 0, _("could not allocate memory"));
- goto clean;
+ goto cleanup;
}
if (ctl->dryrun) {
@@ -1302,7 +1302,7 @@ main(int argc, char **argv)
unlink(profile);
}
}
- clean:
+ cleanup:
VIR_FREE(included_files);
}
--
1.8.1.4
11 years, 6 months
[libvirt] [PATCH] tests: use portable shell code
by Eric Blake
'make check' fails since commit 470d5c46 on any system with dash
as /bin/sh, because '<<<' is a bash extension. For example:
nwfilterschematest: 23: /home/eblake/libvirt/tests/schematestutils.sh: Syntax error: redirection unexpected
Also, there is no need to spawn a grep process when shell globbing
can do the same.
* tests/schematestutils.sh: Replace bashism and subprocess with a
faster and portable construct.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
Pushing under the build-breaker rule.
tests/schematestutils.sh | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/tests/schematestutils.sh b/tests/schematestutils.sh
index e739b99..e594f04 100644
--- a/tests/schematestutils.sh
+++ b/tests/schematestutils.sh
@@ -20,18 +20,12 @@ do
result=`$cmd 2>&1`
ret=$?
- grep -- '-invalid.xml$' <<< "$xml" 2>&1 >/dev/null
- invalid=$?
-
- # per xmllint man page, the return codes for validation error
- # are 3 and 4
- if test $invalid -eq 0; then
- if test $ret -eq 4 || test $ret -eq 3; then
- ret=0
- elif test $ret -eq 0; then
- ret=3
- fi
- fi
+ # Alter ret if error was expected.
+ case $xml:$ret in
+ *-invalid.xml:[34]) ret=0 ;;
+ *-invalid.xml:0) ret=3 ;;
+ esac
+
test_result $n $(basename $(dirname $xml))"/"$(basename $xml) $ret
if test "$verbose" = "1" && test $ret != 0 ; then
printf '%s\n' "$cmd" "$result"
--
1.8.1.4
11 years, 6 months
[libvirt] an old bug reappear-TimeoutError
by yue
hi,
i encounter an error of libvirt, which is reported in 2011. i intended to update the ticket(spice password) of vm.
https://bugzilla.redhat.com/show_bug.cgi?id=676205
---------log------------------
Thread-162::ERROR::2013-05-08 13:50:46,000::BindingXMLRPC::909::vdsm::(wrapper) libvirt error
Traceback (most recent call last):
File "/usr/share/vdsm/BindingXMLRPC.py", line 904, in wrapper
res = f(*args, **kwargs)
File "/usr/share/vdsm/BindingXMLRPC.py", line 213, in vmSetTicket
return vm.setTicket(password, ttl, existingConnAction, params)
File "/usr/share/vdsm/API.py", line 550, in setTicket
return v.setTicket(password, ttl, existingConnAction, params)
File "/usr/share/vdsm/libvirtvm.py", line 2245, in setTicket
self._dom.updateDeviceFlags(graphics.toxml(), 0)
File "/usr/share/vdsm/libvirtvm.py", line 524, in f
raise toe
TimeoutError: Timed out during operation: cannot acquire state change lock
11 years, 6 months
[libvirt] [PATCH] Replace 'goto err' with 'goto cleanup' in udev interface driver
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
The udev interface driver did not follow standard naming
convention for goto labels.
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/interface/interface_backend_udev.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c
index 1c47e5c..f9a179f 100644
--- a/src/interface/interface_backend_udev.c
+++ b/src/interface/interface_backend_udev.c
@@ -112,21 +112,21 @@ udevInterfaceOpen(virConnectPtr conn,
if (VIR_ALLOC(driverState) < 0) {
virReportOOMError();
- goto err;
+ goto cleanup;
}
driverState->udev = udev_new();
if (!driverState->udev) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("failed to create udev context"));
- goto err;
+ goto cleanup;
}
conn->interfacePrivateData = driverState;
return VIR_DRV_OPEN_SUCCESS;
-err:
+cleanup:
VIR_FREE(driverState);
return VIR_DRV_OPEN_ERROR;
@@ -166,7 +166,7 @@ udevNumOfInterfacesByStatus(virConnectPtr conn, virUdevStatus status)
_("failed to get number of %s interfaces on host"),
virUdevStatusString(status));
count = -1;
- goto err;
+ goto cleanup;
}
/* Do the scan to load up the enumeration */
@@ -180,7 +180,7 @@ udevNumOfInterfacesByStatus(virConnectPtr conn, virUdevStatus status)
count++;
}
-err:
+cleanup:
if (enumerate)
udev_enumerate_unref(enumerate);
udev_unref(udev);
@@ -207,7 +207,7 @@ udevListInterfacesByStatus(virConnectPtr conn,
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to get list of %s interfaces on host"),
virUdevStatusString(status));
- goto err;
+ goto error;
}
/* Do the scan to load up the enumeration */
@@ -229,7 +229,7 @@ udevListInterfacesByStatus(virConnectPtr conn,
dev = udev_device_new_from_syspath(udev, path);
if (VIR_STRDUP(names[count], udev_device_get_sysname(dev)) < 0) {
udev_device_unref(dev);
- goto err;
+ goto error;
}
udev_device_unref(dev);
@@ -241,7 +241,7 @@ udevListInterfacesByStatus(virConnectPtr conn,
return count;
-err:
+error:
if (enumerate)
udev_enumerate_unref(enumerate);
udev_unref(udev);
@@ -422,14 +422,14 @@ udevInterfaceLookupByName(virConnectPtr conn, const char *name)
virReportError(VIR_ERR_NO_INTERFACE,
_("couldn't find interface named '%s'"),
name);
- goto err;
+ goto cleanup;
}
macaddr = udev_device_get_sysattr_value(dev, "address");
ret = virGetInterface(conn, name, macaddr);
udev_device_unref(dev);
-err:
+cleanup:
udev_unref(udev);
return ret;
@@ -452,7 +452,7 @@ udevInterfaceLookupByMACString(virConnectPtr conn, const char *macstr)
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to lookup interface with MAC address '%s'"),
macstr);
- goto err;
+ goto cleanup;
}
/* Match on MAC */
@@ -469,7 +469,7 @@ udevInterfaceLookupByMACString(virConnectPtr conn, const char *macstr)
virReportError(VIR_ERR_NO_INTERFACE,
_("couldn't find interface with MAC address '%s'"),
macstr);
- goto err;
+ goto cleanup;
}
/* Check that we didn't get multiple items back */
@@ -477,7 +477,7 @@ udevInterfaceLookupByMACString(virConnectPtr conn, const char *macstr)
virReportError(VIR_ERR_MULTIPLE_INTERFACES,
_("the MAC address '%s' matches multiple interfaces"),
macstr);
- goto err;
+ goto cleanup;
}
dev = udev_device_new_from_syspath(udev, udev_list_entry_get_name(dev_entry));
@@ -485,7 +485,7 @@ udevInterfaceLookupByMACString(virConnectPtr conn, const char *macstr)
ret = virGetInterface(conn, name, macstr);
udev_device_unref(dev);
-err:
+cleanup:
if (enumerate)
udev_enumerate_unref(enumerate);
udev_unref(udev);
@@ -1043,13 +1043,13 @@ udevInterfaceGetXMLDesc(virInterfacePtr ifinfo,
ifacedef = udevGetIfaceDef(udev, ifinfo->name);
if (!ifacedef)
- goto err;
+ goto cleanup;
xmlstr = virInterfaceDefFormat(ifacedef);
virInterfaceDefFree(ifacedef);
-err:
+cleanup:
/* decrement our udev ptr */
udev_unref(udev);
--
1.8.1.4
11 years, 6 months
[libvirt] [PATCH] build: fix build with old polkit0
by Jim Fehlig
Commit 979e9c56 missed one case of providing the timestamp
parameter to virNetServerClientGetUNIXIdentity() when WITH_POLKIT0
is defined.
---
Pushed under the build breaker rule.
daemon/remote.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index 3b6446d..1d21478 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -2899,6 +2899,7 @@ remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED,
struct daemonClientPrivate *priv =
virNetServerClientGetPrivateData(client);
DBusConnection *sysbus;
+ unsigned long long timestamp;
virMutexLock(&priv->lock);
@@ -2913,7 +2914,7 @@ remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED,
}
if (virNetServerClientGetUNIXIdentity(client, &callerUid, &callerGid,
- &callerPid) < 0) {
+ &callerPid, ×tamp) < 0) {
VIR_ERROR(_("cannot get peer socket identity"));
goto authfail;
}
--
1.8.0.1
11 years, 6 months