File: /var/www/secured/artro-patch.com.ua/php-chroot-bind
#!/bin/bash
_CHROOTS_CMD="ls -1d /var/www/secured/*/"
_SYSTEMD_UNIT_DIR="/etc/systemd/system"
_BIND="\
/usr/share/zoneinfo \
/dev/urandom \
/dev/zero \
/dev/null \
/etc/resolv.conf \
/lib/x86_64-linux-gnu/libnss_dns.so.2 \
/usr/share/ca-certificates \
/etc/ssl/certs"
# File with additional binds for specific chroots. Relative to the chroot.
_BIND_LOCAL="../bind.conf"
is_bound() {
mount | grep " on $1 type " > /dev/null && return 0 || return 1
}
get_binds() {
local chroot="$1"
echo $_BIND
cd "$chroot"
[ -f "$_BIND_LOCAL" ] && cat "$_BIND_LOCAL"
}
delete_path() {
local chroot="$1"
local path="$2"
local lastPath=""
local cmd="echo \" (Not deleted, use -do)\""
while [ "$path" != "/" ]; do lastPath="$path"; path=`dirname $path`; done;
$_OPT_DO && cmd="rm -rf \"${chroot}${lastPath}\" && echo \" (deleted)\""
[ -e "${chroot}${lastPath}" ] && echo -en "\tRemove: ${chroot}${lastPath}" && eval "$cmd" && return 0
return 1
}
create_systemd_units() {
local chroot=""
local eChroot=""
local bind=""
local eBind=""
local mountpoint=""
[ ! -f "${_SYSTEMD_UNIT_DIR}/php-chroots.target" ] && \
cat <<- END > "${_SYSTEMD_UNIT_DIR}/php-chroots.target" && \
echo -e "Created ${_SYSTEMD_UNIT_DIR}/php-chroots.target"
# PHP-FPM-CHROOT-BIND
[Install]
WantedBy=php7.0-fpm.service
[Unit]
Description=Bind all binds for all PHP-FPM chroots
Before=php7.0-fpm.service
END
$_CHROOTS_CMD | while read chroot; do
eChroot="`systemd-escape -p \"${chroot}\"`"
[ ! -f "${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target" ] && \
cat <<- END > "${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target" && \
echo -e "Created ${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target"
# PHP-FPM-CHROOT-BIND
[Unit]
Description=Bind all binds for PHP-FPM chroot ${chroot}
END
for bind in `get_binds "${chroot}"`; do
eBind="`systemd-escape -p \"${bind}\"`"
mountpoint="`systemd-escape -p \"${chroot}${bind}\"`"
[ ! -f "${_SYSTEMD_UNIT_DIR}/${mountpoint}.mount" ] && \
cat <<- END > "${_SYSTEMD_UNIT_DIR}/${mountpoint}.mount" && \
echo -e "Created ${_SYSTEMD_UNIT_DIR}/${mountpoint}.mount"
# PHP-FPM-CHROOT-BIND
[Unit]
Description=Bind ${bind} for PHP-FPM chroot ${chroot}
Requires=php-chroot-create-mountpoint-file-${eBind}@${eChroot}.service
Requires=php-chroot-create-mountpoint-dir-${eBind}@${eChroot}.service
BindsTo=php-chroot-${eChroot}.target
[Mount]
What=${bind}
Where=${chroot}${bind}
Type=none
Options=bind
END
[ ! -f "${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-file-${eBind}@.service" ] && \
cat <<- END > "${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-file-${eBind}@.service" && \
echo -e "Created ${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-file-${eBind}@.service"
# PHP-FPM-CHROOT-BIND
[Unit]
Description=Create mountpoint (file) for ${bind} in PHP-FPM Chroot
Before=%i-${eBind}.mount
ConditionPathExists=!/%I${bind}
ConditionPathExists=${bind}
ConditionPathIsDirectory=!${bind}
[Service]
Type=oneshot
ExecStart=/bin/mkdir -p "/%I${bind}" ; /bin/rm -r "/%I${bind}" ; /usr/bin/touch "/%I${bind}"
END
[ ! -f "${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-dir-${eBind}@.service" ] && \
cat <<- END > "${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-dir-${eBind}@.service" && \
echo -e "Created ${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-dir-${eBind}@.service"
# PHP-FPM-CHROOT-BIND
[Unit]
Description=Create mountpoint (dir) for ${bind} in PHP-FPM Chroot
Before=%i-${eBind}.mount
ConditionPathExists=!/%I${bind}
ConditionPathExists=${bind}
ConditionPathIsDirectory=${bind}
[Service]
Type=oneshot
ExecStart=/bin/mkdir -p "/%I${bind}"
END
echo "Requires=${mountpoint}.mount" >> "${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target"
done
echo "BindsTo=php-chroots.target" >> "${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target"
echo "Wants=php-chroot-${eChroot}.target" >> "${_SYSTEMD_UNIT_DIR}/php-chroots.target"
done
return 0
}
list_systemd_units() {
local unit=""
ls -1b "${_SYSTEMD_UNIT_DIR}/"* 2> /dev/null | while read unit; do
[ -f "$unit" ] && head -n1 "${unit}" | \
grep -x "# PHP-FPM-CHROOT-BIND" > /dev/null && echo "${unit}"
done
return 0
}
delete_systemd_units() {
ls -1b "${_SYSTEMD_UNIT_DIR}/"* 2> /dev/null | while read unit; do
[ -f "$unit" ] && head -n1 "${unit}" | \
grep -x "# PHP-FPM-CHROOT-BIND" > /dev/null && \
echo -n "${unit}" && if $_OPT_DO; then
rm "${unit}" && echo " (deleted)"
else
echo " (not deleted, use -do)"
fi
done
return 0
}
# Parse commandline
_OPT_CLEAN=false
_OPT_CREATE=false
_OPT_LIST=false
_OPT_DO=false
_OPT_UPDATE=false
case "$1" in
"status") _OPT_ACTION="status";;
"bind" ) _OPT_ACTION="bind";;
"unbind")
_OPT_ACTION="unbind"
[ "$2" = "clean" ] && _OPT_CLEAN=true
[ "$3" = "-do" ] && _OPT_DO=true
[ -n "$2" ] && ! $_OPT_CLEAN && _OPT_ACTION="help"
[ -n "$3" ] && ! $_OPT_DO && _OPT_ACTION="help"
;;
"systemd")
_OPT_ACTION="systemd"
[ "$2" = "clean" ] && _OPT_CLEAN=true
[ "$2" = "create" ] && _OPT_CREATE=true
[ "$2" = "list" ] && _OPT_LIST=true
[ "$2" = "update" ] && _OPT_UPDATE=true
$_OPT_CLEAN || $_OPT_CREATE || $_OPT_LIST || $_OPT_UPDATE || _OPT_ACTION="help"
[ "$3" = "-do" ] && _OPT_DO=true
[ -n "$3" ] && ! $_OPT_DO && _OPT_ACTION="help"
;;
*) _OPT_ACTION="help";;
esac
# Print help
[ "$_OPT_ACTION" = "help" ] && cat <<EOF && exit 1
Usage: $0 <command> [<subcommand> [-do]]
<command> can be one of
status:
Show if pathes defined in \$_BIND are mounted (green)
or not (red)
bind:
Bind any path defined in \$_BIND to any chroot
given by \$_CHROOTS_CMD if it is not bound already.
unbind [clean [-do]]:
Unmount all binds defined in \$_BIND mounted to chroots.
If "clean" is given, the mountpoints created for binding
will be deleted. If -do is omitted it will only print what
would be deleted. Use with -do to actually delete.
systemd create:
Create systemd unit files in \$_SYSTEMD_UNIT_DIR to
setup binds automatically on boot.
systemd list:
List systemd unit files in \$_SYSTEMD_UNIT_DIR
systemd clean [-do]:
Remove all files from \$_SYSTEMD_UNIT_DIR generated by
this script. Files are determined by starting with
# PHP-FPM-CHROOT bind
Without -do it is only shown what files would be deleted.
Use with -do to actually delete.
systemd update:
Same as
$0 systemd clean -do && $0 systemd create
Can be used to keep systemd configuration for binds
in sync with available chroots.
EOF
# List systemd unit files
[ "$_OPT_ACTION" = "systemd" ] && $_OPT_LIST && list_systemd_units && exit
# Set up systemd unit files
[ "$_OPT_ACTION" = "systemd" ] && $_OPT_CREATE && create_systemd_units && exit
# Clean up systemd unit files
[ "$_OPT_ACTION" = "systemd" ] && $_OPT_CLEAN && delete_systemd_units && exit
# Update systemd unit files
[ "$_OPT_ACTION" = "systemd" ] && $_OPT_UPDATE && $0 systemd clean -do && $0 systemd create && systemctl daemon-reload && exit
# Do operation with chroots
$_CHROOTS_CMD | while read chroot; do
echo "Chroot: $chroot"
for bind in `get_binds "${chroot}"`; do
mountpoint="${chroot}${bind}"
# List binds
if [ "$_OPT_ACTION" = "status" ]; then
is_bound "$mountpoint" && echo -en "\t\033[32m+" || echo -en "\t\033[31m-"
echo -e "\033[0m ${bind}"
continue
fi
# Bind if not bound
if [ "$_OPT_ACTION" = "bind" ] && ! is_bound "${mountpoint}"; then
# Create mountpoint (could be directory or file)
[ -d "${bind}" ] && mkdir -p "${mountpoint}" || mkdir -p "${chroot}`dirname ${bind}`" && touch "${mountpoint}"
# Mount bind read-only
echo -en "\t " && mount -v -o "bind,ro" "${bind}" "${mountpoint}"
continue
fi
# Unbind if bound
[ "$_OPT_ACTION" = "unbind" ] && is_bound "${mountpoint}" && echo -en "\t" && umount -v "${mountpoint}"
done;
# Clean up directories and files created as mountpoint
[ "$_OPT_ACTION" = "unbind" ] && $_OPT_CLEAN && for bind in `get_binds "${chroot}"`; do delete_path "${chroot}" "${bind}"; done;
done;