474 lines
16 KiB
Diff
474 lines
16 KiB
Diff
From 52a921e1276748f9de7115078fd2999e750299c0 Mon Sep 17 00:00:00 2001
|
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
Date: Thu, 5 Feb 2026 13:17:38 +0000
|
|
Subject: [PATCH] filesystems: Optionally display filesystem version
|
|
|
|
Unlike the recent change to virt-inspector (commit bb210ca433
|
|
("inspector: For xfs, try to find and print the filesystem version"))
|
|
this does not require the ability to mount the XFS v4 filesystem so it
|
|
will work on RHEL 10.
|
|
|
|
$ virt-filesystems -a rhel-7.0.img --long --fs-version
|
|
Name Type VFS Label Size Parent FSVersion
|
|
/dev/sda1 filesystem ext4 - 510873600 - -
|
|
/dev/sda3 filesystem xfs - 4820303872 - 4
|
|
|
|
$ virt-filesystems -a rhel-7.3.img --long --fs-version
|
|
Name Type VFS Label Size Parent FSVersion
|
|
/dev/sda1 filesystem ext4 - 510873600 - -
|
|
/dev/sda3 filesystem xfs - 4820303872 - 5
|
|
|
|
Fixes: https://issues.redhat.com/browse/RHEL-144074
|
|
(cherry picked from commit fc61c9439d84fdaab71e1628eb5b95f18ff40ce1)
|
|
---
|
|
.gitignore | 1 +
|
|
filesystems/Makefile.am | 6 +++-
|
|
filesystems/filesystems.c | 46 ++++++++++++++++++------
|
|
filesystems/utils.c | 60 ++++++++++++++++++++++++++++++++
|
|
filesystems/utils.h | 30 ++++++++++++++++
|
|
filesystems/virt-filesystems.pod | 12 ++++++-
|
|
inspector/Makefile.am | 6 +++-
|
|
inspector/inspector.c | 39 ++-------------------
|
|
8 files changed, 150 insertions(+), 50 deletions(-)
|
|
create mode 100644 filesystems/utils.c
|
|
create mode 100644 filesystems/utils.h
|
|
|
|
diff --git a/.gitignore b/.gitignore
|
|
index ed850a20f..0b26da37b 100644
|
|
--- a/.gitignore
|
|
+++ b/.gitignore
|
|
@@ -18,6 +18,7 @@
|
|
stamp-*.pod
|
|
|
|
.deps
|
|
+.dirstamp
|
|
.libs
|
|
Makefile
|
|
Makefile.in
|
|
diff --git a/filesystems/Makefile.am b/filesystems/Makefile.am
|
|
index 17e3b9c6f..625592ff3 100644
|
|
--- a/filesystems/Makefile.am
|
|
+++ b/filesystems/Makefile.am
|
|
@@ -25,7 +25,11 @@ EXTRA_DIST = \
|
|
|
|
bin_PROGRAMS = virt-filesystems
|
|
|
|
-virt_filesystems_SOURCES = filesystems.c
|
|
+virt_filesystems_SOURCES = \
|
|
+ filesystems.c \
|
|
+ utils.c \
|
|
+ utils.h \
|
|
+ $(NULL)
|
|
|
|
virt_filesystems_CPPFLAGS = \
|
|
-DGUESTFS_NO_DEPRECATED=1 \
|
|
diff --git a/filesystems/filesystems.c b/filesystems/filesystems.c
|
|
index ecaeb0bb2..e86d92be0 100644
|
|
--- a/filesystems/filesystems.c
|
|
+++ b/filesystems/filesystems.c
|
|
@@ -39,6 +39,7 @@
|
|
#include "structs-cleanups.h"
|
|
#include "options.h"
|
|
#include "display-options.h"
|
|
+#include "utils.h"
|
|
|
|
/* These globals are shared with options.c. */
|
|
guestfs_h *g;
|
|
@@ -75,7 +76,8 @@ static int output = 0;
|
|
#define COLUMN_SIZE 32 /* bytes, or human-readable if -h */
|
|
#define COLUMN_PARENTS 64
|
|
#define COLUMN_UUID 128 /* if --uuid */
|
|
-#define NR_COLUMNS 8
|
|
+#define COLUMN_FS_VERSION 256 /* if --fs-version */
|
|
+#define NR_COLUMNS 9
|
|
static int columns;
|
|
|
|
static void do_output_title (void);
|
|
@@ -111,6 +113,8 @@ usage (int status)
|
|
" --extra Display swap and data filesystems\n"
|
|
" --filesystems Display mountable filesystems\n"
|
|
" --format[=raw|..] Force disk format for -a option\n"
|
|
+ " --fs-version|--fs-versions\n"
|
|
+ " Add filesystem version to --long output\n"
|
|
" -h|--human-readable Human-readable sizes in --long output\n"
|
|
" --help Display brief help\n"
|
|
" --keys-from-stdin Read passphrases from stdin\n"
|
|
@@ -157,6 +161,8 @@ main (int argc, char *argv[])
|
|
{ "extra", 0, 0, 0 },
|
|
{ "filesystems", 0, 0, 0 },
|
|
{ "format", 2, 0, 0 },
|
|
+ { "fs-version", 0, 0, 0 },
|
|
+ { "fs-versions", 0, 0, 0 },
|
|
{ "help", 0, 0, HELP_OPTION },
|
|
{ "human-readable", 0, 0, 'h' },
|
|
{ "keys-from-stdin", 0, 0, 0 },
|
|
@@ -191,6 +197,7 @@ main (int argc, char *argv[])
|
|
int no_title = 0; /* --no-title */
|
|
int long_mode = 0; /* --long|-l */
|
|
int uuid = 0; /* --uuid */
|
|
+ int fs_version = 0; /* --fs-version */
|
|
int title;
|
|
|
|
g = guestfs_create ();
|
|
@@ -227,6 +234,9 @@ main (int argc, char *argv[])
|
|
output |= OUTPUT_FILESYSTEMS_EXTRA;
|
|
} else if (STREQ (long_options[option_index].name, "filesystems")) {
|
|
output |= OUTPUT_FILESYSTEMS;
|
|
+ } else if (STREQ (long_options[option_index].name, "fs-version") ||
|
|
+ STREQ (long_options[option_index].name, "fs-versions")) {
|
|
+ fs_version = 1;
|
|
} else if (STREQ (long_options[option_index].name, "logical-volumes") ||
|
|
STREQ (long_options[option_index].name, "logvols") ||
|
|
STREQ (long_options[option_index].name, "lvs")) {
|
|
@@ -337,6 +347,8 @@ main (int argc, char *argv[])
|
|
columns |= COLUMN_MBR;
|
|
if (uuid)
|
|
columns |= COLUMN_UUID;
|
|
+ if (fs_version)
|
|
+ columns |= COLUMN_FS_VERSION;
|
|
}
|
|
|
|
/* Display title by default only in long mode. */
|
|
@@ -379,7 +391,7 @@ static void do_output_pvs (void);
|
|
static void do_output_partitions (void);
|
|
static void do_output_blockdevs (void);
|
|
|
|
-static void write_row (const char *name, const char *type, const char *vfs_type, const char *vfs_label, int mbr_id, int64_t size, char **parents, const char *uuid);
|
|
+static void write_row (const char *name, const char *type, const char *vfs_type, const char *vfs_label, int mbr_id, int64_t size, char **parents, const char *uuid, const char *fs_version);
|
|
static void write_row_strings (char **strings, size_t len);
|
|
|
|
static char **no_parents (void);
|
|
@@ -410,6 +422,8 @@ do_output_title (void)
|
|
headings[len++] = "Parent";
|
|
if ((columns & COLUMN_UUID))
|
|
headings[len++] = "UUID";
|
|
+ if ((columns & COLUMN_FS_VERSION))
|
|
+ headings[len++] = "FSVersion";
|
|
assert (len <= NR_COLUMNS);
|
|
|
|
write_row_strings ((char **) headings, len);
|
|
@@ -450,13 +464,15 @@ do_output_filesystems (void)
|
|
exit (EXIT_FAILURE);
|
|
|
|
for (i = 0; fses[i] != NULL; i += 2) {
|
|
+ const char *fs_type = fses[i+1];
|
|
CLEANUP_FREE char *dev = NULL, *vfs_label = NULL, *vfs_uuid = NULL;
|
|
+ CLEANUP_FREE char *fs_version = NULL;
|
|
CLEANUP_FREE_STRING_LIST char **parents = NULL;
|
|
int64_t size = -1;
|
|
|
|
/* Skip swap and unknown, unless --extra flag was given. */
|
|
if (!(output & OUTPUT_FILESYSTEMS_EXTRA) &&
|
|
- (STREQ (fses[i+1], "swap") || STREQ (fses[i+1], "unknown")))
|
|
+ (STREQ (fs_type, "swap") || STREQ (fs_type, "unknown")))
|
|
continue;
|
|
|
|
dev = guestfs_canonical_device_name (g, fses[i]);
|
|
@@ -486,6 +502,12 @@ do_output_filesystems (void)
|
|
error (EXIT_FAILURE, errno, "strdup");
|
|
}
|
|
}
|
|
+ if ((columns & COLUMN_FS_VERSION)) {
|
|
+ const char *version = get_filesystem_version (g, fses[i], fs_type);
|
|
+ fs_version = strdup (version ? version : "");
|
|
+ if (fs_version == NULL)
|
|
+ error (EXIT_FAILURE, errno, "strdup");
|
|
+ }
|
|
if ((columns & COLUMN_SIZE)) {
|
|
CLEANUP_FREE char *device = guestfs_mountable_device (g, fses[i]);
|
|
CLEANUP_FREE char *subvolume = NULL;
|
|
@@ -533,7 +555,7 @@ do_output_filesystems (void)
|
|
parents = no_parents ();
|
|
|
|
write_row (dev, "filesystem",
|
|
- fses[i+1], vfs_label, -1, size, parents, vfs_uuid);
|
|
+ fs_type, vfs_label, -1, size, parents, vfs_uuid, fs_version);
|
|
}
|
|
}
|
|
|
|
@@ -573,7 +595,7 @@ do_output_lvs (void)
|
|
}
|
|
|
|
write_row (lvs[i], "lv",
|
|
- NULL, NULL, -1, size, (char **) parents, uuid);
|
|
+ NULL, NULL, -1, size, (char **) parents, uuid, NULL);
|
|
}
|
|
}
|
|
|
|
@@ -601,7 +623,8 @@ do_output_vgs (void)
|
|
parents = parents_of_vg (vgs->val[i].vg_name);
|
|
|
|
write_row (name, "vg",
|
|
- NULL, NULL, -1, (int64_t) vgs->val[i].vg_size, parents, uuid);
|
|
+ NULL, NULL, -1, (int64_t) vgs->val[i].vg_size, parents, uuid,
|
|
+ NULL);
|
|
}
|
|
}
|
|
|
|
@@ -649,7 +672,7 @@ do_output_pvs (void)
|
|
uuid[32] = '\0';
|
|
write_row (dev, "pv",
|
|
NULL, NULL, -1, (int64_t) pvs->val[i].pv_size,
|
|
- (char **) parents, uuid);
|
|
+ (char **) parents, uuid, NULL);
|
|
}
|
|
}
|
|
|
|
@@ -715,7 +738,7 @@ do_output_partitions (void)
|
|
}
|
|
|
|
write_row (dev, "partition",
|
|
- NULL, NULL, mbr_id, size, (char **) parents, NULL);
|
|
+ NULL, NULL, mbr_id, size, (char **) parents, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
@@ -749,7 +772,7 @@ do_output_blockdevs (void)
|
|
parents = no_parents ();
|
|
|
|
write_row (dev, "device",
|
|
- NULL, NULL, -1, size, parents, NULL);
|
|
+ NULL, NULL, -1, size, parents, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
@@ -882,7 +905,8 @@ parents_of_vg (char *vg)
|
|
static void
|
|
write_row (const char *name, const char *type,
|
|
const char *vfs_type, const char *vfs_label, int mbr_id,
|
|
- int64_t size, char **parents, const char *uuid)
|
|
+ int64_t size, char **parents, const char *uuid,
|
|
+ const char *fs_version)
|
|
{
|
|
const char *strings[NR_COLUMNS];
|
|
CLEANUP_FREE char *parents_str = NULL;
|
|
@@ -930,6 +954,8 @@ write_row (const char *name, const char *type,
|
|
}
|
|
if ((columns & COLUMN_UUID))
|
|
strings[len++] = uuid;
|
|
+ if ((columns & COLUMN_FS_VERSION))
|
|
+ strings[len++] = fs_version;
|
|
assert (len <= NR_COLUMNS);
|
|
|
|
write_row_strings ((char **) strings, len);
|
|
diff --git a/filesystems/utils.c b/filesystems/utils.c
|
|
new file mode 100644
|
|
index 000000000..9de32f1bd
|
|
--- /dev/null
|
|
+++ b/filesystems/utils.c
|
|
@@ -0,0 +1,60 @@
|
|
+/* Utility function used by virt-filesystems and virrt-inspector
|
|
+ * Copyright (C) 2026 Red Hat Inc.
|
|
+ *
|
|
+ * 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.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
+ */
|
|
+
|
|
+#include <config.h>
|
|
+
|
|
+#include "guestfs.h"
|
|
+
|
|
+#include "guestfs-utils.h"
|
|
+#include "utils.h"
|
|
+
|
|
+const char *
|
|
+get_filesystem_version (guestfs_h *g, const char *dev, const char *fs_type)
|
|
+{
|
|
+ const char *version = NULL;
|
|
+
|
|
+#ifdef GUESTFS_HAVE_XFS_INFO2
|
|
+ /* For type=xfs, try to guess the filesystem version. */
|
|
+ if (STREQ (fs_type, "xfs")) {
|
|
+ CLEANUP_FREE_STRING_LIST char **hash = NULL;
|
|
+ size_t i;
|
|
+
|
|
+ guestfs_push_error_handler (g, NULL, NULL);
|
|
+
|
|
+ hash = guestfs_xfs_info2 (g, dev);
|
|
+ if (hash) {
|
|
+ for (i = 0; hash[i] != NULL; i += 2) {
|
|
+ if (STREQ (hash[i], "meta-data.crc")) {
|
|
+ if (STREQ (hash[i+1], "0"))
|
|
+ version = "4";
|
|
+ else if (STREQ (hash[i+1], "1"))
|
|
+ version = "5";
|
|
+ break;
|
|
+ }
|
|
+ /* If new XFS versions are added in future then we can test
|
|
+ * for new fields here ...
|
|
+ */
|
|
+ }
|
|
+ }
|
|
+
|
|
+ guestfs_pop_error_handler (g);
|
|
+ }
|
|
+#endif /* GUESTFS_HAVE_XFS_INFO2 */
|
|
+
|
|
+ return version;
|
|
+}
|
|
diff --git a/filesystems/utils.h b/filesystems/utils.h
|
|
new file mode 100644
|
|
index 000000000..284f8e1ac
|
|
--- /dev/null
|
|
+++ b/filesystems/utils.h
|
|
@@ -0,0 +1,30 @@
|
|
+/* Utility function used by virt-filesystems and virrt-inspector
|
|
+ * Copyright (C) 2026 Red Hat Inc.
|
|
+ *
|
|
+ * 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.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
+ */
|
|
+
|
|
+#ifndef GUESTFS_FILESYSTEMS_UTILS_H
|
|
+#define GUESTFS_FILESYSTEMS_UTILS_H
|
|
+
|
|
+#include "guestfs.h"
|
|
+
|
|
+/* For XFS, return the filesystem version (eg. "4" or "5"). This may
|
|
+ * return NULL if no filesystem version is known.
|
|
+ */
|
|
+const char *get_filesystem_version (guestfs_h *g,
|
|
+ const char *dev, const char *fs_type);
|
|
+
|
|
+#endif /* GUESTFS_FILESYSTEMS_UTILS_H */
|
|
diff --git a/filesystems/virt-filesystems.pod b/filesystems/virt-filesystems.pod
|
|
index 7955d6a84..c72ae3cf7 100644
|
|
--- a/filesystems/virt-filesystems.pod
|
|
+++ b/filesystems/virt-filesystems.pod
|
|
@@ -197,6 +197,14 @@ If you have untrusted raw-format guest disk images, you should use
|
|
this option to specify the disk format. This avoids a possible
|
|
security problem with malicious guests (CVE-2010-3851).
|
|
|
|
+=item B<--fs-version>
|
|
+
|
|
+=item B<--fs-versions>
|
|
+
|
|
+In I<--long> mode, display the filesystem version. Currently this
|
|
+only has any effect for XFS, displaying either C<4> (for XFS v4) or
|
|
+C<5> (for XFS v5). XFS v4 support will be removed from Linux in 2030.
|
|
+
|
|
=item B<-h>
|
|
|
|
=item B<--human-readable>
|
|
@@ -221,7 +229,9 @@ external programs.
|
|
Use I<-h> if you want sizes to be displayed in human-readable format.
|
|
The default is to show raw numbers of I<bytes>.
|
|
|
|
-Use I<--uuid> to display UUIDs too.
|
|
+Use I<--fs-version> to display filesystem versions.
|
|
+
|
|
+Use I<--uuid> to display UUIDs.
|
|
|
|
=item B<--lvs>
|
|
|
|
diff --git a/inspector/Makefile.am b/inspector/Makefile.am
|
|
index 04c608f44..637a10415 100644
|
|
--- a/inspector/Makefile.am
|
|
+++ b/inspector/Makefile.am
|
|
@@ -48,7 +48,10 @@ dist_doc_DATA = \
|
|
bin_PROGRAMS = virt-inspector
|
|
|
|
virt_inspector_SOURCES = \
|
|
- inspector.c
|
|
+ ../filesystems/utils.c \
|
|
+ ../filesystems/utils.h \
|
|
+ inspector.c \
|
|
+ $(NULL)
|
|
|
|
virt_inspector_CPPFLAGS = \
|
|
-DGUESTFS_NO_DEPRECATED=1 \
|
|
@@ -56,6 +59,7 @@ virt_inspector_CPPFLAGS = \
|
|
-I$(top_srcdir)/common/utils -I$(top_builddir)/common/utils \
|
|
-I$(top_srcdir)/common/structs -I$(top_builddir)/common/structs \
|
|
-I$(top_srcdir)/lib -I$(top_builddir)/lib \
|
|
+ -I$(top_srcdir)/filesystems -I$(top_builddir)/filesystems \
|
|
-I$(top_srcdir)/include \
|
|
-I$(top_srcdir)/common/options -I$(top_builddir)/common/options \
|
|
-I$(top_srcdir)/fish \
|
|
diff --git a/inspector/inspector.c b/inspector/inspector.c
|
|
index fc6b9f0d0..be34e8794 100644
|
|
--- a/inspector/inspector.c
|
|
+++ b/inspector/inspector.c
|
|
@@ -44,6 +44,7 @@
|
|
#include "options.h"
|
|
#include "display-options.h"
|
|
#include "libxml2-writer-macros.h"
|
|
+#include "utils.h"
|
|
|
|
/* Currently open libguestfs handle. */
|
|
guestfs_h *g;
|
|
@@ -569,42 +570,6 @@ output_mountpoints (xmlTextWriterPtr xo, char *root)
|
|
} end_element ();
|
|
}
|
|
|
|
-static const char *
|
|
-get_filesystem_version (const char *dev, const char *fs_type)
|
|
-{
|
|
- const char *version = NULL;
|
|
-
|
|
-#ifdef GUESTFS_HAVE_XFS_INFO2
|
|
- /* For type=xfs, try to guess the filesystem version. */
|
|
- if (STREQ (fs_type, "xfs")) {
|
|
- CLEANUP_FREE_STRING_LIST char **hash = NULL;
|
|
- size_t i;
|
|
-
|
|
- guestfs_push_error_handler (g, NULL, NULL);
|
|
-
|
|
- hash = guestfs_xfs_info2 (g, dev);
|
|
- if (hash) {
|
|
- for (i = 0; hash[i] != NULL; i += 2) {
|
|
- if (STREQ (hash[i], "meta-data.crc")) {
|
|
- if (STREQ (hash[i+1], "0"))
|
|
- version = "4";
|
|
- else if (STREQ (hash[i+1], "1"))
|
|
- version = "5";
|
|
- break;
|
|
- }
|
|
- /* If new XFS versions are added in future then we can test
|
|
- * for new fields here ...
|
|
- */
|
|
- }
|
|
- }
|
|
-
|
|
- guestfs_pop_error_handler (g);
|
|
- }
|
|
-#endif /* GUESTFS_HAVE_XFS_INFO2 */
|
|
-
|
|
- return version;
|
|
-}
|
|
-
|
|
static void
|
|
output_filesystems (xmlTextWriterPtr xo, char *root)
|
|
{
|
|
@@ -634,7 +599,7 @@ output_filesystems (xmlTextWriterPtr xo, char *root)
|
|
|
|
str = guestfs_vfs_type (g, filesystems[i]);
|
|
if (str && str[0]) {
|
|
- const char *version = get_filesystem_version (dev, str);
|
|
+ const char *version = get_filesystem_version (g, dev, str);
|
|
start_element ("type") {
|
|
if (version)
|
|
attribute ("version", version);
|