armbian_rootenc_setup.sh 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195
  1. #!/bin/bash
  2. RED="\e[31;1m" GREEN="\e[32;1m" YELLOW="\e[33;1m" BLUE="\e[34;1m" PURPLE="\e[35;1m" RESET="\e[0m"
  3. PROGNAME=$(basename $0)
  4. TITLE='Armbian Encrypted Root Filesystem Setup'
  5. CONFIG_VARS='
  6. ARMBIAN_IMAGE
  7. BOOTPART_LABEL
  8. ROOTFS_NAME
  9. DISK_PASSWD
  10. UNLOCKING_USERHOST
  11. IP_ADDRESS
  12. ADD_ALL_MODS
  13. USE_LOCAL_AUTHORIZED_KEYS
  14. '
  15. STATES='
  16. card_partitioned
  17. bootpart_copied
  18. bootpart_label_created
  19. rootpart_copied
  20. target_configured
  21. '
  22. USER_OPTS_INFO="
  23. NO_CLEANUP no cleanup of mounts after program run
  24. FORCE_REBUILD force full rebuild
  25. FORCE_RECONFIGURE force reconfiguration
  26. ADD_ALL_MODS add all currently loaded modules to initramfs
  27. USE_LOCAL_AUTHORIZED_KEYS use local 'authorized_keys' file
  28. PARTITION_ONLY partition and create filesystems only
  29. ERASE zero boot sector, boot partition and beginning of root partition
  30. ROOTENC_REUSE_FS reuse existing filesystems (for development only)
  31. ROOTENC_TESTING developer tweaks
  32. ROOTENC_PAUSE pause along the way
  33. ROOTENC_IGNORE_APT_ERRORS continue even if apt update fails
  34. "
  35. RSYNC_VERBOSITY='--info=progress2'
  36. print_help() {
  37. echo " ${PROGNAME^^}: Create an Armbian image with encrypted root filesystem
  38. USAGE: $PROGNAME [options] <SD card device name>
  39. OPTIONS: '-h' Print this help message
  40. '-C' Don't perform unmounts or clean up build directory at exit
  41. '-d' Produce tons of debugging output
  42. '-f' Force reconfiguration of target system
  43. '-F' Force a complete rebuild of target system
  44. '-m' Add all currently loaded modules to the initramfs (may help
  45. fix blank screen on bootup issues)
  46. '-p' Partition and create filesystems only. Do not copy data
  47. '-s' Use 'authorized_keys' file from working directory, if available
  48. (see below)
  49. '-v' Be more verbose
  50. '-u' Perform an 'apt upgrade' after each 'apt update'
  51. '-z' Erase boot sector and first partition of SD card before partitioning
  52. (an extra paranoia step, but it can’t hurt)
  53. For non-interactive operation, set the following variables in your environment
  54. or on the command line:
  55. ROOTFS_NAME - device mapper name of target root filesystem
  56. IP_ADDRESS - IP address of target (set to 'dhcp' for dynamic IP
  57. or 'none' to disable remote SSH unlocking support)
  58. BOOTPART_LABEL - Boot partition label of target
  59. DISK_PASSWD - Disk password of target root filesystem
  60. UNLOCKING_USERHOST - USER@HOST of remote unlocking host
  61. INSTRUCTIONS FOR USE
  62. This script must be invoked as superuser on a running Armbian system.
  63. Packages will be installed using APT, so the system must be Internet-
  64. connected and its clock correctly set.
  65. If remote unlocking via SSH is desired, the unlocking host must be reachable.
  66. Alternatively, SSH public keys for the unlocking host or hosts may be listed
  67. in the file 'authorized_keys' in the current directory. This file has the
  68. same format as a standard SSH 'authorized_keys' file.
  69. Architecture of host and target (e.g. 64-bit or 32-bit ARM) must be the same.
  70. For best results, the host and target hardware should also be identical or
  71. similar. Building on a host with more memory than the target, for example,
  72. may lead to disk unlocking failure on the target. For most users, who’ll be
  73. building for the currently-running board, this point is a non-issue.
  74. 1. Place an Armbian boot image file for the target system in the current
  75. directory. For best results, the image file should match the Debian
  76. or Ubuntu release of the host system.
  77. 2. Insert a USB card reader with a blank micro-SD card for the target
  78. system into the host’s USB port.
  79. 3. Determine the SD card’s device name using 'dmesg' or 'lsblk'.
  80. 4. Invoke the script with the device name as argument. If any options
  81. are desired, they must precede the device name.
  82. If the board has an eMMC, it may be used as the target device instead of
  83. an SD card." | less
  84. }
  85. pause() {
  86. echo -ne $GREEN'(Press any key to continue)'$RESET >&$stderr_dup
  87. read
  88. no_fmsg=1
  89. }
  90. _debug_pause() { [ "$ROOTENC_PAUSE" ] && pause; true; }
  91. imsg() { echo -e "$1" >&$stdout_dup; no_fmsg=1; }
  92. imsg_nonl() { echo -ne "$1" >&$stdout_dup; no_fmsg=1; }
  93. tmsg() {
  94. no_fmsg=1
  95. [ "$ROOTENC_TESTING" ] || return 0
  96. echo -e "$1" >&$stdout_dup
  97. }
  98. warn() { echo -e "$YELLOW$1$RESET" >&$stdout_dup; no_fmsg=1; }
  99. warn_nonl() { echo -ne "$YELLOW$1$RESET" >&$stdout_dup; no_fmsg=1; }
  100. rmsg() { echo -e "$RED$1$RESET" >&$stdout_dup; no_fmsg=1; }
  101. gmsg() { echo -e "$GREEN$1$RESET" >&$stdout_dup; no_fmsg=1; }
  102. pu_msg() { echo -e "$PURPLE$1$RESET" >&$stdout_dup; no_fmsg=1; }
  103. do_partprobe() {
  104. if [ "$VERBOSE" ]; then partprobe; else partprobe 2>/dev/null; fi
  105. no_fmsg=1
  106. }
  107. _show_output() { [ "$VERBOSE" ] || exec 1>&$stdout_dup 2>&$stderr_dup; }
  108. _hide_output() { [ "$VERBOSE" ] || exec &>'/dev/null'; }
  109. bail() { exit; }
  110. die() {
  111. echo -e "$RED$1$RESET" >&$stdout_dup
  112. no_fmsg=1
  113. exit 1
  114. }
  115. _fmsg() {
  116. local funcname=$1 errval=$2 res
  117. if [ "${funcname:0:1}" == '_' -o "$no_fmsg" ]; then
  118. no_fmsg=
  119. return 0
  120. fi
  121. if [ "$errval" -eq 0 ]; then res='OK'; else res="False ($errval)"; fi
  122. printf "$BLUE%-32s $res$RESET\n" "$funcname" >&$stdout_dup
  123. }
  124. _sigint_handler() {
  125. warn "\nExiting at user request"
  126. usr_exit=1
  127. exit 1
  128. }
  129. _exit_handler() {
  130. local err=$?
  131. _show_output
  132. [ $err -ne 0 -a -z "$usr_exit" ] && {
  133. rmsg "$SCRIPT_DESC exiting with error (exit code $err)"
  134. }
  135. return $err
  136. }
  137. _do_header() {
  138. echo
  139. local reply
  140. if banner=$(toilet --filter border --filter gay --width 51 -s -f smbraille "$TITLE" 2>/dev/null); then
  141. while read reply; do
  142. echo -e " $reply"
  143. done <<-EOF
  144. $banner
  145. EOF
  146. else
  147. echo -n ' '
  148. echo $TITLE
  149. echo
  150. fi
  151. echo " For detailed usage information,"
  152. echo " invoke with the '-h' switch"
  153. echo
  154. }
  155. _warn_user_opts() {
  156. local out
  157. while read opt text; do
  158. [ "$opt" ] || continue
  159. [ $(eval echo -n \$$opt) ] && out+=" + $text\n"
  160. done <<-EOF
  161. $USER_OPTS_INFO
  162. EOF
  163. [ "$out" ] && {
  164. warn " The following user options are in effect:"
  165. warn_nonl "${out}"
  166. }
  167. }
  168. _set_host_vars() {
  169. BUILD_DIR='armbian_rootenc_build'
  170. SRC_ROOT="$BUILD_DIR/src"
  171. BOOT_ROOT="$BUILD_DIR/boot"
  172. TARGET_ROOT="$BUILD_DIR/target"
  173. CONFIG_VARS_FILE="$BOOT_ROOT/.rootenc_config_vars"
  174. host_distro=$(lsb_release --short --codename)
  175. host_kernel=$(ls '/boot' | egrep '^vmlinu[xz]') # allow 'vmlinux' or 'vmlinuz'
  176. }
  177. check_sdcard_name_and_params() {
  178. local dev chk
  179. dev=$1
  180. [ "$dev" ] || die "You must supply a device name"
  181. [ "${dev:0:5}" == '/dev/' ] || dev="/dev/$dev"
  182. [ -e "$dev" ] || die "$dev does not exist"
  183. chk="$(lsblk --noheadings --nodeps --list --output=TYPE $dev 2>/dev/null)"
  184. [ "$chk" != 'disk' ] && {
  185. [ "$chk" == 'part' ] && die "$dev is a partition, not a block device!"
  186. die "$dev is not a block device!"
  187. }
  188. local pttype size nodos oversize removable non_removable part_sep
  189. pttype=$(blkid --output=udev $dev | grep TYPE | cut -d '=' -f2)
  190. size="$(lsblk --noheadings --nodeps --list --output=SIZE --bytes $dev 2>/dev/null)"
  191. removable="$(lsblk --noheadings --nodeps --list --output=RM $dev 2>/dev/null)"
  192. nodos=$([ "$pttype" -a "$pttype" != 'dos' ] && echo "Partition type is ${pttype^^}")
  193. oversize=$([ $size -gt 137438953472 ] && echo 'Size is > 128GiB')
  194. non_removable=$([ $removable -ne 0 ] || echo 'Device is non-removable')
  195. SD_INFO="$(lsblk --noheadings --nodeps --list --output=VENDOR,MODEL,SIZE $dev 2>/dev/null)"
  196. SD_INFO=${SD_INFO// / }
  197. [ "$nodos" -o "$oversize" -o "$non_removable" ] && {
  198. warn " $dev ($SD_INFO) doesn’t appear to be an SD card"
  199. warn " for the following reasons:"
  200. [ "$non_removable" ] && warn " $non_removable"
  201. [ "$nodos" ] && warn " $nodos"
  202. [ "$oversize" ] && warn " $oversize"
  203. _user_confirm ' Are you sure this is the correct device of your blank SD card?' 'no'
  204. }
  205. SDCARD_DEVNAME=${dev:5}
  206. [ "${SDCARD_DEVNAME%[0-9]}" == $SDCARD_DEVNAME ] || part_sep='p'
  207. BOOT_DEVNAME=$SDCARD_DEVNAME${part_sep}1
  208. ROOT_DEVNAME=$SDCARD_DEVNAME${part_sep}2
  209. [ "$SDCARD_DEVNAME" ] || die 'You must supply a device name for the SD card!'
  210. pu_msg "Will write to target $dev ($SD_INFO)"
  211. }
  212. _get_user_var() {
  213. local var desc dfl prompt pat pat_errmsg vtest cprompt seen_prompt reply redo
  214. var=$1 desc=$2 dfl=$3 prompt=$4 pat=$5 pat_errmsg=$6 vtest=$7
  215. while true; do
  216. [ -z "${!var}" -o "$seen_prompt" -o "$redo" ] && {
  217. if [ "$seen_prompt" ]; then
  218. echo -n " Enter $desc: "
  219. else
  220. cprompt=
  221. while read reply; do
  222. cprompt+=" ${reply## }\n"
  223. done <<-EOF
  224. $prompt
  225. EOF
  226. echo
  227. if [ "$dfl" ]; then
  228. printf "${cprompt:0:-2} " "$dfl"
  229. else
  230. echo -ne "${cprompt:0:-2} "
  231. fi
  232. seen_prompt=1
  233. fi
  234. eval "read $var"
  235. }
  236. redo=1
  237. [ -z "${!var}" -a "$dfl" ] && eval "$var=$dfl"
  238. [ "${!var}" ] || {
  239. rmsg " $desc must not be empty"
  240. continue
  241. }
  242. [ "$pat" ] && {
  243. echo "${!var}" | egrep -qi "$pat" || {
  244. rmsg " ${!var}: $pat_errmsg"
  245. continue
  246. }
  247. }
  248. [ "$vtest" ] && {
  249. $vtest || continue
  250. }
  251. break
  252. done
  253. }
  254. _get_user_vars() {
  255. _get_user_var 'IP_ADDRESS' 'IP address' '' \
  256. "Enter the IP address of the target machine.
  257. Enter 'dhcp' for a dynamic IP or 'none' for no remote SSH unlocking support
  258. IP address:" \
  259. '^(dhcp|none|[0-9]{1,3}\.[0-9]{1,3}\.[0-9]+\.[0-9]{1,3})$' \
  260. 'malformed IP address'
  261. IP_ADDRESS=${IP_ADDRESS,,}
  262. _get_user_var 'BOOTPART_LABEL' 'boot partition label' 'ARMBIAN_BOOT' \
  263. "Enter a boot partition label for the target machine,
  264. or hit ENTER for the default (%s): " \
  265. '^[A-Za-z0-9_]{1,16}$' \
  266. "Label must contain no more than 16 characters in the set 'A-Za-z0-9_'"
  267. _get_user_var 'ROOTFS_NAME' 'root filesystem device name' 'rootfs' \
  268. "Enter a device name for the encrypted root filesystem,
  269. or hit ENTER for the default (%s):" \
  270. '^[a-z0-9_]{1,48}$' \
  271. "Name must contain no more than 48 characters in the set 'a-z0-9_'" \
  272. '_test_rootfs_mounted'
  273. _get_user_var 'DISK_PASSWD' 'disk password' '' \
  274. "Choose a simple disk password for the installation process.
  275. Once your encrypted system is up and running, you can change
  276. the password using the 'cryptsetup' command.
  277. Enter password:" \
  278. '^[A-Za-z0-9_ ]{1,10}$' \
  279. "Temporary disk password must contain no more than 10 characters in the set 'A-Za-z0-9_ '"
  280. if [ "$IP_ADDRESS" == 'none' ]; then
  281. UNLOCKING_USERHOST=
  282. elif [ -e 'authorized_keys' -a "$USE_LOCAL_AUTHORIZED_KEYS" ]; then
  283. UNLOCKING_USERHOST=
  284. else
  285. _get_user_var 'UNLOCKING_USERHOST' 'USER@HOST' '' \
  286. "Enter the user@host of the machine you'll be unlocking from:" \
  287. '\S+@\S+' \
  288. 'malformed USER@HOST' \
  289. '_test_unlocking_host_available'
  290. fi
  291. true
  292. }
  293. _test_rootfs_mounted() {
  294. [ -e "/dev/mapper/$ROOTFS_NAME" ] && {
  295. local mnt=$(lsblk --list --noheadings --output=MOUNTPOINT /dev/mapper/$ROOTFS_NAME)
  296. [ "$mnt" ] && {
  297. rmsg " Device '$ROOTFS_NAME' is in use and mounted on $mnt"
  298. return 1
  299. }
  300. }
  301. return 0
  302. }
  303. _test_unlocking_host_available() {
  304. local ul_host=${UNLOCKING_USERHOST#*@}
  305. ping -c1 $ul_host &>/dev/null || {
  306. rmsg " Unable to ping host '$ul_host'"
  307. return 1
  308. }
  309. }
  310. _test_sdcard_mounted() {
  311. local chk="$(lsblk --noheadings --list --output=MOUNTPOINT /dev/$SDCARD_DEVNAME)"
  312. [ -z "$chk" ] || {
  313. lsblk --output=NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT /dev/$SDCARD_DEVNAME
  314. die "Device /dev/$SDCARD_DEVNAME has mounted partitions!"
  315. }
  316. }
  317. get_authorized_keys() {
  318. [ -e 'authorized_keys' -a "$USE_LOCAL_AUTHORIZED_KEYS" ] || {
  319. rsync "$UNLOCKING_USERHOST:.ssh/id_*.pub" 'authorized_keys'
  320. }
  321. }
  322. _apt_update() {
  323. [ "$ROOTENC_IGNORE_APT_ERRORS" ] && set +e
  324. apt --yes update
  325. [ "$APT_UPGRADE" ] && apt --yes upgrade
  326. [ "$ROOTENC_IGNORE_APT_ERRORS" ] && set -e
  327. true
  328. }
  329. _print_pkgs_to_install() {
  330. local pkgs pkgs_ssh
  331. case $1 in
  332. 'host')
  333. case "$host_distro" in
  334. focal|bionic|buster) pkgs='cryptsetup-bin ed' ;;
  335. *) pkgs='cryptsetup ed'
  336. warn "Warning: unrecognized host distribution '$host_distro'" ;;
  337. esac ;;
  338. 'target')
  339. case "$target_distro" in
  340. focal|buster) pkgs='cryptsetup-initramfs' pkgs_ssh='dropbear-initramfs' ;;
  341. bionic) pkgs='cryptsetup' pkgs_ssh='dropbear-initramfs' ;;
  342. *) pkgs='cryptsetup' pkgs_ssh='dropbear'
  343. warn "Warning: unrecognized target distribution '$target_distro'" ;;
  344. esac
  345. [ "$IP_ADDRESS" != 'none' ] && pkgs+=" $pkgs_ssh" ;;
  346. esac
  347. for i in $pkgs; do
  348. dpkg -l $i 2>/dev/null | grep -q ^ii || echo $i
  349. done
  350. }
  351. apt_install_host() {
  352. local pkgs=$(_print_pkgs_to_install 'host')
  353. [ "$pkgs" ] && {
  354. _apt_update
  355. apt --yes install $pkgs
  356. }
  357. true
  358. }
  359. create_build_dir() {
  360. mkdir -p $BUILD_DIR
  361. mkdir -p $SRC_ROOT
  362. mkdir -p $BOOT_ROOT
  363. mkdir -p $TARGET_ROOT
  364. }
  365. umount_target() {
  366. for i in $BOOT_ROOT $TARGET_ROOT; do
  367. while mountpoint -q $i; do
  368. umount -Rl $i
  369. done
  370. done
  371. }
  372. remove_build_dir() {
  373. [ -d $TARGET_ROOT ] && rmdir $TARGET_ROOT
  374. [ -d $BOOT_ROOT ] && rmdir $BOOT_ROOT
  375. [ -d $SRC_ROOT ] && rmdir $SRC_ROOT
  376. [ -d $BUILD_DIR ] && rmdir $BUILD_DIR
  377. true
  378. }
  379. _get_device_maps() {
  380. local dm_type=$1
  381. local varname="device_maps_${dm_type}"
  382. eval "$varname="
  383. local data=$(lsblk --list --noheadings --output=KNAME,MOUNTPOINT | egrep '^dm-[0-9]')
  384. while read kname mountpoint; do
  385. [ "$dm_type" == 'unmounted' -a "$mountpoint" ] && continue
  386. [ "$dm_type" == 'mounted_on_target' -a \
  387. "${mountpoint: -${#TARGET_ROOT}}" != "$TARGET_ROOT" ] && continue
  388. eval "$varname+=/dev/$kname "
  389. done <<-EOF
  390. $data
  391. EOF
  392. tmsg "$varname=[${!varname}]"
  393. }
  394. _close_device_maps() {
  395. local dm_type=$1
  396. local varname="device_maps_${dm_type}"
  397. for i in ${!varname}; do
  398. tmsg "closing $i"
  399. cryptsetup status $i > '/dev/null' && cryptsetup luksClose $i
  400. done
  401. }
  402. _preclean() {
  403. close_loopmount
  404. _get_device_maps 'unmounted'
  405. _close_device_maps 'unmounted'
  406. _get_device_maps 'mounted_on_target'
  407. umount_target
  408. _close_device_maps 'mounted_on_target'
  409. remove_build_dir
  410. }
  411. _clean() {
  412. local err=$?
  413. [ $err -ne 0 -a -z "$usr_exit" ] && rmsg "$SCRIPT_DESC exiting with error (exit code $err)"
  414. pu_msg "Cleaning up, please wait..."
  415. _show_output
  416. close_loopmount
  417. _get_device_maps 'mounted_on_target'
  418. umount_target
  419. update_config_vars_file
  420. _close_device_maps 'mounted_on_target'
  421. [ -e 'authorized_keys' -a -z "$USE_LOCAL_AUTHORIZED_KEYS" ] && shred -u 'authorized_keys'
  422. remove_build_dir
  423. }
  424. get_armbian_image() {
  425. ARMBIAN_IMAGE="$(ls *.img)"
  426. [ "$ARMBIAN_IMAGE" ] || die 'You must place an Armbian image in the current directory!'
  427. local count=$(echo "$ARMBIAN_IMAGE" | wc -l)
  428. [ "$count" == 1 ] || die "More than one image file present!:\n$ARMBIAN_IMAGE"
  429. }
  430. _confirm_user_vars() {
  431. echo
  432. echo " Armbian image: $ARMBIAN_IMAGE"
  433. echo " Target device: /dev/$SDCARD_DEVNAME ($SD_INFO)"
  434. echo " Root filesystem device name: /dev/mapper/$ROOTFS_NAME"
  435. echo " Target IP address: $IP_ADDRESS"
  436. echo " Boot partition label: $BOOTPART_LABEL"
  437. echo " Disk password: $DISK_PASSWD"
  438. [ "$UNLOCKING_USERHOST" ] && echo " user@host of unlocking machine: $UNLOCKING_USERHOST"
  439. echo
  440. _user_confirm ' Are these settings correct?' 'yes'
  441. }
  442. setup_loopmount() {
  443. LOOP_DEV=$(losetup -f)
  444. losetup -P $LOOP_DEV $ARMBIAN_IMAGE
  445. mount ${LOOP_DEV}p1 $SRC_ROOT
  446. START_SECTOR=$(fdisk -l $LOOP_DEV -o Start | tail -n1 | tr -d ' ') # usually 32768
  447. BOOT_SECTORS=409600 # 200MB
  448. }
  449. _umount_with_check() {
  450. mountpoint -q $1 && umount $1
  451. }
  452. update_config_vars_file() {
  453. mount "/dev/$BOOT_DEVNAME" $BOOT_ROOT
  454. _print_config_vars $CONFIG_VARS_FILE
  455. umount $BOOT_ROOT
  456. }
  457. _print_states() {
  458. for i in $STATES; do
  459. echo $i: ${!i}
  460. done
  461. }
  462. _update_state_from_config_vars() {
  463. [ -e $CONFIG_VARS_FILE ] || return 0
  464. local reply
  465. while read reply; do eval "c$reply"; done <<-EOF
  466. $(cat $CONFIG_VARS_FILE)
  467. EOF
  468. local saved_states cfgvar_changed
  469. saved_states="$(_print_states)"
  470. cfgvar_changed=
  471. [ $cARMBIAN_IMAGE != $ARMBIAN_IMAGE ] && cfgvar_changed+=' ARMBIAN_IMAGE' card_partitioned='n'
  472. [ $cBOOTPART_LABEL != $BOOTPART_LABEL ] && cfgvar_changed+=' BOOTPART_LABEL' bootpart_label_created='n'
  473. [ $cROOTFS_NAME != $ROOTFS_NAME ] && cfgvar_changed+=' ROOTFS_NAME' target_configured='n'
  474. [ $cDISK_PASSWD != $DISK_PASSWD ] && cfgvar_changed+=' DISK_PASSWD' rootpart_copied='n'
  475. [ "$UNLOCKING_USERHOST" -a "$cUNLOCKING_USERHOST" != "$UNLOCKING_USERHOST" ] && {
  476. cfgvar_changed+=' UNLOCKING_USERHOST' target_configured='n'
  477. }
  478. [ $cIP_ADDRESS != $IP_ADDRESS ] && cfgvar_changed+=' IP_ADDRESS' target_configured='n'
  479. [ "$cADD_ALL_MODS" != "$ADD_ALL_MODS" ] && cfgvar_changed+=' ADD_ALL_MODS' target_configured='n'
  480. [ "$IP_ADDRESS" -a "$cUSE_LOCAL_AUTHORIZED_KEYS" != "$USE_LOCAL_AUTHORIZED_KEYS" ] && {
  481. cfgvar_changed+=' USE_LOCAL_AUTHORIZED_KEYS' target_configured='n'
  482. }
  483. [ $card_partitioned == 'n' ] && {
  484. bootpart_copied='n'
  485. bootpart_label_created='n'
  486. rootpart_copied='n'
  487. target_configured='n'
  488. }
  489. [ $bootpart_copied == 'n' ] && bootpart_label_created='n'
  490. [ $rootpart_copied == 'n' ] && target_configured='n'
  491. [ "$saved_states" != "$(_print_states)" ] && {
  492. warn "Install state altered due to changed config vars:$cfgvar_changed"
  493. for i in $STATES; do
  494. if [ "${!i}" == 'n' ]; then
  495. imsg " $i: ${RED}no$RESET"
  496. else
  497. imsg " $i: ${GREEN}yes$RESET"
  498. fi
  499. done
  500. _delete_state_files
  501. }
  502. true
  503. }
  504. _add_state_file() {
  505. local state=$1 cmd=$2
  506. if [ "$cmd" == 'target' ]; then
  507. touch "$TARGET_ROOT/boot/.rootenc_install_state/$state"
  508. else
  509. [ "$cmd" == 'mount' ] && mount "/dev/$BOOT_DEVNAME" $BOOT_ROOT
  510. mkdir -p "$BOOT_ROOT/.rootenc_install_state"
  511. touch "$BOOT_ROOT/.rootenc_install_state/$state"
  512. [ "$cmd" == 'mount' ] && umount $BOOT_ROOT
  513. fi
  514. eval "$state='y'"
  515. tmsg "added state file '$state'"
  516. }
  517. _delete_state_files() {
  518. for i in $STATES; do
  519. local fn="$BOOT_ROOT/.rootenc_install_state/$i"
  520. [ ${!i} == 'n' -a -e $fn ] && /bin/rm $fn
  521. done
  522. true
  523. }
  524. _get_state_from_state_files() {
  525. for i in $STATES; do
  526. if [ -e "$BOOT_ROOT/.rootenc_install_state/$i" ]; then
  527. eval "$i=y"
  528. else
  529. eval "$i=n"
  530. fi
  531. done
  532. }
  533. _print_state_from_state_files() {
  534. imsg 'Install state:'
  535. for i in $STATES; do
  536. if [ -e "$BOOT_ROOT/.rootenc_install_state/$i" ]; then
  537. imsg " $i: ${GREEN}yes$RESET"
  538. else
  539. imsg " $i: ${RED}no$RESET"
  540. fi
  541. done
  542. }
  543. check_install_state() {
  544. for i in $STATES; do eval "$i=n"; done
  545. if [ "$FORCE_REBUILD" ]; then
  546. return
  547. else
  548. do_partprobe
  549. lsblk --noheadings --list /dev/$SDCARD_DEVNAME -o 'NAME' | grep -q $BOOT_DEVNAME || return 0
  550. lsblk --noheadings --list /dev/$BOOT_DEVNAME -o 'FSTYPE' | grep -q 'ext4' || return 0
  551. mount "/dev/$BOOT_DEVNAME" $BOOT_ROOT
  552. _get_state_from_state_files
  553. if [ "$target_configured" == 'y' -a "$FORCE_RECONFIGURE" ]; then
  554. target_configured='n'
  555. _delete_state_files
  556. fi
  557. _print_state_from_state_files
  558. _update_state_from_config_vars
  559. _umount_with_check $BOOT_ROOT
  560. fi
  561. }
  562. close_loopmount() {
  563. while mountpoint -q $SRC_ROOT; do
  564. umount $SRC_ROOT
  565. done
  566. for i in $(losetup --noheadings --raw --list -j $ARMBIAN_IMAGE | awk '{print $1}'); do
  567. losetup -d $i
  568. done
  569. }
  570. _user_confirm() {
  571. local prompt1 prompt2 dfl_action reply
  572. prompt1=$1 dfl_action=$2
  573. if [ "$dfl_action" == 'yes' ]; then
  574. prompt2='(Y/n)'
  575. else
  576. prompt2='(y/N)'
  577. fi
  578. imsg_nonl "$prompt1 $prompt2 "
  579. read -n1 reply
  580. [ "$reply" ] && imsg ''
  581. [ "$dfl_action" == 'yes' -a -z "$reply" ] && return
  582. [ "$reply" == 'y' -o "$reply" == 'Y' ] && return
  583. warn "Exiting at user request"
  584. usr_exit=1
  585. exit 1
  586. }
  587. erase_boot_sector_and_first_partition() {
  588. local sectors count
  589. sectors=$((START_SECTOR+BOOT_SECTORS+100))
  590. count=$(((sectors/8192)+1))
  591. pu_msg "Erasing up to beginning of second partition ($sectors sectors, ${count}M):"
  592. _show_output
  593. dd if=/dev/zero \
  594. of=/dev/$SDCARD_DEVNAME \
  595. status=progress \
  596. bs=$((512*8192)) \
  597. count=$count
  598. _hide_output
  599. }
  600. create_partition_label() {
  601. pu_msg "Creating new partition label on /dev/$SDCARD_DEVNAME"
  602. local fdisk_cmds="o\nw\n"
  603. set +e
  604. echo -e "$fdisk_cmds" | fdisk "/dev/$SDCARD_DEVNAME"
  605. set -e
  606. do_partprobe
  607. }
  608. copy_boot_loader() {
  609. local count
  610. count=$((START_SECTOR/2048))
  611. pu_msg "Copying boot loader ($START_SECTOR sectors, ${count}M):"
  612. _show_output
  613. dd if=$ARMBIAN_IMAGE \
  614. of=/dev/$SDCARD_DEVNAME \
  615. status=progress \
  616. bs=$((512*2048)) \
  617. count=$count
  618. _hide_output
  619. do_partprobe
  620. }
  621. _print_config_vars() {
  622. local outfile=$1
  623. local data="$(for i in $CONFIG_VARS; do echo "$i=${!i}"; done)"
  624. if [ "$outfile" ]; then echo "$data" > $outfile; else echo "$data"; fi
  625. }
  626. partition_sd_card() {
  627. local p1_end p2_start fdisk_cmds bname rname fstype
  628. p1_end=$((START_SECTOR+BOOT_SECTORS-1))
  629. p2_start=$((p1_end+1))
  630. fdisk_cmds="o\nn\np\n1\n$START_SECTOR\n$p1_end\nn\np\n2\n$p2_start\n\nw\n"
  631. set +e
  632. echo -e "$fdisk_cmds" | fdisk "/dev/$SDCARD_DEVNAME"
  633. set -e
  634. do_partprobe
  635. bname="$(lsblk --noheadings --list --output=NAME /dev/$BOOT_DEVNAME)"
  636. [ "$bname" == $BOOT_DEVNAME ] || die 'Partitioning failed!'
  637. rname="$(lsblk --noheadings --list --output=NAME /dev/$ROOT_DEVNAME)"
  638. [ "$rname" == $ROOT_DEVNAME ] || die 'Partitioning failed!'
  639. # filesystem is required by call to _add_state_file(), so we must create it here
  640. fstype=$(lsblk --noheadings --list --output=FSTYPE "/dev/$BOOT_DEVNAME")
  641. [ "$fstype" == 'ext4' -a "$ROOTENC_REUSE_FS" ] || mkfs.ext4 -F "/dev/$BOOT_DEVNAME"
  642. do_partprobe
  643. _add_state_file 'card_partitioned' 'mount'
  644. }
  645. _do_partition() {
  646. imsg "All data on /dev/$SDCARD_DEVNAME ($SD_INFO) will be destroyed!!!"
  647. _user_confirm 'Are you sure you want to continue?' 'no'
  648. if [ "$ERASE" ]; then
  649. erase_boot_sector_and_first_partition
  650. else
  651. create_partition_label
  652. fi
  653. copy_boot_loader
  654. partition_sd_card
  655. }
  656. copy_system_boot() {
  657. [ "$PARTITION_ONLY" ] && {
  658. _add_state_file 'bootpart_copied' 'mount'
  659. return
  660. }
  661. mount "/dev/$BOOT_DEVNAME" $BOOT_ROOT
  662. pu_msg "Copying files to boot partition:"
  663. _show_output
  664. rsync $RSYNC_VERBOSITY --archive $SRC_ROOT/boot/* $BOOT_ROOT
  665. _hide_output
  666. [ -e "$BOOT_ROOT/boot" ] || (cd $BOOT_ROOT && ln -s . 'boot')
  667. _add_state_file 'bootpart_copied'
  668. umount $BOOT_ROOT
  669. }
  670. create_bootpart_label() {
  671. e2label "/dev/$BOOT_DEVNAME" "$BOOTPART_LABEL"
  672. do_partprobe
  673. _add_state_file 'bootpart_label_created' 'mount'
  674. }
  675. copy_system_root() {
  676. if ! cryptsetup isLuks "/dev/$ROOT_DEVNAME"; then
  677. pu_msg "Formatting encrypted root partition:"
  678. echo -n $DISK_PASSWD | cryptsetup luksFormat "/dev/$ROOT_DEVNAME" '-'
  679. fi
  680. echo $DISK_PASSWD | cryptsetup luksOpen "/dev/$ROOT_DEVNAME" $ROOTFS_NAME
  681. local fstype=$(lsblk --noheadings --list --output=FSTYPE "/dev/mapper/$ROOTFS_NAME")
  682. [ "$fstype" == 'ext4' -a "$ROOTENC_REUSE_FS" ] || mkfs.ext4 -F "/dev/mapper/$ROOTFS_NAME"
  683. [ "$PARTITION_ONLY" ] || {
  684. mount "/dev/mapper/$ROOTFS_NAME" $TARGET_ROOT
  685. pu_msg "Copying system to encrypted root partition:"
  686. _show_output
  687. rsync $RSYNC_VERBOSITY --archive --exclude=boot $SRC_ROOT/* $TARGET_ROOT
  688. _hide_output
  689. sync
  690. mkdir -p "$TARGET_ROOT/boot"
  691. touch "$TARGET_ROOT/root/.no_rootfs_resize"
  692. umount $TARGET_ROOT
  693. }
  694. cryptsetup luksClose $ROOTFS_NAME
  695. do_partprobe
  696. _add_state_file 'rootpart_copied' 'mount'
  697. }
  698. mount_target() {
  699. echo $DISK_PASSWD | cryptsetup luksOpen "/dev/$ROOT_DEVNAME" $ROOTFS_NAME
  700. mount "/dev/mapper/$ROOTFS_NAME" $TARGET_ROOT
  701. mount "/dev/$BOOT_DEVNAME" "$TARGET_ROOT/boot"
  702. local src dest args
  703. while read src dest args; do
  704. mount $args $src $TARGET_ROOT/$dest
  705. done <<-EOF
  706. udev dev -t devtmpfs -o rw,relatime,nosuid,mode=0755
  707. devpts dev/pts -t devpts
  708. tmpfs dev/shm -t tmpfs -o rw,nosuid,nodev,relatime
  709. proc proc -t proc
  710. sys sys -t sysfs
  711. EOF
  712. }
  713. _copy_to_target() {
  714. local fn=$1
  715. if [ -e $fn ]; then
  716. echo "Copying '$fn'"
  717. cat $fn > $TARGET_ROOT/$fn
  718. else
  719. imsg "Unable to copy '$fn' to target (file does not exist)"
  720. false
  721. fi
  722. }
  723. create_etc_crypttab() {
  724. local root_uuid="$(lsblk --noheadings --list --nodeps --output=UUID /dev/$ROOT_DEVNAME)"
  725. echo "$ROOTFS_NAME UUID=$root_uuid none initramfs,luks" > "$TARGET_ROOT/etc/crypttab"
  726. _display_file "$TARGET_ROOT/etc/crypttab"
  727. }
  728. copy_etc_files() {
  729. _copy_to_target '/etc/resolv.conf'
  730. _copy_to_target '/etc/hosts'
  731. set +e
  732. _copy_to_target /etc/apt/apt.conf.d/*proxy
  733. set -e
  734. }
  735. _set_target_vars() {
  736. target_distro=$(chroot $TARGET_ROOT 'lsb_release' '--short' '--codename')
  737. target_kernel=$(chroot $TARGET_ROOT 'ls' '/boot' | egrep '^vmlinu[xz]')
  738. imsg "$(printf '%-8s %-28s %s' '' 'Host' 'Target')"
  739. imsg "$(printf '%-8s %-28s %s' '' '----' '------')"
  740. imsg "$(printf '%-8s %-28s %s' 'distro:' $host_distro $target_distro)"
  741. imsg "$(printf '%-8s %-28s %s' 'kernel:' $host_kernel $target_kernel)"
  742. }
  743. _distros_match() {
  744. [ $host_distro == $target_distro ]
  745. }
  746. _kernels_match() {
  747. [ ${host_kernel%.*} == ${target_kernel%.*} ] || return 1
  748. [ ${host_kernel##*-} == ${target_kernel##*-} ]
  749. }
  750. copy_etc_files_distro_specific() {
  751. local files='/etc/apt/sources.list /etc/apt/sources.list.d/armbian.list'
  752. if _distros_match; then
  753. for i in $files; do _copy_to_target $i; done
  754. else
  755. warn 'Warning: host and target distros do not match:'
  756. for i in $files; do imsg " not copying $i"; done
  757. fi
  758. }
  759. _display_file() {
  760. local name text reply
  761. if [ "$2" ]; then
  762. name="$1"
  763. text="$2"
  764. else
  765. name=${1#$TARGET_ROOT}
  766. text="$(cat $1)"
  767. fi
  768. hl='────────────────────────────────────────'
  769. hl="$hl$hl$hl"
  770. hls=${hl:0:${#name}+1}
  771. echo "┌─$hls─┐"
  772. echo "│ $name: │"
  773. echo "├─$hls─┘"
  774. echo "$text" | sed 's/^/│ /'
  775. }
  776. edit_armbianEnv() {
  777. local file text
  778. file="$TARGET_ROOT/boot/armbianEnv.txt"
  779. ed $file <<-'EOF'
  780. g/^\s*rootdev=/d
  781. g/^\s*console=/d
  782. g/^\s*bootlogo=/d
  783. wq
  784. EOF
  785. text="rootdev=/dev/mapper/$ROOTFS_NAME
  786. console=display
  787. bootlogo=false"
  788. echo "$text" >> $file
  789. _display_file $file
  790. }
  791. edit_boot_cmd() {
  792. local file="$TARGET_ROOT/boot/boot.cmd"
  793. ed $file <<-'EOF'
  794. g/^\s*setenv rootdev/d
  795. g/^\s*setenv console/d
  796. g/^\s*setenv bootlogo/d
  797. wq
  798. EOF
  799. _display_file $file
  800. }
  801. # Add the following lines to '/etc/initramfs-tools/initramfs.conf'. If
  802. # your board’s IP address will be statically configured, substitute the
  803. # correct static IP address after 'IP='. If it will be configured via
  804. # DHCP, omit the IP line entirely:
  805. edit_initramfs_conf() {
  806. local file="$TARGET_ROOT/etc/initramfs-tools/initramfs.conf"
  807. ed $file <<-'EOF'
  808. g/^\s*IP=/s/^/# /
  809. g/^\s*DEVICE=/d
  810. wq
  811. EOF
  812. [ "$IP_ADDRESS" == 'dhcp' -o "$IP_ADDRESS" == 'none' ] || {
  813. echo "IP=$IP_ADDRESS:::255.255.255.0::eth0:off" >> $file
  814. }
  815. [ "$IP_ADDRESS" == 'none' ] || echo "DEVICE=eth0" >> $file
  816. _display_file $file
  817. }
  818. edit_initramfs_modules() {
  819. local modlist file hdr
  820. [ "$ADD_ALL_MODS" ] && {
  821. if ! _kernels_match; then
  822. warn 'Host and target kernels do not match. Not adding modules to initramfs'
  823. elif ! _distros_match; then
  824. warn 'Host and target distros do not match. Not adding modules to initramfs'
  825. else
  826. modlist=$(lsmod | cut -d ' ' -f1 | tail -n+2)
  827. fi
  828. }
  829. file="$TARGET_ROOT/etc/initramfs-tools/modules"
  830. hdr="# List of modules that you want to include in your initramfs.
  831. # They will be loaded at boot time in the order below.
  832. #
  833. # Syntax: module_name [args ...]
  834. #
  835. # You must run update-initramfs(8) to effect this change.
  836. #
  837. "
  838. echo "$hdr$modlist" > $file
  839. _display_file $file
  840. }
  841. copy_authorized_keys() {
  842. local dest="$TARGET_ROOT/etc/dropbear-initramfs"
  843. mkdir -p $dest
  844. /bin/cp 'authorized_keys' $dest
  845. _display_file "$dest/authorized_keys"
  846. }
  847. create_fstab() {
  848. local boot_uuid file text
  849. boot_uuid="$(lsblk --noheadings --list --output=UUID /dev/$BOOT_DEVNAME)"
  850. file="$TARGET_ROOT/etc/fstab"
  851. text="/dev/mapper/$ROOTFS_NAME / ext4 defaults,noatime,nodiratime,commit=600,errors=remount-ro 0 1
  852. UUID=$boot_uuid /boot ext4 defaults,noatime,nodiratime,commit=600,errors=remount-ro 0 2
  853. tmpfs /tmp tmpfs defaults,nosuid 0 0"
  854. echo "$text" > $file
  855. _display_file $file
  856. }
  857. edit_dropbear_cfg() {
  858. local dest file text
  859. dest="$TARGET_ROOT/etc/dropbear-initramfs"
  860. file="$dest/config"
  861. text='DROPBEAR_OPTIONS="-p 2222"
  862. DROPBEAR=y'
  863. if [ "$IP_ADDRESS" == 'none' ]; then
  864. [ -e $file ] && rm -v $file
  865. true
  866. else
  867. mkdir -p $dest
  868. [ -e $file ] && grep -q '^DROPBEAR_OPTIONS="-p 2222"' $file || echo "$text" >> $file
  869. _display_file $file
  870. fi
  871. }
  872. create_cryptroot_unlock_sh() {
  873. local dest file text
  874. dest="$TARGET_ROOT/etc/initramfs-tools/hooks"
  875. file="$dest/cryptroot-unlock.sh"
  876. text='#!/bin/sh
  877. if [ "$1" = "prereqs" ]; then echo "dropbear-initramfs"; exit 0; fi
  878. . /usr/share/initramfs-tools/hook-functions
  879. source="/tmp/cryptroot-unlock-profile"
  880. root_home=$(echo $DESTDIR/root-*)
  881. root_home=${root_home#$DESTDIR}
  882. echo "if [ \"\$SSH_CLIENT\" ]; then /usr/bin/cryptroot-unlock; fi" > $source
  883. copy_file ssh_login_profile $source $root_home/.profile
  884. exit 0'
  885. mkdir -p $dest
  886. echo "$text" > $file
  887. chmod 755 $file
  888. _display_file $file
  889. }
  890. # begin chroot functions:
  891. make_image() {
  892. local cmd text
  893. cmd="mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scr"
  894. local text=$($cmd)
  895. _display_file "$cmd" "$text"
  896. }
  897. apt_install_target() {
  898. local pkgs=$(_print_pkgs_to_install 'target')
  899. [ "$pkgs" ] && {
  900. echo "target packages to install: $pkgs"
  901. local ls1 ls2
  902. _show_output
  903. ls1=$(ls -l /boot/initrd.img-*)
  904. # DEBUG:
  905. # dpkg-reconfigure $pkgs # doesn't work in chroot
  906. # apt --yes purge $pkgs
  907. # apt-get --yes --purge autoremove
  908. dpkg --configure --pending --force-confdef
  909. set +e
  910. apt --yes purge 'bash-completion'
  911. apt --yes purge 'command-not-found'
  912. set -e
  913. _apt_update
  914. echo 'force-confdef' > /root/.dpkg.cfg
  915. apt --yes install $pkgs
  916. rm /root/.dpkg.cfg
  917. apt --yes autoremove
  918. ls2=$(ls -l /boot/initrd.img-*)
  919. [ "$ls1" != "$ls2" ] && initramfs_updated='y'
  920. _hide_output
  921. }
  922. true
  923. }
  924. update_initramfs() {
  925. [ "$ROOTENC_TESTING" ] && return 0
  926. _show_output
  927. local ver=$(echo /boot/vmlinu?-* | sed 's/.boot.vmlinu.-//')
  928. update-initramfs -k $ver -u
  929. _hide_output
  930. }
  931. check_initramfs() {
  932. local text chk count
  933. text="$(lsinitramfs /boot/initrd.img*)"
  934. set +e
  935. chk=$(echo "$text" | grep 'cryptsetup')
  936. count=$(echo "$chk" | wc -l)
  937. [ "$count" -gt 5 ] || { echo "$text"; die 'Cryptsetup scripts missing in initramfs image'; }
  938. _display_file "lsinitramfs /boot/initrd.img* | grep 'cryptsetup'" "$chk"
  939. [ "$IP_ADDRESS" == 'none' ] || {
  940. chk=$(echo "$text" | grep 'dropbear')
  941. count=$(echo "$chk" | wc -l)
  942. [ "$count" -gt 5 ] || { echo "$text"; die 'Dropbear scripts missing in initramfs image'; }
  943. _display_file "lsinitramfs /boot/initrd.img* | grep 'dropbear'" "$chk"
  944. chk=$(echo "$text" | grep 'authorized_keys')
  945. count=$(echo "$chk" | wc -l)
  946. [ "$count" -eq 1 ] || { echo "$text"; die 'authorized_keys missing in initramfs image'; }
  947. _display_file "lsinitramfs /boot/initrd.img* | grep 'authorized_keys'" "$chk"
  948. }
  949. set -e
  950. }
  951. configure_target() {
  952. [ "$PARTITION_ONLY" ] && return
  953. mount_target
  954. _set_target_vars
  955. copy_etc_files
  956. copy_etc_files_distro_specific
  957. edit_boot_cmd
  958. edit_initramfs_conf
  959. edit_initramfs_modules
  960. [ "$IP_ADDRESS" == 'none' ] || copy_authorized_keys
  961. create_etc_crypttab
  962. create_fstab
  963. edit_dropbear_cfg
  964. [ "$IP_ADDRESS" == 'none' ] || create_cryptroot_unlock_sh
  965. edit_armbianEnv
  966. _debug_pause
  967. _show_output # this must be done before entering chroot
  968. /bin/cp $0 $TARGET_ROOT
  969. export 'ROOTFS_NAME' 'IP_ADDRESS' 'target_distro' 'ROOTENC_TESTING' 'ROOTENC_PAUSE' 'ROOTENC_IGNORE_APT_ERRORS' 'APT_UPGRADE'
  970. chroot $TARGET_ROOT "./$PROGNAME" $ORIG_OPTS 'in_target'
  971. /bin/cp -a '/etc/resolv.conf' "$TARGET_ROOT/etc" # this could be a symlink
  972. /bin/rm "$TARGET_ROOT/$PROGNAME"
  973. _add_state_file 'target_configured' 'target'
  974. }
  975. _set_env_vars() {
  976. shopt -s extglob
  977. local name val
  978. while [ $# -gt 0 ]; do
  979. name=${1%=?*} val=${1#+([A-Z_])=}
  980. [ "$name" == "$1" -o "$val" == "$1" ] && die "$1: illegal argument (must be in format 'NAME=value')"
  981. eval "$name=$val"
  982. shift
  983. done
  984. shopt -u extglob
  985. }
  986. # begin execution
  987. while getopts hCdmfFpsuvz OPT
  988. do
  989. case "$OPT" in
  990. h) print_help; exit ;;
  991. C) NO_CLEANUP='y' ;;
  992. F) FORCE_REBUILD='y' ;;
  993. f) FORCE_RECONFIGURE='y' ;;
  994. m) ADD_ALL_MODS='y' ;;
  995. p) PARTITION_ONLY='y' ;;
  996. s) USE_LOCAL_AUTHORIZED_KEYS='y' ;;
  997. u) APT_UPGRADE='y' ;;
  998. d) DEBUG='y' ;&
  999. v) VERBOSE='y' RSYNC_VERBOSITY='--verbose' ;;
  1000. z) ERASE='y' ;;
  1001. *) exit ;;
  1002. esac
  1003. ORIG_OPTS+="-$OPT "
  1004. done
  1005. shift $((OPTIND-1))
  1006. trap '_fmsg "$FUNCNAME" $?' RETURN
  1007. trap '_sigint_handler' INT
  1008. trap '_exit_handler' EXIT
  1009. set -o functrace
  1010. exec {stdout_dup}>&1
  1011. exec {stderr_dup}>&2
  1012. [ $UID == 0 -o $EUID == 0 ] || die 'This program must be run as root!'
  1013. export HOME='/root'
  1014. [ "$DEBUG" ] && set -x
  1015. ARG1=$1; shift
  1016. _set_env_vars $@
  1017. if [ "$ARG1" == 'in_target' ]; then
  1018. SCRIPT_DESC='Target script'
  1019. set -e
  1020. _hide_output
  1021. make_image
  1022. [ "$target_distro" == 'bionic' ] && {
  1023. echo 'export CRYPTSETUP=y' > '/etc/initramfs-tools/conf.d/cryptsetup'
  1024. }
  1025. apt_install_target
  1026. [ "$initramfs_updated" ] || update_initramfs
  1027. check_initramfs
  1028. else
  1029. SCRIPT_DESC='Host script'
  1030. _do_header
  1031. _set_host_vars
  1032. get_armbian_image
  1033. apt_install_host # we need cryptsetup in next cmd
  1034. _preclean
  1035. check_sdcard_name_and_params $ARG1
  1036. _get_user_vars
  1037. _test_sdcard_mounted
  1038. _warn_user_opts
  1039. _confirm_user_vars
  1040. set -e
  1041. [ "$IP_ADDRESS" == 'none' ] || get_authorized_keys
  1042. create_build_dir
  1043. [ "$NO_CLEANUP" ] || trap '_clean' EXIT
  1044. setup_loopmount
  1045. _debug_pause
  1046. check_install_state
  1047. _hide_output
  1048. [ "$card_partitioned" == 'n' ] && _do_partition
  1049. _debug_pause
  1050. [ "$bootpart_copied" == 'n' ] && copy_system_boot
  1051. [ "$bootpart_label_created" == 'n' ] && create_bootpart_label
  1052. [ "$rootpart_copied" == 'n' ] && copy_system_root
  1053. [ "$target_configured" == 'n' ] && configure_target
  1054. sync
  1055. gmsg 'All done!'
  1056. if [ "$IP_ADDRESS" != 'none' ]; then
  1057. imsg "To unlock the target disk, execute the following from the unlocking host:"
  1058. imsg " ssh -p 2222 root@${IP_ADDRESS/dhcp/TARGET_IP}"
  1059. fi
  1060. fi