armbian_rootenc_setup.sh 32 KB

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