A utility for downloading and verifying FreeBSD releases and snapshots
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

462 lines
15 KiB

  1. #
  2. # Copyright 2018, 2022 John-Mark Gurney.
  3. # All rights reserved.
  4. #
  5. # Redistribution and use in source and binary forms, with or without
  6. # modification, are permitted provided that the following conditions
  7. # are met:
  8. # 1. Redistributions of source code must retain the above copyright
  9. # notice, this list of conditions and the following disclaimer.
  10. # 2. Redistributions in binary form must reproduce the above copyright
  11. # notice, this list of conditions and the following disclaimer in the
  12. # documentation and/or other materials provided with the distribution.
  13. #
  14. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. # SUCH DAMAGE.
  25. #
  26. # $Id$
  27. #
  28. BEGIN {
  29. vmroot = "https://download.freebsd.org/ftp/snapshots/VM-IMAGES/"
  30. ociroot = "https://download.freebsd.org/ftp/snapshots/OCI-IMAGES/"
  31. isoroot = "https://download.freebsd.org/ftp/snapshots/ISO-IMAGES/"
  32. bciroot = "https://download.freebsd.org/ftp/snapshots/CI-IMAGES/"
  33. relvmroot = "https://download.freebsd.org/ftp/releases/VM-IMAGES/"
  34. relociroot = "https://download.freebsd.org/ftp/releases/OCI-IMAGES/"
  35. relisoroot = "https://download.freebsd.org/ftp/releases/ISO-IMAGES/"
  36. relbciroot = "https://download.freebsd.org/ftp/releases/CI-IMAGES/"
  37. #print "begin" > "/dev/stderr"
  38. hexdigits["0"] = 0
  39. hexdigits["1"] = 1
  40. hexdigits["2"] = 2
  41. hexdigits["3"] = 3
  42. hexdigits["4"] = 4
  43. hexdigits["5"] = 5
  44. hexdigits["6"] = 6
  45. hexdigits["7"] = 7
  46. hexdigits["8"] = 8
  47. hexdigits["9"] = 9
  48. hexdigits["A"] = 10
  49. hexdigits["B"] = 11
  50. hexdigits["C"] = 12
  51. hexdigits["D"] = 13
  52. hexdigits["E"] = 14
  53. hexdigits["F"] = 15
  54. if (DO_TESTS == 1) {
  55. run_tests()
  56. exit(0)
  57. }
  58. }
  59. function run_tests() {
  60. fromhextests["3D"] = 61
  61. fromhextests["3F"] = 63
  62. for (i in fromhextests) {
  63. if (fromhex(i) != fromhextests[i]) {
  64. printf("ERROR: fromhex failed on %s, expecting %d, got %d.\n", i, fromhextests[i], fromhex(i))
  65. exit(1)
  66. }
  67. }
  68. validrevs[0] = "r369411"
  69. validrevs[1] = "c122cf32f2a"
  70. validrevs[2] = "b83b87f53e73"
  71. for (i in validrevs) {
  72. if (!isrev(validrevs[i])) {
  73. print "ERROR: valid rev not valid: " validrevs[i]
  74. exit(1)
  75. }
  76. }
  77. invalidrevs[0] = "asoijw23r"
  78. for (i in invalidrevs) {
  79. if (isrev(invalidrevs[i])) {
  80. print "ERROR: invalid rev valid: " invalidrevs[i]
  81. exit(1)
  82. }
  83. }
  84. MID = "custommid"
  85. fnametst[0] = "FreeBSD-13.0-CURRENT-arm64-aarch64-20200903-c122cf32f2a.qcow2.xz"
  86. typeres[0] = "vm"
  87. parseres[0] = "vm 13.0-CURRENT arm64-aarch64 xxx 20200903 c122cf32f2a qcow2 FreeBSD-13.0-CURRENT-arm64-aarch64-20200903-c122cf32f2a.qcow2.xz https://download.freebsd.org/ftp/snapshots/VM-IMAGES/13.0-CURRENT/aarch64/20200903/FreeBSD-13.0-CURRENT-arm64-aarch64-20200903-c122cf32f2a.qcow2.xz custommid"
  88. fnametst[1] = "FreeBSD-13.0-CURRENT-powerpc-powerpcspe-20181026-r339752-bootonly.iso"
  89. typeres[1] = "iso"
  90. parseres[1] = "iso 13.0-CURRENT powerpc-powerpcspe xxx 20181026 r339752 bootonly FreeBSD-13.0-CURRENT-powerpc-powerpcspe-20181026-r339752-bootonly.iso https://download.freebsd.org/ftp/snapshots/ISO-IMAGES/13.0/FreeBSD-13.0-CURRENT-powerpc-powerpcspe-20181026-r339752-bootonly.iso custommid"
  91. fnametst[2] = "FreeBSD-13.0-CURRENT-arm64-aarch64-PINE64-LTS-20181026-r339752.img.xz"
  92. typeres[2] = "iso"
  93. parseres[2] = "iso 13.0-CURRENT arm64-aarch64 PINE64-LTS 20181026 r339752 xxx FreeBSD-13.0-CURRENT-arm64-aarch64-PINE64-LTS-20181026-r339752.img.xz https://download.freebsd.org/ftp/snapshots/ISO-IMAGES/13.0/FreeBSD-13.0-CURRENT-arm64-aarch64-PINE64-LTS-20181026-r339752.img.xz custommid"
  94. fnametst[3] = "FreeBSD-13.0-CURRENT-i386-20181026-r339752.vmdk.xz"
  95. typeres[3] = "vm"
  96. parseres[3] = "vm 13.0-CURRENT i386 xxx 20181026 r339752 vmdk FreeBSD-13.0-CURRENT-i386-20181026-r339752.vmdk.xz https://download.freebsd.org/ftp/snapshots/VM-IMAGES/13.0-CURRENT/i386/20181026/FreeBSD-13.0-CURRENT-i386-20181026-r339752.vmdk.xz custommid"
  97. fnametst[4] = "FreeBSD-12.1-BETA3-amd64-mini-memstick.img.xz"
  98. typeres[4] = "iso"
  99. parseres[4] = "iso 12.1-BETA3 amd64 mini-memstick xxx unspec xxx FreeBSD-12.1-BETA3-amd64-mini-memstick.img.xz https://download.freebsd.org/ftp/releases/ISO-IMAGES/12.1/FreeBSD-12.1-BETA3-amd64-mini-memstick.img.xz custommid"
  100. fnametst[5] = "FreeBSD-12.1-RC1-amd64-mini-memstick.img.xz"
  101. typeres[5] = "iso"
  102. parseres[5] = "iso 12.1-RC1 amd64 mini-memstick xxx unspec xxx FreeBSD-12.1-RC1-amd64-mini-memstick.img.xz https://download.freebsd.org/ftp/releases/ISO-IMAGES/12.1/FreeBSD-12.1-RC1-amd64-mini-memstick.img.xz custommid"
  103. fnametst[6] = "FreeBSD-12.1-RELEASE-arm64-aarch64.vmdk.xz"
  104. typeres[6] = "vm"
  105. parseres[6] = "vm 12.1-RELEASE arm64-aarch64 xxx xxx unspec vmdk FreeBSD-12.1-RELEASE-arm64-aarch64.vmdk.xz https://download.freebsd.org/ftp/releases/VM-IMAGES/12.1-RELEASE/aarch64/Latest/FreeBSD-12.1-RELEASE-arm64-aarch64.vmdk.xz custommid"
  106. fnametst[7] = "FreeBSD-13.1-RELEASE-riscv-riscv64.vmdk.xz"
  107. typeres[7] = "vm"
  108. parseres[7] = "vm 13.1-RELEASE riscv-riscv64 xxx xxx unspec vmdk FreeBSD-13.1-RELEASE-riscv-riscv64.vmdk.xz https://download.freebsd.org/ftp/releases/VM-IMAGES/13.1-RELEASE/riscv64/Latest/FreeBSD-13.1-RELEASE-riscv-riscv64.vmdk.xz custommid"
  109. fnametst[8] = "FreeBSD-13.1-RELEASE-amd64-BASIC-CI.raw.xz"
  110. typeres[8] = "vm"
  111. parseres[8] = "vm 13.1-RELEASE amd64 BASIC-CI xxx unspec raw FreeBSD-13.1-RELEASE-amd64-BASIC-CI.raw.xz https://download.freebsd.org/ftp/releases/CI-IMAGES/13.1-RELEASE/amd64/Latest/FreeBSD-13.1-RELEASE-amd64-BASIC-CI.raw.xz custommid"
  112. fnametst[9] = "FreeBSD-13.1-STABLE-amd64-20230114-b83b87f53e73-253383-bootonly.iso"
  113. typeres[9] = "iso"
  114. parseres[9] = "iso 13.1-STABLE amd64 xxx 20230114 b83b87f53e73-c253383 bootonly FreeBSD-13.1-STABLE-amd64-20230114-b83b87f53e73-253383-bootonly.iso https://download.freebsd.org/ftp/snapshots/ISO-IMAGES/13.1/FreeBSD-13.1-STABLE-amd64-20230114-b83b87f53e73-253383-bootonly.iso custommid"
  115. fnametst[10] = "FreeBSD-13.0-CURRENT-sparc64-20181026-r339752-bootonly.iso"
  116. typeres[10] = "iso"
  117. parseres[10] = "iso 13.0-CURRENT sparc64 xxx 20181026 r339752 bootonly FreeBSD-13.0-CURRENT-sparc64-20181026-r339752-bootonly.iso https://download.freebsd.org/ftp/snapshots/ISO-IMAGES/13.0/FreeBSD-13.0-CURRENT-sparc64-20181026-r339752-bootonly.iso custommid"
  118. fnametst[11] = "FreeBSD-14.2-RELEASE-riscv-riscv64-container-image-static.txz"
  119. typeres[11] = "oci"
  120. parseres[11] = "oci 14.2-RELEASE riscv-riscv64 xxx xxx unspec txz FreeBSD-14.2-RELEASE-riscv-riscv64-container-image-static.txz https://download.freebsd.org/ftp/releases/OCI-IMAGES/14.2-RELEASE/riscv64/Latest/FreeBSD-14.2-RELEASE-riscv-riscv64-container-image-static.txz custommid"
  121. #res = sprintf("%s %s %s %s %s %s %s %s %s %s", type, parts[2] "-" parts[3], arch, platform, date, rev, vers, fname, url, MID)
  122. fnametst[12] = "FreeBSD-15.0-CURRENT-riscv-riscv64-container-image-20241128-edfccce309a6-273911-static.txz"
  123. typeres[12] = "oci"
  124. parseres[12] = "oci 15.0-CURRENT riscv-riscv64 xxx 20241128 edfccce309a6-c273911 txz FreeBSD-15.0-CURRENT-riscv-riscv64-container-image-20241128-edfccce309a6-273911-static.txz https://download.freebsd.org/ftp/snapshots/OCI-IMAGES/15.0-CURRENT/riscv64/20241128/FreeBSD-15.0-CURRENT-riscv-riscv64-container-image-20241128-edfccce309a6-273911-static.txz custommid"
  125. for (tstidx in fnametst) {
  126. type = typeres[tstidx]
  127. tres = parse_fname(fnametst[tstidx])
  128. if (tres != parseres[tstidx]) {
  129. print "ERROR: invalid fname parse (idx " tstidx ") of " fnametst[tstidx]
  130. print "got:"
  131. print tres
  132. print "expected:"
  133. print parseres[tstidx]
  134. exit(1)
  135. }
  136. }
  137. }
  138. function fromhex(val) {
  139. r = 0
  140. while (val) {
  141. r = r * 16 + hexdigits[substr(val, 1, 1)]
  142. val = substr(val, 2)
  143. }
  144. return r
  145. }
  146. {
  147. #print "raw " $0 > "/dev/stderr"
  148. }
  149. !MID && tolower($1) == "message-id:" {
  150. MID=$2
  151. sub(".*<", "", MID)
  152. sub(">.*", "", MID)
  153. }
  154. !haveboundary && tolower($1) == "content-type:" && tolower($2) == "multipart/signed;" && check == 0 {
  155. getboundary = 1
  156. next
  157. }
  158. getboundary == 1 {
  159. getboundary = 0
  160. haveboundary = 1
  161. if (substr($2, 1, 9) == "boundary=")
  162. boundary=substr($2, 11, length($2) - 11)
  163. next
  164. }
  165. haveboundary && $1 == ("--" boundary) {
  166. sigbody = 1
  167. bodyheaders = 1
  168. }
  169. !haveboundary && $0 == "-----BEGIN PGP SIGNED MESSAGE-----" {
  170. sigbody = 1
  171. }
  172. # Skip processing till we have the body
  173. !sigbody {
  174. next
  175. }
  176. bodyheaders {
  177. if (tolower($1) == "content-transfer-encoding:" && tolower($2) == "quoted-printable")
  178. quotedprintable = 1
  179. if ($0 == "") {
  180. #print "end of headers " $0 > "/dev/stderr"
  181. bodyheaders = 0
  182. }
  183. next
  184. }
  185. quotedprintable {
  186. #print "orig raw " $0 > "/dev/stderr"
  187. contline = 0
  188. if (substr($0, length($0), 1) == "=") {
  189. contline = 1
  190. $0 = substr($0, 1, length($0) - 1)
  191. }
  192. procline = $0
  193. line = ""
  194. while (1) {
  195. #print "procline " procline > "/dev/stderr"
  196. #print "line " line > "/dev/stderr"
  197. pos = index(procline, "=")
  198. #print "pos " pos > "/dev/stderr"
  199. if (pos == 0) {
  200. line = line procline
  201. break
  202. }
  203. line = line substr(procline, 1, pos - 1) sprintf("%c", fromhex(substr(procline, pos + 1, 2)))
  204. procline = substr(procline, pos + 3)
  205. }
  206. $0 = line
  207. #print " new raw " $0 > "/dev/stderr"
  208. if (contline) {
  209. #print "continuing" > "/dev/stderr"
  210. prevline = prevline $0
  211. next
  212. }
  213. $0 = prevline $0
  214. prevline = ""
  215. #print "mid " MID > "/dev/stderr"
  216. #print "proc raw " $0 > "/dev/stderr"
  217. }
  218. $0 == "== ISO CHECKSUMS ==" ||
  219. $0 == "ISO Image Checksums" {
  220. type = "iso"
  221. }
  222. $0 == "== VM IMAGE CHECKSUMS ==" ||
  223. $0 == "Virtual Machine Disk Image Checksums" {
  224. type = "vm"
  225. }
  226. $0 == "OCI Container Checksums" {
  227. type = "oci"
  228. }
  229. function isdate(date) {
  230. m = match(date, "[0-9]+")
  231. if (m && RLENGTH == 8)
  232. return 1
  233. return 0
  234. }
  235. function isrev(s) {
  236. if (substr(s, 1, 1) == "r")
  237. return 1
  238. m = match(s, "[0-9a-f]+")
  239. if (m && RLENGTH >= 11)
  240. return 1
  241. return 0
  242. }
  243. function isrelease(relpart) {
  244. if (index(relpart, "BETA") == 1 || index(relpart, "RC") == 1 ||
  245. index(relpart, "RELEASE") == 1)
  246. return 1
  247. return 0
  248. }
  249. #FreeBSD-13.0-CURRENT-arm64-aarch64-20200903-c122cf32f2a.qcow2.xz
  250. #FreeBSD-13.0-CURRENT-powerpc-powerpcspe-20181026-r339752-bootonly.iso
  251. #FreeBSD-13.0-CURRENT-sparc64-20181026-r339752-bootonly.iso.asc
  252. #FreeBSD-13.0-CURRENT-arm64-aarch64-PINE64-LTS-20181026-r339752.img.xz
  253. #FreeBSD-13.0-CURRENT-i386-20181026-r339752.vmdk.xz
  254. #FreeBSD-12.1-BETA3-amd64-mini-memstick.img.xz
  255. #FreeBSD-12.1-RC1-amd64-mini-memstick.img.xz
  256. #FreeBSD-12.1-RELEASE-arm64-aarch64.vmdk.xz
  257. #FreeBSD-13.1-RELEASE-riscv-riscv64.vmdk.xz
  258. #FreeBSD-13.1-RELEASE-amd64-BASIC-CI.raw.xz
  259. #FreeBSD-13.1-STABLE-amd64-20230114-b83b87f53e73-253383-bootonly.iso
  260. /.*SHA512 (.*) = [0-9a-f]+/ {
  261. #print "raw " $0 > "/dev/stderr"
  262. # Strip parens
  263. fname = substr($2, 2, length($2) - 2)
  264. a = parse_fname(fname)
  265. print(a)
  266. }
  267. function parse_fname(fname) {
  268. split(fname, dotparts, ".")
  269. # recombine around dot in version, strips off ALL extensions (including vm type)
  270. basename = dotparts[1] "." dotparts[2]
  271. cnt = split(basename, parts, "-")
  272. # make arch part, may include additional part
  273. arch = parts[4]
  274. basearch = arch
  275. if (parts[4] == "arm" || parts[4] == "riscv" ||
  276. (parts[4] == "powerpc" && parts[5] == "powerpcspe") ||
  277. (parts[4] == "powerpc" && parts[5] == "powerpc64") ||
  278. parts[4] == "arm64") {
  279. # FreeBSD-11.3-STABLE-arm64-aarch64-20191011-r353406-memstick.img
  280. basearch = parts[5]
  281. arch = parts[4] "-" parts[5]
  282. nextidx = 6
  283. } else {
  284. # FreeBSD-11.3-STABLE-amd64-20191011-r353406.qcow2.xz
  285. nextidx = 5
  286. }
  287. # find date, may be platform first
  288. if (isrelease(parts[3])) {
  289. if (nextidx > cnt) {
  290. # FreeBSD-12.1-BETA3-i386.vhd.xz
  291. platform = "xxx"
  292. } else if (cnt == nextidx) {
  293. # FreeBSD-12.1-RC1-powerpc-powerpcspe-dvd1.iso
  294. platform = parts[nextidx]
  295. nextidx += 1
  296. } else if (type == "oci") {
  297. platform = "xxx"
  298. nextidx += 2
  299. } else {
  300. # FreeBSD-12.1-BETA3-amd64-mini-memstick.img.xz
  301. platform = parts[nextidx] "-" parts[nextidx + 1]
  302. nextidx += 2
  303. }
  304. date = "xxx"
  305. } else if (isdate(parts[nextidx])) {
  306. # FreeBSD-11.3-STABLE-amd64-20191011-r353406.qcow2.xz
  307. platform = "xxx"
  308. date = parts[nextidx]
  309. nextidx += 1
  310. } else if (type == "oci") {
  311. platform = "xxx"
  312. nextidx += 2
  313. date = parts[nextidx]
  314. nextidx += 1
  315. } else {
  316. # FreeBSD-13.0-CURRENT-arm64-aarch64-PINE64-LTS-20181026-r339752.img.xz
  317. platform = parts[nextidx]
  318. date = parts[nextidx + 1]
  319. if (isdate(date)) {
  320. # FreeBSD-13.0-CURRENT-arm64-aarch64-PINEBOOK-20191011-r353427.img.xz
  321. nextidx += 2
  322. } else {
  323. # FreeBSD-13.0-CURRENT-arm64-aarch64-PINE64-LTS-20181026-r339752.img.xz
  324. date = parts[nextidx + 2]
  325. platform = parts[nextidx] "-" parts[nextidx + 1]
  326. nextidx += 3
  327. }
  328. }
  329. # if this part doesn't begin w/ r (for svn rev), skip it, we can't parse
  330. # others for now
  331. rev = parts[nextidx]
  332. if (isrelease(parts[3])) {
  333. # FreeBSD-12.1-RC1-amd64-mini-memstick.img.xz
  334. rev = "unspec"
  335. } else if (!isrev(rev)) {
  336. print "invalid rev, skipping: " rev > "/dev/stderr"
  337. #print "raw " $0 > "/dev/stderr"
  338. #printf("%s %s %s %s %s %s %s %s %s %s\n", type, parts[2] "-" parts[3], arch, platform, date, rev, vers, fname, url, MID) > "/dev/stderr"
  339. return
  340. } else {
  341. # we have rev, but check if next part is also part of it
  342. if (parts[nextidx + 1] ~ /^[0-9]+$/) {
  343. rev = rev "-c" parts[nextidx + 1]
  344. nextidx += 1
  345. }
  346. }
  347. if (nextidx >= cnt)
  348. vers="xxx"
  349. else {
  350. vers=""
  351. sep=""
  352. for (i = nextidx + 1; i <= cnt; i++) {
  353. vers = vers sep parts[i]
  354. sep="-"
  355. }
  356. }
  357. if (isrelease(parts[3])) {
  358. if (platform == "BASIC-CI") {
  359. vers = dotparts[3]
  360. url = relbciroot parts[2] "-" parts[3] "/" basearch "/Latest/" fname
  361. } else if (type == "vm") {
  362. vers = dotparts[3]
  363. url = relvmroot parts[2] "-" parts[3] "/" basearch "/Latest/" fname
  364. } else if (type == "oci") {
  365. vers = dotparts[3]
  366. url = relociroot parts[2] "-" parts[3] "/" basearch "/Latest/" fname
  367. } else
  368. url = relisoroot parts[2] "/" fname
  369. } else {
  370. if (platform == "BASIC-CI") {
  371. vers = dotparts[3]
  372. url = bciroot parts[2] "-" parts[3] "/" basearch "/" date "/" fname
  373. } else if (type == "vm") {
  374. vers = dotparts[3]
  375. url = vmroot parts[2] "-" parts[3] "/" basearch "/" date "/" fname
  376. } else if (type == "oci") {
  377. vers = dotparts[3]
  378. url = ociroot parts[2] "-" parts[3] "/" basearch "/" date "/" fname
  379. } else
  380. url = isoroot parts[2] "/" fname
  381. }
  382. # double check that date is valid, if not, skip it
  383. if (date != "xxx" && !isdate(date))
  384. return
  385. res = sprintf("%s %s %s %s %s %s %s %s %s %s", type, parts[2] "-" parts[3], arch, platform, date, rev, vers, fname, url, MID)
  386. #printf("%s %s %s %s %s %s %s %s %s %s\n", type, parts[2] "-" parts[3], arch, platform, date, rev, vers, fname, url, MID) > "/dev/stderr"
  387. return res
  388. }