定制 Ubuntu 18.04 UEFI 启动盘初探(1)

  工作中需要制作定制化的Ubuntu启动盘,之前有用 buildroot 做过,但是在安装工具方面还是没有Ubuntu灵活方便,所以还是准备基于Ubuntu来制作。

  网上的文章大部分是基于Ubuntu 安装盘来制作,server版本约1GB大小,desktop版本约需要1.9GB。它有以下优点和缺点,即修改目标。

优点:

  • 使用 squash 文件系统,和initramrd相比,不需要全部加载进内存,对内存需求较低
  • 有完整的启动脚本,很多改动需求只要修改这些脚本的配置参数就可以达成

缺点:

  • 镜像太大无法满足频繁改动升级的需要
  • 不需要安装功能,考虑剪除
  • 不是所有应用都需要安装,考虑剪除
  • 需要为不同项目灵活更换配套驱动及工具,需要另行安装
  • 启动界面应按项目内容显示提示菜单

首先研究 boot/grub/grub.cfg中的启动参数,其中 boot=casper 将影响 init脚本中的 BOOT参数值。

menuentry "Try Ubuntu without installing" {
    set gfxpayload=keep
    linux    /casper/vmlinuz  file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash ---
    initrd    /casper/initrd.lz

然后研究 casper/initrd.lz,它负责加载squash文件系统。注意“. /scripts/${BOOT}”会提供“mountroot()”函数。

. /scripts/local
. /scripts/nfs
. /scripts/${BOOT}
parse_numeric ${ROOT}
maybe_break mountroot
mount_top
mount_premount
mountroot

 以下是“mountroot()”函数及其注释,看得出来,大部分casper启动功能都在这里完成。

执行下面3个脚本,都可不予支持

    run_scripts /scripts/casper-premount
10driver_updates
只有带启动参数 debian-installer/driver-update=*
才会真正执行(去找启动盘上的 /cdrom/ubuntu-drivers/$(uname -r)下的驱动更新)
 
20iso_scan
只有带启动参数 iso-scan/filename=* 才会真正执行
 
30custom_installation
只有带启动参数 debian-installer/custom-installation=* 才会真正执行
 
      if [ ! -z "${NETBOOT}" ]; then

如果网络引导,可不予支持,不过支持这个功能调试比较方便

        if do_netmount ; then
              livefs_root="${mountpoint}"
          else
              panic "Unable to find a live file system on the network"
          fi
      else
本地引导         # Scan local devices for the image
          i=0

尝试60次,每次间隔1秒

        while [ "$i" -lt 60 ]; do
 》参考 find_livefs 的实现《             livefs_root=$(find_livefs $i)
搜索启动盘,优先搜启动参数live-media=*指定的设备,
如果没有指定或没能搜到,会在合适时机遍历所有设备搜索
            if [ "${livefs_root}" ]; then
其中 /bin/fstype 查看磁盘文件格式的功能不错,值得注意                 break
              fi
              sleep 1
              i="$(($i + 1))"
          done
      fi
   
      if [ -z "${livefs_root}" ]; then
          panic "Unable to find a medium containing a live file system"
      fi
   
如果启动参数指定 toram     if [ "${TORAM}" ]; then
  则将文件系统加载在内存         live_dest="ram"
如果启动参数指定 todisk=*     elif [ "${TODISK}" ]; then
  则将文件系统加载在磁盘         live_dest="${TODISK}"
      fi
      if [ "${live_dest}" ]; then
          log_begin_msg "Copying live_media to ${live_dest}"
 》参考 copy_live_to 的实现《         copy_live_to "${livefs_root}" "${live_dest}"
          log_end_msg
      fi
   
挂载镜像到目录,会调用setup_unionfs()
 会从/cdrom/casper/下匹配 "ext2" "squashfs" "dir" 后缀的文件或文件夹,并挂载
    mount_images_in_directory "${livefs_root}" "${rootmnt}"
   
      # initialize the /var/crash directory in overlayfs so that inotify for
crash处理机制,并不理解实际工作机制。     # /var/crash works and update-notifier will notify of crashes
      touch /root/var/crash/crash.init
      rm /root/var/crash/crash.init
   
      log_end_msg
   
      # Allow to override USERNAME and HOST based on media information
从initrd的/etc/casper.conf提取到FLAVOUR变量     # make it skipable by setting FLAVOUR= in casper.conf
如果FLAVOUR为空,从启动盘的/.disk/info提取     if [ -f /cdrom/.disk/info ] && [ -z "$FLAVOUR" ]; then
它将影响 HOST,USERNAME,USERFULLNAME,BUILD_SYSTEM         FLAVOUR="$(cut -d' ' -f1 "/cdrom/.disk/info" 2>/dev/null | tr '[A-Z]' '[a-z]')" || FLAVOUR=
/etc/casper.conf里的值是         if [ -n "$FLAVOUR" ]; then
export USERNAME="ubuntu"             HOST=$FLAVOUR
export USERFULLNAME="Live session user"             USERNAME=$FLAVOUR
export HOST="ubuntu"             export HOST USERNAME
export BUILD_SYSTEM="Ubuntu"             sed -i "s,USERNAME=.*,USERNAME=\"$FLAVOUR\",g; s,HOST=.*,HOST=\"$FLAVOUR\",g" /etc/casper.conf
          fi
      fi
   
      # Apply command lines override of HOST, USERNAME and USERFULLNAME
如果命令行有传参设置,
则优先使用其设置 HOST,USERNAME,USERFULLNAME
    [ -n "$CMD_HOST" ] && HOST=$CMD_HOST && export HOST
      [ -n "$CMD_USERNAME" ] && USERNAME=$CMD_USERNAME && export USERNAME
      [ -n "$CMD_USERFULLNAME" ] && USERFULLNAME=$CMD_USERFULLNAME && export USERFULLNAME
      if [ -n "$CMD_HOST" ] || [ -n "$CMD_USERNAME" ] || [ -n "$CMD_USERFULLNAME" ]; then
          sed -i "s,USERNAME=.*,USERNAME=\"$USERNAME\",g; s,USERFULLNAME=.*,USERFULLNAME=\"$USERFULLNAME\",g; s,HOST=.*,HOST=\"$HOST\",g" /etc/casper.conf
      fi
   
      # unionfs-fuse needs /dev to be bind-mounted for the duration of
      # casper-bottom; udev's init script will take care of things after that
如果是unionfs-fuse文件系统,     if [ "${UNIONFS}" = unionfs-fuse ]; then
用“mount -n -o bind ...”挂载/dev设备目录         mount -n -o bind /dev "${rootmnt}/dev"
      fi
   
      # Open up two fifo's fd's for debconf-communicate to use. Speeds up
      # the Casper process considerably.
      log_begin_msg "Creating debconf-communicate fifo mechanism"
用 fifo 加速casper过程     mkfifo /tmp/debconf-in.fifo
结束前这些fifo会被释放删除     mkfifo /tmp/debconf-out.fifo
   
      # Make the template database read-only, so that passthrough debconf
      # instances can write to it directly; otherwise templates are only
      # passed through when necessary.  Use temporary config databases as
      # well; we'll copy their contents back at the end.
      DEBCONF_TMPDIR="$(chroot /root mktemp -dt debconf.XXXXXX)"
      cp -a /root/var/cache/debconf/config.dat "/root$DEBCONF_TMPDIR/"
      cp -a /root/var/cache/debconf/passwords.dat "/root$DEBCONF_TMPDIR/"
      sed "s,^Filename: /var/cache/debconf/\(config\|passwords\).dat$,Filename: $DEBCONF_TMPDIR/\1.dat,; /^Name: templatedb/a\
  Readonly: true" /root/etc/debconf.conf >"/root$DEBCONF_TMPDIR/debconf.conf"
   
      DEBCONF_SYSTEMRC="$DEBCONF_TMPDIR/debconf.conf" chroot /root debconf-communicate -fnoninteractive casper > /tmp/debconf-out.fifo < /tmp/debconf-in.fifo &
      debconfpid="$!"
   
      if [ ! -p /tmp/debconf-in.fifo ] || [ ! -p /tmp/debconf-out.fifo ]; then
          log_warning_msg "failed to setup debconf-communicate channel"
      fi
      log_end_msg
   
      # Order matters!
      # These file descriptors must stay open until we're finished with
      # debconf-communicate.
      exec 4/tmp/debconf-in.fifo
   
      maybe_break casper-bottom
      [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/casper-bottom"
   
》参考对应脚本《     run_scripts /scripts/casper-bottom
      [ "$quiet" != "y" ] && log_end_msg
   
      if [ "${UNIONFS}" = unionfs-fuse ]; then
          umount "${rootmnt}/dev"
      fi
   
      # Close the fd's associated with debconf-communicate.
      exec 3>&- 4<&-
      rm -f /tmp/debconf-in.fifo
      rm -f /tmp/debconf-out.fifo
      wait $debconfpid
   
      # Copy config database changes back to the master files.
      chroot /root debconf-copydb tmpdb config \
          --config=Name:tmpdb --config=Driver:File \
          --config="Filename:$DEBCONF_TMPDIR/config.dat"
      chroot /root debconf-copydb tmpdb passwords \
          --config=Name:tmpdb --config=Driver:File \
          --config="Filename:$DEBCONF_TMPDIR/passwords.dat"
      rm -rf "$DEBCONF_TMPDIR"
   
      exec 1>&6 6>&-
      exec 2>&7 7>&-
      kill "$tailpid"
      cp casper.log "${rootmnt}/var/log/"
      if [ -f /etc/casper.conf ]; then
          cp /etc/casper.conf "${rootmnt}/etc/"
      fi

要修改 casper/initrd.lz, 先了解怎么解压和重新打包

# 解压 initrd.lz

mkdir initrd-dir
cd initrd-dir
cp  ../initrd.lz initrd.lzma
unlzma -d initrd.lzma
cpio -id < initrd
rm  initrd

# 重新打包为 initrd2.lz
cd initrd-dir
find . | cpio --quiet --dereference -o -H newc > ../initrd2
cd ..
lzma -7 initrd2
mv initrd2.lzma  initrd2.lz

这样我们可以做一些改动,比如升级busybox。

/scripts/casper会解析启动参数 live-media-path,我们可以通过指定该值来改变 squashfs文件的搜索路径$LIVE_MEDIA_PATH。

            live-media-path=*)
                LIVE_MEDIA_PATH="${x#live-media-path=}"
                export LIVE_MEDIA_PATH
                echo "export LIVE_MEDIA_PATH=\"$LIVE_MEDIA_PATH\"" >> /etc/casper.conf ;;

 

下一节尝试 用cubic 工具定制启动盘,因为使用这个工具可以将注意力集中在配置软件上。

 

你可能感兴趣的:(Linux,Debian,Ubuntu,系统备份,脚本)