製作著作 © 2002, 2003, 2004 Jens Schweikhardt
$FreeBSD: head/ja_JP.eucJP/articles/fbsd-from-scratch/article.xml
39632 2012-10-01 11:56:00Z gabor $
FreeBSD は The FreeBSD Foundation の登録商標です。
Adobe, Acrobat, Acrobat Reader および PostScript は アメリカ合衆国および/またはその他の国の Adobe Systems Incorporated の登録商標または商標です。
製造者および販売者が製品を区別するのに 用いている表示の多くは、商標とされています。 この文書に登場する表示のうち FreeBSD Project がその商標を確認しているものには、その表示に続いて “™” または “�” 記号がおかれています。
今までに make world を使ってシステムをアップグレードした経験はあるでしょうか? もしディスクに一つのシステムしか入れていない場合は問題です。 installworld が途中で止まってしまったら、 あなたのシステムは壊れたまま、もう起動しなくなってしまうかも知れません。 あるいは、installworld が正常に終了しても、 新しいカーネルは起動に失敗してしまうかも知れません。 さて、そうなってしまったら、Fixit CD を取り出して半年前のバックアップを戻す、 なんてはめになってしまうかも知れませんよね。
わたしは、“アップグレードの時はディスクを初期化する” という方法がよいと考えています。パーティションではなくディスク全体のデータを 消去することで、アップグレードの手順では無視されるような古いデータが 残ってしまうことを防ぐことができます。ただ、 パーティションを全部初期化するということは、 ports/packages をすべて再コンパイル・再インストールしなければならず、 設定ファイルも注意深く作成し直さなければならないということです。 こういう作業を自動化したいと思いませんか? そう思う人は、この先を読み進めましょう。
これはもっともな質問です。 すでに sysinstall がありますし、 カーネルとユーザランドツールをコンパイルする方法には、 もっと有名な方法が他にもあるからです。
sysinstall の問題は、「何を、どこに、 どうやってインストールするのか」が非常に限定されているという点です。
sysinstall は通常、構築ずみの配布物セットと packages を (CD, DVD, FTP などの) 別の場所からインストールする時に使われるものであり、 make buildworld の結果をインストールできるようにはできていません。
現在稼働中のシステム中にあるディレクトリに、 新しいシステムをインストールすることはできません。
Vinum パーティションへのインストールはできません。
構築ずみの packages はインストールできますが、 ports を構築することはできません。
スクリプトを使ったり、 インストール後に変更するための処理を自由に入れることは困難です。
最後の大きな理由として、sysinstall が、公式にもう積極的に使わないプログラムと考えられている、 ということがあげられます。
システム全体を構築してインストールする方法は、 ハンドブックにある方法が有名です。 これはデフォルトで既存のシステムを置き換えるもので、 カーネルとモジュールだけが保存され、 システムバイナリ、ヘッダ、その他の多くのファイルは上書きされます。 使われなくなった古いファイルはそのまま残り、 動作に問題が出ることもあります。 何らかの理由でアップグレードに失敗すると、 システムを元の状態に戻することは不可能か、できても非常に困難です。
「FreeBSD をゼロから設定する」方法は、これらの問題をすべて解決できます。 考え方は単純です。 稼働中のシステムを使って空のディレクトリにシステムをインストールします。 その時、その新しいシステムのディレクトリツリーには、 新しいパーティションを適切にマウントしておaきます。 数多くある設定ファイルは、コピーできるものは適切な場所にコピーし、 それができないものには mergemaster(8) を使います。 新しいシステムに対するインストール後の設定は、 古いシステムを動作させながら、新しいシステムに対して chroot して 自由に行なうことができます。具体的には、 シェルスクリプト、もしくは make の実行で構成される、次の 3 段階でこれらを実現します。
stage_1.sh: 新しい起動可能なシステムを空のディレクトリ以下に作成し、 必要なファイルをマージ、もしくはコピーします。 そして、新しいシステムを起動します。
stage_2.sh: 必要な ports をインストールします。
stage_3.mk: ひとつ前の段階でインストールしたソフトウェアの、 インストール後の設定を行ないます。
新しいシステムを構築するために「FreeBSD をゼロから設定する」方法を使い、 それが数週間、満足する程度に動作していることを確認したら、 もう一度それを使って、大元のシステムを再インストールすることができます。 これからはいつでも好きな時にシステムを更新して、 初期化・再インストールしたパーティションに切り替えるだけでよくなるわけです。
Linux From Scratch (もしくは省略して LFS) について耳にしたり、試された方がいらっしゃるかも知れません。 LFS も同じように、稼働中のシステムを使ってシステムをゼロから構築し、 空のパーティションにインストールする方法が書かれています。 LFS が話題の中心としているのは、(カーネル、コンパイラ、デバイス、 シェル、端末データベースなどの) 各システムコンポーネントの役割と、 それらのインストールの詳細を見せることのようです。 この「FreeBSD をゼロから設定する」では、そのような詳細には触れません。 わたしの目的は、インストールを終わりまで自動化することであり、 システム構築時の泥くさい過程を全部説明することではありません。 FreeBSD をそのようなレベルで掘り下げてみたい人は、 /usr/src/Makefile を読んで、 make buildworld の動作を追いかけるところから始めましょう。
また、「FreeBSD をゼロから設定する」方法にも、 次のような欠点があることを心に留めておいてください。
第 2 段階で ports をコンパイルしている間、 システムは通常の用途に使用することができません。 もしプロダクションサーバを運用しているなら、 第 2 段階でダウンタイムが発生することを考慮に入れなければなりません。 stage_2.conf.default の ports のコンパイルには、 AMD1800+、10,000rpm SCSI、1GB の RAM を搭載したシステムで、 約 4 時間かかります。ports の代わりに package をインストールすれば、この時間を 10 分程度にまで大幅に短縮することも可能です。
「FreeBSD をゼロから設定する」方法を実行するには、 次のものが必要です。
ソースと ports ツリーを含む、稼働中の FreeBSD システム
新しいシステムをインストールするための、 最低 1 個の未使用パーティション
mergemaster(8) を実行した経験。もしくは、 それを実行する勇気。
インターネット接続環境がない、あるいは遅い場合には、 インストールしたい ports の配布ファイル
Bourne シェル (sh(1)) を使ってシェルスクリプトを作成するための基礎知識
新しいシステムを起動する方法を、 対話的あるいは設定ファイルを使ってブートローダに 教えることができること
この文書の初版では、第 1 段階にひとつのシェルスクリプトを使っていました。 カスタマイズはすべて、そのスクリプトを編集する必要があったのですが、 利用者からの意見を参考にして、スクリプトのコードとデータを分離することにしました。 そのため新しいスクリプトでは、コードスクリプトを変更せずに、 複数の異なるシステムに異なる構成のデータを置くことが可能になりました。
第 1 段階のコードスクリプトは stage_1.sh であり、次のように 1 個の引数をつけて実行すると
設定ファイルとして stage_1.conf.default を読み込み、 ログファイルとして stage_1.log.default に書き込みます。
文末にわたしが使っている stage_1.conf.default が添付してあります。 あなたが考える “完璧なシステム” に合わせて、 各設定をカスタマイズしてください。あなたが変更しそうな設定には、 詳細なコメントを追加してあります。設定スクリプトでは、 create_file_systems, create_etc_fstab, copy_files, all_remaining_customization という、 4 個のシェル関数を提供しなければなりません (これは、 stage_1.sh から呼ばれる順に書いてあります)。
考慮すべき点は、以下のとおりです。
パーティションの配置
わたしは、システム全体を一つの大きな パーティションに入れるという考え方が好きではないので、 普通は /、 /usr、 /var の パーティションを分割し、/tmp を /var/tmp のシンボリックリンクにしています。 また、/home (ユーザのホームディレクトリ)、 /home/ncvs (FreeBSD CVS リポジトリの複製), /usr/ports (ports ツリー), /src (チェックアウトした src ツリー)、 /share (news スプールなど、バックアップする必要がない、 その他の共有データ) といったファイルシステムを、 古いシステムと新しいシステムで共有しています。
その他の項目
これは、新しいシステムの起動後にすぐに実行したいことや、 第 2 段階の前に実行したい内容のことです。 なぜ第 1 段階で単純に新しいシステムに chroot してお気に入りの ports をインストールしないのかというと、理論的にも、 実際の手順にも卵鶏問題があるからです。第 1 段階では、 古いカーネルが動作していますが、chroot 環境には、 新しいバイナリとヘッダが使われています。もしその新しいバイナリが、 古いカーネルには存在しない新しいシステムコールを使っていたら、 SIGSYS, Bad system call というエラーが出て停止してしまうでしょう。わたしは lang/perl5 を構築する時にも問題が発生することを確認しています。
stage_1.sh を実行する前に、 make installworld installkernel を実行するために通常行なう作業を完了させておいてください。 これらは、たとえば次のようなものです。
カーネルコンフィグファイルの設定
make buildworld を正常終了させておくこと
make buildkernel KERNCONF=whatever を正常終了させておくこと
初めて stage_1.sh を実行した場合は、 稼働中のシステムから新しいシステムへとコピーされる設定ファイルは /usr/src のものと比べると古いので、 mergemaster がどうするかを聞いてきます。 おすすめは、ここで変更点を統合しておくことです。 もし、何度も質問に答えるのが面倒であれば、 稼働中のシステムのファイルを更新しておきましょう (ただしこれは、そうできればの話です。 -STABLE のシステムを実行していて、 -CURRENT を構築する、 もしくはその逆のようなケースでは、そうしてはいけません)。 次に mergemaster を実行した時、 RCS バージョン ID が /usr/src にあるファイルと一致しているものは、処理が飛ばされるようになります。
stage_1.sh スクリプトは set -e が指定されており、 最初のコマンドが失敗 (終了コードが 0 以外) すると停止します。 そのため、エラーを見逃してしまうということはないでしょう。 これは、タイプミスなどで未定義の変数を使った場合にもエラーになります。 次に進む前に、stage_1.conf.default にあるエラーを全部修正しておいてください。
stage_1.sh では mergemaster が実行されます。 統合作業をしなければならないファイルが一つもない状態でも、 実行の終わりに次のメッセージが表示されます。
*** Comparison complete Do you wish to delete what is left of /var/tmp/temproot.stage1? [no] no
no と答えるか、 単に Enter を押してください。 なぜかと言うと、mergemaster は /var/tmp/temproot.stage1 にサイズが 0 のファイルをいくつか残すからです。 これは、後で新しいシステムに (存在しなければ) コピーされます。
この後、インストールされたファイルのリストがページャ (デフォルトでは more(1) です。less(1) を使うこともできます) に表示されます。
*** You chose the automatic install option for files that did not exist on your system. The following were installed for you: /newroot/etc/defaults/rc.conf ... /newroot/COPYRIGHT (END)
q を入力してページャを終了します。 すると login.conf に関して、次のように表示されます。
*** You installed a login.conf file, so make sure that you run '/usr/bin/cap_mkdb /newroot/etc/login.conf' to rebuild your login.conf database Would you like to run it now? y or n [n]
これに対する答えはどちらでも構いません。 どう答えても、スクリプトから cap_mkdb(1) が実行されます。
次に示すのは、筆者の使っている stage_1.conf.default ですが、たくさんの部分を書き換える必要がありますので注意してください。 どこを書き換えればよいのかについては、コメントを読めば十分理解できると思います。
警告newfs(8) コマンドには注意してください。 マウントずみのパーティションに新しいファイルシステムを作成することはできないものの、 このスクリプトはマウントされていない /dev/da0s1a, /dev/da0s1e, /dev/da2s1e をすべて削除します。 ひとつ間違えれば、あなたの環境を破壊してしまう可能性がありますので、 デバイス名の変更は注意深く行なってください。
# This file: stage_1.conf.default, sourced by stage_1.sh. # # $Id: stage_1.conf.default,v 1.5 2011-05-14 20:44:31 hrs Exp $ # $FreeBSD: head/en_US.ISO8859-1/articles/fbsd-from-scratch/stage_1.conf.default 38826 2012-05-17 19:12:14Z hrs $ # Root mount point where you create the new system. Because it is only # used as a mount point, no space will be used on that file system as all # files are of course written to the mounted file system(s). DESTDIR="/newroot" # Where your src tree is. SRC="/usr/src" # Where your obj is. MAKEOBJDIRPREFIX="/usr/obj" # Your kernel config name as from make buildkernel KERNCONF=... KERNCONF="HAL9000" # Your target architecture as used for make buildworld TARGET=... # If you did not specify a TARGET when building world, it defaulted # to the build architecture (run "uname -m" to find out if you are unsure). TARGET="i386" # amd64 arm i386 ia64 mips pc98 powerpc sparc64 # Available time zones are those under /usr/share/zoneinfo. TIMEZONE="Europe/Berlin" # # The create_file_systems function must create the mountpoints under # DESTDIR, create the file systems, and then mount them under DESTDIR. # create_file_systems () { # The new root file system. Mandatory. # Change DEVICE names. DEVICE=/dev/daXYZs1a mkdir -m 755 -p ${DESTDIR} chown root:wheel ${DESTDIR} newfs -U ${DEVICE} mount -o noatime ${DEVICE} ${DESTDIR} # Additional file systems and initial mount points. Optional. DEVICE=/dev/daXYZs1e mkdir -m 755 -p ${DESTDIR}/var chown root:wheel ${DESTDIR}/var newfs -U ${DEVICE} mount -o noatime ${DEVICE} ${DESTDIR}/var DEVICE=/dev/daXYZs1e mkdir -m 755 -p ${DESTDIR}/usr chown root:wheel ${DESTDIR}/usr newfs -U ${DEVICE} mount -o noatime ${DEVICE} ${DESTDIR}/usr } # # The create_etc_fstab function must create an fstab matching the # file systems created in create_file_systems. # create_etc_fstab () { cat <<EOF >${DESTDIR}/etc/fstab # Device Mountpoint FStype Options Dump Pass# /dev/da0s1b none swap sw 0 0 /dev/da1s1b none swap sw 0 0 /dev/da2s2b none swap sw 0 0 /dev/da3s2b none swap sw 0 0 /dev/da0s1a / ufs rw,noatime 1 1 /dev/da0s1e /var ufs rw,noatime 1 1 /dev/da2s1e /usr ufs rw,noatime 1 1 /dev/vinum/Share /share ufs rw,noatime 0 2 /dev/vinum/home /home ufs rw,noatime 0 2 /dev/vinum/ncvs /home/ncvs ufs rw,noatime 0 2 /dev/vinum/ports /usr/ports ufs rw,noatime 0 2 /dev/ad1s1a /flash ufs rw,noatime 0 0 /dev/ad0s1 /2k ntfs ro,noauto 0 0 /dev/ad0s6 /linux ext2fs ro,noauto 0 0 # /dev/cd0 /cdrom cd9660 ro,noauto 0 0 /dev/cd1 /dvd cd9660 ro,noauto 0 0 proc /proc procfs rw 0 0 linproc /compat/linux/proc linprocfs rw 0 0 EOF chmod 644 ${DESTDIR}/etc/fstab chown root:wheel ${DESTDIR}/etc/fstab } # # The copy_files function is used to copy files before mergemaster is run. # copy_files () { # Add or remove from this list at your discretion. Mostly mandatory. for f in \ /.profile \ /etc/devd.conf \ /etc/devd.rules \ /etc/exports \ /etc/group \ /etc/hosts \ /etc/inetd.conf \ /etc/ipfw.conf \ /etc/make.conf \ /etc/master.passwd \ /etc/nsswitch.conf \ /etc/ntp.conf \ /etc/printcap \ /etc/profile \ /etc/rc.conf \ /etc/resolv.conf \ /etc/src.conf \ /etc/sysctl.conf \ /etc/ttys \ /etc/mail/aliases \ /etc/mail/aliases.db \ /etc/mail/hal9000.mc \ /etc/mail/service.switch \ /etc/ssh/*key* \ /etc/ssh/*_config \ /etc/X11/xorg.conf \ /var/cron/tabs/* \ /root/.profile \ /boot/*.bmp \ /boot/loader.conf \ /boot/device.hints ; do cp -p ${f} ${DESTDIR}${f} done } # # Everything else you want to tune in the new system. # NOTE: Do not install too many binaries here. With the old system running and # the new binaries and headers installed you are likely to run into bootstrap # problems. Ports should be compiled after you have booted in the new system. # all_remaining_customization () { # Without the compat symlink the linux_base files end up on the root fs: cd ${DESTDIR} mkdir -m 755 usr/compat; chown root:wheel usr/compat; ln -s usr/compat mkdir -m 755 usr/compat/linux; chown root:wheel usr/compat/linux mkdir -m 555 usr/compat/linux/proc; chown root:wheel usr/compat/linux/proc mkdir -m 755 boot/grub; chown root:wheel boot/grub mkdir -m 755 linux 2k; chown root:wheel linux 2k mkdir -m 755 src; chown root:wheel src mkdir -m 755 share; chown root:wheel share mkdir -m 755 dvd cdrom flash; chown root:wheel dvd cdrom flash mkdir -m 755 home; chown root:wheel home mkdir -m 755 usr/ports; chown root:wheel usr/ports # Create the ntp and slip log files. touch ${DESTDIR}/var/log/ntp ${DESTDIR}/var/log/slip.log # Make /usr/src point to the right directory. Optional. # Note: some ports need part of the src tree, e.g. emulators/kqemu, # sysutils/lsof, sysutils/fusefs, ... cd ${DESTDIR}/usr if test "${SRC}" != /usr/src; then rmdir src; ln -s ${SRC} fi if test "${MAKEOBJDIRPREFIX}" != /usr/obj; then rmdir obj; ln -s ${MAKEOBJDIRPREFIX} fi # My personal preference is to symlink tmp -> var/tmp. Optional. cd ${DESTDIR}; rmdir tmp; ln -s var/tmp # Make spooldirs for the printers in my /etc/printcap. cd ${DESTDIR}/var/spool/output/lpd; mkdir -p as od ev te lp da touch ${DESTDIR}/var/log/lpd-errs # If you do not have /home on a shared partition, you may want to copy it: # mkdir -p ${DESTDIR}/home # cd /home; tar cf - . | (cd ${DESTDIR}/home; tar xpvf -) } # vim: tabstop=2:expandtab:shiftwidth=2:syntax=sh: # EOF $RCSfile: stage_1.conf.default,v $
ダウンロード: stage_1.conf.default .
このスクリプトを実行すると、 起動した時に次のような状態になっているシステムがインストールされます。
稼働中のシステムと同じユーザとグループ
Ethernet と PPP を経由した、 ファイアウォールありのインターネット接続環境
正しいタイムゾーンと NTP 設定
/etc/ttys や inetd など、その他の細かな設定。
他の部分に対する設定は、第 2 段階が終わるまで動作しません。 たとえば、プリンタや X11 の設定ファイルもコピーされますが、 プリンタは PostScript® ユーティリティなど、 ベースシステムに含まれないアプリケーションを使うことが多いでしょう。 X11 はサーバ、ライブラリ、プログラムをコンパイルしないと動作しません。
注意: この段階で ports をコンパイルするのではなく、 (コンパイルずみの) packages をインストールすることもできます。 その場合、stage_2.sh は 単に pkg_add コマンドを羅列するだけになるでしょう。 読者のみなさんにとって、そういうスクリプトを書くのは難しくないと思いますので、 ここではもっと柔軟で、ports を使った伝統的な方法について考えることにします。
次に紹介する stage_2.sh スクリプトは、 わたしが好みの ports
をインストールするために使ったものです。 これは何度でも実行でき、インストールずみの ports
があれば、 飛ばして処理されます。スクリプトは 実行せず、実行される内容だけ を表示する (dryrun) オプション
(-n
) があります。実行時には stage_1.sh と同様、
設定スクリプトを示すためのひとつの引数を指定します。
これは、ports のリストを stage_2.conf.default というファイルから読み込みます。
ports リストは、空白で区切られた 2 個以上のキーワードからなっています。 カテゴリ、port 名に始まり、オプションとして port をコンパイルしてインストールするためのコマンド (デフォルトは make install BATCH=yes < /dev/null) が続きます。 空白行と # から始まる行は無視されます。 おそらく多くの場合に考えなければならないのは、カテゴリ名と port 名だけでしょう。 ports によっては、たとえば次のように make 変数を使って微調整することができます。
www mozilla make WITHOUT_MAILNEWS=yes WITHOUT_CHATZILLA=yes install
実際には任意のシェルコマンドを指定できますので、 make を使う以外にも応用は可能です。
java linux-sun-jdk13 yes | make install news inn-stable CONFIGURE_ARGS="--enable-uucp-rnews --enable-setgid-inews" make install
news/inn-stable の行は、 CONFIGURE_ARGS という シェル変数を定義した例です。 この port の Makefile は、 この指定した値を変数の初期値として、その他の必須の引数と一緒に使います。 これと
news inn-stable make CONFIGURE_ARGS="--enable-uucp-rnews --enable-setgid-inews" install
のようにして make 変数をコマンドラインに設定した場合との違いは、 こちらの場合に変数そのものを完全に上書きしてしまうという点です。 どの方法を使えばいいのかについては、各 port によります。
インストールしたい ports が、 対話的インストールを使っていないことを確認してください。 ports は、あなたが標準入力に明示的に指定したもの以外、 標準入力を読み込む動作をしてはいけません。 もし ports がそのように作られていると、ports はヒアドキュメントにある ports リストの次の行を読み込んで混乱してしまいます。 stage_2.sh を実行した時、 ある port が飛ばされたり、動作が止まってしまうようなことがあれば、 おそらくこれが原因でしょう。
次に示すのは stage_2.conf.default です。 これは、インストールされる port それぞれに対して LOGDIR/category+port という名前のログファイルが作成されます。
# vim: syntax=sh # $Id: stage_2.conf.default,v 1.4 2008-12-03 21:59:51 schweikh Exp $ # $FreeBSD: head/en_US.ISO8859-1/articles/fbsd-from-scratch/stage_2.conf.default 38826 2012-05-17 19:12:14Z hrs $ ports-mgmt portaudit devel ccache shells zsh devel gettext archivers unzip archivers zip security sudo x11 xorg x11-servers xorg-server x11-fonts xorg-fonts-100dpi x11-fonts xorg-fonts-75dpi x11-fonts xorg-fonts-miscbitmaps x11-fonts xorg-fonts-truetype x11-fonts xorg-fonts-type1 x11-fonts gnu-unifont make install && mkfontdir /usr/local/lib/X11/fonts/local x11-fonts urwfonts x11-fonts webfonts x11-toolkits open-motif x11-wm ctwm x11 wdm security openssh-askpass astro xplanet astro xephem editors vim print ghostscript8 print psutils-a4 print a2ps-a4 print gv print transfig print teTeX print cups-base emulators linux_base-fc6 print acroread8 yes accept | make install PAGER=ls java jdk16 echo true > files/license.sh; make install BATCH=yes < /dev/null www apache22 www amaya www firefox3 www checkbot www p5-HTML-Parser www validator www mplayer-plugin math p5-Math-Combinatorics math p5-Bit-Vector graphics evince graphics xfig graphics xv graphics gphoto2 multimedia xawtv lang expect lang gawk lang python news tin net freebsd-uucp net cvsup-without-gui net rsync ftp wget textproc ispell german ispell-neu german ispell-alt textproc docproj sysutils samefile sysutils smartmontools sysutils pstree sysutils cdrtools sysutils dvd+rw-tools sysutils grub sysutils lsof devel subversion-freebsd devel bcc devel ddd devel gindent devel ctags devel ElectricFence devel strace devel perltidy mail procmail mail metamail mail mutt-devel ports-mgmt portupgrade news inn CONFIGURE_ARGS="--enable-uucp-rnews --enable-setgid-inews" make BATCH=yes install < /dev/null misc figlet-fonts security gpa mail spamoracle textproc rman multimedia mplayer multimedia mplayer-fonts multimedia acidrip multimedia ogle multimedia ogle-gui audio pacpl audio p5-CDDB_get audio cowbell shells bash editors openoffice.org-3-RC java eclipse java netbeans
ダウンロード: stage_2.conf.default.
第 2 段階で、好みの ports がインストールされましたが、 ports には、設定を必要とするものがあります。 第 3 段階は、インストール後の設定を行なう段階です。 stage_2.sh の最後にこの段階を統合することもできたのですが、 わたしは port をインストールすることと初期設定を変更することが異なる工程であると考えたため、 独立した段階としています。
第 3 段階は、Makefile として実装しています。 これは、次のように実行することで、設定対象を簡単に選ぶことができるからです。
stage_2.sh の段階で、 stage_3.mk を共有パーティションに置くか、 新しいシステムのどこかにコピーするなどして、 新しいシステムが起動した時に stage_3.mk が使えるようにしておきましょう。
対話的で、かつ make BATCH=YES install でのインストールに対応していない port の自動インストールは難しいかも知れません。 対話的にインストールする ports には、ライセンス条項の同意を尋ねられた時に yes と入力するだけのものがいくつかあります。 そのように入力が標準入力から読みとられる場合は、 適切な回答をインストールコマンド (通常は make install) にパイプで渡すことができます (わたしが stage_2.conf.default の java/linux-sun-jdk14 でとった方法がそうです)。
しかしこの方法は、たとえば editors/staroffice52 の場合にはうまく動きません。 これは X11 が実行されていることを要求するからです。 インストール手順には多くのクリックや文字入力が必要なので、 他の ports のように自動化することはできません。 わたしは、次のようにして問題を回避しました。 最初に古いシステムで staroffice の package を作成し、
# cd /usr/ports/editors/staroffice52 # make package ===> Building package for staroffice-5.2_1 Creating package /usr/ports/editors/staroffice52/staroffice-5.2_1.tbz Registering depends:. Creating bzip'd tar ball in '/usr/ports/editors/staroffice52/staroffice-5.2_1.tbz'
その後、第 2 段階で次のようにしたわけです。
その他に、設定ファイルのアップグレード問題に気をつける必要があります。 一般的に、設定ファイルの書式や内容がいつ変更されるかを知ることはできません。 新しいグループが /etc/group に追加されるかも知れませんし、/etc/passwd に新しいフィールドが追加されるかも知れません。 このような例は、実際に過去にありました。 単純に古いシステムから新しいシステムに設定ファイルをコピーするだけで ほとんどの場合は十分なのですが、時には不都合な場合もあります。 古いファイルを上書きする方法でシステムをアップグレードしたら、 ローカルにある設定ファイルに新しく追加されたかも知れない項目を統合する目的で mergemaster を使うと思います。 しかし残念なことに、mergemaster はベースシステムに存在するファイルだけで、インストールした ports については何も処理を行なってくれません。 サードパーティ製ソフトウェアには、 リリースのたびに設定ファイルのフォーマットが変更され、 わたしをイライラさせるようなものもあります。 このような予告なしの変更を検出するために、 わたしは変更した設定ファイルを stage_3.mk と同じディレクトリにコピーしておき、 make ルールを使って結果を比較しています。 たとえば、apache の httpd.conf であれば、次のような config_apache というターゲットを用意しておきます。
@if ! cmp -s /usr/local/etc/apache2/httpd.conf httpd.conf; then \ echo "ATTENTION: the httpd.conf has changed. Please examine if"; \ echo "the modifications are still correct. Here is the diff:"; \ diff -u /usr/local/etc/apache2/httpd.conf httpd.conf; \ fi
差分が無害なものであると確認できたら、 cp /usr/local/etc/apache2/httpd.conf httpd.conf を実行するわけです。
わたしは 5-CURRENT から 5-CURRENT に更新するために 「FreeBSD をゼロから設定する」方法を数回使いましたが、 4-STABLE と 5-CURRENT の間で更新を行なった経験はありません。 異なるメジャーリリース番号の間は、非常の多数の変更が行なわれているため、 更新作業はもっと複雑なものになると思います。 (試したわけではないのですが) 4-STABLE から 4-STABLE への更新であれば、「FreeBSD をゼロから設定する」方法は問題なく動作するはずです。 4-STABLE のユーザは、次の点を考慮してください。
注意: デバイスファイルシステム devfs(5) を使ってなければ、 all_remaining_customization の中で MAKEDEV(8) を使い、 ハードウェア用のデバイスファイルを作成するとよいでしょう。
ここでは、すでに説明した設定ファイルの他に必要な、 3 個のファイルを示します。
これは stage_1.sh スクリプトです。内容を変更する必要はないでしょう。
#!/bin/sh # # stage_1.sh - FreeBSD From Scratch, Stage 1: System Installation. # Usage: ./stage_1.sh profile # will read profile # and write ./stage_1.log.profile # # Author: Jens Schweikhardt # $Id: stage_1.sh,v 1.7 2008-12-11 19:48:21 schweikh Exp $ # $FreeBSD: head/en_US.ISO8859-1/articles/fbsd-from-scratch/stage_1.sh 38826 2012-05-17 19:12:14Z hrs $ PATH=/bin:/usr/bin:/sbin:/usr/sbin # Prerequisites: # # a) Successfully completed "make buildworld" and "make buildkernel" # b) Unused partitions (at least one for the root fs, probably more for # the new /usr and /var, to your liking.) # c) A customized profile file. if test $# -ne 1; then echo "usage: stage_1.sh profile" 1>&2 exit 1 fi # ---------------------------------------------------------------------------- # # Step 1: Create an empty directory tree below $DESTDIR. # ---------------------------------------------------------------------------- # step_one () { create_file_systems # Now create all the other directories. Mandatory. cd ${SRC}/etc; make distrib-dirs DESTDIR=${DESTDIR} TARGET=${TARGET} } # ---------------------------------------------------------------------------- # # Step 2: Fill the empty /etc directory tree and put a few files in /. # ---------------------------------------------------------------------------- # step_two () { copy_files # Delete mergemaster's temproot, if any. TEMPROOT=/var/tmp/temproot.stage1 if test -d ${TEMPROOT}; then chflags -R 0 ${TEMPROOT} rm -rf ${TEMPROOT} fi export MAKEDEVPATH="/bin:/sbin:/usr/bin" mergemaster -i -m ${SRC}/etc -t ${TEMPROOT} -D ${DESTDIR} cap_mkdb ${DESTDIR}/etc/login.conf pwd_mkdb -d ${DESTDIR}/etc -p ${DESTDIR}/etc/master.passwd # Mergemaster does not create empty files, e.g. in /var/log. Do so now, # but do not clobber files that may have been copied with copy_files. cd ${TEMPROOT} find . -type f | sed 's,^\./,,' | while read f; do if test -r ${DESTDIR}/${f}; then echo "${DESTDIR}/${f} already exists; not copied" else echo "Creating empty ${DESTDIR}/${f}" cp -p ${f} ${DESTDIR}/${f} fi done chflags -R 0 ${TEMPROOT} rm -rf ${TEMPROOT} } # ---------------------------------------------------------------------------- # # Step 3: Install world. # ---------------------------------------------------------------------------- # step_three () { cd ${SRC} make installworld DESTDIR=${DESTDIR} TARGET=${TARGET} } # ---------------------------------------------------------------------------- # # Step 4: Install kernel and modules. # ---------------------------------------------------------------------------- # step_four () { cd ${SRC} # The loader.conf and device.hints are required by the installkernel target. # If you have not copied them in Step 2, cp them as shown in the next 2 lines. # cp sys/boot/forth/loader.conf ${DESTDIR}/boot/defaults # cp sys/${TARGET}/conf/GENERIC.hints ${DESTDIR}/boot/device.hints make installkernel DESTDIR=${DESTDIR} KERNCONF=${KERNCONF} TARGET=${TARGET} } # ---------------------------------------------------------------------------- # # Step 5: Install /etc/fstab and time zone info. # ---------------------------------------------------------------------------- # step_five () { create_etc_fstab # Setup time zone info; pretty much mandatory. cp ${DESTDIR}/usr/share/zoneinfo/${TIMEZONE} ${DESTDIR}/etc/localtime if test -r /etc/wall_cmos_clock; then cp -p /etc/wall_cmos_clock ${DESTDIR}/etc/wall_cmos_clock fi } # ---------------------------------------------------------------------------- # # Step 6: All remaining customization. # ---------------------------------------------------------------------------- # step_six () { all_remaining_customization } do_steps () { echo "PROFILE=${PROFILE}" echo "TARGET=${TARGET}" echo "DESTDIR=${DESTDIR}" echo "SRC=${SRC}" echo "KERNCONF=${KERNCONF}" echo "TIMEZONE=${TIMEZONE}" echo "TYPE=${TYPE}" echo "REVISION=${REVISION}" echo "BRANCH=${BRANCH}" echo "RELDATE=${RELDATE}" step_one step_two step_three step_four step_five step_six } # ---------------------------------------------------------------------------- # # The ball starts rolling here. # ---------------------------------------------------------------------------- # PROFILE="$1" set -x -e -u # Stop for any error or use of an undefined variable. . ${PROFILE} # Determine a few variables from the sources that were used to make the # world. The variables can be used to modify actions, e.g. depending on # the system's version. The __FreeBSD_version numbers # for RELDATE are documented in the Porter's Handbook, # doc/en_US.ISO8859-1/books/porters-handbook/freebsd-versions.html. # Scheme is: <major><two digit minor><0 if release branch, otherwise 1>xx # The result will be something like # # TYPE="FreeBSD" # REVISION="8.0" # BRANCH="RC" { "CURRENT", "STABLE", "RELEASE" } # RELDATE="800028" # eval $(awk '/^(TYPE|REVISION|BRANCH)=/' ${SRC}/sys/conf/newvers.sh) RELDATE=$(awk '/^[ \t]*#[ \t]*define[ \t][ \t]*__FreeBSD_version[ \t]/ { print $3 }' ${SRC}/sys/sys/param.h) echo "=> Logging to stage_1.${PROFILE}.log" do_steps 2>&1 | tee "stage_1.${PROFILE}.log" # vim: tabstop=2:expandtab:shiftwidth=2: # EOF $RCSfile: stage_1.sh,v $
ダウンロード: stage_1.sh.
これは stage_2.sh スクリプトです。最初の部分にある変数を変更しましょう。
#!/bin/sh # # stage_2.sh - FreeBSD From Scratch, Stage 2: Ports Installation. # Usage: ./stage_2.sh [-hnp] configname # # Author: Jens Schweikhardt # $Id: stage_2.sh,v 1.5 2004-07-19 21:02:26 schweikh Exp $ # $FreeBSD: head/en_US.ISO8859-1/articles/fbsd-from-scratch/stage_2.sh 38826 2012-05-17 19:12:14Z hrs $ DBDIR="/var/db/pkg" PORTS="/usr/ports" : ${PACKAGES:=${PORTS}/packages} LOGDIR="/home/root/setup/ports.log"; mkdir -p ${LOGDIR} PKG_PATH="/cdrom/packages/All:/dvd/packages/All" PKG= MYNAME="$(basename $0)" usage () { exec >&2 echo "usage: ${MYNAME} [-hnp] configname" echo "" echo " Options:" echo " -h Print this help text." echo " -n Dryrun: just show what would be done." echo " -p Install a precompiled package if one can be found." echo "" echo " The config file (stage_2.conf.configname) is a list of" echo " ports to install with one entry per line. Each line" echo " consists of two or three space separated fields:" echo " category, port, and optionally a build command." echo "" exit 1 } # Look for a package in these locations in sequence. # Returns as soon as the first is found. Result on stdout. # # ${PORTS}/${CATEGORY}/${NAME} # ${PACKAGES}/All # ${PACKAGES}/${CATEGORY} # ${PKG_PATH} # find_package () { echo "${PORTS}/${CATEGORY}/${NAME}:${PACKAGES}/All:${PACKAGES}/${CATEGORY}:${PKG_PATH}" | tr : '\n' | while read d; do test -d "${d}" || continue PKG=$(ls ${d}/${PKGNAME}.* 2>/dev/null) test $? -eq 0 && echo "${PKG}" && return done } # # Parse command line arguments. # args=`getopt hnp $*` if test $? != 0; then usage fi set -- $args DRYRUN= CHKPKG= for i; do case "$i" in -n) DRYRUN="yes"; shift;; -p) CHKPKG="yes"; shift;; --) shift; break;; *) usage;; esac done if test $# -eq 1; then DATAFILE="$1" else usage fi # # Loop over the ports list. # while read CATEGORY NAME CMD; do case "${CATEGORY}" in \#*) continue;; '') continue;; esac DIR="${PORTS}/${CATEGORY}/${NAME}" if ! test -d "${DIR}"; then echo "$DIR does not exist -- ignored" continue fi cd ${DIR} PKGNAME=`make -V PKGNAME` if test -n "${CHKPKG}"; then PKG=$(find_package) else PKG="" fi if test -d "${DBDIR}/${PKGNAME}"; then echo "${CATEGORY}/${NAME} already installed as ${PKGNAME}" continue fi LOG="${LOGDIR}/${CATEGORY}+${NAME}" echo "===> Installing ${CATEGORY}/${NAME}; logging to ${LOG}" test -n "${CMD}" || CMD="make install BATCH=yes < /dev/null" if test -n "${DRYRUN}"; then if test -n "${PKG}"; then echo pkg_add -v ${PKG} else echo "${CMD}" fi continue fi date "++++ Started %v %T +++" > ${LOG} STARTED=$(date +%s) ( if test -n "${PKG}"; then echo "Found package ${PKG}" pkg_add -v ${PKG} else echo "CMD: ${CMD}" make clean eval "${CMD}" make clean # Uncomment if diskspace is tight under ${PORTS}. fi ) 2>&1 | tee -a ${LOG} FINISHED=$(date +%s) DURATION=$(dc -e "${FINISHED} ${STARTED} - p") date "++++ Finished %v %T after ${DURATION} secs +++" >> ${LOG} done < stage_2.conf.${DATAFILE} # vim: tabstop=4: # EOF $RCSfile: stage_2.sh,v $
ダウンロード: stage_2.sh.
これは、わたしが使っている stage_3.mk です。 設定を自動的におこなうための手順を、ここに入れます。
# stage_3.mk - FreeBSD From Scratch, Stage 3: Ports Post-Configuration. # Usage: make -f stage_3.mk all (configure everything) # or make -f stage_3.mk target (just configure target) # # Author: Jens Schweikhardt # # It is a good idea to make sure any target can be made more than # once without ill effect. # # $Id: stage_3.mk,v 1.5 2008-12-03 21:59:51 schweikh Exp $ # $FreeBSD: head/en_US.ISO8859-1/articles/fbsd-from-scratch/stage_3.mk 38826 2012-05-17 19:12:14Z hrs $ .POSIX: message: @echo "Please use one of the following targets:" @echo "config_apache" @echo "config_cups" @echo "config_firefox" @echo "config_inn" @echo "config_javaplugin" @echo "config_openoffice" @echo "config_sudo" @echo "config_TeX" @echo "config_tin" @echo "config_wdm" @echo "config_uucp" @echo "all -- all of the above" all: \ config_apache \ config_cups \ config_firefox \ config_inn \ config_javaplugin \ config_openoffice \ config_sudo \ config_TeX \ config_tin \ config_wdm \ config_uucp APACHE = apache22 config_apache: # 1. Modify httpd.conf. perl -pi \ -e 's/^\s*ServerAdmin.*/ServerAdmin schweikh\@schweikhardt.net/;' \ -e 's/^#?ServerName .*/ServerName hal9000.schweikhardt.net:80/;' \ -e 's/^\s*Listen.*/Listen 127.0.0.1:80/;' \ -e 's/^\s*Deny from all/ Allow from 127.0.0.1/i;' \ -e 's,/usr/local/www/$(APACHE)/cgi-bin/,/home/opt/www/cgi-bin/,;' \ /usr/local/etc/$(APACHE)/httpd.conf cp w3c-validator.conf /usr/local/etc/$(APACHE)/Includes # 2. Restore symlinks to web pages. cd /usr/local/www/$(APACHE)/data && \ ln -fs /home/schweikh/prj/homepage schweikhardt.net && \ ln -fs /home/opt/www/test . # 3. Restore W3C Validator config. mkdir -p /etc/w3c cp /usr/local/www/validator/htdocs/config/validator.conf.sample \ /etc/w3c/validator.conf perl -pi \ -e 's/^Allow Private IPs.*/Allow Private IPs = yes/;' \ /etc/w3c/validator.conf # Test if the httpd.conf has changed. @if ! cmp -s /usr/local/etc/$(APACHE)/httpd.conf httpd.conf; then \ echo "ATTENTION: the httpd.conf has changed. Please examine if"; \ echo "the modifications are still correct. If so you can simply"; \ echo "cp /usr/local/etc/$(APACHE)/httpd.conf httpd.conf"; \ echo "to make this message go away. Here is the diff:"; \ diff -u /usr/local/etc/$(APACHE)/httpd.conf httpd.conf; \ fi if test -f /var/run/httpd.pid; then \ /usr/local/etc/rc.d/$(APACHE) stop; \ /usr/local/etc/rc.d/$(APACHE) start; \ else \ /usr/local/etc/rc.d/$(APACHE) start; \ fi # The original ppd file is from http://www.cups.org/ppd.php?L63+I0+T+Q2300 # = http://www.cups.org/ppd/hp/de/hpc2325s.ppd.gz config_cups: chmod 644 /usr/local/etc/cups/cupsd.conf cp printers.conf /usr/local/etc/cups/printers.conf cp LaserJet_2300d.ppd /usr/local/etc/cups/ppd/LaserJet_2300d.ppd config_firefox: # Make this group wheel writable to allow extensions being installed. chmod -R g+w /usr/local/lib/firefox3/chrome config_inn: pw usermod -n news -d /usr/local/news -s /bin/sh mkdir -p /share/news/spool/outgoing \ /share/news/spool/incoming \ /share/news/spool/articles \ /share/news/spool/overview \ /share/news/spool/tmp \ /share/news/db chown -R news:news /share/news # Give the news system its initial configuration. cd /home/root/setup && \ if test ! -f /share/news/db/active; then \ echo "installing /share/news/db/active"; \ install -C -o news -g news -m 664 active /share/news/db; \ fi; \ if test ! -f /share/news/db/newsgroups; then \ echo "installing /share/news/db/newsgroups"; \ install -C -o news -g news -m 664 newsgroups /share/news/db; \ fi # Configure storage method. cd /home/root/setup && \ printf "%s\n%s\n%s\n%s\n" \ "method tradspool {" \ " newsgroups: *" \ " class: 0" \ "}" \ >storage.conf && \ install -C -o news -g news -m 664 storage.conf /usr/local/news/etc # Configure newsfeeds. printf "%s\n%s\n" \ "ME:*::" \ "shuttle/news2.shuttle.de:!junk,!control:B32768/512,Tf,Wfb:" \ >/usr/local/news/etc/newsfeeds # Configure inn.conf. perl -pi \ -e 's/^#*\s*(organization:\s*).*/$$1"An Open Pod Bay Door"/;' \ -e 's/^#*\s*(pathhost:\s*).*/$$1hal9000.schweikhardt.net/;' \ -e 's/^#*\s*(server:).*/$$1 localhost/;' \ -e 's/^#*\s*(domain:).*/$$1 schweikhardt.net/;' \ -e 's/^#*\s*(fromhost:).*/$$1 schweikhardt.net/;' \ -e 's,^#*\s*(moderatormailer:).*,$$1 \%s\@moderators.isc.org,;' \ -e 's,^#*\s*(pathdb:\s*).*,$$1/share/news/db,;' \ -e 's,/usr/local/news/spool,/share/news/spool,;' \ /usr/local/news/etc/inn.conf # Create empty history, if none there. # See post-install in /usr/ports/news/inn-stable/Makefile. set -e; cd /share/news/db; \ if test ! -f history; then \ touch history; \ chmod 644 history; \ chown news:news history; \ su -fm news -c "/usr/local/news/bin/makedbz -i"; \ for s in dir hash index; do \ mv history.n.$${s} history.$${s}; \ done; \ fi # Configure send-uucp. echo shuttle:shuttle >/usr/local/news/etc/send-uucp.cf # Satisfy inncheck: set -e; cd /usr/local/news/etc; \ chown news:news *; \ chmod 640 control.ctl expire.ctl nntpsend.ctl readers.conf /usr/local/news/bin/inncheck # Test if the inn.conf has changed. @if ! cmp -s /usr/local/news/etc/inn.conf inn.conf; then \ echo "ATTENTION: the inn.conf has changed. Please examine if"; \ echo "the modifications are still correct. If so you can simply"; \ echo "cp /usr/local/news/etc/inn.conf inn.conf"; \ echo "to make this message go away. Here is the diff:"; \ diff -u /usr/local/news/etc/inn.conf inn.conf; \ fi if ! test -f /usr/local/news/run/innd.pid; then \ /usr/local/etc/rc.d/innd start; \ fi config_javaplugin: cd /usr/local/lib/firefox3/plugins && \ ln -fs /usr/local/jdk1.6.0/jre/plugin/$$(uname -m)/ns7/libjavaplugin_oji.so config_openoffice: # Copy some truetype files so ooo can use them. find /usr/local/openoffice.org* -type d -name truetype \ -exec echo cp *.ttf {} \; -exec cp *.ttf {} \; config_sudo: if ! grep -q schweikh /usr/local/etc/sudoers; then \ echo 'schweikh ALL = (ALL) NOPASSWD: ALL' >> /usr/local/etc/sudoers; \ fi chmod 440 /usr/local/etc/sudoers config_TeX: # textproc/docproj advises: to typeset the FreeBSD Handbook with JadeTeX, # change the following settings to the listed values: perl -pi \ -e 's/^% original texmf.cnf/% texmf.cnf/;' \ -e 's/^(hash_extra\s*=\s*).*/$${1}60000/;' \ -e 's/^(pool_size\s*=\s*).*/$${1}1000000/;' \ -e 's/^(max_strings\s*=\s*).*/$${1}70000/;' \ -e 's/^(save_size\s*=\s*).*/$${1}10000/;' \ /usr/local/share/texmf/web2c/texmf.cnf # Test if the texmf.cnf has changed. @if ! cmp -s /usr/local/share/texmf/web2c/texmf.cnf texmf.cnf; then \ echo "ATTENTION: the texmf.cnf has changed. Please examine if"; \ echo "the modifications are still correct. If so you can simply"; \ echo "cp /usr/local/share/texmf/web2c/texmf.cnf texmf.cnf"; \ echo "to make this message go away. Here is the diff:"; \ diff -u /usr/local/share/texmf/web2c/texmf.cnf texmf.cnf; \ fi config_tin: # Point tin to our files. printf "%s\n%s\n%s\n" \ "activefile=/share/news/db/active" \ "newsgroupsfile=/share/news/db/newsgroups" \ "spooldir=/share/news/spool/articles" \ >/usr/local/etc/tin.defaults config_wdm: cp daemon1-JS-1600x1200.jpg FreeBSD_small.png \ /usr/local/lib/X11/wdm/pixmaps perl -pi \ -e 's,^(DisplayManager\*wdmBg:).*,\1 pixmap:/usr/local/lib/X11/wdm/pixmaps/daemon1-JS-1600x1200.jpg,;' \ -e 's,^(DisplayManager\*wdmLogo:).*,\1 /usr/local/lib/X11/wdm/pixmaps/FreeBSD_small.png,;' \ -e 's,^(DisplayManager\*wdmWm:).*,\1 ctwm:icewm:xfce4:tvtwm,;' \ /usr/local/lib/X11/wdm/wdm-config @if ! cmp -s /usr/local/lib/X11/wdm/wdm-config wdm-config; then \ echo "ATTENTION: the wdm-config has changed. Please examine if"; \ echo "the modifications are still correct. If so you can simply"; \ echo "cp /usr/local/lib/X11/wdm/wdm-config wdm-config"; \ echo "to make this message go away. Here is the diff:"; \ diff -u /usr/local/lib/X11/wdm/wdm-config wdm-config; \ fi config_uucp: cd /etc/mail && make install SENDMAIL_MC=/etc/mail/hal9000.mc # Make the uucp user's shell the correct uucico, so su(1) works. chpass -s /usr/local/libexec/uucp/uucico uucp # UUCP expects to find /usr/bin/rnews. cd /usr/bin && ln -fs ../local/news/bin/rnews . # Actual UUCP configuration. echo nodename js2015 > /usr/local/etc/uucp/config echo shuttle js2015 `cat uucp` > /usr/local/etc/uucp/call printf 'port tcp\ntype tcp\n' > /usr/local/etc/uucp/port printf "%s\n" \ "call-login *" \ "call-password *" \ "time any" \ "system shuttle" \ "address mail.s.shuttle.de" \ "commands rmail rnews" \ "port tcp" \ >/usr/local/etc/uucp/sys cd /usr/local/etc/uucp && chown uucp:uucp * && chmod o-rwx * # Trigger uucico after booting. mkdir -p /usr/local/etc/rc.d cp uucp.sh /usr/local/etc/rc.d # Rebuild the aliases.db. cp aliases /etc/mail/aliases newaliases # vim: tabstop=4: # EOF $RCSfile: stage_3.mk,v $
ダウンロード: stage_3.mk.
本文書、および他の文書は ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/ からダウンロードできます。
FreeBSD に関する質問がある場合には、ドキュメント を読んだ上で <[email protected]> まで (英語で)
連絡してください。
本文書に関する質問については、<[email protected]> まで電子メールを (英語で)
送ってください。