char device[128]; /* device path (e.g. /dev/loop<N>) */
char *filename; /* backing file for loopcxt_set_... */
int fd; /* open(/dev/looo<N>) */
+ dev_t devno; /* loop device devno from /sys */
mode_t mode; /* fd mode O_{RDONLY,RDWR} */
uint64_t blocksize; /* used by loopcxt_setup_device() */
unsigned int extra_check:1; /* unusual stuff for iterator */
unsigned int info_failed:1; /* LOOP_GET_STATUS ioctl failed */
unsigned int control_ok:1; /* /dev/loop-control success */
+ unsigned int is_lost:1; /* device in /sys, but missing in /dev */
struct path_cxt *sysfs; /* pointer to /sys/dev/block/<maj:min>/ */
struct loop_config config; /* for GET/SET ioctl */
extern int loopdev_is_autoclear(const char *device);
extern char *loopdev_get_backing_file(const char *device);
+extern dev_t loopcxt_get_devno(struct loopdev_cxt *lc);
extern int loopdev_has_backing_file(const char *device);
+extern int loopcxt_is_lost(struct loopdev_cxt *lc);
extern int loopdev_is_used(const char *device, const char *filename,
uint64_t offset, uint64_t sizelimit, int flags);
extern char *loopdev_find_by_backing_file(const char *filename,
DBG(CXT, ul_debugobj(lc, "closing old open fd"));
}
lc->fd = -1;
+ lc->is_lost = 0;
+ lc->devno = 0;
lc->mode = O_RDONLY;
lc->blocksize = 0;
lc->has_info = 0;
return lc && *lc->device;
}
+dev_t loopcxt_get_devno(struct loopdev_cxt *lc)
+{
+ if (!lc || !loopcxt_has_device(lc))
+ return 0;
+ if (!lc->devno)
+ lc->devno = sysfs_devname_to_devno(lc->device);
+ return lc->devno;
+}
+
+int loopcxt_is_lost(struct loopdev_cxt *lc)
+{
+ if (!lc || !loopcxt_has_device(lc))
+ return 0;
+ if (lc->is_lost)
+ return 1;
+
+ lc->is_lost = access(lc->device, F_OK) != 0
+ && loopcxt_get_devno(lc) != 0;
+
+ return lc->is_lost;
+}
+
/*
* @lc: context
* @flags: LOOPDEV_FL_* flags
return NULL;
if (!lc->sysfs) {
- dev_t devno = sysfs_devname_to_devno(lc->device);
+ dev_t devno = loopcxt_get_devno(lc);
if (!devno) {
DBG(CXT, ul_debugobj(lc, "sysfs: failed devname to devno"));
return NULL;
!(lc->iter.flags & LOOPITER_FL_FREE))
return 0; /* caller does not care about device status */
- if (!is_loopdev(lc->device)) {
- DBG(ITER, ul_debugobj(&lc->iter, "%s does not exist", lc->device));
- return -errno;
- }
-
- DBG(ITER, ul_debugobj(&lc->iter, "%s exist", lc->device));
-
used = loopcxt_get_offset(lc, NULL) == 0;
if ((lc->iter.flags & LOOPITER_FL_USED) && used)
/*
* @lc: context
- * @devno: returns encryption type
+ * @type: returns encryption type
*
* Cryptoloop is DEPRECATED!
*
/*
* @lc: context
- * @devno: returns crypt name
*
* Cryptoloop is DEPRECATED!
*
* 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);
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;
return res;
}
-static dev_t get_device_devno(struct loopdev_cxt *lc, struct stat *st)
-{
- if (st->st_rdev)
- return st->st_rdev;
-
- if (loopcxt_get_device(lc)
- && stat(loopcxt_get_device(lc), st) == 0
- && S_ISBLK(st->st_mode)
- && major(st->st_rdev) == LOOPDEV_MAJOR)
- return st->st_rdev;
-
- return 0;
-}
-
static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln)
{
size_t i;
- struct stat st = { .st_rdev = 0 };
for (i = 0; i < ncolumns; i++) {
const char *p = NULL; /* external data */
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);
}
case COL_MAJMIN:
{
- dev_t dev = get_device_devno(lc, &st);
+ dev_t dev = loopcxt_get_devno(lc);
if (dev)
xasprintf(&np, raw || json ? "%u:%u" :"%3u:%-3u",
major(dev), minor(dev));
break;
}
case COL_MAJ: {
- dev_t dev = get_device_devno(lc, &st);
+ dev_t dev = loopcxt_get_devno(lc);
if (dev)
xasprintf(&np, "%u", major(dev));
break;
}
case COL_MIN: {
- dev_t dev = get_device_devno(lc, &st);
+ dev_t dev = loopcxt_get_devno(lc);
if (dev)
xasprintf(&np, "%u", minor(dev));
break;
}
/* 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;
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;
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;
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++;
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++;
break;
}
+ if (res && (act == A_SET_CAPACITY
+ || 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;
}