ctdb-protocol: Fix typo in type of return variable
[samba.git] / ctdb / config / ctdbd_wrapper
1 #!/bin/sh
2
3 # ctdbd wrapper - start or stop CTDB
4
5 usage ()
6 {
7     echo "usage: ctdbd_wrapper <pidfile> { start | stop }"
8     exit 1
9 }
10
11 [ $# -eq 2 ] || usage
12
13 pidfile="$1"
14 action="$2"
15
16 ############################################################
17
18 if [ -z "$CTDB_BASE" ] ; then
19     export CTDB_BASE="/usr/local/etc/ctdb"
20 fi
21
22 . "${CTDB_BASE}/functions"
23 loadconfig "ctdb"
24
25 [ -n "$CTDB_SOCKET" ] && export CTDB_SOCKET
26
27 ctdbd="${CTDBD:-/usr/local/sbin/ctdbd}"
28
29 ############################################################
30
31 # ctdbd_is_running()
32
33 # Check if ctdbd is running.  ctdbd is only considered to running if
34 # the PID in the PID file is active and is called "ctdbd".  Return
35 # true if this is the case.  Print the PID regardless, since it can be
36 # used to kill stale processes in the session.
37
38 ctdbd_is_running ()
39 {
40         if read _pid 2>/dev/null <"$pidfile" ; then
41                 echo "$_pid"
42
43                 # This could be optimised with ps options -q and -h.
44                 # However, -q is not generally available because it is
45                 # fairly new and -h is not in some older distros.  The
46                 # options below are portable.
47                 _cmd=$(ps -p "$_pid" -o comm | tail -n +2)
48                 [ "$_cmd" = "ctdbd" ]
49         else
50                 # Missing/empty PID file
51                 return 1
52         fi
53 }
54
55 ############################################################
56
57 # If necessary, mount volatile database directory on tmpfs
58 dbdir_tmpfs_start ()
59 {
60     if [ -z "$CTDB_DBDIR_TMPFS_OPTIONS" ] ; then
61         return
62     fi
63
64     # Shortcut for readability
65     _opts="$CTDB_DBDIR_TMPFS_OPTIONS"
66
67     mkdir -p "$CTDB_DBDIR" || exit $?
68
69     # If already mounted then remount, otherwise mount
70     if findmnt -t tmpfs "$CTDB_DBDIR" >/dev/null ; then
71         mount -t tmpfs -o "remount,$_opts" none "$CTDB_DBDIR" || \
72             exit $?
73     else
74         mount -t tmpfs -o "$_opts" none "$CTDB_DBDIR" || exit $?
75     fi
76 }
77
78 # If necessary, unmount volatile database tmpfs directory on exit
79 dbdir_tmpfs_stop ()
80 {
81     if [ -z "$CTDB_DBDIR_TMPFS_OPTIONS" ] ; then
82         return
83     fi
84
85     if [ -d "$CTDB_DBDIR" ] && findmnt -t tmpfs "$CTDB_DBDIR" >/dev/null ; then
86         umount "$CTDB_DBDIR"
87     fi
88 }
89
90 # Only the nested function references its arguments
91 # shellcheck disable=SC2120
92 build_ctdb_options ()
93 {
94     ctdb_options=""
95
96     maybe_set ()
97     {
98         # If the given variable isn't set then do nothing
99         [ -n "$2" ] || return
100         # If a required value for the variable and it doesn't match,
101         # then do nothing
102         [ -z "$3" -o "$3" = "$2" ] || return
103
104         val="'$2'"
105         case "$1" in
106             --*) sep="=" ;;
107             -*)  sep=" " ;;
108         esac
109         # For these options we're only passing a value-less flag.
110         if [ -n "$3" ] ; then
111             val=""
112             sep=""
113         fi
114
115         ctdb_options="${ctdb_options}${ctdb_options:+ }${1}${sep}${val}"
116     }
117
118     if [ -z "$CTDB_RECOVERY_LOCK" ] ; then
119         echo "No recovery lock specified. Starting CTDB without split brain prevention."
120     fi
121     maybe_set "--reclock"                "$CTDB_RECOVERY_LOCK"
122
123     maybe_set "--pidfile"                "$pidfile"
124
125     # build up ctdb_options variable from optional parameters
126     maybe_set "--logging"                "$CTDB_LOGGING"
127     maybe_set "--nlist"                  "$CTDB_NODES"
128     maybe_set "--socket"                 "$CTDB_SOCKET"
129     maybe_set "--listen"                 "$CTDB_NODE_ADDRESS"
130     maybe_set "--public-addresses"       "$CTDB_PUBLIC_ADDRESSES"
131     maybe_set "--public-interface"       "$CTDB_PUBLIC_INTERFACE"
132     maybe_set "--dbdir"                  "$CTDB_DBDIR"
133     maybe_set "--dbdir-persistent"       "$CTDB_DBDIR_PERSISTENT"
134     maybe_set "--dbdir-state"            "$CTDB_DBDIR_STATE"
135     maybe_set "--event-script-dir"       "$CTDB_EVENT_SCRIPT_DIR"
136     maybe_set "--transport"              "$CTDB_TRANSPORT"
137     maybe_set "-d"                       "$CTDB_DEBUGLEVEL"
138     maybe_set "--notification-script"    "$CTDB_NOTIFY_SCRIPT"
139     maybe_set "--start-as-disabled"      "$CTDB_START_AS_DISABLED"    "yes"
140     maybe_set "--start-as-stopped "      "$CTDB_START_AS_STOPPED"     "yes"
141     maybe_set "--no-recmaster"           "$CTDB_CAPABILITY_RECMASTER" "no"
142     maybe_set "--no-lmaster"             "$CTDB_CAPABILITY_LMASTER"   "no"
143     maybe_set "--nosetsched"             "$CTDB_NOSETSCHED"           "yes"
144     maybe_set "--script-log-level"       "$CTDB_SCRIPT_LOG_LEVEL"
145     maybe_set "--max-persistent-check-errors" "$CTDB_MAX_PERSISTENT_CHECK_ERRORS"
146 }
147
148 export_debug_variables ()
149 {
150     [ -n "$CTDB_DEBUG_HUNG_SCRIPT" ] && export CTDB_DEBUG_HUNG_SCRIPT
151     [ -n "$CTDB_EXTERNAL_TRACE" ] && export CTDB_EXTERNAL_TRACE
152     [ -n "$CTDB_DEBUG_LOCKS" ] && export CTDB_DEBUG_LOCKS
153 }
154
155 kill_ctdbd ()
156 {
157     _session="$1"
158
159     if [ -n "$_session" ] ; then
160         pkill -9 -s "$_session" 2>/dev/null
161     fi
162 }
163
164 ############################################################
165
166 start()
167 {
168     if _session=$(ctdbd_is_running) ; then
169         echo "CTDB is already running"
170         return 0
171     fi
172
173     # About to start new $ctdbd.  The main daemon is not running but
174     # there may still be other processes around, so do some cleanup.
175     kill_ctdbd "$_session"
176
177     dbdir_tmpfs_start
178
179     # build_ctdb_options() takes no arguments
180     # shellcheck disable=SC2119
181     build_ctdb_options
182
183     export_debug_variables
184
185     # Explicitly trying to disable core files, no other way
186     # shellcheck disable=SC2039
187     if [ "$CTDB_SUPPRESS_COREFILE" = "yes" ]; then
188         ulimit -c 0
189     else
190         ulimit -c unlimited
191     fi
192
193     # Unsupported option easily avoided by not using configuration variable
194     # shellcheck disable=SC2039
195     if [ -n "$CTDB_MAX_OPEN_FILES" ]; then
196         ulimit -n "$CTDB_MAX_OPEN_FILES"
197     fi
198
199     _d=$(dirname "$pidfile")
200     mkdir -p "$_d"
201
202     if [ -n "$CTDB_VALGRIND" -a "$CTDB_VALGRIND" != "no" ] ; then
203         if [ "$CTDB_VALGRIND" = "yes" ] ; then
204             ctdbd="valgrind -q --log-file=/usr/local/var/log/ctdb_valgrind ${ctdbd}"
205         else
206             ctdbd="${CTDB_VALGRIND} ${ctdbd}"
207         fi
208         ctdb_options="${ctdb_options} --valgrinding"
209     fi
210
211     case "$CTDB_LOGGING" in
212         syslog:udp|syslog:udp-rfc5424)
213             logger -t ctdbd "CTDB is being run with ${CTDB_LOGGING}.  If nothing is logged then check your syslogd configuration"
214             ;;
215         syslog|syslog:*) : ;;
216         file:*)
217             logger -t ctdbd "CTDB is being run without syslog enabled.  Logs will be in ${CTDB_LOGGING#file:}"
218             ;;
219         *)
220             logger -t ctdbd "CTDB is being run without syslog enabled.  Logs will be in log.ctdb"
221     esac
222
223     eval "$ctdbd" "$ctdb_options" || return 1
224
225     # Wait until ctdbd has started and is ready to respond to clients.
226     _pid=""
227     _timeout="${CTDB_STARTUP_TIMEOUT:-10}"
228     _count=0
229     while [ "$_count" -lt "$_timeout" ] ; do
230         # If we don't have the PID then try to read it.
231         [ -n "$_pid" ] || read _pid 2>/dev/null <"$pidfile"
232
233         # If we got the PID but the PID file has gone or the process
234         # is no longer running then stop waiting... CTDB is dead.
235         if [ -n "$_pid" ] ; then
236             if [ ! -e "$pidfile" ] || ! kill -0 "$_pid" 2>/dev/null ; then
237                 echo "CTDB exited during initialisation - check logs."
238                 kill_ctdbd "$_pid"
239                 drop_all_public_ips >/dev/null 2>&1
240                 return 1
241             fi
242
243             if $CTDB runstate first_recovery startup running >/dev/null 2>&1 ; then
244                 return 0
245             fi
246         fi
247
248         _count=$((_count + 1))
249         sleep 1
250     done
251
252     echo "Timed out waiting for initialisation - check logs - killing CTDB"
253     kill_ctdbd "$_pid"
254     drop_all_public_ips >/dev/null 2>&1
255     return 1
256 }
257
258 stop()
259 {
260     if ! _session=$(ctdbd_is_running) ; then
261         echo "CTDB is not running"
262         return 0
263     fi
264
265     $CTDB shutdown
266
267     # Wait for remaining CTDB processes to exit...
268     _timeout=${CTDB_SHUTDOWN_TIMEOUT:-30}
269     _count=0
270     _terminated=false
271     while [ "$_count" -lt "$_timeout" ] ; do
272         if ! pkill -0 -s "$_session" 2>/dev/null ; then
273             _terminated=true
274             break
275         fi
276
277         _count=$((_count + 1))
278         sleep 1
279     done
280
281     if ! $_terminated ; then
282         echo "Timed out waiting for CTDB to shutdown.  Killing CTDB processes."
283         kill_ctdbd "$_session"
284         drop_all_public_ips >/dev/null 2>&1
285
286         sleep 1
287
288         if pkill -0 -s "$_session" ; then
289             # If SIGKILL didn't work then things are bad...
290             echo "Failed to kill all CTDB processes.  Giving up."
291             return 1
292         fi
293     fi
294
295     dbdir_tmpfs_stop
296
297     return 0
298 }
299
300 ############################################################
301
302 # Allow notifications for start/stop.
303 if [ -x "$CTDB_BASE/rc.ctdb" ] ; then
304     "$CTDB_BASE/rc.ctdb" "$action"
305 fi
306
307 case "$action" in
308     start) start ;;
309     stop)  stop  ;;
310     *)
311         echo "usage: $0 {start|stop}"
312         exit 1
313 esac