armbian_rootenc_setup.sh 34 KB

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