2 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
3 * Originally from Ted's losetup.c
5 * losetup.c - setup and control loop devices
14 #include <sys/ioctl.h>
17 #include <sys/sysmacros.h>
25 #include "pathnames.h"
28 #include "canonicalize.h"
31 A_CREATE
= 1, /* setup a new device */
32 A_DELETE
, /* delete given device(s) */
33 A_DELETE_ALL
, /* delete all devices */
34 A_SHOW
, /* list devices */
35 A_FIND_FREE
, /* find first unused */
36 A_SET_CAPACITY
, /* set device capacity */
42 * A function to read the passphrase either from the terminal or from
43 * an open file descriptor.
45 static char *xgetpass(int pfd
, const char *prompt
)
50 if (pfd
< 0) /* terminal */
51 return getpass(prompt
);
57 /* we're running out of space in the buffer.
61 pass
= realloc(tmppass
, buflen
);
63 /* realloc failed. Stop reading. */
64 warn(_("Out of memory while reading passphrase"));
65 pass
= tmppass
; /* the old buffer hasn't changed */
69 if (read(pfd
, pass
+i
, 1) != 1 ||
70 pass
[i
] == '\n' || pass
[i
] == 0)
81 static int printf_loopdev(struct loopdev_cxt
*lc
)
89 fname
= loopcxt_get_backing_file(lc
);
93 if (loopcxt_get_backing_devno(lc
, &dev
) == 0)
94 loopcxt_get_backing_inode(lc
, &ino
);
98 * Probably non-root user (no permissions to
99 * call LOOP_GET_STATUS ioctls).
101 printf("%s: []: (%s)",
102 loopcxt_get_device(lc
), fname
);
104 if (loopcxt_get_offset(lc
, &x
) == 0 && x
)
105 printf(_(", offset %ju"), x
);
107 if (loopcxt_get_sizelimit(lc
, &x
) == 0 && x
)
108 printf(_(", sizelimit %ju"), x
);
113 printf("%s: [%04d]:%" PRIu64
" (%s)",
114 loopcxt_get_device(lc
), dev
, ino
, fname
);
116 if (loopcxt_get_offset(lc
, &x
) == 0 && x
)
117 printf(_(", offset %ju"), x
);
119 if (loopcxt_get_sizelimit(lc
, &x
) == 0 && x
)
120 printf(_(", sizelimit %ju"), x
);
122 if (loopcxt_get_encrypt_type(lc
, &type
) == 0) {
123 const char *e
= loopcxt_get_crypt_name(lc
);
125 if ((!e
|| !*e
) && type
== 1)
128 printf(_(", encryption %s (type %ju)"), e
, type
);
134 static int show_all_loops(struct loopdev_cxt
*lc
, const char *file
,
135 uint64_t offset
, int flags
)
137 struct stat sbuf
, *st
= &sbuf
;
139 if (loopcxt_init_iterator(lc
, LOOPITER_FL_USED
))
142 if (!file
|| stat(file
, st
))
145 while (loopcxt_next(lc
) == 0) {
147 if (file
&& !loopcxt_is_used(lc
, st
, file
, offset
, flags
))
152 loopcxt_deinit_iterator(lc
);
156 static int set_capacity(struct loopdev_cxt
*lc
)
158 int fd
= loopcxt_get_fd(lc
);
161 warn(_("%s: open failed"), loopcxt_get_device(lc
));
162 else if (ioctl(fd
, LOOP_SET_CAPACITY
) != 0)
163 warnx(_("%s: set capacity failed"), loopcxt_get_device(lc
));
170 static int delete_loop(struct loopdev_cxt
*lc
)
172 if (loopcxt_delete_device(lc
))
173 warn(_("%s: detach failed"), loopcxt_get_device(lc
));
180 static int delete_all_loops(struct loopdev_cxt
*lc
)
184 if (loopcxt_init_iterator(lc
, LOOPITER_FL_USED
))
187 while (loopcxt_next(lc
) == 0)
188 res
+= delete_loop(lc
);
190 loopcxt_deinit_iterator(lc
);
197 fputs(_("\nUsage:\n"), out
);
199 _(" %1$s loop_device give info\n"
200 " %1$s -a | --all list all used\n"
201 " %1$s -d | --detach <loopdev> [<loopdev> ...] delete\n"
202 " %1$s -D | --detach-all delete all used\n"
203 " %1$s -f | --find find unused\n"
204 " %1$s -c | --set-capacity <loopdev> resize\n"
205 " %1$s -j | --associated <file> [-o <num>] list all associated with <file>\n"
206 " %1$s [options] {-f|--find|loopdev} <file> setup\n"),
207 program_invocation_short_name
);
209 fputs(_("\nOptions:\n"), out
);
210 fputs(_(" -e, --encryption <type> enable data encryption with specified <name/num>\n"
211 " -h, --help this help\n"
212 " -o, --offset <num> start at offset <num> into file\n"
213 " --sizelimit <num> loop limited to only <num> bytes of the file\n"
214 " -p, --pass-fd <num> read passphrase from file descriptor <num>\n"
215 " -r, --read-only setup read-only loop device\n"
216 " --show print device name (with -f <file>)\n"
217 " -v, --verbose verbose mode\n\n"), out
);
219 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
222 int main(int argc
, char **argv
)
224 struct loopdev_cxt lc
;
225 int act
= 0, flags
= 0, passfd
= -1, c
;
226 char *file
= NULL
, *encryption
= NULL
;
227 uint64_t offset
= 0, sizelimit
= 0;
228 int res
= 0, showdev
= 0, lo_flags
= 0;
230 loopcxt_init(&lc
, 0);
231 /*loopcxt_enable_debug(&lc, TRUE);*/
233 static const struct option longopts
[] = {
234 { "all", 0, 0, 'a' },
235 { "set-capacity", 1, 0, 'c' },
236 { "detach", 1, 0, 'd' },
237 { "detach-all", 0, 0, 'D' },
238 { "encryption", 1, 0, 'e' },
239 { "find", 0, 0, 'f' },
240 { "help", 0, 0, 'h' },
241 { "associated", 1, 0, 'j' },
242 { "offset", 1, 0, 'o' },
243 { "sizelimit", 1, 0, 128 },
244 { "pass-fd", 1, 0, 'p' },
245 { "read-only", 0, 0, 'r' },
246 { "show", 0, 0, 's' },
247 { "verbose", 0, 0, 'v' },
251 setlocale(LC_ALL
, "");
252 bindtextdomain(PACKAGE
, LOCALEDIR
);
255 while ((c
= getopt_long(argc
, argv
, "ac:d:De:E:fhj:o:p:rsv",
256 longopts
, NULL
)) != -1) {
258 if (act
&& strchr("acdDfj", c
))
260 _("the options %s are mutually exclusive"),
261 "--{all,associated,set-capacity,detach,detach-all,find}");
268 act
= A_SET_CAPACITY
;
269 loopcxt_set_device(&lc
, optarg
);
272 lo_flags
|= LO_FLAGS_READ_ONLY
;
276 loopcxt_set_device(&lc
, optarg
);
296 if (strtosize(optarg
, &offset
))
298 _("invalid offset '%s' specified"), optarg
);
299 flags
|= LOOPDEV_FL_OFFSET
;
302 passfd
= strtol_or_err(optarg
,
303 _("invalid passphrase file descriptor"));
311 case 128: /* --sizelimit */
312 if (strtosize(optarg
, &sizelimit
))
314 _("invalid size '%s' specified"), optarg
);
315 flags
|= LOOPDEV_FL_SIZELIMIT
;
325 if (act
== A_FIND_FREE
&& optind
< argc
) {
327 * losetup -f <backing_file>
330 file
= argv
[optind
++];
334 * losetup <loopdev> <backing_file>
339 errx(EXIT_FAILURE
, _("no loop device specified"));
340 loopcxt_set_device(&lc
, argv
[optind
++]);
343 errx(EXIT_FAILURE
, _("no file specified"));
344 file
= argv
[optind
++];
347 if (act
!= A_CREATE
&&
348 (encryption
|| sizelimit
|| passfd
!= -1 || lo_flags
|| showdev
))
350 _("the options %s are allowed to loop device setup only"),
351 "--{encryption,sizelimit,pass-fd,read-only,show}");
353 if (act
!= A_CREATE
&& act
!= A_SHOW
&& (flags
& LOOPDEV_FL_OFFSET
))
354 errx(EXIT_FAILURE
, _("the option --offset is not allowed in this context."));
360 int hasdev
= loopcxt_has_device(&lc
);
364 if(mlockall(MCL_CURRENT
| MCL_FUTURE
))
365 err(EXIT_FAILURE
, _("couldn't lock into memory"));
367 pass
= xgetpass(passfd
, _("Password: "));
370 /* Note that loopcxt_{find_unused,set_device}() resets
373 if (!hasdev
&& (res
= loopcxt_find_unused(&lc
))) {
374 warnx(_("not found unused device"));
377 if (encryption
&& pass
)
378 loopcxt_set_encryption(&lc
, encryption
, pass
);
379 if (flags
& LOOPDEV_FL_OFFSET
)
380 loopcxt_set_offset(&lc
, offset
);
381 if (flags
& LOOPDEV_FL_SIZELIMIT
)
382 loopcxt_set_offset(&lc
, sizelimit
);
384 loopcxt_set_flags(&lc
, lo_flags
);
385 if ((res
= loopcxt_set_backing_file(&lc
, file
))) {
386 warn(_("%s: failed to use backing file"), file
);
390 res
= loopcxt_setup_device(&lc
);
393 if (errno
!= EBUSY
) {
394 warn(_("failed to setup loop device"));
397 } while (hasdev
== 0);
401 if (showdev
&& res
== 0)
402 printf("%s\n", loopcxt_get_device(&lc
));
406 res
= delete_loop(&lc
);
407 while (optind
< argc
) {
408 loopcxt_set_device(&lc
, argv
[optind
++]);
409 res
+= delete_loop(&lc
);
413 res
= delete_all_loops(&lc
);
416 if (loopcxt_find_unused(&lc
))
417 warn(_("find unused loop device failed"));
419 printf("%s\n", loopcxt_get_device(&lc
));
422 res
= show_all_loops(&lc
, file
, offset
, flags
);
425 res
= set_capacity(&lc
);
433 return res
? EXIT_FAILURE
: EXIT_SUCCESS
;