blob: 2908dbc88883a7341fe881cd34ef64b12e9d1aaa [file] [log] [blame]
/*
* losetup.c - setup and control loop devices
*/
#include "internal.h"
const char losetup_usage[] = "losetup\n"
"\n"
"\tlosetup loop_device give info\n"
"\tlosetup -d loop_device delete\n"
"\tlosetup [ -o offset ] loop_device file setup\n";
/* from mount-2.6d */
/*
* losetup.c - setup and control loop devices
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
/* #include "loop.h" */
/*
* include/linux/loop.h
*
* Written by Theodore Ts'o, 3/29/93.
*
* Copyright 1993 by Theodore Ts'o. Redistribution of this file is
* permitted under the GNU Public License.
*/
#define LO_NAME_SIZE 64
#define LO_KEY_SIZE 32
struct loop_info {
int lo_number; /* ioctl r/o */
dev_t lo_device; /* ioctl r/o */
unsigned long lo_inode; /* ioctl r/o */
dev_t lo_rdevice; /* ioctl r/o */
int lo_offset;
int lo_encrypt_type;
int lo_encrypt_key_size; /* ioctl w/o */
int lo_flags; /* ioctl r/o */
char lo_name[LO_NAME_SIZE];
unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
unsigned long lo_init[2];
char reserved[4];
};
/*
* IOCTL commands --- we will commandeer 0x4C ('L')
*/
#define LOOP_SET_FD 0x4C00
#define LOOP_CLR_FD 0x4C01
#define LOOP_SET_STATUS 0x4C02
#define LOOP_GET_STATUS 0x4C03
/* #include "lomount.h" */
extern int set_loop (const char *, const char *, int, int *);
extern int del_loop (const char *);
static void show_loop(const char *device)
{
struct loop_info loopinfo;
int fd;
if ((fd = open(device, O_RDWR)) < 0) {
perror(device);
return;
}
if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) < 0) {
perror("Cannot get loop info");
close(fd);
return;
}
printf("%s: [%04x]:%ld (%s) offset %d\n",
device, (unsigned int)loopinfo.lo_device, loopinfo.lo_inode,
loopinfo.lo_name, loopinfo.lo_offset);
close(fd);
}
int set_loop(const char *device, const char *file, int offset, int *loopro)
{
struct loop_info loopinfo;
int fd, ffd, mode;
mode = *loopro ? O_RDONLY : O_RDWR;
if ((ffd = open (file, mode)) < 0 && !*loopro
&& (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) {
perror (file);
return 1;
}
if ((fd = open (device, mode)) < 0) {
close(ffd);
perror (device);
return 1;
}
*loopro = (mode == O_RDONLY);
memset(&loopinfo, 0, sizeof(loopinfo));
strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
loopinfo.lo_name[LO_NAME_SIZE-1] = 0;
loopinfo.lo_offset = offset;
loopinfo.lo_encrypt_key_size = 0;
if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
perror("ioctl: LOOP_SET_FD");
exit(1);
}
if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
(void) ioctl(fd, LOOP_CLR_FD, 0);
perror("ioctl: LOOP_SET_STATUS");
exit(1);
}
close(fd);
close(ffd);
return 0;
}
int del_loop(const char *device)
{
int fd;
if ((fd = open(device, O_RDONLY)) < 0) {
perror(device);
exit(1);
}
if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
perror("ioctl: LOOP_CLR_FD");
exit(1);
}
close(fd);
return(0);
}
static int losetup_usage_fn(void)
{
fprintf(stderr, losetup_usage);
exit(1);
}
int losetup_main(struct FileInfo * i, int argc, char * * argv)
{
char *offset;
int delete,off,c;
int ro = 0;
delete = off = 0;
offset = NULL;
while ((c = getopt(argc,argv,"do:")) != EOF) {
switch (c) {
case 'd':
delete = 1;
break;
case 'o':
offset = optarg;
break;
default:
losetup_usage_fn();
}
}
if (argc == 1) losetup_usage_fn();
if ((delete && (argc != optind+1 || offset)) ||
(!delete && (argc < optind+1 || argc > optind+2)))
losetup_usage_fn();
if (argc == optind+1)
if (delete)
del_loop(argv[optind]);
else
show_loop(argv[optind]);
else {
if (offset && sscanf(offset,"%d",&off) != 1)
losetup_usage_fn();
set_loop(argv[optind],argv[optind+1],off,&ro);
}
return 0;
}