mknet.sh 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #!/bin/sh
  2. #
  3. #-
  4. # Copyright (c) 2009-2015 Juan Romero Pardines.
  5. # All rights reserved.
  6. #
  7. # Redistribution and use in source and binary forms, with or without
  8. # modification, are permitted provided that the following conditions
  9. # are met:
  10. # 1. Redistributions of source code must retain the above copyright
  11. # notice, this list of conditions and the following disclaimer.
  12. # 2. Redistributions in binary form must reproduce the above copyright
  13. # notice, this list of conditions and the following disclaimer in the
  14. # documentation and/or other materials provided with the distribution.
  15. #
  16. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21. # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25. # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. #-
  27. readonly PROGNAME=$(basename "$0")
  28. readonly REQTOOLS="xbps-install tar"
  29. # This script needs to jump around, so we'll remember where we started
  30. # so that we can get back here
  31. readonly CURDIR="$(pwd)"
  32. # This source pulls in all the functions from lib.sh. This set of
  33. # functions makes it much easier to work with chroots and abstracts
  34. # away all the problems with running binaries with QEMU.
  35. # shellcheck source=./lib.sh
  36. . ./lib.sh
  37. # Die is a function provided in lib.sh which handles the cleanup of
  38. # the mounts and removal of temporary directories if the running
  39. # program exists unexpectedly.
  40. trap 'bailout' INT TERM
  41. bailout() {
  42. [ -d "$BOOT_DIR" ] && rm -rf "$BOOT_DIR"
  43. die "An unchecked exception has occured!"
  44. }
  45. usage() {
  46. cat <<-EOH
  47. Usage: $PROGNAME [options] <rootfs-tarball>
  48. Generates a network-bootable tarball from a Void Linux ROOTFS generated by mkrootfs.
  49. OPTIONS
  50. -r <repo> Use this XBPS repository. May be specified multiple times
  51. -c <cachedir> Use this XBPS cache directory (default: )
  52. -i <lz4|gzip|bzip2|xz>
  53. Compression type for the initramfs image (default: xz)
  54. -o <file> Output file name for the netboot tarball (default: automatic)
  55. -K linux<version> Install a custom Linux version on ISO image (default: linux metapackage)
  56. -k <keymap> Default keymap to use (default: us)
  57. -l <locale> Default locale to use (default: en_US.UTF-8)
  58. -C "<arg> ..." Add additional kernel command line arguments
  59. -T <title> Modify the bootloader title (default: Void Linux)
  60. -S <image> Set a custom splash image for the bootloader (default: data/splash.png)
  61. -h Show this help and exit
  62. -V Show version and exit
  63. EOH
  64. }
  65. # ########################################
  66. # SCRIPT EXECUTION STARTS HERE
  67. # ########################################
  68. while getopts "r:c:C:T:K:i:o:k:l:S:Vh" opt; do
  69. case $opt in
  70. r) XBPS_REPOSITORY="--repository=$OPTARG $XBPS_REPOSITORY";;
  71. c) XBPS_CACHEDIR="--cachedir=$OPTARG";;
  72. i) INITRAMFS_COMPRESSION="$OPTARG";;
  73. K) KERNELPKG="$OPTARG";;
  74. o) OUTPUT_FILE="$OPTARG";;
  75. k) KEYMAP="$OPTARG";;
  76. l) LOCALE="$OPTARG";;
  77. C) BOOT_CMDLINE="$OPTARG";;
  78. T) BOOT_TITLE="$OPTARG";;
  79. S) SPLASH_IMAGE="$OPTARG";;
  80. V) version; exit 0;;
  81. h) usage; exit 0;;
  82. *) usage >&2; exit 1;;
  83. esac
  84. done
  85. shift $((OPTIND - 1))
  86. BASE_TARBALL="$1"
  87. # We need to infer the target architecture from the filename. All
  88. # other scripts are able to get this from the platforms map because a
  89. # platform is manually specified. Since the netboot tarballs target
  90. # only architectures, its necessary to pull this information from the
  91. # filename.
  92. XBPS_TARGET_ARCH=${BASE_TARBALL%%-ROOTFS*}
  93. XBPS_TARGET_ARCH=${XBPS_TARGET_ARCH##void-}
  94. # Knowing the target arch, we can set the cache up if it hasn't
  95. # already been set
  96. set_cachedir
  97. # This is an aweful hack since the script isn't using privesc
  98. # mechanisms selectively. This is a TODO item.
  99. if [ "$(id -u)" -ne 0 ]; then
  100. die "need root perms to continue, exiting."
  101. fi
  102. # Before going any further, check that the tools that are needed are
  103. # present. If we delayed this we could check for the QEMU binary, but
  104. # its a reasonable tradeoff to just bail out now.
  105. check_tools
  106. # We need to operate on a tempdir, if this fails to create, it is
  107. # absolutely crucial to bail out so that we don't hose the system that
  108. # is running the script.
  109. ROOTFS=$(mktemp -d) || die "failed to create ROOTFS tempdir, exiting..."
  110. BOOT_DIR=$(mktemp -d) || die "failed to create BOOT_DIR tempdir, exiting..."
  111. PXELINUX_DIR="$BOOT_DIR/pxelinux.cfg"
  112. # Now that we have a directory for the ROOTFS, we can expand the
  113. # existing base filesystem into the directory
  114. info_msg "Expanding base tarball $BASE_TARBALL into $ROOTFS for $PLATFORM build."
  115. tar xf "$BASE_TARBALL" -C "$ROOTFS"
  116. info_msg "Install additional dracut modules"
  117. # This section sets up the dracut modules that need to be present on
  118. # the ROOTFS to build the PXE tarball. This includes the netmenu
  119. # module and the autoinstaller
  120. mkdir -p "$ROOTFS/usr/lib/dracut/modules.d/05netmenu"
  121. cp dracut/netmenu/* "$ROOTFS/usr/lib/dracut/modules.d/05netmenu/"
  122. # The netmenu can directly launch the manual installer from the
  123. # initrd. This is the same installer that's on the live media with
  124. # all its quirks, oddities, and wierdness. It's included here for
  125. # places where you might have a lab network and need to run manual
  126. # installs from the network.
  127. cp installer.sh "$ROOTFS/usr/lib/dracut/modules.d/05netmenu/"
  128. # Of course with a PXE environment unattended installs are the norm.
  129. # The autoinstaller is loaded as a very high priority dracut module
  130. # and will fail the build if it can't be installed.
  131. mkdir -p "$ROOTFS/usr/lib/dracut/modules.d/01autoinstaller"
  132. cp dracut/autoinstaller/* "$ROOTFS/usr/lib/dracut/modules.d/01autoinstaller/"
  133. info_msg "Install kernel and additional required netboot packages"
  134. # The rootfs has no kernel in it, so it needs to have at the very
  135. # least dracut, syslinux, and linux installed. binutils provides
  136. # /usr/bin/strip which lets us shrink down the size of the initrd
  137. # dracut-network provides the in-initrd network stack dialog is needed
  138. # by the install environment. ${INITRAMFS_COMPRESSION} is the name of
  139. # the compressor we want to use (lz4 by default).
  140. if [ -z "${XBPS_TARGET_ARCH##*86*}" ] ; then
  141. # This platform is x86 or compatible, we should use
  142. # syslinux/pxelinux to boot the system.
  143. info_msg "Selecting syslinux bootloader"
  144. bootloader_pkg=syslinux
  145. else
  146. # This is likely an arm platform of some kind. In general these
  147. # either have u-boot or a u-boot compatible loader, so we'll use
  148. # that to produce a uImage and a uInitrd
  149. info_msg "Selecting u-boot bootloader"
  150. bootloader_pkg=uboot-mkimage
  151. fi
  152. run_cmd_target "xbps-install $XBPS_CONFFILE $XBPS_CACHEDIR $XBPS_REPOSITORY -r $ROOTFS -Sy ${KERNELPKG-linux} dracut binutils dracut-network dialog ${INITRAMFS_COMPRESSION-xz} ${bootloader_pkg}"
  153. run_cmd_chroot "$ROOTFS" "xbps-reconfigure -a"
  154. # Dracut needs to know the kernel version that will be using this
  155. # initrd so that it can install the kernel drivers in it. Normally
  156. # this check is quite complex, but since this is a clean rootfs and we
  157. # just installed exactly one kernel, this check can get by with a
  158. # really naive command to figure out the kernel version
  159. KERNELVERSION=$(ls "$ROOTFS/usr/lib/modules/")
  160. # Now that things are setup, we can call dracut and build the initrd.
  161. # This will pretty much step through the normal process to build
  162. # initrd with the exception that the autoinstaller and netmenu are
  163. # force added since no module depends on them.
  164. info_msg "Building initrd for kernel version $KERNELVERSION"
  165. run_cmd_chroot "$ROOTFS" "env -i /usr/bin/dracut \
  166. -N \
  167. --${INITRAMFS_COMPRESSION-xz} \
  168. --add-drivers ahci \
  169. --force-add 'autoinstaller netmenu' \
  170. --omit systemd \
  171. /boot/initrd \
  172. $KERNELVERSION"
  173. [ $? -ne 0 ] && die "Failed to generate the initramfs"
  174. info_msg "Collect netboot components"
  175. if [ ${bootloader_pkg} = "syslinux" ] ; then
  176. # The whole point of this endeavor is to get the files needed for PXE.
  177. # Now that they have been generated, we copy them out of the doomed
  178. # ROOTFS and into the $BOOT_DIR where we're staging the rest of the
  179. # tarball
  180. mv -v "$ROOTFS/boot/initrd" "$BOOT_DIR"
  181. cp -v "$ROOTFS/boot/vmlinuz-$KERNELVERSION" "$BOOT_DIR/vmlinuz"
  182. # The initrd has *very* restrictive permissions by default. To
  183. # prevent some SysAdmin down the road having a very frustrating time
  184. # debugging this, we just fix this here and now.
  185. chmod 0644 "$BOOT_DIR/initrd"
  186. # Now we need to grab the rest of the files that go in the tarball.
  187. # Some of these are always required, some of these are canonical, and
  188. # some of this list is from trial and error. Either way, this is the
  189. # minimum needed to get Void up and booting on metal from the network.
  190. for prog in pxelinux.0 ldlinux.c32 libcom32.c32 vesamenu.c32 libutil.c32 chain.c32 ; do
  191. cp -v "$ROOTFS/usr/lib/syslinux/$prog" "$BOOT_DIR"
  192. done
  193. # Lastly we need the default pxelinux config and the splash image.
  194. # This is user configurable, but if that isn't set then we'll use the
  195. # one from data/splash.png instead
  196. mkdir -p "$PXELINUX_DIR"
  197. cp -f pxelinux.cfg/pxelinux.cfg.in "$PXELINUX_DIR/default"
  198. cp -f "${SPLASH_IMAGE-data/splash.png}" "$BOOT_DIR"
  199. # This sets all the variables in the default config file
  200. info_msg "Configuring pxelinux.0 default boot menu"
  201. sed -i -e "s|@@SPLASHIMAGE@@|$(basename "${SPLASH_IMAGE-splash.png}")|" \
  202. -e "s|@@KERNVER@@|${KERNELVERSION}|" \
  203. -e "s|@@KEYMAP@@|${KEYMAP-us}|" \
  204. -e "s|@@ARCH@@|$XBPS_TARGET_ARCH|" \
  205. -e "s|@@LOCALE@@|${LOCALE-en_US.UTF-8}|" \
  206. -e "s|@@BOOT_TITLE@@|${BOOT_TITLE-Void Linux}|" \
  207. -e "s|@@BOOT_CMDLINE@@|${BOOT_CMDLINE}|" \
  208. "$PXELINUX_DIR/default"
  209. else
  210. # u-boot has far far fewer components, but u-boot artifacts do
  211. # require some pre-processing
  212. if [ ! -f "$ROOTFS/boot/uImage" ] ; then
  213. # Build the uImage, this is really just the kernel with a wrapper
  214. # to make u-boot happy. It also sets the load and entry
  215. # addresses, though in general these are overriden by the u-boot
  216. # configuration.
  217. run_cmd_chroot "$ROOTFS" "env -i /usr/bin/mkimage -A arm -O linux -T kernel -C none -a 0x00000000 -e 0x00000000 -n 'Void Kernel' -d /boot/zImage /boot/uImage"
  218. # Build the uInitrd which is similarly just a copy of the real
  219. # initrd in a format that u-boot is willing to ingest.
  220. run_cmd_chroot "$ROOTFS" "env -i /usr/bin/mkimage -A arm -O linux -T ramdisk -C none -a 0 -e 0 -n 'Void Installer Initrd' -d /boot/initrd /boot/uInitrd"
  221. # Copy out the artifacts that are worth keeping
  222. cp "$ROOTFS/boot/uImage" "$BOOT_DIR"
  223. cp "$ROOTFS/boot/uInitrd" "$BOOT_DIR"
  224. cp -r "$ROOTFS/boot/dtbs" "$BOOT_DIR"
  225. else
  226. # Copy the existing uImage out
  227. cp "$ROOTFS/boot/uImage" "$BOOT_DIR"
  228. fi
  229. fi
  230. # Compress the artifacts for distribution
  231. OUTPUT_FILE="void-${XBPS_TARGET_ARCH}-NETBOOT-$(date -u +%Y%m%d).tar.gz"
  232. info_msg "Compressing results to $OUTPUT_FILE"
  233. cd "$BOOT_DIR" || die "Could not enter image dir"
  234. tar -zcvf "$CURDIR/$OUTPUT_FILE" .
  235. cd "$CURDIR" || die "Could not return to working directory"
  236. # As a final cleanup step, remove the ROOTFS and the expanded BOOT_DIR
  237. info_msg "Cleaning up and removing build directories"
  238. cleanup_chroot
  239. [ -d "$ROOTFS" ] && rm -rf "$ROOTFS"
  240. [ -d "$BOOT_DIR" ] && rm -rf "$BOOT_DIR"