2016-08-04 10:49:46 +02:00
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
/*
|
2013-01-08 15:00:23 +01:00
|
|
|
* No copyright is claimed. This code is in the public domain; do with
|
|
|
|
* it what you wish.
|
|
|
|
*
|
|
|
|
* Written by Karel Zak <kzak@redhat.com>
|
2011-05-30 16:37:31 +02:00
|
|
|
*
|
|
|
|
* -- based on mount/losetup.c
|
|
|
|
*
|
|
|
|
* Simple library for work with loop devices.
|
|
|
|
*
|
|
|
|
* - requires kernel 2.6.x
|
|
|
|
* - reads info from /sys/block/loop<N>/loop/<attr> (new kernels)
|
|
|
|
* - reads info by ioctl
|
|
|
|
* - supports *unlimited* number of loop devices
|
|
|
|
* - supports /dev/loop<N> as well as /dev/loop/<N>
|
|
|
|
* - minimize overhead (fd, loopinfo, ... are shared for all operations)
|
|
|
|
* - setup (associate device and backing file)
|
|
|
|
* - delete (dis-associate file)
|
|
|
|
* - old LOOP_{SET,GET}_STATUS (32bit) ioctls are unsupported
|
|
|
|
* - extendible
|
|
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
|
|
|
|
#include "linux_version.h"
|
|
|
|
#include "c.h"
|
|
|
|
#include "sysfs.h"
|
|
|
|
#include "pathnames.h"
|
|
|
|
#include "loopdev.h"
|
|
|
|
#include "canonicalize.h"
|
2013-04-09 14:32:50 +02:00
|
|
|
#include "blkdev.h"
|
2014-11-04 14:08:45 +01:00
|
|
|
#include "debug.h"
|
2011-05-30 16:37:31 +02:00
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
/*
|
|
|
|
* Debug stuff (based on include/debug.h)
|
|
|
|
*/
|
2017-02-12 01:19:33 +01:00
|
|
|
static UL_DEBUG_DEFINE_MASK(loopdev);
|
2014-11-04 14:08:45 +01:00
|
|
|
UL_DEBUG_DEFINE_MASKNAMES(loopdev) = UL_DEBUG_EMPTY_MASKNAMES;
|
2011-09-29 23:28:36 +02:00
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
#define LOOPDEV_DEBUG_INIT (1 << 1)
|
|
|
|
#define LOOPDEV_DEBUG_CXT (1 << 2)
|
|
|
|
#define LOOPDEV_DEBUG_ITER (1 << 3)
|
|
|
|
#define LOOPDEV_DEBUG_SETUP (1 << 4)
|
2011-09-29 23:28:36 +02:00
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
#define DBG(m, x) __UL_DBG(loopdev, LOOPDEV_DEBUG_, m, x)
|
|
|
|
#define ON_DBG(m, x) __UL_DBG_CALL(loopdev, LOOPDEV_DEBUG_, m, x)
|
2011-09-29 23:28:36 +02:00
|
|
|
|
2018-01-12 11:01:26 +01:00
|
|
|
#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(loopdev)
|
|
|
|
#include "debugobj.h"
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
static void loopdev_init_debug(void)
|
2011-09-29 23:28:36 +02:00
|
|
|
{
|
2014-11-04 14:08:45 +01:00
|
|
|
if (loopdev_debug_mask)
|
|
|
|
return;
|
2018-01-17 13:58:29 +01:00
|
|
|
__UL_INIT_DEBUG_FROM_ENV(loopdev, LOOPDEV_DEBUG_, 0, LOOPDEV_DEBUG);
|
2011-09-29 23:28:36 +02:00
|
|
|
}
|
|
|
|
|
2012-06-12 15:41:47 +02:00
|
|
|
/*
|
|
|
|
* see loopcxt_init()
|
|
|
|
*/
|
2011-05-30 16:37:31 +02:00
|
|
|
#define loopcxt_ioctl_enabled(_lc) (!((_lc)->flags & LOOPDEV_FL_NOIOCTL))
|
2012-06-12 15:41:47 +02:00
|
|
|
#define loopcxt_sysfs_available(_lc) (!((_lc)->flags & LOOPDEV_FL_NOSYSFS)) \
|
|
|
|
&& !loopcxt_ioctl_enabled(_lc)
|
2011-05-30 16:37:31 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
* @device: device name, absolute device path or NULL to reset the current setting
|
|
|
|
*
|
|
|
|
* Sets device, absolute paths (e.g. "/dev/loop<N>") are unchanged, device
|
|
|
|
* names ("loop<N>") are converted to the path (/dev/loop<N> or to
|
|
|
|
* /dev/loop/<N>)
|
|
|
|
*
|
2014-05-14 12:53:24 +02:00
|
|
|
* This sets the device name, but does not check if the device exists!
|
|
|
|
*
|
2011-05-30 16:37:31 +02:00
|
|
|
* Returns: <0 on error, 0 on success
|
|
|
|
*/
|
|
|
|
int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
|
|
|
|
{
|
|
|
|
if (!lc)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2012-10-17 11:42:21 +02:00
|
|
|
if (lc->fd >= 0) {
|
2011-05-30 16:37:31 +02:00
|
|
|
close(lc->fd);
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "closing old open fd"));
|
2012-10-17 11:42:21 +02:00
|
|
|
}
|
2011-05-30 16:37:31 +02:00
|
|
|
lc->fd = -1;
|
2011-06-10 15:38:13 +02:00
|
|
|
lc->mode = 0;
|
2019-01-22 11:37:35 +01:00
|
|
|
lc->blocksize = 0;
|
2011-05-30 16:37:31 +02:00
|
|
|
lc->has_info = 0;
|
2011-12-20 18:25:04 +01:00
|
|
|
lc->info_failed = 0;
|
2011-05-30 16:37:31 +02:00
|
|
|
*lc->device = '\0';
|
2020-09-30 05:28:30 +02:00
|
|
|
memset(&lc->config, 0, sizeof(lc->config));
|
2011-05-30 16:37:31 +02:00
|
|
|
|
|
|
|
/* set new */
|
|
|
|
if (device) {
|
|
|
|
if (*device != '/') {
|
|
|
|
const char *dir = _PATH_DEV;
|
|
|
|
|
|
|
|
/* compose device name for /dev/loop<n> or /dev/loop/<n> */
|
|
|
|
if (lc->flags & LOOPDEV_FL_DEVSUBDIR) {
|
|
|
|
if (strlen(device) < 5)
|
|
|
|
return -1;
|
|
|
|
device += 4;
|
|
|
|
dir = _PATH_DEV_LOOP "/"; /* _PATH_DEV uses tailing slash */
|
|
|
|
}
|
|
|
|
snprintf(lc->device, sizeof(lc->device), "%s%s",
|
|
|
|
dir, device);
|
2019-05-20 12:46:39 +02:00
|
|
|
} else
|
|
|
|
xstrncpy(lc->device, device, sizeof(lc->device));
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "%s name assigned", device));
|
2011-05-30 16:37:31 +02:00
|
|
|
}
|
|
|
|
|
2018-05-15 13:08:47 +02:00
|
|
|
ul_unref_path(lc->sysfs);
|
|
|
|
lc->sysfs = NULL;
|
2011-05-30 16:37:31 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-18 22:05:16 +02:00
|
|
|
int loopcxt_has_device(struct loopdev_cxt *lc)
|
2011-12-21 19:24:58 +01:00
|
|
|
{
|
|
|
|
return lc && *lc->device;
|
|
|
|
}
|
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
* @flags: LOOPDEV_FL_* flags
|
|
|
|
*
|
2016-02-03 15:00:37 +01:00
|
|
|
* Initialize loop handler.
|
2011-05-30 16:37:31 +02:00
|
|
|
*
|
2011-06-10 15:38:13 +02:00
|
|
|
* We have two sets of the flags:
|
|
|
|
*
|
|
|
|
* * LOOPDEV_FL_* flags control loopcxt_* API behavior
|
|
|
|
*
|
|
|
|
* * LO_FLAGS_* are kernel flags used for LOOP_{SET,GET}_STAT64 ioctls
|
|
|
|
*
|
|
|
|
* Note about LOOPDEV_FL_{RDONLY,RDWR} flags. These flags are used for open(2)
|
|
|
|
* syscall to open loop device. By default is the device open read-only.
|
|
|
|
*
|
2018-02-15 22:02:18 +01:00
|
|
|
* The exception is loopcxt_setup_device(), where the device is open read-write
|
2011-06-10 15:38:13 +02:00
|
|
|
* if LO_FLAGS_READ_ONLY flags is not set (see loopcxt_set_flags()).
|
|
|
|
*
|
2011-05-30 16:37:31 +02:00
|
|
|
* Returns: <0 on error, 0 on success.
|
|
|
|
*/
|
|
|
|
int loopcxt_init(struct loopdev_cxt *lc, int flags)
|
|
|
|
{
|
2012-06-21 10:40:43 +02:00
|
|
|
int rc;
|
2011-11-07 16:45:11 +01:00
|
|
|
struct stat st;
|
2012-04-02 17:33:34 +02:00
|
|
|
struct loopdev_cxt dummy = UL_LOOPDEVCXT_EMPTY;
|
2011-11-07 16:45:11 +01:00
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
if (!lc)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
loopdev_init_debug();
|
|
|
|
DBG(CXT, ul_debugobj(lc, "initialize context"));
|
|
|
|
|
2012-04-02 17:33:34 +02:00
|
|
|
memcpy(lc, &dummy, sizeof(dummy));
|
2011-05-30 16:37:31 +02:00
|
|
|
lc->flags = flags;
|
2012-06-21 10:40:43 +02:00
|
|
|
|
|
|
|
rc = loopcxt_set_device(lc, NULL);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
2011-05-30 16:37:31 +02:00
|
|
|
|
2012-10-17 11:43:39 +02:00
|
|
|
if (stat(_PATH_SYS_BLOCK, &st) || !S_ISDIR(st.st_mode)) {
|
|
|
|
lc->flags |= LOOPDEV_FL_NOSYSFS;
|
|
|
|
lc->flags &= ~LOOPDEV_FL_NOIOCTL;
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "init: disable /sys usage"));
|
2012-10-17 11:43:39 +02:00
|
|
|
}
|
|
|
|
|
2011-09-15 16:17:45 +02:00
|
|
|
if (!(lc->flags & LOOPDEV_FL_NOSYSFS) &&
|
2012-10-17 11:42:21 +02:00
|
|
|
get_linux_version() >= KERNEL_VERSION(2,6,37)) {
|
2011-05-30 16:37:31 +02:00
|
|
|
/*
|
|
|
|
* Use only sysfs for basic information about loop devices
|
|
|
|
*/
|
|
|
|
lc->flags |= LOOPDEV_FL_NOIOCTL;
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "init: ignore ioctls"));
|
2012-10-17 11:42:21 +02:00
|
|
|
}
|
2011-05-30 16:37:31 +02:00
|
|
|
|
2012-10-17 11:42:21 +02:00
|
|
|
if (!(lc->flags & LOOPDEV_FL_CONTROL) && !stat(_PATH_DEV_LOOPCTL, &st)) {
|
2011-11-07 16:45:11 +01:00
|
|
|
lc->flags |= LOOPDEV_FL_CONTROL;
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "init: loop-control detected "));
|
2012-10-17 11:42:21 +02:00
|
|
|
}
|
2011-11-07 16:45:11 +01:00
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
*
|
|
|
|
* Deinitialize loop context
|
|
|
|
*/
|
|
|
|
void loopcxt_deinit(struct loopdev_cxt *lc)
|
|
|
|
{
|
2012-05-28 12:26:36 +02:00
|
|
|
int errsv = errno;
|
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
if (!lc)
|
|
|
|
return;
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "de-initialize"));
|
2011-09-29 23:28:36 +02:00
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
free(lc->filename);
|
|
|
|
lc->filename = NULL;
|
|
|
|
|
2012-06-21 10:40:43 +02:00
|
|
|
ignore_result( loopcxt_set_device(lc, NULL) );
|
2011-05-30 16:37:31 +02:00
|
|
|
loopcxt_deinit_iterator(lc);
|
2012-05-28 12:26:36 +02:00
|
|
|
|
|
|
|
errno = errsv;
|
2011-05-30 16:37:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
*
|
|
|
|
* Returns newly allocated device path.
|
|
|
|
*/
|
|
|
|
char *loopcxt_strdup_device(struct loopdev_cxt *lc)
|
|
|
|
{
|
2014-07-17 14:08:18 +02:00
|
|
|
if (!lc || !*lc->device)
|
2011-05-30 16:37:31 +02:00
|
|
|
return NULL;
|
|
|
|
return strdup(lc->device);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
*
|
|
|
|
* Returns pointer device name in the @lc struct.
|
|
|
|
*/
|
|
|
|
const char *loopcxt_get_device(struct loopdev_cxt *lc)
|
|
|
|
{
|
2014-07-17 14:08:18 +02:00
|
|
|
return lc && *lc->device ? lc->device : NULL;
|
2011-05-30 16:37:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
*
|
|
|
|
* Returns pointer to the sysfs context (see lib/sysfs.c)
|
|
|
|
*/
|
2018-05-15 13:08:47 +02:00
|
|
|
static struct path_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc)
|
2011-05-30 16:37:31 +02:00
|
|
|
{
|
|
|
|
if (!lc || !*lc->device || (lc->flags & LOOPDEV_FL_NOSYSFS))
|
|
|
|
return NULL;
|
|
|
|
|
2018-05-15 13:08:47 +02:00
|
|
|
if (!lc->sysfs) {
|
|
|
|
dev_t devno = sysfs_devname_to_devno(lc->device);
|
2011-09-29 23:28:36 +02:00
|
|
|
if (!devno) {
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "sysfs: failed devname to devno"));
|
2011-05-30 16:37:31 +02:00
|
|
|
return NULL;
|
2011-09-29 23:28:36 +02:00
|
|
|
}
|
2018-05-15 13:08:47 +02:00
|
|
|
|
|
|
|
lc->sysfs = ul_new_sysfs_path(devno, NULL, NULL);
|
|
|
|
if (!lc->sysfs)
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "sysfs: init failed"));
|
2011-05-30 16:37:31 +02:00
|
|
|
}
|
2011-09-29 23:28:36 +02:00
|
|
|
|
2018-05-15 13:08:47 +02:00
|
|
|
return lc->sysfs;
|
2011-05-30 16:37:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
*
|
|
|
|
* Returns: file descriptor to the open loop device or <0 on error. The mode
|
|
|
|
* depends on LOOPDEV_FL_{RDWR,RDONLY} context flags. Default is
|
|
|
|
* read-only.
|
|
|
|
*/
|
|
|
|
int loopcxt_get_fd(struct loopdev_cxt *lc)
|
|
|
|
{
|
|
|
|
if (!lc || !*lc->device)
|
2011-06-10 15:38:13 +02:00
|
|
|
return -EINVAL;
|
2011-05-30 16:37:31 +02:00
|
|
|
|
2011-06-10 15:38:13 +02:00
|
|
|
if (lc->fd < 0) {
|
|
|
|
lc->mode = lc->flags & LOOPDEV_FL_RDWR ? O_RDWR : O_RDONLY;
|
2013-04-03 16:13:06 +02:00
|
|
|
lc->fd = open(lc->device, lc->mode | O_CLOEXEC);
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "open %s [%s]: %m", lc->device,
|
2014-01-24 13:58:40 +01:00
|
|
|
lc->flags & LOOPDEV_FL_RDWR ? "rw" : "ro"));
|
2011-06-10 15:38:13 +02:00
|
|
|
}
|
2011-05-30 16:37:31 +02:00
|
|
|
return lc->fd;
|
|
|
|
}
|
|
|
|
|
2011-06-10 15:38:13 +02:00
|
|
|
int loopcxt_set_fd(struct loopdev_cxt *lc, int fd, int mode)
|
|
|
|
{
|
|
|
|
if (!lc)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
lc->fd = fd;
|
|
|
|
lc->mode = mode;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
* @flags: LOOPITER_FL_* flags
|
|
|
|
*
|
2020-07-14 14:31:29 +02:00
|
|
|
* Iterator can be used to scan list of the free or used loop devices.
|
2011-05-30 16:37:31 +02:00
|
|
|
*
|
|
|
|
* Returns: <0 on error, 0 on success
|
|
|
|
*/
|
|
|
|
int loopcxt_init_iterator(struct loopdev_cxt *lc, int flags)
|
|
|
|
{
|
|
|
|
struct loopdev_iter *iter;
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if (!lc)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2011-09-29 23:28:36 +02:00
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
iter = &lc->iter;
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(ITER, ul_debugobj(iter, "initialize"));
|
2011-05-30 16:37:31 +02:00
|
|
|
|
|
|
|
/* always zeroize
|
|
|
|
*/
|
|
|
|
memset(iter, 0, sizeof(*iter));
|
|
|
|
iter->ncur = -1;
|
|
|
|
iter->flags = flags;
|
|
|
|
iter->default_check = 1;
|
|
|
|
|
|
|
|
if (!lc->extra_check) {
|
|
|
|
/*
|
|
|
|
* Check for /dev/loop/<N> subdirectory
|
|
|
|
*/
|
2011-09-15 16:17:45 +02:00
|
|
|
if (!(lc->flags & LOOPDEV_FL_DEVSUBDIR) &&
|
2011-05-30 16:37:31 +02:00
|
|
|
stat(_PATH_DEV_LOOP, &st) == 0 && S_ISDIR(st.st_mode))
|
|
|
|
lc->flags |= LOOPDEV_FL_DEVSUBDIR;
|
|
|
|
|
|
|
|
lc->extra_check = 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
*
|
|
|
|
* Returns: <0 on error, 0 on success
|
|
|
|
*/
|
|
|
|
int loopcxt_deinit_iterator(struct loopdev_cxt *lc)
|
|
|
|
{
|
2012-02-02 14:48:03 +01:00
|
|
|
struct loopdev_iter *iter;
|
2011-05-30 16:37:31 +02:00
|
|
|
|
|
|
|
if (!lc)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
iter = &lc->iter;
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(ITER, ul_debugobj(iter, "de-initialize"));
|
2011-05-30 16:37:31 +02:00
|
|
|
|
|
|
|
free(iter->minors);
|
|
|
|
if (iter->proc)
|
|
|
|
fclose(iter->proc);
|
2012-06-12 15:41:47 +02:00
|
|
|
if (iter->sysblock)
|
|
|
|
closedir(iter->sysblock);
|
2016-08-17 12:28:33 +02:00
|
|
|
|
|
|
|
memset(iter, 0, sizeof(*iter));
|
2011-05-30 16:37:31 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Same as loopcxt_set_device, but also checks if the device is
|
2019-01-14 23:40:34 +01:00
|
|
|
* associated with any file.
|
2011-05-30 16:37:31 +02:00
|
|
|
*
|
|
|
|
* Returns: <0 on error, 0 on success, 1 device does not match with
|
|
|
|
* LOOPITER_FL_{USED,FREE} flags.
|
|
|
|
*/
|
|
|
|
static int loopiter_set_device(struct loopdev_cxt *lc, const char *device)
|
|
|
|
{
|
|
|
|
int rc = loopcxt_set_device(lc, device);
|
|
|
|
int used;
|
|
|
|
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (!(lc->iter.flags & LOOPITER_FL_USED) &&
|
|
|
|
!(lc->iter.flags & LOOPITER_FL_FREE))
|
|
|
|
return 0; /* caller does not care about device status */
|
|
|
|
|
2014-05-14 12:53:24 +02:00
|
|
|
if (!is_loopdev(lc->device)) {
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(ITER, ul_debugobj(&lc->iter, "%s does not exist", lc->device));
|
2014-05-14 12:53:24 +02:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(ITER, ul_debugobj(&lc->iter, "%s exist", lc->device));
|
2014-05-14 12:53:24 +02:00
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
used = loopcxt_get_offset(lc, NULL) == 0;
|
|
|
|
|
|
|
|
if ((lc->iter.flags & LOOPITER_FL_USED) && used)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((lc->iter.flags & LOOPITER_FL_FREE) && !used)
|
|
|
|
return 0;
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(ITER, ul_debugobj(&lc->iter, "failed to use %s device", lc->device));
|
|
|
|
|
2012-06-21 10:40:43 +02:00
|
|
|
ignore_result( loopcxt_set_device(lc, NULL) );
|
2011-05-30 16:37:31 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmpnum(const void *p1, const void *p2)
|
|
|
|
{
|
2018-07-23 11:17:28 +02:00
|
|
|
return (((* (const int *) p1) > (* (const int *) p2)) -
|
|
|
|
((* (const int *) p1) < (* (const int *) p2)));
|
2011-05-30 16:37:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The classic scandir() is more expensive and less portable.
|
|
|
|
* We needn't full loop device names -- loop numbers (loop<N>)
|
|
|
|
* are enough.
|
|
|
|
*/
|
|
|
|
static int loop_scandir(const char *dirname, int **ary, int hasprefix)
|
|
|
|
{
|
|
|
|
DIR *dir;
|
|
|
|
struct dirent *d;
|
|
|
|
unsigned int n, count = 0, arylen = 0;
|
|
|
|
|
|
|
|
if (!dirname || !ary)
|
|
|
|
return 0;
|
2014-11-04 14:08:45 +01:00
|
|
|
|
|
|
|
DBG(ITER, ul_debug("scan dir: %s", dirname));
|
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
dir = opendir(dirname);
|
|
|
|
if (!dir)
|
|
|
|
return 0;
|
|
|
|
free(*ary);
|
|
|
|
*ary = NULL;
|
|
|
|
|
|
|
|
while((d = readdir(dir))) {
|
|
|
|
#ifdef _DIRENT_HAVE_D_TYPE
|
|
|
|
if (d->d_type != DT_BLK && d->d_type != DT_UNKNOWN &&
|
|
|
|
d->d_type != DT_LNK)
|
|
|
|
continue;
|
|
|
|
#endif
|
|
|
|
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (hasprefix) {
|
|
|
|
/* /dev/loop<N> */
|
|
|
|
if (sscanf(d->d_name, "loop%u", &n) != 1)
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
/* /dev/loop/<N> */
|
|
|
|
char *end = NULL;
|
|
|
|
|
2014-06-19 01:12:22 +02:00
|
|
|
errno = 0;
|
2011-05-30 16:37:31 +02:00
|
|
|
n = strtol(d->d_name, &end, 10);
|
|
|
|
if (d->d_name == end || (end && *end) || errno)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (n < LOOPDEV_DEFAULT_NNODES)
|
|
|
|
continue; /* ignore loop<0..7> */
|
|
|
|
|
|
|
|
if (count + 1 > arylen) {
|
|
|
|
int *tmp;
|
|
|
|
|
|
|
|
arylen += 1;
|
|
|
|
|
|
|
|
tmp = realloc(*ary, arylen * sizeof(int));
|
|
|
|
if (!tmp) {
|
|
|
|
free(*ary);
|
2016-04-03 18:43:19 +02:00
|
|
|
*ary = NULL;
|
2012-02-01 13:06:34 +01:00
|
|
|
closedir(dir);
|
2011-05-30 16:37:31 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*ary = tmp;
|
|
|
|
}
|
2011-09-12 15:35:33 +02:00
|
|
|
if (*ary)
|
|
|
|
(*ary)[count++] = n;
|
2011-05-30 16:37:31 +02:00
|
|
|
}
|
2011-09-12 15:35:33 +02:00
|
|
|
if (count && *ary)
|
2011-05-30 16:37:31 +02:00
|
|
|
qsort(*ary, count, sizeof(int), cmpnum);
|
|
|
|
|
|
|
|
closedir(dir);
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2012-06-12 15:41:47 +02:00
|
|
|
/*
|
|
|
|
* Set the next *used* loop device according to /proc/partitions.
|
|
|
|
*
|
|
|
|
* Loop devices smaller than 512 bytes are invisible for this function.
|
|
|
|
*/
|
|
|
|
static int loopcxt_next_from_proc(struct loopdev_cxt *lc)
|
|
|
|
{
|
|
|
|
struct loopdev_iter *iter = &lc->iter;
|
|
|
|
char buf[BUFSIZ];
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(ITER, ul_debugobj(iter, "scan /proc/partitions"));
|
2012-06-12 15:41:47 +02:00
|
|
|
|
|
|
|
if (!iter->proc)
|
2013-04-03 16:13:06 +02:00
|
|
|
iter->proc = fopen(_PATH_PROC_PARTITIONS, "r" UL_CLOEXECSTR);
|
2012-06-12 15:41:47 +02:00
|
|
|
if (!iter->proc)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
while (fgets(buf, sizeof(buf), iter->proc)) {
|
|
|
|
unsigned int m;
|
2012-07-09 22:26:27 +02:00
|
|
|
char name[128 + 1];
|
2012-06-12 15:41:47 +02:00
|
|
|
|
|
|
|
|
|
|
|
if (sscanf(buf, " %u %*s %*s %128[^\n ]",
|
|
|
|
&m, name) != 2 || m != LOOPDEV_MAJOR)
|
|
|
|
continue;
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(ITER, ul_debugobj(iter, "checking %s", name));
|
2012-06-12 15:41:47 +02:00
|
|
|
|
|
|
|
if (loopiter_set_device(lc, name) == 0)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the next *used* loop device according to
|
|
|
|
* /sys/block/loopN/loop/backing_file (kernel >= 2.6.37 is required).
|
|
|
|
*
|
|
|
|
* This is preferred method.
|
|
|
|
*/
|
|
|
|
static int loopcxt_next_from_sysfs(struct loopdev_cxt *lc)
|
|
|
|
{
|
|
|
|
struct loopdev_iter *iter = &lc->iter;
|
|
|
|
struct dirent *d;
|
|
|
|
int fd;
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(ITER, ul_debugobj(iter, "scanning /sys/block"));
|
2012-06-12 15:41:47 +02:00
|
|
|
|
|
|
|
if (!iter->sysblock)
|
|
|
|
iter->sysblock = opendir(_PATH_SYS_BLOCK);
|
|
|
|
|
|
|
|
if (!iter->sysblock)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
fd = dirfd(iter->sysblock);
|
|
|
|
|
|
|
|
while ((d = readdir(iter->sysblock))) {
|
misc: fix gcc-7 snprintf warnings -Wformat-truncation
../lib/loopdev.c: In function 'loopcxt_next_from_sysfs':
../lib/loopdev.c:545:32: warning: '/loop/backing_file' directive output may be truncated writing 18 bytes into a region of size between 1 and 256 [-Wformat-truncation=]
snprintf(name, sizeof(name), "%s/loop/backing_file", d->d_name);
^~~~~~~~~~~~~~~~~~~~~~
../lib/loopdev.c:545:3: note: 'snprintf' output between 19 and 274 bytes into a destination of size 256
snprintf(name, sizeof(name), "%s/loop/backing_file", d->d_name);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../lib/sysfs.c: In function 'sysfs_is_partition_dirent':
../lib/sysfs.c:343:31: warning: '/start' directive output may be truncated writing 6 bytes into a region of size between 1 and 256 [-Wformat-truncation=]
snprintf(path, sizeof(path), "%s/start", d->d_name);
^~~~~~~~~~
../lib/sysfs.c:343:2: note: 'snprintf' output between 7 and 262 bytes into a destination of size 256
snprintf(path, sizeof(path), "%s/start", d->d_name);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../lib/sysfs.c: In function 'sysfs_partno_to_devno':
../lib/sysfs.c:372:32: warning: '/partition' directive output may be truncated writing 10 bytes into a region of size between 1 and 256 [-Wformat-truncation=]
snprintf(path, sizeof(path), "%s/partition", d->d_name);
^~~~~~~~~~~~~~
../lib/sysfs.c:372:3: note: 'snprintf' output between 11 and 266 bytes into a destination of size 256
snprintf(path, sizeof(path), "%s/partition", d->d_name);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../lib/sysfs.c:377:33: warning: '/dev' directive output may be truncated writing 4 bytes into a region of size between 1 and 256 [-Wformat-truncation=]
snprintf(path, sizeof(path), "%s/dev", d->d_name);
^~~~~~~~
../lib/sysfs.c:377:4: note: 'snprintf' output between 5 and 260 bytes into a destination of size 256
snprintf(path, sizeof(path), "%s/dev", d->d_name);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Signed-off-by: Ruediger Meier <ruediger.meier@ga-group.nl>
2017-06-11 23:18:21 +02:00
|
|
|
char name[NAME_MAX + 18 + 1];
|
2012-06-12 15:41:47 +02:00
|
|
|
struct stat st;
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(ITER, ul_debugobj(iter, "check %s", d->d_name));
|
2012-06-12 15:41:47 +02:00
|
|
|
|
|
|
|
if (strcmp(d->d_name, ".") == 0
|
|
|
|
|| strcmp(d->d_name, "..") == 0
|
|
|
|
|| strncmp(d->d_name, "loop", 4) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
snprintf(name, sizeof(name), "%s/loop/backing_file", d->d_name);
|
2016-02-29 12:38:58 +01:00
|
|
|
if (fstatat(fd, name, &st, 0) != 0)
|
2012-06-12 15:41:47 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (loopiter_set_device(lc, d->d_name) == 0)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
/*
|
|
|
|
* @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;
|
2011-09-29 23:28:36 +02:00
|
|
|
|
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
iter = &lc->iter;
|
|
|
|
if (iter->done)
|
|
|
|
return 1;
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(ITER, ul_debugobj(iter, "next"));
|
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
/* A) Look for used loop devices in /proc/partitions ("losetup -a" only)
|
|
|
|
*/
|
|
|
|
if (iter->flags & LOOPITER_FL_USED) {
|
2012-06-12 15:41:47 +02:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (loopcxt_sysfs_available(lc))
|
|
|
|
rc = loopcxt_next_from_sysfs(lc);
|
|
|
|
else
|
|
|
|
rc = loopcxt_next_from_proc(lc);
|
|
|
|
if (rc == 0)
|
|
|
|
return 0;
|
2011-05-30 16:37:31 +02:00
|
|
|
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) {
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(ITER, ul_debugobj(iter, "next: default check"));
|
2011-05-30 16:37:31 +02:00
|
|
|
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) {
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(ITER, ul_debugobj(iter, "next: scanning /dev"));
|
2011-05-30 16:37:31 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @device: path to device
|
|
|
|
*/
|
|
|
|
int is_loopdev(const char *device)
|
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
|
2016-08-30 21:00:38 +02:00
|
|
|
if (device && stat(device, &st) == 0 &&
|
2011-05-30 16:37:31 +02:00
|
|
|
S_ISBLK(st.st_mode) &&
|
2016-08-30 21:00:38 +02:00
|
|
|
major(st.st_rdev) == LOOPDEV_MAJOR)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
errno = ENODEV;
|
|
|
|
return 0;
|
2011-05-30 16:37:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
*
|
|
|
|
* Returns result from LOOP_GET_STAT64 ioctl or NULL on error.
|
|
|
|
*/
|
|
|
|
struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
2014-05-14 12:53:24 +02:00
|
|
|
if (!lc || lc->info_failed) {
|
|
|
|
errno = EINVAL;
|
2011-05-30 16:37:31 +02:00
|
|
|
return NULL;
|
2014-05-14 12:53:24 +02:00
|
|
|
}
|
|
|
|
errno = 0;
|
2011-05-30 16:37:31 +02:00
|
|
|
if (lc->has_info)
|
2020-09-30 05:28:30 +02:00
|
|
|
return &lc->config.info;
|
2011-05-30 16:37:31 +02:00
|
|
|
|
|
|
|
fd = loopcxt_get_fd(lc);
|
|
|
|
if (fd < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2020-09-30 05:28:30 +02:00
|
|
|
if (ioctl(fd, LOOP_GET_STATUS64, &lc->config.info) == 0) {
|
2011-05-30 16:37:31 +02:00
|
|
|
lc->has_info = 1;
|
2011-12-20 18:25:04 +01:00
|
|
|
lc->info_failed = 0;
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "reading loop_info64 OK"));
|
2020-09-30 05:28:30 +02:00
|
|
|
return &lc->config.info;
|
2011-05-30 16:37:31 +02:00
|
|
|
}
|
|
|
|
|
2014-05-14 12:53:24 +02:00
|
|
|
lc->info_failed = 1;
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "reading loop_info64 FAILED"));
|
2014-05-14 12:53:24 +02:00
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
*
|
2020-07-09 19:14:32 +02:00
|
|
|
* Returns (allocated) string with path to the file associated
|
2011-05-30 16:37:31 +02:00
|
|
|
* with the current loop device.
|
|
|
|
*/
|
|
|
|
char *loopcxt_get_backing_file(struct loopdev_cxt *lc)
|
|
|
|
{
|
2018-05-15 13:08:47 +02:00
|
|
|
struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
|
2011-05-30 16:37:31 +02:00
|
|
|
char *res = NULL;
|
|
|
|
|
|
|
|
if (sysfs)
|
2011-06-10 15:38:13 +02:00
|
|
|
/*
|
2019-01-14 23:40:34 +01:00
|
|
|
* This is always preferred, the loop_info64
|
2011-06-10 15:38:13 +02:00
|
|
|
* has too small buffer for the filename.
|
|
|
|
*/
|
2018-05-15 13:08:47 +02:00
|
|
|
ul_path_read_string(sysfs, &res, "loop/backing_file");
|
2011-05-30 16:37:31 +02:00
|
|
|
|
|
|
|
if (!res && loopcxt_ioctl_enabled(lc)) {
|
|
|
|
struct loop_info64 *lo = loopcxt_get_info(lc);
|
|
|
|
|
|
|
|
if (lo) {
|
|
|
|
lo->lo_file_name[LO_NAME_SIZE - 2] = '*';
|
|
|
|
lo->lo_file_name[LO_NAME_SIZE - 1] = '\0';
|
|
|
|
res = strdup((char *) lo->lo_file_name);
|
|
|
|
}
|
|
|
|
}
|
2011-09-29 23:28:36 +02:00
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "get_backing_file [%s]", res));
|
2011-05-30 16:37:31 +02:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
* @offset: returns offset number for the given device
|
|
|
|
*
|
|
|
|
* Returns: <0 on error, 0 on success
|
|
|
|
*/
|
|
|
|
int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset)
|
|
|
|
{
|
2018-05-15 13:08:47 +02:00
|
|
|
struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
|
2011-05-30 16:37:31 +02:00
|
|
|
int rc = -EINVAL;
|
|
|
|
|
|
|
|
if (sysfs)
|
2018-05-15 13:08:47 +02:00
|
|
|
rc = ul_path_read_u64(sysfs, offset, "loop/offset");
|
2011-05-30 16:37:31 +02:00
|
|
|
|
|
|
|
if (rc && loopcxt_ioctl_enabled(lc)) {
|
|
|
|
struct loop_info64 *lo = loopcxt_get_info(lc);
|
|
|
|
if (lo) {
|
|
|
|
if (offset)
|
|
|
|
*offset = lo->lo_offset;
|
2011-12-20 18:25:04 +01:00
|
|
|
rc = 0;
|
2014-05-14 12:53:24 +02:00
|
|
|
} else
|
|
|
|
rc = -errno;
|
2011-05-30 16:37:31 +02:00
|
|
|
}
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "get_offset [rc=%d]", rc));
|
2011-05-30 16:37:31 +02:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-09-26 16:14:51 +02:00
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
* @blocksize: returns logical blocksize for the given device
|
|
|
|
*
|
|
|
|
* Returns: <0 on error, 0 on success
|
|
|
|
*/
|
|
|
|
int loopcxt_get_blocksize(struct loopdev_cxt *lc, uint64_t *blocksize)
|
|
|
|
{
|
2018-05-15 13:08:47 +02:00
|
|
|
struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
|
2017-09-26 16:14:51 +02:00
|
|
|
int rc = -EINVAL;
|
|
|
|
|
|
|
|
if (sysfs)
|
2018-05-15 13:08:47 +02:00
|
|
|
rc = ul_path_read_u64(sysfs, blocksize, "queue/logical_block_size");
|
2017-09-26 16:14:51 +02:00
|
|
|
|
|
|
|
/* Fallback based on BLKSSZGET ioctl */
|
|
|
|
if (rc) {
|
|
|
|
int fd = loopcxt_get_fd(lc);
|
|
|
|
int sz = 0;
|
|
|
|
|
|
|
|
if (fd < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
rc = blkdev_get_sector_size(fd, &sz);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
*blocksize = sz;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG(CXT, ul_debugobj(lc, "get_blocksize [rc=%d]", rc));
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-05-30 16:37:31 +02:00
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
* @sizelimit: returns size limit for the given device
|
|
|
|
*
|
|
|
|
* Returns: <0 on error, 0 on success
|
|
|
|
*/
|
|
|
|
int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size)
|
|
|
|
{
|
2018-05-15 13:08:47 +02:00
|
|
|
struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
|
2011-05-30 16:37:31 +02:00
|
|
|
int rc = -EINVAL;
|
|
|
|
|
|
|
|
if (sysfs)
|
2018-05-15 13:08:47 +02:00
|
|
|
rc = ul_path_read_u64(sysfs, size, "loop/sizelimit");
|
2011-05-30 16:37:31 +02:00
|
|
|
|
|
|
|
if (rc && loopcxt_ioctl_enabled(lc)) {
|
|
|
|
struct loop_info64 *lo = loopcxt_get_info(lc);
|
|
|
|
if (lo) {
|
|
|
|
if (size)
|
|
|
|
*size = lo->lo_sizelimit;
|
2011-12-20 18:25:04 +01:00
|
|
|
rc = 0;
|
2014-05-14 12:53:24 +02:00
|
|
|
} else
|
|
|
|
rc = -errno;
|
2011-05-30 16:37:31 +02:00
|
|
|
}
|
|
|
|
|
2014-11-04 14:08:45 +01:00
|
|
|
DBG(CXT, ul_debugobj(lc, "get_sizelimit [rc=%d]", rc));
|
2011-12-20 18:25:04 +01:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @lc: context
|
|
|
|
* @devno: returns encryption type
|
|
|
|
*
|
|
|
|
* Cryptoloop is DEPRECATED!
|
|
|
|
*
|
|
|
|
* Returns: <0 on error, 0 on success
|
|
|
|
*/
|
|
|
|
int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type)
|
|
|
|
{
|
|
|
|
struct loop_info64 *lo = loopcxt_get_info(lc);
|
2014-05-14 12:53:24 +02:00
|
|
|
int rc;
|
2011-12-20 18:25:04 +01:00
|
|
|
|
2014-05-14 12:53:24 +02:00
|
|
|
/* not provided by sysfs */
|
2011-12-20 18:25:04 +01:00
|
|