InstallPrawnOS.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #!/bin/bash
  2. #See the block of "echos" in main() for description of this script
  3. # This file is part of PrawnOS (http://www.prawnos.com)
  4. # Copyright (c) 2018 Hal Emmerich <hal@halemmerich.com>
  5. # PrawnOS is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License version 2
  7. # as published by the Free Software Foundation.
  8. # PrawnOS is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. # You should have received a copy of the GNU General Public License
  13. # along with PrawnOS. If not, see <https://www.gnu.org/licenses/>.
  14. RESOURCES=/InstallResources
  15. # Grab the boot device, which is either /dev/sda for usb or /dev/mmcblk0 for an sd card
  16. BOOT_DEVICE=$(mount | head -n 1 | cut -d '2' -f 1)
  17. main() {
  18. echo "---------------------------------------------------------------------------------------------------------------------"
  19. echo "PrawnOS Install or Expand Script"
  20. echo "Installation sets up the internal emmc partitions, root encryption, and copies the filesystem from the"
  21. echo "current boot device to the target device. The target device cannot be the current boot device"
  22. echo
  23. echo "Expansion simply targets the booted device, and expands the filesystem to fill the entire thing instead of just 2GB."
  24. echo "Because of this, root encryption cannot be setup"
  25. echo
  26. echo "For installation, this script can be quit and re-ran at any point."
  27. echo "Unfortunately for expansion this is not the case"
  28. echo "---------------------------------------------------------------------------------------------------------------------"
  29. echo
  30. echo "Expand or Install?: "
  31. echo "The currently booted device is ${BOOT_DEVICE}"
  32. while true; do
  33. read -p "[I]nstall or [E]xpand?" IE
  34. case $IE in
  35. [Ii]* ) install; break;;
  36. [Ee]* ) expand; break;;
  37. * ) echo "Please answer I or E";;
  38. esac
  39. done
  40. }
  41. #Now to pick the install target: internal, sd, or usb
  42. #if target is usb, and boot device is usb, target is sdb
  43. #and whether to enable crypto
  44. install() {
  45. echo "Pick an install target. This can be the Internal Emmc, an SD card, or a USB device"
  46. echo "Please ensure you have only have the booted device and the desired target device inserted."
  47. echo "The currently booted device is ${BOOT_DEVICE}"
  48. while true; do
  49. read -p "[I]nternal Emmc, [S]D card, or [U]SB device?: " ISU
  50. case $ISU in
  51. [Ii]* ) TARGET=/dev/mmcblk2p; break;;
  52. [Ss]* ) TARGET=/dev/mmcblk0p; break;;
  53. [Uu]* ) TARGET=USB; break;;
  54. * ) echo "Please answer I, S, or U";;
  55. esac
  56. done
  57. if [[ $TARGET == "USB" ]]
  58. then
  59. if [[ $BOOT_DEVICE == "/dev/sda" ]]
  60. then
  61. TARGET=/dev/sdb
  62. else
  63. TARGET=/dev/sda
  64. fi
  65. fi
  66. if [[ $TARGET == $BOOT_DEVICE ]]
  67. then
  68. echo "Can't install to booted device, please ensure you have *only* the booted device and target device inserted"
  69. exit
  70. fi
  71. #cut off the "p" if we are using an sd card or internal emmc, doesn't change TARGET if we are using usb
  72. TARGET_NO_P=$(echo $TARGET | cut -d 'p' -f 1)
  73. if [ ! -e $TARGET_NO_P ];
  74. then
  75. echo "${TARGET_NO_P} does not exist, have you plugged in your target sd card or usb device?"
  76. exit 1
  77. fi
  78. #Now on to the installation, basically copy InstallToInternal.sh
  79. while true; do
  80. read -p "This will ERASE ALL DATA ON ${TARGET_NO_P} and reboot when finished, do you want to continue? [y/N]" yn
  81. case $yn in
  82. [Yy]* ) break;;
  83. [Nn]* ) exit;;
  84. * ) echo "Please answer y or n";;
  85. esac
  86. done
  87. umount ${TARGET}1 || /bin/true
  88. umount ${TARGET}2 || /bin/true
  89. if [[ $TARGET == "/dev/mmcblk2p" ]]
  90. then
  91. emmc_partition
  92. else
  93. external_partition $TARGET_NO_P
  94. fi
  95. KERNEL_PARTITION=${TARGET}1
  96. ROOT_PARTITION=${TARGET}2
  97. CRYPTO=false
  98. echo Writing kernel partition
  99. dd if=/dev/zero of=$KERNEL_PARTITION bs=512 count=65536
  100. dd if=${BOOT_DEVICE}1 of=$KERNEL_PARTITION conv=notrunc
  101. #Handle full disk encryption
  102. echo "Would you like to setup full disk encrytion using LUKs/DmCrypt?"
  103. select yn in "Yes" "No"
  104. do
  105. case $yn,$REPLY in
  106. Yes,*|*,Yes )
  107. CRYPTO=true
  108. # Since iteration count is based on cpu power, and the rk3288 isn't as fast as a usual
  109. # desktop cpu, manually supply -i 15000 for security at the cost of a slightly slower unlock
  110. dmesg -n 2
  111. echo "Enter the password you would like to use to unlock the encrypted root partition at boot"
  112. cryptsetup -q -y -s 512 luksFormat -i 15000 $ROOT_PARTITION || exit 1
  113. echo "Now unlock the newly created encrypted root partition so we can mount it and install the filesystem"
  114. cryptsetup luksOpen $ROOT_PARTITION luksroot || exit 1
  115. dmesg -n 7
  116. ROOT_PARTITION=/dev/mapper/luksroot
  117. break
  118. ;;
  119. No,*|*,No )
  120. break
  121. ;;
  122. * )
  123. echo "Invalid Option, please enter Yes or No, 1 or 2"
  124. ;;
  125. esac
  126. done
  127. echo Writing Filesystem, this will take about 4 minutes...
  128. mkfs.ext4 -F -b 1024 $ROOT_PARTITION
  129. INSTALL_MOUNT=/mnt/install_mount
  130. mkdir -p $INSTALL_MOUNT/
  131. mount $ROOT_PARTITION $INSTALL_MOUNT/
  132. rsync -ah --info=progress2 --info=name0 --numeric-ids -x / $INSTALL_MOUNT/
  133. #Remove the live-fstab and install a base fstab
  134. rm $INSTALL_MOUNT/etc/fstab
  135. echo "${ROOT_PARTITION} / ext4 defaults,noatime 0 1" > $INSTALL_MOUNT/etc/fstab
  136. while true; do
  137. read -p "Install a desktop environment and the supporting packages? [Y/n]" ins
  138. case $ins in
  139. [Yy]* ) install_packages $INSTALL_MOUNT; break;;
  140. [Nn]* ) break;;
  141. * ) echo "Please answer y or n";;
  142. esac
  143. done
  144. umount $ROOT_PARTITION
  145. echo Running fsck
  146. e2fsck -p -f $ROOT_PARTITION
  147. if [[ $CRYPTO == "true" ]]
  148. then
  149. # unmount and close encrypted storage
  150. # let things settle, otherwise cryptsetup complainssss
  151. sleep 2
  152. cryptsetup luksClose luksroot
  153. fi
  154. echo "Please remove the booted device after power off is complete"
  155. while true; do
  156. read -p "Reboot? [y/N]" re
  157. case $re in
  158. [Yy]* ) reboot;;
  159. [Nn]* ) exit;;
  160. * ) echo "Please answer y or n";;
  161. esac
  162. done
  163. }
  164. #Setup partition map on internal emmc
  165. emmc_partition() {
  166. #disable dmesg, writing the partition map tries to write the the first gpt table, which is unmodifiable
  167. dmesg -D
  168. echo Writing partition map to internal emmc
  169. DISK_SZ="$(blockdev --getsz /dev/mmcblk2)"
  170. echo Total disk size is: $DISK_SZ
  171. if [ $DISK_SZ = 30785536 ]
  172. then
  173. echo Detected Emmc Type 1
  174. sfdisk /dev/mmcblk2 < $RESOURCES/mmc.partmap
  175. elif [ $DISK_SZ = 30777344 ]
  176. then
  177. echo Detected Emmc Type 2
  178. sfdisk /dev/mmcblk2 < $RESOURCES/mmc_type2.partmap
  179. else
  180. echo ERROR! Not a known EMMC type, please open an issue on github or send SolidHal an email with the Total disk size reported above
  181. echo Try a fallback value? This will allow installation to continue, at the cost of a very small amoutnt of disk space. This may not work.
  182. select yn in "Yes" "No"
  183. do
  184. case $yn,$REPLY in
  185. Yes,*|*,Yes )
  186. echo Trying Emmc Type 2
  187. sfdisk /dev/mmcblk2 < $RESOURCES/mmc_type2.partmap
  188. break
  189. ;;
  190. * )
  191. echo "Invalid Option, please enter Yes or No, 1 or 2"
  192. ;;
  193. esac
  194. done
  195. fi
  196. dmesg -E
  197. }
  198. #Setup partition map for external bootable device, aka usb or sd card
  199. external_partition() {
  200. EXTERNAL_TARGET=$1
  201. kernel_start=8192
  202. kernel_size=65536
  203. root_start=$(($kernel_start + $kernel_size))
  204. #wipe the partition map, cgpt doesn't like anything weird in the primary or backup partition maps
  205. sgdisk -Z $EXTERNAL_TARGET
  206. partprobe $EXTERNAL_TARGET
  207. #make the base gpt partition map
  208. parted --script $EXTERNAL_TARGET mklabel gpt
  209. cgpt create $EXTERNAL_TARGET
  210. #must use cgpt to make the kernel partition, as we need the -S, -T, and -P variables
  211. cgpt add -i 1 -t kernel -b $kernel_start -s $kernel_size -l Kernel -S 1 -T 5 -P 10 $EXTERNAL_TARGET
  212. #Now the main filesystem
  213. #cgpt doesn't seem to handle this part correctly
  214. sgdisk -N 2 $EXTERNAL_TARGET
  215. #Set the type to "data"
  216. sgdisk -t 2:0700 $EXTERNAL_TARGET
  217. #Name it "properly" - Probably not required, but looks nice
  218. sgdisk -c 2:Root $EXTERNAL_TARGET
  219. #Reload the partition mapping
  220. partprobe $EXTERNAL_TARGET
  221. }
  222. #simply expand to fill the current boot device
  223. expand() {
  224. if [[ $BOOT_DEVICE == "/dev/mmcblk2" ]]
  225. then
  226. echo "Can't expand to fill internal emmc, install will have done this already"
  227. exit
  228. fi
  229. #Make the boot partition fille the whole drive
  230. #Delete the partition
  231. sgdisk -d 2 $BOOT_DEVICE
  232. #Make new partition map entry, with full size
  233. sgdisk -N 2 $BOOT_DEVICE
  234. #Set the type to "data"
  235. sgdisk -t 2:0700 $BOOT_DEVICE
  236. #Name it "properly" - Probably not required, but looks nice
  237. sgdisk -c 2:Root $BOOT_DEVICE
  238. #Reload the partition mapping
  239. partprobe $BOOT_DEVICE
  240. #Force the filesystem to fill the new partition
  241. resize2fs -f ${BOOT_DEVICE}2
  242. echo "/dev/${BOOT_DEVICE}2 / ext4 defaults,noatime 0 1" > /etc/fstab
  243. while true; do
  244. read -p "Install a desktop environment and the supporting packages? [Y/n]" ins
  245. case $ins in
  246. [Yy]* ) /InstallResources/InstallPackages.sh; reboot;;
  247. [Nn]* ) exit;;
  248. * ) echo "Please answer y or n";;
  249. esac
  250. done
  251. }
  252. #Install all packages, desktop environment to target device
  253. install_packages() {
  254. TARGET_MOUNT=$1
  255. echo "Installing Packages"
  256. mount -t proc proc $TARGET_MOUNT/proc/
  257. mount --rbind /sys $TARGET_MOUNT/sys/
  258. mount --rbind /dev $TARGET_MOUNT/dev/
  259. chroot $TARGET_MOUNT/ ./InstallResources/InstallPackages.sh
  260. umount $TARGET_MOUNT/proc/
  261. mount --make-rprivate /sys
  262. mount --make-rprivate /dev
  263. umount -R $TARGET_MOUNT/sys/
  264. umount -R $TARGET_MOUNT/dev/
  265. }
  266. #call the main function, script technically starts here
  267. #Organized this way so that main can come before the functions it calls
  268. main "$@"; exit