Subject: The smallest multi-user system
To: NetBSD - Users <netbsd-users@netbsd.org>
From: Brian Rose <lists@brianrose.net>
List: netbsd-users
Date: 08/21/2003 23:41:43
This is a pretty long email. There ... I warned you.

After much trial and error I have devised a small NetBSD system that will boot up and start a login session. I crunched this into a ramdrive image which I then embedded into a kernel. This kernel was configured to mount the internal ramdrive as the root, so the whole thing was wrapped up into one nice clean file. I then compressed this file (to about 1,068kB), stuck it on a floppy and booted from it. Below I will detail all the steps that are needed to produce a small system that will get you to the login prompt. Afterwards, I have the script files I used to automate this.

The first thing I did was create a kernel. Some code changes were needed in the 1.6.0 kernel that I was working with. This change was needed to prevent the kernel from going into single user mode when the ramdisk is root. Newer kernels may or may not need changes.

The configuration file needed the following lines to create the ramdisk and boot from it.

# Enable the hooks used for initializing the root memory-disk.
options         MEMORY_DISK_HOOKS
options         MEMORY_DISK_IS_ROOT          # force root on memory disk
options         MEMORY_DISK_SERVER=1         # userspace memory disk support
#options        MEMORY_DISK_ROOT_SIZE=2880   # 1.44M, same as a floppy
options         MEMORY_DISK_ROOT_SIZE=8192   # 4Meg
options         MEMORY_RBFLAGS=0             # don't force single user

I also needed to change this code in my 1.6.0 kernel. The changes are noted by ##'s.

in sys/dev/md_root.c
  /*
   * This is called during open (i.e. mountroot)
   */

  ##  #ifndef MEMORY_RBFLAGS
  ##  #define MEMORY_RBFLAGS RB_SINGLE
  ##  #endif

  void
  md_open_hook(int unit, struct md_conf *md)
  {

  ##  //            ............................... added code
  ##  if (unit == 0 && (MEMORY_RBFLAGS & RB_SINGLE) ) {

      /* The root ramdisk only works single-user. */
      boothowto |= RB_SINGLE;
      }
  } 

Once this was done I built my kernel in the normal manner. 

Next I had to populate the filesystem. The following files will be needed for the multiuser system.

  /sbin/init
  /sbin/mount
  /sbin/mount_ffs
  /sbin/mount_mfs
  /sbin/umount
  /sbin/ttyflags
  /sbin/pwd_mkdb
  /sbin/newfs
  /usr/bin/passwd
  /usr/bin/login
  /bin/sh

  /etc/rc
  /etc/fstab
  /etc/ttys
  /etc/master.passwd
  /etc/pwd.db
  /etc/spwd.db
  /etc/gettytab
  /usr/share/misc/termcap

I copied the password files from my host system and removed the uneeded user entries manually. I also trimmed the termcap file to just the required entries. The termcap file is about 500k otherwise. The rc file is a simple shell script with the following contents.

  echo Initializing system...
  export PATH=/sbin:/bin:/usr/sbin:/usr/bin
  mount -ua
  ttyflags -a


You will also need the /dev nodes. I first copied MAKEDEV into the filesystems dev directory and then did a './MAKEDEV floppy ramdisk wscons' from within that directory.

I then created an image file using makefs, embedded this image into a kernel using mdsetimage, compressed it and then copied it to a bootable floppy. Then I booted and there was much rejoicing!

Enjoy!

--
Brian



================= My crunchgen configuration file ========

srcdirs /usr/src/bin /usr/src/sbin /usr/src/usr.bin /usr/src/usr.sbin /usr/src/libexec


progs init mount newfs mount_ffs sh ttyflags getty pwd_mkdb passwd login reboot ls

ln sh -sh
ln newfs mount_mfs

# special init objpaths /usr/src/sbin/init/init.smallprog.o

# libraries used by the programs
# ---------------- Minimum single user files
# init : -lutil -lcrypt
# mount :
# newfs : -lutil
# mount_ffs : 
# sh : -ll -ledit -ltermcap
# ---------------- Minimum multiuser files
# ttyflags : 
# getty : -lutil -ltermcap
# pwd_mkdb : -lutil
# passwd : -lrpcsvc -lcrypt -lutil -lkrb5 -lcrypto -lasn1 -lcom_err -lroken
# login : -lutil -lcrypt  -lskey  -lkrb5 -lasn1  -lkrb -lcrypto -lroken -lcom_err
# ---------------- Useful utilities
# ls : -
# reboot : -lutil
# umount :
#
libs -lutil -ll -ledit -ltermcap -lcrypt -lrpcsvc -lkrb5 -lkrb -lcrypto -lasn1 -lcom_err -lroken -lskey






=================== Create the crunched binary ==============
  #!/bin/sh
  cd work
  cp ../pcm5894.multi.conf .
  crunchgen -m Makefile pcm5894.multi.conf
  make -f Makefile objs exe
  cd ..
  ls -l work/pcm5894.multi







=================== Populate the filesystem =================

  #!/bin/sh
  # This file is used to populate a directory with the contents needed
  # to run a minimal NetBSD system. As of now there are two parts to
  # this. The first part consists of all the files needed to boot to
  # a single-user shell and some utilities to move around the filesystem. 
  #
  # The second part includes all the files needed to boot into a multi-user
  # configuration, with a login screen and password authentication.
  #######################################################

  if test $1 ; then
    echo Populating $1
   else
    echo "No directory specified"
    exit
  fi


  rm -rf $1/*
  echo -n "Creating directory strucutre..."
  mkdir $1/bin $1/sbin $1/usr $1/etc $1/var $1/dev $1/tmp $1/root $1/home 
  mkdir $1/usr/bin $1/usr/sbin $1/usr/libexec
  mkdir $1/var/run $1/var/db $1/var/crash
  echo "Done."

  #-------------------- Make the /dev nodes
  echo -n "Creating the /dev nodes..."
  cp /dev/MAKEDEV $1/dev
  cd $1/dev
  ./MAKEDEV floppy ramdisk wscons
  cd ../..
  echo "Done."

  #-------------------- Fill in the filesystem
  echo -n "Creating the data files..."
  echo "/dev/md0a / ffs rw 1 1" > $1/etc/fstab

  #-------------------- Setup the basic rc script
  echo "echo Initializing system..." > $1/etc/rc
  echo "export PATH=/sbin:/bin:/usr/sbin:/usr/bin" >> $1/etc/rc
  echo "" >> $1/etc/rc
  echo "Done."

  #######################################
  #   Files for a single boot system    #
  #######################################
  echo -n "Creating single user links and files..."
  cp work/pcm5894.multi $1/sbin/init
  ln $1/sbin/init $1/bin/ls
  ln $1/sbin/init $1/bin/cp
  ln $1/sbin/init $1/bin/cat
  ln $1/sbin/init $1/bin/mkdir
  ln $1/sbin/init $1/sbin/mount
  ln $1/sbin/init $1/sbin/mount_ffs
  ln $1/sbin/init $1/sbin/mount_mfs
  ln $1/sbin/init $1/sbin/umount
  ln $1/sbin/init $1/bin/sh


  #------------- Setup the single user rc script
  echo "mount -ua" >> $1/etc/rc

  echo "Done."

  ##############################################
  #   Files for a mutiuser system              #
  ##############################################
  echo -n "Adding multiuser links and files..."
  #----------------------- Multiuser directories
  mkdir $1/usr/share
  mkdir $1/usr/share/misc
 
  # -------------------- Multiuser program files
  ln $1/sbin/init $1/usr/libexec/getty
  ln $1/sbin/init $1/sbin/ttyflags
  ln $1/sbin/init $1/sbin/pwd_mkdb
  ln $1/sbin/init $1/usr/bin/passwd
  ln $1/sbin/init $1/usr/bin/login
  ln $1/sbin/init $1/sbin/reboot
  ln $1/sbin/init $1/sbin/newfs

  #------------------------ multiuser data files
  cp /etc/ttys $1/etc
  cp /etc/master.passwd $1/etc
  cp /etc/pwd.db $1/etc
  cp /etc/spwd.db $1/etc
  cp /etc/passwd $1/etc
  cp termcap.mini $1/usr/share/misc/termcap 
  cp /etc/gettytab $1/etc

  #---------------- Setup the multiuser rc script
  echo "ttyflags -a" >> $1/etc/rc

  echo "Done."

  #########################################
  #   Files for a minimal rc.d system     #
  #########################################
  #-------------------- Directories
  #-------------------- Programs
  #-------------------- Data files
  #-------------------- rc entries






================== Create the image and kernel ================

#!/bin/sh

if test $1 ; then
  echo Building with filesystem in $1
 else
  echo "No directory specified"
  exit
fi
makefs -s 4m -t ffs crunch.image $1
mdsetimage netbsd.nodebug crunch.image
gzip -c netbsd.nodebug > netbsd
ls -l netbsd