Advertisement
awchjimmy

pacstrap

Sep 18th, 2018
114
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 9.05 KB | None | 0 0
  1. [root@917e8160b71e /]# cat /usr/sbin/pacstrap
  2. #!/bin/bash
  3.  
  4. #
  5. # Assumptions:
  6. #  1) User has partitioned, formatted, and mounted partitions on /mnt
  7. #  2) Network is functional
  8. #  3) Arguments passed to the script are valid pacman targets
  9. #  4) A valid mirror appears in /etc/pacman.d/mirrorlist
  10. #
  11.  
  12. shopt -s extglob
  13.  
  14. # generated from util-linux source: libmount/src/utils.c
  15. declare -A pseudofs_types=([anon_inodefs]=1
  16.                            [autofs]=1
  17.                            [bdev]=1
  18.                            [binfmt_misc]=1
  19.                            [cgroup]=1
  20.                            [cgroup2]=1
  21.                            [configfs]=1
  22.                            [cpuset]=1
  23.                            [debugfs]=1
  24.                            [devfs]=1
  25.                            [devpts]=1
  26.                            [devtmpfs]=1
  27.                            [dlmfs]=1
  28.                            [fuse.gvfs-fuse-daemon]=1
  29.                            [fusectl]=1
  30.                            [hugetlbfs]=1
  31.                            [mqueue]=1
  32.                            [nfsd]=1
  33.                            [none]=1
  34.                            [pipefs]=1
  35.                            [proc]=1
  36.                            [pstore]=1
  37.                            [ramfs]=1
  38.                            [rootfs]=1
  39.                            [rpc_pipefs]=1
  40.                            [securityfs]=1
  41.                            [sockfs]=1
  42.                            [spufs]=1
  43.                            [sysfs]=1
  44.                            [tmpfs]=1)
  45.  
  46. # generated from: pkgfile -vbr '/fsck\..+' | awk -F. '{ print $NF }' | sort
  47. declare -A fsck_types=([cramfs]=1
  48.                        [exfat]=1
  49.                        [ext2]=1
  50.                        [ext3]=1
  51.                        [ext4]=1
  52.                        [ext4dev]=1
  53.                        [jfs]=1
  54.                        [minix]=1
  55.                        [msdos]=1
  56.                        [reiserfs]=1
  57.                        [vfat]=1
  58.                        [xfs]=1)
  59.  
  60. out() { printf "$1 $2\n" "${@:3}"; }
  61. error() { out "==> ERROR:" "$@"; } >&2
  62. msg() { out "==>" "$@"; }
  63. msg2() { out "  ->" "$@";}
  64. die() { error "$@"; exit 1; }
  65.  
  66. ignore_error() {
  67.   "$@" 2>/dev/null
  68.   return 0
  69. }
  70.  
  71. in_array() {
  72.   local i
  73.   for i in "${@:2}"; do
  74.     [[ $1 = "$i" ]] && return 0
  75.   done
  76.   return 1
  77. }
  78.  
  79. chroot_add_mount() {
  80.   mount "$@" && CHROOT_ACTIVE_MOUNTS=("$2" "${CHROOT_ACTIVE_MOUNTS[@]}")
  81. }
  82.  
  83. chroot_maybe_add_mount() {
  84.   local cond=$1; shift
  85.   if eval "$cond"; then
  86.     chroot_add_mount "$@"
  87.   fi
  88. }
  89.  
  90. chroot_setup() {
  91.   CHROOT_ACTIVE_MOUNTS=()
  92.   [[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap'
  93.   trap 'chroot_teardown' EXIT
  94.  
  95.   chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev &&
  96.   chroot_add_mount sys "$1/sys" -t sysfs -o nosuid,noexec,nodev,ro &&
  97.   ignore_error chroot_maybe_add_mount "[[ -d '$1/sys/firmware/efi/efivars' ]]" \
  98.       efivarfs "$1/sys/firmware/efi/efivars" -t efivarfs -o nosuid,noexec,nodev &&
  99.   chroot_add_mount udev "$1/dev" -t devtmpfs -o mode=0755,nosuid &&
  100.   chroot_add_mount devpts "$1/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec &&
  101.   chroot_add_mount shm "$1/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev &&
  102.   chroot_add_mount run "$1/run" -t tmpfs -o nosuid,nodev,mode=0755 &&
  103.   chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,strictatime,nodev,nosuid
  104. }
  105.  
  106. chroot_teardown() {
  107.   umount "${CHROOT_ACTIVE_MOUNTS[@]}"
  108.   unset CHROOT_ACTIVE_MOUNTS
  109. }
  110.  
  111. try_cast() (
  112.   _=$(( $1#$2 ))
  113. ) 2>/dev/null
  114.  
  115. valid_number_of_base() {
  116.   local base=$1 len=${#2} i=
  117.  
  118.   for (( i = 0; i < len; i++ )); do
  119.     try_cast "$base" "${2:i:1}" || return 1
  120.   done
  121.  
  122.   return 0
  123. }
  124.  
  125. mangle() {
  126.   local i= chr= out=
  127.   local {a..f}= {A..F}=
  128.  
  129.   for (( i = 0; i < ${#1}; i++ )); do
  130.     chr=${1:i:1}
  131.     case $chr in
  132.       [[:space:]\\])
  133.         printf -v chr '%03o' "'$chr"
  134.         out+=\\
  135.         ;;
  136.     esac
  137.     out+=$chr
  138.   done
  139.  
  140.   printf '%s' "$out"
  141. }
  142.  
  143. unmangle() {
  144.   local i= chr= out= len=$(( ${#1} - 4 ))
  145.   local {a..f}= {A..F}=
  146.  
  147.   for (( i = 0; i < len; i++ )); do
  148.     chr=${1:i:1}
  149.     case $chr in
  150.       \\)
  151.         if valid_number_of_base 8 "${1:i+1:3}" ||
  152.             valid_number_of_base 16 "${1:i+1:3}"; then
  153.           printf -v chr '%b' "${1:i:4}"
  154.           (( i += 3 ))
  155.         fi
  156.         ;;
  157.     esac
  158.     out+=$chr
  159.   done
  160.  
  161.   printf '%s' "$out${1:i}"
  162. }
  163.  
  164. optstring_match_option() {
  165.   local candidate pat patterns
  166.  
  167.   IFS=, read -ra patterns <<<"$1"
  168.   for pat in "${patterns[@]}"; do
  169.     if [[ $pat = *=* ]]; then
  170.       # "key=val" will only ever match "key=val"
  171.       candidate=$2
  172.     else
  173.       # "key" will match "key", but also "key=anyval"
  174.       candidate=${2%%=*}
  175.     fi
  176.  
  177.     [[ $pat = "$candidate" ]] && return 0
  178.   done
  179.  
  180.   return 1
  181. }
  182.  
  183. optstring_remove_option() {
  184.   local o options_ remove=$2 IFS=,
  185.  
  186.   read -ra options_ <<<"${!1}"
  187.  
  188.   for o in "${!options_[@]}"; do
  189.     optstring_match_option "$remove" "${options_[o]}" && unset 'options_[o]'
  190.   done
  191.  
  192.   declare -g "$1=${options_[*]}"
  193. }
  194.  
  195. optstring_normalize() {
  196.   local o options_ norm IFS=,
  197.  
  198.   read -ra options_ <<<"${!1}"
  199.  
  200.   # remove empty fields
  201.   for o in "${options_[@]}"; do
  202.     [[ $o ]] && norm+=("$o")
  203.   done
  204.  
  205.   # avoid empty strings, reset to "defaults"
  206.   declare -g "$1=${norm[*]:-defaults}"
  207. }
  208.  
  209. optstring_append_option() {
  210.   if ! optstring_has_option "$1" "$2"; then
  211.     declare -g "$1=${!1},$2"
  212.   fi
  213.  
  214.   optstring_normalize "$1"
  215. }
  216.  
  217. optstring_prepend_option() {
  218.   local options_=$1
  219.  
  220.   if ! optstring_has_option "$1" "$2"; then
  221.     declare -g "$1=$2,${!1}"
  222.   fi
  223.  
  224.   optstring_normalize "$1"
  225. }
  226.  
  227. optstring_get_option() {
  228.   local opts o
  229.  
  230.   IFS=, read -ra opts <<<"${!1}"
  231.   for o in "${opts[@]}"; do
  232.     if optstring_match_option "$2" "$o"; then
  233.       declare -g "$o"
  234.       return 0
  235.     fi
  236.   done
  237.  
  238.   return 1
  239. }
  240.  
  241. optstring_has_option() {
  242.   local "${2%%=*}"
  243.  
  244.   optstring_get_option "$1" "$2"
  245. }
  246.  
  247. dm_name_for_devnode() {
  248.   read dm_name <"/sys/class/block/${1#/dev/}/dm/name"
  249.   if [[ $dm_name ]]; then
  250.     printf '/dev/mapper/%s' "$dm_name"
  251.   else
  252.     # don't leave the caller hanging, just print the original name
  253.     # along with the failure.
  254.     print '%s' "$1"
  255.     error 'Failed to resolve device mapper name for: %s' "$1"
  256.   fi
  257. }
  258.  
  259. fstype_is_pseudofs() {
  260.   (( pseudofs_types["$1"] ))
  261. }
  262.  
  263. fstype_has_fsck() {
  264.   (( fsck_types["$1"] ))
  265. }
  266.  
  267.  
  268. hostcache=0
  269. copykeyring=1
  270. copymirrorlist=1
  271.  
  272. usage() {
  273.   cat <<EOF
  274. usage: ${0##*/} [options] root [packages...]
  275.  
  276.   Options:
  277.     -C config      Use an alternate config file for pacman
  278.     -c             Use the package cache on the host, rather than the target
  279.     -G             Avoid copying the host's pacman keyring to the target
  280.     -i             Avoid auto-confirmation of package selections
  281.     -M             Avoid copying the host's mirrorlist to the target
  282.  
  283.     -h             Print this help message
  284.  
  285. pacstrap installs packages to the specified new root directory. If no packages
  286. are given, pacstrap defaults to the "base" group.
  287.  
  288. EOF
  289. }
  290.  
  291. if [[ -z $1 || $1 = @(-h|--help) ]]; then
  292.   usage
  293.   exit $(( $# ? 0 : 1 ))
  294. fi
  295.  
  296. (( EUID == 0 )) || die 'This script must be run with root privileges'
  297.  
  298. while getopts ':C:cdGiM' flag; do
  299.   case $flag in
  300.     C)
  301.       pacman_config=$OPTARG
  302.       ;;
  303.     d)
  304.       # retired flag. does nothing.
  305.       ;;
  306.     c)
  307.       hostcache=1
  308.       ;;
  309.     i)
  310.       interactive=1
  311.       ;;
  312.     G)
  313.       copykeyring=0
  314.       ;;
  315.     M)
  316.       copymirrorlist=0
  317.       ;;
  318.     :)
  319.       die '%s: option requires an argument -- '\''%s'\' "${0##*/}" "$OPTARG"
  320.       ;;
  321.     ?)
  322.       die '%s: invalid option -- '\''%s'\' "${0##*/}" "$OPTARG"
  323.       ;;
  324.   esac
  325. done
  326. shift $(( OPTIND - 1 ))
  327.  
  328. (( $# )) || die "No root directory specified"
  329. newroot=$1; shift
  330. pacman_args=("${@:-base}")
  331.  
  332. if (( ! hostcache )); then
  333.   pacman_args+=(--cachedir="$newroot/var/cache/pacman/pkg")
  334. fi
  335.  
  336. if (( ! interactive )); then
  337.   pacman_args+=(--noconfirm)
  338. fi
  339.  
  340. if [[ $pacman_config ]]; then
  341.   pacman_args+=(--config="$pacman_config")
  342. fi
  343.  
  344. [[ -d $newroot ]] || die "%s is not a directory" "$newroot"
  345.  
  346. # create obligatory directories
  347. msg 'Creating install root at %s' "$newroot"
  348. mkdir -m 0755 -p "$newroot"/var/{cache/pacman/pkg,lib/pacman,log} "$newroot"/{dev,run,etc}
  349. mkdir -m 1777 -p "$newroot"/tmp
  350. mkdir -m 0555 -p "$newroot"/{sys,proc}
  351.  
  352. # mount API filesystems
  353. chroot_setup "$newroot" || die "failed to setup chroot %s" "$newroot"
  354.  
  355. msg 'Installing packages to %s' "$newroot"
  356. if ! pacman -r "$newroot" -Sy "${pacman_args[@]}"; then
  357.   die 'Failed to install packages to new root'
  358. fi
  359.  
  360. if (( copykeyring )); then
  361.   # if there's a keyring on the host, copy it into the new root, unless it exists already
  362.   if [[ -d /etc/pacman.d/gnupg && ! -d $newroot/etc/pacman.d/gnupg ]]; then
  363.     cp -a /etc/pacman.d/gnupg "$newroot/etc/pacman.d/"
  364.   fi
  365. fi
  366.  
  367. if (( copymirrorlist )); then
  368.   # install the host's mirrorlist onto the new root
  369.   cp -a /etc/pacman.d/mirrorlist "$newroot/etc/pacman.d/"
  370. fi
  371.  
  372. # vim: et ts=2 sw=2 ft=sh:
  373. [root@917e8160b71e /]#
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement