#!/usr/bin/env bash
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.

# --- utility functions ---

p_echo()
{
    echo "$@" >&2
}

write() {

    local filename="$1"

    local directory=`dirname "$filename"`
    mkdirectory "$directory"
    if [ "x$?" != "x0" ] ; then
        ERROR=$?
        p_echo "Can not create directory $directory"
        return $ERROR
    fi

    # Check target file can be replaced
    if [ -f "$filename" ] ; then
        if [ ! -w "$filename" -o ! -r "$filename" ] ; then
            p_echo "Can not read/write to $filename"
            return 100
        fi
    fi

    # Put new content into temporary file
    local tmpfile
    tmpfile=`mktemp "$filename".XXXXXX`
    if [ "x$?" != "x0" -o ! -w "$tmpfile" ] ; then
        p_echo "Can not create temporary file $tmpfile"
        return 101
    fi

    # Correct owner & permissions
    chown "$FILE_OWNERGROUP" "$tmpfile" && chmod "$FILE_PERMS" "$tmpfile"

    cat > "$tmpfile"
    if [ "x$?" != "x0" ] ; then
        p_echo "Error writing to $tmpfile"
        rm -f "$tmpfile"
        return 101
    fi

    # Check that new file is not empty
    if [ ! -s "$tmpfile" ] ; then
        p_echo "No or empty input supplied on utility's standard input stream!"
        rm -f "$tmpfile"
        return 101
    fi

    # Commit changes to target file (disable interactivity in mv)
    mv -f "$tmpfile" "$filename"
    if [ "x$?" != "x0" ] ; then
        ERROR=$?
        rm -f "$tmpfile"
        return $ERROR
    fi

    return $?
}

mklink() {
    if ! echo "$1" | grep -q ':' 2>/dev/null; then
        p_echo "Invalid format for mklink: wait source:destinstation, got $1"
        return 102
    fi

    local filename="${1%%:*}"
    local destination="${1#*:}"
    local directory=`dirname "$filename"`
    local destination_directory=`dirname "$destination"`

    if ! [ -d "$directory" -a -f "$filename" ]; then
        p_echo "Path $filename doesn't exist"
        return 100
    fi

    if [ ! -d "$destination_directory" ]; then
        p_echo "Destination directory '$destination_directory' not exist"
        return 100
    fi

    if [ -f "$destination" -a ! -L "$destination" ]; then
        p_echo "Refusing to create symlink '$destination': file with the same name already exists"
        return 101
    fi

    local fname=`basename "$filename"`
    local lnkname="last_${fname#*_}"
    # Create convenience symlink to last written config
    pushd "$directory"
    if [ ! -f "$lnkname" -o -L "$lnkname" ] ; then
        ln -snfT "$fname" "$lnkname"
    else
        p_echo "Refusing to create symlink '$directory/$lnkname': file with the same name already exists"
        ERROR=101
    fi
    popd
    # Create symlink for argument
    ln -snfT "$filename" "$destination"
    local tmp_err="$?"
    [ "$tmp_err" = "0" ] || ERROR="$tmp_err"

    return $ERROR
}

mkdirectory() {

    local path="$1"

    if [ -d "$path" ] ; then
        return 0
    fi

    if [ -e "$path" ] ; then
        p_echo "File $path already exists"
        return 100
    fi

    mkdir "$path"
    if [ "x$?" != "x0" ] ; then
        ERROR=$?
        return $ERROR
    fi

    chmod "$DIR_PERMS" "$path"
    if [ "x$?" != "x0" ] ; then
        ERROR=$?
        return $ERROR
    fi
    chown "$DIR_OWNERGROUP" "$path"
    if [ "x$?" != "x0" ] ; then
        ERROR=$?
        return $ERROR
    fi

    return $?
}

check() {
    local id file
    while read data; do
        if [ "x$data" != "x" ]; then
            id=${data%%:*};
            file=${data#*:};
            if [ ! -f $file ]; then
                echo "$id:File '$file' not found";
            fi
        fi
    done
    return 0
}

backup_file() {

    local filename="$1"

    [ ! -f "$filename" ] && return 0

    cp -f "$filename" "$filename.bak"
    chown "$FILE_OWNERGROUP" "$filename.bak" && chmod "$FILE_PERMS" "$filename.bak"

    return $?
}

restore_file() {

    local filename="$1"

    [ ! -f "$filename.bak" ] && return 0

    cp -f "$filename.bak" "$filename"
    chown "$FILE_OWNERGROUP" "$filename" && chmod "$FILE_PERMS" "$filename"

    return $?
}
#!/usr/bin/env bash
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.

usage() {
    cat << EOH

Usage: $0 [options]

 Helper utility to manage Apache configuration files

OPTIONS:
 -t      - Test current configuration of web server.
 -d dir  - Create directory.
 -w file - Write content from stdin to the specified file.
 -b file - Create backup copy of specified file.
 -r file - Restore backup copy of specified file if present.
 -l file:destination - Switch or create symlink to the specified file
           and switch or create 'last_*' symlink
 -c      - Read configuration files list from stdin and check their
           their presence. Each line should be like '<id>:<filepath>'.

EOH
}

set_params()
{
    DIR_OWNERGROUP="www-data":"psacln"
    DIR_PERMS=770
    FILE_OWNERGROUP="root":"www-data"
    FILE_PERMS=600
}

# --- script ---

if [ $# -eq 0 ] ; then
    usage
    exit 0
fi

getopts "td:w:l:cb:r:" OPTION

set_params

ERROR=0
case $OPTION in
    t)
        [ ! -e "/etc/apache2/envvars" ] || source /etc/apache2/envvars
        /usr/sbin/apache2ctl -t
        ERROR=$?
        ;;
    d)
        mkdirectory "$OPTARG"
        ERROR=$?
        ;;
    w)
        write "$OPTARG"
        ERROR=$?
        ;;
    l)
        mklink "$OPTARG"
        ERROR=$?
        ;;
    c)
        check
        ERROR=$?
        ;;
    b)
        backup_file "$OPTARG"
        ERROR=$?
        ;;
    r)
        restore_file "$OPTARG"
        ERROR=$?
        ;;
    *)
        usage
        ERROR=1
        ;;
esac

exit $ERROR

#
# Helper utility for file operations with Apache's configuration files.
#
