/* * Returns: 0 = success, < 0 error, 1 not found */ int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, const char *filename, uint64_t offset, int flags) { int rc, hasst; struct stat st; if (!filename) return -EINVAL; hasst = !stat(filename, &st); rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED); if (rc) return rc; while ((rc = loopcxt_next(lc)) == 0) { if (loopcxt_is_used(lc, hasst ? &st : NULL, filename, offset, flags)) break; } loopcxt_deinit_iterator(lc); return rc; }
/* * Note that LOOP_CTL_GET_FREE ioctl is supported since kernel 3.1. In older * kernels we have to check all loop devices to found unused one. * * See kernel commit 770fe30a46a12b6fb6b63fbe1737654d28e8484. */ int loopcxt_find_unused(struct loopdev_cxt *lc) { int rc = -1; DBG(lc, loopdev_debug("find_unused requested")); if (lc->flags & LOOPDEV_FL_CONTROL) { int ctl = open(_PATH_DEV_LOOPCTL, O_RDWR); if (ctl >= 0) rc = ioctl(ctl, LOOP_CTL_GET_FREE); if (rc >= 0) { char name[16]; snprintf(name, sizeof(name), "loop%d", rc); rc = loopiter_set_device(lc, name); } if (ctl >= 0) close(ctl); DBG(lc, loopdev_debug("find_unused by loop-control [rc=%d]", rc)); } if (rc < 0) { rc = loopcxt_init_iterator(lc, LOOPITER_FL_FREE); if (rc) return rc; rc = loopcxt_next(lc); loopcxt_deinit_iterator(lc); DBG(lc, loopdev_debug("find_unused by scan [rc=%d]", rc)); } return rc; }
/* * @lc: context * * Deinitialize loop context */ void loopcxt_deinit(struct loopdev_cxt *lc) { if (!lc) return; DBG(lc, loopdev_debug("de-initialize")); free(lc->filename); lc->filename = NULL; loopcxt_set_device(lc, NULL); loopcxt_deinit_iterator(lc); }
static int delete_all_loops(struct loopdev_cxt *lc) { int res = 0; if (loopcxt_init_iterator(lc, LOOPITER_FL_USED)) return -1; while (loopcxt_next(lc) == 0) res += delete_loop(lc); loopcxt_deinit_iterator(lc); return res; }
static int show_all_loops(struct loopdev_cxt *lc, const char *file, uint64_t offset, int flags) { struct stat sbuf, *st = &sbuf; if (loopcxt_init_iterator(lc, LOOPITER_FL_USED)) return -1; if (!file || stat(file, st)) st = NULL; while (loopcxt_next(lc) == 0) { if (file && !loopcxt_is_used(lc, st, file, offset, flags)) continue; printf_loopdev(lc); } loopcxt_deinit_iterator(lc); return 0; }
/* * @lc: context, has to initialized by loopcxt_init_iterator() * * Returns: 0 on success, -1 on error, 1 at the end of scanning. The details * about the current loop device are available by * loopcxt_get_{fd,backing_file,device,offset, ...} functions. */ int loopcxt_next(struct loopdev_cxt *lc) { struct loopdev_iter *iter; if (!lc) return -EINVAL; DBG(lc, loopdev_debug("iter: next")); iter = &lc->iter; if (iter->done) return 1; /* A) Look for used loop devices in /proc/partitions ("losetup -a" only) */ if (iter->flags & LOOPITER_FL_USED) { char buf[BUFSIZ]; if (!iter->proc) iter->proc = fopen(_PATH_PROC_PARTITIONS, "r"); while (iter->proc && fgets(buf, sizeof(buf), iter->proc)) { unsigned int m; char name[128]; if (sscanf(buf, " %u %*s %*s %128[^\n ]", &m, name) != 2 || m != LOOPDEV_MAJOR) continue; if (loopiter_set_device(lc, name) == 0) return 0; } goto done; } /* B) Classic way, try first eight loop devices (default number * of loop devices). This is enough for 99% of all cases. */ if (iter->default_check) { for (++iter->ncur; iter->ncur < LOOPDEV_DEFAULT_NNODES; iter->ncur++) { char name[16]; snprintf(name, sizeof(name), "loop%d", iter->ncur); if (loopiter_set_device(lc, name) == 0) return 0; } iter->default_check = 0; } /* C) the worst possibility, scan whole /dev or /dev/loop/<N> */ if (!iter->minors) { iter->nminors = (lc->flags & LOOPDEV_FL_DEVSUBDIR) ? loop_scandir(_PATH_DEV_LOOP, &iter->minors, 0) : loop_scandir(_PATH_DEV, &iter->minors, 1); iter->ncur = -1; } for (++iter->ncur; iter->ncur < iter->nminors; iter->ncur++) { char name[16]; snprintf(name, sizeof(name), "loop%d", iter->minors[iter->ncur]); if (loopiter_set_device(lc, name) == 0) return 0; } done: loopcxt_deinit_iterator(lc); return 1; }