cros-medium-setup 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. #!/usr/bin/env bash
  2. # Copyright (C) 2016 Paul Kocialkowski <contact@paulk.fr>
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. SYS_BLOCK_PATH="/sys/class/block"
  17. DEV_PATH="/dev"
  18. DEVICE="device"
  19. VENDOR="vendor"
  20. MODEL="model"
  21. NAME="name"
  22. KERNEL="kernel"
  23. IMG="img"
  24. KERNEL_MODULES="modules/lib"
  25. KERNEL_PARTITION_INDEX=1
  26. ROOTFS_PARTITION_INDEX=2
  27. # Size in blocks (512 kiB)
  28. GPT_SIZE=34
  29. KERNEL_SIZE=16384
  30. usage() {
  31. printf '%s\n' "$executable [action] [storage] [rootfs tarball|kernel files] [medium]" >&2
  32. printf '\n%s\n' 'Actions:' >&2
  33. printf '%s\n' ' partitions - Setup partitions on storage' >&2
  34. printf '%s\n' ' rootfs - Install rootfs tarball to storage' >&2
  35. printf '%s\n' ' kernel - Install kernel files to storage' >&2
  36. usage_storage
  37. printf '\n%s\n' 'Environment variables:' >&2
  38. printf '%s\n' ' KERNEL_PATH - Path to the kernel image' >&2
  39. printf '%s\n' ' VBOOT_TOOLS_PATH - Path to vboot tools' >&2
  40. }
  41. usage_storage() {
  42. printf '\n%s\n' 'Storage:' >&2
  43. local nodes=$( ls "$SYS_BLOCK_PATH" )
  44. local node_path
  45. local name
  46. for node in $nodes
  47. do
  48. node_path="$DEV_PATH/$node"
  49. if ! [ -b "$node_path" ]
  50. then
  51. continue
  52. fi
  53. name=$( storage_name "$node_path" )
  54. if [ -z "$name" ]
  55. then
  56. continue
  57. fi
  58. printf '%s\n' " $node_path - $name" >&2
  59. done
  60. }
  61. storage_affect_confirm() {
  62. local storage_path=$1
  63. local name=$( storage_name "$storage_path" )
  64. local confirm
  65. printf '%s\n' 'This is going to affect the following storage:'
  66. printf '%s\n' " $storage_path - $name"
  67. printf '%s' 'Press enter to confirm: '
  68. read confirm
  69. }
  70. storage_name() {
  71. local storage_path=$1
  72. local node=$( basename "$storage_path" )
  73. local vendor_path="$SYS_BLOCK_PATH/$node/$DEVICE/$VENDOR"
  74. local model_path="$SYS_BLOCK_PATH/$node/$DEVICE/$MODEL"
  75. local name_path="$SYS_BLOCK_PATH/$node/$DEVICE/$NAME"
  76. local vendor
  77. local name
  78. if [ -f "$model_path" ]
  79. then
  80. name=$( cat "$model_path" )
  81. elif [ -f "$name_path" ]
  82. then
  83. name=$( cat "$name_path" )
  84. else
  85. return 0
  86. fi
  87. name=$( printf '%s\n' "$name" | sed -e "s/^[[:space:]]*//;s/[[:space:]]*$//" )
  88. if [ -f "$vendor_path" ]
  89. then
  90. vendor=$( cat "$vendor_path" )
  91. vendor=$( printf '%s\n' "$vendor" | sed -e "s/^[[:space:]]*//;s/[[:space:]]*$//" )
  92. name="$vendor $name"
  93. fi
  94. printf '%s\n' "$name"
  95. }
  96. storage_partition_path() {
  97. local storage_path=$1
  98. local index=$2
  99. storage_partition_path="$storage_path$index"
  100. if ! [ -b "$storage_partition_path" ]
  101. then
  102. storage_partition_path="$storage_path""p$index"
  103. fi
  104. if ! [ -b "$storage_partition_path" ]
  105. then
  106. return 1
  107. fi
  108. printf '%s\n' "$storage_partition_path"
  109. }
  110. storage_partition_mount_path() {
  111. local storage_partition_path=$1
  112. local storage_partition_mount_path=$( udisksctl info -b "$storage_partition_path" | grep "MountPoints" | sed "s/.*MountPoints:[[:space:]]*\(.*\)/\1/g" )
  113. printf '%s\n' "$storage_partition_mount_path"
  114. }
  115. partitions() {
  116. local storage_path=$1
  117. local storage_rootfs_path
  118. local partitions
  119. local start
  120. storage_affect_confirm "$storage_path"
  121. partitions=$( mount | grep -P "^$storage_path" | sed "s/^\([^[:space:]]*\).*/\1/g" )
  122. for partition in $partitions
  123. do
  124. # Partition may already be unmounted.
  125. udisksctl unmount -b "$partition" || true
  126. done
  127. ( printf '%s\n' "g" ; printf '%s\n' "w" ) | fdisk "$storage_path"
  128. cgpt create "$storage_path"
  129. start=$GPT_SIZE
  130. size=$KERNEL_SIZE
  131. cgpt add -b "$start" -s "$size" -P 1 -S 1 -t kernel -l kernel "$storage_path"
  132. start=$(( $start + $size ))
  133. size=$( cgpt show "$storage_path" | grep "Sec GPT table" | sed "s/[[:space:]]*\([0-9]*\).*/\1/g" )
  134. size=$(( $size - $start ))
  135. cgpt add -b "$start" -s "$size" -t rootfs -l rootfs "$storage_path"
  136. blockdev --rereadpt "$storage_path" || partprobe "$storage_path"
  137. storage_rootfs_path=$( storage_partition_path "$storage_path" "$ROOTFS_PARTITION_INDEX" )
  138. mkfs.ext4 -F "$storage_rootfs_path"
  139. printf '\n%s\n' "Setup partitions on storage $storage_path"
  140. }
  141. rootfs() {
  142. local storage_path=$1
  143. local rootfs_tarball_path=$2
  144. local storage_rootfs_path=$( storage_partition_path "$storage_path" "$ROOTFS_PARTITION_INDEX" )
  145. local storage_rootfs_mount_path
  146. storage_affect_confirm "$storage_path"
  147. # Partition may already be mounted.
  148. udisksctl mount -b "$storage_rootfs_path" || true
  149. storage_rootfs_mount_path=$( storage_partition_mount_path "$storage_rootfs_path" )
  150. tar -xf "$rootfs_tarball_path" -ps -C "$storage_rootfs_mount_path"
  151. udisksctl unmount -b "$storage_rootfs_path"
  152. printf '\n%s\n' "Installed rootfs on storage $storage_path"
  153. }
  154. kernel() {
  155. local storage_path=$1
  156. local kernel_files_path=$2
  157. local medium=$3
  158. local storage_kernel_path=$( storage_partition_path "$storage_path" "$KERNEL_PARTITION_INDEX" )
  159. local storage_rootfs_path=$( storage_partition_path "$storage_path" "$ROOTFS_PARTITION_INDEX" )
  160. local kernel_image_path="$kernel_files_path/$KERNEL-$medium.$IMG"
  161. local kernel_modules_path="$kernel_files_path/$KERNEL_MODULES"
  162. local storage_rootfs_mount_path
  163. storage_affect_confirm "$storage_path"
  164. cat "$kernel_image_path" > "$storage_kernel_path"
  165. sync
  166. # Partition may already be mounted.
  167. udisksctl mount -b "$storage_rootfs_path" || true
  168. storage_rootfs_mount_path=$( storage_partition_mount_path "$storage_rootfs_path" )
  169. rsync -a --keep-dirlinks "$kernel_modules_path" "$storage_rootfs_mount_path/"
  170. sync
  171. udisksctl unmount -b "$storage_rootfs_path"
  172. printf '\n%s\n' "Installed kernel on storage $storage_path"
  173. }
  174. requirements() {
  175. local requirement
  176. local requirement_path
  177. for requirement in "$@"
  178. do
  179. requirement_path=$( which "$requirement" || true )
  180. if [ -z "$requirement_path" ]
  181. then
  182. printf '%s\n' "Missing requirement: $requirement" >&2
  183. exit 1
  184. fi
  185. done
  186. }
  187. setup() {
  188. root=$(readlink -f "$( dirname "$0" )" )
  189. executable=$( basename "$0" )
  190. if [ -z "$KERNEL_PATH" ]
  191. then
  192. KERNEL_PATH=$root
  193. fi
  194. if ! [ -z "$VBOOT_TOOLS_PATH" ]
  195. then
  196. PATH="$PATH:$VBOOT_TOOLS_PATH"
  197. fi
  198. }
  199. cros_medium_setup() {
  200. local action=$1
  201. local storage_path=$2
  202. local rootfs_tarball_path=$3
  203. local kernel_files_path=$3
  204. local medium=$4
  205. set -e
  206. setup "$@"
  207. if [ -z "$action" ] || [ -z "$storage_path" ]
  208. then
  209. usage
  210. exit 1
  211. fi
  212. case $action in
  213. "partitions")
  214. requirements "udisksctl" "fdisk" "cgpt" "mkfs.ext4"
  215. partitions "$storage_path"
  216. ;;
  217. "rootfs")
  218. if [ -z "$rootfs_tarball_path" ]
  219. then
  220. usage
  221. exit 1
  222. fi
  223. requirements "udisksctl" "tar"
  224. rootfs "$storage_path" "$rootfs_tarball_path"
  225. ;;
  226. "kernel")
  227. if [ -z "$kernel_files_path" ] || [ -z "$medium" ]
  228. then
  229. usage
  230. exit 1
  231. fi
  232. requirements "udisksctl" "rsync"
  233. kernel "$storage_path" "$kernel_files_path" "$medium"
  234. ;;
  235. *)
  236. usage
  237. exit 1
  238. ;;
  239. esac
  240. }
  241. cros_medium_setup "$@"