7

I have a script, this script creates a dump in /path/of/directory and deletes it instantly. I want to copy that dump before it gets deleted.

I tried;

dump=$(ls -a | grep -E "^[0-9]+$")
cp $dump fulldump

But I only got a half of the script, not the full one.

8
  • You could probably create an eBPF program that would hook the unlink syscall and prevent the file from being deleted (assuming that you have root). Sep 5, 2022 at 2:46
  • You can use inotify (see unix.stackexchange.com/questions/134615/…) to see when the file gets saved to, and then suspend or freeze the other process, (see unix.stackexchange.com/questions/2107/…) - copy the file, and then unfreeze the other process.
    – abcsec
    Sep 5, 2022 at 12:43
  • 10
    This question is nonsensical. Edit the script so it doesn't delete the file.
    – miken32
    Sep 5, 2022 at 15:05
  • 4
    attention answerers: the file in question is actually a named pipe, according to a comment by OP.
    – Esther
    Sep 5, 2022 at 17:46
  • 7
    Result of the comments: I recommend to open this as a new question, but with the following info stated in the question: a) The file in question is actually a named pipe, and b) The script in question is a third-party script that is not allowed to be edited. A fitting title might be "How to sniff and dump traffic in a named pipe without changing the script that sets up and uses the pipe". (Prepare for answers like "it's impossible", but maaybe someone knows a trick or two more than me.)
    – orithena
    Sep 5, 2022 at 18:28

4 Answers 4

20

You can use chattr to prevent file deletion (while allowing file creation and modification), and other handy permissions

For directory:

sudo chattr -R +a /TEMP/

or if just the (existing) file:

sudo chattr +a /TEMP/youCantDeleteMe.txt

To revert permissions use -a in place of +a

$ mkdir Documents/TEMP && cd $_
$ echo can edit > youCantDeleteMe.txt 

$ sudo chattr -R +a ../TEMP/

$ echo after plusA on file>> youCantDeleteMe.txt 
$ cat youCantDeleteMe.txt 
can edit
after plusA on file

$ sudo rm youCantDeleteMe.txt 
rm: cannot remove 'youCantDeleteMe.txt': Operation not permitted

$ ls -lA
-rw-rw-r-- 1 v v   25 Sep  5 05:59 youCantDeleteMe.txt
$ echo . > youCantDeleteMe.txt 
bash: youCantDeleteMe.txt: Operation not permitted

$ touch somebody
$ ls -lA
-rw-rw-r-- 1 v v  0 Sep  5 06:04 somebody
-rw-rw-r-- 1 v v 25 Sep  5 05:59 youCantDeleteMe.txt

$ sudo rm somebody 
rm: cannot remove 'somebody': Operation not permitted

$ sudo chattr +a ./undel.txt
chattr: No such file or directory while trying to stat ./undel.txt

And to later remove the file

$ sudo chattr -R -a ../TEMP/
$ ls -lA
drwxrwxr-x 2 v v 4096 Sep  5 06:17 .
drwxr-xr-x 7 v v 4096 Sep  5 05:57 ..
-rw-rw-r-- 1 v v    0 Sep  5 06:04 somebody
-rw-rw-r-- 1 v v   25 Sep  5 05:59 youCantDeleteMe.txt

$ rm -rf ./*
$ ls -la
drwxrwxr-x 2 v v 4096 Sep  5 06:17 .
drwxr-xr-x 7 v v 4096 Sep  5 05:57 ..
 
3
  • It worked and didn't delete the file. But since my dump is fifo (pipe) file, I can't read/write/copy anything in it. Is there a way to read/write/copy?
    – Erikli
    Sep 6, 2022 at 9:56
  • 1
    @Erikli I recommend asking that as a separate question; it's an interesting one, but the answer is very different.
    – wizzwizz4
    Sep 7, 2022 at 22:11
  • @wizzwizz4 I have created it; askubuntu.com/q/1428335/1614432
    – Erikli
    Sep 8, 2022 at 16:30
19

Congratulations, seems like you have created a race condition.

  • Two processes are racing to perform operations upon the same file.

  • Generally, race conditions are considered a bug for exactly the reason you encountered -- the results are unpredictable.

There are several ways to fix a race condition (semaphores, lockfiles, delays etc.) Some can involve fairly substantial coding.

However, in your specific case, you asked about a script. Happily, you can edit scripts. The simplest solution is to edit your script to place the dump in your preferred location.

6
  • The script isn't open source, I can't edit it.
    – Erikli
    Sep 4, 2022 at 15:22
  • 4
    Then you cannot fix the race condition. File a bug with the developers of that software. Or keep trying to copy the file repeatedly -- you will get a different amount of the dump each time. At some point, you might get the whole thing.
    – user535733
    Sep 4, 2022 at 15:24
  • 15
    A "pipe file" would be a named pipe (search for that term; great tutorials are out there). That's vital information that needs to be in your Question above, it changes the possible answers entirely: Accessing the data might be as simple as cat < $dump
    – user535733
    Sep 4, 2022 at 15:32
  • 12
    Adding to the comment by @user535733: It also changes the chances of getting the file contents (without stealing that data from the script!) to zero: It isn't a file, it's a named pipe. Which can be read from and written to like a file, but there's a crucial difference: The data is never written to disk and everything can only be read once. So if OP manages to read (partial) data from that named pipe, this data is then lost to the pipe consumer in the script!
    – orithena
    Sep 5, 2022 at 10:58
  • 4
    @Erikli A script implies readable plain text, not a binary executable. If that's true, can you copy it, change the copy, and change the system to use your copy instead of the original? That might be as simple as renaming the original (as a backup - don't delete it) and giving your version that same name in the same location instead. (now the same code runs your version, even if it's hard-coded)
    – AaronD
    Sep 6, 2022 at 15:22
15

The strace utility is commonly used to show the system calls made by a process, but it can also intercept them.

Try:

strace -f -e inject=unlink,unlinkat:retval=0 /the/script script-args...

Then every time the process or its children invokes the unlink or unlinkat system calls (which are the normal ways to delete a file), strace will intercept it and cause it to return 0, indicating success, but without actually doing anything.

There will be a lot of output tracing all the system calls. You can add -e trace=unlink,unlinkat to display those calls only, or -o logfile to send the whole output to a file (possibly /dev/null). Make sure these arguments go before /the/script on the command line.

Note this will prevent the script from deleting any files at all; hopefully that's okay. There's a -P option to strace that is supposed to restrict the tracing to calls that access a given file, but I couldn't get it to work correctly in a simple test.

Other variants are also possible: for instance, you can make the unlink/unlinkat system calls fail with an error code, or have them send SIGSTOP to the process so you can poke around before continuing it. See the strace man page for the details on all its capabilities.

1
  • Wow! Great information. If I had read the man page for strace closely, I still probably would not have realized how useful that could be. Sep 7, 2022 at 22:43
6

Depending on the speed with which the dump is opened and then written, you may be able to create a hard link to it while it is being written. This hardlink will ensure that the data space does not get deallocated when the file is deleted using its original name. E.g.:

your-script &
ln /path/of/directory/dumpfile /some/other/path/on/the/same/filesystem
wait   #  wait until your-script exits
do-something-with /some/other/path/on/the/same/filesystem

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .