A_FIND_FREE, /* find first unused */
A_SET_CAPACITY, /* set device capacity */
A_SET_DIRECT_IO, /* set accessing backing file by direct io */
+ A_SET_BLOCKSIZE, /* set logical block size of the loop device */
};
enum {
COL_RO,
COL_SIZELIMIT,
COL_DIO,
+ COL_LOGSEC,
};
/* basic output flags */
double whint;
int flags;
const char *help;
+
+ int json_type; /* default is string */
};
static struct colinfo infos[] = {
- [COL_AUTOCLR] = { "AUTOCLEAR", 1, SCOLS_FL_RIGHT, N_("autoclear flag set")},
+ [COL_AUTOCLR] = { "AUTOCLEAR", 1, SCOLS_FL_RIGHT, N_("autoclear flag set"), SCOLS_JSON_BOOLEAN},
[COL_BACK_FILE] = { "BACK-FILE", 0.3, 0, N_("device backing file")},
- [COL_BACK_INO] = { "BACK-INO", 4, SCOLS_FL_RIGHT, N_("backing file inode number")},
+ [COL_BACK_INO] = { "BACK-INO", 4, SCOLS_FL_RIGHT, N_("backing file inode number"), SCOLS_JSON_NUMBER},
[COL_BACK_MAJMIN] = { "BACK-MAJ:MIN", 6, 0, N_("backing file major:minor device number")},
[COL_NAME] = { "NAME", 0.25, 0, N_("loop device name")},
- [COL_OFFSET] = { "OFFSET", 5, SCOLS_FL_RIGHT, N_("offset from the beginning")},
- [COL_PARTSCAN] = { "PARTSCAN", 1, SCOLS_FL_RIGHT, N_("partscan flag set")},
- [COL_RO] = { "RO", 1, SCOLS_FL_RIGHT, N_("read-only device")},
- [COL_SIZELIMIT] = { "SIZELIMIT", 5, SCOLS_FL_RIGHT, N_("size limit of the file in bytes")},
+ [COL_OFFSET] = { "OFFSET", 5, SCOLS_FL_RIGHT, N_("offset from the beginning"), SCOLS_JSON_NUMBER},
+ [COL_PARTSCAN] = { "PARTSCAN", 1, SCOLS_FL_RIGHT, N_("partscan flag set"), SCOLS_JSON_BOOLEAN},
+ [COL_RO] = { "RO", 1, SCOLS_FL_RIGHT, N_("read-only device"), SCOLS_JSON_BOOLEAN},
+ [COL_SIZELIMIT] = { "SIZELIMIT", 5, SCOLS_FL_RIGHT, N_("size limit of the file in bytes"), SCOLS_JSON_NUMBER},
[COL_MAJMIN] = { "MAJ:MIN", 3, 0, N_("loop device major:minor number")},
- [COL_DIO] = { "DIO", 1, SCOLS_FL_RIGHT, N_("access backing file with direct-io")},
+ [COL_DIO] = { "DIO", 1, SCOLS_FL_RIGHT, N_("access backing file with direct-io"), SCOLS_JSON_BOOLEAN},
+ [COL_LOGSEC] = { "LOG-SEC", 4, SCOLS_FL_RIGHT, N_("logical sector size in bytes"), SCOLS_JSON_NUMBER},
};
static int columns[ARRAY_SIZE(infos) * 2] = {-1};
if (loopcxt_get_sizelimit(lc, &x) == 0 && x)
printf(_(", sizelimit %ju"), x);
- printf("\n");
- return 0;
+ goto done;
}
printf("%s: [%04d]:%" PRIu64 " (%s)",
if (e && *e)
printf(_(", encryption %s (type %u)"), e, type);
}
+
+done:
+ free(fname);
printf("\n");
return 0;
}
case COL_PARTSCAN:
p = loopcxt_is_partscan(lc) ? "1" : "0";
break;
+ case COL_LOGSEC:
+ if (loopcxt_get_blocksize(lc, &x) == 0)
+ xasprintf(&np, "%jd", x);
+ break;
default:
return -EINVAL;
}
for (i = 0; i < ncolumns; i++) {
struct colinfo *ci = get_column_info(i);
+ struct libscols_column *cl;
- if (!scols_table_new_column(tb, ci->name, ci->whint, ci->flags))
+ cl = scols_table_new_column(tb, ci->name, ci->whint, ci->flags);
+ if (!cl)
err(EXIT_FAILURE, _("failed to allocate output column"));
+ if (json)
+ scols_column_set_json_type(cl, ci->json_type);
}
/* only one loopdev requested (already assigned to loopdev_cxt) */
fputs(USAGE_SEPARATOR, out);
fputs(_(" -o, --offset <num> start at offset <num> into file\n"), out);
fputs(_(" --sizelimit <num> device is limited to <num> bytes of the file\n"), out);
+ fputs(_(" -b, --sector-size <num> set the logical sector size to <num>\n"), out);
fputs(_(" -P, --partscan create a partitioned loop device\n"), out);
fputs(_(" -r, --read-only set up a read-only loop device\n"), out);
fputs(_(" --direct-io[=<on|off>] open backing file with O_DIRECT\n"), out);
fputs(_(" -l, --list list info about all or specified (default)\n"), out);
fputs(_(" -n, --noheadings don't print headings for --list output\n"), out);
fputs(_(" -O, --output <cols> specify columns to output for --list\n"), out);
+ fputs(_(" --output-all output all columns\n"), out);
fputs(_(" --raw use raw --list output format\n"), out);
fputs(USAGE_SEPARATOR, out);
exit(EXIT_SUCCESS);
}
-static void warn_size(const char *filename, uint64_t size)
+static void warn_size(const char *filename, uint64_t size, uint64_t offset, int flags)
{
struct stat st;
if (stat(filename, &st) || S_ISBLK(st.st_mode))
return;
size = st.st_size;
+
+ if (flags & LOOPDEV_FL_OFFSET)
+ size -= offset;
}
if (size < 512)
static int create_loop(struct loopdev_cxt *lc,
int nooverlap, int lo_flags, int flags,
- const char *file, uint64_t offset, uint64_t sizelimit)
+ const char *file, uint64_t offset, uint64_t sizelimit,
+ uint64_t blocksize)
{
int hasdev = loopcxt_has_device(lc);
int rc = 0;
errx(EXIT_FAILURE, _("%s: overlapping encrypted loop device exists"), file);
}
- lc->info.lo_flags &= !LO_FLAGS_AUTOCLEAR;
- if (loopcxt_set_status(lc)) {
+ lc->info.lo_flags &= ~LO_FLAGS_AUTOCLEAR;
+ if (loopcxt_ioctl_status(lc)) {
loopcxt_deinit(lc);
errx(EXIT_FAILURE, _("%s: failed to re-use loop device"), file);
}
loopcxt_set_sizelimit(lc, sizelimit);
if (lo_flags)
loopcxt_set_flags(lc, lo_flags);
+ if (blocksize > 0)
+ loopcxt_set_blocksize(lc, blocksize);
+
if ((rc = loopcxt_set_backing_file(lc, file))) {
warn(_("%s: failed to use backing file"), file);
break;
struct loopdev_cxt lc;
int act = 0, flags = 0, no_overlap = 0, c;
char *file = NULL;
- uint64_t offset = 0, sizelimit = 0;
+ uint64_t offset = 0, sizelimit = 0, blocksize = 0;
int res = 0, showdev = 0, lo_flags = 0;
char *outarg = NULL;
int list = 0;
- unsigned long use_dio = 0, set_dio = 0;
+ unsigned long use_dio = 0, set_dio = 0, set_blocksize = 0;
enum {
OPT_SIZELIMIT = CHAR_MAX + 1,
OPT_SHOW,
OPT_RAW,
- OPT_DIO
+ OPT_DIO,
+ OPT_OUTPUT_ALL
};
static const struct option longopts[] = {
{ "all", no_argument, NULL, 'a' },
{ "associated", required_argument, NULL, 'j' },
{ "json", no_argument, NULL, 'J' },
{ "list", no_argument, NULL, 'l' },
+ { "sector-size", required_argument, NULL, 'b' },
{ "noheadings", no_argument, NULL, 'n' },
{ "offset", required_argument, NULL, 'o' },
{ "output", required_argument, NULL, 'O' },
+ { "output-all", no_argument, NULL, OPT_OUTPUT_ALL },
{ "sizelimit", required_argument, NULL, OPT_SIZELIMIT },
{ "partscan", no_argument, NULL, 'P' },
{ "read-only", no_argument, NULL, 'r' },
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
- atexit(close_stdout);
+ close_stdout_atexit();
if (loopcxt_init(&lc, 0))
err(EXIT_FAILURE, _("failed to initialize loopcxt"));
- while ((c = getopt_long(argc, argv, "ac:d:Dfhj:JlLno:O:PrvV",
+ while ((c = getopt_long(argc, argv, "ab:c:d:Dfhj:JlLno:O:PrvV",
longopts, NULL)) != -1) {
err_exclusive_options(c, longopts, excl, excl_st);
case 'a':
act = A_SHOW;
break;
+ case 'b':
+ set_blocksize = 1;
+ blocksize = strtosize_or_err(optarg, _("failed to parse logical block size"));
+ break;
case 'c':
act = A_SET_CAPACITY;
if (!is_loopdev(optarg) ||
case 'f':
act = A_FIND_FREE;
break;
- case 'h':
- usage();
- break;
case 'J':
json = 1;
break;
outarg = optarg;
list = 1;
break;
+ case OPT_OUTPUT_ALL:
+ for (ncolumns = 0; ncolumns < ARRAY_SIZE(infos); ncolumns++)
+ columns[ncolumns] = ncolumns;
+ break;
case 'P':
lo_flags |= LO_FLAGS_PARTSCAN;
break;
break;
case 'v':
break;
- case 'V':
- printf(UTIL_LINUX_VERSION);
- return EXIT_SUCCESS;
case OPT_SIZELIMIT: /* --sizelimit */
sizelimit = strtosize_or_err(optarg, _("failed to parse size"));
flags |= LOOPDEV_FL_SIZELIMIT;
break;
+
+ case 'h':
+ usage();
+ case 'V':
+ print_version(EXIT_SUCCESS);
default:
errtryhelp(EXIT_FAILURE);
}
}
+ ul_path_init_debug();
+ ul_sysfs_init_debug();
+
/* default is --list --all */
if (argc == 1) {
act = A_SHOW;
columns[ncolumns++] = COL_RO;
columns[ncolumns++] = COL_BACK_FILE;
columns[ncolumns++] = COL_DIO;
+ columns[ncolumns++] = COL_LOGSEC;
}
if (act == A_FIND_FREE && optind < argc) {
*/
act = A_CREATE;
file = argv[optind++];
+
+ if (optind < argc)
+ errx(EXIT_FAILURE, _("unexpected arguments"));
}
if (list && !act && optind == argc)
/*
* losetup [--list] <device>
* OR
- * losetup --direct-io[=off] <device>
+ * losetup {--direct-io[=off]|--logical-blocksize=size}... <device>
*/
- if (!set_dio)
+ if (!(set_dio || set_blocksize))
act = A_SHOW_ONE;
- else
+ if (set_dio)
act = A_SET_DIRECT_IO;
+ if (set_blocksize)
+ act = A_SET_BLOCKSIZE;
if (!is_loopdev(argv[optind]) ||
loopcxt_set_device(&lc, argv[optind]))
err(EXIT_FAILURE, _("%s: failed to use device"),
(sizelimit || lo_flags || showdev))
errx(EXIT_FAILURE,
_("the options %s are allowed during loop device setup only"),
- "--{sizelimit,read-only,show}");
+ "--{sizelimit,partscan,read-only,show}");
if ((flags & LOOPDEV_FL_OFFSET) &&
act != A_CREATE && (act != A_SHOW || !file))
switch (act) {
case A_CREATE:
- res = create_loop(&lc, no_overlap, lo_flags, flags, file, offset, sizelimit);
+ res = create_loop(&lc, no_overlap, lo_flags, flags, file,
+ offset, sizelimit, blocksize);
if (res == 0) {
if (showdev)
printf("%s\n", loopcxt_get_device(&lc));
- warn_size(file, sizelimit);
+ warn_size(file, sizelimit, offset, flags);
if (set_dio)
goto lo_set_dio;
}
warn("%s", loopcxt_get_device(&lc));
break;
case A_SET_CAPACITY:
- res = loopcxt_set_capacity(&lc);
+ res = loopcxt_ioctl_capacity(&lc);
if (res)
warn(_("%s: set capacity failed"),
loopcxt_get_device(&lc));
break;
case A_SET_DIRECT_IO:
- lo_set_dio:
- res = loopcxt_set_dio(&lc, use_dio);
+lo_set_dio:
+ res = loopcxt_ioctl_dio(&lc, use_dio);
if (res)
warn(_("%s: set direct io failed"),
loopcxt_get_device(&lc));
break;
+ case A_SET_BLOCKSIZE:
+ res = loopcxt_ioctl_blocksize(&lc, blocksize);
+ if (res)
+ warn(_("%s: set logical block size failed"),
+ loopcxt_get_device(&lc));
+ break;
default:
warnx(_("bad usage"));
errtryhelp(EXIT_FAILURE);