[PATCH libpciaccess] Allow building without O_CLOEXEC
Aaron Plattner
aplattner at nvidia.com
Mon Sep 22 12:24:54 PDT 2014
Old versions of Linux don't support O_CLOEXEC, so rather than failing to build,
allow building without O_CLOEXEC if a new ALLOW_NO_O_CLOEXEC flag is defined.
Create a new helper function, pci_open_cloexec that uses O_CLOEXEC when it's
available and falls back to open + fcntl when it's not. Route all calls to open
that pass O_CLOEXEC through this new function instead using the following
Coccinelle patch:
@@
expression path, flags;
@@
-open(path, flags | O_CLOEXEC)
+pci_open_cloexec(path, flags)
Signed-off-by: Aaron Plattner <aplattner at nvidia.com>
---
There are three calls to open() that don't use O_CLOEXEC -- are those bugs?
src/linux_devmem.c: fd = open("/dev/mem", O_RDONLY, 0);
src/netbsd_pci.c: fd = open("/dev/ttyE0", O_RDONLY);
src/netbsd_pci.c: pcifd = open(netbsd_devname, O_RDWR);
src/common_vgaarb.c | 2 +-
src/freebsd_pci.c | 10 +++++-----
src/linux_sysfs.c | 26 +++++++++++++-------------
src/netbsd_pci.c | 2 +-
src/openbsd_pci.c | 2 +-
src/pciaccess_private.h | 33 +++++++++++++++++++++++++++++----
src/solx_devfs.c | 4 ++--
src/x86_pci.c | 4 ++--
8 files changed, 54 insertions(+), 29 deletions(-)
diff --git a/src/common_vgaarb.c b/src/common_vgaarb.c
index c59bd788dc5e..f3b523e67c3a 100644
--- a/src/common_vgaarb.c
+++ b/src/common_vgaarb.c
@@ -131,7 +131,7 @@ pci_device_vgaarb_init(void)
if (!pci_sys)
return -1;
- if ((pci_sys->vgaarb_fd = open ("/dev/vga_arbiter", O_RDWR | O_CLOEXEC)) < 0) {
+ if ((pci_sys->vgaarb_fd = pci_open_cloexec ("/dev/vga_arbiter", O_RDWR)) < 0) {
return errno;
}
diff --git a/src/freebsd_pci.c b/src/freebsd_pci.c
index 9505a1c17d21..e40d80847bf0 100644
--- a/src/freebsd_pci.c
+++ b/src/freebsd_pci.c
@@ -112,7 +112,7 @@ pci_device_freebsd_map_range(struct pci_device *dev,
int fd, err = 0;
- fd = open("/dev/mem", O_RDWR | O_CLOEXEC);
+ fd = pci_open_cloexec("/dev/mem", O_RDWR);
if (fd == -1)
return errno;
@@ -157,7 +157,7 @@ pci_device_freebsd_unmap_range( struct pci_device *dev,
if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
(map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE))
{
- fd = open("/dev/mem", O_RDWR | O_CLOEXEC);
+ fd = pci_open_cloexec("/dev/mem", O_RDWR);
if (fd != -1) {
mrd.mr_base = map->base;
mrd.mr_len = map->size;
@@ -297,7 +297,7 @@ pci_device_freebsd_read_rom( struct pci_device * dev, void * buffer )
}
printf("Using rom_base = 0x%lx\n", (long)rom_base);
- memfd = open( "/dev/mem", O_RDONLY | O_CLOEXEC );
+ memfd = pci_open_cloexec( "/dev/mem", O_RDONLY );
if ( memfd == -1 )
return errno;
@@ -574,7 +574,7 @@ pci_device_freebsd_open_legacy_io(struct pci_io_handle *ret,
struct pci_device *dev, pciaddr_t base, pciaddr_t size)
{
#if defined(__i386__) || defined(__amd64__)
- ret->fd = open("/dev/io", O_RDWR | O_CLOEXEC);
+ ret->fd = pci_open_cloexec("/dev/io", O_RDWR);
if (ret->fd < 0)
return NULL;
@@ -735,7 +735,7 @@ pci_system_freebsd_create( void )
int i;
/* Try to open the PCI device */
- pcidev = open( "/dev/pci", O_RDWR | O_CLOEXEC );
+ pcidev = pci_open_cloexec( "/dev/pci", O_RDWR );
if ( pcidev == -1 )
return ENXIO;
diff --git a/src/linux_sysfs.c b/src/linux_sysfs.c
index 08c99719bcba..120cd6411893 100644
--- a/src/linux_sysfs.c
+++ b/src/linux_sysfs.c
@@ -100,7 +100,7 @@ pci_system_linux_sysfs_create( void )
if ( pci_sys != NULL ) {
pci_sys->methods = & linux_sysfs_methods;
#ifdef HAVE_MTRR
- pci_sys->mtrr_fd = open("/proc/mtrr", O_WRONLY | O_CLOEXEC);
+ pci_sys->mtrr_fd = pci_open_cloexec("/proc/mtrr", O_WRONLY);
#endif
err = populate_entries(pci_sys);
}
@@ -247,7 +247,7 @@ pci_device_linux_sysfs_probe( struct pci_device * dev )
dev->bus,
dev->dev,
dev->func );
- fd = open( name, O_RDONLY | O_CLOEXEC);
+ fd = pci_open_cloexec(name, O_RDONLY);
if ( fd != -1 ) {
char * next;
pciaddr_t low_addr;
@@ -309,7 +309,7 @@ pci_device_linux_sysfs_read_rom( struct pci_device * dev, void * buffer )
dev->dev,
dev->func );
- fd = open( name, O_RDWR | O_CLOEXEC);
+ fd = pci_open_cloexec(name, O_RDWR);
if ( fd == -1 ) {
#ifdef LINUX_ROM
/* If reading the ROM using sysfs fails, fall back to the old
@@ -390,7 +390,7 @@ pci_device_linux_sysfs_read( struct pci_device * dev, void * data,
dev->dev,
dev->func );
- fd = open( name, O_RDONLY | O_CLOEXEC);
+ fd = pci_open_cloexec(name, O_RDONLY);
if ( fd == -1 ) {
return errno;
}
@@ -450,7 +450,7 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data,
dev->dev,
dev->func );
- fd = open( name, O_WRONLY | O_CLOEXEC);
+ fd = pci_open_cloexec(name, O_WRONLY);
if ( fd == -1 ) {
return errno;
}
@@ -501,7 +501,7 @@ pci_device_linux_sysfs_map_range_wc(struct pci_device *dev,
dev->dev,
dev->func,
map->region);
- fd = open(name, open_flags | O_CLOEXEC);
+ fd = pci_open_cloexec(name, open_flags);
if (fd == -1)
return errno;
@@ -566,7 +566,7 @@ pci_device_linux_sysfs_map_range(struct pci_device *dev,
dev->func,
map->region);
- fd = open(name, open_flags | O_CLOEXEC);
+ fd = pci_open_cloexec(name, open_flags);
if (fd == -1) {
return errno;
}
@@ -689,7 +689,7 @@ static void pci_device_linux_sysfs_enable(struct pci_device *dev)
dev->dev,
dev->func );
- fd = open( name, O_RDWR | O_CLOEXEC);
+ fd = pci_open_cloexec(name, O_RDWR);
if (fd == -1)
return;
@@ -711,7 +711,7 @@ static int pci_device_linux_sysfs_boot_vga(struct pci_device *dev)
dev->dev,
dev->func );
- fd = open( name, O_RDONLY | O_CLOEXEC);
+ fd = pci_open_cloexec(name, O_RDONLY);
if (fd == -1)
return 0;
@@ -754,7 +754,7 @@ pci_device_linux_sysfs_open_device_io(struct pci_io_handle *ret,
snprintf(name, PATH_MAX, "%s/%04x:%02x:%02x.%1u/resource%d",
SYS_BUS_PCI, dev->domain, dev->bus, dev->dev, dev->func, bar);
- ret->fd = open(name, O_RDWR | O_CLOEXEC);
+ ret->fd = pci_open_cloexec(name, O_RDWR);
if (ret->fd < 0)
return NULL;
@@ -778,7 +778,7 @@ pci_device_linux_sysfs_open_legacy_io(struct pci_io_handle *ret,
snprintf(name, PATH_MAX, "/sys/class/pci_bus/%04x:%02x/legacy_io",
dev->domain, dev->bus);
- ret->fd = open(name, O_RDWR | O_CLOEXEC);
+ ret->fd = pci_open_cloexec(name, O_RDWR);
if (ret->fd >= 0)
break;
@@ -925,7 +925,7 @@ pci_device_linux_sysfs_map_legacy(struct pci_device *dev, pciaddr_t base,
snprintf(name, PATH_MAX, "/sys/class/pci_bus/%04x:%02x/legacy_mem",
dev->domain, dev->bus);
- fd = open(name, flags | O_CLOEXEC);
+ fd = pci_open_cloexec(name, flags);
if (fd >= 0)
break;
@@ -934,7 +934,7 @@ pci_device_linux_sysfs_map_legacy(struct pci_device *dev, pciaddr_t base,
/* If not, /dev/mem is the best we can do */
if (!dev)
- fd = open("/dev/mem", flags | O_CLOEXEC);
+ fd = pci_open_cloexec("/dev/mem", flags);
if (fd < 0)
return errno;
diff --git a/src/netbsd_pci.c b/src/netbsd_pci.c
index 52591b08f737..87bb2feb2504 100644
--- a/src/netbsd_pci.c
+++ b/src/netbsd_pci.c
@@ -909,7 +909,7 @@ pci_system_netbsd_create(void)
ndevs = 0;
nbuses = 0;
snprintf(netbsd_devname, 32, "/dev/pci%d", nbuses);
- pcifd = open(netbsd_devname, O_RDWR | O_CLOEXEC);
+ pcifd = pci_open_cloexec(netbsd_devname, O_RDWR);
while (pcifd > 0) {
ioctl(pcifd, PCI_IOC_BUSINFO, &businfo);
buses[nbuses].fd = pcifd;
diff --git a/src/openbsd_pci.c b/src/openbsd_pci.c
index fe034f3b046b..3d66598b5b77 100644
--- a/src/openbsd_pci.c
+++ b/src/openbsd_pci.c
@@ -571,7 +571,7 @@ pci_system_openbsd_create(void)
for (domain = 0; domain < sizeof(pcifd) / sizeof(pcifd[0]); domain++) {
snprintf(path, sizeof(path), "/dev/pci%d", domain);
- pcifd[domain] = open(path, O_RDWR | O_CLOEXEC);
+ pcifd[domain] = pci_open_cloexec(path, O_RDWR);
if (pcifd[domain] == -1)
break;
ndomains++;
diff --git a/src/pciaccess_private.h b/src/pciaccess_private.h
index 9f4e8f9ab573..0de989bceab4 100644
--- a/src/pciaccess_private.h
+++ b/src/pciaccess_private.h
@@ -40,13 +40,16 @@
/*
* O_CLOEXEC fixes an fd leak case (see 'man 2 open' for details). I don't
* know of any OS we support where this isn't available in a sufficiently
- * new version, so warn unconditionally.
+ * new version, so fail if ALLOW_NO_O_CLOEXEC is not defined.
*/
#include <sys/fcntl.h>
-#ifndef O_CLOEXEC
-#warning O_CLOEXEC not available, please upgrade.
-#define O_CLOEXEC 0
+#if !defined(O_CLOEXEC)
+# if defined(ALLOW_NO_O_CLOEXEC)
+# include <unistd.h>
+# else
+# error O_CLOEXEC not available, please upgrade.
+# endif
#endif
@@ -191,3 +194,25 @@ extern void pci_system_openbsd_init_dev_mem( int );
extern int pci_system_solx_devfs_create( void );
extern int pci_system_x86_create( void );
extern void pci_io_cleanup( void );
+
+static inline int pci_open_cloexec( const char *path, int flags )
+{
+#if defined(O_CLOEXEC)
+ return open(path, flags | O_CLOEXEC);
+#else
+ int fd = open(path, flags);
+ if (fd >= 0) {
+ int flags = fcntl(fd, F_GETFD);
+ if (flags == -1) {
+ close(fd);
+ return -1;
+ }
+ flags |= FD_CLOEXEC;
+ if (fcntl(fd, F_SETFD, flags) == -1) {
+ close(fd);
+ return -1;
+ }
+ }
+ return fd;
+#endif
+}
diff --git a/src/solx_devfs.c b/src/solx_devfs.c
index f57239304a43..2d4b102f8cf1 100644
--- a/src/solx_devfs.c
+++ b/src/solx_devfs.c
@@ -415,7 +415,7 @@ probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg)
nexus_path, first_bus, last_bus);
#endif
- if ((fd = open(nexus_path, O_RDWR | O_CLOEXEC)) >= 0) {
+ if ((fd = pci_open_cloexec(nexus_path, O_RDWR)) >= 0) {
probe_args_t args;
nexus->fd = fd;
@@ -718,7 +718,7 @@ pci_device_solx_devfs_map_range(struct pci_device *dev,
#endif
if (map_fd < 0) {
- if ((map_fd = open(map_dev, O_RDWR | O_CLOEXEC)) < 0) {
+ if ((map_fd = pci_open_cloexec(map_dev, O_RDWR)) < 0) {
err = errno;
(void) fprintf(stderr, "can not open %s: %s\n", map_dev,
strerror(errno));
diff --git a/src/x86_pci.c b/src/x86_pci.c
index 49c1cabc3c6c..7088ff9a016d 100644
--- a/src/x86_pci.c
+++ b/src/x86_pci.c
@@ -457,7 +457,7 @@ pci_device_x86_read_rom(struct pci_device *dev, void *buffer)
return ENOSYS;
}
- memfd = open("/dev/mem", O_RDONLY | O_CLOEXEC);
+ memfd = pci_open_cloexec("/dev/mem", O_RDONLY);
if (memfd == -1)
return errno;
@@ -637,7 +637,7 @@ static int
pci_device_x86_map_range(struct pci_device *dev,
struct pci_device_mapping *map)
{
- int memfd = open("/dev/mem", O_RDWR | O_CLOEXEC);
+ int memfd = pci_open_cloexec("/dev/mem", O_RDWR);
int prot = PROT_READ;
if (memfd == -1)
--
2.1.0
More information about the xorg-devel
mailing list