]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_db: make attr_set and attr_remove handle parent pointers
authorDarrick J. Wong <djwong@kernel.org>
Fri, 15 Mar 2024 22:51:21 +0000 (15:51 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 10 Apr 2024 00:21:31 +0000 (17:21 -0700)
Make it so that xfs_db can load up the filesystem (somewhat uselessly)
with parent pointers.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
db/attrset.c
libxfs/libxfs_api_defs.h
man/man8/xfs_db.8

index 15e6c3fa5fe716a823433a0aa48c02748a659d5f..26b3e7882b1c883db928f120dc043ee67c9014a0 100644 (file)
@@ -24,11 +24,11 @@ static void         attrset_help(void);
 
 static const cmdinfo_t attr_set_cmd =
        { "attr_set", "aset", attr_set_f, 1, -1, 0,
-         N_("[-r|-s|-u] [-n] [-R|-C] [-v n] name"),
+         N_("[-r|-s|-u|-p] [-n] [-R|-C] [-v n] name"),
          N_("set the named attribute on the current inode"), attrset_help };
 static const cmdinfo_t attr_remove_cmd =
        { "attr_remove", "aremove", attr_remove_f, 1, -1, 0,
-         N_("[-r|-s|-u] [-n] name"),
+         N_("[-r|-s|-u|-p] [-n] name"),
          N_("remove the named attribute from the current inode"), attrset_help };
 
 static void
@@ -44,6 +44,7 @@ attrset_help(void)
 "  -r -- 'root'\n"
 "  -u -- 'user'                (default)\n"
 "  -s -- 'secure'\n"
+"  -p -- 'parent'\n"
 "\n"
 " For attr_set, these options further define the type of set operation:\n"
 "  -C -- 'create'    - create attribute, fail if it already exists\n"
@@ -62,6 +63,49 @@ attrset_init(void)
        add_command(&attr_remove_cmd);
 }
 
+static unsigned char *
+get_buf_from_file(
+       const char      *fname,
+       size_t          bufsize,
+       int             *namelen)
+{
+       FILE            *fp;
+       unsigned char   *buf;
+       size_t          sz;
+
+       buf = malloc(bufsize + 1);
+       if (!buf) {
+               perror("malloc");
+               return NULL;
+       }
+
+       fp = fopen(fname, "r");
+       if (!fp) {
+               perror(fname);
+               goto out_free;
+       }
+
+       sz = fread(buf, sizeof(char), bufsize, fp);
+       if (sz == 0) {
+               printf("%s: Could not read anything from file\n", fname);
+               goto out_fp;
+       }
+
+       fclose(fp);
+
+       *namelen = sz;
+       return buf;
+out_fp:
+       fclose(fp);
+out_free:
+       free(buf);
+       return NULL;
+}
+
+#define LIBXFS_ATTR_NS         (LIBXFS_ATTR_SECURE | \
+                                LIBXFS_ATTR_ROOT | \
+                                LIBXFS_ATTR_PARENT)
+
 static int
 attr_set_f(
        int                     argc,
@@ -69,6 +113,8 @@ attr_set_f(
 {
        struct xfs_da_args      args = { };
        char                    *sp;
+       char                    *name_from_file = NULL;
+       char                    *value_from_file = NULL;
        int                     c;
 
        if (cur_typ == NULL) {
@@ -80,20 +126,23 @@ attr_set_f(
                return 0;
        }
 
-       while ((c = getopt(argc, argv, "rusCRnv:")) != EOF) {
+       while ((c = getopt(argc, argv, "ruspCRnN:v:V:")) != EOF) {
                switch (c) {
                /* namespaces */
                case 'r':
+                       args.attr_filter &= ~LIBXFS_ATTR_NS;
                        args.attr_filter |= LIBXFS_ATTR_ROOT;
-                       args.attr_filter &= ~LIBXFS_ATTR_SECURE;
                        break;
                case 'u':
-                       args.attr_filter &= ~(LIBXFS_ATTR_ROOT |
-                                             LIBXFS_ATTR_SECURE);
+                       args.attr_filter &= ~LIBXFS_ATTR_NS;
                        break;
                case 's':
+                       args.attr_filter &= ~LIBXFS_ATTR_NS;
                        args.attr_filter |= LIBXFS_ATTR_SECURE;
-                       args.attr_filter &= ~LIBXFS_ATTR_ROOT;
+                       break;
+               case 'p':
+                       args.attr_filter &= ~LIBXFS_ATTR_NS;
+                       args.attr_filter |= XFS_ATTR_PARENT;
                        break;
 
                /* modifiers */
@@ -106,6 +155,10 @@ attr_set_f(
                        args.xattr_flags &= ~XATTR_CREATE;
                        break;
 
+               case 'N':
+                       name_from_file = optarg;
+                       break;
+
                case 'n':
                        /*
                         * We never touch attr2 these days; leave this here to
@@ -115,6 +168,11 @@ attr_set_f(
 
                /* value length */
                case 'v':
+                       if (value_from_file) {
+                               dbprintf(_("already set value file\n"));
+                               return 0;
+                       }
+
                        args.valuelen = strtol(optarg, &sp, 0);
                        if (*sp != '\0' ||
                            args.valuelen < 0 || args.valuelen > 64 * 1024) {
@@ -123,30 +181,64 @@ attr_set_f(
                        }
                        break;
 
+               case 'V':
+                       if (args.valuelen != 0) {
+                               dbprintf(_("already set valuelen\n"));
+                               return 0;
+                       }
+
+                       value_from_file = optarg;
+                       break;
+
                default:
                        dbprintf(_("bad option for attr_set command\n"));
                        return 0;
                }
        }
 
-       if (optind != argc - 1) {
-               dbprintf(_("too few options for attr_set (no name given)\n"));
-               return 0;
-       }
+       if (name_from_file) {
+               int namelen;
 
-       args.name = (const unsigned char *)argv[optind];
-       if (!args.name) {
-               dbprintf(_("invalid name\n"));
-               return 0;
-       }
+               if (optind != argc) {
+                       dbprintf(_("too many options for attr_set (no name needed)\n"));
+                       return 0;
+               }
 
-       args.namelen = strlen(argv[optind]);
-       if (args.namelen >= MAXNAMELEN) {
-               dbprintf(_("name too long\n"));
-               return 0;
+               args.name = get_buf_from_file(name_from_file, MAXNAMELEN,
+                               &namelen);
+               if (!args.name)
+                       return 0;
+
+               args.namelen = namelen;
+       } else {
+               if (optind != argc - 1) {
+                       dbprintf(_("too few options for attr_set (no name given)\n"));
+                       return 0;
+               }
+
+               args.name = (const unsigned char *)argv[optind];
+               if (!args.name) {
+                       dbprintf(_("invalid name\n"));
+                       return 0;
+               }
+
+               args.namelen = strlen(argv[optind]);
+               if (args.namelen >= MAXNAMELEN) {
+                       dbprintf(_("name too long\n"));
+                       goto out;
+               }
        }
 
-       if (args.valuelen) {
+       if (value_from_file) {
+               int valuelen;
+
+               args.value = get_buf_from_file(value_from_file,
+                               XFS_XATTR_SIZE_MAX, &valuelen);
+               if (!args.value)
+                       goto out;
+
+               args.valuelen = valuelen;
+       } else if (args.valuelen) {
                args.value = memalign(getpagesize(), args.valuelen);
                if (!args.value) {
                        dbprintf(_("cannot allocate buffer (%d)\n"),
@@ -176,6 +268,8 @@ out:
                libxfs_irele(args.dp);
        if (args.value)
                free(args.value);
+       if (name_from_file)
+               free((void *)args.name);
        return 0;
 }
 
@@ -185,6 +279,7 @@ attr_remove_f(
        char                    **argv)
 {
        struct xfs_da_args      args = { };
+       char                    *name_from_file = NULL;
        int                     c;
 
        if (cur_typ == NULL) {
@@ -196,20 +291,27 @@ attr_remove_f(
                return 0;
        }
 
-       while ((c = getopt(argc, argv, "rusn")) != EOF) {
+       while ((c = getopt(argc, argv, "ruspnN:")) != EOF) {
                switch (c) {
                /* namespaces */
                case 'r':
+                       args.attr_filter &= ~LIBXFS_ATTR_NS;
                        args.attr_filter |= LIBXFS_ATTR_ROOT;
-                       args.attr_filter &= ~LIBXFS_ATTR_SECURE;
                        break;
                case 'u':
-                       args.attr_filter &= ~(LIBXFS_ATTR_ROOT |
-                                             LIBXFS_ATTR_SECURE);
+                       args.attr_filter &= ~LIBXFS_ATTR_NS;
                        break;
                case 's':
+                       args.attr_filter &= ~LIBXFS_ATTR_NS;
                        args.attr_filter |= LIBXFS_ATTR_SECURE;
-                       args.attr_filter &= ~LIBXFS_ATTR_ROOT;
+                       break;
+               case 'p':
+                       args.attr_filter &= ~LIBXFS_ATTR_NS;
+                       args.attr_filter |= XFS_ATTR_PARENT;
+                       break;
+
+               case 'N':
+                       name_from_file = optarg;
                        break;
 
                case 'n':
@@ -225,21 +327,37 @@ attr_remove_f(
                }
        }
 
-       if (optind != argc - 1) {
-               dbprintf(_("too few options for attr_remove (no name given)\n"));
-               return 0;
-       }
+       if (name_from_file) {
+               int namelen;
 
-       args.name = (const unsigned char *)argv[optind];
-       if (!args.name) {
-               dbprintf(_("invalid name\n"));
-               return 0;
-       }
+               if (optind != argc) {
+                       dbprintf(_("too many options for attr_set (no name needed)\n"));
+                       return 0;
+               }
 
-       args.namelen = strlen(argv[optind]);
-       if (args.namelen >= MAXNAMELEN) {
-               dbprintf(_("name too long\n"));
-               return 0;
+               args.name = get_buf_from_file(name_from_file, MAXNAMELEN,
+                               &namelen);
+               if (!args.name)
+                       return 0;
+
+               args.namelen = namelen;
+       } else {
+               if (optind != argc - 1) {
+                       dbprintf(_("too few options for attr_remove (no name given)\n"));
+                       return 0;
+               }
+
+               args.name = (const unsigned char *)argv[optind];
+               if (!args.name) {
+                       dbprintf(_("invalid name\n"));
+                       return 0;
+               }
+
+               args.namelen = strlen(argv[optind]);
+               if (args.namelen >= MAXNAMELEN) {
+                       dbprintf(_("name too long\n"));
+                       return 0;
+               }
        }
 
        if (libxfs_iget(mp, NULL, iocur_top->ino, 0, &args.dp)) {
@@ -261,5 +379,7 @@ attr_remove_f(
 out:
        if (args.dp)
                libxfs_irele(args.dp);
+       if (name_from_file)
+               free((void *)args.name);
        return 0;
 }
index b6f83f40c8265b27dbb60eb052342448fd186185..4f0eeccfabbe7fba2b44c9180278632e53d7263b 100644 (file)
@@ -15,6 +15,7 @@
  */
 #define LIBXFS_ATTR_ROOT               XFS_ATTR_ROOT
 #define LIBXFS_ATTR_SECURE             XFS_ATTR_SECURE
+#define LIBXFS_ATTR_PARENT             XFS_ATTR_PARENT
 
 #define xfs_agfl_size                  libxfs_agfl_size
 #define xfs_agfl_walk                  libxfs_agfl_walk
index 937b17e79a35eeb428973d6377549ad26eeab771..a561bdc492d4f3f681f857568df807c67c9f3a84 100644 (file)
@@ -184,10 +184,14 @@ Displays the length, free block count, per-AG reservation size, and per-AG
 reservation usage for a given AG.
 If no argument is given, display information for all AGs.
 .TP
-.BI "attr_remove [\-r|\-u|\-s] [\-n] " name
+.BI "attr_remove [\-p|\-r|\-u|\-s] [\-n] [\-N " namefile "|" name "] "
 Remove the specified extended attribute from the current file.
 .RS 1.0i
 .TP 0.4i
+.B \-p
+Sets the attribute in the parent namespace.
+Only one namespace option can be specified.
+.TP
 .B \-r
 Sets the attribute in the root namespace.
 Only one namespace option can be specified.
@@ -200,14 +204,21 @@ Only one namespace option can be specified.
 Sets the attribute in the secure namespace.
 Only one namespace option can be specified.
 .TP
+.B \-N
+Read the name from this file.
+.TP
 .B \-n
 Do not enable 'noattr2' mode on V4 filesystems.
 .RE
 .TP
-.BI "attr_set [\-r|\-u|\-s] [\-n] [\-R|\-C] [\-v " namelen "] " name
+.BI "attr_set [\-p\-r|\-u|\-s] [\-n] [\-R|\-C] [\-v " valuelen "|\-V " valuefile "] [\-N " namefile "|" name "] "
 Sets an extended attribute on the current file with the given name.
 .RS 1.0i
 .TP 0.4i
+.B \-p
+Sets the attribute in the parent namespace.
+Only one namespace option can be specified.
+.TP
 .B \-r
 Sets the attribute in the root namespace.
 Only one namespace option can be specified.
@@ -220,6 +231,9 @@ Only one namespace option can be specified.
 Sets the attribute in the secure namespace.
 Only one namespace option can be specified.
 .TP
+.B \-N
+Read the name from this file.
+.TP
 .B \-n
 Do not enable 'noattr2' mode on V4 filesystems.
 .TP
@@ -231,6 +245,9 @@ The command will fail if the attribute does not already exist.
 Create the attribute.
 The command will fail if the attribute already exists.
 .TP
+.B \-V
+Read the value from this file.
+.TP
 .B \-v
 Set the attribute value to a string of this length containing the letter 'v'.
 .RE