SHA256
1
0
forked from pool/gswrap
Files
gswrap/gswrap

359 lines
8.7 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
#
# Copyright (c) 2019 SuSE GmbH Nuernberg, Germany.
# Copyright (c) 2021 SuSE SUSE Software Solutions Germany GmbH.
# Copyright (c) 2019,2021 Werner Fink
#
# Wrapper script for ghostscript based on bwrap, the container setup
# utility, which does use e.g. unshare(2) system call to create a
# safe container environment.
#
# Please report bugfixes or comments at https://www.suse.com/feedback/
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
ghostscript=@@GS@@
for prog in fuser realpath
do
type $prog >& /dev/null && continue
echo "GS: No $prog found in path" 1>&2
exit 1
done
user=nobody
home="/home/$user"
uid=$(id -u "$user")
gid=$(id -g "$user")
lock=$(mktemp "${TMPDIR:-/tmp}/.gswrap-XXXXXXXXXX") || exit 1
unlock ()
{
test -e "$lock" || return
fuser -TERM "$lock"
rm -f "$lock"
}
finish ()
{
# Used with trap to copy output files back to original cwd or directory
# to be able to hide the original cwd or directory from ghostscript process
local dir="$1"
local tmp="$2"
if test -d "$tmp"
then
for ps in "$tmp/"*
do
test -e "$ps" || continue
test -p "$ps" && continue
test -d "$dir" || continue
mv -f "$ps" "$dir"
done
rm -rf "$tmp"
fi
unlock
}
trap 'unlock' EXIT SIGINT SIGHUP
typeset -i safer=0
typeset pipecmd=""
typeset -i pipepos
typeset -a opts=()
typeset -i o=0
for lib in $(ldd $ghostscript | sed -rn 's|.*=>[[:blank:]]+||;s|[[:blank:]]*(/[^[:blank:]]+)[[:blank:]]+.*|\1|p')
do
opts[o++]=--ro-bind
opts[o++]="$lib"
opts[o++]="$lib"
done
for dir in /lib/tls /lib64/tls /lib64/x86_64 /usr/lib/ghostscript /usr/lib64/ghostscript /etc/ghostscript
do
test -d "$dir" || continue
opts[o++]=--ro-bind
opts[o++]="$dir"
opts[o++]="$dir"
done
typeset -a argv=("$@")
typeset -i c=0 argc=${#argv[@]}
for ((c=0; c < argc; c++))
do
arg="${argv[c]}"
case "$arg" in
-dSAFER)
let safer++
;;
-o)
if ((c+1 >= argc))
then
echo "GS: found -o without argument" 1>&2
exit 1
else
unset argv[c]
argv[c+1]=-sOutputFile="${argv[c+1]}"
fi
;;
-sOutputFile=*)
case "${arg#-sOutputFile=}" in
%stdout%|%stderr%|%stdout|%stderr|-|"")
continue ;;
%pipe%*)
pipecmd="${arg#-sOutputFile=%pipe%}"
let pipepos=c
;;
esac
file="${arg#-sOutputFile=}"
dir="${file%/*}"
file="${file##*/}"
if test -n "$file"
then
if test -n "$dir" -a "$dir" = "/dev"
then
# Only /dev/null or /dev/zero allowed
if test "$file" != null -a "$file" != zero
then
echo "GS: only /dev/null or /dev/zero allowed" 1>&2
exit 1
fi
opts[o++]=--dir
opts[o++]="$home/out"
elif test -n "$dir" -a -d "$dir"
then
tmp=$(mktemp -d "$dir/.gswrap-XXXXXXXXXX") || exit 1
trap "finish '$dir' '$tmp'" EXIT SIGINT SIGHUP
opts[o++]=--bind
opts[o++]="${tmp+"$tmp"}"
opts[o++]="$home/out"
else
tmp=$(mktemp -d "$PWD/.gswrap-XXXXXXXXXX") || exit 1
trap "finish '$PWD' '$tmp'" EXIT SIGINT SIGHUP
opts[o++]=--bind
opts[o++]="${tmp+"$tmp"}"
opts[o++]="$home/out"
fi
fi
argv[c]="-sOutputFile=$home/out/${file}"
continue
;;
-sDEVICE=*)
case "${arg#-sDEVICE=}" in
x11*)
;;
*)
unset DISPLAY
;;
esac
continue
;;
@*)
opts[o++]=--ro-bind
opts[o++]="${arg#@}"
opts[o++]="$home/${arg#@}"
continue
;;
-*)
continue
;;
esac
test -e "$arg" || continue
if test "${arg##*/}" = "$arg"
then
opts[o++]=--ro-bind
opts[o++]="$arg"
opts[o++]="$home/$arg"
else
arg="$(realpath "$arg")" || exit 1
argv[c]="$arg"
test "$arg" != / || continue
test "$arg" != /home || continue
test "$arg" != $home || continue
opts[o++]=--ro-bind
opts[o++]="$arg"
opts[o++]="$arg"
fi
done
# If no -dSAFER then execute the orignal ghostscript program now
if ((safer == 0))
then
exec -a ${0} $ghostscript ${1+"$@"}
fi
if test -n "$pipecmd"
then
mkfifo -m 666 "${tmp}/fd"
fd="${tmp}/fd"
exec "$pipecmd" < $fd &
argv[pipepos]="-sOutputFile=$home/fifo"
opts[o++]=--bind
opts[o++]="$fd"
opts[o++]="$home/fifo"
fi
# User might have some own font configurations as well
if test -d /var/cache/fontconfig
then
opts[o++]=--ro-bind
opts[o++]="/var/cache/fontconfig"
opts[o++]="/var/cache/fontconfig"
fi
if test -s "$HOME/.fonts.conf"
then
opts[o++]=--ro-bind
opts[o++]="${HOME+"$HOME"}/.fonts.conf"
opts[o++]="$home/.fonts.conf"
fi
for dir in "$HOME/.fontconfig" "$HOME/.config/fontconfig" "$HOME/.cache/fontconfig"
do
test -d "$dir" || continue
opts[o++]=--ro-bind
opts[o++]="$dir"
opts[o++]="${home}${dir#$HOME}"
done
# Display
if test -n "$DISPLAY"
then
: ${XAUTHORITY:="$HOME/.Xauthority"}
for dir in /usr/lib/ghostscript /usr/lib64/ghostscript
do
test -d "$dir" || continue
for x11 in $dir/*/X11.so
do
test -e "$x11" || continue
for lib in $(ldd "$x11" | sed -rn 's|.*=>[[:blank:]]+||;s|[[:blank:]]*(/[^[:blank:]]+)[[:blank:]]+.*|\1|p')
do
case "${opts[@]}" in
*[:blank:]${lib}[:blank:]*) continue ;;
esac
opts[o++]=--ro-bind
opts[o++]="$lib"
opts[o++]="$lib"
done
done
done
# for x11 in /tmp/.X11-unix /tmp/.XIM-unix /tmp/.ICE-unix /tmp/.font-unix /tmp/.X${DISPLAY##*:}-lock
for x11 in /tmp/.X11-unix
do
test -e "${x11}" || continue
opts[o++]=--ro-bind
opts[o++]="${x11}"
opts[o++]="${x11}"
done
opts[o++]=--ro-bind
opts[o++]="${XAUTHORITY+"$XAUTHORITY"}"
opts[o++]="$home/.Xauthority"
opts[o++]=--setenv
opts[o++]=XAUTHORITY
opts[o++]="$home/.Xauthority"
opts[o++]=--setenv
opts[o++]=DISPLAY
opts[o++]="${DISPLAY+"$DISPLAY"}"
if test -n "${DISPLAY%:*}"
then
# For display over e.g. local network as with slogin -X skip --unshare-net
# and allow hostname resolution via running nscd (that is nscd should be up)
opts[o++]=--ro-bind
opts[o++]="/var/run/nscd/socket"
opts[o++]="/var/run/nscd/socket"
opts[o++]=--unshare-user-try
opts[o++]=--unshare-ipc
opts[o++]=--unshare-pid
opts[o++]=--unshare-uts
opts[o++]=--unshare-cgroup-try
else
opts[o++]=--unshare-all
fi
if test -n "${GHOSTVIEW}"
then
opts[o++]=--setenv
opts[o++]=GHOSTVIEW
opts[o++]="{GHOSTVIEW+"$GHOSTVIEW"}"
fi
if test -n "${GHOSTVIEW_COLORS}"
then
opts[o++]=--setenv
opts[o++]=GHOSTVIEW_COLORS
opts[o++]="${GHOSTVIEW+"$GHOSTVIEW_COLORS"}"
fi
else
opts[o++]=--unshare-all
fi
if test -e /proc/$$/uid_map
then
opts[o++]=--uid
opts[o++]="$uid"
fi
if test -e /proc/$$/gid_map
then
opts[o++]=--gid
opts[o++]="$gid"
fi
# This is for debugging only
# add you binary like /bin/ls or /usr/bin/strace for further usage
# as replacement or prefix of ghostscript in the last line.
# Clearly the `false´ should then changed to `true´
if false
then
for bin in /usr/bin/strace
do
opts[o++]=--ro-bind
opts[o++]="$bin"
opts[o++]="$bin"
for lib in $(ldd "$bin" | sed -rn 's|.*=>[[:blank:]]+||;s|[[:blank:]]*(/[^[:blank:]]+)[[:blank:]]+.*|\1|p')
do
case "${opts[@]}" in
*[:blank:]${lib}[:blank:]*) continue ;;
esac
opts[o++]=--ro-bind
opts[o++]="$lib"
opts[o++]="$lib"
done
done
fi
unset o c argc arg
set -- "${argv[@]}"
set -euo pipefail
(exec -c -a gs /usr/bin/bwrap \
--dev /dev \
--proc /proc \
--tmpfs /run \
--tmpfs /tmp \
--ro-bind /bin/false /bin/false \
--ro-bind $ghostscript /usr/bin/gs \
--ro-bind /usr/share/ghostscript /usr/share/ghostscript \
--ro-bind /usr/share/fonts /usr/share/fonts \
--ro-bind /etc/fonts /etc/fonts \
--ro-bind "$lock" /tmp/.lock \
--lock-file /tmp/.lock \
--dir "/run/user/$uid" \
--dir /var \
--symlink ../run var/run \
--symlink ../tmp var/tmp \
--dir "$home" \
--chdir "$home" \
"${opts[@]}" \
--new-session \
--sync-fd 0 \
--sync-fd 1 \
--sync-fd 2 \
--setenv XDG_RUNTIME_DIR "/run/user/$uid" \
--setenv USER "$user" \
--setenv LOGNAME "$user" \
--setenv SHELL /bin/false \
--setenv HOME "$home" \
--setenv PATH /bin:/usr/bin \
--setenv MAIL /dev/null \
--die-with-parent \
/usr/bin/gs ${1+"$@"})
rm -f "$lock"