doc/en/tutorials/upgrade/upgrade.docb
John Fieber 89fd5bd633 A nifty new tutorial on how to upgrade a system using a "make world".
I have not personally done a "make world" since the 386BSD + patchkit days
so additional reviews from people who have would be good.

Submitted by:	Nik Clayton <nik@blueberry.co.uk>
1997-06-25 16:57:02 +00:00

539 lines
19 KiB
Text

<!-- $Id: upgrade.docb,v 1.1 1997-06-25 16:57:02 jfieber Exp $ -->
<!DOCTYPE BOOK PUBLIC "-//Davenport//DTD DocBook V3.0//EN">
<book>
<bookinfo>
<bookbiblio>
<title/Upgrading FreeBSD from source/
<authorgroup>
<author>
<firstname/Nik/
<surname/Clayton/
<affiliation>
<address><email/Nik.Clayton@blueberry.co.uk/</address>
</affiliation>
</author>
</authorgroup>
<pubdate>$Date: 1997-06-25 16:57:02 $</pubdate>
</bookbiblio>
</bookinfo>
<preface>
<title/Overview/
<para>After following the instructions in the handbook, and acquiring the
latest copies of the FreeBSD source code, you now want to upgrade your
system to the latest and greatest. There are a number of steps to go
through in order to do this.</para>
<para>This document takes you through those steps one by one.</para>
</preface>
<chapter>
<title>Check <filename>/etc/make.conf</filename></title>
<para>Examine the file <filename>/etc/make.conf</filename>. This contains
some default defines for <command/make/, which will be used when you
rebuild the source. They're also used every time you use <command/make/,
so it's a good idea to make sure they're set to something sensible for
your system.</para>
<para>Everything is, by default, commented out. Uncomment those entries
that look useful. For a typical user (not a developer), you'll probably
want to uncomment the CFLAGS and NOPROFILE definitions. If your machine
has a floating point unit (386DX, 486DX, Pentium and up class machines)
then you can also uncomment the HAVE_FPU line.</para>
<!-- XXX the definitions above should be wrapped in appropriate DocBook
markup. Don't know what it is yet, though -->
</chapter>
<chapter>
<title/Get the system to single user mode/
<para>You want to compile the system in single user mode. Apart from the
obvious benefit of making things go slightly faster, re-making the system
will touch a lot of important system files, all the standard system
binaries, libraries, include files and so on. Try to change these on a
running system and you're asking for trouble.</para>
<para>As the superuser, you can execute
<informalexample>
<screen><prompt/#/ <userinput/shutdown now/</screen>
</informalexample>
from a running system, which will drop it to single user mode.</para>
<para>Alternatively, reboot the system, and at the boot prompt, enter the
-s flag. The system will then boot single user. At the shell prompt you
should then run
<informalexample>
<screen><prompt/#/ <userinput/fsck -p/
<prompt/#/ <userinput>mount -u /</userinput>
<prompt/#/ <userinput/mount -a -t ufs/
<prompt/#/ <userinput/swapon -a/</screen>
</informalexample>
which check the filesystems, remounts <filename>/</filename> read/write,
mounts all the other UFS filesystems referenced in
<filename>/etc/fstbab</filename> and then turns swapping on.</para>
</chapter>
<chapter>
<title/Recompile the source/
<para>In general, this is as simple as
<informalexample>
<screen><prompt/#/ <userinput>cd /usr/src</userinput>
<prompt/#/ <userinput>make world 2>&1 | tee /var/tmp/mw.out</userinput></screen>
</informalexample>
which will re-make the world, storing a copy of all the STDOUT and STDERR
messages in <filename>/var/tmp/mw.out</filename>. It's important to use
<filename>/var/tmp</filename>, as plain <filename>/tmp</filename> is
generally cleared out when you reboot, and you want this output to stay
around for a while.</para>
<note>
<title><filename>/bin/sh</filename> specific</title>
<para>The <quote>2>&1</quote> construct is specific to the
<filename>/bin/sh</filename> shell. Under <filename>/bin/csh</filename>
you could use
<informalexample>
<screen><prompt/#/ <userinput>make world |& tee /var/tmp/mw.out</userinput>
</screen>
</informalexample>
</para>
<para>Other shells have their own constructs to do the same
thing.</para>
</note>
<para>Then go and make yourself several cups of tea. Remaking the world is
a long process. One of our servers, a 200Mhz P6 with fairly
run-of-the-mill SCSI disks, 64MB RAM and 256MB swap it takes a shade under
two hours to complete.</para>
<para>One of the 32MB (128MB swap), P133 machines takes about 5
hours.</para>
<para>The only caveat I am aware of is that (at least the last few times I
tried it with 2.1.5), <command/make world/ expected the <quote/dict/
distribution set to be installed. Otherwise it dies.</para>
<para>Which means, whenever I have to install a new machine, I generally
download the <quote/bin/, <quote/src/ and <quote/dict/ distributions, and
install them. I then make the world to get everything else.</para>
<para>This may have changed up to 2.1.7. I unfortunately do not have the
spare machines to test it.</para>
</chapter>
<chapter>
<title/Build and populate a new root directory somewhere safe/
<para>Remaking the world will not update certain directories (in
particular, <filename>/etc</filename>, <filename>/var</filename> and
<filename>/usr</filename>) with new or changed configuration files. This
is something you have to do by hand, eyeball, and judicious use of the
<command/diff/ command.</para>
<sect1>
<title>Backup your existing <filename>/etc</filename></title>
<para>Although, in theory, nothing's going to touch this directory
automatically, it's always better to be sure. So copy your existing
<filename>/etc</filename> directory somewhere safe. Something like
<informalexample>
<screen><prompt/#/ <userinput>cp -rp /etc /etc.old</userinput></screen>
</informalexample>
will do the trick (-r does a recursive copy, -p preserves times,
ownerships on files and suchlike).</para>
</sect1>
<sect1>
<title/Build a dummy root/
<para>You need to build a dummy set of directories to install the new
<filename>/etc</filename> and other files into. I generally choose to
put this dummy dir in <filename>/var/tmp/root</filename>, and there are
a number of subdirectories required under this as well. So execute
<informalexample>
<screen><prompt/#/ <userinput>mkdir /var/tmp/root</userinput>
<prompt/#/ <userinput>mtree -deU -f /usr/src/etc/mtree/BSD.root.dist -p /var/tmp/root/</userinput>
<prompt/#/ <userinput>mtree -deU -f /usr/src/etc/mtree/BSD.var.dist -p /var/tmp/root/var/</userinput>
<prompt/#/ <userinput>mtree -deU -f /usr/src/etc/mtree/BSD.usr.dist -p /var/tmp/root/usr/</userinput></screen>
</informalexample>
which will build the necessary directory structure.</para>
<para>A lot of these subdirs are extraneous, but you can ignore them
for the time being, they'll be removed in the next
step.</para>
</sect1>
<sect1>
<title/Install the updated files/
<para>Now that the directory tree has been built, you have to install
the new files from <filename>/usr/src/etc</filename> into it.
<informalexample>
<screen><prompt/#/ <userinput>cd /usr/src/etc</userinput>
<prompt/#/ <userinput>make DESTDIR=/var/tmp/root distribution</userinput></screen>
</informalexample>
This will leave several redundant empty directories scattered
around, cluttering up your <command/ls/ output. The simplest way
to get rid of them is to do
<informalexample>
<screen><prompt/#/ <userinput>find -d . -type d | /usr/bin/perl -lne \
'opendir(D,$_);@f=readdir(D);rmdir if $#f != 1;closedir(D);'</userinput></screen>
</informalexample>
which does a depth first search, examines each directory, and if the
number of files in that directory is 2 ('1' is not a typo in the
script) i.e., '.' and '..' then it removes the
directory.</para>
</sect1>
</chapter>
<chapter>
<title>Merge in the changed files from
<filename>/var/tmp/root/*</filename></title>
<para><filename>/var/tmp/root</filename> now contains all the files that
should be placed in appropriate locations below
<filename>/</filename>. You now have to go through each of these files,
determining how they differ with your existing files. This is not a task
that can be automated (at the moment).</para>
<para>Note that some of the files that will have been installed in
<filename>/var/tmp/root</filename> have a leading '.'. Make sure you use
<command/ls -a/ to catch them.</para>
<para>The simplest way to do this is to use the <command/diff/ command to
compare the two files. Use either the '-c' for the context output format,
or '-u' for the unified output format. I find it easier to read context
diffs.</para>
<para>For example,
<informalexample>
<screen><prompt/#/ <userinput>diff -c /etc/shells /var/tmp/root/etc/shells</userinput></screen>
</informalexample>
will show you the differences between your
<filename>/etc/shells</filename> file and the new
<filename>/etc/shells</filename> file. Use these to decide whether to
merge in changes that you've made or whether to copy over your old
file.</para>
<para>When it comes to <filename>/var/tmp/root/dev</filename>, you should
just copy over the <filename/MAKEDEV/ file. You may need to examine and
update <filename/MAKEDEV.local/ if you previously had to customise it for
your local environment.</para>
<para>You will use those scripts a little later to update your
<filename>/dev</filename> directory.</para>
<para>Here is a (probably incomplete) list of files that you will
probably want to merge or copy by hand.
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry/Copy/
<entry/Merge/
</row>
</thead>
<tbody>
<row>
<entry/<emphasis/<filename/passwd///
<entry/<filename/inetd.conf//
</row>
<row>
<entry/<emphasis/<filename/master.passwd///
<entry/<emphasis/<filename/login.access///
</row>
<row>
<entry/<emphasis/<filename/pwd.db///
<entry/<filename/printcap//
</row>
<row>
<entry/<emphasis/<filename/spwd.db///
<entry/<filename/remote//
</row>
<row>
<entry/<emphasis/<filename/group///
<entry/<filename/services//
</row>
<row>
<entry/<filename/aliases/ (nb: run <command/newaliases/)/
<entry/<emphasis/<filename/shells///
</row>
<row>
<entry/<filename/crontab//
<entry/<emphasis/<filename/ttys///
</row>
<row>
<entry/<filename/csh.*//
<entry/<filename/fbtab//
</row>
<row>
<entry/<filename/dumpdates//
<entry/<filename/exports//
</row>
<row>
<entry/<emphasis/<filename/fstab///
<entry/<emphasis/<filename/sysconfig///
</row>
<row>
<entry/<filename/host//
<entry/<filename/rc.local//
</row>
<row/<entry/<filename/magic///
<row><entry><filename>namedb/*</filename></entry></row>
<row><entry><filename>ppp/*</filename></entry></row>
<row/<entry/<filename/profile///
<row/<entry/<filename/resolv.conf///
<row/<entry/<filename/ntp.*///
<row/<entry/<filename/start_if.*///
<row/<entry/<filename/XF86*///
</tbody>
</tgroup>
</informaltable></para>
<para>That is not an exhaustive list, and changes to FreeBSd in the future
may necessitate moving files from the <emphasis/Copy/ column to the
<emphasis/Merge/ column. But you get the idea.</para>
<para>Those filenames shown in <emphasis/emphasised type/ are vital to
the correct running of the system. Be extra sure that they are present
and correct before you reboot.</para>
<note>
<title><filename>/etc/rc.conf</filename></title>
<para>I note from the mailing lists that
<filename>/etc/sysconfig</filename> is being renamed to
<filename>/etc/rc.conf</filename>, and that the contents of the file may
be altering. I can not currently build a system to include these changes
in this document.</para>
</note>
</chapter>
<chapter>
<title>Update <filename>/dev</filename></title>
<para>For safety's sake, this is a multistep process. You should already
have copied in the <filename/MAKEDEV/ script to
<filename>/dev</filename>. Do the following,
<informalexample>
<screen><prompt/#/ <userinput>ls -la /dev > /var/tmp/dev1.out</userinput>
<prompt/#/ <userinput>ls -la /var/tmp/root/dev > /var/tmp/dev2.out</userinput>
</screen></informalexample></para>
<para>This gives you a reference for when things go wrong&hellip; Run a
quick diff over these two files to see if anything's missing. If you use
slices in your disk partitioning (which may not be necessary on a
'dangerously dedicated' disk) then these slices have almost certainly not
been made.</para>
<para>Note down the devices that exist in <filename/dev1.out/ and not
<filename/dev2.out/, and the necessary commands to remake them.</para>
<para>Now do,
<informalexample>
<screen><prompt/#/ <userinput>cd /dev</userinput>
<prompt/#/ <userinput>sh MAKEDEV all</userinput>
</screen>
</informalexample>
This will generate all the standard devices. You must now do whatever's
necessary to recreate devices that you noticed as missing in the previous
step. For my setup, that involved doing
<informalexample>
<screen><prompt/#/ <userinput>sh MAKEDEV sd0s1a</userinput>
<prompt/#/ <userinput>sh MAKEDEV sd1s1a</userinput>
</screen>
</informalexample>
to create the slice entries on my two disks. Your circumstances may
vary. If at all in doubt, make sure you have a handy boot and fixit
floppy, and a very recent backup of your system.</para>
</chapter>
<chapter>
<title/Set the timezone/
<para>If you didn't copy over the <filename/localtime/ file from your old
<filename>/etc</filename> (which is probably a good idea, you may as well
generate it fresh), run <command/tzsetup/ (in
<filename>/usr/sbin</filename>) to set your timezone.</para>
</chapter>
<chapter>
<title/Rebooting/
<para>You're now done. After you've verified that everything appears to be
in the right place (pay particular attention to the <emphasis/emphasised/
files listed earlier), you can reboot the system. A simple
<command/fastboot/ should do it.</para>
</chapter>
<chapter>
<title/Compiling a new kernel/
<para>To take full advantage of your new system you should recompile the
kernel. This is practically a necessity, as certain memory structures may
have changed, and programs like <command/ps/ and <command/top/ will fail
to work until the kernel and source code versions are the same.</para>
<para>Follow the handbook instructions for compiling a new kernel. If you
have previously built a custom kernel then carefully examine the
<filename/LINT/ config file to see if there are any new options which you
should take advantage of.</para>
<para>Once your new kernel is built and installed, reboot.</para>
</chapter>
<chapter>
<title>That's it</title>
<para>You should now have successfully upgraded your FreeBSD system.
Congratulations. It's likely that over the next few days you'll notice
little oddities that don't work as expected, or small upgrades you've
forgotten to do. Something I missed for several days was that
<filename>/etc/magic</filename> was missing. It was only when I went to
run <command/file/ that I realised. A quick <command/make install/ in
<filename>/usr/src/usr.bin/file</filename> sorted that one out.</para>
</chapter>
<chapter>
<title/Questions?/
<sect1>
<title/Do I need to re-make the world for every change?/
<para>There's no easy answer to this one, as it depends on the nature of
the change. For example, I've just run CVSup, and it's shown the
following files as being updated since I last ran it;</para>
<informalexample>
<screen><filename>src/games/cribbage/instr.c</filename>
<filename>src/games/sail/pl_main.c</filename>
<filename>src/release/sysinstall/config.c</filename>
<filename>src/release/sysinstall/media.c</filename>
<filename>src/share/mk/bsd.port.mk</filename></screen>
</informalexample>
<para>There's nothing in there that I'd re-make the world for. I'd go to
the appropriate sub-directories and <command/make all install/, and
that's about it. But if something major changed, like, say,
<filename>src/lib/libc/stdlib</filename> then I'd probably either
re-make the world, or at least those parts of it that are statically
linked (as well as anything else I might have added that's statically
linked).</para>
<para>At the end of the day, it's your call. You might be happy
re-making the world every fortnight say, and let changes accumulate over
that fortnight. Or you might want to re-make just those things that have
changed, and are confident you can spot all the dependencies.</para>
<para>And, of course, this all depends on how often you want to upgrade,
and whether you are tracking -stable, a release candidate (2.2 at the
time of writing), or -current.</para>
<para>In any case, it's always worthwhile to subscribe to the relevant
mailing lists, depending on which version of FreeBSD you are staying up
to date with. Not only will this give you a <quote/heads up/ of
forthcoming changes, but it also means you'll see problems other people
might be having making the world, and lets you learn from their
problems.</para>
</sect1>
<sect1>
<title/Can I use one machine as a <emphasis/master/ to upgrade lots of
machines?/
<para>People often ask on the FreeBSD mailing lists whether they can do
all the compiling on one machine, and then use the results of that
compile to <command/make install/ on to other machines around the
network.</para>
<para>This is not something I've done. However, in a message to
questions@freebsd.org, Antonio Bemfica suggested the following
approach:</para>
<screen>
Date: Thu, 20 Feb 1997 14:05:01 -0400 (AST)
From: Antonio Bemfica &lt;bemfica@militzer.me.tuns.ca&gt;
To: freebsd-questions@freebsd.org
Message-ID: &lt;Pine.BSI.3.94.970220135725.245C-100000@militzer.me.tuns.ca&gt;
Josef Karthauser asked:
&gt; Has anybody got a good method for upgrading machines on a network
First make world, etc. on your main machine
Second, mount / and /usr from the remote machine:
main_machine% mount remote_machine:/ /mnt
main_machine% mount remote_machine:/usr /mnt/usr
Third, do a 'make install' with /mnt as the destination:
main_machine% make install DESTDIR=/mnt
Repeat for every other remote machine on your network. It works fine
for me.
Antonio
</screen>
<para>Which sounds interesting. Note that, of course, you will not
upgrade the target machines <filename>/etc</filename> directory (and
others as outlined above) by doing this.</para>
</sect1>
</chapter>
</book>