ctdb-scripts: Dump stack traces of smbd processes after shutdown
[samba.git] / ctdb / config / events.d / 50.samba
1 #!/bin/sh
2 # ctdb event script for Samba
3
4 [ -n "$CTDB_BASE" ] || \
5     CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
6
7 . "${CTDB_BASE}/functions"
8
9 detect_init_style
10
11 case $CTDB_INIT_STYLE in
12         suse)
13                 CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-smb}
14                 CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-nmb}
15                 ;;
16         debian)
17                 CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-samba}
18                 CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-""}
19                 ;;
20         *)
21                 # Use redhat style as default:
22                 CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-smb}
23                 CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-""}
24                 ;;
25 esac
26
27 # service_name is used by various functions
28 # shellcheck disable=SC2034
29 service_name="samba"
30
31 loadconfig
32
33 service_state_dir=$(ctdb_setup_service_state_dir) || exit $?
34
35 service_start ()
36 {
37     # make sure samba is not already started
38     service "$CTDB_SERVICE_SMB" stop > /dev/null 2>&1
39     if [ -n "$CTDB_SERVICE_NMB" ] ; then
40         service "$CTDB_SERVICE_NMB" stop > /dev/null 2>&1
41     fi
42     killall -0 -q smbd && {
43         sleep 1
44         # make absolutely sure samba is dead
45         killall -q -9 smbd
46     }
47     killall -0 -q nmbd && {
48         sleep 1
49         # make absolutely sure samba is dead
50         killall -q -9 nmbd
51     }
52
53     # start Samba service. Start it reniced, as under very heavy load
54     # the number of smbd processes will mean that it leaves few cycles
55     # for anything else
56     net serverid wipe
57
58     if [ -n "$CTDB_SERVICE_NMB" ] ; then
59         nice_service "$CTDB_SERVICE_NMB" start || die "Failed to start nmbd"
60     fi
61
62     nice_service "$CTDB_SERVICE_SMB" start || die "Failed to start samba"
63 }
64
65 service_stop ()
66 {
67     service "$CTDB_SERVICE_SMB" stop
68     program_stack_traces "smbd" 5
69     if [ -n "$CTDB_SERVICE_NMB" ] ; then
70         service "$CTDB_SERVICE_NMB" stop
71     fi
72 }
73
74 ######################################################################
75 # Show the testparm output using a cached smb.conf to avoid delays due
76 # to registry access.
77
78 smbconf_cache="$service_state_dir/smb.conf.cache"
79
80 testparm_foreground_update ()
81 {
82     _timeout="$1"
83
84     # No need to remove these temporary files, since there are only 2
85     # of them.
86     _out="${smbconf_cache}.out"
87     _err="${smbconf_cache}.err"
88
89     timeout "$_timeout" testparm -v -s >"$_out" 2>"$_err"
90     case $? in
91         0) : ;;
92         124)
93             if [ -f "$smbconf_cache" ] ; then
94                 echo "WARNING: smb.conf cache update timed out - using old cache file"
95                 return 1
96             else
97                 echo "ERROR: smb.conf cache create failed - testparm command timed out"
98                 exit 1
99             fi
100             ;;
101         *)
102             if [ -f "$smbconf_cache" ] ; then
103                 echo "WARNING: smb.conf cache update failed - using old cache file"
104                 cat "$_err"
105                 return 1
106             else
107                 echo "ERROR: smb.conf cache create failed - testparm failed with:"
108                 cat "$_err"
109                 exit 1
110             fi
111     esac
112
113     # Only using $$ here to avoid a collision.  This is written into
114     # CTDB's own state directory so there is no real need for a secure
115     # temporary file.
116     _tmpfile="${smbconf_cache}.$$"
117     # Patterns to exclude...
118     _pat='^[[:space:]]+(registry[[:space:]]+shares|include|copy|winbind[[:space:]]+separator)[[:space:]]+='
119     grep -Ev "$_pat" <"$_out" >"$_tmpfile"
120     mv "$_tmpfile" "$smbconf_cache" # atomic
121
122     return 0
123 }
124
125 testparm_background_update ()
126 {
127     _timeout="$1"
128
129     testparm_foreground_update "$_timeout" >/dev/null 2>&1 </dev/null &
130 }
131
132 testparm_cat ()
133 {
134     testparm -s "$smbconf_cache" "$@" 2>/dev/null
135 }
136
137 list_samba_shares ()
138 {
139     testparm_cat |
140     sed -n -e 's@^[[:space:]]*path[[:space:]]*=[[:space:]]@@p' |
141     sed -e 's/"//g'
142 }
143
144 list_samba_ports ()
145 {
146     testparm_cat --parameter-name="smb ports" |
147     sed -e 's@,@ @g'
148 }
149
150 ###########################
151
152 ctdb_start_stop_service
153
154 is_ctdb_managed_service || exit 0
155
156 ###########################
157
158 case "$1" in
159 startup)
160         ctdb_service_start
161         ;;
162
163 shutdown)
164         ctdb_service_stop
165         ;;
166
167 monitor)
168         testparm_foreground_update 10
169         ret=$?
170
171         smb_ports="$CTDB_SAMBA_CHECK_PORTS"
172         if [ -z "$smb_ports" ] ; then
173             smb_ports=$(list_samba_ports)
174             [ -n "$smb_ports" ] || die "Failed to set smb ports"
175         fi
176         # Intentionally unquoted multi-word value here
177         # shellcheck disable=SC2086
178         ctdb_check_tcp_ports $smb_ports || exit $?
179
180         if [ "$CTDB_SAMBA_SKIP_SHARE_CHECK" != "yes" ] ; then
181             list_samba_shares | ctdb_check_directories || exit $?
182         fi
183
184         if [ $ret -ne 0 ] ; then
185             testparm_background_update 10
186         fi
187         ;;
188 esac
189
190 exit 0