On Mac OSX, how can I open a deleted file which is still open by a process

deleted-filesosx

b2-osx108v8-01:~ bamboo$ lsof -p 264
COMMAND PID   USER   FD     TYPE            DEVICE  SIZE/OFF     NODE NAME
<lines removed>
java    264 bamboo   20w     REG               1,2    240906 14883372 /Users/bamboo/bamboo-agent-home/xml-data/build-dir/ST-SSINR-B2OSML/SimbaProcessManager.log.0
<lines removed>

The /Users/bamboo/bamboo-agent-home/xml-data/build-dir/ST-SSINR-B2OSML directory has already been deleted, but the file is still open by our daemon process. How can I look at this log? On Linux, I'd use /proc/264/fd/20, but that doesn't seem to be available on OSX.

Best Answer

<EDIT>

If this was Linux, you could also use a gdb trick. But it turns out we can rule out that trick on OS X, because it relies on Linux-specific behaviour of /dev/fd/ (/proc/self/fd/).

That's all I know, I don't have a positive suggestion.

</EDIT>

It could go horribly horribly wrong, but have you considered gdb? Two miracles in one package: a C interpreter, and a way to inject code into the process of your choice! Apparently you can also use it for debugging.

Fortunately the C standard library also includes a function which interprets scripts. The scripting language on your platform might be more convenient to write than C...

I thought of a script which uses less for OS X. This is a fragile hack to seek back to the start of the logfile based on OS X, bash: less works on open file descriptors, cat doesn't After reading the whole log file with less, the FD position should be at the end of the file, which is hopefully the original position before we meddled with it.

<EDIT>But it only works if the file was also opened for reading. According to your lsof output, the file was only open for writing.</EDIT>

gdb -p 264 <<EOF
call (int) system("exec </dev/null >/tmp/log 2>&1; less /dev/fd/20")
EOF

I cast the return type, because otherwise my system complained that it did not know the return type of system(). Presumably this also means that it wasn't sure of the argument types either, so this is already sounding like such a great idea.

Using system() to manipulate file descriptors somehow worked when I tried it on my Linux box... once. I don't promise it will always work :). E.g., technically this is not guaranteed to be safe if the program is executing a signal handler, or indeed system() itself. (system() is not one of the few functions which is guaranteed to be "re-entrant").