InstallPrawnOS.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. #!/bin/bash
  2. #See the block of "echos" in main() for description of this script
  3. # This file is part of PrawnOS (https://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. # Only try to unmount if the device is mounted
  88. # If it is, try anyway, the dd will (likely) take care of it anyway
  89. if findmnt ${TARGET}1 > /dev/null
  90. then
  91. umount ${TARGET}1 || /bin/true
  92. fi
  93. if findmnt ${TARGET}2 > /dev/null
  94. then
  95. umount ${TARGET}2 || /bin/true
  96. fi
  97. if [[ $TARGET == "/dev/mmcblk2p" ]]
  98. then
  99. emmc_partition
  100. else
  101. external_partition $TARGET_NO_P
  102. fi
  103. KERNEL_PARTITION=${TARGET}1
  104. ROOT_PARTITION=${TARGET}2
  105. CRYPTO=false
  106. echo Writing kernel partition
  107. dd if=/dev/zero of=$KERNEL_PARTITION bs=512 count=65536
  108. dd if=${BOOT_DEVICE}1 of=$KERNEL_PARTITION conv=notrunc
  109. #Handle full disk encryption
  110. echo "Would you like to setup full disk encrytion using LUKs/DmCrypt?"
  111. select yn in "Yes" "No"
  112. do
  113. case $yn,$REPLY in
  114. Yes,*|*,Yes )
  115. CRYPTO=true
  116. # Since iteration count is based on cpu power, and the rk3288 isn't as fast as a usual
  117. # desktop cpu, manually supply -i 15000 for security at the cost of a slightly slower unlock
  118. dmesg -n 2
  119. echo "Enter the password you would like to use to unlock the encrypted root partition at boot"
  120. cryptsetup -q -y -s 512 luksFormat -i 15000 $ROOT_PARTITION || exit 1
  121. echo "Now unlock the newly created encrypted root partition so we can mount it and install the filesystem"
  122. cryptsetup luksOpen $ROOT_PARTITION luksroot || exit 1
  123. dmesg -n 7
  124. ROOT_PARTITION=/dev/mapper/luksroot
  125. break
  126. ;;
  127. No,*|*,No )
  128. break
  129. ;;
  130. * )
  131. echo "Invalid Option, please enter Yes or No, 1 or 2"
  132. ;;
  133. esac
  134. done
  135. echo Writing Filesystem, this will take about 4 minutes...
  136. mkfs.ext4 -F -b 1024 $ROOT_PARTITION
  137. INSTALL_MOUNT=/mnt/install_mount
  138. mkdir -p $INSTALL_MOUNT/
  139. mount $ROOT_PARTITION $INSTALL_MOUNT/
  140. rsync -ah --info=progress2 --info=name0 --numeric-ids -x / $INSTALL_MOUNT/
  141. #Remove the live-fstab and install a base fstab
  142. rm $INSTALL_MOUNT/etc/fstab
  143. echo "${ROOT_PARTITION} / ext4 defaults,noatime 0 1" > $INSTALL_MOUNT/etc/fstab
  144. while true; do
  145. read -p "Install a desktop environment and the supporting packages? [Y/n]" ins
  146. case $ins in
  147. [Yy]* ) install_packages $INSTALL_MOUNT; break;;
  148. [Nn]* ) break;;
  149. * ) echo "Please answer y or n";;
  150. esac
  151. done
  152. umount $ROOT_PARTITION
  153. echo Running fsck
  154. e2fsck -p -f $ROOT_PARTITION
  155. if [[ $CRYPTO == "true" ]]
  156. then
  157. # unmount and close encrypted storage
  158. # let things settle, otherwise cryptsetup complainssss
  159. sleep 2
  160. cryptsetup luksClose luksroot
  161. fi
  162. echo "Please remove the booted device after power off is complete"
  163. while true; do
  164. read -p "Reboot? [y/N]" re
  165. case $re in
  166. [Yy]* ) reboot;;
  167. [Nn]* ) exit;;
  168. * ) echo "Please answer y or n";;
  169. esac
  170. done
  171. }
  172. #Setup partition map on internal emmc
  173. emmc_partition() {
  174. #disable dmesg, writing the partition map tries to write the the first gpt table, which is unmodifiable
  175. dmesg -D
  176. echo Writing partition map to internal emmc
  177. DISK_SZ="$(blockdev --getsz /dev/mmcblk2)"
  178. echo Total disk size is: $DISK_SZ
  179. if [ $DISK_SZ = 30785536 ]
  180. then
  181. echo Detected Emmc Type 1
  182. sfdisk /dev/mmcblk2 < $RESOURCES/mmc.partmap
  183. elif [ $DISK_SZ = 30777344 ]
  184. then
  185. echo Detected Emmc Type 2
  186. sfdisk /dev/mmcblk2 < $RESOURCES/mmc_type2.partmap
  187. else
  188. 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
  189. 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.
  190. select yn in "Yes" "No"
  191. do
  192. case $yn,$REPLY in
  193. Yes,*|*,Yes )
  194. echo Trying Emmc Type 2
  195. sfdisk /dev/mmcblk2 < $RESOURCES/mmc_type2.partmap
  196. break
  197. ;;
  198. * )
  199. echo "Invalid Option, please enter Yes or No, 1 or 2"
  200. ;;
  201. esac
  202. done
  203. fi
  204. dmesg -E
  205. }
  206. #Setup partition map for external bootable device, aka usb or sd card
  207. external_partition() {
  208. EXTERNAL_TARGET=$1
  209. kernel_start=8192
  210. kernel_size=65536
  211. #wipe the partition map, cgpt doesn't like anything weird in the primary or backup partition maps
  212. sgdisk -Z $EXTERNAL_TARGET
  213. partprobe $EXTERNAL_TARGET
  214. #make the base gpt partition map
  215. parted --script $EXTERNAL_TARGET mklabel gpt
  216. cgpt create $EXTERNAL_TARGET
  217. #must use cgpt to make the kernel partition, as we need the -S, -T, and -P variables
  218. cgpt add -i 1 -t kernel -b $kernel_start -s $kernel_size -l Kernel -S 1 -T 5 -P 10 $EXTERNAL_TARGET
  219. #Now the main filesystem
  220. #cgpt doesn't seem to handle this part correctly
  221. sgdisk -N 2 $EXTERNAL_TARGET
  222. #Set the type to "data"
  223. sgdisk -t 2:0700 $EXTERNAL_TARGET
  224. #Name it "properly" - Probably not required, but looks nice
  225. sgdisk -c 2:Root $EXTERNAL_TARGET
  226. #Reload the partition mapping
  227. partprobe $EXTERNAL_TARGET
  228. }
  229. #simply expand to fill the current boot device
  230. expand() {
  231. # need to strip the "p" if BOOT_DEVICE is an sd card or emmc
  232. BOOT_DEVICE_NO_P=$(echo $BOOT_DEVICE | cut -d 'p' -f 1)
  233. if [[ $BOOT_DEVICE == "/dev/mmcblk2" ]]
  234. then
  235. echo "Can't expand to fill internal emmc, install will have done this already"
  236. exit
  237. fi
  238. #Make the boot partition fille the whole drive
  239. #Delete the partition
  240. sgdisk -d 2 $BOOT_DEVICE_NO_P
  241. #Make new partition map entry, with full size
  242. sgdisk -N 2 $BOOT_DEVICE_NO_P
  243. #Set the type to "data"
  244. sgdisk -t 2:0700 $BOOT_DEVICE_NO_P
  245. #Name it "properly" - Probably not required, but looks nice
  246. sgdisk -c 2:Root $BOOT_DEVICE_NO_P
  247. #Reload the partition mapping
  248. partprobe $BOOT_DEVICE_NO_P
  249. #Force the filesystem to fill the new partition
  250. resize2fs -f ${BOOT_DEVICE}2
  251. echo "/dev/${BOOT_DEVICE}2 / ext4 defaults,noatime 0 1" > /etc/fstab
  252. while true; do
  253. read -p "Install a desktop environment and the supporting packages? [Y/n]" ins
  254. case $ins in
  255. [Yy]* ) /InstallResources/InstallPackages.sh; reboot;;
  256. [Nn]* ) exit;;
  257. * ) echo "Please answer y or n";;
  258. esac
  259. done
  260. }
  261. #Install all packages, desktop environment to target device
  262. install_packages() {
  263. TARGET_MOUNT=$1
  264. echo "Installing Packages"
  265. mount -t proc proc $TARGET_MOUNT/proc/
  266. mount --rbind /sys $TARGET_MOUNT/sys/
  267. mount --rbind /dev $TARGET_MOUNT/dev/
  268. chroot $TARGET_MOUNT/ ./InstallResources/InstallPackages.sh
  269. umount $TARGET_MOUNT/proc/
  270. mount --make-rprivate /sys
  271. mount --make-rprivate /dev
  272. umount -R $TARGET_MOUNT/sys/
  273. umount -R $TARGET_MOUNT/dev/
  274. }
  275. #call the main function, script technically starts here
  276. #Organized this way so that main can come before the functions it calls
  277. main "$@"; exit