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