@@ -6,7 +6,7 @@ TOPDIR = ..
include $(TOPDIR)/include/builddefs
LTCOMMAND = xfs_io
-LSRCFILES = xfs_bmap.sh xfs_freeze.sh xfs_mkfile.sh
+LSRCFILES = xfs_bmap.sh xfs_freeze.sh xfs_mkfile.sh xfs_property
HFILES = init.h io.h
CFILES = \
attr.c \
@@ -92,6 +92,7 @@ install: default
$(LTINSTALL) -m 755 xfs_bmap.sh $(PKG_SBIN_DIR)/xfs_bmap
$(LTINSTALL) -m 755 xfs_freeze.sh $(PKG_SBIN_DIR)/xfs_freeze
$(LTINSTALL) -m 755 xfs_mkfile.sh $(PKG_SBIN_DIR)/xfs_mkfile
+ $(LTINSTALL) -m 755 xfs_property $(PKG_SBIN_DIR)/xfs_property
install-dev:
-include .dep
new file mode 100755
@@ -0,0 +1,77 @@
+#!/bin/bash -f
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2024 Oracle. All Rights Reserved.
+# Author: Darrick J. Wong <djwong@kernel.org>
+#
+
+OPTS=""
+USAGE="Usage: xfs_property [-V] [mountpoint|device|file] [list [-v]|get name...|set name=value...|remove name...]"
+
+# Try to find a loop device associated with a file. We only want to return
+# one loopdev (multiple loop devices can attach to a single file) so we grab
+# the last line and return it if it's actually a block device.
+try_find_loop_dev_for_file() {
+ local x="$(losetup -O NAME -j "$1" 2> /dev/null | tail -n 1)"
+ test -b "${x}" && echo "${x}"
+}
+
+while getopts "V" c
+do
+ case $c in
+ V) xfs_io -p xfs_info -V
+ status=$?
+ exit ${status}
+ ;;
+ *) echo "${USAGE}" 1>&2
+ exit 2
+ ;;
+ esac
+done
+set -- extra "$@"
+shift $OPTIND
+
+if [ $# -lt 2 ]; then
+ echo "${USAGE}" 1>&2
+ exit 2
+fi
+
+target="$1"
+shift
+subcommand="$1"
+shift
+
+db_args=()
+io_args=()
+
+case "$subcommand" in
+"list")
+ vparam=
+ if [ $# -eq 1 ] && [ "$1" = "-v" ]; then
+ vparam=" -v"
+ fi
+ db_args+=('-c' "attr_list -Z${vparam}")
+ io_args+=('-c' "listfsprops${vparam}")
+ ;;
+"get"|"remove"|"set")
+ for arg in "$@"; do
+ db_args+=('-c' "attr_${subcommand} -Z ${arg/=/ }")
+ io_args+=('-c' "${subcommand}fsprops ${arg}")
+ done
+ ;;
+*)
+ echo "${USAGE}" 1>&2
+ exit 2
+esac
+
+# See if we can map the arg to a loop device
+loopdev="$(try_find_loop_dev_for_file "${target}")"
+test -n "${loopdev}" && target="${loopdev}"
+
+# If we find a mountpoint for the device, do a live query; otherwise try
+# reading the fs with xfs_db.
+if mountpt="$(findmnt -t xfs -f -n -o TARGET "${target}" 2> /dev/null)"; then
+ exec xfs_io -p xfs_property "${io_args[@]}" "${mountpt}"
+else
+ exec xfs_db -p xfs_property -x -c 'path /' "${db_args[@]}" "${target}"
+fi
new file mode 100644
@@ -0,0 +1,61 @@
+.TH xfs_property 8
+.SH NAME
+xfs_property \- examine and edit properties about an XFS filesystem
+.SH SYNOPSIS
+.B xfs_property
+.I target
+.B get
+.IR name ...
+.br
+.B xfs_property
+.I target
+.B list [ \-v ]
+.br
+.B xfs_property
+.I target
+.B set
+.IR name=value ...
+.br
+.B xfs_property
+.I target
+.B remove
+.IR name ...
+.br
+.B xfs_property \-V
+.SH DESCRIPTION
+.B xfs_property
+retrieves, lists, sets, or removes properties of an XFS filesystem.
+Filesystem properties are root-controlled attributes set on the root directory
+of the filesystem to enable the system administrator to coordinate with
+userspace programs.
+
+.I target
+is one of: the root directory of a mounted filesystem; a block device containing
+an XFS filesystem; or a regular file containing an XFS filesystem.
+
+.SH OPTIONS
+.TP
+.B \-V
+Print the version number and exits.
+
+.SH COMMANDS
+.TP
+.B get
+.IR name ...
+Prints the values of the given filesystem properties.
+.TP
+.B list
+Lists the names of all filesystem properties.
+If the
+.B -v
+flag is specified, prints the values as well.
+.TP
+.B set
+.IR name = value ...
+Sets the given filesystem properties to the specified values and prints what
+was set.
+.TP
+.B
+remove
+.IR name ...
+Unsets the given filesystem properties.