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 <[email protected]> --- 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 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
