#include "nls.h"
#include "strutils.h"
#include "loopdev.h"
+#include "closestream.h"
+#include "optutils.h"
enum {
A_CREATE = 1, /* setup a new device */
static int verbose;
-/*
- * 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. */
- warn(_("Out of memory while reading passphrase"));
- pass = tmppass; /* the old buffer hasn't changed */
- break;
- }
- }
- if (read(pfd, pass+i, 1) != 1 ||
- pass[i] == '\n' || pass[i] == 0)
- break;
- }
-
- if (pass == NULL)
- return "";
-
- pass[i] = 0;
- return pass;
-}
static int printf_loopdev(struct loopdev_cxt *lc)
{
dev_t dev = 0;
ino_t ino = 0;
char *fname = NULL;
- int type;
+ uint32_t type;
fname = loopcxt_get_backing_file(lc);
if (!fname)
}
printf("%s: [%04d]:%" PRIu64 " (%s)",
- loopcxt_get_device(lc), dev, ino, fname);
+ loopcxt_get_device(lc), (int) dev, ino, fname);
if (loopcxt_get_offset(lc, &x) == 0 && x)
printf(_(", offset %ju"), x);
if ((!e || !*e) && type == 1)
e = "XOR";
if (e && *e)
- printf(_(", encryption %s (type %ju)"), e, type);
+ printf(_(", encryption %s (type %u)"), e, type);
}
printf("\n");
return 0;
int fd = loopcxt_get_fd(lc);
if (fd < 0)
- warn(_("%s: open failed"), loopcxt_get_device(lc));
+ warn(_("cannot open %s"), loopcxt_get_device(lc));
else if (ioctl(fd, LOOP_SET_CAPACITY) != 0)
warnx(_("%s: set capacity failed"), loopcxt_get_device(lc));
else
" -j, --associated <file> list all devices associated with <file>\n"), out);
fputs(USAGE_SEPARATOR, out);
- fputs(_(" -e, --encryption <type> enable encryption with specified <name/num>\n"
- " -o, --offset <num> start at offset <num> into file\n"
+ fputs(_(" -o, --offset <num> start at offset <num> into file\n"
" --sizelimit <num> device limited to <num> bytes of the file\n"
- " -p, --pass-fd <num> read passphrase from file descriptor <num>\n"
+ " -P, --partscan create partitioned loop device\n"
" -r, --read-only setup read-only loop device\n"
" --show print device name after setup (with -f)\n"
" -v, --verbose verbose mode\n"), out);
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
}
+static void warn_size(const char *filename, uint64_t size)
+{
+ struct stat st;
+
+ if (!size) {
+ if (stat(filename, &st))
+ return;
+ size = st.st_size;
+ }
+
+ if (size < 512)
+ warnx(_("%s: warning: file smaller than 512 bytes, the loop device "
+ "maybe be useless or invisible for system tools."),
+ filename);
+ else if (size % 512)
+ warnx(_("%s: warning: file does not fit into a 512-byte sector "
+ "the end of the file will be ignored."),
+ filename);
+}
+
int main(int argc, char **argv)
{
struct loopdev_cxt lc;
- int act = 0, flags = 0, passfd = -1, c;
- char *file = NULL, *encryption = NULL;
+ int act = 0, flags = 0, c;
+ char *file = NULL;
uint64_t offset = 0, sizelimit = 0;
int res = 0, showdev = 0, lo_flags = 0;
{ "offset", 1, 0, 'o' },
{ "sizelimit", 1, 0, OPT_SIZELIMIT },
{ "pass-fd", 1, 0, 'p' },
+ { "partscan", 0, 0, 'P' },
{ "read-only", 0, 0, 'r' },
{ "show", 0, 0, OPT_SHOW },
{ "verbose", 0, 0, 'v' },
{ NULL, 0, 0, 0 }
};
+ static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
+ { 'D','a','c','d','f','j' },
+ { 0 }
+ };
+ int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
+
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
+ atexit(close_stdout);
+
+ if (loopcxt_init(&lc, 0))
+ err(EXIT_FAILURE, _("failed to initialize loopcxt"));
- loopcxt_init(&lc, 0);
loopcxt_enable_debug(&lc, getenv("LOOPDEV_DEBUG") ? TRUE : FALSE);
- while ((c = getopt_long(argc, argv, "ac:d:De:E:fhj:o:p:rvV",
+ while ((c = getopt_long(argc, argv, "ac:d:De:E:fhj:o:p:PrvV",
longopts, NULL)) != -1) {
- if (act && strchr("acdDfj", c))
- errx(EXIT_FAILURE,
- _("the options %s are mutually exclusive"),
- "--{all,associated,set-capacity,detach,detach-all,find}");
+ err_exclusive_options(c, longopts, excl, excl_st);
switch (c) {
case 'a':
break;
case 'c':
act = A_SET_CAPACITY;
- loopcxt_set_device(&lc, optarg);
+ if (loopcxt_set_device(&lc, optarg))
+ err(EXIT_FAILURE, _("%s: failed to use device"),
+ optarg);
break;
case 'r':
lo_flags |= LO_FLAGS_READ_ONLY;
break;
case 'd':
act = A_DELETE;
- loopcxt_set_device(&lc, optarg);
+ if (loopcxt_set_device(&lc, optarg))
+ err(EXIT_FAILURE, _("%s: failed to use device"),
+ optarg);
break;
case 'D':
act = A_DELETE_ALL;
break;
case 'E':
case 'e':
- encryption = optarg;
+ errx(EXIT_FAILURE, _("encryption not supported, use cryptsetup(8) instead"));
break;
case 'f':
act = A_FIND_FREE;
file = optarg;
break;
case 'o':
- if (strtosize(optarg, &offset))
- errx(EXIT_FAILURE,
- _("invalid offset '%s' specified"), optarg);
+ offset = strtosize_or_err(optarg, _("failed to parse offset"));
flags |= LOOPDEV_FL_OFFSET;
break;
case 'p':
- passfd = strtol_or_err(optarg,
- _("invalid passphrase file descriptor"));
+ warn(_("--pass-fd is no longer supported"));
+ break;
+ case 'P':
+ lo_flags |= LO_FLAGS_PARTSCAN;
break;
case OPT_SHOW:
showdev = 1;
printf(UTIL_LINUX_VERSION);
return EXIT_SUCCESS;
case OPT_SIZELIMIT: /* --sizelimit */
- if (strtosize(optarg, &sizelimit))
- errx(EXIT_FAILURE,
- _("invalid size '%s' specified"), optarg);
+ sizelimit = strtosize_or_err(optarg, _("failed to parse size"));
flags |= LOOPDEV_FL_SIZELIMIT;
break;
default:
* losetup <device>
*/
act = A_SHOW_ONE;
- loopcxt_set_device(&lc, argv[optind++]);
+ if (loopcxt_set_device(&lc, argv[optind]))
+ err(EXIT_FAILURE, _("%s: failed to use device"),
+ argv[optind]);
+ optind++;
}
if (!act) {
/*
if (optind >= argc)
errx(EXIT_FAILURE, _("no loop device specified"));
- loopcxt_set_device(&lc, argv[optind++]);
+ if (loopcxt_set_device(&lc, argv[optind]))
+ err(EXIT_FAILURE, _("%s: failed to use device"),
+ argv[optind]);
+ optind++;
if (optind >= argc)
errx(EXIT_FAILURE, _("no file specified"));
}
if (act != A_CREATE &&
- (encryption || sizelimit || passfd != -1 || lo_flags || showdev))
+ (sizelimit || lo_flags || showdev))
errx(EXIT_FAILURE,
_("the options %s are allowed to loop device setup only"),
- "--{encryption,sizelimit,pass-fd,read-only,show}");
+ "--{sizelimit,read-only,show}");
if ((flags & LOOPDEV_FL_OFFSET) &&
act != A_CREATE && (act != A_SHOW || !file))
switch (act) {
case A_CREATE:
{
- char *pass = NULL;
int hasdev = loopcxt_has_device(&lc);
- if (encryption) {
-#ifdef MCL_FUTURE
- if(mlockall(MCL_CURRENT | MCL_FUTURE))
- err(EXIT_FAILURE, _("couldn't lock into memory"));
-#endif
- pass = xgetpass(passfd, _("Password: "));
- }
do {
/* Note that loopcxt_{find_unused,set_device}() resets
* loopcxt struct.
warnx(_("not found unused device"));
break;
}
- if (encryption && pass)
- loopcxt_set_encryption(&lc, encryption, pass);
if (flags & LOOPDEV_FL_OFFSET)
loopcxt_set_offset(&lc, offset);
if (flags & LOOPDEV_FL_SIZELIMIT)
- loopcxt_set_offset(&lc, sizelimit);
+ loopcxt_set_sizelimit(&lc, sizelimit);
if (lo_flags)
loopcxt_set_flags(&lc, lo_flags);
if ((res = loopcxt_set_backing_file(&lc, file))) {
if (res == 0)
break; /* success */
if (errno != EBUSY) {
- warn(_("failed to setup loop device"));
+ warn(_("%s: failed to setup loop device"),
+ hasdev && loopcxt_get_fd(&lc) < 0 ?
+ loopcxt_get_device(&lc) : file);
break;
}
} while (hasdev == 0);
- free(pass);
-
- if (showdev && res == 0)
- printf("%s\n", loopcxt_get_device(&lc));
+ if (res == 0) {
+ if (showdev)
+ printf("%s\n", loopcxt_get_device(&lc));
+ warn_size(file, sizelimit);
+ }
break;
}
case A_DELETE:
res = delete_loop(&lc);
while (optind < argc) {
- loopcxt_set_device(&lc, argv[optind++]);
+ if (loopcxt_set_device(&lc, argv[optind]))
+ warn(_("%s: failed to use device"),
+ argv[optind]);
+ optind++;
res += delete_loop(&lc);
}
break;