Skip to content

Latest commit

 

History

History
1022 lines (920 loc) · 48.8 KB

200404-12.md

File metadata and controls

1022 lines (920 loc) · 48.8 KB

Truth of the Legend -- UNIX 考古学 第12回

Second Berkeley Software Distribution

リード文

BSD Unix の存在が広く一般に知られるようになったのは 1983 年の 4.2BSD の発表前後からです。そのためか BSD Unix が有する 多くの特徴は全て 4.2BSD をルーツと理解しがちなのですが、 実際には 4.2BSD 以前より BSD Unix は存在していました。今回から 数回に渡り、Second Berkeley Software Distribution を体験して いただきながら、BSD Unix のルーツを紹介していきたいと思います。


Bill Joyの功績

今回も Bill Joy の話題から始めましょう。かつて私が BSD Unix を 使い始めたころ、1つの素朴な疑問を抱いていました。 「何故、Bill Joy は Unix の英雄なのか?」という疑問です。 当時 Bill Joy という名前は BSD Unix と対で語られることが大変多く、 BSD Unix は Bill Joy が一人で作ったかのように錯覚するくらいでした。 が、実際の 4.3BSD に付属する論文やドキュメントを見ると、 多くの場合、そこには他の開発者の名前が綴られています。 もちろん Bill Joy の名前も多く見かけるのですが、 「彼の名前だけ」というものは大変稀だったように記憶しています。 「一体、Bill Joy は何を作って英雄になったんだろうか?」 当時の私にとってこれは大いなる疑問でした。

もちろん DEC の VAX-11 で動作する 3BSD 以降の BSD Unix の開発においても、 Bill Joy は多大なる貢献をしています。しかし、その努力の大部分は DARPA の資金を得て巨大になってしまった開発プロジェクトを運営するための役割、 いわゆるディレクタとしての仕事であったように私は推測しています。 一般的に、どのようなプロジェクトでもディレクタの果たしている役割や その仕事は具体的な成果として大変見えにくいもなりがちです。 Bill Joy の場合もそれは同じで 3BSD 以降の BSD Unix の中に Bill Joy の 成果の具体的な痕跡を見出すのは難しいものでしょう。実際、1980 年代初頭の BSD 開発プロジェクトは、大学の研究開発プロジェクトとしては異例なぐらい 大規模なプロジェクトになっていました。このような多くの人間が関わる 巨大プロジェクトにおいて、事実上のディレクタとして周囲からの認知を 得るためには際立った実績も必要です。結果的に Bill Joy がそのような 役割を果たせたのは、周囲が彼の実績を十分認知していた。つまり Bill Joy は これらのシステムを開発する以前から、既に「Unix の英雄」だったと思われます。 したがって、彼を Unix の英雄に押し上げたのは 1BSD と 2BSD であったと 理解するべきだと私は考えています。 BSD Unix を技術的成果という視点で見た場合、 着目されるのは 4BSD 以降ということになるのでしょうが、 それよりも幾分社会科学的視点にずらした場合、 つまり考古学的視点で見ると 2BSD は BSD Unix を理解する上での 興味深い対象の1つであることは明らかです。

2BSD が発表されたのは 1978 年初夏あたりですが、この 1978 年は UCB の Unix コミュニティーに取って節目の年であったといえるでしょう。 1975 年の Ken Thompson の来訪以来続いてきた Unix システムに対する 改善努力が 2BSD という形で結実したこと。そしてこの年の新製品であった DEC の VAX へのハードウェアプラットホームを移行する動き。1978 年は この二つの異なる流れが同時に並行して存在し、交錯していた時期にあたります。 2BSD は UCB の Unix コミュニティーにとって、新たなステップアップのための 重要な踏み台の役割を果たしたように私は考えています。そして、 その内容から後の BSD Unix を形作る原始の姿を見て取ることができます。 世の BSD Unix フリークの諸君! BSD を語るなら 2BSD も抑えておいた ほうがよいですよ! ここには「Unix の英雄」である Bill Joy の痕跡が 目一杯詰まっていますから。

2BSD の内訳

2BSD のオリジナルディストリビューションも The Unix Heritage Society (http://www.tuhs.org/) の Unix Archive から入手することができます。

2BSD は 1BSD と同様に BTL が開発したオリジナル Unix に対する追加コマンドの セットとしてまとめられています。1BSD が UCB で開発されたコマンドを 集めたアーカイブテープのような体裁であったのに対し、2BSD では Version 6 やその派生システム、あるいは Version 7 に対応できるようソースコードは 整理されていました。今日で言うところのリリーシングを意識した体裁になった というべきでしょうか。

しかし、実際の 2BSD の開発は Version 6 Unix をベースにしたシステムで 行われていたようです。第10回でも紹介したように、この当時の UCB の Unix 環境は 1975 年に Ken Thompson が持ち込んだ Version 6 Unix + 50 Bugs が ベースになっていたと推測されます。このシステムに対し、その後に BTL から 非公式に配布された様々な追加ツール、例えば PCC や make などが その都度インストールされた結果、システムは Version 6 と Version 7 の間の 中間バージョンのような内容に発展していたと推測されます。これは 2BSD に 収録されている READ_ME の中に「このプログラムは新しい C コンパイラでないと コンパイルできません」といった注釈からもうかがい知ることができます。

更に UCB の Unix 環境について説明しなければならないことがもう1つあります。 UCB において Version 7 Unix と呼ばれたシステムは実際には VAX 上で動作する UNIX/32V ではないかと推測されることです。というのも、2BSD に収録されている コマンドのうちの幾つかは Version 7 用の設定をしても PDP-11 の上で動作する オリジナルの Version 7 Unix ではコンパイルに失敗するからです。ソースコードを 確認してみたところ、Version 7 用の設定が PDP-11 よりも大きなリソースを確保 するように見受けられました。

文献等での確認ができないため、これはあくまでも状況証拠でしかないのですが、 UNIX/32V は 1978 年 4 月の段階で既に基本機能が動作するようになっていました。 UCB が仮想記憶の開発/実装を目的として UNIX/32V のライセンスを取得したのは 1978 年 11 月のことですが、実際にはその数ヶ月前から非公式な形で UNIX/32V を 入手していたのではないかと私は推測しています。 つまり「UCB での Version 6 から Version 7 への移行は PDP-11 から VAX-11 への 移行と同時に行われたのではないか?」と私は考えています。既に様々な追加や 拡張を施してしまっている UCB の Version 6 はオリジナルの Version 6 とは 全く違ったものになっており、この状態は特に他の Unix を稼動させているサイト とのコードの整合性という観点で大きな問題になっていたと思われます。無保証の システムを維持運営していく上での唯一の命綱は他のユーザーとの連携ですから、 これはかなり致命的な状態であり放置しておけなかったわけです。とはいえ、 多くのユーザーに自分たちが使っているシステム、自分たちで作り上げたコマンドや ライブラリが搭載されているシステムを放棄させるのは大変難しい。 そこで「より高速で、多くのリソースを持つ」と思われる VAX-11 でユーザーを 吊り上げて、無理やりシステムを移行してしまう。「VAX が使いたければ我慢しろ」 といったセリフが飛び交ったのではないでしょうか。 まぁライセンスに対する意識も今日よりルーズであり、 いわゆるリリースエンジニアリングという概念も存在しなかった当時のことですから、 確かな情報は残されていません。その真相を知るためには 正しく考古学的アプローチが必要だということになります。

インストールの準備

さて 2BSD を体験していただくためにはベースシステムが必要になりますが、 今回は本連載の第7回、第8回、第9回でご紹介した Version 7 Unix を 利用することにします。2BSD のインストールには make を使用しますので、 システムの時計が正しく設定される必要があります。そこで第9回で紹介した Y2K対応済みのシステムを用意しました。(付属CD-ROM xxxxxx) 今回はこのシステムをベースに 2BSD をインストールしますが、 このシステムの作り方については第9回の記事を参考にしてください。

2BSD のインストールでは、これまでの説明に幾つか加えなければならない 事柄があります。その1つは SIMH を PDP-11/70 として起動する方法です。 これまでご紹介した手順は SIMH を PDP-11/45 相当のマシンとして起動する ものでしたが、UCB ではこれよりリソースの大きい PDP-11/70 を使用していました。 今回はこの PDP-11/70 に相当するマシンとして SIMH を起動する必要があります。 これには SIMH の起動時のパラメータを幾つか変更する必要があります。

実行例1 PDP-11/70 を想定した起動

$ pdp11

PDP-11 simulator V3.0-2
sim> set cpu URH70
sim> set cpu 2M
Disabling XQ
sim> set rp0 RP06
sim> att rp0 RP0.DSK
sim> set rp1 RP06
sim> att rp1 RP1.DSK
RP: creating new file
Create bad block table on last track? [N]
sim> att tm0 2bsd.tar.tap
sim> boot rp0
boot
Boot
: hp(0,0)unix
mem = 2020544
# DATE 200402051822
THU FEB  5 18:22:00 JST 2004
# <CNTL-D>
RESTRICTED RIGHTS: USE, DUPLICATION, OR DISCLOSURE
IS SUBJECT TO RESTRICTIONS STATED IN YOUR CONTRACT WITH
WESTERN ELECTRIC COMPANY, INC.
WED DEC 31 20:12:48 EST 1969

login: root
Password:
You have mail.
#

実行例1をご覧ください。ここではCPU に対してこれまでとは違う設定を 行っています。まず "set cpu URH70" は PDP-11/70 の MASSBUS ADAPTER である RH70 のエミュレーションを有効にすることを意味しています。次の "set cpu 2M" はメインメモリを 2MB まで広げることを意味しています。この2つの設定が SIMH を PDP-11/70 に相当するマシンとして起動するポイントです。

さらにこの実行例では2番目のディスクとテープに関する設定も行っています。 テープに関して 2BSD の tar アーカイブ(付属CD-ROM xxxxxx)を指定しています。 2番目のディスクはこの 2BSD の tar アーカイブの内容を展開するための領域として、 /mnt ファイルシステムを使用する目的で設定しました。 この2番目のディスクを /mnt ファイルシステムとして Unix からマウントするにはファイルシステムを作成する必要があります。

実行例2 /mnt ファイルシステムの作成

# /etc/mknod /dev/rp7 b 6 15
# /etc/mknod /dev/rrp7 c 14 15
# /etc/mkfs /dev/rp7 322278
isize = 65496
m/n = 3 500
# mkdir /mnt
# /etc/mount /dev/rp7 /mnt
#

実行例2をご覧ください。これは2番目のディスクにファイルシステムを作成し、 /mnt にマウントするまでを示しています。mknod コマンドで該当するデバイス ファイルを作成し、mkfs コマンドでファイルシステムを作成、 マウントポイントとなる /mnt ディレクトリを作成して、 ディスクをマウントするごく一般的な手順です。 これで次回からは最後の mount コマンドを実行するだけで /mnt ファイルシステムを利用することができます。 今回の作業では一時的に使用するだけですが、 ファイルシステムを常時使用したければ 最後の mount コマンドを /etc/rc に記述しておくと良いでしょう。 ここでご紹介したセカンドディスクに関わる設定について、 ★コラム1に更に詳しい話を解説しておきます。

2BSD のインストール

それでは 2BSD のインストールを始めましょう。 2BSD にはインストール手順を解説したドキュメントが付属します。 今回は原則としてこのドキュメント(★注1)の手順に従って作業を進めます。

最初の "Extracting the tape" は無視していただいて結構です。 The Unix Heritage Society の Unix Archive に保管されている ディストリビューションはオリジナルテープを展開して tar アーカイブ としてまとめ直したものですので、この手順は不要になります。 そのかわり tar アーカイブを先ほど作成した /mnt ファイルシステムに 展開します。

実行例3 2BSDの展開

# cd /mnt
# cat /dev/rmt0 | tar xvf -
tar: bin/ - cannot create
x bin/csh, 40412 bytes, 79 tape blocks
tar: bin/etc/ - cannot create
x bin/etc/htmp, 0 bytes, 0 tape blocks
x bin/etc/install, 81 bytes, 1 tape blocks
x bin/etc/termcap, 5650 bytes, 12 tape blocks
x bin/etc/ttytype, 0 bytes, 0 tape blocks
x bin/install, 135 bytes, 1 tape blocks
tar: bin/lib/ - cannot create
x bin/lib/ex2.0preserve, 10738 bytes, 21 tape blocks

    ....

x upgrade/src/makefile, 1155 bytes, 3 tape blocks
x upgrade/src/mkstr.c, 5074 bytes, 10 tape blocks
x upgrade/src/msgs.c, 5139 bytes, 11 tape blocks
x upgrade/src/printenv.c, 608 bytes, 2 tape blocks
x upgrade/src/READ_ME, 129 bytes, 1 tape blocks
x upgrade/src/reset.c, 328 bytes, 1 tape blocks
x upgrade/src/setenv.c, 876 bytes, 2 tape blocks
x upgrade/src/strings.c, 2550 bytes, 5 tape blocks
x upgrade/src/tset.c, 14725 bytes, 29 tape blocks
x upgrade/src/tset.del.h, 1119 bytes, 3 tape blocks
x upgrade/src/whereis.c, 3851 bytes, 8 tape blocks
#

実行例3を御覧ください。これは tar コマンドを使った ごく普通のテープからファイルを展開する手順です。実行例の中で "tar: xxx/ - cannot create" なるエラーメッセージが多数表示されますが、 これは Version 7 の tar コマンドが現在の tar アーカイブに含まれる ディレクトリに関する情報を認識できない事が原因です。 しかし、ファイルそのものは正しく展開できますので、 このエラーメッセージは無視してもらって構いません。

次の "Installation Preparation" は Version 7/Version 6/Other Version 6 のうち、いずれの Unix にインストールかを決めるよう指示されています。 Other Version 6 とは PWD/UNIX (後述 )などオリジナルの Version 6 Unix から 派生したシステムを意味します。原則として Version 7 を選択すればよいのですが、 前述の理由によりうまくコンパイルできない場合がありますので、 その場合は必要に応じてコンパイルできる方法を都度説明します。

"New files to be added" は 2BSD で追加されるファイル/ディレクトリの説明です。

そして "Installation procedure" で 2BSD のインストール手順が解説されています。 示されている手順に沿って作業を進めていきましょう。

実行例4 インストールディレクトリの作成

# cd /mnt/
# sh -x setup
+ mkdir /usr/ucb
+ mkdir /usr/msgs
+ cat /dev/null
+ mkdir /usr/include
mkdir: cannot make directory /usr/include
+ mkdir /usr/include/retrofit
+ mkdir /usr/lib/me
+ mkdir /usr/lib/tabset
+ mkdir /usr/msgs
mkdir: cannot make directory /usr/msgs
+ mkdir /usr/preserve
+ mkdir /usr/ucb
mkdir: cannot make directory /usr/ucb
#

実行例4を御覧ください。これは "Installation procedure" の 1. の 手順を実行した例です。2BSD に収録されているコマンドは原則として /usr/ucb にインストールされます。また、各コマンドが使用する ディレクトリも併せて作成されます。

実行例5 関連ヘッダーファイルのインストール

# cd upgrade/include
# sh -x install
+ mkdir /usr/include
mkdir: cannot make directory /usr/include
+ mkdir /usr/include/retrofit /usr/include/retrofit/sys
mkdir: cannot make directory /usr/include/retrofit
+ cp ctype.h /usr/include/retrofit/ctype.h
+ cp errno.h /usr/include/retrofit/errno.h
+ cp pwd.h /usr/include/retrofit/pwd.h
+ cp retrofit.h /usr/include/retrofit/retrofit.h
+ cp setjmp.h /usr/include/retrofit/setjmp.h
+ cp sgtty.h /usr/include/retrofit/sgtty.h
+ cp signal.h /usr/include/retrofit/signal.h
+ cp sys/dir.h /usr/include/retrofit/sys/dir.h
+ cp sys/stat.h /usr/include/retrofit/sys/stat.h
+ cp sys/types.h /usr/include/retrofit/sys/types.h
# rm /usr/include/retrofit/retrofit.h
# touch /usr/include/retrofit/retrofit.h
#

実行例5は "Installation procedure" の 2. の手順を実行した例です。 この手順は本来 Version 6 Unix のためのものなのですが、今回の作業でも これらのヘッダーファイルを必要とする場合がありますのでインストールを しておきます。なお /usr/include/retrofit/retrofit.h だけは 内容が空のダミーファイルに差し替えておく必要があります。注意してください。

次に "Installation procedure" の 3. 4. の手順は飛ばし、5. の Version 7 に 対する手順を実行します。

実行例6 termlib のインストール

# cd ../../src/termlib
# make install
cc -O -c termcap.c
cc -O -c tgoto.c
cc -O -c tputs.c
ar cr termlib.a termcap.o tgoto.o tputs.o
cp termlib.a /usr/lib/libtermlib.a
cp termcap /etc
chdir tabset ; install
mkdir: cannot make directory /usr/lib/tabset
#

実行例6は 5-a の termlib をインストールを実行したものです。 ここで "mkdir: cannot make directory /usr/lib/tabset" なるエラーが 出力されますが、これは無視して構いません。この当時の Unix では 究極の問題解決法として「見なかったことにする」という手も良く使われました。

実行例7 src ディレクトリのコンパイル/インストール

# cd /mnt/src
# touch /usr/include/retrofit.h
# cp clock.c clock.c-
# ed clock.c

    ....

# diff -e clock.c- clock.c
4a
#include <setjmp.h>
jmp_buf reslab;

#define setexit()       setjmp(reslab)
#define reset()         longjmp(reslab)
.
# cp finger.c finger.c-
# ed finger.c

    ....

# diff -e finger.c- finger.c
74,75c
        short   loggedin;       /* flag for being logged in */
        short   writeable;      /* flag for tty being writeable */
.
55c

.
50a
 */
.
47,48d
# cp ../upgrade/libretro/typeof.c .
# cp makefile makefile-
# ed makefile

    ....

# diff -e makefile- makefile
189c
        ${CC} ${CFLAGS} tset.c typeof.c ${LIBS}
.
# make
cc -O apropos.c -ltermlib -s
cp a.out /usr/ucb/apropos
cp astags.sh /usr/ucb/astags
cc -O chessclock.c -ltermlib -s
cp a.out /usr/ucb/chessclock
cc -O ckdir.c -ltermlib -s
cp a.out /usr/ucb/ckdir
cc -O clear.c -ltermlib -s
cp a.out /usr/ucb/clear
cc -O clock.c -ltermlib -s
cp a.out /usr/ucb/clock
cc -O cr3.c -ltermlib -s
cp a.out /usr/ucb/cr3
cp ctags.sh /usr/ucb/ctags
cp cxref.sh /usr/ucb/cxref
cc -O daytime.c -ltermlib -s
cp a.out /usr/ucb/daytime
cc -O diffdir.c -ltermlib -s
cp a.out /usr/ucb/diffdir
cc -O double.c -ltermlib -s
cp a.out /usr/ucb/double
cc -O dribble.c -ltermlib -s
cp a.out /usr/ucb/dribble
cc -O expand.c -ltermlib -s
cp a.out /usr/ucb/expand
cc -O finger.c -ltermlib -s
cp a.out /usr/ucb/finger
cc -O fleece.c -ltermlib -s
cp a.out /usr/ucb/fleece
cc -O fold.c -ltermlib -s
cp a.out /usr/ucb/fold
cc -O funny.c -ltermlib -s
cp a.out /usr/ucb/funny
cc -O getNAME.c -ltermlib -s
cp a.out /usr/ucb/getNAME
cc -O gets.c -ltermlib -s
cp a.out /usr/ucb/gets
cc -O grep.c -ltermlib -s
cp a.out /usr/ucb/grep
cc -O head.c -ltermlib -s
cp a.out /usr/ucb/head
cc -O iul.c -ltermlib -s
cp a.out /usr/ucb/iul
cc -O lock.c -ltermlib -s
cp a.out /usr/ucb/lock
cp makewhatis.sh /usr/ucb/makewhatis
cc -O man.c -ltermlib -s
cp a.out /usr/ucb/man
cc -O num.c -ltermlib -s
cp a.out /usr/ucb/num
cp print.sh /usr/ucb/print
cc -O see.c -ltermlib -s
cp a.out /usr/ucb/see
cc -O soelim.c -ltermlib -s
cp a.out /usr/ucb/soelim
cc -O ssp.c -ltermlib -s
cp a.out /usr/ucb/ssp
cc -O tod.c -ltermlib -s
cp a.out /usr/ucb/tod
cc -O tra.c -ltermlib -s
cp a.out /usr/ucb/tra
cc -O untmp.c -ltermlib -s
cp a.out /usr/ucb/untmp
cp w.sh /usr/ucb/w
cc -O whatis.c -ltermlib -s
cp a.out /usr/ucb/whatis
cc -O whoami.c -ltermlib -s
cp a.out /usr/ucb/whoami
cc -O xstr.c -ltermlib -s
cp a.out /usr/ucb/xstr
cc -O from.c -ltermlib -s
cp a.out /usr/ucb/from
cc -O last.c -ltermlib -s
cp a.out /usr/ucb/last
cc -O ls.c -ltermlib -s
cp a.out /usr/ucb/ls
cc -O mkstr.c -ltermlib -s
cp a.out /usr/ucb/mkstr
cc -O msgs.c -ltermlib -s
cp a.out /usr/ucb/msgs
cc -O printenv.c -ltermlib -s
cp a.out /usr/ucb/printenv
cc -O reset.c -ltermlib -s
cp a.out /usr/ucb/reset
cc -O saveboottime.c -ltermlib -s
cp a.out /usr/ucb/saveboottime
cc -O strings.c -ltermlib -s
cp a.out /usr/ucb/strings
cc -O tset.c typeof.c -ltermlib -s
tset.c:
typeof.c:
cp a.out /usr/ucb/tset
# rm /usr/ucb/ls
#

実行例7は 5-b の src ディレクトリの下にあるコマンドのインストールを 実行しています。ここでは make を実行する前に手直しが必要です。 まずソースの clock.c, finger.c を修正します。"diff -e" で 修正のための ed のコマンドを掲載しましたので、この通りに修正してください。 それから ../upgrade/libretro/typeof.c をカレントディレクトリにコピーします。 さらにこの typeof.c をリンクするように makefile も修正します。

これで事前の手直しは終りです。make コマンドを実行しましょう。 このディレクトリでコンパイルされたコマンドは全て /usr/ucb に インストールされます。ここでインストールされるコマンドの中には BSD 版 ls も含まれますが、ターミナル設定の問題から SIMH の コンソールでは文字化けが発生する事を確認しています。 ターミナル設定については次号で触れる予定なので、 ここではインストールされた /usr/ucb/ls を削除しておいてください。

インストールが終ったら /usr/ucb の中をのぞいてみましょう。 オールドユーザーの皆さんにとっては懐かしい名前が見つかるのでは ないでしょうか。これらは BSD Unix 固有のコマンドで、この中には 現在の Unix でもサポートされているコマンドもあれば、現在では もう使われなくなったコマンドもあります。ですが、これらのコマンドは この後の csh や ex(vi) のインストールの際、必要になる場合があるので 取り敢えず全部インストールしておいてください。

C Shell の起源

さて、ここで一息入れて 2BSD の著名な成果の1つである C Shell に関連した話、 C Shell の起源についてご紹介しましょう。

C Shell は Bourne Shell と共に Unix の代表的なシェルとして 広く良く知られています。一般的な Unix の入門書ではその導入部で 必ずと言っていいほどこの2つのシェルが紹介されますので、 これらがシェルの元祖と理解しがちなのですが、実際に C Shell が 世に出たのは 2BSD のリリースからです。1971 年の Version 1 Unix の 段階で既にシェルは存在していましたので、Unix の歴史という観点では、 C Shell の出現はかなり後の出来事だといえるでしょう。実際 1970年代には シェルというプログラムは模索の段階にありました。私が調べた限り Bourne Shell と C Shell は「初期のシェルに関する議論を集約した成果」と理解するのが 正しいようです。

Thompson Shell

シェルの元祖はいうまでもなく Ken Thompson 自身の手で書かれましたもので、 Unix に関する最初の論文である "The UNIX Time-Sharing System" (http://cm.bell-labs.com/cm/cs/who/dmr/cacm.html) の中でその詳細が紹介されています。 論文を読んでいただくと良くわかるのですが、 このシェルは本当にシェルとしての基本機能しか サポートしていないもので、例えば今日のビルドイン コマンドなどは全くサポートされていません。

この Thompson Shell は 1973 年の Version 3 あるいは Version 4 Unix までは 標準の(そして唯一の)シェルでした。また1970年代に起こったシェルに関する 議論では「実用性を向上させるためには、この Thompson Shell にどのような 機能拡張するべきか?」というテーマが出発点であったと思われます。 以降、様々人が様々な方法でシェルの拡張に取り組みました。

PWB Shell/Mashey Shell

Thompson Shell に対する機能拡張の著名な試みとして Programmer's Workbench (PWB) のシェルがあります。

PWB は初期の Unix の開発にも関わった Rudd Canaday が中心となった 開発プロジェクトで、Version 3 から Version 6 までの Unix を応用した 大規模ソフトウェア開発のためのシステムでした。PWB は Shell 以外にも Remote Job Entry (RJE) や Source Code Control System (SCCS) ★コラム2など 現在でも著名なソフトウェア開発ツールが含まれていましたが、Unix とは 独立したシステムとしてライセンスされたため、Unix ほどには普及しませんでした。

さて PWB Shell ですが、このシェルは John Mashey のグループに よって開発されたもので、おそらく PWB に必要であったであろう 大量のシェルスクリプトをより良く記述するために、 主にシェルプログラミング機能の強化が図られました。 このシェルは 1977 年の初頭には完成し、 元祖の Thompson Shell に対するところから、 開発者の名前をとって Mashey Shell とも呼ばれています。

Bourne Shell

Bourne Shell の開発は 1975 年頃から着手されていたそうです。 が、様々な紆余曲折によりその開発は遅々として進みませんでした。 もっぱら、新機能を入れては削るといった亀のような歩みで前進していました。 最終的には Thompson Shell をベースに Mashey Shell の機能を統合した形で まとまることになったわけですが、BTL ではこれが標準シェルとなりました。 もっとも、その BTL でも実行速度の早い Mashey Shell とどちらが望ましいか? という議論があったそうです。つまり 1970 年代から「最強シェルはどれか?」 という宗旨論争は存在したというわけですね。

C Shell の開発

シェルの開発史からも伺えるように、Version 6 Unix は今日の Unix とは かなり違うものの、当時は安定バージョンとして各所で受け入れられており、 その上で様々な野心的な試みがなされていました。もちろんこの当時の開発の 主力は BTL であったわけですが、UCB の Unix コミュニティーは Ken Thompson の客員を契機に Unix に関する技術スキルを急速に高めて このトレンドに乗って、徐々に Unix コミュニティー全体を牽引する 実力を高めていったと考えられます。スタイルを重んじる BTL とは異なり、 徹底した実利指向に基づくそのアプローチには Unix コミュニティーでも 賛否両論があったようですが、その爆発的なソフトウェア生産能力は周囲を 驚嘆させるものでした。C Shell もまたその代表的な成果の1つといえる でしょう。

C Shell もまた Bill Joy 自身の手で開発された Unix コマンドです。 その開発はおそらく 1977 年の末から 1978 年初頭の時期に、 Pascal システムあるいは ex のメンテナンスなどの複数の開発作業と 並行して進められたと推測されます。その開発の馬力には驚かされます。

一般に「C と良く似た記述ができる」として知られている C Shell ですが、実はこれは Mashey Shell が元になっています。 Mashey Shell の開発者である John Mashey はこのシェルについて 論文を発表していますが、Bill Joy はこの論文にインスパイヤされて、 C Shell の開発に着手したといいます。当時の UCB が PWB のライセンスを 保持していたかどうかは定かではありませんが、Bill Joy は論文だけを手がかりに 独自の実装で Mashey Shell のシェルプログラミング機能の再現を試みた、 これが C Shell の始まりであったと推測されます。C Shell の if-the-else-endif, break, breakaw, onintr, while-end などの構文は Mashey Shell から直接影響を 受けたものだとされています。

2BSD の収録されている C Shell は公式にリリースされた最初のバージョンであり、 C Shell には2BSD 以降も様々な機能追加と改変が繰り返されたことを考えると、 2BSD バージョンはおそらく Mashey Shell の影響を最も色濃く残している バージョンとも言えるのではないかと思います。

C Shell のインストール

それでは C Shell のインストールを始めましょう。 実は C Shell は Version 7 の設定だとコンパイルは成功しますが、 PDP-11 の上では正しく実行されません。(前述の通り Version 7 の 設定は UNIX/32V のための設定だと推測されます) そこで、ここでは PDP-11 の上で正しく実行できるコンパイル手順を紹介します。

まず PDP-11 で C Shell をコンパイルするには PCC ではなく、 Dennis Ritchie が開発したオリジナルの古い C コンパイラが必要です。 オリジナルの Version 7 Unix では古い C コンパイラのソースコードは 収録されていますが、そのバイナリはインストールされていないので、 古い C コンパイラをコンパイルする必要があります。

実行例8 古い C コンパイラのコンパイル

# cd /usr/src/cmd/c
# make
cc -O -n -s -c c00.c
cc -O -n -s -c c01.c
cc -O -n -s -c c02.c
cc -O -n -s -c c03.c
cc -O -n -s -c c04.c
cc -O -n -s -c c05.c
cc -O -n -s -o c0 c00.o c01.o c02.o c03.o c04.o c05.o
cc -O -n -s -c c10.c
cc -O -n -s -c c11.c
cc -O -n -s -c c12.c
cc -O -n -s -c c13.c
cvopt <table.s >table.i
as -o table.o table.i
rm table.i
cc -O -n -s -o c1 c10.o c11.o c12.o c13.o table.o
cc -O -n -s -c c20.c
cc -O -n -s -c c21.c
cc -i -O -s -o c2 c20.o c21.o
#

実行例8を御覧ください。 ここでは単に make するだけで OK です。これで古い C コンパイラの 実態である c0 c1 c2 が作成されます。PCC のフロントエンドは このディレクトリにある c0 c1 c2 を認識していますので、 これらのバイナリを移動させる必要はありません。

次に C Shell 本体のコンパイルを実行します。

実行例9 csh のコンパイル

# mv makefile makefile.v7
# cp makefile.v6 makefile
# ed makefile

    ....

# diff -e makefile.v6 makefile
37c
        ${CC} -n ${OBJS}
.
# make install
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.dol.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.dol.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.err.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.err.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.exec.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.exec.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.exp.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.exp.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.func.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.func.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.glob.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.glob.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.hist.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.hist.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.lex.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.lex.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.misc.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.misc.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.parse.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.parse.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.print.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.print.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.sem.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.sem.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.set.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.set.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.wait.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o sh.wait.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP alloc.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o alloc.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP sh.init.c | /usr/ucb/xstr -c -
./sh.local.h: 63: NCARGS redefined
./sh.local.h: 64: NOFILE redefined
./sh.local.h: 65: FSHIN redefined
./sh.local.h: 66: FSHOUT redefined
./sh.local.h: 67: FSHDIAG redefined
./sh.local.h: 68: FOLDSTD redefined
cc -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP -S x.c
echo -ed - <:rofix x.s
-ed - x.s
as - -o sh.init.o x.s
rm x.s
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP 11printf.c | /usr/ucb/xstr -c -
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o 11printf.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP getpwent.c | /usr/ucb/xstr -c -
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o getpwent.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP getpwnam.c | /usr/ucb/xstr -c -
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o getpwnam.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP getpwuid.c | /usr/ucb/xstr -c -
cc -c -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP x.c
mv x.o getpwuid.o
cc -E -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP errlst.c | /usr/ucb/xstr -c -
cc -O -I/usr/include/retrofit -Dpdp11 -t1 -DNORMAL6 -DNOHELP -S x.c
echo -ed - <:rofix x.s
-ed - x.s
as -o errlst.o x.s
rm x.s
/usr/ucb/xstr
cc -S xs.c
ed - <:rofix xs.s
as -o strings.o xs.s
rm xs.s
cc -n sh.o sh.dol.o sh.err.o sh.exec.o sh.exp.o sh.func.o sh.glob.o sh.hist.o  sh.lex.o sh.misc.o sh.parse.o sh.print.o sh.sem.o sh.set.o  sh.wait.o alloc.o sh.init.o 11printf.o getpwent.o getpwnam.o   getpwuid.o errlst.o strings.o
cp a.out x
strip x
rm -f /bin/csh
mv x /bin/csh
rm -f /bin/makesh
ln /bin/csh /bin/makesh
#

# /etc/shutdown 0
Broadcast Message ...

System going down. Bye


Kill Process Phase

******   WAIT FOR SECOND # CHARACTER   ******
****** DO A SYNC, THEN HALT THE SYSTEM ******
# SYNC
# SYNC
# SYNC
#
Simulation stopped, PC: 016666 (BR 16552)
sim> quit
Goodbye
$

実行例9を御覧ください。 まず makefile は Version 6 用のものを修正して使います。デフォルトが Version 7 用の makefile ですので、これを mv して makefile.v6 を makefile にコピーします。修正要領は diff コマンドの出力どおりです。 これで事前の手直しはおわりです。"make install" を実行しましょう。 マクロの redefined のメッセージがたくさん出力されますが、これは 無視してください。なお C Shell のコンパイルには /usr/ucb/xstr という コマンドが使用されます。このコマンドが正しくインストールされてないと C Shell のコンパイルも失敗しますので注意してください。

以上、今回は 2BSD に収録されている基本コマンドと C Shell のコンパイル/ インストールについて御紹介しました。手順がいささか繁雑でしたので混乱 される方もいらっしゃったかも知れません。実行例を良く見て、作業を進めて ください。次回は 2BSD に収録にされている ex/vi のコンパイル/インストール、 および termcap の設定等について御紹介したいと考えています。お楽しみに。


★コラム1 Version 7 のディスクパーティション

この連載で以前、私は 「Version 7 ではディスクパーティションはサポートされてなかった」と 紹介したかと思いますが、この発言は不正確だったと言わざる得ません。 確かに Version 7 の標準的な機能としてディスクパーティションは サポートされていなかったのですが、幾つかのデバイスドライバ (例えば hp ドライバ)に関しては、 1つのディスクを複数の領域に分けて管理する、 いわゆる今日のディスクパーティションに 相当する機能が実装されていました。 Version 7 の付属ドキュメントである "Setting Up Unix - Seventh Edition" には以下の記述があります。

The big disk drivers (rp.c and hp.c) have partition tables
in them which you may want to experiment with.

この実装はいわゆる experimental implementation、 つまり比較的容量の大きなディスクに限定して「試しに実装してみた」ものと いうことのようです。おそらくユーザーのディスクパーティションに対する 要求があったのだと推測されます。

ディスクパーティションを指定するためのエントリであるデバイスファイルに 関するルールは今日の仕様をほぼ同じです。デバイスファイルの major number が ドライバの指定する番号、minor number がディスクのユニット番号を意味しますが、 ディスクパーティションをサポートするデバイスに関しては minor number の 下位 3 Bit がディスクパーティションを指定する番号、パーティションテーブル に対するインデックス値になっています。

で、問題のパーティションテーブルなんですが、これはデバイスドライバの中に ハードコードされていました。したがってディスクパーティションの構成を 変更するにはカーネルを再コンパイルするしかなかったわけです。今日では disklabel などパーティションテーブルを直接操作できる手段が用意されてますから、 それに比べればいささか使い勝手の悪いものであったことは否めません。 /usr/sys/dev/hp.c のパーティションテーブルに該当する部分を次に示します。

52
53	struct	size
54	{
55		daddr_t	nblocks;
56		int	cyloff;
57	} hp_sizes[8] =
58	{
59		9614,	0,		/* cyl 0 thru 22 */
60		8778,	23,		/* cyl 23 thru 43 */
61		0,	0,
62		0,	0,
63		161348,	44,		/* cyl 44 thru 429 */
64		160930, 430,		/* cyl 430 thru 814 */
65		153406,	44,		/* cyl 44 thru 410 (rp04, rp05) */
66		322278,	44,		/* cyl 44 thru 814 (rp06) */
67	};
68

パーティションテーブルに設定されているブロック数とオフセット値から パーティションの各スロットの使い道が暗黙のうちに想定されていました。 スロット0 (hp_size[0]) はルートパーティション、スロット1はスワップ パーティションを想定していたと思われます。更に、スロット4からスロット7には /usr パーティションを想定した候補が4種類用意されているようです。 コメントからも伺えるようにスロット6は RP04 および RP05 を使った場合の /usr パーティションのエントリ、スロット7は RP06 を使った場合の /usr パーティションのエントリを意味するようです。

実行例2では "/etc/mknod /dev/rp7 b 6 15" というコマンドで セカンドドライブのエントリを作りましたが、これはディスクユニット1番 (つまり2台目のディスク)のスロット7のパーティションという意味になります。

このように特定のディスク装置に強く依存する形でディスクパーティションが 実装されたことには、当時のディスク装置は今日のものに比べ、容量、性能だけ でなく信頼性、安定性も極端に低かったという理由があります。もちろん パーティションテーブルに設定されているブロック数/オフセット値は ユーザーが任意に変えることのできるものなのですが、 この値が適当でないと性能が極端に落ちたり、最悪の場合はディスクが 物理的にクラッシュするようなことが頻繁に起きました。故に多くの ユーザーは安定して動作することが確認されている値を あまり変えたがらなかったのでした。

今日のようにユーザーがディスクパーティションをユーザーの判断で 任意に設定されるようになるのは SCSI などのディスクに関する インターフェース規格が登場し、制御のためにマイクロプロセッサが 搭載されたディスク装置、すなわちインテリジェントディスクが 製品として一般に広く普及するようになってからのでことです。

★コラム2 Source Code Control System (SCCS)

今となっては SCCS という名前にピンとこない方も多いでしょうから、 蛇足ながら解説しておきます。 SCCS を一言で述べると CVS のお爺さんにあたるシステムといえるでしょう。 SCCS は Unix にリビジョン管理の概念を持ち込んだ最初のツールです。 当時、このリビジョン管理の考え方は大変画期的なものでしたので、 同種のツールが Unix の以外のシステムにおいても多数開発されました。

ところが、SCCS は PWB/UNIX の成果の一部でしたので、 オリジナル Unix にはバンドルされませんでした。 当時の Unix ユーザーで SCCS を利用できたのは PWB/UNIX のライセンスも 取得したごく一部ユーザーだけだったようです。(後に Tool Chest という形で ツールだけが独立してライセンスされるようになりましたが) そこで UCB において Unix 上で動く同種のツールとして開発されたのが Revision Control System (RCS) です。 こちらはライセンス上の制約がなかったため 1980 年代に広く普及しました。

そして皆さんが良くご存知の CVS の開発は、 この RCS を拡張することから始まりました。 当初の CVS は RCS のラッパーとして実装されており、 RCS がインストールされてなければ動かないシステムでした。 もっとも、現在の CVS は RCS の機能を完全に取り込んでしまっているので、 別途 RCS をインストールする必要はありませんが、、、CVS のソースコード に対して RCS というキーワードで grep すると、どこが該当する部分かが わかります。

ちなみに BSD Unix そのものの開発では、なんと SCCS が使われていました。 1992 年に Kirk からその説明を受けた時「ゲッ」と思ったことを思い出します。 CSRG CD-ROM にはこの BSD Unix の SCCS のログも収録されていますので、 興味のある方はご覧になってください。

★注1

このドキュメントは ms マクロを使った roff ドキュメントで、 ディストリビューションのトップディレクトリに install.ms という ファイル名で収録されています。HTML に変換したものを http://roguelife.org/~fujita/COOKIES/HISTORY/2BSD/install.html に置きましたので、こちらもどうぞ。