mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-25 22:15:20 +00:00
util: fix virFileOpenAs return value and resulting error logs
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 jump down to the error return (which returns ret instead of fd) in the previously mentioned 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 caller 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.
This commit is contained in:
parent
7ca784c4a5
commit
a2c1bedbd8
@ -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-2013 SUSE LINUX Products GmbH, Nuernberg, Germany.
|
||||||
* Copyright (C) 2011 Univention GmbH.
|
* Copyright (C) 2011 Univention GmbH.
|
||||||
*
|
*
|
||||||
@ -550,8 +550,8 @@ libxlSaveImageOpen(libxlDriverPrivatePtr driver, const char *from,
|
|||||||
char *xml = NULL;
|
char *xml = NULL;
|
||||||
|
|
||||||
if ((fd = virFileOpenAs(from, O_RDONLY, 0, -1, -1, 0)) < 0) {
|
if ((fd = virFileOpenAs(from, O_RDONLY, 0, -1, -1, 0)) < 0) {
|
||||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
virReportSystemError(-fd,
|
||||||
"%s", _("cannot read domain image"));
|
_("Failed to open domain image file '%s'"), from);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2569,10 +2569,9 @@ qemuOpenFile(virQEMUDriverPtr driver, const char *path, int oflags,
|
|||||||
|
|
||||||
/* First try creating the file as root */
|
/* First try creating the file as root */
|
||||||
if (!is_reg) {
|
if (!is_reg) {
|
||||||
fd = open(path, oflags & ~O_CREAT);
|
if ((fd = open(path, oflags & ~O_CREAT)) < 0) {
|
||||||
if (fd < 0) {
|
fd = -errno;
|
||||||
virReportSystemError(errno, _("unable to open %s"), path);
|
goto error;
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR, uid, gid,
|
if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR, uid, gid,
|
||||||
@ -2583,13 +2582,8 @@ qemuOpenFile(virQEMUDriverPtr driver, const char *path, int oflags,
|
|||||||
qemu user (cfg->user) is non-root, just set a flag to
|
qemu user (cfg->user) is non-root, just set a flag to
|
||||||
bypass security driver shenanigans, and retry the operation
|
bypass security driver shenanigans, and retry the operation
|
||||||
after doing setuid to qemu user */
|
after doing setuid to qemu user */
|
||||||
if ((fd != -EACCES && fd != -EPERM) ||
|
if ((fd != -EACCES && fd != -EPERM) || cfg->user == getuid())
|
||||||
cfg->user == getuid()) {
|
goto error;
|
||||||
virReportSystemError(-fd,
|
|
||||||
_("Failed to create file '%s'"),
|
|
||||||
path);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* On Linux we can also verify the FS-type of the directory. */
|
/* On Linux we can also verify the FS-type of the directory. */
|
||||||
switch (path_shared) {
|
switch (path_shared) {
|
||||||
@ -2600,8 +2594,10 @@ qemuOpenFile(virQEMUDriverPtr driver, const char *path, int oflags,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case -1:
|
case -1:
|
||||||
virReportSystemError(errno,
|
virReportSystemError(-fd, oflags & O_CREAT
|
||||||
_("Failed to create file "
|
? _("Failed to create file "
|
||||||
|
"'%s': couldn't determine fs type")
|
||||||
|
: _("Failed to open file "
|
||||||
"'%s': couldn't determine fs type"),
|
"'%s': couldn't determine fs type"),
|
||||||
path);
|
path);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -2609,10 +2605,7 @@ qemuOpenFile(virQEMUDriverPtr driver, const char *path, int oflags,
|
|||||||
case 0:
|
case 0:
|
||||||
default:
|
default:
|
||||||
/* local file - log the error returned by virFileOpenAs */
|
/* local file - log the error returned by virFileOpenAs */
|
||||||
virReportSystemError(-fd,
|
goto error;
|
||||||
_("Failed to create file '%s'"),
|
|
||||||
path);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retry creating the file as cfg->user */
|
/* Retry creating the file as cfg->user */
|
||||||
@ -2621,8 +2614,9 @@ qemuOpenFile(virQEMUDriverPtr driver, const char *path, int oflags,
|
|||||||
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
|
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
|
||||||
cfg->user, cfg->group,
|
cfg->user, cfg->group,
|
||||||
vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
|
vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
|
||||||
virReportSystemError(-fd,
|
virReportSystemError(-fd, oflags & O_CREAT
|
||||||
_("Error from child process creating '%s'"),
|
? _("Error from child process creating '%s'")
|
||||||
|
: _("Error from child process opening '%s'"),
|
||||||
path);
|
path);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -2641,6 +2635,13 @@ cleanup:
|
|||||||
*bypassSecurityDriver = bypass_security;
|
*bypassSecurityDriver = bypass_security;
|
||||||
virObjectUnref(cfg);
|
virObjectUnref(cfg);
|
||||||
return fd;
|
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
|
/* Helper function to execute a migration to file with a correct save header
|
||||||
|
@ -405,7 +405,7 @@ virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
vol->target.perms.gid,
|
vol->target.perms.gid,
|
||||||
operation_flags)) < 0) {
|
operation_flags)) < 0) {
|
||||||
virReportSystemError(-fd,
|
virReportSystemError(-fd,
|
||||||
_("cannot create path '%s'"),
|
_("Failed to create file '%s'"),
|
||||||
vol->target.path);
|
vol->target.path);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -893,7 +893,7 @@ virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid)
|
|||||||
int fd, ret;
|
int fd, ret;
|
||||||
|
|
||||||
if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -952,7 +952,7 @@ virStorageFileGetMetadataRecurse(const char *path, const char *directory,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -973,9 +973,11 @@ virFileOpenForked(const char *path, int openflags, mode_t mode,
|
|||||||
* uid:gid before returning (even if it already existed with a
|
* uid:gid before returning (even if it already existed with a
|
||||||
* different owner). If @flags includes VIR_FILE_OPEN_FORCE_MODE,
|
* different owner). If @flags includes VIR_FILE_OPEN_FORCE_MODE,
|
||||||
* ensure it has those permissions before returning (again, even if
|
* ensure it has those permissions before returning (again, even if
|
||||||
* the file already existed with different permissions). The return
|
* the file already existed with different permissions).
|
||||||
* value (if non-negative) is the file descriptor, left open. Returns
|
*
|
||||||
* -errno on failure. */
|
* The return value (if non-negative) is the file descriptor, left
|
||||||
|
* open. Returns -errno on failure.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
virFileOpenAs(const char *path, int openflags, mode_t mode,
|
virFileOpenAs(const char *path, int openflags, mode_t mode,
|
||||||
uid_t uid, gid_t gid, unsigned int flags)
|
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) {
|
if ((fd = open(path, openflags, mode)) < 0) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
|
if (!(flags & VIR_FILE_OPEN_FORK))
|
||||||
|
goto error;
|
||||||
} else {
|
} else {
|
||||||
ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags);
|
ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags);
|
||||||
if (ret < 0)
|
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
|
/* On Linux we can also verify the FS-type of the
|
||||||
* directory. (this is a NOP on other platforms). */
|
* directory. (this is a NOP on other platforms). */
|
||||||
switch (virStorageFileIsSharedFS(path)) {
|
if (virStorageFileIsSharedFS(path) <= 0)
|
||||||
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;
|
goto error;
|
||||||
case 0:
|
|
||||||
default:
|
|
||||||
/* file isn't on a recognized network FS */
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* passed all prerequisites - retry the open w/fork+setuid */
|
/* passed all prerequisites - retry the open w/fork+setuid */
|
||||||
if ((fd = virFileOpenForked(path, openflags, mode, uid, gid, flags)) < 0) {
|
if ((fd = virFileOpenForked(path, openflags, mode, uid, gid, flags)) < 0) {
|
||||||
ret = fd;
|
ret = fd;
|
||||||
fd = -1;
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* File is successfully opened */
|
/* File is successfully opened */
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (fd < 0) {
|
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 {
|
|
||||||
/* some other failure after the open succeeded */
|
/* some other failure after the open succeeded */
|
||||||
VIR_FORCE_CLOSE(fd);
|
VIR_FORCE_CLOSE(fd);
|
||||||
}
|
}
|
||||||
|
/* whoever failed the open last has already set ret = -errno */
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user