FreeBSD From Scratch
Prev |  | Next

# 4 Stage One: System Installation

The first version of this article used a single shell script for stage one where all your customization had to be done by editing the script. After valuable user feedback I have decided to separate the code and data in the scripts. This allows to have different configuration data sets to install different systems without changing any of the code scripts.

The code script for stage one is `stage_1.sh` and when run with exactly one argument, like

    # ./stage_1.sh default

will read its configuration from `stage_1.conf.default` and write a log to `stage_1.log.default`.

Further below you find my `stage_1.conf.default`. You need to customize it in various places to match your idea of the “perfect system”. I have tried to extensively comment the places you should adapt. The configuration script must provide four shell functions, `create_file_systems`, `create_etc_fstab`, `copy_files` and `all_remaining_customization` (in case it matters: this is also the sequence in which they will be called from `stage_1.sh`).

The points to ponder are:

- Partition layout.

  I do not subscribe to the idea of a single huge partition for the whole system. My systems generally have at least one partition for `/`, `/usr` and `/var` with `/tmp` symlinked to `/var/tmp`. In addition I share the file systems for `/home` (user homes), `/home/ncvs` (FreeBSD CVS repository replica), `/usr/ports` (the ports tree), `/src` (various checked out src trees) and `/share` (other shared data without the need for backups, like the news spool).

- Luxury items.

  What you want immediately after booting the new system and even before starting stage two. The reason for not simply chrooting to the new system during stage one and installing all my beloved ports is that in theory and in practice there are bootstrap and consistency issues: stage one has your old kernel running, but the chrooted environment consists of new binaries and headers. If the new binaries use a new system call, these binaries will die with `SIGSYS, Bad system call`, because the old kernel does not have that system call. I have seen other issues when I tried building `lang/perl5.8`.

Before you run `stage_1.sh` make sure you have completed the usual tasks in preparation for `make installworld installkernel`, like:

- configured your kernel config file

- successfully completed `make buildworld`

- successfully completed `make buildkernel KERNCONF=`whatever``

When you run `stage_1.sh` for the first time, and the config files copied from your running system to the new system are not up-to-date with respect to what is under `/usr/src`, `mergemaster` will ask you how to proceed. I recommend merging the changes. If you get tired of going through the dialogues you can simply update the files on your running system once (Only if this is an option. You probably do not want to do this if one of your systems runs `-STABLE` and the other `-CURRENT`. The changes may be incompatible). Subsequent `mergemaster` invocations will detect that the RCS version IDs match those under `/usr/src` and skip the file.

The `stage_1.sh` script will stop at the first command that fails (returns a non-zero exit status) due to `set -e`, so you cannot overlook errors. It will also stop if you use an unset environment variable, probably due to a typo. You should correct any errors in your version of `stage_1.conf.default` before you go on.

In `stage_1.sh` we invoke `mergemaster`. Even if none of the files requires a merge, it will display and ask at the end

    *** Comparison complete
    *** Saving mtree database for future upgrades

    Do you wish to delete what is left of /var/tmp/temproot.stage1? [no] no

Please answer `no` or just hit Enter. The reason is that `mergemaster` will have left a few zero sized files below `/var/tmp/temproot.stage1` which will be copied to the new system later (unless already there).

After that `mergemaster` will list the files it installed and ask if the new `login.conf` should be generated:

    *** 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

    *** You installed a new aliases file into /newroot/etc/mail, but
        the newaliases command is limited to the directories configured
        in sendmail.cf.  Make sure to create your aliases database by
        hand when your sendmail configuration is done.

    *** 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]

The answer does not matter since `stage_1.sh` will run cap_mkdb(1) for you in any case.

Here is the author's `stage_1.conf.default`, which you need to modify substantially. The comments give you enough information what to change.

    # 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: release/8.4.0/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 $

Download `stage_1.conf.default` .

Running this script installs a system that when booted provides:

- Inherited users and groups.

- Firewalled Internet connectivity over Ethernet.

- Correct time zone and NTP.

- Some more minor configuration, like `/etc/ttys` and `inetd`.

Other areas are prepared for configuration, but will not work until stage two is completed. For example we have copied files to configure printing and X11. Printing however is likely to need applications not found in the base system, like PostScript® utilities. X11 will not run before we have compiled the server, libraries and programs.

Prev | Home | Next
Prerequisites |  | Stage Two: Ports Installation