]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_db: add a directory path lookup command
authorDarrick J. Wong <djwong@kernel.org>
Fri, 12 Feb 2021 22:23:05 +0000 (17:23 -0500)
committerEric Sandeen <sandeen@sandeen.net>
Fri, 12 Feb 2021 22:23:05 +0000 (17:23 -0500)
Add a command to xfs_db so that we can navigate to inodes by path.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Chandan Babu R <chandanrlinux@gmail.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
db/Makefile
db/command.c
db/command.h
db/namei.c [new file with mode: 0644]
man/man8/xfs_db.8

index 9d502bf0d0d66445f0c61ddeeba7a0ec2e4fef68..beafb105826932dba892c7e23f79239c36cb4502 100644 (file)
@@ -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 timelimit.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)
index 438283699b2ec4870f8e3bf56ac6b51076e7da35..02f778b9316b86fa2e3a9ce59c8a779cd61ac2aa 100644 (file)
@@ -131,6 +131,7 @@ init_commands(void)
        logformat_init();
        io_init();
        metadump_init();
+       namei_init();
        output_init();
        print_init();
        quit_init();
index 6913c8171fe11aaf86b8a6d6417964eec471c2fb..498983ff92fa3d4eac13a6f7b17c4c69763cec19 100644 (file)
@@ -33,3 +33,4 @@ extern void           btdump_init(void);
 extern void            info_init(void);
 extern void            btheight_init(void);
 extern void            timelimit_init(void);
+extern void            namei_init(void);
diff --git a/db/namei.c b/db/namei.c
new file mode 100644 (file)
index 0000000..6fddbc4
--- /dev/null
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2021 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#include "libxfs.h"
+#include "command.h"
+#include "output.h"
+#include "init.h"
+#include "io.h"
+#include "type.h"
+#include "input.h"
+#include "faddr.h"
+#include "fprint.h"
+#include "field.h"
+#include "inode.h"
+
+/* Path lookup */
+
+/* Key for looking up metadata inodes. */
+struct dirpath {
+       /* Array of string pointers. */
+       char            **path;
+
+       /* Number of strings in path. */
+       unsigned int    depth;
+};
+
+static void
+path_free(
+       struct dirpath  *dirpath)
+{
+       unsigned int    i;
+
+       for (i = 0; i < dirpath->depth; i++)
+               free(dirpath->path[i]);
+       free(dirpath->path);
+       free(dirpath);
+}
+
+/* Chop a freeform string path into a structured path. */
+static struct dirpath *
+path_parse(
+       const char      *path)
+{
+       struct dirpath  *dirpath;
+       const char      *p = path;
+       const char      *endp = path + strlen(path);
+
+       dirpath = calloc(sizeof(*dirpath), 1);
+       if (!dirpath)
+               return NULL;
+
+       while (p < endp) {
+               char            **new_path;
+               const char      *next_slash;
+
+               next_slash = strchr(p, '/');
+               if (next_slash == p) {
+                       p++;
+                       continue;
+               }
+               if (!next_slash)
+                       next_slash = endp;
+
+               new_path = realloc(dirpath->path,
+                               (dirpath->depth + 1) * sizeof(char *));
+               if (!new_path) {
+                       path_free(dirpath);
+                       return NULL;
+               }
+
+               dirpath->path = new_path;
+               dirpath->path[dirpath->depth] = strndup(p, next_slash - p);
+               dirpath->depth++;
+
+               p = next_slash + 1;
+       }
+
+       return dirpath;
+}
+
+/* Given a directory and a structured path, walk the path and set the cursor. */
+static int
+path_navigate(
+       struct xfs_mount        *mp,
+       xfs_ino_t               rootino,
+       struct dirpath          *dirpath)
+{
+       struct xfs_inode        *dp;
+       xfs_ino_t               ino = rootino;
+       unsigned int            i;
+       int                     error;
+
+       error = -libxfs_iget(mp, NULL, ino, 0, &dp);
+       if (error)
+               return error;
+
+       for (i = 0; i < dirpath->depth; i++) {
+               struct xfs_name xname = {
+                       .name   = dirpath->path[i],
+                       .len    = strlen(dirpath->path[i]),
+               };
+
+               if (!S_ISDIR(VFS_I(dp)->i_mode)) {
+                       error = ENOTDIR;
+                       goto rele;
+               }
+
+               error = -libxfs_dir_lookup(NULL, dp, &xname, &ino, NULL);
+               if (error)
+                       goto rele;
+               if (!xfs_verify_ino(mp, ino)) {
+                       error = EFSCORRUPTED;
+                       goto rele;
+               }
+
+               libxfs_irele(dp);
+               dp = NULL;
+
+               error = -libxfs_iget(mp, NULL, ino, 0, &dp);
+               switch (error) {
+               case EFSCORRUPTED:
+               case EFSBADCRC:
+               case 0:
+                       break;
+               default:
+                       return error;
+               }
+       }
+
+       set_cur_inode(ino);
+rele:
+       if (dp)
+               libxfs_irele(dp);
+       return error;
+}
+
+/* Walk a directory path to an inode and set the io cursor to that inode. */
+static int
+path_walk(
+       char            *path)
+{
+       struct dirpath  *dirpath;
+       char            *p = path;
+       xfs_ino_t       rootino = mp->m_sb.sb_rootino;
+       int             error = 0;
+
+       if (*p == '/') {
+               /* Absolute path, start from the root inode. */
+               p++;
+       } else {
+               /* Relative path, start from current dir. */
+               if (iocur_top->typ != &typtab[TYP_INODE] ||
+                   !S_ISDIR(iocur_top->mode))
+                       return ENOTDIR;
+
+               rootino = iocur_top->ino;
+       }
+
+       dirpath = path_parse(p);
+       if (!dirpath)
+               return ENOMEM;
+
+       error = path_navigate(mp, rootino, dirpath);
+       path_free(dirpath);
+       return error;
+}
+
+static void
+path_help(void)
+{
+       dbprintf(_(
+"\n"
+" Navigate to an inode via directory path.\n"
+       ));
+}
+
+static int
+path_f(
+       int             argc,
+       char            **argv)
+{
+       int             c;
+       int             error;
+
+       while ((c = getopt(argc, argv, "")) != -1) {
+               switch (c) {
+               default:
+                       path_help();
+                       return 0;
+               }
+       }
+
+       error = path_walk(argv[optind]);
+       if (error) {
+               dbprintf("%s: %s\n", argv[optind], strerror(error));
+               exitcode = 1;
+       }
+
+       return 0;
+}
+
+static struct cmdinfo path_cmd = {
+       .name           = "path",
+       .altname        = NULL,
+       .cfunc          = path_f,
+       .argmin         = 1,
+       .argmax         = 1,
+       .canpush        = 0,
+       .args           = "",
+       .help           = path_help,
+};
+
+void
+namei_init(void)
+{
+       path_cmd.oneline = _("navigate to an inode by path");
+       add_command(&path_cmd);
+}
index 55388be68b932af01411900953d9c7162851c402..4df265ecd59e010bc72f36dcb23c3b3a65a550e7 100644 (file)
@@ -831,6 +831,10 @@ See the
 .B print
 command.
 .TP
+.BI "path " dir_path
+Walk the directory tree to an inode using the supplied path.
+Absolute and relative paths are supported.
+.TP
 .B pop
 Pop location from the stack.
 .TP