blob: 2908dbc88883a7341fe881cd34ef64b12e9d1aaa [file] [log] [blame]
Eric Andersencc8ed391999-10-05 16:24:54 +00001/*
2 * losetup.c - setup and control loop devices
3 */
4
5
6#include "internal.h"
7
8const char losetup_usage[] = "losetup\n"
9"\n"
10"\tlosetup loop_device give info\n"
11"\tlosetup -d loop_device delete\n"
12"\tlosetup [ -o offset ] loop_device file setup\n";
13
14/* from mount-2.6d */
15
16/*
17 * losetup.c - setup and control loop devices
18 */
19
20#include <stdio.h>
21#include <string.h>
22#include <ctype.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <getopt.h>
26#include <errno.h>
27#include <sys/ioctl.h>
28#include <linux/fs.h>
29/* #include "loop.h" */
30
31/*
32 * include/linux/loop.h
33 *
34 * Written by Theodore Ts'o, 3/29/93.
35 *
36 * Copyright 1993 by Theodore Ts'o. Redistribution of this file is
37 * permitted under the GNU Public License.
38 */
39
40#define LO_NAME_SIZE 64
41#define LO_KEY_SIZE 32
42
43struct loop_info {
44 int lo_number; /* ioctl r/o */
45 dev_t lo_device; /* ioctl r/o */
46 unsigned long lo_inode; /* ioctl r/o */
47 dev_t lo_rdevice; /* ioctl r/o */
48 int lo_offset;
49 int lo_encrypt_type;
50 int lo_encrypt_key_size; /* ioctl w/o */
51 int lo_flags; /* ioctl r/o */
52 char lo_name[LO_NAME_SIZE];
53 unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
54 unsigned long lo_init[2];
55 char reserved[4];
56};
57
58/*
59 * IOCTL commands --- we will commandeer 0x4C ('L')
60 */
61
62#define LOOP_SET_FD 0x4C00
63#define LOOP_CLR_FD 0x4C01
64#define LOOP_SET_STATUS 0x4C02
65#define LOOP_GET_STATUS 0x4C03
66
67/* #include "lomount.h" */
68
69extern int set_loop (const char *, const char *, int, int *);
70extern int del_loop (const char *);
71
72static void show_loop(const char *device)
73{
74 struct loop_info loopinfo;
75 int fd;
76
77 if ((fd = open(device, O_RDWR)) < 0) {
78 perror(device);
79 return;
80 }
81 if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) < 0) {
82 perror("Cannot get loop info");
83 close(fd);
84 return;
85 }
86 printf("%s: [%04x]:%ld (%s) offset %d\n",
87 device, (unsigned int)loopinfo.lo_device, loopinfo.lo_inode,
88 loopinfo.lo_name, loopinfo.lo_offset);
89 close(fd);
90}
91
92
93int set_loop(const char *device, const char *file, int offset, int *loopro)
94{
95 struct loop_info loopinfo;
96 int fd, ffd, mode;
97
98 mode = *loopro ? O_RDONLY : O_RDWR;
99 if ((ffd = open (file, mode)) < 0 && !*loopro
100 && (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) {
101 perror (file);
102 return 1;
103 }
104 if ((fd = open (device, mode)) < 0) {
105 close(ffd);
106 perror (device);
107 return 1;
108 }
109 *loopro = (mode == O_RDONLY);
110
111 memset(&loopinfo, 0, sizeof(loopinfo));
112 strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
113 loopinfo.lo_name[LO_NAME_SIZE-1] = 0;
114
115 loopinfo.lo_offset = offset;
116
117 loopinfo.lo_encrypt_key_size = 0;
118 if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
119 perror("ioctl: LOOP_SET_FD");
120 exit(1);
121 }
122 if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
123 (void) ioctl(fd, LOOP_CLR_FD, 0);
124 perror("ioctl: LOOP_SET_STATUS");
125 exit(1);
126 }
127 close(fd);
128 close(ffd);
129 return 0;
130}
131
132int del_loop(const char *device)
133{
134 int fd;
135
136 if ((fd = open(device, O_RDONLY)) < 0) {
137 perror(device);
138 exit(1);
139 }
140 if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
141 perror("ioctl: LOOP_CLR_FD");
142 exit(1);
143 }
144 close(fd);
145 return(0);
146}
147
148
149static int losetup_usage_fn(void)
150{
151 fprintf(stderr, losetup_usage);
152 exit(1);
153}
154
155int losetup_main(struct FileInfo * i, int argc, char * * argv)
156{
157 char *offset;
158 int delete,off,c;
159 int ro = 0;
160
161 delete = off = 0;
162 offset = NULL;
163 while ((c = getopt(argc,argv,"do:")) != EOF) {
164 switch (c) {
165 case 'd':
166 delete = 1;
167 break;
168 case 'o':
169 offset = optarg;
170 break;
171 default:
172 losetup_usage_fn();
173 }
174 }
175 if (argc == 1) losetup_usage_fn();
176 if ((delete && (argc != optind+1 || offset)) ||
177 (!delete && (argc < optind+1 || argc > optind+2)))
178 losetup_usage_fn();
179 if (argc == optind+1)
180 if (delete)
181 del_loop(argv[optind]);
182 else
183 show_loop(argv[optind]);
184 else {
185 if (offset && sscanf(offset,"%d",&off) != 1)
186 losetup_usage_fn();
187 set_loop(argv[optind],argv[optind+1],off,&ro);
188 }
189 return 0;
190}