install.sh 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337
  1. #!/usr/bin/env bash
  2. set -Eeuo pipefail
  3. ETFS="boot/etfsboot.com"
  4. FB="falling back to manual installation!"
  5. EFISYS="efi/microsoft/boot/efisys_noprompt.bin"
  6. backup () {
  7. local count=1
  8. local iso="$1"
  9. local name="unknown"
  10. local root="$STORAGE/backups"
  11. local previous="$STORAGE/windows.base"
  12. if [ -f "$previous" ]; then
  13. previous=$(<"$previous")
  14. previous="${previous//[![:print:]]/}"
  15. [ -n "$previous" ] && name="${previous%.*}"
  16. fi
  17. if ! makeDir "$root"; then
  18. error "Failed to create directory \"$root\" !"
  19. return 1
  20. fi
  21. local folder="$name"
  22. local dir="$root/$folder"
  23. while [ -d "$dir" ]
  24. do
  25. count=$((count+1))
  26. folder="${name}.${count}"
  27. dir="$root/$folder"
  28. done
  29. rm -rf "$dir"
  30. if ! makeDir "$dir"; then
  31. error "Failed to create directory \"$dir\" !"
  32. return 1
  33. fi
  34. [ -f "$iso" ] && mv -f "$iso" "$dir/"
  35. find "$STORAGE" -maxdepth 1 -type f -iname 'data.*' -not -iname '*.iso' -exec mv -n {} "$dir/" \;
  36. find "$STORAGE" -maxdepth 1 -type f -iname 'windows.*' -not -iname '*.iso' -exec mv -n {} "$dir/" \;
  37. find "$STORAGE" -maxdepth 1 -type f \( -iname '*.rom' -or -iname '*.vars' \) -exec mv -n {} "$dir/" \;
  38. [ -z "$(ls -A "$dir")" ] && rm -rf "$dir"
  39. [ -z "$(ls -A "$root")" ] && rm -rf "$root"
  40. return 0
  41. }
  42. skipInstall() {
  43. local iso="$1"
  44. local method=""
  45. local magic byte
  46. local boot="$STORAGE/windows.boot"
  47. local previous="$STORAGE/windows.base"
  48. if [ -f "$previous" ]; then
  49. previous=$(<"$previous")
  50. previous="${previous//[![:print:]]/}"
  51. if [ -n "$previous" ]; then
  52. if [[ "${STORAGE,,}/${previous,,}" != "${iso,,}" ]]; then
  53. if ! hasDisk; then
  54. rm -f "$STORAGE/$previous"
  55. return 1
  56. fi
  57. if [[ "${iso,,}" == "${STORAGE,,}/windows."* ]]; then
  58. method="your custom .iso file was changed"
  59. else
  60. if [[ "${previous,,}" != "windows."* ]]; then
  61. method="the VERSION variable was changed"
  62. else
  63. method="your custom .iso file was removed"
  64. if [ -f "$boot" ]; then
  65. info "Detected that $method, will be ignored."
  66. return 0
  67. fi
  68. fi
  69. fi
  70. info "Detected that $method, a backup of your previous installation will be saved..."
  71. ! backup "$STORAGE/$previous" && error "Backup failed!"
  72. return 1
  73. fi
  74. fi
  75. fi
  76. [ -f "$boot" ] && hasDisk && return 0
  77. [ ! -f "$iso" ] && return 1
  78. [ ! -s "$iso" ] && return 1
  79. # Check if the ISO was already processed by our script
  80. magic=$(dd if="$iso" seek=0 bs=1 count=1 status=none | tr -d '\000')
  81. magic="$(printf '%s' "$magic" | od -A n -t x1 -v | tr -d ' \n')"
  82. byte="16" && [[ "$MANUAL" == [Yy1]* ]] && byte="17"
  83. if [[ "$magic" != "$byte" ]]; then
  84. info "The ISO will be processed again because the configuration was changed..."
  85. return 1
  86. fi
  87. return 0
  88. }
  89. startInstall() {
  90. html "Starting $APP..."
  91. if [ -z "$CUSTOM" ]; then
  92. local file="${VERSION//\//}.iso"
  93. if [[ "${VERSION,,}" == "http"* ]]; then
  94. file=$(basename "${VERSION%%\?*}")
  95. printf -v file '%b' "${file//%/\\x}"
  96. file="${file//[!A-Za-z0-9._-]/_}"
  97. else
  98. local language
  99. language=$(getLanguage "$LANGUAGE" "culture")
  100. language="${language%%-*}"
  101. if [ -n "$language" ] && [[ "${language,,}" != "en" ]]; then
  102. file="${VERSION//\//}_${language,,}.iso"
  103. fi
  104. fi
  105. BOOT="$STORAGE/$file"
  106. fi
  107. TMP="$STORAGE/tmp"
  108. rm -rf "$TMP"
  109. skipInstall "$BOOT" && return 1
  110. if hasDisk; then
  111. ! backup "" && error "Backup failed!"
  112. fi
  113. if ! makeDir "$TMP"; then
  114. error "Failed to create directory \"$TMP\" !"
  115. fi
  116. if [ -z "$CUSTOM" ]; then
  117. ISO=$(basename "$BOOT")
  118. ISO="$TMP/$ISO"
  119. if [ -f "$BOOT" ] && [ -s "$BOOT" ]; then
  120. mv -f "$BOOT" "$ISO"
  121. fi
  122. fi
  123. rm -f "$BOOT"
  124. find "$STORAGE" -maxdepth 1 -type f -iname 'data.*' -not -iname '*.iso' -delete
  125. find "$STORAGE" -maxdepth 1 -type f -iname 'windows.*' -not -iname '*.iso' -delete
  126. find "$STORAGE" -maxdepth 1 -type f \( -iname '*.rom' -or -iname '*.vars' \) -delete
  127. return 0
  128. }
  129. writeFile() {
  130. local txt="$1"
  131. local path="$2"
  132. echo "$txt" >"$path"
  133. if ! setOwner "$path"; then
  134. error "Failed to set the owner for \"$path\" !"
  135. fi
  136. return 0
  137. }
  138. finishInstall() {
  139. local iso="$1"
  140. local aborted="$2"
  141. local base byte
  142. if [ ! -s "$iso" ] || [ ! -f "$iso" ]; then
  143. error "Failed to find ISO file: $iso" && return 1
  144. fi
  145. if [[ "$iso" == "$STORAGE/"* ]]; then
  146. ! setOwner "$iso" && error "Failed to set the owner for \"$iso\" !"
  147. fi
  148. if [[ "$aborted" != [Yy1]* ]]; then
  149. # Mark ISO as prepared via magic byte
  150. byte="16" && [[ "$MANUAL" == [Yy1]* ]] && byte="17"
  151. if ! printf '%b' "\x$byte" | dd of="$iso" bs=1 seek=0 count=1 conv=notrunc status=none; then
  152. warn "failed to set magic byte in ISO file: $iso"
  153. fi
  154. fi
  155. local file="$STORAGE/windows.ver"
  156. cp -f /run/version "$file"
  157. ! setOwner "$file" && error "Failed to set the owner for \"$file\" !"
  158. if [[ "$iso" == "$STORAGE/"* ]]; then
  159. if [[ "$aborted" != [Yy1]* ]] || [ -z "$CUSTOM" ]; then
  160. base=$(basename "$iso")
  161. file="$STORAGE/windows.base"
  162. writeFile "$base" "$file"
  163. fi
  164. fi
  165. if [[ "${PLATFORM,,}" == "x64" ]]; then
  166. if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
  167. file="$STORAGE/windows.mode"
  168. writeFile "$BOOT_MODE" "$file"
  169. if [[ "${MACHINE,,}" != "q35" ]]; then
  170. file="$STORAGE/windows.old"
  171. writeFile "$MACHINE" "$file"
  172. fi
  173. else
  174. # Enable secure boot + TPM on manual installs as Win11 requires
  175. if [[ "$MANUAL" == [Yy1]* || "$aborted" == [Yy1]* ]]; then
  176. if [[ "${DETECTED,,}" == "win11"* ]]; then
  177. BOOT_MODE="windows_secure"
  178. file="$STORAGE/windows.mode"
  179. writeFile "$BOOT_MODE" "$file"
  180. fi
  181. fi
  182. # Enable secure boot on multi-socket systems to workaround freeze
  183. if [ -n "$SOCKETS" ] && [[ "$SOCKETS" != "1" ]]; then
  184. BOOT_MODE="windows_secure"
  185. file="$STORAGE/windows.mode"
  186. writeFile "$BOOT_MODE" "$file"
  187. fi
  188. fi
  189. fi
  190. if [ -n "${ARGS:-}" ]; then
  191. ARGUMENTS="$ARGS ${ARGUMENTS:-}"
  192. file="$STORAGE/windows.args"
  193. writeFile "$ARGS" "$file"
  194. fi
  195. if [ -n "${VGA:-}" ] && [[ "${VGA:-}" != "virtio"* ]]; then
  196. file="$STORAGE/windows.vga"
  197. writeFile "$VGA" "$file"
  198. fi
  199. if [ -n "${USB:-}" ] && [[ "${USB:-}" != "qemu-xhci"* ]]; then
  200. file="$STORAGE/windows.usb"
  201. writeFile "$USB" "$file"
  202. fi
  203. if [ -n "${DISK_TYPE:-}" ] && [[ "${DISK_TYPE:-}" != "scsi" ]]; then
  204. file="$STORAGE/windows.type"
  205. writeFile "$DISK_TYPE" "$file"
  206. fi
  207. if [ -n "${ADAPTER:-}" ] && [[ "${ADAPTER:-}" != "virtio-net-pci" ]]; then
  208. file="$STORAGE/windows.net"
  209. writeFile "$ADAPTER" "$file"
  210. fi
  211. rm -rf "$TMP"
  212. return 0
  213. }
  214. abortInstall() {
  215. local dir="$1"
  216. local iso="$2"
  217. local efi
  218. [[ "${iso,,}" == *".esd" ]] && exit 60
  219. [[ "${UNPACK:-}" == [Yy1]* ]] && exit 60
  220. efi=$(find "$dir" -maxdepth 1 -type d -iname efi -print -quit)
  221. if [ -z "$efi" ]; then
  222. [[ "${PLATFORM,,}" == "x64" ]] && BOOT_MODE="windows_legacy"
  223. fi
  224. if [ -n "$CUSTOM" ]; then
  225. BOOT="$iso"
  226. REMOVE="N"
  227. else
  228. if [[ "$iso" != "$BOOT" ]]; then
  229. if ! mv -f "$iso" "$BOOT"; then
  230. error "Failed to move ISO file: $iso" && return 1
  231. fi
  232. fi
  233. fi
  234. finishInstall "$BOOT" "Y" && return 0
  235. return 1
  236. }
  237. findFile() {
  238. local dir file base
  239. local fname="$1"
  240. local boot="$STORAGE/windows.boot"
  241. dir=$(find / -maxdepth 1 -type d -iname "$fname" -print -quit)
  242. [ ! -d "$dir" ] && dir=$(find "$STORAGE" -maxdepth 1 -type d -iname "$fname" -print -quit)
  243. if [ -d "$dir" ]; then
  244. if ! hasDisk || [ ! -f "$boot" ]; then
  245. error "The bind $dir maps to a file that does not exist!" && return 1
  246. fi
  247. fi
  248. file=$(find / -maxdepth 1 -type f -iname "$fname" -print -quit)
  249. [ ! -s "$file" ] && file=$(find "$STORAGE" -maxdepth 1 -type f -iname "$fname" -print -quit)
  250. if [ ! -s "$file" ] && [[ "${VERSION,,}" != "http"* ]]; then
  251. base=$(basename "$VERSION")
  252. file="$STORAGE/$base"
  253. fi
  254. if [ ! -f "$file" ] || [ ! -s "$file" ]; then
  255. return 0
  256. fi
  257. local size
  258. size="$(stat -c%s "$file")"
  259. [ -z "$size" ] || [[ "$size" == "0" ]] && return 0
  260. ISO="$file"
  261. CUSTOM="$file"
  262. BOOT="$STORAGE/windows.$size.iso"
  263. return 0
  264. }
  265. detectCustom() {
  266. CUSTOM=""
  267. ! findFile "custom.iso" && return 1
  268. [ -n "$CUSTOM" ] && return 0
  269. ! findFile "boot.iso" && return 1
  270. [ -n "$CUSTOM" ] && return 0
  271. return 0
  272. }
  273. extractESD() {
  274. local iso="$1"
  275. local dir="$2"
  276. local version="$3"
  277. local desc="$4"
  278. local size size_gb sizes space space_gb
  279. local desc total total1 total2 total3 total4
  280. local imageIndex links links1 links2 links3 links4
  281. local msg="Extracting $desc bootdisk"
  282. info "$msg..." && html "$msg..."
  283. if [ "$(stat -c%s "$iso")" -lt 100000000 ]; then
  284. error "Invalid ESD file: Size is smaller than 100 MB" && return 1
  285. fi
  286. rm -rf "$dir"
  287. if ! makeDir "$dir"; then
  288. error "Failed to create directory \"$dir\" !" && return 1
  289. fi
  290. size=9606127360
  291. size_gb=$(formatBytes "$size")
  292. space=$(df --output=avail -B 1 "$dir" | tail -n 1)
  293. space_gb=$(formatBytes "$space")
  294. if (( size > space )); then
  295. error "Not enough free space in $STORAGE, have $space_gb available but need at least $size_gb." && return 1
  296. fi
  297. local esdImageCount
  298. esdImageCount=$(wimlib-imagex info "$iso" | awk '/Image Count:/ {print $3}')
  299. if [ -z "$esdImageCount" ]; then
  300. error "Cannot read the image count in ESD file!" && return 1
  301. fi
  302. sizes=$(wimlib-imagex info "$iso" | grep "Total Bytes:")
  303. links=$(wimlib-imagex info "$iso" | grep "Hard Link Bytes:")
  304. total1=$(awk "NR==1{ print; }" <<< "$sizes" | cut -d':' -f2 | sed 's/^ *//')
  305. links1=$(awk "NR==1{ print; }" <<< "$links" | cut -d':' -f2 | sed 's/^ *//')
  306. total=$(( total1 - links1 ))
  307. total3=$(awk "NR==3{ print; }" <<< "$sizes" | cut -d':' -f2 | sed 's/^ *//')
  308. links3=$(awk "NR==3{ print; }" <<< "$links" | cut -d':' -f2 | sed 's/^ *//')
  309. total3=$(( total3 - links3 ))
  310. total3=$(( total3 + 60000000 ))
  311. /run/progress.sh "$dir" "$total" "$msg ([P])..." &
  312. imageIndex="1"
  313. wimlib-imagex apply "$iso" "$imageIndex" "$dir" --quiet 2>/dev/null || {
  314. retVal=$?
  315. fKill "progress.sh"
  316. error "Extracting $desc bootdisk failed ($retVal)" && return 1
  317. }
  318. fKill "progress.sh"
  319. local bootWimFile="$dir/sources/boot.wim"
  320. local installWimFile="$dir/sources/install.wim"
  321. local msg="Extracting $desc environment"
  322. info "$msg..." && html "$msg..."
  323. imageIndex="2"
  324. /run/progress.sh "$bootWimFile" "$total3" "$msg ([P])..." &
  325. wimlib-imagex export "$iso" "$imageIndex" "$bootWimFile" --compress=none --quiet || {
  326. retVal=$?
  327. fKill "progress.sh"
  328. error "Adding WinPE failed ($retVal)" && return 1
  329. }
  330. fKill "progress.sh"
  331. local msg="Extracting $desc setup"
  332. info "$msg..."
  333. imageIndex="3"
  334. /run/progress.sh "$bootWimFile" "$total3" "$msg ([P])..." &
  335. wimlib-imagex export "$iso" "$imageIndex" "$bootWimFile" --compress=none --boot --quiet || {
  336. retVal=$?
  337. fKill "progress.sh"
  338. error "Adding Windows Setup failed ($retVal)" && return 1
  339. }
  340. fKill "progress.sh"
  341. if [[ "${PLATFORM,,}" == "x64" ]]; then
  342. LABEL="CCCOMA_X64FRE_EN-US_DV9"
  343. else
  344. LABEL="CPBA_A64FRE_EN-US_DV9"
  345. fi
  346. local msg="Extracting $desc image"
  347. info "$msg..." && html "$msg..."
  348. local edition imageEdition
  349. edition=$(getCatalog "$version" "name")
  350. if [ -z "$edition" ]; then
  351. error "Invalid VERSION specified, value \"$version\" is not recognized!" && return 1
  352. fi
  353. for (( imageIndex=4; imageIndex<=esdImageCount; imageIndex++ )); do
  354. imageEdition=$(wimlib-imagex info "$iso" "$imageIndex" | grep '^Description:' | sed 's/Description:[ \t]*//')
  355. [[ "${imageEdition,,}" != "${edition,,}" ]] && continue
  356. total4=$(du -sb "$iso" | cut -f1)
  357. total4=$(( total4 + 3000000 ))
  358. /run/progress.sh "$installWimFile" "$total4" "$msg ([P])..." &
  359. wimlib-imagex export "$iso" "$imageIndex" "$installWimFile" --compress=LZMS --chunk-size 128K --quiet || {
  360. retVal=$?
  361. fKill "progress.sh"
  362. error "Addition of $imageIndex to the $desc image failed ($retVal)" && return 1
  363. }
  364. fKill "progress.sh"
  365. return 0
  366. done
  367. fKill "progress.sh"
  368. error "Failed to find product '$edition' in install.wim!" && return 1
  369. }
  370. extractImage() {
  371. local iso="$1"
  372. local dir="$2"
  373. local version="$3"
  374. local desc="local ISO"
  375. local file size size_gb space space_gb
  376. if [ -z "$CUSTOM" ]; then
  377. desc="downloaded ISO"
  378. if [[ "$version" != "http"* ]]; then
  379. desc=$(printVersion "$version" "$desc")
  380. fi
  381. fi
  382. if [[ "${iso,,}" == *".esd" ]]; then
  383. extractESD "$iso" "$dir" "$version" "$desc" && return 0
  384. return 1
  385. fi
  386. local msg="Extracting $desc image"
  387. info "$msg..." && html "$msg..."
  388. rm -rf "$dir"
  389. if ! makeDir "$dir"; then
  390. error "Failed to create directory \"$dir\" !" && return 1
  391. fi
  392. size=$(stat -c%s "$iso")
  393. size_gb=$(formatBytes "$size")
  394. space=$(df --output=avail -B 1 "$dir" | tail -n 1)
  395. space_gb=$(formatBytes "$space")
  396. if (( size < 100000000 )); then
  397. error "Invalid ISO file: Size is smaller than 100 MB" && return 1
  398. fi
  399. if (( size > space )); then
  400. error "Not enough free space in $STORAGE, have $space_gb available but need at least $size_gb." && return 1
  401. fi
  402. rm -rf "$dir"
  403. /run/progress.sh "$dir" "$size" "$msg ([P])..." &
  404. if ! 7z x "$iso" -o"$dir" > /dev/null; then
  405. fKill "progress.sh"
  406. error "Failed to extract ISO file: $iso" && return 1
  407. fi
  408. fKill "progress.sh"
  409. if [[ "${UNPACK:-}" != [Yy1]* ]]; then
  410. LABEL=$(isoinfo -d -i "$iso" | sed -n 's/Volume id: //p')
  411. else
  412. file=$(find "$dir" -maxdepth 1 -type f -iname "*.iso" -print -quit)
  413. if [ -z "$file" ]; then
  414. error "Failed to find any .iso file in archive!" && return 1
  415. fi
  416. if ! 7z x "$file" -o"$dir" > /dev/null; then
  417. error "Failed to extract archive!" && return 1
  418. fi
  419. LABEL=$(isoinfo -d -i "$file" | sed -n 's/Volume id: //p')
  420. rm -f "$file"
  421. fi
  422. return 0
  423. }
  424. getPlatform() {
  425. local xml="$1"
  426. local tag="ARCH"
  427. local platform="x64"
  428. local arch
  429. arch=$(sed -n "/$tag/{s/.*<$tag>\(.*\)<\/$tag>.*/\1/;p}" <<< "$xml")
  430. case "${arch,,}" in
  431. "0" ) platform="x86" ;;
  432. "9" ) platform="x64" ;;
  433. "12" ) platform="arm64" ;;
  434. esac
  435. echo "$platform"
  436. return 0
  437. }
  438. checkPlatform() {
  439. local xml="$1"
  440. local platform compat
  441. platform=$(getPlatform "$xml")
  442. case "${platform,,}" in
  443. "x86" ) compat="x64" ;;
  444. "x64" ) compat="$platform" ;;
  445. "arm64" ) compat="$platform" ;;
  446. * ) compat="${PLATFORM,,}" ;;
  447. esac
  448. [[ "${compat,,}" == "${PLATFORM,,}" ]] && return 0
  449. error "You cannot boot ${platform^^} images on a $PLATFORM CPU!"
  450. return 1
  451. }
  452. hasVersion() {
  453. local id="$1"
  454. local tag="$2"
  455. local xml="$3"
  456. local edition
  457. [ ! -f "/run/assets/$id.xml" ] && return 1
  458. edition=$(printEdition "$id" "")
  459. [ -z "$edition" ] && return 1
  460. [[ "${xml,,}" != *"<${tag,,}>${edition,,}</${tag,,}>"* ]] && return 1
  461. return 0
  462. }
  463. selectVersion() {
  464. local tag="$1"
  465. local xml="$2"
  466. local platform="$3"
  467. local id name prefer
  468. name=$(sed -n "/$tag/{s/.*<$tag>\(.*\)<\/$tag>.*/\1/;p}" <<< "$xml")
  469. [[ "$name" == *"Operating System"* ]] && name=""
  470. [ -z "$name" ] && return 0
  471. id=$(fromName "$name" "$platform")
  472. [ -z "$id" ] && warn "Unknown ${tag,,}: '$name'" && return 0
  473. prefer="$id-enterprise"
  474. hasVersion "$prefer" "$tag" "$xml" && echo "$prefer" && return 0
  475. prefer="$id-ultimate"
  476. hasVersion "$prefer" "$tag" "$xml" && echo "$prefer" && return 0
  477. prefer="$id"
  478. hasVersion "$prefer" "$tag" "$xml" && echo "$prefer" && return 0
  479. prefer=$(getVersion "$name" "$platform")
  480. echo "$prefer"
  481. return 0
  482. }
  483. detectVersion() {
  484. local xml="$1"
  485. local id platform
  486. platform=$(getPlatform "$xml")
  487. id=$(selectVersion "DISPLAYNAME" "$xml" "$platform")
  488. [ -z "$id" ] && id=$(selectVersion "PRODUCTNAME" "$xml" "$platform")
  489. [ -z "$id" ] && id=$(selectVersion "NAME" "$xml" "$platform")
  490. echo "$id"
  491. return 0
  492. }
  493. detectLanguage() {
  494. local xml="$1"
  495. local lang=""
  496. if [[ "$xml" == *"LANGUAGE><DEFAULT>"* ]]; then
  497. lang="${xml#*LANGUAGE><DEFAULT>}"
  498. lang="${lang%%<*}"
  499. else
  500. if [[ "$xml" == *"FALLBACK><DEFAULT>"* ]]; then
  501. lang="${xml#*FALLBACK><DEFAULT>}"
  502. lang="${lang%%<*}"
  503. fi
  504. fi
  505. if [ -z "$lang" ]; then
  506. warn "Language could not be detected from ISO!" && return 0
  507. fi
  508. local culture
  509. culture=$(getLanguage "$lang" "culture")
  510. [ -n "$culture" ] && LANGUAGE="$lang" && return 0
  511. warn "Invalid language detected: \"$lang\""
  512. return 0
  513. }
  514. setXML() {
  515. local file="/custom.xml"
  516. if [ -d "$file" ]; then
  517. error "The bind $file maps to a file that does not exist!" && exit 67
  518. fi
  519. [ ! -f "$file" ] || [ ! -s "$file" ] && file="$STORAGE/custom.xml"
  520. [ ! -f "$file" ] || [ ! -s "$file" ] && file="/run/assets/custom.xml"
  521. [ ! -f "$file" ] || [ ! -s "$file" ] && file="$1"
  522. [ ! -f "$file" ] || [ ! -s "$file" ] && file="/run/assets/$DETECTED.xml"
  523. [ ! -f "$file" ] || [ ! -s "$file" ] && return 1
  524. XML="$file"
  525. return 0
  526. }
  527. detectImage() {
  528. local dir="$1"
  529. local version="$2"
  530. local desc msg find language
  531. XML=""
  532. if [ -z "$DETECTED" ] && [ -z "$CUSTOM" ]; then
  533. [[ "${version,,}" != "http"* ]] && DETECTED="$version"
  534. fi
  535. if [ -n "$DETECTED" ]; then
  536. skipVersion "${DETECTED,,}" && return 0
  537. if ! setXML "" && [[ "$MANUAL" != [Yy1]* ]]; then
  538. MANUAL="Y"
  539. desc=$(printEdition "$DETECTED" "this version")
  540. warn "the answer file for $desc was not found ($DETECTED.xml), $FB."
  541. fi
  542. return 0
  543. fi
  544. info "Detecting version from ISO image..."
  545. if detectLegacy "$dir"; then
  546. desc=$(printEdition "$DETECTED" "$DETECTED")
  547. info "Detected: $desc"
  548. return 0
  549. fi
  550. local src wim info
  551. src=$(find "$dir" -maxdepth 1 -type d -iname sources -print -quit)
  552. if [ ! -d "$src" ]; then
  553. warn "failed to locate 'sources' folder in ISO image, $FB" && return 1
  554. fi
  555. wim=$(find "$src" -maxdepth 1 -type f \( -iname install.wim -or -iname install.esd \) -print -quit)
  556. if [ ! -f "$wim" ]; then
  557. warn "failed to locate 'install.wim' or 'install.esd' in ISO image, $FB" && return 1
  558. fi
  559. info=$(wimlib-imagex info -xml "$wim" | iconv -f UTF-16LE -t UTF-8)
  560. checkPlatform "$info" || exit 67
  561. DETECTED=$(detectVersion "$info")
  562. if [ -z "$DETECTED" ]; then
  563. msg="Failed to determine Windows version from image"
  564. if setXML "" || [[ "$MANUAL" == [Yy1]* ]]; then
  565. info "${msg}!"
  566. else
  567. MANUAL="Y"
  568. warn "${msg}, $FB."
  569. fi
  570. return 0
  571. fi
  572. desc=$(printEdition "$DETECTED" "$DETECTED")
  573. detectLanguage "$info"
  574. if [[ "${LANGUAGE,,}" != "en" && "${LANGUAGE,,}" != "en-"* ]]; then
  575. language=$(getLanguage "$LANGUAGE" "desc")
  576. desc+=" ($language)"
  577. fi
  578. info "Detected: $desc"
  579. setXML "" && return 0
  580. if [[ "$DETECTED" == "win81x86"* || "$DETECTED" == "win10x86"* ]]; then
  581. error "The 32-bit version of $desc is not supported!" && return 1
  582. fi
  583. msg="the answer file for $desc was not found ($DETECTED.xml)"
  584. local fallback="/run/assets/${DETECTED%%-*}.xml"
  585. if setXML "$fallback" || [[ "$MANUAL" == [Yy1]* ]]; then
  586. [[ "$MANUAL" != [Yy1]* ]] && warn "${msg}."
  587. else
  588. MANUAL="Y"
  589. warn "${msg}, $FB."
  590. fi
  591. return 0
  592. }
  593. prepareImage() {
  594. local iso="$1"
  595. local dir="$2"
  596. local desc missing
  597. desc=$(printVersion "$DETECTED" "$DETECTED")
  598. setMachine "$DETECTED" "$iso" "$dir" "$desc" || return 1
  599. skipVersion "$DETECTED" && return 0
  600. if [[ "${BOOT_MODE,,}" != "windows_legacy" ]]; then
  601. [ -f "$dir/$ETFS" ] && [ -f "$dir/$EFISYS" ] && return 0
  602. missing=$(basename "$dir/$EFISYS")
  603. [ ! -f "$dir/$ETFS" ] && missing=$(basename "$dir/$ETFS")
  604. error "Failed to locate file \"${missing,,}\" in ISO image!"
  605. return 1
  606. fi
  607. prepareLegacy "$iso" "$dir" "$desc" && return 0
  608. error "Failed to extract boot image from ISO image!"
  609. return 1
  610. }
  611. updateXML() {
  612. local asset="$1"
  613. local language="$2"
  614. local culture region user admin pass keyboard
  615. [ -z "$HEIGHT" ] && HEIGHT="720"
  616. [ -z "$WIDTH" ] && WIDTH="1280"
  617. sed -i "s/>Windows for Docker</>$APP for $ENGINE</g" "$asset"
  618. sed -i "s/<VerticalResolution>1080<\/VerticalResolution>/<VerticalResolution>$HEIGHT<\/VerticalResolution>/g" "$asset"
  619. sed -i "s/<HorizontalResolution>1920<\/HorizontalResolution>/<HorizontalResolution>$WIDTH<\/HorizontalResolution>/g" "$asset"
  620. culture=$(getLanguage "$language" "culture")
  621. if [ -n "$culture" ] && [[ "${culture,,}" != "en-us" ]]; then
  622. sed -i "s/<UILanguage>en-US<\/UILanguage>/<UILanguage>$culture<\/UILanguage>/g" "$asset"
  623. fi
  624. region="$REGION"
  625. [ -z "$region" ] && region="$culture"
  626. if [ -n "$region" ] && [[ "${region,,}" != "en-us" ]]; then
  627. sed -i "s/<UserLocale>en-US<\/UserLocale>/<UserLocale>$region<\/UserLocale>/g" "$asset"
  628. sed -i "s/<SystemLocale>en-US<\/SystemLocale>/<SystemLocale>$region<\/SystemLocale>/g" "$asset"
  629. fi
  630. keyboard="$KEYBOARD"
  631. [ -z "$keyboard" ] && keyboard="$culture"
  632. if [ -n "$keyboard" ] && [[ "${keyboard,,}" != "en-us" ]]; then
  633. sed -i "s/<InputLocale>en-US<\/InputLocale>/<InputLocale>$keyboard<\/InputLocale>/g" "$asset"
  634. sed -i "s/<InputLocale>0409:00000409<\/InputLocale>/<InputLocale>$keyboard<\/InputLocale>/g" "$asset"
  635. fi
  636. user=$(echo "$USERNAME" | sed 's/[^[:alnum:]@!._-]//g')
  637. if [ -n "$user" ]; then
  638. sed -i "s/-name \"Docker\"/-name \"$user\"/g" "$asset"
  639. sed -i "s/<Name>Docker<\/Name>/<Name>$user<\/Name>/g" "$asset"
  640. sed -i "s/where name=\"Docker\"/where name=\"$user\"/g" "$asset"
  641. sed -i "s/<FullName>Docker<\/FullName>/<FullName>$user<\/FullName>/g" "$asset"
  642. sed -i "s/<Username>Docker<\/Username>/<Username>$user<\/Username>/g" "$asset"
  643. fi
  644. [ -n "$PASSWORD" ] && pass="$PASSWORD" || pass="admin"
  645. pw=$(printf '%s' "${pass}Password" | iconv -f utf-8 -t utf-16le | base64 -w 0)
  646. admin=$(printf '%s' "${pass}AdministratorPassword" | iconv -f utf-8 -t utf-16le | base64 -w 0)
  647. sed -i "s/<Value>password<\/Value>/<Value>$admin<\/Value>/g" "$asset"
  648. sed -i "s/<PlainText>true<\/PlainText>/<PlainText>false<\/PlainText>/g" "$asset"
  649. sed -z "s/<Password>...........<Value \/>/<Password>\n <Value>$pw<\/Value>/g" -i "$asset"
  650. sed -z "s/<Password>...............<Value \/>/<Password>\n <Value>$pw<\/Value>/g" -i "$asset"
  651. sed -z "s/<AdministratorPassword>...........<Value \/>/<AdministratorPassword>\n <Value>$admin<\/Value>/g" -i "$asset"
  652. sed -z "s/<AdministratorPassword>...............<Value \/>/<AdministratorPassword>\n <Value>$admin<\/Value>/g" -i "$asset"
  653. if [ -n "$EDITION" ]; then
  654. [[ "${EDITION^^}" == "CORE" ]] && EDITION="STANDARDCORE"
  655. sed -i "s/SERVERSTANDARD<\/Value>/SERVER${EDITION^^}<\/Value>/g" "$asset"
  656. fi
  657. if [ -n "$KEY" ]; then
  658. sed -i '/<ProductKey>/,/<\/ProductKey>/d' "$asset"
  659. sed -i "s/<\/UserData>/ <ProductKey>\n <Key>${KEY}<\/Key>\n <WillShowUI>OnError<\/WillShowUI>\n <\/ProductKey>\n <\/UserData>/g" "$asset"
  660. fi
  661. return 0
  662. }
  663. addDriver() {
  664. local id="$1"
  665. local path="$2"
  666. local target="$3"
  667. local driver="$4"
  668. local desc=""
  669. local folder=""
  670. if [ -z "$id" ]; then
  671. warn "no Windows version specified for \"$driver\" driver!" && return 0
  672. fi
  673. case "${id,,}" in
  674. "win7x86"* ) folder="w7/x86" ;;
  675. "win7x64"* ) folder="w7/amd64" ;;
  676. "win81x64"* ) folder="w8.1/amd64" ;;
  677. "win10x64"* ) folder="w10/amd64" ;;
  678. "win11x64"* ) folder="w11/amd64" ;;
  679. "win2025"* ) folder="2k25/amd64" ;;
  680. "win2022"* ) folder="2k22/amd64" ;;
  681. "win2019"* ) folder="2k19/amd64" ;;
  682. "win2016"* ) folder="2k16/amd64" ;;
  683. "win2012"* ) folder="2k12R2/amd64" ;;
  684. "win2008"* ) folder="2k8R2/amd64" ;;
  685. "win10arm64"* ) folder="w10/ARM64" ;;
  686. "win11arm64"* ) folder="w11/ARM64" ;;
  687. "winvistax86"* ) folder="2k8/x86" ;;
  688. "winvistax64"* ) folder="2k8/amd64" ;;
  689. esac
  690. if [ -z "$folder" ]; then
  691. desc=$(printVersion "$id" "$id")
  692. if [[ "${id,,}" != *"x86"* ]]; then
  693. warn "no \"$driver\" driver available for \"$desc\" !" && return 0
  694. else
  695. warn "no \"$driver\" driver available for the 32-bit version of \"$desc\" !" && return 0
  696. fi
  697. fi
  698. [ ! -d "$path/$driver/$folder" ] && return 0
  699. case "${id,,}" in
  700. "winvista"* )
  701. [[ "${driver,,}" == "viorng" ]] && return 0
  702. ;;
  703. esac
  704. local dest="$path/$target/$driver"
  705. mkdir -p "$dest" || return 1
  706. cp -Lr "$path/$driver/$folder/." "$dest" || return 1
  707. return 0
  708. }
  709. addDrivers() {
  710. local src="$1"
  711. local tmp="$2"
  712. local file="$3"
  713. local index="$4"
  714. local version="$5"
  715. local drivers="$tmp/drivers"
  716. rm -rf "$drivers"
  717. mkdir -p "$drivers"
  718. local msg="Adding drivers to image..."
  719. info "$msg" && html "$msg"
  720. if [ -z "$version" ]; then
  721. version="win11x64"
  722. warn "Windows version unknown, falling back to Windows 11 drivers..."
  723. fi
  724. if ! bsdtar -xf /var/drivers.txz -C "$drivers"; then
  725. error "Failed to extract drivers from archive!" && return 1
  726. fi
  727. local target="\$WinPEDriver\$"
  728. local dest="$drivers/$target"
  729. mkdir -p "$dest" || return 1
  730. wimlib-imagex update "$file" "$index" --command "delete --force --recursive /$target" >/dev/null || true
  731. addDriver "$version" "$drivers" "$target" "qxl" || return 1
  732. addDriver "$version" "$drivers" "$target" "viofs" || return 1
  733. addDriver "$version" "$drivers" "$target" "sriov" || return 1
  734. addDriver "$version" "$drivers" "$target" "smbus" || return 1
  735. addDriver "$version" "$drivers" "$target" "qxldod" || return 1
  736. addDriver "$version" "$drivers" "$target" "viorng" || return 1
  737. addDriver "$version" "$drivers" "$target" "viostor" || return 1
  738. addDriver "$version" "$drivers" "$target" "viomem" || return 1
  739. addDriver "$version" "$drivers" "$target" "NetKVM" || return 1
  740. addDriver "$version" "$drivers" "$target" "Balloon" || return 1
  741. addDriver "$version" "$drivers" "$target" "vioscsi" || return 1
  742. addDriver "$version" "$drivers" "$target" "pvpanic" || return 1
  743. addDriver "$version" "$drivers" "$target" "vioinput" || return 1
  744. addDriver "$version" "$drivers" "$target" "viogpudo" || return 1
  745. addDriver "$version" "$drivers" "$target" "vioserial" || return 1
  746. addDriver "$version" "$drivers" "$target" "qemupciserial" || return 1
  747. local dst="$src/\$OEM\$/\$\$/Drivers"
  748. mkdir -p "$dst" || return 1
  749. cp -Lr "$dest/." "$dst" || return 1
  750. case "${version,,}" in
  751. "win11x64"* | "win2025"* )
  752. # Workaround Virtio GPU driver bug
  753. rm -rf "$dest/viogpudo"
  754. ;;
  755. esac
  756. if ! wimlib-imagex update "$file" "$index" --command "add $dest /$target" >/dev/null; then
  757. return 1
  758. fi
  759. rm -rf "$drivers"
  760. return 0
  761. }
  762. updateImage() {
  763. local dir="$1"
  764. local asset="$2"
  765. local language="$3"
  766. local tmp="/tmp/install"
  767. local file="autounattend.xml"
  768. local org="${file//.xml/.org}"
  769. local dat="${file//.xml/.dat}"
  770. local desc path src wim xml index result
  771. skipVersion "${DETECTED,,}" && return 0
  772. if [ ! -s "$asset" ] || [ ! -f "$asset" ]; then
  773. asset=""
  774. if [[ "$MANUAL" != [Yy1]* ]]; then
  775. MANUAL="Y"
  776. warn "no answer file provided, $FB."
  777. fi
  778. fi
  779. rm -rf "$tmp"
  780. mkdir -p "$tmp"
  781. src=$(find "$dir" -maxdepth 1 -type d -iname sources -print -quit)
  782. if [ ! -d "$src" ]; then
  783. error "failed to locate 'sources' folder in ISO image, $FB" && return 1
  784. fi
  785. wim=$(find "$src" -maxdepth 1 -type f \( -iname boot.wim -or -iname boot.esd \) -print -quit)
  786. if [ ! -f "$wim" ]; then
  787. error "failed to locate 'boot.wim' or 'boot.esd' in ISO image, $FB" && return 1
  788. fi
  789. index="1"
  790. result=$(wimlib-imagex info -xml "$wim" | iconv -f UTF-16LE -t UTF-8)
  791. if [[ "${result^^}" == *"<IMAGE INDEX=\"2\">"* ]]; then
  792. index="2"
  793. fi
  794. if ! addDrivers "$src" "$tmp" "$wim" "$index" "$DETECTED"; then
  795. error "Failed to add drivers to image!"
  796. fi
  797. if ! addFolder "$src"; then
  798. error "Failed to add OEM folder to image!"
  799. fi
  800. if wimlib-imagex extract "$wim" "$index" "/$file" "--dest-dir=$tmp" >/dev/null 2>&1; then
  801. if ! wimlib-imagex extract "$wim" "$index" "/$dat" "--dest-dir=$tmp" >/dev/null 2>&1; then
  802. if ! wimlib-imagex extract "$wim" "$index" "/$org" "--dest-dir=$tmp" >/dev/null 2>&1; then
  803. if ! wimlib-imagex update "$wim" "$index" --command "rename /$file /$org" > /dev/null; then
  804. warn "failed to backup original answer file ($file)."
  805. fi
  806. fi
  807. fi
  808. fi
  809. if [[ "$MANUAL" != [Yy1]* ]]; then
  810. xml=$(basename "$asset")
  811. info "Adding $xml for automatic installation..."
  812. local answer="$tmp/$xml"
  813. cp "$asset" "$answer"
  814. updateXML "$answer" "$language"
  815. if ! wimlib-imagex update "$wim" "$index" --command "add $answer /$file" > /dev/null; then
  816. MANUAL="Y"
  817. warn "failed to add answer file ($xml) to ISO image, $FB"
  818. else
  819. wimlib-imagex update "$wim" "$index" --command "add $answer /$dat" > /dev/null || true
  820. fi
  821. fi
  822. if [[ "$MANUAL" == [Yy1]* ]]; then
  823. wimlib-imagex update "$wim" "$index" --command "delete --force /$file" > /dev/null || true
  824. if wimlib-imagex extract "$wim" "$index" "/$org" "--dest-dir=$tmp" >/dev/null 2>&1; then
  825. if ! wimlib-imagex update "$wim" "$index" --command "add $tmp/$org /$file" > /dev/null; then
  826. warn "failed to restore original answer file ($org)."
  827. fi
  828. fi
  829. fi
  830. local find="$file"
  831. [[ "$MANUAL" == [Yy1]* ]] && find="$org"
  832. path=$(find "$dir" -maxdepth 1 -type f -iname "$find" -print -quit)
  833. if [ -f "$path" ]; then
  834. if [[ "$MANUAL" != [Yy1]* ]]; then
  835. mv -f "$path" "${path%.*}.org"
  836. else
  837. mv -f "$path" "${path%.*}.xml"
  838. fi
  839. fi
  840. rm -rf "$tmp"
  841. return 0
  842. }
  843. removeImage() {
  844. local iso="$1"
  845. [ ! -f "$iso" ] && return 0
  846. [ -n "$CUSTOM" ] && return 0
  847. rm -f "$iso" 2> /dev/null || warn "failed to remove $iso !"
  848. return 0
  849. }
  850. buildImage() {
  851. local dir="$1"
  852. local failed=""
  853. local cat="BOOT.CAT"
  854. local log="/run/shm/iso.log"
  855. local base size size_gb space space_gb desc
  856. if [ -f "$BOOT" ]; then
  857. error "File $BOOT does already exist?!" && return 1
  858. fi
  859. base=$(basename "$BOOT")
  860. local out="$TMP/${base%.*}.tmp"
  861. rm -f "$out"
  862. desc=$(printVersion "$DETECTED" "ISO")
  863. local msg="Building $desc image"
  864. info "$msg..." && html "$msg..."
  865. [ -z "$LABEL" ] && LABEL="Windows"
  866. if [ ! -f "$dir/$ETFS" ]; then
  867. error "Failed to locate file \"$ETFS\" in ISO image!" && return 1
  868. fi
  869. size=$(du -h -b --max-depth=0 "$dir" | cut -f1)
  870. size_gb=$(formatBytes "$size")
  871. space=$(df --output=avail -B 1 "$TMP" | tail -n 1)
  872. space_gb=$(formatBytes "$space")
  873. if (( size > space )); then
  874. error "Not enough free space in $STORAGE, have $space_gb available but need at least $size_gb." && return 1
  875. fi
  876. /run/progress.sh "$out" "$size" "$msg ([P])..." &
  877. if [[ "${BOOT_MODE,,}" != "windows_legacy" ]]; then
  878. genisoimage -o "$out" -b "$ETFS" -no-emul-boot -c "$cat" -iso-level 4 -J -l -D -N -joliet-long -relaxed-filenames -V "${LABEL::30}" \
  879. -udf -boot-info-table -eltorito-alt-boot -eltorito-boot "$EFISYS" -no-emul-boot -allow-limited-size -quiet "$dir" 2> "$log" || failed="y"
  880. else
  881. case "${DETECTED,,}" in
  882. "win2k"* | "winxp"* | "win2003"* )
  883. genisoimage -o "$out" -b "$ETFS" -no-emul-boot -boot-load-seg 1984 -boot-load-size 4 -c "$cat" -iso-level 2 -J -l -D -N -joliet-long \
  884. -relaxed-filenames -V "${LABEL::30}" -quiet "$dir" 2> "$log" || failed="y" ;;
  885. "win9"* )
  886. genisoimage -o "$out" -b "$ETFS" -J -r -V "${LABEL::30}" -quiet "$dir" 2> "$log" || failed="y" ;;
  887. * )
  888. genisoimage -o "$out" -b "$ETFS" -no-emul-boot -c "$cat" -iso-level 2 -J -l -D -N -joliet-long -relaxed-filenames -V "${LABEL::30}" \
  889. -udf -allow-limited-size -quiet "$dir" 2> "$log" || failed="y" ;;
  890. esac
  891. fi
  892. fKill "progress.sh"
  893. if [ -n "$failed" ]; then
  894. [ -s "$log" ] && echo "$(<"$log")"
  895. error "Failed to build image!" && return 1
  896. fi
  897. local error=""
  898. local hide="Warning: creating filesystem that does not conform to ISO-9660."
  899. [ -s "$log" ] && error="$(<"$log")"
  900. [[ "$error" != "$hide" ]] && echo "$error"
  901. mv -f "$out" "$BOOT" || return 1
  902. ! setOwner "$BOOT" && error "Failed to set the owner for \"$BOOT\" !"
  903. return 0
  904. }
  905. bootWindows() {
  906. if [ -f "$STORAGE/windows.args" ]; then
  907. ARGS=$(<"$STORAGE/windows.args")
  908. ARGS="${ARGS//[![:print:]]/}"
  909. ARGUMENTS="$ARGS ${ARGUMENTS:-}"
  910. fi
  911. if [ -s "$STORAGE/windows.vga" ] && [ -f "$STORAGE/windows.vga" ]; then
  912. if [ -z "${VGA:-}" ]; then
  913. VGA=$(<"$STORAGE/windows.vga")
  914. VGA="${VGA//[![:print:]]/}"
  915. fi
  916. fi
  917. if [ -s "$STORAGE/windows.usb" ] && [ -f "$STORAGE/windows.usb" ]; then
  918. if [ -z "${USB:-}" ]; then
  919. USB=$(<"$STORAGE/windows.usb")
  920. USB="${USB//[![:print:]]/}"
  921. fi
  922. fi
  923. if [ -s "$STORAGE/windows.net" ] && [ -f "$STORAGE/windows.net" ]; then
  924. if [ -z "${ADAPTER:-}" ]; then
  925. ADAPTER=$(<"$STORAGE/windows.net")
  926. ADAPTER="${ADAPTER//[![:print:]]/}"
  927. fi
  928. fi
  929. if [ -s "$STORAGE/windows.type" ] && [ -f "$STORAGE/windows.type" ]; then
  930. if [ -z "${DISK_TYPE:-}" ]; then
  931. DISK_TYPE=$(<"$STORAGE/windows.type")
  932. DISK_TYPE="${DISK_TYPE//[![:print:]]/}"
  933. fi
  934. fi
  935. if [ -s "$STORAGE/windows.mode" ] && [ -f "$STORAGE/windows.mode" ]; then
  936. BOOT_MODE=$(<"$STORAGE/windows.mode")
  937. BOOT_MODE="${BOOT_MODE//[![:print:]]/}"
  938. fi
  939. if [ -s "$STORAGE/windows.old" ] && [ -f "$STORAGE/windows.old" ]; then
  940. if [[ "${PLATFORM,,}" == "x64" ]]; then
  941. MACHINE=$(<"$STORAGE/windows.old")
  942. MACHINE="${MACHINE//[![:print:]]/}"
  943. fi
  944. fi
  945. return 0
  946. }
  947. ######################################
  948. ! parseVersion && exit 58
  949. ! parseLanguage && exit 56
  950. ! detectCustom && exit 59
  951. if ! startInstall; then
  952. bootWindows && return 0
  953. exit 68
  954. fi
  955. if [ ! -s "$ISO" ] || [ ! -f "$ISO" ]; then
  956. if ! downloadImage "$ISO" "$VERSION" "$LANGUAGE"; then
  957. rm -f "$ISO" 2> /dev/null || true
  958. exit 61
  959. fi
  960. fi
  961. DIR="$TMP/unpack"
  962. if ! extractImage "$ISO" "$DIR" "$VERSION"; then
  963. rm -f "$ISO" 2> /dev/null || true
  964. exit 62
  965. fi
  966. if ! detectImage "$DIR" "$VERSION"; then
  967. abortInstall "$DIR" "$ISO" && return 0
  968. exit 60
  969. fi
  970. if ! prepareImage "$ISO" "$DIR"; then
  971. abortInstall "$DIR" "$ISO" && return 0
  972. exit 66
  973. fi
  974. if ! updateImage "$DIR" "$XML" "$LANGUAGE"; then
  975. abortInstall "$DIR" "$ISO" && return 0
  976. exit 63
  977. fi
  978. if ! removeImage "$ISO"; then
  979. exit 64
  980. fi
  981. if ! buildImage "$DIR"; then
  982. exit 65
  983. fi
  984. if ! finishInstall "$BOOT" "N"; then
  985. exit 69
  986. fi
  987. html "Successfully prepared image for installation..."
  988. return 0