I was editing the SVN pre-commit hook to add some checks on the files being committed, potentially rejecting a commit if certain strings were found in the file(s). I use svnlook to examine the contents of the commit transaction to get the list of files, looping through the list to grep for the strings. The hook is a standard bash script, nothing fancy. This is running on RHEL 8.6, and the SVN client is TortoiseSVN running on Win10.
While making this change, I was outputting the error messages to stderr and exiting with a non-zero return code, and confirming that TortoiseSVN was displaying this stderr output when it rejected the commit. To trace the script so that I could diagnose any issues, I also had it output to stdout, redirecting that output to a file, as in:
export LOG_FILE=/tmp/svn.pre-commit.out
echo "checking file $TXN_SOURCE_FILE for string $VAR_SEARCH_STRING" >> $LOG_FILE
I would try the commit, the hook would reject it, and TortoiseSVN would dutifully report the reason for the rejection based on the stderr output. But when I looked for the file /tmp/svn.pre-commit.out, it was nowhere to be found.
To get around this, I ended up doing a $LOG_FILE | mailx -s 'hook output' my_email_address
, which did email the output to my inbox. OK, so it seems that the file gets created, and I have my output, but it's still weird that I can't find the file. I added the following (prior to the lines that pipe the file to mailx):
echo "About to do 'ls -l' of $LOG_FILE" >> $LOG_FILE
ls -l $LOG_FILE >> $LOG_FILE
sleep 60
During the 60 second sleep interval, I used a second terminal session and did -l /tmp/svn*
, and received a "No such file or directory" message. But when the email arrived in my inbox, it included the lines:
About to do 'ls -l' of /tmp/svn.pre-commit.out -rw-r--r--. 1 apache apache 1668 May 7 18:48 /tmp/svn.pre-commit.outThis leads me to two questions. First, for those who have debugged SVN hooks, what methods have you used to trace/debug the script's operation? Second, how does SVN make this happen? Within the context of the script, the file seems to exist, but from the command line, it does not, even during the time that the script is sleeping. I presume that this is all done to prevent the hooks from filling up a filesystem with files, but how is it done? I'm curious whether this is something that I can exploit as a means of cleaning up output files from other scripts that I write that are not SVN hooks. edit 2024/05/08 14:20:00 CDT I added a
/tmp/test_temp_file; ls -l /tmp/test_temp_file >> $LOG_FILE
in the pre-commit hook. As I did previously, I had the hook do a $LOG_FILE | mailx ...
to get the contents of $LOG_FILE sent to my inbox before exiting. The email showed that the touch did indeed create a 0 byte file in /tmp, but I was not able to see that file while the hook was sleeping, nor after the hook exited.
I also did a /home/user_dir/test_temp_file; ls -l /home/user_dir/test_temp_file >> $LOG_FILE
. That file is visible while the hook is sleeping, and remains after the hook exits.
Further, I have changed the script to put LOG_FILE into a different directory via LOG_FILE=/home/user_dir/svn.pre-commit.out
. The log file is visible while the hook is sleeping, and remains after the hook exits.
It is only files that the script creates in /tmp via
or using redirection that exhibit this quirky behavior. They seem to be available to the script for the duration of its execution, but not visible to anyone else, either while the script executes or after it exits.
After re-reading @G-Man's second comment, I updated the hook script to include the -lai /
and
in the script, with the output redirected to $LOG_FILE. Comparing that to the output from the command line when the hook is not running, I see that the inode number for /tmp differs. Also, the output from
includes several lines when run from the script that are not present when running from the command line while the script is not running:
devtmpfs on /dev type devtmpfs (rw,nosuid,seclabel,size=1982272k,nr_inodes=495568,mode=755)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,seclabel)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,seclabel,mode=755)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
edit 2024/05/09 17:20:00 CDT
SOLVED
The fact that the inode for the /tmp visible to the hook script differed from the inode for /tmp at the Linux command line was really odd. Additional testing showed that restarting the httpd daemon would result in the hook script seeing yet another inode number for /tmp. Performing multiple SVN commits without restarting httpd showed that the inode remained constant, but if we restarted httpd, we would end up with another inode number.
Running / -inum _inode_ -print
provided the answer. The pseudo /tmp was actually a subdirectory a couple of levels deep within /tmp. Specifically it was /tmp/systemd-private-037e4427fdb644818be8d68d3c1a8bb4-httpd.service-7zRNLg/tmp. The '7zRNLg' portion changes each time the httpd daemon is restarted.
It appears that httpd is creating this directory and then doing a --bind /tmp /tmp/systemd-private-037e4427fdb644818be8d68d3c1a8bb4-httpd.service-7zRNLg/tmp
. Then when the hook script runs, it is forked from the httpd process, inheriting this private /tmp directory.
For those who are curious, the permissions on /tmp/systemd-private-037e4427fdb644818be8d68d3c1a8bb4-httpd.service-7zRNLg are set to 700, with owner set to root.
I am not sure why there was nothing identifying this private temporary directory in the output of the
command that ran inside the script. If anyone has any suggestions on that point, please share.
Asked by mc301
(11 rep)
May 7, 2024, 11:13 PM
Last activity: Mar 19, 2025, 04:41 PM
Last activity: Mar 19, 2025, 04:41 PM