auto.sh 223 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861
  1. #!/bin/bash
  2. ##
  3. ## License: GPL
  4. ## It can reinstall Debian, Ubuntu, Kali, AlpineLinux, CentOS, AlmaLinux, RockyLinux, Fedora and Windows OS via network automatically without any other external measures and manual operations.
  5. ## Default root password: LeitboGi0ro
  6. ## Written By MoeClub.org
  7. ## Blog: https://moeclub.org
  8. ## Modified By 秋水逸冰
  9. ## Blog: https://teddysun.com/
  10. ## Modified By VPS收割者
  11. ## Blog: https://www.idcoffer.com/
  12. ## Modified By airium
  13. ## Blog: https://github.com/airium
  14. ## Modified By 王煎饼
  15. ## Github: https://github.com/bin456789/
  16. ## Modified By nat.ee
  17. ## Forum: https://hostloc.com/space-uid-49984.html
  18. ## Modified By Leitbogioro
  19. ## Blog: https://www.zhihu.com/column/originaltechnic
  20. # color
  21. underLine='\033[4m'
  22. aoiBlue='\033[36m'
  23. blue='\033[34m'
  24. yellow='\033[33m'
  25. green='\033[32m'
  26. red='\033[31m'
  27. plain='\033[0m'
  28. export tmpVER=''
  29. export tmpDIST=''
  30. export tmpURL=''
  31. export tmpWORD=''
  32. export tmpMirror=''
  33. export tmpDHCP=''
  34. export targetRelese=''
  35. export targetLang='cn'
  36. export TimeZone=''
  37. export setIpStack=''
  38. export ipAddr=''
  39. export ipMask=''
  40. export ipGate=''
  41. export ipDNS='8.8.8.8 1.1.1.1'
  42. export ip6Addr=''
  43. export ip6Mask=''
  44. export ip6Gate=''
  45. export ip6DNS='2001:4860:4860::8888 2606:4700:4700::1111'
  46. export IncDisk=''
  47. export interface=''
  48. export interfaceSelect=''
  49. export setInterfaceName='0'
  50. export autoPlugAdapter='0'
  51. export IsCN=''
  52. export Relese=''
  53. export sshPORT=''
  54. export ddMode='0'
  55. export setNet='0'
  56. export setNetbootXyz='0'
  57. export setRDP='0'
  58. export tmpSetIPv6=''
  59. export setIPv6='1'
  60. export setRaid=''
  61. export setDisk=''
  62. export partitionTable='mbr'
  63. export setMemCheck='1'
  64. export isMirror='0'
  65. export FindDists='0'
  66. export setFileType=''
  67. export loaderMode='0'
  68. export LANG="en_US.UTF-8"
  69. export IncFirmware='0'
  70. export SpikCheckDIST='0'
  71. export UNKNOWHW='0'
  72. export UNVER='6.4'
  73. export GRUBDIR=''
  74. export GRUBFILE=''
  75. export GRUBVER=''
  76. export VER=''
  77. export setCMD=""
  78. export setConsole=''
  79. export setAutoConfig='1'
  80. export FirmwareImage=''
  81. export AddNum='1'
  82. export DebianModifiedProcession=''
  83. while [[ $# -ge 1 ]]; do
  84. case $1 in
  85. -version)
  86. shift
  87. tmpVER="$1"
  88. shift
  89. ;;
  90. -debian|-Debian)
  91. shift
  92. Relese='Debian'
  93. tmpDIST="$1"
  94. shift
  95. ;;
  96. -ubuntu|-Ubuntu)
  97. shift
  98. ddMode='1'
  99. finalDIST="$1"
  100. targetRelese='Ubuntu'
  101. shift
  102. ;;
  103. -kali|-Kali)
  104. shift
  105. Relese='Kali'
  106. tmpDIST="$1"
  107. shift
  108. ;;
  109. -centos|-CentOS|-cent|-Cent)
  110. shift
  111. Relese='CentOS'
  112. tmpDIST="$1"
  113. shift
  114. ;;
  115. -rocky|-rockylinux|-RockyLinux)
  116. shift
  117. Relese='RockyLinux'
  118. tmpDIST="$1"
  119. shift
  120. ;;
  121. -alma|-almalinux|-AlmaLinux)
  122. shift
  123. Relese='AlmaLinux'
  124. tmpDIST="$1"
  125. shift
  126. ;;
  127. -fedora|-Fedora)
  128. shift
  129. Relese='Fedora'
  130. tmpDIST="$1"
  131. shift
  132. ;;
  133. -alpine|-alpinelinux|-AlpineLinux|-alpineLinux)
  134. shift
  135. Relese='AlpineLinux'
  136. tmpDIST="$1"
  137. shift
  138. ;;
  139. -win|-windows)
  140. shift
  141. ddMode='1'
  142. finalDIST="$1"
  143. targetRelese='Windows'
  144. shift
  145. ;;
  146. -lang|-language)
  147. shift
  148. targetLang="$1"
  149. shift
  150. ;;
  151. -dd|--image)
  152. shift
  153. ddMode='1'
  154. tmpURL="$1"
  155. shift
  156. ;;
  157. --networkstack)
  158. shift
  159. setIpStack="$1"
  160. shift
  161. ;;
  162. --ip-addr)
  163. shift
  164. ipAddr="$1"
  165. shift
  166. ;;
  167. --ip-mask)
  168. shift
  169. ipMask="$1"
  170. shift
  171. ;;
  172. --ip-gate)
  173. shift
  174. ipGate="$1"
  175. shift
  176. ;;
  177. --ip-dns)
  178. shift
  179. ipDNS="$1"
  180. shift
  181. ;;
  182. --ip6-addr)
  183. shift
  184. ip6Addr="$1"
  185. shift
  186. ;;
  187. --ip6-mask)
  188. shift
  189. ip6Mask="$1"
  190. shift
  191. ;;
  192. --ip6-gate)
  193. shift
  194. ip6Gate="$1"
  195. shift
  196. ;;
  197. --ip6-dns)
  198. shift
  199. ip6DNS="$1"
  200. shift
  201. ;;
  202. --network)
  203. shift
  204. tmpDHCP="$1"
  205. shift
  206. ;;
  207. --adapter)
  208. shift
  209. interfaceSelect="$1"
  210. shift
  211. ;;
  212. --netdevice-unite)
  213. shift
  214. setInterfaceName='1'
  215. ;;
  216. --autoplugadapter)
  217. shift
  218. autoPlugAdapter='1'
  219. ;;
  220. --loader)
  221. shift
  222. loaderMode='1'
  223. ;;
  224. -mirror)
  225. shift
  226. isMirror='1'
  227. tmpMirror="$1"
  228. shift
  229. ;;
  230. -rdp)
  231. shift
  232. setRDP='1'
  233. WinRemote="$1"
  234. shift
  235. ;;
  236. -raid)
  237. shift
  238. setRaid="$1"
  239. shift
  240. ;;
  241. -setdisk)
  242. shift
  243. setDisk="$1"
  244. shift
  245. ;;
  246. -partition)
  247. shift
  248. partitionTable="$1"
  249. shift
  250. ;;
  251. -timezone)
  252. shift
  253. TimeZone="$1"
  254. shift
  255. ;;
  256. -cmd)
  257. shift
  258. setCMD="$1"
  259. shift
  260. ;;
  261. -console)
  262. shift
  263. setConsole="$1"
  264. shift
  265. ;;
  266. -firmware)
  267. shift
  268. IncFirmware="1"
  269. shift
  270. ;;
  271. -filetype)
  272. shift
  273. setFileType="$1"
  274. shift
  275. ;;
  276. -port)
  277. shift
  278. sshPORT="$1"
  279. shift
  280. ;;
  281. -pwd)
  282. shift
  283. tmpWORD="$1"
  284. shift
  285. ;;
  286. --setipv6)
  287. shift
  288. tmpSetIPv6="$1"
  289. shift
  290. ;;
  291. --allbymyself)
  292. shift
  293. setAutoConfig='0'
  294. ;;
  295. --nomemcheck)
  296. shift
  297. setMemCheck='0'
  298. ;;
  299. -netbootxyz)
  300. shift
  301. setNetbootXyz='1'
  302. shift
  303. ;;
  304. *)
  305. if [[ "$1" != 'error' ]]; then echo -ne "\nInvaild option: '$1'\n\n"; fi
  306. echo -ne " Usage:\n\tbash $(basename $0)\t-debian [${underLine}${yellow}dists-name${plain}]\n\t\t\t\t-ubuntu [${underLine}dists-name${plain}]\n\t\t\t\t-kali [${underLine}dists-name${plain}]\n\t\t\t\t-alpine [${underLine}dists-name${plain}]\n\t\t\t\t-centos [${underLine}dists-name${plain}]\n\t\t\t\t-rockylinux [${underLine}dists-name${plain}]\n\t\t\t\t-almalinux [${underLine}dists-name${plain}]\n\t\t\t\t-fedora [${underLine}dists-name${plain}]\n\t\t\t\t-version [32/i386|64/${underLine}${yellow}amd64${plain}|arm/${underLine}${yellow}arm64${plain}] [${underLine}${yellow}dists-verison${plain}]\n\t\t\t\t--ip-addr/--ip-gate/--ip-mask\n\t\t\t\t-apt/-yum/-mirror\n\t\t\t\t-dd/--image\n\t\t\t\t-pwd [linux password]\n\t\t\t\t-port [linux ssh port]\n"
  307. exit 1
  308. ;;
  309. esac
  310. done
  311. # Check Root
  312. [[ "$EUID" -ne '0' || $(id -u) != '0' ]] && echo -ne "\n[${red}Error${plain}] This script must be executed as root!\n\nTry to type:\n${yellow}sudo -s\n${plain}\nAfter entering the password, switch to root dir to execute this script:\n${yellow}cd ~${plain}\n\n" && exit 1
  313. # Ping delay to YouTube($2), Instagram($3), Wikipedia($4) and BBC($5), support both IPv4 and IPv6 access, $1 is $IPStackType
  314. function checkCN() {
  315. for TestUrl in "$2" "$3" "$4" "$5"; do
  316. # "rtt" result of ping command of Alpine Linux is "round-trip" and it can't handle "sed -n" well.
  317. IPv4PingDelay=`ping -4 -c 2 -w 2 "$TestUrl" | grep "rtt\|round-trip" | cut -d'/' -f5 | awk -F'.' '{print $NF}' | sed -E '/^[0-9]\+\(\.[0-9]\+\)\?$/p'`
  318. IPv6PingDelay=`ping -6 -c 2 -w 2 "$TestUrl" | grep "rtt\|round-trip" | cut -d'/' -f5 | awk -F'.' '{print $NF}' | sed -E '/^[0-9]\+\(\.[0-9]\+\)\?$/p'`
  319. if [[ "$1"="BiStack" ]]; then
  320. [[ "$IPv4PingDelay" != "" || "$IPv6PingDelay" != "" ]] && tmpIsCN+="" || tmpIsCN+="cn"
  321. elif [[ "$1"="IPv4Stack" ]]; then
  322. [[ "$IPv4PingDelay" != "" ]] && tmpIsCN+="" || tmpIsCN+="cn"
  323. elif [[ "$1"="IPv6Stack" ]]; then
  324. [[ "$IPv6PingDelay" != "" ]] && tmpIsCN+="" || tmpIsCN+="cn"
  325. fi
  326. done
  327. # If testing servers are all unaccessible, the server may be in mainland of China.
  328. [[ $(echo $tmpIsCN | grep -o "cn" | wc -l) == "4" ]] && { IsCN="cn"; ipDNS="119.29.29.29 223.6.6.6"; ip6DNS="2402:4e00:: 2400:3200::1"; }
  329. }
  330. # "$1" is "$ipDNS" or "$ip6DNS"
  331. # The delimiter of several dns settings in automatic response file of Debian is " "(space), for RedHat, it's ","(comma).
  332. # Reference: https://lists.debian.org/debian-user/2009/10/msg00149.html
  333. # https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/installation_guide/sect-kickstart-syntax
  334. function checkDNS() {
  335. if [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]]; then
  336. tmpDNS=`echo $1 | sed 's/ /,/g'`
  337. echo "$tmpDNS"
  338. else
  339. echo "$1"
  340. fi
  341. }
  342. function dependence() {
  343. Full='0';
  344. for BIN_DEP in `echo "$1" |sed 's/,/\n/g'`
  345. do
  346. if [[ -n "$BIN_DEP" ]]; then
  347. Found='0';
  348. for BIN_PATH in `echo "$PATH" |sed 's/:/\n/g'`
  349. do
  350. ls $BIN_PATH/$BIN_DEP >/dev/null 2>&1;
  351. if [ $? == '0' ]; then
  352. Found='1';
  353. break;
  354. fi
  355. done
  356. if [ "$Found" == '1' ]; then
  357. echo -en "[${green}ok${plain}]\t";
  358. else
  359. Full='1';
  360. echo -en "[${red}Not Install${plain}]";
  361. fi
  362. echo -en "\t$BIN_DEP\n";
  363. fi
  364. done
  365. if [ "$Full" == '1' ]; then
  366. echo -ne "\n[${red}Error${plain}] Please use '${yellow}apt-get${plain}' or '${yellow}yum / dnf${plain}' install it. \n\n"
  367. exit 1;
  368. fi
  369. }
  370. function selectMirror() {
  371. [ $# -ge 3 ] || exit 1
  372. Relese=$(echo "$1" |sed -r 's/(.*)/\L\1/')
  373. DIST=$(echo "$2" |sed 's/\ //g' |sed -r 's/(.*)/\L\1/')
  374. VER=$(echo "$3" |sed 's/\ //g' |sed -r 's/(.*)/\L\1/')
  375. New=$(echo "$4" |sed 's/\ //g')
  376. [ -n "$Relese" ] && [ -n "$DIST" ] && [ -n "$VER" ] || exit 1
  377. if [ "$Relese" == "debian" ] || [ "$Relese" == "ubuntu" ] || [ "$Relese" == "kali" ]; then
  378. [ "$DIST" == "focal" ] && legacy="legacy-" || legacy=""
  379. TEMP="SUB_MIRROR/dists/${DIST}/main/installer-${VER}/current/${legacy}images/netboot/${Relese}-installer/${VER}/initrd.gz"
  380. [[ "$Relese" == "kali" ]] && TEMP="SUB_MIRROR/dists/${DIST}/main/installer-${VER}/current/images/netboot/debian-installer/${VER}/initrd.gz"
  381. elif [ "$Relese" == "centos" ] || [ "$Relese" == "rockylinux" ] || [ "$Relese" == "almalinux" ]; then
  382. if [ "$Relese" == "centos" ] && [[ "$RedHatSeries" -le "7" ]]; then
  383. TEMP="SUB_MIRROR/${DIST}/os/${VER}/images/pxeboot/initrd.img"
  384. else
  385. TEMP="SUB_MIRROR/${DIST}/BaseOS/${VER}/os/images/pxeboot/initrd.img"
  386. fi
  387. elif [ "$Relese" == "fedora" ]; then
  388. TEMP="SUB_MIRROR/releases/${DIST}/Server/${VER}/os/images/pxeboot/initrd.img"
  389. elif [ "$Relese" == "alpinelinux" ]; then
  390. TEMP="SUB_MIRROR/${DIST}/releases/${VER}/netboot/initramfs-lts"
  391. fi
  392. [ -n "$TEMP" ] || exit 1
  393. mirrorStatus=0
  394. declare -A MirrorBackup
  395. if [[ "$IsCN" == "cn" ]]; then
  396. MirrorBackup=(["debian0"]="" ["debian1"]="http://ftp.cn.debian.org/debian" ["debian2"]="http://mirror.nju.edu.cn/debian" ["debian3"]="http://mirrors.ustc.edu.cn/debian" ["debian4"]="https://mirrors.aliyun.com/debian-archive/debian" ["ubuntu0"]="" ["ubuntu1"]="https://mirrors.ustc.edu.cn/ubuntu" ["ubuntu2"]="http://mirrors.xjtu.edu.cn/ubuntu" ["kali0"]="" ["kali1"]="https://mirrors.tuna.tsinghua.edu.cn/kali" ["kali2"]="http://mirrors.zju.edu.cn/kali" ["alpinelinux0"]="" ["alpinelinux1"]="http://mirror.nju.edu.cn/alpine" ["alpinelinux2"]="http://mirrors.tuna.tsinghua.edu.cn/alpine" ["centos0"]="" ["centos1"]="https://mirrors.ustc.edu.cn/centos-stream" ["centos2"]="https://mirrors.bfsu.edu.cn/centos-stream" ["centos3"]="https://mirrors.tuna.tsinghua.edu.cn/centos" ["centos4"]="http://mirror.nju.edu.cn/centos-altarch" ["centos5"]="https://mirrors.tuna.tsinghua.edu.cn/centos-vault" ["fedora0"]="" ["fedora1"]="https://mirrors.tuna.tsinghua.edu.cn/fedora" ["fedora2"]="https://mirrors.bfsu.edu.cn/fedora" ["rockylinux0"]="" ["rockylinux1"]="http://mirror.nju.edu.cn/rocky" ["rockylinux2"]="http://mirrors.sdu.edu.cn/rocky" ["almalinux0"]="" ["almalinux1"]="https://mirror.sjtu.edu.cn/almalinux" ["almalinux2"]="http://mirrors.neusoft.edu.cn/almalinux")
  397. else
  398. MirrorBackup=(["debian0"]="" ["debian1"]="http://deb.debian.org/debian" ["debian2"]="http://mirrors.ocf.berkeley.edu/debian" ["debian3"]="http://ftp.yz.yamagata-u.ac.jp/pub/linux/debian" ["debian4"]="http://archive.debian.org/debian" ["ubuntu0"]="" ["ubuntu1"]="http://archive.ubuntu.com/ubuntu" ["ubuntu2"]="http://ports.ubuntu.com" ["kali0"]="" ["kali1"]="https://mirrors.ocf.berkeley.edu/kali" ["kali2"]="http://ftp.yz.yamagata-u.ac.jp/pub/linux/kali" ["alpinelinux0"]="" ["alpinelinux1"]="http://dl-cdn.alpinelinux.org/alpine" ["alpinelinux2"]="https://mirrors.edge.kernel.org/alpine" ["centos0"]="" ["centos1"]="http://mirror.stream.centos.org" ["centos2"]="http://mirrors.ocf.berkeley.edu/centos-stream" ["centos3"]="http://mirror.centos.org/centos" ["centos4"]="http://mirror.centos.org/altarch" ["centos5"]="http://vault.centos.org" ["fedora0"]="" ["fedora1"]="http://mirrors.rit.edu/fedora/fedora/linux" ["fedora2"]="http://ftp.iij.ad.jp/pub/linux/Fedora/fedora/linux" ["rockylinux0"]="" ["rockylinux1"]="http://download.rockylinux.org/pub/rocky" ["rockylinux2"]="http://mirrors.iu13.net/rocky" ["almalinux0"]="" ["almalinux1"]="http://repo.almalinux.org/almalinux" ["almalinux2"]="http://ftp.iij.ad.jp/pub/linux/almalinux")
  399. fi
  400. echo "$New" | grep -q '^http://\|^https://\|^ftp://' && MirrorBackup[${Relese}0]="${New%*/}"
  401. for mirror in $(echo "${!MirrorBackup[@]}" |sed 's/\ /\n/g' |sort -n |grep "^$Relese"); do
  402. Current="${MirrorBackup[$mirror]}"
  403. [ -n "$Current" ] || continue
  404. MirrorURL=`echo "$TEMP" |sed "s#SUB_MIRROR#${Current}#g"`
  405. wget --no-check-certificate --spider --timeout=3 -o /dev/null "$MirrorURL"
  406. [ $? -eq 0 ] && mirrorStatus=1 && break
  407. done
  408. [ $mirrorStatus -eq 1 ] && echo "$Current" || exit 1
  409. }
  410. function getIPv4Address() {
  411. # Differences from scope link, scope host and scope global of IPv4, reference: https://qiita.com/testnin2/items/7490ff01a4fe1c7ad61f
  412. iAddr=`ip -4 addr show | grep -wA 5 "$interface" | grep -wv "lo\|host" | grep -w "inet" | grep -w "scope global*\|link*" | head -n 1 | awk -F " " '{for (i=2;i<=NF;i++)printf("%s ", $i);print ""}' | awk '{print$1}'`
  413. [[ -n "$interface4" && -n "$interface6" && "$interface4" != "$interface6" ]] && iAddr=`ip -4 addr show | grep -wA 5 "$interface4" | grep -wv "lo\|host" | grep -w "inet" | grep -w "scope global*\|link*" | head -n 1 | awk -F " " '{for (i=2;i<=NF;i++)printf("%s ", $i);print ""}' | awk '{print$1}'`
  414. ipAddr=`echo ${iAddr} | cut -d'/' -f1`
  415. ipPrefix=`echo ${iAddr} | cut -d'/' -f2`
  416. ipMask=`netmask "$ipPrefix"`
  417. # Get real IPv4 subnet of current System
  418. ip4RouteScopeLink=`ip -4 route show scope link | grep -iv "warp\|wgcf\|wg[0-9]\|docker[0-9]" | grep -w "$interface4" | grep -w "$ipAddr" | grep -m1 -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -n 1`
  419. actualIp4Prefix=`ip -4 route show scope link | grep -iv "warp\|wgcf\|wg[0-9]\|docker[0-9]" | grep -w "$interface4" | grep -w "$ip4RouteScopeLink" | head -n 1 | awk '{print $1}' | awk -F '/' '{print $2}'`
  420. [[ -z "$actualIp4Prefix" ]] && actualIp4Prefix="$ipPrefix"
  421. actualIp4Subnet=`netmask "$actualIp4Prefix"`
  422. # In most situation, at least 99.9% probability, the first hop of the network should be the same as the available gateway.
  423. # But in 0.1%, they are actually different.
  424. # Because one of the first hop of a tested machine is 5.45.72.1, I told Debian installer this router as a gateway
  425. # But installer said the correct gateway should be 5.45.76.1, in a typical network, for example, your home,
  426. # the default gateway is the same as the first route hop of the machine, it may be 192.168.0.1.
  427. # If possible, we should configure out the real available gateway of the network.
  428. FirstRoute=`ip -4 route show default | grep -iv "warp\|wgcf\|wg[0-9]\|docker[0-9]" | grep -w "via" | grep -w "dev $interface4*" | head -n 1 | awk -F " " '{for (i=3;i<=NF;i++)printf("%s ", $i);print ""}' | awk '{print$1}'`
  429. # We should find it in ARP, the first hop IP and gateway IP is managed by the same device, use device mac address to configure it out.
  430. RouterMac=`arp -n | grep "$FirstRoute" | awk '{print$3}'`
  431. FrFirst=`echo "$FirstRoute" | cut -d'.' -f 1,2`
  432. FrThird=`echo "$FirstRoute" | cut -d'.' -f 3`
  433. # Print all matched available gateway.
  434. ipGates=`ip -4 route show | grep -iv "warp\|wgcf\|wg[0-9]\|docker[0-9]" | grep -v "via" | grep -w "dev $interface4*" | grep -w "proto*" | grep -w "scope global\|link src $ipAddr*" | awk '{print$1}'`
  435. # Figure out the line of this list.
  436. ipGateLine=`echo "$ipGates" | wc -l`
  437. # The line determines the cycling times.
  438. for ((i=1; i<="$ipGateLine"; i++)) do
  439. # Current one gateway of the ip gateways. the formart is as of 10.0.0.0/22
  440. tmpIpGate=`echo "$ipGates" | sed -n ''$i'p'`
  441. # Intercept a standard IPv4 address.
  442. tmpIgAddr=`echo $tmpIpGate | cut -d'/' -f1`
  443. # Intercept the prefix of the gateway.
  444. tmpIgPrefix=`echo $tmpIpGate | cut -d'/' -f2`
  445. # Calculate the first ip in all network segment, it should be the the same range with gateway in this network.
  446. minIpGate=`ipv4Calc "$tmpIgAddr" "$tmpIgPrefix" | grep "FirstIP:" | awk '{print$2}'`
  447. # Intercept the A and B class of the current ip address of gateway.
  448. tmpIpGateFirst=`echo "$minIpGate" | cut -d'.' -f 1,2`
  449. tmpIpGateThird=`echo "$minIpGate" | cut -d'.' -f 3`
  450. # If the class A and B class of the current local ip address is as same as current gateway, this gateway may a valid one.
  451. [[ "$FrFirst" == "$tmpIpGateFirst" ]] && {
  452. if [[ "$FrThird" == "$tmpIpGateThird" ]]; then
  453. ipGate="$FirstRoute"
  454. break
  455. elif [[ "$FrThird" != "$tmpIpGateThird" ]]; then
  456. # The A, B and C class address of min ip gate.
  457. tmpMigFirst=`echo $minIpGate | cut -d'.' -f 1,2,3`
  458. # Search it in ARP, it's belonged to the same network device which has been distinguished by mac address of first hop of the IP.
  459. ipGate=`arp -n | grep "$tmpMigFirst" | grep "$RouterMac" | awk '{print$1}'`
  460. break
  461. fi
  462. }
  463. done
  464. # If there is no one of other gateway in this current network, use if access the public internet, the first hop route of this machine as the gateway.
  465. [[ "$ipGates" == "" || "$ipGate" == "" ]] && ipGate="$FirstRoute"
  466. transferIPv4AddressFormat "$ipAddr" "$ipGate"
  467. }
  468. # $1 is "$ipAddr", $2 is "$ipGate".
  469. function transferIPv4AddressFormat() {
  470. # Some cloud providers like Godaddy, Arkecx, Hetzner(include DHCP) etc, the subnet mask of IPv4 static network configuration of their original template OS is incorrect.
  471. # The following is the sample:
  472. #
  473. # auto eth0
  474. # iface eth0 inet static
  475. # address 190.168.23.175
  476. # netmask 255.255.255.240
  477. # dns-nameservers 8.8.8.8 8.8.4.4
  478. # up ip -4 route add default via 169.254.0.1 dev eth0 onlink
  479. #
  480. # The netmask tells the total number of IP in the network is only 15(240 - 255),
  481. # but we obsessed that there are more than 15 IPv4 addresses between 169.254.0.1 and 190.168.23.175 clearly.
  482. # So if netmask is 255.255.255.240(prefix is 28), the computer only find IP between 190.168.23.160 and 190.168.23.175,
  483. # the gateway 169.254.0.1 is obviously not be included in this range.
  484. # So we need to expand the range of the netmask(reduce the value number of the prefix) to make sure the IPv4 gateway can be contained.
  485. # If this mistake has not be repaired, Debian installer will return error "untouchable gateway".
  486. # DHCP IPv4 network(even IPv4 netmask is "32") may not be effected by this situation.
  487. # The following consulted calculations are calculated by Vultr IPv4 subnet calculator, reference: https://www.vultr.com/resources/subnet-calculator/
  488. ipv4SubnetCertificate "$1" "$2"
  489. ipPrefix="$tmpIpMask"
  490. ipMask=`netmask "$tmpIpMask"`
  491. # Some servers' provided by Hetzner are so confused because the IPv4 configurations of them are static but they are not fitted with standard, here is a sample:
  492. #
  493. # auto ens3
  494. # iface ens3 inet static
  495. # address: 89.163.208.5
  496. # netmask: 255.255.255.0
  497. # broadcast +
  498. # up ip -f inet route add 169.254.0.1 dev ens3
  499. # up ip -f inet route add default via 169.254.0.1 dev ens3
  500. #
  501. # The A class of address and gateway are entirely different, although we should make sure the value of the suggested subnet mask is "128.0.0.1"(prefix "1")
  502. # to expand IPv4 range as large as possible, but in above situation, the largest IPv4 range is from 0.0.0.0 to 127.255.255.255, the IPv4 gate "169.254.0.1"
  503. # can't be included, so the reserve approach is to get the result of "ip -4 route show scope link"(89.163.208.0/24) to ensure the correct subnet and gateway,
  504. # then we can fix these weird settings from incorrect network router.
  505. # IPv4 network from Hetzner support dhcp even though it's configurated by static in "/etc/network/interfaces".
  506. # ip4RangeFirst=`ipv4Calc "$1" "$actualIp4Prefix" | grep "FirstIP:" | awk '{print$2}' | cut -d'.' -f1`
  507. # ip4RangeLast=`ipv4Calc "$1" "$actualIp4Prefix" | grep "LastIP:" | awk '{print$2}' | cut -d'.' -f1`
  508. ip4AddrFirst=`echo $1 | cut -d'.' -f1`
  509. ip4AddrSecond=`echo $1 | cut -d'.' -f2`
  510. ip4GateFirst=`echo $2 | cut -d'.' -f1`
  511. ip4GateSecond=`echo $2 | cut -d'.' -f2`
  512. ip4GateThird=`echo $2 | cut -d'.' -f3`
  513. # Common ranges of IPv4 intranet:
  514. # Reference: https://hczhang.cn/network/reserved-ip-addresses.html
  515. [[ "$ip4AddrFirst""$ip4AddrSecond" != "$ip4GateFirst""$ip4GateSecond" ]] && {
  516. [[ "$ip4GateFirst" == "169" && "$ip4GateSecond" == "254" ]] || [[ "$ip4GateFirst" == "172" && "$ip4GateSecond" -ge "16" && "$ip4GateSecond" -le "31" ]] || [[ "$ip4GateFirst" == "192" && "$ip4GateSecond" == "168" ]] || [[ "$ip4GateFirst" == "100" && "$ip4GateSecond" -ge "64" && "$ip4GateSecond" -le "127" ]] || [[ "$ip4GateFirst" == "10" && "$ip4GateSecond" -ge "0" && "$ip4GateSecond" -le "255" ]] || [[ "$ip4GateFirst" == "127" && "$ip4GateSecond" -ge "0" && "$ip4GateSecond" -le "255" ]] || [[ "$ip4GateFirst" == "198" && "$ip4GateSecond" -ge "18" && "$ip4GateSecond" -le "19" ]] || [[ "$ip4GateFirst" == "192" && "$ip4GateSecond" == "0" && "$ip4GateThird" == "0" || "$ip4GateThird" == "2" ]] || [[ "$ip4GateFirst" == "198" && "$ip4GateSecond" == "51" && "$ip4GateThird" == "100" ]] || [[ "$ip4GateFirst" == "203" && "$ip4GateSecond" == "0" && "$ip4GateThird" == "113" ]] || [[ "$ip4AddrFirst" != "$ip4GateFirst" ]] && {
  517. # [[ -z "$ip4RouteScopeLink" ]] && ipGate=`ipv4Calc "$1" "$ipPrefix" | grep "FirstIP:" | awk '{print$2}'` || ipGate=`ipv4Calc "$ip4RouteScopeLink" "$ipPrefix" | grep "FirstIP:" | awk '{print$2}'`
  518. if [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'kali' ]]; then
  519. ipPrefix="$actualIp4Prefix"
  520. ipMask="$actualIp4Subnet"
  521. Network4Config="isStatic"
  522. # Redirecting all actual names of network adapters to "eth0", "eth1"... by force aims to make a convenience to adding gateway(route) in soft hacking process.
  523. setInterfaceName='1'
  524. fi
  525. # Temporary installation of Debian 12 and Kali can't handle IPv4 public address and IPv4 private gateway well, so we prefer to invoke irregular IPv6 parameters to configure network in "busybox" and write static configs for IPv4 in later stage of the installation.
  526. [[ "$IPStackType" == "BiStack" ]] && BiStackPreferIpv6Status='1'
  527. # Installation environment of Debian 11 and former releases can't handle either irregular(gateway is not within the range of which is calculated by IP/mask) IPv4 or IPv6 parameters, so we need to execute a "ip route add" trick to make sure the networking of pure IPv4 stack servers works normally in "busybox".
  528. [[ "$IPStackType" == "IPv4Stack" ]] && BurnIrregularIpv4Status='1'
  529. }
  530. }
  531. }
  532. function netmask() {
  533. n="${1:-32}"
  534. b=""
  535. m=""
  536. for((i=0;i<32;i++)){
  537. [ $i -lt $n ] && b="${b}1" || b="${b}0"
  538. }
  539. for((i=0;i<4;i++)){
  540. s=`echo "$b"|cut -c$[$[$i*8]+1]-$[$[$i+1]*8]`
  541. [ "$m" == "" ] && m="$((2#${s}))" || m="${m}.$((2#${s}))"
  542. }
  543. echo "$m"
  544. }
  545. # $1 is IPv4 address, $2 is IPv4 subnet.
  546. function ipv4Calc() {
  547. tmpIp4="$1"
  548. tmpIp4Mask=`netmask "$2"`
  549. IFS=. read -r i1 i2 i3 i4 <<< "$tmpIp4"
  550. IFS=. read -r m1 m2 m3 m4 <<< "$tmpIp4Mask"
  551. tmpNetwork="$((i1 & m1)).$((i2 & m2)).$((i3 & m3)).$((i4 & m4))"
  552. tmpBroadcast="$((i1 & m1 | 255-m1)).$((i2 & m2 | 255-m2)).$((i3 & m3 | 255-m3)).$((i4 & m4 | 255-m4))"
  553. tmpFirstIP="$((i1 & m1)).$((i2 & m2)).$((i3 & m3)).$(((i4 & m4)+1))"
  554. tmpFiLast="$(echo "$tmpFirstIP" | cut -d'.' -f 4)"
  555. FirstIP="$tmpFirstIP"
  556. tmpLastIP="$((i1 & m1 | 255-m1)).$((i2 & m2 | 255-m2)).$((i3 & m3 | 255-m3)).$(((i4 & m4 | 255-m4)-1))"
  557. tmpLiLast="$(echo "$tmpLastIP" | cut -d'.' -f 4)"
  558. LastIP="$tmpLastIP"
  559. [[ "$tmpFiLast" > "$tmpLiLast" ]] && {
  560. FirstIP="$tmpLastIP"
  561. LastIP="$tmpFirstIP"
  562. }
  563. [[ "$2" > "31" ]] && {
  564. FirstIP="$tmpNetwork"
  565. LastIP="$tmpNetwork"
  566. }
  567. echo -e "Network: $tmpNetwork\nBroadcast: $tmpBroadcast\nFirstIP: $FirstIP\nLastIP: $LastIP\n"
  568. }
  569. # Unsuitable settings of subnet will cause not only "Death Red" of Debian installer which is called "unreachable gateway"
  570. # but also contributes to some additional negative results as of if it's wider than the actual,
  571. # this host will lose communications with some other servers which are serving in public internet because these will be treated as intranet hosts.
  572. # To the opposite, if the subnet of one server is narrower than the actual, this host will lose communications with some local hosts because these will be treated as public servers.
  573. # As an environment of a VPS, a narrower subnet causes less bad subsequentials than a wider prefer because VPS is usually be used by individual.
  574. # If it's in a cluster such as home, office or company which is a place of that usually needs to transmit data with other hosts within LAN(local area network),
  575. # the better opinion is to setting a wider value if you don't know them well.
  576. # To figure out the most suitable subnet of a class segment of one IP or just a specific IP address,
  577. # you can visit: https://bgp.tools/ which allows you to inquire announced allocations of IP addresses that were assigned by Internet Organizations.
  578. #
  579. # $1 is "$ipAddr", $2 is "$ipGate"
  580. function ipv4SubnetCertificate() {
  581. # If the IP and gateway are not in the same IPv4 A class, the prefix of netmask should be "1", transfer to whole IPv4 address is 128.0.0.1
  582. # The range of 190.168.23.175/1 is 128.0.0.0 - 255.255.255.255, the gateway 169.254.0.1 can be included.
  583. [[ `echo $1 | cut -d'.' -f 1` != `echo $2 | cut -d'.' -f 1` ]] && tmpIpMask="1"
  584. # If the IP and gateway are in the same IPv4 A class, not in the same IPv4 B class, the prefix of netmask should less equal than "8", transfer to whole IPv4 address is 255.0.0.0
  585. # The range of 190.168.23.175/8 is 190.0.0.0 - 190.255.255.255, the gateway 169... can't be included.
  586. [[ `echo $1 | cut -d'.' -f 1` == `echo $2 | cut -d'.' -f 1` ]] && tmpIpMask="8"
  587. # If the IP and gateway are in the same IPv4 A B class, not in the same IPv4 C class, the prefix of netmask should less equal than "16", transfer to whole IPv4 address is 255.255.0.0
  588. # The range of 190.168.23.175/16 is 190.168.0.0 - 190.168.255.255, the gateway 169... can't be included.
  589. [[ `echo $1 | cut -d'.' -f 1,2` == `echo $2 | cut -d'.' -f 1,2` ]] && tmpIpMask="16"
  590. # If the IP and gateway are in the same IPv4 A B C class, not in the same IPv4 D class, the prefix of netmask should less equal than "24", transfer to whole IPv4 address is 255.255.255.0
  591. # The range of 190.168.23.175/24 is 190.168.23.0 - 190.168.23.255, the gateway 169... can't be included.
  592. [[ `echo $1 | cut -d'.' -f 1,2,3` == `echo $2 | cut -d'.' -f 1,2,3` ]] && tmpIpMask="24"
  593. # So in summary of the IPv4 sample in above, we should assign subnet mask "128.0.0.1"(prefix "1") for it.
  594. }
  595. # $1 is "$setDisk"
  596. function getDisk() {
  597. # $disks is definited as the default disk, if server has 2 and more disks, the first disk will be responsible of the grub booting.
  598. rootPart=`lsblk -ip | grep -v "fd[0-9]*\|sr[0-9]*\|ram[0-9]*\|loop[0-9]*" | sed 's/[[:space:]]*$//g' | grep -w "part /\|part /boot" | head -n 1 | cut -d' ' -f1 | sed 's/..//'`
  599. # majorMin=`lsblk -ip | grep -w "$rootPart" | head -n 1 | awk '{print $2}' | sed -r 's/:(.*)/:0/g'`
  600. diskSuffix=${rootPart: -4}
  601. # ssd like NVMe(/dev/nvme0n1), MMC sd card(/dev/mmcblk0) are parted with "p number" suffix like: "/dev/nvme0n1p1" "/dev/mmcblk0p2",
  602. # The partitions of vda and sda devices are ended with number "/dev/sda1" "/dev/vda2".
  603. [[ -n `echo $diskSuffix | grep -o "[0-9]p[0-9]"` ]] && disks=`echo $rootPart | sed 's/p[0-9]*.$//'` || disks=`echo $rootPart | sed 's/[0-9]*.$//'`
  604. # disks=`lsblk -ip | grep -w "$majorMin" | head -n 1 | awk '{print $1}'`
  605. [[ -z "$disks" ]] && disks=`lsblk -ip | grep -v "fd[0-9]*\|sr[0-9]*\|ram[0-9]*\|loop[0-9]*" | sed 's/[[:space:]]*$//g' | grep -w "disk /\|disk /boot" | head -n 1 | cut -d' ' -f1`
  606. [[ -z "$disks" ]] && disks=`lsblk -ip | grep -v "fd[0-9]*\|sr[0-9]*\|ram[0-9]*\|loop[0-9]*" | sed 's/[[:space:]]*$//g' | grep -w "disk" | grep -i "[0-9]g\|[0-9]t\|[0-9]p\|[0-9]e\|[0-9]z\|[0-9]y" | head -n 1 | cut -d' ' -f1`
  607. [ -n "$disks" ] || echo ""
  608. echo "$disks" | grep -q "/dev"
  609. [ $? -eq 0 ] && IncDisk="$disks" || IncDisk="/dev/$disks"
  610. AllDisks=""
  611. # Find all disks on this server.
  612. for Count in `lsblk -ipd | grep -v "fd[0-9]*\|sr[0-9]*\|ram[0-9]*\|loop[0-9]*" | sed 's/[[:space:]]*$//g' | grep -w "disk" | grep -i "[0-9]g\|[0-9]t\|[0-9]p\|[0-9]e\|[0-9]z\|[0-9]y" | cut -d' ' -f1`; do
  613. AllDisks+="$Count "
  614. done
  615. AllDisks=$(echo "$AllDisks" | sed 's/.$//')
  616. # All numbers of disks' statistic of this server.
  617. disksNum=$(echo $AllDisks | grep -o "/dev/*" | wc -l)
  618. # Some cloud providers using first SCSI/SATA device like "sda" to mount ISO image instead of using "sr0":
  619. #
  620. # root@node:~# lsblk -ipf
  621. # NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
  622. # /dev/sda iso9660 Joliet Extension cidata 2023-07-13-09-35-07-00
  623. # /dev/sr0
  624. # /dev/vda
  625. # |-/dev/vda1
  626. # |-/dev/vda2 vfat FAT32 0BBB-E1CA 119.9M 0% /boot/efi
  627. # `-/dev/vda3 xfs 0c93f6bc-ef9c-468d-be02-84b4a70d3678 44.4G 11% /
  628. #
  629. # Because of "sda" can't be written, If system is selected to install on "sda", the installation will meet a fatal,
  630. # So we should exclude all these devices.
  631. for (( d=1; d<=$disksNum; d++ )); do
  632. currentDisk=$(echo "$AllDisks" | cut -d' ' -f$d)
  633. checkIfIsoPartition=$(lsblk -ipf | grep "$currentDisk" | head -n 1 | awk '{print $2}' | grep -i "iso")
  634. [[ -z "$checkIfIsoPartition" ]] && tmpAllDisks+="$currentDisk "
  635. done
  636. tmpAllDisks=$(echo "$tmpAllDisks" | sed 's/.$//')
  637. [[ "$AllDisks" != "$tmpAllDisks" ]] && {
  638. AllDisks="$tmpAllDisks"
  639. disksNum=$(echo $AllDisks | grep -o "/dev/*" | wc -l)
  640. [[ "$IncDisk" =~ "$AllDisks" ]] || IncDisk=$(echo "$AllDisks" | cut -d' ' -f1)
  641. }
  642. # Allow user to install system to one disk manually.
  643. [[ -n "$1" && "$1" =~ ^[a-z0-9]+$ && "$1" != "all" ]] && {
  644. [[ "$1" =~ "/dev/" ]] && IncDisk="$1" || IncDisk="/dev/$1"
  645. }
  646. }
  647. function diskType() {
  648. echo `udevadm info --query all "$1" 2>/dev/null |grep 'ID_PART_TABLE_TYPE' |cut -d'=' -f2`
  649. }
  650. # $1 is "$setRaid", $2 is "$disksNum", $3 is "$AllDisks", $4 is "$linux_relese".
  651. function setRaidRecipe() {
  652. [[ -n "$1" ]] && {
  653. # Soft Raid 0, 1, 5, 6 and 10 methods are supported by Debian, only one disk can't be as a component for any Raid method.
  654. # Raid 0 needs at least two disks, all space of the disks will be exploited, and it's the most dangerous for the safety of the data.
  655. # Raid 1 needs at least two disks, the space can be exploited is always equal one disk, it's safest for the date but a bit wasteful.
  656. # Raid 5 needs at least three disks, it storages data on two disks and storages parity checking data on one disk, it's not save on any single disk over 4TB.
  657. # Raid 6 needs at least four disks, it's an enhanced version of Raid 5, it uses two parity stripes by practicing of dividing data across the set of drives,
  658. # it allows for two disk failures within the RAID set before any data is lost.
  659. # Raid 10 needs at least four disks, it's a combination of Raid 0 and Raid 1, the disk 0 and disk 1 as a set of Raid 0, the same as disk 2 and disk 3,
  660. # and then the sets of disk 0,1 and disk 2,3 are composed as one Raid 1.
  661. # These Raid recipes are also applicable to Kali, fuck Canonical again! you deperated the compatibility of "preseed.cfg" installation procession from Ubuntu 22.04 and later.
  662. if [[ "$1" == "0" || "$1" == "1" || "$1" == "5" || "$1" == "6" || "$1" == "10" ]]; then
  663. [[ "$1" == "0" || "$1" == "1" ]] && [[ "$2" -lt "2" ]] && {
  664. echo -ne "\n[${red}Error${plain}] There are $2 drives on your machine, Raid $1 partition recipe only supports a basic set of dual drive or more!\n"
  665. exit 1
  666. }
  667. [[ "$1" == "5" ]] && [[ "$2" -lt "3" ]] && {
  668. echo -ne "\n[${red}Error${plain}] There are $2 drives on your machine, Raid $1 partition recipe only supports a basic set of triple drive or more!\n"
  669. exit 1
  670. }
  671. [[ "$1" == "6" || "$1" == "10" ]] && [[ "$2" -lt "4" ]] && {
  672. echo -ne "\n[${red}Error${plain}] There are $2 drives on your machine, Raid $1 partition recipe only supports a basic set of quad drive or more!\n"
  673. exit 1
  674. }
  675. else
  676. echo -ne "\n[${red}Error${plain}] Raid $1 partition recipe is not suitable, only Raid 0, 1, 5, 6 or 10 is supported!\n"
  677. exit 1
  678. fi
  679. if [[ "$4" == 'debian' ]] || [[ "$4" == 'kali' ]]; then
  680. for (( r=1;r<="$2";r++ )); do
  681. tmpAllDisksPart=`echo "$3" | cut -d ' ' -f"$r"`
  682. # Some NVME controller hard drives like "/dev/nvme0n1" etc are end of a number in there names must add "p" with partition numbers for "d-i partman-auto-raid/recipe string",
  683. # SCSI controller or Virtual controller drives like "/dev/sda" or "/dev/vda" are not effected by this situation.
  684. # Drives and their partitions must be connected with "#" like "/dev/nvme0n1p2#/dev/nvme0n2p2".
  685. echo "${tmpAllDisksPart: -1}" | [[ -n "`sed -n '/^[0-9][0-9]*$/p'`" ]] && tmpAllDisksPart="$tmpAllDisksPart""p" || tmpAllDisksPart="$tmpAllDisksPart"
  686. AllDisksPart1+="$tmpAllDisksPart""1#"
  687. AllDisksPart2+="$tmpAllDisksPart""2#"
  688. AllDisksPart3+="$tmpAllDisksPart""3#"
  689. done
  690. AllDisksPart1=`echo "$AllDisksPart1" | sed 's/.$//'`
  691. AllDisksPart2=`echo "$AllDisksPart2" | sed 's/.$//'`
  692. AllDisksPart3=`echo "$AllDisksPart3" | sed 's/.$//'`
  693. # Remove existed raid md devices without confirming; select raid recipe and all disks; don't assign swap; when one device on raid 1 is offline, the system still can be booted.
  694. # Reference: https://wiki.ubuntu.com/BootDegradedRaid
  695. RaidRecipes=`echo -e "d-i partman-md/confirm boolean true
  696. d-i partman-md/confirm_nooverwrite boolean true
  697. d-i partman-md/confirm_nochanges boolean false
  698. d-i partman-basicfilesystems/no_swap boolean false
  699. d-i partman-auto/method string raid
  700. d-i partman-auto/disk string $3
  701. d-i mdadm/boot_degraded boolean true"`
  702. # In environment of UEFI firmware motherboard computers, it's not suggested to creat any Raid recipe for "/boot/efi" partition,
  703. # in any virtual machine which created by VMware Workstation Pro, version up to the current 17.0.2(2023/6), host OS is Windows 10 Enterprise x64,
  704. # we must assign an additional Raid 1 recipe for "/boot" partition to prevent the case of following to happen:
  705. # otherwise except of the first reboot of the Debian 12 installed soon, the next time hard reboot the system, it will failed into "GNU GRUB version 2.0x"
  706. # and we must type "exit" to fallback to "Boot Manager", select and enter the default opinion of "Boot normally" and then find that Debian can be booted by grub.
  707. # This is a particularly fatal for those servers which has no permission to access VNC in website back-end management and impossible to manipulate UEFI boot manager to boot the system normally.
  708. if [[ "$EfiSupport" == "enabled" ]]; then
  709. FormatDisk=`echo -e "$RaidRecipes
  710. d-i partman-auto-raid/recipe string \
  711. 1 $2 0 ext4 /boot $AllDisksPart2 . \
  712. $1 $2 0 ext4 / $AllDisksPart3 .
  713. d-i partman-auto/expert_recipe string multiraid :: \
  714. 1075 100 2150 free \\$bootable{ } \\$primary{ } method{ efi } \\$iflabel{ gpt } \\$reusemethod{ } format{ } . \
  715. 269 150 538 raid \\$primary{ } method{ raid } . \
  716. 100 200 -1 raid \\$primary{ } method{ raid } .
  717. d-i partman-efi/non_efi_system boolean true
  718. d-i partman-partitioning/choose_label select gpt
  719. d-i partman-partitioning/default_label string gpt"`
  720. else
  721. # GPT table partition should not be included in BIOS Raid recipes so that it will cause Debian installer "Unable to install GRUB in /dev/sda" by installing grub.
  722. FormatDisk=`echo -e "$RaidRecipes
  723. d-i partman-auto-raid/recipe string \
  724. 1 $2 0 ext4 /boot $AllDisksPart1 . \
  725. $1 $2 0 ext4 / $AllDisksPart2 .
  726. d-i partman-auto/expert_recipe string multiraid :: \
  727. 1075 100 2150 raid \\$bootable{ } \\$primary{ } method{ raid } . \
  728. 100 200 -1 raid \\$primary{ } method{ raid } .
  729. "`
  730. fi
  731. # Reference: https://github.com/airium/Linux-Reinstall/blob/master/install-raid0.sh
  732. # https://www.debian.org/releases/bookworm/example-preseed.txt
  733. # https://www.cnblogs.com/zhangshan-log/articles/14542166.html
  734. # https://gist.github.com/jnerius/6573343
  735. # https://gist.github.com/bearice/331a954d86d890d9dbeacdd7de3aabe8
  736. # https://lala.im/7911.html
  737. # https://github.com/office-itou/Linux/blob/master/installer/source/preseed_debian.cfg
  738. # https://qiita.com/YasuhiroABE/items/ff233459035d8187263d
  739. #
  740. elif [[ "$4" == 'centos' ]] || [[ "$4" == 'rockylinux' ]] || [[ "$4" == 'almalinux' ]] || [[ "$4" == 'fedora' ]]; then
  741. tmpKsAllDisks=$(echo "$3" | sed 's/\/dev\///g')
  742. ksRaidVolumes=()
  743. ksRaidConfigs=""
  744. ksRaidRecipes=""
  745. if [[ "$EfiSupport" == "enabled" ]]; then
  746. for (( partitionIndex=0; partitionIndex<="2"; partitionIndex++ )); do
  747. disksIndex="1"
  748. for currentDisk in $tmpKsAllDisks; do
  749. tmpKsRaidVolumes="raid."$partitionIndex""$disksIndex""
  750. if [[ "$partitionIndex" == "0" ]]; then
  751. tmpKsRaidConfigs="part "$tmpKsRaidVolumes" --size="512" --ondisk="$currentDisk""
  752. elif [[ "$partitionIndex" == "1" ]]; then
  753. tmpKsRaidConfigs="part "$tmpKsRaidVolumes" --size="1024" --ondisk="$currentDisk""
  754. elif [[ "$partitionIndex" == "2" ]]; then
  755. tmpKsRaidConfigs="part "$tmpKsRaidVolumes" --size="0" --grow --ondisk="$currentDisk""
  756. fi
  757. disksIndex=$(expr "$disksIndex" + 1)
  758. ksRaidVolumes[$partitionIndex]+=""$tmpKsRaidVolumes" "
  759. ksRaidConfigs+=""$tmpKsRaidConfigs"\n"
  760. done
  761. done
  762. ksRaidConfigs=$(echo -e "$ksRaidConfigs")
  763. ksRaidRecipes=`echo -e "raid /boot --fstype="xfs" --device="boot" --level="1" ${ksRaidVolumes[0]}
  764. raid /boot/efi --fstype="efi" --device="boot-efi" --level="1" ${ksRaidVolumes[1]}
  765. raid / --fstype="xfs" --device="root" --level="$1" ${ksRaidVolumes[2]}
  766. "`
  767. else
  768. for (( partitionIndex=0; partitionIndex<="2"; partitionIndex++ )); do
  769. disksIndex="1"
  770. for currentDisk in $tmpKsAllDisks; do
  771. tmpKsRaidVolumes="raid."$partitionIndex""$disksIndex""
  772. if [[ "$partitionIndex" == "0" ]]; then
  773. tmpKsRaidConfigs="part biosboot --fstype="biosboot" --size="1" --ondisk="$currentDisk""
  774. elif [[ "$partitionIndex" == "1" ]]; then
  775. tmpKsRaidConfigs="part "$tmpKsRaidVolumes" --size="1024" --ondisk="$currentDisk""
  776. elif [[ "$partitionIndex" == "2" ]]; then
  777. tmpKsRaidConfigs="part "$tmpKsRaidVolumes" --size="0" --grow --ondisk="$currentDisk""
  778. fi
  779. disksIndex=$(expr "$disksIndex" + 1)
  780. ksRaidVolumes[$partitionIndex]+=""$tmpKsRaidVolumes" "
  781. ksRaidConfigs+=""$tmpKsRaidConfigs"\n"
  782. done
  783. done
  784. ksRaidConfigs=$(echo -e "$ksRaidConfigs")
  785. ksRaidRecipes=`echo -e "raid /boot --fstype="xfs" --device="boot" --level="1" ${ksRaidVolumes[1]}
  786. raid / --fstype="xfs" --device="root" --level="$1" ${ksRaidVolumes[2]}
  787. "`
  788. fi
  789. FormatDisk="${ksRaidConfigs}
  790. ${ksRaidRecipes}"
  791. # Reference: <Example 27.4. Using the raid Kickstart command>. https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/installation_guide/sect-kickstart-syntax
  792. # https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/installation_guide/sect-kickstart-examples
  793. # https://gist.github.com/micmoyles/587131aa19089e5c18916949c26b65e7
  794. # <4.3.3.1. ソフトウェアRAID1でのシステムパーティションの作成>. https://dl.acronis.com/u/software-defined/html/AcronisCyberInfrastructure_3_5_installation_guide_ja-JP/installing-using-pxe/creating-kickstart-file.html#kickstart-file-example
  795. else
  796. echo -ne "\n[${red}Warning${plain}] Raid $1 recipe is not supported by target system!\n"
  797. exit 1
  798. fi
  799. }
  800. }
  801. # $1 is timezone checkfile direction, $2 $3 $4 $5 and $6/$7/$8 are different IP geography location data providers to avoid if any of them has a downtime.
  802. function getUserTimeZone() {
  803. if [[ ! "$TimeZone" =~ ^[a-zA-Z] ]]; then
  804. loginUser=`who am i | awk '{print $1}' | sed 's/(//g' | sed 's/)//g'`
  805. [[ -z "$loginUser" ]] && loginUser="root"
  806. # Alpine Linux doesn't support "who am i".
  807. # In some situations, there are several users with different IPs to connect to server by ssh service,
  808. # So we need to filter a list of "Send-Q" and IPs from netstat and sort from largest to smallest by "Sent-Q" to ensure which IP is the current user,
  809. # because the "Sent-Q" can record the data packs which IP is active for current ssh user.
  810. # The same as for IPv6s.
  811. GuestIP=`netstat -naputeoW | grep -i 'established' | grep -i 'sshd: '$loginUser'' | grep -iw '^tcp\|udp' | awk '{print $3,$5}' | sort -t ' ' -k 1 -rn | awk '{print $2}' | head -n 1 | cut -d':' -f'1'`
  812. [[ "$GuestIP" == "" ]] && GuestIP=`netstat -naputeoW | grep -i 'established' | grep -i 'sshd: '$loginUser'' | grep -iw '^tcp6\|udp6' | awk '{print $3,$5}' | sort -t ' ' -k 1 -rn | awk '{print $2}' | head -n 1 | awk -F':' '{for (i=1;i<=NF-1;i++)printf("%s:", $i);print ""}' | sed 's/.$//'`
  813. for Count in "$2$GuestIP" "$3$GuestIP" "$4$GuestIP" "$5$GuestIP/json/" "$6" "$7" "$8"; do
  814. [[ "$TimeZone" == "Asia/Shanghai" ]] && break
  815. if [[ "$Count" =~ ^[a-zA-Z0-9]+$ ]]; then
  816. tmpApi=`echo -n "$Count" | base64 -d`
  817. Count="https://api.ipgeolocation.io/timezone?apiKey=$tmpApi&ip=$GuestIP"
  818. fi
  819. TimeZone=`curl -s "$Count" -A firefox | jq '.timezone, .time_zone' | grep -v "null" | tr -d '"'`
  820. checkTz=`echo $TimeZone | cut -d'/' -f 1`
  821. [[ -n "$checkTz" && "$checkTz" =~ ^[a-zA-Z] ]] && break
  822. done
  823. [[ -z "$TimeZone" ]] && TimeZone="Asia/Tokyo"
  824. else
  825. echo `timedatectl list-timezones` >> "$1"
  826. [[ `grep -c "$TimeZone" "$1"` == "0" || ! "/usr/share/zoneinfo/$1" ]] && TimeZone="Asia/Tokyo"
  827. rm -rf "$1"
  828. fi
  829. }
  830. function checkEfi() {
  831. EfiStatus=`efibootmgr l`
  832. EfiVars=""
  833. for Count in "$1" "$2" "$3" "$4"; do
  834. EfiVars=`ls -Sa $Count | wc -l`
  835. [[ "$EfiVars" -ge "1" ]] && break
  836. done
  837. if [[ "$EfiStatus" == "" ]] || [[ "$EfiVars" == "0" ]]; then
  838. EfiSupport="disabled"
  839. elif [[ -n `echo "$EfiStatus" | grep -i "bootcurrent" | awk '{print $2}' | sed -n '/^[[:xdigit:]]*$/p' | head -n 1` || -n `echo "$EfiStatus" | grep -i "bootorder" | awk '{print $2}' | awk -F ',' '{print $NF}' | sed -n '/^[[:xdigit:]]*$/p' | head -n 1` ]] && [[ "$EfiVars" != "0" ]]; then
  840. EfiSupport="enabled"
  841. else
  842. echo -ne "\n[${red}Error${plain}] UEFI boot firmware of your system could not be confirmed!\n"
  843. exit 1
  844. fi
  845. }
  846. # "/boot/grub/" "/boot/grub2/" "/etc/" "grub.cfg" "grub.conf" "/boot/efi/EFI/"
  847. function checkGrub() {
  848. GRUBDIR=""
  849. GRUBFILE=""
  850. for Count in "$1" "$2" "$3"; do
  851. # Don't support grub1 of CentOS/Redhat Enterprise Linux/Oracle Linux 6.x
  852. if [[ -f "$Count""$4" ]] && [[ `grep -c "insmod*" $Count$4` -ge "1" ]]; then
  853. GRUBDIR="$Count"
  854. GRUBFILE="$4"
  855. elif [[ -f "$Count""$5" ]] && [[ `grep -c "insmod*" $Count$5` -ge "1" ]]; then
  856. GRUBDIR="$Count"
  857. GRUBFILE="$5"
  858. fi
  859. done
  860. if [[ -z "$GRUBFILE" ]] || [[ `grep -c "insmod*" $GRUBDIR$GRUBFILE` == "0" ]]; then
  861. for Count in "$4" "$5"; do
  862. GRUBFILE=`find "$6" -name "$Count"`
  863. if [[ -n "$GRUBFILE" ]]; then
  864. GRUBDIR=`echo "$GRUBFILE" | sed "s/$Count//g"`
  865. GRUBFILE="$Count"
  866. break
  867. fi
  868. done
  869. fi
  870. GRUBDIR=`echo ${GRUBDIR%?}`
  871. if [[ `awk '/menuentry*/{print NF}' $GRUBDIR/$GRUBFILE | head -n 1` -ge "1" ]] || [[ `awk '/feature*/{print $a}' $GRUBDIR/$GRUBFILE | head -n 1` != "" ]]; then
  872. if [[ -n `grep -w "grub2-mkconfig" $GRUBDIR/$GRUBFILE` ]] || [[ `type grub2-mkconfig` != "" ]]; then
  873. GRUBTYPE="isGrub2"
  874. elif [[ -n `grep -w "grub-mkconfig" $GRUBDIR/$GRUBFILE` ]] || [[ `type grub-mkconfig` != "" ]]; then
  875. GRUBTYPE="isGrub1"
  876. elif [[ "$CurrentOS" == "CentOS" || "$CurrentOS" == "OracleLinux" ]] && [[ "$CurrentOSVer" -le "6" ]]; then
  877. GRUBTYPE="isGrub1"
  878. fi
  879. fi
  880. }
  881. # $1 is $linux_relese, $2 is $RedHatSeries, $3 is $targetRelese
  882. function checkMem() {
  883. TotalMem1=$(cat /proc/meminfo | grep "^MemTotal:" | sed 's/kb//i' | grep -o "[0-9]*" | awk -F' ' '{print $NF}')
  884. TotalMem2=$(free -k | grep -wi "mem*" | awk '{printf $2}')
  885. # In any servers that total memory below 2.5GB to install debian, the low memory installation will be force enabled, "lowmem=+0, 1 or 2" is only for Debian like, 0 is lowest, 1 is medium, 2 is the highest.
  886. [[ "$1" == 'debian' ]] || [[ "$1" == 'ubuntu' ]] || [[ "$1" == 'kali' ]] && {
  887. [[ "$TotalMem1" -ge "2558072" || "$TotalMem2" -ge "2558072" ]] && lowmemLevel="" || lowmemLevel="lowmem=+1"
  888. [[ "$setMemCheck" == '1' ]] && {
  889. [[ "$TotalMem1" -le "329760" || "$TotalMem2" -le "329760" ]] && {
  890. echo -ne "\n[${red}Error${plain}] Minimum system memory requirement is 384MB!\n"
  891. exit 1
  892. }
  893. }
  894. }
  895. # Without the function of OS re-installation templates in control panel which provided by cloud companies(many companies even have not).
  896. # A independent VPS with only one hard drive is lack of the secondary hard drive to format and copy new OS file to main hard drive.
  897. # So PXE installation need to use memory as a 'hard drive' temporary.
  898. # For redhat series, the main OS installation file is 'squashfs.img', for example, this is the link of rockylinux 8 LiveOS iso file:
  899. # http://dl.rockylinux.org/pub/rocky/8/Live/x86_64/Rocky-8-MATE-x86_64-latest.iso
  900. # If you download and mount it, you will found that the size of '/LiveOS/squashfs.img' is 1.55GB!
  901. # It means in first step of netboot installation, this 1.55GB file will be all downloaded and loaded in memory!
  902. # So and consider other install programs if necessary, even 2GB memory is not enough, 2.5GB only just pass, it's so ridiculous!
  903. # Debian 11 PXE installation will be able in low memory mode just 512M, why redhat loves swallow memory so much, is shame on you!
  904. # Redhat 9 slightly improved the huge occupy of the memory, 2GB RAM machine can run it successfully, but CentOS 9-stream needs 2.5GB RAM more.
  905. # Technology companies usually add useless functions and redundant code in new version of software increasingly.
  906. # They never optimize or improve it, just tell users they need to pay more to expand their hardware performance and adjust to the endless demand of them. it's not a correct decision.
  907. [[ "$setMemCheck" == '1' ]] && {
  908. [[ "$1" == 'fedora' || "$1" == 'rockylinux' || "$1" == 'almalinux' || "$1" == 'centos' ]] && {
  909. if [[ "$1" == 'rockylinux' || "$1" == 'almalinux' || "$1" == 'centos' ]]; then
  910. if [[ "$2" == "8" ]] || [[ "$1" == 'centos' && "$2" -ge "9" ]]; then
  911. [[ "$TotalMem1" -le "2198342" || "$TotalMem2" -le "2198342" ]] && {
  912. echo -ne "\n[${red}Error${plain}] Minimum system memory requirement is 2.5GB!\n"
  913. exit 1
  914. }
  915. elif [[ "$2" -ge "9" ]]; then
  916. [[ "$TotalMem1" -le "1740800" || "$TotalMem2" -le "1740800" ]] && {
  917. echo -ne "\n[${red}Error${plain}] Minimum system memory requirement is 2GB!\n"
  918. exit 1
  919. }
  920. elif [[ "$2" == "7" ]]; then
  921. [[ "$TotalMem1" -le "1319006" || "$TotalMem2" -le "1319006" ]] && {
  922. echo -ne "\n[${red}Error${plain}] Minimum system memory requirement is 1.5GB!\n"
  923. exit 1
  924. }
  925. fi
  926. elif [[ "$1" == 'fedora' ]]; then
  927. [[ "$TotalMem1" -le "1740800" || "$TotalMem2" -le "1740800" ]] && {
  928. echo -ne "\n[${red}Error${plain}] Minimum system memory requirement is 2GB!\n"
  929. exit 1
  930. }
  931. fi
  932. }
  933. [[ "$1" == 'alpinelinux' || "$3" == 'Ubuntu' ]] && {
  934. [[ "$TotalMem1" -le "895328" || "$TotalMem2" -le "895328" ]] && {
  935. echo -ne "\n[${red}Error${plain}] Minimum system memory requirement is 1GB!\n"
  936. exit 1
  937. }
  938. }
  939. }
  940. }
  941. function checkVirt() {
  942. virtType=""
  943. for Count in $(dmidecode -s system-manufacturer | awk '{print $1}' | sed 's/[A-Z]/\l&/g') $(systemd-detect-virt | sed 's/[A-Z]/\l&/g') $(lscpu | grep -i "hypervisor vendor" | cut -d ':' -f 2 | sed 's/^[ \t]*//g' | sed 's/[A-Z]/\l&/g'); do
  944. virtType+="$Count"
  945. done
  946. virtWhat=$(virt-what)
  947. }
  948. function checkSys() {
  949. CurrentOSVer=`cat /etc/os-release | grep -w "VERSION_ID=*" | awk -F '=' '{print $2}' | sed 's/\"//g' | cut -d'.' -f 1`
  950. apt update -y
  951. # Try to fix error of connecting to current mirror for Debian.
  952. if [[ $? -ne 0 ]]; then
  953. apt update -y > /root/apt_execute.log
  954. if [[ `grep -i "debian" /root/apt_execute.log` ]] && [[ `grep -i "err:[0-9]" /root/apt_execute.log` || `grep -i "404 not found" /root/apt_execute.log` ]]; then
  955. currentDebianMirror=$(sed -n '/^deb /'p /etc/apt/sources.list | head -n 1 | awk '{print $2}' | sed -e 's|^[^/]*//||' -e 's|/.*$||')
  956. if [[ "$CurrentOSVer" -gt "9" ]]; then
  957. # Replace invalid mirror of Debian to 'deb.debian.org' if current version has not been 'EOL'(End Of Life).
  958. sed -ri "s/$currentDebianMirror/deb.debian.org/g" /etc/apt/sources.list
  959. else
  960. # Replace invalid mirror of Debian to 'archive.debian.org' because it had been marked with 'EOL'.
  961. sed -ri "s/$currentDebianMirror/archive.debian.org/g" /etc/apt/sources.list
  962. fi
  963. # Disable get security update.
  964. sed -ri 's/^deb-src/# deb-src/g' /etc/apt/sources.list
  965. apt update -y
  966. fi
  967. rm -rf /root/apt_execute.log
  968. fi
  969. apt install lsb-release -y
  970. # Delete mirrors from elrepo.org because it will causes dnf/yum checking updates continuously(maybe some of the server mirror lists are in the downtime?)
  971. [[ `grep -wri "elrepo.org" /etc/yum.repos.d/` != "" ]] && {
  972. elrepoFile=`grep -wri "elrepo.org" /etc/yum.repos.d/ | head -n 1 | cut -d':' -f 1`
  973. mv "$elrepoFile" "$elrepoFile.bak"
  974. }
  975. yum install redhat-lsb -y
  976. OsLsb=`lsb_release -d | awk '{print$2}'`
  977. RedHatRelease=""
  978. for Count in `cat /etc/redhat-release | awk '{print$1}'` `cat /etc/system-release | awk '{print$1}'` `cat /etc/os-release | grep -w "ID=*" | awk -F '=' '{print $2}' | sed 's/\"//g'` "$OsLsb"; do
  979. [[ -n "$Count" ]] && RedHatRelease=`echo -e "$Count"`"$RedHatRelease"
  980. done
  981. DebianRelease=""
  982. IsUbuntu=`uname -a | grep -i "ubuntu"`
  983. IsDebian=`uname -a | grep -i "debian"`
  984. IsKali=`uname -a | grep -i "kali"`
  985. for Count in `cat /etc/os-release | grep -w "ID=*" | awk -F '=' '{print $2}'` `cat /etc/issue | awk '{print $1}'` "$OsLsb"; do
  986. [[ -n "$Count" ]] && DebianRelease=`echo -e "$Count"`"$DebianRelease"
  987. done
  988. AlpineRelease=""
  989. apk update
  990. for Count in `cat /etc/os-release | grep -w "ID=*" | awk -F '=' '{print $2}'` `cat /etc/issue | awk '{print $3}' | head -n 1` `uname -v | awk '{print $1}' | sed 's/[^a-zA-Z]//g'`; do
  991. [[ -n "$Count" ]] && AlpineRelease=`echo -e "$Count"`"$AlpineRelease"
  992. done
  993. if [[ `echo "$RedHatRelease" | grep -i 'centos'` != "" ]]; then
  994. CurrentOS="CentOS"
  995. elif [[ `echo "$RedHatRelease" | grep -i 'cloudlinux'` != "" ]]; then
  996. CurrentOS="CloudLinux"
  997. elif [[ `echo "$RedHatRelease" | grep -i 'alma'` != "" ]]; then
  998. CurrentOS="AlmaLinux"
  999. elif [[ `echo "$RedHatRelease" | grep -i 'rocky'` != "" ]]; then
  1000. CurrentOS="RockyLinux"
  1001. elif [[ `echo "$RedHatRelease" | grep -i 'fedora'` != "" ]]; then
  1002. CurrentOS="Fedora"
  1003. elif [[ `echo "$RedHatRelease" | grep -i 'virtuozzo'` != "" ]]; then
  1004. CurrentOS="Vzlinux"
  1005. elif [[ `echo "$RedHatRelease" | grep -i 'ol\|oracle'` != "" ]]; then
  1006. CurrentOS="OracleLinux"
  1007. elif [[ `echo "$RedHatRelease" | grep -i 'opencloud'` != "" ]]; then
  1008. CurrentOS="OpenCloudOS"
  1009. elif [[ `echo "$RedHatRelease" | grep -i 'alibaba\|alinux\|aliyun'` != "" ]]; then
  1010. CurrentOS="AlibabaCloudLinux"
  1011. elif [[ `echo "$RedHatRelease" | grep -i 'amazon\|amzn'` != "" ]]; then
  1012. CurrentOS="AmazonLinux"
  1013. amazon-linux-extras install epel -y
  1014. elif [[ `echo "$RedHatRelease" | grep -i 'red\|rhel'` != "" ]]; then
  1015. CurrentOS="RedHatEnterpriseLinux"
  1016. elif [[ `echo "$RedHatRelease" | grep -i 'anolis'` != "" ]]; then
  1017. CurrentOS="OpenAnolis"
  1018. elif [[ `echo "$RedHatRelease" | grep -i 'scientific'` != "" ]]; then
  1019. CurrentOS="ScientificLinux"
  1020. elif [[ `echo "$AlpineRelease" | grep -i 'alpine'` != "" ]]; then
  1021. CurrentOS="AlpineLinux"
  1022. elif [[ "$IsUbuntu" ]] || [[ `echo "$DebianRelease" | grep -i 'ubuntu'` != "" ]]; then
  1023. CurrentOS="Ubuntu"
  1024. CurrentOSVer=`lsb_release -r | awk '{print$2}' | cut -d'.' -f1`
  1025. elif [[ "$IsDebian" ]] || [[ `echo "$DebianRelease" | grep -i 'debian'` != "" ]]; then
  1026. CurrentOS="Debian"
  1027. CurrentOSVer=`lsb_release -r | awk '{print$2}' | cut -d'.' -f1`
  1028. elif [[ "$IsKali" ]] || [[ `echo "$DebianRelease" | grep -i 'kali'` != "" ]]; then
  1029. CurrentOS="Kali"
  1030. CurrentOSVer=`lsb_release -r | awk '{print$2}' | cut -d'.' -f1`
  1031. else
  1032. echo -ne "\n[${red}Error${plain}] Does't support your system!\n"
  1033. exit 1
  1034. fi
  1035. # Don't support Redhat like linux OS under 6 version.
  1036. if [[ "$CurrentOS" == "CentOS" || "$CurrentOS" == "OracleLinux" ]] && [[ "$CurrentOSVer" -le "6" ]]; then
  1037. echo -e "Does't support your system!\n"
  1038. exit 1
  1039. fi
  1040. # Remove "inetutils-ping" because it does not support "ping -4" or "ping -6".
  1041. apt purge inetutils-ping -y
  1042. # Debian like linux OS necessary components.
  1043. apt install cpio curl dnsutils efibootmgr fdisk file gzip iputils-ping jq net-tools openssl subnetcalc tuned virt-what wget xz-utils -y
  1044. # Redhat like Linux OS prefer to use dnf instead of yum because former has a higher execute efficiency.
  1045. yum install epel-release -y
  1046. yum install dnf -y
  1047. if [[ $? -eq 0 ]]; then
  1048. # To avoid "Failed loading plugin "osmsplugin": No module named 'librepo'"
  1049. # Reference: https://anatolinicolae.com/failed-loading-plugin-osmsplugin-no-module-named-librepo/
  1050. [[ "$CurrentOS" == "CentOS" && "$CurrentOSVer" == "8" ]] && dnf install python3-librepo -y
  1051. # Redhat like linux OS necessary components.
  1052. dnf install bind-utils cpio curl dnsutils efibootmgr file gzip ipcalc jq net-tools openssl redhat-lsb syslinux tuned util-linux virt-what wget xz --skip-broken -y
  1053. # dnf update -y
  1054. else
  1055. yum install dnf -y > /root/yum_execute.log 2>&1
  1056. # In some versions of CentOS 8 which are not subsumed into CentOS-stream are end of supporting by CentOS official, so the source is failure.
  1057. # We need to change the source from http://mirror.centos.org to http://vault.centos.org to make repository is still available.
  1058. # Reference: https://techglimpse.com/solve-failed-synchronize-cache-repo-appstream/
  1059. # https://qiita.com/yamada-hakase/items/cb1b6124e11ca65e2a2b
  1060. if [[ `grep -i "failed to synchronize" /root/yum_execute.log` || `grep -i "no urls in mirrorlist" /root/yum_execute.log` ]]; then
  1061. if [[ "$CurrentOS" == "CentOS" ]]; then
  1062. cd /etc/yum.repos.d/
  1063. sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
  1064. sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
  1065. [[ "$CurrentOSVer" == "8" ]] && dnf install python3-librepo -y
  1066. fi
  1067. yum install epel-release -y
  1068. yum install dnf -y
  1069. # Run dnf update and install components.
  1070. # In official template of AlmaLinux 9 of Linode, "tuned" must be installed otherwise "grub2-mkconfig" can't work formally.
  1071. # Reference: https://phanes.silogroup.org/fips-disa-stig-hardening-on-centos9/
  1072. dnf install bind-utils cpio curl dnsutils efibootmgr file gzip ipcalc jq net-tools openssl redhat-lsb syslinux tuned util-linux virt-what wget xz --skip-broken -y
  1073. # dnf update -y
  1074. # Oracle Linux 7 doesn't support DNF.
  1075. elif [[ `grep -i "no package" /root/yum_execute.log` ]]; then
  1076. yum install bind-utils cpio curl dnsutils efibootmgr file gzip ipcalc jq net-tools openssl redhat-lsb syslinux tuned util-linux virt-what wget xz --skip-broken -y
  1077. # yum update -y
  1078. fi
  1079. rm -rf /root/yum_execute.log
  1080. fi
  1081. # Alpine Linux necessary components and configurations.
  1082. [[ "$CurrentOS" == "AlpineLinux" ]] && {
  1083. # Get current version number of Alpine Linux
  1084. CurrentAlpineVer=$(cut -d. -f1,2 </etc/alpine-release)
  1085. # Try to remove comments of any valid mirror.
  1086. sed -i 's/#//' /etc/apk/repositories
  1087. # Add community mirror.
  1088. [[ ! `grep -i "community" /etc/apk/repositories` ]] && sed -i '$a\http://ftp.udx.icscoe.jp/Linux/alpine/v'${CurrentAlpineVer}'/community' /etc/apk/repositories
  1089. # Add testing mirror.
  1090. # [[ ! `grep -i "testing" /etc/apk/repositories` ]] && sed -i '$a\http://ftp.udx.icscoe.jp/Linux/alpine/edge/testing' /etc/apk/repositories
  1091. # Alpine Linux use "apk" as package management.
  1092. apk update
  1093. apk add bash bind-tools coreutils cpio curl efibootmgr file gawk grep gzip ipcalc jq net-tools openssl sed shadow tzdata util-linux virt-what wget xz
  1094. # Use bash to replace ash.
  1095. sed -i 's/root:\/bin\/ash/root:\/bin\/bash/g' /etc/passwd
  1096. }
  1097. }
  1098. # $1 is "$ipAddr", $2 is "$ip6Addr"
  1099. function checkIpv4OrIpv6() {
  1100. for ((w=1; w<=2; w++)); do
  1101. IPv4DNSLookup=`timeout 0.3s dig -4 TXT +short o-o.myaddr.l.google.com @ns1.google.com | sed 's/\"//g'`
  1102. [[ "$IPv4DNSLookup" == "" ]] && IPv4DNSLookup=`timeout 0.3s dig -4 TXT CH +short whoami.cloudflare @1.1.1.1 | sed 's/\"//g'`
  1103. [[ "$IPv4DNSLookup" != "" ]] && break
  1104. done
  1105. for ((x=1; x<=2; x++)); do
  1106. IPv6DNSLookup=`timeout 0.3s dig -6 TXT +short o-o.myaddr.l.google.com @ns1.google.com | sed 's/\"//g'`
  1107. [[ "$IPv6DNSLookup" == "" ]] && IPv6DNSLookup=`timeout 0.3s dig -6 TXT CH +short whoami.cloudflare @2606:4700:4700::1111 | sed 's/\"//g'`
  1108. [[ "$IPv6DNSLookup" != "" ]] && break
  1109. done
  1110. for y in "$3" "$4" "$5" "$6"; do
  1111. IPv4PingDNS=`timeout 0.3s ping -4 -c 1 "$y" | grep "rtt\|round-trip" | cut -d'/' -f5 | awk -F'.' '{print $NF}' | sed -E '/^[0-9]\+\(\.[0-9]\+\)\?$/p'`"$IPv4PingDNS"
  1112. [[ "$IPv4PingDNS" != "" ]] && break
  1113. done
  1114. for z in "$7" "$8" "$9" "$10"; do
  1115. IPv6PingDNS=`timeout 0.3s ping -6 -c 1 "$z" | grep "rtt\|round-trip" | cut -d'/' -f5 | awk -F'.' '{print $NF}' | sed -E '/^[0-9]\+\(\.[0-9]\+\)\?$/p'`"$IPv6PingDNS"
  1116. [[ "$IPv6PingDNS" != "" ]] && break
  1117. done
  1118. # Use ping -4/-6 to replace dig -4/-6 because some IPv4 network will callback IPv6 address from DNS even if we use "dig -4" to get DNS result.
  1119. [[ "$IPv4PingDNS" =~ ^[0-9] && "$IPv6PingDNS" =~ ^[0-9] ]] && IPStackType="BiStack"
  1120. [[ "$IPv4PingDNS" =~ ^[0-9] && ! "$IPv6PingDNS" =~ ^[0-9] ]] && IPStackType="IPv4Stack"
  1121. [[ ! "$IPv4PingDNS" =~ ^[0-9] && "$IPv6PingDNS" =~ ^[0-9] ]] && IPStackType="IPv6Stack"
  1122. [[ -n "$1" || -n "$2" ]] && {
  1123. if [[ -n "$1" && -z "$2" ]]; then
  1124. for ipCheck in "$1" "$ipGate"; do
  1125. verifyIPv4FormatLawfulness "$ipCheck"
  1126. done
  1127. elif [[ -n "$1" && -n "$2" ]]; then
  1128. for ipCheck in "$1" "$ipGate"; do
  1129. verifyIPv4FormatLawfulness "$ipCheck"
  1130. done
  1131. for ipCheck in "$2" "$ip6Gate"; do
  1132. verifyIPv6FormatLawfulness "$ipCheck"
  1133. done
  1134. IPStackType="BiStack"
  1135. elif [[ -z "$1" && -n "$2" ]]; then
  1136. for ipCheck in "$2" "$ip6Gate"; do
  1137. verifyIPv6FormatLawfulness "$ipCheck"
  1138. done
  1139. fi
  1140. }
  1141. [[ $(echo "$setIpStack" | grep -i "bi\|bistack\|dual\|two") ]] && IPStackType="BiStack"
  1142. [[ $(echo "$setIpStack" | grep -i "4\|i4\|ip4\|ipv4") ]] && IPStackType="IPv4Stack"
  1143. [[ $(echo "$setIpStack" | grep -i "6\|i6\|ip6\|ipv6") ]] && IPStackType="IPv6Stack"
  1144. # [[ "$IPStackType" == "IPv4Stack" ]] && setIPv6="0" || setIPv6="1"
  1145. [[ "$tmpSetIPv6" == "0" ]] && setIPv6="0" || setIPv6="1"
  1146. }
  1147. function verifyIPv4FormatLawfulness() {
  1148. [[ -n "$1" ]] && IP_Check="$1"
  1149. if expr "$IP_Check" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null; then
  1150. for i in 1 2 3 4; do
  1151. if [ $(echo "$IP_Check" | cut -d. -f$i) -gt 255 ]; then
  1152. echo "fail ($IP_Check)"
  1153. exit 1
  1154. fi
  1155. done
  1156. IP_Check="isIPv4"
  1157. fi
  1158. [[ "$IP_Check" != "isIPv4" ]] && {
  1159. echo -ne "\n[${red}Error${plain}] Invalid inputted IPv4 format!\n"
  1160. exit 1
  1161. }
  1162. }
  1163. function verifyIPv6FormatLawfulness() {
  1164. [[ -n "$1" ]] && IPv6_Check="$1"
  1165. # If the last two strings of IPv6 is "::", we should replace ":" to "0" for the last string to make sure it's a valid IPv6(can't end with ":").
  1166. [[ "${IPv6_Check: -1}" == ":" ]] && IPv6_Check=$(echo "$IPv6_Check" | sed 's/.$/0/')
  1167. # If the first two strings of IPv6 is "::", we should replace ":" to "0" for the first string to make sure it's a valid IPv6(can't start with ":").
  1168. [[ "${IPv6_Check:0:1}" == ":" ]] && IPv6_Check=$(echo "$IPv6_Check" | sed 's/^./0/')
  1169. # Add ":" in the last of the IPv6 address for cut all items infront of the ":" by split by symbol ":".
  1170. IP6_Check_Temp="$IPv6_Check"":"
  1171. # Total numbers of the hex blocks in IPv6 address includes with empty value(abbreviation of "0000").
  1172. IP6_Hex_Num=`echo "$IP6_Check_Temp" | tr -cd ":" | wc -c`
  1173. # Default number of empty values of the hex block is "0".
  1174. IP6_Hex_Abbr="0"
  1175. # The first filter plays a role of:
  1176. # 1. check if 0-9 or a-z and ":" in original IPv6;
  1177. # 2. the longest number of ":" in IPv6 is "7", because of variable "IP6_Check_Temp" one more ":" has been add,
  1178. # so the total number of ":" in variable "IP6_Check_Temp" should be less or equal "8".
  1179. if [[ `echo "$IPv6_Check" | grep -i '[[:xdigit:]]' | grep ':'` ]] && [[ "$IP6_Hex_Num" -le "8" ]]; then
  1180. # IPv6 address doesn't allow two "::" existed, the number of ":" should not above 7.
  1181. # If number of ":" is less than 6, at least one "::" is required.
  1182. # IPv6 can't end with "hex_number:"
  1183. [[ `echo "$1" | grep -o ":::" | wc -l` -gt "0" ]] || [[ `echo "$1" | grep -o "::" | wc -l` -gt "1" || `echo "$1" | grep -o ":" | wc -l` -gt "7" ]] || [[ "$IP6_Hex_Num" -le "7" && `echo "$1" | grep -o "::" | wc -l` -lt "1" ]] || [[ "${1: -2}" != "::" && "${1: -1}" == ":" ]] && { echo -ne "\n[${red}Error${plain}] Invalid inputted IPv6 format!\n"; exit 1; }
  1184. # Total cycles of the check(sequence of the current hex block).
  1185. for ((i=1; i<="$IP6_Hex_Num"; i++)); do
  1186. # Every IPv6 hex block of current cycle.
  1187. IP6_Hex=$(echo "$IP6_Check_Temp" | cut -d: -f$i)
  1188. # Count "::" abbreviations for this IPv6.
  1189. [[ "$IP6_Hex" == "" ]] && IP6_Hex_Abbr=`expr $IP6_Hex_Abbr + 1`
  1190. # String number of letters or numbers in one block should less or equal "4".
  1191. if [[ `echo "$IP6_Hex" | wc -m` -le "5" ]]; then
  1192. # The second filter plays a reversion role of the following to exclude an effective IPv6 hex block:
  1193. # 1. Except 0-9 and a-f;
  1194. # 2. Abbreviation of hex block should be appeared less than or equal one time in principle.
  1195. [[ `echo "$IP6_Hex" | grep -iE '[^0-9a-f]'` || "$IP6_Hex_Abbr" -gt "1" ]] && { echo -ne "\n[${red}Error${plain}] Invalid inputted IPv6 format!\n"; exit 1; }
  1196. else
  1197. echo -ne "\n[${red}Error${plain}] Invalid inputted IPv6 format!\n"; exit 1;
  1198. fi
  1199. done
  1200. IP6_Check="isIPv6"
  1201. fi
  1202. [[ "$IP6_Check" != "isIPv6" ]] && { echo -ne "\n[${red}Error${plain}] Invalid inputted IPv6 format!\n"; exit 1; }
  1203. }
  1204. # Some "BiStack" types are accomplished by Warp which provided by CloudFlare, so we need to distinguish whether IPv4 or IPv6 stack is enabled by Warp then exclude it.
  1205. # $1 is "warp*.conf", maybe "warp.conf" or "warp-profile.conf"; $2 is "wgcf*.conf", maybe "wgcf.conf" or "wgcf-profile.conf"; $3 is "wg[0-9]", maybe "wg0.conf" or etc.
  1206. # $4/$5/$6 are "warp*/wgcf*/wg[0-9]", $7/$8 are "PrivateKey/PublicKey".
  1207. function checkWarp() {
  1208. warpConfFiles=$(find / -maxdepth 6 -name "$1" -print -or -name "$2" -print -or -name "$3" -print)
  1209. sysctlWarpProcess=$(systemctl 2>&1 | grep -i "$4\|$5\|$6" | wc -l)
  1210. rcWarpProcess=$(rc-status 2>&1 | grep -i "$4\|$5\|$6" | wc -l)
  1211. [[ "$IPStackType" == "BiStack" ]] && {
  1212. [[ -n "$warpConfFiles" ]] && {
  1213. for warpConfFile in $(find / -maxdepth 6 -name "$1" -print -or -name "$2" -print -or -name "$3" -print); do
  1214. if [[ $(grep -ic "$7" "$warpConfFile") -ge "1" || $(grep -ic "$8" "$warpConfFile") -ge "1" ]]; then
  1215. warpStatic="1"
  1216. break
  1217. fi
  1218. done
  1219. }
  1220. [[ "$sysctlWarpProcess" -gt "0" || "$rcWarpProcess" -gt "0" ]] && warpStatic="1"
  1221. }
  1222. [[ "$warpStatic" == "1" ]] && {
  1223. [[ -z "$ipGate" ]] && IPStackType="IPv6Stack"
  1224. [[ -z "$ip6Gate" ]] && IPStackType="IPv4Stack"
  1225. }
  1226. }
  1227. # Examples:
  1228. # input: ::
  1229. # output: 0:0:0:0:0:0:0:0
  1230. # input: 2620:119:35::c4
  1231. # output: 2620:119:35:0:0:0:0:c4
  1232. function fillAbbrOfIpv6() {
  1233. inputIpv6="$1"
  1234. # Static of how many delimiters of ":" are in one ipv6 address, only one abbreviation of "::" is allowed in one IPv6 address in principle.
  1235. delimiterNum=$(echo $inputIpv6 | awk '{print gsub(/:/, "")}')
  1236. replaceStr=""
  1237. # A standard of IPv6 should have 7 colons, the number "7" minus total numbers of colons in an abbreviated IPv6 address and add "0" after every ":" can help us to fulfill the whole IPv6 address.
  1238. for ((i=0; i<=$((7-$delimiterNum)); i++)); do
  1239. replaceStr="$replaceStr"":0"
  1240. done
  1241. # Must add one ":" after the last of expanded "0" to separate with the following IPv6 block which is not been abbreviated.
  1242. replaceStr="$replaceStr"":"
  1243. # Replace abbreviated IPv6 address "::" to expanded IPv6 address($replaceStr).
  1244. ipv6Expanded=${inputIpv6/::/$replaceStr}
  1245. # If the last two strings of abbreviated IPv6 is "::", we should add a "0" for the last ":" to pledge the validation of this IPv6(can't end with ":").
  1246. [[ "$ipv6Expanded" == *: ]] && ipv6Expanded="$ipv6Expanded""0"
  1247. # If the first two strings of abbreviated IPv6 is "::", we should add a "0" for the first ":" to pledge the validation of this IPv6(can't begin with ":").
  1248. [[ "$ipv6Expanded" == :* ]] && ipv6Expanded="0""$ipv6Expanded"
  1249. # Return IPv6 which is filled with one "0" in every abbreviated block.
  1250. echo "$ipv6Expanded"
  1251. }
  1252. # Examples:
  1253. # input: 0:0:0:0:0:0:0:0
  1254. # output: 0000:0000:0000:0000:0000:0000:0000:0000
  1255. # input: 2620:119:35:0:0:0:0:c4
  1256. # output: 2620:0119:0035:0000:0000:0000:0000:00c4
  1257. function ultimateFormatOfIpv6() {
  1258. abbrExpandedOfIpv6=$(fillAbbrOfIpv6 "$1")
  1259. # To make a new array names "$ipv6Hex" to storage every hex block like "2620" "119e" of IPv6, this array should have 8 indices.
  1260. ipv6Hex=(${abbrExpandedOfIpv6//:/ })
  1261. for ((j=0; j<8; j++)); do
  1262. # Static number of strings in every hex block of IPv6.
  1263. length="${#ipv6Hex[j]}"
  1264. # Use decrement cycle to count how many zeroes need to be fulfilled because there are most 4 strings in one hex block in theory.
  1265. for ((k=4; k>$length; k--)); do
  1266. # Zeroes which must be added on the head if number of digits of a hexadecimal number in one hex block is less than 4.
  1267. ipv6Hex[j]="0${ipv6Hex[j]}"
  1268. done
  1269. done
  1270. # Return all elements of array of "$ipv6Hex" which is filled with 4 digits in every hexadecimal block and use colon to stitch with hexes instead of space to achieve the recovery of an abbreviated IPv6 address.
  1271. echo ${ipv6Hex[@]} | sed 's/ /\:/g'
  1272. }
  1273. function getIPv6Address() {
  1274. # Differences from scope link, scope host and scope global of IPv6, reference: https://qiita.com/_dakc_/items/4eefa443306860bdcfde
  1275. allI6Addrs=`ip -6 addr show | grep -wA 65536 "$interface\|$interface6" | grep -wv "lo" | grep -wv "link\|host" | grep -w "inet6" | grep "scope" | grep "global" | awk -F " " '{for (i=2;i<=NF;i++)printf("%s ", $i);print ""}' | awk '{print $1}'`
  1276. i6Addr=`echo "$allI6Addrs" | head -n 1`
  1277. i6AddrNum=`echo "$allI6Addrs" | wc -l`
  1278. collectAllIpv6Addresses "$i6AddrNum"
  1279. ip6Addr=`echo ${i6Addr} | cut -d'/' -f1`
  1280. ip6Mask=`echo ${i6Addr} | cut -d'/' -f2`
  1281. ip6Gate=`ip -6 route show default | grep -iv "warp\|wgcf\|wg[0-9]\|docker[0-9]" | grep -w "$interface\|$interface6" | grep -w "via" | grep "dev" | head -n 1 | awk -F " " '{for (i=3;i<=NF;i++)printf("%s ", $i);print ""}' | awk '{print$1}'`
  1282. # Get real IPv6 subnet of current System
  1283. actualIp6Prefix=`ip -6 route show | grep -iv "warp\|wgcf\|wg[0-9]\|docker[0-9]" | grep -w "$interface\|$interface6" | grep -v "default" | grep -v "multicast" | grep -P '../[0-9]{1,3}' | head -n 1 | awk '{print $1}' | awk -F '/' '{print $2}'`
  1284. [[ -z "$actualIp6Prefix" || "$i6AddrNum" -ge "2" ]] && actualIp6Prefix="$ip6Mask"
  1285. transferIPv6AddressFormat "$ip6Addr" "$ip6Gate"
  1286. }
  1287. # $1 is "$ip6Addr", $2 is "$ip6Gate".
  1288. function transferIPv6AddressFormat() {
  1289. # Some Bi-Stack server has a public IPv4 address with a private IPv4 gateway and has a dhcp configuration for IPv6 stack,
  1290. # so we need to tell Debian installer IPv6 static configurations to config IPv6 network first by force.
  1291. [[ "$BiStackPreferIpv6Status" == "1" ]] && Network6Config="isStatic"
  1292. # In some original template OS of cloud provider like Akile.io etc,
  1293. # if prefix of IPv6 mask is 128 in static network configuration, it means there is only one IPv6(current server itself) in the network.
  1294. # The following is the sample:
  1295. #
  1296. # auto eth0
  1297. # iface eth0 inet6 static
  1298. # address 2603:c020:8:a19b::ffff:e6da
  1299. # gateway 2603:c020:8:a19b::ffff
  1300. # netmask 128
  1301. # dns-nameservers 2001:4860:4860::8888
  1302. #
  1303. # In this condition, if IPv6 gateway has a different address with IPv6 address, the Debian installer couldn't find the correct gateway.
  1304. # The installation will fail in the end. The reason is mostly the upstream wrongly configurated the current network of this system.
  1305. # So we try to revise this value for 8 levels to expand the range of the IPv6 network and help installer to find the correct gateway.
  1306. # DHCP IPv6 network(even IPv6 netmask is "128") may not be effected by this situation.
  1307. # The result of function ' ipv6SubnetCalc "$ip6Mask" ' is "$ip6Subnet"
  1308. # The following consulted calculations are calculated by Vultr IPv6 subnet calculator and IPv6 subnet range calculator which is provided by iP Jisuanqi.
  1309. # Reference: https://www.vultr.com/resources/subnet-calculator-ipv6/
  1310. # https://ipjisuanqi.com/ipv6.html
  1311. [[ "$Network6Config" == "isStatic" ]] && {
  1312. # IPv6 expansion algorithm code reference: https://blog.caoyu.info/expand-ipv6-by-shell.html
  1313. ip6AddrWhole=`ultimateFormatOfIpv6 "$1"`
  1314. ip6GateWhole=`ultimateFormatOfIpv6 "$2"`
  1315. tmpIp6AddrFirst=`echo $ip6AddrWhole | sed 's/\(.\{4\}\).*/\1/' | sed 's/[a-z]/\u&/g'`
  1316. tmpIp6GateFirst=`echo $ip6GateWhole | sed 's/\(.\{4\}\).*/\1/' | sed 's/[a-z]/\u&/g'`
  1317. if [[ "$tmpIp6AddrFirst" != "$tmpIp6GateFirst" ]]; then
  1318. # If some brave guys set --network "static" by force, IPv6 address, mask and gateway of IPv6 DHCP configurations like Oracle Cloud etc. are:
  1319. # a public IPv6 address, a "128" mask, a local IPv6 gateway(starts with "fe80" mostly, like "fe80::200:f1e9:dec3:4ab").
  1320. # The value of mask must be set as "128", not "1" which determined by first condition of above because the local IPv6 address is unique in its' network
  1321. # and plays the role of IPv6 network discovery and identical authentication to ensure that authenticated device is certificated by upstream.
  1322. # Explanation of using local IPv6 address as gateway quoted from Scott Hogg:
  1323. #
  1324. # Link-local IPv6 addresses are on every interface of every IPv6-enabled host and router. They are essential for LAN-based Neighbor Discovery communication.
  1325. # After the host has gone through the Duplicate Address Detection (DAD) process ensuring that its link-local address (and associated IID) is unique on the LAN segment,
  1326. # it then proceeds to sending an ICMPv6 Router Solicitation (RS) message sourced from that address.
  1327. #
  1328. # There are total three IPv6 address ranges divided into local address: fe80::/10, fec0::/10, fc00::/7.
  1329. # "fe80::/10" is similar with "169.254.0.0/16" of IPv4 of February, 2006 according to RFC 4291, ranges from fe80:0000:0000:0000:0000:0000:0000:0000 to febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff.
  1330. # "fec0::/10" is similar with "192.168.0.0/16" of IPv4 which was deprecated and returned to public IPv6 address again of September, 2004 according to RFC 3879.
  1331. # The function of "fec0::/10" was replaced by "fc00::/7" of October, 2005 according to RFC 4193, ranges from fc00:0000:0000:0000:0000:0000:0000:0000 to fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff.
  1332. # So we need to calculate ranges of "fe80::/10" and "fc00::/7", if IPv6 address is public and IPv6 gateway belongs to local IPv6 address.
  1333. # English strings in hexadecimal must be converted as capital alphabets that comparison operations can be processed by shell.
  1334. # Reference: https://blogs.infoblox.com/ipv6-coe/fe80-1-is-a-perfectly-valid-ipv6-default-gateway-address/ chapter: Link-Local Address as Default Gateway
  1335. # https://www.wdic.org/w/WDIC/IPv6%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9 chapter: アドレスの種類(Types of address) → エニキャストアドレス(Anycast address)
  1336. # https://www.wdic.org/w/WDIC/IPv6%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9 chapter: サイトローカルアドレス(Site local address)
  1337. # https://www.wdic.org/w/WDIC/%E3%83%A6%E3%83%8B%E3%83%BC%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%83%A6%E3%83%8B%E3%82%AD%E3%83%A3%E3%82%B9%E3%83%88%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9
  1338. # https://www.ipentec.com/document/network-format-ipv6-local-adddress chapter: IPv6のリンクローカルアドレス(Link local address of IPv6)
  1339. # https://www.rfc-editor.org/rfc/rfc4291.html#section-2.4 chapter: 2.4. Address Type Identification
  1340. if [[ "$((16#$tmpIp6GateFirst))" -ge "$((16#FE80))" && "$((16#$tmpIp6GateFirst))" -le "$((16#FEBF))" ]] || [[ "$((16#$tmpIp6GateFirst))" -ge "$((16#FC00))" && "$((16#$tmpIp6GateFirst))" -le "$((16#FDFF))" ]]; then
  1341. tmpIp6Mask="64"
  1342. else
  1343. # If the IPv6 and IPv6 gateway are not in the same IPv6 A class, the prefix of netmask should be "1",
  1344. # transfer to whole IPv6 subnet address is 8000:0000:0000:0000:0000:0000:0000:0000.
  1345. # The range of 2603:c020:8:a19b::ffff:e6da/1 is 0000:0000:0000:0000:0000:0000:0000:0000 - 7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff, the gateway 2603:c020:0008:a19b:0000:0000:0000:ffff can be included.
  1346. tmpIp6Mask="1"
  1347. fi
  1348. else
  1349. ipv6SubnetCertificate "$ip6AddrWhole" "$ip6GateWhole"
  1350. fi
  1351. ip6Mask="$tmpIp6Mask"
  1352. # Because of function "ipv6SubnetCalc" includes self-increment,
  1353. # so we need to confirm the goal of IPv6 prefix and make function to operate only one time in the last to save performance and avoid all
  1354. # gears of IPv6 prefix which meets well with the conditions of above are transformed to whole IPv6 addresses in one variable.
  1355. # The same thought of moving function "netmask" to the last, only need to transform IPv4 prefix to whole IPv4 address for one time.
  1356. ipv6SubnetCalc "$ip6Mask"
  1357. # So in summary of the IPv6 sample in above, we should assign subnet mask "ffff:ffff:ffff:ffff:ffff:ffff:0000:0000"(prefix is "96") for it.
  1358. }
  1359. }
  1360. # $1 is "$ip6AddrWhole", $2 is "$$ip6GateWhole".
  1361. function ipv6SubnetCertificate() {
  1362. # If the IP and gateway are in the same IPv6 A class, not in the same IPv6 B class, the prefix of netmask should less equal than "16",
  1363. # transfer to whole IPv6 subnet address is ffff:0000:0000:0000:0000:0000:0000:0000.
  1364. # The range of 2603:c020:8:a19b::ffff:e6da/16 is 2603:0000:0000:0000:0000:0000:0000:0000 - 2603:ffff:ffff:ffff:ffff:ffff:ffff:ffff, the gateway 2603:... can be included.
  1365. [[ `echo $1 | cut -d':' -f 1` == `echo $2 | cut -d':' -f 1` ]] && tmpIp6Mask="16"
  1366. # If the IP and gateway are in the same IPv6 A B class, not in the same IPv6 C class, the prefix of netmask should less equal than "32",
  1367. # transfer to whole IPv6 subnet address is ffff:ffff:0000:0000:0000:0000:0000:0000.
  1368. # The range of 2603:c020:8:a19b::ffff:e6da/32 is 2603:c020:0000:0000:0000:0000:0000:0000 - 2603:c020:ffff:ffff:ffff:ffff:ffff:ffff, the gateway 2603:... can be included.
  1369. [[ `echo $1 | cut -d':' -f 1,2` == `echo $2 | cut -d':' -f 1,2` ]] && tmpIp6Mask="32"
  1370. # If the IP and gateway are in the same IPv6 A B C class, not in the same IPv6 D class, the prefix of netmask should less equal than "48",
  1371. # transfer to whole IPv6 subnet address is ffff:ffff:ffff:0000:0000:0000:0000:0000.
  1372. # The range of 2603:c020:8:a19b::ffff:e6da/48 is 2603:c020:0008:0000:0000:0000:0000:0000 - 2603:c020:0008:ffff:ffff:ffff:ffff:ffff, the gateway 2603:... can be included.
  1373. [[ `echo $1 | cut -d':' -f 1,2,3` == `echo $2 | cut -d':' -f 1,2,3` ]] && tmpIp6Mask="48"
  1374. # If the IP and gateway are in the same IPv6 A B C D class, not in the same IPv6 E class, the prefix of netmask should less equal than "64",
  1375. # transfer to whole IPv6 subnet address is ffff:ffff:ffff:ffff:0000:0000:0000:0000.
  1376. # The range of 2603:c020:8:a19b::ffff:e6da/64 is 2603:c020:0008:a19b:0000:0000:0000:0000 - 2603:c020:0008:a19b:ffff:ffff:ffff:ffff, the gateway 2603:... can be included.
  1377. [[ `echo $1 | cut -d':' -f 1,2,3,4` == `echo $2 | cut -d':' -f 1,2,3,4` ]] && tmpIp6Mask="64"
  1378. # If the IP and gateway are in the same IPv6 A B C D E class, not in the same IPv6 F class, the prefix of netmask should less equal than "80",
  1379. # transfer to whole IPv6 subnet address is ffff:ffff:ffff:ffff:ffff:0000:0000:0000.
  1380. # The range of 2603:c020:8:a19b::ffff:e6da/80 is 2603:c020:0008:a19b:0000:0000:0000:0000 - 2603:c020:0008:a19b:0000:ffff:ffff:ffff, the gateway 2603:... can be included.
  1381. [[ `echo $1 | cut -d':' -f 1,2,3,4,5` == `echo $2 | cut -d':' -f 1,2,3,4,5` ]] && tmpIp6Mask="80"
  1382. # If the IP and gateway are in the same IPv6 A B C D E F class, not in the same IPv6 G class, the prefix of netmask should less equal than "96",
  1383. # transfer to whole IPv6 subnet address is ffff:ffff:ffff:ffff:ffff:ffff:0000:0000.
  1384. # The range of 2603:c020:8:a19b::ffff:e6da/96 is 2603:c020:0008:a19b:0000:0000:0000:0000 - 2603:c020:0008:a19b:0000:0000:ffff:ffff, the gateway 2603:... can be included.
  1385. [[ `echo $1 | cut -d':' -f 1,2,3,4,5,6` == `echo $2 | cut -d':' -f 1,2,3,4,5,6` ]] && tmpIp6Mask="96"
  1386. # If the IP and gateway are in the same IPv6 A B C D E F G class, not in the same IPv6 H class, the prefix of netmask should less equal than "112",
  1387. # transfer to whole IPv6 subnet address is ffff:ffff:ffff:ffff:ffff:ffff:ffff:0000.
  1388. # The range of 2603:c020:8:a19b::ffff:e6da/112 is 2603:c020:0008:a19b:0000:0000:ffff:0000 - 2603:c020:0008:a19b:0000:0000:ffff:ffff, the gateway 2603:c020:0008:a19b:0000:0000:0000:ffff can't be included.
  1389. [[ `echo $1 | cut -d':' -f 1,2,3,4,5,6,7` == `echo $2 | cut -d':' -f 1,2,3,4,5,6,7` ]] && tmpIp6Mask="112"
  1390. }
  1391. # $1 is $ip6Mask
  1392. function ipv6SubnetCalc() {
  1393. tmpIp6Subnet=""
  1394. ip6Subnet=""
  1395. ip6SubnetEleNum=`expr $1 / 4`
  1396. ip6SubnetEleNumRemain=`expr $1 - $ip6SubnetEleNum \* 4`
  1397. if [[ "$ip6SubnetEleNumRemain" == 0 ]]; then
  1398. ip6SubnetHex="0"
  1399. elif [[ "$ip6SubnetEleNumRemain" == 1 ]]; then
  1400. ip6SubnetHex="8"
  1401. elif [[ "$ip6SubnetEleNumRemain" == 2 ]]; then
  1402. ip6SubnetHex="c"
  1403. elif [[ "$ip6SubnetEleNumRemain" == 3 ]]; then
  1404. ip6SubnetHex="e"
  1405. fi
  1406. for ((i=1; i<="$ip6SubnetEleNum"; i++)); do
  1407. tmpIp6Subnet+="f"
  1408. done
  1409. tmpIp6Subnet=$tmpIp6Subnet$ip6SubnetHex
  1410. for ((j=1; j<=`expr 32 - $ip6SubnetEleNum`; j++)); do
  1411. tmpIp6Subnet+="0"
  1412. done
  1413. if [[ `echo $tmpIp6Subnet | wc -c` -ge "33" ]]; then
  1414. tmpIp6Subnet=`echo $tmpIp6Subnet | sed 's/.$//'`
  1415. fi
  1416. for ((k=0; k<=7; k++)); do
  1417. ip6Subnet+=$(echo ${tmpIp6Subnet:`expr $k \* 4`:4})":"
  1418. done
  1419. ip6Subnet=`echo ${ip6Subnet%?}`
  1420. }
  1421. # $1 is "$i6AddrNum".
  1422. function collectAllIpv6Addresses() {
  1423. [[ "$1" -ge "2" && "$IPStackType" != "IPv4Stack" ]] && {
  1424. Network6Config="isStatic"
  1425. i6Addrs=()
  1426. for tmpIp6 in $allI6Addrs; do
  1427. # The best way to add several elements into an array by using "for" loop in the shell.
  1428. # Reference: https://linuxhandbook.com/bash-append-array/
  1429. i6Addrs[${#i6Addrs[@]}]=$tmpIp6
  1430. done
  1431. if [[ "$IPStackType" == "IPv6Stack" ]] || [[ "$IPStackType" == "BiStack" && -n "$interface4" && -n "$interface6" && "$interface4" != "$interface6" ]]; then
  1432. # A sample result of the following arrays which were programmed by "for" loops:
  1433. #
  1434. # ${i6Addrs[@]} : 2606:a8c0:3:6f::b/64 2606:a8c0:3:6f::a/64 2606:a8c0:3::64/128
  1435. # ${allI6AddrsWithoutSuffix[@]} : 2606:a8c0:3:6f::b 2606:a8c0:3:6f::a 2606:a8c0:3::64
  1436. # ${allI6AddrsWithUltimateFormat[@]} : 2606:a8c0:0003:006f:0000:0000:0000:000b 2606:a8c0:0003:006f:0000:0000:0000:000a 2606:a8c0:0003:0000:0000:0000:0000:0064
  1437. # ${allI6AddrsWithOmittedClassesNum[@]} : 3 3 4
  1438. # $omittedClassesMaxNum : 4
  1439. # $mainIp6Index : 2
  1440. # $i6Addr : 2606:a8c0:3::64/128
  1441. #
  1442. # To find out the segment with the largest range of one IPv6 in all of the IPv6s as default to config IPv6 network in netboot environment for machines of IPv6 stack.
  1443. allI6AddrsWithoutSuffix=()
  1444. for tmpIp6 in ${i6Addrs[@]}; do
  1445. tmpIp6=$(echo $tmpIp6 | cut -d'/' -f1)
  1446. allI6AddrsWithoutSuffix[${#allI6AddrsWithoutSuffix[@]}]=$tmpIp6
  1447. done
  1448. allI6AddrsWithUltimateFormat=()
  1449. for tmpIp6 in ${allI6AddrsWithoutSuffix[@]}; do
  1450. tmpIp6=$(ultimateFormatOfIpv6 "$tmpIp6")
  1451. allI6AddrsWithUltimateFormat[${#allI6AddrsWithUltimateFormat[@]}]=$tmpIp6
  1452. done
  1453. allI6AddrsWithOmittedClassesNum=()
  1454. for tmpIp6 in ${allI6AddrsWithUltimateFormat[@]}; do
  1455. tmpIp6=$(echo $tmpIp6 | grep -oi "0000" | wc -l)
  1456. allI6AddrsWithOmittedClassesNum[${#allI6AddrsWithOmittedClassesNum[@]}]=$tmpIp6
  1457. done
  1458. omittedClassesMaxNum=${allI6AddrsWithOmittedClassesNum[0]}
  1459. for tmpIp6 in ${!allI6AddrsWithOmittedClassesNum[@]}; do
  1460. if [[ "$omittedClassesMaxNum" -le "${allI6AddrsWithOmittedClassesNum[${tmpIp6}]}" ]]; then
  1461. omittedClassesMaxNum=${allI6AddrsWithOmittedClassesNum[${tmpIp6}]}
  1462. fi
  1463. done
  1464. getArrItemIdx "${allI6AddrsWithOmittedClassesNum[*]}" "$omittedClassesMaxNum"
  1465. mainIp6Index="$index"
  1466. i6Addr=${i6Addrs[$mainIp6Index]}
  1467. fi
  1468. }
  1469. }
  1470. # Debian installer can't accept any command that writing multi lines by one "sed -i" or "echo -e" etc in "preseed.cfg".
  1471. # For example, if we want to add two lines or more like "up ip addr add IPv6one/48 dev eth0" and "up ip addr add IPv6two/40 dev eth0" to "network file",
  1472. # using "sed -i '$a\\tup ip addr add IPv6one/48 dev eth0' 'network file';" and then "sed -i '$a\\tup ip addr add IPv6two/40 dev eth0' 'network file';" is necessary.
  1473. # Otherwise, if try to use "sed -i '$a\\tup ip addr add IPv6one/48 dev eth0\n\tup ip addr add IPv6two/40 dev eth0' 'network file';"
  1474. # to add two IPv6 addresses config lines in the same "sed -i", Debian installer will meet a fatal.
  1475. #
  1476. # An excellent method to add multiple IPv6 addresses and the IPv6 gateway of them in Bi-stack(dual-stack) network configuration file for Debian/Kali, here is the sample:
  1477. #
  1478. # allow-hotplug eth0
  1479. # iface eth0 inet static
  1480. # address 59.67.82.30
  1481. # gateway 59.67.82.1
  1482. # netmask 255.255.255.0
  1483. # dns-nameservers 1.0.0.1 8.8.4.4 2606:4700:4700::1001 2001:4860:4860::8844
  1484. # up ip addr add 2a12:a520:d420::736f/48 dev eth0
  1485. # up ip addr add 2a12:a520:2e0b::a89c:11de/40 dev eth0
  1486. # up ip -6 route add 2a12:a520:2e0b:0000:0000:0000:0000:0001 dev eth0
  1487. # up ip -6 route add default via 2a12:a520:2e0b:0000:0000:0000:0000:0001 dev eth0
  1488. #
  1489. # A standard format of adding multiple IPv6 configs into IPv6 stack server for Debian series:
  1490. #
  1491. # allow-hotplug enp3s0
  1492. # iface enp3s0 inet6 static
  1493. # address 2606:a8c0:3::64/128
  1494. # gateway 2606:a8c0:3::1
  1495. # dns-nameservers 2606:4700:4700::1001 2001:4860:4860::8844
  1496. # dns-search debian
  1497. # up ip addr add 2606:a8c0:3:6f::3b/64 dev enp3s0
  1498. # up ip addr add 2606:a8c0:3:6f::a/64 dev enp3s0
  1499. #
  1500. # A standard formart of adding multiple IPv6 addresses for the second network adapter in Bi-stack(dual-stack) server for Debian series:
  1501. # The first network adapter which is called such as "eth0" plays a role of establishing IPv4 stack network,
  1502. # and then the second network adapter of "eth1" is responsible of creating multiple terms of IPv6 stack networking configurations.
  1503. # This uncommon and extreme situation can only be applied for Debian series at current because the file of "/etc/network/interfaces" is easily to be modified.
  1504. #
  1505. # allow-hotplug eth0
  1506. # iface eth0 inet static
  1507. # address 104.36.84.237/32
  1508. # gateway 104.36.84.1
  1509. # dns-nameservers 1.0.0.1 8.8.4.4
  1510. #
  1511. # allow-hotplug eth1
  1512. # iface eth1 inet6 static
  1513. # address 2606:a8c0:3::64/128
  1514. # gateway 2606:a8c0:3::1
  1515. # dns-nameservers 2606:4700:4700::1001 2001:4860:4860::8844
  1516. # up ip -6 addr add 2606:a8c0:3:6f::2f/64 dev eth1
  1517. # up ip -6 addr add 2606:a8c0:3:6f::1c/64 dev eth1
  1518. #
  1519. # $1 is "$i6AddrNum", $2 is "in-target", $3 is 'netconfig file'.
  1520. function writeMultipleIpv6Addresses() {
  1521. [[ "$1" -ge "2" && "$IPStackType" != "IPv4Stack" ]] && {
  1522. # For environment of IPv6 stack, one main IPv6 config will be written to system by "preseed" or "kickstart" into the unattend file to config the network firstly.
  1523. # So the main IPv6 config should be excluded in the array of "i6Addrs[@]" for the later stage of writing other IPv6s to the network config file in the newly installed system.
  1524. if [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'kali' ]]; then
  1525. if [[ "$IPStackType" == "IPv6Stack" ]] || [[ "$IPStackType" == "BiStack" && -n "$interface4" && -n "$interface6" && "$interface4" != "$interface6" ]]; then
  1526. unset i6Addrs[$mainIp6Index]
  1527. fi
  1528. for writeIp6s in ${i6Addrs[@]}; do
  1529. [[ "$IPStackType" == "BiStack" && -n "$interface4" && -n "$interface6" && "$interface4" != "$interface6" ]] && ip6AddrItem="up ip -6 addr add $writeIp6s dev $interface6" || ip6AddrItem="up ip addr add $writeIp6s dev $interface6"
  1530. tmpWriteIp6sCmd+=''$2' sed -i '\''$a\\t'$ip6AddrItem''\'' '$3'; '
  1531. done
  1532. writeIp6sCmd=$(echo $tmpWriteIp6sCmd)
  1533. writeIp6GateCmd=''$2' sed -i '\''$a\\tup ip -6 route add '$ip6Gate' dev '$interface6''\'' '$3'; '$2' sed -i '\''$a\\tup ip -6 route add default via '$ip6Gate' dev '$interface6''\'' '$3';'
  1534. addIpv6DnsForPreseed=''$2' sed -ri '\''s/'$ipDNS'/'$ipDNS' '$ip6DNS'/g'\'' '$3';'
  1535. preferIpv6Access=''$2' sed -i '\''$alabel 2002::/16'\'' /etc/gai.conf; '$2' sed -i '\''$alabel 2001:0::/32'\'' /etc/gai.conf;'
  1536. SupportIPv6orIPv4=''$writeIp6sCmd' '$writeIp6GateCmd' '$addIpv6DnsForPreseed' '$preferIpv6Access''
  1537. [[ "$IPStackType" == "IPv6Stack" ]] && SupportIPv6orIPv4=''$writeIp6sCmd' '$preferIpv6Access''
  1538. [[ "$IPStackType" == "BiStack" && -n "$interface4" && -n "$interface6" && "$interface4" != "$interface6" ]] && {
  1539. addIpv6Adapter=''$2' sed -i '\''$a\ '\'' '$3'; '$2' sed -i '\''$aallow-hotplug '$interface6''\'' '$3';'
  1540. addFirstIpv6Config=''$2' sed -i '\''$aiface '$interface6' inet6 static'\'' '$3'; '$2' sed -i '\''$a\\taddress '$i6Addr''\'' '$3'; '$2' sed -i '\''$a\\tgateway '$ip6Gate''\'' '$3'; '$2' sed -i '\''$a\\tdns-nameservers '$ip6DNS''\'' '$3';'
  1541. SupportIPv6orIPv4=''$addIpv6Adapter' '$addFirstIpv6Config' '$writeIp6sCmd' '$preferIpv6Access''
  1542. }
  1543. elif [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]]; then
  1544. # The following strategy of adding multiple IPv6 addresses with subnet, gateway and DNS parameters is only suitable for
  1545. # Redhat series(9+, Fedora 30+) which are using "NetworkManager" to manage the configurations of the networking by default.
  1546. # The first IPv6 address will be written to the target system which has a native syntax support was provided by kickstart from Redhat,
  1547. # so we just need to add the second and more IPv6 addresses in the late command of the kickstart which area is involved from "%post" to "%end".
  1548. for (( tmpI6Index="0"; tmpI6Index<"$1"; tmpI6Index++ )); do
  1549. writeIp6s="${i6Addrs[$tmpI6Index]}"
  1550. ipv6AddressOrder=$(expr $tmpI6Index + 1)
  1551. ip6AddrItem+='address'$ipv6AddressOrder'='$writeIp6s','$ip6Gate'\n'
  1552. done
  1553. ip6AddrItems=''$ip6AddrItem''
  1554. addIpv6DnsForRedhat='dns='$ip6DNS1';'$ip6DNS2';'
  1555. addIpv6AddrsForRedhat='sed -i '\''/addr-gen-mode=eui64/a\'$ip6AddrItems''$addIpv6DnsForRedhat''\'' '$3''
  1556. setIpv6ConfigMethodForRedhat='sed -ri '\''s/method=auto/method=manual/g'\'' '$3''
  1557. [[ "$IPStackType" == "IPv6Stack" ]] && { ip6AddrItems=$(echo $ip6AddrItem | sed 's/..$//'); deleteOriginalIpv6Coning='sed -ri '\''/address1.*/d'\'' '$3''; addIpv6AddrsForRedhat='sed -i '\''/addr-gen-mode=eui64/a\'$ip6AddrItems''\'' '$3''; setIpv6ConfigMethodForRedhat=""; }
  1558. fi
  1559. }
  1560. }
  1561. # This function help us to sort sizes for different files from different directions.
  1562. # "$FilesDirArr" storages original absolute pathes of files.
  1563. # "$FilesLineArr" receives amount of alphabets and numbers etc. in one file from "$FilesDirNum"
  1564. # "$FilesDir" is the list of absolute files' pathes those are executed by command like "grep" etc.
  1565. # According to file size, "$tmpSizeArray" sorts "$FilesLineArr"'s numbers from smallest to largest(-sort h) or from largest to smallest(-sort hr).
  1566. # "$1" are direction of files, "$2" is sort method.
  1567. function sortFileSize() {
  1568. FilesDirArr=()
  1569. FilesLineArr=()
  1570. FilesDir="$1"
  1571. for Count in $FilesDir; do
  1572. FilesDirArr+=($Count)
  1573. FilesDirNum=`cat $Count | wc -c`
  1574. FilesLineArr+=($FilesDirNum)
  1575. done
  1576. tmpSizeArray=(`echo ${FilesLineArr[*]} | tr ' ' '\n' | $2`)
  1577. }
  1578. # This function may help us to find the index order in one array if we provide a random data in this array.
  1579. # "$1" is one array like "${FilesLineArr[*]}", "$2" is one element which index of this array needs to be found like "${tmpSizeArray[0]}"
  1580. function getArrItemIdx() {
  1581. arr=$1
  1582. item=$2
  1583. index=0
  1584. for i in ${arr[*]}; do
  1585. [[ $item == $i ]] && {
  1586. echo $index >>/dev/null 2>&1
  1587. return
  1588. }
  1589. index=$(( $index + 1 ))
  1590. done
  1591. }
  1592. # "$1" is the absolute path of a file.
  1593. function splitDirAndFile() {
  1594. FileName=`echo $1 | awk -F/ '{print $NF}'`
  1595. FileDirection=`echo $1 | sed "s/$FileName//g"`
  1596. }
  1597. # In Debian 11 OS template of DigitalOcean, there are 5 directions deposing network configurations after filtered by command of "find" and "grep":
  1598. # /run/network/interfaces.d/eth0 31 bytes
  1599. # /run/network/interfaces.d/eth1 31 bytes
  1600. # /etc/network/interfaces 755 bytes
  1601. # /etc/network/interfaces.d/50-cloud-init 716 bytes
  1602. # /etc/network/cloud-interfaces-template 39 bytes
  1603. # We should get help by some algorithms to select the largest size of the file, the correct network configuration, "/etc/network/interfaces" is just there.
  1604. #
  1605. # "$1" is an array which storages temp files. "$2" is sort method, "sort -hr" is largest, "sort -h" is smallest.
  1606. function getLargestOrSmallestFile() {
  1607. for Count in "$1"; do
  1608. sortFileSize "$Count" "$2"
  1609. getArrItemIdx "${FilesLineArr[*]}" "${tmpSizeArray[0]}"
  1610. fullFilePath="${FilesDirArr[$index]}"
  1611. [[ "$fullFilePath" != "" ]] && {
  1612. splitDirAndFile "$fullFilePath"
  1613. break
  1614. }
  1615. done
  1616. }
  1617. # A function about parsing "*.yaml" files by native bash.
  1618. # Reference: https://stackoverflow.com/questions/5014632/how-can-i-parse-a-yaml-file-from-a-linux-shell-script
  1619. function parseYaml() {
  1620. prefix=$2
  1621. s='[[:space:]]*' w='[a-zA-Z0-9_]*'
  1622. fs=$(echo @|tr @ '\034')
  1623. sed -ne "s|,$s\]$s\$|]|" \
  1624. -e ":1;s|^\($s\)\($w\)$s:$s\[$s\(.*\)$s,$s\(.*\)$s\]|\1\2: [\3]\n\1 - \4|;t1" \
  1625. -e "s|^\($s\)\($w\)$s:$s\[$s\(.*\)$s\]|\1\2:\n\1 - \3|;p" $1 | \
  1626. sed -ne "s|,$s}$s\$|}|" \
  1627. -e ":1;s|^\($s\)-$s{$s\(.*\)$s,$s\($w\)$s:$s\(.*\)$s}|\1- {\2}\n\1 \3: \4|;t1" \
  1628. -e "s|^\($s\)-$s{$s\(.*\)$s}|\1-\n\1 \2|;p" | \
  1629. sed -ne "s|^\($s\):|\1|" \
  1630. -e "s|^\($s\)-$s[\"']\(.*\)[\"']$s\$|\1$fs$fs\2|p" \
  1631. -e "s|^\($s\)-$s\(.*\)$s\$|\1$fs$fs\2|p" \
  1632. -e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p" \
  1633. -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" | \
  1634. awk -F$fs '{
  1635. indent=length($1)/2
  1636. vname[indent]=$2
  1637. for (i in vname) {if (i>indent) {delete vname[i]; idx[i]=0}}
  1638. if (length($2)==0) {vname[indent]= ++idx[indent]}
  1639. if (length($3)>0) {
  1640. vn=""
  1641. for (i=0;i<indent;i++) {vn=(vn)(vname[i])("_")}
  1642. printf("%s%s%s=\"%s\"\n","'$prefix'",vn,vname[indent],$3)
  1643. }
  1644. }'
  1645. }
  1646. # $1 is $CurrentOS
  1647. function getInterface() {
  1648. # Network config file for Ubuntu 16.04 and former version,
  1649. # Debian all version included the latest Debian 11 is deposited in /etc/network/interfaces, they managed by "ifupdown".
  1650. # Ubuntu 18.04 and later version, using netplan to replace legacy ifupdown, the network config file is in /etc/netplan/
  1651. interface=""
  1652. Interfaces=`cat /proc/net/dev |grep ':' | cut -d':' -f1 | sed 's/\s//g' | grep -iv '^lo\|^sit\|^stf\|^gif\|^dummy\|^vmnet\|^vir\|^gre\|^ipip\|^ppp\|^bond\|^tun\|^tap\|^ip6gre\|^ip6tnl\|^teql\|^ocserv\|^vpn'`
  1653. # Some server has two different network adapters and for example: eth0 is for IPv4, eth1 is for IPv6, so we need to distinguish whether they are the same.
  1654. default4Route=`ip -4 route show default | grep "^default"`
  1655. # In Vultr server of 2.5$/mo plan, it has only IPv6 address, so the default route is via IPv6.
  1656. default6Route=`ip -6 route show default | grep "^default"`
  1657. for item in `echo "$Interfaces"`; do
  1658. [ -n "$item" ] || continue
  1659. echo "$default4Route" | grep -q "$item"
  1660. [ $? -eq 0 ] && interface4="$item" && break
  1661. done
  1662. for item in `echo "$Interfaces"`; do
  1663. [ -n "$item" ] || continue
  1664. echo "$default6Route" | grep -q "$item"
  1665. [ $? -eq 0 ] && interface6="$item" && break
  1666. done
  1667. interface="$interface4 $interface6"
  1668. [[ "$interface4" == "$interface6" ]] && interface=`echo "$interface" | cut -d' ' -f 1`
  1669. [[ -z "$interface4" || -z "$interface6" ]] && {
  1670. interface=`echo "$interface" | sed 's/[[:space:]]//g'`
  1671. [[ -z "$interface4" ]] && interface4="$interface"
  1672. [[ -z "$interface6" ]] && interface6="$interface"
  1673. }
  1674. echo "$interface" > /dev/null
  1675. # Some templates of cloud provider like Bandwagonhosts, Ubuntu 22.04, may modify parameters in " GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0" " in /etc/default/grub
  1676. # to make Linux kernel redirect names of network adapters from real name like ens18, ens3, enp0s4 to eth0, eth1, eth2...
  1677. # This setting may confuse program to get real adapter name from reading /proc/cat/dev
  1678. GrubCmdLine=`grep "GRUB_CMDLINE_LINUX" /etc/default/grub | grep -v "#" | grep "net.ifnames=0\|biosdevname=0"`
  1679. # So we need to comfirm whether adapter name is renamed and whether we should inherit it into new system.
  1680. if [[ -n "$GrubCmdLine" && -z "$interfaceSelect" ]] || [[ "$interface4" == "eth0" ]] || [[ "$interface6" == "eth0" ]]|| [[ "$linux_relese" == 'kali' ]] || [[ "$linux_relese" == 'alpinelinux' ]]; then
  1681. setInterfaceName='1'
  1682. fi
  1683. if [[ "$1" == 'CentOS' || "$1" == 'AlmaLinux' || "$1" == 'RockyLinux' || "$1" == 'Fedora' || "$1" == 'Vzlinux' || "$1" == 'OracleLinux' || "$1" == 'OpenCloudOS' || "$1" == 'AlibabaCloudLinux' || "$1" == 'ScientificLinux' || "$1" == 'AmazonLinux' || "$1" == 'RedHatEnterpriseLinux' || "$1" == 'OpenAnolis' || "$1" == 'CloudLinux' ]]; then
  1684. [[ ! $(find / -maxdepth 5 -path /*network-scripts -type d -print -or -path /*system-connections -type d -print) ]] && {
  1685. echo -ne "\n[${red}Error${plain}] Invalid network configuration!\n"
  1686. exit 1
  1687. }
  1688. NetCfgWhole=()
  1689. tmpNetCfgFiles=""
  1690. for Count in $(find / -maxdepth 5 -path /*network-scripts -type d -print -or -path /*system-connections -type d -print); do
  1691. NetCfgDir="$Count""/"
  1692. # If "NetworkManager" replaced "network-scripts", there is a file called "readme-ifcfg-rh.txt" in dir: /etc/sysconfig/network-scripts/
  1693. # NetCfgFile=`ls -Sl $NetCfgDir 2>/dev/null | awk -F' ' '{print $NF}' | grep -iv 'lo\|sit\|stf\|gif\|dummy\|vmnet\|vir\|gre\|ipip\|ppp\|bond\|tun\|tap\|ip6gre\|ip6tnl\|teql\|ocserv\|vpn\|readme' | grep -s "$interface" | head -n 1`
  1694. # Condition of "grep -iv 'lo\|sit\|stf..." has been deperated because the config file name of "NetworkManager" which initiated by "cloud init" is like "cloud-init-eth0.nmconnection".
  1695. # Different from command "grep", command "ls" can only show file name but not full file direction.
  1696. # There are 3 files named "ifcfg-ens18 ifcfg-eth0 ifcfg-eth1" in dir "/etc/sysconfig/network-scripts/" of Almalinux 8 of Bandwagonhosts template.
  1697. # We should select the correct one by adjust whether includes interface name and file size.
  1698. # Files in "/etc/sysconfig/network-scripts/", reference: https://zetawiki.com/wiki/%EB%B6%84%EB%A5%98:/etc/sysconfig/network-scripts
  1699. NetCfgFiles=`ls -Sl $NetCfgDir 2>/dev/null | awk -F' ' '{print $NF}' | grep -iv 'readme\|ifcfg-lo\|ifcfg-bond\|ifup\|ifdown\|vpn\|init.ipv6-global\|network-functions' | grep -s "ifcfg\|nmconnection"`
  1700. for Files in $NetCfgFiles; do
  1701. if [[ `grep -w "$interface4\|$interface6" "$NetCfgDir$Files"` != "" ]]; then
  1702. tmpNetCfgFiles+=$(echo -e "\n""$NetCfgDir$Files")
  1703. fi
  1704. done
  1705. getLargestOrSmallestFile "$tmpNetCfgFiles" "sort -hr"
  1706. NetCfgFile="$FileName"
  1707. # In Google Cloud Platform, network configuration files of Redhat Enterprise 8+, CentOS-stream 8+, RockyLinux 8+ are all named " 'Wired connection 1.nmconnection' " in "/run/NetworkManager/system-connections/" direction.
  1708. # Yes, that's right, the name of this file includes spaces and two single quotes which are in the first and last.
  1709. # Only command "ls" can show the whole file name:
  1710. #
  1711. # [root@instance-2 ~]# ls -l /run/NetworkManager/system-connections/
  1712. # total 4
  1713. # -rw-------. 1 root root 270 May 4 22:15 'Wired connection 1.nmconnection'
  1714. #
  1715. # Many commands in linux can't handle these son of bitches because single quote is a strong reference so that the strings between two single quotes can't be any parameters.
  1716. # The most typical case is when you search these fuckin files by "grub", the result deleted two single quotes automatically like:
  1717. #
  1718. # [root@instance-2 ~]# grep -r "ipv4" /run/NetworkManager/system-connections/
  1719. # /run/NetworkManager/system-connections/Wired connection 1.nmconnection:[ipv4]
  1720. #
  1721. # When we try to use command "head" and "tail" to be pipeline items after the first command "ls", the result is also the same:
  1722. #
  1723. # [root@instance-2 ~]# ls /run/NetworkManager/system-connections/ | head -n 1 | tail -n 1
  1724. # Wired connection 1.nmconnection
  1725. #
  1726. # A file name includes space is very dangerous in linux because the operating system will use a couple of single quotes to bundle it as a "not be referenced" file to prevent os identify them error.
  1727. # No matter what command you choice, unless attach its' absolute direction and execute it with other commands directly in the shell, it can work correctly, otherwise you wanna be cried when handle them by parameters transactions.
  1728. # We should use "grep" to extract which key words we need and print the result to another file.
  1729. # If this universe has hell, those jackass who deployed these tortured settings of OS templates works on Google Cloud Platform will go to there when they died.
  1730. if [[ ! -z "$NetCfgFile" && ! -f "$NetCfgDir$NetCfgFile" ]]; then
  1731. tmpNetcfgDir="/root/tmp/installNetcfgCollections/"
  1732. [[ ! -d "$tmpNetcfgDir" ]] && mkdir -p "$tmpNetcfgDir"
  1733. if [[ "$NetCfgFile" =~ "nmconnection" ]]; then
  1734. NetCfgFile="$interface.nmconnection"
  1735. grep -wr "$interface\|\[ipv4\]\|\[ipv6\]\|\[connection\]\|\[ethernet\]\|id=*\|interface-name=*\|type=*\|method=*" "$NetCfgDir" | cut -d ':' -f 2 | tee -a "$tmpNetcfgDir$NetCfgFile"
  1736. NetCfgDir="$tmpNetcfgDir"
  1737. elif [[ "$NetCfgFile" =~ "ifcfg" ]]; then
  1738. NetCfgFile="$ifcfg-$interface"
  1739. grep -wr "$interface\|BOOTPROTO=*\|DEVICE=*\|ONBOOT=*\|TYPE=*\|HWADDR=*\|IPV6_AUTOCONF=*\|DHCPV6C=*" "$NetCfgDir" | cut -d ':' -f 2 | tee -a "$tmpNetcfgDir$NetCfgFile"
  1740. NetCfgDir="$tmpNetcfgDir"
  1741. fi
  1742. fi
  1743. # The following conditions must appeared at least 3 times in a vaild network config file.
  1744. [[ `grep -wcs "$interface4\|$interface6\|BOOTPROTO=*\|DEVICE=*\|ONBOOT=*\|TYPE=*\|HWADDR=*\|id=*\|\[connection\]\|interface-name=*\|type=*\|method=*" $NetCfgDir$NetCfgFile` -ge "3" ]] && {
  1745. # In AlmaLinux 9 template of DigitalOcean, network adapter name is "eth0", there are two network config files in the OS, and they all belong to "eth0".
  1746. # /etc/sysconfig/network-scripts/ifcfg-eth0
  1747. # /etc/NetworkManager/system-connections/eth0.nmconnection
  1748. # Which is the vaild one? We can storage them to one array first.
  1749. NetCfgWhole+=("$NetCfgDir$NetCfgFile")
  1750. }
  1751. done
  1752. # If index "1"(starts in "0") is not empty, it means there at least two network config files in current OS.
  1753. if [[ "${NetCfgWhole[1]}" != "" ]]; then
  1754. for c in "${NetCfgWhole[@]}"; do
  1755. # Cloud providers usually use automatic tools like SolusVM or Cloud-init etc. to initial different Linux OS.
  1756. # The first row of the network config files is showed like the following example regularly:
  1757. # # Generated by SolusVM
  1758. # # Created by cloud-init on instance boot automatically, do not edit.
  1759. # So the "#" and preposition "(did something) by (who)" is a obvious hint to help us to distinguish:
  1760. [[ `sed -e "4"p "$c" | grep " by " | grep -c "#"` -ge "1" ]] && {
  1761. NetCfgWhole="$c"
  1762. break
  1763. }
  1764. done
  1765. # If the array of "${NetCfgWhole}" doesn't be turned into a parameter, it means there are not any annotates generated by automatic tools.
  1766. # We need to import command "declare" to make an inspection to comfirm whether it's an array or a parameter,
  1767. # If it's still an arrary, we can only assume the index "0" in this array as the valid network config file.
  1768. [[ `declare -p NetCfgWhole 2>/dev/null | grep -iw '^declare -a'` ]] && {
  1769. NetCfgWhole="${NetCfgWhole[0]}"
  1770. }
  1771. fi
  1772. splitDirAndFile "$NetCfgWhole"
  1773. NetCfgFile="$FileName"
  1774. NetCfgDir="$FileDirection"
  1775. else
  1776. readNetplan=$(find $(echo `find / -maxdepth 4 -path /*netplan`) -maxdepth 1 -name "*.yaml" -print)
  1777. readIfupdown=$(find / -maxdepth 5 -path /*network -type d -print | grep -v "lib\|systemd")
  1778. if [[ ! -z "$readNetplan" ]]; then
  1779. # Ubuntu 18+ network configuration
  1780. networkManagerType="netplan"
  1781. tmpNetCfgFiles=""
  1782. for Count in $readNetplan; do
  1783. tmpNetCfgFiles+=$(echo -e "\n"`grep -wrl "network" | grep -wrl "ethernets" | grep -wrl "$interface4\|$interface6" | grep -wrl "version" "$Count" 2>/dev/null`)
  1784. done
  1785. getLargestOrSmallestFile "$tmpNetCfgFiles" "sort -hr"
  1786. NetCfgFile="$FileName"
  1787. NetCfgDir="$FileDirection"
  1788. NetCfgWhole="$NetCfgDir$NetCfgFile"
  1789. elif [[ ! -z "$readIfupdown" ]]; then
  1790. # Debian/Kali/AlpineLinux network configuration
  1791. # Some versions of Ubuntu 18 like virmach template use ifupdown not netplan.
  1792. networkManagerType="ifupdown"
  1793. # Collect all eligible config files by the several parent directions names "network".
  1794. # Reference: https://wiki.debian.org/NetworkConfiguration
  1795. # https://wiki.debian.org/IPv6PrefixDelegation
  1796. tmpNetCfgFiles=""
  1797. for Count in $readIfupdown; do
  1798. if [[ "$IPStackType" == "IPv4Stack" ]]; then
  1799. NetCfgFiles=`grep -wrl 'iface' | grep -wrl "auto\|dhcp\|static\|manual" | grep -wrl 'inet\|ip addr\|ip route' "$Count""/" 2>/dev/null | grep -v "if-*" | grep -v "state" | grep -v "helper" | grep -v "template"`
  1800. elif [[ "$IPStackType" == "BiStack" ]] || [[ "$IPStackType" == "IPv6Stack" ]]; then
  1801. NetCfgFiles=`grep -wrl 'iface' | grep -wrl "auto\|dhcp\|static\|manual" | grep -wrl 'inet\|ip addr\|ip route\|inet6\|ip -6' "$Count""/" 2>/dev/null | grep -v "if-*" | grep -v "state" | grep -v "helper" | grep -v "template"`
  1802. fi
  1803. for Files in $NetCfgFiles; do
  1804. if [[ `grep -w "$interface4\|$interface6" "$Files"` != "" ]]; then
  1805. tmpNetCfgFiles+=$(echo -e "\n""$Files")
  1806. fi
  1807. done
  1808. done
  1809. getLargestOrSmallestFile "$tmpNetCfgFiles" "sort -hr"
  1810. NetCfgFile="$FileName"
  1811. NetCfgDir="$FileDirection"
  1812. NetCfgWhole="$NetCfgDir$NetCfgFile"
  1813. else
  1814. echo -ne "\n[${red}Error${plain}] Invalid network configuration!\n"
  1815. exit 1
  1816. fi
  1817. fi
  1818. }
  1819. # $1 is "$ipMask", $2 is "$ip6Mask". Can only accept prefix number transmit.
  1820. function acceptIPv4AndIPv6SubnetValue() {
  1821. [[ -n "$1" ]] && {
  1822. if [[ `echo "$1" | grep '^[[:digit:]]*$'` && "$1" -ge "1" && "$1" -le "32" ]]; then
  1823. ipPrefix="$1"
  1824. actualIp4Prefix="$ipPrefix"
  1825. ipMask=`netmask "$1"`
  1826. actualIp4Subnet=`netmask "$1"`
  1827. else
  1828. echo -ne "\n[${red}Warning${plain}] Only accept prefix format of IPv4 address, length from 1 to 32."
  1829. echo -ne "\nIPv4 CIDR Calculator: https://www.vultr.com/resources/subnet-calculator/\n"
  1830. exit 1
  1831. fi
  1832. }
  1833. [[ -n "$2" ]] && {
  1834. if [[ `echo "$2" | grep '^[[:digit:]]*$'` && "$2" -ge "1" && "$2" -le "128" ]]; then
  1835. actualIp6Prefix="$2"
  1836. ipv6SubnetCalc "$2"
  1837. else
  1838. echo -ne "\n[${red}Warning${plain}] Only accept prefix format of IPv6 address, length from 1 to 128."
  1839. echo -ne "\nIPv6 CIDR Calculator: https://en.rakko.tools/tools/27/\n"
  1840. exit 1
  1841. fi
  1842. }
  1843. }
  1844. # To confuse whether ipv4 is dhcp or static and whether ipv6 is dhcp or static in Redhat like os in version 9 and later,
  1845. # $1 is $NetCfgDir, $2 is $NetCfgFile, $3 is "ipv4" or "ipv6", $4 is "method="
  1846. function checkIpv4OrIpv6ConfigForRedhat9Later() {
  1847. IpTypeLine="`awk '/\['$3'\]/{print NR}' $1/$2 | head -n 2 | tail -n 1`"
  1848. ConnectTypeArray=()
  1849. CtaSpace=()
  1850. for tmpConnectType in `awk '/'$4'/{print NR}' $1/$2`; do
  1851. ConnectTypeArray+=("$tmpConnectType" "$ConnectTypeArray")
  1852. [[ `expr $tmpConnectType - $IpTypeLine` -gt "0" ]] && CtaSpace+=(`expr "$tmpConnectType" - "$IpTypeLine"` "$CtaSpace")
  1853. done
  1854. minArray=${CtaSpace[0]}
  1855. for ((i=1;i<=`grep -io "$4" $1/$2 | wc -l`;i++)); do
  1856. for j in ${CtaSpace[@]}; do
  1857. [[ "$minArray" -gt "$j" ]] && minArray=$j
  1858. done
  1859. done
  1860. NetCfgLineNum=`expr $minArray + $IpTypeLine`
  1861. }
  1862. # For those IPv6 only servers which Redhat series OS are need to be installed in environment of anaconda,
  1863. # we need to assign a valid IPv6 config in grub so that "install.img" can be loaded.
  1864. # Reference: https://www.golinuxcloud.com/ipv6-uefi-pxe-boot-kickstart-rhel-centos-8/#Step-8_Configure_grubcfg_Dracut_Kernel_Menu
  1865. # https://binaryfury.wann.net/2016/03/installing-centos-7-on-an-ipv6-only-system/
  1866. function ipv6ForRedhatGrub() {
  1867. if [[ "$IPStackType" == "IPv6Stack" ]]; then
  1868. ipv6NameserverForKsGrub="nameserver=$ip6DNS1 nameserver=$ip6DNS2"
  1869. if [[ "$Network6Config" == "isStatic" ]]; then
  1870. ipv6StaticConfForKsGrub="noipv4 ip=[$ip6Addr]::[$ip6Gate]:$actualIp6Prefix::$interface:none $ipv6NameserverForKsGrub"
  1871. else
  1872. ipv6StaticConfForKsGrub="noipv4 $ipv6NameserverForKsGrub"
  1873. fi
  1874. fi
  1875. }
  1876. # If original system using DHCP, skip IP address, subnet mask, gateway, DNS server settings manually.
  1877. # In many DHCP servers, manual settings may cause some additional problems.
  1878. # For example, in Hetzner's machine, the network configuration of official template is DHCP for IPv4, STATIC for IPv6,
  1879. # If we config both IPv4 and IPv6 as STATIC, IPv4 network will failure, even though according to the bullshit network config guide which provided by Hetzner:
  1880. # https://docs.hetzner.com/cloud/servers/static-configuration/
  1881. # So we need to distinguish whether IPv4 is DHCP or STATIC and whether IPv6 is DHCP or STATIC separately and clearly.
  1882. # $1 is $CurrentOS, $2 is $CurrentOSVer, $3 is $IPStackType
  1883. function checkDHCP() {
  1884. getInterface "$1"
  1885. if [[ "$1" == 'CentOS' || "$1" == 'AlmaLinux' || "$1" == 'RockyLinux' || "$1" == 'Fedora' || "$1" == 'Vzlinux' || "$1" == 'OracleLinux' || "$1" == 'OpenCloudOS' || "$1" == 'AlibabaCloudLinux' || "$1" == 'ScientificLinux' || "$1" == 'AmazonLinux' || "$1" == 'RedHatEnterpriseLinux' || "$1" == 'OpenAnolis' || "$1" == 'CloudLinux' ]]; then
  1886. # RedHat like linux system 8 and before network config name is "ifcfg-interface", deposited in /etc/sysconfig/network-scripts/
  1887. # RedHat like linux system 9 and later network config name is "interface.nmconnection", deposited in /etc/NetworkManager/system-connections/
  1888. # In some templates like RockyLinux 9 x64 of DigitalOcean, both "/etc/sysconfig/network-scripts/ifcfg-eth0" and "/etc/NetworkManager/system-connections/ens3.nmconnection" are existed.
  1889. # in "ifcfg-eth0", BOOTPROTO=none; in "ens3.nmconnection", [ipv4] method=auto. the actually network adapter is "eth0", so the vaild network config file name is "ifcfg-eth0".
  1890. # So we need to check the type of the network configuration file to determine whether the method of config is dhcp or static.
  1891. if [[ "$NetCfgFile" =~ "ifcfg" ]]; then
  1892. # "BOOTPROTO=dhcp" is for IPv4 DHCP, "=none" or "=static" is Static.
  1893. # "IPv6_AUTOCONf=yes" or "DHCPV6C=yes" is IPv6 DHCP, "=no" is IPv6 Static.
  1894. # For IPv6 STATIC configuration, "IPv6_AUTOCONf=no" or "DHCPV6C=no" doesn't exist is allowed.
  1895. # For IPv6 DHCP configuration, "IPv6_AUTOCONf=yes" or "DHCPV6C=yes" is necessary.
  1896. # Reference: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/s1-networkscripts-interfaces
  1897. if [[ "$3" == "IPv4Stack" ]]; then
  1898. Network6Config="isDHCP"
  1899. [[ -n `grep -Ewirn "BOOTPROTO=none|BOOTPROTO=\"none\"|BOOTPROTO=\'none\'|BOOTPROTO=NONE|BOOTPROTO=\"NONE\"|BOOTPROTO=\'NONE\'|BOOTPROTO=static|BOOTPROTO=\"static\"|BOOTPROTO=\'static\'|BOOTPROTO=STATIC|BOOTPROTO=\"STATIC\"|BOOTPROTO=\'STATIC\'" $NetCfgWhole` ]] && Network4Config="isStatic" || Network4Config="isDHCP"
  1900. elif [[ "$3" == "BiStack" ]]; then
  1901. [[ -n `grep -Ewirn "BOOTPROTO=none|BOOTPROTO=\"none\"|BOOTPROTO=\'none\'|BOOTPROTO=NONE|BOOTPROTO=\"NONE\"|BOOTPROTO=\'NONE\'|BOOTPROTO=static|BOOTPROTO=\"static\"|BOOTPROTO=\'static\'|BOOTPROTO=STATIC|BOOTPROTO=\"STATIC\"|BOOTPROTO=\'STATIC\'" $NetCfgWhole` ]] && Network4Config="isStatic" || Network4Config="isDHCP"
  1902. [[ -n `grep -Ewirn "IPV6_AUTOCONF=yes|IPV6_AUTOCONF=\"yes\"|IPV6_AUTOCONF=YES|IPV6_AUTOCONF=\"YES\"|DHCPV6C=yes|DHCPV6C=\"yes\"" $NetCfgWhole` ]] && Network6Config="isDHCP" || Network6Config="isStatic"
  1903. elif [[ "$3" == "IPv6Stack" ]]; then
  1904. Network4Config="isDHCP"
  1905. [[ -n `grep -Ewirn "IPV6_AUTOCONF=yes|IPV6_AUTOCONF=\"yes\"|IPV6_AUTOCONF=YES|IPV6_AUTOCONF=\"YES\"|DHCPV6C=yes|DHCPV6C=\"yes\"" $NetCfgWhole` ]] && Network6Config="isDHCP" || Network6Config="isStatic"
  1906. fi
  1907. elif [[ "$NetCfgFile" =~ "nmconnection" ]]; then
  1908. # In NetworkManager for Redhat 9 and later, IPv4 and IPv6 share the same config method and value like the following sample:
  1909. #
  1910. # [ethernet]
  1911. #
  1912. # [ipv4]
  1913. # method=auto
  1914. #
  1915. # [ipv6]
  1916. # addr-gen-mode=eui64
  1917. # method=auto
  1918. #
  1919. # So we need to import the function "checkIpv4OrIpv6ConfigForRedhat9Later" to confuse.
  1920. # which "method=auto or manual" is belonged to [ipv4], which "method=auto or manual" is belonged to [ipv6].
  1921. checkIpv4OrIpv6ConfigForRedhat9Later "$NetCfgDir" "$NetCfgFile" "ipv4" "method="
  1922. NetCfg4LineNum="$NetCfgLineNum"
  1923. checkIpv4OrIpv6ConfigForRedhat9Later "$NetCfgDir" "$NetCfgFile" "ipv6" "method="
  1924. NetCfg6LineNum="$NetCfgLineNum"
  1925. if [[ "$3" == "IPv4Stack" ]]; then
  1926. Network6Config="isDHCP"
  1927. [[ `sed -n "$NetCfg4LineNum"p $NetCfgWhole` == "method=auto" ]] && Network4Config="isDHCP" || Network4Config="isStatic"
  1928. elif [[ "$3" == "BiStack" ]]; then
  1929. [[ `sed -n "$NetCfg4LineNum"p $NetCfgWhole` == "method=auto" ]] && Network4Config="isDHCP" || Network4Config="isStatic"
  1930. [[ `sed -n "$NetCfg6LineNum"p $NetCfgWhole` == "method=auto" ]] && Network6Config="isDHCP" || Network6Config="isStatic"
  1931. elif [[ "$3" == "IPv6Stack" ]]; then
  1932. Network4Config="isDHCP"
  1933. [[ `sed -n "$NetCfg6LineNum"p $NetCfgWhole` == "method=auto" ]] && Network6Config="isDHCP" || Network6Config="isStatic"
  1934. fi
  1935. fi
  1936. elif [[ "$1" == 'Debian' ]] || [[ "$1" == 'Kali' ]] || [[ "$1" == 'Ubuntu' && "$networkManagerType" == "ifupdown" ]] || [[ "$1" == 'AlpineLinux' ]]; then
  1937. # Debian network configs may be deposited in the following directions.
  1938. # /etc/network/interfaces or /etc/network/interfaces.d/interface or /run/network/interfaces.d/interface
  1939. if [[ "$3" == "IPv4Stack" ]]; then
  1940. Network6Config="isDHCP"
  1941. [[ `grep -iw "iface" $NetCfgWhole | grep -iw "$interface4" | grep -iw "inet" | grep -ic "auto\|dhcp"` -ge "1" ]] && Network4Config="isDHCP" || Network4Config="isStatic"
  1942. elif [[ "$3" == "BiStack" ]]; then
  1943. [[ `grep -iw "iface" $NetCfgWhole | grep -iw "$interface4" | grep -iw "inet" | grep -ic "auto\|dhcp"` -ge "1" ]] && Network4Config="isDHCP" || Network4Config="isStatic"
  1944. [[ `grep -iw "iface" $NetCfgWhole | grep -iw "$interface6" | grep -iw "inet6" | grep -ic "auto\|dhcp"` -ge "1" ]] && Network6Config="isDHCP" || Network6Config="isStatic"
  1945. elif [[ "$3" == "IPv6Stack" ]]; then
  1946. Network4Config="isDHCP"
  1947. [[ `grep -iw "iface" $NetCfgWhole | grep -iw "$interface6" | grep -iw "inet6" | grep -ic "auto\|dhcp"` -ge "1" ]] && Network6Config="isDHCP" || Network6Config="isStatic"
  1948. fi
  1949. elif [[ "$1" == 'Ubuntu' && "$networkManagerType" == "netplan" ]]; then
  1950. # For netplan(Ubuntu 18 and later), if network configuration is Static whether IPv4 or IPv6.
  1951. # in "*.yaml" config file, dhcp(4 or 6): no or false doesn't exist is allowed.
  1952. # But if is DHCP, dhcp(4 or 6): yes or true is necessary.
  1953. # Typical format of dhcp status in "*.yaml" is "dhcp4/6: true/false" or "dhcp4/6: yes/no".
  1954. # The raw sample processed by function "parseYaml" is: " network_ethernets_enp1s0_dhcp4="true" network_ethernets_enp1s0_dhcp6="true" ".
  1955. dhcpStatus=$(parseYaml "$NetCfgWhole" | grep "$interface" | grep "dhcp")
  1956. if [[ "$3" == "IPv4Stack" ]]; then
  1957. Network6Config="isDHCP"
  1958. [[ "$dhcpStatus" =~ "dhcp4=\"true\"" || "$dhcpStatus" =~ "dhcp4=\"yes\"" ]] && Network4Config="isDHCP" || Network4Config="isStatic"
  1959. elif [[ "$3" == "BiStack" ]]; then
  1960. [[ "$dhcpStatus" =~ "dhcp4=\"true\"" || "$dhcpStatus" =~ "dhcp4=\"yes\"" ]] && Network4Config="isDHCP" || Network4Config="isStatic"
  1961. [[ "$dhcpStatus" =~ "dhcp6=\"true\"" || "$dhcpStatus" =~ "dhcp6=\"yes\"" ]] && Network6Config="isDHCP" || Network6Config="isStatic"
  1962. elif [[ "$3" == "IPv6Stack" ]]; then
  1963. Network4Config="isDHCP"
  1964. [[ "$dhcpStatus" =~ "dhcp6=\"true\"" || "$dhcpStatus" =~ "dhcp6=\"yes\"" ]] && Network6Config="isDHCP" || Network6Config="isStatic"
  1965. fi
  1966. fi
  1967. [[ "$Network4Config" == "" ]] && Network4Config="isStatic"
  1968. [[ "$Network6Config" == "" ]] && Network6Config="isStatic"
  1969. rm -rf "$tmpNetcfgDir"
  1970. }
  1971. # $1 is "$tmpDHCP".
  1972. function setDhcpOrStatic() {
  1973. [[ "$1" == "dhcp" || "$1" == "auto" || "$1" == "automatic" || "$1" == "true" || "$1" == "yes" || "$1" == "1" ]] && {
  1974. Network4Config="isDHCP"
  1975. Network6Config="isDHCP"
  1976. }
  1977. [[ "$1" == "static" || "$1" == "manual" || "$1" == "none" || "$1" == "false" || "$1" == "no" || "$1" == "0" ]] && {
  1978. Network4Config="isStatic"
  1979. Network6Config="isStatic"
  1980. }
  1981. }
  1982. # $1 is "in-target"
  1983. function DebianModifiedPreseed() {
  1984. if [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'kali' ]]; then
  1985. # Must use ";" instead of using "&&", "echo -e" etc to combine multiple commands, or write text in files, recommend sed.
  1986. # Can't pass parameters correctly in preseed environment.
  1987. # DebianVimVer=`ls -a /usr/share/vim | grep vim[0-9]`
  1988. if [[ "$DebianDistNum" -ge "9" && "$DebianDistNum" -le "11" ]]; then
  1989. DebianVimVer="vim"`expr ${DebianDistNum} + 71`
  1990. elif [[ "$DebianDistNum" -ge "12" ]]; then
  1991. DebianVimVer="vim"`expr ${DebianDistNum} + 78`
  1992. elif [[ "$DIST" =~ "kali-" ]]; then
  1993. DebianVimVer="vim90"
  1994. else
  1995. DebianVimVer=""
  1996. fi
  1997. # Set parameter "mouse-=a" in /usr/share/vim/vim-version/defaults.vim to support copy text from terminal to client.
  1998. VimSupportCopy="$1 sed -i 's/set mouse=a/set mouse-=a/g' /usr/share/vim/${DebianVimVer}/defaults.vim;"
  1999. # Enable cursor edit backspace freely in insert mode.
  2000. # Reference: https://wonderwall.hatenablog.com/entry/2016/03/23/232634
  2001. VimIndentEolStart="$1 sed -i 's/set compatible/set nocompatible/g' /etc/vim/vimrc.tiny; $1 sed -i '/set nocompatible/a\set backspace=2' /etc/vim/vimrc.tiny;"
  2002. [[ "$DebianVimVer" == "" ]] && { VimSupportCopy=""; VimIndentEolStart=""; }
  2003. AptUpdating="$1 apt update -y;"
  2004. # pre-install some commonly used software.
  2005. # InstallComponents="$1 apt install sudo apt-transport-https bc binutils ca-certificates cron curl debian-keyring debian-archive-keyring dnsutils dosfstools dpkg efibootmgr ethtool fail2ban file figlet iputils-tracepath jq lrzsz libnet-ifconfig-wrapper-perl lsof libnss3 lsb-release mtr-tiny mlocate netcat-openbsd net-tools ncdu nmap ntfs-3g parted psmisc python3 socat sosreport subnetcalc tcpdump telnet traceroute unzip unrar-free uuid-runtime vim vim-gtk3 wget xz-utils -y;"
  2006. InstallComponents="$1 apt install apt-transport-https ca-certificates cron curl dnsutils dpkg fail2ban file lrzsz lsb-release net-tools sudo traceroute unzip vim wget xz-utils -y;"
  2007. # In Debian 9 and former, some certificates are expired.
  2008. DisableCertExpiredCheck="$1 sed -i '/^mozilla\/DST_Root_CA_X3/s/^/!/' /etc/ca-certificates.conf; $1 update-ca-certificates -f;"
  2009. if [[ "$IsCN" == "cn" ]]; then
  2010. # Modify /root/.bashrc to support colorful filename.
  2011. ChangeBashrc="$1 rm -rf /root/.bashrc; $1 wget --no-check-certificate -qO /root/.bashrc 'https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Debian/.bashrc';"
  2012. # Need to install "resolvconf" manually after all installation ended, logged into new system.
  2013. # DNS server validation must setting up in installed system, can't in preseeding!
  2014. # Set China DNS server from Tencent Cloud and Alibaba Cloud permanently.
  2015. SetDNS="CNResolvHead"
  2016. DnsChangePermanently="$1 mkdir -p /etc/resolvconf/resolv.conf.d/; $1 wget --no-check-certificate -qO /etc/resolvconf/resolv.conf.d/head 'https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Debian/network/${SetDNS}';"
  2017. # Modify logging in welcome information(Message Of The Day) of Debian and make it more pretty.
  2018. ModifyMOTD="$1 rm -rf /etc/update-motd.d/ /etc/motd /run/motd.dynamic; $1 mkdir -p /etc/update-motd.d/; $1 wget --no-check-certificate -qO /etc/update-motd.d/00-header 'https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Debian/updatemotd/00-header'; $1 wget --no-check-certificate -qO /etc/update-motd.d/10-sysinfo 'https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Debian/updatemotd/10-sysinfo'; $1 wget --no-check-certificate -qO /etc/update-motd.d/90-footer 'https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Debian/updatemotd/90-footer'; $1 chmod +x /etc/update-motd.d/00-header; $1 chmod +x /etc/update-motd.d/10-sysinfo; $1 chmod +x /etc/update-motd.d/90-footer;"
  2019. # Change "security.debian.org" to "mirrors.tuna.tsinghua.edu.cn". Reference: https://mirrors.tuna.tsinghua.edu.cn/help/debian/
  2020. ChangeSecurityMirror="$1 sed -i 's/security.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list;"
  2021. else
  2022. ChangeBashrc="$1 rm -rf /root/.bashrc; $1 wget --no-check-certificate -qO /root/.bashrc 'https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Debian/.bashrc';"
  2023. # Set DNS server from Cloudflare and Google permanently.
  2024. SetDNS="NomalResolvHead"
  2025. DnsChangePermanently="$1 mkdir -p /etc/resolvconf/resolv.conf.d/; $1 wget --no-check-certificate -qO /etc/resolvconf/resolv.conf.d/head 'https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Debian/network/${SetDNS}';"
  2026. ModifyMOTD="$1 rm -rf /etc/update-motd.d/ /etc/motd /run/motd.dynamic; $1 mkdir -p /etc/update-motd.d/; $1 wget --no-check-certificate -qO /etc/update-motd.d/00-header 'https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Debian/updatemotd/00-header'; $1 wget --no-check-certificate -qO /etc/update-motd.d/10-sysinfo 'https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Debian/updatemotd/10-sysinfo'; $1 wget --no-check-certificate -qO /etc/update-motd.d/90-footer 'https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Debian/updatemotd/90-footer'; $1 chmod +x /etc/update-motd.d/00-header; $1 chmod +x /etc/update-motd.d/10-sysinfo; $1 chmod +x /etc/update-motd.d/90-footer;"
  2027. ChangeSecurityMirror=""
  2028. fi
  2029. # For multiple interfaces environment, if the interface which is configurated by "auto", regardless of it is plugged by internet cable,
  2030. # Debian/Kali will continuously try to wake and start up it contains with dhcp even timeout.
  2031. # Set up with "allow-hotplug(default setting by Debian/Kali installer)" will skip this problem, but if one interface has more than 1 IP or it will connect to
  2032. # another network bridge, when system restarted, the interfaces' initialization will be failed, in most of VPS environments, the interfaces of machine should be stable,
  2033. # so replace the default from "allow-hotplug" to "auto" for interfaces config method is a better idea?
  2034. [[ "$autoPlugAdapter" == "1" ]] && AutoPlugInterfaces="$1 sed -ri \"s/allow-hotplug $interface4/auto $interface4/g\" /etc/network/interfaces; $1 sed -ri \"s/allow-hotplug $interface6/auto $interface6/g\" /etc/network/interfaces;" || AutoPlugInterfaces=""
  2035. # If the network config type of server is DHCP and it have both public IPv4 and IPv6 address,
  2036. # Debian install program even get nerwork config with DHCP, but after log into new system,
  2037. # only the IPv4 of the server has been configurated.
  2038. # so need to write "iface interface inet6 dhcp" to /etc/network/interfaces in preseeding process for Bi-stack machine,
  2039. # to avoid config IPv6 manually after log into new system.
  2040. SupportIPv6orIPv4=""
  2041. ReplaceActualIpPrefix=""
  2042. if [[ "$IPStackType" == "IPv4Stack" ]]; then
  2043. [[ "$BurnIrregularIpv4Status" == "1" ]] && BurnIrregularIpv4Gate="$1 sed -i '\$a\\\tgateway $actualIp4Gate' /etc/network/interfaces;"
  2044. # This IPv4Stack machine should be setting as IPv4 network accessing priority.
  2045. SupportIPv6orIPv4="$1 sed -i '\$aprecedence ::ffff:0:0/96' /etc/gai.conf;"
  2046. ReplaceActualIpPrefix="$1 sed -ri \"s/address $ipAddr\/$ipPrefix/address $ipAddr\/$actualIp4Prefix/g\" /etc/network/interfaces;"
  2047. elif [[ "$IPStackType" == "BiStack" ]]; then
  2048. # Enable IPv4 dhcp or static configurations.
  2049. if [[ "$BiStackPreferIpv6Status" == "1" ]]; then
  2050. if [[ "$Network4Config" == "isDHCP" ]]; then
  2051. SupportIPv6orIPv4="$1 sed -i '\$aiface $interface inet dhcp' /etc/network/interfaces; $1 sed -i '\$alabel 2002::/16' /etc/gai.conf; $1 sed -i '\$alabel 2001:0::/32' /etc/gai.conf;"
  2052. [[ -n "$interface4" && -n "$interface6" && "$interface4" != "$interface6" ]] && SupportIPv6orIPv4="$1 sed -i '\$a\ ' /etc/network/interfaces; $1 sed -i '\$aallow-hotplug $interface4' /etc/network/interfaces; $1 sed -i '\$aiface $interface4 inet dhcp' /etc/network/interfaces; $1 sed -i '\$alabel 2002::/16' /etc/gai.conf; $1 sed -i '\$alabel 2001:0::/32' /etc/gai.conf;"
  2053. ReplaceActualIpPrefix="$1 sed -ri \"s/address $ip6Addr\/$ip6Mask/address $ip6Addr\/$actualIp6Prefix/g\" /etc/network/interfaces;"
  2054. elif [[ "$Network4Config" == "isStatic" ]]; then
  2055. SupportIPv6orIPv4="$1 sed -i '\$aiface $interface inet static' /etc/network/interfaces; $1 sed -i '\$a\\\taddress $ipAddr' /etc/network/interfaces; $1 sed -i '\$a\\\tnetmask $MASK' /etc/network/interfaces; $1 sed -i '\$a\\\tgateway $GATE' /etc/network/interfaces; $1 sed -i '\$a\\\tdns-nameservers $ipDNS' /etc/network/interfaces; $1 sed -i '\$alabel 2002::/16' /etc/gai.conf; $1 sed -i '\$alabel 2001:0::/32' /etc/gai.conf;"
  2056. [[ -n "$interface4" && -n "$interface6" && "$interface4" != "$interface6" ]] && SupportIPv6orIPv4="$1 sed -i '\$a\ ' /etc/network/interfaces; $1 sed -i '\$aallow-hotplug $interface4' /etc/network/interfaces; $1 sed -i '\$aiface $interface4 inet static' /etc/network/interfaces; $1 sed -i '\$a\\\taddress $ipAddr' /etc/network/interfaces; $1 sed -i '\$a\\\tnetmask $MASK' /etc/network/interfaces; $1 sed -i '\$a\\\tgateway $GATE' /etc/network/interfaces; $1 sed -i '\$a\\\tdns-nameservers $ipDNS' /etc/network/interfaces; $1 sed -i '\$alabel 2002::/16' /etc/gai.conf; $1 sed -i '\$alabel 2001:0::/32' /etc/gai.conf;"
  2057. ReplaceActualIpPrefix="$1 sed -ri \"s/address $ip6Addr\/$ip6Mask/address $ip6Addr\/$actualIp6Prefix/g\" /etc/network/interfaces; $1 sed -ri \"s/netmask $MASK/netmask $actualIp4Subnet/g\" /etc/network/interfaces;"
  2058. fi
  2059. else
  2060. [[ "$BurnIrregularIpv4Status" == "1" ]] && BurnIrregularIpv4Gate="$1 sed -i '\$a\\\tgateway $actualIp4Gate' /etc/network/interfaces;"
  2061. if [[ "$Network6Config" == "isDHCP" ]]; then
  2062. # Enable IPv6 dhcp and set prefer IPv6 access for BiStack or IPv6Stack machine: add "label 2002::/16", "label 2001:0::/32" in last line of the "/etc/gai.conf"
  2063. SupportIPv6orIPv4="$1 sed -i '\$aiface $interface inet6 dhcp' /etc/network/interfaces; $1 sed -i '\$alabel 2002::/16' /etc/gai.conf; $1 sed -i '\$alabel 2001:0::/32' /etc/gai.conf;"
  2064. [[ -n "$interface4" && -n "$interface6" && "$interface4" != "$interface6" ]] && SupportIPv6orIPv4="$1 sed -i '\$a\ ' /etc/network/interfaces; $1 sed -i '\$aallow-hotplug $interface6' /etc/network/interfaces; $1 sed -i '\$aiface $interface6 inet6 dhcp' /etc/network/interfaces; $1 sed -i '\$alabel 2002::/16' /etc/gai.conf; $1 sed -i '\$alabel 2001:0::/32' /etc/gai.conf;"
  2065. ReplaceActualIpPrefix="$1 sed -ri \"s/address $ipAddr\/$ipPrefix/address $ipAddr\/$actualIp4Prefix/g\" /etc/network/interfaces;"
  2066. elif [[ "$Network6Config" == "isStatic" ]]; then
  2067. SupportIPv6orIPv4="$1 sed -i '\$aiface $interface inet6 static' /etc/network/interfaces; $1 sed -i '\$a\\\taddress $ip6Addr' /etc/network/interfaces; $1 sed -i '\$a\\\tnetmask $ip6Mask' /etc/network/interfaces; $1 sed -i '\$a\\\tgateway $ip6Gate' /etc/network/interfaces; $1 sed -i '\$a\\\tdns-nameservers $ip6DNS' /etc/network/interfaces; $1 sed -i '\$alabel 2002::/16' /etc/gai.conf; $1 sed -i '\$alabel 2001:0::/32' /etc/gai.conf;"
  2068. [[ -n "$interface4" && -n "$interface6" && "$interface4" != "$interface6" ]] && SupportIPv6orIPv4="$1 sed -i '\$a\ ' /etc/network/interfaces; $1 sed -i '\$aallow-hotplug $interface6' /etc/network/interfaces; $1 sed -i '\$aiface $interface6 inet6 static' /etc/network/interfaces; $1 sed -i '\$a\\\taddress $ip6Addr' /etc/network/interfaces; $1 sed -i '\$a\\\tnetmask $ip6Mask' /etc/network/interfaces; $1 sed -i '\$a\\\tgateway $ip6Gate' /etc/network/interfaces; $1 sed -i '\$a\\\tdns-nameservers $ip6DNS' /etc/network/interfaces; $1 sed -i '\$alabel 2002::/16' /etc/gai.conf; $1 sed -i '\$alabel 2001:0::/32' /etc/gai.conf;"
  2069. ReplaceActualIpPrefix="$1 sed -ri \"s/address $ipAddr\/$ipPrefix/address $ipAddr\/$actualIp4Prefix/g\" /etc/network/interfaces; $1 sed -ri \"s/netmask $ip6Mask/netmask $actualIp6Prefix/g\" /etc/network/interfaces;"
  2070. fi
  2071. fi
  2072. writeMultipleIpv6Addresses "$i6AddrNum" "$1" '/etc/network/interfaces'
  2073. elif [[ "$IPStackType" == "IPv6Stack" ]]; then
  2074. # This IPv6Stack machine should be setting as IPv6 network accessing priority.
  2075. SupportIPv6orIPv4="$1 sed -i '\$alabel 2002::/16' /etc/gai.conf; $1 sed -i '\$alabel 2001:0::/32' /etc/gai.conf;"
  2076. ReplaceActualIpPrefix="$1 sed -ri \"s/address $ip6Addr\/$ip6Mask/address $ip6Addr\/$actualIp6Prefix/g\" /etc/network/interfaces;"
  2077. writeMultipleIpv6Addresses "$i6AddrNum" "$1" '/etc/network/interfaces'
  2078. fi
  2079. # a typical network configuration sample of IPv6 static for Debian:
  2080. # iface eth0 inet static
  2081. # address 10.0.0.72
  2082. # netmask 255.255.255.0
  2083. # gateway 10.0.0.1
  2084. # dns-nameservers 1.0.0.1 8.4.4.8
  2085. #
  2086. # a typical network configuration sample of IPv6 static for Debian:
  2087. # iface eth0 inet6 static
  2088. # address 2702:b43c:492a:9d1e:8270:fd59:6de4:20f1
  2089. # netmask 128
  2090. # gateway fe80::200:17ff:fe9e:f9d0
  2091. # dns-nameservers 2606:4700:4700::1001 2001:4860:4860::8844
  2092. [[ "$linux_relese" == 'kali' ]] && {
  2093. ChangeBashrc=""
  2094. # Enable Kali ssh service.
  2095. EnableSSH="$1 update-rc.d ssh enable; $1 /etc/init.d/ssh restart;"
  2096. # Revise terms of license from "Debian" to "Kali" in motd file of "00-header".
  2097. ReviseMOTD="$1 sed -ri 's/Debian/Kali/g' /etc/update-motd.d/00-header;"
  2098. SupportZSH="$1 apt install zsh -y; $1 chsh -s /bin/zsh; $1 rm -rf /root/.bashrc.original;"
  2099. }
  2100. # Fail2ban configurations.
  2101. # Reference: https://github.com/fail2ban/fail2ban/issues/2756
  2102. # https://www.mail-archive.com/[email protected]/msg1879390.html
  2103. EnableFail2ban="$1 sed -i '/\[Definition\]/a allowipv6 = auto' /etc/fail2ban/fail2ban.conf; $1 sed -ri 's/backend.*/backend = systemd/g' /etc/fail2ban/jail.conf; $1 update-rc.d fail2ban enable; $1 /etc/init.d/fail2ban restart;"
  2104. # For some cloud providers which servers boot from their own grub2 bootloader first by force, not boot from grub in harddisk of our own servers directly,
  2105. # we need to creat a soft link for grub2 from grub1 to make sure the first reboot after installation won't meet a fatal.
  2106. # In this situation, the partition table and filesystem of the newly installed OS must be "mbr" and "ext4".
  2107. # This case has been occurred in these cloud providers such as "app.cloudcone.com", "www.readyidc.com".
  2108. CreateSoftLinkToGrub2FromGrub1="$1 ln -s /boot/grub/ /boot/grub2;"
  2109. export DebianModifiedProcession="${AptUpdating} ${InstallComponents} ${DisableCertExpiredCheck} ${ChangeBashrc} ${VimSupportCopy} ${VimIndentEolStart} ${DnsChangePermanently} ${ModifyMOTD} ${ChangeSecurityMirror} ${AutoPlugInterfaces} ${BurnIrregularIpv4Gate} ${SupportIPv6orIPv4} ${ReplaceActualIpPrefix} ${EnableSSH} ${ReviseMOTD} ${SupportZSH} ${EnableFail2ban} ${CreateSoftLinkToGrub2FromGrub1}"
  2110. fi
  2111. }
  2112. function DebianPreseedProcess() {
  2113. if [[ "$setAutoConfig" == "1" ]]; then
  2114. ddWindowsEarlyCommandsOfAnna='anna-install libfuse2-udeb fuse-udeb ntfs-3g-udeb libcrypto3-udeb libpcre2-8-0-udeb libssl3-udeb libuuid1-udeb zlib1g-udeb wget-udeb'
  2115. tmpDdWinsEarlyCommandsOfAnna="$ddWindowsEarlyCommandsOfAnna"
  2116. # Default to make a GPT partition to support 3TB hard drive or larger.
  2117. # To remove LVM VGM PVM force automatically:
  2118. # https://serverfault.com/questions/571363/unable-to-automatically-remove-lvm-data
  2119. # To part all disks:
  2120. # https://unix.stackexchange.com/questions/341253/using-d-i-partman-recipe-strings
  2121. if [[ "$disksNum" -gt "1" && "$setDisk" == "all" ]]; then
  2122. [[ "$partitionTable" == "gpt" ]] && FormatDisk=`echo -e "d-i partman-auto/disk string $AllDisks\nd-i partman-auto/method string regular\nd-i partman-auto/init_automatically_partition select Guided - use entire disk\nd-i partman-auto/choose_recipe select All files in one partition (recommended for new users)\nd-i partman-basicfilesystems/choose_label string gpt\nd-i partman-basicfilesystems/default_label string gpt\nd-i partman-partitioning/choose_label string gpt\nd-i partman-partitioning/default_label string gpt\nd-i partman/choose_label string gpt\nd-i partman/default_label string gpt"` || FormatDisk=`echo -e "d-i partman-auto/disk string $AllDisks\nd-i partman-auto/method string regular\nd-i partman-auto/init_automatically_partition select Guided - use entire disk\nd-i partman-auto/choose_recipe select All files in one partition (recommended for new users)"`
  2123. PartmanEarlyCommand='debconf-set partman-auto/disk '${AllDisks}';'
  2124. else
  2125. [[ "$partitionTable" == "gpt" ]] && FormatDisk=`echo -e "d-i partman-auto/disk string $IncDisk\nd-i partman-auto/method string regular\nd-i partman-auto/init_automatically_partition select Guided - use entire disk\nd-i partman-auto/choose_recipe select All files in one partition (recommended for new users)\nd-i partman-basicfilesystems/choose_label string gpt\nd-i partman-basicfilesystems/default_label string gpt\nd-i partman-partitioning/choose_label string gpt\nd-i partman-partitioning/default_label string gpt\nd-i partman/choose_label string gpt\nd-i partman/default_label string gpt"` || FormatDisk=`echo -e "d-i partman-auto/disk string $IncDisk\nd-i partman-auto/method string regular\nd-i partman-auto/init_automatically_partition select Guided - use entire disk\nd-i partman-auto/choose_recipe select All files in one partition (recommended for new users)"`
  2126. PartmanEarlyCommand='debconf-set partman-auto/disk "$(list-devices disk | grep '${IncDisk}' | head -n 1)";'
  2127. fi
  2128. # Default single disk format recipe( -partition="gpt" ):
  2129. # d-i partman-auto/disk string $AllDisks/$IncDisk
  2130. # d-i partman-auto/method string regular
  2131. # d-i partman-auto/init_automatically_partition select Guided - use entire disk
  2132. # d-i partman-auto/choose_recipe select All files in one partition (recommended for new users)
  2133. # d-i partman-basicfilesystems/choose_label string gpt
  2134. # d-i partman-basicfilesystems/default_label string gpt
  2135. # d-i partman-partitioning/choose_label string gpt
  2136. # d-i partman-partitioning/default_label string gpt
  2137. # d-i partman/choose_label string gpt
  2138. # d-i partman/default_label string gpt
  2139. setRaidRecipe "$setRaid" "$disksNum" "$AllDisks" "$linux_relese"
  2140. # Debian 11 and former versions couldn't accept irregular IPv6 format configs, they can only be recognized by Debian 12+ and Kali, dd mode(base system is Debian 12) prefer IPv4 to config network.
  2141. if [[ "$BiStackPreferIpv6Status" == "1" ]]; then
  2142. if [[ "$linux_relese" == 'debian' && "$DebianDistNum" -le "11" ]] || [[ "$ddMode" == '1' ]]; then
  2143. BiStackPreferIpv6Status=""
  2144. BurnIrregularIpv4Status='1'
  2145. fi
  2146. fi
  2147. # A valid method to add an irregular gateway by force:
  2148. # This method aims to hack IPv4 network service and add IPv4 route by force in busybox, so we need to assign "none" for "d-i netcfg/get_gateway string" to avoid Debian installer report "unreachable gateway",
  2149. # don't forget to write IPv4 gateway back in "d-i preseed/late_command" stage.
  2150. # Reference: https://lab.civicrm.org/infra/ops/blob/master/ansible/roles/kvm-server/templates/etc/preseeds/host/preseed.cfg
  2151. #
  2152. # Reserved empty variables for engineering debugging, if you are not known them well, don't uncomment with them!
  2153. # BurnIrregularIpv4Status='1'
  2154. # ipPrefix=""
  2155. # MASK=""
  2156. [[ Network4Config == "isDHCP" || "$interfaceSelect" != "auto" ]] && BurnIrregularIpv4Status='0'
  2157. [[ "$BurnIrregularIpv4Status" == "1" ]] && {
  2158. actualIp4Gate="$GATE"
  2159. GATE="none"
  2160. if [[ "$IPStackType" == "IPv4Stack" ]]; then
  2161. writeDnsByForce='echo '\''nameserver '$ipDNS1''\'' > /etc/resolv.conf && echo '\''nameserver '$ipDNS2''\'' >> /etc/resolv.conf'
  2162. elif [[ "$IPStackType" == "BiStack" ]]; then
  2163. writeDnsByForce='echo '\''nameserver '$ipDNS1''\'' > /etc/resolv.conf && echo '\''nameserver '$ip6DNS1''\'' >> /etc/resolv.conf && echo '\''nameserver '$ipDNS2''\'' >> /etc/resolv.conf && echo '\''nameserver '$ip6DNS2''\'' >> /etc/resolv.conf'
  2164. fi
  2165. # If subnet of some machines of IPv4 config is "32"(255.255.255.255) means the intranet range is smallest, just including the server itself,
  2166. # the "onlink" must be included in command of adding gateway(route) by force via soft hack, for example:
  2167. #
  2168. # ip route add default via 10.0.0.1 dev eth0 onlink
  2169. #
  2170. # to tell the networking service that the gateway of "10.0.0.1" will serve the device of network adapter "eth0" via "onlink" by IPv4 stack protocol
  2171. # because "onlink" stipulates networking to establish a connection from local to gateway by "arp" directly without creating any area of intranet.
  2172. [[ "$ddMode" == '0' ]] && tmpDdWinsEarlyCommandsOfAnna=''
  2173. BurnIrregularIpv4ByForce=`echo -e 'd-i preseed/early_command string ip link set '$interface4' up; ip addr add '$IPv4'/'$ipPrefix' dev '$interface4'; echo "(ip route add '$actualIp4Gate' dev '$interface4' || true) && (ip route add default via '$actualIp4Gate' dev '$interface4' onlink || true) && '$writeDnsByForce'" > /bin/ethdetect; echo "(test -x /bin/ethdetect && /bin/ethdetect) || true" >> /usr/share/debconf/confmodule; '$tmpDdWinsEarlyCommandsOfAnna''`
  2174. }
  2175. # Prefer to use IPv4 stack to config networking.
  2176. if [[ "$IPStackType" == "IPv4Stack" ]] || [[ "$IPStackType" == "BiStack" && "$BiStackPreferIpv6Status" != "1" ]]; then
  2177. [[ "$Network4Config" == "isStatic" ]] && NetConfigManually=`echo -e "d-i netcfg/disable_autoconfig boolean true\nd-i netcfg/dhcp_failed note\nd-i netcfg/dhcp_options select Configure network manually\nd-i netcfg/get_ipaddress string $IPv4\nd-i netcfg/get_netmask string $MASK\nd-i netcfg/get_gateway string $GATE\nd-i netcfg/get_nameservers string $ipDNS\nd-i netcfg/no_default_route boolean true\nd-i netcfg/confirm_static boolean true"` || NetConfigManually=""
  2178. # Prefer to use IPv6 stack to configure network because Debian 12 supports public IPv6 address with private gateway like "fe80::1" and works well,
  2179. # if IPv4 configuration of one BiStack server has public IPv4 and private gateway like "172.31.1.1" because this case will cause Debian installer notices "unreachable gateway".
  2180. elif [[ "$IPStackType" == "IPv6Stack" ]] || [[ "$IPStackType" == "BiStack" && "$BiStackPreferIpv6Status" == "1" ]]; then
  2181. [[ "$Network6Config" == "isStatic" ]] && NetConfigManually=`echo -e "d-i netcfg/disable_autoconfig boolean true\nd-i netcfg/dhcp_failed note\nd-i netcfg/dhcp_options select Configure network manually\nd-i netcfg/get_ipaddress string $ip6Addr\nd-i netcfg/get_netmask string $ip6Subnet\nd-i netcfg/get_gateway string $ip6Gate\nd-i netcfg/get_nameservers string $ip6DNS\nd-i netcfg/no_default_route boolean true\nd-i netcfg/confirm_static boolean true"` || NetConfigManually=""
  2182. fi
  2183. # Debian installer can only identify the full IPv6 address of IPv6 mask,
  2184. # so we need to covert IPv6 prefix shortening from "0-128" to whole IPv6 address.
  2185. # The result of "$ip6Subnet" is calculated by function "ipv6SubnetCalc".
  2186. #
  2187. # Manually network setting configurations, including:
  2188. # d-i netcfg/disable_autoconfig boolean true
  2189. # d-i netcfg/dhcp_failed note
  2190. # d-i netcfg/dhcp_options select Configure network manually
  2191. # d-i netcfg/get_ipaddress string $IPv4/$ip6Addr
  2192. # d-i netcfg/get_netmask string $MASK/$ip6Subnet
  2193. # d-i netcfg/get_gateway string $GATE/$ip6Gate
  2194. # d-i netcfg/get_nameservers string $ipDNS/$ip6DNS
  2195. # d-i netcfg/no_default_route boolean true
  2196. # d-i netcfg/confirm_static boolean true
  2197. DebianModifiedPreseed "in-target"
  2198. cat >/tmp/boot/preseed.cfg<<EOF
  2199. ### Unattended Installation
  2200. d-i auto-install/enable boolean true
  2201. d-i debconf/priority select critical
  2202. ### Localization
  2203. d-i debian-installer/locale string en_US.UTF-8
  2204. d-i debian-installer/country string US
  2205. d-i debian-installer/language string en
  2206. d-i debian-installer/allow_unauthenticated boolean true
  2207. d-i console-setup/layoutcode string us
  2208. d-i keyboard-configuration/xkb-keymap string us
  2209. ### Low memory mode
  2210. d-i lowmem/low boolean true
  2211. ### Disable security, updates and backports
  2212. d-i apt-setup/services-select multiselect
  2213. ### Disable source repositories
  2214. d-i apt-setup/enable-source-repositories boolean false
  2215. ### Enable contrib and non-free
  2216. d-i apt-setup/non-free boolean true
  2217. d-i apt-setup/contrib boolean true
  2218. ### Disable CD-rom automatic scan
  2219. d-i apt-setup/cdrom/set-first boolean false
  2220. d-i apt-setup/cdrom/set-next boolean false
  2221. d-i apt-setup/cdrom/set-failed boolean false
  2222. ### Network configuration
  2223. d-i netcfg/choose_interface select $interfaceSelect
  2224. ${NetConfigManually}
  2225. d-i hw-detect/load_firmware boolean true
  2226. ${BurnIrregularIpv4ByForce}
  2227. ### Mirror settings
  2228. d-i mirror/country string manual
  2229. d-i mirror/http/hostname string $MirrorHost
  2230. d-i mirror/http/directory string $MirrorFolder
  2231. d-i mirror/http/proxy string
  2232. ### Account setup
  2233. d-i passwd/root-login boolean ture
  2234. d-i passwd/make-user boolean false
  2235. d-i passwd/root-password-crypted password $myPASSWORD
  2236. d-i user-setup/allow-password-weak boolean true
  2237. d-i user-setup/encrypt-home boolean false
  2238. ### Clock and time zone setup
  2239. d-i clock-setup/utc boolean true
  2240. d-i time/zone string ${TimeZone}
  2241. d-i clock-setup/ntp boolean true
  2242. d-i clock-setup/ntp-server string ntp.nict.jp
  2243. ### Get harddisk name and Windows DD installation set up
  2244. d-i preseed/early_command string ${ddWindowsEarlyCommandsOfAnna}
  2245. d-i partman/early_command string \
  2246. lvremove --select all -ff -y; \
  2247. vgremove --select all -ff -y; \
  2248. pvremove /dev/* -ff -y; \
  2249. [[ -n "\$(blkid -t TYPE='vfat' -o device)" ]] && umount "\$(blkid -t TYPE='vfat' -o device)"; \
  2250. ${PartmanEarlyCommand} \
  2251. wget -qO- '$DDURL' | $DEC_CMD | /bin/dd of=\$(list-devices disk | grep ${IncDisk} | head -n 1); \
  2252. /bin/ntfs-3g \$(list-devices partition | grep ${IncDisk} | head -n 1) /mnt; \
  2253. cd '/mnt/ProgramData/Microsoft/Windows/Start Menu/Programs'; \
  2254. cd Start* || cd start*; \
  2255. cp -f '/net.bat' './net.bat'; \
  2256. /sbin/reboot; \
  2257. umount /media || true; \
  2258. ### Partitioning
  2259. d-i partman-lvm/device_remove_lvm boolean true
  2260. d-i partman-lvm/device_remove_lvm_span boolean true
  2261. d-i partman-lvm/confirm boolean true
  2262. d-i partman-lvm/confirm_nooverwrite boolean true
  2263. d-i partman-partitioning/confirm_write_new_label boolean true
  2264. d-i partman/choose_partition select finish
  2265. d-i partman/confirm boolean true
  2266. d-i partman/confirm_nooverwrite boolean true
  2267. d-i partman/default_filesystem string ext4
  2268. d-i partman/mount_style select uuid
  2269. d-i partman-md/device_remove_md boolean true
  2270. ${FormatDisk}
  2271. ### Package selection
  2272. tasksel tasksel/first multiselect minimal
  2273. d-i pkgsel/include string openssh-server
  2274. # Automatic updates are not applied, everything is updated manually.
  2275. d-i pkgsel/update-policy select none
  2276. d-i pkgsel/upgrade select none
  2277. ### Disable to upload developer statistics anonymously
  2278. popularity-contest popularity-contest/participate boolean false
  2279. ### Grub
  2280. d-i grub-installer/only_debian boolean true
  2281. d-i grub-installer/with_other_os boolean true
  2282. d-i grub-installer/bootdev string ${IncDisk}
  2283. d-i grub-installer/force-efi-extra-removable boolean true
  2284. d-i debian-installer/add-kernel-opts string net.ifnames=0 biosdevname=0 ipv6.disable=1
  2285. ### Shutdown machine
  2286. d-i finish-install/reboot_in_progress note
  2287. d-i debian-installer/exit/reboot boolean true
  2288. ### Write preseed
  2289. d-i preseed/late_command string \
  2290. sed -ri 's/^#?Port.*/Port ${sshPORT}/g' /target/etc/ssh/sshd_config; \
  2291. sed -ri 's/^#?PermitRootLogin.*/PermitRootLogin yes/g' /target/etc/ssh/sshd_config; \
  2292. sed -ri 's/^#?PasswordAuthentication.*/PasswordAuthentication yes/g' /target/etc/ssh/sshd_config; \
  2293. echo '@reboot root cat /etc/run.sh 2>/dev/null |base64 -d >/tmp/run.sh; rm -rf /etc/run.sh; sed -i /^@reboot/d /etc/crontab; bash /tmp/run.sh' >>/target/etc/crontab; \
  2294. echo '' >>/target/etc/crontab; \
  2295. echo '${setCMD}' >/target/etc/run.sh; \
  2296. ${DebianModifiedProcession}
  2297. EOF
  2298. fi
  2299. }
  2300. alpineInstallOrDdAdditionalFiles() {
  2301. AlpineInitFile="$1"
  2302. AlpineDnsFile="$2"
  2303. AlpineMotd="$3"
  2304. AlpineInitFileName="alpineConf.start"
  2305. if [[ "$targetRelese" == 'Ubuntu' ]]; then
  2306. if [[ "$ubuntuVER" == "amd64" ]]; then
  2307. targetLinuxMirror="$4"
  2308. elif [[ "$ubuntuVER" == "arm64" ]]; then
  2309. targetLinuxMirror="$5"
  2310. fi
  2311. AlpineInitFile="$6"
  2312. AlpineInitFileName="ubuntuConf.start"
  2313. [[ "$setIPv6" == "0" ]] && setIPv6="0" || setIPv6="1"
  2314. elif [[ "$targetRelese" == 'Windows' ]]; then
  2315. AlpineInitFile="$7"
  2316. AlpineInitFileName="windowsConf.start"
  2317. windowsStaticConfigCmd="$8"
  2318. fi
  2319. }
  2320. # $1 is "$tmpURL".
  2321. verifyUrlValidationOfDdImages() {
  2322. echo "$1" | grep -q '^http://\|^ftp://\|^https://'
  2323. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Please input a vaild URL, only support http://, ftp:// and https:// ! \n" && exit 1
  2324. tmpURLCheck=$(echo $(curl -s -I -X GET $1) | grep -wi "http/[0-9]*" | awk '{print $2}')
  2325. [[ -z "$tmpURLCheck" || ! "$tmpURLCheck" =~ ^[0-9]+$ ]] && {
  2326. echo -ne "\n[${red}Error${plain}] The mirror of DD images is temporarily unavailable!\n"
  2327. exit 1
  2328. }
  2329. DDURL="$1"
  2330. # Decompress command selection
  2331. if [[ "$setFileType" == "gz" ]]; then
  2332. DEC_CMD="gunzip -dc"
  2333. [[ $(echo "$DDURL" | grep -o ...$) == ".xz" ]] && DEC_CMD="xzcat"
  2334. elif [[ "$setFileType" == "xz" ]]; then
  2335. DEC_CMD="xzcat"
  2336. [[ $(echo "$DDURL" | grep -o ...$) == ".gz" ]] && DEC_CMD="gunzip -dc"
  2337. else
  2338. [[ $(echo "$DDURL" | grep -o ...$) == ".xz" ]] && DEC_CMD="xzcat"
  2339. [[ $(echo "$DDURL" | grep -o ...$) == ".gz" ]] && DEC_CMD="gunzip -dc"
  2340. fi
  2341. }
  2342. checkSys
  2343. # Get the name of network adapter($interface).
  2344. # [[ -z "$interface" ]] && interface=`getInterface "$CurrentOS"
  2345. # Try to enable IPv4 by DHCP
  2346. # timeout 5 dhclient -4 $interface
  2347. # Try to enable IPv6 by DHCP
  2348. # timeout 5 dhclient -6 $interface
  2349. # IPv4 and IPv6 DNS check servers from OpenDNS, Quad9, Verisign and TWNIC.
  2350. checkIpv4OrIpv6 "$ipAddr" "$ip6Addr" "208.67.220.220" "9.9.9.9" "64.6.65.6" "101.102.103.104" "2620:0:ccc::2" "2620:fe::9" "2620:74:1b::1:1" "2001:de4::101"
  2351. # Youtube, Instagram, Wikipedia and BBC are all have public IPv4 and IPv6 address and are also banned in mainland of China.
  2352. checkCN "$IPStackType" "www.youtube.com" "www.instagram.com" "www.wikipedia.org" "bbc.com"
  2353. checkEfi "/sys/firmware/efi/efivars/" "/sys/firmware/efi/vars/" "/sys/firmware/efi/runtime-map/" "/sys/firmware/efi/mok-variables/"
  2354. checkVirt
  2355. if [[ "$sshPORT" ]];then
  2356. if [[ ! ${sshPORT} -ge "1" ]] || [[ ! ${sshPORT} -le "65535" ]] || [[ `grep '^[[:digit:]]*$' <<< '${sshPORT}'` ]]; then
  2357. sshPORT='22'
  2358. fi
  2359. else
  2360. sshPORT=$(grep -Ei "^port|^#port" /etc/ssh/sshd_config | head -n 1 | awk -F' ' '{print $2}')
  2361. [[ "$sshPORT" == "" ]] && sshPORT=$(netstat -anp | grep -i 'sshd: root' | grep -iw 'tcp' | awk '{print $4}' | head -n 1 | cut -d':' -f'2')
  2362. [[ "$sshPORT" == "" ]] && sshPORT=$(netstat -anp | grep -i 'sshd: root' | grep -iw 'tcp6' | awk '{print $4}' | head -n 1 | awk -F':' '{print $NF}')
  2363. if [[ "$sshPORT" == "" ]] || [[ ! ${sshPORT} -ge "1" ]] || [[ ! ${sshPORT} -le "65535" ]] || [[ `grep '^[[:digit:]]*$' <<< '${sshPORT}'` ]]; then
  2364. sshPORT='22'
  2365. fi
  2366. fi
  2367. # Disable SELinux
  2368. [[ -f /etc/selinux/config ]] && {
  2369. SELinuxStatus=$(sestatus -v | grep "SELinux status:" | grep enabled)
  2370. [[ "$SELinuxStatus" != "" ]] && echo -ne "\n${aoiBlue}# Disabled SELinux${plain}" && setenforce 0
  2371. }
  2372. [[ ! -d "/tmp/" ]] && mkdir /tmp
  2373. if [[ "$loaderMode" == "0" ]]; then
  2374. checkGrub "/boot/grub/" "/boot/grub2/" "/etc/" "grub.cfg" "grub.conf" "/boot/efi/EFI/"
  2375. if [[ -z "$GRUBTYPE" ]]; then
  2376. echo -ne "\n[${red}Error${plain}] Not Found grub.\n"
  2377. exit 1
  2378. fi
  2379. fi
  2380. [[ "$ddMode" == '1' ]] && {
  2381. if [[ "$targetRelese" == 'Ubuntu' ]] || [[ "$targetRelese" == 'Windows' ]]; then
  2382. Relese='AlpineLinux'
  2383. tmpDIST='edge'
  2384. if [[ "$targetRelese" == 'Windows' ]]; then
  2385. [[ "$VER" == "aarch64" || "$VER" == "arm64" ]] && {
  2386. echo -ne "\n[${red}Error${plain}] ${targetRelese} doesn't support ${VER} architecture.\n"
  2387. exit 1
  2388. }
  2389. fi
  2390. else
  2391. Relese='Debian'
  2392. tmpDIST='12'
  2393. fi
  2394. }
  2395. [[ -n "$Relese" ]] || Relese='Debian'
  2396. linux_relese=$(echo "$Relese" |sed 's/\ //g' |sed -r 's/(.*)/\L\1/')
  2397. clear && echo -ne "\n${aoiBlue}# Check Dependence${plain}\n\n"
  2398. dependence awk,basename,cat,cpio,curl,cut,dig,dirname,file,find,grep,gzip,iconv,ip,lsblk,openssl,sed,wget,xz;
  2399. ipDNS1=$(echo $ipDNS | cut -d ' ' -f 1)
  2400. ipDNS2=$(echo $ipDNS | cut -d ' ' -f 2)
  2401. ip6DNS1=$(echo $ip6DNS | cut -d ' ' -f 1)
  2402. ip6DNS2=$(echo $ip6DNS | cut -d ' ' -f 2)
  2403. ipDNS=$(checkDNS "$ipDNS")
  2404. ip6DNS=$(checkDNS "$ip6DNS")
  2405. if [[ -n "$ipAddr" && -n "$ipMask" && -n "$ipGate" ]] && [[ -z "$ip6Addr" && -z "$ip6Mask" && -z "$ip6Gate" ]]; then
  2406. setNet='1'
  2407. checkDHCP "$CurrentOS" "$CurrentOSVer" "$IPStackType"
  2408. Network4Config="isStatic"
  2409. acceptIPv4AndIPv6SubnetValue "$ipMask" ""
  2410. [[ "$IPStackType" != "IPv4Stack" ]] && getIPv6Address
  2411. elif [[ -n "$ipAddr" && -n "$ipMask" && -n "$ipGate" ]] && [[ -n "$ip6Addr" && -n "$ip6Mask" && -n "$ip6Gate" ]]; then
  2412. setNet='1'
  2413. [[ -z "$interfaceSelect" ]] && getInterface "$CurrentOS"
  2414. Network4Config="isStatic"
  2415. Network6Config="isStatic"
  2416. acceptIPv4AndIPv6SubnetValue "$ipMask" "$ip6Mask"
  2417. elif [[ -z "$ipAddr" && -z "$ipMask" && -z "$ipGate" ]] && [[ -n "$ip6Addr" && -n "$ip6Mask" && -n "$ip6Gate" ]]; then
  2418. setNet='1'
  2419. checkDHCP "$CurrentOS" "$CurrentOSVer" "$IPStackType"
  2420. Network6Config="isStatic"
  2421. acceptIPv4AndIPv6SubnetValue "" "$ip6Mask"
  2422. getIPv4Address
  2423. fi
  2424. if [[ "$setNet" == "0" ]]; then
  2425. [[ -z "$tmpDHCP" ]] && checkDHCP "$CurrentOS" "$CurrentOSVer" "$IPStackType"
  2426. getIPv4Address
  2427. [[ "$IPStackType" != "IPv4Stack" ]] && getIPv6Address
  2428. if [[ "$IPStackType" == "BiStack" && "$i6AddrNum" -ge "2" ]]; then
  2429. Network4Config="isStatic"
  2430. [[ "$BiStackPreferIpv6Status" == "1" ]] && {
  2431. BiStackPreferIpv6Status=""
  2432. BurnIrregularIpv4Status='1'
  2433. }
  2434. fi
  2435. fi
  2436. setDhcpOrStatic "$tmpDHCP"
  2437. checkWarp "warp*.conf" "wgcf*.conf" "wg[0-9].conf" "warp*" "wgcf*" "wg[0-9]" "privatekey" "publickey"
  2438. IPv4="$ipAddr"; MASK="$ipMask"; GATE="$ipGate";
  2439. if [[ -z "$IPv4" && -z "$MASK" && -z "$GATE" ]] && [[ -z "$ip6Addr" && -z "$ip6Mask" && -z "$ip6Gate" ]]; then
  2440. echo -ne "\n[${red}Error${plain}] The network of your machine may not be available!\n"
  2441. bash $0 error
  2442. exit 1
  2443. fi
  2444. echo -ne "\n${aoiBlue}# Network Details${plain}\n"
  2445. [[ -n "$interfaceSelect" ]] && echo -ne "\n[${yellow}Adapter Name${plain}] $interfaceSelect" || echo -ne "\n[${yellow}Adapter Name${plain}] $interface"
  2446. [[ -n "$NetCfgWhole" ]] && echo -ne "\n[${yellow}Network File${plain}] $NetCfgWhole" || echo -ne "\n[${yellow}Network File${plain}] N/A"
  2447. echo -ne "\n[${yellow}Server Stack${plain}] $IPStackType\n"
  2448. [[ "$IPStackType" != "IPv6Stack" ]] && echo -ne "\n[${yellow}IPv4 Method${plain}] $Network4Config\n" || echo -ne "\n[${yellow}IPv4 Method${plain}] N/A\n"
  2449. [[ "$IPv4" && "$IPStackType" != "IPv6Stack" ]] && echo -e "[${yellow}IPv4 Address${plain}] ""$IPv4" || echo -e "[${yellow}IPv4 Address${plain}] ""N/A"
  2450. [[ "$IPv4" && "$IPStackType" != "IPv6Stack" ]] && echo -e "[${yellow}IPv4 Subnet${plain}] ""$actualIp4Subnet" || echo -e "[${yellow}IPv4 Subnet${plain}] ""N/A"
  2451. [[ "$IPv4" && "$IPStackType" != "IPv6Stack" ]] && echo -e "[${yellow}IPv4 Gateway${plain}] ""$GATE" || echo -e "[${yellow}IPv4 Gateway${plain}] ""N/A"
  2452. [[ "$IPv4" && "$IPStackType" != "IPv6Stack" ]] && echo -e "[${yellow}IPv4 DNS${plain}] ""$ipDNS" || echo -e "[${yellow}IPv4 DNS${plain}] ""N/A"
  2453. [[ "$IPStackType" != "IPv4Stack" ]] && echo -ne "\n[${yellow}IPv6 Method${plain}] $Network6Config\n" || echo -ne "\n[${yellow}IPv6 Method${plain}] N/A\n"
  2454. [[ "$ip6Addr" && "$IPStackType" != "IPv4Stack" ]] && echo -e "[${yellow}IPv6 Address${plain}] ""$ip6Addr" || echo -e "[${yellow}IPv6 Address${plain}] ""N/A"
  2455. [[ "$ip6Addr" && "$IPStackType" != "IPv4Stack" ]] && echo -e "[${yellow}IPv6 Subnet${plain}] ""$actualIp6Prefix" || echo -e "[${yellow}IPv6 Subnet${plain}] ""N/A"
  2456. [[ "$ip6Addr" && "$IPStackType" != "IPv4Stack" ]] && echo -e "[${yellow}IPv6 Gateway${plain}] ""$ip6Gate" || echo -e "[${yellow}IPv6 Gateway${plain}] ""N/A"
  2457. [[ "$ip6Addr" && "$IPStackType" != "IPv4Stack" ]] && echo -e "[${yellow}IPv6 DNS${plain}] ""$ip6DNS" || echo -e "[${yellow}IPv6 DNS${plain}] ""N/A"
  2458. getUserTimeZone "/root/timezonelists" "https://api.ip.sb/geoip/" "http://ifconfig.co/json?ip=" "http://ip-api.com/json/" "https://ipapi.co/" "YjNhNjAxNjY5YTFiNDI2MmFmOGYxYjJjZDk3ZjNiN2YK" "MmUxMjBhYmM0Y2Q4NDM1ZDhhMmQ5YzQzYzk4ZTZiZTEK" "NjBiMThjZWJlMWU1NGQ5NDg2YWY0MTgyMWM0ZTZiZDgK"
  2459. [[ -z "$TimeZone" ]] && TimeZone="Asia/Tokyo"
  2460. echo -ne "\n${aoiBlue}# User Timezone${plain}\n\n"
  2461. echo "$TimeZone"
  2462. [[ -z "$tmpWORD" || "$linux_relese" == 'alpinelinux' || "$targetRelese" == 'Ubuntu' ]] && tmpWORD='LeitboGi0ro'
  2463. myPASSWORD=$(openssl passwd -1 ''$tmpWORD'')
  2464. [[ -z "$myPASSWORD" ]] && myPASSWORD='$1$OCy2O5bt$m2N6XMgFUwCn/2PPP114J/'
  2465. echo -ne "\n${aoiBlue}# SSH or RDP Port, Username and Password${plain}\n\n"
  2466. if [[ "$targetRelese" == 'Windows' && "$tmpURL" == "" || "$tmpURL" =~ "dl.lamp.sh" ]]; then
  2467. echo "3389"
  2468. echo "Administrator"
  2469. echo "Teddysun.com"
  2470. elif [[ -z "$targetRelese" && "$ddMode" == '1' ]]; then
  2471. echo -e "N/A\nN/A\nN/A"
  2472. else
  2473. echo "$sshPORT"
  2474. echo "root"
  2475. echo "$tmpWORD"
  2476. fi
  2477. setDisk=$(echo "$setDisk" | sed 's/[A-Z]/\l&/g')
  2478. getDisk "$setDisk"
  2479. echo -ne "\n${aoiBlue}# Installing Disks${plain}\n\n"
  2480. [[ "$setDisk" == "all" || -n "$setRaid" ]] && echo "$AllDisks" || echo "$IncDisk"
  2481. echo -ne "\n${aoiBlue}# Motherboard Firmware${plain}\n\n"
  2482. [[ "$EfiSupport" == "enabled" ]] && echo "UEFI" || echo "BIOS"
  2483. # Get architecture of current os automatically
  2484. ArchName=`uname -m`
  2485. [[ -z "$ArchName" ]] && ArchName=$(echo `hostnamectl status | grep "Architecture" | cut -d':' -f 2`)
  2486. case $ArchName in arm64) VER="arm64";; aarch64) VER="aarch64";; x86|i386|i686) VER="i386";; x86_64) VER="x86_64";; x86-64) VER="x86-64";; amd64) VER="amd64";; *) VER="";; esac
  2487. # Exchange architecture name
  2488. if [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'ubuntu' ]] || [[ "$linux_relese" == 'kali' ]]; then
  2489. # In debian 12, the result of "uname -m" is "x86_64";
  2490. # the result of "echo `hostnamectl status | grep "Architecture" | cut -d':' -f 2`" is "x86-64"
  2491. if [[ "$VER" == "x86_64" ]] || [[ "$VER" == "x86-64" ]]; then
  2492. VER="amd64"
  2493. elif [[ "$VER" == "aarch64" ]]; then
  2494. VER="arm64"
  2495. fi
  2496. elif [[ "$linux_relese" == 'alpinelinux' ]] || [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]]; then
  2497. if [[ "$VER" == "amd64" ]] || [[ "$VER" == "x86-64" ]]; then
  2498. VER="x86_64"
  2499. elif [[ "$VER" == "arm64" ]]; then
  2500. VER="aarch64"
  2501. fi
  2502. fi
  2503. # Check and exchange input architecture name
  2504. tmpVER="$(echo "$tmpVER" |sed -r 's/(.*)/\L\1/')"
  2505. if [[ -n "$tmpVER" ]]; then
  2506. case "$tmpVER" in
  2507. i386|i686|x86|32)
  2508. VER="i386"
  2509. ;;
  2510. amd64|x86_64|x64|64)
  2511. [[ "$linux_relese" == 'alpinelinux' ]] || [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]] && VER='x86_64' || VER='amd64'
  2512. ;;
  2513. aarch64|arm64|arm)
  2514. [[ "$linux_relese" == 'alpinelinux' ]] || [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]] && VER='aarch64' || VER='arm64'
  2515. ;;
  2516. *)
  2517. VER=''
  2518. ;;
  2519. esac
  2520. fi
  2521. [[ ! -n "$VER" ]] && {
  2522. echo -ne "\n[${red}Error${plain}] Unknown architecture.\n"
  2523. bash $0 error
  2524. exit 1
  2525. }
  2526. [[ -z "$tmpDIST" ]] && {
  2527. [ "$Relese" == 'Debian' ] && tmpDIST='12'
  2528. [ "$Relese" == 'Kali' ] && tmpDIST='rolling'
  2529. [ "$Relese" == 'AlpineLinux' ] && tmpDIST='edge'
  2530. [ "$Relese" == 'CentOS' ] && tmpDIST='9'
  2531. [ "$Relese" == 'RockyLinux' ] && tmpDIST='9'
  2532. [ "$Relese" == 'AlmaLinux' ] && tmpDIST='9'
  2533. [ "$Relese" == 'Fedora' ] && tmpDIST='38'
  2534. }
  2535. [[ -z "$finalDIST" ]] && {
  2536. [ "$targetRelese" == 'Ubuntu' ] && finalDIST='22.04'
  2537. [ "$targetRelese" == 'Windows' ] && finalDIST='server 2022'
  2538. }
  2539. if [[ -n "$tmpDIST" ]]; then
  2540. if [[ "$Relese" == 'Debian' ]]; then
  2541. SpikCheckDIST='0'
  2542. DIST="$(echo "$tmpDIST" |sed -r 's/(.*)/\L\1/')"
  2543. DebianDistNum="${DIST}"
  2544. echo "$DIST" |grep -q '[0-9]'
  2545. [[ $? -eq '0' ]] && {
  2546. isDigital="$(echo "$DIST" |grep -o '[\.0-9]\{1,\}' |sed -n '1h;1!H;$g;s/\n//g;$p' |cut -d'.' -f1)";
  2547. [[ -n $isDigital ]] && {
  2548. [[ "$isDigital" == '7' ]] && DIST='wheezy'
  2549. [[ "$isDigital" == '8' ]] && DIST='jessie'
  2550. [[ "$isDigital" == '9' ]] && DIST='stretch'
  2551. [[ "$isDigital" == '10' ]] && DIST='buster'
  2552. [[ "$isDigital" == '11' ]] && DIST='bullseye'
  2553. [[ "$isDigital" == '12' ]] && DIST='bookworm'
  2554. [[ "$isDigital" == '13' ]] && DIST='trixie'
  2555. # [[ "$isDigital" == '14' ]] && DIST='forky'
  2556. # Debian releases TBA reference: https://wiki.debian.org/DebianReleases
  2557. # https://en.wikipedia.org/wiki/Debian_version_history#Release_table
  2558. }
  2559. }
  2560. LinuxMirror=$(selectMirror "$Relese" "$DIST" "$VER" "$tmpMirror")
  2561. fi
  2562. if [[ "$Relese" == 'Kali' ]]; then
  2563. SpikCheckDIST='0'
  2564. DIST="$(echo "$tmpDIST" |sed -r 's/(.*)/\L\1/')"
  2565. [[ ! "$DIST" =~ "kali-" ]] && DIST="kali-""$DIST"
  2566. # Kali Linux releases reference: https://www.kali.org/releases/
  2567. LinuxMirror=$(selectMirror "$Relese" "$DIST" "$VER" "$tmpMirror")
  2568. fi
  2569. if [[ "$Relese" == 'AlpineLinux' ]]; then
  2570. SpikCheckDIST='0'
  2571. DIST="$(echo "$tmpDIST" |sed -r 's/(.*)/\L\1/')"
  2572. # Recommend "edge" version of Alpine Linux to make sure to keep always updating.
  2573. AlpineVer1=`echo "$DIST" | sed 's/[a-z][A-Z]*//g' | cut -d"." -f 1`
  2574. AlpineVer2=`echo "$DIST" | sed 's/[a-z][A-Z]*//g' | cut -d"." -f 2`
  2575. if [[ "$AlpineVer1" -lt "3" || "$AlpineVer2" -le "15" ]] && [[ "$DIST" != "edge" ]]; then
  2576. echo -ne "\n[${red}Warning${plain}] $Relese $DIST is not supported!\n"
  2577. exit 1
  2578. fi
  2579. [[ "$DIST" != "edge" && ! "$DIST" =~ "v" ]] && DIST="v""$DIST"
  2580. # Alpine Linux releases reference: https://alpinelinux.org/releases/
  2581. LinuxMirror=$(selectMirror "$Relese" "$DIST" "$VER" "$tmpMirror")
  2582. fi
  2583. if [[ "$Relese" == 'CentOS' ]] || [[ "$Relese" == 'RockyLinux' ]] || [[ "$Relese" == 'AlmaLinux' ]] || [[ "$Relese" == 'Fedora' ]]; then
  2584. SpikCheckDIST='1'
  2585. DISTCheck="$(echo "$tmpDIST" |grep -o '[\.0-9]\{1,\}' |head -n1)"
  2586. RedHatSeries=`echo "$tmpDIST" | cut -d"." -f 1 | cut -d"-" -f 1`
  2587. # CentOS and CentOS stream releases history:
  2588. # https://endoflife.date/centos
  2589. if [[ "$linux_relese" == 'centos' ]]; then
  2590. [[ "$RedHatSeries" =~ [0-9]{${#1}} ]] && {
  2591. if [[ "$RedHatSeries" == "6" ]]; then
  2592. DISTCheck="6.10"
  2593. echo -ne "\n[${red}Warning${plain}] $Relese $DISTCheck is not supported!\n"
  2594. exit 1
  2595. elif [[ "$RedHatSeries" == "7" ]]; then
  2596. DISTCheck="7.9.2009"
  2597. elif [[ "$RedHatSeries" -ge "8" ]] && [[ ! "$RedHatSeries" =~ "-stream" ]]; then
  2598. DISTCheck="$RedHatSeries""-stream"
  2599. elif [[ "$RedHatSeries" -le "5" ]]; then
  2600. echo -ne "\n[${red}Warning${plain}] $Relese $DISTCheck is not supported!\n"
  2601. else
  2602. echo -ne "\n[${red}Error${plain}] Invaild $DIST! version!\n"
  2603. fi
  2604. }
  2605. LinuxMirror=$(selectMirror "$Relese" "$DISTCheck" "$VER" "$tmpMirror")
  2606. DIST="$DISTCheck"
  2607. fi
  2608. if [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]]; then
  2609. [[ "$RedHatSeries" =~ [0-9]{${#1}} ]] && {
  2610. # RockyLinux releases history:
  2611. # https://wiki.rockylinux.org/rocky/version/
  2612. # AlmaLinux releases history:
  2613. # https://wiki.almalinux.org/release-notes/
  2614. if [[ "$linux_relese" == 'rockylinux' || "$linux_relese" == 'almalinux' ]] && [[ "$RedHatSeries" -le "7" ]]; then
  2615. echo -ne "\n[${red}Warning${plain}] $Relese $DISTCheck is not supported!\n"
  2616. exit 1
  2617. # Fedora releases history:
  2618. # https://en.wikipedia.org/wiki/Fedora_Linux_release_history
  2619. elif [[ "$linux_relese" == 'fedora' ]] && [[ "$RedHatSeries" -le "36" ]]; then
  2620. echo -ne "\n[${red}Warning${plain}] $Relese $DISTCheck is not supported!\n"
  2621. exit 1
  2622. fi
  2623. }
  2624. LinuxMirror=$(selectMirror "$Relese" "$DISTCheck" "$VER" "$tmpMirror")
  2625. DIST="$DISTCheck"
  2626. fi
  2627. [[ -z "$DIST" ]] && {
  2628. echo -ne '\nThe dists version not found in this mirror, Please check it! \n\n'
  2629. bash $0 error
  2630. exit 1
  2631. }
  2632. if [[ "$linux_relese" == 'centos' ]] && [[ "$RedHatSeries" -le "7" ]]; then
  2633. wget --no-check-certificate -qO- "$LinuxMirror/$DIST/os/$VER/.treeinfo" | grep -q 'general'
  2634. [[ $? != '0' ]] && {
  2635. echo -ne "\n[${red}Warning${plain}] $Relese $DISTCheck was not found in this mirror, Please change mirror try again!\n"
  2636. exit 1
  2637. }
  2638. elif [[ "$linux_relese" == 'centos' && "$RedHatSeries" -ge "8" ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]]; then
  2639. wget --no-check-certificate -qO- "$LinuxMirror/$DIST/BaseOS/$VER/os/media.repo" | grep -q 'mediaid'
  2640. [[ $? != '0' ]] && {
  2641. echo -ne "\n[${red}Warning${plain}] $Relese $DISTCheck was not found in this mirror, Please change mirror try again!\n"
  2642. exit 1
  2643. }
  2644. elif [[ "$linux_relese" == 'fedora' ]]; then
  2645. wget --no-check-certificate -qO- "$LinuxMirror/releases/$DIST/Server/$VER/os/media.repo" | grep -q 'mediaid'
  2646. [[ $? != '0' ]] && {
  2647. echo -ne "\n[${red}Warning${plain}] $Relese $DISTCheck was not found in this mirror, Please change mirror try again!\n"
  2648. exit 1
  2649. }
  2650. fi
  2651. fi
  2652. fi
  2653. [[ -z "$LinuxMirror" ]] && {
  2654. echo -ne "\n[${red}Error${plain}] Invaild mirror! \n"
  2655. [ "$Relese" == 'Debian' ] && echo -ne "${yellow}Please check mirror lists:${plain} https://www.debian.org/mirror/list\n\n"
  2656. [ "$Relese" == 'Ubuntu' ] && echo -ne "${yellow}Please check mirror lists:${plain} https://launchpad.net/ubuntu/+archivemirrors\n\n"
  2657. [ "$Relese" == 'Kali' ] && echo -ne "${yellow}Please check mirror lists:${plain} https://http.kali.org/README.mirrorlist\n\n"
  2658. [ "$Relese" == 'AlpineLinux' ] && echo -ne "${yellow}Please check mirror lists:${plain} https://mirrors.alpinelinux.org/\n\n"
  2659. [ "$Relese" == 'CentOS' ] && echo -ne "${yellow}Please check mirror lists:${plain} https://www.centos.org/download/mirrors/\n\n"
  2660. [ "$Relese" == 'RockyLinux' ] && echo -ne "${yellow}Please check mirror lists:${plain} https://mirrors.rockylinux.org/mirrormanager/mirrors\n\n"
  2661. [ "$Relese" == 'AlmaLinux' ] && echo -ne "${yellow}Please check mirror lists:${plain} https://mirrors.almalinux.org/\n\n"
  2662. [ "$Relese" == 'Fedora' ] && echo -ne "${yellow}Please check mirror lists:${plain} https://mirrors.fedoraproject.org/\n\n"
  2663. # bash $0 error
  2664. exit 1
  2665. }
  2666. [[ "$setNetbootXyz" == "1" ]] && SpikCheckDIST="1"
  2667. if [[ "$SpikCheckDIST" == '0' ]]; then
  2668. echo -ne "\n${aoiBlue}# Check DIST${plain}\n"
  2669. DistsList="$(wget --no-check-certificate -qO- "$LinuxMirror/dists/" |grep -o 'href=.*/"' |cut -d'"' -f2 |sed '/-\|old\|Debian\|experimental\|stable\|test\|sid\|devel/d' |grep '^[^/]' |sed -n '1h;1!H;$g;s/\n//g;s/\//\;/g;$p')"
  2670. [[ "$linux_relese" == 'kali' ]] && DistsList="$(wget --no-check-certificate -qO- "$LinuxMirror/dists/" | grep -o 'href=.*/"' | cut -d'"' -f2 | grep '^[^/]' | sed -n '1h;1!H;$g;s/\n//g;s/\//\;/g;$p')"
  2671. [[ "$linux_relese" == 'alpinelinux' ]] && DistsList="$(wget --no-check-certificate -qO- "$LinuxMirror/" | grep -o 'href=.*/"' | cut -d'"' -f2 | grep '^[^/]' | sed -n '1h;1!H;$g;s/\n//g;s/\//\;/g;$p')"
  2672. for CheckDEB in `echo "$DistsList" |sed 's/;/\n/g'`
  2673. do
  2674. # In some mirror, the value of parameter "DistsList" is "?C=N;O=Dbookworm;bullseye;buster;http:;;wisepoint.jp;product;wpshibb;"
  2675. # The second item in "DistsList" which is splited by ";" is O=Dbookworm.
  2676. # So we need to check whether "DIST" is approximately equal(contains) to "CheckDEB".
  2677. [[ "$CheckDEB" =~ "$DIST" ]] && FindDists='1' && break;
  2678. done
  2679. [[ "$FindDists" == '0' ]] && {
  2680. echo -ne '\n[${red}Error${plain}] The dists version not found, Please check it! \n\n'
  2681. exit 1
  2682. }
  2683. echo -e "\nSuccess"
  2684. fi
  2685. if [[ "$ddMode" == '1' ]]; then
  2686. if [[ "$targetRelese" == 'Ubuntu' ]]; then
  2687. ubuntuDIST="$(echo "$finalDIST" |sed -r 's/(.*)/\L\1/')"
  2688. UbuntuDistNum=`echo "$ubuntuDIST" | cut -d'.' -f1`
  2689. echo "$ubuntuDIST" |grep -q '[0-9]'
  2690. [[ $? -eq '0' ]] && {
  2691. ubuntuDigital="$(echo "$ubuntuDIST" |grep -o '[\.0-9]\{1,\}' |sed -n '1h;1!H;$g;s/\n//g;$p')"
  2692. ubuntuDigital1=`echo "$ubuntuDigital" | cut -d'.' -f1`
  2693. ubuntuDigital2=`echo "$ubuntuDigital" | cut -d'.' -f2`
  2694. if [[ "$ubuntuDigital1" -le "19" || "$ubuntuDigital1" -ge "23" || $((${ubuntuDigital1} % 2)) = 1 ]] || [[ "$ubuntuDigital2" != "04" ]]; then
  2695. echo -ne "\n[${red}Error${plain}] The dists version not found, Please check it! \n'"
  2696. exit 1
  2697. fi
  2698. [[ -n $ubuntuDigital ]] && {
  2699. # [[ "$ubuntuDigital" == '12.04' ]] && finalDIST='precise'
  2700. # [[ "$ubuntuDigital" == '14.04' ]] && finalDIST='trusty'
  2701. # [[ "$ubuntuDigital" == '16.04' ]] && finalDIST='xenial'
  2702. # [[ "$ubuntuDigital" == '18.04' ]] && finalDIST='bionic'
  2703. [[ "$ubuntuDigital" == '20.04' ]] && finalDIST='focal'
  2704. # Ubuntu 22.04 and future versions started to using "Cloud-init" to replace legacy "d-i(Debian installer)" which is designed to support network installation of Debian like system.
  2705. # "Cloud-init" make a high hardware requirements of the server, one requirement must be demanded is CPU virtualization support.
  2706. # Many vps which are virtualizated by a physical machine, despite parent machine support virtualization, but sub-servers don't support.
  2707. # Because Ubuntu 22.04 and future version removed critical file of "initrd.gz" and "linux" which are critical files to implement "d-i".
  2708. # For example, the official of Ubuntu 22.04(jammy) mirror site doesn't provide any related files to download, the following is here:
  2709. # http://archive.ubuntu.com/ubuntu/dists/jammy/main/installer-amd64/current/legacy-images/
  2710. # So we have no possibility to accomplish Ubuntu network installation in future.
  2711. # Canonical.inc is son of a bitch, they change back and forth, pood and pee everywhere.
  2712. # More discussions: https://discourse.ubuntu.com/t/netbooting-the-live-server-installer/14510/18
  2713. [[ "$ubuntuDigital" == '22.04' ]] && finalDIST='jammy'
  2714. # Ubuntu releases reference: https://releases.ubuntu.com/
  2715. }
  2716. }
  2717. if [[ "$VER" == "x86_64" ]] || [[ "$VER" == "x86-64" ]]; then
  2718. ubuntuVER="amd64"
  2719. elif [[ "$VER" == "aarch64" ]]; then
  2720. ubuntuVER="arm64"
  2721. fi
  2722. if [[ "$tmpURL" == "" ]]; then
  2723. tmpURL="https://cloud-images.a.disk.re/Ubuntu/"
  2724. fi
  2725. echo "$tmpURL" | grep -q '^http://\|^ftp://\|^https://'
  2726. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Please input a vaild URL, only support http://, ftp:// and https:// ! \n" && exit 1
  2727. tmpURLCheck=$(echo $(curl -s -I -X GET $tmpURL) | grep -wi "http/[0-9]*" | awk '{print $2}')
  2728. [[ -z "$tmpURLCheck" || ! "$tmpURLCheck" =~ ^[0-9]+$ ]] && {
  2729. echo -ne "\n[${red}Error${plain}] The mirror of DD images is temporarily unavailable!\n"
  2730. exit 1
  2731. }
  2732. DDURL="$tmpURL$finalDIST-server-cloudimg-$ubuntuVER.raw"
  2733. ReleaseName="$targetRelese $finalDIST $ubuntuVER"
  2734. elif [[ "$targetRelese" == 'Windows' ]]; then
  2735. if [[ -z "$tmpURL" ]]; then
  2736. tmpURL="https://dl.lamp.sh/vhd"
  2737. [[ `echo "$finalDIST" | grep -i "server"` ]] && tmpFinalDIST=`echo $finalDIST | awk -F ' |-|_' '{print $2}'`
  2738. [[ `echo "$finalDIST" | grep -i "pro"` || `echo "$finalDIST" | grep -i "ltsc"` ]] && tmpFinalDIST=`echo $finalDIST | awk -F ' |-|_' '{print $1}'`
  2739. [[ "$finalDIST" =~ ^[0-9]+$ ]] && tmpFinalDIST="$finalDIST"
  2740. if [[ "$tmpFinalDIST" -ge "2012" && "$tmpFinalDIST" -le "2019" ]]; then
  2741. tmpTargetLang="$targetLang"
  2742. else
  2743. [[ "$targetLang" == 'cn' ]] && tmpTargetLang="zh-""$targetLang"
  2744. [[ "$targetLang" == 'en' ]] && tmpTargetLang="$targetLang""-us"
  2745. [[ "$targetLang" == 'ja' ]] && tmpTargetLang="ja-""$targetLang"
  2746. fi
  2747. if [[ "$tmpFinalDIST" == "2012" ]]; then
  2748. tmpURL="$tmpURL/"${tmpTargetLang}"_win"${tmpFinalDIST}"r2.xz"
  2749. showFinalDIST="Server $tmpFinalDIST R2"
  2750. elif [[ "$tmpFinalDIST" -ge "2016" && "$tmpFinalDIST" -le "2022" ]]; then
  2751. tmpURL="$tmpURL/"${tmpTargetLang}"_win"${tmpFinalDIST}".xz"
  2752. showFinalDIST="Server $tmpFinalDIST"
  2753. elif [[ "$tmpFinalDIST" -ge "10" && "$tmpFinalDIST" -le "11" ]]; then
  2754. [[ "$tmpFinalDIST" == "10" ]] && { tmpURL="$tmpURL/"${tmpTargetLang}"_windows"${tmpFinalDIST}"_ltsc.xz"; showFinalDIST="$tmpFinalDIST Enterprise LTSC"; }
  2755. [[ "$tmpFinalDIST" == "11" ]] && { tmpURL="$tmpURL/"${tmpTargetLang}"_windows"${tmpFinalDIST}"_22h2.xz"; showFinalDIST="$tmpFinalDIST Pro for Workstations 22H2"; }
  2756. fi
  2757. if [[ "$EfiSupport" == "enabled" ]]; then
  2758. [[ "$tmpFinalDIST" == "10" ]] && tmpURL=`echo $tmpURL | sed 's/windows/win/g'`
  2759. tmpURL=`echo $tmpURL | sed 's/...$/_uefi.xz/g'`
  2760. fi
  2761. ReleaseName="$targetRelese $showFinalDIST"
  2762. else
  2763. showFinalDIST=""
  2764. ReleaseName="$targetRelese"
  2765. fi
  2766. verifyUrlValidationOfDdImages "$tmpURL"
  2767. elif [[ -z "$targetRelese" && "$tmpURL" != "" ]]; then
  2768. verifyUrlValidationOfDdImages "$tmpURL"
  2769. ReleaseName="Self-Modified OS"
  2770. else
  2771. echo -ne "\n[${red}Warning${plain}] Please input a vaild image URL!\n"
  2772. exit 1
  2773. fi
  2774. fi
  2775. if [ -z "$interfaceSelect" ]; then
  2776. if [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'ubuntu' ]] || [[ "$linux_relese" == 'kali' ]]; then
  2777. interfaceSelect="auto"
  2778. elif [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]]; then
  2779. interfaceSelect="link"
  2780. fi
  2781. else
  2782. # If the kernel of original system is loaded with parameter "net.ifnames=0 biosdevname=0" and users don't want to set this
  2783. # one in new system, they have to assign a valid, real name of their network adapter and the parameter "$interface"
  2784. # will be written to new network configuration in preseed file for new system.
  2785. interface4=`echo "$interfaceSelect" | cut -d' ' -f 1`
  2786. interface6=`echo "$interfaceSelect" | cut -d' ' -f 2`
  2787. interface="$interface4"
  2788. [[ -z "$interface6" ]] && {
  2789. interface=`echo "$interfaceSelect" | sed 's/[[:space:]]//g'`
  2790. interface6="$interface"
  2791. }
  2792. fi
  2793. # The first network adapter name is must be "eth0" if kernel is loaded with parameter "net.ifnames=0 biosdevname=0".
  2794. [[ "$setInterfaceName" == "1" ]] && {
  2795. interface="eth0"
  2796. interface4="eth0"
  2797. interface6="eth0"
  2798. [[ -n "$interface4" && -n "$interface6" && "$interface4" != "$interface6" ]] && {
  2799. interface4="eth0"
  2800. interface6="eth1"
  2801. }
  2802. }
  2803. echo -ne "\n${aoiBlue}# Installation Starting${plain}\n"
  2804. [[ "$ddMode" == '1' ]] && echo -ne "${blue}Auto Mode${plain} Insatll [${yellow}$ReleaseName${plain}]\n$DDURL\n"
  2805. if [[ "$linux_relese" == 'centos' ]]; then
  2806. if [[ "$DIST" != "$UNVER" ]]; then
  2807. awk 'BEGIN{print '${UNVER}'-'${DIST}'}' |grep -q '^-'
  2808. if [ $? != '0' ]; then
  2809. UNKNOWHW='1'
  2810. echo -ne "\nThe version lower than ${red}$UNVER${plain} may not support in auto mode!\n"
  2811. fi
  2812. fi
  2813. fi
  2814. [[ "$setNetbootXyz" == "0" ]] && echo -ne "\n[${yellow}$Relese${plain}] [${yellow}$DIST${plain}] [${yellow}$VER${plain}] Downloading...\n" || echo -ne "\n[${yellow}netboot.xyz${plain}] Downloading...\n"
  2815. # RAM of RedHat series is 2GB required at least.
  2816. [[ "$setNetbootXyz" == "0" ]] && {
  2817. checkMem "$linux_relese" "$RedHatSeries" "$targetRelese"
  2818. Add_OPTION="$Add_OPTION $lowmemLevel"
  2819. }
  2820. if [[ "$setNetbootXyz" == "1" ]]; then
  2821. [[ "$VER" == "x86_64" || "$VER" == "amd64" ]] && apt install grub-imageboot -y
  2822. if [[ "$EfiSupport" == "enabled" ]] || [[ "$VER" == "aarch64" || "$VER" == "arm64" ]]; then
  2823. echo -ne "\n[${red}Error${plain}] Netbootxyz doesn't support $VER architecture!\n"
  2824. bash $0 error
  2825. exit 1
  2826. fi
  2827. # NetbootXYZ set to boot from an existing Linux installation using GRUB
  2828. # Reference: https://netboot.xyz/docs/booting/grub
  2829. if [[ "$IsCN" == "cn" ]]; then
  2830. NetbootXyzUrl="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/RedHat/NetbootXyz/netboot.xyz.iso"
  2831. NetbootXyzGrub="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/RedHat/NetbootXyz/60_grub-imageboot"
  2832. else
  2833. NetbootXyzUrl="https://boot.netboot.xyz/ipxe/netboot.xyz.iso"
  2834. NetbootXyzGrub="https://raw.githubusercontent.com/formorer/grub-imageboot/master/bin/60_grub-imageboot"
  2835. fi
  2836. [[ ! -d "/boot/images/" ]] && mkdir /boot/images/
  2837. rm -rf /boot/images/netboot.xyz.iso
  2838. echo -ne "[${yellow}Mirror${plain}] $NetbootXyzUrl\n"
  2839. wget --no-check-certificate -qO '/boot/images/netboot.xyz.iso' "$NetbootXyzUrl"
  2840. [[ ! -f "/etc/grub.d/60_grub-imageboot" ]] && wget --no-check-certificate -qO '/etc/grub.d/60_grub-imageboot' "$NetbootXyzGrub"
  2841. chmod 755 /etc/grub.d/60_grub-imageboot
  2842. [[ ! -z "$GRUBTYPE" && "$GRUBTYPE" == "isGrub2" ]] && {
  2843. rm -rf /boot/memdisk
  2844. cp /usr/share/syslinux/memdisk /boot/memdisk
  2845. ln -s /usr/share/grub/grub-mkconfig_lib /usr/lib/grub/grub-mkconfig_lib
  2846. }
  2847. elif [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'ubuntu' ]] || [[ "$linux_relese" == 'kali' ]]; then
  2848. [ "$DIST" == "focal" ] && legacy="legacy-" || legacy=""
  2849. InitrdUrl="${LinuxMirror}/dists/${DIST}/main/installer-${VER}/current/${legacy}images/netboot/${linux_relese}-installer/${VER}/initrd.gz"
  2850. VmLinuzUrl="${LinuxMirror}/dists/${DIST}${inUpdate}/main/installer-${VER}/current/${legacy}images/netboot/${linux_relese}-installer/${VER}/linux"
  2851. [[ "$linux_relese" == 'kali' ]] && {
  2852. InitrdUrl="${LinuxMirror}/dists/${DIST}/main/installer-${VER}/current/images/netboot/debian-installer/${VER}/initrd.gz"
  2853. VmLinuzUrl="${LinuxMirror}/dists/${DIST}/main/installer-${VER}/current/images/netboot/debian-installer/${VER}/linux"
  2854. }
  2855. echo -ne "[${yellow}Mirror${plain}] $InitrdUrl\n\t $VmLinuzUrl\n"
  2856. wget --no-check-certificate -qO '/tmp/initrd.img' "$InitrdUrl"
  2857. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download 'initrd.img' for ${yellow}$linux_relese${plain} failed! \n" && exit 1
  2858. wget --no-check-certificate -qO '/tmp/vmlinuz' "$VmLinuzUrl"
  2859. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download 'vmlinuz' for ${yellow}$linux_relese${plain} failed! \n" && exit 1
  2860. MirrorHost="$(echo "$LinuxMirror" |awk -F'://|/' '{print $2}')"
  2861. MirrorFolder="$(echo "$LinuxMirror" |awk -F''${MirrorHost}'' '{print $2}')"
  2862. [ -n "$MirrorFolder" ] || MirrorFolder="/"
  2863. elif [[ "$linux_relese" == 'alpinelinux' ]]; then
  2864. InitrdUrl="${LinuxMirror}/${DIST}/releases/${VER}/netboot/initramfs-lts"
  2865. VmLinuzUrl="${LinuxMirror}/${DIST}/releases/${VER}/netboot/vmlinuz-lts"
  2866. ModLoopUrl="${LinuxMirror}/${DIST}/releases/${VER}/netboot/modloop-lts"
  2867. echo -ne "[${yellow}Mirror${plain}] $InitrdUrl\n\t $VmLinuzUrl\n"
  2868. wget --no-check-certificate -qO '/tmp/initrd.img' "$InitrdUrl"
  2869. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download 'initramfs-lts' for ${yellow}$linux_relese${plain} failed! \n" && exit 1
  2870. wget --no-check-certificate -qO '/tmp/vmlinuz' "$VmLinuzUrl"
  2871. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download 'vmlinuz-lts' for ${yellow}$linux_relese${plain} failed! \n" && exit 1
  2872. elif [[ "$linux_relese" == 'centos' ]] && [[ "$RedHatSeries" -le "7" ]]; then
  2873. InitrdUrl="${LinuxMirror}/${DIST}/os/${VER}/images/pxeboot/initrd.img"
  2874. VmLinuzUrl="${LinuxMirror}/${DIST}/os/${VER}/images/pxeboot/vmlinuz"
  2875. echo -ne "[${yellow}Mirror${plain}] $InitrdUrl\n\t $VmLinuzUrl\n"
  2876. wget --no-check-certificate -qO '/tmp/initrd.img' "$InitrdUrl"
  2877. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download 'initrd.img' for ${yellow}$linux_relese${plain} failed! \n" && exit 1
  2878. wget --no-check-certificate -qO '/tmp/vmlinuz' "$VmLinuzUrl"
  2879. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download 'vmlinuz' for ${yellow}$linux_relese${plain} failed! \n" && exit 1
  2880. elif [[ "$linux_relese" == 'centos' && "$RedHatSeries" -ge "8" ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]]; then
  2881. InitrdUrl="${LinuxMirror}/${DIST}/BaseOS/${VER}/os/images/pxeboot/initrd.img"
  2882. VmLinuzUrl="${LinuxMirror}/${DIST}/BaseOS/${VER}/os/images/pxeboot/vmlinuz"
  2883. echo -ne "[${yellow}Mirror${plain}] $InitrdUrl\n\t $VmLinuzUrl\n"
  2884. wget --no-check-certificate -qO '/tmp/initrd.img' "$InitrdUrl"
  2885. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download 'initrd.img' for ${yellow}$linux_relese${plain} failed! \n" && exit 1
  2886. wget --no-check-certificate -qO '/tmp/vmlinuz' "$VmLinuzUrl"
  2887. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download 'vmlinuz' for ${yellow}$linux_relese${plain} failed! \n" && exit 1
  2888. elif [[ "$linux_relese" == 'fedora' ]]; then
  2889. InitrdUrl="${LinuxMirror}/releases/${DIST}/Server/${VER}/os/images/pxeboot/initrd.img"
  2890. VmLinuzUrl="${LinuxMirror}/releases/${DIST}/Server/${VER}/os/images/pxeboot/vmlinuz"
  2891. echo -ne "[${yellow}Mirror${plain}] $InitrdUrl\n\t $VmLinuzUrl\n"
  2892. wget --no-check-certificate -qO '/tmp/initrd.img' "$InitrdUrl"
  2893. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download 'initrd.img' for ${yellow}$linux_relese${plain} failed! \n" && exit 1
  2894. wget --no-check-certificate -qO '/tmp/vmlinuz' "$VmLinuzUrl"
  2895. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download 'vmlinuz' for ${yellow}$linux_relese${plain} failed! \n" && exit 1
  2896. else
  2897. bash $0 error
  2898. exit 1
  2899. fi
  2900. if [[ "$IncFirmware" == '1' ]]; then
  2901. if [[ "$linux_relese" == 'debian' ]]; then
  2902. if [[ "$IsCN" == "cn" ]]; then
  2903. wget --no-check-certificate -qO '/tmp/firmware.cpio.gz' "https://mirrors.ustc.edu.cn/debian-cdimage/unofficial/non-free/firmware/${DIST}/current/firmware.cpio.gz"
  2904. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download firmware for ${red}$linux_relese${plain} failed! \n" && exit 1
  2905. else
  2906. wget --no-check-certificate -qO '/tmp/firmware.cpio.gz' "http://cdimage.debian.org/cdimage/unofficial/non-free/firmware/${DIST}/current/firmware.cpio.gz"
  2907. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download firmware for ${red}$linux_relese${plain} failed! \n" && exit 1
  2908. fi
  2909. if [[ "$ddMode" == '1' ]]; then
  2910. vKernel_udeb=$(wget --no-check-certificate -qO- "http://$LinuxMirror/dists/$DIST/main/installer-$VER/current/images/udeb.list" | grep '^acpi-modules' | head -n1 | grep -o '[0-9]\{1,2\}.[0-9]\{1,2\}.[0-9]\{1,2\}-[0-9]\{1,2\}' | head -n1)
  2911. [[ -z "vKernel_udeb" ]] && vKernel_udeb="6.1.0-11"
  2912. fi
  2913. elif [[ "$linux_relese" == 'kali' ]]; then
  2914. if [[ "$IsCN" == "cn" ]]; then
  2915. wget --no-check-certificate -qO /root/kaliFirmwareCheck 'https://mirrors.tuna.tsinghua.edu.cn/kali/pool/non-free/f/firmware-nonfree/?C=S&O=D'
  2916. kaliFirmwareName=$(grep "href=\"firmware-nonfree" /root/kaliFirmwareCheck | head -n 1 | awk -F'\">' '/tar.xz/{print $3}' | cut -d'<' -f1 | cut -d'/' -f2)
  2917. wget --no-check-certificate -qO '/tmp/kali_firmware.tar.xz' "https://mirrors.tuna.tsinghua.edu.cn/kali/pool/non-free/f/firmware-nonfree/$kaliFirmwareName"
  2918. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download firmware for ${red}$linux_relese${plain} failed! \n" && exit 1
  2919. rm -rf /root/kaliFirmwareCheck
  2920. else
  2921. wget --no-check-certificate -qO /root/kaliFirmwareCheck 'https://mirrors.ocf.berkeley.edu/kali/pool/non-free/f/firmware-nonfree/?C=S&O=D'
  2922. kaliFirmwareName=$(grep "href=\"firmware-nonfree" /root/kaliFirmwareCheck | head -n 1 | awk -F'\">' '/tar.xz/{print $3}' | cut -d'<' -f1 | cut -d'/' -f2)
  2923. wget --no-check-certificate -qO '/tmp/kali_firmware.tar.xz' "https://mirrors.ocf.berkeley.edu/kali/pool/non-free/f/firmware-nonfree/$kaliFirmwareName"
  2924. [[ $? -ne '0' ]] && echo -ne "\n[${red}Error${plain}] Download firmware for ${red}$linux_relese${plain} failed! \n" && exit 1
  2925. rm -rf /root/kaliFirmwareCheck
  2926. fi
  2927. decompressedKaliFirmwareDir=$(echo $kaliFirmwareName | cut -d'.' -f 1 | sed 's/_/-/g')
  2928. fi
  2929. fi
  2930. [[ -d /tmp/boot ]] && rm -rf /tmp/boot
  2931. mkdir -p /tmp/boot
  2932. cd /tmp/boot
  2933. if [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'ubuntu' ]] || [[ "$linux_relese" == 'kali' ]] || [[ "$linux_relese" == 'alpinelinux' ]]; then
  2934. COMPTYPE="gzip"
  2935. elif [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]]; then
  2936. COMPTYPE="$(file ../initrd.img |grep -o ':.*compressed data' |cut -d' ' -f2 |sed -r 's/(.*)/\L\1/' |head -n1)"
  2937. [[ -z "$COMPTYPE" ]] && echo "Detect compressed type fail." && exit 1
  2938. fi
  2939. CompDected='0'
  2940. for COMP in `echo -en 'gzip\nlzma\nxz'`
  2941. do
  2942. if [[ "$COMPTYPE" == "$COMP" ]]; then
  2943. CompDected='1'
  2944. if [[ "$COMPTYPE" == 'gzip' ]]; then
  2945. NewIMG="initrd.img.gz"
  2946. else
  2947. NewIMG="initrd.img.$COMPTYPE"
  2948. fi
  2949. mv -f "/tmp/initrd.img" "/tmp/$NewIMG"
  2950. break;
  2951. fi
  2952. done
  2953. [[ "$CompDected" != '1' ]] && echo "Detect compressed type not support." && exit 1
  2954. [[ "$COMPTYPE" == 'lzma' ]] && UNCOMP='xz --format=lzma --decompress'
  2955. [[ "$COMPTYPE" == 'xz' ]] && UNCOMP='xz --decompress'
  2956. [[ "$COMPTYPE" == 'gzip' ]] && UNCOMP='gzip -d'
  2957. $UNCOMP < /tmp/$NewIMG | cpio --extract --make-directories --preserve-modification-time >>/dev/null 2>&1
  2958. if [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'kali' ]] || [[ "$linux_relese" == 'ubuntu' ]]; then
  2959. DebianPreseedProcess
  2960. if [[ "$loaderMode" != "0" ]] && [[ "$setNet" == '0' ]]; then
  2961. sed -i '/netcfg\/disable_autoconfig/d' /tmp/boot/preseed.cfg
  2962. sed -i '/netcfg\/dhcp_options/d' /tmp/boot/preseed.cfg
  2963. sed -i '/netcfg\/get_.*/d' /tmp/boot/preseed.cfg
  2964. sed -i '/netcfg\/confirm_static/d' /tmp/boot/preseed.cfg
  2965. fi
  2966. # If server has only one disk, lv/vg/pv volumes removement by force should be disallowed, it may causes partitioner continuous execution but not finished.
  2967. if [[ "$disksNum" -le "1" || "$setDisk" != "all" || -n "$setRaid" ]]; then
  2968. sed -i 's/lvremove --select all -ff -y;//g' /tmp/boot/preseed.cfg
  2969. sed -i 's/vgremove --select all -ff -y;//g' /tmp/boot/preseed.cfg
  2970. sed -i 's/pvremove \/dev\/\* -ff -y;//g' /tmp/boot/preseed.cfg
  2971. elif [[ "$disksNum" -gt "1" && "$setDisk" == "all" ]]; then
  2972. # Some virtual machines will hanging on partition step if execute pvremove.
  2973. [[ -z "$virtWhat" ]] || sed -i 's/pvremove \/dev\/\* -ff -y;//g' /tmp/boot/preseed.cfg
  2974. fi
  2975. if [[ "$disksNum" -gt "1" ]] && [[ -n "$setRaid" ]]; then
  2976. sed -i 's/d-i partman\/early_command.*//g' /tmp/boot/preseed.cfg
  2977. sed -ri "/d-i grub-installer\/bootdev.*/c\d-i grub-installer\/bootdev string $AllDisks" /tmp/boot/preseed.cfg
  2978. fi
  2979. # Debian 8 and former or Raid mode don't support xfs.
  2980. [[ "$DebianDistNum" -le "8" || -n "$setRaid" ]] && sed -i '/d-i\ partman\/default_filesystem string xfs/d' /tmp/boot/preseed.cfg
  2981. if [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'kali' ]]; then
  2982. sed -i '/user-setup\/allow-password-weak/d' /tmp/boot/preseed.cfg
  2983. sed -i '/user-setup\/encrypt-home/d' /tmp/boot/preseed.cfg
  2984. sed -i '/pkgsel\/update-policy/d' /tmp/boot/preseed.cfg
  2985. sed -i 's/umount\ \/media.*true\;\ //g' /tmp/boot/preseed.cfg
  2986. [[ -f '/tmp/firmware.cpio.gz' ]] && gzip -d < /tmp/firmware.cpio.gz | cpio --extract --verbose --make-directories --no-absolute-filenames >>/dev/null 2>&1
  2987. # Uncompressed hardware drivers size of Kali firmware non-free such as "firmware-nonfree_20230210.orig.tar.xz" is almost 800MB,
  2988. # if the physical memory of server is below 3GB, I suggested that not load parameter "-firmware".
  2989. [[ -f '/tmp/kali_firmware.tar.xz' ]] && {
  2990. tar -Jxvf '/tmp/kali_firmware.tar.xz' -C /tmp/
  2991. mv /tmp/$decompressedKaliFirmwareDir/* '/tmp/boot/lib/firmware/'
  2992. }
  2993. fi
  2994. # To avoid to entry into low memory mode.
  2995. [[ "$TotalMem1" -ge "2558072" || "$TotalMem2" -ge "2558072" ]] && sed -i '/d-i\ lowmem\/low boolean true/d' /tmp/boot/preseed.cfg
  2996. # Ubuntu 20.04 and below does't support xfs, force grub-efi installation to the removable media path may cause grub install failed, low memory mode.
  2997. if [[ "$linux_relese" == 'ubuntu' ]]; then
  2998. sed -i '/d-i\ partman\/default_filesystem string xfs/d' /tmp/boot/preseed.cfg
  2999. sed -i '/d-i\ grub-installer\/force-efi-extra-removable/d' /tmp/boot/preseed.cfg
  3000. sed -i '/d-i\ lowmem\/low boolean true/d' /tmp/boot/preseed.cfg
  3001. fi
  3002. if [[ "$partitionTable" == "gpt" ]]; then
  3003. sed -i 's/default_filesystem string ext4/default_filesystem string xfs/g' /tmp/boot/preseed.cfg
  3004. fi
  3005. # Kali preseed.cfg reference:
  3006. # https://github.com/iesplin/kali-preseed/blob/master/preseed/core-minimal.cfg
  3007. #
  3008. # Kali metapackages reference:
  3009. # https://www.kali.org/docs/general-use/metapackages/
  3010. if [[ "$linux_relese" == 'kali' ]]; then
  3011. sed -i 's/first multiselect minimal/first multiselect standard/g' /tmp/boot/preseed.cfg
  3012. sed -i 's/upgrade select none/upgrade select full-upgrade/g' /tmp/boot/preseed.cfg
  3013. sed -i 's/include string openssh-server/include string kali-linux-core openssh-server/g' /tmp/boot/preseed.cfg
  3014. sed -i 's/d-i grub-installer\/with_other_os boolean true//g' /tmp/boot/preseed.cfg
  3015. fi
  3016. # Disable get security updates for those versions of Debian which were 'EOL'(9 and former in 2023.07).
  3017. if [[ "$linux_relese" != 'kali' ]]; then
  3018. if [[ "$tmpIpMask" -ge "16" || "$IPStackType" == "IPv6Stack" || "$BiStackPreferIpv6Status" == "1" || "$BurnIrregularIpv4Status" == "1" ]] && [[ "$linux_relese" == 'debian' && "$DebianDistNum" -gt "9" ]]; then
  3019. sed -i '/d-i\ apt-setup\/services-select multiselect/d' /tmp/boot/preseed.cfg
  3020. sed -i '/d-i\ apt-setup\/enable-source-repositories boolean false/d' /tmp/boot/preseed.cfg
  3021. fi
  3022. fi
  3023. # Static network environment doesn't support ntp clock setup.
  3024. if [[ "$Network4Config" == "isStatic" ]] || [[ "$Network6Config" == "isStatic" ]]; then
  3025. sed -i 's/ntp boolean true/ntp boolean false/g' /tmp/boot/preseed.cfg
  3026. sed -i '/d-i\ clock-setup\/ntp-server string ntp.nict.jp/d' /tmp/boot/preseed.cfg
  3027. fi
  3028. # If network adapter is not redirected, delete this setting to new system.
  3029. [[ "$setInterfaceName" == "0" ]] && sed -i 's/net.ifnames=0 biosdevname=0//g' /tmp/boot/preseed.cfg
  3030. # If user not setting disable IPv6 or network is IPv6 or bio-stack, "ipv6.disable=1" should be deleted.
  3031. [[ "$setIPv6" == "1" ]] && sed -i 's/ipv6.disable=1//g' /tmp/boot/preseed.cfg
  3032. [[ "$ddMode" == '1' ]] && {
  3033. WinNoDHCP(){
  3034. echo -ne "for\0040\0057f\0040\0042tokens\00753\0052\0042\0040\0045\0045i\0040in\0040\0050\0047netsh\0040interface\0040show\0040interface\0040\0136\0174more\0040\00533\0040\0136\0174findstr\0040\0057I\0040\0057R\0040\0042本地\0056\0052\0040以太\0056\0052\0040Local\0056\0052\0040Ethernet\0042\0047\0051\0040do\0040\0050set\0040EthName\0075\0045\0045j\0051\r\nnetsh\0040\0055c\0040interface\0040ip\0040set\0040address\0040name\0075\0042\0045EthName\0045\0042\0040source\0075static\0040address\0075$IPv4\0040mask\0075$MASK\0040gateway\0075$GATE\r\nnetsh\0040\0055c\0040interface\0040ip\0040add\0040dnsservers\0040name\0075\0042\0045EthName\0045\0042\0040address\00758\00568\00568\00568\0040index\00751\0040validate\0075no\r\n\r\n" >>'/tmp/boot/net.tmp';
  3035. }
  3036. WinRDP(){
  3037. echo -ne "netsh\0040firewall\0040set\0040portopening\0040protocol\0075ALL\0040port\0075$WinRemote\0040name\0075RDP\0040mode\0075ENABLE\0040scope\0075ALL\0040profile\0075ALL\r\nnetsh\0040firewall\0040set\0040portopening\0040protocol\0075ALL\0040port\0075$WinRemote\0040name\0075RDP\0040mode\0075ENABLE\0040scope\0075ALL\0040profile\0075CURRENT\r\nreg\0040add\0040\0042HKLM\0134SYSTEM\0134CurrentControlSet\0134Control\0134Network\0134NewNetworkWindowOff\0042\0040\0057f\r\nreg\0040add\0040\0042HKLM\0134SYSTEM\0134CurrentControlSet\0134Control\0134Terminal\0040Server\0042\0040\0057v\0040fDenyTSConnections\0040\0057t\0040reg\0137dword\0040\0057d\00400\0040\0057f\r\nreg\0040add\0040\0042HKLM\0134SYSTEM\0134CurrentControlSet\0134Control\0134Terminal\0040Server\0134Wds\0134rdpwd\0134Tds\0134tcp\0042\0040\0057v\0040PortNumber\0040\0057t\0040reg\0137dword\0040\0057d\0040$WinRemote\0040\0057f\r\nreg\0040add\0040\0042HKLM\0134SYSTEM\0134CurrentControlSet\0134Control\0134Terminal\0040Server\0134WinStations\0134RDP\0055Tcp\0042\0040\0057v\0040PortNumber\0040\0057t\0040reg\0137dword\0040\0057d\0040$WinRemote\0040\0057f\r\nreg\0040add\0040\0042HKLM\0134SYSTEM\0134CurrentControlSet\0134Control\0134Terminal\0040Server\0134WinStations\0134RDP\0055Tcp\0042\0040\0057v\0040UserAuthentication\0040\0057t\0040reg\0137dword\0040\0057d\00400\0040\0057f\r\nFOR\0040\0057F\0040\0042tokens\00752\0040delims\0075\0072\0042\0040\0045\0045i\0040in\0040\0050\0047SC\0040QUERYEX\0040TermService\0040\0136\0174FINDSTR\0040\0057I\0040\0042PID\0042\0047\0051\0040do\0040TASKKILL\0040\0057F\0040\0057PID\0040\0045\0045i\r\nFOR\0040\0057F\0040\0042tokens\00752\0040delims\0075\0072\0042\0040\0045\0045i\0040in\0040\0050\0047SC\0040QUERYEX\0040UmRdpService\0040\0136\0174FINDSTR\0040\0057I\0040\0042PID\0042\0047\0051\0040do\0040TASKKILL\0040\0057F\0040\0057PID\0040\0045\0045i\r\nSC\0040START\0040TermService\r\n\r\n" >>'/tmp/boot/net.tmp';
  3038. }
  3039. echo -ne "\0100ECHO\0040OFF\r\n\r\ncd\0056\0076\0045WINDIR\0045\0134GetAdmin\r\nif\0040exist\0040\0045WINDIR\0045\0134GetAdmin\0040\0050del\0040\0057f\0040\0057q\0040\0042\0045WINDIR\0045\0134GetAdmin\0042\0051\0040else\0040\0050\r\necho\0040CreateObject\0136\0050\0042Shell\0056Application\0042\0136\0051\0056ShellExecute\0040\0042\0045\0176s0\0042\0054\0040\0042\0045\0052\0042\0054\0040\0042\0042\0054\0040\0042runas\0042\0054\00401\0040\0076\0076\0040\0042\0045temp\0045\0134Admin\0056vbs\0042\r\n\0042\0045temp\0045\0134Admin\0056vbs\0042\r\ndel\0040\0057f\0040\0057q\0040\0042\0045temp\0045\0134Admin\0056vbs\0042\r\nexit\0040\0057b\00402\0051\r\n\r\n" >'/tmp/boot/net.tmp';
  3040. [[ "$setNet" == '1' ]] && WinNoDHCP;
  3041. [[ "$setNet" == '0' ]] && [[ "$AutoNet" == '0' ]] && WinNoDHCP;
  3042. [[ "$setRDP" == '1' ]] && [[ -n "$WinRemote" ]] && WinRDP
  3043. echo -ne "ECHO\0040SELECT\0040VOLUME\0075\0045\0045SystemDrive\0045\0045\0040\0076\0040\0042\0045SystemDrive\0045\0134diskpart\0056extend\0042\r\nECHO\0040EXTEND\0040\0076\0076\0040\0042\0045SystemDrive\0045\0134diskpart\0056extend\0042\r\nSTART\0040/WAIT\0040DISKPART\0040\0057S\0040\0042\0045SystemDrive\0045\0134diskpart\0056extend\0042\r\nDEL\0040\0057f\0040\0057q\0040\0042\0045SystemDrive\0045\0134diskpart\0056extend\0042\r\n\r\n" >>'/tmp/boot/net.tmp';
  3044. echo -ne "cd\0040\0057d\0040\0042\0045ProgramData\0045\0057Microsoft\0057Windows\0057Start\0040Menu\0057Programs\0057Startup\0042\r\ndel\0040\0057f\0040\0057q\0040net\0056bat\r\n\r\n\r\n" >>'/tmp/boot/net.tmp';
  3045. iconv -f 'UTF-8' -t 'GBK' '/tmp/boot/net.tmp' -o '/tmp/boot/net.bat'
  3046. rm -rf '/tmp/boot/net.tmp'
  3047. }
  3048. [[ "$ddMode" == '0' ]] && {
  3049. sed -i '/anna-install/d' /tmp/boot/preseed.cfg
  3050. sed -i 's/wget.*\/sbin\/reboot\;\ //g' /tmp/boot/preseed.cfg
  3051. }
  3052. # Commands of "d-i preseed/early_command" in "preseed.cfg" can only appear at one time, otherwise if there are two or more "preseed/early_command" in one preseed,
  3053. # Debian installer can only execute one of them instead of running all of them because soft hack for irregular IPv4 configs and dd Windows will all using "preseed/early_command".
  3054. [[ "$BurnIrregularIpv4Status" == "1" ]] && {
  3055. sed -i '/early_command string anna-install/d' /tmp/boot/preseed.cfg
  3056. }
  3057. elif [[ "$linux_relese" == 'alpinelinux' ]]; then
  3058. # Alpine Linux only support booting with IPv4 by dhcp or static, not support booting from IPv6 by any method.
  3059. [[ "$IPStackType" == "IPv6Stack" ]] && {
  3060. echo -ne "\n[${red}Error${plain}] Does't support $IPStackType!\n"
  3061. exit 1
  3062. }
  3063. # Hostname should not be "localhost"
  3064. HostName=$(hostname)
  3065. [[ "$HostName" == "" || "$HostName" == "localhost" ]] && {
  3066. [[ -n "$targetRelese" ]] && HostName="$targetRelese" || HostName="AlpineLinux"
  3067. }
  3068. # Enable IPv6
  3069. echo "ipv6" >> /tmp/boot/etc/modules
  3070. if [[ "$setAutoConfig" == "1" ]]; then
  3071. AlpineInitLineNum=$(grep -E -n '^exec (/bin/busybox )?switch_root' /tmp/boot/init | cut -d: -f1)
  3072. AlpineInitLineNum=$((AlpineInitLineNum - 1))
  3073. if [[ "$IsCN" == "cn" ]]; then
  3074. alpineInstallOrDdAdditionalFiles "https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Alpine/alpineInit.sh" "https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Alpine/network/resolv_cn.conf" "https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Alpine/motd.sh" "mirrors.ustc.edu.cn" "mirrors.tuna.tsinghua.edu.cn" "https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Ubuntu/ubuntuInit.sh" "https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Windows/windowsInit.sh" "https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Windows/SetupComplete.bat"
  3075. else
  3076. alpineInstallOrDdAdditionalFiles "https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Alpine/alpineInit.sh" "https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Alpine/network/resolv.conf" "https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Alpine/motd.sh" "archive.ubuntu.com" "ports.ubuntu.com" "https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Ubuntu/ubuntuInit.sh" "https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Windows/windowsInit.sh" "https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Windows/SetupComplete.bat"
  3077. fi
  3078. # Cloud init configurate documents and resources:
  3079. # Ubuntu cloud images:
  3080. # https://cloud-images.ubuntu.com/daily/server/
  3081. # customize Ubuntu cloud images by our own:
  3082. # https://bleatingsheep.org/2022/03/14/%E7%94%A8-Ubuntu-Cloud-Images-%E5%88%B6%E4%BD%9C%E8%87%AA%E5%B7%B1%E7%9A%84%E4%BA%91%E9%95%9C%E5%83%8F%EF%BC%88%E9%85%8D%E7%BD%AE-cloud-init-%E7%9A%84-NoCloud-%E6%95%B0%E6%8D%AE%E6%BA%90%EF%BC%89/
  3083. # documents from Redhat:
  3084. # https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/configuring_and_managing_cloud-init_for_rhel_8/configuring-cloud-init_cloud-content
  3085. # network configuration:
  3086. # https://cloudinit.readthedocs.io/en/latest/reference/network-config-format-v2.html
  3087. # valid "*.yaml" format regulations for netplan samples:
  3088. # https://qiita.com/zen3/items/757f96cbe522a9ad397d
  3089. # netplan will deperate the "gateway4" and "gateway6", use "routes" to replace it.
  3090. # https://rohhie.net/ubuntu22-04-netplan-gateway4-has-been-deprecated/
  3091. # enable netplan configuration permanently to prevent to be changed by cloud init during rebooting from the new OS
  3092. # https://askubuntu.com/questions/1051655/convert-etc-network-interfaces-to-netplan
  3093. # disable cloud init service when next restart
  3094. # https://cloudinit.readthedocs.io/en/latest/howto/disable_cloud_init.html
  3095. if [[ "$IPStackType" == "IPv4Stack" ]]; then
  3096. if [[ "$Network4Config" == "isDHCP" ]]; then
  3097. if [[ "$IsCN" == "cn" ]]; then
  3098. AlpineNetworkConf="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Alpine/network/dhcp_interfaces"
  3099. [[ "$targetRelese" == 'Ubuntu' ]] && cloudInitUrl="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Ubuntu/CloudInit/dhcp_interfaces.cfg"
  3100. else
  3101. AlpineNetworkConf="https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Alpine/network/dhcp_interfaces"
  3102. [[ "$targetRelese" == 'Ubuntu' ]] && cloudInitUrl="https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Ubuntu/CloudInit/dhcp_interfaces.cfg"
  3103. fi
  3104. elif [[ "$Network4Config" == "isStatic" ]]; then
  3105. if [[ "$IsCN" == "cn" ]]; then
  3106. AlpineNetworkConf="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Alpine/network/ipv4_static_interfaces"
  3107. [[ "$targetRelese" == 'Ubuntu' ]] && cloudInitUrl="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Ubuntu/CloudInit/ipv4_static_interfaces.cfg"
  3108. else
  3109. AlpineNetworkConf="https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Alpine/network/ipv4_static_interfaces"
  3110. [[ "$targetRelese" == 'Ubuntu' ]] && cloudInitUrl="https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Ubuntu/CloudInit/ipv4_static_interfaces.cfg"
  3111. fi
  3112. fi
  3113. elif [[ "$IPStackType" == "BiStack" ]]; then
  3114. # Alpine Linux doesn't support IPv6 automatic config, must manually.
  3115. if [[ "$Network4Config" == "isDHCP" ]]; then
  3116. [[ "$IsCN" == "cn" ]] && AlpineNetworkConf="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Alpine/network/ipv6_static_interfaces" || AlpineNetworkConf="https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Alpine/network/ipv6_static_interfaces"
  3117. elif [[ "$Network4Config" == "isStatic" ]]; then
  3118. [[ "$IsCN" == "cn" ]] && AlpineNetworkConf="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Alpine/network/ipv4_ipv6_static_interfaces" || AlpineNetworkConf="https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Alpine/network/ipv4_ipv6_static_interfaces"
  3119. fi
  3120. [[ "$targetRelese" == 'Ubuntu' ]] && {
  3121. if [[ "$Network4Config" == "isDHCP" ]] && [[ "$Network6Config" == "isDHCP" ]]; then
  3122. [[ "$IsCN" == "cn" ]] && cloudInitUrl="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Ubuntu/CloudInit/dhcp_interfaces.cfg" || cloudInitUrl="https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Ubuntu/CloudInit/dhcp_interfaces.cfg"
  3123. elif [[ "$Network4Config" == "isDHCP" ]] && [[ "$Network6Config" == "isStatic" ]]; then
  3124. [[ "$IsCN" == "cn" ]] && cloudInitUrl="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Ubuntu/CloudInit/ipv4_dhcp_ipv6_static_interfaces.cfg" || cloudInitUrl="https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Ubuntu/CloudInit/ipv4_dhcp_ipv6_static_interfaces.cfg"
  3125. elif [[ "$Network4Config" == "isStatic" ]] && [[ "$Network6Config" == "isDHCP" ]]; then
  3126. [[ "$IsCN" == "cn" ]] && cloudInitUrl="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Ubuntu/CloudInit/ipv4_static_ipv6_dhcp_interfaces.cfg" || cloudInitUrl="https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Ubuntu/CloudInit/ipv4_static_ipv6_dhcp_interfaces.cfg"
  3127. elif [[ "$Network4Config" == "isStatic" ]] && [[ "$Network6Config" == "isStatic" ]]; then
  3128. [[ "$IsCN" == "cn" ]] && cloudInitUrl="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/Ubuntu/CloudInit/ipv4_static_ipv6_static_interfaces.cfg" || cloudInitUrl="https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/Ubuntu/CloudInit/ipv4_static_ipv6_static_interfaces.cfg"
  3129. fi
  3130. }
  3131. fi
  3132. # All the following steps are processed in the temporary Alpine Linux.
  3133. cat <<EOF | sed -i "${AlpineInitLineNum}r /dev/stdin" /tmp/boot/init
  3134. # Download "interfaces" templates and replace IP details.
  3135. wget --no-check-certificate -O \$sysroot/etc/network/tmp_interfaces ${AlpineNetworkConf}
  3136. # Config nameservers
  3137. rm -rf \$sysroot/etc/resolv.conf
  3138. wget --no-check-certificate -O \$sysroot/etc/resolv.conf ${AlpineDnsFile}
  3139. chmod a+x \$sysroot/etc/resolv.conf
  3140. # Add customized motd
  3141. rm -rf \$sysroot/etc/motd
  3142. wget --no-check-certificate -O \$sysroot/etc/profile.d/motd.sh ${AlpineMotd}
  3143. chmod a+x \$sysroot/etc/profile.d/motd.sh
  3144. # Modify initial file.
  3145. # To determine main hard drive.
  3146. echo "IncDisk "${IncDisk} >> \$sysroot/root/alpine.config
  3147. # To determine mirror.
  3148. echo "LinuxMirror "${LinuxMirror} >> \$sysroot/root/alpine.config
  3149. # To determine release of Alpine Linux
  3150. echo "alpineVer "${DIST} >> \$sysroot/root/alpine.config
  3151. # To determine target system mirror.
  3152. echo "targetLinuxMirror "${targetLinuxMirror} >> \$sysroot/root/alpine.config
  3153. # To determine Windows network static config file.
  3154. echo "windowsStaticConfigCmd "${windowsStaticConfigCmd} >> \$sysroot/root/alpine.config
  3155. # To determine Windows network IPv4 static or dhcp.
  3156. echo "Network4Config "${Network4Config} >> \$sysroot/root/alpine.config
  3157. # Tod determine Windows dd package decompress method.
  3158. echo "DEC_CMD "${DEC_CMD} >> \$sysroot/root/alpine.config
  3159. # To determine timezone.
  3160. echo "TimeZone "${TimeZone} >> \$sysroot/root/alpine.config
  3161. # To determine root password.
  3162. echo 'tmpWORD '$tmpWORD'' >> \$sysroot/root/alpine.config
  3163. # To determine ssh port.
  3164. echo "sshPORT "${sshPORT} >> \$sysroot/root/alpine.config
  3165. # To determine IPv4 static config
  3166. echo "IPv4 "${IPv4} >> \$sysroot/root/alpine.config
  3167. echo "MASK "${MASK} >> \$sysroot/root/alpine.config
  3168. echo "ipPrefix "${ipPrefix} >> \$sysroot/root/alpine.config
  3169. echo "actualIp4Prefix "${actualIp4Prefix} >> \$sysroot/root/alpine.config
  3170. echo "actualIp4Subnet "${actualIp4Subnet} >> \$sysroot/root/alpine.config
  3171. echo "GATE "${GATE} >> \$sysroot/root/alpine.config
  3172. echo "ipDNS1 "${ipDNS1} >> \$sysroot/root/alpine.config
  3173. echo "ipDNS2 "${ipDNS2} >> \$sysroot/root/alpine.config
  3174. # To determine Ipv6 static config
  3175. echo "ip6Addr "${ip6Addr} >> \$sysroot/root/alpine.config
  3176. echo "ip6Mask "${ip6Mask} >> \$sysroot/root/alpine.config
  3177. echo "actualIp6Prefix "${actualIp6Prefix} >> \$sysroot/root/alpine.config
  3178. echo "ip6Gate "${ip6Gate} >> \$sysroot/root/alpine.config
  3179. echo "ip6DNS1 "${ip6DNS1} >> \$sysroot/root/alpine.config
  3180. echo "ip6DNS2 "${ip6DNS2} >> \$sysroot/root/alpine.config
  3181. # To determine whether to disable IPv6 modules
  3182. echo "setIPv6 "${setIPv6} >> \$sysroot/root/alpine.config
  3183. # To Determine hostname
  3184. echo "HostName "${HostName} >> \$sysroot/root/alpine.config
  3185. # To Determine dd image url
  3186. echo "DDURL "${DDURL} >> \$sysroot/root/alpine.config
  3187. # To Determine cloud init url
  3188. echo "cloudInitUrl "${cloudInitUrl} >> \$sysroot/root/alpine.config
  3189. # Download initial file.
  3190. wget --no-check-certificate -O \$sysroot/etc/local.d/${AlpineInitFileName} ${AlpineInitFile}
  3191. # Set initial file execute automatically.
  3192. chmod a+x \$sysroot/etc/local.d/${AlpineInitFileName}
  3193. ln -s /etc/init.d/local \$sysroot/etc/runlevels/default/
  3194. EOF
  3195. fi
  3196. elif [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]]; then
  3197. RedHatUrl=""
  3198. RepoBase=""
  3199. RepoAppStream=""
  3200. [[ "$IsCN" == "cn" ]] && RepoEpel="repo --name=epel --baseurl=http://mirrors.ustc.edu.cn/epel/${RedHatSeries}/Everything/${VER}/" || RepoEpel="repo --name=epel --mirrorlist=https://mirrors.fedoraproject.org/mirrorlist?repo=epel-${RedHatSeries}&arch=${VER}"
  3201. AuthMethod="authselect --useshadow --passalgo sha512"
  3202. SetTimeZone="timezone --utc ${TimeZone}"
  3203. [[ "$IsCN" == "cn" ]] && FirewallRule="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/RedHat/RHEL9Public.xml" || FirewallRule="https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/RedHat/RHEL9Public.xml"
  3204. if [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]]; then
  3205. if [[ "$RedHatSeries" -ge "8" ]]; then
  3206. RedHatUrl="${LinuxMirror}/${DIST}/BaseOS/${VER}/os/"
  3207. RepoBase="repo --name=base --baseurl=${LinuxMirror}/${DIST}/BaseOS/${VER}/os/"
  3208. RepoAppStream="repo --name=appstream --baseurl=${LinuxMirror}/${DIST}/AppStream/${VER}/os/"
  3209. elif [[ "$linux_relese" == 'centos' ]] && [[ "$RedHatSeries" -le "7" ]]; then
  3210. RedHatUrl="${LinuxMirror}/${DIST}/os/${VER}/"
  3211. AuthMethod="auth --useshadow --passalgo=sha512"
  3212. SetTimeZone="timezone --isUtc ${TimeZone}"
  3213. RepoBase="repo --name=base --baseurl=${LinuxMirror}/${DIST}/os/${VER}/"
  3214. RepoAppStream="repo --name=updates --baseurl=${LinuxMirror}/${DIST}/updates/${VER}/"
  3215. [[ "$IsCN" == "cn" ]] && FirewallRule="https://gitee.com/mb9e8j2/Tools/raw/master/Linux_reinstall/RedHat/RHEL7Public.xml" || FirewallRule="https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/RedHat/RHEL7Public.xml"
  3216. fi
  3217. elif [[ "$linux_relese" == 'fedora' ]]; then
  3218. RedHatUrl="${LinuxMirror}/releases/${DIST}/Server/${VER}/os/"
  3219. RepoBase="repo --name=base --baseurl=${LinuxMirror}/releases/${DIST}/Server/${VER}/os/"
  3220. [[ "$IsCN" == "cn" ]] && RepoAppStream="repo --name=updates --baseurl=http://mirrors.bfsu.edu.cn/fedora/updates/${DIST}/Everything/${VER}/" || RepoAppStream="repo --name=updates --mirrorlist=https://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f${DIST}&arch=${VER}"
  3221. [[ "$IsCN" == "cn" ]] && RepoEpel="repo --name=epel --baseurl=http://mirrors.163.com/fedora/releases/${DIST}/Everything/${VER}/os/" || RepoEpel="repo --name=epel --mirrorlist=https://mirrors.fedoraproject.org/mirrorlist?repo=fedora-${DIST}&arch=${VER}"
  3222. fi
  3223. # If network adapter is redirected, the "eth0" is default.
  3224. # --bootproto="a value" is exclusive to IPv4, --bootproto=dhcp is IPv4 DHCP, --bootproto=static is IPv4 Static.
  3225. # --ipv6="a vaild IPv6 address/netmask bits" is for IPv6 static, and then --ipv6gateway="a valid IPv6 gateway" is necessary, --ipv6=auto is for IPv6 DHCP.
  3226. # For IPv6 only network environment, no matter dhcp or static, IPv4 configuration must be disabled(--noipv4),
  3227. # in this situation, CentOS 7 doesn't accept any IPv4 DNS value.
  3228. # Reference: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/system_design_guide/kickstart-commands-and-options-reference_system-design-guide#network_kickstart-commands-for-network-configuration
  3229. writeMultipleIpv6Addresses "$i6AddrNum" "" '/etc/NetworkManager/system-connections/'$interface'.nmconnection'
  3230. if [[ "$IPStackType" == "IPv4Stack" ]]; then
  3231. if [[ "$Network4Config" == "isDHCP" ]]; then
  3232. NetConfigManually="network --device=$interface --bootproto=dhcp --ipv6=auto --nameserver=$ipDNS,$ip6DNS --hostname=$(hostname) --onboot=on"
  3233. elif [[ "$Network4Config" == "isStatic" ]]; then
  3234. NetConfigManually="network --device=$interface --bootproto=static --ip=$IPv4 --netmask=$actualIp4Subnet --gateway=$GATE --ipv6=auto --nameserver=$ipDNS,$ip6DNS --hostname=$(hostname) --onboot=on"
  3235. fi
  3236. elif [[ "$IPStackType" == "BiStack" ]]; then
  3237. if [[ "$Network4Config" == "isDHCP" ]] && [[ "$Network6Config" == "isDHCP" ]]; then
  3238. NetConfigManually="network --device=$interface --bootproto=dhcp --ipv6=auto --nameserver=$ipDNS,$ip6DNS --hostname=$(hostname) --onboot=on"
  3239. elif [[ "$Network4Config" == "isDHCP" ]] && [[ "$Network6Config" == "isStatic" ]]; then
  3240. NetConfigManually="network --device=$interface --bootproto=dhcp --ipv6=$ip6Addr/$actualIp6Prefix --ipv6gateway=$ip6Gate --nameserver=$ipDNS,$ip6DNS --hostname=$(hostname) --onboot=on"
  3241. elif [[ "$Network4Config" == "isStatic" ]] && [[ "$Network6Config" == "isDHCP" ]]; then
  3242. NetConfigManually="network --device=$interface --bootproto=static --ip=$IPv4 --netmask=$actualIp4Subnet --gateway=$GATE --ipv6=auto --nameserver=$ipDNS,$ip6DNS --hostname=$(hostname) --onboot=on"
  3243. elif [[ "$Network4Config" == "isStatic" ]] && [[ "$Network6Config" == "isStatic" ]]; then
  3244. NetConfigManually="network --device=$interface --bootproto=static --ip=$IPv4 --netmask=$actualIp4Subnet --gateway=$GATE --ipv6=$ip6Addr/$actualIp6Prefix --ipv6gateway=$ip6Gate --nameserver=$ipDNS,$ip6DNS --hostname=$(hostname) --onboot=on"
  3245. fi
  3246. # By adding multiple IPv6 addresses is only support these servers which are configurated in IPv4 networking in temporary environment of anaconda during the installation at current.
  3247. [[ "$i6AddrNum" -ge "2" ]] && NetConfigManually="network --device=$interface --bootproto=static --ip=$IPv4 --netmask=$actualIp4Subnet --gateway=$GATE --nameserver=$ipDNS --hostname=$(hostname) --onboot=on"
  3248. elif [[ "$IPStackType" == "IPv6Stack" ]]; then
  3249. if [[ "$Network6Config" == "isDHCP" ]]; then
  3250. NetConfigManually="network --device=$interface --bootproto=dhcp --ipv6=auto --nameserver=$ip6DNS --hostname=$(hostname) --onboot=on --activate --noipv4"
  3251. elif [[ "$Network6Config" == "isStatic" ]]; then
  3252. NetConfigManually="network --device=$interface --bootproto=dhcp --ipv6=$ip6Addr/$actualIp6Prefix --ipv6gateway=$ip6Gate --nameserver=$ip6DNS --hostname=$(hostname) --onboot=on --activate --noipv4"
  3253. fi
  3254. fi
  3255. # Recipes for part disk in BIOS or UEFI manually.
  3256. # Reference: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/installation_guide/sect-kickstart-syntax
  3257. # https://blog.adachin.me/archives/3621
  3258. # https://www.cnblogs.com/hukey/p/14919346.html
  3259. ksIncDisk=`echo $IncDisk | cut -d'/' -f 3`
  3260. ksAllDisks=`echo $AllDisks | sed 's/\/dev\///g' | sed 's/ /,/g'`
  3261. [[ "$disksNum" -le "1" || "$setDisk" != "all" ]] && {
  3262. clearPart="clearpart --drives=${ksIncDisk} --all --initlabel"
  3263. [[ "$EfiSupport" == "enabled" ]] && FormatDisk=`echo -e "part / --fstype="xfs" --ondisk="$ksIncDisk" --grow --size="0"\npart swap --ondisk="$ksIncDisk" --size="1024"\npart /boot --fstype="xfs" --ondisk="$ksIncDisk" --size="512"\npart /boot/efi --fstype="efi" --ondisk="$ksIncDisk" --size="1024""` || FormatDisk=`echo -e "part / --fstype="xfs" --ondisk="$ksIncDisk" --grow --size="0"\npart swap --ondisk="$ksIncDisk" --size="1024"\npart /boot --fstype="xfs" --ondisk="$ksIncDisk" --size="1024"\npart biosboot --fstype=biosboot --ondisk="$ksIncDisk" --size=1"`
  3264. }
  3265. [[ "$setDisk" == "all" || -n "$setRaid" ]] && {
  3266. clearPart="clearpart --all --initlabel"
  3267. FormatDisk="autopart"
  3268. }
  3269. setRaidRecipe "$setRaid" "$disksNum" "$AllDisks" "$linux_relese"
  3270. if [[ "$setAutoConfig" == "1" ]]; then
  3271. cat >/tmp/boot/ks.cfg<<EOF
  3272. # platform x86, AMD64, or Intel EM64T, or ARM aarch64
  3273. # Firewall configuration
  3274. firewall --enabled --ssh
  3275. # Use network installation
  3276. url --url="${RedHatUrl}"
  3277. ${RepoBase}
  3278. ${RepoAppStream}
  3279. ${RepoEpel}
  3280. # Root password
  3281. rootpw --iscrypted $myPASSWORD
  3282. # System authorization information
  3283. ${AuthMethod}
  3284. # Disable system configuration
  3285. firstboot --disable
  3286. # System language
  3287. lang en_US
  3288. # Keyboard layouts
  3289. keyboard us
  3290. # SELinux configuration
  3291. selinux --disabled
  3292. # Use text install
  3293. text
  3294. # unsupported_hardware
  3295. # vnc
  3296. # dont't config display manager
  3297. skipx
  3298. # System Timezone
  3299. ${SetTimeZone}
  3300. # Network Configuration
  3301. ${NetConfigManually}
  3302. # System bootloader configuration
  3303. bootloader --location=mbr --boot-drive=${ksIncDisk} --append="rhgb quiet crashkernel=auto net.ifnames=0 biosdevname=0 ipv6.disable=1"
  3304. # Clear the Master Boot Record
  3305. zerombr
  3306. ${clearPart}
  3307. # Disk partitioning information
  3308. ${FormatDisk}
  3309. # Reboot after installation
  3310. reboot
  3311. %packages --ignoremissing
  3312. @^minimal-environment
  3313. bind-utils
  3314. curl
  3315. epel-release
  3316. fail2ban
  3317. file
  3318. lrzsz
  3319. net-tools
  3320. traceroute
  3321. vim
  3322. wget
  3323. xz
  3324. %end
  3325. # Enable services
  3326. services --enabled=fail2ban,firewalld
  3327. # All modified command should only be executed between %post and %end location!
  3328. %post --interpreter=/bin/bash
  3329. # Disable selinux
  3330. sed -ri "/^#?SELINUX=permissive/c\SELINUX=disabled" /etc/selinux/config
  3331. sed -ri "/^#?SELINUX=enforcing/c\SELINUX=disabled" /etc/selinux/config
  3332. # Allow password login
  3333. sed -ri "/^#?PermitRootLogin.*/c\PermitRootLogin yes" /etc/ssh/sshd_config
  3334. sed -ri "/^#?PasswordAuthentication.*/c\PasswordAuthentication yes" /etc/ssh/sshd_config
  3335. # Change ssh port
  3336. sed -ri "/^#?Port.*/c\Port ${sshPORT}" /etc/ssh/sshd_config
  3337. rm -rf /etc/firewalld/zones/public.xml
  3338. wget --no-check-certificate -qO /etc/firewalld/zones/public.xml '$FirewallRule'
  3339. sed -ri 's/port=""/port="${sshPORT}"/g' /etc/firewalld/zones/public.xml
  3340. firewall-cmd --reload
  3341. # Write fail2ban config
  3342. touch /etc/fail2ban/jail.d/local.conf
  3343. echo -ne "[DEFAULT]\nbanaction = firewallcmd-ipset\nbackend = systemd\n\n[sshd]\nenabled = true" > /etc/fail2ban/jail.d/local.conf
  3344. # Fail2ban config
  3345. touch /var/log/fail2ban.log
  3346. sed -i -E 's/^(logtarget =).*/\1 \/var\/log\/fail2ban.log/' /etc/fail2ban/fail2ban.conf
  3347. systemctl enable fail2ban
  3348. # Add multiple IPv6 addresses
  3349. ${deleteOriginalIpv6Coning}
  3350. ${addIpv6AddrsForRedhat}
  3351. ${setIpv6ConfigMethodForRedhat}
  3352. # Clean logs and kickstart files
  3353. rm -rf /root/anaconda-ks.cfg
  3354. rm -rf /root/install.*log
  3355. rm -rf /root/original-ks.cfg
  3356. %end
  3357. EOF
  3358. fi
  3359. # If network adapter is not redirected, delete this setting to new system.
  3360. [[ "$setInterfaceName" == "0" ]] && sed -i 's/ net.ifnames=0 biosdevname=0//g' /tmp/boot/ks.cfg
  3361. # Support to add --setipv6 "0" to disable IPv6 modules permanently.
  3362. [[ "$setIPv6" == "1" ]] && sed -i 's/ipv6.disable=1//g' /tmp/boot/ks.cfg
  3363. [[ "$UNKNOWHW" == '1' ]] && sed -i 's/^unsupported_hardware/#unsupported_hardware/g' /tmp/boot/ks.cfg
  3364. [[ "$(echo "$DIST" |grep -o '^[0-9]\{1\}')" == '5' ]] && sed -i '0,/^%end/s//#%end/' /tmp/boot/ks.cfg
  3365. fi
  3366. # find . | cpio -H newc --create --verbose | gzip -1 > /tmp/initrd.img
  3367. rm -rf /boot/initrd.img
  3368. rm -rf /boot/vmlinuz
  3369. find . | cpio -o -H newc | gzip -1 > /tmp/initrd.img
  3370. # Grub config start
  3371. # Debian/Ubuntu/Kali Grub1 set start
  3372. if [[ ! -z "$GRUBTYPE" && "$GRUBTYPE" == "isGrub1" ]]; then
  3373. if [[ "$setNetbootXyz" == "0" ]]; then
  3374. READGRUB='/tmp/grub.read'
  3375. [[ -f $READGRUB ]] && rm -rf $READGRUB
  3376. touch $READGRUB
  3377. # Backup original grub config file
  3378. cp $GRUBDIR/$GRUBFILE "$GRUBDIR/$GRUBFILE_$(date "+%Y%m%d%H%M").bak"
  3379. # Read grub file, search boot item.
  3380. #
  3381. # Here is the sample of "menuentry" in most regular Debian like Linux releases:
  3382. #
  3383. # menuentry 'Debian GNU/Linux' {
  3384. # load_video
  3385. # insmod ...
  3386. # if [ x$grub_platform = xxen ]; then insmod ...; fi
  3387. # set root='hd...'
  3388. # if [ x$feature_platform_search_hint = xy ]; then
  3389. # search --no-floppy --fs-uuid --set=root --hint- ...
  3390. # else
  3391. # search --no-floppy --fs-uuid --set=root some uuid
  3392. # fi
  3393. # echo 'Loading Linux ...'
  3394. # linux /boot/vmlinuz
  3395. # echo 'Loading initial ramdisk ...'
  3396. # initrd /boot/initrd.img
  3397. # }
  3398. #
  3399. # But in Ubuntu series(version 20.04+) of official templates of Amazon Lightsail, there are two "}" in one set of the "menuentry" like:
  3400. #
  3401. # menuentry 'Ubuntu' {
  3402. # gfxpayload ...
  3403. # insmod ...
  3404. # if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
  3405. # if [ x$feature_platform_search_hint = xy ]; then ...; fi
  3406. # if [ "${initrdfail}" = 1 ]; then
  3407. # linux /boot/vmlinuz
  3408. # initrd /boot/initrd.img
  3409. # else
  3410. # ...
  3411. # fi
  3412. # initrdfail
  3413. # }
  3414. #
  3415. # Original regex " grep -om 1 'menuentry\ [^}]*}' " written by "MoeClub" can only matches end to " menuentry 'Ubuntu' {..... if [ "${initrdfail} " so that " grep -om 1 'menuentry\ [^}]*}%%%%%%% " caused "$READGRUB" has nothing.
  3416. # That's why we need to add "." to split every regex conditions and delete space lines of "# code comments".
  3417. #
  3418. # Some grub file is written as a binary file, add parameter "-a, --text" process this file as if it were text; this is equivalent to the --binary-files=text option
  3419. cat $GRUBDIR/$GRUBFILE | sed -n '1h;1!H;$g;s/\n/%%%%%%%/g;$p' | grep -aom 1 'menuentry\ [^{].*{.[^}].*}%%%%%%%' | sed 's/%%%%%%%/\n/g' | grep -v '^#' | sed '/^[[:space:]]*$/d' >$READGRUB
  3420. LoadNum="$(cat $READGRUB | grep -c 'menuentry ')"
  3421. if [[ "$LoadNum" -eq '1' ]]; then
  3422. cat $READGRUB | sed '/^$/d' >/tmp/grub.new;
  3423. elif [[ "$LoadNum" -gt '1' ]]; then
  3424. CFG0="$(awk '/menuentry /{print NR}' $READGRUB | head -n 1)";
  3425. CFG2="$(awk '/menuentry /{print NR}' $READGRUB | head -n 2 | tail -n 1)";
  3426. CFG1="";
  3427. for tmpCFG in `awk '/}/{print NR}' $READGRUB`; do
  3428. [ "$tmpCFG" -gt "$CFG0" -a "$tmpCFG" -lt "$CFG2" ] && CFG1="$tmpCFG";
  3429. done
  3430. [[ -z "$CFG1" ]] && {
  3431. echo -ne "\n[${red}Error${plain}] Read $GRUBFILE.\n";
  3432. exit 1;
  3433. }
  3434. sed -n "$CFG0,$CFG1"p $READGRUB >/tmp/grub.new;
  3435. [[ -f /tmp/grub.new ]] && [[ "$(grep -c '{' /tmp/grub.new)" -eq "$(grep -c '}' /tmp/grub.new)" ]] || {
  3436. echo -ne "\n[${red}Error${plain}] Not configure $GRUBFILE.\n";
  3437. exit 1;
  3438. }
  3439. fi
  3440. [ ! -f /tmp/grub.new ] && echo -ne "\n[${red}Error${plain}] $GRUBFILE. " && exit 1;
  3441. sed -i "/menuentry.*/c\menuentry\ \'Install OS \[$Relese\ $DIST\ $VER\]\'\ --class debian\ --class\ gnu-linux\ --class\ gnu\ --class\ os\ \{" /tmp/grub.new
  3442. sed -i "/echo.*Loading/d" /tmp/grub.new;
  3443. INSERTGRUB="$(awk '/menuentry /{print NR}' $GRUBDIR/$GRUBFILE|head -n 1)"
  3444. [[ -n "$(grep 'linux.*/\|kernel.*/' /tmp/grub.new |awk '{print $2}' |tail -n 1 |grep '^/boot/')" ]] && Type='InBoot' || Type='NoBoot';
  3445. LinuxKernel="$(grep 'linux.*/\|kernel.*/' /tmp/grub.new |awk '{print $1}' |head -n 1)";
  3446. [[ -z "$LinuxKernel" ]] && echo -ne "\n${red}Error${plain} read grub config!\n" && exit 1;
  3447. LinuxIMG="$(grep 'initrd.*/' /tmp/grub.new |awk '{print $1}' |tail -n 1)";
  3448. [ -z "$LinuxIMG" ] && sed -i "/$LinuxKernel.*\//a\\\tinitrd\ \/" /tmp/grub.new && LinuxIMG='initrd';
  3449. # If network adapter need to redirect eth0, eth1... in new system, add this setting in grub file of the current system for netboot install file which need to be loaded after restart.
  3450. # The same behavior for grub2.
  3451. [[ "$setInterfaceName" == "1" ]] && Add_OPTION="$Add_OPTION net.ifnames=0 biosdevname=0" || Add_OPTION="$Add_OPTION"
  3452. [[ "$setIPv6" == "0" ]] && Add_OPTION="$Add_OPTION ipv6.disable=1" || Add_OPTION="$Add_OPTION"
  3453. if [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'ubuntu' ]] || [[ "$linux_relese" == 'kali' ]]; then
  3454. # The method for Debian series installer to search network adapter automatically is to set "d-i netcfg/choose_interface select auto" in preseed file.
  3455. # The same behavior for grub2.
  3456. BOOT_OPTION="auto=true $Add_OPTION hostname=$(hostname) domain=$linux_relese quiet"
  3457. elif [[ "$linux_relese" == 'alpinelinux' ]]; then
  3458. # Reference: https://wiki.alpinelinux.org/wiki/PXE_boot
  3459. # IPv4 dhcp config:
  3460. # ip=dhcp or not assign it.
  3461. # Allow a valid IPv4 static config:
  3462. # ip=client-ip::geteway:mask::adapter::dns:
  3463. # Sample:
  3464. # ip=179.86.100.76::179.86.100.1:255.255.255.0::eth0::1.0.0.1 8.8.8.8:
  3465. # Any of IPv6 address format can't be recognized.
  3466. [[ "$Network4Config" == "isStatic" ]] && Add_OPTION="ip=$IPv4::$GATE:$MASK::$interface::$ipDNS:" || Add_OPTION="ip=dhcp"
  3467. BOOT_OPTION="alpine_repo=$LinuxMirror/$DIST/main modloop=$ModLoopUrl $Add_OPTION"
  3468. # Add_OPTION="ip=[2603:c020:800d:ae3d:6cde:8519:f1e3:a522]::[fe80::200:17ff:fe4c:e267]:[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]::eth0::[2606:4700:4700::1001]:"
  3469. # BOOT_OPTION="alpine_repo=$LinuxMirror/$DIST/main modloop=$LinuxMirror/$DIST/releases/$VER/netboot/modloop-lts ip=2001:19f0:000c:05b9:5400:04ff:fe74:7d40::fe80:0000:0000:0000:fc00:04ff:fe74:7d40:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff::eth0::2606:4700:4700:0000:0000:0000:0000:1001:"
  3470. elif [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]]; then
  3471. ipv6ForRedhatGrub
  3472. # The method for Redhat series installer to search network adapter automatically is to set "ksdevice=link" in grub file of the current system for netboot install file which need to be loaded after restart.
  3473. # The same behavior for grub2.
  3474. # "ksdevice=interface" will be deprecated in future versions of anaconda.
  3475. # Reference: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/performing_an_advanced_rhel_8_installation/kickstart-and-advanced-boot-options_installing-rhel-as-an-experienced-user
  3476. BOOT_OPTION="inst.ks=file://ks.cfg $Add_OPTION inst.nomemcheck quiet $ipv6StaticConfForKsGrub"
  3477. fi
  3478. [[ "$setAutoConfig" == "0" ]] && sed -i 's/inst.ks=file:\/\/ks.cfg//' $GRUBDIR/$GRUBFILE
  3479. [ -n "$setConsole" ] && BOOT_OPTION="$BOOT_OPTION --- console=$setConsole"
  3480. [[ "$Type" == 'InBoot' ]] && {
  3481. sed -i "/$LinuxKernel.*\//c\\\t$LinuxKernel\\t\/boot\/vmlinuz $BOOT_OPTION" /tmp/grub.new;
  3482. sed -i "/$LinuxIMG.*\//c\\\t$LinuxIMG\\t\/boot\/initrd.img" /tmp/grub.new;
  3483. }
  3484. [[ "$Type" == 'NoBoot' ]] && {
  3485. sed -i "/$LinuxKernel.*\//c\\\t$LinuxKernel\\t\/vmlinuz $BOOT_OPTION" /tmp/grub.new;
  3486. sed -i "/$LinuxIMG.*\//c\\\t$LinuxIMG\\t\/initrd.img" /tmp/grub.new;
  3487. }
  3488. sed -i '$a\\n' /tmp/grub.new;
  3489. sed -i ''${INSERTGRUB}'i\\n' $GRUBDIR/$GRUBFILE;
  3490. sed -i ''${INSERTGRUB}'r /tmp/grub.new' $GRUBDIR/$GRUBFILE;
  3491. [[ -f $GRUBDIR/grubenv ]] && sed -i 's/saved_entry/#saved_entry/g' $GRUBDIR/grubenv;
  3492. # Debian/Ubuntu grub1 set end
  3493. elif [[ "$setNetbootXyz" == "1" ]]; then
  3494. grub-mkconfig -o $GRUBDIR/$GRUBFILE >>/dev/null 2>&1
  3495. grub-set-default "Bootable ISO Image: netboot.xyz" >>/dev/null 2>&1
  3496. grub-reboot "Bootable ISO Image: netboot.xyz" >>/dev/null 2>&1
  3497. fi
  3498. elif [[ ! -z "$GRUBTYPE" && "$GRUBTYPE" == "isGrub2" ]]; then
  3499. if [[ "$setNetbootXyz" == "0" ]]; then
  3500. # RedHat grub2 set start
  3501. # Confirm linux and initrd kernel direction
  3502. if [[ -f /boot/grub2/grubenv ]] && [[ -d /boot/loader/entries ]] && [[ "$(ls /boot/loader/entries | wc -w)" != "" ]]; then
  3503. LoaderPath=$(cat /boot/grub2/grubenv | grep 'saved_entry=' | awk -F '=' '{print $2}')
  3504. LpLength=`echo ${#LoaderPath}`
  3505. LpFile="/boot/loader/entries/$LoaderPath.conf"
  3506. # The saved_entry of OpenCloudOS(Tencent Cloud) is equal "0"
  3507. # [root@VM-4-11-opencloudos ~]# cat /boot/grub2/grubenv
  3508. # GRUB Environment Block
  3509. # saved_entry=0
  3510. # kernelopts=root=UUID=c21f153f-c0a8-42db-9ba5-8299e3c3d5b9 ro quiet elevator=noop console=ttyS0,115200 console=tty0 vconsole.keymap=us crashkernel=1800M-64G:256M,64G-128G:512M,128G-:768M vconsole.font=latarcyrheb-sun16 net.ifnames=0 biosdevname=0 intel_idle.max_cstate=1 intel_pstate=disable iommu=pt amd_iommu=on
  3511. # boot_success=0
  3512. if [[ "$LpLength" -le "1" ]] || [[ ! -f "$LpFile" ]]; then
  3513. LpFile=`ls -Sl /boot/loader/entries/ | grep -wv "*rescue*" | awk -F' ' '{print $NF}' | sed -n '2p'`
  3514. [[ "$(cat /boot/loader/entries/$LpFile | grep '^linux /boot/')" ]] && BootDIR='/boot' || BootDIR=''
  3515. else
  3516. [[ "$(cat $LpFile | grep '^linux /boot/')" ]] && BootDIR='/boot' || BootDIR=''
  3517. fi
  3518. else
  3519. [[ -n "$(grep 'linux.*/\|kernel.*/' $GRUBDIR/$GRUBFILE | awk '{print $2}' | tail -n 1 | grep '^/boot/')" ]] && BootDIR='/boot' || BootDIR=''
  3520. fi
  3521. # Confirm if BIOS or UEFI firmware for architecture of x86_64(AMD64) processors.
  3522. if [[ "$VER" == "x86_64" || "$VER" == "amd64" ]]; then
  3523. [[ "$EfiSupport" == "enabled" ]] && BootHex="efi" || BootHex="16"
  3524. # The architecture of aarch64(ARM64) processors have matched for only UEFI firmware even nowadays.
  3525. elif [[ "$VER" == "aarch64" || "$VER" == "arm64" ]]; then
  3526. BootHex=""
  3527. fi
  3528. # Get main menuentry parameter from current system
  3529. CFG0="$(awk '/insmod part_/{print NR}' $GRUBDIR/$GRUBFILE|head -n 1)"
  3530. CFG2tmp="$(awk '/--fs-uuid --set=root/{print NR}' $GRUBDIR/$GRUBFILE|head -n 2|tail -n 1)"
  3531. CFG2=`expr $CFG2tmp + 1`
  3532. CFG1=""
  3533. for tmpCFG in `awk '/fi/{print NR}' $GRUBDIR/$GRUBFILE`; do
  3534. [ "$tmpCFG" -ge "$CFG0" -a "$tmpCFG" -le "$CFG2" ] && CFG1="$tmpCFG"
  3535. done
  3536. if [[ -z "$CFG1" ]]; then
  3537. # In standard Redhat like linux OS with grub2 above version of 7, the OS boot configuration in "grub.cfg" is like:
  3538. #
  3539. # insmod part_msdos
  3540. # insmod xfs
  3541. # set root='hd0,msdos1'
  3542. # if [ x$feature_platform_search_hint = xy ]; then
  3543. # search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' d34311d7-62fd-419e-8f19-71494c773ddd
  3544. # else
  3545. # search --no-floppy --fs-uuid --set=root d34311d7-62fd-419e-8f19-71494c773ddd
  3546. # fi
  3547. #
  3548. # But in RockyLinux 9.1 of official templates in Oracle Cloud, OVH Cloud etc, the boot configuration in "grub.cfg" is different from any other of Redhat release versions compeletely:
  3549. #
  3550. # insmod part_gpt
  3551. # insmod xfs
  3552. # search --no-floppy --fs-uuid --set=root 11000e8c-9777-43c3-a83b-54a13d609fdb
  3553. # insmod part_gpt
  3554. # insmod fat
  3555. # search --no-floppy --fs-uuid --set=boot 9E70-9B63
  3556. #
  3557. # In CentOS 7, Fedora 36+, AlmaLinux/CentOS-stream/RockyLinux 8+ of official templates in Linode, all the samples are the same:
  3558. #
  3559. # insmod part_msdos
  3560. # insmod ext2
  3561. # set root='hd0,gpt2'
  3562. # insmod part_msdos
  3563. # insmod ext2
  3564. # set boot='hd0,gpt2'
  3565. #
  3566. # Only the following method will effective:
  3567. #
  3568. # The expect component in grub file should be like "search --no-floppy --fs-uuid --set=root 9340b3c7-e898-44ae-bd1e-4c58dec2b16d" or "set boot='hd0'".
  3569. SetRootCfg="$(awk '/--fs-uuid --set=root/{print NR}' $GRUBDIR/$GRUBFILE | head -n 2 | tail -n 1)"
  3570. [[ "$SetRootCfg" == "" ]] && SetRootCfg="$(awk '/set root='\''hd[0-9]/{print NR}' /boot/grub2/grub.cfg | head -n 2 | tail -n 1)"
  3571. # An array for depositing all rows of "insmod part_".
  3572. InsmodPartArray=()
  3573. # An array for row number of "search --no-floppy --fs-uuid --set=root..." minus row number of "insmod part_".
  3574. IpaSpace=()
  3575. # Static how many times does "insmod part_" appeared and storage rows in array of "InsmodPartArray",
  3576. # storage minus rows in arrary of "IpaSpace"
  3577. for tmpCFG in `awk '/insmod part_/{print NR}' $GRUBDIR/$GRUBFILE`; do
  3578. InsmodPartArray+=("$tmpCFG" "$InsmodPartArray")
  3579. # One number of row minus another one shouldn't be less than "0".
  3580. [[ `expr $SetRootCfg - $tmpCFG` -gt "0" ]] && IpaSpace+=(`expr "$SetRootCfg" - "$tmpCFG"` "$IpaSpace")
  3581. done
  3582. # Definite order "0" in "IpaSpace" as a default value of variable of "minArray".
  3583. minArray=${IpaSpace[0]}
  3584. # The outer condition of this cycle is to definite how many times does it will execute.
  3585. for ((i=1;i<=`grep -io "insmod part_*" $GRUBDIR/$GRUBFILE | wc -l`;i++)); do
  3586. # The inner condition of this cycle is the orders in array of "IpaSpace".
  3587. for j in ${IpaSpace[@]}; do
  3588. # A typical buddle sort for compare whether the current variable "minArray" is greater than the order of number in "IpaSpace" of current cycle.
  3589. # If "minArray" is greater than the order "j" in array of "IpaSpace", the less one "j" will replace the former "IpaSpace".
  3590. [[ $minArray -gt $j ]] && minArray=$j
  3591. done
  3592. done
  3593. # The least "minArray" will be the result and once it plus "SetRootCfg" will be the nearest row number of "insmod part_".
  3594. # So we can figure out the valid section of boot configuration in "grub.cfg" like:
  3595. #
  3596. # insmod part_gpt
  3597. # insmod xfs
  3598. # search --no-floppy --fs-uuid --set=root 9340b3c7-e898-44ae-bd1e-4c58dec2b16d
  3599. #
  3600. CFG0=`expr $SetRootCfg - $minArray`
  3601. CFG1="$SetRootCfg"
  3602. fi
  3603. [[ -z "$CFG0" || -z "$CFG1" ]] && {
  3604. echo -ne "\n[${red}Error${plain}] Read $GRUBFILE.\n"
  3605. exit 1
  3606. }
  3607. sed -n "$CFG0,$CFG1"p $GRUBDIR/$GRUBFILE >/tmp/grub.new
  3608. sed -i -e 's/^/ /' /tmp/grub.new
  3609. [[ -f /tmp/grub.new ]] && [[ "$(grep -c '{' /tmp/grub.new)" -eq "$(grep -c '}' /tmp/grub.new)" ]] || {
  3610. echo -ne "\n[${red}Error${plain}] Not configure $GRUBFILE. \n"
  3611. exit 1
  3612. }
  3613. [ ! -f /tmp/grub.new ] && echo -ne "\n[${red}Error${plain}] $GRUBFILE.\n" && exit 1
  3614. # Set IPv6 or distribute unite network adapter interface
  3615. [[ "$setInterfaceName" == "1" ]] && Add_OPTION="net.ifnames=0 biosdevname=0" || Add_OPTION=""
  3616. [[ "$setIPv6" == "0" ]] && Add_OPTION="$Add_OPTION ipv6.disable=1" || Add_OPTION="$Add_OPTION"
  3617. # Write menuentry to grub
  3618. if [[ "$linux_relese" == 'ubuntu' || "$linux_relese" == 'debian' || "$linux_relese" == 'kali' ]]; then
  3619. BOOT_OPTION="auto=true $Add_OPTION hostname=$(hostname) domain=$linux_relese quiet"
  3620. elif [[ "$linux_relese" == 'alpinelinux' ]]; then
  3621. [[ "$Network4Config" == "isStatic" ]] && Add_OPTION="ip=$IPv4::$GATE:$MASK::$interface::$ipDNS:" || Add_OPTION="ip=dhcp"
  3622. BOOT_OPTION="alpine_repo=$LinuxMirror/$DIST/main modloop=$ModLoopUrl $Add_OPTION"
  3623. elif [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]]; then
  3624. ipv6ForRedhatGrub
  3625. BOOT_OPTION="inst.ks=file://ks.cfg $Add_OPTION inst.nomemcheck quiet $ipv6StaticConfForKsGrub"
  3626. fi
  3627. [[ "$setAutoConfig" == "0" ]] && sed -i 's/inst.ks=file:\/\/ks.cfg//' $GRUBDIR/$GRUBFILE
  3628. cat >> /etc/grub.d/40_custom <<EOF
  3629. menuentry 'Install $Relese $DIST $VER' --class $linux_relese --class gnu-linux --class gnu --class os {
  3630. load_video
  3631. set gfxpayload=text
  3632. insmod gzio
  3633. $(cat /tmp/grub.new)
  3634. linux$BootHex $BootDIR/vmlinuz $BOOT_OPTION
  3635. initrd$BootHex $BootDIR/initrd.img
  3636. }
  3637. EOF
  3638. # Make grub2 to prefer installation item to boot first.
  3639. sed -ri 's/GRUB_DEFAULT=0/GRUB_DEFAULT=saved/g' /etc/default/grub
  3640. # Refreshing current system grub2 service
  3641. grub2-mkconfig -o $GRUBDIR/$GRUBFILE >>/dev/null 2>&1
  3642. grub2-set-default "Install $Relese $DIST $VER" >>/dev/null 2>&1
  3643. grub2-reboot "Install $Relese $DIST $VER" >>/dev/null 2>&1
  3644. # RedHat grub set end
  3645. elif [[ "$setNetbootXyz" == "1" ]]; then
  3646. grub2-mkconfig -o $GRUBDIR/$GRUBFILE >>/dev/null 2>&1
  3647. grub2-set-default "Bootable ISO Image: netboot.xyz" >>/dev/null 2>&1
  3648. grub2-reboot "Bootable ISO Image: netboot.xyz" >>/dev/null 2>&1
  3649. fi
  3650. fi
  3651. # Grub config end
  3652. if [[ "$loaderMode" == "0" ]]; then
  3653. # sleep 5 && reboot || sudo reboot >/dev/null 2>&1
  3654. cp -f /tmp/initrd.img /boot/initrd.img || sudo cp -f /tmp/initrd.img /boot/initrd.img
  3655. cp -f /tmp/vmlinuz /boot/vmlinuz || sudo cp -f /tmp/vmlinuz /boot/vmlinuz
  3656. chown root:root $GRUBDIR/$GRUBFILE
  3657. chmod 444 $GRUBDIR/$GRUBFILE
  3658. else
  3659. rm -rf "$HOME/loader"
  3660. mkdir -p "$HOME/loader"
  3661. cp -rf "/tmp/initrd.img" "$HOME/loader/initrd.img"
  3662. cp -rf "/tmp/vmlinuz" "$HOME/loader/vmlinuz"
  3663. [[ -f "/tmp/initrd.img" ]] && rm -rf "/tmp/initrd.img"
  3664. [[ -f "/tmp/vmlinuz" ]] && rm -rf "/tmp/vmlinuz"
  3665. echo && ls -AR1 "$HOME/loader"
  3666. fi
  3667. echo -ne "\n[${green}Finish${plain}] Input '${yellow}reboot${plain}' to continue the subsequential installation.\n"
  3668. exit 1