JFIF   ( %!1!%)+...383,7(-.+  ++-+++++-++-++--+--+-+-------+-++-+--+---+++--+7+-+"F!1AQaq"2BRb#3Sr$CDsT&!Q1Aa"2Rbq ?򉄘ǷLR HR,nNb .&W)fJbMOYxj-\bT2(4CQ"qiC/ " %0Jl"e2V  0SDd2@TV^{cW&F͉x9#l,.XɳvRZ C8S 6ml!@!E! `FS!M #(d)Q lml1ml Ų&x(ʨ2NFmj@D<dN5UN˄uTB emLAy#` ` ` I!I 6āHBxL & J#7BQ.$hv h q+tC"EJ) 8R e2U2Y@j%6PF^4LnNBp"8)4JI-ֲvK ^؊)hz[T5˗",Rҥf8ڤS4ʘ!`D ` X+ L,(hl)*S##`6[`0*L T H*HA@I&&r1kr*r*)N$#L  1#ZFSl `[( ("((he`4 Ch [="A R / 0I`twCDcWh"i) cLad\BcLKHZ"ZEW$Ƚ@A~i^`S *A&h:+c Y6vϕGClRPs.`H`(@<$qDe pL@DpLX, E2MP A  `II m& AQ "AT rbg# g2!SiLj*3L \ G;TFL`K BMy 2S`YLh1 d >-"ZfD^Q DH" RAbEV#Lfq,(rETp64-IJ!*p4F$q;G8DQ/TKP2$jp3KW]FtLtƉ1ol]VBgػJH6 )h61GJR7Nj.Z4piJRDd]t]0dP]:N.b'⹙SvDSz]L,_#ugT&[~?cS^"{Bh{/=ۑxOk̳O59o dar793`)SeYM@\ "$E(Tm&)N2Ih)F5EDed(FS,Pa @!@#@lea HCD$11jCLJqcod S3yd*,lL+QEfsgW1nw)cT#dS HXkFJB"6(ʝH)H"#EZh:Y`khݳh%Sc<mlAko2]gDqQtro=3OƸU9_-t8UvW3sGəg*#:c)><"wc\ASmT|6Ę>9~#1Ƈ~ڒE1vVi# I MM#u$8W 5ǍfƬΜg*Qpi1ȩFOf۔S,/⎯(Lrմ`(Z LsbA \6 6dm[I=!r:REI.wgzG)ԇSbӑxuׇTyyL^e'x^ty4Z&eB]I|v59Jjhm;Ng񷫳n<ϞҼѝjk;׹DlY^ҍ\+x9V!j([cmS.NO6jxNζrm&oײizT$N>?~ Sl-:iڥk\at#E!CL`.O0a*w/WV7/r)DŽt7'Nĵ#7O1 ]{[/-2bA<$&Gm_4t)_>)mjG;V^'k59o>ɌM,ؾf9z6 4v_3T.5V/RD-5 %T5XTޫ4TaZ`U *ƱUƲ UG"5+sJJ2E9#܎kr2G3Bb,XM6H: ?@p!'\4V02aԙ) hbZ]:` ev3ʘ'}!ohȒ*TJjr[RFyQ*#{h{R]J]Lr-.D-.җfo$D ?X0%~1P.Og{cWϫ22&Ϭ_V.W3nmiOl}+!˫#`kR33aUb0-g:qmsέ+0HO|&nhOn+}n5QF_"gvLm/z'+r'n_oC语i|1}Gi|}_D~9JZ_%DVQp\koۅjAs~/c0ksUJi^W9W5!>?O:q|ˣSIB/&K<(lg(%Wg$|LW7vߤW߇q|jef3D H\S6(eJb*@&sTKTW/*@v:.N- @ITʓ1Zg&-eꓝM r]EMס{q$b]'7Z7N:O~lNlP7iͲk)$O^퉢<YSD*hr'Z#5e6t[Fdh AJǔP9P 1\R).Il+jI*,(ܢ22N*OwKFX gc?\mB7iA+εe8 "ġ/p5pW-$މ-[a 5ViAW/V{/&UsF./՞ҕ*)rZg.^_+gt_z-oAbqQn*WlHyZ*\TaEewlLR3ԹȭN}MM}aih"5ܕRT$:~'TcT|*)xGC>n+r{XU xuF"<~67у'fxlf`r3D*#Z1ђfH`2dIWo/qB| 63xxW6^m%Kvg>\>x>!H5Nr8J/FJ9Wx(Hou" S'kWاC\9ְ#^OaҮ+~gnkuЉ,aWU*1 읍jnb|e= :2.UL`Q}YS&gI.c=a`%j:C%2@^>])25/ܙ<lzwɛ)ݣS4h3=J tyϬ.E7 8ڞGZu\_JHsݢϑ}IZ"ӳ=X<Ɖ2{a:{7L+>V}c)*lo Yv&+|L;>+/Sj26K+澡*;>-s"}M2] Ig5aCL*r"&\} #^R.7_Mgf}.ߌy(}Z\gP&ʠHj%</{.]rߙQ`>;5g;u6dԛ %xb|oՋTJ5Ϥ(]XqP>f{Jk2,8'~ZU6tMQsg XKg^2ϓ3},[wo۴I|ܷ%[Ol\Pkr]Y//cg6U⧻/VПi8ys_n<\~cze!!H~x;QJZKȮ^ȧG|cS~8ji,Fo+,y~?pk)u /in3JmkX(Mj1N 4c Epc>BO *LfQO&` c;LjcYf 1ɻ)CLsY^Y5" lP/wuEln&dav,(;'W9ej ku`-KHI՟%ԁʁ 1\}?OjsF^Xn$Ё.օC>D:?I @aGE.ĩ1 $ et~T`߸Ir'RX.Zwc%~U=r>-UaFbǺ?R=Z?i'[ASS;siJrzy>nxu$[_B\4}:r'ҵj1_v-[;y?ֹ0I16 . M%4^!S&t ! h !zQð.bBT ?@]?CHq(rd!.$>/x+bnʎNN#w)` )*f!-ɂ\(طYLHzc`Uq7BfCcE0ԉ4Fم쏠ce5T r͸GVlФ?ѣ} mhrkly.Ts㷖)Mө S^%'g>wk%bP[}j~ǾV#K -Fgv켼ǨgɼeSz/6{M=BPZFu\Q75n3Iݤ.W9QfF{vJwF't[@iVj4G~KOnH߿_Do=.c.One?E+GfGN⧭H?4;u`ua|V-+j4?48n ɦ=-]puv&Jc}K>b%U x8pz6L8AXFsW]N55ҦbIWZQ7ï Ԗ3cjz匩ӺOTɖƴ%a'MI}cdR$ݚIζ̝ LIu>J3{^෠㜦˯xܿe\b"2y'x{ RDW b+o2KFhR0:U늞En>լRӉt Iڹ\ wշQEv"v;EJ)yl[5:F0=b4,\PqKtv4{bQz:>C7"8W#Zjdd| cjz%K %Z 9dD{=NFʳAƩtI)kS*s$`:A\ʬ*ֹ9{Nl|eJ١rQnM%z_#x_•TO><)kyD %GN<~y>vfǧB)F)c\lې(#\ h`fgfjTBdhhHL2Y0^ Y0^-"D!QaI15 m~ gՒd|;#gMn(P$l H.R2^PU")pN` N8󫅂OJ;^jz\uumJMF|ηq[]$Vrrt:Q^;QPkHՠ{]HwˆMuIr7!r&- j%"9LtUb56+^TWBqdhHAD7 HwKH^F3LIq #hK`]IWKiH?کǴeԥQ>g{^q^>HKoOB||8aݏS}{S_]ϸ/X~ܵw'OSPAf֩ܟ[>7 @[ֵ;G߇QU*Cթ *OKU^zz[fRnpcJX9u<iq8B]u8 ]I,;[G#2W.¸D8rPG Y%PBJ= wo;PJgx6;yB`3zZGPAͫy{5Nb_re*ONHR]Ji)U{Ӓ:qqɏ[mB4࢒I$ 2vpBADY`DIVAn"Bh$&&cMbdB 鮆wHR'E(ѸZA*H~{B M҅n\@N{7ISCp Vd( r+bg|ns:qg:|J|ɪV.UVaAS͓FyRuLѦT騬 `3􏳕{eo/Tz8DkW?,cl~TqLne֠[B*D +t 6˦S;5KjV3e WBrT.XSHm sl5F%NGM`Y )": J!W4]HTrPX2 QYɕ\m2VLd+`,^ѺiPztUGY6+cӧ6] U%u/ˈFOiB*nFF#ұJ Z/c')?Q͟5.8E~G6e<\?}GkhMFUظOqhEA - "`dQ#(4Ԧf VLmc@q5J8K; M^JZnn)9Zm\ qIJqS: i[9~Oaƒ]Z4F&+666( N]쁼LM(oyvUI/Χ[ھ]hTˉG".SeYgu;hRDtڬv=5 ׁqMS\Ȭi5D]1$*0UL1QY`QdLb[+z9";'yi`OT/4{@EZ'Y0>4I*d nM#5hі.vrM[]Ä;]\ʦS,叕DQZq0fӌI͋]TNK"#;?F;aURx_4WDm+F*0XJE@){ 1R-E2(@Qh l D rT.Q;[J;[`30`ɀ 2#=JeSsxRjG=`H rLJ@ Y$JaB2/x( "Id'6O0CI$:Ol+}I>[L|iK+]ZrH*2Aʶ uHRd)OrrbSx=5dmue1neܬ"e>Lw94勲u ҏ_4GuоJw]QtgSk(qW(6h|v= 1=P/\YZ|R>"*5W/ίR'o %R$5= .!VIRMf4*aR5nv% Usj:V Lj]Bn/TZ&.2„ܒBP)aYRʌW!#ErGf';tW$czI*\KI,c7Zc-ўj|p+-ђ{eg 2;R_{VLM]7sؒFmԻy853gҾqJG!E̤ӏqzs༿? U#R)ŧU(,>,&,-^e^۔.b EW^n<)\9.QeJuFiSh2"EL8yeCKQD\5R,D5.P]c1STt*ZFJ.T:N #%]M}khOe(͓iEMsɆ3( YF<"Ly^*[ry6.ɸm k݊iT%nM8 $Q#F# q 1*?% iS^4oܗ wWPS,aNޖxOxڽqp#F6&o,7LJuMΤK(Td{U Ƹf|q5U{3[FLNK6ӵQY5+'>Q3FSk).&:5z yZq/*q$d+Ge+$lO@Nڤy5eBvˌ䖥shS:JksgksF ꧸oi-FYxy9[Vȼĝ'_.[y2U*c?E+:TsWՀgOS> z75>ncߏ-Kz8ԋ,Ϧ70Z9_1h$Xiu10)0$+$! qsE4wRkh2*T.s%DH:`:=k.'WB{ ȮRGҷ7чVg)CHS}1ݍԳۂ<8g_4y*-Ml\]mZT)mJ~|k<6zWjf4'*u%RNRȉZA) .VLtp 4 V&mtJ#l˅;&{]8>TmhoLXOeD^_J>]jsSej﫦iOM SK([!Vc5zn-A@p]Ӄ \3kmK>#-sܧ?NLar@Js?…Xldny]݌E5•9.8hh69#7js׳R,'pqt:kgPhRԄ+ՕG9}="ֲ\kǁm R73pg$t3+o |o\]'ee5ɐ.7ѐ|ZعSF{qkx5-$Q h5*1yM$ 7)hJ2Kg`-hn*>)EYDIkBpȩAzfǪ>7O K#lߤg]:u~huُ۵u}(mjGIj܏6ES~/5CiRy|kVKGBޭ3;w /jꏈUu>iƪi:WRo'yr4C/?c:w!?\'?#Q:>u/?uEeuG*xY2)?־CAr*23_ץ}գk1%(_ _6aԗ _4 $ϗ+ϫɆzǾIgu?Y<#_xS>i\uɇ۽r}[ͫyRoWCC!H,iD։"Cj5 4] cTk2YZRBvRY~FqQt^RO-g"QP]Ih/t:ljs YӹqI] wqXp KV+8j} uu8PGP&zF:;8+ Sx9(. Q}:ƻWr,Ũ*'shfƧ-6__5,DH{* qp묘G MA}QRe{dyMucǨɾ7߈Avϩe͜jmUi p3\5,ާbf:o+7#ܾ~iU#up=}˄k{NV8m!ҌiptޜBvKi}!ש3UK)`igӞVMR'J[ky~g&6vǍ7ķ>uXd(3瓓[]QTTqnͮz1~_͓k俸0~Z1գ =18cL 5^lf^k^<ҲJɬcC-[^;J8j_q=WpeA_6 4.Ntc>Sv2Jf;G8. 5[,;ArSTˬmpmzjGe EoǩOgDWaGhz<|kT\$Q=u/ci˜S mN&Ok~'0,a} s + NC-G'(*>vw~&*wYG Ŷ K-L/$߮l/A/^:Z@X- Q-D2`@M2+w$Q"胊"47&+Dh'9Y* L7VhT+ -?K]Ik \Ϣgy) s v z)Z ˦2&ލ OjmG9@8F_u䊜r>3K%Yg-FFI]e+Kxkzװy"\Q4Ri'0+P=V&Sw3N/U|UEt*uS c M*tsBE 2ʃ@Kir(˫LRr璜Zy@].%NbXvz덟 hӰNMe#|g͒po9^licxB[e' {U? mlt%?霋ǒxZc X]ϗ15SeE{-Ӕi~DƯO|ë5a@G=%<ƧAs*+tzo, IpȔ|:X6J3Z5JXd]2 3%v*GvE@(S&SX7D0^{5t Z{ﮄsh- ]ɑqEV=^Ki9äBtI@&pEg*O<`F-}ǎ51H,<~qibQѓɳx#l$G9td1U+Sq%B[jOq+^ޏ7K >YY  $KK{*˝e"|$g"6v,,9.DaA,qэI~ܨ|kdv; hz2]x5{M5M~yלqTzUl9Mӏ.WVnkun !jzKO!v|& ;gۇ2BrI閵C tqHe[Zkގ=Q;OԶiᵞBcIU eN cOGz S__>.hNgG6).J$_Taѯ5^LqeB]O?A]H;ò{^0ٺuޚxB|:q'xu4"9Ο7k^eZ_fQOmzm̗{c3ٵKO|m*ek(8"yO(ٵ{LJb2Ǩkgg1_/qrDՆ[_l\ I~Bsc/x ),,̿@PFޞ>O)<<=5m=^x6}~6qoYGޣiY{uN+<,CǚwVxe~c!,5R4u/9In=G•^PF6ɼM򿶤$"\|78ؖYU cXFOKc4s-=6O<;.ϴ޶$q>e? qY}StirX?e/&R'ʑ[ѯMi{?8\g^>\!-VZCf.ȾzRWMh_{^H)mz}V%չM.EJUz7z>ZW6\BW~:W3!S_4~m ǚ! ;VeGKFڵ858Buj:ZZ(/H׭eav!$gpLV)țAJO~YBꤞ厅XJdjg{hR9~_f '5U+}W5%ZjzgTtozYD @%JK\qymeЪKIIp"xoz\B1$G)8Ԅ Jeyc".yyVBR-%BEA-k^Luj cYwԄ%X!e-4ZRḡlJvYsB԰˗0?RM\TlaߏVu4BmY!UyYylgd!m2$i=[hN,6)_~7͖CDF2zÕ{?l;Hܲk׋!/XAłrCXEI{]P[e! ?%Ktqܱ5! jַĞ*TvAG)fuxTҖV7~ 4=r! ob%jTwU$Bnqed䤿@0P&V]HJ)^YrޯĿbsY8=1! n}UD*7uƫi~!s[W{V9J;~Ӯ|[3s۷dڔIj?qJ'O,IkE]G(5\ۖ7)-g,ŶǗ=~e>k쐁%(g˦o[fxN_baGBm:܆VGЗ,G_D!/og,ҢVܤ_iS_~@ SkidSec Webshell

SkidSec WebShell

Server Address : 172.31.38.4

Web Server : Apache/2.4.58 (Ubuntu)

Uname : Linux ip-172-31-38-4 6.14.0-1017-aws #17~24.04.1-Ubuntu SMP Wed Nov 5 10:48:17 UTC 2025 x86_64

PHP Version : 7.4.33



Current Path : /proc/self/root/lib/open-iscsi/



Current File : //proc/self/root/lib/open-iscsi/umountiscsi.sh
#!/bin/sh
#
# This script umounts mounted iSCSI devices on shutdown, if possible.
# It is supposed to catch most use cases but is not designed to work
# for every corner-case. It handles LVM and multipath, but only if
# one of the following stackings is used:
#   LVM -> multipath -> iSCSI
#   multipath -> iSCSI
#   LVM -> iSCSI
#   LVM -> LUKS -> multipath -> iSCSI
#   LVM -> LUKS -> iSCSI
#   LUKS -> LVM -> multipath -> iSCSI
#   LUKS -> multipath -> iSCSI
#   LUKS -> LVM -> iSCSI
#   LUKS -> iSCSI
# It does not try to umount anything belonging to any device that is
# also used as a backing store for the root filesystem. Any iSCSI
# device part of the backing store of the root filesystem will be noted
# in /run/open-iscsi/shutdown-keep-sessions, so that the session not be
# closed on shutdown.
#
# KNOWN ISSUES:
#    - It doesn't handle submounts properly in all corner cases.
#      Specifically, it doesn't handle a non-iSCSI mount below an
#      iSCSI mount if it isn't also marked _netdev in /etc/fstab.
#    - It does not handle other things device mapper can do, such as
#      RAID, crypto, manual mappings of parts of disks, etc.
#    - It doesn't try to kill programs still accessing those mounts,
#      umount will just fail then.
#    - It doesn't handle more complicated stackings such as overlayfs,
#      FUSE filesystems, loop devices, etc.
#    - It doesn't handle swap.
#
# LONG TERM GOAL:
#    - In the long term, there should be a solution where for each part
#      of the stacking (device mapper, LVM, overlayfs, etc.) explicit
#      depdendencies are declared with the init system such that it can
#      be automatically dismantled. That would make this script
#      superfluous and also not be a layering violation, as it
#      currently is.
#
# Author: Christian Seiler <christian@iwakd.de>
#

PATH=/usr/sbin:/sbin:/usr/bin:/bin

EXCLUDE_MOUNTS_AT_SHUTDOWN=""
if [ -f /etc/default/open-iscsi ]; then
	. /etc/default/open-iscsi
fi

MULTIPATH=/sbin/multipath
PVS=/sbin/pvs
LVS=/sbin/lvs
VGS=/sbin/vgs
VGCHANGE=/sbin/vgchange
CRYPTSETUP=/sbin/cryptsetup
DMSETUP=/sbin/dmsetup

if [ -x $PVS ] && [ -x $LVS ] && [ -x $VGCHANGE ] ; then
	HAVE_LVM=1
else
	HAVE_LVM=0
fi
if [ -x $CRYPTSETUP ] && [ -x $DMSETUP ] ; then
	HAVE_LUKS=1
else
	HAVE_LUKS=0
fi

DRY_RUN=0

# We need to make sure that we don't try to umount the root device
# and for systemd systems, also /usr (which is pre-mounted in initrd
# there).
EXCLUDE_MOUNTS="/"
if [ -d /run/systemd/system ] ; then
        EXCLUDE_MOUNTS="$EXCLUDE_MOUNTS /usr"
fi
EXCLUDE_MOUNTS="${EXCLUDE_MOUNTS}${EXCLUDE_MOUNTS_AT_SHUTDOWN+ $EXCLUDE_MOUNTS_AT_SHUTDOWN}"
unset _EXCLUDE_MOUNTS

error_usage() {
	echo "Usage: $0 [--dry-run | --timeout secs]" >&2
	exit 1
}

timeout=0

if [ $# -gt 2 ] ; then
	error_usage
fi

if [ $# -eq 2 ] ; then
	if [ x"$1"x != x"--timeout"x ] ; then
		error_usage
	fi
	case "$2" in
		(-1)            timeout="$2" ;;
		(*[!0-9]*|"")   error_usage ;;
		(*)             timeout="$2" ;;
	esac
elif [ $# -eq 1 ] ; then
	if [ x"$1"x != x"--dry-run"x ] ; then
		error_usage
	fi
	DRY_RUN=1
fi

# poor man's hash implementation using shell variables
hash_keys() {
	_hash_keys_hash_key_prefix="${1}_"
	(
		IFS='='
		set | while read var value ; do
			if [ x"${var#$_hash_keys_hash_key_prefix}"x != x"${var}"x ] ; then
				printf '%s\n' "${var#$_hash_keys_hash_key_prefix}"
			fi
		done
	)
}


hash_clear() {
	for k in $(hash_keys "$1") ; do
		unset "${1}_${k}"
	done
}

hash_get() {
	_hash_get_var="$2_$(printf '%s' "$3" | sed 's%[^A-Za-z0-9_]%_%g')"
	eval _hash_get_value=\$${_hash_get_var}
	eval $1=\${_hash_get_value}
}

hash_set() {
	_hash_set_var="$1_$(printf '%s' "$2" | sed 's%[^A-Za-z0-9_]%_%g')"
	eval ${_hash_set_var}=\${3}
}

hash_unset() {
	_hash_set_var="$1_$(printf '%s' "$2" | sed 's%[^A-Za-z0-9_]%_%g')"
	unset ${_hash_set_var}
}

in_set() {
	eval _set=\$$1
	case "${_set}" in
		("$2"|*" $2"|"$2 "*|*" $2 "*) return 0 ;;
		(*)                           return 1 ;;
	esac
}

_add_to_set() {
	eval _set=\$$1
	case "${_set}" in
		("$2"|*" $2"|"$2 "*|*" $2 "*) ;;
		("")    _set="$2" ;;
		(*)     _set="${_set} $2" ;;
	esac
	eval $1=\${_set}
}

add_to_set() {
	_add_to_set_set="$1"
	shift
	for _add_to_set_val in "$@" ; do
		_add_to_set "${_add_to_set_set}" "${_add_to_set_val}"
	done
}

hash_add_to_set() {
	_hash_add_to_set_var="$1_$(printf '%s' "$2" | sed 's%[^A-Za-z0-9_]%_%g')"
	shift
	shift
	add_to_set "${_hash_add_to_set_var}" "$@"
}

device_majmin() {
	eval $1=\"\"
	_majmin_dec=$(LC_ALL=C ls -lnd /dev/"$2" | while read _perms _links _uid _gid _majcomma _min _rest ; do
		if [ x"${_majcomma%,}"x != x"${_majcomma}"x ] ; then
			printf '%s' ${_majcomma%,}:${_min}
		fi
		break
	done)
	[ -n "${_majmin_dec}" ] || return
	eval $1=\${_majmin_dec}
}

get_lvm_vgs() {
	# handle the case where we didn't get passed any PVs
	# at all
	[ $# -gt 0 ] || return 0
	# subshell for pwd change
	(
		cd /dev
		$PVS --noheadings -o vg_name "$@" 2>/dev/null
	)
}

enumerate_luks() {
	hash_clear LUKS_DEVICES_REVERSE_MAP

	_all_crypt_devices=$($DMSETUP info --noheadings -o name -c -S subsystem=CRYPT 2>/dev/null || :)
	for _crypt_device in ${_all_crypt_devices} ; do
		[ -b "/dev/mapper/${_crypt_device}" ] || continue
		_crypt_device="$(readlink -fe "/dev/mapper/${_crypt_device}" 2>/dev/null || :)"
		_crypt_device="${_crypt_device#/dev/}"
		[ -b "/dev/${_crypt_device}" ] || continue
		# dmsetup deps is weird, it outputs the following:
		# 1 dependencies : (XYZ)
		_dep=$($DMSETUP deps -o blkdevname "/dev/${_crypt_device}" | sed -n '1s%.*: (\(.*\)).*%\1%p')
		if [ -n "$_dep" ] && [ -b "/dev/${_dep}" ] ; then
			_dep="$(readlink -fe "/dev/$_dep" 2>/dev/null || :)"
			_dep="${_dep#/dev/}"
		fi
		if [ -n "$_dep" ] && [ -b "/dev/${_dep}" ] ; then
			hash_set LUKS_DEVICES_REVERSE_MAP "${_dep}" "${_crypt_device}"
		fi
	done
}

enumerate_iscsi_devices() {
	# Empty arrays
	iscsi_disks=""
	iscsi_partitions=""
	iscsi_multipath_disks=""
	iscsi_multipath_disk_aliases=""
	iscsi_multipath_partitions=""
	iscsi_lvm_vgs=""
	iscsi_lvm_lvs=""
	iscsi_potential_mount_sources=""
	iscsi_luks_pass1=""
	iscsi_luks_pass2=""

	hash_clear ISCSI_DEVICE_SESSIONS
	hash_clear ISCSI_MPALIAS_SESSIONS
	hash_clear ISCSI_LVMVG_SESSIONS
	hash_clear ISCSI_NUMDEVICE_SESSIONS
	ISCSI_EXCLUDED_SESSIONS=""

	# We first need to generate a global reverse mapping of all
	# cryptsetup (e.g. LUKS) devices, because there's no easy way
	# to query "is this the encrypted backing of an active crypto
	# mapping?
	enumerate_luks

	# Look for all iscsi disks
	for _host_dir in /sys/devices/platform/host* /sys/devices/pci*/*/*/host* ; do
		if ! [ -d "$_host_dir"/iscsi_host* ] || ! [ -d "$_host_dir"/iscsi_host/host* ] ; then
			continue
		fi
		for _session_dir in "$_host_dir"/session* ; do
			[ -d "$_session_dir"/target* ] || continue
			for _block_dev_dir in "$_session_dir"/target*/*\:*/block/* ; do
				_block_dev=${_block_dev_dir##*/}
				[ x"${_block_dev}"x != x"*"x ] || continue
				add_to_set iscsi_disks "${_block_dev}"
				hash_add_to_set ISCSI_DEVICE_SESSIONS "${_block_dev}" ${_session_dir}
			done
		done
	done

	# Look for all partitions on those disks
	for _disk in $iscsi_disks ; do
		hash_get _disk_sessions ISCSI_DEVICE_SESSIONS "${_disk}"
		for _part_dir in /sys/class/block/"${_disk}"/"${_disk}"?* ; do
			_part="${_part_dir##*/}"
			[ x"${_part}"x != x"${_disk}?*"x ] || continue
			add_to_set iscsi_partitions "${_part}"
			hash_set ISCSI_DEVICE_SESSIONS "${_part}" "${_disk_sessions}"
		done
	done

	if [ -x $MULTIPATH ] ; then
		# Look for all multipath disks
		for _disk in $iscsi_disks ; do
			hash_get _disk_sessions ISCSI_DEVICE_SESSIONS "${_disk}"
			for _alias in $($MULTIPATH -v1 -l /dev/"$_disk") ; do
				_mp_dev="$(readlink -fe "/dev/mapper/${_alias}" || :)"
				[ -n "${_mp_dev}" ] || continue
				add_to_set iscsi_multipath_disks "${_mp_dev#/dev/}"
				add_to_set iscsi_multipath_disk_aliases "${_alias}"
				hash_add_to_set ISCSI_DEVICE_SESSIONS "${_mp_dev#/dev/}" ${_disk_sessions}
				hash_add_to_set ISCSI_MPALIAS_SESSIONS "${_alias}" ${_disk_sessions}
			done
		done

		# Look for partitions on these multipath disks
		for _alias in $iscsi_multipath_disk_aliases ; do
			hash_get _mp_sessions ISCSI_MPALIAS_SESSIONS "${_alias}"
			for _part_name in /dev/mapper/"${_alias}"-part* ; do
				_part="$(readlink -fe "$_part_name" 2>/dev/null || :)"
				[ -n "${_part}" ] || continue
				add_to_set iscsi_multipath_partitions "${_part#/dev/}"
				hash_set ISCSI_DEVICE_SESSIONS "${_part#/dev/}" "${_mp_sessions}"
			done
		done
	fi

	if [ $HAVE_LUKS -eq 1 ] ; then
		# Look for all LUKS devices.
		for _dev in $iscsi_disks $iscsi_partitions $iscsi_multipath_disks $iscsi_multipath_partitions ; do
			hash_get _luksDev LUKS_DEVICES_REVERSE_MAP "${_dev}"
			[ -n "${_luksDev}" ] || continue
			add_to_set iscsi_luks_pass1 "${_luksDev}"
			hash_get _currentSession ISCSI_DEVICE_SESSIONS "${_dev}"
			if [ -n "${_currentSession}" ] ; then
				hash_set ISCSI_DEVICE_SESSIONS "${_luksDev}" "${_currentSession}"
			fi
		done
	fi

	if [ $HAVE_LVM -eq 1 ] ; then
		# Look for all LVM volume groups that have a backing store
		# on any iSCSI device we found. Also, add $LVMGROUPS set in
		# /etc/default/open-iscsi (for more complicated stacking
		# configurations we don't automatically detect).
		for _vg in $(get_lvm_vgs $iscsi_disks $iscsi_partitions $iscsi_multipath_disks $iscsi_multipath_partitions $iscsi_luks_pass1) $LVMGROUPS ; do
			add_to_set iscsi_lvm_vgs "$_vg"
		done

		# $iscsi_lvm_vgs is now unique list
		for _vg in $iscsi_lvm_vgs ; do
			# get PVs to track iSCSI sessions
			for _pv in $($VGS --noheadings -o pv_name "$_vg" 2>/dev/null) ; do
				_pv_dev="$(readlink -fe "$_pv" 2>/dev/null || :)"
				[ -n "${_pv_dev}" ] || continue
				hash_get _pv_sessions ISCSI_DEVICE_SESSIONS "${_pv_dev#/dev/}"
				hash_add_to_set ISCSI_LVMVG_SESSIONS "${_vg}" ${_pv_sessions}
			done

			# now we collected all sessions belonging to this VG
			hash_get _vg_sessions ISCSI_LVMVG_SESSIONS "${_vg}"

			# find all LVs
			for _lv in $($VGS --noheadings -o lv_name "$_vg" 2>/dev/null) ; do
				_dev="$(readlink -fe "/dev/${_vg}/${_lv}" 2>/dev/null || :)"
				[ -n "${_dev}" ] || continue
				iscsi_lvm_lvs="$iscsi_lvm_lvs ${_dev#/dev/}"
				hash_set ISCSI_DEVICE_SESSIONS "${_dev#/dev/}" "${_vg_sessions}"
			done
		done
	fi

	if [ $HAVE_LUKS -eq 1 ] ; then
		# Look for all LUKS devices.
		for _dev in $iscsi_lvm_lvs ; do
			hash_get _luksDev LUKS_DEVICES_REVERSE_MAP "${_dev}"
			[ -n "${_luksDev}" ] || continue
			add_to_set iscsi_luks_pass2 "${_luksDev}"
			hash_get _currentSession ISCSI_DEVICE_SESSIONS "${_dev}"
			if [ -n "${_currentSession}" ] ; then
				hash_set ISCSI_DEVICE_SESSIONS "${_luksDev}" "${_currentSession}"
			fi
		done
	fi

	# Gather together all mount sources
	iscsi_potential_mount_sources="$iscsi_potential_mount_sources $iscsi_disks $iscsi_partitions"
	iscsi_potential_mount_sources="$iscsi_potential_mount_sources $iscsi_multipath_disks $iscsi_multipath_partitions"
	iscsi_potential_mount_sources="$iscsi_potential_mount_sources $iscsi_lvm_lvs"
	iscsi_potential_mount_sources="$iscsi_potential_mount_sources $iscsi_luks_pass1 $iscsi_luks_pass2"

	# Convert them to numerical representation
	iscsi_potential_mount_sources_majmin=""
	for _src in $iscsi_potential_mount_sources ; do
		device_majmin _src_majmin "$_src"
		[ -n "$_src_majmin" ] || continue
		iscsi_potential_mount_sources_majmin="${iscsi_potential_mount_sources_majmin} ${_src_majmin}"
		hash_get _dev_sessions ISCSI_DEVICE_SESSIONS "${_src}"
		hash_set ISCSI_NUMDEVICE_SESSIONS "${_src_majmin}" "${_dev_sessions}"
	done

	# Enumerate mount points
	iscsi_mount_points=""
	iscsi_mount_point_ids=""
	while read _mpid _mppid _mpdev _mpdevpath _mppath _mpopts _other ; do
		if in_set iscsi_potential_mount_sources_majmin "$_mpdev" ; then
			if in_set EXCLUDE_MOUNTS "${_mppath}" ; then
				hash_get _dev_sessions ISCSI_NUMDEVICE_SESSIONS "${_mpdev}"
				add_to_set ISCSI_EXCLUDED_SESSIONS $_dev_sessions
				continue
			fi
			# list mountpoints in reverse order (in case
			# some are stacked) mount --move may cause the
			# order of /proc/self/mountinfo to not always
			# reflect the stacking order, so this is not
			# fool-proof, but it's better than nothing
			iscsi_mount_points="$_mppath $iscsi_mount_points"
			iscsi_mount_point_ids="$_mpid $iscsi_mount_points"
		fi
	done < /proc/self/mountinfo
}

try_umount() {
	# in order to handle stacking try twice; together with the fact
	# that the list of mount points is in reverse order of the
	# contents /proc/self/mountinfo this should catch most cases
	for retry in 1 2 ; do
		for path in $iscsi_mount_points ; do
			# first try to see if it really is a mountpoint
			# still (might be the second round this is done
			# and the mount is already gone, or something
			# else umounted it first)
			if ! fstab-decode mountpoint -q "$path" ; then
				continue
			fi

			# try to umount it
			if ! fstab-decode umount "$path" ; then
				# unfortunately, umount's exit code
				# may be a false negative, i.e. it
				# might give a failure exit code, even
				# though it succeeded, so check again
				if fstab-decode mountpoint -q "$path" ; then
					echo "Could not unmount $path" >&2
					any_umount_failed=1
				fi
			fi
		done
	done
}

try_deactivate_lvm() {
	[ $HAVE_LVM -eq 1 ] || return

	for vg in $iscsi_lvm_vgs ; do
		vg_excluded=0
		hash_get vg_sessions ISCSI_LVMVG_SESSIONS "$vg"
		for vg_session in $vg_sessions ; do
			if in_set ISCSI_EXCLUDED_SESSIONS "$vg_session" ; then
				vg_excluded=1
			fi
		done
		if [ $vg_excluded -eq 1 ] ; then
			# volume group on same iSCSI session as excluded
			# mount, don't disable it
			# (FIXME: we should only exclude VGs that contain
			# those mounts, not also those that happen to be
			# in the same iSCSI session)
			continue
		fi
		if ! $VGCHANGE --available=n $vg ; then
			# Make sure the volume group (still) exists. If
			# it doesn't we count that as deactivated, so
			# don't fail then.
			_vg_test=$(vgs -o vg_name --noheadings $vg 2>/dev/null || :)
			if [ -n "${_vg_test}" ] ; then
				echo "Cannot deactivate Volume Group $vg" >&2
				any_umount_failed=1
			fi
		fi
	done
}

try_dismantle_multipath() {
	[ -x $MULTIPATH ] || return

	for mpalias in $iscsi_multipath_disk_aliases ; do
		mp_excluded=0
		hash_get mp_sessions ISCSI_MPALIAS_SESSIONS "$mpalias"
		for mp_session in $mp_sessions ; do
			if in_set ISCSI_EXCLUDED_SESSIONS "$mp_session" ; then
				mp_excluded=1
			fi
		done
		if [ $mp_excluded -eq 1 ] ; then
			# multipath device on same iSCSI session as
			# excluded mount, don't disable it
			# (FIXME: we should only exclude multipath mounts
			# that contain those mounts, not also those that
			# happen to be in the same iSCSI session)
			continue
		fi
		if ! $MULTIPATH -f $mpalias ; then
			echo "Cannot dismantle Multipath Device $mpalias" >&2
			any_umount_failed=1
		fi
	done
}

try_dismantle_luks() {
	[ $HAVE_LUKS -eq 1 ] || return
	case "$1" in
	1)	iscsi_luks_current_pass="$iscsi_luks_pass1" ;;
	2|*)	iscsi_luks_current_pass="$iscsi_luks_pass2" ;;
	esac

	for luksDev in $iscsi_luks_current_pass ; do
		luks_excluded=0
		hash_get device_sessions ISCSI_DEVICE_SESSIONS "$luksDev"
		for device_session in $device_sessions ; do
			if in_set ISCSI_EXCLUDED_SESSIONS "$device_session" ; then
				luks_excluded=1
			fi
		done
		if [ $luks_excluded -eq 1 ] ; then
			continue
		fi
		_luksName="$($DMSETUP info -c --noheadings -o name /dev/"$luksDev" 2>/dev/null || :)"
		[ -n "${_luksName}" ] || continue
		if ! $CRYPTSETUP close "${_luksName}" ; then
			echo "Cannot dismantle cryptsetup device ${_luksName}" >&2
			any_umount_failed=1
		fi
	done
}

# Don't do this if we are using systemd as init system, since systemd
# takes care of network filesystems (including those marked _netdev) by
# itself.
if ! [ -d /run/systemd/system ] && [ $HANDLE_NETDEV -eq 1 ] && [ $DRY_RUN -eq 0 ]; then
	echo "Unmounting all devices marked _netdev";
	umount -a -O _netdev >/dev/null 2>&1
fi

enumerate_iscsi_devices

# Dry run? Just print what we want to do (useful for administrator to check).
if [ $DRY_RUN -eq 1 ] ; then
	echo "$0: would umount the following mount points:"
	had_mount=0
	if [ -n "$iscsi_mount_points" ] ; then
		for v in $iscsi_mount_points ; do
			echo "  $v"
			had_mount=1
		done
	fi
	[ $had_mount -eq 1 ] || echo "  (none)"

	echo "$0: would disable the following LUKS devices (second pass):"
	had_luks=0
	if [ -n "$iscsi_luks_pass2" ] ; then
		for v in ${iscsi_luks_pass2} ; do
			luks_excluded=0
			hash_get device_sessions ISCSI_DEVICE_SESSIONS "$v"
			for device_session in $device_sessions ; do
				if in_set ISCSI_EXCLUDED_SESSIONS "$device_session" ; then
					luks_excluded=1
				fi
			done
			if [ $luks_excluded -eq 1 ] ; then
				continue
			fi
			_luksName="$($DMSETUP info -c --noheadings -o name /dev/"$v" 2>/dev/null || :)"
			[ -n "${_luksName}" ] || continue
			echo "  ${_luksName}"
			had_luks=1
		done
	fi
	[ $had_luks -eq 1 ] || echo "  (none)"

	echo "$0: would deactivate the following LVM Volume Groups:"
	had_vg=0
	if [ -n "$iscsi_lvm_vgs" ] ; then
		for v in $iscsi_lvm_vgs ; do
			# sync this exclusion logic with try_deactivate_lvm
			vg_excluded=0
			hash_get vg_sessions ISCSI_LVMVG_SESSIONS "$v"
			for vg_session in $vg_sessions ; do
				if in_set ISCSI_EXCLUDED_SESSIONS "$vg_session" ; then
					vg_excluded=1
				fi
			done
			if [ $vg_excluded -eq 1 ] ; then
				continue
			fi
			echo "  $v"
			had_vg=1
		done
	fi
	[ $had_vg -eq 1 ] || echo "  (none)"

	echo "$0: would disable the following LUKS devices (first pass):"
	had_luks=0
	if [ -n "$iscsi_luks_pass1" ] ; then
		for v in ${iscsi_luks_pass1} ; do
			luks_excluded=0
			hash_get device_sessions ISCSI_DEVICE_SESSIONS "$v"
			for device_session in $device_sessions ; do
				if in_set ISCSI_EXCLUDED_SESSIONS "$device_session" ; then
					luks_excluded=1
				fi
			done
			if [ $luks_excluded -eq 1 ] ; then
				continue
			fi
			_luksName="$($DMSETUP info -c --noheadings -o name /dev/"$v" 2>/dev/null || :)"
			[ -n "${_luksName}" ] || continue
			echo "  ${_luksName}"
			had_luks=1
		done
	fi
	[ $had_luks -eq 1 ] || echo "  (none)"

	echo "$0: would deactivate the following multipath volumes:"
	had_mp=0
	if [ -n "$iscsi_multipath_disk_aliases" ] ; then
		for v in $iscsi_multipath_disk_aliases ; do
			# sync this exclusion logic with try_dismantle_multipath
			mp_excluded=0
			hash_get mp_sessions ISCSI_MPALIAS_SESSIONS "$v"
			for mp_session in $mp_sessions ; do
				if in_set ISCSI_EXCLUDED_SESSIONS "$mp_session" ; then
					mp_excluded=1
				fi
			done
			if [ $mp_excluded -eq 1 ] ; then
				continue
			fi
			echo "  $v"
			had_mp=1
		done
	fi
	[ $had_mp -eq 1 ] || echo "  (none)"

	if [ -n "$ISCSI_EXCLUDED_SESSIONS" ] ; then
		echo "$0: the following sessions are excluded from disconnection (because / or another excluded mount is on them):"
		for v in $ISCSI_EXCLUDED_SESSIONS ; do
			echo "  $v"
		done
	fi

	exit 0
fi

# after our first enumeration, write out a list of sessions that
# shouldn't be terminated because excluded mounts are on those
# sessions
if [ -n "$ISCSI_EXCLUDED_SESSIONS" ] ; then
	mkdir -p -m 0700 /run/open-iscsi
	for session in $ISCSI_EXCLUDED_SESSIONS ; do
		printf '%s\n' $session
	done > /run/open-iscsi/shutdown-keep-sessions
else
	# make sure there's no leftover from a previous call
	rm -f /run/open-iscsi/shutdown-keep-sessions
fi

any_umount_failed=0
try_umount
try_dismantle_luks 2
try_deactivate_lvm
try_dismantle_luks 1
try_dismantle_multipath

while [ $any_umount_failed -ne 0 ] && ( [ $timeout -gt 0 ] || [ $timeout -eq -1 ] ) ; do
	# wait a bit, perhaps there was still a program that
	# was terminating
	sleep 1

	# try again and decrease timeout
	enumerate_iscsi_devices
	any_umount_failed=0
	try_umount
	try_dismantle_luks 2
	try_deactivate_lvm
	try_dismantle_luks 1
	try_dismantle_multipath
	if [ $timeout -gt 0 ] ; then
		timeout=$((timeout - 1))
	fi
done

# Create signaling file (might be useful)
if [ $any_umount_failed -eq 1 ] ; then
	touch /run/open-iscsi/some_umount_failed
else
	rm -f /run/open-iscsi/some_umount_failed
fi
exit $any_umount_failed