How to hook bash commands or syscalls in order to preserve extended file attributes?

0

I wrote a backupsystem depending on extended file attributes. Many editing programs (like vim) remove these attributes from the files they edit. My idea is to hook any bash command referencing a file, so that the attributes get saved into a variable or temp file. A post-command-hook then reloads these attributes. I found out that one can run an arbitrary command before and after every bash command using trap i.e. adding:

trap date DEBUG

in .bashrc will run the date command before any bash command. However, I was not able to limit this to bash commands working on a file and get the filename. I'd love to be able to write something like this:

trap 'getfattr -d {} > /tmp/{}.xattr' FILECOMMAND

FILECOMMAND would imply that this hook is only exeuted for commands operating on a file

{} would be the absolute filepath of the file that is operated on

Another hook after the command could be written to override the file attributes of {} with the content of /tmp/{}.xattr

Is this somehow possible?

Another vague idea would be to hook systemcalls writing to files and executing some code in the hook methods, preserving the file attributes.

Any constructive input would be highly appreciated.

openGLisLife

Posted 2019-03-12T15:56:04.413

Reputation: 11

1When you edit a file, your editor may save changes in place. But at the same time any other process may read inconsistent, partially changed data from the file; power failure or a bug may occur mid-change and leave you a file that is neither the old version, nor a new one (data loss!). Solution: save the edited data as a separate file and then mv it to the old name. mv is atomic (unless between filesystems) so in case of trouble you have either the old file or the whole new one. Maybe it's not programs "remove attributes" but rather "fail or neglect to copy attributes to the new file". – Kamil Maciorowski – 2019-03-12T18:02:48.080

Thank you for pointing that out. The fileId changes when editing a file, which verifies that a new file was created. It is probably a good idea to work on the path then instead of the file itself – openGLisLife – 2019-03-12T18:38:58.830

Create a vi alias wrapper. Pass $@ to the preVi script, to vi and to postVi. Along the lines of alias vi='preVi $@; vi $@; postVi $@' – Ted D. – 2019-03-12T19:13:15.303

This hasn't really worked for me, but led me on the right path. I ended up creating a function in my .bashrc and setting it as an alias for vi:
alias vi='Vi'; function Vi () {tempPath="/tmp/$1.attr"; getfattr -d "$1" > "$tempPath"; /usr/bin/vi "$1"; setfattr --restore="$tempPath";} this works for vi and could be easily done for any command manually. Any ideas to make this more generic, so it works for every command?
– openGLisLife – 2019-03-12T22:37:39.837

Answers

0

I ended up writing a python script, that makes a given command c preserve the file attributes of any files c gets as an argument.

This is achived by modifying this template and appending it to the users .bashrc file:

#preserve xattr for <COMMAND_NAME>
alias <COMMAND_NAME>='<FUNCTION_NAME>'
function <FUNCTION_NAME> ()
{
    #find files in attribute list
    for arg in "$@"
    do
        filesToPreserve=()
            if [ -f "$arg" ];
        then
            #printf "argument: %s seems to be a file -> preserving attributes\n"
            filesToPreserve+=("$arg")
        fi
    done

    #save xattr
    tempPathes=()
    for file in "${filesToPreserve[@]}"
    do
        tempPath="/tmp/$file.attr"
        getfattr -d "$file" > "$tempPath"
        tempPathes+=("$tempPath")
    done

    #run actual command
    <COMMAND_PATH> "$@"

    #restore xattr
    for p in "${tempPathes[@]}"
    do
        setfattr --restore="$p"
    done
}

The Python script for doing this can be found on my github: xAttri

openGLisLife

Posted 2019-03-12T15:56:04.413

Reputation: 11