=== Managing Files in cvsman === ===== Introduction ===== This document describes using the cvsman utility to manage files across multiple hosts. It assumes a basic knowledge of using CVS. ===== Concepts ===== The basic concept behind cvsman is a file collection. This is a group of files that are managed together. The concept comes from the old BSD sup(1) utility. The server "serves" this collection, and various clients "subscribe" to the collection. In the cvsman world, the server is CVS, the colleciton is a specific module in CVS, and the clients are merely machines who have the module checked out. cvsman provides the glue for updating the module and then moving the files where they need to go on the client host. Some definitions: collection Group of files managed in one CVS module collection directory The directory on the client host where the CVS module has been checked out list file The file specifying the include/exclude lists for the client host. This file lives in /hosts, and is usually named the same as the client's hostname. ===== Setting Up a Collection ===== A collection is just a CVS module with a specific hierarchy. It has only two subdirectories that are required. These subdirectories are 'hosts' and 'root'. The 'hosts' subdirectory contains the list files. These are files describing what each particular client host wants out of the file collection. The 'root' directory is the root of the managed file space. It acts as '/'. Any file under the 'root' directory is mapped to itself in the regular directory hierarchy. So, 'root/etc/hosts' is mapped to '/etc/hosts'. To create the collection, merely create a directory with the 'hosts' and 'root' subdirectories, then import it into CVS. Voila, a collection. ===== Adding Files to the Collection ===== Adding files is easy. Merely copy them to their appropriate place in the 'root' subdirectory and add them to CVS. Once committed, they are now part of the collection. Make sure to handle binary files properly with the '-kb' flag to cvs add. ===== File Permissions ===== CVS is not perfect about file permissions in the repository. Generally, a file that is readable becomes world-readable, and a file that is executable becomes world-executable. This is OK for most files, but not for all (eg /etc/shadow). cvsman supports a permissions file called '.cvsperms'. This file lives in any of the directories under 'root' and only affects its siblings in its directory. The file contains permission directives, one per line. Each directive specifies the basename of the file to act on, the uid to set the file to, the gid for the same, and the permission bits, in octal without the leading 0. So, for '/etc/shadow' to be locked down, you would have the following: ---- in root/etc/.cvsperms: shadow/0/0/600 ---- This specifies that the file 'shadow' is owned by root.root and has permissions of 0600. cvsman not only sets the permissions on the file after installing it in the regular filesystem hierarchy, it *also* sets the permissions on the file in the collection directory. Otherwise, while no one could view /etc/shadow, they could certainly view /root/etc/shadow. This would not be a good thing. Note, by the way, the restrictions this might place if the permissions were specified as 'shadow/0/0/000'. ===== Configuring the File List ===== The file list specifies which files in the collection the client host is interested in. Why not just copy all files in the collection? If you blindly copy all files, you then have to create distinct collections for every host that has a slightly different need. This is not that nice. Imagine a collection managing some files in /etc. This collection manages /etc/hosts, /etc/resolv.conf, and /etc/profile. However, you have both Debian GNU/Linux and Red Hat Linux machines that need this information. The Debian machines have /etc/profile, but the Red Hat machines modify /etc/profile via scriptlets in /etc/profile.d. If there was merely a blind copy, one would have to have a collection for Debian machines and a collection for Red Hat machines. These collections would only differ in their handling of /etc/profile. To manage /etc/hosts, one would have to modify the /etc/hosts file in both collections. Obviously, one of the chief reasons for file collections is to manage a given file in one place. The above example doesn't allow that, so it is not sufficient. Imagine, instead, that the same collection could handle both Red Hat and Debian machines. The Debian hosts could specify they were interested in /etc/hosts, /etc/resolv.conf, and /etc/profile, while the Red Hat hosts could specify they were interested in /etc/profile.d/*, not /etc/profile. This is where the list file comes into play. List files live in the 'hosts' subdirectory of the collection. By default, a host's list file is named by the host's hostname (what a mouthful). Eg, the host 'mymachine' keeps its list in 'hosts/mymachine'. This default is precisely the output of /bin/hostname, so if /bin/hostname were to return 'mymachine.mydomain.com', the list file would indeed be 'hosts/mymachine.mydomain.com'. A list file with a different name can be used, and that is described later in this document. ===== Including and Excluding Files ===== A host specifies it is interested in a file or files with an 'include' directive. The directive takes a shell pattern, so it can specify multiple files at a time. These are absolute paths as the file will look when installed. For example (note that the directives must start on the beginning of the line): include /etc/profile.d/* This would tell cvsman that the host is interested in all files in the root/etc/profile.d/ directory, to be installed in /etc/profile.d/. There is one problem with the above example if there were only an 'include' directive. If the host wants 9 of the 10 files in root/etc/profile.d/, the host cannot use the wildcard. The wildcard would pull in the 10th file as well. Instead, the host would have to specify all 9 files in separate include directives. This is solved by the 'exclude' directive. This directive lists a file pattern of files to ignore. So, to exclude the 10th file, the host might have the following in the list file: include /etc/profile.d/* exclude /etc/profile.d/db2.sh Every file in root/etc/profile.d/ will be installed *except* the file 'db2.sh'. ===== Executing Programs After File Updates ===== There is still one problem. If a host updates the configuration file for a daemon or service, how does that service know the file has changed? For this reason, the list file supports the 'execute' directive. The 'execute' directive takes a shell command as its argument. This command can be anything, so be careful (see the security issues section above). The 'execute' directives are edited in the order they appear in the list file but *after* all files have been installed. Say a host is managing the 'sendmail.cf' file in cvsman. The following list file will update the file and tell sendmail to reload it: include /etc/sendmail.cf execute /etc/init.d/sendmail reload The file 'root/etc/sendmail.cf' will be installed in '/etc/sendmail.cf', and then sendmail will be reloaded. Note that the 'execute' directive follows the 'include' directive for readability only. No matter the order, the file '/etc/sendmail.cf' will be instaled *before* the 'execute' directive is run. ===== The Configuration File ===== There is one other required file in the cvsman collection directory, though this file is often not actually kept in CVS. This file is called 'config' and sits at the root of the collection directory. It contains the configuration variables for cvsman. The syntax of the file is very simple. It is one variable per line, with the variables written as 'name:value'. Three variables are currently supported: securepath The PATH to run 'execute' directives under. If not specified, it defaults to "/usr/sbin:/usr/bin:/sbin:/bin". host The name of the host list file. This is the name of the file under the 'hosts' subdirectory to examine for this host's directives. This defaults to the output of /bin/hostname as stated above. CVS_RSH This sets the environment variable CVS_RSH to the value when cvsman is doing CVS updates, allowing the use of ssh and the like for CVS authentication. For an example, the following might be a configuration for a host that wishes to run with a path that includes /usr/local/sbin and uses the :ext: protocol for CVS to use ssh: securepath:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin CVS_RSH:/usr/bin/ssh ===== Executing cvsman ===== When cvsman runs, it only needs to know the collection directory. It can discover all the other things it needs to know from the config and list files. cvsman defaults to searching for the collection in '/var/lib/cvsman'. If there is only one collection to be managed on the system, the administrator can check out the collection to this directory and cvsman will happily use it. If there is more than one collection or if the administrator wishes to run the collection out of a different directory, the '-d' option tells cvsman where to find it: cvsman -d /mount/collections/collection1 cvsman also supports two other options. The '-v' option tells cvsman to be verbose about what it is doing. The '-n' option, like make and CVS, tells cvsman not to actually install or modify anything. ===== Conclusion ===== This should provide all the information needed to get cvsman working on any system.