[PATCH 21/26] xfs_db: support printing time limits

Darrick J. Wong
2020-10-26T23:38:28Z

From: Darrick J. Wong <darrick.wong@oracle.com>

Support printing the minimum and maxium timestamp limits on this
filesystem.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
db/Makefile | 3 +
db/command.c | 1
db/command.h | 1
db/timelimit.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++
man/man8/xfs_db.8 | 23 ++++++++
5 files changed, 187 insertions(+), 1 deletion(-)
create mode 100644 db/timelimit.c

diff --git a/db/Makefile b/db/Makefile
index 67908a2c3c98..beafb1058269 100644
--- a/db/Makefile
+++ b/db/Makefile
@@ -14,7 +14,8 @@ HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \
io.h logformat.h malloc.h metadump.h output.h print.h quit.h sb.h \
sig.h strvec.h text.h type.h write.h attrset.h symlink.h fsmap.h \
fuzz.h
-CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c namei.c
+CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c namei.c \
+ timelimit.c
LSRCFILES = xfs_admin.sh xfs_ncheck.sh xfs_metadump.sh

LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBFROG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD)
diff --git a/db/command.c b/db/command.c
index 053097742b12..02f778b9316b 100644
--- a/db/command.c
+++ b/db/command.c
@@ -140,4 +140,5 @@ init_commands(void)
write_init();
dquot_init();
fuzz_init();
+ timelimit_init();
}
diff --git a/db/command.h b/db/command.h
index bf130e63c85c..fd5cead9be78 100644
--- a/db/command.h
+++ b/db/command.h
@@ -33,3 +33,4 @@ extern void btdump_init(void);
extern void info_init(void);
extern void btheight_init(void);
extern void namei_init(void);
+extern void timelimit_init(void);
diff --git a/db/timelimit.c b/db/timelimit.c
new file mode 100644
index 000000000000..53a0a399a7f2
--- /dev/null
+++ b/db/timelimit.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ */
+#include "libxfs.h"
+#include "command.h"
+#include "output.h"
+#include "init.h"
+
+enum show_what {
+ SHOW_AUTO,
+ SHOW_CLASSIC,
+ SHOW_BIGTIME,
+};
+
+
+enum print_how {
+ PRINT_RAW,
+ PRINT_PRETTY,
+ PRINT_COMPACT,
+};
+
+static void
+show_limit(
+ const char *tag,
+ int64_t limit,
+ enum print_how how)
+{
+ if (how == PRINT_COMPACT) {
+ dbprintf("%" PRId64 " ", limit);
+ return;
+ }
+
+ if (how == PRINT_PRETTY && limit <= LONG_MAX && limit >= LONG_MIN) {
+ time_t tt = limit;
+ char *c;
+
+ c = ctime(&tt);
+ if (c) {
+ dbprintf("%s = %24.24s\n", tag, c);
+ return;
+ }
+ }
+
+ dbprintf("%s = %" PRId64 "\n", tag, limit);
+}
+
+static void
+show_limits(
+ enum show_what whatkind,
+ enum print_how how)
+{
+ enum print_how grace_how = how;
+
+ switch (whatkind) {
+ case SHOW_AUTO:
+ /* should never get here */
+ break;
+ case SHOW_CLASSIC:
+ show_limit("time.min", XFS_LEGACY_TIME_MIN, how);
+ show_limit("time.max", XFS_LEGACY_TIME_MAX, how);
+ show_limit("dqtimer.min", XFS_DQ_LEGACY_EXPIRY_MIN, how);
+ show_limit("dqtimer.max", XFS_DQ_LEGACY_EXPIRY_MAX, how);
+ break;
+ case SHOW_BIGTIME:
+ show_limit("time.min",
+ xfs_bigtime_to_unix(XFS_BIGTIME_TIME_MIN), how);
+ show_limit("time.max",
+ xfs_bigtime_to_unix(XFS_BIGTIME_TIME_MAX), how);
+ show_limit("dqtimer.min",
+ xfs_dq_bigtime_to_unix(XFS_DQ_BIGTIME_EXPIRY_MIN),
+ how);
+ show_limit("dqtimer.max",
+ xfs_dq_bigtime_to_unix(XFS_DQ_BIGTIME_EXPIRY_MAX),
+ how);
+ break;
+ }
+
+ /* grace periods are always integers */
+ if (grace_how != PRINT_COMPACT)
+ grace_how = PRINT_RAW;
+ show_limit("dqgrace.min", XFS_DQ_GRACE_MIN, grace_how);
+ show_limit("dqgrace.min", XFS_DQ_GRACE_MAX, grace_how);
+
+ if (how == PRINT_COMPACT)
+ dbprintf("\n");
+}
+
+static int
+timelimit_f(
+ int argc,
+ char **argv)
+{
+ enum show_what whatkind = SHOW_AUTO;
+ enum print_how how = PRINT_RAW;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp("--classic", argv[i]))
+ whatkind = SHOW_CLASSIC;
+ else if (!strcmp("--bigtime", argv[i]))
+ whatkind = SHOW_BIGTIME;
+ else if (!strcmp("--pretty", argv[i]))
+ how = PRINT_PRETTY;
+ else if (!strcmp("--compact", argv[i]))
+ how = PRINT_COMPACT;
+ else {
+ dbprintf(_("%s: bad option for timelimit command\n"),
+ argv[i]);
+ return 1;
+ }
+ }
+
+ if (whatkind == SHOW_AUTO) {
+ if (xfs_sb_version_hasbigtime(&mp->m_sb))
+ whatkind = SHOW_BIGTIME;
+ else
+ whatkind = SHOW_CLASSIC;
+ }
+
+ show_limits(whatkind, how);
+ return 0;
+}
+
+static void
+timelimit_help(void)
+{
+ dbprintf(_(
+"\n"
+" Print the minimum and maximum supported values for inode timestamps,\n"
+" disk quota expiration timers, and disk quota grace periods supported\n"
+" by this filesystem.\n"
+"\n"
+" Options:\n"
+" --classic -- Force printing of the classic time limits.\n"
+" --bigtime -- Force printing of the bigtime limits.\n"
+" --pretty -- Pretty-print the time limits.\n"
+" --compact -- Print the limits in a single line.\n"
+"\n"
+));
+
+}
+
+static const cmdinfo_t timelimit_cmd = {
+ .name = "timelimit",
+ .cfunc = timelimit_f,
+ .argmin = 0,
+ .argmax = -1,
+ .canpush = 0,
+ .args = N_("[--classic|--bigtime] [--pretty]"),
+ .oneline = N_("display timestamp limits"),
+ .help = timelimit_help,
+};
+
+void
+timelimit_init(void)
+{
+ add_command(&timelimit_cmd);
+}
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index fefe862b7564..f2520e9ad1ac 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -905,6 +905,29 @@ The possible data types are:
.BR rtsummary ", " sb ", " symlink " and " text .
See the TYPES section below for more information on these data types.
.TP
+.BI "timelimit [" OPTIONS ]
+Print the minimum and maximum supported values for inode timestamps,
+quota expiration timers, and quota grace periods supported by this
+filesystem.
+Options include:
+.RS 1.0i
+.TP 0.4i
+.B \--bigtime
+Print the time limits of an XFS filesystem with the
+.B bigtime
+feature enabled.
+.TP 0.4i
+.B \--classic
+Print the time limits of a classic XFS filesystem.
+.TP 0.4i
+.B \--compact
+Print all limits as raw values on a single line.
+.TP 0.4i
+.B \--pretty
+Print the timestamps in the current locale's date and time format instead of
+raw seconds since the Unix epoch.
+.RE
+.TP
.BI "uuid [" uuid " | " generate " | " rewrite " | " restore ]
Set the filesystem universally unique identifier (UUID).
The filesystem UUID can be used by