views:

278

answers:

2

I have a Mercurial repository set up on a Linux server, and some (but not all) users have permission to push to it. They connect to the repository over ssh.

These users are members of a unix group together. Below is the script I'm using to alter a repository to allow it to receive pushes from them.

Can this be improved? Are there unnecessary operations in here? Is anything bad style for a bash script?

#!/bin/bash                                                                     

if [[ $# -lt 2 ]]; then
    echo Usage: $0 directory groupname
    exit 1
fi

if ! chown -R :$2 $1; then
    echo chown failure
    exit 2
fi

if ! find $1/.hg -type d -exec chmod g+s {} \;; then
    echo chmod failure
    exit 3
fi

if ! find $1 -perm -u+r -exec chmod g+r {} \;; then
    echo chmod failure 2
    exit 4
fi

if ! find $1 -perm -u+w -exec chmod g+w {} \;; then
    echo chmod failure 3
    exit 5
fi

if ! find $1 -perm -u+x -exec chmod g+x {} \;; then
    echo chmod failure 4
    exit 6
fi
+1  A: 

Couple minor things: It's a good idea to echo error messages to stderr by redirecting with >&2. And you should add double quotes around variables so your script will work with file names that have spaces.

You could change the initial line to #!/bin/bash -e to have the script immediately exit if there's an error. That'd let you remove all the if statements. Or if you want more control you could use the trap ERR command to call custom error-handling code:

#!/bin/bash

function uhoh() {
    echo "error in script!" >&2
    exit 1
}

trap uhoh ERR

if [[ $# -lt 2 ]]; then
    echo "Usage: $0 directory groupname" >&2
    exit 1
fi

chown -R :"$2" "$1"
find "$1"/.hg -type d -exec chmod g+s {} \;
find "$1" -perm -u+r -exec chmod g+r {} \;
find "$1" -perm -u+w -exec chmod g+w {} \;
find "$1" -perm -u+x -exec chmod g+x {} \;

Personally I'd just go with the /bin/bash -e option if you want to stop the script as soon as something fails. I think checking the result of every command and having a different exit code for each one is overkill. You don't need to be that robust, and nobody's gonna be doing anything different for exit code 3 vs. exit code 4...

John Kugelman
+1  A: 

Running find with -exec launches a separate chown process for each file. You'll get a lot less process thrash (and more speed) if you do:

find "$1"/.hg -type d -print0 | xargs chmod g+s
find "$1" -perm -u+r -print0 | xargs chmod g+r
find "$1" -perm -u+w -print0 | xargs chmod g+w
find "$1" -perm -u+x -print0 | xargs chmod g+x

As an aside, have you looked at Mercurial's ACL Extension in combination with hg-ssh? So long as the only access is ssh, it does the same sort of thing.

Ry4an
Newer GNU finds (they implemented it relatively late, it's in POSIX since ages...) know "-exec .... {} +", which will spawn the process using as many arguments as fit into the environment space, effectively doing what xargs would do.
TheBonsai
Thanks for pointing out the ACL Extension. Another option I found from your links was mercurial-server (http://mercurial.selenic.com/wiki/SharedSSH). I think I'll stick with my script for now, though, with John, TheBonsai, and your changes.
Jim Hunziker