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:/lib/cryptsetup/
Upload File :
Current File : //lib/cryptsetup/functions
if [ "${0#/usr/share/initramfs-tools/hooks/}" != "$0" ] ||
        [ "${0#/etc/initramfs-tools/hooks/}" != "$0" ]; then
    # called from an initramfs-tools hook script
    TABFILE="$DESTDIR/cryptroot/crypttab"
elif [ "${0#/scripts/}" != "$0" ]; then
    # called at initramfs stage from a boot script
    TABFILE="/cryptroot/crypttab"
    CRYPTROOT_COUNT_FILE="/run/cryptroot.initrd.cnt"
else
    TABFILE="${TABFILE-/etc/crypttab}"
fi
export DM_DEFAULT_NAME_MANGLING_MODE=hex # for dmsetup(8)

# Logging helpers. Send the argument list to plymouth(1), or fold it
# and print it to the standard error.
cryptsetup_message() {
    local IFS=' '
    if [ "${0#/scripts/}" != "$0" ] && [ -x /bin/plymouth ] && plymouth --ping; then
        plymouth message --text="cryptsetup: $*"
    elif [ ${#*} -lt 70 ]; then
        echo "cryptsetup: $*" >&2
    else
        # use busybox's fold(1) and sed(1) at initramfs stage
        echo "cryptsetup: $*" | fold -s | sed '1! s/^/    /' >&2
    fi
    return 0
}

# crypttab_parse_options([--export], [--quiet], [--missing-path={ignore|warn|fail}])
#   Parse $_CRYPTTAB_OPTIONS, a comma-separated option string from the
#   crypttab(5) 4th column, and sets corresponding variables
#   CRYPTTAB_OPTION_<option>=<value> (which are added to the environment
#   if --export is set).  If --path-exists isn't set to "ignore" (the
#   default), then options taking a file name, such as header=<path>,
#   need to point to an existing path, otherwise a warning is printed;
#   and an error is raised if the value is set to "fail".
#   For error and warning messages, CRYPTTAB_NAME, (resp. CRYPTTAB_KEY)
#   should be set to the (unmangled) mapped device name (resp. key
#   file).
#   Moreover CRYPTTAB_TYPE is set the device type.
#   Return 1 on parsing error, 0 otherwise (incl. if unknown options
#   were encountered).
crypttab_parse_options() {
    local quiet="n" export="n" missing_path="ignore"
    while [ $# -gt 0 ]; do
        case "$1" in
            --quiet) quiet="y";;
            --export) export="y";;
            --missing-path=*) missing_path="${1#--missing-path=}";;
            *) cryptsetup_message "WARNING: crypttab_parse_options(): unknown option $1"
        esac
        shift
    done

    local IFS=',' x OPTION VALUE
    CRYPTTAB_TYPE=""
    unset -v CRYPTTAB_OPTION_cipher \
             CRYPTTAB_OPTION_size \
             CRYPTTAB_OPTION_sector_size \
             CRYPTTAB_OPTION_hash \
             CRYPTTAB_OPTION_offset \
             CRYPTTAB_OPTION_skip \
             CRYPTTAB_OPTION_verify \
             CRYPTTAB_OPTION_readonly \
             CRYPTTAB_OPTION_discard \
             CRYPTTAB_OPTION_plain \
             CRYPTTAB_OPTION_luks \
             CRYPTTAB_OPTION_tcrypt \
             CRYPTTAB_OPTION_veracrypt \
             CRYPTTAB_OPTION_bitlk \
             CRYPTTAB_OPTION_fvault2 \
             CRYPTTAB_OPTION_swap \
             CRYPTTAB_OPTION_tmp \
             CRYPTTAB_OPTION_check \
             CRYPTTAB_OPTION_checkargs \
             CRYPTTAB_OPTION_tries \
             CRYPTTAB_OPTION_initramfs \
             CRYPTTAB_OPTION_noearly \
             CRYPTTAB_OPTION_noauto \
             CRYPTTAB_OPTION_loud \
             CRYPTTAB_OPTION_quiet \
             CRYPTTAB_OPTION_keyscript \
             CRYPTTAB_OPTION_keyslot \
             CRYPTTAB_OPTION_header \
             CRYPTTAB_OPTION_tcrypthidden \
             CRYPTTAB_OPTION_same_cpu_crypt \
             CRYPTTAB_OPTION_submit_from_crypt_cpus \
             CRYPTTAB_OPTION_no_read_workqueue \
             CRYPTTAB_OPTION_no_write_workqueue
    # use $_CRYPTTAB_OPTIONS not $CRYPTTAB_OPTIONS as options values may
    # contain '\054' which is decoded to ',' in the latter
    for x in $_CRYPTTAB_OPTIONS; do
        OPTION="${x%%=*}"
        VALUE="${x#*=}"
        if [ "$x" = "$OPTION" ]; then
            unset -v VALUE
        else
            VALUE="$(printf '%b' "$VALUE")"
        fi
        if ! crypttab_validate_option; then
            if [ "$quiet" = "n" ]; then
                cryptsetup_message "ERROR: $CRYPTTAB_NAME: invalid value for '${x%%=*}' option, skipping"
            fi
            return 1
        elif [ -z "${OPTION+x}" ]; then
            continue
        fi
        if [ "$export" = "y" ]; then
            export "CRYPTTAB_OPTION_$OPTION"="${VALUE-yes}"
        else
            eval "CRYPTTAB_OPTION_$OPTION"='${VALUE-yes}'
        fi
    done
    IFS=" "

    if ! _get_crypt_type; then # set CRYPTTAB_TYPE to the type of crypt device
        CRYPTTAB_TYPE="plain"
        if [ "$quiet" = "n" ]; then
            cryptsetup_message "WARNING: $CRYPTTAB_NAME: couldn't determine device type," \
                               "assuming default ($CRYPTTAB_TYPE)."
        fi
    fi

    if [ "$quiet" = "n" ] && [ -n "${CRYPTTAB_OPTION_header+x}" ] && [ "$CRYPTTAB_TYPE" != "luks" ]; then
        cryptsetup_message "WARNING: $CRYPTTAB_NAME: Headers are only supported for LUKS devices."
    fi
    if [ "$CRYPTTAB_TYPE" = "plain" ]; then
        # the compiled-in default for these are subject to change
        options='cipher size'
        if [ -n "${CRYPTTAB_OPTION_keyscript+x}" ] || [ "$CRYPTTAB_KEY" = "none" ]; then
            options="$options hash" # --hash is being ignored in plain mode with keyfile specified
        fi
        for o in $options; do
            if [ "$quiet" = "n" ] && eval [ -z "\${CRYPTTAB_OPTION_$o+x}" ]; then
                cryptsetup_message "WARNING: Option '$o' missing in crypttab for plain dm-crypt" \
                    "mapping $CRYPTTAB_NAME. Please read /usr/share/doc/cryptsetup-initramfs/README.initramfs.gz and" \
                    "add the correct '$o' option to your crypttab(5)."
            fi
        done
    fi
}

# crypttab_validate_option()
#   Validate $OPTION=$VALUE (or flag $OPTION if VALUE is unset).  return
#   1 on error, unsets OPTION for unknown or useless options.
crypttab_validate_option() {
    # option aliases
    case "$OPTION" in
        read-only) OPTION="readonly";;
        key-slot) OPTION="keyslot";;
        tcrypt-hidden) OPTION="tcrypthidden";;
        tcrypt-veracrypt) OPTION="veracrypt";;
    esac

    # sanitize the option name so CRYPTTAB_OPTION_$OPTION is a valid variable name
    local o="$OPTION"
    case "$o" in
        keyfile-offset) OPTION="keyfile_offset";;
        keyfile-size) OPTION="keyfile_size";;
        sector-size) OPTION="sector_size";;
        same-cpu-crypt) OPTION="same_cpu_crypt";;
        submit-from-crypt-cpus) OPTION="submit_from_crypt_cpus";;
        no-read-workqueue) OPTION="no_read_workqueue";;
        no-write-workqueue) OPTION="no_write_workqueue";;
    esac

    case "$o" in
        # value must be a non-empty string
        cipher|hash)
            [ -n "${VALUE:+x}" ] || return 1
        ;;
        # value must be a non-empty string, and an existing path if --missing-path is set
        header)
            [ -n "${VALUE:+x}" ] || return 1
            if [ "$missing_path" != "ignore" ]; then
                if [ ! -e "$VALUE" ]; then
                    cryptsetup_message "WARNING: $CRYPTTAB_NAME: $VALUE does not exist";
                    [ "$missing_path" = "warn" ] || return 1
                fi
            fi
        ;;
        # numeric options >0
        size|keyfile-size|sector-size)
            if ! printf '%s' "${VALUE-}" | grep -Exq "0*[1-9][0-9]*"; then
                return 1
            fi
        ;;
        # numeric options >=0
        offset|skip|tries|keyslot|keyfile-offset)
            if ! printf '%s' "${VALUE-}" | grep -Exq "[0-9]+"; then
                return 1
            fi
        ;;
        tmp)
            if [ -z "${VALUE+x}" ]; then
                VALUE="ext4" # 'tmp flag'
            elif [ -z "$VALUE" ]; then
                return 1
            fi
        ;;
        check)
            if [ -z "${VALUE+x}" ]; then
                if [ -n "${CRYPTDISKS_CHECK-}" ]; then
                    VALUE="$CRYPTDISKS_CHECK"
                else
                    unset -v OPTION
                    return 0
                fi
            fi
            if [ "${VALUE#/}" = "$VALUE" ]; then
                VALUE="/lib/cryptsetup/checks/$VALUE"
            fi
            if [ ! -x "$VALUE" ] || [ ! -f "$VALUE" ]; then
                return 1
            fi
        ;;
        checkargs)
            [ -n "${VALUE+x}" ] || return 1 # must have a value (possibly empty)
        ;;
        keyscript)
            [ -n "${VALUE:+x}" ] || return 1 # must have a value
            if [ "${VALUE#/}" = "$VALUE" ]; then
                VALUE="/lib/cryptsetup/scripts/$VALUE"
            fi
            if [ ! -x "$VALUE" ] || [ ! -f "$VALUE" ]; then
                return 1
            fi
        ;;
        # and now the flags
        verify) ;;
        loud) ;;
        quiet) ;;
        initramfs) ;;
        noearly) ;;
        noauto) ;;
        readonly) ;;
        discard) ;;
        plain) ;;
        luks) ;;
        swap) ;;
        tcrypt) ;;
        veracrypt) ;;
        tcrypthidden) ;;
        bitlk) ;;
        fvault2) ;;
        same-cpu-crypt) ;;
        submit-from-crypt-cpus) ;;
        no-read-workqueue) ;;
        no-write-workqueue) ;;
        *)
            if [ "${quiet:-n}" = "n" ]; then
                cryptsetup_message "WARNING: $CRYPTTAB_NAME: ignoring unknown option '$o'";
            fi
            unset -v OPTION
        ;;
    esac
}

# crypttab_resolve_source()
#   Resolve the CRYPTTAB_SOURCE variable, containing value of the second
#   field of a crypttab(5)-like file.
#   On error (non-existing source), CRYPTTAB_SOURCE is not changed and 1
#   is returned.
crypttab_resolve_source() {
    # return immediately if source is a regular file
    [ ! -f "$CRYPTTAB_SOURCE" ] || return 0
    # otherwise resolve the block device specification
    local dev="$CRYPTTAB_SOURCE"
    dev="$(_resolve_device_spec "$dev")" && CRYPTTAB_SOURCE="$dev" || return 1
}

# run_keyscript($tried_count)
#   exec()'ute `$CRYPTTAB_OPTION_keyscript "$CRYPTTAB_KEY"`.
#   If $CRYPTTAB_OPTION_keyscript is unset or null and $CRYPTTAB_KEY is
#   "none" (meaning the passphrase is to be read interactively from the
#   console), then use `/lib/cryptsetup/askpass` as keyscript with a
#   suitable prompt message instead.
#   Since the shell process is replaced with the $CRYPTTAB_OPTION_keyscript
#   program, run_keyscript() must be used on the left-hand side of a
#   pipe, or similar.
run_keyscript() {
    local keyscript keyscriptarg="$CRYPTTAB_KEY"
    export CRYPTTAB_NAME CRYPTTAB_SOURCE CRYPTTAB_OPTIONS
    export _CRYPTTAB_NAME _CRYPTTAB_SOURCE _CRYPTTAB_OPTIONS
    export CRYPTTAB_TRIED="$1"

    if [ -n "${CRYPTTAB_OPTION_keyscript+x}" ] && \
            [ "$CRYPTTAB_OPTION_keyscript" != "/lib/cryptsetup/askpass" ]; then
        # 'keyscript' option is present: export its argument as $CRYPTTAB_KEY
        export CRYPTTAB_KEY _CRYPTTAB_KEY
        keyscript="$CRYPTTAB_OPTION_keyscript"
    elif [ "$keyscriptarg" = "none" ]; then
        # don't export the prompt message as CRYPTTAB_KEY
        keyscript="/lib/cryptsetup/askpass"
        keyscriptarg="Please unlock disk $CRYPTTAB_NAME: "
    fi

    exec "$keyscript" "$keyscriptarg"
}

# _get_crypt_type()
#    Set CRYPTTAB_TYPE to the mapping type, depending on its
#    $CRYPTTAB_OPTION_<option> values
#    Return a non-zero status if the mapping couldn't be determined
_get_crypt_type() {
    local s="$CRYPTTAB_SOURCE" t="" blk_t

    if [ "${CRYPTTAB_OPTION_luks-}" = "yes" ]; then
        t="luks"
    elif [ "${CRYPTTAB_OPTION_tcrypt-}" = "yes" ]; then
        t="tcrypt"
    elif [ "${CRYPTTAB_OPTION_plain-}" = "yes" ]; then
        t="plain"
    elif [ "${CRYPTTAB_OPTION_bitlk-}" = "yes" ]; then
        t="bitlk"
    elif [ "${CRYPTTAB_OPTION_fvault2-}" = "yes" ]; then
        t="fvault2"
    elif [ -n "${CRYPTTAB_OPTION_header+x}" ]; then
        # detached headers are only supported for LUKS devices
        if [ -e "$CRYPTTAB_OPTION_header" ] && /sbin/cryptsetup isLuks -- "$CRYPTTAB_OPTION_header"; then
            t="luks"
        fi
    elif [ -f "$s" ] || s="$(_resolve_device_spec "$CRYPTTAB_SOURCE")"; then
        if /sbin/cryptsetup isLuks -- "$s"; then
            t="luks"
        elif blk_t="$(blkid -s TYPE -o value -- "$s")" && [ "$blk_t" = "BitLocker" ]; then
            t="bitlk"
        fi
    fi

    [ -n "$t" ] || return 1
    CRYPTTAB_TYPE="$t"
}

# unlock_mapping([$keyfile])
#   Run cryptsetup(8) with suitable options and arguments to unlock
#   $CRYPTTAB_SOURCE and setup dm-crypt managed device-mapper mapping
#   $CRYPTTAB_NAME.
unlock_mapping() {
    local keyfile="${1:--}"

    if [ "$CRYPTTAB_TYPE" = "luks" ] || [ "$CRYPTTAB_TYPE" = "tcrypt" ]; then
        # ignored for LUKS and TCRYPT devices
        unset -v CRYPTTAB_OPTION_cipher \
                 CRYPTTAB_OPTION_size \
                 CRYPTTAB_OPTION_hash \
                 CRYPTTAB_OPTION_offset \
                 CRYPTTAB_OPTION_skip
    fi
    if [ "$CRYPTTAB_TYPE" = "plain" ] || [ "$CRYPTTAB_TYPE" = "tcrypt" ]; then
        unset -v CRYPTTAB_OPTION_keyfile_size
    fi
    if [ "$CRYPTTAB_TYPE" = "tcrypt" ]; then
        # ignored for TCRYPT devices
        unset -v CRYPTTAB_OPTION_keyfile_offset
    else
        # ignored for non-TCRYPT devices
        unset -v CRYPTTAB_OPTION_veracrypt CRYPTTAB_OPTION_tcrypthidden
    fi

    if [ "$CRYPTTAB_TYPE" != "luks" ]; then
        # ignored for non-LUKS devices
        unset -v CRYPTTAB_OPTION_keyslot
    fi

    /sbin/cryptsetup -T1 \
        ${CRYPTTAB_OPTION_header:+--header="$CRYPTTAB_OPTION_header"} \
        ${CRYPTTAB_OPTION_cipher:+--cipher="$CRYPTTAB_OPTION_cipher"} \
        ${CRYPTTAB_OPTION_size:+--key-size="$CRYPTTAB_OPTION_size"} \
        ${CRYPTTAB_OPTION_sector_size:+--sector-size="$CRYPTTAB_OPTION_sector_size"} \
        ${CRYPTTAB_OPTION_hash:+--hash="$CRYPTTAB_OPTION_hash"} \
        ${CRYPTTAB_OPTION_offset:+--offset="$CRYPTTAB_OPTION_offset"} \
        ${CRYPTTAB_OPTION_skip:+--skip="$CRYPTTAB_OPTION_skip"} \
        ${CRYPTTAB_OPTION_verify:+--verify-passphrase} \
        ${CRYPTTAB_OPTION_readonly:+--readonly} \
        ${CRYPTTAB_OPTION_discard:+--allow-discards} \
        ${CRYPTTAB_OPTION_veracrypt:+--veracrypt} \
        ${CRYPTTAB_OPTION_keyslot:+--key-slot="$CRYPTTAB_OPTION_keyslot"} \
        ${CRYPTTAB_OPTION_tcrypthidden:+--tcrypt-hidden} \
        ${CRYPTTAB_OPTION_keyfile_size:+--keyfile-size="$CRYPTTAB_OPTION_keyfile_size"} \
        ${CRYPTTAB_OPTION_keyfile_offset:+--keyfile-offset="$CRYPTTAB_OPTION_keyfile_offset"} \
        ${CRYPTTAB_OPTION_same_cpu_crypt:+--perf-same_cpu_crypt} \
        ${CRYPTTAB_OPTION_submit_from_crypt_cpus:+--perf-submit_from_crypt_cpus} \
        ${CRYPTTAB_OPTION_no_read_workqueue:+--perf-no_read_workqueue} \
        ${CRYPTTAB_OPTION_no_write_workqueue:+--perf-no_write_workqueue} \
        --type="$CRYPTTAB_TYPE" --key-file="$keyfile" \
        open -- "$CRYPTTAB_SOURCE" "$CRYPTTAB_NAME"
}

# resume_mapping([$keyfile])
#   Run cryptsetup(8) with suitable options and arguments to resume
#   $CRYPTTAB_NAME.
resume_mapping() {
    local keyfile="${1:--}"

    /sbin/cryptsetup -T1 \
        ${CRYPTTAB_OPTION_header:+--header="$CRYPTTAB_OPTION_header"} \
        ${CRYPTTAB_OPTION_keyslot:+--key-slot="$CRYPTTAB_OPTION_keyslot"} \
        ${CRYPTTAB_OPTION_keyfile_size:+--keyfile-size="$CRYPTTAB_OPTION_keyfile_size"} \
        ${CRYPTTAB_OPTION_keyfile_offset:+--keyfile-offset="$CRYPTTAB_OPTION_keyfile_offset"} \
        --type="$CRYPTTAB_TYPE" --key-file="$keyfile" \
        luksResume "$CRYPTTAB_NAME"
}

# resume_device($device)
#   Resume $device with endless retries. Used by cryptsetup-suspend-wrapper.
resume_device() {
    local device="$1"
    # check if device is really suspended
    if [ "$(dmsetup info -c --noheadings -o suspended -- "$device" 2>/dev/null)" != "Suspended" ]; then
        cryptsetup_message "ERROR: $device: device was not suspendend"
        return 1
    fi

    if ! crypttab_find_entry "$device" || ! crypttab_parse_options --quiet; then
        cryptsetup_message "ERROR: $device: not found in $TABFILE"
        return 1
    fi

    if [ "$CRYPTTAB_TYPE" != "luks" ]; then
        cryptsetup_message "ERROR: $CRYPTTAB_NAME: unable to resume non-LUKS device"
        return 1
    fi

    # Loop endlessly until the resume command succeeded
    while true; do
        if [ -z "${CRYPTTAB_OPTION_keyscript+x}" ] && [ "$CRYPTTAB_KEY" != "none" ]; then
            resume_mapping "$CRYPTTAB_KEY" && break || true
        else
            run_keyscript 1 | resume_mapping && break || true
        fi
    done
}

# crypttab_key_check()
#   Sanity checks for keyfile $CRYPTTAB_KEY.  CRYPTTAB_NAME and
#   CRYPTTAB_OPTION_<option> must be set appropriately.
crypttab_key_check() {
    if [ ! -f "$CRYPTTAB_KEY" ] && [ ! -b "$CRYPTTAB_KEY" ] && [ ! -c "$CRYPTTAB_KEY" ] ; then
        cryptsetup_message "WARNING: $CRYPTTAB_NAME: keyfile '$CRYPTTAB_KEY' not found"
        return 0
    fi

    if [ "$CRYPTTAB_KEY" = "/dev/random" ] || [ "$CRYPTTAB_KEY" = "/dev/urandom" ]; then
        if [ -n "${CRYPTTAB_OPTION_luks+x}" ] || [ -n "${CRYPTTAB_OPTION_tcrypt+x}" ]; then
            cryptsetup_message "WARNING: $CRYPTTAB_NAME: has random data as key"
            return 1
        else
            return 0
        fi
    fi

    local mode="$(stat -L -c"%04a" -- "$CRYPTTAB_KEY")"
    if [ $(stat -L -c"%u" -- "$CRYPTTAB_KEY") -ne 0 ] || [ "${mode%00}" = "$mode" ]; then
        cryptsetup_message "WARNING: $CRYPTTAB_NAME: key file $CRYPTTAB_KEY has" \
            "insecure ownership, see /usr/share/doc/cryptsetup/README.Debian.gz."
    fi
}

# _resolve_device_spec($spec)
#   Resolve LABEL=<label>, UUID=<uuid>, PARTUUID=<partuuid> and
#   PARTLABEL=<partlabel> to a block special device.  If $spec is
#   already a (link to a block special device) then it is echoed as is.
#   Return 1 if $spec doesn't correspond to a block special device.
_resolve_device_spec() {
    local spec="$1"
    case "$spec" in
        UUID=*|LABEL=*|PARTUUID=*|PARTLABEL=*)
            # don't use /dev/disk/by-label/... to avoid gessing udev mangling
            spec="$(blkid -l -t "$spec" -o device)" || spec=
        ;;
    esac
    [ -b "$spec" ] && printf '%s\n' "$spec" || return 1
}

# dm_blkdevname($name)
#   Print the mapped device name, or return 1 if the the device doesn't exist.
dm_blkdevname() {
    local name="$1" dev
    # /dev/mapper/$name isn't reliable due to udev mangling
    if dev="$(dmsetup info -c --noheadings -o blkdevname -- "$name" 2>/dev/null)" &&
            [ -n "$dev" ] && [ -b "/dev/$dev" ]; then
        echo "/dev/$dev"
        return 0
    else
        return 1
    fi
}

# crypttab_find_entry([--quiet], $target)
#   Search in the crypttab(5) for the given $target, and sets the
#   variables CRYPTTAB_NAME, CRYPTTAB_SOURCE, CRYPTTAB_KEY and
#   CRYPTTAB_OPTIONS accordingly.  (In addition _CRYPTTAB_NAME,
#   _CRYPTTAB_SOURCE, _CRYPTTAB_KEY and _CRYPTTAB_OPTIONS are set to the
#   unmangled values before decoding the escape sequence.)  If there are
#   duplicates then only the first match is considered.
#   Return 0 if a match is found, and 1 otherwise.
crypttab_find_entry() {
    local target="$1" quiet="n" IFS
    if [ "$target" = "--quiet" ] && [ $# -eq 2 ]; then
        quiet="y"
        target="$2"
    fi

    if [ -f "$TABFILE" ]; then
        while IFS=" 	" read -r _CRYPTTAB_NAME _CRYPTTAB_SOURCE _CRYPTTAB_KEY _CRYPTTAB_OPTIONS; do
            if [ "${_CRYPTTAB_NAME#\#}" != "$_CRYPTTAB_NAME" ] || [ -z "$_CRYPTTAB_NAME" ]; then
                # ignore comments and empty lines
                continue
            fi

            # unmangle names
            CRYPTTAB_NAME="$(printf '%b' "$_CRYPTTAB_NAME")"
            if [ -z "$_CRYPTTAB_SOURCE" ] || [ -z "$_CRYPTTAB_KEY" ]; then
                cryptsetup_message "WARNING: '$CRYPTTAB_NAME' is missing some arguments, see crypttab(5)"
                continue
            elif [ "$CRYPTTAB_NAME" = "$target" ]; then
                CRYPTTAB_SOURCE="$( printf '%b' "$_CRYPTTAB_SOURCE" )"
                CRYPTTAB_KEY="$(    printf '%b' "$_CRYPTTAB_KEY"    )"
                CRYPTTAB_OPTIONS="$(printf '%b' "$_CRYPTTAB_OPTIONS")"
                return 0
            fi
        done <"$TABFILE"
    fi

    if [ "$quiet" = "n" ]; then
        cryptsetup_message "WARNING: target '$target' not found in $TABFILE"
    fi
    return 1
}

# crypttab_foreach_entry($callback)
#   Iterate through the crypttab(5) and run the given $callback for each
#   entry found. Variables CRYPTTAB_NAME, CRYPTTAB_SOURCE, CRYPTTAB_KEY
#   and CRYPTTAB_OPTIONS are set accordingly and available to the
#   $callback.  (In addition _CRYPTTAB_NAME, _CRYPTTAB_SOURCE,
#   _CRYPTTAB_KEY and _CRYPTTAB_OPTIONS are set to the original values
#   before decoding the escape sequence.)
#   Return 0 if a match is found, and 1 otherwise.
crypttab_foreach_entry() {
    local callback="$1" IFS
    local _CRYPTTAB_NAME _CRYPTTAB_SOURCE _CRYPTTAB_KEY _CRYPTTAB_OPTIONS \
           CRYPTTAB_NAME  CRYPTTAB_SOURCE  CRYPTTAB_KEY  CRYPTTAB_OPTIONS

    [ -f "$TABFILE" ] || return
    while IFS=" 	" read -r _CRYPTTAB_NAME _CRYPTTAB_SOURCE _CRYPTTAB_KEY _CRYPTTAB_OPTIONS <&9; do
        if [ "${_CRYPTTAB_NAME#\#}" != "$_CRYPTTAB_NAME" ] || [ -z "$_CRYPTTAB_NAME" ]; then
            # ignore comments and empty lines
            continue
        fi

        # unmangle names
        CRYPTTAB_NAME="$(printf '%b' "$_CRYPTTAB_NAME")"

        if [ -z "$_CRYPTTAB_SOURCE" ] || [ -z "$_CRYPTTAB_KEY" ]; then
            cryptsetup_message "WARNING: '$CRYPTTAB_NAME' is missing some arguments, see crypttab(5)"
            continue
        fi

        CRYPTTAB_SOURCE="$( printf '%b' "$_CRYPTTAB_SOURCE" )"
        CRYPTTAB_KEY="$(    printf '%b' "$_CRYPTTAB_KEY"    )"
        CRYPTTAB_OPTIONS="$(printf '%b' "$_CRYPTTAB_OPTIONS")"

        "$callback" 9<&-
    done 9<"$TABFILE"
}

# _device_uuid($device)
#   Print the UUID attribute of given block special $device.  Return 0
#   on success, 1 on error.
_device_uuid() {
    local device="$1" uuid
    if uuid="$(blkid -s UUID -o value -- "$device")" && [ -n "$uuid" ]; then
        printf '%s\n' "$uuid"
    else
        return 1
    fi
}

# _resolve_device({$device | $spec})
#   Take a path to (or spec for) a block special device, and set DEV to
#   the (symlink to block) device, and MAJ (resp. MIN) to its major-ID
#   (resp. minor ID) decimal value.  On error these variables are not
#   changed and 1 is returned.
_resolve_device() {
    local spec="$1" dev devno maj min
    if dev="$(_resolve_device_spec "$spec")" &&
            devno="$(stat -L -c"%t:%T" -- "$dev" 2>/dev/null)" &&
            maj="${devno%:*}" && min="${devno#*:}" &&
            [ "$devno" = "$maj:$min" ] && [ -n "$maj" ] && [ -n "$min" ] &&
            maj=$(( 0x$maj )) && min=$(( 0x$min )) && [ $maj -gt 0 ]; then
        DEV="$dev"
        MAJ="$maj"
        MIN="$min"
        return 0
    else
        cryptsetup_message "ERROR: Couldn't resolve device $spec"
    fi
    return 1
}

# get_mnt_devno($mountpoint)
#   Print the major:minor device ID(s) holding the file system currently
#   mounted currenty mounted on $mountpoint.
#   Return 0 on success, 1 on error (if $mountpoint is not a mountpoint).
get_mnt_devno() {
    local wantmount="$1" devnos="" uuid dev IFS
    local spec mountpoint fstype _ DEV MAJ MIN

    while IFS=" 	" read -r spec mountpoint fstype _; do
        # treat lines starting with '#' as comments; /proc/mounts
        # doesn't seem to contain these but per procfs(5) the format of
        # that file is analogous to fstab(5)'s
        if [ "${spec#\#}" = "$spec" ] && [ -n "$spec" ] &&
                [ "$(printf '%b' "$mountpoint")" = "$wantmount" ]; then
            # take the last mountpoint if used several times (shadowed)
            unset -v devnos
            spec="$(printf '%b' "$spec")"
            _resolve_device "$spec" || continue # _resolve_device() already warns on error
            fstype="$(printf '%b' "$fstype")"
            if [ "$fstype" = "btrfs" ]; then
                # btrfs can span over multiple devices
                if uuid="$(_device_uuid "$DEV")"; then
                    for dev in "/sys/fs/$fstype/$uuid/devices"/*/dev; do
                        devnos="${devnos:+$devnos }$(cat "$dev")"
                    done
                else
                    cryptsetup_message "ERROR: $spec: Couldn't determine UUID"
                fi
            elif [ -n "$fstype" ]; then
                devnos="$MAJ:$MIN"
            fi
        fi
    done </proc/mounts

    if [ -z "${devnos:+x}" ]; then
        return 1 # not found
    else
        printf '%s' "$devnos"
    fi
}

# foreach_cryptdev([--reverse], $callback, $maj:$min, [$maj:$min ..])
#   Run $callback on the (unmangled) name of each dm-crypt device
#   recursively holding $maj:$min (typically corresponding to an md,
#   linear, or dm-crypt device).  Slaves that aren't dm-crypt devices
#   are ignored.
#   By default each device is processed after its *slaves*.  If
#   --reverse is set then each device is processed after its *holders*
#   instead.
foreach_cryptdev() {
    local callback="$1" reverse="n" devno base
    shift
    if [ "$callback" = "--reverse" ]; then
        reverse="y"
        callback="$1"
        shift
    fi
    for devno in "$@"; do
        base="/sys/dev/block/$devno"
        if [ ! -d "$base" ]; then
            cryptsetup_message "ERROR: Couldn't find sysfs directory for $devno"
            return 1
        fi
        _foreach_cryptdev "$base"
    done
}
_foreach_cryptdev() {
    local d="$1" devno maj min name t d2
    [ "$reverse" = "y" ] && t="holders" || t="slaves"
    [ -d "$d/$t" ] || return 0
    for d2 in "$d/$t"/*; do
        if [ -d "$d2" ] && d2="$(realpath -e -- "$d2")"; then
            _foreach_cryptdev "$d2"
        fi
    done
    if [ -d "$d/dm" ] && devno="$(cat "$d/dev")" &&
            maj="${devno%:*}" && min="${devno#*:}" &&
            [ "$devno" = "$maj:$min" ] && [ -n "$maj" ] && [ -n "$min" ] &&
            [ "$(dmsetup info -c --noheadings -o subsystem -j "$maj" -m "$min")" = "CRYPT" ] &&
            name="$(dmsetup info -c --noheadings -o unmangled_name -j "$maj" -m "$min")"; then
        "$callback" "$name"
    fi
}

# vim: set filetype=sh :