+ /* If device is free, claim it. */
+ if (rc && errno == ENXIO) {
+ memset(&loopinfo, 0, sizeof(loopinfo));
+ safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE);
+ loopinfo.lo_offset = offset;
+ /* Associate free loop device with file. */
+ if (ioctl(dfd, LOOP_SET_FD, ffd) == 0) {
+ if (ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo) == 0)
+ rc = 0;
+ else
+ ioctl(dfd, LOOP_CLR_FD, 0);
+ }
+
+ /* If this block device already set up right, re-use it.
+ * (Yes this is racy, but associating two loop devices with the same
+ * file isn't pretty either. In general, mounting the same file twice
+ * without using losetup manually is problematic.)
+ */
+ } else
+ if (strcmp(file, (char *)loopinfo.lo_file_name) != 0
+ || offset != loopinfo.lo_offset
+ ) {
+ rc = -1;
+ }
+ close(dfd);
+ try_again:
+ if (*device) break;
+ }
+ close(ffd);
+ if (rc == 0) {
+ if (!*device)
+ *device = xstrdup(dev);
+ return (mode == O_RDONLY); /* 1:ro, 0:rw */
+ }
+ return rc;
+}