This paper was originally published in the
Proceedings for The Third World Conference on System
Administration, Networking and Security, Washington DC,
``Make'' as a UNIX System Administration Tool
IntroductionThe UNIX make(1) program is traditionally thought about as a programmer's development tool. By design, its purpose is to build file(s) from other files, through a set of specified actions (for example, building an executable by compiling and linking a number of source files). The make program decides when a compile (or set of compiles) is necessary, based on the dependencies between and among source and object files.
This basic functionality also lets make be a useful tool to perform certain routine UNIX system administration tasks. One classic example of this usage is the Makefile used to maintain NIS (Network Information Service \- formerly known as Yellow Pages) maps on a NIS server. In the case of NIS, as well as many other similar cases, the make program can be executed on an hourly basis from cron , without wasting much CPU time, because make , with its dependency rules, is able to decide whether any real work need to take place.
This paper will show several other practical application where make and file dependency rules are part of the solution.
Saving important system files
A common problem encountered in UNIX administration is diagnosing the problem after one or more system files such as /etc/passwd, /etc/group or /etc/hosts has been modified and the system starts to display some kind of wrong behavior. At many sites, this is handled by logging everybody changes a file, using a version control system, such as SCCS (Source Code Control System) or RCS (Revision Control System). If this is done for each change, it will leave a clear audit trail of when, why, and by whom each change has been performed. However, system administrators are only human, and even with the best intentions, they might not always remember to check in the changes.
Therefore, if a system starts misbehaving, it might be necessary to go back through the backups for that particular part of the system, which can both be time consuming and inconvenient if the system does not function correctly. It is therefore desirable to automate tracking of all changes made to the systems configuration, while preserving the previous configuration in an manner which is reasonably easy to access.
The makefile shown in Appendix A is one such possible solution to this problem. It is intended to be executed from cron at a regular interval (I use one hour). It will copy any system file which has been modified to a separate location and then (optionally) check the file into a source control system.
Most systems have either SCCS or RCS available, but not always both. In order to enable the same makefile to be used on every system in a heterogeneous environment, it has been written so the decision of what source control system to use is made at runtime. If directory directory named ``RCS'' exists, the RCS system will be used, and if the a directory named ``SCCS'' exists, the SCCS system will be used. If neither of these directories exists, files will still be copied, but no version control system will be invoked.
This system will, of course, not tell who made any given changes, and neither will it have any information as to why a change has been done. It should therefore not necessarily be seen as a replacement for a procedure where the system administrators track such information, whether with a version control system, or by any other means. It does, however, provide an easy method for automatically tracking changes to important system files; it also provides a faster and more convenient way to restore old versions of a given file.
Assist in named configuration file maintenance
Another place where make(1) can participate in automating some of the work a system administrator has to do is in the maintenance of the configuration files for the domain name server ( named(8) ). Whenever a configuration file for the name server is modified, its sequence number must be incremented. If the person making the changes forgets to do so, then the change will not propagate properly to the other name servers.
The makefile in Appendix B is primarily used as a tool to handle the update of the serial numbers. However, it also has a number of other entries, which simplify other common tasks, mostly by reducing the amount of typing which is necessary. One example is whenever the name server is restarted with this make script, any messages it sends to syslogd will be shown on the screen. This minimizes the risk of an system administrator making a change and failing to notice any problems arising from the change.
With this makefile, the named data files, which are updated by the system administrator, are kept in /etc/named and all begin with the prefix ``db.'' (e.g. db.127.0.0). Whenever the system administrator checks the file out for update, RCS will automatically update the the version number. After the file has been updated, a call of make (without any argument) will check the file in under RCS (and the caller be prompted for comments on the change) and then copy the file to /etc/namedb/dbdir , while removing the preceding ``$Revision:'' from the RCS revision number.
One word of caution: the domain name server has its own special interpretation of the dot in the serial number. When the name server loads the data files, it will substitute any dots in the sequence numbers with ``000''. Therefore ``1.1'' becomes ``10001'' and ``1.11'' becomes ``100011''. This is not a problem, as long as the major revision number is unchanged. However, if the current version number is 1.4593, and the major release number is bumped, so the new release number becomes 2.1, then, according to the name server, the old version number where ``10004593'', while the new number is ``20001'', and therefore considered very old and out of date. As an alternate method, the sequence number can be based on the date. It requires a little more elaborate edition of the RCS provided date field, but is otherwise little different from the current strategy.
Maintain local and network wide files"
There are a number of files on a UNIX system which simultaneously contain data specific to the local system and data of a more generic nature which applies to a large number of systems. Because of this split nature, it is not possible to maintain the file from a central location and distribute it as appropriate. The following examples show three different ways of solving this problem.
Maintain network wide content of /etc/motd
While the common usage of X on workstation and X terminals has caused most users to stay logged in for days at a time, it has greatly diminished the usage of putting system related information in the message of the day file ( /etc/motd ). However, it is still good practice to notify users of recent or upcoming changes to the system. In order to make this manageable at all, it will need to be possible to centralize the maintenance to a large degree.
The small makefile in Appendix C expects the information in the motd file to be kept in three files. The first, motd.loc , contains information which is only relevant to the local system. The motd.net contains information which is relevant to multiple systems, and therefore is maintained centrally and distributed in an adequate fashion, with a tool such as rdist(1) fdist , or track . Finally, information about the kernel (BSD style) is kept in the file motd.ker . If make is then called on an hourly basis, then it will rebuild the official motd file whenever any of the three files mentioned above is modified.
Maintain network-wide content of /etc/group
The makefile discussed above is small and simple. However, if for some reason the concatenation fails, it is possible that the resulting file will be left empty. This may be acceptable for a file, such as /etc/motd , whose purpose is purely of informative nature. However, if the file contains data which is used by the system in one form or another, an accidental truncation is not acceptable. The makefile in Appendix D rebuilds the /etc/group file in a similar manner to the makefile for /etc/motd in Appendix C, however, great care has been taken in this implementation, to ensure that if any step of the build process fails, then the original /etc/group file is left in place without any changes.
This example's technique uses the the UNIX ln(1) command to implement a simple file locking. Traditionally, if a file is attempted to be linked to an already existing file, then the link program would fail and return an appropriate error code. However, in recent years, a number of UNIX system have been shipped where this command is severely broken and just overwrites the target file. The makefile in this example should not be installed on such systems, unless either the ln(1) command has been fixed or an alternative method of file locking implemented.
The file creation is performed in three steps:
Maintain network wide crontab files
Here's how to Maintain crontab for various system users (such as "root" "uucp", "usenet", "adm", etc). For each user, there will be a network-wide and an optional local component of the crontab file. This method is based on a System V style cron daemon, where each user has its own crontab file. There is no reason the principles discussed here could not be applied to a BSD style crontab file.
AcknowledgmentsI thank Rob Kolstad for proofreading this paper.