一人だけで管理しているサーバの設定ファイルを更新するとき、皆さんはどのように管理しているだろうか。
私は以下のようにしていた。
例えば、httpd.confを2013/8/25に変更しようとするとき。

# vi httpd.conf
# cp -p httpd.conf httpd.conf.20130825

経験のある方はご存じだろうが、長い間これを続けると、ディレクトリが散らかって酷い事になる。

ではバージョン管理を導入すべきか?
でも、一人で管理しているサーバなのに、わざわざsubversionを入れる?それはちょっと。

というのが長らくの悩みであったのだが、実はrcsという簡便なリビジョン管理ツールがあることを知った。今さらではあるが。
しかし、これがまた実に快適であった。
快適すぎて、今ではどこのディレクトリでもRCSディレクトリ(後述)を掘ってしまうくらいになってしまった。

そんなRCSについて以下に記す。

RCSとは。

RCSとはRevision Control System
きわめて軽量単純なGNU製のリビジョン管理システムである。
一人で使う分には十分(いちおう、ロック機能はあるよ!)。
だいたいのUNIX系OSには最初から入っている。
FreeBSDはベースシステムに入っているので、インストール不要。これはポイント。
もちろんLinuxにも(Redhatの5にあることは確認)

コマンドの使い方を示す。FreeBSD環境下のもの。
Linux向けmanはこちら。
http://linuxjm.sourceforge.jp/html/GNU_rcs/man1/co.1.html

RCSのコマンド

使うコマンドはおおよそ以下のようなもの。
詳しくはman。

co - check out RCS revisions
ci - check in RCS revisions
rlog - print log messages and other information about RCS files
rcsdiff - compare RCS revisions

RCSへの登録

ためしに、/etc/rc.confを、RCSで管理してみる。
最初にやることはRCSに登録すること。
ci(check in)コマンドを使う。
ciにrc.confを渡してやるだけ。

初回は「ファイルの説明を入れろ」と聞いてくるので、“System Setting file"などと入れてみる。
ドット「.」を入れれば完了。

$ cd /etc
$ sudo ci rc.conf
Password:
rc.conf,v  <--  rc.conf
enter description, terminated with single '.' or end of file:
NOTE: This is NOT the log message!
>> System Setting File
>> .
initial revision: 1.1
done

最初のバージョンは1.1になる。

初回チェックインの注意

驚くことに、初めてチェックインするとファイルが消える。
代わりと言ってはなんだが、ファイル名末尾に「,v」と付いたファイルが現れる。

$ ls -l rc.conf
ls: rc.conf: No such file or directory
$ ls -l rc.conf*
-r--r--r--  1 root  wheel  353 Aug 25 12:50 rc.conf,v

RCSはそれぞれのファイルを、この「,v」ファイルで管理しているのである。
しかしrc.confが無くなられては困る。
そこでco(check out)コマンドにより、「,v」からrc.confを取り出す。

$ sudo co rc.conf
rc.conf,v  -->  rc.conf
revision 1.1
done
$ ls -l rc.conf*
-r--r--r--  1 root  wheel  156 Aug 25 12:55 rc.conf
-r--r--r--  1 root  wheel  353 Aug 25 12:50 rc.conf,v

並べてみると「,v」には管理情報が含まれているせいでサイズが少し増えている。

しかしちょっと待て。

「,v」が散らかる→RCSディレクトリで解決

新しいファイルをRCSに登録する都度、「,v」が増えていくのではたまらない。
しかし、そこはさすがに考えられていて、同じディレクトリにRCSというディレクトリがあれば、その下に「,v」を作ってくれる。
さきほど作ったrc.conf,vを消してから試してみる。

$ sudo rm rc.conf,v
$ sudo mkdir RCS
$ sudo ci ./rc.conf
./RCS/rc.conf,v  <--  ./rc.conf
(略)
initial revision: 1.1
done
$ ls ./RCS
rc.conf,v

と、ご覧の通り/etc/RCSの下に「,v」が作られる。
こうしておけば「,v」ファイルが散らかって困ることはない。
忘れずにチェックアウト。
RCS/rc.conf,vから取り出されていることが分かる。

$ sudo co rc.conf
RCS/rc.conf,v  -->  rc.conf
revision 1.1
done

ファイルの更新(チェックアウト)

今度はファイルを更新してみる。
修正したファイルをチェックイン(ci)するだけなのだが、それに先立つチェックアウト(co)の時に考慮すべきことがある。
それはファイルのロック。

単にcoしただけのrc.confのパーミッションを見てみると、読み取り専用(444)になってしまっている(本来は644)。

$ ls -l rc.conf
-r--r--r--  1 root  wheel  156 Aug 25 12:55 rc.conf

なにも無計画にしているわけではない。
「RCSで管理しているファイルを迂闊に書き換えないように」というRCS師匠のありがたい配慮である。
これを避けるには、ファイルのロックをしてからチェックアウトをすればよい。
coの際に-lオプション(lock)を与えるだけ。

$ sudo co -l rc.conf
Password:
RCS/rc.conf,v  -->  rc.conf
revision 1.1 (locked)
done
$ ls -l ./rc.conf
-rw-r--r--  1 root  wheel  156 Aug 25 12:56 ./rc.conf

(locked)という表示が増えている。
また、パーミッションも644になっている。
これでファイル変更の準備ができた。

ファイルの更新(チェックイン)

修正が済んだらチェックイン。
チェックアウトの時と同じように、ロックの考慮が必要。
端的に言えばロックを解除する。
ciの際に-uオプション(unlock)を与える。

$ sudo ci -u ./rc.conf
./RCS/rc.conf,v  <--  ./rc.conf
new revision: 1.2; previous revision: 1.1
enter log message, terminated with single '.' or end of file:
>> disable sendmail on boot
>> .
done
$

log message、つまり修正内容の記入が求められるので書き入れたのちドット「.」で終了。
そしてロック解除したために、再びファイルのバーミッションが444に戻っている。

$ ls -l ./rc.conf
-r--r--r--  1 root  wheel  283 Aug 25 19:29 ./rc.conf

履歴の確認

RCSで管理しているファイルに対しrlogを発行すると履歴が表示される。

$ rlog ./rc.conf

RCS file: ./RCS/rc.conf,v
Working file: ./rc.conf
head: 1.2
branch:
locks: strict
access list:
symbolic names:
keyword substitution: kv
total revisions: 2;     selected revisions: 2
description:
System configuration file
----------------------------
revision 1.2
date: 2013/08/25 10:29:49;  author: root;  state: Exp;  lines: +6 -0
disable sendmail on boot
----------------------------
revision 1.1
date: 2013/08/25 04:07:09;  author: root;  state: Exp;
Initial revision
----------------------------

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

revisoin 1.2では9行追加されていることを示している。
デフォルトではタイムスタンプがUTC。
これは分かりにくいので、ローカルタイムで表示する。
そのためには-zLTを与える。

$ rlog -zLT ./rc.conf

RCS file: ./RCS/rc.conf,v
Working file: ./rc.conf
head: 1.2
branch:
locks: strict
access list:
symbolic names:
keyword substitution: kv
total revisions: 2;     selected revisions: 2
description:
System setting file
----------------------------
revision 1.2
date: 2013-08-25 19:29:49+09;  author: root;  state: Exp;  lines: +6 -0
disable sendmail on boot
----------------------------
revision 1.1
date: 2013-08-25 13:07:09+09;  author: root;  state: Exp;
Initial revision
----------------------------
=============================================================================

差分の確認

二つのバージョン間の差分を確認するには、rcsdiffを使う。

$ rcsdiff -r1.1 -r1.2 ./rc.conf
===================================================================
RCS file: ./RCS/rc.conf,v
retrieving revision 1.1
retrieving revision 1.2
diff -r1.1 -r1.2
6a7,12
>
> # kill sendmail
> sendmail_enable="NO"
> sendmail_submit_enable="NO"
> sendmail_outbound_enable="NO"
> sendmail_msp_queue_enable="NO"

特定のバージョンを取り出す。

coに-rオプションでバージョンナンバを指定する。
1.1を取り出したいなら-r1.1。

$ sudo co -r1.1 rc.conf
RCS/rc.conf,v  -->  rc.conf
revision 1.1
done

しかしこれでは手元にあるファイルが上書きされる。
都合が悪い場合には-pオプションを使う。
-pオプションは結果を標準出力に表示させるもの。

$ sudo co -p -r1.1 rc.conf > /tmp/rc.conf
RCS/rc.conf,v  -->  standard output
revision 1.1

ident文字列の埋め込み

ファイルを特定しやすくするための仕組みがident文字列。
ある文字列を埋め込んでおくと、RCSが自動的に置換・更新をしてくれる。
実際に見てもらった方が早い。

rc.confに埋め込んでみる。
ident文字列には何種類かあるが、ここでは「$Id$」を使う。

しかし、$Id$といきなり書いてはいけない。コメントとして埋め込もう。
すなわち、#のあとに続ける。
(同様に、たとえばxmlなら”<!-“と”->“の間、というようにフォーマットに合わせたコメント文に埋め込むとよい)

rc.confの例

#$Id$
hostname="hogehoge"
keymap="jp.106.kbd"
ifconfig_em0="DHCP"
sshd_enable="YES"

これをチェックインすると、自動的に以下のように変換してくれる。

$ head -1 /etc/rc.conf
#$Id: rc.conf,v 1.2 2013/08/24 10:52:27 root Exp $

これは便利である。
実はこの文字列、よく見かけたのだが、やっとその秘密が分かった。

しかしタイムスタンプはUTCである。
チェックインのときに-zLTと指定すればローカルタイムで置換してくれる。

$ sudo ci -u -zLT ./rc.conf
./RCS/rc.conf,v  <--  ./rc.conf
new revision: 1.4; previous revision: 1.3
enter log message, terminated with single '.' or end of file:
>> update timestamp from UTC to LT
>> .
done
$ head -1 ./rc.conf
#$Id: rc.conf,v 1.4 2013-08-24 20:18:36+09 root Exp $

ident文字列のちょっとしたノウハウ

ident文字列の場所はどこでもよい。
しかし、1行目か2行目がよいでしょう。

ident文字列はファイルのIDとして埋め込んでいる。
IDの場所がバージョンごとに違うと、のちのち差分を確認するときに見にくくなってしまうから。