s3/util: mvxattr, a tool to rename extended attributes
authorRalph Boehme <slow@samba.org>
Fri, 3 Feb 2017 13:57:45 +0000 (14:57 +0100)
committerJeremy Allison <jra@samba.org>
Fri, 10 Feb 2017 21:24:59 +0000 (22:24 +0100)
Usage: mvxattr -s STRING -d STRING PATH [PATH ...]
  -s, --from=STRING         xattr source name
  -d, --to=STRING           xattr destination name
  -l, --follow-symlinks     follow symlinks, the default is to ignore them
  -p, --print               print files where the xattr got renamed
  -v, --verbose             print files as they are checked
  -f, --force               force overwriting of destination xattr

Help options:
  -?, --help            Show this help message
  --usage               Display brief usage message

Bug: https://bugzilla.samba.org/show_bug.cgi?id=12490

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Fri Feb 10 22:24:59 CET 2017 on sn-devel-144

docs-xml/manpages/mvxattr.1.xml [new file with mode: 0644]
docs-xml/wscript_build
source3/utils/mvxattr.c [new file with mode: 0644]
source3/utils/wscript_build
source3/wscript

diff --git a/docs-xml/manpages/mvxattr.1.xml b/docs-xml/manpages/mvxattr.1.xml
new file mode 100644 (file)
index 0000000..034dc3a
--- /dev/null
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="mvxattr.1">
+
+<refmeta>
+       <refentrytitle>mvxattr</refentrytitle>
+       <manvolnum>1</manvolnum>
+       <refmiscinfo class="source">Samba</refmiscinfo>
+       <refmiscinfo class="manual">User Commands</refmiscinfo>
+       <refmiscinfo class="version">4.7</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+       <refname>mvxattr</refname>
+       <refpurpose>Recursively rename extended attributes</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+       <cmdsynopsis>
+               <command>mvxattr</command>
+               <arg choice="req">-s STRING, --from=STRING</arg>
+               <arg choice="req">-d STRING, --to=STRING</arg>
+               <arg choice="opt">-l, --follow-symlinks</arg>
+               <arg choice="opt">-p, --print</arg>
+               <arg choice="opt">-v, --verbose</arg>
+               <arg choice="opt">-f, --force</arg>
+               <arg choice="req">PATH [PATH ...]</arg>
+       </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+       <title>DESCRIPTION</title>
+
+       <para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle>
+       <manvolnum>1</manvolnum></citerefentry> suite.</para>
+
+       <para>mvxattr is a simple utility to recursively rename extended
+       attributes.</para>
+
+       <para>By default all symlinks are ignored, use <option>-l</option> to
+       follow them.</para>
+</refsect1>
+
+<refsect1>
+       <title>OPTIONS</title>
+
+       <variablelist>
+       <varlistentry>
+               <term>-s STRING, --from=STRING</term>
+               <listitem><para>Source xattr name</para></listitem>
+       </varlistentry>
+
+       <varlistentry>
+               <term>-d STRING, --to=STRING</term>
+               <listitem><para>Destination xattr name</para></listitem>
+       </varlistentry>
+
+       <varlistentry>
+               <term>-l, --follow-symlinks</term>
+               <listitem><para>Follow symlinks, the default is to ignore
+               them.</para></listitem>
+       </varlistentry>
+
+       <varlistentry>
+               <term>-p, --print</term>
+               <listitem><para>Print files where the xattr got renamed.</para></listitem>
+       </varlistentry>
+
+       <varlistentry>
+               <term>-v, --verbose</term>
+               <listitem><para>Print files as they are checked.</para></listitem>
+       </varlistentry>
+
+       <varlistentry>
+               <term>-f, --force</term>
+               <listitem><para>Force overwriting of destination xattr.</para></listitem>
+       </varlistentry>
+       </variablelist>
+
+</refsect1>
+
+<refsect1>
+       <title>VERSION</title>
+
+       <para>This man page is correct for version 4 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+       <title>AUTHOR</title>
+
+       <para>The original Samba software and related utilities were created by
+       Andrew Tridgell. Samba is now developed by the Samba Team as an Open
+       Source project similar to the way the Linux kernel is developed.</para>
+
+       <para>The mvxattr manpage was written by Ralph Boehme.</para>
+
+</refsect1>
+
+</refentry>
index 2b3a18003f89372bc6c171e3fa13770edb8fe8ad..0b690a878ff0931370be7180d64bc72dd8e2f75f 100644 (file)
@@ -18,6 +18,7 @@ manpages='''
          manpages/idmap_script.8
          manpages/idmap_tdb.8
          manpages/idmap_tdb2.8
+         manpages/mvxattr.1
          manpages/net.8
          manpages/nmbd.8
          manpages/nmblookup.1
diff --git a/source3/utils/mvxattr.c b/source3/utils/mvxattr.c
new file mode 100644 (file)
index 0000000..9cc2ec0
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+   Unix SMB/CIFS implementation.
+   xattr renaming
+   Copyright (C) Ralph Boehme 2017
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "popt_common.h"
+#include <ftw.h>
+
+static struct rename_xattr_state {
+       int follow_symlink;
+       int print;
+       int force;
+       int verbose;
+       char *xattr_from;
+       char *xattr_to;
+} state;
+
+static int rename_xattr(const char *path,
+                       const struct stat *sb,
+                       int typeflag,
+                       struct FTW *ftwbuf)
+{
+       ssize_t len;
+       int ret;
+
+       if (typeflag == FTW_SL) {
+               d_printf("Ignoring symlink %s\n", path);
+               return 0;
+       }
+
+       if (state.verbose) {
+               d_printf("%s\n", path);
+       }
+
+       len = getxattr(path, state.xattr_from, NULL, 0);
+       if (len < 0) {
+               if (errno == ENOATTR) {
+                       return 0;
+               }
+               d_printf("getxattr [%s] failed [%s]\n",
+                        path, strerror(errno));
+               return -1;
+       }
+
+       {
+               uint8_t buf[len];
+
+               len = getxattr(path, state.xattr_from, &buf[0], len);
+               if (len == -1) {
+                       d_printf("getxattr [%s] failed [%s]\n",
+                                path, strerror(errno));
+                       return -1;
+               }
+
+               ret = setxattr(path, state.xattr_to, &buf[0], len, XATTR_CREATE);
+               if (ret != 0) {
+                       if (errno != EEXIST) {
+                               d_printf("setxattr [%s] failed [%s]\n",
+                                        path, strerror(errno));
+                               return -1;
+                       }
+                       if (!state.force) {
+                               d_printf("destination [%s:%s] exists, use -f to force\n",
+                                        path, state.xattr_to);
+                               return -1;
+                       }
+                       ret = setxattr(path, state.xattr_to, &buf[0], len, XATTR_REPLACE);
+                       if (ret != 0) {
+                               d_printf("setxattr [%s:%s] failed [%s]\n",
+                                        path, state.xattr_to, strerror(errno));
+                               return -1;
+                       }
+               }
+
+               ret = removexattr(path, state.xattr_from);
+               if (ret != 0) {
+                       d_printf("removexattr [%s:%s] failed [%s]\n",
+                                path, state.xattr_from, strerror(errno));
+                       return -1;
+               }
+
+               if (state.print) {
+                       d_printf("Renamed %s to %s on %s\n",
+                                state.xattr_from, state.xattr_to, path);
+               }
+       }
+
+       return 0;
+}
+
+int main(int argc, const char *argv[])
+{
+       int c;
+       const char *path = NULL;
+       poptContext pc;
+       struct poptOption long_options[] = {
+               POPT_AUTOHELP
+               {"from",                's', POPT_ARG_STRING,   &state.xattr_from,      's', "xattr source name" },
+               {"to",                  'd', POPT_ARG_STRING,   &state.xattr_to,        'd', "xattr destination name" },
+               {"follow-symlinks",     'l', POPT_ARG_NONE,     &state.follow_symlink,  'l', "follow symlinks, the default is to ignore them" },
+               {"print",               'p', POPT_ARG_NONE,     &state.print,           'p', "print files where the xattr got renamed" },
+               {"verbose",             'v', POPT_ARG_NONE,     &state.verbose,         'v', "print files as they are checked" },
+               {"force",               'f', POPT_ARG_NONE,     &state.force,           'f', "force overwriting of destination xattr" },
+               POPT_TABLEEND
+       };
+       TALLOC_CTX *frame = talloc_stackframe();
+       const char *s = NULL;
+       int ret = 0;
+
+       if (getuid() != 0) {
+               d_printf("%s only works as root!\n", argv[0]);
+               ret = 1;
+               goto done;
+       }
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptSetOtherOptionHelp(pc, "-s STRING -d STRING PATH [PATH ...]");
+
+       while ((c = poptGetNextOpt(pc)) != -1) {
+               switch (c) {
+               case 's':
+                       s = poptGetOptArg(pc);
+                       state.xattr_from = talloc_strdup(frame, s);
+                       if (state.xattr_from == NULL) {
+                               ret = 1;
+                               goto done;
+                       }
+                       break;
+               case 'd':
+                       s = poptGetOptArg(pc);
+                       state.xattr_to = talloc_strdup(frame, s);
+                       if (state.xattr_to == NULL) {
+                               ret = 1;
+                               goto done;
+                       }
+                       break;
+               }
+       }
+
+       if (state.xattr_from == NULL || state.xattr_to == NULL) {
+               poptPrintUsage(pc, stderr, 0);
+               ret = 1;
+               goto done;
+       }
+
+       if (poptPeekArg(pc) == NULL) {
+               poptPrintUsage(pc, stderr, 0);
+               ret = 1;
+               goto done;
+       }
+
+       while ((path = poptGetArg(pc)) != NULL) {
+               ret = nftw(path, rename_xattr, 256,
+                          state.follow_symlink ? 0 : FTW_PHYS);
+       }
+
+       poptFreeContext(pc);
+
+done:
+       TALLOC_FREE(frame);
+       return ret;
+}
index 0b9356a79804662a503e042d41048b022dfc0169..4295f85924914284958a7b102f1c7b83d2b60cc5 100644 (file)
@@ -249,3 +249,11 @@ bld.SAMBA3_BINARY('net',
                  trusts_util
                  IDMAP_AUTORID_TDB
                  ''')
+
+bld.SAMBA3_BINARY('mvxattr',
+                 source='mvxattr.c',
+                 deps='''
+                 talloc
+                 popt_samba3
+                 ''',
+                 enabled=bld.env.build_mvxattr)
index 821d4ed114f2c99b5847cc9f111ac84378f55154..b886e1b69e44c1c8bd18d9f9e8d06f1bd4a2a86c 100644 (file)
@@ -1625,6 +1625,9 @@ main() {
         else:
             Logs.info("ncurses not available, not building regedit")
 
+    if conf.CHECK_HEADERS('ftw.h') and conf.CHECK_FUNCS('nftw'):
+        conf.env.build_mvxattr = True
+
     conf.CHECK_FUNCS_IN('DES_pcbc_encrypt', 'crypto')
     if Options.options.with_fake_kaserver == True:
         conf.CHECK_HEADERS('afs/param.h afs/stds.h', together=True)