Introduce VIR_CLOSE to be used rather than close()

Since bugs due to double-closed file descriptors are difficult to track down in a multi-threaded system, I am introducing the VIR_CLOSE(fd) macro to help avoid mistakes here.

There are lots of places where close() is being used. In this patch I am only cleaning up usage of close() in src/conf where the problems were.

I also dare to declare close() as being deprecated in libvirt code base (HACKING).
This commit is contained in:
Stefan Berger 2010-10-19 10:23:51 -04:00
parent b2c9a87940
commit f04de501bc
11 changed files with 161 additions and 22 deletions

17
HACKING
View File

@ -318,6 +318,23 @@ routines, use the macros from memory.h
VIR_FREE(domain);
File handling
=============
Use of the close() API is deprecated in libvirt code base to help avoiding
double-closing of a file descriptor. Instead of this API, use the macro from
files.h
- eg close a file descriptor
if (VIR_CLOSE(fd) < 0) {
virReportSystemError(errno, _("failed to close file"));
}
- eg close a file descriptor in an error path, without losing the previous
errno value
VIR_FORCE_CLOSE(fd);
String comparisons
==================

View File

@ -389,7 +389,30 @@
</pre></li>
</ul>
<h2><a name="file_handling">File handling</a></h2>
<p>
Use of the close() API is deprecated in libvirt code base to help
avoiding double-closing of a file descriptor. Instead of this API,
use the macro from files.h
</p>
<ul>
<li><p>eg close a file descriptor</p>
<pre>
if (VIR_CLOSE(fd) &lt; 0) {
virReportSystemError(errno, _("failed to close file"));
}
</pre></li>
<li><p>eg close a file descriptor in an error path, without losing
the previous errno value</p>
<pre>
VIR_FORCE_CLOSE(fd);
</pre></li>
</ul>
<h2><a name="string_comparision">String comparisons</a></h2>

View File

@ -82,7 +82,8 @@ UTIL_SOURCES = \
util/uuid.c util/uuid.h \
util/util.c util/util.h \
util/xml.c util/xml.h \
util/virterror.c util/virterror_internal.h
util/virterror.c util/virterror_internal.h \
util/files.c util/files.h
EXTRA_DIST += util/threads-pthread.c util/threads-win32.c

View File

@ -46,6 +46,7 @@
#include "nwfilter_conf.h"
#include "ignore-value.h"
#include "storage_file.h"
#include "files.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
@ -6798,7 +6799,7 @@ int virDomainSaveXML(const char *configDir,
goto cleanup;
}
if (close(fd) < 0) {
if (VIR_CLOSE(fd) < 0) {
virReportSystemError(errno,
_("cannot save config file '%s'"),
configFile);
@ -6807,8 +6808,8 @@ int virDomainSaveXML(const char *configDir,
ret = 0;
cleanup:
if (fd != -1)
close(fd);
VIR_FORCE_CLOSE(fd);
VIR_FREE(configFile);
return ret;
}
@ -7765,10 +7766,14 @@ int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
}
if (virStorageFileGetMetadataFromFD(path, fd, format, &meta) < 0) {
close(fd);
VIR_FORCE_CLOSE(fd);
goto cleanup;
}
close(fd);
if (VIR_CLOSE(fd) < 0)
virReportSystemError(errno,
_("could not close file %s"),
path);
if (virHashAddEntry(paths, path, (void*)0x1) < 0) {
virReportOOMError();

View File

@ -43,6 +43,7 @@
#include "util.h"
#include "buf.h"
#include "c-ctype.h"
#include "files.h"
#define MAX_BRIDGE_ID 256
#define VIR_FROM_THIS VIR_FROM_NETWORK
@ -687,7 +688,7 @@ int virNetworkSaveXML(const char *configDir,
goto cleanup;
}
if (close(fd) < 0) {
if (VIR_CLOSE(fd) < 0) {
virReportSystemError(errno,
_("cannot save config file '%s'"),
configFile);
@ -697,8 +698,7 @@ int virNetworkSaveXML(const char *configDir,
ret = 0;
cleanup:
if (fd != -1)
close(fd);
VIR_FORCE_CLOSE(fd);
VIR_FREE(configFile);

View File

@ -45,6 +45,7 @@
#include "nwfilter_conf.h"
#include "domain_conf.h"
#include "c-ctype.h"
#include "files.h"
#define VIR_FROM_THIS VIR_FROM_NWFILTER
@ -2193,7 +2194,7 @@ int virNWFilterSaveXML(const char *configDir,
goto cleanup;
}
if (close(fd) < 0) {
if (VIR_CLOSE(fd) < 0) {
virReportSystemError(errno,
_("cannot save config file '%s'"),
configFile);
@ -2203,9 +2204,7 @@ int virNWFilterSaveXML(const char *configDir,
ret = 0;
cleanup:
if (fd != -1)
close(fd);
VIR_FORCE_CLOSE(fd);
VIR_FREE(configFile);
return ret;
@ -2604,7 +2603,7 @@ virNWFilterPoolObjSaveDef(virNWFilterDriverStatePtr driver,
goto cleanup;
}
if (close(fd) < 0) {
if (VIR_CLOSE(fd) < 0) {
virReportSystemError(errno,
_("cannot save config file %s"),
pool->configFile);
@ -2614,8 +2613,7 @@ virNWFilterPoolObjSaveDef(virNWFilterDriverStatePtr driver,
ret = 0;
cleanup:
if (fd != -1)
close(fd);
VIR_FORCE_CLOSE(fd);
VIR_FREE(xml);

View File

@ -43,6 +43,7 @@
#include "buf.h"
#include "util.h"
#include "memory.h"
#include "files.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
@ -1560,7 +1561,7 @@ virStoragePoolObjSaveDef(virStorageDriverStatePtr driver,
goto cleanup;
}
if (close(fd) < 0) {
if (VIR_CLOSE(fd) < 0) {
virReportSystemError(errno,
_("cannot save config file %s"),
pool->configFile);
@ -1570,9 +1571,7 @@ virStoragePoolObjSaveDef(virStorageDriverStatePtr driver,
ret = 0;
cleanup:
if (fd != -1)
close(fd);
VIR_FORCE_CLOSE(fd);
VIR_FREE(xml);
return ret;

View File

@ -35,6 +35,7 @@
#include "xml.h"
#include "virterror_internal.h"
#include "uuid.h"
#include "files.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
@ -286,12 +287,12 @@ virStorageGenerateQcowPassphrase(unsigned char *dest)
if (r <= 0) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot read from /dev/urandom"));
close(fd);
VIR_FORCE_CLOSE(fd);
return -1;
}
if (dest[i] >= 0x20 && dest[i] <= 0x7E)
i++; /* Got an acceptable character */
}
close(fd);
VIR_FORCE_CLOSE(fd);
return 0;
}

View File

@ -769,3 +769,6 @@ virXPathLongLong;
virXPathULongLong;
virXPathLongHex;
virXPathULongHex;
# files.h
virClose;

46
src/util/files.c Normal file
View File

@ -0,0 +1,46 @@
/*
* memory.c: safer file handling
*
* Copyright (C) 2010 IBM Corporation
* Copyright (C) 2010 Stefan Berger
* Copyright (C) 2010 RedHat, Inc.
* Copyright (C) 2010 Eric Blake
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <config.h>
#include <unistd.h>
#include "files.h"
int virClose(int *fdptr, bool preserve_errno)
{
int saved_errno;
int rc = 0;
if (*fdptr >= 0) {
if (preserve_errno)
saved_errno = errno;
rc = close(*fdptr);
*fdptr = -1;
if (preserve_errno)
errno = saved_errno;
}
return rc;
}

46
src/util/files.h Normal file
View File

@ -0,0 +1,46 @@
/*
* files.h: safer file handling
*
* Copyright (C) 2010 IBM Corporation
* Copyright (C) 2010 Stefan Berger
* Copyright (C) 2010 RedHat, Inc.
* Copyright (C) 2010 Eric Blake
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __VIR_FILES_H_
# define __VIR_FILES_H_
# include <stdbool.h>
# include "internal.h"
# include "ignore-value.h"
/* Don't call this directly - use the macros below */
int virClose(int *fdptr, bool preserve_errno) ATTRIBUTE_RETURN_CHECK;
/* For use on normal paths; caller must check return value,
and failure sets errno per close(). */
# define VIR_CLOSE(FD) virClose(&(FD), false)
/* For use on cleanup paths; errno is unaffected by close,
and no return value to worry about. */
# define VIR_FORCE_CLOSE(FD) ignore_value(virClose(&(FD), true))
#endif /* __VIR_FILES_H */