unsigned int control_ok:1; /* /dev/loop-control success */
struct path_cxt *sysfs; /* pointer to /sys/dev/block/<maj:min>/ */
- struct loop_config config; /* for GET/SET ioctl */
+ struct loop_config config; /* for GET/SET ioctl */
struct loopdev_iter iter; /* scans /sys or /dev for used/free devices */
};
int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize);
int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags);
int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename);
+int loopcxt_set_refname(struct loopdev_cxt *lc, const char *refname);
extern char *loopcxt_get_backing_file(struct loopdev_cxt *lc);
+extern char *loopcxt_get_refname(struct loopdev_cxt *lc);
extern int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno);
extern int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino);
extern int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset);
return res;
}
+/*
+ * @lc: context
+ *
+ * Returns (allocated) string with loop reference. The same as backing file by
+ * default.
+ */
+char *loopcxt_get_refname(struct loopdev_cxt *lc)
+{
+ char *res = NULL;
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+
+ if (lo) {
+ lo->lo_file_name[LO_NAME_SIZE - 1] = '\0';
+ res = strdup((char *) lo->lo_file_name);
+ }
+
+ DBG(CXT, ul_debugobj(lc, "get_refname [%s]", res));
+ return res;
+}
+
/*
* @lc: context
* @offset: returns offset number for the given device
return 0;
}
+/*
+ * @lc: context
+ * @refname: reference name (used to overwrite lo_file_name where is backing
+ * file by default)
+ *
+ * The setting is removed by loopcxt_set_device() loopcxt_next()!
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int loopcxt_set_refname(struct loopdev_cxt *lc, const char *refname)
+{
+ if (!lc)
+ return -EINVAL;
+
+ memset(lc->config.info.lo_file_name, 0, sizeof(lc->config.info.lo_file_name));
+ if (refname)
+ xstrncpy((char *)lc->config.info.lo_file_name, refname, LO_NAME_SIZE);
+
+ DBG(CXT, ul_debugobj(lc, "set refname=%s", (char *)lc->config.info.lo_file_name));
+ return 0;
+}
+
/*
* @lc: context
* @filename: backing file path (the path will be canonicalized)
if (!lc->filename)
return -errno;
- xstrncpy((char *)lc->config.info.lo_file_name, lc->filename, LO_NAME_SIZE);
+ if (!lc->config.info.lo_file_name[0])
+ loopcxt_set_refname(lc, lc->filename);
- DBG(CXT, ul_debugobj(lc, "set backing file=%s", lc->config.info.lo_file_name));
+ DBG(CXT, ul_debugobj(lc, "set backing file=%s", lc->filename));
return 0;
}
COL_MAJMIN,
COL_OFFSET,
COL_PARTSCAN,
+ COL_REF,
COL_RO,
COL_SIZELIMIT,
COL_DIO,
[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")},
if (loopcxt_get_blocksize(lc, &x) == 0)
xasprintf(&np, "%jd", x);
break;
+ case COL_REF:
+ np = loopcxt_get_refname(lc);
+ break;
default:
return -EINVAL;
}
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);
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);
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;
{
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;
OPT_SIZELIMIT = CHAR_MAX + 1,
OPT_SHOW,
OPT_RAW,
+ OPT_REF,
OPT_DIO,
OPT_OUTPUT_ALL
};
{ "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' },
case 'r':
lo_flags |= LO_FLAGS_READ_ONLY;
break;
+ case OPT_REF:
+ refname = optarg;
+ break;
case 'd':
act = A_DELETE;
if (!is_loopdev(optarg) ||
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)