PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB`Mini Shell

HOME


Mini Shell 1.0
DIR:/proc/self/root/cpanel_installer/
Upload File :
Current File : //proc/self/root/cpanel_installer/install_ubuntu
#!/usr/bin/perl
# cpanel - installd/install_ubuntu                 Copyright 2021 cPanel, L.L.C.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
package installd::install;

use strict;
use warnings;

use POSIX;
use Cwd          ();
use Getopt::Long ();

use lib '.';
use lib 'installd';    # mainly for use by automated testing that does not enter the install directory
require Common;

my $distro;
my $distro_version;
my $distro_arch;
my $aptcheck = 0;
my $force;

my $skip_apache     = -e '/root/skipapache' ? 1 : 0;
my $skip_repo_setup = 0;
my $skip_license_check;
my $collect_output = undef;

my $installstart;

my $original_pid = $$;

exit run(@ARGV) unless caller;

sub run {
    my (@args) = @_;
    my $ret = eval { script(@args) };
    if ($@) {
        chomp $@;
        print STDERR $@;
        return 1;
    }
    return $ret;
}

sub script {
    my (@args) = @_;

    local $ENV{'CPANEL_BASE_INSTALL'} = 1;
    local $ENV{'LANG'}                = 'C';
    delete $ENV{'LANGUAGE'};

    local $| = 1;
    umask 022;

    if ( open my $fh, '<', $Common::lock_file ) {
        print "The system detected an installer lock file: ($Common::lock_file)\n";
        print "Make certain that an installer is not already running.\n\n";
        print "You can remove this file and re-run the cPanel installation process after you are certain that another installation is not already in progress.\n\n";
        my $pid = <$fh>;
        if ($pid) {
            chomp $pid;
            print `ps auxwww |grep $pid`;    ## no critic(ProhibitQxAndBackticks)
        }
        else {
            print "Warning: The system could not find pid information in the $Common::lock_file file.\n";
        }
        return 1;
    }

    # Create the lock file.
    if ( open my $fh, '>', $Common::lock_file ) {
        print {$fh} "$$\n";

        close $fh;
    }
    else {
        Common::FATAL("Unable to write lock file $Common::lock_file");

        return 1;
    }

    $original_pid = $$;

    END {
        return if $$ != $original_pid;

        # Required for testing.
        return if $INC{'Test/More.pm'};

        Common::cleanup_lock_file_and_gpg_homedir();
    }

    # Open the install logs for append.
    $installstart = Common::open_logs();

    # Determine local distro and version. Fail if unsupported.
    ( $distro, $distro_version, $distro_arch ) = check_system_support();
    my $options = {};
    Getopt::Long::GetOptionsFromArray(
        \@args,
        'force'            => \$force,
        'skipapache'       => \$skip_apache,
        'skipreposetup'    => \$skip_repo_setup,
        'skiplicensecheck' => \$skip_license_check,
    );

    # Validate hostname is FQDN.
    Common::check_hostname();

    # Do the clean install check pause right after
    # network manager so they see the warning since
    # this will pause for 5 seconds
    Common::clean_install_check();

    # Validate that various files are in place.
    Common::check_files();

    # Bootstrap checks.
    Common::INFO("Running health checks prior to start.");
    disable_systemd_resolved_if_enabled();
    Common::check_resolv_conf();

    # Unset the kernel flag that prevents even root from accessing other users files in /tmp
    Common::ssystem( "sysctl", "fs.protected_regular=0" );

    # Then configure this to be the default upon reboot
    my $prot_file = '/usr/lib/sysctl.d/protect-links.conf';
    my @orig_prot_file_contents;
    if ( -f $prot_file ) {
        open( my $prot_rd_fh, '<', $prot_file );
        while (<$prot_rd_fh>) {
            push( @orig_prot_file_contents, $_ );
        }
        close($prot_rd_fh);
        open( my $prot_wr_fh, '>', $prot_file );
        foreach my $line (@orig_prot_file_contents) {
            if ( $line =~ m/fs\.protected_regular/ ) {
                print $prot_wr_fh "fs.protected_regular = 0\n";
            }
            else {
                print $prot_wr_fh "$line";
            }
        }
        close($prot_wr_fh);
    }

    # Configure alternate temp dir for debconf since /tmp is often mounted noexec
    mkdir '/root/tmp';
    open( my $debconf_fh, '>>', '/etc/apt/apt.conf.d/50extracttemplates' );
    print $debconf_fh "APT\n{\n ExtractTemplates\n\t\{\n\t\tTempDir /root/tmp;\n\t};\n};\n";
    close($debconf_fh);

    # Make sure we import the GPG keys before anything tries to `apt update`
    mkdir '/var/cpanel/';
    Common::fetch_gpg_key_once();

    # This package is needed for File::FcntlLock, used by the wrapper script for all other packages
    apt_nohang_ssystem( 'apt', 'install', '-y', 'libfile-fcntllock-perl' );

    update_apt();
    check_apt_works();

    my $ensure_pkgs_installed;
    if ( $ensure_pkgs_installed = fork() ) {

        #parent
    }
    else {
        $collect_output = '';

        # Must run before bootstrap to install wget if needed
        local $@;
        eval { ensure_pkgs_installed( $distro, $distro_version ); };
        print $collect_output;
        undef $collect_output;
        die if $@;

        exit(0);
    }
    {
        # While the ensure is running in the background
        # we show the message warning that they need a clean
        # server
        local $SIG{'INT'} = sub {
            kill( 'TERM', $ensure_pkgs_installed );
            Common::WARN("Install terminated by user input");
            exit(0);
        };
        Common::warn_clean_server_needed();
        local $?;
        waitpid( $ensure_pkgs_installed, 0 );
        if ( $? != 0 ) {
            die "ensure_pkgs_installed failed: $?";
        }

    }

    # Assure minimum setup: wget & co
    Common::bootstrap( $distro, $distro_version );

    # Remove known packages that will conflict with what we want to install
    disable_software();

    my $install_version = Common::get_cpanel_version();

    # Install base distro required RPMS and setup YUM
    my $lts = Common::get_lts_version();
    Common::INFO("Installing cPanel & WHM major version ${lts}.");

    do_clock_update( $distro, $distro_version );

    # Start nscd if its not running since it will improve package install time
    Common::ssystem("ps -U nscd -h 2>/dev/null || /sbin/service nscd start");

    # Copy custom cpanel.config into place if provided
    Common::setup_custom_cpanel_config();
    create_config_files($options);

    # Look for conditions that require tier manipulation or require us to block the install.
    check_for_install_version_blockers( $distro, $distro_version, $distro_arch, $force );

    # bootstrap the cPanel perl ecosystem
    # We don't fork here, like we do on rhel derivatives, due to the fail-on-lock nature of apt/dpkg + requirements of fix-cpanel-perl

    $collect_output = '';
    local $@;
    eval { Common::bootstrap_cpanel_perl($install_version); };
    print $collect_output;
    undef $collect_output;
    die if $@;

    # Needs wget, working network connection.
    Common::check_if_we_can_get_to_httpupdate();

    # Make sure the OS is relatively clean.
    Common::check_no_mysql();

    # Check that we're in runlevel 3 or 5.
    check_runlevel($distro_version);

    my $installer_dir = Cwd::getcwd();

    # Do this after sanity checks so that we fail before creating the touch file.
    Common::DEBUG("Parsing command line arguments.");
    Common::get_install_type(@args);    # Set DNSONLY if need be.

    Common::check_license_conflict() unless $skip_license_check;    # need dnsonly file to be set

    # TODO: Get rid of these files and replace them with /var/cpanel/dnsonly
    # Disable services by touching files.
    if ( Common::is_dnsonly() ) {
        my @dnsonlydisable = qw( cpdavd );
        foreach my $dis_service (@dnsonlydisable) {
            Common::touch( '/etc/' . $dis_service . 'disable' );
        }
    }

    # by default, selinux tools (selinux-utils) are not installed on Ubuntu Server, but we
    # can leave this here just in case.
    # Set selinux to permissive mode for installation.
    if ( -e '/usr/sbin/setenforce' ) {
        Common::ssystem( '/usr/sbin/setenforce', '0', { ignore_errors => 1 } );
    }

    # Start background rpm download only after disable_software
    # since it does rpm -e
    my $background_rpm_download_pid = background_download_packages_used_during_initial_install($distro_version);

    # Now software is installed, call rdate in case it couldn't be called earlier in the bootstrap script.
    update_system_clock( $distro, $distro_version );

    Common::create_feature_showcase_dir();

    Common::create_slash_scripts_symlink();

    # Install cpanel files and directories. TERMINATE if failure.
    Common::updatenow(
        'skipapache'    => $skip_apache     ? 1 : 0,
        'skipreposetup' => $skip_repo_setup ? 1 : 0
    );

    chmod( 0700, '/usr/local/cpanel/scripts/cpanel_initial_install' );

    system( '/usr/local/cpanel/scripts/cpanel_initial_install', '--skipapache', $skip_apache, '--skipreposetup', $skip_repo_setup, '--installstart', $installstart );

    if ( $? >> 8 != 0 ) {
        kill 'TERM', $background_rpm_download_pid if $background_rpm_download_pid;
        Common::FATAL('The system failed to run the /usr/local/cpanel/scripts/cpanel_initial_install script.');

        return 1;
    }

    # Cleanup before exiting
    waitpid( $background_rpm_download_pid, 0 );
    return 0;
}

# no-op on ubuntu currently, but saving since it could easily be useful in the future
sub create_config_files {
    my ($options) = @_;
    return;
}

sub apt_nohang_ssystem {
    my @cmd = @_;

    $aptcheck = 1;
    my $failcount = 0;
    my $result    = 1;
    while ($result) {    # While apt is failing.
        $result = Common::ssystem(@cmd);
        last if ( !$result );    # apt came back clean. Stop re-trying

        $failcount++;
        if ( $failcount > 5 ) {
            Common::FATAL("apt failed $failcount times. The installation process cannot continue.");
        }
    }
    $aptcheck = 0;
    return;
}

sub get_distro_release_pkg {

    if ( !-f '/etc/debian_version' ) {
        Common::invalid_system("The system could not detect a valid release file for this distribution");
    }
    chomp( my $apt_pkg = `dpkg-query -S /etc/debian_version` );    ## no critic(ProhibitQxAndBackticks)
    $apt_pkg =~ s/\:\s+.+//;
    return $apt_pkg;
}

sub check_system_support {

    # TODO: add back in some logic to check the actual system based on installed package(s) rather than trusting the text file
    # Some of these variables are unused *as of now*. However! some of these values may be useful for 'filling in the blanks' when the RPM check we do fails to provide all required info.
    # For now, only the $system and $machine variables are used, $machine only when Amazon Linux is detected. See https://metacpan.org/pod/POSIX#uname for more info.
    my ( $system, $nodename, $release, $version, $machine ) = POSIX::uname();

    if ( $system =~ m/linux/i ) {

        my $distro_arch = get_system_arch();
        my $release_pkg = get_distro_release_pkg();
        my ( $distro_name, $distro_vers, $distro_prettyname ) = get_distro_vers();

        $release_pkg or Common::invalid_system("Apt packages do not manage release file.");

        Common::INFO("$distro_prettyname (Linux) detected!");

        Common::INFO("Checking RAM now...");
        my $total_memory = Common::get_total_memory();
        my $min_memory   = 768;

        if ( $total_memory < $min_memory ) {
            Common::ERROR("cPanel, L.L.C. requires a minimum of $min_memory MB of RAM for your operating system.");
            Common::FATAL("Increase the server's total amount of RAM, and then reinstall cPanel & WHM.");
        }

        return ( $distro_name, $distro_vers, $distro_arch );
    }
    else {
        Common::invalid_system("Could not detect version for operating system");
    }

    Common::invalid_system("Unknown or unsupported operating system: $system");
    return;
}

sub check_runlevel {
    my ($distro_version) = @_;

    `systemctl is-active multi-user.target >/dev/null 2>&1`;    ## no critic(ProhibitQxAndBackticks)
    return if $? == 0;
    if ($force) {
        Common::WARN('The installation process detected that the multi-user.target is not active (boot is probably not finished).');
        Common::WARN('The multi-user.target must be active. Proceeding anyway because --force was specified!');
    }
    else {
        Common::ERROR('The installation process detected that the multi-user.target is not active (boot is probably not finished).');
        Common::FATAL('The multi-user.target must be active before the installation can continue.');
    }

    # From `man runlevel` :
    #       Table 1. Mapping between runlevels and systemd targets
    #       ┌─────────┬───────────────────┐
    #       │Runlevel │ Target            │
    #       ├─────────┼───────────────────┤
    #       │0        │ poweroff.target   │
    #       ├─────────┼───────────────────┤
    #       │1        │ rescue.target     │
    #       ├─────────┼───────────────────┤
    #       │2, 3, 4  │ multi-user.target │
    #       ├─────────┼───────────────────┤
    #       │5        │ graphical.target  │
    #       ├─────────┼───────────────────┤
    #       │6        │ reboot.target     │
    #       └─────────┴───────────────────┘

    my $runlevel = `runlevel`;    ## no critic(ProhibitQxAndBackticks)
    chomp $runlevel;
    my ( $prev, $curr ) = split /\s+/, $runlevel;

    my $message;

    # currently we allow runlevel 3 or 5, as 5 is the default even on Ubuntu Server, just with no X installed or running
    # runlevel can also return unknown
    if    ( !defined $curr )           { $message = "The installation process could not determine the server's current runlevel."; }
    elsif ( $curr != 3 || $curr != 5 ) { $message = "The installation process detected that the server was in runlevel $curr."; }
    else                               { return; }

    # the system claims to be in an unsupported runlevel.
    if ($force) {
        Common::WARN($message);
        Common::WARN('The server must be in runlevel 3. Proceeding anyway because --force was specified!');
        return;
    }
    else {
        Common::ERROR("The installation process detected that the server was in runlevel $curr.");
        Common::FATAL('The server must be in runlevel 3 before the installation can continue.');
    }

    Common::FATAL('Runlevel logic failed. This should never happen. The installer cannot continue.');
    return;
}

sub ensure_pkgs_installed {
    my ( $distro, $distro_version ) = @_;

    Common::INFO("Installing packages needed to download and run the cPanel initial install.");

    # Assure wget/bzip2/gpg are installed for centhat. These packages are needed prior to sysup
    my @packages_to_install = qw/wget bzip2 gpg-agent xz-utils nscd psmisc python3 rdate cron sysstat net-tools debconf-utils/;

    if (@packages_to_install) {
        apt_nohang_ssystem( './apt-get-wait', '-y', 'install', @packages_to_install );
    }

    return;
}

sub disable_software {
    my @remove_pkgs = qw(
      dovecot-core
      dovecot-imapd
      dovecot-lmtpd
      dovecot-pop3d
      exim4
      mysql-server
      mysql-server-8.0
      mysql-server-core-8.0
      mysql-common
      mysql-client
      mysql-client-8.0
      mysql-client-core-8.0
      portreserve
      postfix
      sendmail
      spamassassin
      libapache2-mod-perl2
      mariadb-client
      mariadb-client-10.3
      mariadb-client-core-10.3
      mariadb-common
      mariadb-plugin-connect
      mariadb-server
      mariadb-server-10.3
      mariadb-server-core-10.3
      mariadb-test
      mycli
      pure-ftpd
      proftpd-basic
    );

    Common::INFO('Ensuring that prelink is disabled...');

    if ( open( my $fh, '+<', '/etc/sysconfig/prelink' ) ) {
        my @lines = map { my $s = $_; $s =~ s/^(PRELINKING=)yes(.*)$/$1no$2/; $s } <$fh>;
        seek( $fh, 0, 0 );
        print {$fh} @lines;
        truncate( $fh, tell($fh) );
    }

    Common::INFO('Ensuring that conflicting services are not installed...');
    Common::ssystem( './dpkg-wait', '-r', '--force-depends', @remove_pkgs, { ignore_errors => 1 } );

    return;
}

# we need to call update first to ensure we have a full package list, otherwise it won't be able to find packages for install
sub update_apt {
    Common::ssystem("./apt-get-wait update");
    return;
}

sub check_apt_works {
    local $ENV{'LC_ALL'} = 'C';
    my $out = `apt info libc6 2>&1`;    ## no critic(ProhibitQxAndBackticks)
    return if ( $out =~ m/Installed\-Size:\s/ );

    Common::ERROR( q{Your operating system's packagge update method } . qq{(apt) could not locate the libc6 package. } . q{This is an indication of an improper setup. } . q{You must correct this error before you proceed. } );
    Common::FATAL("\n\n");
    return;
}

# This code is somewhat of a duplication of the code for updatenow that blocks updates based on configuration
# settings. It needs to be here also because of the bootstrap level nature for when this needs to run.
sub check_for_install_version_blockers {
    my ( $distro, $distro_version, $distro_arch, $force ) = @_;

    my $lts_version = Common::get_lts_version();
    my $tier        = Common::get_cpanel_tier();
    $lts_version or Common::FATAL("The system could not determine the target version from your tier: $tier");

    if ( $lts_version < 69 ) {
        Common::FATAL("You cannot install versions of cPanel & WHM prior to cPanel & WHM version 70.");
    }

    if ( $distro =~ m/bsd/i ) {
        Common::FATAL("cPanel & WHM does not support BSD.");
    }

    if ( $distro_arch ne 'x86_64' ) {
        Common::FATAL("cPanel &WHM only support 64-bit versions of Ubuntu.");
    }

    if ( $lts_version < 97 ) {
        Common::FATAL("cPanel & WHM only supports Ubuntu on version 98 or greater.");
    }

    my $staging_dir = Common::get_staging_dir();
    if ( $staging_dir ne '' && $staging_dir ne '/usr/local/cpanel' ) {
        Common::FATAL("STAGING_DIR must be set to /usr/local/cpanel during installs.");
    }

    # pull in cpanel.config settings or return if the file's not there (defaults will assert)
    return if ( !-e '/var/cpanel/cpanel.config' );
    my $cpanel_config = Common::read_config('/var/cpanel/cpanel.config');

    if ( $cpanel_config->{'mysql-version'} ) {

        # Ubuntu is currently forced to MySQL 8.0 on all cPanel versions.
        # Keep this short circuit here until things change.
        if ( ( $lts_version >= 97 ) && $cpanel_config->{'mysql-version'} ne '8.0' ) {
            Common::FATAL("The mysql-version value in /var/cpanel/cpanel.config is either invalid or references an unsupported MySQL/MariaDB version.  cPanel & WHM version $lts_version only supports MySQL version 8.0 on Ubuntu.");
        }

        # The only supported installable versions are:
        # 5.7, 8.0, 10.2, 10.3 10.5 10.6
        # The following will recommend a specific version in error output:
        # 5.5, 5.6, 10.0, 10.1
        my $supported_versions = qr{^(?:
            5\.[5-7]
            | 8(?:\.0)?
            | 10(?:\.[0-3,5-6])?
        )$}x;
        unless ( $cpanel_config->{'mysql-version'} =~ m/$supported_versions/ ) {
            Common::FATAL('The mysql-version value in /var/cpanel/cpanel.config is either invalid or references an unsupported MySQL/MariaDB version.');
        }

        my %db_id = Common::get_db_identifiers( $cpanel_config->{'mysql-version'} );

        my $advice = Common::get_db_version_advice( $cpanel_config->{'mysql-version'}, $lts_version, $distro_version, $db_id{'plain'} );

        if ( $advice->{ver} && $advice->{action} ) {
            Common::FATAL("You must set $db_id{'stylized'} to version $advice->{ver} or $advice->{action} in the /var/cpanel/cpanel.config file for cPanel & WHM version $lts_version.");
        }
    }

    if ( defined $cpanel_config->{'mailserver'} && $cpanel_config->{'mailserver'} =~ m/^courier$/i ) {
        Common::FATAL("You must use 'dovecot' or 'disabled' for the mailserver in the /var/cpanel/cpanel.config file for cPanel & WHM version $lts_version.");
    }

    return;
}

sub update_system_clock {
    my ( $distro, $distro_version ) = @_;

    my @time_sync_call =
        -x '/usr/sbin/rdate' ? ( '/usr/sbin/rdate', '-s', 'rdate.cpanel.net' )
      : -x '/usr/bin/rdate'  ? ( '/usr/bin/rdate', '-s', 'rdate.cpanel.net' )
      : -x '/bin/rdate'      ? ( '/bin/rdate', '-s', 'rdate.cpanel.net' )
      :                        ();

    # Complain if we don't have an rdate binary.
    if ( !@time_sync_call ) {
        Common::ERROR("The system could not set the system clock because the rdate binary is missing.");
        return;
    }

    # Set the clock
    my $was = time();
    Common::ssystem(@time_sync_call);
    my $now = time();
    Common::INFO( "The system set the clock to: " . localtime($now) );
    my $change = $now - $was;

    # Adjust the start time if it shifted more than 10 seconds.
    if ( abs($change) > 10 ) {
        Common::WARN("The system changed the clock by $change seconds.");
        $installstart += $change;
        Common::WARN( "The system adjusted the starting time to " . localtime($installstart) . "." );
    }
    else {
        Common::INFO("The system changed the clock by $change seconds.");
    }

    return 1;
}

sub do_clock_update {
    my ( $distro, $distro_version ) = @_;

    # Sync the clock.
    if ( !update_system_clock( $distro, $distro_version ) ) {
        WARN( "The current system time is set to: " . `date` );    ## no critic(ProhibitQxAndBackticks)
        WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        WARN("The installation process could not verify the system time. The utility to set time from a remote host, rdate or chrony, is not installed.");
        WARN("If your system time is incorrect by more than a few hours, source compilations will subtly fail.");
        WARN("This issue may result in an overall installation failure.");
        WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    }
    return;
}

# These packages are needed for MySQL later in the install
# By downloading them now we do not have to wait for them later
sub background_download_packages_used_during_initial_install {
    my $distro_version = shift || die "distro_version required";

    my @python2_packages                  = qw{python python-devel python-docs python-setuptools };
    my @sysup_packages_to_install         = qw{quota expat libexpat1-dev};
    my @ea4_packages_to_install           = qw{elinks libssh2-1 libssh2-1-dev libvpx6 libvpx-dev libwww-perl libkrb5-dev libcompress-raw-bzip2-perl libcompress-raw-zlib-perl autoconf automake};
    my @mysql_support_packages_to_install = qw{libnuma1 grep libuser coreutils libdbi-perl};
    my @packages_to_install               = ( @mysql_support_packages_to_install, @sysup_packages_to_install, @ea4_packages_to_install );

    if ( my $pid = fork() ) {

        # Parent
        return $pid;
    }
    else {
        $collect_output = '';
        local $@;
        eval { apt_nohang_ssystem( './apt-get-wait', '--download-only', '-y', 'install', @packages_to_install ); };
        print $collect_output;
        undef $collect_output;
        die if $@;

        exit(0);
    }
    die "Failed to fork to create background package download: $!";
}

# Copied from Cpanel::RpmUtils::Parse
sub parse_rpm {
    my ($name_with_version) = @_;
    my @name_version_parts = split( m{-}, $name_with_version );

    my $release = pop @name_version_parts;    # 1.192.el6  (glibc-common-2.12)
    my $version = pop @name_version_parts;    # 2.12  (glibc-common)

    my $name = join( '-', @name_version_parts );
    $name =~ s/^\d+://;                       # TODO/YAGNI: include epoch (or lack thereof) in results?

    return {
        'release' => $release,
        'version' => $version,
        'name'    => $name
    };
}

sub max {
    my ( $a, $b ) = @_;

    return $a > $b ? $a : $b;
}

sub version_cmp {
    my ( $a, $b ) = @_;

    my @parts_a = split /\./, $a;
    my @parts_b = split /\./, $b;

    my $len = max( scalar @parts_a, scalar @parts_b );

    for ( my $i = 0; $i < $len; $i++ ) {
        my $part_a = $parts_a[$i];
        my $part_b = $parts_b[$i];

        return 1  unless defined $part_b;
        return -1 unless defined $part_a;

        my $result = $part_a <=> $part_b;

        return $result unless $result == 0;
    }

    return 0;
}

sub version_lt {
    my ( $a, $b ) = @_;
    return version_cmp( $a, $b ) < 0 ? 1 : 0;
}

sub version_gte {
    my ( $a, $b ) = @_;
    return version_cmp( $a, $b ) > -1 ? 1 : 0;
}

sub get_system_arch {
    chomp( my $system_arch = `uname -m` );    ## no critic(ProhibitQxAndBackticks)
    if ( !$system_arch ) {
        chomp( $system_arch = `dpkg --print-architecture` );    ## no critic(ProhibitQxAndBackticks)
    }
    if ( !$system_arch ) {
        Common::FATAL('Unable to determine system architecture!');
    }
    return $system_arch;
}

sub get_distro_vers {
    my ( $distro_name, $distro_vers, $distro_prettyname );
    if ( open( my $os_vers_fh, '<', '/etc/os-release' ) ) {
        while ( my $line = <$os_vers_fh> ) {
            chomp $line;
            my ( $name, $val ) = split( /=/, $line );
            if ( $name eq 'NAME' )        { $distro_name       = $val }
            if ( $name eq 'VERSION_ID' )  { $distro_vers       = $val }
            if ( $name eq 'PRETTY_NAME' ) { $distro_prettyname = $val }
        }
        close($os_vers_fh);
        if ( !$distro_name || !$distro_vers || !$distro_prettyname ) {
            Common::FATAL('Could not get expected information from /etc/os-release, this indicates an improper setup.');
        }
    }
    else {
        Common::FATAL('Could not open /etc/os-release, this indicates an improper setup.');
    }
    return ( $distro_name, $distro_vers, $distro_prettyname );
}

sub disable_systemd_resolved_if_enabled {
    print "Disabling systemd-resolved if it is enabled...";
    my $needs_action = `systemctl list-unit-files | grep systemd-resolved`;
    Common::ssystem(qw{systemctl disable --now systemd-resolved}) if $needs_action;

    # Remove the symlink and put a viable one in place
    if ( -l '/etc/resolv.conf' ) {
        unlink '/etc/resolv.conf';
        if ( open( my $fh, '>', '/etc/resolv.conf' ) ) {
            print $fh "nameserver 1.1.1.1\nnameserver 8.8.8.8\n";
            close($fh);
        }
        else {
            Common::WARN( 'Could not create new /etc/resolv.conf : ' . $! );
        }
    }
}

1;