Hi, I'm a newbie Subversion user and I recently setup my repository to
use the "post-commit" hook. I had to jump through quite a few hoops to
set it up the way I wanted and thought the details of my experience
might be helpfull to others. There may be a better way to do what I did
and all suggestions and comments are welcome. First of all, let me say
that I think the development team is doing a great job on Subversion,
and I thank you all very much for trying to improve upon CVS.
Let me start with a description of what I was trying to do. My
development effort involves Oracle Reports and Forms files. These files
are created by Oracle tools on the developer machines and are very
independent of one another. Each file is essentially its own little
program. Once the developer has finished the form or report (the
source), they need to deploy it to the server. This involved scp'ing the
file to the server, loging into the server, compiling the file on the
server, and copying the resulting binary to a special area. In an effort
to simplify things, they wanted the version control system to handle the
deployment for them.
Now, a description of what I did. A little background on the repository
setup would probably help. The repository is on the same server as the
deployment environment. The repository is owned by my CM user. Each
developer has an account on the server and accesses the repository using
SVN+SSH. This makes sure that the commits are not anonymous. Now, in
order to satisfy the user's request, I thought I would use the
post-commit hook. My approach was to have the post-commit hook update a
workspace(sandbox) on the server, make the out-of-date forms and
reports, and deploy the new binaries to the appropriate directory. I
know that I could have probably exported the files as opposed to
performing an update of a workspace, but then I would have to have
compiled all of the files as opposed to only the ones that had changed
since the last make. Although each form and report does not take long to
compile, there are quite a few of them and I didn't want the user to
wait on a commit to compile 30+ files. Anyway, I went with the update
approach. I created a bash script called post-commit that performed the
necessary steps. As long as I connected as my CM user, the script ran
fine. However, when I tried to commit some files as one of the
developers, I ran into a few problems. The first problem was that
multiple users cannot share a single workspace. The solution to this
problem (as suggested by someone on this mailing list) was to turn the
setuid bit on for the post-commit script. This did not initially work
though. The problem is that many unix systems ignore the setuid bit on
scripts. There are apparently some issues with race conditions in the
kernel. After doing some more research, someone suggested creating a
small 'C' program that calls the script, and turn the setuid bit on for
the 'C' program. This is apparently the solution also used by Perl
script developers. So, now I have a small executable called post-commit
that calls my original script post-commit.bash. The setuid bit is turned
on for the post-commit executable, but not for the bash script. The
executable and script are both owned by my CM user. At first try, this
also did not work. The problem is that even though the effective user
was changed to my CM user, the bash shell by default will ignore the
setuid bit of the parent process. To get around this, you apparently
have to start the shell with "#!/bin/bash -p". The "-p" will allow it to
recognize the setuid bit of the parent. I think the "-p" stands for
posix compliant mode or something.
After modifying the bash script, things were beginning to work somewhat.
When a user committed files, the executable ran, switched the effective
user to my CM user, called the script, the script then updated my
workarea, and tried to compile the out-of-date files. The next problem,
was that my compiles were failing. The java program that Oracle provides
to compile the forms was complaining about libraries not being found
even though the LD_LIBRARY_PATH was being set immediately before the
java program was called. Turns out that on many unix systems, the
LD_LIBRARY_PATH is ignored if the real user id and the effective user id
are not the same. In my case the users real id was their login id and
the effective user id was the CM user id as a result of the setuid bit
being on. After some more research, the solution turned out to be the
need to set the real user id to be the same as the effective user id in
the small 'C' wrapper program (post-commit) before the script
(post-commit.bash) is called. The problem here is that in order to be
able to set the real user id using "setuid()", you have to be root. So,
my c code now looks like:
#define REAL_SCRIPT "pathtoscript/post-commit.bash"
#include <sys/types.h>
#include <unistd.h>
main( ac, av )
char **av;
{
setuid( myCMUserID );
seteuid( myCMUserID );
execv( REAL_SCRIPT, av );
}
And, after I compile, I change the ownership of the executable to root;
so, my listing now looks something like:
-rwsr-xr-x 1 root users 7584 Jan 21 08:27 post-commit
-rwxr-xr-x 1 cmusers users 4136 Jan 20 16:39 post-commit.bash
-rw-r--r-- 1 cmusers users 705 Jan 21 10:58 post-commit.c
So, when a developer commits a file(s), the post-commit executable runs
as root, sets the real and effective user ids to the CM user, and then
executes the post-commit.bash script. This seems to work o.k. for now.
Yes, I know there are probably all kinds of security issues related to
this approach, but access to the server is very limited, and to be
honest, I don't know of a better aproach.
Anyway, that was long and drawn out, but hopefully it might save someone
else some time. All comments and suggestions for improvement are welcome.
Tony
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@subversion.tigris.org
For additional commands, e-mail: users-help@subversion.tigris.org
Received on Wed Jan 21 18:14:01 2004