2006-12-06 17:26:24 -06:00
|
|
|
/* Originally from Ted's losetup.c */
|
2006-12-06 17:25:32 -06:00
|
|
|
/*
|
|
|
|
* losetup.c - setup and control loop devices
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <fcntl.h>
|
2006-12-06 17:25:34 -06:00
|
|
|
#include <errno.h>
|
2006-12-06 17:25:32 -06:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/ioctl.h>
|
2006-12-06 17:25:34 -06:00
|
|
|
#include <sys/stat.h>
|
2006-12-06 17:25:43 -06:00
|
|
|
#include <sys/mman.h>
|
2006-12-06 17:26:05 -06:00
|
|
|
#include <sys/sysmacros.h>
|
2007-12-03 07:17:23 -06:00
|
|
|
#include <inttypes.h>
|
2007-11-23 08:13:22 -06:00
|
|
|
#include <dirent.h>
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
#include "loop.h"
|
|
|
|
#include "lomount.h"
|
2006-12-06 17:25:46 -06:00
|
|
|
#include "xstrncpy.h"
|
2006-12-06 17:25:39 -06:00
|
|
|
#include "nls.h"
|
2007-10-25 03:19:12 -05:00
|
|
|
#include "sundries.h"
|
|
|
|
#include "xmalloc.h"
|
2007-10-25 05:29:51 -05:00
|
|
|
#include "realpath.h"
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2007-03-22 08:22:10 -05:00
|
|
|
#define SIZE(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
#ifdef LOOP_SET_FD
|
2006-12-06 17:26:14 -06:00
|
|
|
|
2007-11-26 04:13:37 -06:00
|
|
|
static int is_associated(int dev, struct stat *file, unsigned long long offset, int isoff);
|
|
|
|
|
2006-12-06 17:26:14 -06:00
|
|
|
static int
|
|
|
|
loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info)
|
|
|
|
{
|
|
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
info->lo_number = info64->lo_number;
|
|
|
|
info->lo_device = info64->lo_device;
|
|
|
|
info->lo_inode = info64->lo_inode;
|
|
|
|
info->lo_rdevice = info64->lo_rdevice;
|
|
|
|
info->lo_offset = info64->lo_offset;
|
|
|
|
info->lo_encrypt_type = info64->lo_encrypt_type;
|
|
|
|
info->lo_encrypt_key_size = info64->lo_encrypt_key_size;
|
|
|
|
info->lo_flags = info64->lo_flags;
|
|
|
|
info->lo_init[0] = info64->lo_init[0];
|
|
|
|
info->lo_init[1] = info64->lo_init[1];
|
|
|
|
if (info->lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
|
|
|
|
memcpy(info->lo_name, info64->lo_crypt_name, LO_NAME_SIZE);
|
|
|
|
else
|
|
|
|
memcpy(info->lo_name, info64->lo_file_name, LO_NAME_SIZE);
|
|
|
|
memcpy(info->lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE);
|
|
|
|
|
|
|
|
/* error in case values were truncated */
|
|
|
|
if (info->lo_device != info64->lo_device ||
|
|
|
|
info->lo_rdevice != info64->lo_rdevice ||
|
|
|
|
info->lo_inode != info64->lo_inode ||
|
|
|
|
info->lo_offset != info64->lo_offset)
|
|
|
|
return -EOVERFLOW;
|
|
|
|
|
|
|
|
return 0;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2007-11-23 08:13:22 -06:00
|
|
|
#define DEV_LOOP_PATH "/dev/loop"
|
|
|
|
#define DEV_PATH "/dev"
|
|
|
|
#define SYSFS_BLOCK_PATH "/sys/block"
|
|
|
|
#define LOOPMAJOR 7
|
|
|
|
#define NLOOPS_DEFAULT 8 /* /dev/loop[0-7] */
|
|
|
|
|
|
|
|
struct looplist {
|
|
|
|
int flag; /* scanning options */
|
|
|
|
int ndef; /* number of tested default devices */
|
|
|
|
struct dirent **names; /* scandir-like list of loop devices */
|
|
|
|
int nnames; /* number of items in names */
|
|
|
|
int ncur; /* current possition in direcotry */
|
|
|
|
char name[32]; /* device name */
|
|
|
|
int ct_perm; /* count permission problems */
|
|
|
|
int ct_succ; /* count number of successfully
|
|
|
|
detected devices */
|
|
|
|
};
|
|
|
|
|
|
|
|
#define LLFLG_USEDONLY (1 << 1) /* return used devices only */
|
|
|
|
#define LLFLG_FREEONLY (1 << 2) /* return non-used devices */
|
|
|
|
#define LLFLG_DONE (1 << 3) /* all is done */
|
|
|
|
#define LLFLG_SYSFS (1 << 4) /* try to use /sys/block */
|
|
|
|
#define LLFLG_SUBDIR (1 << 5) /* /dev/loop/N */
|
|
|
|
#define LLFLG_DFLT (1 << 6) /* directly try to check default loops */
|
|
|
|
|
|
|
|
int
|
|
|
|
is_loop_device (const char *device) {
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
return (stat(device, &st) == 0 &&
|
|
|
|
S_ISBLK(st.st_mode) &&
|
|
|
|
major(st.st_rdev) == LOOPMAJOR);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
is_loop_used(int fd)
|
|
|
|
{
|
|
|
|
struct loop_info li;
|
|
|
|
return ioctl (fd, LOOP_GET_STATUS, &li) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
looplist_mk_devname(struct looplist *ll, int num)
|
|
|
|
{
|
|
|
|
if (ll->flag & LLFLG_SUBDIR)
|
|
|
|
snprintf(ll->name, sizeof(ll->name),
|
|
|
|
DEV_LOOP_PATH "/%d", num);
|
|
|
|
else
|
|
|
|
snprintf(ll->name, sizeof(ll->name),
|
|
|
|
DEV_PATH "/loop%d", num);
|
|
|
|
|
|
|
|
return is_loop_device(ll->name) ? ll->name : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ignores all non-loop devices, default loop devices */
|
|
|
|
static int
|
|
|
|
filter_loop(const struct dirent *d)
|
|
|
|
{
|
|
|
|
return strncmp(d->d_name, "loop", 4) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* all loops exclude default loops */
|
|
|
|
static int
|
|
|
|
filter_loop_ndflt(const struct dirent *d)
|
|
|
|
{
|
|
|
|
int mn;
|
|
|
|
|
|
|
|
if (strncmp(d->d_name, "loop", 4) == 0 &&
|
|
|
|
sscanf(d->d_name, "loop%d", &mn) == 1 &&
|
|
|
|
mn >= NLOOPS_DEFAULT)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
filter_loop_num(const struct dirent *d)
|
|
|
|
{
|
|
|
|
char *end = NULL;
|
|
|
|
int mn = strtol(d->d_name, &end, 10);
|
|
|
|
|
|
|
|
if (mn >= NLOOPS_DEFAULT && end && *end == '\0')
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
looplist_open(struct looplist *ll, int flag)
|
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
memset(ll, 0, sizeof(*ll));
|
|
|
|
ll->flag = flag;
|
|
|
|
ll->ndef = -1;
|
|
|
|
ll->ncur = -1;
|
|
|
|
|
|
|
|
if (stat(DEV_PATH, &st) == -1 || (!S_ISDIR(st.st_mode)))
|
|
|
|
return -1; /* /dev doesn't exist */
|
|
|
|
|
|
|
|
if (stat(DEV_LOOP_PATH, &st) == 0 && S_ISDIR(st.st_mode))
|
|
|
|
ll->flag |= LLFLG_SUBDIR; /* /dev/loop/ exists */
|
|
|
|
|
|
|
|
if ((ll->flag & LLFLG_USEDONLY) &&
|
|
|
|
stat(SYSFS_BLOCK_PATH, &st) == 0 &&
|
|
|
|
S_ISDIR(st.st_mode))
|
|
|
|
ll->flag |= LLFLG_SYSFS; /* try to use /sys/block/loopN */
|
|
|
|
|
|
|
|
ll->flag |= LLFLG_DFLT; /* required! */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
looplist_close(struct looplist *ll)
|
|
|
|
{
|
|
|
|
if (ll->names) {
|
|
|
|
for(++ll->ncur; ll->ncur < ll->nnames; ll->ncur++)
|
|
|
|
free(ll->names[ll->ncur]);
|
|
|
|
|
|
|
|
free(ll->names);
|
|
|
|
ll->names = NULL;
|
|
|
|
ll->nnames = 0;
|
|
|
|
}
|
|
|
|
ll->ncur = -1;
|
|
|
|
ll->flag |= LLFLG_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
looplist_is_wanted(struct looplist *ll, int fd)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!(ll->flag & (LLFLG_USEDONLY | LLFLG_FREEONLY)))
|
|
|
|
return 1;
|
|
|
|
ret = is_loop_used(fd);
|
|
|
|
|
|
|
|
if ((ll->flag & LLFLG_USEDONLY) && ret == 0)
|
|
|
|
return 0;
|
|
|
|
if ((ll->flag & LLFLG_FREEONLY) && ret == 1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
looplist_next(struct looplist *ll)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int ret;
|
|
|
|
char *dirname, *dev;
|
|
|
|
|
|
|
|
if (ll->flag & LLFLG_DONE)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* A) try to use /sys/block/loopN devices (for losetup -a only)
|
|
|
|
*/
|
|
|
|
if (ll->flag & LLFLG_SYSFS) {
|
|
|
|
int mn;
|
|
|
|
|
|
|
|
if (!ll->nnames) {
|
|
|
|
ll->nnames = scandir(SYSFS_BLOCK_PATH, &ll->names,
|
|
|
|
filter_loop, versionsort);
|
|
|
|
ll->ncur = -1;
|
|
|
|
}
|
|
|
|
for(++ll->ncur; ll->ncur < ll->nnames; ll->ncur++) {
|
|
|
|
ret = sscanf(ll->names[ll->ncur]->d_name, "loop%d", &mn);
|
|
|
|
free(ll->names[ll->ncur]);
|
|
|
|
if (ret != 1)
|
|
|
|
continue;
|
|
|
|
dev = looplist_mk_devname(ll, mn);
|
|
|
|
if (dev) {
|
|
|
|
ll->ct_succ++;
|
|
|
|
if ((fd = open(dev, O_RDONLY)) > -1) {
|
|
|
|
if (looplist_is_wanted(ll, fd))
|
|
|
|
return fd;
|
|
|
|
close(fd);
|
|
|
|
} else if (errno == EACCES)
|
|
|
|
ll->ct_perm++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ll->nnames)
|
|
|
|
free(ll->names);
|
|
|
|
ll->names = NULL;
|
|
|
|
ll->ncur = -1;
|
|
|
|
ll->nnames = 0;
|
|
|
|
ll->flag &= ~LLFLG_SYSFS;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* B) Classic way, try first eight loop devices (default number
|
|
|
|
* of loop devices). This is enough for 99% of all cases.
|
|
|
|
*/
|
|
|
|
if (ll->flag & LLFLG_DFLT) {
|
|
|
|
for (++ll->ncur; ll->ncur < NLOOPS_DEFAULT; ll->ncur++) {
|
|
|
|
dev = looplist_mk_devname(ll, ll->ncur);
|
|
|
|
if (dev) {
|
|
|
|
ll->ct_succ++;
|
|
|
|
if ((fd = open(dev, O_RDONLY)) > -1) {
|
|
|
|
if (looplist_is_wanted(ll, fd))
|
|
|
|
return fd;
|
|
|
|
close(fd);
|
|
|
|
} else if (errno == EACCES)
|
|
|
|
ll->ct_perm++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ll->flag &= ~LLFLG_DFLT;
|
|
|
|
ll->ncur = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* C) the worst posibility, scan all /dev or /dev/loop
|
|
|
|
*/
|
|
|
|
dirname = ll->flag & LLFLG_SUBDIR ? DEV_LOOP_PATH : DEV_PATH;
|
|
|
|
|
|
|
|
if (!ll->nnames) {
|
|
|
|
ll->nnames = scandir(dirname, &ll->names,
|
|
|
|
ll->flag & LLFLG_SUBDIR ?
|
|
|
|
filter_loop_num : filter_loop_ndflt,
|
|
|
|
versionsort);
|
|
|
|
ll->ncur = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(++ll->ncur; ll->ncur < ll->nnames; ll->ncur++) {
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
snprintf(ll->name, sizeof(ll->name),
|
|
|
|
"%s/%s", dirname, ll->names[ll->ncur]->d_name);
|
|
|
|
free(ll->names[ll->ncur]);
|
|
|
|
ret = stat(ll->name, &st);
|
|
|
|
|
|
|
|
if (ret == 0 && S_ISBLK(st.st_mode) &&
|
|
|
|
major(st.st_rdev) == LOOPMAJOR &&
|
|
|
|
minor(st.st_rdev) >= NLOOPS_DEFAULT) {
|
|
|
|
ll->ct_succ++;
|
|
|
|
fd = open(ll->name, O_RDONLY);
|
|
|
|
|
|
|
|
if (fd != -1) {
|
|
|
|
if (looplist_is_wanted(ll, fd))
|
|
|
|
return fd;
|
|
|
|
close(fd);
|
|
|
|
} else if (errno == EACCES)
|
|
|
|
ll->ct_perm++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
looplist_close(ll);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
#ifdef MAIN
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:44 -06:00
|
|
|
static int
|
2007-11-23 08:13:22 -06:00
|
|
|
show_loop_fd(int fd, char *device) {
|
2006-12-06 17:25:43 -06:00
|
|
|
struct loop_info loopinfo;
|
2006-12-06 17:26:14 -06:00
|
|
|
struct loop_info64 loopinfo64;
|
2007-11-23 08:13:22 -06:00
|
|
|
int errsv;
|
2006-12-06 17:26:14 -06:00
|
|
|
|
|
|
|
if (ioctl(fd, LOOP_GET_STATUS64, &loopinfo64) == 0) {
|
|
|
|
|
|
|
|
loopinfo64.lo_file_name[LO_NAME_SIZE-2] = '*';
|
|
|
|
loopinfo64.lo_file_name[LO_NAME_SIZE-1] = 0;
|
|
|
|
loopinfo64.lo_crypt_name[LO_NAME_SIZE-1] = 0;
|
|
|
|
|
2007-12-03 07:17:23 -06:00
|
|
|
printf("%s: [%04" PRIx64 "]:%" PRIu64 " (%s)",
|
2006-12-06 17:26:14 -06:00
|
|
|
device, loopinfo64.lo_device, loopinfo64.lo_inode,
|
|
|
|
loopinfo64.lo_file_name);
|
|
|
|
|
|
|
|
if (loopinfo64.lo_offset)
|
2007-12-03 07:17:23 -06:00
|
|
|
printf(_(", offset %" PRIu64 ), loopinfo64.lo_offset);
|
2006-12-06 17:26:14 -06:00
|
|
|
|
|
|
|
if (loopinfo64.lo_sizelimit)
|
2007-12-03 07:17:23 -06:00
|
|
|
printf(_(", sizelimit %" PRIu64 ), loopinfo64.lo_sizelimit);
|
2006-12-06 17:26:14 -06:00
|
|
|
|
|
|
|
if (loopinfo64.lo_encrypt_type ||
|
|
|
|
loopinfo64.lo_crypt_name[0]) {
|
2007-10-08 11:59:18 -05:00
|
|
|
char *e = (char *)loopinfo64.lo_crypt_name;
|
2006-12-06 17:26:14 -06:00
|
|
|
|
|
|
|
if (*e == 0 && loopinfo64.lo_encrypt_type == 1)
|
|
|
|
e = "XOR";
|
2007-12-03 07:17:23 -06:00
|
|
|
printf(_(", encryption %s (type %" PRIu32 ")"),
|
2006-12-06 17:26:14 -06:00
|
|
|
e, loopinfo64.lo_encrypt_type);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
return 0;
|
2006-12-06 17:26:12 -06:00
|
|
|
}
|
2006-12-06 17:26:13 -06:00
|
|
|
|
2006-12-06 17:26:14 -06:00
|
|
|
if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) == 0) {
|
|
|
|
printf ("%s: [%04x]:%ld (%s)",
|
2007-10-08 11:59:18 -05:00
|
|
|
device, (unsigned int)loopinfo.lo_device, loopinfo.lo_inode,
|
2006-12-06 17:26:14 -06:00
|
|
|
loopinfo.lo_name);
|
|
|
|
|
|
|
|
if (loopinfo.lo_offset)
|
|
|
|
printf(_(", offset %d"), loopinfo.lo_offset);
|
|
|
|
|
|
|
|
if (loopinfo.lo_encrypt_type)
|
|
|
|
printf(_(", encryption type %d\n"),
|
|
|
|
loopinfo.lo_encrypt_type);
|
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
errsv = errno;
|
|
|
|
fprintf(stderr, _("loop: can't get info on device %s: %s\n"),
|
|
|
|
device, strerror (errsv));
|
|
|
|
return 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2007-03-22 08:22:10 -05:00
|
|
|
|
2007-11-23 08:13:22 -06:00
|
|
|
static int
|
|
|
|
show_loop(char *device) {
|
|
|
|
int ret, fd;
|
|
|
|
|
|
|
|
if ((fd = open(device, O_RDONLY)) < 0) {
|
|
|
|
int errsv = errno;
|
|
|
|
fprintf(stderr, _("loop: can't open device %s: %s\n"),
|
|
|
|
device, strerror (errsv));
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
ret = show_loop_fd(fd, device);
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-22 08:22:10 -05:00
|
|
|
static int
|
|
|
|
show_used_loop_devices (void) {
|
2007-11-23 08:13:22 -06:00
|
|
|
struct looplist ll;
|
|
|
|
int fd;
|
2007-03-22 08:22:10 -05:00
|
|
|
|
2007-11-23 08:13:22 -06:00
|
|
|
if (looplist_open(&ll, LLFLG_USEDONLY) == -1) {
|
|
|
|
error(_("%s: /dev directory does not exist."), progname);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while((fd = looplist_next(&ll)) != -1) {
|
|
|
|
show_loop_fd(fd, ll.name);
|
|
|
|
close(fd);
|
2007-03-22 08:22:10 -05:00
|
|
|
}
|
2007-11-23 08:13:22 -06:00
|
|
|
looplist_close(&ll);
|
2007-03-22 08:22:10 -05:00
|
|
|
|
2007-11-23 08:13:22 -06:00
|
|
|
if (ll.ct_succ && ll.ct_perm) {
|
2007-03-22 08:22:10 -05:00
|
|
|
error(_("%s: no permission to look at /dev/loop#"), progname);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-11-26 04:13:37 -06:00
|
|
|
/* list all associated loop devices */
|
|
|
|
static int
|
|
|
|
show_associated_loop_devices(char *filename, unsigned long long offset, int isoff)
|
|
|
|
{
|
|
|
|
struct looplist ll;
|
|
|
|
struct stat filestat;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (stat(filename, &filestat) == -1) {
|
|
|
|
perror(filename);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (looplist_open(&ll, LLFLG_USEDONLY) == -1) {
|
|
|
|
error(_("%s: /dev directory does not exist."), progname);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while((fd = looplist_next(&ll)) != -1) {
|
|
|
|
if (is_associated(fd, &filestat, offset, isoff) == 1)
|
|
|
|
show_loop_fd(fd, ll.name);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
looplist_close(&ll);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-11-23 08:13:22 -06:00
|
|
|
#endif /* MAIN */
|
2006-12-06 17:25:34 -06:00
|
|
|
|
2007-09-11 07:35:34 -05:00
|
|
|
/* check if the loopfile is already associated with the same given
|
|
|
|
* parameters.
|
|
|
|
*
|
|
|
|
* returns: -1 error
|
|
|
|
* 0 unused
|
|
|
|
* 1 loop device already used
|
|
|
|
*/
|
|
|
|
static int
|
2007-11-26 04:13:37 -06:00
|
|
|
is_associated(int dev, struct stat *file, unsigned long long offset, int isoff)
|
2007-09-11 07:35:34 -05:00
|
|
|
{
|
|
|
|
struct loop_info64 linfo64;
|
|
|
|
struct loop_info64 linfo;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (ioctl(dev, LOOP_GET_STATUS64, &linfo64) == 0) {
|
|
|
|
if (file->st_dev == linfo64.lo_device &&
|
|
|
|
file->st_ino == linfo64.lo_inode &&
|
2007-11-26 04:13:37 -06:00
|
|
|
(isoff == 0 || offset == linfo64.lo_offset))
|
2007-09-11 07:35:34 -05:00
|
|
|
ret = 1;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (ioctl(dev, LOOP_GET_STATUS, &linfo) == 0) {
|
|
|
|
if (file->st_dev == linfo.lo_device &&
|
|
|
|
file->st_ino == linfo.lo_inode &&
|
2007-11-26 04:13:37 -06:00
|
|
|
(isoff == 0 || offset == linfo.lo_offset))
|
2007-09-11 07:35:34 -05:00
|
|
|
ret = 1;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return errno == ENXIO ? 0 : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if the loop file is already used with the same given
|
|
|
|
* parameters. We check for device no, inode and offset.
|
|
|
|
* returns: associated devname or NULL
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
loopfile_used (const char *filename, unsigned long long offset) {
|
2007-11-23 08:13:22 -06:00
|
|
|
struct looplist ll;
|
|
|
|
char *devname = NULL;
|
|
|
|
struct stat filestat;
|
|
|
|
int fd;
|
2007-09-11 07:35:34 -05:00
|
|
|
|
|
|
|
if (stat(filename, &filestat) == -1) {
|
|
|
|
perror(filename);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-11-23 08:13:22 -06:00
|
|
|
if (looplist_open(&ll, LLFLG_USEDONLY) == -1) {
|
|
|
|
error(_("%s: /dev directory does not exist."), progname);
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-09-11 07:35:34 -05:00
|
|
|
|
2007-11-23 08:13:22 -06:00
|
|
|
while((fd = looplist_next(&ll)) != -1) {
|
2007-11-26 04:13:37 -06:00
|
|
|
int res = is_associated(fd, &filestat, offset, 1);
|
2007-11-23 08:13:22 -06:00
|
|
|
close(fd);
|
|
|
|
if (res == 1) {
|
|
|
|
devname = xstrdup(ll.name);
|
|
|
|
break;
|
2007-09-11 07:35:34 -05:00
|
|
|
}
|
|
|
|
}
|
2007-11-23 08:13:22 -06:00
|
|
|
looplist_close(&ll);
|
|
|
|
|
|
|
|
return devname;
|
2007-09-11 07:35:34 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
loopfile_used_with(char *devname, const char *filename, unsigned long long offset)
|
|
|
|
{
|
|
|
|
struct stat statbuf;
|
|
|
|
int fd, ret;
|
|
|
|
|
|
|
|
if (!is_loop_device(devname))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (stat(filename, &statbuf) == -1) {
|
|
|
|
perror(filename);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = open(devname, O_RDONLY);
|
|
|
|
if (fd == -1) {
|
|
|
|
perror(devname);
|
|
|
|
return -1;
|
|
|
|
}
|
2007-11-26 04:13:37 -06:00
|
|
|
ret = is_associated(fd, &statbuf, offset, 1);
|
2007-09-11 07:35:34 -05:00
|
|
|
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
char *
|
2006-12-06 17:25:43 -06:00
|
|
|
find_unused_loop_device (void) {
|
2007-11-23 08:13:22 -06:00
|
|
|
struct looplist ll;
|
|
|
|
char *devname = NULL;
|
|
|
|
int fd;
|
2006-12-06 17:25:43 -06:00
|
|
|
|
2007-11-23 08:13:22 -06:00
|
|
|
if (looplist_open(&ll, LLFLG_FREEONLY) == -1) {
|
|
|
|
error(_("%s: /dev directory does not exist."), progname);
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-12-06 17:26:26 -06:00
|
|
|
|
2007-11-23 08:13:22 -06:00
|
|
|
if ((fd = looplist_next(&ll)) != -1) {
|
|
|
|
close(fd);
|
|
|
|
devname = xstrdup(ll.name);
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
2007-11-23 08:13:22 -06:00
|
|
|
looplist_close(&ll);
|
|
|
|
if (devname)
|
|
|
|
return devname;
|
2006-12-06 17:25:43 -06:00
|
|
|
|
2007-11-23 08:13:22 -06:00
|
|
|
if (ll.ct_succ && ll.ct_perm)
|
2006-12-06 17:26:26 -06:00
|
|
|
error(_("%s: no permission to look at /dev/loop#"), progname);
|
2007-11-23 08:13:22 -06:00
|
|
|
else if (ll.ct_succ)
|
|
|
|
error(_("%s: could not find any free loop device"), progname);
|
|
|
|
else
|
2006-12-06 17:25:43 -06:00
|
|
|
error(_(
|
2006-12-06 17:26:24 -06:00
|
|
|
"%s: Could not find any loop device. Maybe this kernel "
|
2006-12-06 17:26:14 -06:00
|
|
|
"does not know\n"
|
|
|
|
" about the loop device? (If so, recompile or "
|
2006-12-06 17:26:24 -06:00
|
|
|
"`modprobe loop'.)"), progname);
|
2007-11-23 08:13:22 -06:00
|
|
|
return NULL;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:26:14 -06:00
|
|
|
/*
|
|
|
|
* A function to read the passphrase either from the terminal or from
|
|
|
|
* an open file descriptor.
|
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
xgetpass(int pfd, const char *prompt) {
|
|
|
|
char *pass;
|
|
|
|
int buflen, i;
|
|
|
|
|
|
|
|
if (pfd < 0) /* terminal */
|
|
|
|
return getpass(prompt);
|
|
|
|
|
|
|
|
pass = NULL;
|
|
|
|
buflen = 0;
|
|
|
|
for (i=0; ; i++) {
|
|
|
|
if (i >= buflen-1) {
|
|
|
|
/* we're running out of space in the buffer.
|
|
|
|
* Make it bigger: */
|
|
|
|
char *tmppass = pass;
|
|
|
|
buflen += 128;
|
|
|
|
pass = realloc(tmppass, buflen);
|
|
|
|
if (pass == NULL) {
|
|
|
|
/* realloc failed. Stop reading. */
|
|
|
|
error("Out of memory while reading passphrase");
|
|
|
|
pass = tmppass; /* the old buffer hasn't changed */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-12-06 17:26:24 -06:00
|
|
|
if (read(pfd, pass+i, 1) != 1 ||
|
|
|
|
pass[i] == '\n' || pass[i] == 0)
|
2006-12-06 17:26:14 -06:00
|
|
|
break;
|
|
|
|
}
|
2006-12-06 17:26:24 -06:00
|
|
|
|
2006-12-06 17:26:14 -06:00
|
|
|
if (pass == NULL)
|
|
|
|
return "";
|
2006-12-06 17:26:24 -06:00
|
|
|
|
|
|
|
pass[i] = 0;
|
|
|
|
return pass;
|
2006-12-06 17:26:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
digits_only(const char *s) {
|
|
|
|
while (*s)
|
|
|
|
if (!isdigit(*s++))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
int
|
2006-12-06 17:26:16 -06:00
|
|
|
set_loop(const char *device, const char *file, unsigned long long offset,
|
2008-04-15 05:57:35 -05:00
|
|
|
unsigned long long sizelimit, const char *encryption, int pfd, int *options) {
|
2006-12-06 17:26:14 -06:00
|
|
|
struct loop_info64 loopinfo64;
|
2006-12-06 17:26:31 -06:00
|
|
|
int fd, ffd, mode, i;
|
2006-12-06 17:25:43 -06:00
|
|
|
char *pass;
|
2007-10-25 05:29:51 -05:00
|
|
|
char *filename;
|
2006-12-06 17:25:43 -06:00
|
|
|
|
2007-09-11 07:35:34 -05:00
|
|
|
if (verbose) {
|
|
|
|
char *xdev = loopfile_used(file, offset);
|
|
|
|
|
|
|
|
if (xdev) {
|
|
|
|
printf(_("warning: %s is already associated with %s\n"),
|
|
|
|
file, xdev);
|
|
|
|
free(xdev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-28 21:47:33 -05:00
|
|
|
mode = (*options & SETLOOP_RDONLY) ? O_RDONLY : O_RDWR;
|
2006-12-06 17:26:14 -06:00
|
|
|
if ((ffd = open(file, mode)) < 0) {
|
2007-10-28 21:47:33 -05:00
|
|
|
if (!(*options & SETLOOP_RDONLY) && errno == EROFS)
|
2006-12-06 17:26:14 -06:00
|
|
|
ffd = open(file, mode = O_RDONLY);
|
2006-12-06 17:25:43 -06:00
|
|
|
if (ffd < 0) {
|
2006-12-06 17:26:14 -06:00
|
|
|
perror(file);
|
2006-12-06 17:25:43 -06:00
|
|
|
return 1;
|
|
|
|
}
|
2007-10-28 21:47:33 -05:00
|
|
|
*options |= SETLOOP_RDONLY;
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
2006-12-06 17:26:14 -06:00
|
|
|
if ((fd = open(device, mode)) < 0) {
|
2006-12-06 17:25:43 -06:00
|
|
|
perror (device);
|
2007-11-21 09:46:33 -06:00
|
|
|
close(ffd);
|
2006-12-06 17:25:43 -06:00
|
|
|
return 1;
|
|
|
|
}
|
2006-12-06 17:26:14 -06:00
|
|
|
memset(&loopinfo64, 0, sizeof(loopinfo64));
|
|
|
|
|
2007-10-25 05:29:51 -05:00
|
|
|
if (!(filename = canonicalize(file)))
|
|
|
|
filename = (char *) file;
|
|
|
|
xstrncpy((char *)loopinfo64.lo_file_name, filename, LO_NAME_SIZE);
|
2006-12-06 17:26:14 -06:00
|
|
|
|
|
|
|
if (encryption && *encryption) {
|
|
|
|
if (digits_only(encryption)) {
|
|
|
|
loopinfo64.lo_encrypt_type = atoi(encryption);
|
|
|
|
} else {
|
|
|
|
loopinfo64.lo_encrypt_type = LO_CRYPT_CRYPTOAPI;
|
2007-10-08 11:59:18 -05:00
|
|
|
snprintf((char *)loopinfo64.lo_crypt_name, LO_NAME_SIZE,
|
2006-12-06 17:26:14 -06:00
|
|
|
"%s", encryption);
|
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
2006-12-06 17:26:14 -06:00
|
|
|
|
|
|
|
loopinfo64.lo_offset = offset;
|
2008-04-15 05:57:35 -05:00
|
|
|
loopinfo64.lo_sizelimit = sizelimit;
|
2006-12-06 17:25:43 -06:00
|
|
|
|
2007-05-08 06:52:18 -05:00
|
|
|
#ifdef MCL_FUTURE
|
2006-12-06 17:25:43 -06:00
|
|
|
/*
|
|
|
|
* Oh-oh, sensitive data coming up. Better lock into memory to prevent
|
|
|
|
* passwd etc being swapped out and left somewhere on disk.
|
|
|
|
*/
|
2007-05-08 06:52:18 -05:00
|
|
|
if (loopinfo64.lo_encrypt_type != LO_CRYPT_NONE) {
|
|
|
|
if(mlockall(MCL_CURRENT | MCL_FUTURE)) {
|
|
|
|
perror("memlock");
|
|
|
|
fprintf(stderr, _("Couldn't lock into memory, exiting.\n"));
|
|
|
|
exit(1);
|
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-12-06 17:26:14 -06:00
|
|
|
switch (loopinfo64.lo_encrypt_type) {
|
2006-12-06 17:25:43 -06:00
|
|
|
case LO_CRYPT_NONE:
|
2006-12-06 17:26:14 -06:00
|
|
|
loopinfo64.lo_encrypt_key_size = 0;
|
2006-12-06 17:25:43 -06:00
|
|
|
break;
|
|
|
|
case LO_CRYPT_XOR:
|
2006-12-06 17:26:14 -06:00
|
|
|
pass = getpass(_("Password: "));
|
2006-12-06 17:26:24 -06:00
|
|
|
goto gotpass;
|
2006-12-06 17:25:43 -06:00
|
|
|
default:
|
2006-12-06 17:26:14 -06:00
|
|
|
pass = xgetpass(pfd, _("Password: "));
|
2006-12-06 17:26:24 -06:00
|
|
|
gotpass:
|
2006-12-06 17:26:31 -06:00
|
|
|
memset(loopinfo64.lo_encrypt_key, 0, LO_KEY_SIZE);
|
2007-10-08 11:59:18 -05:00
|
|
|
xstrncpy((char *)loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE);
|
2006-12-06 17:26:31 -06:00
|
|
|
memset(pass, 0, strlen(pass));
|
|
|
|
loopinfo64.lo_encrypt_key_size = LO_KEY_SIZE;
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
2006-12-06 17:26:14 -06:00
|
|
|
|
|
|
|
if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
|
2007-10-25 05:10:31 -05:00
|
|
|
int rc = 1;
|
|
|
|
|
2007-06-20 08:17:45 -05:00
|
|
|
if (errno == EBUSY) {
|
|
|
|
if (verbose)
|
2007-10-25 05:10:31 -05:00
|
|
|
printf(_("ioctl LOOP_SET_FD failed: %s\n"),
|
|
|
|
strerror(errno));
|
|
|
|
rc = 2;
|
|
|
|
} else
|
2007-06-20 08:17:45 -05:00
|
|
|
perror("ioctl: LOOP_SET_FD");
|
2007-10-25 05:10:31 -05:00
|
|
|
|
|
|
|
close(fd);
|
|
|
|
close(ffd);
|
2007-10-25 05:29:51 -05:00
|
|
|
if (file != filename)
|
|
|
|
free(filename);
|
2007-10-25 05:10:31 -05:00
|
|
|
return rc;
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
2006-12-06 17:26:14 -06:00
|
|
|
close (ffd);
|
|
|
|
|
2007-10-28 21:47:33 -05:00
|
|
|
if (*options & SETLOOP_AUTOCLEAR)
|
|
|
|
loopinfo64.lo_flags = LO_FLAGS_AUTOCLEAR;
|
|
|
|
|
2006-12-06 17:26:19 -06:00
|
|
|
i = ioctl(fd, LOOP_SET_STATUS64, &loopinfo64);
|
|
|
|
if (i) {
|
2006-12-06 17:26:14 -06:00
|
|
|
struct loop_info loopinfo;
|
|
|
|
int errsv = errno;
|
|
|
|
|
2006-12-06 17:26:19 -06:00
|
|
|
i = loop_info64_to_old(&loopinfo64, &loopinfo);
|
|
|
|
if (i) {
|
2006-12-06 17:26:14 -06:00
|
|
|
errno = errsv;
|
2007-10-28 21:47:33 -05:00
|
|
|
*options &= ~SETLOOP_AUTOCLEAR;
|
2006-12-06 17:26:14 -06:00
|
|
|
perror("ioctl: LOOP_SET_STATUS64");
|
2006-12-06 17:26:19 -06:00
|
|
|
} else {
|
|
|
|
i = ioctl(fd, LOOP_SET_STATUS, &loopinfo);
|
|
|
|
if (i)
|
|
|
|
perror("ioctl: LOOP_SET_STATUS");
|
2007-10-28 21:47:33 -05:00
|
|
|
else if (*options & SETLOOP_AUTOCLEAR)
|
|
|
|
{
|
|
|
|
i = ioctl(fd, LOOP_GET_STATUS, &loopinfo);
|
|
|
|
if (i || !(loopinfo.lo_flags & LO_FLAGS_AUTOCLEAR))
|
|
|
|
*options &= ~SETLOOP_AUTOCLEAR;
|
|
|
|
}
|
2006-12-06 17:26:14 -06:00
|
|
|
}
|
2006-12-06 17:26:19 -06:00
|
|
|
memset(&loopinfo, 0, sizeof(loopinfo));
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
2007-10-28 21:47:33 -05:00
|
|
|
else if (*options & SETLOOP_AUTOCLEAR)
|
|
|
|
{
|
|
|
|
i = ioctl(fd, LOOP_GET_STATUS64, &loopinfo64);
|
|
|
|
if (i || !(loopinfo64.lo_flags & LO_FLAGS_AUTOCLEAR))
|
|
|
|
*options &= ~SETLOOP_AUTOCLEAR;
|
|
|
|
}
|
2006-12-06 17:26:19 -06:00
|
|
|
memset(&loopinfo64, 0, sizeof(loopinfo64));
|
2006-12-06 17:26:14 -06:00
|
|
|
|
2007-10-28 21:47:33 -05:00
|
|
|
|
2006-12-06 17:26:19 -06:00
|
|
|
if (i) {
|
|
|
|
ioctl (fd, LOOP_CLR_FD, 0);
|
|
|
|
close (fd);
|
2007-10-25 05:29:51 -05:00
|
|
|
if (file != filename)
|
|
|
|
free(filename);
|
2006-12-06 17:26:19 -06:00
|
|
|
return 1;
|
|
|
|
}
|
2007-10-28 21:47:33 -05:00
|
|
|
|
|
|
|
/*
|
|
|
|
* HACK: here we're leeking a file descriptor,
|
|
|
|
* but mount is a short-lived process anyway.
|
|
|
|
*/
|
|
|
|
if (!(*options & SETLOOP_AUTOCLEAR))
|
|
|
|
close (fd);
|
2006-12-06 17:26:19 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
if (verbose > 1)
|
2008-04-15 05:57:35 -05:00
|
|
|
printf(_("set_loop(%s,%s,%llu,%llu): success\n"),
|
|
|
|
device, filename, offset, sizelimit);
|
2007-10-25 05:29:51 -05:00
|
|
|
if (file != filename)
|
|
|
|
free(filename);
|
2006-12-06 17:25:43 -06:00
|
|
|
return 0;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2007-10-25 05:10:31 -05:00
|
|
|
int
|
2006-12-06 17:25:43 -06:00
|
|
|
del_loop (const char *device) {
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if ((fd = open (device, O_RDONLY)) < 0) {
|
|
|
|
int errsv = errno;
|
|
|
|
fprintf(stderr, _("loop: can't delete device %s: %s\n"),
|
|
|
|
device, strerror (errsv));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (ioctl (fd, LOOP_CLR_FD, 0) < 0) {
|
|
|
|
perror ("ioctl: LOOP_CLR_FD");
|
2007-08-21 08:13:43 -05:00
|
|
|
close(fd);
|
2006-12-06 17:25:43 -06:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
close (fd);
|
|
|
|
if (verbose > 1)
|
|
|
|
printf(_("del_loop(%s): success\n"), device);
|
|
|
|
return 0;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
#else /* no LOOP_SET_FD defined */
|
|
|
|
static void
|
|
|
|
mutter(void) {
|
2006-12-06 17:25:43 -06:00
|
|
|
fprintf(stderr,
|
|
|
|
_("This mount was compiled without loop support. "
|
|
|
|
"Please recompile.\n"));
|
2007-11-23 08:13:22 -06:00
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:34 -06:00
|
|
|
int
|
2008-04-15 05:57:35 -05:00
|
|
|
set_loop(const char *device, const char *file, unsigned long long offset,
|
|
|
|
unsigned long long sizelimit, const char *encryption, int pfd, int *loopro,
|
|
|
|
int keysz, int hash_pass) {
|
2006-12-06 17:25:43 -06:00
|
|
|
mutter();
|
|
|
|
return 1;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
del_loop (const char *device) {
|
2006-12-06 17:25:43 -06:00
|
|
|
mutter();
|
|
|
|
return 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2006-12-06 17:25:34 -06:00
|
|
|
|
|
|
|
char *
|
|
|
|
find_unused_loop_device (void) {
|
2006-12-06 17:25:43 -06:00
|
|
|
mutter();
|
|
|
|
return 0;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
|
2007-11-23 08:13:22 -06:00
|
|
|
#endif /* !LOOP_SET_FD */
|
2006-12-06 17:25:43 -06:00
|
|
|
|
|
|
|
#ifdef MAIN
|
|
|
|
|
|
|
|
#ifdef LOOP_SET_FD
|
|
|
|
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
static void
|
|
|
|
usage(void) {
|
2007-06-27 10:32:51 -05:00
|
|
|
fprintf(stderr, _("\nUsage:\n"
|
2007-11-26 04:13:37 -06:00
|
|
|
" %1$s loop_device give info\n"
|
|
|
|
" %1$s -a | --all list all used\n"
|
|
|
|
" %1$s -d | --detach <loopdev> delete\n"
|
|
|
|
" %1$s -f | --find find unused\n"
|
|
|
|
" %1$s -j | --associated <file> [-o <num>] list all associated with <file>\n"
|
|
|
|
" %1$s [ options ] {-f|--find|loopdev} <file> setup\n"
|
2007-06-27 10:32:51 -05:00
|
|
|
"\nOptions:\n"
|
|
|
|
" -e | --encryption <type> enable data encryption with specified <name/num>\n"
|
|
|
|
" -h | --help this help\n"
|
|
|
|
" -o | --offset <num> start at offset <num> into file\n"
|
2008-04-15 05:57:35 -05:00
|
|
|
" --sizelimit <num> loop limited to only <num> bytes of the file\n"
|
2007-06-27 10:32:51 -05:00
|
|
|
" -p | --pass-fd <num> read passphrase from file descriptor <num>\n"
|
|
|
|
" -r | --read-only setup read-only loop device\n"
|
|
|
|
" -s | --show print device name (with -f <file>)\n"
|
|
|
|
" -v | --verbose verbose mode\n\n"),
|
2007-03-22 08:22:10 -05:00
|
|
|
progname);
|
2006-12-06 17:25:43 -06:00
|
|
|
exit(1);
|
2007-06-27 10:32:51 -05:00
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char **argv) {
|
2008-04-15 05:57:35 -05:00
|
|
|
char *p, *offset, *sizelimit, *encryption, *passfd, *device, *file, *assoc;
|
2007-03-22 08:22:10 -05:00
|
|
|
int delete, find, c, all;
|
2006-12-06 17:25:43 -06:00
|
|
|
int res = 0;
|
2007-06-18 08:44:02 -05:00
|
|
|
int showdev = 0;
|
2006-12-06 17:25:43 -06:00
|
|
|
int ro = 0;
|
2006-12-06 17:26:14 -06:00
|
|
|
int pfd = -1;
|
2008-04-15 05:57:35 -05:00
|
|
|
unsigned long long off, slimit;
|
2007-06-27 10:32:51 -05:00
|
|
|
struct option longopts[] = {
|
|
|
|
{ "all", 0, 0, 'a' },
|
|
|
|
{ "detach", 0, 0, 'd' },
|
|
|
|
{ "encryption", 1, 0, 'e' },
|
|
|
|
{ "find", 0, 0, 'f' },
|
|
|
|
{ "help", 0, 0, 'h' },
|
2007-11-26 04:13:37 -06:00
|
|
|
{ "associated", 1, 0, 'j' },
|
2007-06-27 10:32:51 -05:00
|
|
|
{ "offset", 1, 0, 'o' },
|
2008-04-15 05:57:35 -05:00
|
|
|
{ "sizelimit", 1, 0, 128 },
|
2007-06-27 10:32:51 -05:00
|
|
|
{ "pass-fd", 1, 0, 'p' },
|
|
|
|
{ "read-only", 0, 0, 'r' },
|
|
|
|
{ "show", 0, 0, 's' },
|
|
|
|
{ "verbose", 0, 0, 'v' },
|
|
|
|
{ NULL, 0, 0, 0 }
|
|
|
|
};
|
2006-12-06 17:25:43 -06:00
|
|
|
|
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
|
|
textdomain(PACKAGE);
|
|
|
|
|
2007-03-22 08:22:10 -05:00
|
|
|
delete = find = all = 0;
|
2006-12-06 17:26:24 -06:00
|
|
|
off = 0;
|
2008-04-15 05:57:35 -05:00
|
|
|
slimit = 0;
|
|
|
|
assoc = offset = sizelimit = encryption = passfd = NULL;
|
2006-12-06 17:26:24 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
progname = argv[0];
|
2006-12-06 17:26:24 -06:00
|
|
|
if ((p = strrchr(progname, '/')) != NULL)
|
|
|
|
progname = p+1;
|
|
|
|
|
2007-11-26 04:13:37 -06:00
|
|
|
while ((c = getopt_long(argc, argv, "ade:E:fhj:o:p:rsv",
|
2007-06-27 10:32:51 -05:00
|
|
|
longopts, NULL)) != -1) {
|
2006-12-06 17:25:43 -06:00
|
|
|
switch (c) {
|
2007-03-22 08:22:10 -05:00
|
|
|
case 'a':
|
|
|
|
all = 1;
|
|
|
|
break;
|
2007-03-22 14:54:07 -05:00
|
|
|
case 'r':
|
|
|
|
ro = 1;
|
|
|
|
break;
|
2006-12-06 17:25:43 -06:00
|
|
|
case 'd':
|
|
|
|
delete = 1;
|
|
|
|
break;
|
2006-12-06 17:26:14 -06:00
|
|
|
case 'E':
|
2006-12-06 17:25:43 -06:00
|
|
|
case 'e':
|
|
|
|
encryption = optarg;
|
|
|
|
break;
|
2006-12-06 17:26:24 -06:00
|
|
|
case 'f':
|
|
|
|
find = 1;
|
|
|
|
break;
|
2007-11-26 04:13:37 -06:00
|
|
|
case 'j':
|
|
|
|
assoc = optarg;
|
|
|
|
break;
|
2006-12-06 17:25:43 -06:00
|
|
|
case 'o':
|
|
|
|
offset = optarg;
|
|
|
|
break;
|
2006-12-06 17:26:14 -06:00
|
|
|
case 'p':
|
|
|
|
passfd = optarg;
|
|
|
|
break;
|
2007-06-18 08:44:02 -05:00
|
|
|
case 's':
|
|
|
|
showdev = 1;
|
|
|
|
break;
|
2006-12-06 17:25:43 -06:00
|
|
|
case 'v':
|
|
|
|
verbose = 1;
|
|
|
|
break;
|
2008-04-15 05:57:35 -05:00
|
|
|
|
|
|
|
case 128: /* --sizelimit */
|
|
|
|
sizelimit = optarg;
|
|
|
|
break;
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
}
|
2006-12-06 17:26:24 -06:00
|
|
|
|
|
|
|
if (argc == 1) {
|
2006-12-06 17:25:43 -06:00
|
|
|
usage();
|
2006-12-06 17:26:24 -06:00
|
|
|
} else if (delete) {
|
2008-04-15 05:57:35 -05:00
|
|
|
if (argc != optind+1 || encryption || offset || sizelimit ||
|
2007-11-26 04:13:37 -06:00
|
|
|
find || all || showdev || assoc || ro)
|
2006-12-06 17:26:24 -06:00
|
|
|
usage();
|
|
|
|
} else if (find) {
|
2007-11-26 04:13:37 -06:00
|
|
|
if (all || assoc || argc < optind || argc > optind+1)
|
2007-03-22 08:22:10 -05:00
|
|
|
usage();
|
|
|
|
} else if (all) {
|
|
|
|
if (argc > 2)
|
2006-12-06 17:26:24 -06:00
|
|
|
usage();
|
2007-11-26 04:13:37 -06:00
|
|
|
} else if (assoc) {
|
|
|
|
if (encryption || showdev || passfd || ro)
|
|
|
|
usage();
|
2006-12-06 17:26:24 -06:00
|
|
|
} else {
|
|
|
|
if (argc < optind+1 || argc > optind+2)
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
|
2007-11-26 04:13:37 -06:00
|
|
|
if (offset && sscanf(offset, "%llu", &off) != 1)
|
|
|
|
usage();
|
|
|
|
|
2008-04-15 05:57:35 -05:00
|
|
|
if (sizelimit && sscanf(sizelimit, "%llu", &slimit) != 1)
|
|
|
|
usage();
|
|
|
|
|
2007-03-22 08:22:10 -05:00
|
|
|
if (all)
|
|
|
|
return show_used_loop_devices();
|
2007-11-26 04:13:37 -06:00
|
|
|
else if (assoc)
|
|
|
|
return show_associated_loop_devices(assoc, off, offset ? 1 : 0);
|
2007-03-22 08:22:10 -05:00
|
|
|
else if (find) {
|
2006-12-06 17:26:24 -06:00
|
|
|
device = find_unused_loop_device();
|
|
|
|
if (device == NULL)
|
|
|
|
return -1;
|
|
|
|
if (argc == optind) {
|
2007-06-20 08:17:47 -05:00
|
|
|
if (verbose)
|
|
|
|
printf("Loop device is %s\n", device);
|
2006-12-06 17:26:24 -06:00
|
|
|
printf("%s\n", device);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
file = argv[optind];
|
2006-12-06 17:25:43 -06:00
|
|
|
} else {
|
2006-12-06 17:26:24 -06:00
|
|
|
device = argv[optind];
|
|
|
|
if (argc == optind+1)
|
|
|
|
file = NULL;
|
|
|
|
else
|
|
|
|
file = argv[optind+1];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (delete)
|
|
|
|
res = del_loop(device);
|
|
|
|
else if (file == NULL)
|
|
|
|
res = show_loop(device);
|
|
|
|
else {
|
2006-12-06 17:26:16 -06:00
|
|
|
if (passfd && sscanf(passfd, "%d", &pfd) != 1)
|
2006-12-06 17:26:14 -06:00
|
|
|
usage();
|
2007-06-20 08:17:47 -05:00
|
|
|
do {
|
2008-04-15 05:57:35 -05:00
|
|
|
res = set_loop(device, file, off, slimit, encryption, pfd, &ro);
|
2007-06-20 08:17:47 -05:00
|
|
|
if (res == 2 && find) {
|
|
|
|
if (verbose)
|
|
|
|
printf("stolen loop=%s...trying again\n",
|
|
|
|
device);
|
|
|
|
free(device);
|
|
|
|
if (!(device = find_unused_loop_device()))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} while (find && res == 2);
|
|
|
|
|
|
|
|
if (verbose && res == 0)
|
|
|
|
printf("Loop device is %s\n", device);
|
|
|
|
|
|
|
|
if (res == 0 && showdev && find)
|
2007-06-18 08:44:02 -05:00
|
|
|
printf("%s\n", device);
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* LOOP_SET_FD not defined */
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char **argv) {
|
|
|
|
fprintf(stderr,
|
|
|
|
_("No loop support was available at compile time. "
|
|
|
|
"Please recompile.\n"));
|
|
|
|
return -1;
|
|
|
|
}
|
2007-11-23 08:13:22 -06:00
|
|
|
#endif /* !LOOP_SET_FD*/
|
|
|
|
#endif /* MAIN */
|