Ultimate Guide To CVS Server Administration in Fedora 6
Ultimate Guide To CVS Server Administration in Fedora 6
Administration in Fedora 6
ATOzTOA
www.atoztoa.com
[email protected]
March 2009
2 Introduction 5
2.1 Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Tools Needed . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3 Installation 6
3.1 CVS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.2 CVS ACL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.3 XINETD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4 Users 8
4.1 Types of Users . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.1.1 CVS Administrator . . . . . . . . . . . . . . . . . . . . . 8
4.1.2 CVS Users . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.2 Creating Users . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.2.1 Creating CVS Administrator . . . . . . . . . . . . . . . 8
4.2.2 Creating CVS Users . . . . . . . . . . . . . . . . . . . . 8
5 Creating Repository 9
5.1 Creating Folder Structure . . . . . . . . . . . . . . . . . . . . . 9
5.1.1 Repository . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5.1.2 Utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5.1.3 Backup . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5.2 Exporting CVSROOT . . . . . . . . . . . . . . . . . . . . . . . . 9
5.3 Changing Ownership/Permissions . . . . . . . . . . . . . . . . 9
6 Managing Repository 10
6.1 Initializing Repository . . . . . . . . . . . . . . . . . . . . . . . 10
6.2 Managing CVS Modules . . . . . . . . . . . . . . . . . . . . . . 10
6.2.1 Creating a New Module . . . . . . . . . . . . . . . . . . 10
6.2.2 Importing Modules . . . . . . . . . . . . . . . . . . . . . 10
6.2.3 Exporting Modules . . . . . . . . . . . . . . . . . . . . . 12
7 Setting User Access Rights 13
7.1 Access Permissions . . . . . . . . . . . . . . . . . . . . . . . . . 13
7.2 Setting Default Permissions . . . . . . . . . . . . . . . . . . . . 13
7.3 Using acl / racl . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
7.3.1 General Syntax . . . . . . . . . . . . . . . . . . . . . . . 14
7.3.2 ACL Admin . . . . . . . . . . . . . . . . . . . . . . . . . 14
7.3.3 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . 14
7.3.4 Important Information . . . . . . . . . . . . . . . . . . . 15
7.4 Manually editing access file . . . . . . . . . . . . . . . . . . . 15
7.4.1 Careful! . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
8 Setting Up pserver 17
8.1 Configuring xinetd . . . . . . . . . . . . . . . . . . . . . . . . . 17
8.1.1 Adding pserver service . . . . . . . . . . . . . . . . . . 17
8.1.2 Restarting xinetd . . . . . . . . . . . . . . . . . . . . . . 17
9 Passwords 18
9.1 CVS Password file . . . . . . . . . . . . . . . . . . . . . . . . . . 18
9.2 Set CVS Password - The Simple Way . . . . . . . . . . . . . . . 18
9.2.1 Passwords and Login . . . . . . . . . . . . . . . . . . . 18
9.2.2 Utility Scripts . . . . . . . . . . . . . . . . . . . . . . . . 19
9.2.3 Adding / Changing Passwords . . . . . . . . . . . . . . 20
9.3 Set CVS Password - The Complex but Automated Way . . . . 21
9.3.1 Expect . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
9.3.2 Passwords and Sudo . . . . . . . . . . . . . . . . . . . . 21
9.3.3 Utility Scripts . . . . . . . . . . . . . . . . . . . . . . . . 22
9.3.4 Adding / Changing Passwords . . . . . . . . . . . . . . 25
2
11.2.2 the program . . . . . . . . . . . . . . . . . . . . . . . . . 28
11.2.3 use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
11.2.4 hooking the program . . . . . . . . . . . . . . . . . . . . 29
11.3 post-commit hook . . . . . . . . . . . . . . . . . . . . . . . . . . 30
11.3.1 when? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
11.3.2 the program . . . . . . . . . . . . . . . . . . . . . . . . . 30
11.3.3 use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
11.3.4 hooking the program . . . . . . . . . . . . . . . . . . . . 31
11.4 Careful! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
13 Conclusion 45
References 46
3
1 Preface
1.1 Who Should Read This Guide?
This guide is intended for CVS Administrators. But, this can also be used by
anyone interested in familiarizing how the CVS Server works, even setup a
local CVS Server.
1.2 Prerequisites
The user of this guide is expected to have a basic understanding of the
following. . .
• Linux/Unix Shell
• Linux Commands
Tips
• While copying the code for the scrips, a) for large scrips which spans
across multiple pages, remember to delete the page number after pasting,
b) if copying to vim directly, the ‘(acute / grave) will be replaced by
.(dot), so better paste to some other editor and copy again.
• Take care to execute the commands as the user shown in the document,
for example, [cvsadmin@localhost cvstools]$ means execute as
user cvsadmin from the directory cvstools.
4
2 Introduction
2.1 Terminology
CVS . . . . . . . . . . . . . . . . . . . . . . CVS refers to the CVS Setup as a whole.
CVS Server / CVS Box . . . . This is the Machine on which the CVS is
going to run.
Backup Server . . . . . . . . . . . . This is the Machine on which the CVS
Backup is taken.
cvsadmin . . . . . . . . . . . . . . . . . User who is acting as CVS Administrator
/cvs/repo . . . . . . . . . . . . . . . . The CVS repository is basically a directory
in which all the files and directories under
the version control are stored. Normally,
the repository will be /cvs/repo/[name of
project]. But, here we are not considering
that, if you need to create such a repository
just change this term across this guide.
/cvs/repo/CVSROOT . . . . CVSROOT directory inside the Repository.
CVSROOT. . . . . . . . . . . . . . . . The path to the Repository, which is
exported.
/cvs/repo/Test-Module . . The directory Test-Module inside the
Repository.
Test-Module . . . . . . . . . . . . . . The CVS Module used as example.
pserver . . . . . . . . . . . . . . . . . . . The CVS Password Server which manages
the access to CVS through the network.
5
3 Installation
3.1 CVS
This step need not be executed if cvs is already installed.
cvsacl comes with latest cvs source, skip this step if installing cvsacl.
[root@localhost ˜]# yum install cvs
OR
Normally the download will be the full cvs source patched using cvsacl. So,
no need to execute the previous step (Section 3.1. Install CVS from cvsacl
source.
[root@localhost ˜]# <extract cvsacl source>
[root@localhost ˜]# <change to cvsacl directory>
[root@localhost cvs-x.xx.xx-cvsacl-x.x.x]# ./configure
[root@localhost cvs-x.xx.xx-cvsacl-x.x.x]# make
[root@localhost cvs-x.xx.xx-cvsacl-x.x.x]# make install
If the command
cvs racl
prints anything other than ”Unknown command: ‘racl’ ”, then CVS ACL
installation is Successful! (Even if it prints ”Segmentation fault”...)
6
3.3 XINETD
[root@localhost ˜]# yum install xinetd
OR
7
4 Users
4.1 Types of Users
4.1.1 CVS Administrator
• user who is going to administrate the CVS.
• does not have root permissions, but may be given sudo access.
• username is cvsadmin.
8
5 Creating Repository
5.1 Creating Folder Structure
5.1.1 Repository
mkdir - create directory
[root@localhost ˜]# mkdir -p /cvs/repo
5.1.2 Utility
This will contain various utility scripts for backup, hooks etc.
[root@localhost ˜]# mkdir /cvs/cvstools
5.1.3 Backup
This will contain local backup of the repository.
[root@localhost ˜]# mkdir /cvs/backup
su - switch user
[root@localhost ˜]# su cvsadmin
9
6 Managing Repository
6.1 Initializing Repository
[cvsadmin@localhost ˜]$ cvs -d /cvs/repo init
OR simply
[cvsadmin@localhost ˜]$ cvs init
if CVSROOT is properly exported.
10
Example Project tree
Test_Project/
|-- Makefile
|-- inc
| ‘-- foo.h
‘-- src
‘-- foo.c
Importing
[cvsadmin@localhost ˜]$ cd Test_Project
[cvsadmin@localhost Test_Project]$ cvs import Project_Foo INITIAL BASE
[cvsadmin@localhost Test_Project]$ cd ..
[cvsadmin@localhost ˜]$ rm -rf Test_Project
Verifying
[cvsadmin@localhost ˜]$ cvs co Project_Foo
[cvsadmin@localhost ˜]$ cd Project_Foo
[cvsadmin@localhost Project_Foo]$ tree
.
|-- CVS
| |-- Entries
| |-- Entries.Log
| |-- Repository
| ‘-- Root
|-- Makefile
|-- inc
| |-- CVS
| | |-- Entries
| | |-- Repository
| | ‘-- Root
| ‘-- foo.h
‘-- src
|-- CVS
| |-- Entries
| |-- Repository
| ‘-- Root
‘-- foo.c
5 directories, 13 files
11
6.2.3 Exporting Modules
Exporting is used to get a snapshot of a Module in CVS without the CVS
directories or Admin files.
Exporting
[cvsadmin@localhost ˜]$ cvs export -D NOW Project_Foo
Verifying
[cvsadmin@localhost ˜]$ cd Project_Foo
[cvsadmin@localhost Project_Foo]$ tree
.
|-- Makefile
|-- inc
| ‘-- foo.h
‘-- src
‘-- foo.c
2 directories, 3 files
This will export a version of the Module which is no later than Jan 01, 2009.
This will export a version of the Module which was tagged using ’PROJECT BASE’.
12
7 Setting User Access Rights
7.1 Access Permissions
File: /cvs/repo/CVSROOT/aclconfig
# Set ‘UseCVSACL’ to yes to use CVSACL feature.
UseCVSACL=yes
13
7.3 Using acl / racl
7.3.1 General Syntax
acl command is used on checked out files or directories.
Usage: cvs acl [user||group:permissions] [-Rl] [-r tag] [directories...] [files...]
-R Process directories recursively.
-r rev Existing revision/tag.
-l List defined ACLs.
This command sets permission p (acl admin) to the user cvsadmin for ALL
revisions/tags of ALL modules.
7.3.3 Examples
1. Enable read permission for user1 in all revisions of Test-Module Module.
14
[cvsadmin@localhost ˜]$ cvs racl user2:a -r ALL Test-Module
File: /cvs/repo/CVSROOT/access
# CVS ACL definitions file. DO NOT EDIT MANUALLY (Yeah I know !!!)
# Admin
d:ALL:ALL:cvsadmin!p:
15
7.4.1 Careful!
The access rights specified by each line for a particular [module/directory/file:username]
pair is overridden by any following lines with same [module/directory/file:username]
pair.
Example:
d:Test-Module:ALL:user1!wcd:
d:Test-Module/test:ALL:user1!t:
The w,c,d permissions are given to all folders inside Test-Module by the
first line (which includes Test-Module/test). The second line specifies an
access permission for [Test-Module/test:user1] pair, thus overriding
the w,c,d permissions for Test-Module/test. Result, every directory in
Test-Module except Test-Module/test will have w,c,d permissions, but
no t permission and Test-Module/test will have t permission, but no
w,c,d permission.
To avoid this, whenever adding a new line which is going to override another
line (or part thereof), replicate all the permissions already granted.
Corrected Example:
d:Test-Module:ALL:user1!wcd:
d:Test-Module/test:ALL:user1!wcdt:
Here, the second line overrides the first, but explicitly keeps the permissions.
Result, every directory in Test-Module except Test-Module/test will have
w,c,d permissions, but no t permission and Test-Module/test will have
w,c,d,t permission.
16
8 Setting Up pserver
8.1 Configuring xinetd
8.1.1 Adding pserver service
Create file, if does not already exist, /etc/xinetd.d/cvspserver as root.
[root@localhost ˜]# vi /etc/xinetd.d/cvspserver
Add the following lines to the file. . . Change the CVS Repository path in
server args to /cvs/repo.
File: /etc/xinetd.d/cvspserver
service cvspserver
{
disable = no
protocol = tcp
socket_type = stream
wait = no
user = root
server = /usr/bin/cvs
server_args = -f --allow-root=/cvs/repo pserver
passenv =
groups = yes
}
17
9 Passwords
This section is NOT applicable for cvsadmin.
Till this step, only cvsadmin had access to the CVS Repository. Let’s create
the CVS Password file to authenticate other users. The path of the file is
/cvs/repo/CVSROOT/passwd.
18
9.2.2 Utility Scripts
calc-hash.pl
File: /cvs/cvstools/calc-hash.pl
#!/usr/bin/perl
#
# Simple script to take a username and password and
# return a line suitable for pasting into the CVS
# password file.
#
($u, $p)=@ARGV;
@d=(A..Z,a..z);
$s=$d[rand(52)].$d[rand(52)];
print $u.":".crypt($p, $s).":cvsadmin\n";
cvspasswd
File: /cvs/cvstools/cvspasswd
#!/bin/sh
if [ "$1" = "" ]; then
echo "Usage: $0 <username>"
exit
fi
sed -i "/$1:/ d" /cvs/repo/CVSROOT/passwd
echo "Changing CVS password for user $1."
19
read -s -p "New CVS Password: " pass
echo
read -s -p "Retype new UNIX password: " pass1
echo
if [ "$pass" != "$pass1" ]; then
echo "Sorry, passwords do not match."
else
./calc-hash.pl $1 $pass >> /cvs/repo/CVSROOT/passwd
unset $’pass’
echo "CVS Password Changed Successfully."
fi
File: /cvs/repo/CVSROOT/passwd
user1:CQmulL9HYBk1U:cvsadmin
user2:xyhoQaRr1ARJI:cvsadmin
20
9.3 Set CVS Password - The Complex but Automated Way
The user is given login permission, but the only command which executes
is that for changing the password. The user need not be at the CVS Box and
cvsadmin is not needed for changing password.
9.3.1 Expect
Expect is an automation and testing tool written as an extension to Tcl scripting
language.
Installation
[root@localhost ˜]# yum install expect
OR
Testing
If the command
expect
21
Add sudo permission for CVS users.
[root@localhost ˜]# echo "user1 ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
[root@localhost ˜]# echo "user2 ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
Caution: editing sudoers file directly is NOT recommended. If in the above command,
>> is mistyped as >, then the file will be overwritten by that line!
calc-hash.pl
File: /cvs/cvstools/calc-hash.pl
#!/usr/bin/perl
#
# Simple script to take a username and password and
# return a line suitable for pasting into the CVS
# password file.
#
($u, $p)=@ARGV;
@d=(A..Z,a..z);
$s=$d[rand(52)].$d[rand(52)];
print $u.":".crypt($p, $s).":cvsadmin\n";
22
userpasswd
File: /cvs/cvstools/userpasswd
#!/bin/sh
# Change User Password using expect
# \
exec expect -f "$0" ${1+"$@"}
set password [lindex $argv 1]
spawn sudo passwd [lindex $argv 0]
sleep 1
expect "assword:"
send "$password\r"
expect "assword:"
send "$password\r"
expect eof
File: /cvs/cvstools/cvspasswd
#!/bin/sh
echo -e "\nYou are successfully logged into CVS..."
echo "======================================="
echo -e -n "\nPress ’Q’ to quit or any other key to change your password... "
read ch
if [ "$ch" = "q" -o "$ch" = "Q" ]; then
exit
fi
23
echo "Changing password for user $USER."
read -s -p "New CVS Password: " pass
echo
read -s -p "Retype new CVS password: " pass1
echo
if [ "$pass" != "$pass1" ]; then
echo "Sorry, passwords do not match."
else
# Change CVS password
sudo sed -i "/$USER:/ d" /cvs/repo/CVSROOT/passwd
/cvs/cvstools/calc-hash.pl $USER $pass >> /cvs/repo/CVSROOT/passwd
# Change user password
/cvs/cvstools/userpasswd $USER $pass
unset $’pass’
echo -e "\nPassword Changed Successfully."
echo -n "Press any key..."
read
fi
rshell
Need to make the script cvspasswd as the ’login shell’ for CVS users.
File: /cvs/cvstools/rshell.c
#include<unistd.h>
main()
{
execl("/bin/sh", "sh", "/cvs/cvstools/cvspasswd", 0);
}
24
Compile the code using gcc.
[cvsadmin@localhost cvstools]$ gcc -o rshell rshell.c
Copy to /bin.
[cvsadmin@localhost cvstools]$ sudo cp rshell /bin/
CVS Users
When a user login to the CVS Box using ssh, rshell gets invoked and the
script cvspassword is executed. User can change the password, if desired.
Once the script finishes execution, the shell also exits, restricting the user
from any other action.
CVS Administrator
Script in Action
[cvsadmin@localhost cvstools]# sudo su user1
25
Changing password for user user1.
New UNIX password:
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
The Result
File: /cvs/repo/CVSROOT/passwd
user1:CQmulL9HYBk1U:cvsadmin
user2:xyhoQaRr1ARJI:cvsadmin
26
10 Accessing CVS through Network
Make sure that the port used by pserver is not blocked by the Firewall in the
CVS Box. The port is specified in the file /etc/services.
File: /etc/services
..
.
cvspserver 2401/tcp # CVS client/server operations
cvspserver 2401/udp # CVS client/server operations
..
.
2. cervisia
10.1.2 Windows
1. WinCVS
2. TortoiseCVS
10.2.2 In Windows
Set the environment variable CVSROOT in the Client to
:pserver:<username>@<ip of CVS Box>:/cvs/repo.
27
11 Hooks, the Final Frontier
11.1 What are hooks?
Hook is the way of triggered automation, i.e., automation triggered by an
event. CVS provides 2 such hooks into the commit process - a pre-commit
hook and a post-commit hook. Each hook can be linked to a script which
will be executed just before and just after committing the changes to the
repository.
File: /cvs/cvstools/pre-commit.sh
#!/bin/sh
LOG_FILE=/cvs/repo/CVSROOT/commitlog
DATE=‘date "+%m/%d/%y [%H:%M:%S]"‘
for file in $*
do
echo "$DATE: Pre-commit check for $file" >> $LOG_FILE
done
28
$1 is the name of commit directory & $* contains the files in the commit.
11.2.3 use
The pre-commit program acts as a filter. If the program returns successfully,
the files will be committed. If the program returns with a non-zero exit
status, then the files won’t be committed.
Uses include checking for coding standards, changing tabs to spaces etc.
regular expression : match the directory (relative to /cvs/repo) that includes the changed
file(s).
program to run : the program to run when contents of matched directory changes.
Test-Module/* /cvs/cvstools/pre-commit.sh
File: /cvs/repo/CVSROOT/commitinfo
# The "commitinfo" file is used to control pre-commit checks.
# The filter on the right is invoked with the repository and
# a list of files to check. A non-zero exit of the filter
# program will cause the commit to be aborted.
#
# The first entry on a line is a regular expression which is
# tested against the directory that the change is being
# committed to, relative to the $CVSROOT. For the first match
# that is found, then the remainder of the line is the name of
29
# the filter to run.
#
# If the repository name does not match any of the regular
# expressions in this file, the "DEFAULT" line is used,
# if it is specified.
#
# If the name "ALL" appears as a regular expression it is
# always used in addition to the first matching regex or "DEFAULT".
Test-Module/* /cvs/cvstools/pre-commit.sh
..
.
File: /cvs/cvstools/post-commit.sh
#!/bin/sh
LOG_FILE=/path/to/cvsrepo/CVSROOT/commitlog
DATE=‘date "+%m/%d/%y [%H:%M:%S]"‘
for file in $*
do
echo "$DATE: Post-commit notification for $file" >> $LOG_FILE
done
30
$* contains the files that were committed.
cat is used to eat extra input because if the program fails to read all input
passed by the post-commit event, an error is thrown. . .
cvs [commit aborted]: received broken pipe signal
11.3.3 use
The post-commit program acts as a notifier that the repository has been
changed.
Uses include playing a sound, updating a log file, sending emails to users
etc.
regular expression : match the directory (relative to /cvs/repo) that includes the changed
file(s).
program to run : the program to run when contents of matched directory changes.
Test-Module/* /cvs/cvstools/post-commit.sh %s
31
A sample loginfo file, the comments explain it all. . .
File: /cvs/repo/CVSROOT/loginfo
# The "loginfo" file controls where "cvs commit" log information
# is sent. The first entry on a line is a regular expression
# which must match the directory that the change is being made to,
# relative to the $CVSROOT. If a match is found, then the
# remainder of the line is a filter program that should expect
# log information on its standard input.
#
# If the repository name does not match any of the regular
# expressions in this file, the "DEFAULT" line is used, if it
# is specified.
#
# If the name ALL appears as a regular expression it is always
# used in addition to the first matching regex or DEFAULT.
#
# You may specify a format string as part of the
# filter. The string is composed of a ‘%’ followed
# by a single format character, or followed by a set of format
# characters surrounded by ‘{’ and ‘}’ as separators. The
# format characters are:
#
# s = file name
# V = old version number (pre-checkin)
# v = new version number (post-checkin)
#
# For example:
#DEFAULT (echo ""; id; echo %s; date; cat) >> commitlog
# or
#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> commitlog
Test-Module/* /cvs/cvstools/post-commit.sh %s
..
.
11.4 Careful!
The cvs commit command will block until all registered programs complete,
so keep the filter and notifier as brief as possible.
32
12 Backup and Restore
One of the main purposes of CVS is to protect the content against Machine
crashes. CVS Server is also a Machine, it can crash. That’s why CVS needs
to be backed up regularly.
The CVS Backup is taken on another machine, which is normally kept under
firesafe conditions and in turn backed up to tapes regularly.
This activity requires operations in both CVS Server and Backup Server. Take care
in which machine each command is executed.
12.1.1 Information
• IP Address : 10.20.30.40
Check SSH
In CVS Server,
[cvsadmin@localhost ˜]$ ssh 10.20.30.40
33
If it is the first time connecting to Backup Server, a prompt asking for confirmation
to add the Host to known hosts comes up...
The authenticity of host ’10.20.30.40 (10.20.30.40)’ can’t be established.
RSA key fingerprint is .......
Are you sure you want to continue connecting (yes/no)?
Provide the password given to user cvsadmin in the Backup Server. If the
password is correct, shell prompt in Backup Server is reached.
Generate Key
Entering a passphrase while generating the key, would require to enter a password each
time using SSH/SCP to the server, which defeats the purpose of keys.
Copy Key
Testing
34
If shell prompt of Backup Server is reached without asking for password, the
setup is a success.
Protect Key
Change the permission for the key file so that it is inaccessible to other users.
In CVS Server,
[cvsadmin@localhost ˜]$ chmod 600 ˜/.ssh/id_dsa ˜/.ssh/id_dsa.pub
12.2 Backup
CAUTION! The CVS Repository is not locked during backup. This may sometimes
render some files in the backup to be inconsistent. Information on locking the
Repository : [8]
35
# >> ------------------------------------ <<
#
REPO_PATH=/cvs/repo # Path of Repository
#
WORKING_PATH=/home/cvsadmin/cvs-working # CVS Working Directory
#
REMOTE_IP=10.20.30.40 # IP of Backup server
REMOTE_USER=cvsadmin # Username in Backup server
REMOTE_PATH=/home/$REMOTE_USER/CVSBackup # Path in Backup Server
#
# =============================================================================
#
echo -e "\nStarting Backup of CVS Repository...\n"
#
# =============================================================================
# Checking paths...
# =============================================================================
#
if [ ! -d $REPO_PATH ]; then
echo "Repository $REPO_PATH NOT Found..."
exit 1
fi
#
# =============================================================================
# Local Variables (Modify if needed...)
# =============================================================================
#
BACKUP_PATH=$WORKING_PATH/backup
BACKUP_LOG=$WORKING_PATH/log
YMD="‘date +%y%m%d‘"
LOG="$BACKUP_LOG/CVSBackup-$YMD.log"
TAR="/bin/tar"
#
# =============================================================================
# Setting up paths...
# =============================================================================
#
# Backup paths...
if [ ! -d $WORKING_PATH ]; then
echo "Working directory ’$WORKING_PATH’ does not exist... creating..."
mkdir -p $WORKING_PATH
if [ ! -d $WORKING_PATH ]; then
echo "Working directory ’$WORKING_PATH’ could not be created..."
exit 1
fi
fi
mkdir -p $BACKUP_PATH
mkdir -p $BACKUP_LOG
# Module List
MODULE_LIST=‘ls -l $REPO_PATH | awk ’{ print $9}’ | grep -v ’ˆ$’‘
# Count
MODULE_COUNT=‘ls -l $REPO_PATH | egrep -c ’ˆd’‘
#
# =============================================================================
# Main Script
# =============================================================================
#
DATE="‘date‘"
#
# Start logging...
touch $LOG
36
echo "--------------------- Start of Log File ----------------------------------" > $LOG
echo "" >> $LOG
echo "Total of" $MODULE_COUNT "CVS Modules to backup..." >> $LOG
echo "" >> $LOG
echo "Backup Location : "$REMOTE_IP:$REMOTE_PATH >> $LOG
echo "Remote Backup Method : scp" >> $LOG
echo "" >> $LOG
echo "Backup process started : $DATE" >> $LOG
echo "" >> $LOG
echo "Backup Individual Modules..." >> $LOG
echo " -------------------------------------------------------------------------" >> $LOG
sleep 1
#
# Loop start...
# -----------------------------------------------------------------------------
#
for MODULE_NAME in $MODULE_LIST; do
#
# ----- Backup each Module -----
MODULE_PATH="$MODULE_NAME"
#
echo " Backup Module Name : $MODULE_PATH" >> $LOG
echo " Backup File name : Backup-$YMD-$MODULE_NAME.tar.gz" >> $LOG
#
$TAR -C $REPO_PATH -cpzf $BACKUP_PATH/Backup-$YMD-$MODULE_NAME.tar.gz $MODULE_PATH >> $LOG
#
FILE_SIZE=‘du -sh $BACKUP_PATH/Backup-$YMD-$MODULE_NAME.tar.gz | awk ’{print $1}’‘
#
echo " Backup File size : $FILE_SIZE " >> $LOG
echo " Backup complete. " >> $LOG
echo " -------------------------------------------------------------------------" >> $LOG
#
done
#
# -----------------------------------------------------------------------------
# Loop end...
#
echo "Backup Individual Modules... Complete." >> $LOG
echo "" >> $LOG
#
# =============================================================================
# Final Backup - Single Archive
# =============================================================================
#
# Single Archive
echo "Final Backup - Single Archive..." >> $LOG
echo "--------------------------------------------------------------------------" >> $LOG
echo "Backup File name : Backup-$YMD.tar.gz" >> $LOG
#
# Change dir so tar can use relative path
cd $BACKUP_PATH
$TAR -cpzf $BACKUP_PATH/Backup-$YMD.tar.gz Backup-$YMD-*.tar.gz
#
# Cleanup Individual backup files
rm -f $BACKUP_PATH/Backup-$YMD-*.tar.gz
#
FILE_SIZE=‘du -sh $BACKUP_PATH/Backup-$YMD.tar.gz | awk ’{print $1}’‘
#
echo "Backup File size : $FILE_SIZE " >> $LOG
echo "--------------------------------------------------------------------------" >> $LOG
#
echo -n "Copying to Backup server... " >> $LOG
37
#
# Copy to Backup Server
scp -q $BACKUP_PATH/Backup-$YMD.tar.gz $REMOTE_USER@$REMOTE_IP:$REMOTE_PATH/
#
if [ "$?" -ne "0" ]; then
echo "Copy to Backup server: scp failed..."
echo "Failed!" >> $LOG
exit 1
fi
#
echo "Success." >> $LOG
#
DATE="‘date‘"
echo "" >> $LOG
echo "Backup process complete : $DATE" >> $LOG
echo "" >> $LOG
echo "------------------------- End of Log File --------------------------------" >> $LOG
cd
echo -e "CVS Repository Backup Successful...\n"
exit 0
# *** End of Backup Script *** #
38
Add the following lines to the file. . .
File: /cvs/cvstools/cvsbackup.cron
# [min] [hour] [day of month] [month] [day of week] [program to be run]
0 22 * * * /cvs/cvstools/backup
12.4 Restore
12.4.1 The Process
1. If Backup File found in Local Backup, use local backup
2. If Local Backup does not contain Backup File, copy from Backup Server
and keep a copy in Local Backup
39
Add the following lines to the file. . .
File: /cvs/cvstools/restore
#!/bin/bash
# Script used to restore CVS Repository from Backup Server
# - Tar is used - Relative Paths used for Restore
# - Backup Archive downloaded using scp
# =============================================================================
# >> ------------------------------------ <<
# >> Configuration Variables (Modifiable) <<
# >> ------------------------------------ <<
#
REPO_PATH=/cvs/repo # Path of Repository
#
WORKING_PATH=/home/cvsadmin/cvs-working # Local Directory for Backup
#
REMOTE_IP=10.20.30.40 # IP of Backup server
REMOTE_USER=cvsadmin # Username in Backup server
REMOTE_PATH=/home/$REMOTE_USER/CVSBackup # Path in Backup Server
LAST_BACKUP_DATE="‘date +%y%m%d‘" # Last Backup Date (yymmdd)
#
# =============================================================================
#
echo -e "\nStarting Restore of CVS Repository..."
#
# =============================================================================
# Checking paths...
# =============================================================================
#
if [ ! -d $REPO_PATH ]; then
echo "Repository $REPO_PATH NOT Found..."
exit 1
fi
#
# =============================================================================
# Local Variables (Modify if needed...)
# =============================================================================
#
BACKUP_PATH=$WORKING_PATH/backup
RESTORE_PATH=$WORKING_PATH/restore
RESTORE_LOG=$WORKING_PATH/log
YMD="‘date +%y%m%d‘"
LOG="$RESTORE_LOG/CVSRestore-$YMD.log"
TAR="/bin/tar"
#
# =============================================================================
# Setting up paths...
# =============================================================================
#
# Backup paths...
if [ ! -d $WORKING_PATH ]; then
echo "Local directory ’$WORKING_PATH’ does not exist... creating..."
mkdir -p $WORKING_PATH
if [ ! -d $WORKING_PATH ]; then
echo "Local directory ’$WORKING_PATH’ could not be created..."
exit 1
fi
fi
mkdir -p $RESTORE_PATH
mkdir -p $RESTORE_LOG
#
40
# Start logging...
touch $LOG
DATE="‘date‘"
echo "--------------------- Start of Log File ----------------------------------" > $LOG
echo "" >> $LOG
echo "Restore process started : $DATE" >> $LOG
echo "" >> $LOG
#
# Cleanup Backup Files from previous restore
rm -f $RESTORE_PATH/*.*
#
# Check if Local Backup Exist
echo -n "Checking Local Backup... " >> $LOG
if [[ -e $BACKUP_PATH/Backup-$LAST_BACKUP_DATE.tar.gz ]]; then
#
# =============================================================================
# Copying from Local Backup - Single Archive
# =============================================================================
#
echo "Found." >> $LOG
echo -n "Copying from Local Backup... " >> $LOG
cp $BACKUP_PATH/Backup-$LAST_BACKUP_DATE.tar.gz $RESTORE_PATH/
else
#
# =============================================================================
# Copying from Backup server - Single Archive
# =============================================================================
#
echo "Missing." >> $LOG
echo -n "Copying from Backup Server... " >> $LOG
#
# Copy from Backup Server
scp -q $REMOTE_USER@$REMOTE_IP:$REMOTE_PATH/Backup-$LAST_BACKUP_DATE.tar.gz $RESTORE_PATH/
#
# Copy to Local Backup
cp $RESTORE_PATH/Backup-$LAST_BACKUP_DATE.tar.gz $BACKUP_PATH/
#
fi
#
if [ "$?" -ne "0" ]; then
echo "Copy from Backup server: scp failed..."
echo "Failed!" >> $LOG
exit 1
fi
#
echo "Success." >> $LOG
echo "" >> $LOG
#
# Single Archive
echo "Backup File - Single Archive..." >> $LOG
echo "--------------------------------------------------------------------------" >> $LOG
echo "Backup File name : Backup-$LAST_BACKUP_DATE.tar.gz" >> $LOG
#
FILE_SIZE=‘du -sh $RESTORE_PATH/Backup-$LAST_BACKUP_DATE.tar.gz | awk ’{print $1}’‘
#
echo "Backup File size : $FILE_SIZE " >> $LOG
echo "--------------------------------------------------------------------------" >> $LOG
#
# =============================================================================
# Extract from Backup File
# =============================================================================
#
41
# Extract Single Archive
$TAR -C $RESTORE_PATH -xpzf $RESTORE_PATH/Backup-$LAST_BACKUP_DATE.tar.gz
#
# Remove Single Archive
rm $RESTORE_PATH/Backup-$LAST_BACKUP_DATE.tar.gz
#
# Module List
MODULE_LIST=‘ls -l $RESTORE_PATH | awk ’{ print $9}’ | grep -v ’ˆ$’‘
# Count
MODULE_COUNT=‘ls -l $RESTORE_PATH | egrep -c ’ˆ-’‘
#
# =============================================================================
# Main Script
# =============================================================================
#
DATE="‘date‘"
#
echo "Total of" $MODULE_COUNT "CVS Modules available for restore..." >> $LOG
echo "" >> $LOG
echo "Restore Individual Modules..." >> $LOG
sleep 1
#
# Loop start...
# -----------------------------------------------------------------------------
#
echo -e "\nCAUTION! Restoring will delete existing files in the Module!\n"
#
for MODULE_FILENAME in $MODULE_LIST
do
#
# ----- Restore each Module -----
#
# Confirmation?
MODULE_NAME=‘echo $MODULE_FILENAME | awk -F’-’ ’{print $3}’ | awk -F’.’ ’{print $1}’‘
#
echo -n "Restore Module $MODULE_NAME [Y/n]? "
read confirm
if [ "$confirm" = "" -o "$confirm" = "Y" -o "$confirm" = "y" ]; then
echo " -------------------------------------------------------------------------" >> $LOG
echo " Restore Module Name : $MODULE_NAME" >> $LOG
echo " Backup File name : $MODULE_FILENAME" >> $LOG
#
FILE_SIZE=‘du -sh $RESTORE_PATH/$MODULE_FILENAME | awk ’{print $1}’‘
#
echo " Backup File size : $FILE_SIZE " >> $LOG
#
rm -rf $REPO_PATH/$MODULE_NAME
#
$TAR -C $REPO_PATH -xpzf $RESTORE_PATH/$MODULE_FILENAME
#
echo " Restore complete." >> $LOG
echo " -------------------------------------------------------------------------" >> $LOG
fi
#
done
#
# -----------------------------------------------------------------------------
# Loop end...
#
echo "Restore Individual Modules... Complete." >> $LOG
#
DATE="‘date‘"
42
echo "" >> $LOG
echo "Restore process complete : $DATE" >> $LOG
echo "" >> $LOG
echo "------------------------- End of Log File --------------------------------" >> $LOG
cd
echo -e "\nCVS Repository Backup Successful...\n"
exit 0
# *** End of Backup Script *** #
If CVSROOT is not restored, then the other Modules may not be accessible
using pserver. In that case, checkout the Module from CVS Box itself as
described in Section 6.2.1.
This method also works in the case of restoring only Project Modules to
a freshly set-up CVS Repository.
For huge Repositories, redundant copies of large size is not efficient. But,
for small and highly volatile Repositories, where files gets deleted from CVS
very often, the accumulating system is better.
43
For changing the backup from accumulating to rotating, follow these steps.
CAUTION! The rotating backup script cannot use the Backup files created using
accumulating backup script.
Replace all occurences of YMD after ’Local Variables’ section to TODAY. YMD
is needed in LOG.
to
LAST_BACKUP_DATE="‘date +%a‘" # Last Backup Day (ddd)
44
13 Conclusion
Discussing all the intricacies of CVS Server will be almost impossible. Almost
all basic features have been covered in this guide.
45
References
[1] http://cvsacl.sourceforge.net/index.html#install
[2] http://www.linuxfromscratch.org/blfs/view/stable/
server/cvsserver.html
[3] http://www.faqs.org/docs/ldev/0130091154_198.htm
[4] http://www.idevelopment.info/data/Programming/
change_management/unix_cvs/PROGRAMMING_Importing_
Projects_into_CVS.shtml
[5] http://www.devdaily.com/blog/post/cvs/
export-project-from-cvs-repository/
[6] http://pragmaticautomation.com/cgi-bin/pragauto.
cgi/Monitor/LettingCVSPullTheTrigger.rdoc/style/
print
[7] http://www.cyberciti.biz/tips/
change-linux-or-unix-system-password-using-php-script.
html
[8] http://docstore.mik.ua/orelly/other/cvs/
cvs-CHP-6-SECT-7.htm
[9] http://www.hostingrails.com/wiki/27/
HowTo-SSHSCP-without-a-password
[10] http://www.scrounge.org/linux/cron.html
46