* [PATCHSET v3 0/2] xfs_db: add minimal directory navigation @ 2021-01-09 6:27 Darrick J. Wong 2021-01-09 6:27 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 2021-01-09 6:27 ` [PATCH 2/2] xfs_db: add an ls command Darrick J. Wong 0 siblings, 2 replies; 16+ messages in thread From: Darrick J. Wong @ 2021-01-09 6:27 UTC (permalink / raw) To: sandeen, darrick.wong; +Cc: linux-xfs Hi all, This patchset improves the usability of xfs_db by enabling users to navigate to inodes by path and to list the contents of directories. v2: Various cleanups and reorganizing suggested by dchinner v3: Rebase to 5.10-rc0 If you're going to start using this mess, you probably ought to just pull from my git trees, which are linked below. This is an extraordinary way to destroy everything. Enjoy! Comments and questions are, as always, welcome. --D xfsprogs git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=xfs_db-directory-navigation fstests git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=xfs_db-directory-navigation --- db/Makefile | 3 db/command.c | 1 db/command.h | 1 db/namei.c | 612 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 20 ++ 6 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 db/namei.c ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/2] xfs_db: add a directory path lookup command 2021-01-09 6:27 [PATCHSET v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong @ 2021-01-09 6:27 ` Darrick J. Wong 2021-01-09 6:27 ` [PATCH 2/2] xfs_db: add an ls command Darrick J. Wong 1 sibling, 0 replies; 16+ messages in thread From: Darrick J. Wong @ 2021-01-09 6:27 UTC (permalink / raw) To: sandeen, darrick.wong; +Cc: linux-xfs From: Darrick J. Wong <djwong@kernel.org> Add a command to xfs_db so that we can navigate to inodes by path. Signed-off-by: Darrick J. Wong <djwong@kernel.org> --- db/Makefile | 3 - db/command.c | 1 db/command.h | 1 db/namei.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_db.8 | 4 + 5 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 db/namei.c diff --git a/db/Makefile b/db/Makefile index 9d502bf0..beafb105 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 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) diff --git a/db/command.c b/db/command.c index 43828369..02f778b9 100644 --- a/db/command.c +++ b/db/command.c @@ -131,6 +131,7 @@ init_commands(void) logformat_init(); io_init(); metadump_init(); + namei_init(); output_init(); print_init(); quit_init(); diff --git a/db/command.h b/db/command.h index 6913c817..498983ff 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 timelimit_init(void); +extern void namei_init(void); diff --git a/db/namei.c b/db/namei.c new file mode 100644 index 00000000..eebebe15 --- /dev/null +++ b/db/namei.c @@ -0,0 +1,223 @@ +// 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); + if (error) + return error; + + path_free(dirpath); + return 0; +} + +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); +} diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 55388be6..4df265ec 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -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 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 2/2] xfs_db: add an ls command 2021-01-09 6:27 [PATCHSET v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong 2021-01-09 6:27 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong @ 2021-01-09 6:27 ` Darrick J. Wong 1 sibling, 0 replies; 16+ messages in thread From: Darrick J. Wong @ 2021-01-09 6:27 UTC (permalink / raw) To: sandeen, darrick.wong; +Cc: linux-xfs From: Darrick J. Wong <djwong@kernel.org> Add to xfs_db the ability to list a directory. Signed-off-by: Darrick J. Wong <djwong@kernel.org> --- db/namei.c | 389 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 16 ++ 3 files changed, 406 insertions(+) diff --git a/db/namei.c b/db/namei.c index eebebe15..e75b5ebd 100644 --- a/db/namei.c +++ b/db/namei.c @@ -215,9 +215,398 @@ static struct cmdinfo path_cmd = { .help = path_help, }; +/* List a directory's entries. */ + +static const char *filetype_strings[XFS_DIR3_FT_MAX] = { + [XFS_DIR3_FT_UNKNOWN] = "unknown", + [XFS_DIR3_FT_REG_FILE] = "regular", + [XFS_DIR3_FT_DIR] = "directory", + [XFS_DIR3_FT_CHRDEV] = "chardev", + [XFS_DIR3_FT_BLKDEV] = "blkdev", + [XFS_DIR3_FT_FIFO] = "fifo", + [XFS_DIR3_FT_SOCK] = "socket", + [XFS_DIR3_FT_SYMLINK] = "symlink", + [XFS_DIR3_FT_WHT] = "whiteout", +}; + +static const char * +get_dstr( + struct xfs_mount *mp, + uint8_t filetype) +{ + if (!xfs_sb_version_hasftype(&mp->m_sb)) + return filetype_strings[XFS_DIR3_FT_UNKNOWN]; + + if (filetype >= XFS_DIR3_FT_MAX) + return filetype_strings[XFS_DIR3_FT_UNKNOWN]; + + return filetype_strings[filetype]; +} + +static void +dir_emit( + struct xfs_mount *mp, + xfs_dir2_dataptr_t off, + char *name, + ssize_t namelen, + xfs_ino_t ino, + uint8_t dtype) +{ + char *display_name; + struct xfs_name xname = { .name = name }; + const char *dstr = get_dstr(mp, dtype); + xfs_dahash_t hash; + bool good; + + if (namelen < 0) { + /* Negative length means that name is null-terminated. */ + display_name = name; + xname.len = strlen(name); + good = true; + } else { + /* + * Otherwise, name came from a directory entry, so we have to + * copy the string to a buffer so that we can add the null + * terminator. + */ + display_name = malloc(namelen + 1); + memcpy(display_name, name, namelen); + display_name[namelen] = 0; + xname.len = namelen; + good = libxfs_dir2_namecheck(name, namelen); + } + hash = libxfs_dir2_hashname(mp, &xname); + + dbprintf("%-10u %-18llu %-14s 0x%08llx %3d %s %s\n", off & 0xFFFFFFFF, + ino, dstr, hash, xname.len, + display_name, good ? _("(good)") : _("(corrupt)")); + + if (display_name != name) + free(display_name); +} + +static int +list_sfdir( + struct xfs_da_args *args) +{ + struct xfs_inode *dp = args->dp; + struct xfs_mount *mp = dp->i_mount; + struct xfs_da_geometry *geo = args->geo; + struct xfs_dir2_sf_entry *sfep; + struct xfs_dir2_sf_hdr *sfp; + xfs_ino_t ino; + xfs_dir2_dataptr_t off; + unsigned int i; + uint8_t filetype; + + sfp = (struct xfs_dir2_sf_hdr *)dp->i_df.if_u1.if_data; + + /* . and .. entries */ + off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, + geo->data_entry_offset); + dir_emit(args->dp->i_mount, off, ".", -1, dp->i_ino, XFS_DIR3_FT_DIR); + + ino = libxfs_dir2_sf_get_parent_ino(sfp); + off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, + geo->data_entry_offset + + libxfs_dir2_data_entsize(mp, sizeof(".") - 1)); + dir_emit(args->dp->i_mount, off, "..", -1, ino, XFS_DIR3_FT_DIR); + + /* Walk everything else. */ + sfep = xfs_dir2_sf_firstentry(sfp); + for (i = 0; i < sfp->count; i++) { + ino = libxfs_dir2_sf_get_ino(mp, sfp, sfep); + filetype = libxfs_dir2_sf_get_ftype(mp, sfep); + off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, + xfs_dir2_sf_get_offset(sfep)); + + dir_emit(args->dp->i_mount, off, (char *)sfep->name, + sfep->namelen, ino, filetype); + sfep = libxfs_dir2_sf_nextentry(mp, sfp, sfep); + } + + return 0; +} + +/* List entries in block format directory. */ +static int +list_blockdir( + struct xfs_da_args *args) +{ + struct xfs_inode *dp = args->dp; + struct xfs_mount *mp = dp->i_mount; + struct xfs_buf *bp; + struct xfs_da_geometry *geo = mp->m_dir_geo; + xfs_dir2_dataptr_t diroff; + unsigned int offset; + unsigned int end; + int error; + + error = xfs_dir3_block_read(NULL, dp, &bp); + if (error) + return error; + + end = xfs_dir3_data_end_offset(geo, bp->b_addr); + for (offset = geo->data_entry_offset; offset < end;) { + struct xfs_dir2_data_unused *dup = bp->b_addr + offset; + struct xfs_dir2_data_entry *dep = bp->b_addr + offset; + uint8_t filetype; + + if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { + /* Unused entry */ + offset += be16_to_cpu(dup->length); + continue; + } + + /* Real entry */ + diroff = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, offset); + offset += libxfs_dir2_data_entsize(mp, dep->namelen); + filetype = libxfs_dir2_data_get_ftype(dp->i_mount, dep); + dir_emit(mp, diroff, (char *)dep->name, dep->namelen, + be64_to_cpu(dep->inumber), filetype); + } + + libxfs_trans_brelse(args->trans, bp); + return error; +} + +/* List entries in leaf format directory. */ +static int +list_leafdir( + struct xfs_da_args *args) +{ + struct xfs_bmbt_irec map; + struct xfs_iext_cursor icur; + struct xfs_inode *dp = args->dp; + struct xfs_mount *mp = dp->i_mount; + struct xfs_buf *bp = NULL; + struct xfs_ifork *ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK); + struct xfs_da_geometry *geo = mp->m_dir_geo; + xfs_dir2_off_t dirboff; + xfs_dablk_t dabno = 0; + int error = 0; + + /* Read extent map. */ + if (!(ifp->if_flags & XFS_IFEXTENTS)) { + error = -libxfs_iread_extents(NULL, dp, XFS_DATA_FORK); + if (error) + return error; + } + + while (dabno < geo->leafblk) { + unsigned int offset; + unsigned int length; + + /* Find mapping for leaf block. */ + if (!xfs_iext_lookup_extent(dp, ifp, dabno, &icur, &map)) + break; + if (map.br_startoff >= geo->leafblk) + break; + libxfs_trim_extent(&map, dabno, geo->leafblk - dabno); + + /* Read the directory block of that first mapping. */ + error = xfs_dir3_data_read(NULL, dp, map.br_startoff, 0, &bp); + if (error) + break; + + dirboff = xfs_dir2_da_to_byte(geo, map.br_startoff); + for (offset = geo->data_entry_offset; offset < geo->blksize;) { + struct xfs_dir2_data_entry *dep; + struct xfs_dir2_data_unused *dup; + uint8_t filetype; + + dup = bp->b_addr + offset; + dep = bp->b_addr + offset; + + if (be16_to_cpu(dup->freetag) == + XFS_DIR2_DATA_FREE_TAG) { + /* Skip unused entry */ + length = be16_to_cpu(dup->length); + offset += length; + continue; + } + + offset += libxfs_dir2_data_entsize(mp, dep->namelen); + filetype = libxfs_dir2_data_get_ftype(mp, dep); + + dir_emit(mp, xfs_dir2_byte_to_dataptr(dirboff + offset), + (char *)dep->name, dep->namelen, + be64_to_cpu(dep->inumber), filetype); + } + + dabno += XFS_DADDR_TO_FSB(mp, bp->b_length); + libxfs_buf_relse(bp); + bp = NULL; + } + + if (bp) + libxfs_buf_relse(bp); + + return error; +} + +/* Read the directory, display contents. */ +int +listdir( + struct xfs_inode *dp) +{ + struct xfs_da_args args = { + .dp = dp, + .geo = dp->i_mount->m_dir_geo, + }; + int error; + int isblock; + + if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) + return list_sfdir(&args); + + error = -libxfs_dir2_isblock(&args, &isblock); + if (error) + return error; + + if (isblock) + return list_blockdir(&args); + return list_leafdir(&args); +} + +/* List the inode number of the currently selected inode. */ +static int +inum_cur(void) +{ + if (iocur_top->typ != &typtab[TYP_INODE]) + return ENOENT; + + dbprintf("%llu\n", iocur_top->ino); + return 0; +} + +/* If the io cursor points to a directory, list its contents. */ +static int +ls_cur( + char *tag) +{ + struct xfs_inode *dp; + int error = 0; + + if (iocur_top->typ != &typtab[TYP_INODE] || + !S_ISDIR(iocur_top->mode)) + return ENOTDIR; + + error = -libxfs_iget(mp, NULL, iocur_top->ino, 0, &dp); + if (error) + return error; + + if (!S_ISDIR(VFS_I(dp)->i_mode)) { + error = ENOTDIR; + goto rele; + } + + /* List the contents of a directory. */ + if (tag) + dbprintf(_("%s:\n"), tag); + + error = listdir(dp); + if (error) + goto rele; + +rele: + libxfs_irele(dp); + return error; +} + +static void +ls_help(void) +{ + dbprintf(_( +"\n" +" List the contents of the currently selected directory inode.\n" +"\n" +" Options:\n" +" -i -- Resolve the given paths to their corresponding inode numbers.\n" +" If no paths are given, display the current inode number.\n" +"\n" +" Directory contents will be listed in the format:\n" +" dir_cookie inode_number type hash name_length name\n" + )); +} + +static int +ls_f( + int argc, + char **argv) +{ + bool inum_only = false; + int c; + int error = 0; + + while ((c = getopt(argc, argv, "i")) != -1) { + switch (c) { + case 'i': + inum_only = true; + break; + default: + ls_help(); + return 0; + } + } + + if (optind == argc) { + if (inum_only) + error = inum_cur(); + else + error = ls_cur(NULL); + if (error) { + dbprintf("%s\n", strerror(error)); + exitcode = 1; + } + + return 0; + } + + for (c = optind; c < argc; c++) { + push_cur(); + + error = path_walk(argv[c]); + if (error) + goto err_cur; + + if (inum_only) + error = inum_cur(); + else + error = ls_cur(argv[c]); + if (error) + goto err_cur; + + pop_cur(); + } + + return 0; +err_cur: + pop_cur(); + if (error) { + dbprintf("%s: %s\n", argv[c], strerror(error)); + exitcode = 1; + } + return 0; +} + +static struct cmdinfo ls_cmd = { + .name = "ls", + .altname = "l", + .cfunc = ls_f, + .argmin = 0, + .argmax = -1, + .canpush = 0, + .args = "[-i] [paths...]", + .help = ls_help, +}; + void namei_init(void) { path_cmd.oneline = _("navigate to an inode by path"); add_command(&path_cmd); + + ls_cmd.oneline = _("list directory contents"); + add_command(&ls_cmd); } diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 9492955d..9a00ce66 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -190,6 +190,7 @@ #define xfs_trans_resv_calc libxfs_trans_resv_calc #define xfs_trans_roll_inode libxfs_trans_roll_inode #define xfs_trans_roll libxfs_trans_roll +#define xfs_trim_extent libxfs_trim_extent #define xfs_verify_agbno libxfs_verify_agbno #define xfs_verify_agino libxfs_verify_agino diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 4df265ec..58727495 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -806,6 +806,22 @@ This makes it easier to find discrepancies in the reservation calculations between xfsprogs and the kernel, which will help when diagnosing minimum log size calculation errors. .TP +.BI "ls [\-i] [" paths "]..." +List the contents of a directory. +If a path resolves to a directory, the directory will be listed. +If no paths are supplied and the IO cursor points at a directory inode, +the contents of that directory will be listed. + +The output format is: +directory cookie, inode number, file type, hash, name length, name. +.RS 1.0i +.TP 0.4i +.B \-i +Resolve each of the given paths to an inode number and print that number. +If no paths are given and the IO cursor points to an inode, print the inode +number. +.RE +.TP .BI "metadump [\-egow] " filename Dumps metadata to a file. See .BR xfs_metadump (8) ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCHSET v5 0/2] xfs_db: add minimal directory navigation @ 2021-02-09 4:09 Darrick J. Wong 2021-02-09 4:09 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 0 siblings, 1 reply; 16+ messages in thread From: Darrick J. Wong @ 2021-02-09 4:09 UTC (permalink / raw) To: sandeen, djwong; +Cc: Chandan Babu R, linux-xfs, chandanrlinux Hi all, This patchset improves the usability of xfs_db by enabling users to navigate to inodes by path and to list the contents of directories. v2: Various cleanups and reorganizing suggested by dchinner v3: Rebase to 5.10-rc0 v4: fix memory leak v5: pick up a review from Chandan; no other changes If you're going to start using this mess, you probably ought to just pull from my git trees, which are linked below. This is an extraordinary way to destroy everything. Enjoy! Comments and questions are, as always, welcome. --D xfsprogs git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=xfs_db-directory-navigation fstests git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=xfs_db-directory-navigation --- db/Makefile | 3 db/command.c | 1 db/command.h | 1 db/namei.c | 609 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 20 ++ 6 files changed, 634 insertions(+), 1 deletion(-) create mode 100644 db/namei.c ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/2] xfs_db: add a directory path lookup command 2021-02-09 4:09 [PATCHSET v5 0/2] xfs_db: add minimal directory navigation Darrick J. Wong @ 2021-02-09 4:09 ` Darrick J. Wong 0 siblings, 0 replies; 16+ messages in thread From: Darrick J. Wong @ 2021-02-09 4:09 UTC (permalink / raw) To: sandeen, djwong; +Cc: Chandan Babu R, linux-xfs, chandanrlinux From: Darrick J. Wong <djwong@kernel.org> 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> --- db/Makefile | 3 - db/command.c | 1 db/command.h | 1 db/namei.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_db.8 | 4 + 5 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 db/namei.c diff --git a/db/Makefile b/db/Makefile index 9d502bf0..beafb105 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 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) diff --git a/db/command.c b/db/command.c index 43828369..02f778b9 100644 --- a/db/command.c +++ b/db/command.c @@ -131,6 +131,7 @@ init_commands(void) logformat_init(); io_init(); metadump_init(); + namei_init(); output_init(); print_init(); quit_init(); diff --git a/db/command.h b/db/command.h index 6913c817..498983ff 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 timelimit_init(void); +extern void namei_init(void); diff --git a/db/namei.c b/db/namei.c new file mode 100644 index 00000000..6fddbc4a --- /dev/null +++ b/db/namei.c @@ -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); +} diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 55388be6..4df265ec 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -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 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCHSET v4 0/2] xfs_db: add minimal directory navigation @ 2021-02-03 19:42 Darrick J. Wong 2021-02-03 19:43 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 0 siblings, 1 reply; 16+ messages in thread From: Darrick J. Wong @ 2021-02-03 19:42 UTC (permalink / raw) To: sandeen, djwong; +Cc: Chandan Babu R, linux-xfs, chandanrlinux Hi all, This patchset improves the usability of xfs_db by enabling users to navigate to inodes by path and to list the contents of directories. v2: Various cleanups and reorganizing suggested by dchinner v3: Rebase to 5.10-rc0 v4: fix memory leak If you're going to start using this mess, you probably ought to just pull from my git trees, which are linked below. This is an extraordinary way to destroy everything. Enjoy! Comments and questions are, as always, welcome. --D xfsprogs git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=xfs_db-directory-navigation fstests git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=xfs_db-directory-navigation --- db/Makefile | 3 db/command.c | 1 db/command.h | 1 db/namei.c | 609 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 20 ++ 6 files changed, 634 insertions(+), 1 deletion(-) create mode 100644 db/namei.c ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/2] xfs_db: add a directory path lookup command 2021-02-03 19:42 [PATCHSET v4 0/2] xfs_db: add minimal directory navigation Darrick J. Wong @ 2021-02-03 19:43 ` Darrick J. Wong 2021-02-04 9:39 ` Chandan Babu R 0 siblings, 1 reply; 16+ messages in thread From: Darrick J. Wong @ 2021-02-03 19:43 UTC (permalink / raw) To: sandeen, djwong; +Cc: linux-xfs, chandanrlinux From: Darrick J. Wong <djwong@kernel.org> Add a command to xfs_db so that we can navigate to inodes by path. Signed-off-by: Darrick J. Wong <djwong@kernel.org> --- db/Makefile | 3 - db/command.c | 1 db/command.h | 1 db/namei.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_db.8 | 4 + 5 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 db/namei.c diff --git a/db/Makefile b/db/Makefile index 9d502bf0..beafb105 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 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) diff --git a/db/command.c b/db/command.c index 43828369..02f778b9 100644 --- a/db/command.c +++ b/db/command.c @@ -131,6 +131,7 @@ init_commands(void) logformat_init(); io_init(); metadump_init(); + namei_init(); output_init(); print_init(); quit_init(); diff --git a/db/command.h b/db/command.h index 6913c817..498983ff 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 timelimit_init(void); +extern void namei_init(void); diff --git a/db/namei.c b/db/namei.c new file mode 100644 index 00000000..6fddbc4a --- /dev/null +++ b/db/namei.c @@ -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); +} diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 55388be6..4df265ec 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -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 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] xfs_db: add a directory path lookup command 2021-02-03 19:43 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong @ 2021-02-04 9:39 ` Chandan Babu R 0 siblings, 0 replies; 16+ messages in thread From: Chandan Babu R @ 2021-02-04 9:39 UTC (permalink / raw) To: Darrick J. Wong; +Cc: sandeen, linux-xfs, chandanrlinux On 04 Feb 2021 at 01:13, Darrick J. Wong wrote: > From: Darrick J. Wong <djwong@kernel.org> > > Add a command to xfs_db so that we can navigate to inodes by path. Looks good to me. Reviewed-by: Chandan Babu R <chandanrlinux@gmail.com> > > Signed-off-by: Darrick J. Wong <djwong@kernel.org> > --- > db/Makefile | 3 - > db/command.c | 1 > db/command.h | 1 > db/namei.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > man/man8/xfs_db.8 | 4 + > 5 files changed, 228 insertions(+), 1 deletion(-) > create mode 100644 db/namei.c > > > diff --git a/db/Makefile b/db/Makefile > index 9d502bf0..beafb105 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 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) > diff --git a/db/command.c b/db/command.c > index 43828369..02f778b9 100644 > --- a/db/command.c > +++ b/db/command.c > @@ -131,6 +131,7 @@ init_commands(void) > logformat_init(); > io_init(); > metadump_init(); > + namei_init(); > output_init(); > print_init(); > quit_init(); > diff --git a/db/command.h b/db/command.h > index 6913c817..498983ff 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 timelimit_init(void); > +extern void namei_init(void); > diff --git a/db/namei.c b/db/namei.c > new file mode 100644 > index 00000000..6fddbc4a > --- /dev/null > +++ b/db/namei.c > @@ -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); > +} > diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 > index 55388be6..4df265ec 100644 > --- a/man/man8/xfs_db.8 > +++ b/man/man8/xfs_db.8 > @@ -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 -- chandan ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCHSET v3 0/2] xfs_db: add minimal directory navigation @ 2021-01-16 1:24 Darrick J. Wong 2021-01-16 1:24 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 0 siblings, 1 reply; 16+ messages in thread From: Darrick J. Wong @ 2021-01-16 1:24 UTC (permalink / raw) To: sandeen, djwong; +Cc: linux-xfs Hi all, This patchset improves the usability of xfs_db by enabling users to navigate to inodes by path and to list the contents of directories. v2: Various cleanups and reorganizing suggested by dchinner v3: Rebase to 5.10-rc0 If you're going to start using this mess, you probably ought to just pull from my git trees, which are linked below. This is an extraordinary way to destroy everything. Enjoy! Comments and questions are, as always, welcome. --D xfsprogs git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=xfs_db-directory-navigation fstests git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=xfs_db-directory-navigation --- db/Makefile | 3 db/command.c | 1 db/command.h | 1 db/namei.c | 612 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 20 ++ 6 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 db/namei.c ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/2] xfs_db: add a directory path lookup command 2021-01-16 1:24 [PATCHSET v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong @ 2021-01-16 1:24 ` Darrick J. Wong 2021-01-20 12:35 ` Chandan Babu R 0 siblings, 1 reply; 16+ messages in thread From: Darrick J. Wong @ 2021-01-16 1:24 UTC (permalink / raw) To: sandeen, djwong; +Cc: linux-xfs From: Darrick J. Wong <djwong@kernel.org> Add a command to xfs_db so that we can navigate to inodes by path. Signed-off-by: Darrick J. Wong <djwong@kernel.org> --- db/Makefile | 3 - db/command.c | 1 db/command.h | 1 db/namei.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_db.8 | 4 + 5 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 db/namei.c diff --git a/db/Makefile b/db/Makefile index 9d502bf0..beafb105 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 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) diff --git a/db/command.c b/db/command.c index 43828369..02f778b9 100644 --- a/db/command.c +++ b/db/command.c @@ -131,6 +131,7 @@ init_commands(void) logformat_init(); io_init(); metadump_init(); + namei_init(); output_init(); print_init(); quit_init(); diff --git a/db/command.h b/db/command.h index 6913c817..498983ff 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 timelimit_init(void); +extern void namei_init(void); diff --git a/db/namei.c b/db/namei.c new file mode 100644 index 00000000..eebebe15 --- /dev/null +++ b/db/namei.c @@ -0,0 +1,223 @@ +// 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); + if (error) + return error; + + path_free(dirpath); + return 0; +} + +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); +} diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 55388be6..4df265ec 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -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 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] xfs_db: add a directory path lookup command 2021-01-16 1:24 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong @ 2021-01-20 12:35 ` Chandan Babu R 2021-01-20 17:39 ` Darrick J. Wong 0 siblings, 1 reply; 16+ messages in thread From: Chandan Babu R @ 2021-01-20 12:35 UTC (permalink / raw) To: Darrick J. Wong; +Cc: sandeen, linux-xfs On 16 Jan 2021 at 06:54, Darrick J. Wong wrote: > From: Darrick J. Wong <djwong@kernel.org> > > Add a command to xfs_db so that we can navigate to inodes by path. > > Signed-off-by: Darrick J. Wong <djwong@kernel.org> > --- > db/Makefile | 3 - > db/command.c | 1 > db/command.h | 1 > db/namei.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > man/man8/xfs_db.8 | 4 + > 5 files changed, 231 insertions(+), 1 deletion(-) > create mode 100644 db/namei.c > > > diff --git a/db/Makefile b/db/Makefile > index 9d502bf0..beafb105 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 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) > diff --git a/db/command.c b/db/command.c > index 43828369..02f778b9 100644 > --- a/db/command.c > +++ b/db/command.c > @@ -131,6 +131,7 @@ init_commands(void) > logformat_init(); > io_init(); > metadump_init(); > + namei_init(); > output_init(); > print_init(); > quit_init(); > diff --git a/db/command.h b/db/command.h > index 6913c817..498983ff 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 timelimit_init(void); > +extern void namei_init(void); > diff --git a/db/namei.c b/db/namei.c > new file mode 100644 > index 00000000..eebebe15 > --- /dev/null > +++ b/db/namei.c > @@ -0,0 +1,223 @@ > +// 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); > + if (error) > + return error; Memory pointed by dirpath (and its members) is not freed if the call to path_navigate() returns a non-zero error value. > + > + path_free(dirpath); > + return 0; > +} > + > +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); > +} > diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 > index 55388be6..4df265ec 100644 > --- a/man/man8/xfs_db.8 > +++ b/man/man8/xfs_db.8 > @@ -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 -- chandan ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] xfs_db: add a directory path lookup command 2021-01-20 12:35 ` Chandan Babu R @ 2021-01-20 17:39 ` Darrick J. Wong 0 siblings, 0 replies; 16+ messages in thread From: Darrick J. Wong @ 2021-01-20 17:39 UTC (permalink / raw) To: Chandan Babu R; +Cc: sandeen, linux-xfs On Wed, Jan 20, 2021 at 06:05:35PM +0530, Chandan Babu R wrote: > > On 16 Jan 2021 at 06:54, Darrick J. Wong wrote: > > From: Darrick J. Wong <djwong@kernel.org> > > > > Add a command to xfs_db so that we can navigate to inodes by path. > > > > Signed-off-by: Darrick J. Wong <djwong@kernel.org> > > --- > > db/Makefile | 3 - > > db/command.c | 1 > > db/command.h | 1 > > db/namei.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > > man/man8/xfs_db.8 | 4 + > > 5 files changed, 231 insertions(+), 1 deletion(-) > > create mode 100644 db/namei.c > > > > > > diff --git a/db/Makefile b/db/Makefile > > index 9d502bf0..beafb105 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 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) > > diff --git a/db/command.c b/db/command.c > > index 43828369..02f778b9 100644 > > --- a/db/command.c > > +++ b/db/command.c > > @@ -131,6 +131,7 @@ init_commands(void) > > logformat_init(); > > io_init(); > > metadump_init(); > > + namei_init(); > > output_init(); > > print_init(); > > quit_init(); > > diff --git a/db/command.h b/db/command.h > > index 6913c817..498983ff 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 timelimit_init(void); > > +extern void namei_init(void); > > diff --git a/db/namei.c b/db/namei.c > > new file mode 100644 > > index 00000000..eebebe15 > > --- /dev/null > > +++ b/db/namei.c > > @@ -0,0 +1,223 @@ <snip some of this out> > > +/* 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); > > + if (error) > > + return error; > > Memory pointed by dirpath (and its members) is not freed if the call to > path_navigate() returns a non-zero error value. Good catch, thanks! --D ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 0/2] xfs_db: add minimal directory navigation @ 2020-11-25 20:38 Darrick J. Wong 2020-11-25 20:38 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 0 siblings, 1 reply; 16+ messages in thread From: Darrick J. Wong @ 2020-11-25 20:38 UTC (permalink / raw) To: sandeen, darrick.wong; +Cc: linux-xfs Hi all, Improve the usability of xfs_db by enabling users to navigate to inodes by path and to list the contents of directories. v2: Various cleanups and reorganizing suggested by dchinner v3: Rebase to 5.10-rc0 If you're going to start using this mess, you probably ought to just pull from my git trees, which are linked below. This is an extraordinary way to destroy everything. Enjoy! Comments and questions are, as always, welcome. --D xfsprogs git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=xfs_db-directory-navigation fstests git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=xfs_db-directory-navigation --- db/Makefile | 3 db/command.c | 1 db/command.h | 1 db/namei.c | 612 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 20 ++ 6 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 db/namei.c ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/2] xfs_db: add a directory path lookup command 2020-11-25 20:38 [PATCH v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong @ 2020-11-25 20:38 ` Darrick J. Wong 2020-12-01 10:16 ` Christoph Hellwig 0 siblings, 1 reply; 16+ messages in thread From: Darrick J. Wong @ 2020-11-25 20:38 UTC (permalink / raw) To: sandeen, darrick.wong; +Cc: linux-xfs From: Darrick J. Wong <darrick.wong@oracle.com> Add a command to xfs_db so that we can navigate to inodes by path. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- db/Makefile | 3 - db/command.c | 1 db/command.h | 1 db/namei.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_db.8 | 4 + 5 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 db/namei.c diff --git a/db/Makefile b/db/Makefile index 9d502bf0d0d6..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 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) diff --git a/db/command.c b/db/command.c index 438283699b2e..02f778b9316b 100644 --- a/db/command.c +++ b/db/command.c @@ -131,6 +131,7 @@ init_commands(void) logformat_init(); io_init(); metadump_init(); + namei_init(); output_init(); print_init(); quit_init(); diff --git a/db/command.h b/db/command.h index 6913c8171fe1..498983ff92fa 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 timelimit_init(void); +extern void namei_init(void); diff --git a/db/namei.c b/db/namei.c new file mode 100644 index 000000000000..13ae7f7d116b --- /dev/null +++ b/db/namei.c @@ -0,0 +1,223 @@ +// 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" +#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); + if (error) + return error; + + path_free(dirpath); + return 0; +} + +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); +} diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 55388be68b93..4df265ecd59e 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -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 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] xfs_db: add a directory path lookup command 2020-11-25 20:38 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong @ 2020-12-01 10:16 ` Christoph Hellwig 0 siblings, 0 replies; 16+ messages in thread From: Christoph Hellwig @ 2020-12-01 10:16 UTC (permalink / raw) To: Darrick J. Wong; +Cc: sandeen, linux-xfs Looks good, Reviewed-by: Christoph Hellwig <hch@lst.de> ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 0/2] xfs_db: add minimal directory navigation @ 2020-11-16 17:35 Darrick J. Wong 2020-11-16 17:35 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 0 siblings, 1 reply; 16+ messages in thread From: Darrick J. Wong @ 2020-11-16 17:35 UTC (permalink / raw) To: sandeen, darrick.wong; +Cc: linux-xfs Hi all, Improve the usability of xfs_db by enabling users to navigate to inodes by path and to list the contents of directories. v2: Various cleanups and reorganizing suggested by dchinner If you're going to start using this mess, you probably ought to just pull from my git trees, which are linked below. This is an extraordinary way to destroy everything. Enjoy! Comments and questions are, as always, welcome. --D xfsprogs git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=xfs_db-directory-navigation fstests git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=xfs_db-directory-navigation --- db/Makefile | 2 db/command.c | 1 db/command.h | 1 db/namei.c | 612 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 20 ++ 6 files changed, 636 insertions(+), 1 deletion(-) create mode 100644 db/namei.c ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/2] xfs_db: add a directory path lookup command 2020-11-16 17:35 [PATCH v2 0/2] xfs_db: add minimal directory navigation Darrick J. Wong @ 2020-11-16 17:35 ` Darrick J. Wong 0 siblings, 0 replies; 16+ messages in thread From: Darrick J. Wong @ 2020-11-16 17:35 UTC (permalink / raw) To: sandeen, darrick.wong; +Cc: linux-xfs From: Darrick J. Wong <darrick.wong@oracle.com> Add a command to xfs_db so that we can navigate to inodes by path. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- db/Makefile | 2 db/command.c | 1 db/command.h | 1 db/namei.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_db.8 | 4 + 5 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 db/namei.c diff --git a/db/Makefile b/db/Makefile index 9bd9bf514f5d..67908a2c3c98 100644 --- a/db/Makefile +++ b/db/Makefile @@ -14,7 +14,7 @@ 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 +CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c namei.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 0fb44efaec59..053097742b12 100644 --- a/db/command.c +++ b/db/command.c @@ -131,6 +131,7 @@ init_commands(void) logformat_init(); io_init(); metadump_init(); + namei_init(); output_init(); print_init(); quit_init(); diff --git a/db/command.h b/db/command.h index b8499de0be17..bf130e63c85c 100644 --- a/db/command.h +++ b/db/command.h @@ -32,3 +32,4 @@ extern void convert_init(void); extern void btdump_init(void); extern void info_init(void); extern void btheight_init(void); +extern void namei_init(void); diff --git a/db/namei.c b/db/namei.c new file mode 100644 index 000000000000..13ae7f7d116b --- /dev/null +++ b/db/namei.c @@ -0,0 +1,223 @@ +// 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" +#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); + if (error) + return error; + + path_free(dirpath); + return 0; +} + +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); +} diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 7f73d458cf76..d67e108a706a 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -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 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 0/2] xfs_db: add minimal directory navigation @ 2020-10-26 23:32 Darrick J. Wong 2020-10-26 23:32 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 0 siblings, 1 reply; 16+ messages in thread From: Darrick J. Wong @ 2020-10-26 23:32 UTC (permalink / raw) To: sandeen, darrick.wong; +Cc: linux-xfs Hi all, Improve the usability of xfs_db by enabling users to navigate to inodes by path and to list the contents of directories. If you're going to start using this mess, you probably ought to just pull from my git trees, which are linked below. This is an extraordinary way to destroy everything. Enjoy! Comments and questions are, as always, welcome. --D xfsprogs git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=xfs_db-directory-navigation fstests git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=xfs_db-directory-navigation --- db/Makefile | 2 db/command.c | 1 db/command.h | 1 db/namei.c | 608 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 18 + 6 files changed, 630 insertions(+), 1 deletion(-) create mode 100644 db/namei.c ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/2] xfs_db: add a directory path lookup command 2020-10-26 23:32 [PATCH 0/2] xfs_db: add minimal directory navigation Darrick J. Wong @ 2020-10-26 23:32 ` Darrick J. Wong 2020-10-28 0:35 ` Dave Chinner 2020-11-15 16:30 ` Eric Sandeen 0 siblings, 2 replies; 16+ messages in thread From: Darrick J. Wong @ 2020-10-26 23:32 UTC (permalink / raw) To: sandeen, darrick.wong; +Cc: linux-xfs From: Darrick J. Wong <darrick.wong@oracle.com> Add a command to xfs_db so that we can navigate to inodes by path. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- db/Makefile | 2 db/command.c | 1 db/command.h | 1 db/namei.c | 228 +++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_db.8 | 4 + 5 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 db/namei.c diff --git a/db/Makefile b/db/Makefile index 9bd9bf514f5d..67908a2c3c98 100644 --- a/db/Makefile +++ b/db/Makefile @@ -14,7 +14,7 @@ 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 +CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c namei.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 0fb44efaec59..053097742b12 100644 --- a/db/command.c +++ b/db/command.c @@ -131,6 +131,7 @@ init_commands(void) logformat_init(); io_init(); metadump_init(); + namei_init(); output_init(); print_init(); quit_init(); diff --git a/db/command.h b/db/command.h index b8499de0be17..bf130e63c85c 100644 --- a/db/command.h +++ b/db/command.h @@ -32,3 +32,4 @@ extern void convert_init(void); extern void btdump_init(void); extern void info_init(void); extern void btheight_init(void); +extern void namei_init(void); diff --git a/db/namei.c b/db/namei.c new file mode 100644 index 000000000000..3c9889d62338 --- /dev/null +++ b/db/namei.c @@ -0,0 +1,228 @@ +// 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" +#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 ret = 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]) { + dbprintf(_("current object is not an inode.\n")); + return -1; + } + + if (!S_ISDIR(iocur_top->mode)) { + dbprintf(_("current inode %llu is not a directory.\n"), + (unsigned long long)iocur_top->ino); + return -1; + } + rootino = iocur_top->ino; + } + + dirpath = path_parse(p); + if (!dirpath) { + dbprintf(_("%s: not enough memory to parse.\n"), path); + return -1; + } + + ret = path_navigate(mp, rootino, dirpath); + if (ret) { + dbprintf(_("%s: %s\n"), path, strerror(ret)); + ret = -1; + } + + path_free(dirpath); + return ret; +} + +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; + + while ((c = getopt(argc, argv, "")) != -1) { + switch (c) { + default: + path_help(); + return 0; + } + } + + if (path_walk(argv[optind])) + exitcode = 1; + return 0; +} + +static const cmdinfo_t path_cmd = { + .name = "path", + .altname = NULL, + .cfunc = path_f, + .argmin = 1, + .argmax = 1, + .canpush = 0, + .args = "", + .oneline = N_("navigate to an inode by path"), + .help = path_help, +}; + +void +namei_init(void) +{ + add_command(&path_cmd); +} diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 7f73d458cf76..d67e108a706a 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -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 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] xfs_db: add a directory path lookup command 2020-10-26 23:32 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong @ 2020-10-28 0:35 ` Dave Chinner 2020-10-29 18:38 ` Darrick J. Wong 2020-11-15 16:30 ` Eric Sandeen 1 sibling, 1 reply; 16+ messages in thread From: Dave Chinner @ 2020-10-28 0:35 UTC (permalink / raw) To: Darrick J. Wong; +Cc: sandeen, linux-xfs On Mon, Oct 26, 2020 at 04:32:34PM -0700, Darrick J. Wong wrote: > From: Darrick J. Wong <darrick.wong@oracle.com> > > Add a command to xfs_db so that we can navigate to inodes by path. > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> .... > +/* 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; > +} This could return negative errors.... > +/* 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 ret = 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]) { > + dbprintf(_("current object is not an inode.\n")); > + return -1; > + } > + > + if (!S_ISDIR(iocur_top->mode)) { > + dbprintf(_("current inode %llu is not a directory.\n"), > + (unsigned long long)iocur_top->ino); > + return -1; > + } > + rootino = iocur_top->ino; > + } > + > + dirpath = path_parse(p); > + if (!dirpath) { > + dbprintf(_("%s: not enough memory to parse.\n"), path); > + return -1; > + } and this could return -ENOMEM here with no error message.... > + > + ret = path_navigate(mp, rootino, dirpath); > + if (ret) { > + dbprintf(_("%s: %s\n"), path, strerror(ret)); > + ret = -1; > + } ... don't overwrite ret here, move the dbprintf() to the caller and the one error message captures all possible errors. Also, no need for _() for a format string that contains no translatable text.... Otherwise, looks fine. -Dave. -- Dave Chinner david@fromorbit.com ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] xfs_db: add a directory path lookup command 2020-10-28 0:35 ` Dave Chinner @ 2020-10-29 18:38 ` Darrick J. Wong 0 siblings, 0 replies; 16+ messages in thread From: Darrick J. Wong @ 2020-10-29 18:38 UTC (permalink / raw) To: Dave Chinner; +Cc: sandeen, linux-xfs On Wed, Oct 28, 2020 at 11:35:51AM +1100, Dave Chinner wrote: > On Mon, Oct 26, 2020 at 04:32:34PM -0700, Darrick J. Wong wrote: > > From: Darrick J. Wong <darrick.wong@oracle.com> > > > > Add a command to xfs_db so that we can navigate to inodes by path. > > > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> > .... > > +/* 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; > > +} > > This could return negative errors.... > > > +/* 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 ret = 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]) { > > + dbprintf(_("current object is not an inode.\n")); > > + return -1; > > + } > > + > > + if (!S_ISDIR(iocur_top->mode)) { > > + dbprintf(_("current inode %llu is not a directory.\n"), > > + (unsigned long long)iocur_top->ino); > > + return -1; > > + } > > + rootino = iocur_top->ino; > > + } > > + > > + dirpath = path_parse(p); > > + if (!dirpath) { > > + dbprintf(_("%s: not enough memory to parse.\n"), path); > > + return -1; > > + } > > and this could return -ENOMEM here with no error message.... > > > + > > + ret = path_navigate(mp, rootino, dirpath); > > + if (ret) { > > + dbprintf(_("%s: %s\n"), path, strerror(ret)); > > + ret = -1; > > + } > > ... don't overwrite ret here, move the dbprintf() to the caller and > the one error message captures all possible errors. > > Also, no need for _() for a format string that contains no > translatable text.... Ok, will fix. Thanks! --D > Otherwise, looks fine. > > -Dave. > -- > Dave Chinner > david@fromorbit.com ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] xfs_db: add a directory path lookup command 2020-10-26 23:32 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 2020-10-28 0:35 ` Dave Chinner @ 2020-11-15 16:30 ` Eric Sandeen 1 sibling, 0 replies; 16+ messages in thread From: Eric Sandeen @ 2020-11-15 16:30 UTC (permalink / raw) To: Darrick J. Wong; +Cc: linux-xfs On 10/26/20 6:32 PM, Darrick J. Wong wrote: > From: Darrick J. Wong <darrick.wong@oracle.com> > > Add a command to xfs_db so that we can navigate to inodes by path. > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> ... > +/* Path lookup */ > + > +/* Key for looking up metadata inodes. */ > +struct dirpath { > + /* Array of string pointers. */ > + char **path; > + > + /* Number of strings in path. */ > + unsigned int depth; > +}; This generates warnings for me in gcc-4.8.5 (hah, I know) as well as gcc-9. namei.c:101:12: warning: pointer targets in initialization of ‘const unsigned char *’ from ‘char *’ differ in signedness [-Wpointer-sign] due to the "unsigned char *" type from: commit e2bcd936eb95d0019ca5e05f9fdd27e770ddded1 Author: Dave Chinner <david@fromorbit.com> Date: Wed Jan 20 10:44:58 2010 +1100 xfs: directory names are unsigned Convert the struct xfs_name to use unsigned chars for the name strings to match both what is stored on disk (__uint8_t) and what the VFS expects (unsigned char). Signed-off-by: Dave Chinner <david@fromorbit.com> Reviewed-by: Christoph Hellwig <hch@lst.de> so maybe just cast to shut it up? diff --git a/db/namei.c b/db/namei.c index 4b467ff8..a902f302 100644 --- a/db/namei.c +++ b/db/namei.c @@ -98,7 +98,7 @@ path_navigate( for (i = 0; i < dirpath->depth; i++) { struct xfs_name xname = { - .name = dirpath->path[i], + .name = (unsigned char *)dirpath->path[i], .len = strlen(dirpath->path[i]), }; @@ -253,7 +253,7 @@ dir_emit( uint8_t dtype) { char *display_name; - struct xfs_name xname = { .name = name }; + struct xfs_name xname = { .name = (unsigned char *)name }; const char *dstr = get_dstr(mp, dtype); xfs_dahash_t hash; bool good; ^ permalink raw reply related [flat|nested] 16+ messages in thread
end of thread, other threads:[~2021-02-09 4:14 UTC | newest] Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2021-01-09 6:27 [PATCHSET v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong 2021-01-09 6:27 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 2021-01-09 6:27 ` [PATCH 2/2] xfs_db: add an ls command Darrick J. Wong -- strict thread matches above, loose matches on Subject: below -- 2021-02-09 4:09 [PATCHSET v5 0/2] xfs_db: add minimal directory navigation Darrick J. Wong 2021-02-09 4:09 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 2021-02-03 19:42 [PATCHSET v4 0/2] xfs_db: add minimal directory navigation Darrick J. Wong 2021-02-03 19:43 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 2021-02-04 9:39 ` Chandan Babu R 2021-01-16 1:24 [PATCHSET v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong 2021-01-16 1:24 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 2021-01-20 12:35 ` Chandan Babu R 2021-01-20 17:39 ` Darrick J. Wong 2020-11-25 20:38 [PATCH v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong 2020-11-25 20:38 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 2020-12-01 10:16 ` Christoph Hellwig 2020-11-16 17:35 [PATCH v2 0/2] xfs_db: add minimal directory navigation Darrick J. Wong 2020-11-16 17:35 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 2020-10-26 23:32 [PATCH 0/2] xfs_db: add minimal directory navigation Darrick J. Wong 2020-10-26 23:32 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 2020-10-28 0:35 ` Dave Chinner 2020-10-29 18:38 ` Darrick J. Wong 2020-11-15 16:30 ` Eric Sandeen
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.