platform-upgrade 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #!/bin/bash
  2. # https://github.com/calmh/smartos-platform-upgrade
  3. # Copyright (c) 2012-2016 Jakob Borg & Contributors
  4. # Distributed under the MIT License
  5. # us-east.manta.joyent.com currently uses a wildcard certificate based on the
  6. # Thawte Primary Root CA.
  7. # SHA-1=91:C6:D6:EE:3E:8A:C8:63:84:E5:48:C2:99:29:5C:75:6C:81:7B:81
  8. # SHA-256=8D:72:2F:81:A9:C1:13:C0:79:1D:F1:36:A2:96:6D:B2:6C:95:0A:97:1D:B4:6B:41:99:F4:EA:54:B7:8B:FB:9F
  9. cert_file=$(mktemp)
  10. function cleanup {
  11. rm "$cert_file"
  12. }
  13. trap cleanup EXIT
  14. cat >"$cert_file" <<EOF
  15. -----BEGIN CERTIFICATE-----
  16. MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
  17. iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
  18. cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
  19. BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
  20. MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
  21. BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
  22. aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
  23. dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
  24. AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
  25. 3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
  26. tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
  27. Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
  28. VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
  29. 79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
  30. c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
  31. Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
  32. c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
  33. UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
  34. Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
  35. BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
  36. A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
  37. Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
  38. VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
  39. ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
  40. 8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
  41. iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
  42. Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
  43. XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
  44. qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
  45. VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
  46. L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
  47. jjxDah2nGN59PRbxYvnKkKj9
  48. -----END CERTIFICATE-----
  49. -----BEGIN CERTIFICATE-----
  50. MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB
  51. iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
  52. cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
  53. BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx
  54. MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV
  55. BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE
  56. ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g
  57. VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
  58. AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N
  59. TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj
  60. eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E
  61. oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk
  62. Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY
  63. uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j
  64. BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb
  65. +ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G
  66. A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw
  67. CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0
  68. LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr
  69. BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv
  70. bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov
  71. L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H
  72. ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH
  73. 7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi
  74. H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx
  75. RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv
  76. xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38
  77. sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL
  78. l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq
  79. 6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY
  80. LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5
  81. yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K
  82. 00u/I5sUKUErmgQfky3xxzlIPK1aEn8=
  83. -----END CERTIFICATE-----
  84. EOF
  85. function _curl {
  86. curl -s --cacert "$cert_file" $@
  87. }
  88. function usage() {
  89. cat <<- "USAGE"
  90. $ platform-upgrade [-u URL -s MD5SUM_URL] [-f]
  91. OPTIONS:
  92. -u URL : Remote/local url of platform-version.tgz file
  93. -s MD5SUM_URL : Remote/local url of md5 checksum file
  94. -f : Force installation if version is already present
  95. EXAMPLE:
  96. # Use default Joyent URL for latest platform image
  97. platform-upgrade
  98. # Use local platform and checksum file
  99. platform-upgrade -u file:///tmp/platform-20180510T153535Z.tgz -s file:///tmp/md5sum.txt
  100. USAGE
  101. }
  102. force="false"
  103. while getopts :fu:s: option; do
  104. case "$option" in
  105. u)
  106. platform_url="$OPTARG"
  107. ;;
  108. s)
  109. md5sums_url="$OPTARG"
  110. ;;
  111. f)
  112. force="true"
  113. ;;
  114. \?)
  115. usage
  116. exit -1
  117. ;;
  118. esac
  119. done
  120. shift $((OPTIND-1))
  121. if [[ -n $platform_url ]] && [[ ! -n $md5sums_url ]]; then
  122. usage
  123. exit -1
  124. fi
  125. if [[ ! -n $platform_url ]]; then
  126. host=https://us-east.manta.joyent.com
  127. latest_path="${host}$(_curl "$host/Joyent_Dev/public/SmartOS/latest")"
  128. version="$(expr "$latest_path" : '.*\([0-9]\{8\}T[0-9]\{6\}Z\).*')"
  129. latest_spec_path="$(_curl "$host/Joyent_Dev/public/SmartOS/$version")"
  130. header="$(expr "$latest_spec_path" : '.*platform-release-\([0-9]\{8\}\)-.*')"
  131. platform_url="$latest_path/platform-release-$header-$version.tgz"
  132. if [[ ! -n $md5sums_url ]]; then
  133. md5sums_url="$latest_path/md5sums.txt"
  134. fi
  135. else
  136. header="$(expr "$platform_url" : '.*platform-release-\([0-9]\{8\}\)-.*')"
  137. version="$(expr "$platform_url" : '.*\([0-9]\{8\}T[0-9]\{6\}Z\).*')"
  138. fi
  139. platform_file="platform-release-$header-$version.tgz"
  140. platform_dir="platform-$version"
  141. IFS=_ read brand kernel < <(uname -v)
  142. if [[ $kernel == $version ]]; then
  143. echo "Already on latest version ($kernel)."
  144. $force || exit -1
  145. fi
  146. tmp=$(mktemp -d)
  147. cd "$tmp" || exit -1
  148. echo -n "Downloading $platform_file..."
  149. if ! _curl -o "$platform_file" "$platform_url" ; then
  150. echo " failed"
  151. exit -1
  152. else
  153. echo " OK"
  154. fi
  155. echo -n "Verifying checksum..."
  156. _curl "$md5sums_url" \
  157. | grep "$platform_file" \
  158. | awk '{print $1}' > expected.md5
  159. openssl md5 "$platform_file" | awk '{print $2}' > actual.md5
  160. if ! cmp -s actual.md5 expected.md5 ; then
  161. echo " failed"
  162. exit -1
  163. else
  164. echo " OK"
  165. fi
  166. echo -n "Extracting latest platform..."
  167. if ! gtar zxf "$platform_file" ; then
  168. echo " failed"
  169. exit -1
  170. else
  171. echo " OK"
  172. fi
  173. echo -n "Marking release version..."
  174. if ! echo $version > $platform_dir/VERSION ; then
  175. echo " failed"
  176. exit -1
  177. else
  178. echo " OK"
  179. fi
  180. echo -n "Checking current boot device..."
  181. if [[ -z $1 ]] ; then
  182. removables=($(diskinfo -cH | \
  183. awk 'BEGIN { FS="\t" } $7~/\?\?R./ { print $2 }'))
  184. echo -n " detected ${removables[@]}"
  185. if [[ ${#removables[@]} -eq 0 ]]; then
  186. echo
  187. echo "Error: Unable to detect removable device."
  188. diskinfo
  189. echo "Specify correct device on the command line."
  190. exit -1
  191. elif [[ ${#removables[@]} -gt 1 ]]; then
  192. echo
  193. echo "Error: more than one removable device detected."
  194. diskinfo -cH | awk 'BEGIN { FS="\t" } $7~/\?\?R./ { print }'
  195. echo "Specify correct device on the command line."
  196. exit -1
  197. fi
  198. # Look for a GPT/EFI VTOC; if there isn't one, then this is almost
  199. # certainly an MBR-partitioned device. If it's a GPT label, then we
  200. # want the slice that's of type 2 (ROOT).
  201. if [[ -e "/dev/dsk/${removables[0]}" ]]; then
  202. partition=$(/usr/sbin/prtvtoc -h "/dev/dsk/${removables[0]}" | \
  203. awk ' $2 == 2 { print $1 }')
  204. if [[ $? -eq 0 && -n "$partition" ]]; then
  205. echo -n ", GPT label"
  206. usb="/dev/dsk/${removables[0]}s${partition}"
  207. fi
  208. fi
  209. if [[ -z "$usb" ]]; then
  210. echo -n ", MBR label"
  211. usb="/dev/dsk/${removables[0]}p1"
  212. fi
  213. else
  214. usb="$1"
  215. echo -n " using $usb"
  216. fi
  217. umount "$usb" 2>/dev/null
  218. mkdir usb
  219. if ! mount -F pcfs -o foldcase "$usb" "$tmp/usb" ; then
  220. echo ", mount failed"
  221. exit -1
  222. else
  223. echo -n ", mounted"
  224. fi
  225. if [[ ! -d usb/platform ]] ; then
  226. echo ", missing platform dir"
  227. exit -1
  228. else
  229. echo ", OK"
  230. fi
  231. echo -n "Updating platform on boot device..."
  232. if ! rsync -rltD "$platform_dir/" usb/platform.new/ ; then
  233. echo " failed"
  234. exit -1
  235. else
  236. echo " OK"
  237. fi
  238. echo -n "Remounting boot device..."
  239. umount "$usb" 2>/dev/null
  240. if ! mount -F pcfs -o foldcase "$usb" "$tmp/usb" ; then
  241. echo " failed"
  242. exit -1
  243. else
  244. echo " OK"
  245. fi
  246. echo -n "Verifying kernel checksum on boot device..."
  247. openssl dgst -sha1 "$platform_dir"/i86pc/kernel/amd64/unix | cut -d ' ' -f 2 > kernel.expected
  248. openssl dgst -sha1 usb/platform.new/i86pc/kernel/amd64/unix | cut -d ' ' -f 2 > kernel.actual
  249. if ! cmp -s kernel.actual kernel.expected ; then
  250. echo " failed"
  251. exit -1
  252. else
  253. echo " OK"
  254. fi
  255. echo -n "Verifying boot_archive checksum on boot device..."
  256. openssl dgst -sha1 usb/platform.new/i86pc/amd64/boot_archive | cut -d ' ' -f 2 > boot_archive.actual
  257. if ! cmp -s boot_archive.actual usb/platform.new/i86pc/amd64/boot_archive.hash ; then
  258. echo " failed"
  259. exit -1
  260. else
  261. echo " OK"
  262. fi
  263. echo -n "Activating new platform on $usb..."
  264. rm -rf usb/old
  265. mkdir usb/old
  266. if ! ( mv usb/platform usb/old && mv usb/platform.new usb/platform ) ; then
  267. echo " failed"
  268. exit -1
  269. else
  270. echo " OK"
  271. fi
  272. echo
  273. echo "Boot device upgraded. To do:"
  274. echo
  275. echo " 1) Sanity check the contents of $tmp/usb"
  276. echo " 2) umount $usb"
  277. echo " 3) reboot"