100% found this document useful (3 votes)
2K views47 pages

Ultimate Guide To CVS Server Administration in Fedora 6

This document provides instructions for administering a CVS server on Fedora 6. It covers installing and configuring CVS and related tools, creating users and repositories, setting permissions, accessing the server remotely, using hooks for pre/post commit functions, and backing up the repository. The goal is to help administrators set up a full-featured CVS server to manage software source code and documentation.

Uploaded by

ATOzTOA
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (3 votes)
2K views47 pages

Ultimate Guide To CVS Server Administration in Fedora 6

This document provides instructions for administering a CVS server on Fedora 6. It covers installing and configuring CVS and related tools, creating users and repositories, setting permissions, accessing the server remotely, using hooks for pre/post commit functions, and backing up the repository. The goal is to help administrators set up a full-featured CVS server to manage software source code and documentation.

Uploaded by

ATOzTOA
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 47

Ultimate Guide to CVS Server

Administration in Fedora 6

ATOzTOA
www.atoztoa.com
[email protected]

March 2009

This document was generated using LATEX.


Contents
1 Preface 4
1.1 Who Should Read This Guide? . . . . . . . . . . . . . . . . . . 4
1.2 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 How to use this guide? . . . . . . . . . . . . . . . . . . . . . . . 4

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

10 Accessing CVS through Network 27


10.1 CVS Clients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
10.1.1 Linux Box . . . . . . . . . . . . . . . . . . . . . . . . . . 27
10.1.2 Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
10.2 Setting CVSROOT . . . . . . . . . . . . . . . . . . . . . . . . . . 27
10.2.1 In Linux Box . . . . . . . . . . . . . . . . . . . . . . . . . 27
10.2.2 In Windows . . . . . . . . . . . . . . . . . . . . . . . . . 27
10.3 Accessing CVS Modules . . . . . . . . . . . . . . . . . . . . . . 27

11 Hooks, the Final Frontier 28


11.1 What are hooks? . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
11.2 pre-commit hook . . . . . . . . . . . . . . . . . . . . . . . . . . 28
11.2.1 when? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

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

12 Backup and Restore 33


12.1 Setting Up Backup Server . . . . . . . . . . . . . . . . . . . . . 33
12.1.1 Information . . . . . . . . . . . . . . . . . . . . . . . . . 33
12.1.2 Creating User . . . . . . . . . . . . . . . . . . . . . . . . 33
12.1.3 Setting up password-less ’scp’ . . . . . . . . . . . . . . 33
12.2 Backup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
12.2.1 The Process . . . . . . . . . . . . . . . . . . . . . . . . . 35
12.2.2 The Script . . . . . . . . . . . . . . . . . . . . . . . . . . 35
12.2.3 Executing Backup . . . . . . . . . . . . . . . . . . . . . . 38
12.3 Automatic Daily Backup . . . . . . . . . . . . . . . . . . . . . . 38
12.4 Restore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
12.4.1 The Process . . . . . . . . . . . . . . . . . . . . . . . . . 39
12.4.2 The Script . . . . . . . . . . . . . . . . . . . . . . . . . . 39
12.4.3 Executing Restore . . . . . . . . . . . . . . . . . . . . . . 43
12.5 Rotating Backups . . . . . . . . . . . . . . . . . . . . . . . . . . 43
12.5.1 Backup script . . . . . . . . . . . . . . . . . . . . . . . . 44
12.5.2 Restore script . . . . . . . . . . . . . . . . . . . . . . . . 44

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

• How to use an editor in Linux?

• How Linux file permissions work?

1.3 How to use this guide?


This is a setp-by-step guide covering the setting up and management of
CVS Server. All steps can be executed from top to bottom and the Server
will be up and running. If this guide is used for troubleshooting, then look
at the particular section and do the necessary steps.

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.

• If the CVS Repository is in another path, then remember to use that


path wherever the repository path (/cvs/repo) is used in the document.

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.

2.2 Tools Needed


CVS . . . . . . . . . . . . . . . . . . . . . . CVS Server
cvsacl . . . . . . . . . . . . . . . . . . . . CVS ACL can be used to Specify Access
Permissions for CVS Users.
xinetd . . . . . . . . . . . . . . . . . . . . The eXtended InterNET Daemon, is an
open-source super-server daemon which
manages Internet-based connectivity.

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

Download cvs source from


http://ftp.gnu.org/non-gnu/cvs/source/stable/1.11.22/cvs-1.
11.22.tar.bz2
file size 2.8M.
[root@localhost ˜]# tar xvjf cvs-1.11.22.tar.bz2
[root@localhost ˜]# cd cvs-1.11.22
[root@localhost cvs-1.11.22]# ./configure
[root@localhost cvs-1.11.22]# make
[root@localhost cvs-1.11.22]# make install

3.2 CVS ACL


Download and install latest version of cvsacl from
http://cvsacl.sourceforge.net/index.html#install.

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

Download binary rpm from


http://archives.fedoraproject.org/pub/archive/fedora/linux/
core/6/i386/os/Fedora/RPMS/xinetd-2.3.14-8.i386.rpm
file size 124K.
[root@localhost ˜]# rpm -Uvh xinetd-2.3.14-8.i386.rpm

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.

4.1.2 CVS Users


• users who are going to use the CVS.
• will be having restricted access.
• will NOT have their own home directory and they cannot login to the
CVS Box.
• will be having different levels of access to the CVS Repository.
• usernames used in this guide are user1, user2.

4.2 Creating Users


4.2.1 Creating CVS Administrator
useradd - add user
[root@localhost ˜]# useradd cvsadmin
passwd - change user password
[root@localhost ˜]# passwd cvsadmin
Add sudo permission.
[root@localhost ˜]# echo "cvsadmin ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

4.2.2 Creating CVS Users


[root@localhost ˜]# useradd -M user1
[root@localhost ˜]# useradd -M user2
-M flag : do not create user’s home directory

8
5 Creating Repository
5.1 Creating Folder Structure
5.1.1 Repository
mkdir - create directory
[root@localhost ˜]# mkdir -p /cvs/repo

-p flag : Create the full directory tree if it does not exist.

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

5.2 Exporting CVSROOT


Add CVSROOT environment variable to shell startup file.
[root@localhost ˜]# echo "export CVSROOT=/cvs/repo" >> /etc/profile

5.3 Changing Ownership/Permissions


Give cvsadmin full ownership over /cvs directory tree.

chown - change file/folder ownership


[root@localhost cvs]# chown -R cvsadmin:cvsadmin /cvs

su - switch user
[root@localhost ˜]# su cvsadmin

chmod - change permissions


[cvsadmin@localhost ˜]$ chmod 0770 /cvs/repo

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.

6.2 Managing CVS Modules


6.2.1 Creating a New Module
We will add a new Module named Test-Module to the CVS.

Create the new directory /cvs/repo/Test-Module as user cvsadmin.


[cvsadmin@localhost ˜]$ mkdir /cvs/repo/Test-Module
This module won’t be accessible through pserver until the Entries file is
populated. Checkout the module from CVS Box itself.
[cvsadmin@localhost ˜]$ cvs co Test-Module
Create a new file named testfile inside the Checked out directory and
commit it to CVS.
[cvsadmin@localhost ˜]$ cd Test-Module
[cvsadmin@localhost ˜]$ echo "Test" > testfile
[cvsadmin@localhost ˜]$ cvs add testfile
[cvsadmin@localhost ˜]$ cvs commit -m "Initial" testfile
The procedure is same for any new modules. The message ”Initial” may
be anything, it is the message stored along with the initial version of the
module.

6.2.2 Importing Modules


An existing Project tree can be imported into the CVS as a new Module.

General Syntax of CVS Import


cvs import <project name> <vendor tag> <release tag>
All 3 arguments are mandatory.

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.

General Syntax of CVS Export


cvs export [-r tag] [-D date] <module name>

A tag or date must be specified.

Exporting
[cvsadmin@localhost ˜]$ cvs export -D NOW Project_Foo

NOW will export the latest version of the Module.

Verifying
[cvsadmin@localhost ˜]$ cd Project_Foo
[cvsadmin@localhost Project_Foo]$ tree
.
|-- Makefile
|-- inc
| ‘-- foo.h
‘-- src
‘-- foo.c

2 directories, 3 files

Date and Tag


[cvsadmin@localhost ˜]$ cvs export -D 2009-01-01 Project_Foo

This will export a version of the Module which is no later than Jan 01, 2009.

[cvsadmin@localhost ˜]$ cvs export -r PROJECT_BASE Project_Foo

This will export a version of the Module which was tagged using ’PROJECT BASE’.

12
7 Setting User Access Rights
7.1 Access Permissions

n no access NO access on the repository.


r read Only read access on repository. Allowed to run
cvs subcommands: annotate, checkout, diff, export,
log, rannotate, rdiff, rlog, status.
w write Only cvs commit/checkin action. NOT allowed to
add/remove any file to/from repository.
t tag Allows cvs tag and rtag subcommands to run.
Includes read permission. Does not include write
permission.
c create Allows cvs add and import subcommands to run.
Includes commit permission. Does not include
write permission.
d delete Allows cvs remove command to run. Does not
include write permission.
a full access except All access (above permissions) to repository, but it
admin rights cannot modify permissions. Only acl admins may
modify the acl definitions.
p acl admin User is an acl admin, allowed any action on
repository.

7.2 Setting Default Permissions


The default permissions are defined in file /cvs/repo/CVSROOT/aclconfig.

Change the file so that only UseCVSACL and CVSACLDefaultPermissions


are enabled, and the rest are commented.

ALERT! Setting CVSACLDefaultPermissions is important!

File: /cvs/repo/CVSROOT/aclconfig
# Set ‘UseCVSACL’ to yes to use CVSACL feature.
UseCVSACL=yes

# Default CVSACL Permission to use.


CVSACLDefaultPermissions=r
..
.

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.

racl command is used on repository without a working copy.


Usage: cvs racl [user||group:permissions] [-Rl] [-r tag] [directories...] [files...]
-R Process directories recursively.
-r rev Existing revision/tag.
-l List defined ACLs.

7.3.2 ACL Admin


Define cvsadmin as acl administrator.
[cvsadmin@localhost ˜]$ cvs racl cvsadmin:p -r ALL ALL

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.

[cvsadmin@localhost ˜]$ cvs racl user1:r -r ALL Test-Module

2. Enable write, delete, create permission for user1 in Test-Module Module.

[cvsadmin@localhost ˜]$ cvs racl user1:wcd -r ALL Test-Module

3. Disable access permission for user1 to the Test-Module/Locked directory.

[cvsadmin@localhost ˜]$ cvs racl user1:n -r ALL Test-Module/Locked

4. Enable write, create permission for user2 in Test-Module Module.

[cvsadmin@localhost ˜]$ cvs racl user2:wc -r ALL Test-Module

5. Enable full access permission for user2 in Test-Module Module.

14
[cvsadmin@localhost ˜]$ cvs racl user2:a -r ALL Test-Module

6. Add tag permission also for user1 in Test-Module Module.


[cvsadmin@localhost ˜]$ cvs racl user1:+t -r ALL Test-Module

7. Remove delete permission for user1 in Test-Module Module.


[cvsadmin@localhost ˜]$ cvs racl user1:-d -r ALL Test-Module

8. Disable access permission for all users in CVSROOT Module.


[cvsadmin@localhost ˜]$ cvs racl ALL:n -r ALL CVSROOT

7.3.4 Important Information


Setting access rights for a single file using cvs racl is not working as of
writing this guide. Need to manually edit the access file as expained in
next section.

7.4 Manually editing access file


The access file is created when cvs init is executed. This file can be
manually edited to set the user permissions for CVS ACL.

Each line in the file will have the format


d:<modulename/directory/file>:<revision/tag>:<username>!<permissions>:
Line starting with ’#’ is a comment.

An example access file. . .

File: /cvs/repo/CVSROOT/access
# CVS ACL definitions file. DO NOT EDIT MANUALLY (Yeah I know !!!)

# Admin
d:ALL:ALL:cvsadmin!p:

# Module Name : Test-Module


d:Test-Module:ALL:user1!a:
d:Test-Module:ALL:user2!wct:

# Module Name : CVSROOT (No Access!!!)


d:CVSROOT:ALL:user1!n:
d:CVSROOT:ALL:user2!n:

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
}

If need to add multiple repositories to pserver, modify the server args

server args = -f --allow-root=/cvs/repo --allow-root=/cvs/repo2


[...] pserver

8.1.2 Restarting xinetd


Restart the xinetd services.
[root@localhost ˜]# /etc/init.d/xinetd restart

17
9 Passwords
This section is NOT applicable for cvsadmin.

9.1 CVS Password file


There is two passwords, one used for login to the CVS Box (user password) and
another to access the CVS (CVS password).

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.

An entry in the file has the following form:


<username>:<encoded password>:<cvsadmin username>

Create file /cvs/repo/CVSROOT/passwd.


[root@localhost ˜]# su cvsadmin
[cvsadmin@localhost ˜]$ touch /cvs/repo/CVSROOT/passwd

9.2 Set CVS Password - The Simple Way


The login is disabled for CVS Users, the users cannot login and change their
passwords. The password is changed directly at the CVS Box with the help
of cvsadmin.

9.2.1 Passwords and Login


No password is needed as the users are not allowed to login.

Remove login permission for the users.


[root@localhost ˜]# chsh -s /sbin/nologin user1
[root@localhost ˜]# chsh -s /sbin/nologin user2

18
9.2.2 Utility Scripts

calc-hash.pl

Create file calc-hash.pl.


[cvsadmin@localhost ˜]$ cd /cvs/cvstools
[cvsadmin@localhost cvstools]$ vi calc-hash.pl

Add the following lines to the file. . .

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";

Add execute permission. . .


[cvsadmin@localhost cvstools]$ chmod +x calc-hash.pl

cvspasswd

Create one more script file cvspasswd.


[cvsadmin@localhost cvstools]$ vi cvspasswd

Add the following lines to the file. . .

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

Add execute permission. . .


[cvsadmin@localhost cvstools]$ chmod +x cvspasswd

9.2.3 Adding / Changing Passwords


Execute cvspasswd for each user.
[cvsadmin@localhost cvstools]$ ./cvspasswd user1
Changing CVS password for user user1.
New CVS Password:
Retype new UNIX password:
CVS Password Changed Successfully.

[cvsadmin@localhost cvstools]$ ./cvspasswd user2


Changing CVS password for user user2.
New CVS Password:
Retype new UNIX password:
CVS Password Changed Successfully.

The final passwd file. . .

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

Download two binary rpms from


http://archives.fedoraproject.org/pub/archive/fedora/linux/
core/6/source/SRPMS/tcl-8.4.13-3.fc6.src.rpm
file size 6.5M.
http://archives.fedoraproject.org/pub/archive/fedora/linux/
core/6/source/SRPMS/expect-5.43.0-5.1.src.rpm
file size 537K.
[root@localhost ˜]# rpm -Uvh tcl-8.4.13-3.fc6.src.rpm
[root@localhost ˜]# rpm -Uvh expect-5.43.0-5.1.src.rpm

Testing

If the command
expect

displays an expectx.x> prompt, then expect is working.


Caution: if expect cannot be installed properly, then this step won’t work.

9.3.2 Passwords and Sudo


Set passwords for CVS users.
[root@localhost ˜]# passwd user1
[root@localhost ˜]# passwd user2

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!

Add write permission to CVS Password File, /cvs/repo/CVSROOT/passwd.


[root@localhost ˜]# chmod 666 /cvs/repo/CVSROOT/passwd

9.3.3 Utility Scripts

calc-hash.pl

Create file calc-hash.pl.

This file is same as that in Section 9.2.2.


[cvsadmin@localhost ˜]$ sudo mkdir /cvs/cvstools
[cvsadmin@localhost ˜]$ sudo chown cvsadmin:cvsadmin /cvs/cvstools
[cvsadmin@localhost ˜]$ cd /cvs/cvstools
[cvsadmin@localhost cvstools]$ vi calc-hash.pl

Add the following lines to the file. . .

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";

Add execute permission. . .


[cvsadmin@localhost cvstools]$ chmod +x calc-hash.pl

22
userpasswd

Create script for changing user password (login password).

Create file userpasswd.


[cvsadmin@localhost cvstools]$ vi userpasswd

Add the following lines to the file. . .

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

Add execute permission. . .


[cvsadmin@localhost cvstools]$ chmod +x userpasswd

Create one more script file cvspasswd.


[cvsadmin@localhost cvstools]$ vi cvspasswd

Add the following lines to the file. . .

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

Add execute permission. . .


[cvsadmin@localhost cvstools]$ chmod +x cvspasswd

rshell

Need to make the script cvspasswd as the ’login shell’ for CVS users.

Create a .c file rshell.c.


[cvsadmin@localhost cvstools]$ vi rshell.c

Add the following lines to the file. . .

File: /cvs/cvstools/rshell.c
#include<unistd.h>
main()
{
execl("/bin/sh", "sh", "/cvs/cvstools/cvspasswd", 0);
}

The code executes /bin/sh and runs sh /cvs/cvstools/cvspasswd.

24
Compile the code using gcc.
[cvsadmin@localhost cvstools]$ gcc -o rshell rshell.c

Copy to /bin.
[cvsadmin@localhost cvstools]$ sudo cp rshell /bin/

Change login shell

Set /bin/rshell as the login shell for CVS users.


[cvsadmin@localhost cvstools]$ sudo chsh -s /bin/rshell user1
[cvsadmin@localhost cvstools]$ sudo chsh -s /bin/rshell user2

9.3.4 Adding / Changing Passwords

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

cvsadmin can change user passwords by logging in as the particular user,


which will invoke the script.
[cvsadmin@localhost ˜]$ sudo su user1

Script in Action
[cvsadmin@localhost cvstools]# sudo su user1

You are successfully logged into CVS...


=======================================

Press ’Q’ to quit or any other key to change your password...


Changing password for user user1.
New CVS Password:
Retype new CVS password:
spawn sudo passwd user1

25
Changing password for user user1.
New UNIX password:
Retype new UNIX password:
passwd: all authentication tokens updated successfully.

Password Changed Successfully.


Press any key...

The Result

The final passwd file. . .

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
..
.

10.1 CVS Clients


10.1.1 Linux Box
1. cvs

2. cervisia

10.1.2 Windows
1. WinCVS

2. TortoiseCVS

10.2 Setting CVSROOT


10.2.1 In Linux Box
$ export CVSROOT=:pserver:<username>@<ip of CVS Box>:/cvs/repo

10.2.2 In Windows
Set the environment variable CVSROOT in the Client to
:pserver:<username>@<ip of CVS Box>:/cvs/repo.

10.3 Accessing CVS Modules


The way the CVS is accessed differs across CVS Clients. The details of using
CVS Clients will make another guide by itself, so it is not discussed in detail
here.

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.

11.2 pre-commit hook


11.2.1 when?
The pre-commit hook is triggered after typing cvs commit, but before the
changes are actually saved to the repository.

11.2.2 the program


A program can be registered to be run when a commit is attempted. Some
information is automatically passed as argument to the program - a) the
CVS directory where the commit is occurring and b) the name of each of the
file in the commit.

An example shell script (it can be any program). . .


[cvsadmin@localhost cvstools]$ vi pre-commit.sh

File: /cvs/cvstools/pre-commit.sh
#!/bin/sh

LOG_FILE=/cvs/repo/CVSROOT/commitlog
DATE=‘date "+%m/%d/%y [%H:%M:%S]"‘

echo "$DATE: A commit is occurring in $1" >> $LOG_FILE


shift

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.

Add execute permission to the file pre-commit.sh.


[cvsadmin@localhost cvstools]$ chmod +x pre-commit.sh

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.

11.2.4 hooking the program


For registering the program with the hook, an entry is made in the file
/cvs/repo/CVSROOT/commitinfo.

Each entry is of the form:


<regular expression> <program to run>

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.

To run the script pre-commit.sh when a pre-commit event occurs in a


sub-directory of the Test-Module module, add the following line to the file
/cvs/repo/CVSROOT/commitinfo:

Test-Module/* /cvs/cvstools/pre-commit.sh

A sample commitinfo file, the comments explain it all. . .

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
..
.

11.3 post-commit hook


11.3.1 when?
The post-commit hook is triggered after changes are saved to the repository.

11.3.2 the program


A program can be registered to be run when a commit is complete. Some
information is automatically passed as argument to the program - the name
of each file that was committed.

An example shell script (it can be any program). . .


[cvsadmin@localhost cvstools]$ vi post-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

# Eat extra input


cat > /dev/null

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

Add execute permission to the file post-commit.sh.


[cvsadmin@localhost cvstools]$ chmod +x post-commit.sh

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.

11.3.4 hooking the program


For registering the program with the hook, an entry is made in the file
/cvs/repo/CVSROOT/loginfo.

Each entry is of the form:


<regular expression> <program to run>

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.

To run the script post-commit.sh when a post-commit event occurs in a


sub-directory of the Test-Module module, add the following line to the file
/cvs/repo/CVSROOT/loginfo:

Test-Module/* /cvs/cvstools/post-commit.sh %s

%s is expanded to include name of each committed file.

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.

12.1 Setting Up Backup Server


The data protection mechanisms in Backup Server is not covered here.

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

• Linux Version : Fedora 6

12.1.2 Creating User


In Backup Server, create a new user ’cvsadmin’.
[root@cvsbackup ˜]# useradd cvsadmin
[root@cvsbackup ˜]# passwd cvsadmin

12.1.3 Setting up password-less ’scp’


The backup is send from CVS Server to Backup Server using scp (secure
copy). It is done automatically using script, so a way of using scp without a
password is needed.

Check SSH

Check ssh from CVS Server to Backup Server.

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)?

Type ’yes’ followed by ’Enter’.


Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ’10.20.30.40’ (RSA) to the list of known hosts.
[email protected]’s password:

Provide the password given to user cvsadmin in the Backup Server. If the
password is correct, shell prompt in Backup Server is reached.

Try ifconfig and check the ip address.

Logout of Backup Server.

Generate Key

Create a unique key which is used to authenticate the session, instead of


the password.
[cvsadmin@localhost ˜]$ sh-keygen -t dsa
Press ’Enter’ for all questions, do NOT enter a passphrase. If asked whether
to overwrite, ’say yes’.

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

Copy the generated key to Backup Server.


[cvsadmin@localhost ˜]$ ssh-copy-id -i ˜/.ssh/id_dsa.pub [email protected]

Provide the password for cvsadmin in the Backup Server.

From now on, scp/ssh will work without a password.

Testing

Try ssh to the Backup Server.


[cvsadmin@localhost ˜]$ ssh 10.20.30.40

34
If shell prompt of Backup Server is reached without asking for password, the
setup is a success.

Logout of Backup Server.

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]

12.2.1 The Process


1. Create seperate archive for each module in CVS Repository

2. Create a single archive containing the seperate archives

3. Remove the seperate archives

4. Copy the single archive to Backup Server

5. Keep the single archive in CVS Server Local Backup

12.2.2 The Script


Create backup script file backup.
[cvsadmin@localhost cvstools]$ vi backup
Add the following lines to the file. . .
File: /cvs/cvstools/backup
#!/bin/bash
# Script used to backup CVS Repository onto Backup Server
# - Tar is used - Relative Paths used for Backup
# - Uploaded using scp
# =============================================================================
# >> ------------------------------------ <<
# >> Configuration Variables (Modifiable) <<

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 *** #

Add execute permission. . .


[cvsadmin@localhost cvstools]$ chmod +x backup

12.2.3 Executing Backup


Edit backup script...
[cvsadmin@localhost cvstools]$ vi backup

Set the paths under ’Configuration Variables’ section in the script.

Execute the script.


[cvsadmin@localhost cvstools]$ ./backup

12.3 Automatic Daily Backup


cron is used for automated backup of CVS.

The backup script is run at 10 PM each day.

Create cron file cvsbackup.cron


[cvsadmin@localhost cvstools]$ vi cvsbackup.cron

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

Add to cron scheduler.


[cvsadmin@localhost cvstools]$ crontab /cvs/cvsbackup/cvsbackup.cron

This will schedule the backup script to run.

For listing the jobs,


[cvsadmin@localhost cvstools]$ crontab -l

For removing the jobs,


[cvsadmin@localhost cvstools]$ crontab -r

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

3. Extract single archive to get seperate archives

4. Prompt for confirmation from user before restoring each Module

12.4.2 The Script


Create restore script file restore.
[cvsadmin@localhost cvstools]$ vi restore

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 *** #

Add execute permission. . .


[cvsadmin@localhost cvstools]$ chmod +x restore

12.4.3 Executing Restore


Edit restore script...
[cvsadmin@localhost cvstools]$ vi restore

Set the paths under ’Configuration Variables’ section.

Set LAST BACKUP DATE to the date of the backup to be used.

Execute the script.

[cvsadmin@localhost cvstools]$ ./restore

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.

12.5 Rotating Backups


In the above scripts, the Backup is generated for each day which goes on
accumulating. In rotating backup, the only unique part in the Backup filename
is the Weekday, so after one week the older backup files are automatically
overwritten.

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.

12.5.1 Backup script


Add the line
TODAY="‘date +%a‘"

to the ’Local Variables’ section.

Replace all occurences of YMD after ’Local Variables’ section to TODAY. YMD
is needed in LOG.

12.5.2 Restore script


Change the line
LAST_BACKUP_DATE="‘date +%y%m%d‘" # Last Backup Date (yymmdd)

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.

Send comments and suggestions to the author.

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

You might also like