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
+Usage of the "fdopen()", "close()", "fclose()" APIs is deprecated in libvirt
+code base to help avoiding double-closing of files or file descriptors, which
+is particulary dangerous in a multi-threaded applications. Instead of these
+APIs, use the macros from files.h
+
+- eg opening a file from a file descriptor
+
+ if ((file = VIR_FDOPEN(fd, "r")) == NULL) {
+ virReportSystemError(errno, "%s",
+ _("failed to open file from file descriptor"));
+ return -1;
+ }
+ /* fd is now invalid; only access the file using file variable */
+
+
- e.g. close a file descriptor
if (VIR_CLOSE(fd) < 0) {
- virReportSystemError(errno, _("failed to close file"));
+ virReportSystemError(errno, "%s", _("failed to close file"));
+ }
+
+
+
+- eg close a file
+
+ if (VIR_FCLOSE(file) < 0) {
+ virReportSystemError(errno, "%s", _("failed to close file"));
}
-- eg close a file descriptor in an error path, without losing the previous
-"errno" value
+- eg close a file or file descriptor in an error path, without losing the
+previous "errno" value
VIR_FORCE_CLOSE(fd);
+ VIR_FORCE_FCLOSE(file);
return -1;
}
- if (!(fh = fdopen(fd, "w"))) {
+ if (!(fh = VIR_FDOPEN(fd, "w"))) {
VIR_ERROR(_("Failed to fdopen pid file '%s' : %s"),
pidFile, virStrerror(errno, ebuf, sizeof ebuf));
VIR_FORCE_CLOSE(fd);
if (fprintf(fh, "%lu\n", (unsigned long)getpid()) < 0) {
VIR_ERROR(_("%s: Failed to write to pid file '%s' : %s"),
argv0, pidFile, virStrerror(errno, ebuf, sizeof ebuf));
- fclose(fh);
+ VIR_FORCE_FCLOSE(fh);
return -1;
}
- if (fclose(fh) == EOF) {
+ if (VIR_FCLOSE(fh) == EOF) {
VIR_ERROR(_("%s: Failed to close pid file '%s' : %s"),
argv0, pidFile, virStrerror(errno, ebuf, sizeof ebuf));
return -1;
<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
+ Usage of the <code>fdopen()</code>, <code>close()</code>, <code>fclose()</code>
+ APIs is deprecated in libvirt code base to help avoiding double-closing of files
+ or file descriptors, which is particulary dangerous in a multi-threaded
+ applications. Instead of these APIs, use the macros from files.h
</p>
- <ul>
+ <ul>
+ <li><p>eg opening a file from a file descriptor</p>
+
+<pre>
+ if ((file = VIR_FDOPEN(fd, "r")) == NULL) {
+ virReportSystemError(errno, "%s",
+ _("failed to open file from file descriptor"));
+ return -1;
+ }
+ /* fd is now invalid; only access the file using file variable */
+</pre></li>
+
<li><p>e.g. close a file descriptor</p>
<pre>
if (VIR_CLOSE(fd) < 0) {
- virReportSystemError(errno, _("failed to close file"));
+ virReportSystemError(errno, "%s", _("failed to close file"));
}
-</pre>
- </li>
+</pre></li>
+
+ <li><p>eg close a file</p>
+
+<pre>
+ if (VIR_FCLOSE(file) < 0) {
+ virReportSystemError(errno, "%s", _("failed to close file"));
+ }
+</pre></li>
- <li><p>eg close a file descriptor in an error path, without losing
+ <li><p>eg close a file or file descriptor in an error path, without losing
the previous <code>errno</code> value</p>
<pre>
VIR_FORCE_CLOSE(fd);
+ VIR_FORCE_FCLOSE(file);
</pre>
</li>
</ul>
# files.h
virClose;
+virFclose;
+virFdopen;
# hash.h
#include "virterror_internal.h"
#include "count-one-bits.h"
#include "intprops.h"
+#include "files.h"
#define VIR_FROM_THIS VIR_FROM_NONE
}
cleanup:
- if (pathfp)
- fclose(pathfp);
+ VIR_FORCE_FCLOSE(pathfp);
VIR_FREE(path);
return value;
}
cleanup:
- fclose(pathfp);
+ VIR_FORCE_FCLOSE(pathfp);
VIR_FREE(path);
return ret;
return -1;
}
ret = linuxNodeInfoCPUPopulate(cpuinfo, nodeinfo);
- fclose(cpuinfo);
+ VIR_FORCE_FCLOSE(cpuinfo);
if (ret < 0)
return -1;
dom = NULL;
}
- fclose(fp);
+ VIR_FORCE_FCLOSE(fp);
return 0;
virReportOOMError();
cleanup:
- fclose(fp);
+ VIR_FORCE_FCLOSE(fp);
if (dom)
virDomainObjUnref(dom);
return -1;
{
char *conf_file;
char uuidstr[VIR_UUID_STRING_BUFLEN];
+ FILE *fp = NULL;
int ret = -1;
if (uuid == NULL)
goto cleanup;
if (uuidstr[0] == 0) {
- FILE *fp = fopen(conf_file, "a"); /* append */
+ fp = fopen(conf_file, "a"); /* append */
if (fp == NULL)
goto cleanup;
virUUIDFormat(uuid, uuidstr);
- /* Record failure if fprintf or fclose fails,
+ /* Record failure if fprintf or VIR_FCLOSE fails,
and be careful always to close the stream. */
- if ((fprintf(fp, "\n#UUID: %s\n", uuidstr) < 0)
- + (fclose(fp) == EOF))
+ if ((fprintf(fp, "\n#UUID: %s\n", uuidstr) < 0) ||
+ (VIR_FCLOSE(fp) == EOF))
goto cleanup;
}
ret = 0;
cleanup:
+ VIR_FORCE_FCLOSE(fp);
VIR_FREE(conf_file);
return ret;
}
}
ok = fscanf(fp, "%d\n", &veid ) == 1;
- fclose(fp);
+ VIR_FORCE_FCLOSE(fp);
if (ok && veid >= 0)
return veid;
max_veid = veid;
}
}
- fclose(fp);
+ VIR_FORCE_FCLOSE(fp);
if (max_veid == 0) {
max_veid = 100;
return -1;
cleanup:
- fclose(fp);
+ VIR_FORCE_FCLOSE(fp);
return -1;
#undef ADD_ARG
/* startstack -> processor */
"%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
&usertime, &systime, &cpu) != 3) {
- fclose(pidinfo);
+ VIR_FORCE_FCLOSE(pidinfo);
VIR_WARN0("cannot parse process status data");
errno = -EINVAL;
return -1;
VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d",
pid, tid, usertime, systime, cpu);
- fclose(pidinfo);
+ VIR_FORCE_FCLOSE(pidinfo);
return 0;
}
goto cleanup;
}
- if ((list = fdopen(fd, "r")) == NULL) {
+ if ((list = VIR_FDOPEN(fd, "r")) == NULL) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("cannot read fd"));
goto cleanup;
VIR_FREE(reg);
- if (list)
- fclose(list);
- else
- VIR_FORCE_CLOSE(fd);
+ VIR_FORCE_FCLOSE(list);
+ VIR_FORCE_CLOSE(fd);
while ((err = waitpid(child, &exitstatus, 0) == -1) && errno == EINTR);
goto cleanup;
}
- if ((fp = fdopen(fd, "r")) == NULL) {
+ if ((fp = VIR_FDOPEN(fd, "r")) == NULL) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("cannot read fd"));
+ "%s", _("cannot open file using fd"));
goto cleanup;
}
VIR_FREE(v[i]);
VIR_FREE(v);
- if (fp)
- fclose (fp);
- else
- VIR_FORCE_CLOSE(fd);
+ VIR_FORCE_FCLOSE(fp);
+ VIR_FORCE_CLOSE(fd);
while ((w_err = waitpid (child, &exitstatus, 0) == -1) && errno == EINTR)
/* empty */ ;
while ((getmntent_r(mtab, &ent, buf, sizeof(buf))) != NULL) {
if (STREQ(ent.mnt_dir, pool->def->target.path)) {
- fclose(mtab);
+ VIR_FORCE_FCLOSE(mtab);
return 1;
}
}
- fclose(mtab);
+ VIR_FORCE_FCLOSE(mtab);
return 0;
}
goto out;
}
- if ((fp = fdopen(fd, "r")) == NULL) {
+ if ((fp = VIR_FDOPEN(fd, "r")) == NULL) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to open stream for file descriptor "
"when reading output from '%s': '%s'"),
}
VIR_FREE(line);
- if (fp != NULL) {
- fclose(fp);
- } else {
- VIR_FORCE_CLOSE(fd);
- }
+ VIR_FORCE_FCLOSE(fp);
+ VIR_FORCE_CLOSE(fd);
return ret;
}
}
gottype = fgets(typestr, 3, typefile);
- fclose(typefile);
+ VIR_FORCE_FCLOSE(typefile);
if (gottype == NULL) {
virReportSystemError(errno,
if (fscanf(file, "%d", &vm->pid) != 1) {
errno = EINVAL;
- fclose(file);
+ VIR_FORCE_FCLOSE(file);
goto cleanup;
}
- if (fclose(file) < 0)
+ if (VIR_FCLOSE(file) < 0)
goto cleanup;
rc = 0;
if (fscanf(pidinfo, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu", &usertime, &systime) != 2) {
umlDebug("not enough arg");
- fclose(pidinfo);
+ VIR_FORCE_FCLOSE(pidinfo);
return -1;
}
umlDebug("Got %llu %llu %llu", usertime, systime, *cpuTime);
- fclose(pidinfo);
+ VIR_FORCE_FCLOSE(pidinfo);
return 0;
}
#include "memory.h"
#include "cgroup.h"
#include "logging.h"
+#include "files.h"
#define CGROUP_MAX_VAL 512
}
}
- fclose(mounts);
+ VIR_FORCE_FCLOSE(mounts);
return 0;
no_memory:
- if (mounts)
- fclose(mounts);
+ VIR_FORCE_FCLOSE(mounts);
return -ENOMEM;
}
}
}
- fclose(mapping);
+ VIR_FORCE_FCLOSE(mapping);
return 0;
no_memory:
- fclose(mapping);
+ VIR_FORCE_FCLOSE(mapping);
return -ENOMEM;
}
#include "memory.h"
#include "virterror_internal.h"
#include "logging.h"
+#include "files.h"
#define VIR_FROM_THIS VIR_FROM_NETWORK
#define DNSMASQ_HOSTSFILE_SUFFIX "hostsfile"
for (i = 0; i < nhosts; i++) {
if (fputs(hosts[i].host, f) == EOF || fputc('\n', f) == EOF) {
rc = errno;
- fclose(f);
+ VIR_FORCE_FCLOSE(f);
if (istmp)
unlink(tmp);
}
}
- if (fclose(f) == EOF) {
+ if (VIR_FCLOSE(f) == EOF) {
rc = errno;
goto cleanup;
}
return rc;
}
+
+
+int virFclose(FILE **file, bool preserve_errno)
+{
+ int saved_errno;
+ int rc = 0;
+
+ if (*file) {
+ if (preserve_errno)
+ saved_errno = errno;
+ rc = fclose(*file);
+ *file = NULL;
+ if (preserve_errno)
+ errno = saved_errno;
+ }
+
+ return rc;
+}
+
+
+FILE *virFdopen(int *fdptr, const char *mode)
+{
+ FILE *file = NULL;
+
+ if (*fdptr >= 0) {
+ file = fdopen(*fdptr, mode);
+ if (file)
+ *fdptr = -1;
+ } else {
+ errno = EBADF;
+ }
+
+ return file;
+}
# define __VIR_FILES_H_
# include <stdbool.h>
+# include <stdio.h>
# include "internal.h"
# include "ignore-value.h"
-/* Don't call this directly - use the macros below */
+/* Don't call these directly - use the macros below */
int virClose(int *fdptr, bool preserve_errno) ATTRIBUTE_RETURN_CHECK;
+int virFclose(FILE **file, bool preserve_errno) ATTRIBUTE_RETURN_CHECK;
+FILE *virFdopen(int *fdptr, const char *mode) 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)
+# define VIR_FCLOSE(FILE) virFclose(&(FILE), false)
+
+/* Wrapper around fdopen that consumes fd on success. */
+# define VIR_FDOPEN(FD, MODE) virFdopen(&(FD), MODE)
/* 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))
+# define VIR_FORCE_FCLOSE(FILE) ignore_value(virFclose(&(FILE), true))
#endif /* __VIR_FILES_H */
virReportSystemError(errno,
"%s",_("cannot determine macvtap's tap device "
"interface index"));
- fclose(file);
+ VIR_FORCE_FCLOSE(file);
return -1;
}
- fclose(file);
+ VIR_FORCE_FCLOSE(file);
if (snprintf(tapname, sizeof(tapname),
"/dev/tap%d", ifindex) >= sizeof(tapname)) {
# include "util.h"
# include "stats_linux.h"
# include "memory.h"
+# include "files.h"
# define VIR_FROM_THIS VIR_FROM_STATS_LINUX
stats->tx_packets = tx_packets;
stats->tx_errs = tx_errs;
stats->tx_drop = tx_drop;
- fclose (fp);
+ VIR_FORCE_FCLOSE (fp);
return 0;
}
}
- fclose (fp);
+ VIR_FORCE_FCLOSE(fp);
virStatsError(VIR_ERR_INTERNAL_ERROR,
"/proc/net/dev: Interface not found");
goto cleanup;
}
- if (!(file = fdopen(fd, "w"))) {
+ if (!(file = VIR_FDOPEN(fd, "w"))) {
rc = errno;
VIR_FORCE_CLOSE(fd);
goto cleanup;
rc = 0;
cleanup:
- if (file &&
- fclose(file) < 0) {
+ if (VIR_FCLOSE(file) < 0)
rc = errno;
- }
return rc;
}
if (fscanf(file, "%d", pid) != 1) {
rc = EINVAL;
- fclose(file);
+ VIR_FORCE_FCLOSE(file);
goto cleanup;
}
- if (fclose(file) < 0) {
+ if (VIR_FCLOSE(file) < 0) {
rc = errno;
goto cleanup;
}
# include "util.h"
# include "block_stats.h"
# include "memory.h"
+# include "files.h"
# define VIR_FROM_THIS VIR_FROM_STATS_LINUX
/* read, but don't bail out before closing */
i = fread (str, 1, sizeof str - 1, fp);
- if (fclose (fp) != 0 /* disk error */
+ if (VIR_FCLOSE(fp) != 0 /* disk error */
|| i < 1) /* ensure we read at least one byte */
return -1;
#include "pci.h"
#include "uuid.h"
#include "fdstream.h"
+#include "files.h"
#define VIR_FROM_THIS VIR_FROM_XEN
return 1;
#endif
#ifdef __sun
- FILE *fh;
+ int fd;
- if (fh = fopen("/dev/xen/domcaps", "r")) {
- fclose(fh);
+ if ((fd = open("/dev/xen/domcaps", O_RDONLY)) >= 0) {
+ VIR_FORCE_CLOSE(fd);
return 1;
}
#endif
capabilities = fopen ("/sys/hypervisor/properties/capabilities", "r");
if (capabilities == NULL) {
if (errno != ENOENT) {
- fclose(cpuinfo);
+ VIR_FORCE_FCLOSE(cpuinfo);
virReportSystemError(errno,
_("cannot read file %s"),
"/sys/hypervisor/properties/capabilities");
cpuinfo,
capabilities);
- if (cpuinfo)
- fclose(cpuinfo);
- if (capabilities)
- fclose(capabilities);
+ VIR_FORCE_FCLOSE(cpuinfo);
+ VIR_FORCE_FCLOSE(capabilities);
return caps;
#endif /* __sun */
#include "internal.h"
#include "nodeinfo.h"
#include "util.h"
+#include "files.h"
#ifndef __linux__
fprintf(stderr, "\n%s\n", error->message);
virFreeError(error);
}
- fclose(cpuinfo);
+ VIR_FORCE_FCLOSE(cpuinfo);
return -1;
}
- fclose(cpuinfo);
+ VIR_FORCE_FCLOSE(cpuinfo);
/* 'nodes' is filled using libnuma.so from current machine
* topology, which makes it unsuitable for the test suite
if (fstat(fileno(fp), &st) < 0) {
fprintf (stderr, "%s: failed to fstat: %s\n", file, strerror(errno));
- fclose(fp);
+ VIR_FORCE_FCLOSE(fp);
return -1;
}
if (st.st_size > (buflen-1)) {
fprintf (stderr, "%s: larger than buffer (> %d)\n", file, buflen-1);
- fclose(fp);
+ VIR_FORCE_FCLOSE(fp);
return -1;
}
if (st.st_size) {
if (fread(*buf, st.st_size, 1, fp) != 1) {
fprintf (stderr, "%s: read failed: %s\n", file, strerror(errno));
- fclose(fp);
+ VIR_FORCE_FCLOSE(fp);
return -1;
}
}
(*buf)[st.st_size] = '\0';
- fclose(fp);
+ VIR_FORCE_FCLOSE(fp);
return st.st_size;
}
#include "xml.h"
#include "testutils.h"
#include "xen/xen_hypervisor.h"
+#include "files.h"
static char *progname;
static char *abs_srcdir;
fail:
free(actualxml);
- if (fp1)
- fclose(fp1);
- if (fp2)
- fclose(fp2);
+ VIR_FORCE_FCLOSE(fp1);
+ VIR_FORCE_FCLOSE(fp2);
virCapabilitiesFree(caps);
return ret;