HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
File: //snap/cups/1100/scripts/run-cupsd
#! /bin/sh

set -e -x

mkdir -p $SNAP_DATA/var/spool/tmp
mkdir -p $SNAP_DATA/var/run/certs
mkdir -p $SNAP_DATA/var/log
mkdir -p $SNAP_DATA/var/cache/fontconfig
mkdir -p $SNAP_COMMON/etc/cups/ppd
mkdir -p $SNAP_COMMON/etc/cups/ssl
mkdir -p $SNAP_COMMON/run
mkdir -m 0755 -p /run/cups

# Set UTF-8
export LC_ALL=C.UTF-8
export LANG=C.UTF-8

# Set a general TMPDIR (for command line utilities)
export TMPDIR=$SNAP_DATA/tmp
mkdir -p $TMPDIR

# The CUPS temp dir (for cupsd, filters, backends, CGI programs, ...)
CUPSTMPDIR=$SNAP_DATA/var/spool/tmp

# Clean up the temporary directories
# We need to chown all files to root and make the files and directories
# accessible for root, otherwise we cannot delete them inside a Snap
for DIR in $TMPDIR $CUPSTMPDIR; do
    while [ -d $DIR ]; do
	chown -R root.root $DIR
	chmod -R u+rwX $DIR
	rm -rf $DIR
    done
done

# Initialize the temp directories
mkdir -p $TMPDIR
chown -R root.root $TMPDIR
chmod -R 1777 $TMPDIR
mkdir -p $CUPSTMPDIR
chown -R root.snap_daemon $CUPSTMPDIR
chmod -R 1770 $CUPSTMPDIR

# Activate full debug logging of cupsd and libcups (Needs "-
# --enable-debug-printfs" be uncommented in CUPS'
# autotools-configure-parameters in snapcraft.yaml)
#export CUPS_DEBUG_LOG=$SNAP_DATA/var/log/debug_log
#export CUPS_DEBUG_LEVEL=99

# Check whether the user and group "snap_daemon" for filters and
# backends exist and the Snap is allowed to use it and only if not run
# filters and backends as root. Note that in a Snap you can only use
# the user "snap_daemon" (UID 584788) for processes which should drop
# the root privileges (daemons or auxiliary processes of daemons, here
# filters and backends). The CUPS user "lp" cannot be used.
# See https://forum.snapcraft.io/t/system-usernames/
# Also check the existence of the "lpadmin" group. Members of this
# group are allowed to do administrative CUPS tasks, like creating
# print queues or deleting other user's jobs. If this group does not
# exist, use the general administration group "adm" instead and go
# root-only for administrative tasks if also this group does not
# exist. On Ubuntu distributions the first user created is in both
# "adm" and "lpadmin" groups.
CUPSUSER=snap_daemon
ALTCUPSUSER=root
CUPSGROUP=snap_daemon
ALTCUPSGROUP=root
CUPSSYSTEMGROUP=lpadmin
ALTCUPSSYSTEMGROUP=adm

TESTFILE=$TMPDIR/testfile
touch $TESTFILE
if ! chown $CUPSUSER $TESTFILE; then
    CUPSUSER=$ALTCUPSUSER;
fi
if ! chgrp $CUPSGROUP $TESTFILE; then
    CUPSGROUP=$ALTCUPSGROUP;
fi
rm -f $TESTFILE

if ! getent group $CUPSSYSTEMGROUP >/dev/null 2>&1; then
    CUPSSYSTEMGROUP=$ALTCUPSSYSTEMGROUP;
    if ! getent group $CUPSSYSTEMGROUP >/dev/null 2>&1; then
	CUPSSYSTEMGROUP=;
    fi
fi

# Create cups-files.conf if not already present
if [ ! -f $SNAP_COMMON/etc/cups/cups-files.conf ]; then
    # Get default cups-files.conf
    CUPSFILESCONF=$SNAP/etc/cups/cups-files.conf
    cp $CUPSFILESCONF $SNAP_COMMON/etc/cups/cups-files.conf
fi

# Set paths for the snap
perl -p -i \
     -e 's:^(\s*\#)?\s*User\s+\S+\s*$:User '"$CUPSUSER"'\n:;' \
     -e 's:^(\s*\#)?\s*Group\s+.*$:Group '"$CUPSGROUP"':;' \
     -e 's:^(\s*\#)?\s*SystemGroup\s+.*$:SystemGroup '"$CUPSSYSTEMGROUP"' root:;' \
     -e 's:^(\s*\#)?\s*AccessLog\s+.*$:AccessLog '"$SNAP_DATA"'/var/log/access_log:;' \
     -e 's:^(\s*\#)?\s*CacheDir\s+.*$:CacheDir '"$SNAP_DATA"'/var/cache:;' \
     -e 's:^(\s*\#)?\s*DataDir\s+.*$:DataDir '"$SNAP"'/share/cups:;' \
     -e 's:^(\s*\#)?\s*DocumentRoot\s+.*$:DocumentRoot '"$SNAP"'/share/cups/doc:;' \
     -e 's:^(\s*\#)?\s*ErrorLog\s+.*$:ErrorLog '"$SNAP_DATA"'/var/log/error_log:;' \
     -e 's:^(\s*\#)?\s*FontPath\s+.*$:\#FontPath (NOT SUPPORTED ANY MORE):;' \
     -e 's:^(\s*\#)?\s*PageLog\s+.*$:PageLog '"$SNAP_DATA"'/var/log/page_log:;' \
     -e 's:^(\s*\#)?\s*Printcap\s+.*$:Printcap '"$SNAP_COMMON"'/etc/printcap:;' \
     -e 's:^(\s*\#)?\s*RequestRoot\s+.*$:RequestRoot '"$SNAP_DATA"'/var/spool:;' \
     -e 's:^(\s*\#)?\s*ServerBin\s+.*$:ServerBin '"$SNAP"'/lib/cups:;' \
     -e 's:^(\s*\#)?\s*ServerRoot\s+.*$:ServerRoot '"$SNAP_COMMON"'/etc/cups:;' \
     -e 's:^(\s*\#)?\s*StateDir\s+.*$:StateDir '"$SNAP_DATA"'/var/run:;' \
     -e 's:^(\s*\#)?\s*TempDir\s+.*$:TempDir '"$SNAP_DATA"'/var/spool/tmp:;' \
     $SNAP_COMMON/etc/cups/cups-files.conf

# Determine if we have a classically installed system CUPS (from
# DEB/RPM/source for example). If so, we will run as a proxy to pass
# through jobs of snapped applications to prevent these applications
# from doing administrative tasks on the system's CUPS, even if the
# system's CUPS has no Snap mediation functionality.
#
# To get the old behavior of two CUPS daemons (classic and Snap)
# running independently on the same machine, create a file named
# /var/snap/cups/common/no-proxy Note that this mode is not
# recommended for production. It is not thoroughly tested and can
# easily confuse users. It is only intended for development.
#
# Also if you disable a system's CUPS but keep its configuration
# files and want to run the Snap's CUPS instead, please create the
# /var/snap/cups/common/no-proxy file to force the Snap into
# standard mode.
PROXY_MODE=NO
SYSTEM_CUPS_SERVER=
rm -f $SNAP_DATA/var/run/proxy-mode
if [ ! -f $SNAP_COMMON/no-proxy ]; then
    # Check if CUPS is installed classically
    if [ -r /etc/cups/cupsd.conf ]; then
	# Mark that we are in proxy mode, to block execution of cups-browsed
	touch $SNAP_DATA/var/run/proxy-mode
	PROXY_MODE=YES
	# Find out how the system's CUPS is listening for jobs
	SYSTEM_CUPS_SERVER=localhost:631
	# Find a "Listen" line with a domain socket
	if LINE=`grep -E '^[ \t]*Listen[ \t]+/' /etc/cups/cupsd.conf`; then
	    SYSTEM_CUPS_SERVER=`echo $LINE | head -1 | perl -p -e 's:^\s*Listen\s+(\S+)\s*$:\1:'`
	# Find a "Port" line
	elif LINE=`grep -E '^[ \t]*Port[ \t]+[0-9]+[ \t]*$' /etc/cups/cupsd.conf`; then
	    SYSTEM_CUPS_SERVER=localhost:`echo $LINE | head -1 | perl -p -e 's:^\s*Port\s+(\S+)\s*$:\1:'`
	# Find a "Listen" line with *:port
	elif LINE=`grep -E '^[ \t]*Listen[ \t]+\*:[0-9]+[ \t]*$' /etc/cups/cupsd.conf`; then
	    SYSTEM_CUPS_SERVER=localhost:`echo $LINE | head -1 | perl -p -e 's;^\s*Listen\s+\*:(\S+)\s*$;\1;'`
	# Find a "Listen" line with host:port
	elif LINE=`grep -E '^[ \t]*Listen[ \t]+' /etc/cups/cupsd.conf`; then
	    SYSTEM_CUPS_SERVER=`echo $LINE | head -1 | perl -p -e 's:^\s*Listen\s+(\S+)\s*$:\1:'`
	fi
    fi
fi

# Make sure that port and domain socket of this Snap are always used
# Use standard port and domain socket if this is the first CUPS started
# on this system (assumed to be the system's default CUPS)
PORT=631
ALTPORT=10631
DOMAINSOCKET=/run/cups/cups.sock
if [ ! -d /run/cups ]; then
    DOMAINSOCKET=/var/run/cups/cups.sock
fi
ALTDOMAINSOCKET=$SNAP_COMMON/run/cups.sock

if [ "${PROXY_MODE}" = "YES" ]; then
    # In proxy mode do not listen on any port but on the domain socket
    # of the Snap's CUPS
    PORT=
    DOMAINSOCKET=$ALTDOMAINSOCKET
else
    # If the standard port 631 is occupied (by a system CUPS installed via
    # DEB/RPM/source for example) use alternative port
    if $SNAP/scripts/port-occupied $PORT; then
	# CUPS already running, try alternative port
	PORT=$ALTPORT
    fi

    # If the standard domain socket is in use (by a system CUPS installed via
    # DEB/RPM/source for example) or when lpstat errors when querying it
    # use alternative domain socket
    if ! $SNAP/bin/lpstat -h $DOMAINSOCKET -r || \
	    $SNAP/bin/lpstat -h $DOMAINSOCKET -r | grep -qv ' not '; then
	# CUPS already running, try alternative domain socket
	DOMAINSOCKET=$ALTDOMAINSOCKET
    fi
fi

# Create cupsd.conf if not already present
if [ ! -f $SNAP_COMMON/etc/cups/cupsd.conf ]; then
    # Get default cupsd.conf
    CUPSDCONF=$SNAP/etc/cups/cupsd.conf
    cat $CUPSDCONF | \
	grep -v 'Listen' | \
	grep -v 'Port' | \
	perl -p -e 's:^(\s*<Location\s*/>\s*)$:$1  Allow \@LOCAL\n:' \
	     > $SNAP_COMMON/etc/cups/cupsd.conf

    # No restrictions on size of log file
    echo MaxLogSize 9999999 >> $SNAP_COMMON/etc/cups/cupsd.conf

    # Debug logging
    perl -p -i -e 's:^(\s*)\#?(\s*LogLevel\s+)\S+:\1\2debug:g' $SNAP_COMMON/etc/cups/cupsd.conf

    #chmod 0640 $SNAP_COMMON/etc/cups/cupsd.conf
fi

if [ "${PROXY_MODE}" = "YES" ]; then
    # Remove specifications where to listen from cupsd.conf
    ( cat $SNAP_COMMON/etc/cups/cupsd.conf | grep -v Listen | grep -v Port > $SNAP_COMMON/etc/cups/cupsd.conf.new || true ) && \
	mv $SNAP_COMMON/etc/cups/cupsd.conf.new $SNAP_COMMON/etc/cups/cupsd.conf
else
    # Set the port in cupsd.conf
    ( cat $SNAP_COMMON/etc/cups/cupsd.conf | grep -v Listen | grep -v Port > $SNAP_COMMON/etc/cups/cupsd.conf.new || true ) && \
	echo Port $PORT > $SNAP_COMMON/etc/cups/cupsd.conf && \
	cat $SNAP_COMMON/etc/cups/cupsd.conf.new >> $SNAP_COMMON/etc/cups/cupsd.conf && \
	rm -f $SNAP_COMMON/etc/cups/cupsd.conf.new
fi

# If we stay with the standard domain socket as $DOMAINSOCKET we are in
# stand-alone mode (no classically installed CUPS). In this case we let CUPS
# listen on BOTH the the standard domain and the alternative (Snap) domain
# The alternative domain is used by snapped client applications so that those
# always use this domain and so ALWAYS access the snapped CUPS (which has Snap
# mediation) and NEVER an installed classic CUPS (which often does not have
# SNAP mediation).
# This way CUPS is listening on the alternative domain in all three modes,
# stand-alone, proxy, and parallel
LISTENLINES=
if [ "$DOMAINSOCKET" = "$ALTDOMAINSOCKET" ]; then
    LISTENLINES="Listen $DOMAINSOCKET"
else
    LISTENLINES="Listen $DOMAINSOCKET\nListen $ALTDOMAINSOCKET"
fi

# Set the domain socket in cupsd.conf
( cat $SNAP_COMMON/etc/cups/cupsd.conf | grep -v Listen > $SNAP_COMMON/etc/cups/cupsd.conf.new || true ) && \
    echo $LISTENLINES > $SNAP_COMMON/etc/cups/cupsd.conf && \
    cat $SNAP_COMMON/etc/cups/cupsd.conf.new >> $SNAP_COMMON/etc/cups/cupsd.conf && \
    rm -f $SNAP_COMMON/etc/cups/cupsd.conf.new

# Set the domain socket in client.conf
touch $SNAP_COMMON/etc/cups/client.conf
( cat $SNAP_COMMON/etc/cups/client.conf | grep -v ServerName > $SNAP_COMMON/etc/cups/client.conf.new || true ) && \
    echo ServerName $DOMAINSOCKET > $SNAP_COMMON/etc/cups/client.conf && \
    cat $SNAP_COMMON/etc/cups/client.conf.new >> $SNAP_COMMON/etc/cups/client.conf && \
    rm -f $SNAP_COMMON/etc/cups/client.conf.new

# Create snmp.conf if not already present
if [ ! -f $SNAP_COMMON/etc/cups/snmp.conf ]; then
    # Get default snmp.conf
    cp $SNAP/etc/cups/snmp.conf $SNAP_COMMON/etc/cups/
    chmod 644 $SNAP_COMMON/etc/cups/snmp.conf
fi

# Get further default files but do not overwrite existing ones
yes n | cp -ri $SNAP/etc/cups/ppd $SNAP_COMMON/etc/cups/
yes n | cp -ri $SNAP/etc/cups/ssl $SNAP_COMMON/etc/cups/

# Spawn cupsd in a way that we can grab its PID
SCHEDULER=cupsd
exec $SCHEDULER -f -s $SNAP_COMMON/etc/cups/cups-files.conf -c $SNAP_COMMON/etc/cups/cupsd.conf &
CUPS_PID=$!
echo $CUPS_PID > $SNAP_DATA/var/run/cupsd.pid

if [ "${PROXY_MODE}" = "YES" ]; then
    # Spawn cups-proxyd in a way that we can grab its PID
    # This auxiliary daemon will mirror the system's print queues to this
    # Snap's CUPS daemon
    PROXY_DAEMON=cups-proxyd
    exec $PROXY_DAEMON $DOMAINSOCKET $SYSTEM_CUPS_SERVER -l --logdir $SNAP_DATA/var/log &
    PROXYD_PID=$!
    echo $PROXYD_PID > $SNAP_DATA/var/run/cups-proxyd.pid
else
    # Remove leftover PID file of cups-proxyd
    rm -f $SNAP_DATA/var/run/cups-proxyd.pid
    # Wait for CUPS to listen
    RUNNING=0
    for i in $(seq 10); do
	if $SNAP/bin/lpstat -h $DOMAINSOCKET -r | grep -qv ' not '; then
	    RUNNING=1
	    break
	fi
	sleep 1
    done
    if [ "${RUNNING}" = "1" ]; then
	# Remove mirrored queues from a previous proxy mode session
	for i in $(seq 30); do
	    DELETED=0
	    for p in `lpstat -h $DOMAINSOCKET -v | grep ': proxy://' | cut -d ' ' -f 3 | cut -d : -f 1`; do
		DELETED=1
		lpadmin -h $DOMAINSOCKET -x $p;
	    done
	    if [ "${DELETED}" = "0" ]; then
		break;
	    fi
	    sleep 1
	done
    fi
fi

# Keep this script running until cupsd terminates
wait $CUPS_PID

# Remove CUPS PID file as process is done
rm -f $SNAP_DATA/var/run/cupsd.pid

if [ -r $SNAP_DATA/var/run/cups-proxyd.pid && kill -0 "${PROXYD_PID}" 2>/dev/null]; then
    # Kill cups-proxyd if not already terminated by stop-cupsd
    kill -KILL $PROXYD_PID
fi

# Remove cups-proxyd PID file as process is done
rm -f $SNAP_DATA/var/run/cups-proxyd.pid

# Remove marking that we are in proxy mode
rm -f $SNAP_DATA/var/run/proxy-mode