diff options
author | Manuel Bentele | 2019-06-23 15:23:45 +0200 |
---|---|---|
committer | Manuel Bentele | 2019-06-23 15:23:45 +0200 |
commit | b800dbf06bef3004aa37dc93ec6d2a311cc8ac23 (patch) | |
tree | 060505ba4fd2a3abe654dc8478ef174a9a94c5cf | |
parent | build-sys: release++ (v2.34) (diff) | |
download | kernel-qcow2-util-linux-b800dbf06bef3004aa37dc93ec6d2a311cc8ac23.tar.gz kernel-qcow2-util-linux-b800dbf06bef3004aa37dc93ec6d2a311cc8ac23.tar.xz kernel-qcow2-util-linux-b800dbf06bef3004aa37dc93ec6d2a311cc8ac23.zip |
lib/losetup: added file format support
losetup can set the file format of each loop device during
creation.
Signed-off-by: Manuel Bentele <development@manuel-bentele.de>
-rw-r--r-- | include/loopdev.h | 14 | ||||
-rw-r--r-- | lib/loopdev.c | 86 | ||||
-rw-r--r-- | sys-utils/losetup.c | 68 |
3 files changed, 151 insertions, 17 deletions
diff --git a/include/loopdev.h b/include/loopdev.h index 0e3a7517a..bc68e526b 100644 --- a/include/loopdev.h +++ b/include/loopdev.h @@ -11,6 +11,14 @@ #define LO_CRYPT_DES 2 #define LO_CRYPT_CRYPTOAPI 18 +/* + * loop_info.lo_file_fmt_type + */ +#define LO_FILE_FMT_RAW 0 +#define LO_FILE_FMT_QCOW 1 +#define LO_FILE_FMT_VDI 2 +#define LO_FILE_FMT_VMDK 3 + #define LOOP_SET_FD 0x4C00 #define LOOP_CLR_FD 0x4C01 /* @@ -64,6 +72,7 @@ struct loop_info64 { uint8_t lo_crypt_name[LO_NAME_SIZE]; uint8_t lo_encrypt_key[LO_KEY_SIZE]; uint64_t lo_init[2]; + uint32_t lo_file_fmt_type; }; #define LOOPDEV_MAJOR 7 /* loop major number */ @@ -175,6 +184,7 @@ extern int loopcxt_ioctl_blocksize(struct loopdev_cxt *lc, uint64_t blocksize); int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset); int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit); int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize); +int loopcxt_set_file_fmt_type(struct loopdev_cxt *lc, uint32_t file_fmt_type); int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags); int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename); @@ -185,6 +195,8 @@ extern int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset); extern int loopcxt_get_blocksize(struct loopdev_cxt *lc, uint64_t *blocksize); extern int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size); extern int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type); +extern int loopcxt_get_file_fmt_type(struct loopdev_cxt *lc, uint32_t* file_fmt_type); +extern char *loopcxt_get_file_fmt_type_string(struct loopdev_cxt *lc); extern const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc); extern int loopcxt_is_autoclear(struct loopdev_cxt *lc); extern int loopcxt_is_readonly(struct loopdev_cxt *lc); @@ -205,4 +217,6 @@ extern int loopcxt_is_used(struct loopdev_cxt *lc, uint64_t sizelimit, int flags); +extern int parse_file_fmt_type(const char *file_fmt_type_str, uint32_t *file_fmt_type); + #endif /* UTIL_LINUX_LOOPDEV_H */ diff --git a/lib/loopdev.c b/lib/loopdev.c index ede1b5cdc..676cc02f3 100644 --- a/lib/loopdev.c +++ b/lib/loopdev.c @@ -824,6 +824,75 @@ int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type) } /* + * @file_fmt_type_str: file format type string. + * @file_fmt_type: returns file format type from the given file format string. + * + * Returns: <0 on error, 0 on success + */ +int parse_file_fmt_type(const char *file_fmt_type_str, uint32_t *file_fmt_type) +{ + int rc = 0; + + if (!strcmp(file_fmt_type_str, "RAW")) + *file_fmt_type = LO_FILE_FMT_RAW; + else if (!strcmp(file_fmt_type_str, "QCOW")) + *file_fmt_type = LO_FILE_FMT_QCOW; + else if (!strcmp(file_fmt_type_str, "VDI")) + *file_fmt_type = LO_FILE_FMT_VDI; + else if (!strcmp(file_fmt_type_str, "VMDK")) + *file_fmt_type = LO_FILE_FMT_VMDK; + else + rc = -EINVAL; + + return rc; +} + +/* + * @lc: context + * @file_fmt_type: returns file format type of the given device + * + * Returns: <0 on error, 0 on success + */ +int loopcxt_get_file_fmt_type(struct loopdev_cxt *lc, uint32_t* file_fmt_type) +{ + struct path_cxt *sysfs = loopcxt_get_sysfs(lc); + int rc = 0; + + if (sysfs) { + /* check if file_fmt_type is accessible and supported by the kernel module */ + char* file_fmt_str = NULL; + if (ul_path_read_string(sysfs, &file_fmt_str, "loop/file_fmt_type") == 0) + rc = parse_file_fmt_type(file_fmt_str, file_fmt_type); + } else + rc = -errno; + + if (rc != 0 && loopcxt_ioctl_enabled(lc)) { + struct loop_info64 *lo = loopcxt_get_info(lc); + if (lo) + *file_fmt_type = lo->lo_file_fmt_type; + } + + return 0; +} + +/* + * @lc: context + * + * Returns (allocated) string with file format type of the current loop device. + */ +char *loopcxt_get_file_fmt_type_string(struct loopdev_cxt *lc) +{ + struct path_cxt *sysfs = loopcxt_get_sysfs(lc); + char *res = NULL; + + if (sysfs) + ul_path_read_string(sysfs, &res, "loop/file_fmt_type"); + + DBG(CXT, ul_debugobj(lc, "loopcxt_get_file_fmt_type_string [%s]", res)); + return res; +} + +/* * @lc: context * @devno: returns crypt name * @@ -1124,6 +1193,23 @@ int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize) /* * @lc: context + * @file_fmt_type: kernel LO_FILE_FMT_{RAW,QCOW,VDI,VMDK} flags + * + * The setting is removed by loopcxt_set_device() loopcxt_next()! + * + * Returns: 0 on success, <0 on error. + */ +int loopcxt_set_file_fmt_type(struct loopdev_cxt *lc, uint32_t file_fmt_type) { + if (!lc) + return -EINVAL; + lc->info.lo_file_fmt_type = file_fmt_type; + + DBG(CXT, ul_debugobj(lc, "set file_fmt_type=%u", (unsigned) file_fmt_type)); + return 0; +} + +/* + * @lc: context * @flags: kernel LO_FLAGS_{READ_ONLY,USE_AOPS,AUTOCLEAR} flags * * The setting is removed by loopcxt_set_device() loopcxt_next()! diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c index d862fd8e7..f455b49c3 100644 --- a/sys-utils/losetup.c +++ b/sys-utils/losetup.c @@ -43,6 +43,7 @@ enum { COL_NAME = 0, COL_AUTOCLR, COL_BACK_FILE, + COL_FILE_FMT_TYPE, COL_BACK_INO, COL_BACK_MAJMIN, COL_MAJMIN, @@ -69,18 +70,19 @@ struct colinfo { }; static struct colinfo infos[] = { - [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"), 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"), 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"), SCOLS_JSON_BOOLEAN}, - [COL_LOGSEC] = { "LOG-SEC", 4, SCOLS_FL_RIGHT, N_("logical sector size in bytes"), SCOLS_JSON_NUMBER}, + [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_FILE_FMT_TYPE] = { "FILE-FORMAT", 1, 0, N_("backing file format")}, + [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"), 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"), 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}; @@ -120,11 +122,16 @@ static int printf_loopdev(struct loopdev_cxt *lc) ino_t ino = 0; char *fname; uint32_t type; + char *file_fmt_str; fname = loopcxt_get_backing_file(lc); if (!fname) return -EINVAL; + file_fmt_str = loopcxt_get_file_fmt_type_string(lc); + if (!file_fmt_str) + return -EINVAL; + if (loopcxt_get_backing_devno(lc, &dev) == 0) loopcxt_get_backing_inode(lc, &ino); @@ -141,6 +148,9 @@ static int printf_loopdev(struct loopdev_cxt *lc) if (loopcxt_get_sizelimit(lc, &x) == 0 && x) printf(_(", sizelimit %ju"), x); + + printf(_(", file-format %s"), file_fmt_str); + goto done; } @@ -162,6 +172,8 @@ static int printf_loopdev(struct loopdev_cxt *lc) printf(_(", encryption %s (type %u)"), e, type); } + printf(_(", file-format %s"), file_fmt_str); + done: free(fname); printf("\n"); @@ -241,6 +253,9 @@ static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln) case COL_BACK_FILE: p = loopcxt_get_backing_file(lc); break; + case COL_FILE_FMT_TYPE: + p = loopcxt_get_file_fmt_type_string(lc); + break; case COL_OFFSET: if (loopcxt_get_offset(lc, &x) == 0) xasprintf(&np, "%jd", x); @@ -424,6 +439,7 @@ static void __attribute__((__noreturn__)) usage(void) 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(_(" --show print device name after setup (with -f)\n"), out); + fputs(_(" -t, --type set file format type of the loop device\n"), out); fputs(_(" -v, --verbose verbose mode\n"), out); /* output options */ @@ -473,7 +489,7 @@ static void warn_size(const char *filename, uint64_t size, uint64_t offset, int static int create_loop(struct loopdev_cxt *lc, int nooverlap, int lo_flags, int flags, const char *file, uint64_t offset, uint64_t sizelimit, - uint64_t blocksize) + uint64_t blocksize, uint32_t file_fmt_type) { int hasdev = loopcxt_has_device(lc); int rc = 0; @@ -568,6 +584,12 @@ static int create_loop(struct loopdev_cxt *lc, warn(_("%s: failed to use backing file"), file); break; } + + if ((rc = loopcxt_set_file_fmt_type(lc, file_fmt_type))) { + warn(_("failed to use backing file format type")); + break; + } + errno = 0; rc = loopcxt_setup_device(lc); if (rc == 0) @@ -595,6 +617,8 @@ int main(int argc, char **argv) char *outarg = NULL; int list = 0; unsigned long use_dio = 0, set_dio = 0, set_blocksize = 0; + int use_file_fmt_type = 0; + uint32_t file_fmt_type = 0; enum { OPT_SIZELIMIT = CHAR_MAX + 1, @@ -625,6 +649,7 @@ int main(int argc, char **argv) { "direct-io", optional_argument, NULL, OPT_DIO }, { "raw", no_argument, NULL, OPT_RAW }, { "show", no_argument, NULL, OPT_SHOW }, + { "type", required_argument, NULL, 't' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } @@ -647,7 +672,7 @@ int main(int argc, char **argv) if (loopcxt_init(&lc, 0)) err(EXIT_FAILURE, _("failed to initialize loopcxt")); - while ((c = getopt_long(argc, argv, "ab:c:d:Dfhj:JlLno:O:PrvV", + while ((c = getopt_long(argc, argv, "ab:c:d:Dfhj:JlLno:O:Prt:vV", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); @@ -725,6 +750,14 @@ int main(int argc, char **argv) if (optarg) use_dio = parse_switch(optarg, _("argument error"), "on", "off", NULL); break; + case 't': + if (optarg) { + if (parse_file_fmt_type(optarg, &file_fmt_type) == 0) + use_file_fmt_type = 1; + else + errx(EXIT_FAILURE, _("failed to parse file format type")); + } + break; case 'v': break; case OPT_SIZELIMIT: /* --sizelimit */ @@ -763,6 +796,7 @@ int main(int argc, char **argv) columns[ncolumns++] = COL_AUTOCLR; columns[ncolumns++] = COL_RO; columns[ncolumns++] = COL_BACK_FILE; + columns[ncolumns++] = COL_FILE_FMT_TYPE; columns[ncolumns++] = COL_DIO; columns[ncolumns++] = COL_LOGSEC; } @@ -822,10 +856,10 @@ int main(int argc, char **argv) } if (act != A_CREATE && - (sizelimit || lo_flags || showdev)) + (sizelimit || lo_flags || showdev || use_file_fmt_type)) errx(EXIT_FAILURE, _("the options %s are allowed during loop device setup only"), - "--{sizelimit,partscan,read-only,show}"); + "--{sizelimit,partscan,read-only,show,type}"); if ((flags & LOOPDEV_FL_OFFSET) && act != A_CREATE && (act != A_SHOW || !file)) @@ -838,7 +872,7 @@ int main(int argc, char **argv) switch (act) { case A_CREATE: res = create_loop(&lc, no_overlap, lo_flags, flags, file, - offset, sizelimit, blocksize); + offset, sizelimit, blocksize, file_fmt_type); if (res == 0) { if (showdev) printf("%s\n", loopcxt_get_device(&lc)); |