2 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
3 * Originally from Ted's losetup.c
5 * losetup.c - setup and control loop devices
12 #include <sys/ioctl.h>
22 #include "closestream.h"
25 #define EXCL_ERROR "--{all,associated,set-capacity,detach,detach-all,find}"
28 A_CREATE
= 1, /* setup a new device */
29 A_DELETE
, /* delete given device(s) */
30 A_DELETE_ALL
, /* delete all devices */
31 A_SHOW
, /* list devices */
32 A_SHOW_ONE
, /* print info about one device */
33 A_FIND_FREE
, /* find first unused */
34 A_SET_CAPACITY
, /* set device capacity */
40 static int printf_loopdev(struct loopdev_cxt
*lc
)
48 fname
= loopcxt_get_backing_file(lc
);
52 if (loopcxt_get_backing_devno(lc
, &dev
) == 0)
53 loopcxt_get_backing_inode(lc
, &ino
);
57 * Probably non-root user (no permissions to
58 * call LOOP_GET_STATUS ioctls).
60 printf("%s: []: (%s)",
61 loopcxt_get_device(lc
), fname
);
63 if (loopcxt_get_offset(lc
, &x
) == 0 && x
)
64 printf(_(", offset %ju"), x
);
66 if (loopcxt_get_sizelimit(lc
, &x
) == 0 && x
)
67 printf(_(", sizelimit %ju"), x
);
72 printf("%s: [%04d]:%" PRIu64
" (%s)",
73 loopcxt_get_device(lc
), (int) dev
, ino
, fname
);
75 if (loopcxt_get_offset(lc
, &x
) == 0 && x
)
76 printf(_(", offset %ju"), x
);
78 if (loopcxt_get_sizelimit(lc
, &x
) == 0 && x
)
79 printf(_(", sizelimit %ju"), x
);
81 if (loopcxt_get_encrypt_type(lc
, &type
) == 0) {
82 const char *e
= loopcxt_get_crypt_name(lc
);
84 if ((!e
|| !*e
) && type
== 1)
87 printf(_(", encryption %s (type %u)"), e
, type
);
93 static int show_all_loops(struct loopdev_cxt
*lc
, const char *file
,
94 uint64_t offset
, int flags
)
96 struct stat sbuf
, *st
= &sbuf
;
98 if (loopcxt_init_iterator(lc
, LOOPITER_FL_USED
))
101 if (!file
|| stat(file
, st
))
104 while (loopcxt_next(lc
) == 0) {
106 if (file
&& !loopcxt_is_used(lc
, st
, file
, offset
, flags
))
111 loopcxt_deinit_iterator(lc
);
115 static int set_capacity(struct loopdev_cxt
*lc
)
117 int fd
= loopcxt_get_fd(lc
);
120 warn(_("cannot open %s"), loopcxt_get_device(lc
));
121 else if (ioctl(fd
, LOOP_SET_CAPACITY
) != 0)
122 warnx(_("%s: set capacity failed"), loopcxt_get_device(lc
));
129 static int delete_loop(struct loopdev_cxt
*lc
)
131 if (loopcxt_delete_device(lc
))
132 warn(_("%s: detach failed"), loopcxt_get_device(lc
));
139 static int delete_all_loops(struct loopdev_cxt
*lc
)
143 if (loopcxt_init_iterator(lc
, LOOPITER_FL_USED
))
146 while (loopcxt_next(lc
) == 0)
147 res
+= delete_loop(lc
);
149 loopcxt_deinit_iterator(lc
);
153 static void usage(FILE *out
)
155 fputs(USAGE_HEADER
, out
);
158 _(" %1$s [options] [<loopdev>]\n"
159 " %1$s [options] -f | <loopdev> <file>\n"),
160 program_invocation_short_name
);
162 fputs(USAGE_OPTIONS
, out
);
163 fputs(_(" -a, --all list all used devices\n"
164 " -d, --detach <loopdev> [...] detach one or more devices\n"
165 " -D, --detach-all detach all used devices\n"
166 " -f, --find find first unused device\n"
167 " -c, --set-capacity <loopdev> resize device\n"
168 " -j, --associated <file> list all devices associated with <file>\n"), out
);
169 fputs(USAGE_SEPARATOR
, out
);
171 fputs(_(" -e, --encryption <type> enable encryption with specified <name/num>\n"
172 " -o, --offset <num> start at offset <num> into file\n"
173 " --sizelimit <num> device limited to <num> bytes of the file\n"
174 " -p, --pass-fd <num> read passphrase from file descriptor <num>\n"
175 " -P, --partscan create partitioned loop device\n"
176 " -r, --read-only setup read-only loop device\n"
177 " --show print device name after setup (with -f)\n"
178 " -v, --verbose verbose mode\n"), out
);
180 fputs(USAGE_SEPARATOR
, out
);
181 fputs(USAGE_HELP
, out
);
182 fputs(USAGE_VERSION
, out
);
184 fprintf(out
, USAGE_MAN_TAIL("losetup(8)"));
186 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
189 static void warn_size(const char *filename
, uint64_t size
)
194 if (stat(filename
, &st
))
200 warnx(_("%s: warning: file smaller than 512 bytes, the loop device "
201 "maybe be useless or invisible for system tools."),
204 warnx(_("%s: warning: file does not fit into a 512-byte sector "
205 "the end of the file will be ignored."),
209 int main(int argc
, char **argv
)
211 struct loopdev_cxt lc
;
212 int act
= 0, flags
= 0, passfd
= -1, c
;
213 char *file
= NULL
, *encryption
= NULL
;
214 uint64_t offset
= 0, sizelimit
= 0;
215 int res
= 0, showdev
= 0, lo_flags
= 0;
226 int excl_any
= EXCL_NONE
;
229 OPT_SIZELIMIT
= CHAR_MAX
+ 1,
232 static const struct option longopts
[] = {
233 { "all", 0, 0, 'a' },
234 { "set-capacity", 1, 0, 'c' },
235 { "detach", 1, 0, 'd' },
236 { "detach-all", 0, 0, 'D' },
237 { "encryption", 1, 0, 'e' },
238 { "find", 0, 0, 'f' },
239 { "help", 0, 0, 'h' },
240 { "associated", 1, 0, 'j' },
241 { "offset", 1, 0, 'o' },
242 { "sizelimit", 1, 0, OPT_SIZELIMIT
},
243 { "pass-fd", 1, 0, 'p' },
244 { "partscan", 0, 0, 'P' },
245 { "read-only", 0, 0, 'r' },
246 { "show", 0, 0, OPT_SHOW
},
247 { "verbose", 0, 0, 'v' },
248 { "version", 0, 0, 'V' },
252 setlocale(LC_ALL
, "");
253 bindtextdomain(PACKAGE
, LOCALEDIR
);
255 atexit(close_stdout
);
257 if (loopcxt_init(&lc
, 0))
258 err(EXIT_FAILURE
, _("failed to initialize loopcxt"));
260 loopcxt_enable_debug(&lc
, getenv("LOOPDEV_DEBUG") ? TRUE
: FALSE
);
262 while ((c
= getopt_long(argc
, argv
, "ac:d:De:E:fhj:o:p:PrvV",
263 longopts
, NULL
)) != -1) {
266 exclusive_option(&excl_any
, EXCL_ALL
, EXCL_ERROR
);
270 exclusive_option(&excl_any
, EXCL_SET_CAPACITY
, EXCL_ERROR
);
271 act
= A_SET_CAPACITY
;
272 if (loopcxt_set_device(&lc
, optarg
))
273 err(EXIT_FAILURE
, _("%s: failed to use device"),
277 lo_flags
|= LO_FLAGS_READ_ONLY
;
280 exclusive_option(&excl_any
, EXCL_DETACH
, EXCL_ERROR
);
282 if (loopcxt_set_device(&lc
, optarg
))
283 err(EXIT_FAILURE
, _("%s: failed to use device"),
287 exclusive_option(&excl_any
, EXCL_DETACH_ALL
, EXCL_ERROR
);
295 exclusive_option(&excl_any
, EXCL_FIND
, EXCL_ERROR
);
302 exclusive_option(&excl_any
, EXCL_ASSOCIATED
, EXCL_ERROR
);
307 offset
= strtosize_or_err(optarg
, _("failed to parse offset"));
308 flags
|= LOOPDEV_FL_OFFSET
;
311 passfd
= strtou32_or_err(optarg
,
312 _("invalid passphrase file descriptor"));
315 lo_flags
|= LO_FLAGS_PARTSCAN
;
324 printf(UTIL_LINUX_VERSION
);
326 case OPT_SIZELIMIT
: /* --sizelimit */
327 sizelimit
= strtosize_or_err(optarg
, _("failed to parse size"));
328 flags
|= LOOPDEV_FL_SIZELIMIT
;
338 if (act
== A_FIND_FREE
&& optind
< argc
) {
340 * losetup -f <backing_file>
343 file
= argv
[optind
++];
345 if (!act
&& optind
+ 1 == argc
) {
350 if (loopcxt_set_device(&lc
, argv
[optind
]))
351 err(EXIT_FAILURE
, _("%s: failed to use device"),
357 * losetup <loopdev> <backing_file>
362 errx(EXIT_FAILURE
, _("no loop device specified"));
363 if (loopcxt_set_device(&lc
, argv
[optind
]))
364 err(EXIT_FAILURE
, _("%s failed to use device"),
369 errx(EXIT_FAILURE
, _("no file specified"));
370 file
= argv
[optind
++];
373 if (act
!= A_CREATE
&&
374 (encryption
|| sizelimit
|| passfd
!= -1 || lo_flags
|| showdev
))
376 _("the options %s are allowed to loop device setup only"),
377 "--{encryption,sizelimit,pass-fd,read-only,show}");
379 if ((flags
& LOOPDEV_FL_OFFSET
) &&
380 act
!= A_CREATE
&& (act
!= A_SHOW
|| !file
))
381 errx(EXIT_FAILURE
, _("the option --offset is not allowed in this context."));
387 int hasdev
= loopcxt_has_device(&lc
);
391 if(mlockall(MCL_CURRENT
| MCL_FUTURE
))
392 err(EXIT_FAILURE
, _("couldn't lock into memory"));
394 pass
= xgetpass(passfd
, _("Password: "));
397 /* Note that loopcxt_{find_unused,set_device}() resets
400 if (!hasdev
&& (res
= loopcxt_find_unused(&lc
))) {
401 warnx(_("not found unused device"));
404 if (encryption
&& pass
)
405 loopcxt_set_encryption(&lc
, encryption
, pass
);
406 if (flags
& LOOPDEV_FL_OFFSET
)
407 loopcxt_set_offset(&lc
, offset
);
408 if (flags
& LOOPDEV_FL_SIZELIMIT
)
409 loopcxt_set_sizelimit(&lc
, sizelimit
);
411 loopcxt_set_flags(&lc
, lo_flags
);
412 if ((res
= loopcxt_set_backing_file(&lc
, file
))) {
413 warn(_("%s: failed to use backing file"), file
);
417 res
= loopcxt_setup_device(&lc
);
420 if (errno
!= EBUSY
) {
421 warn(_("%s: failed to setup loop device"),
422 hasdev
&& loopcxt_get_fd(&lc
) < 0 ?
423 loopcxt_get_device(&lc
) : file
);
426 } while (hasdev
== 0);
432 printf("%s\n", loopcxt_get_device(&lc
));
433 warn_size(file
, sizelimit
);
438 res
= delete_loop(&lc
);
439 while (optind
< argc
) {
440 if (loopcxt_set_device(&lc
, argv
[optind
]))
441 warn(_("%s: failed to use device"),
444 res
+= delete_loop(&lc
);
448 res
= delete_all_loops(&lc
);
451 if (loopcxt_find_unused(&lc
))
452 warn(_("find unused loop device failed"));
454 printf("%s\n", loopcxt_get_device(&lc
));
457 res
= show_all_loops(&lc
, file
, offset
, flags
);
460 res
= printf_loopdev(&lc
);
462 warn(_("%s"), loopcxt_get_device(&lc
));
465 res
= set_capacity(&lc
);
473 return res
? EXIT_FAILURE
: EXIT_SUCCESS
;