File: //usr/share/imunify360-webshield/webshieldctl
#!/bin/bash
if [ "$IM360_DEBUG_SHELL" = "1" ]; then
_caller=$(ps -o args= $PPID)
echo "$(date -Iseconds): $_caller [$@]" >> "${0}.log"
set -x
fi
# WARN: At the moment, this script can be called simultaneously from:
# - the agent
# - rpm/deb scriptlets
# - wafd watchdog
# - server's admin (indirectly) or tech support (directly)
# Thus, it's critically important to prevent more than one copy of this script running.
# Lock should be set in the very beginning to avoid spoiling global variables.
exec 4<"$0"
if ! flock -w 10 4 ; then
echo "ERROR: Self-lock timeout." >&2
exit 42
fi
WEBSHIELD=imunify360-webshield
SSL_UNIT=imunify360-webshield-ssl-cache
WAFD_UNIT=imunify360-wafd
MAIN_UNIT=undefined
OUR_MODULES_DIR=/usr/share/imunify360-webshield/modules
NGINX_MODULE_CONF=/etc/nginx/modules-enabled/40-imunify360-access-checker.conf
NGINX_CHECKER_CONF=/etc/nginx/conf.d/imunify360-access-checker.conf
# TODO: consider removing this file and instead using `webshieldctl mode` where needed
readonly STATE_PATH=/usr/share/imunify360-webshield/modularity_mode
readonly COMMON_CONF=/etc/sysconfig/imunify360/imunify360-merged.config
MODULARITY_MODE=
PREVIOUS_MODE=
# In CloudWays environment we integrate with their Nginx server
is_cloudways() {
hostname -f 2>/dev/null | grep -qE '^.+\.(cloudwaysapps|cloudwaysstagingapps)\.com$' && return 0
[ -x /usr/local/sbin/apm ] && /usr/local/sbin/apm info | grep -qi cloudways
}
# In Apache2nginx environment we integrate with ea-nginx
is_apache2nginx_enabled(){
grep -qsx on /var/lib/apache2nginx/state
}
is_apache2nginx_being_enabled() {
grep -qsx installing /var/lib/apache2nginx/setup_status
}
is_force_use_coraza() {
grep -qsxE 'server_type\s*=\s*nginx' /etc/sysconfig/imunify360/integration.conf && is_cloudways
}
# Both support only `nginx` modularity mode
is_nginx_mode_expected(){
is_force_use_coraza || is_cloudways || is_apache2nginx_enabled
}
get_webshield_value_from_config(){
local param=$1
[ -z $param ] && return 0
[ -s $COMMON_CONF ] || return 0
local value=$(awk -F: "
/^WEBSHIELD:\$/ {
section_found=1;
next;
};
section_found == 1 && /^[A-Z][A-Z0-9_-]*:\$/ {
section_over=1;
next;
};
section_found == 1 && section_over != 1 && /^[[:space:]]+$param:/ {
gsub(/[[:space:]]/, \"\", \$2);
print \$2;
}" $COMMON_CONF)
echo $value
}
is_cpanel(){
if [ -x /usr/local/cpanel/cpanel ];then
return 0
fi
return 1
}
is_redhat(){
if [ -e /etc/redhat-release ];then
return 0
fi
return 1
}
has_apache(){
if which apachectl &>/dev/null; then
return 0
fi
return 1
}
is_apache_module_supported(){
has_apache && is_cpanel && [ ! -d /usr/local/lsws ]
}
# We can get WEBSHIELD_ENABLE and WEBSHIELD_MODE from another entity. In this case
# webshieldctl prefers following the state that is passed from the calling entity
# to commit that configuration state to keep consistency, even if it's already been changed.
# However, when a calling entity doesn't provide the state, webshieldctl must detect
# it on its own.
detect_mode() {
# Keep it for comparison when we switch modes
PREVIOUS_MODE=$(<$STATE_PATH)
# WEBSHIELD_ENABLE and WEBSHIELD_MODE might be passed over from a calling process.
# Unless they're defined we detect the state on our own
if [ -z $WEBSHIELD_ENABLE ]; then
WEBSHIELD_ENABLE=$(get_webshield_value_from_config enable)
fi
if [ -z $WEBSHIELD_MODE ]; then
WEBSHIELD_MODE=$(get_webshield_value_from_config mode)
fi
if is_nginx_mode_expected; then
# Assuming nginx module mode - the only supported option in Cloudways and Apache2nginx environment
MODULARITY_MODE=nginx
elif is_apache_module_supported && [ $WEBSHIELD_MODE = module ]; then
MODULARITY_MODE=apache
else
MODULARITY_MODE=standalone
fi
if [ "$PREVIOUS_MODE" != "$MODULARITY_MODE" ]; then
echo "$MODULARITY_MODE" >| "$STATE_PATH"
fi
if [ "$MODULARITY_MODE" = nginx ]; then
MAIN_UNIT=nginx
elif [ "$MODULARITY_MODE" = apache ]; then
MAIN_UNIT=$(get_unit)
else
MAIN_UNIT=$WEBSHIELD
fi
# if cPanel, override path to NGINX_MODULE_CONF and OUR_MODULES_DIR
if is_cpanel && is_apache2nginx_enabled; then
NGINX_MODULE_CONF=/etc/nginx/conf.d/modules/ea-nginx-wafcl-module.conf
OUR_MODULES_DIR=/usr/lib64/nginx/modules
fi
}
# Are we in an environment where we can switch between standalone (proxy) and module-based modes?
is_supported(){
if is_apache_module_supported; then
[ "$1" = "out" ] && echo yes
return 0
fi
[ "$1" = "out" ] && echo no
return 1
}
get_apache_root(){
echo $(apachectl -V | awk -F= '/HTTPD_ROOT/{gsub("\042", "", $2);print $2}')
}
put_apache_conf(){
local access_checker_conf="/usr/share/imunify360-webshield/access_checker.conf"
local filename="access_checker.conf"
local changed=0
if is_apache_module_supported; then
local root=$(get_apache_root)
if is_redhat;then
if [ -d $root/conf.d ];then
if ! cmp -s "$access_checker_conf" "$root/conf.d/$filename"; then
cp "$access_checker_conf" "$root/conf.d/$filename"
changed=1
fi
fi
else
# By default debian-based apache has modules configs in ROOT/mods-available folder
# and enables the modules with placing a symlink to the config file into ROOT/mods-enabled.
# Ubuntu-based cpanel keeps configs in ROOT/conf.d
if [ -d $root/conf.d ];then
if ! cmp -s "$access_checker_conf" "$root/conf.d/$filename"; then
cp "$access_checker_conf" "$root/conf.d/$filename"
changed=1
fi
elif [ -d $root/mods-available ] && [ -d $root/mods-enabled ];then
if ! cmp -s "$access_checker_conf" "$root/mods-enabled/$filename"; then
cp "$access_checker_conf" "$root/mods-available/$filename"
ln -s "$root/mods-available/$filename" "$root/mods-enabled/$filename"
changed=1
fi
# But we've seen different debian apache setups
elif [ -d $root/mods-enabled ];then
if ! cmp -s "$access_checker_conf" "$root/mods-enabled/$filename"; then
cp "$access_checker_conf" "$root/mods-enabled/$filename"
changed=1
fi
fi
fi
fi
[ $changed -eq 0 ] && echo "noop"
}
remove_apache_conf(){
local root=$(get_apache_root)
local changed=0
if [ -f "$root/conf.d/access_checker.conf" ];then
rm -f "$root/conf.d/access_checker.conf"
changed=1
fi
if [ -f "$root/mods-enabled/access_checker.conf" ];then
rm -f "$root/mods-enabled/access_checker.conf"
changed=1
fi
[ $changed -eq 0 ] && echo "noop"
}
get_unit(){
if is_redhat;then
# Both ea-apache and httpd packages supply the same unit: httpd
echo httpd
else
# Ubuntu-based cPanel runs httpd unit. However, it returns 0 even on missing unit file
# So we check output '0/1 unit files listed'
if [ $(systemctl list-unit-files httpd.service 2>&1 | awk '/unit files listed/{print $1}') = '1' ];then
echo httpd
else
echo apache2
fi
fi
}
# the webshield is running as a separate entity
in_standalone_mode() {
[ "$MODULARITY_MODE" = standalone ]
}
# We supplied our module for a hoster's NGINX. No webshield is running
in_nginx_mode(){
[ "$MODULARITY_MODE" = nginx ]
}
# We supplied our module for a hoster's Apache.
# Webshield is running as well and serves non-HTTP/HTTPS ports
in_apache_mode(){
[ "$MODULARITY_MODE" = apache ]
}
is_webshield_enabled(){
[ "$WEBSHIELD_ENABLE" = true ]
}
is_proxy_expected(){
in_standalone_mode || in_apache_mode
}
# In both, standalone proxy imunify360-webshield should not be running.
# It is only used in `standalone` mode (for all ports) and `apache` mode (for hosting panel ports).
should_proxy_be_running(){
is_webshield_enabled && ! is_nginx_mode_expected
}
should_configure_nginx(){
in_nginx_mode
}
# In Apache env we only need the module if Webshield is enabled.
should_configure_apache(){
in_apache_mode
}
put_nginx_conf() {
local changed=0
local version=$(nginx -v 2>&1 | grep -oP '(\d+[.]){2}\d+')
local mod_path="${OUR_MODULES_DIR}/ngx_http_access_checker_module_${version}.so"
if is_force_use_coraza; then
mod_path="${OUR_MODULES_DIR}/ngx_http_waf_module_${version}.so"
elif is_apache2nginx_enabled && is_cpanel; then
# ea-nginx-mod-wafcl is required by Coraza-based WAF
# It is always installed by "apache2nginx setup" script, regardless of Imunify360 installation.
mod_path="${OUR_MODULES_DIR}/ngx_http_waf_module.so"
fi
if [ ! -s $mod_path ]; then
echo "ERROR: Unable to find nginx module for version '$version' in '$mod_path'." >&2
return 1
fi
# WARN: Explicit check that the path is exist and it is a directory
# cause simple 'echo' to a file will raise error with an ambiguous message
# "No such file or directory" like you're trying to *READ* from the file.
# "dirname" does not check type of its argument and just cut everything
# following the last slash.
for path in "$NGINX_MODULE_CONF" "$NGINX_CHECKER_CONF"; do
if [ ! -d $(dirname "$path") ]; then
echo "ERROR: Unable to find directory for config '$path'." >&2
return 1
fi
done
if ! nginx -t ; then
echo "ERROR: Invalid nginx config before installing module." >&2
return 1
fi
local content="load_module ${mod_path};"
if ! cmp -s "$NGINX_MODULE_CONF" <(echo "$content") ; then
echo "$content" >| "$NGINX_MODULE_CONF" || return 1
changed=1
fi
content="access_checker unix:/var/run/imunify360/libiplists-daemon.sock;"
# FIXME: This endpoint string /z0f76a1d14fd21a8fb5fd0d03e0fdc3d3cedae52f
# is hardcoded here, though in wafd it can be redefined in config. We need
# to come up with redefinable endpoint here as well.
local a2nginx_content=$(
cat <<END
$content
access_checker_pass_uri /z0f76a1d14fd21a8fb5fd0d03e0fdc3d3cedae52f;
END
)
if is_apache2nginx_enabled && is_cpanel; then
content=$a2nginx_content
fi
if ! cmp -s "$NGINX_CHECKER_CONF" <(echo "$content") ; then
echo "$content" >| "$NGINX_CHECKER_CONF" || return 1
changed=1
fi
[ $changed -eq 0 ] && echo "noop"
return 0
}
remove_nginx_config() {
if [ -f "$NGINX_MODULE_CONF" ] || [ -f "$NGINX_CHECKER_CONF" ]; then
rm -vf "$NGINX_MODULE_CONF" "$NGINX_CHECKER_CONF"
else
echo "noop"
fi
}
prepare_configs() {
case "${1:-$MODULARITY_MODE}" in
nginx)
put_nginx_conf
;;
apache)
put_apache_conf
;;
esac
}
check_nginx() {
[ -s "$NGINX_MODULE_CONF" ] || return 1
[ -s "$NGINX_CHECKER_CONF" ] || return 1
nginx -T 2> /dev/null | grep -qE '^access_checker\s+unix:/[^.]+[.]sock;$' || return 1
local pid=$(pgrep -f 'nginx:\s+master') || return 1
# pid=1 is acquired by init.
[[ "$pid" =~ ^([2-9]|[1-9][0-9]+)$ ]] || return 1
# for some reason, while nginx is running with loaded module, in test
# environment sometimes there're no references about module in /proc/$pid/maps
if is_force_use_coraza; then
grep -qP '/ngx_http_waf_module_(\d+[.]){2}\d+[.]so$' /proc/${pid}/maps
elif is_cpanel && is_apache2nginx_enabled; then
grep -qF '/ngx_http_waf_module.so' /proc/${pid}/maps
else
grep -qP '/ngx_http_access_checker_module_(\d+[.]){2}\d+[.]so$' /proc/${pid}/maps
fi
}
check_apache(){
has_apache || return 1
apachectl -M | grep -q access_checker_module
}
check_state() {
case "${1:-$MODULARITY_MODE}" in
nginx)
check_nginx
;;
apache)
check_apache
;;
esac
}
has_hosting_panel(){
local checks=(
/usr/local/cpanel/cpanel
/usr/sbin/plesk
/usr/local/directadmin/custombuild/build
)
for i in ${checks[@]};do
[ -e $i ] && return 0
done
return 1
}
count_processes(){
local count=$(ps aux | grep -c '[i]m360:\|webshield-[s]sl-cache')
echo $count
}
check_running(){
# for hosts with hosting panels we expect 5 processes to be running.
# otherwise 4 ones (ssl-cache is not expected to be run on no-panel hosts)
local num=$(count_processes)
local expected
if has_hosting_panel; then expected=3; else expected=2; fi
[ $num -ge $expected ] && return 0
return 1
}
check_stopped(){
local num=$(count_processes)
[ $num -eq 0 ] && return 0
return 1
}
do_enable(){
if should_proxy_be_running; then
if ! systemctl --quiet is-enabled $WEBSHIELD; then
systemctl unmask $WEBSHIELD
systemctl enable $WEBSHIELD
fi
if ! systemctl --quiet is-enabled $SSL_UNIT; then
systemctl enable $SSL_UNIT
fi
else
if systemctl --quiet is-enabled $WEBSHIELD; then
systemctl stop $WEBSHIELD
systemctl disable $WEBSHIELD
systemctl mask $WEBSHIELD
fi
if systemctl --quiet is-enabled $SSL_UNIT; then
systemctl disable $SSL_UNIT
fi
fi
}
safe_reload() {
# WARN: In some cases 'reload-or-restart' action is not applicable
# and need to be done directly.
[ -z $1 ] && return 0
if systemctl --quiet is-active $1 ; then
systemctl reload $1
else
systemctl restart $1
fi
}
cleanup_configs() {
case "${1:-$MODULARITY_MODE}" in
nginx)
remove_nginx_config
;;
apache)
remove_apache_conf
;;
esac
}
do_start(){
local RV=${NOOP_EXIT_CODE:-0}
if ! should_configure_apache && [ "$(cleanup_configs apache)" != noop ]; then
safe_reload "$(get_unit)"
RV=$?
fi
if ! should_configure_nginx && [ "$(cleanup_configs nginx)" != noop ]; then
safe_reload nginx
RV=$?
fi
if should_configure_apache && [ "$(prepare_configs apache)" != noop ]; then
if ! safe_reload $(get_unit); then
cleanup_configs apache
fi
RV=$?
fi
if should_configure_nginx; then
RC=$(prepare_configs nginx)
RV=$?
if [ $RV -eq 0 ];then
if [ "$RC" != noop ]; then
if is_apache2nginx_enabled && is_cpanel; then
# This command processes all nginx virtual hosts
# and reloads nginx afterwards.
/usr/local/cpanel/scripts/ea-nginx config --all
RV=$?
else
if ! nginx -t || ! safe_reload nginx; then
cleanup_configs nginx
fi
RV=$?
fi
else
RV=${NOOP_EXIT_CODE:-0}
fi
fi
fi
if should_proxy_be_running; then
if [ $(systemctl is-enabled $WEBSHIELD 2>/dev/null) = masked ]; then
systemctl unmask $WEBSHIELD
fi
if ! systemctl -q is-active $WEBSHIELD;then
systemctl start $SSL_UNIT
systemctl start $WEBSHIELD
RV=$?
else
# when we change mode we need to restart webshield for it to change
# ports it listens on
if [ "$PREVIOUS_MODE" != "$MODULARITY_MODE" ]; then
systemctl restart $WEBSHIELD
RV=$? # Might be unnecessary. Might case one redundant wafd reload
fi
fi
fi
return $RV
}
# Ths method installs all correct configs and reloads/restarts all services for
# any specific mode of operation **regardless of the current state**.
# It is fully idempotent, calling it multiple times with the same parameters
# (`MODULARITY_MODE`) is safe and would exit
# with `NOOP_EXIT_CODE` if everything is already configured correctly.
# It will not restart services unless necessary (unless configuration has changed).
#
# Implementing every separate transition in every environment is not sustainable:
# * off -> standalone (installation or WEBSHIELD.enable switch while WEBSHIELD_MODE=proxy)
# * standalone -> off (removal or WEBSHIELD.enable while WEBSHIELD_MODE=proxy)
# * off -> apache (cpanel, installation or WEBSHIELD.enable switch while WEBSHIELD_MODE=module)
# * apache -> off (cpanel, removal or WEBSHIELD.enable switch while WEBSHIELD_MODE=module)
# * standalone -> apache (cpanel, WEBSHIELD_MODE change)
# * apache -> standalone (cpanel, WEBSHIELD_MODE change)
# * apache -> nginx (cpanel, apache2nginx installation)
# * nginx -> apache (cpanel, apache2nginx removal while WEBSHIELD_MODE=module)
# * nginx -> standalone (cpanel, apache2nginx removal while WEBSHIELD_MODE=proxy)
# * etc. (probably forgot about several more)
# So instead, this method does:
# * anything -> apache
# * anything -> nginx
# * anything -> standalone
do_activate(){
if is_apache2nginx_being_enabled && systemctl -q is-active $WEBSHIELD; then
systemctl stop $WEBSHIELD || :
return ${NOOP_EXIT_CODE:-99}
fi
local RV
do_enable
RV=$?
[ $RV -ne 0 ] && return $RV
do_start
}
do_disable(){
local RV=${NOOP_EXIT_CODE:-0}
if systemctl -q is-enabled $WEBSHIELD;then
systemctl disable $SSL_UNIT
systemctl disable $WEBSHIELD
RV=$?
fi
return $RV
}
do_stop(){
local RV=${NOOP_EXIT_CODE:-0}
if is_proxy_expected && systemctl -q is-active $WEBSHIELD; then
systemctl stop $SSL_UNIT
systemctl stop $WEBSHIELD
RV=$?
fi
if should_configure_apache && [ "$(cleanup_configs apache)" != noop ]; then
systemctl reload $(get_unit)
RV=$?
fi
if should_configure_nginx && [ "$(cleanup_configs nginx)" != noop ]; then
if is_apache2nginx_enabled && is_cpanel; then
# This command processes all nginx virtual hosts
# and reloads nginx afterwards.
/usr/local/cpanel/scripts/ea-nginx config --all
else
systemctl reload nginx
fi
RV=$?
fi
return $RV
}
do_deactivate(){
if is_apache2nginx_being_enabled && systemctl -q is-active $WEBSHIELD; then
systemctl stop $WEBSHIELD || :
return ${NOOP_EXIT_CODE:-99}
fi
do_stop
local RV0=$?
[ $RV0 -ne 0 ] && [ $RV0 -ne ${NOOP_EXIT_CODE:-0} ] && return $RV0
do_disable
local RV1=$?
# if do_stop returns 0 and do_disable returns 99 we should return 0
[ $RV1 -ne $RV0 ] && return $RV0
return $RV1
}
do_terminate(){
# Called on uninstall.
# WARN: No not use 'remove_nginx_config' function here since it depends
# on current mode. Just try to remove all possible configs for all modes.
local confs=(
/etc/nginx/conf.d/imunify360-access-checker.conf
/etc/nginx/modules-enabled/40-imunify360-access-checker.conf
# apache2nginx and forced Coraza
/etc/nginx/conf.d/modules/ea-nginx-wafcl-module.conf
)
for path in "${confs[@]}"; do
rm -vf "$path"
done
# Apache configs removal is tricky, so it's necessary to use the function here.
remove_apache_conf
remove_nginx_config
# Reload is not a harmful action so it's OK to use it on extra units (e.g. the
# host has both nginx and apache, our module was used in nginx only, but here
# we reload both units - that's fine).
for unit in nginx httpd apache2; do
# WARN: Do not try to restart unit, use reload only! Because it can be disabled
# and restart will produce undefined behaviour.
systemctl --quiet is-active $unit && systemctl reload $unit
done
for unit in $SSL_UNIT $WEBSHIELD $WAFD_UNIT; do
systemctl unmask $unit || :
systemctl disable $unit || :
systemctl stop $unit || :
done
return 0
}
is_active(){
if is_proxy_expected; then
check_running
return $?
fi
check_state
}
is_enabled(){
is_proxy_expected || return 1
systemctl -q is-enabled $WEBSHIELD 2>/dev/null
}
do_restart(){
do_stop
do_start
}
do_reload(){
# WARN: Ignoring errors here is for the compatibility with sysvinit script
# which contains bug - on action "reload" it always exits with code 0.
# try-reload-or-restart is supported only from version 229,
# which is not the case for Centos7. The difference between try-reload-or-restart
# and reload-or-restart is that former does nothing unless the service is running.
# Wafd is no more a part of webshield suite, it's an independent entity
# so it's not supposed to be reloaded here
if systemctl --quiet is-active $SSL_UNIT;then
systemctl reload-or-restart $SSL_UNIT || :
fi
if systemctl --quiet is-active $MAIN_UNIT;then
systemctl reload-or-restart $MAIN_UNIT || :
fi
}
set_mode(){
WEBSHIELD_MODE=$1
detect_mode
do_activate
}
configure() {
do_deactivate || :
systemctl unmask $WEBSHIELD || :
# Also unmask these two units in case they were manually disabled by server admin.
systemctl unmask $SSL_UNIT || :
systemctl unmask $WAFD_UNIT || :
systemctl enable $WAFD_UNIT || :
systemctl start $WAFD_UNIT || :
is_nginx_mode_expected && systemctl mask $WEBSHIELD || :
do_activate || :
# During upgrade we may get a new version of the .so module
# even if there are no changes in configs required.
# Restarting nginx just in case.
# WARNING: 'reload' is not enough, 'restart' must be used!
should_configure_nginx && systemctl restart nginx || :
}
print_help(){
echo "enable : enables webshield starting on boot (without actully starting it)"
echo "is-enabled : shows if the webshield is enabled to start on boot"
echo "is-active : shows if the webshield is running now"
echo "disable : disables webshield starting on boot (without actully stopping it)"
echo "start : starts webshield (without enabling its starting on boot)"
echo "stop : stops webshield (without disabling its starting on boot)"
echo "activate : enables webshield starting on boot and starts it right away"
echo "deactivate : stops webshield right away and disables its starting on boot"
echo "terminate : stops webshield and wafd right away and disables its starting on boot"
echo "mode : shows the current module"
echo "mode-module : if possible switch from standalone to module-based mode"
echo "mode-proxy : if possible switch from module-based to standalone mode"
echo "mode-supported : prints if switching to module-based mode is supported for current system"
echo "reload : reload settings without restart"
}
detect_mode
case "$1" in
enable)
do_enable
;;
disable)
do_disable
;;
is-enabled)
is_enabled
;;
is-active)
is_active
;;
start)
do_start
;;
stop)
do_stop
;;
activate)
do_activate
;;
deactivate)
do_deactivate
;;
terminate)
do_terminate
;;
reload)
do_reload
;;
mode)
if [ "$2" = module ]; then
set_mode 'module'
elif [ "$2" = proxy ]; then
set_mode 'proxy'
elif [ "$2" = supported ]; then
is_supported 'out'
elif [ -z "$2" ]; then
if [ "$MODULARITY_MODE" = standalone ]; then
echo proxy
else
echo "$MODULARITY_MODE"
fi
else
echo "Unknown mode: $2. Exit"
exit
fi
;;
mode-proxy)
set_mode 'proxy'
;;
mode-module)
set_mode 'module'
;;
mode-supported)
is_supported 'out'
;;
is-apache)
in_apache_mode
;;
is-nginx)
in_nginx_mode
;;
is-cloudways)
is_cloudways
;;
is-standalone)
in_standalone_mode
;;
configure)
configure
;;
help)
print_help
;;
*)
echo "Usage: $0 {enable|disable|start|stop|activate|deactivate|is-enabled|is-active|reload|mode|mode proxy|mode module|mode supported|is-apache|is-nginx|is-cloudways|is-standalone|help}"
exit 2
esac