Advertisement
awchjimmy

mkarchiso

Sep 18th, 2018
193
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 13.48 KB | None | 0 0
  1. [root@917e8160b71e /]# cat /usr/sbin/mkarchiso
  2. #!/bin/bash
  3.  
  4. set -e -u
  5.  
  6. export LANG=C
  7.  
  8. app_name=${0##*/}
  9. arch=$(uname -m)
  10. pkg_list=""
  11. run_cmd=""
  12. quiet="y"
  13. pacman_conf="/etc/pacman.conf"
  14. export iso_label="ARCH_$(date +%Y%m)"
  15. iso_publisher="Arch Linux <http://www.archlinux.org>"
  16. iso_application="Arch Linux Live/Rescue CD"
  17. install_dir="arch"
  18. work_dir="work"
  19. out_dir="out"
  20. sfs_mode="sfs"
  21. sfs_comp="xz"
  22. gpg_key=
  23.  
  24. # Show an INFO message
  25. # $1: message string
  26. _msg_info() {
  27.     local _msg="${1}"
  28.     echo "[mkarchiso] INFO: ${_msg}"
  29. }
  30.  
  31. # Show an ERROR message then exit with status
  32. # $1: message string
  33. # $2: exit code number (with 0 does not exit)
  34. _msg_error() {
  35.     local _msg="${1}"
  36.     local _error=${2}
  37.     echo
  38.     echo "[mkarchiso] ERROR: ${_msg}"
  39.     echo
  40.     if [[ ${_error} -gt 0 ]]; then
  41.         exit ${_error}
  42.     fi
  43. }
  44.  
  45. _chroot_init() {
  46.     mkdir -p ${work_dir}/airootfs
  47.     _pacman "base syslinux"
  48. }
  49.  
  50. _chroot_run() {
  51.     eval arch-chroot ${work_dir}/airootfs "${run_cmd}"
  52. }
  53.  
  54. _mount_airootfs() {
  55.     trap "_umount_airootfs" EXIT HUP INT TERM
  56.     mkdir -p "${work_dir}/mnt/airootfs"
  57.     _msg_info "Mounting '${work_dir}/airootfs.img' on '${work_dir}/mnt/airootfs'"
  58.     mount "${work_dir}/airootfs.img" "${work_dir}/mnt/airootfs"
  59.     _msg_info "Done!"
  60. }
  61.  
  62. _umount_airootfs() {
  63.     _msg_info "Unmounting '${work_dir}/mnt/airootfs'"
  64.     umount -d "${work_dir}/mnt/airootfs"
  65.     _msg_info "Done!"
  66.     rmdir "${work_dir}/mnt/airootfs"
  67.     trap - EXIT HUP INT TERM
  68. }
  69.  
  70. # Show help usage, with an exit status.
  71. # $1: exit status number.
  72. _usage ()
  73. {
  74.     echo "usage ${app_name} [options] command <command options>"
  75.     echo " general options:"
  76.     echo "    -p PACKAGE(S)    Package(s) to install, can be used multiple times"
  77.     echo "    -r <command>     Run <command> inside airootfs"
  78.     echo "    -C <file>        Config file for pacman."
  79.     echo "                     Default: '${pacman_conf}'"
  80.     echo "    -L <label>       Set a label for the disk"
  81.     echo "                     Default: '${iso_label}'"
  82.     echo "    -P <publisher>   Set a publisher for the disk"
  83.     echo "                     Default: '${iso_publisher}'"
  84.     echo "    -A <application> Set an application name for the disk"
  85.     echo "                     Default: '${iso_application}'"
  86.     echo "    -D <install_dir> Set an install_dir. All files will by located here."
  87.     echo "                     Default: '${install_dir}'"
  88.     echo "                     NOTE: Max 8 characters, use only [a-z0-9]"
  89.     echo "    -w <work_dir>    Set the working directory"
  90.     echo "                     Default: '${work_dir}'"
  91.     echo "    -o <out_dir>     Set the output directory"
  92.     echo "                     Default: '${out_dir}'"
  93.     echo "    -s <sfs_mode>    Set SquashFS image mode (img or sfs)"
  94.     echo "                     img: prepare airootfs.sfs for dm-snapshot usage"
  95.     echo "                     sfs: prepare airootfs.sfs for overlayfs usage"
  96.     echo "                     Default: ${sfs_mode}"
  97.     echo "    -c <comp_type>   Set SquashFS compression type (gzip, lzma, lzo, xz)"
  98.     echo "                     Default: '${sfs_comp}'"
  99.     echo "    -v               Enable verbose output"
  100.     echo "    -h               This message"
  101.     echo " commands:"
  102.     echo "   init"
  103.     echo "      Make base layout and install base group"
  104.     echo "   install"
  105.     echo "      Install all specified packages (-p)"
  106.     echo "   run"
  107.     echo "      run command specified by -r"
  108.     echo "   prepare"
  109.     echo "      build all images"
  110.     echo "   pkglist"
  111.     echo "      make a pkglist.txt of packages installed on airootfs"
  112.     echo "   iso <image name>"
  113.     echo "      build an iso image from the working dir"
  114.     exit ${1}
  115. }
  116.  
  117. # Shows configuration according to command mode.
  118. # $1: init | install | run | prepare | iso
  119. _show_config () {
  120.     local _mode="$1"
  121.     echo
  122.     _msg_info "Configuration settings"
  123.     _msg_info "                  Command:   ${command_name}"
  124.     _msg_info "             Architecture:   ${arch}"
  125.     _msg_info "        Working directory:   ${work_dir}"
  126.     _msg_info "   Installation directory:   ${install_dir}"
  127.     case "${_mode}" in
  128.         init)
  129.             _msg_info "       Pacman config file:   ${pacman_conf}"
  130.             ;;
  131.         install)
  132.             _msg_info "       Pacman config file:   ${pacman_conf}"
  133.             _msg_info "                 Packages:   ${pkg_list}"
  134.             ;;
  135.         run)
  136.             _msg_info "              Run command:   ${run_cmd}"
  137.             ;;
  138.         prepare)
  139.             ;;
  140.         pkglist)
  141.             ;;
  142.         iso)
  143.             _msg_info "               Image name:   ${img_name}"
  144.             _msg_info "               Disk label:   ${iso_label}"
  145.             _msg_info "           Disk publisher:   ${iso_publisher}"
  146.             _msg_info "         Disk application:   ${iso_application}"
  147.             ;;
  148.     esac
  149.     echo
  150. }
  151.  
  152. # Install desired packages to airootfs
  153. _pacman ()
  154. {
  155.     _msg_info "Installing packages to '${work_dir}/airootfs/'..."
  156.  
  157.     if [[ "${quiet}" = "y" ]]; then
  158.         pacstrap -C "${pacman_conf}" -c -G -M "${work_dir}/airootfs" $* &> /dev/null
  159.     else
  160.         pacstrap -C "${pacman_conf}" -c -G -M "${work_dir}/airootfs" $*
  161.     fi
  162.  
  163.     _msg_info "Packages installed successfully!"
  164. }
  165.  
  166. # Cleanup airootfs
  167. _cleanup () {
  168.     _msg_info "Cleaning up what we can on airootfs..."
  169.  
  170.     # Delete initcpio image(s)
  171.     if [[ -d "${work_dir}/airootfs/boot" ]]; then
  172.         find "${work_dir}/airootfs/boot" -type f -name '*.img' -delete
  173.     fi
  174.     # Delete kernel(s)
  175.     if [[ -d "${work_dir}/airootfs/boot" ]]; then
  176.         find "${work_dir}/airootfs/boot" -type f -name 'vmlinuz*' -delete
  177.     fi
  178.     # Delete pacman database sync cache files (*.tar.gz)
  179.     if [[ -d "${work_dir}/airootfs/var/lib/pacman" ]]; then
  180.         find "${work_dir}/airootfs/var/lib/pacman" -maxdepth 1 -type f -delete
  181.     fi
  182.     # Delete pacman database sync cache
  183.     if [[ -d "${work_dir}/airootfs/var/lib/pacman/sync" ]]; then
  184.         find "${work_dir}/airootfs/var/lib/pacman/sync" -delete
  185.     fi
  186.     # Delete pacman package cache
  187.     if [[ -d "${work_dir}/airootfs/var/cache/pacman/pkg" ]]; then
  188.         find "${work_dir}/airootfs/var/cache/pacman/pkg" -type f -delete
  189.     fi
  190.     # Delete all log files, keeps empty dirs.
  191.     if [[ -d "${work_dir}/airootfs/var/log" ]]; then
  192.         find "${work_dir}/airootfs/var/log" -type f -delete
  193.     fi
  194.     # Delete all temporary files and dirs
  195.     if [[ -d "${work_dir}/airootfs/var/tmp" ]]; then
  196.         find "${work_dir}/airootfs/var/tmp" -mindepth 1 -delete
  197.     fi
  198.     # Delete package pacman related files.
  199.     find "${work_dir}" \( -name "*.pacnew" -o -name "*.pacsave" -o -name "*.pacorig" \) -delete
  200.     _msg_info "Done!"
  201. }
  202.  
  203. # Makes a ext4 filesystem inside a SquashFS from a source directory.
  204. _mkairootfs_img () {
  205.     if [[ ! -e "${work_dir}/airootfs" ]]; then
  206.         _msg_error "The path '${work_dir}/airootfs' does not exist" 1
  207.     fi
  208.  
  209.     _msg_info "Creating ext4 image of 32GiB..."
  210.     truncate -s 32G "${work_dir}/airootfs.img"
  211.     local _qflag=""
  212.     if [[ ${quiet} == "y" ]]; then
  213.         _qflag="-q"
  214.     fi
  215.     mkfs.ext4 ${_qflag} -O ^has_journal,^resize_inode -E lazy_itable_init=0 -m 0 -F "${work_dir}/airootfs.img"
  216.     tune2fs -c 0 -i 0 "${work_dir}/airootfs.img" &> /dev/null
  217.     _msg_info "Done!"
  218.     _mount_airootfs
  219.     _msg_info "Copying '${work_dir}/airootfs/' to '${work_dir}/mnt/airootfs/'..."
  220.     cp -aT "${work_dir}/airootfs/" "${work_dir}/mnt/airootfs/"
  221.     _msg_info "Done!"
  222.     _umount_airootfs
  223.     mkdir -p "${work_dir}/iso/${install_dir}/${arch}"
  224.     _msg_info "Creating SquashFS image, this may take some time..."
  225.     if [[ "${quiet}" = "y" ]]; then
  226.         mksquashfs "${work_dir}/airootfs.img" "${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs" -noappend -comp "${sfs_comp}" -no-progress &> /dev/null
  227.     else
  228.         mksquashfs "${work_dir}/airootfs.img" "${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs" -noappend -comp "${sfs_comp}" -no-progress
  229.     fi
  230.     _msg_info "Done!"
  231.     rm ${work_dir}/airootfs.img
  232. }
  233.  
  234. # Makes a SquashFS filesystem from a source directory.
  235. _mkairootfs_sfs () {
  236.     if [[ ! -e "${work_dir}/airootfs" ]]; then
  237.         _msg_error "The path '${work_dir}/airootfs' does not exist" 1
  238.     fi
  239.  
  240.     mkdir -p "${work_dir}/iso/${install_dir}/${arch}"
  241.     _msg_info "Creating SquashFS image, this may take some time..."
  242.     if [[ "${quiet}" = "y" ]]; then
  243.         mksquashfs "${work_dir}/airootfs" "${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs" -noappend -comp "${sfs_comp}" -no-progress &> /dev/null
  244.     else
  245.         mksquashfs "${work_dir}/airootfs" "${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs" -noappend -comp "${sfs_comp}" -no-progress
  246.     fi
  247.     _msg_info "Done!"
  248. }
  249.  
  250. _mkchecksum () {
  251.     _msg_info "Creating checksum file for self-test..."
  252.     cd "${work_dir}/iso/${install_dir}/${arch}"
  253.     sha512sum airootfs.sfs > airootfs.sha512
  254.     cd ${OLDPWD}
  255.     _msg_info "Done!"
  256. }
  257.  
  258. _mksignature () {
  259.     _msg_info "Creating signature file..."
  260.     cd "${work_dir}/iso/${install_dir}/${arch}"
  261.     gpg --detach-sign --default-key ${gpg_key} airootfs.sfs
  262.     cd ${OLDPWD}
  263.     _msg_info "Done!"
  264. }
  265.  
  266. command_pkglist () {
  267.     _show_config pkglist
  268.  
  269.     _msg_info "Creating a list of installed packages on live-enviroment..."
  270.     pacman -Q --sysroot "${work_dir}/airootfs" > \
  271.         "${work_dir}/iso/${install_dir}/pkglist.${arch}.txt"
  272.     _msg_info "Done!"
  273.  
  274. }
  275.  
  276. # Create an ISO9660 filesystem from "iso" directory.
  277. command_iso () {
  278.     local _iso_efi_boot_args=""
  279.  
  280.     if [[ ! -f "${work_dir}/iso/isolinux/isolinux.bin" ]]; then
  281.          _msg_error "The file '${work_dir}/iso/isolinux/isolinux.bin' does not exist." 1
  282.     fi
  283.     if [[ ! -f "${work_dir}/iso/isolinux/isohdpfx.bin" ]]; then
  284.          _msg_error "The file '${work_dir}/iso/isolinux/isohdpfx.bin' does not exist." 1
  285.     fi
  286.  
  287.     # If exists, add an EFI "El Torito" boot image (FAT filesystem) to ISO-9660 image.
  288.     if [[ -f "${work_dir}/iso/EFI/archiso/efiboot.img" ]]; then
  289.         _iso_efi_boot_args="-eltorito-alt-boot
  290.                            -e EFI/archiso/efiboot.img
  291.                            -no-emul-boot
  292.                            -isohybrid-gpt-basdat"
  293.     fi
  294.  
  295.     _show_config iso
  296.  
  297.     mkdir -p ${out_dir}
  298.     _msg_info "Creating ISO image..."
  299.     local _qflag=""
  300.     if [[ ${quiet} == "y" ]]; then
  301.         _qflag="-quiet"
  302.     fi
  303.     xorriso -as mkisofs ${_qflag} \
  304.         -iso-level 3 \
  305.         -full-iso9660-filenames \
  306.         -volid "${iso_label}" \
  307.         -appid "${iso_application}" \
  308.         -publisher "${iso_publisher}" \
  309.         -preparer "prepared by mkarchiso" \
  310.         -eltorito-boot isolinux/isolinux.bin \
  311.         -eltorito-catalog isolinux/boot.cat \
  312.         -no-emul-boot -boot-load-size 4 -boot-info-table \
  313.         -isohybrid-mbr ${work_dir}/iso/isolinux/isohdpfx.bin \
  314.         ${_iso_efi_boot_args} \
  315.         -output "${out_dir}/${img_name}" \
  316.         "${work_dir}/iso/"
  317.     _msg_info "Done! | $(ls -sh ${out_dir}/${img_name})"
  318. }
  319.  
  320. # create airootfs.sfs filesystem, and push it in "iso" directory.
  321. command_prepare () {
  322.     _show_config prepare
  323.  
  324.     _cleanup
  325.     if [[ ${sfs_mode} == "sfs" ]]; then
  326.         _mkairootfs_sfs
  327.     else
  328.         _mkairootfs_img
  329.     fi
  330.     _mkchecksum
  331.     if [[ ${gpg_key} ]]; then
  332.       _mksignature
  333.     fi
  334. }
  335.  
  336. # Install packages on airootfs.
  337. # A basic check to avoid double execution/reinstallation is done via hashing package names.
  338. command_install () {
  339.     if [[ ! -f "${pacman_conf}" ]]; then
  340.         _msg_error "Pacman config file '${pacman_conf}' does not exist" 1
  341.     fi
  342.  
  343.     #trim spaces
  344.     pkg_list="$(echo ${pkg_list})"
  345.  
  346.     if [[ -z ${pkg_list} ]]; then
  347.         _msg_error "Packages must be specified" 0
  348.         _usage 1
  349.     fi
  350.  
  351.     _show_config install
  352.  
  353.     _pacman "${pkg_list}"
  354. }
  355.  
  356. command_init() {
  357.     _show_config init
  358.     _chroot_init
  359. }
  360.  
  361. command_run() {
  362.     _show_config run
  363.     _chroot_run
  364. }
  365.  
  366. if [[ ${EUID} -ne 0 ]]; then
  367.     _msg_error "This script must be run as root." 1
  368. fi
  369.  
  370. umask 0022
  371.  
  372. while getopts 'p:r:C:L:P:A:D:w:o:s:c:g:vh' arg; do
  373.     case "${arg}" in
  374.         p) pkg_list="${pkg_list} ${OPTARG}" ;;
  375.         r) run_cmd="${OPTARG}" ;;
  376.         C) pacman_conf="${OPTARG}" ;;
  377.         L) iso_label="${OPTARG}" ;;
  378.         P) iso_publisher="${OPTARG}" ;;
  379.         A) iso_application="${OPTARG}" ;;
  380.         D) install_dir="${OPTARG}" ;;
  381.         w) work_dir="${OPTARG}" ;;
  382.         o) out_dir="${OPTARG}" ;;
  383.         s) sfs_mode="${OPTARG}" ;;
  384.         c) sfs_comp="${OPTARG}" ;;
  385.         g) gpg_key="${OPTARG}" ;;
  386.         v) quiet="n" ;;
  387.         h|?) _usage 0 ;;
  388.         *)
  389.             _msg_error "Invalid argument '${arg}'" 0
  390.             _usage 1
  391.             ;;
  392.     esac
  393. done
  394.  
  395. shift $((OPTIND - 1))
  396.  
  397. if [[ $# -lt 1 ]]; then
  398.     _msg_error "No command specified" 0
  399.     _usage 1
  400. fi
  401. command_name="${1}"
  402.  
  403. case "${command_name}" in
  404.     init)
  405.         command_init
  406.         ;;
  407.     install)
  408.         command_install
  409.         ;;
  410.     run)
  411.         command_run
  412.         ;;
  413.     prepare)
  414.         command_prepare
  415.         ;;
  416.     pkglist)
  417.         command_pkglist
  418.         ;;
  419.     iso)
  420.         if [[ $# -lt 2 ]]; then
  421.             _msg_error "No image specified" 0
  422.             _usage 1
  423.         fi
  424.         img_name="${2}"
  425.         command_iso
  426.         ;;
  427.     *)
  428.         _msg_error "Invalid command name '${command_name}'" 0
  429.         _usage 1
  430.         ;;
  431. esac
  432.  
  433. # vim:ts=4:sw=4:et:
  434. [root@917e8160b71e /]#
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement