#!/bin/sh
# ctdb event script for Samba
-. $CTDB_BASE/functions
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
detect_init_style
suse)
CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-smb}
CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-nmb}
- CTDB_SERVICE_WINBIND=${CTDB_SERVICE_WINBIND:-winbind}
;;
debian)
CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-samba}
CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-""}
- CTDB_SERVICE_WINBIND=${CTDB_SERVICE_WINBIND:-winbind}
;;
*)
- # should not happen, but for now use redhat style as default:
+ # Use redhat style as default:
CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-smb}
CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-""}
- CTDB_SERVICE_WINBIND=${CTDB_SERVICE_WINBIND:-winbind}
;;
esac
+# service_name is used by various functions
+# shellcheck disable=SC2034
service_name="samba"
loadconfig
-ctdb_setup_service_state_dir
+service_state_dir=$(ctdb_setup_service_state_dir) || exit $?
service_start ()
{
- # If set then we force-start the relevant service.
- _service_name="$1"
-
- # make sure samba is not already started
- if [ "$_service_name" = "samba" ] || \
- is_ctdb_managed_service "samba" ; then
- service "$CTDB_SERVICE_SMB" stop > /dev/null 2>&1
- if [ -n "$CTDB_SERVICE_NMB" ] ; then
- service "$CTDB_SERVICE_NMB" stop > /dev/null 2>&1
- fi
- killall -0 -q smbd && {
- sleep 1
- # make absolutely sure samba is dead
- killall -q -9 smbd
- }
-
- killall -0 -q nmbd && {
- sleep 1
- # make absolutely sure samba is dead
- killall -q -9 nmbd
- }
- fi
+ # make sure samba is not already started
+ service "$CTDB_SERVICE_SMB" stop > /dev/null 2>&1
+ if [ -n "$CTDB_SERVICE_NMB" ] ; then
+ service "$CTDB_SERVICE_NMB" stop > /dev/null 2>&1
+ fi
+ killall -0 -q smbd && {
+ sleep 1
+ # make absolutely sure samba is dead
+ killall -q -9 smbd
+ }
+ killall -0 -q nmbd && {
+ sleep 1
+ # make absolutely sure samba is dead
+ killall -q -9 nmbd
+ }
- # make sure winbind is not already started
- if [ "$_service_name" = "winbind" ] || \
- check_ctdb_manages_winbind ; then
- service "$CTDB_SERVICE_WINBIND" stop > /dev/null 2>&1
- killall -0 -q winbindd && {
- sleep 1
- # make absolutely sure winbindd is dead
- killall -q -9 winbindd
- }
+ # start Samba service. Start it reniced, as under very heavy load
+ # the number of smbd processes will mean that it leaves few cycles
+ # for anything else
+ net serverid wipe
- fi
-
- # start the winbind service
- if [ "$_service_name" = "winbind" ] || \
- check_ctdb_manages_winbind ; then
- service "$CTDB_SERVICE_WINBIND" start || {
- echo failed to start winbind
- exit 1
- }
- fi
+ if [ -n "$CTDB_SERVICE_NMB" ] ; then
+ nice_service "$CTDB_SERVICE_NMB" start || die "Failed to start nmbd"
+ fi
- # start Samba service. Start it reniced, as under very heavy load
- # the number of smbd processes will mean that it leaves few cycles for
- # anything else
- if [ "$_service_name" = "samba" ] || \
- is_ctdb_managed_service "samba" ; then
- net serverid wipe
-
- if [ -n "$CTDB_SERVICE_NMB" ] ; then
- nice_service "$CTDB_SERVICE_NMB" start || {
- echo failed to start nmbd
- exit 1
- }
- fi
- nice_service "$CTDB_SERVICE_SMB" start || {
- echo failed to start samba
- exit 1
- }
- fi
+ nice_service "$CTDB_SERVICE_SMB" start || die "Failed to start samba"
}
service_stop ()
{
- # If set then we force-stop the relevant service.
- _service_name="$1"
-
- # shutdown Samba when ctdb goes down
- if [ "$_service_name" = "samba" ] || \
- is_ctdb_managed_service "samba" ; then
- service "$CTDB_SERVICE_SMB" stop
- if [ -n "$CTDB_SERVICE_NMB" ] ; then
- service "$CTDB_SERVICE_NMB" stop
- fi
- fi
-
- # stop the winbind service
- if [ "$_service_name" = "winbind" ] || \
- check_ctdb_manages_winbind ; then
- service "$CTDB_SERVICE_WINBIND" stop
- fi
-}
-
-service_reconfigure ()
-{
- # Samba automatically reloads config - no restart needed.
- :
+ service "$CTDB_SERVICE_SMB" stop
+ program_stack_traces "smbd" 5
+ if [ -n "$CTDB_SERVICE_NMB" ] ; then
+ service "$CTDB_SERVICE_NMB" stop
+ fi
}
-# set default samba cleanup period - in minutes
-[ -z "$SAMBA_CLEANUP_PERIOD" ] && {
- SAMBA_CLEANUP_PERIOD=10
-}
+######################################################################
+# Show the testparm output using a cached smb.conf to avoid delays due
+# to registry access.
-# we keep a cached copy of smb.conf here
smbconf_cache="$service_state_dir/smb.conf.cache"
-
-#############################################
-# update the smb.conf cache in the foreground
-testparm_foreground_update() {
- testparm -s 2> /dev/null | egrep -v 'registry.shares.=|include.=' > "$smbconf_cache"
+testparm_foreground_update ()
+{
+ _timeout="$1"
+
+ # No need to remove these temporary files, since there are only 2
+ # of them.
+ _out="${smbconf_cache}.out"
+ _err="${smbconf_cache}.err"
+
+ timeout "$_timeout" testparm -v -s >"$_out" 2>"$_err"
+ case $? in
+ 0) : ;;
+ 124)
+ if [ -f "$smbconf_cache" ] ; then
+ echo "WARNING: smb.conf cache update timed out - using old cache file"
+ return 1
+ else
+ echo "ERROR: smb.conf cache create failed - testparm command timed out"
+ exit 1
+ fi
+ ;;
+ *)
+ if [ -f "$smbconf_cache" ] ; then
+ echo "WARNING: smb.conf cache update failed - using old cache file"
+ cat "$_err"
+ return 1
+ else
+ echo "ERROR: smb.conf cache create failed - testparm failed with:"
+ cat "$_err"
+ exit 1
+ fi
+ esac
+
+ # Only using $$ here to avoid a collision. This is written into
+ # CTDB's own state directory so there is no real need for a secure
+ # temporary file.
+ _tmpfile="${smbconf_cache}.$$"
+ # Patterns to exclude...
+ _pat='^[[:space:]]+(registry[[:space:]]+shares|include|copy|winbind[[:space:]]+separator)[[:space:]]+='
+ grep -Ev "$_pat" <"$_out" >"$_tmpfile"
+ mv "$_tmpfile" "$smbconf_cache" # atomic
+
+ return 0
}
-#############################################
-# update the smb.conf cache in the background
-testparm_background_update() {
- # if the cache doesn't exist, then update in the foreground
- [ -f $smbconf_cache ] || {
- testparm_foreground_update
- }
- # otherwise do a background update
- (
- tmpfile="${smbconf_cache}.$$"
- testparm -s > $tmpfile 2> /dev/null &
- # remember the pid of the teamparm process
- pid="$!"
- # give it 10 seconds to run
- timeleft=10
- while [ $timeleft -gt 0 ]; do
- timeleft=$(($timeleft - 1))
- # see if the process still exists
- kill -0 $pid > /dev/null 2>&1 || {
- # it doesn't exist, grab its exit status
- wait $pid
- [ $? = 0 ] || {
- echo "50.samba: smb.conf background update exited with status $?"
- rm -f "${tmpfile}"
- exit 1
- }
- # put the new smb.conf contents in the cache (atomic rename)
- # make sure we remove references to the registry while doing
- # this to ensure that running testparm on the cache does
- # not use the registry
- egrep -v 'registry.shares.=|include.=' < "$tmpfile" > "${tmpfile}.2"
- rm -f "$tmpfile"
- mv -f "${tmpfile}.2" "$smbconf_cache" || {
- echo "50.samba: failed to update background cache"
- rm -f "${tmpfile}.2"
- exit 1
- }
- exit 0
- }
- # keep waiting for testparm to finish
- sleep 1
- done
- # it took more than 10 seconds - kill it off
- rm -f "${tmpfile}"
- kill -9 "$pid" > /dev/null 2>&1
- echo "50.samba: timed out updating smbconf cache in background"
- exit 1
- ) &
-}
+testparm_background_update ()
+{
+ _timeout="$1"
-##################################################
-# show the testparm output using a cached smb.conf
-# to avoid registry access
-testparm_cat() {
- [ -f $smbconf_cache ] || {
- testparm_foreground_update
- }
- testparm -s "$smbconf_cache" "$@" 2>/dev/null
+ testparm_foreground_update "$_timeout" >/dev/null 2>&1 </dev/null &
}
-# function to see if ctdb manages winbind - this overrides with extra
-# logic if $CTDB_MANAGES_WINBIND is not set or null.
-check_ctdb_manages_winbind() {
- if is_ctdb_managed_service "winbind" ; then
- return 0
- elif [ -n "$CTDB_MANAGES_WINBIND" ] ; then
- # If this variable is set we want to respect it. We return
- # false here because we know it is not set to "yes" - if it
- # were then the 1st "if" above would have succeeded.
- return 1
- else
- _secmode=`testparm_cat --parameter-name=security`
- case "$_secmode" in
- ADS|DOMAIN)
- return 0
- ;;
- *)
- return 1
- ;;
- esac
- fi
+testparm_cat ()
+{
+ testparm -s "$smbconf_cache" "$@" 2>/dev/null
}
list_samba_shares ()
sed -e 's/"//g'
}
-
-###########################
-# periodic cleanup function
-periodic_cleanup() {
- # running smbstatus scrubs any dead entries from the connections
- # and sessionid database
- # echo "Running periodic cleanup of samba databases"
- smbstatus -np > /dev/null 2>&1 &
+list_samba_ports ()
+{
+ testparm_cat --parameter-name="smb ports" |
+ sed -e 's@,@ @g'
}
###########################
ctdb_start_stop_service
-ctdb_start_stop_service "winbind"
-is_ctdb_managed_service || is_ctdb_managed_service "winbind" || exit 0
+is_ctdb_managed_service || exit 0
###########################
-case "$1" in
- startup)
+case "$1" in
+startup)
ctdb_service_start
;;
-
- shutdown)
+
+shutdown)
ctdb_service_stop
;;
- monitor)
- # Create a dummy file to track when we need to do periodic cleanup
- # of samba databases
- periodic_cleanup_file="$service_state_dir/periodic_cleanup"
- [ -f "$periodic_cleanup_file" ] || {
- touch "$periodic_cleanup_file"
- }
- [ `find "$periodic_cleanup_file" -mmin +$SAMBA_CLEANUP_PERIOD | wc -l` -eq 1 ] && {
- # Cleanup the databases
- periodic_cleanup
- touch "$periodic_cleanup_file"
- }
-
- is_ctdb_managed_service "samba" && {
- [ "$CTDB_SAMBA_SKIP_SHARE_CHECK" = "yes" ] || {
- testparm_background_update
-
- testparm_cat | egrep '^WARNING|^ERROR|^Unknown' && {
- testparm_foreground_update
- testparm_cat | egrep '^WARNING|^ERROR|^Unknown' && {
- echo "ERROR: testparm shows smb.conf is not clean"
- exit 1
- }
- }
-
- list_samba_shares |
- ctdb_check_directories_probe || {
- testparm_foreground_update
- list_samba_shares |
- ctdb_check_directories
- } || exit $?
- }
-
- smb_ports="$CTDB_SAMBA_CHECK_PORTS"
- [ -z "$smb_ports" ] && {
- smb_ports=`testparm_cat --parameter-name="smb ports"`
- }
- ctdb_check_tcp_ports $smb_ports || exit $?
- }
-
- # check winbind is OK
- check_ctdb_manages_winbind && {
- ctdb_check_command "winbind" "wbinfo -p"
- }
- ;;
+monitor)
+ testparm_foreground_update 10
+ ret=$?
- takeip|releaseip)
- iface=$2
- ip=$3
- maskbits=$4
+ smb_ports="$CTDB_SAMBA_CHECK_PORTS"
+ if [ -z "$smb_ports" ] ; then
+ smb_ports=$(list_samba_ports)
+ [ -n "$smb_ports" ] || die "Failed to set smb ports"
+ fi
+ # Intentionally unquoted multi-word value here
+ # shellcheck disable=SC2086
+ ctdb_check_tcp_ports $smb_ports || exit $?
- smbcontrol winbindd ip-dropped $ip >/dev/null 2>/dev/null
- ;;
- *)
- ctdb_standard_event_handler "$@"
+ if [ "$CTDB_SAMBA_SKIP_SHARE_CHECK" != "yes" ] ; then
+ list_samba_shares | ctdb_check_directories || exit $?
+ fi
+
+ if [ $ret -ne 0 ] ; then
+ testparm_background_update 10
+ fi
;;
esac