diff options
Diffstat (limited to '')
-rw-r--r-- | sys-utils/losetup.c | 157 |
1 files changed, 117 insertions, 40 deletions
diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c index 1705379..7134542 100644 --- a/sys-utils/losetup.c +++ b/sys-utils/losetup.c @@ -1,6 +1,14 @@ /* - * Copyright (C) 2011 Karel Zak <kzak@redhat.com> - * Originally from Ted's losetup.c + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Original implementation from Ted Ts'o; losetup was part of mount. + * + * Copyright (C) 2011-2023 Karel Zak <kzak@redhat.com> * * losetup.c - setup and control loop devices */ @@ -45,9 +53,14 @@ enum { COL_BACK_FILE, COL_BACK_INO, COL_BACK_MAJMIN, + COL_BACK_MAJ, + COL_BACK_MIN, COL_MAJMIN, + COL_MAJ, + COL_MIN, COL_OFFSET, COL_PARTSCAN, + COL_REF, COL_RO, COL_SIZELIMIT, COL_DIO, @@ -60,7 +73,7 @@ static int raw; static int json; struct colinfo { - const char *name; + const char * const name; double whint; int flags; const char *help; @@ -68,17 +81,22 @@ struct colinfo { int json_type; /* default is string */ }; -static struct colinfo infos[] = { +static const struct colinfo infos[] = { [COL_AUTOCLR] = { "AUTOCLEAR", 1, SCOLS_FL_RIGHT, N_("autoclear flag set"), SCOLS_JSON_BOOLEAN}, [COL_BACK_FILE] = { "BACK-FILE", 0.3, SCOLS_FL_NOEXTREMES, N_("device backing file")}, [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_BACK_MAJ] = { "BACK-MAJ", 6, 0, N_("backing file major device number")}, + [COL_BACK_MIN] = { "BACK-MIN", 6, 0, N_("backing file 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"), SCOLS_JSON_NUMBER}, [COL_PARTSCAN] = { "PARTSCAN", 1, SCOLS_FL_RIGHT, N_("partscan flag set"), SCOLS_JSON_BOOLEAN}, + [COL_REF] = { "REF", 0.1, 0, N_("loop device reference string")}, [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_MAJ] = { "MAJ", 1, SCOLS_FL_RIGHT, N_("loop device major number"), SCOLS_JSON_NUMBER}, + [COL_MIN] = { "MIN", 1, SCOLS_FL_RIGHT, N_("loop device minor number"), SCOLS_JSON_NUMBER}, [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}, }; @@ -94,7 +112,7 @@ static int get_column_id(int num) return columns[num]; } -static struct colinfo *get_column_info(int num) +static const struct colinfo *get_column_info(int num) { return &infos[ get_column_id(num) ]; } @@ -133,23 +151,26 @@ static int printf_loopdev(struct loopdev_cxt *lc) * Probably non-root user (no permissions to * call LOOP_GET_STATUS ioctls). */ - printf("%s: []: (%s)", - loopcxt_get_device(lc), fname); + printf("%s%s: []: (%s)", + loopcxt_get_device(lc), + loopcxt_is_lost(lc) ? " (lost)" : "", + fname); if (loopcxt_get_offset(lc, &x) == 0 && x) printf(_(", offset %ju"), x); - if (loopcxt_get_sizelimit(lc, &x) == 0 && x) printf(_(", sizelimit %ju"), x); + goto done; } - printf("%s: [%04jd]:%ju (%s)", - loopcxt_get_device(lc), (intmax_t) dev, (uintmax_t) ino, fname); + printf("%s%s: [%04jd]:%ju (%s)", + loopcxt_get_device(lc), + loopcxt_is_lost(lc) ? " (lost)" : "", + (intmax_t) dev, (uintmax_t) ino, fname); if (loopcxt_get_offset(lc, &x) == 0 && x) printf(_(", offset %ju"), x); - if (loopcxt_get_sizelimit(lc, &x) == 0 && x) printf(_(", sizelimit %ju"), x); @@ -200,11 +221,24 @@ static int show_all_loops(struct loopdev_cxt *lc, const char *file, return 0; } +static void warn_lost(struct loopdev_cxt *lc) +{ + dev_t devno = loopcxt_get_devno(lc); + + if (devno <= 0) + return; + + warnx(("device node %s (%u:%u) is lost. You may use mknod(1) to recover it."), + loopcxt_get_device(lc), major(devno), minor(devno)); +} + static int delete_loop(struct loopdev_cxt *lc) { - if (loopcxt_delete_device(lc)) + if (loopcxt_delete_device(lc)) { warn(_("%s: detach failed"), loopcxt_get_device(lc)); - else + if (loopcxt_is_lost(lc)) + warn_lost(lc); + } else return 0; return -1; @@ -237,6 +271,10 @@ static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln) switch(get_column_id(i)) { case COL_NAME: p = loopcxt_get_device(lc); + if (loopcxt_is_lost(lc)) { + xasprintf(&np, "%s (lost)", p); + p = NULL; + } break; case COL_BACK_FILE: np = loopcxt_get_backing_file(lc); @@ -257,16 +295,38 @@ static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln) major(dev), minor(dev)); break; } + case COL_BACK_MAJ: + { + dev_t dev = 0; + if (loopcxt_get_backing_devno(lc, &dev) == 0 && dev) + xasprintf(&np, "%u", major(dev)); + break; + } + case COL_BACK_MIN: + { + dev_t dev = 0; + if (loopcxt_get_backing_devno(lc, &dev) == 0 && dev) + xasprintf(&np, "%u", minor(dev)); + break; + } case COL_MAJMIN: { - struct stat st; - - if (loopcxt_get_device(lc) - && stat(loopcxt_get_device(lc), &st) == 0 - && S_ISBLK(st.st_mode) - && major(st.st_rdev) == LOOPDEV_MAJOR) + dev_t dev = loopcxt_get_devno(lc); + if (dev) xasprintf(&np, raw || json ? "%u:%u" :"%3u:%-3u", - major(st.st_rdev), minor(st.st_rdev)); + major(dev), minor(dev)); + break; + } + case COL_MAJ: { + dev_t dev = loopcxt_get_devno(lc); + if (dev) + xasprintf(&np, "%u", major(dev)); + break; + } + case COL_MIN: { + dev_t dev = loopcxt_get_devno(lc); + if (dev) + xasprintf(&np, "%u", minor(dev)); break; } case COL_BACK_INO: @@ -292,6 +352,9 @@ static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln) if (loopcxt_get_blocksize(lc, &x) == 0) xasprintf(&np, "%jd", x); break; + case COL_REF: + np = loopcxt_get_refname(lc); + break; default: return -EINVAL; } @@ -332,7 +395,7 @@ static int show_table(struct loopdev_cxt *lc, scols_table_set_name(tb, "loopdevices"); for (i = 0; i < ncolumns; i++) { - struct colinfo *ci = get_column_info(i); + const struct colinfo *ci = get_column_info(i); struct libscols_column *cl; cl = scols_table_new_column(tb, ci->name, ci->whint, ci->flags); @@ -424,6 +487,7 @@ static void __attribute__((__noreturn__)) usage(void) 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(_(" --loop-ref <string> loop device reference\n"), out); fputs(_(" --show print device name after setup (with -f)\n"), out); fputs(_(" -v, --verbose verbose mode\n"), out); @@ -437,13 +501,13 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" --raw use raw --list output format\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(31)); + fprintf(out, USAGE_HELP_OPTIONS(31)); fputs(USAGE_COLUMNS, out); for (i = 0; i < ARRAY_SIZE(infos); i++) fprintf(out, " %12s %s\n", infos[i].name, _(infos[i].help)); - printf(USAGE_MAN_TAIL("losetup(8)")); + fprintf(out, USAGE_MAN_TAIL("losetup(8)")); exit(EXIT_SUCCESS); } @@ -466,8 +530,8 @@ static void warn_size(const char *filename, uint64_t size, uint64_t offset, int "may 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."), + warnx(_("%s: Warning: file does not end on a 512-byte sector boundary; " + "the remaining end of the file will be ignored."), filename); } @@ -492,7 +556,8 @@ static int find_unused(struct loopdev_cxt *lc) 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, const char *refname, + uint64_t offset, uint64_t sizelimit, uint64_t blocksize) { int hasdev = loopcxt_has_device(lc); @@ -581,7 +646,10 @@ static int create_loop(struct loopdev_cxt *lc, loopcxt_set_flags(lc, lo_flags); if (blocksize > 0) loopcxt_set_blocksize(lc, blocksize); - + if (refname && (rc = loopcxt_set_refname(lc, refname))) { + warnx(_("cannot set loop reference string")); + break; + } if ((rc = loopcxt_set_backing_file(lc, file))) { warn(_("%s: failed to use backing file"), file); break; @@ -598,7 +666,7 @@ static int create_loop(struct loopdev_cxt *lc, } /* errors */ - errpre = hasdev && loopcxt_get_fd(lc) < 0 ? + errpre = hasdev && lc->fd < 0 ? loopcxt_get_device(lc) : file; warn(_("%s: failed to set up loop device"), errpre); break; @@ -611,7 +679,7 @@ int main(int argc, char **argv) { struct loopdev_cxt lc; int act = 0, flags = 0, no_overlap = 0, c; - char *file = NULL; + char *file = NULL, *refname = NULL; uint64_t offset = 0, sizelimit = 0, blocksize = 0; int res = 0, showdev = 0, lo_flags = 0; char *outarg = NULL; @@ -622,6 +690,7 @@ int main(int argc, char **argv) OPT_SIZELIMIT = CHAR_MAX + 1, OPT_SHOW, OPT_RAW, + OPT_REF, OPT_DIO, OPT_OUTPUT_ALL }; @@ -646,6 +715,7 @@ int main(int argc, char **argv) { "read-only", no_argument, NULL, 'r' }, { "direct-io", optional_argument, NULL, OPT_DIO }, { "raw", no_argument, NULL, OPT_RAW }, + { "loop-ref", required_argument, NULL, OPT_REF, }, { "show", no_argument, NULL, OPT_SHOW }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, @@ -684,18 +754,19 @@ int main(int argc, char **argv) break; case 'c': act = A_SET_CAPACITY; - if (!is_loopdev(optarg) || - 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 OPT_REF: + refname = optarg; + break; case 'd': act = A_DELETE; - if (!is_loopdev(optarg) || - loopcxt_set_device(&lc, optarg)) + if (loopcxt_set_device(&lc, optarg)) err(EXIT_FAILURE, _("%s: failed to use device"), optarg); break; @@ -733,6 +804,7 @@ int main(int argc, char **argv) list = 1; break; case OPT_OUTPUT_ALL: + list = 1; for (ncolumns = 0; ncolumns < ARRAY_SIZE(infos); ncolumns++) columns[ncolumns] = ncolumns; break; @@ -822,8 +894,7 @@ int main(int argc, char **argv) else act = A_SHOW_ONE; - if (!is_loopdev(argv[optind]) || - loopcxt_set_device(&lc, argv[optind])) + if (loopcxt_set_device(&lc, argv[optind])) err(EXIT_FAILURE, _("%s: failed to use device"), argv[optind]); optind++; @@ -863,7 +934,7 @@ int main(int argc, char **argv) switch (act) { case A_CREATE: - res = create_loop(&lc, no_overlap, lo_flags, flags, file, + res = create_loop(&lc, no_overlap, lo_flags, flags, file, refname, offset, sizelimit, blocksize); if (res == 0) { if (showdev) @@ -874,8 +945,7 @@ int main(int argc, char **argv) case A_DELETE: res = delete_loop(&lc); while (optind < argc) { - if (!is_loopdev(argv[optind]) || - loopcxt_set_device(&lc, argv[optind])) + if (loopcxt_set_device(&lc, argv[optind])) warn(_("%s: failed to use device"), argv[optind]); optind++; @@ -888,7 +958,8 @@ int main(int argc, char **argv) case A_FIND_FREE: res = find_unused(&lc); if (!res) - printf("%s\n", loopcxt_get_device(&lc)); + printf("%s%s\n", loopcxt_get_device(&lc), + loopcxt_is_lost(&lc) ? " (lost)" : ""); break; case A_SHOW: if (list) @@ -928,7 +999,13 @@ int main(int argc, char **argv) break; } + if (res && (act == A_SET_CAPACITY + || act == A_CREATE + || act == A_SET_DIRECT_IO + || act == A_SET_BLOCKSIZE) + && loopcxt_is_lost(&lc)) + warn_lost(&lc); + loopcxt_deinit(&lc); return res ? EXIT_FAILURE : EXIT_SUCCESS; } - |