diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index 442ee6a..ae5b8e2 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -81,6 +81,10 @@ static const char *usbfs_path = NULL; /* use usbdev*.* device names in /dev instead of the usbfs bus directories */ static int usbdev_names = 0; +/* Linux 2.6.23 adds support for O_CLOEXEC when opening files, which marks the + * close-on-exec flag in the underlying file descriptor. */ +static int supports_flag_cloexec = -1; + /* Linux 2.6.32 adds support for a bulk continuation URB flag. this basically * allows us to mark URBs as being part of a specific logical transfer when * we submit them to the kernel. then, on any error except a cancellation, all @@ -180,6 +184,16 @@ struct linux_transfer_priv { int iso_packet_offset; }; +static int _open(const char *path, int flags) +{ +#if defined(O_CLOEXEC) + if (supports_flag_cloexec) + return open(path, flags | O_CLOEXEC); + else +#endif + return open(path, flags); +} + static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent) { struct libusb_context *ctx = DEVICE_CTX(dev); @@ -194,7 +208,7 @@ static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent) snprintf(path, PATH_MAX, "%s/%03d/%03d", usbfs_path, dev->bus_number, dev->device_address); - fd = open(path, mode | O_CLOEXEC); + fd = _open(path, mode); if (fd != -1) return fd; /* Success */ @@ -205,7 +219,7 @@ static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent) /* Wait 10ms for USB device path creation.*/ nanosleep(&(struct timespec){delay / 1000000, (delay * 1000) % 1000000000UL}, NULL); - fd = open(path, mode | O_CLOEXEC); + fd = _open(path, mode); if (fd != -1) return fd; /* Success */ } @@ -387,6 +401,15 @@ static int op_init(struct libusb_context *ctx) if (monotonic_clkid == -1) monotonic_clkid = find_monotonic_clock(); + if (supports_flag_cloexec == -1) { + /* O_CLOEXEC flag available from Linux 2.6.23 */ + supports_flag_cloexec = kernel_version_ge(2,6,23); + if (supports_flag_cloexec == -1) { + usbi_err(ctx, "error checking for O_CLOEXEC support"); + return LIBUSB_ERROR_OTHER; + } + } + if (supports_flag_bulk_continuation == -1) { /* bulk continuation URB flag available from Linux 2.6.32 */ supports_flag_bulk_continuation = kernel_version_ge(2,6,32); @@ -526,7 +549,7 @@ static int _open_sysfs_attr(struct libusb_device *dev, const char *attr) snprintf(filename, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH, priv->sysfs_dir, attr); - fd = open(filename, O_RDONLY | O_CLOEXEC); + fd = _open(filename, O_RDONLY); if (fd < 0) { usbi_err(DEVICE_CTX(dev), "open %s failed ret=%d errno=%d", filename, fd, errno); @@ -542,12 +565,12 @@ static int __read_sysfs_attr(struct libusb_context *ctx, { char filename[PATH_MAX]; FILE *f; - int r, value; + int fd, r, value; snprintf(filename, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH, devname, attr); - f = fopen(filename, "re"); - if (f == NULL) { + fd = _open(filename, O_RDONLY); + if (fd == -1) { if (errno == ENOENT) { /* File doesn't exist. Assume the device has been disconnected (see trac ticket #70). */ @@ -557,6 +580,13 @@ static int __read_sysfs_attr(struct libusb_context *ctx, return LIBUSB_ERROR_IO; } + f = fdopen(fd, "r"); + if (f == NULL) { + usbi_err(ctx, "fdopen %s failed errno=%d", filename, errno); + close(fd); + return LIBUSB_ERROR_OTHER; + } + r = fscanf(f, "%d", &value); fclose(f); if (r != 1) { diff --git a/libusb/version_nano.h b/libusb/version_nano.h index 723c6c5..f75412b 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11194 +#define LIBUSB_NANO 11195