File modify_cupsd_conf.for_cups-browsed of Package yast2-printer
#! /bin/bash
#
# Johannes Meixner <jsmeix@suse.de>, 2007, 2008, 2009, 2010, 2011, 2014
# set -x
# Make sure to have a clean environment:
export PATH="/sbin:/usr/sbin:/usr/bin:/bin"
export LC_ALL="POSIX"
export LANG="POSIX"
umask 022
# Disable bash file name globbing:
set -f
MY_NAME=${0##*/}
CUPSDCONF="/etc/cups/cupsd.conf"
# Determine if we have CUPS <= 1.5.4 < 1.6 (with traditional CUPS Browsing)
# or CUPS >= 1.6.0 > 1.6 (with cups-browsed):
BROWSEDCONF=""
if zypper versioncmp $( cups-config --version ) 1.6 | grep -q 'newer'
then if test -e /etc/cups/cups-browsed.conf
then BROWSEDCONF="/etc/cups/cups-browsed.conf"
BROWSEDUNITFILE="cups-browsed.service"
fi
fi
KEY="$1"
if test -z "$KEY"
then if test -z "$BROWSEDCONF"
then echo "Read and write $CUPSDCONF (but does not restart cupsd)." 1>&2
else echo "Read and write $CUPSDCONF or $BROWSEDCONF (but does not restart cupsd)." 1>&2
fi
echo "Usage:" 1>&2
echo "$MY_NAME keyword [ new value ]" 1>&2
echo "Without a new value, the current value is reported." 1>&2
echo "Supported keywords and possible new values are:" 1>&2
echo "Browsing [ On | Off ]" 1>&2
if test -n "$BROWSEDCONF"
then echo " Browsing On (re)starts and enables cups-browsed." 1>&2
echo " Browsing Off stops and disables cups-browsed." 1>&2
fi
echo " (Browsing On should be set when BrowseAllow or BrowseAddress is not 'none')" 1>&2
if test -z "$BROWSEDCONF"
then echo "BrowseAllow [ all | @LOCAL | host-address | network-address/netmask ] | BrowseAllow none" 1>&2
echo "e.g.: BrowseAllow '@LOCAL 192.168.100.1 192.168.200.0/255.255.255.0'" 1>&2
echo " BrowseAllow none (to deny all incoming browse packets)" 1>&2
else echo "BrowseAllow [ all | host-address | network-address/netmask ] | BrowseAllow none" 1>&2
echo "e.g.: BrowseAllow '192.168.100.1 192.168.200.0/255.255.255.0'" 1>&2
echo " The former BrowseAllow @LOCAL is no longer supported for cups-browsed." 1>&2
fi
echo "BrowsePoll [ host-address ] | BrowsePoll none" 1>&2
echo "e.g.: BrowsePoll '192.168.100.1 192.168.200.1'" 1>&2
echo " BrowsePoll none (to poll not at all, i.e. no BrowsePoll line)" 1>&2
echo "Listen [ all | network-address ] | Listen localhost" 1>&2
echo "e.g.: Listen '192.168.100.0 192.168.200.0' (localhost is added automatically)" 1>&2
echo " Listen localhost (to have only 'Listen 127.0.0.1:631')" 1>&2
echo "Allow [ all | @LOCAL | @IF(name) | host-address | network-address/netmask ] | Allow none" 1>&2
echo "e.g.: Allow '@LOCAL @IF(eth1) 192.168.100.1 192.168.200.0/255.255.255.0'" 1>&2
echo " (to allow access via the root location '<Location />')" 1>&2
echo " Allow none (to have only 'Allow 127.0.0.2', localhost is allowed in any case)" 1>&2
if test -z "$BROWSEDCONF"
then echo "BrowseAddress [ @LOCAL | @IF(name) | host-address | broadcast-address ] | BrowseAddress none" 1>&2
echo "e.g.: BrowseAddress '@LOCAL @IF(eth1) 192.168.100.1 192.168.200.255'" 1>&2
echo " BrowseAddress none (to send no browse packets, i.e. no BrowseAddress line)" 1>&2
else echo "BrowseAddress @LOCAL | BrowseAddress none" 1>&2
echo "e.g.: BrowseAddress @LOCAL sets BrowseLocalProtocols CUPS in /etc/cups/cups-browsed.conf" 1>&2
echo " The former BrowseAddress [ @IF(name) | host-address | broadcast-address ]" 1>&2
echo " is no longer supported for cups-browsed." 1>&2
echo " BrowseAddress none sets BrowseLocalProtocols none in /etc/cups/cups-browsed.conf" 1>&2
fi
echo "Policies" 1>&2
echo " (reports the existing policy names in '<Policy policy-name>' sections)" 1>&2
echo "DefaultPolicy [ policy-name ] | DefaultPolicy default" 1>&2
echo " (The policy-name must exist as a '<Policy policy-name>' section)" 1>&2
echo "ErrorPolicy [ stop-printer | retry-job | abort-job ]" 1>&2
echo " (if ErrorPolicy is not set, stop-printer is the CUPS default)" 1>&2
echo "DirtyCleanInterval [ seconds ] (since CUPS 1.4)" 1>&2
echo "e.g.: DirtyCleanInterval 30 (default 30 seconds delay until cupsd writes config files)" 1>&2
echo " DirtyCleanInterval 0 (update config files like printers.conf almost immediately)" 1>&2
echo "For the syntax for keywords and values see 'man cupsd.conf'" 1>&2
echo "and http://www.cups.org/documentation.php/ref-cupsd-conf.html" 1>&2
if test -n "$BROWSEDCONF"
then echo "and $BROWSEDCONF and /usr/share/doc/packages/cups-filters/README" 1>&2
fi
echo "In case of ambiguity use the syntax which is described above." 1>&2
echo "Usually case matters, in particular for special values like On Off @LOCAL @IF none all." 1>&2
echo "Multiple values for a keyword must be separated by space in one quoted argument." 1>&2
exit 1
fi
if ! test -r $CUPSDCONF -a -w $CUPSDCONF
then echo "Cannot read or write $CUPSDCONF." 1>&2
exit 2
fi
if test -n "$BROWSEDCONF"
then if ! test -r $BROWSEDCONF -a -w $BROWSEDCONF
then echo "Cannot read or write $BROWSEDCONF." 1>&2
exit 2
fi
fi
# Remove duplicates (ignore case) and remove duplicate, leading and trailing spaces.
# Case is only ignored if there are duplicates (e.g. 'host.domain.com' and 'Host.Domain.com')
# but if there is e.g. only 'Host.Domain.com' it is written exactly this way to cupsd.conf
# because the user may like to have it exactly in cupsd.conf (even if actually case may not matter):
VALUE="$( for V in $2 ; do echo $V ; done | sort -b -f -u | tr -s '[:space:]' ' ' | sed -e 's/ *$//' )"
# Determine if /etc/cups/cups-browsed.conf would be actually used (for read or write)
# which means when the KEY is BrowseAllow or BrowsePoll:
USESBROWSEDCONF=""
if test -n "$BROWSEDCONF"
then case "$KEY" in
BrowseAllow | BrowsePoll | BrowseAddress ) USESBROWSEDCONF="yes";;
esac
fi
# Function to backup /etc/cups/cupsd.conf or /etc/cups/cups-browsed.conf
# and append a log entry of the intended change in the file:
PrepareConfigFile()
{ FILENAME="$1"
if test -z "$FILENAME"
then echo "Aborting because of syntax error: PrepareConfigFile() called without file name argument." 1>&2
exit 3
fi
# Make a backup before anything is changed:
if rpm -V -f $FILENAME | grep -q "^..5.*$FILENAME\$"
then # The FILENAME was already changed (RPM tells that the MD5 sum differs):
if ! cp -p $FILENAME $FILENAME.yast2save
then echo "Failed to backup $FILENAME as $FILENAME.yast2save" 1>&2
exit 3
fi
else # The FILENAME content is the original from the RPM package:
if ! cp -p $FILENAME $FILENAME.yast2orig
then echo "Failed to backup $FILENAME as $FILENAME.yast2orig" 1>&2
exit 3
fi
fi
# Log the intended change before it is actually written:
echo "# $(date '+%F,%T') $MY_NAME $KEY $VALUE" >>$FILENAME
}
# Make a backup of /etc/cups/cupsd.conf or /etc/cups/cups-browsed.conf if it would be changed
# and append a log entry of the intended change in the file:
if test -n "$VALUE"
then # Make a backup of /etc/cups/cups-browsed.conf only when it will be actually changed which means
# when the KEY is BrowseAllow or BrowsePoll or BrowseAddress and the VALUE is non-empty:
if test -n "$USESBROWSEDCONF"
then # Prepare /etc/cups/cups-browsed.conf:
PrepareConfigFile $BROWSEDCONF
else # Prepare /etc/cups/cupsd.conf:
PrepareConfigFile $CUPSDCONF
fi
fi
# Function to output the line number of the last matching line or the line number of the first empty line:
LastMatchingLineNumberOrFirstEmptyLineNumber()
{ FILENAME="$1"
if test -z "$FILENAME"
then echo "Aborting because of syntax error: LastMatchingLineNumberOrFirstEmptyLineNumber() called without file name argument." 1>&2
exit 3
fi
INTENDEDMATCH="$2"
FALLBACKMATCH="$3"
LINE_NUMBER=""
if test -n "$INTENDEDMATCH" -o -n "$FALLBACKMATCH"
then # First try to find the actually intened matching line and then try the fallback match:
for MATCH in "$INTENDEDMATCH" "$FALLBACKMATCH"
do # First try to get and output the line number of the last matching active line:
LINE_NUMBER="$( sed -n -e "/^[[:space:]]*${MATCH}/I=" $FILENAME | tail -n 1 )"
if test -n "$LINE_NUMBER"
then echo "$LINE_NUMBER"
return 0
fi
# Otherwise try to get and output the line number of the last matching non-active line:
LINE_NUMBER="$( sed -n -e "/^[[:space:]]*#[[:space:]]*${MATCH}/I=" $FILENAME | tail -n 1 )"
if test -n "$LINE_NUMBER"
then echo "$LINE_NUMBER"
return 0
fi
done
fi
# When INTENDEDMATCH and FALLBACKMATCH are both empty
# or when neither a matching active line nor a matching non-active line was found
# then as last fallback try to get and output the line number of the first empty line
# (as fallback it is better to write at the first empty line than at the last empty line):
LINE_NUMBER="$( sed -n -e '/^[[:space:]]*$/=' $FILENAME | head -n 1 )"
if test -n "$LINE_NUMBER"
then echo "$LINE_NUMBER"
return 0
fi
echo ""
return 1
}
# Function to append lines with same KEYWORD and one or more VALUES one by one for each VALUE
# at a line number or at the end of the file when the line number is empty:
AppendKeyValueLinesAtLineNumberOrAtEndOfFile()
{ FILENAME="$1"
if test -z "$FILENAME"
then echo "Aborting because of syntax error: AppendKeyValueLinesAtLineNumberOrAtEndOfFile() called without file name argument." 1>&2
exit 3
fi
KEYWORD="$2"
VALUES="$3"
LINE_NUMBER="$4"
if test -n "$LINE_NUMBER"
then # When appending lines one by one at a fixed LINE_NUMBER with 'sed'
# invert the ordering of the values to get the lines added in the file
# in the original ordering of the values:
for V in $( echo "$VALUES" | tac -s ' ' )
do test -n "$V" && sed -i -e "${LINE_NUMBER}a$KEYWORD $V" $FILENAME
done
else # When appending lines one by one at the end of the file,
# append them in the original ordering:
for V in $VALUES
do test -n "$V" && echo -en "\n$KEYWORD $V\n" >>$FILENAME
done
fi
}
# Function to deal with 'Browsing [ On | Off ]'
Browsing()
{ if test -n "$VALUE"
then # Try to substitute an existing active Browsing line (ignore case).
# (If there is more than one active Browsing line it is a broken config file):
sed -i -e "s/^[[:space:]]*$KEY.*/$KEY $VALUE/i" $CUPSDCONF
# There may exist no Browsing line or the above substitute may have failed
# (therefore it tests not only for "^$KEY" but for "^$KEY $VALUE$"):
if ! grep -q "^$KEY $VALUE$" $CUPSDCONF
then # Append a Browsing line below the last active 'Brows' line (ignore case)
# to have the new Browsing line at the matching place
# but if no 'Brows' line exists, append below the first empty line
# which is usually the line after the initial comment block
# and if even no empty line exists, append at the end of the file:
LAST_BROWSE_LINE_NUMBER="$( sed -n -e '/^[^#]*Brows/I=' $CUPSDCONF | tail -n 1 )"
if test -n "$LAST_BROWSE_LINE_NUMBER"
then sed -i -e "${LAST_BROWSE_LINE_NUMBER}a$KEY $VALUE" $CUPSDCONF
else FIRST_EMPTY_LINE_NUMBER="$( sed -n -e '/^[[:space:]]*$/=' $CUPSDCONF | head -n 1 )"
if test -n "$FIRST_EMPTY_LINE_NUMBER"
then sed -i -e "${FIRST_EMPTY_LINE_NUMBER}a$KEY $VALUE\n" $CUPSDCONF
else echo -en "\n$KEY $VALUE\n\n" >>$CUPSDCONF
fi
fi
fi
if test -n "$BROWSEDCONF"
then if test -z "$( type -ap systemctl )"
then echo "Aborting because 'systemctl' not executable (no 'systemd' RPM installed?)" 1>&2
exit 5
fi
case "$VALUE" in
[Oo][Nn] ) if ! { systemctl --quiet enable $BROWSEDUNITFILE && systemctl --quiet restart $BROWSEDUNITFILE ; }
then echo "Failed to enable and/or (re)start $BROWSEDUNITFILE." 1>&2
exit 5
fi ;;
[Oo][Ff][Ff] ) if ! { systemctl --quiet stop $BROWSEDUNITFILE && systemctl --quiet disable $BROWSEDUNITFILE ; }
then echo "Failed to stop and/or disable $BROWSEDUNITFILE." 1>&2
exit 5
fi ;;
* ) echo "Invalid value '$VALUE' for '$KEY'." 1>&2
exit 5 ;;
esac
fi
fi
# Report the resulting setting in any case:
# The 'tr ... [:blank:]' makes sure that all active Browsing entries
# are found if there is more than one which is a broken config.
# Remove leading spaces (to cut the right part).
# Remove trailing spaces (needed for the test below).
RESULT="$( grep -i "^[[:space:]]*$KEY[[:space:]]" $CUPSDCONF | tr -s '[:blank:]' ' ' | sed -e 's/^ *//' | cut -s -d ' ' -f2 | tr -s '\n' ' ' | sed -e 's/ *$//' )"
# Test whether or not the RESULT matches cups-browsed actual status
# if not report a warning on stderr but do not abort in case of errors
# instead adjust the RESULT to match cups-browsed actual status:
if test -n "$BROWSEDCONF"
then if test -z "$( type -ap systemctl )"
then echo "Cannot check cups-browsed status because 'systemctl' not executable (no 'systemd' RPM installed?)" 1>&2
else case "$RESULT" in
[Oo][Nn] ) if ! { systemctl --quiet is-active $BROWSEDUNITFILE && systemctl --quiet is-enabled $BROWSEDUNITFILE ; }
then echo "Browsing is On in /etc/cups/cupsd.conf but cups-browsed not running and/or not enabled" 1>&2
echo "so that Browsing Off is reported to match cups-browsed actual status." 1>&2
RESULT="Off"
fi ;;
[Oo][Ff][Ff] ) if systemctl --quiet is-active $BROWSEDUNITFILE || systemctl --quiet is-enabled $BROWSEDUNITFILE
then echo "Browsing is Off in /etc/cups/cupsd.conf but cups-browsed is running and/or enabled" 1>&2
echo "so that Browsing On is reported to match cups-browsed actual status." 1>&2
RESULT="On"
fi ;;
* ) echo "Invalid value '$VALUE' for '$KEY'." 1>&2
esac
fi
fi
echo -n "$RESULT"
# For a nicer output on a terminal where stdout and stderr is mixed up,
# output a '\n' on stderr to get subsequent stuff (e.g. the shell prompt
# or an error message because of a failed test below) on a new line:
echo 1>&2
# Test if the result is the expected one if a value was specified:
if test -n "$VALUE" -a "${RESULT^^}" != "${VALUE^^}"
then echo "Failed to set '$KEY $VALUE' in $CUPSDCONF." 1>&2
exit 5
fi
}
# Function to deal with 'BrowseAllow [ all | @LOCAL | host-address | network-address/netmask ] | BrowseAllow none'
BrowseAllow()
{ if test -n "$VALUE"
then # When VALUE contains "none" anything else is removed to be secure:
for V in $VALUE
do if test "none" = "$V"
then VALUE="none"
break
fi
done
# When VALUE contains "all" (but not "none", see above) anything else is removed to avoid meaningless stuff:
for V in $VALUE
do if test "all" = "$V"
then VALUE="all"
break
fi
done
if test -n "$BROWSEDCONF"
then # When VALUE is not "all" and not "none" test if its values are valid:
if test "all" != "$VALUE" -a "none" != "$VALUE"
then # When VALUE contains "@LOCAL" abort regardless of possible other values
# to ensure the user gets negative feedback:
for V in $VALUE
do if test "@LOCAL" = "$V"
then echo "BrowseAllow is no longer supported in /etc/cups/cupsd.conf since CUPS >= 1.6." 1>&2
echo "BrowseAllow @LOCAL is not supported in /etc/cups/cups-browsed.conf for cups-browsed." 1>&2
echo "For cups-browsed use BrowseAllow host-address or BrowseAllow network-address/netmask." 1>&2
exit 6
fi
done
# When VALUE contains something that is not of the form of an IPv4 address (netmask is optional)
# abort regardless of possible other values to ensure the user gets negative feedback
# see https://bugs.linuxfoundation.org/show_bug.cgi?id=1204
# and https://bugs.linuxfoundation.org/show_bug.cgi?id=1205
for V in $VALUE
do if ! echo "$V" | egrep -q '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
then echo "For cups-browsed a BrowseAllow value must be either an IPv4 host address (e.g. 192.168.1.12)" 1>&2
echo "or an IPv4 network address plus netmask (e.g. 192.168.1.0/255.255.255.0 or 192.168.1.0/24)." 1>&2
exit 6
fi
done
fi
# All existing active BrowseAllow lines are removed (ignore case).
# Those lines can be removed because YaST supports BrowseAllow lines
# (YaST shows the BrowseAllow entries in the "printing via network" dialog):
sed -i -e '/^[[:space:]]*BrowseAllow.*/Id' $BROWSEDCONF
# For 'BrowseAllow all' do not have any active BrowseAllow line (all were deleted above) because
# no active BrowseAllow line means to accept browse packets from all hosts (see 'man cups-browsed.conf'):
if ! test "all" = "$VALUE"
then if test "none" = "$VALUE"
then # The value 'none' is not explicitly supported (see the source file cups-browsed.c)
# therefore a single value from 192.0.2.0/24 (TEST-NET-1 see RFC5737) is set
# which no real host has which effectively means no browse packets are accepted:
VALUE="192.0.2.1"
fi
# Try to find a matching existing BrowseAllow or 'Brows' line
# where to append the new BrowseAllow lines
# to have the new BrowseAllow lines at the right place
# but if no such line exists, append below the first empty line
# which is usually the line after the initial comment block
# and if even no empty line exists, append at the end of the file:
APPEND_LINE_NUMBER="$( LastMatchingLineNumberOrFirstEmptyLineNumber $BROWSEDCONF BrowseAllow Brows )"
AppendKeyValueLinesAtLineNumberOrAtEndOfFile $BROWSEDCONF $KEY $VALUE $APPEND_LINE_NUMBER
fi
# Check cups-browsed status and enable and (re)start it (needed when it is not 'BrowseAllow none')
# on the other hand only 'BrowseAllow none' does not mean cups-browsed should be stopped and disabled
# but 'BrowseAllow none' means cups-browsed should be restarted but only if it is actually running.
if test -z "$( type -ap systemctl )"
then echo "Aborting because 'systemctl' not executable (no 'systemd' RPM installed?)" 1>&2
exit 5
fi
# See above the special hack for 'BrowseAllow none' by setting "192.0.2.1" as value:
if test "192.0.2.1" = "$VALUE"
then if systemctl --quiet is-active $BROWSEDUNITFILE
then if ! systemctl --quiet restart $BROWSEDUNITFILE
then "Failed to restart $BROWSEDUNITFILE." 1>&2
exit 5
fi
fi
else if ! { systemctl --quiet enable $BROWSEDUNITFILE && systemctl --quiet restart $BROWSEDUNITFILE ; }
then echo "Failed to enable and/or (re)start $BROWSEDUNITFILE." 1>&2
exit 5
fi
fi
else # Set 'BrowseOrder allow,deny' to deny browse packets by default
# and then allow them from certain sources via BrowseAllow entries
# and finally deny from certain sources via BrowseDeny entries.
# All existing active BrowseOrder lines are removed (ignore case).
sed -i -e '/^[[:space:]]*BrowseOrder.*/Id' $CUPSDCONF
# Append the new BrowseOrder line below the last active 'Brows' line (ignore case)
# to have the new BrowseOrder line at the matching place
# but if no 'Brows' line exists, append below the first empty line
# which is usually the line after the initial comment block
# and if even no empty line exists, append at the end of the file:
LAST_BROWSE_LINE_NUMBER="$( sed -n -e '/^[^#]*Brows/I=' $CUPSDCONF | tail -n 1 )"
if test -n "$LAST_BROWSE_LINE_NUMBER"
then sed -i -e "${LAST_BROWSE_LINE_NUMBER}aBrowseOrder allow,deny" $CUPSDCONF
else FIRST_EMPTY_LINE_NUMBER="$( sed -n -e '/^[[:space:]]*$/=' $CUPSDCONF | head -n 1 )"
if test -n "$FIRST_EMPTY_LINE_NUMBER"
then sed -i -e "${FIRST_EMPTY_LINE_NUMBER}aBrowseOrder allow,deny\n" $CUPSDCONF
else echo -en "\nBrowseOrder allow,deny\n\n" >>$CUPSDCONF
fi
fi
# All existing active BrowseAllow lines are removed (ignore case).
# Those lines can be removed because YaST supports BrowseAllow lines
# (YaST shows the BrowseAllow entries in the "printing via network" dialog):
sed -i -e '/^[[:space:]]*BrowseAllow.*/Id' $CUPSDCONF
# All active 'BrowseDeny all' lines are removed (ignore case).
# Such a line was added when the VALUE was "none", see below:
sed -i -e '/^[[:space:]]*BrowseDeny[[:space:]]*all/Id' $CUPSDCONF
# All remaining active BrowseDeny lines are deactivated (ignore case).
# Those lines are not removed because YaST does not support BrowseDeny lines
# so that a remove would silently delete BrowseDeny information:
sed -i -e 's/^[[:space:]]*\(BrowseDeny.*\)$/#\1/i' $CUPSDCONF
# Insert BrowseAllow lines before the BrowseOrder line
# to have the new BrowseAllow lines at the matching place
# and in the ordering of the values (needed for the test below):
if ! test "none" = "$VALUE"
then for V in $VALUE
do test -n "$V" && sed -i -e "/^BrowseOrder /i$KEY $V" $CUPSDCONF
done
else # The 'BrowseOrder allow,deny' line denies browse packets by default
# to be 100% on the safe side have explicite 'BrowseAllow none' and 'BrowseDeny all' lines too:
sed -i -e "/^BrowseOrder /aBrowseAllow none\nBrowseDeny all" $CUPSDCONF
fi
fi
fi
if test -n "$BROWSEDCONF"
then CONFIGFILE=$BROWSEDCONF
else CONFIGFILE=$CUPSDCONF
fi
# Report the resulting setting in any case:
# The 'tr ... [:blank:]' makes sure that all active BrowseAllow entries
# are found if there is more than one which is allowed.
# Remove leading spaces (to cut the right part).
# Remove trailing spaces (needed for the test below).
RESULT="$( grep -i "^[[:space:]]*$KEY[[:space:]]" $CONFIGFILE | sed -e 's/from//I' | tr -s '[:blank:]' ' ' | sed -e 's/^ *//' | cut -s -d ' ' -f2 | tr -s '\n' ' ' | sed -e 's/ *$//' )"
if test -n "$BROWSEDCONF"
then # Fixing the evil hacks above:
if test -z "$RESULT"
then RESULT="all"
fi
if test "192.0.2.1" = "$RESULT"
then RESULT="none"
fi
VALUE="$RESULT"
fi
echo -n "$RESULT"
# For a nicer output on a terminal where stdout and stderr is mixed up,
# output a '\n' on stderr to get subsequent stuff (e.g. the shell prompt
# or an error message because of a failed test below) on a new line:
echo 1>&2
# Test if the result is the expected one if a value was specified:
if test -n "$VALUE" -a "$RESULT" != "$VALUE"
then echo "Failed to set '$KEY $VALUE' in $CONFIGFILE." 1>&2
exit 5
fi
}
# Function to deal with 'BrowsePoll [ host-address ] | BrowsePoll none'
BrowsePoll()
{ if test -n "$BROWSEDCONF"
then CONFIGFILE=$BROWSEDCONF
else CONFIGFILE=$CUPSDCONF
fi
if test -n "$VALUE"
then # All existing active BrowsePoll lines are removed (ignore case).
# Those lines can be removed because YaST supports BrowsePoll lines
# (YaST shows BrowsePoll entries in the "printing via network" dialog):
sed -i -e '/^[[:space:]]*BrowsePoll.*/Id' $CONFIGFILE
if test "none" != "$VALUE"
then # When cups-browsed should poll CUPS <= 1.5 servers,
# there must be a "/version=1.1" suffix to enforce using IPP version 1.1
# because CUPS <= 1.5 servers reject higher IPP version requests with "Bad Request":
if test -n "$BROWSEDCONF"
then # On a CUPS >= 1.6 system "lpstat -h cups_1.5_server -p" results on stderr:
# lpstat: Error - add '/version=1.1' to server name.
if lpstat -h $VALUE -p 2>&1 1>/dev/null | grep -q "add '/version=1.1' to server name"
then VALUE="${VALUE}/version=1.1"
fi
fi
# Try to find a matching existing BrowsePoll or 'Brows' line
# where to append the new BrowsePoll lines
# to have the new BrowsePoll lines at the right place
# but if no such line exists, append below the first empty line
# which is usually the line after the initial comment block
# and if even no empty line exists, append at the end of the file:
APPEND_LINE_NUMBER="$( LastMatchingLineNumberOrFirstEmptyLineNumber $CONFIGFILE BrowsePoll Brows )"
AppendKeyValueLinesAtLineNumberOrAtEndOfFile $CONFIGFILE $KEY $VALUE $APPEND_LINE_NUMBER
fi
# Check cups-browsed status and enable and (re)start it (needed when it is not 'BrowsePoll none')
# on the other hand only 'BrowsePoll none' does not mean cups-browsed should be stopped and disabled
# but 'BrowsePoll none' means cups-browsed should be restarted but only if it is actually running.
if test -n "$BROWSEDCONF"
then if test -z "$( type -ap systemctl )"
then echo "Aborting because 'systemctl' not executable (no 'systemd' RPM installed?)" 1>&2
exit 5
fi
if test "none" = "$VALUE"
then if systemctl --quiet is-active $BROWSEDUNITFILE
then if ! systemctl --quiet restart $BROWSEDUNITFILE
then "Failed to restart $BROWSEDUNITFILE." 1>&2
exit 5
fi
fi
else if ! { systemctl --quiet enable $BROWSEDUNITFILE && systemctl --quiet restart $BROWSEDUNITFILE ; }
then echo "Failed to enable and/or (re)start $BROWSEDUNITFILE." 1>&2
exit 5
fi
fi
fi
fi
# Report the resulting setting in any case:
# The 'tr ... [:blank:]' makes sure that all active BrowsePoll entries
# are found if there is more than one which is allowed.
# Remove leading spaces (to cut the right part).
# Remove trailing spaces (needed for the test below).
RESULT="$( grep -i "^[[:space:]]*$KEY[[:space:]]" $CONFIGFILE | tr -s '[:blank:]' ' ' | sed -e 's/^ *//' | cut -s -d ' ' -f2 | tr -s '\n' ' ' | sed -e 's/ *$//' )"
# A possible "/version=1.1" suffix is removed to get only the plain server name
# because in YaST only the plain server name should be used and visible
# i.e. the special "/version=1.1" suffix for BrowsePoll for should be kept hidden
# from the user so that the entries in the "Print via Network" dialog in YaST
# look consistent because there is also special "/version=1.1" suffix for "client-only"
# where the "/version=1.1" suffix must be removed, see /usr/lib/YaST2/bin/cups_client_only
# so that not any "/version=1.1" suffix should appear in the "Print via Network" dialog:
RESULT="${RESULT%%/version=1.1}"
VALUE="${VALUE%%/version=1.1}"
echo -n "$RESULT"
# For a nicer output on a terminal where stdout and stderr is mixed up,
# output a '\n' on stderr to get subsequent stuff (e.g. the shell prompt
# or an error message because of a failed test below) on a new line:
echo 1>&2
# Test if the result is the expected one if a value was specified:
if test -n "$VALUE"
then if test "none" = "$VALUE"
then RESULT="$( grep -q -i '^[[:space:]]*BrowsePoll' $CONFIGFILE || echo -n 'none' )"
fi
if test "$RESULT" != "$VALUE"
then echo "Failed to set '$KEY $VALUE' in $CONFIGFILE." 1>&2
exit 5
fi
fi
}
# Function to deal with 'Listen [ all | network-address ] | Listen localhost'
Listen()
{ if test -n "$VALUE"
then # Determine if it listens on the domain socket:
LISTEN_DOMAIN_SOCKET_LINE_CONTENT="$( grep -i '^[[:space:]]*Listen.*/cups.sock' $CUPSDCONF | head -n 1 )"
# All existing active Port lines are deactivated (ignore case).
# Those lines are not removed because YaST does not support Port lines
# so that a remove would silently delete Port information:
sed -i -e 's/^[[:space:]]*\(Port.*\)$/#\1/i' $CUPSDCONF
# Determine the first active 'Listen' line (ignore case):
FIRST_LISTEN_LINE_NUMBER="$( sed -n -e '/^[[:space:]]*Listen/I=' $CUPSDCONF | head -n 1 )"
# All existing active Listen lines are removed (ignore case).
# Those lines can be removed because YaST supports Listen lines
# (YaST shows the Listen entries in the "share printers" dialog):
sed -i -e '/^[[:space:]]*Listen.*/Id' $CUPSDCONF
# Insert the mandatory 'Listen localhost' line (see http://www.cups.org/str.php?L2834
# "What is *not* supported is a configuration where only a domain socket is enabled")
# to have the new Listen line where the first active Listen line was
# but if no 'Listen' line exists, append below the first empty line
# which is usually the line after the initial comment block
# and if even no empty line exists, append at the end of the file:
if test -n "$FIRST_LISTEN_LINE_NUMBER"
then sed -i -e "${FIRST_LISTEN_LINE_NUMBER}iListen localhost:631" $CUPSDCONF
else FIRST_EMPTY_LINE_NUMBER="$( sed -n -e '/^[[:space:]]*$/=' $CUPSDCONF | head -n 1 )"
if test -n "$FIRST_EMPTY_LINE_NUMBER"
then sed -i -e "${FIRST_EMPTY_LINE_NUMBER}iListen localhost:631\n" $CUPSDCONF
else echo -en "\nListen localhost:631\n\n" >>$CUPSDCONF
fi
fi
# Append a Listen line for the domain socket (if such a line was there):
if test -n "$LISTEN_DOMAIN_SOCKET_LINE_CONTENT"
then sed -i -e "/^Listen localhost/a$LISTEN_DOMAIN_SOCKET_LINE_CONTENT" $CUPSDCONF
fi
# Insert Listen lines before the 'Listen localhost' line
# to have the new Listen lines at the matching place
# and in the ordering of the values (needed for the test below):
for V in $VALUE
do if test "all" = "$V"
then V="*"
fi
if ! test "localhost" = "$V"
then test -n "$V" && sed -i -e "/^Listen localhost/i$KEY $V:631" $CUPSDCONF
fi
done
fi
# Report the resulting setting in any case:
# The 'tr ... [:blank:]' makes sure that all active Listen entries
# are found if there is more than one which is allowed.
# Remove leading spaces (to cut the right part).
# Remove trailing spaces (needed for the test below).
# Remove '/var/run/cups/cups.sock' because it is only
# an optional default (i.e. not really of interest).
# Unify a localhost (ignore case) or 127.0.0.1 value to "localhost".
# Replace the actual value '*' by the more meaningful word "all".
RESULT="$( grep -i "^[[:space:]]*$KEY[[:space:]]" $CUPSDCONF | sed -e 's/localhost/localhost/i' -e 's/127\.0*0\.0*0\.0*1/localhost/' -e 's/[^ ]*\/cups\.sock//' -e 's/:631//' -e 's/\*/all/' | tr -s '[:blank:]' ' ' | sed -e 's/^ *//' | cut -s -d ' ' -f2 | tr -s '\n' ' ' | sed -e 's/ *$//' )"
echo -n "$RESULT"
# For a nicer output on a terminal where stdout and stderr is mixed up,
# output a '\n' on stderr to get subsequent stuff (e.g. the shell prompt
# or an error message because of a failed test below) on a new line:
echo 1>&2
# Test if the result is the expected one if a value was specified:
if test -n "$VALUE"
then if ! test "localhost" = "$VALUE"
then SPECIFIC_RESULT="$( echo "$RESULT" | sed -e 's/localhost.*//' -e 's/ *$//' )"
else SPECIFIC_RESULT="$RESULT"
fi
if test "$SPECIFIC_RESULT" != "$VALUE"
then echo "Failed to set '$KEY $VALUE' in $CUPSDCONF." 1>&2
exit 5
fi
fi
}
# Function to deal with 'Allow [ all | @LOCAL | @IF(name) | host-address | network-address/netmask ] | Allow none'
Allow()
{ if test -n "$VALUE"
then # Remove '127.0.0.2' from the value because it is set by default in any case
# and it is therefore also removed from the output of the resulting setting.
VALUE="$( echo $VALUE | sed -e 's/127\.00*\.00*\.0*2//g' | tr -s '[:space:]' ' ' | sed -e 's/^ *//' -e 's/ *$//' )"
# Determine where the (first) root location starts (ignore case and ignore spaces):
ROOT_LOCATION_LINE_NUMBER="$( sed -n -e '/[[:space:]]*<[[:space:]]*Location[[:space:]]*\/[[:space:]]*>/I=' $CUPSDCONF | head -n 1 )"
# Remove all root locations (ignore case and ignore spaces).
# (If there is more than one root location it is a broken config file).
# This deletion would remove Deny information and whatever Limit sub-sections
# but on the other hand it makes sure to have a clean root location:
sed -i -e '/[[:space:]]*<[[:space:]]*Location[[:space:]]*\/[[:space:]]*>/I,/[[:space:]]*<[[:space:]]*\/[[:space:]]*Location[[:space:]]*>/Id' $CUPSDCONF
# Insert a new default root location (what we have in our cups RPM by default).
# Set 'Order allow,deny' in the root location to deny packets by default
# and then allow them from certain sources via Allow entries
# and finally deny from certain sources via Deny entries.
# If no root location was there, append it below the first empty line
# which is usually the line after the initial comment block
# and if even no empty line exists, append at the end of the file:
if test -n "$ROOT_LOCATION_LINE_NUMBER"
then sed -i -e "${ROOT_LOCATION_LINE_NUMBER}i<Location />\nOrder allow,deny\nAllow 127.0.0.2\n</Location>" $CUPSDCONF
else FIRST_EMPTY_LINE_NUMBER="$( sed -n -e '/^[[:space:]]*$/=' $CUPSDCONF | head -n 1 )"
if test -n "$FIRST_EMPTY_LINE_NUMBER"
then sed -i -e "${FIRST_EMPTY_LINE_NUMBER}a<Location />\nOrder allow,deny\nAllow 127.0.0.2\n</Location>\n" $CUPSDCONF
else echo -en "\n<Location />\nOrder allow,deny\nAllow 127.0.0.2\n</Location>\n\n" >>$CUPSDCONF
fi
fi
# Determine (again) where the new root location starts (exact match):
ROOT_LOCATION_LINE_NUMBER="$( sed -n -e '/<Location \/>/=' $CUPSDCONF | head -n 1 )"
# Append Allow lines after the '<Location />' line
# to have the new Allow lines at the matching place
# but invert the ordering of the values to get the lines
# in the original ordering of the values (needed for the test below):
if ! test "none" = "$VALUE"
then for V in $( echo "$VALUE" | tac -s ' ' )
do test -n "$V" && sed -i -e "${ROOT_LOCATION_LINE_NUMBER}a$KEY $V" $CUPSDCONF
done
else # The 'Order allow,deny' line denies packets by default
# to be on the safe side have en explicite 'Deny all' line
# but do not have an additional 'Allow none' line too
# because an explicite 'Allow none' line results in YaST
# a "none" entry for the experts settings in the Shareing dialog
# and such a "none" expert setting overrules any other setting
# so that all user would have to remove this expert setting
# manually to allow any kind of remote access.
sed -i -e "${ROOT_LOCATION_LINE_NUMBER}aDeny all" $CUPSDCONF
fi
fi
# Report the resulting setting in any case:
# The 'tr ... [:blank:]' makes sure that all active Allow entries
# in the root location are found if there is more than one which is allowed.
# Remove leading spaces (to cut the right part).
# Remove trailing spaces (needed for the test below).
RESULT="$( sed -n -e '/[[:space:]]*<[[:space:]]*Location[[:space:]]*\/[[:space:]]*>/,/[[:space:]]*<[[:space:]]*\/[[:space:]]*Location[[:space:]]*>/p' $CUPSDCONF | grep -i "^[[:space:]]*$KEY[[:space:]]" | egrep -v '127.0.0.2' | sed -e 's/from//I' | tr -s '[:blank:]' ' ' | sed -e 's/^ *//' | cut -s -d ' ' -f2 | tr -s '\n' ' ' | sed -e 's/ *$//' )"
echo -n "$RESULT"
# For a nicer output on a terminal where stdout and stderr is mixed up,
# output a '\n' on stderr to get subsequent stuff (e.g. the shell prompt
# or an error message because of a failed test below) on a new line:
echo 1>&2
# Test if the result is the expected one if a value was specified:
if test -n "$VALUE"
then if test "none" = "$VALUE"
then EXPECTED_RESULT=""
else EXPECTED_RESULT="$VALUE"
fi
if test "$RESULT" != "$EXPECTED_RESULT"
then echo "Failed to set '$KEY $VALUE' in $CUPSDCONF." 1>&2
exit 5
fi
fi
}
# Function to deal with 'BrowseAddress [ @LOCAL | @IF(name) | host-address | broadcast-address ] | BrowseAddress none'
BrowseAddress()
{ if test -n "$VALUE"
then if test -n "$BROWSEDCONF"
then # Only BrowseAddress @LOCAL or BrowseAddress none is supported for cups-browsed.
# In particular multiple values in $VALUE are not supported for cups-browsed:
if test "@LOCAL" != "$VALUE" -a "none" != "$VALUE"
then echo "Either BrowseAddress @LOCAL or BrowseAddress none is supported for cups-browsed." 1>&2
exit 6
fi
# All existing active BrowseLocalProtocols lines are removed (ignore case).
# Those lines can be removed because YaST supports BrowseLocalProtocols lines
# YaST shows the meaning of BrowseLocalProtocols entries in the "printing via network" dialog.
# The meaning of BrowseLocalProtocols entries in /etc/cups/cups-browsed.conf is:
# BrowseLocalProtocols CUPS <=> BrowseAddress @LOCAL
# BrowseLocalProtocols none <=> BrowseAddress none
# and anything else falls back to BrowseAddress none
sed -i -e '/^[[:space:]]*BrowseLocalProtocols.*/Id' $BROWSEDCONF
# For 'BrowseAddress none' do not have any active BrowseLocalProtocols line (all were deleted above) because
# no active BrowseLocalProtocols line means to not broadcast shared local printers (see 'man cups-browsed.conf'):
if test "@LOCAL" = "$VALUE"
then # Try to find a matching existing BrowseLocalProtocols or 'Brows' line
# where to append the new BrowseLocalProtocols CUPS line
# to have the new BrowseLocalProtocols line at the right place
# but if no such line exists, append below the first empty line
# which is usually the line after the initial comment block
# and if even no empty line exists, append at the end of the file:
APPEND_LINE_NUMBER="$( LastMatchingLineNumberOrFirstEmptyLineNumber $BROWSEDCONF BrowseLocalProtocols Brows )"
AppendKeyValueLinesAtLineNumberOrAtEndOfFile $BROWSEDCONF BrowseLocalProtocols CUPS $APPEND_LINE_NUMBER
fi
# Check cups-browsed status and enable and (re)start it (needed when it is not 'BrowseAddress none')
# on the other hand only 'BrowseAddress none' does not mean cups-browsed should be stopped and disabled
# but 'BrowseAddress none' means cups-browsed should be restarted but only if it is actually running.
if test -z "$( type -ap systemctl )"
then echo "Aborting because 'systemctl' not executable (no 'systemd' RPM installed?)" 1>&2
exit 5
fi
if test "none" = "$VALUE"
then if systemctl --quiet is-active $BROWSEDUNITFILE
then if ! systemctl --quiet restart $BROWSEDUNITFILE
then "Failed to restart $BROWSEDUNITFILE." 1>&2
exit 5
fi
fi
else if ! { systemctl --quiet enable $BROWSEDUNITFILE && systemctl --quiet restart $BROWSEDUNITFILE ; }
then echo "Failed to enable and/or (re)start $BROWSEDUNITFILE." 1>&2
exit 5
fi
fi
else # All existing active BrowseAddress lines are removed (ignore case).
# Those lines can be removed because YaST supports BrowseAddress lines
# (YaST shows BrowseAddress entries in the "share printers" dialog):
sed -i -e '/^[[:space:]]*BrowseAddress.*/Id' $CUPSDCONF
if ! test "none" = "$VALUE"
then # Append the new BrowseAddress lines below the last active 'Brows' line (ignore case)
# to have the new BrowseAddress lines at the matching place
# but if no 'Brows' line exists, append below the first empty line
# which is usually the line after the initial comment block
# and if even no empty line exists, append at the end of the file.
# Invert the ordering of the values to get the lines
# in the original ordering of the values (needed for the test below):
LAST_BROWSE_LINE_NUMBER="$( sed -n -e '/^[^#]*Brows/I=' $CUPSDCONF | tail -n 1 )"
FIRST_EMPTY_LINE_NUMBER="$( sed -n -e '/^[[:space:]]*$/=' $CUPSDCONF | head -n 1 )"
APPEND_LINE_NUMBER=""
if test -n "$LAST_BROWSE_LINE_NUMBER"
then APPEND_LINE_NUMBER="$LAST_BROWSE_LINE_NUMBER"
else if test -n "$FIRST_EMPTY_LINE_NUMBER"
then APPEND_LINE_NUMBER="$FIRST_EMPTY_LINE_NUMBER"
fi
fi
for V in $( echo "$VALUE" | tac -s ' ' )
do if test -n "$APPEND_LINE_NUMBER"
then test -n "$V" && sed -i -e "${APPEND_LINE_NUMBER}a$KEY $V" $CUPSDCONF
else test -n "$V" && echo -en "\n$KEY $V\n" >>$CUPSDCONF
fi
done
fi
fi
fi
# Report the resulting setting in any case:
if test -n "$BROWSEDCONF"
then # The 'tr ... [:blank:]' makes sure that all active BrowseLocalProtocols entries
# are found if there is more than one which is a broken config.
# Remove leading spaces (to cut the right part).
# Remove trailing spaces (needed for the test below).
RESULT="$( grep -i "^[[:space:]]*BrowseLocalProtocols[[:space:]]" $BROWSEDCONF | tr -s '[:blank:]' ' ' | sed -e 's/^ *//' | cut -s -d ' ' -f2 | tr -s '\n' ' ' | sed -e 's/ *$//' )"
case "$RESULT" in
[Cc][Uu][Pp][Ss] ) RESULT="@LOCAL" ;;
* ) RESULT="none" ;;
esac
else # The 'tr ... [:blank:]' makes sure that all active BrowseAddress entries
# are found if there is more than one which is allowed.
# Remove leading spaces (to cut the right part).
# Remove trailing spaces (needed for the test below).
RESULT="$( grep -i "^[[:space:]]*$KEY[[:space:]]" $CUPSDCONF | tr -s '[:blank:]' ' ' | sed -e 's/^ *//' | cut -s -d ' ' -f2 | tr -s '\n' ' ' | sed -e 's/ *$//' )"
fi
echo -n "$RESULT"
# For a nicer output on a terminal where stdout and stderr is mixed up,
# output a '\n' on stderr to get subsequent stuff (e.g. the shell prompt
# or an error message because of a failed test below) on a new line:
echo 1>&2
# Test if the result is the expected one if a value was specified:
if test -n "$VALUE"
then if test "none" = "$VALUE"
then if test -n "$BROWSEDCONF"
then RESULT="$( grep -q -i '^[[:space:]]*BrowseLocalProtocols' $BROWSEDCONF || echo -n 'none' )"
else RESULT="$( grep -q -i '^[[:space:]]*BrowseAddress' $CUPSDCONF || echo -n 'none' )"
fi
fi
if test "$RESULT" != "$VALUE"
then echo "Failed to set '$KEY $VALUE' in $CUPSDCONF." 1>&2
exit 5
fi
fi
}
# Function to report the existing 'Policies'
Policies()
{ # The 'tr ... [:blank:]' makes sure that all active '<Policy policy-name>' entries
# are found if there is more than one which is allowed.
# Remove leading spaces and trailing spaces for a nice output.
RESULT="$( grep -i "^[[:space:]]*<[[:space:]]*Policy[[:space:]]" $CUPSDCONF | tr -d '<>' | tr -s '[:blank:]' ' ' | sed -e 's/^ *//' | cut -s -d ' ' -f2 | tr -s '\n' ' ' | sed -e 's/ *$//' )"
echo -n "$RESULT"
# For a nicer output on a terminal where stdout and stderr is mixed up,
# output a '\n' on stderr to get subsequent stuff (e.g. the shell prompt
# or an error message because of a failed test below) on a new line:
echo 1>&2
}
# Function to deal with 'DefaultPolicy [ policy-name ] | DefaultPolicy default'
DefaultPolicy()
{ if test -n "$VALUE"
then # Try to substitute an existing active DefaultPolicy line (ignore case).
# (If there is more than one active DefaultPolicy line it is a broken config file):
sed -i -e "s/^[[:space:]]*$KEY.*/$KEY $VALUE/i" $CUPSDCONF
# There may exist no DefaultPolicy line or the above substitute may have failed
# (therefore it tests not only for "^$KEY" but for "^$KEY $VALUE$"):
if ! grep -q "^$KEY $VALUE$" $CUPSDCONF
then # Append a DefaultPolicy line below the last active 'Policy' line
# which is usually a '</Policy>' or a 'ErrorPolicy' line (ignore case)
# to have the new DefaultPolicy line at the matching place
# but if no 'Policy' line exists, append below the first empty line
# which is usually the line after the initial comment block
# and if even no empty line exists, append at the end of the file:
LAST_POLICY_LINE_NUMBER="$( sed -n -e '/^[^#]*Policy/I=' $CUPSDCONF | tail -n 1 )"
if test -n "$LAST_POLICY_LINE_NUMBER"
then sed -i -e "${LAST_POLICY_LINE_NUMBER}a$KEY $VALUE" $CUPSDCONF
else FIRST_EMPTY_LINE_NUMBER="$( sed -n -e '/^[[:space:]]*$/=' $CUPSDCONF | head -n 1 )"
if test -n "$FIRST_EMPTY_LINE_NUMBER"
then sed -i -e "${FIRST_EMPTY_LINE_NUMBER}a$KEY $VALUE\n" $CUPSDCONF
else echo -en "\n$KEY $VALUE\n\n" >>$CUPSDCONF
fi
fi
fi
fi
# Report the resulting setting in any case:
# The 'tr ... [:blank:]' makes sure that all active DefaultPolicy entries
# are found if there is more than one which is a broken config.
# Remove leading spaces (to cut the right part).
# Remove trailing spaces (needed for the test below).
RESULT="$( grep -i "^[[:space:]]*$KEY[[:space:]]" $CUPSDCONF | tr -s '[:blank:]' ' ' | sed -e 's/^ *//' | cut -s -d ' ' -f2 | tr -s '\n' ' ' | sed -e 's/ *$//' )"
echo -n "$RESULT"
# For a nicer output on a terminal where stdout and stderr is mixed up,
# output a '\n' on stderr to get subsequent stuff (e.g. the shell prompt
# or an error message because of a failed test below) on a new line:
echo 1>&2
# Test if the result is the expected one if a value was specified:
if test -n "$VALUE" -a "$RESULT" != "$VALUE"
then echo "Failed to set '$KEY $VALUE' in $CUPSDCONF." 1>&2
exit 5
fi
}
# Function to deal with 'ErrorPolicy [ stop-printer | retry-job | abort-job ]'
ErrorPolicy()
{ if test -n "$VALUE"
then # Try to substitute an existing active ErrorPolicy line (ignore case).
# (If there is more than one active ErrorPolicy line it is a broken config file):
sed -i -e "s/^[[:space:]]*$KEY.*/$KEY $VALUE/i" $CUPSDCONF
# There may exist no ErrorPolicy line or the above substitute may have failed
# (therefore it tests not only for "^$KEY" but for "^$KEY $VALUE$"):
if ! grep -q "^$KEY $VALUE$" $CUPSDCONF
then # Append a ErrorPolicy line below the last active 'Policy' line
# which is usually a '</Policy>' or a 'DefaultPolicy' line (ignore case)
# to have the new ErrorPolicy line at the matching place
# but if no 'Policy' line exists, append below the first empty line
# which is usually the line after the initial comment block
# and if even no empty line exists, append at the end of the file:
LAST_POLICY_LINE_NUMBER="$( sed -n -e '/^[^#]*Policy/I=' $CUPSDCONF | tail -n 1 )"
if test -n "$LAST_POLICY_LINE_NUMBER"
then sed -i -e "${LAST_POLICY_LINE_NUMBER}a$KEY $VALUE" $CUPSDCONF
else FIRST_EMPTY_LINE_NUMBER="$( sed -n -e '/^[[:space:]]*$/=' $CUPSDCONF | head -n 1 )"
if test -n "$FIRST_EMPTY_LINE_NUMBER"
then sed -i -e "${FIRST_EMPTY_LINE_NUMBER}a$KEY $VALUE\n" $CUPSDCONF
else echo -en "\n$KEY $VALUE\n\n" >>$CUPSDCONF
fi
fi
fi
fi
# Report the resulting setting in any case:
# The 'tr ... [:blank:]' makes sure that all active ErrorPolicy entries
# are found if there is more than one which is a broken config.
# Remove leading spaces (to cut the right part).
# Remove trailing spaces (needed for the test below).
RESULT="$( grep -i "^[[:space:]]*$KEY[[:space:]]" $CUPSDCONF | tr -s '[:blank:]' ' ' | sed -e 's/^ *//' | cut -s -d ' ' -f2 | tr -s '\n' ' ' | sed -e 's/ *$//' )"
echo -n "$RESULT"
# For a nicer output on a terminal where stdout and stderr is mixed up,
# output a '\n' on stderr to get subsequent stuff (e.g. the shell prompt
# or an error message because of a failed test below) on a new line:
echo 1>&2
# Test if the result is the expected one if a value was specified:
if test -n "$VALUE" -a "$RESULT" != "$VALUE"
then echo "Failed to set '$KEY $VALUE' in $CUPSDCONF." 1>&2
exit 5
fi
}
# Function to deal with 'DirtyCleanInterval [ seconds ]'
DirtyCleanInterval()
{ if test -n "$VALUE"
then # Try to substitute an existing active DirtyCleanInterval line (ignore case).
# (If there is more than one active DirtyCleanInterval line it is a broken config file):
sed -i -e "s/^[[:space:]]*$KEY.*/$KEY $VALUE/i" $CUPSDCONF
# There may exist no DirtyCleanInterval line or the above substitute may have failed
# (therefore it tests not only for "^$KEY" but for "^$KEY $VALUE$"):
if ! grep -q "^$KEY $VALUE$" $CUPSDCONF
then # Append a DirtyCleanInterval line below the first empty line
# which is usually the line after the initial comment block
# but if no empty line exists, append at the end of the file:
FIRST_EMPTY_LINE_NUMBER="$( sed -n -e '/^[[:space:]]*$/=' $CUPSDCONF | head -n 1 )"
if test -n "$FIRST_EMPTY_LINE_NUMBER"
then sed -i -e "${FIRST_EMPTY_LINE_NUMBER}a$KEY $VALUE\n" $CUPSDCONF
else echo -en "\n$KEY $VALUE\n\n" >>$CUPSDCONF
fi
fi
fi
# Report the resulting setting in any case:
# The 'tr ... [:blank:]' makes sure that all active DirtyCleanInterval entries
# are found if there is more than one which is a broken config.
# Remove leading spaces (to cut the right part).
# Remove trailing spaces (needed for the test below).
RESULT="$( grep -i "^[[:space:]]*$KEY[[:space:]]" $CUPSDCONF | tr -s '[:blank:]' ' ' | sed -e 's/^ *//' | cut -s -d ' ' -f2 | tr -s '\n' ' ' | sed -e 's/ *$//' )"
echo -n "$RESULT"
# For a nicer output on a terminal where stdout and stderr is mixed up,
# output a '\n' on stderr to get subsequent stuff (e.g. the shell prompt
# or an error message because of a failed test below) on a new line:
echo 1>&2
# Test if the result is the expected one if a value was specified:
if test -n "$VALUE" -a "$RESULT" != "$VALUE"
then echo "Failed to set '$KEY $VALUE' in $CUPSDCONF." 1>&2
exit 5
fi
}
case "$KEY" in
Browsing) Browsing;;
BrowseAllow) BrowseAllow;;
BrowsePoll) BrowsePoll;;
Listen) Listen;;
Allow) Allow;;
BrowseAddress) BrowseAddress;;
Policies) Policies;;
DefaultPolicy) DefaultPolicy;;
ErrorPolicy) ErrorPolicy;;
DirtyCleanInterval) DirtyCleanInterval;;
*) echo "Unsupported keyword '$KEY'." 1>&2
exit 4 ;;
esac
exit 0