diff --git a/ctdb/config/ctdb.init b/ctdb/config/ctdb.init index 0e0d379873d..83c1493c130 100755 --- a/ctdb/config/ctdb.init +++ b/ctdb/config/ctdb.init @@ -121,7 +121,8 @@ check_status () # status. Note that this probably won't work if # $CTDB_VALGRIND="yes" but this doesn't need full backward # compatibility because it is a debug option. - if [ -d $(dirname "$pidfile") ] ; then + _d=$(dirname "$pidfile") + if [ -d "$_d" ] ; then _pf_opt="-p $pidfile" else _pf_opt="" diff --git a/ctdb/config/ctdbd_wrapper b/ctdb/config/ctdbd_wrapper index 29b015437a1..4d0dde7e0a9 100755 --- a/ctdb/config/ctdbd_wrapper +++ b/ctdb/config/ctdbd_wrapper @@ -62,13 +62,15 @@ ctdbd_is_running () echo "$_pid" # Return value of kill is used - kill -0 $_pid 2>/dev/null + kill -0 "$_pid" 2>/dev/null else # Missing/empty PID file return 1 fi else if _pid=$(pgrep -f "${ctdbd}\>") ; then + # Use word splitting to squash whitespace + # shellcheck disable=SC2086 echo $_pid | sed -e 's@ @,@g' return 0 else @@ -211,7 +213,7 @@ start() fi if [ -n "$CTDB_MAX_OPEN_FILES" ]; then - ulimit -n $CTDB_MAX_OPEN_FILES + ulimit -n "$CTDB_MAX_OPEN_FILES" fi _d=$(dirname "$pidfile") @@ -244,7 +246,7 @@ start() _pid="" _timeout="${CTDB_STARTUP_TIMEOUT:-10}" _count=0 - while [ $_count -lt $_timeout ] ; do + while [ "$_count" -lt "$_timeout" ] ; do # If we don't have the PID then try to read it. [ -n "$_pid" ] || read _pid 2>/dev/null <"$pidfile" @@ -286,7 +288,7 @@ stop() _timeout=${CTDB_SHUTDOWN_TIMEOUT:-30} _count=0 _terminated=false - while [ $_count -lt $_timeout ] ; do + while [ "$_count" -lt "$_timeout" ] ; do if ! pkill -0 -s "$_session" 2>/dev/null ; then _terminated=true break diff --git a/ctdb/config/debug_locks.sh b/ctdb/config/debug_locks.sh index dee719adcc2..9726247a6ae 100755 --- a/ctdb/config/debug_locks.sh +++ b/ctdb/config/debug_locks.sh @@ -37,7 +37,7 @@ loadconfig ctdb awk '{ if($2 == "->") { print $6, $7, $8, $9, "W" } else { print $5, $6, $7, $8 } }' | while read pid rest ; do pname=$(readlink "/proc/${pid}/exe") - echo $pid $pname $rest + echo "$pid $pname $rest" done | sed -e "$sed_cmd" | grep "\.tdb" ) if [ -n "$out" ]; then @@ -51,6 +51,8 @@ loadconfig ctdb pids=$(echo "$out" | grep -v "W$" | grep "$db" | grep -v ctdbd | awk '{print $1}') all_pids="$all_pids $pids" done + # Use word splitting to squash whitespace + # shellcheck disable=SC2086 pids=$(echo $all_pids | tr " " "\n" | sort -u) # For each process waiting, log stack trace diff --git a/ctdb/config/events.d/05.system b/ctdb/config/events.d/05.system index 780b6b98a53..43b472807ea 100755 --- a/ctdb/config/events.d/05.system +++ b/ctdb/config/events.d/05.system @@ -135,6 +135,8 @@ monitor_memory_usage () fi _meminfo=$(get_proc "meminfo") + # Intentional word splitting here + # shellcheck disable=SC2046 set -- $(echo "$_meminfo" | awk ' $1 == "MemAvailable:" { memavail += $2 } $1 == "MemFree:" { memfree += $2 } diff --git a/ctdb/config/events.d/10.external b/ctdb/config/events.d/10.external index 4b22dc7681b..7be301602f8 100644 --- a/ctdb/config/events.d/10.external +++ b/ctdb/config/events.d/10.external @@ -32,7 +32,8 @@ takeover_assigned_ips () $CTDB -X ip | awk -F'|' '{print $2}' | while read ip ; do - if [ -n "$(ip_maskbits_iface $ip)" ] ; then + _ip_details=$(ip_maskbits_iface "$ip") + if [ -n "$_ip_details" ] ; then echo "Assigning $ip to this node ($pnn)" $CTDB moveip "$ip" "$pnn" fi diff --git a/ctdb/config/events.d/10.interface b/ctdb/config/events.d/10.interface index c6938d12ed9..51abc4453ab 100755 --- a/ctdb/config/events.d/10.interface +++ b/ctdb/config/events.d/10.interface @@ -39,6 +39,8 @@ get_all_interfaces () ctdb_ifaces=$($CTDB -X ifaces | sed -e '1d' -e 's@^|@@' -e 's@|.*@@') # Add $ctdb_interfaces and uniquify + # Use word splitting to squash whitespace + # shellcheck disable=SC2086 all_interfaces=$(echo $all_interfaces $ctdb_ifaces | tr ' ' '\n' | sort -u) } @@ -84,6 +86,8 @@ get_iface_ip_maskbits () ip="$2" _maskbits_in="$3" + # Intentional word splitting here + # shellcheck disable=SC2046 set -- $(ip_maskbits_iface "$ip") if [ -n "$1" ] ; then maskbits="$1" diff --git a/ctdb/config/events.d/11.natgw b/ctdb/config/events.d/11.natgw index bf99ad5a05f..61c93a3fa09 100755 --- a/ctdb/config/events.d/11.natgw +++ b/ctdb/config/events.d/11.natgw @@ -157,6 +157,8 @@ natgw_set_slave () natgw_ensure_master () { + # Intentional word splitting here + # shellcheck disable=SC2046 set -- $("${CTDB_HELPER_BINDIR}/ctdb_natgw" master) natgwmaster="${1:--1}" # Default is -1, for failure above natgwip="$2" diff --git a/ctdb/config/events.d/13.per_ip_routing b/ctdb/config/events.d/13.per_ip_routing index b14c95e5b99..cb08856db8f 100755 --- a/ctdb/config/events.d/13.per_ip_routing +++ b/ctdb/config/events.d/13.per_ip_routing @@ -44,6 +44,8 @@ ipv4_is_valid_addr() _count=0 # Get the shell to break up the address into 1 word per octet + # Intentional word splitting here + # shellcheck disable=SC2086 for _o in $(export IFS="." ; echo $_ip) ; do # The 2>/dev/null stops output from failures where an "octet" # is not numeric. The test will still fail. @@ -76,6 +78,8 @@ ipv4_host_addr_to_net () # Convert the host address to an unsigned long by splitting out # the octets and doing the math. _host_ul=0 + # Intentional word splitting here + # shellcheck disable=SC2086 for _o in $(export IFS="." ; echo $_host) ; do _host_ul=$(( (_host_ul << 8) + _o)) # work around Emacs color bug done @@ -130,7 +134,7 @@ ensure_table_id_for_ip () flock --timeout 30 0 || \ die "ensure_table_id_for_ip: failed to lock file $rt_tables" - _new=$CTDB_PER_IP_ROUTING_TABLE_ID_LOW + _new="$CTDB_PER_IP_ROUTING_TABLE_ID_LOW" while read _t _l ; do # Skip comments case "$_t" in @@ -142,15 +146,15 @@ ensure_table_id_for_ip () fi # Potentially update the new table id to be used. The # redirect stops error spam for a non-numeric value. - if [ $_new -le $_t -a \ - $_t -le $CTDB_PER_IP_ROUTING_TABLE_ID_HIGH ] 2>/dev/null ; then + if [ "$_new" -le "$_t" -a \ + "$_t" -le "$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" ] 2>/dev/null ; then _new=$((_t + 1)) fi done # If the new table id is legal then add it to the file and # print it. - if [ $_new -le $CTDB_PER_IP_ROUTING_TABLE_ID_HIGH ] ; then + if [ "$_new" -le "$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" ] ; then printf "%d\t%s\n" "$_new" "$_label" >>"$rt_tables" return 0 else @@ -215,7 +219,8 @@ ip_has_configuration () { _ip="$1" - [ -n "$(get_config_for_ip $_ip)" ] + _conf=$(get_config_for_ip "$_ip") + [ -n "$_conf" ] } add_routing_for_ip () @@ -241,6 +246,8 @@ add_routing_for_ip () get_config_for_ip "$_ip" | while read _i _dest _gw ; do _r="$_dest ${_gw:+via} $_gw dev $_iface table $_table_id" + # Intentionally unquoted multi-word value here + # shellcheck disable=SC2086 ip route add $_r || \ die "add_routing_for_ip: failed to add route: $_r" done @@ -306,9 +313,9 @@ add_missing_routes () # not. while IFS="|" read _x _ip _x _iface _x ; do [ -n "$_iface" ] || continue - + _table_id="${table_id_prefix}${_ip}" - if [ -z "$(ip route show table $_table_id 2>/dev/null)" -o \ + if [ -z "$(ip route show table "$_table_id" 2>/dev/null)" -o \ "$1" = "force" ] ; then add_routing_for_ip "$_iface" "$_ip" fi diff --git a/ctdb/config/events.d/31.clamd b/ctdb/config/events.d/31.clamd index c7b542e2148..2d301ebfbdb 100755 --- a/ctdb/config/events.d/31.clamd +++ b/ctdb/config/events.d/31.clamd @@ -45,7 +45,7 @@ shutdown) ;; monitor) - ctdb_check_unix_socket ${CTDB_CLAMD_SOCKET} || exit $? + ctdb_check_unix_socket "$CTDB_CLAMD_SOCKET" || exit $? ;; esac diff --git a/ctdb/config/events.d/41.httpd b/ctdb/config/events.d/41.httpd index 9e0f6f65857..4d04b39418a 100755 --- a/ctdb/config/events.d/41.httpd +++ b/ctdb/config/events.d/41.httpd @@ -28,7 +28,7 @@ esac cleanup_httpd_semaphore_leak() { killall -q -0 "$service_name" || for i in $(ipcs -s | awk '$3 == "apache" { print $2 }') ; do - ipcrm -s $i + ipcrm -s "$i" done } diff --git a/ctdb/config/events.d/50.samba b/ctdb/config/events.d/50.samba index b2a5fa46013..245566ef27a 100755 --- a/ctdb/config/events.d/50.samba +++ b/ctdb/config/events.d/50.samba @@ -172,6 +172,8 @@ monitor) 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 $? if [ "$CTDB_SAMBA_SKIP_SHARE_CHECK" != "yes" ] ; then diff --git a/ctdb/config/events.d/60.nfs b/ctdb/config/events.d/60.nfs index 3bb6e65b88d..ff313032432 100755 --- a/ctdb/config/events.d/60.nfs +++ b/ctdb/config/events.d/60.nfs @@ -148,14 +148,14 @@ nfs_check_service () _failcount=$(ctdb_counter_get "$_service_name") _unhealthy=false - if [ $unhealthy_after -gt 0 ] ; then - if [ $_failcount -ge $unhealthy_after ] ; then + if [ "$unhealthy_after" -gt 0 ] ; then + if [ "$_failcount" -ge "$unhealthy_after" ] ; then _unhealthy=true echo "ERROR: $_err" fi fi - if [ $restart_every -gt 0 ] ; then + if [ "$restart_every" -gt 0 ] ; then if [ $((_failcount % restart_every)) -eq 0 ] ; then if ! $_unhealthy ; then echo "WARNING: $_err" @@ -208,6 +208,8 @@ ctdb_check_rpc () _localhost="${CTDB_RPCINFO_LOCALHOST:-127.0.0.1}" esac + # $_version is not quoted because it is optional + # shellcheck disable=SC2086 if ! ctdb_check_rpc_out=$(rpcinfo -T "$_family" "$_localhost" \ "$_progname" $_version 2>&1) ; then ctdb_check_rpc_out="$_progname failed RPC check: diff --git a/ctdb/config/functions b/ctdb/config/functions index 1f0ac8d6926..bbf29e73d23 100755 --- a/ctdb/config/functions +++ b/ctdb/config/functions @@ -123,7 +123,7 @@ die () _rc="${2:-1}" echo "$_msg" >&2 - exit $_rc + exit "$_rc" } # Log given message or stdin to either syslog or a CTDB log file @@ -305,7 +305,7 @@ program_stack_traces () _count=1 for _pid in $(pidof "$_prog") ; do - [ $_count -le $_max ] || break + [ "$_count" -le "$_max" ] || break # Do this first to avoid racing with process exit _stack=$(get_proc "${_pid}/stack" 2>/dev/null) @@ -496,7 +496,7 @@ kill_tcp_connections () _remaining=$(get_tcp_connections_for_ip "$_ip" | wc -l) - if [ $_remaining -eq 0 ] ; then + if [ "$_remaining" -eq 0 ] ; then echo "Killed $_killcount TCP connections to released IP $_ip" return fi @@ -563,6 +563,8 @@ add_ip_to_iface () *) _bcast="brd +" ;; esac + # Intentionally unquoted multi-word value here + # shellcheck disable=SC2086 ip addr add "$_ip/$_maskbits" $_bcast dev "$_iface" || { echo "Failed to add $_ip/$_maskbits on dev $_iface" return 1 @@ -632,6 +634,8 @@ drop_ip () { _addr="${1%/*}" # Remove optional maskbits + # Intentional word splitting here + # shellcheck disable=SC2046 set -- $(ip_maskbits_iface "$_addr") if [ -n "$1" ] ; then _maskbits="$1" @@ -897,6 +901,8 @@ ctdb_replay_monitor_status () # Output looks like this: # |monitor|60.nfs|1|ERROR|1314764004.030861|1314764004.035514|foo bar| # This is the cheapest way of getting fields in the middle. + # Intentional word splitting here + # shellcheck disable=SC2046,2086 set -- $(IFS="|" ; echo $_out) _code="$3" _status="$4" diff --git a/ctdb/config/statd-callout b/ctdb/config/statd-callout index 04e80f4dd4f..a300255968d 100755 --- a/ctdb/config/statd-callout +++ b/ctdb/config/statd-callout @@ -1,7 +1,7 @@ #!/bin/sh # This must run as root as CTDB tool commands need to access CTDB socket -[ $(id -u) -eq 0 ] || exec sudo "$0" "$@" +[ "$(id -u)" -eq 0 ] || exec sudo "$0" "$@" # this script needs to be installed so that statd points to it with the -H # command line argument. The easiest way to do that is to put something like this in @@ -90,6 +90,8 @@ case "$1" in awk -v pnn="$pnn" 'pnn == $2 { \ ip = $1; gsub(/\./, "\\.", ip); \ printf "/statd-state@%s@/p\n", ip }') + # Intentional multi-word expansion for multiple files + # shellcheck disable=SC2086 if cat $files | sed -n "$sed_expr" | $CTDB ptrans "ctdb.tdb" ; then rm $files fi diff --git a/ctdb/tools/ctdb_diagnostics b/ctdb/tools/ctdb_diagnostics index a8c8c4281d6..6b33c7ce537 100755 --- a/ctdb/tools/ctdb_diagnostics +++ b/ctdb/tools/ctdb_diagnostics @@ -57,7 +57,7 @@ esac # them to $bad_nodes. _nodes="" for _i in $nodes ; do - if onnode $_i true >/dev/null 2>&1 ; then + if onnode "$_i" true >/dev/null 2>&1 ; then _nodes="${_nodes}${_nodes:+ }${_i}" else bad_nodes="${bad_nodes}${bad_nodes:+,}${_i}" @@ -65,7 +65,7 @@ for _i in $nodes ; do done nodes="$_nodes" -nodes_comma=$(echo $nodes | sed -e 's@[[:space:]]@,@g') +nodes_comma=$(echo "$nodes" | sed -e 's@[[:space:]]@,@g') PATH="$PATH:/sbin:/usr/sbin:/usr/lpp/mmfs/bin" @@ -97,21 +97,22 @@ error() { msg="$1" echo "ERROR: $msg" NUM_ERRORS=`expr $NUM_ERRORS + 1` - echo " ERROR[$NUM_ERRORS]: $msg" >> $ERRORS + echo " ERROR[$NUM_ERRORS]: $msg" >> "$ERRORS" } show_file() { fname="$1" + _fdetails=$(ls -l "$fname" 2>&1) echo " ================================" echo " File: $fname" - echo " `ls -l $fname 2>&1`" + echo " $_fdetails" cat "$fname" 2>&1 | sed 's/^/ /' echo " ================================" } show_all() { echo "running $1 on nodes $nodes_comma" - onnode $nodes_comma "hostname; date; $1 2>&1 | sed 's/^/ /'" 2>&1 + onnode "$nodes_comma" "hostname; date; $1 2>&1 | sed 's/^/ /'" 2>&1 } show_and_compare_files () { @@ -119,19 +120,20 @@ show_and_compare_files () { fmt="$1" ; shift for f ; do + _bf=$(basename "$f") first=true for n in $nodes ; do if $first ; then - onnode $n [ -r "$f" ] || { - msg=$(printf "$fmt" "$f" $n) + onnode "$n" [ -r "$f" ] || { + msg=$(printf "$fmt" "$f" "$n") error "$msg" continue 2; } - fstf=$tmpdir/`basename $f`.node$n - onnode $n cat $f > $fstf 2>&1 + fstf="${tmpdir}/${_bf}.node${n}" + onnode "$n" cat "$f" >"$fstf" 2>&1 echo " ================================" echo " File (on node $n): $f" @@ -141,17 +143,19 @@ show_and_compare_files () { first=false else echo "Testing for same config file $f on node $n" - tmpf=$tmpdir/`basename $f`.node$n - onnode $n cat $f > $tmpf 2>&1 - diff $diff_opts $fstf $tmpf >/dev/null 2>&1 || { + tmpf="${tmpdir}/${_bf}.node${n}" + onnode "$n" cat "$f" >"$tmpf" 2>&1 + # Intentional multi-word splitting on diff_opts + # shellcheck disable=SC2086 + diff $diff_opts "$fstf" "$tmpf" >/dev/null 2>&1 || { error "File $f is different on node $n" - diff -u $diff_opts $fstf $tmpf + diff -u $diff_opts "$fstf" "$tmpf" } - rm -f $tmpf + rm -f "$tmpf" fi done - rm -f $fstf + rm -f "$fstf" done } @@ -188,10 +192,14 @@ cat <. -prog=$(basename $0) +prog=$(basename "$0") usage () { @@ -111,11 +111,11 @@ echo_nth () { local n="$1" ; shift - shift $n + shift "$n" local node="$1" if [ -n "$node" -a "$node" != "#DEAD" ] ; then - echo $node + echo "$node" else echo "${prog}: \"node ${n}\" does not exist" >&2 exit 1 @@ -132,8 +132,8 @@ parse_nodespec () *-*) seq "${i%-*}" "${i#*-}" 2>/dev/null || invalid_nodespec ;; all|any|ok|healthy|con|connected) echo "$i" ;; *) - [ $i -gt -1 ] 2>/dev/null || $names_ok || invalid_nodespec - echo $i + [ "$i" -gt -1 ] 2>/dev/null || $names_ok || invalid_nodespec + echo "$i" esac done ) @@ -162,6 +162,8 @@ get_nodes_with_status () IFS="${IFS}|" while IFS="" read i ; do + # Intentional word splitting + # shellcheck disable=SC2086 set -- $i # split line on colons shift # line starts with : so 1st field is empty local pnn="$1" ; shift @@ -183,6 +185,8 @@ get_nodes_with_status () invalid_nodespec esac + # Intentional multi-word expansion + # shellcheck disable=SC2086 echo_nth "$pnn" $all_nodes done <<<"$ctdb_status_output" ) @@ -193,11 +197,13 @@ get_any_available_node () local all_nodes="$1" # We do a recursive onnode to find which nodes are up and running. - local out=$($0 -pq all ctdb pnn 2>&1) + local out=$("$0" -pq all ctdb pnn 2>&1) local line while read line ; do local pnn="${line#PNN:}" if [ "$pnn" != "$line" ] ; then + # Intentional multi-word expansion + # shellcheck disable=SC2086 echo_nth "$pnn" $all_nodes return 0 fi @@ -250,11 +256,13 @@ get_nodes () get_nodes_with_status "$all_nodes" "connected" || exit 1 ;; [0-9]|[0-9][0-9]|[0-9][0-9][0-9]) - echo_nth $n $all_nodes + # Intentional multi-word expansion + # shellcheck disable=SC2086 + echo_nth "$n" $all_nodes ;; *) $names_ok || invalid_nodespec - echo $n + echo "$n" esac done } @@ -342,6 +350,8 @@ else fi pids="" +# Intentional multi-word expansion +# shellcheck disable=SC2086 trap 'kill -TERM $pids 2>/dev/null' INT TERM # There's a small race here where the kill can fail if no processes # have been added to $pids and the script is interrupted. However, @@ -350,21 +360,21 @@ retcode=0 for n in $nodes ; do set -o pipefail 2>/dev/null if $parallel ; then - { exec 3>&1 ; { $SSH $ssh_opts $EXTRA_SSH_OPTS $n "$command" | stdout_filter >&3 ; } 2>&1 | stderr_filter ; } & + { exec 3>&1 ; { $SSH $ssh_opts $EXTRA_SSH_OPTS "$n" "$command" | stdout_filter >&3 ; } 2>&1 | stderr_filter ; } & pids="${pids} $!" else if $verbose ; then echo >&2 ; echo ">> NODE: $n <<" >&2 fi - { exec 3>&1 ; { $SSH $ssh_opts $EXTRA_SSH_OPTS $n "$command" | stdout_filter >&3 ; } 2>&1 | stderr_filter ; } + { exec 3>&1 ; { $SSH $ssh_opts $EXTRA_SSH_OPTS "$n" "$command" | stdout_filter >&3 ; } 2>&1 | stderr_filter ; } [ $? = 0 ] || retcode=$? fi done $parallel && { for p in $pids; do - wait $p + wait "$p" [ $? = 0 ] || retcode=$? done }