Currently in varisous e2fsprogs tools, most notably tune2fs and e2fsck
we will get the device name by passing the user provided string into
blkid_get_devname(). This library function however is primarily intended
for parsing "NAME=value" tokens. It will return the device matching the
specified token, NULL if nothing is found, or copy of the string if it's
not in "NAME=value" format.
However in case where we're passing in a file name that contains an
equal sign blkid_get_devname() will treat it as a token and will attempt
to find the device with the match. Likely finding nothing.
Fix it by checking existence of the file first and then attempt to call
blkid_get_devname(). In case of a collision, notify the user and
automatically prefer the one returned by blkid_get_devname(). Otherwise
return either the existing file, or NULL.
We do it this way to avoid some existing file in working directory (for
example LABEL=volume-name) masking an actual device containing the
matchin LABEL. User can specify full, or relative path (e.g.
./LABEL=volume-name) to make sure the file is used instead.
Link: https://lore.kernel.org/r/20220812130122.69468-1-lczerner@redhat.com
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Reported-by: Daniel Ng <danielng@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
$(top_srcdir)/lib/ext2fs/fast_commit.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
$(top_srcdir)/lib/ext2fs/kernel-list.h $(top_srcdir)/lib/ext2fs/compiler.h \
$(srcdir)/problem.h $(srcdir)/jfs_user.h \
- $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/version.h
+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/version.h \
+ $(top_srcdir)/lib/support/devname.h
dirinfo.o: $(srcdir)/dirinfo.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
#include "e2p/e2p.h"
#include "uuid/uuid.h"
#include "support/plausible.h"
+#include "support/devname.h"
#include "e2fsck.h"
#include "problem.h"
#include "jfs_user.h"
goto sscanf_err;
break;
case 'j':
- ctx->journal_name = blkid_get_devname(ctx->blkid,
- optarg, NULL);
+ ctx->journal_name = get_devname(ctx->blkid,
+ optarg, NULL);
if (!ctx->journal_name) {
com_err(ctx->program_name, 0,
_("Unable to resolve '%s'"),
ctx->io_options = strchr(argv[optind], '?');
if (ctx->io_options)
*ctx->io_options++ = 0;
- ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0);
+ ctx->filesystem_name = get_devname(ctx->blkid, argv[optind], 0);
if (!ctx->filesystem_name) {
com_err(ctx->program_name, 0, _("Unable to resolve '%s'"),
argv[optind]);
quotaio.o \
quotaio_v2.o \
quotaio_tree.o \
- dict.o
+ dict.o \
+ devname.o
SRCS= $(srcdir)/argv_parse.c \
$(srcdir)/cstring.c \
$(srcdir)/quotaio.c \
$(srcdir)/quotaio_tree.c \
$(srcdir)/quotaio_v2.c \
- $(srcdir)/dict.c
+ $(srcdir)/dict.c \
+ $(srcdir)/devname.c
LIBRARY= libsupport
LIBDIR= support
$(srcdir)/quotaio_tree.h
dict.o: $(srcdir)/dict.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/dict.h
+devname.o: $(srcdir)/devname.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/nls-enable.h $(srcdir)/devname.h
--- /dev/null
+/*
+ * devname.c --- Support function to translate a user provided string
+ * identifying a device to an actual device path
+ *
+ * Copyright (C) 2022 Red Hat, Inc., Lukas Czerner <lczerner@redhat.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "devname.h"
+#include "nls-enable.h"
+
+/*
+ * blkid_get_devname() is primarily intended for parsing "NAME=value"
+ * tokens. It will return the device matching the specified token, NULL if
+ * nothing is found, or copy of the string if it's not in "NAME=value"
+ * format.
+ * get_devname() takes the same parameters and works the same way as
+ * blkid_get_devname() except it can handle '=' in the file name.
+ */
+char *get_devname(blkid_cache cache, const char *token, const char *value)
+{
+ int is_file = 0;
+ char *ret = NULL;
+
+ if (!token)
+ goto out;
+
+ if (value) {
+ ret = blkid_get_devname(cache, token, value);
+ goto out;
+ }
+
+ if (access(token, F_OK) == 0)
+ is_file = 1;
+
+ ret = blkid_get_devname(cache, token, NULL);
+ if (ret) {
+ /*
+ * In case of collision prefer the result from
+ * blkid_get_devname() to avoid a file masking file system with
+ * existing tag.
+ */
+ if (is_file && (strcmp(ret, token) != 0)) {
+ fprintf(stderr,
+ _("Collision found: '%s' refers to both '%s' "
+ "and a file '%s'. Using '%s'!\n"),
+ token, ret, token, ret);
+ }
+ goto out;
+ }
+
+out_strdup:
+ if (is_file)
+ ret = strdup(token);
+out:
+ return ret;
+}
--- /dev/null
+/*
+ * devname.c --- Figure out if a pathname is ext* or something else.
+ *
+ * Copyright (C) 2022 Red Hat, Inc., Lukas Czerner <lczerner@redhat.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#ifndef DEVNAME_H_
+#define DEVNAME_H_
+
+#include "blkid/blkid.h"
+
+char *get_devname(blkid_cache cache, const char *token, const char *value);
+
+#endif /* DEVNAME_H_ */
$(STATIC_LIBS) $(STATIC_LIBE2P) $(STATIC_LIBUUID) \
$(LIBINTL) $(SYSLIBS) $(STATIC_LIBBLKID) $(LIBMAGIC)
-fsck: $(FSCK_OBJS) $(DEPLIBBLKID)
+fsck: $(FSCK_OBJS) $(DEPLIBBLKID) $(DEPLIBS)
$(E) " LD $@"
$(Q) $(CC) $(ALL_LDFLAGS) -o fsck $(FSCK_OBJS) $(LIBBLKID) \
- $(LIBINTL) $(SYSLIBS)
+ $(LIBINTL) $(SYSLIBS) $(LIBS)
-fsck.profiled: $(FSCK_OBJS) $(PROFILED_DEPLIBBLKID)
+fsck.profiled: $(FSCK_OBJS) $(PROFILED_DEPLIBBLKID) $(PROFILED_DEPLIBS)
$(E) " LD $@"
$(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o fsck.profiled $(PROFILED_FSCK_OBJS) \
- $(PROFILED_LIBBLKID) $(LIBINTL) $(SYSLIBS)
+ $(PROFILED_LIBBLKID) $(LIBINTL) $(SYSLIBS) $(PROFILED_LIBS)
badblocks: $(BADBLOCKS_OBJS) $(DEPLIBS)
$(E) " LD $@"
$(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h \
$(top_srcdir)/lib/ext2fs/compiler.h $(top_srcdir)/lib/support/plausible.h \
$(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \
- $(top_srcdir)/lib/support/quotaio_tree.h $(top_srcdir)/lib/e2p/e2p.h \
- $(srcdir)/util.h $(top_srcdir)/version.h \
+ $(top_srcdir)/lib/support/quotaio_tree.h $(top_srcdir)/lib/support/devname.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(srcdir)/util.h $(top_srcdir)/version.h \
$(top_srcdir)/lib/support/nls-enable.h
mklost+found.o: $(srcdir)/mklost+found.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
$(top_srcdir)/lib/ext2fs/bitops.h $(top_srcdir)/lib/support/nls-enable.h
fsck.o: $(srcdir)/fsck.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/version.h \
- $(top_srcdir)/lib/support/nls-enable.h $(srcdir)/fsck.h
+ $(top_srcdir)/lib/support/nls-enable.h $(top_srcdir)/lib/support/devname.h \
+ $(srcdir)/fsck.h
util.o: $(srcdir)/util.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_err.h \
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/hashmap.h \
$(top_srcdir)/lib/ext2fs/bitops.h $(top_srcdir)/lib/support/nls-enable.h \
- $(srcdir)/util.h
+ $(srcdir)/util.h $(top_srcdir)/lib/support/devname.h
uuidgen.o: $(srcdir)/uuidgen.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/support/nls-enable.h
blkid.o: $(srcdir)/blkid.c $(top_builddir)/lib/config.h \
#include "ext2fs/ext2fs.h"
#include "blkid/blkid.h"
#include "support/nls-enable.h"
+#include "support/devname.h"
#include "../version.h"
parse_escape(freq);
parse_escape(passno);
- dev = blkid_get_devname(cache, device, NULL);
+ dev = get_devname(cache, device, NULL);
if (dev)
device = dev;
}
if (optind < argc - 1 || optind == argc)
usage();
- device_name = blkid_get_devname(NULL, argv[optind], NULL);
+ device_name = get_devname(NULL, argv[optind], NULL);
if (!device_name) {
com_err(program_name, 0, _("Unable to resolve '%s'"),
argv[optind]);
#endif
#include "../version.h"
+#include "support/devname.h"
#include "support/nls-enable.h"
#include "fsck.h"
#include "blkid/blkid.h"
parse_escape(freq);
parse_escape(passno);
- dev = blkid_get_devname(cache, device, NULL);
+ dev = get_devname(cache, device, NULL);
if (dev)
device = dev;
progname);
exit(EXIT_ERROR);
}
- dev = blkid_get_devname(cache, arg, NULL);
+ dev = get_devname(cache, arg, NULL);
if (!dev && strchr(arg, '=')) {
/*
* Check to see if we failed because
#include "et/com_err.h"
#include "support/plausible.h"
#include "support/quotaio.h"
+#include "support/devname.h"
#include "uuid/uuid.h"
#include "e2p/e2p.h"
#include "util.h"
io_options = strchr(argv[1], '?');
if (io_options)
*io_options++ = 0;
- device_name = blkid_get_devname(NULL, argv[1], NULL);
+ device_name = get_devname(NULL, argv[1], NULL);
if (!device_name) {
com_err("e2label", 0, _("Unable to resolve '%s'"),
argv[1]);
io_options = strchr(argv[optind], '?');
if (io_options)
*io_options++ = 0;
- device_name = blkid_get_devname(NULL, argv[optind], NULL);
+ device_name = get_devname(NULL, argv[optind], NULL);
if (!device_name) {
com_err(program_name, 0, _("Unable to resolve '%s'"),
argv[optind]);
#include "ext2fs/ext2_fs.h"
#include "ext2fs/ext2fs.h"
#include "support/nls-enable.h"
+#include "support/devname.h"
#include "blkid/blkid.h"
#include "util.h"
arg ? arg : "NONE");
#endif
if (strcmp(token, "device") == 0) {
- journal_device = blkid_get_devname(NULL, arg, NULL);
+ journal_device = get_devname(NULL, arg, NULL);
if (!journal_device) {
if (arg)
fprintf(stderr, _("\nCould not find "