@@ -104,6 +104,64 @@ wait_for_cf_postgres_down() {
104104 cd /tmp && ! su cfpostgres -c " $PREFIX /bin/psql -l" > /dev/null 2>&1
105105}
106106
107+ cf_agent_pids () {
108+ # Prints the PIDs of running cf-agent processes, except our own ancestors
109+ # (cf-agent may be running this package upgrade) and, where /proc tells
110+ # us, processes in other mount namespaces (containers).
111+ _ancestors=" "
112+ _pid=$$
113+ while [ -n " $_pid " ] && [ " $_pid " -gt 1 ]; do
114+ _ancestors=" $_ancestors$_pid "
115+ _pid=$( ps -o ppid= -p " $_pid " 2> /dev/null | tr -d ' ' )
116+ done
117+ _ns=$( readlink /proc/self/ns/mnt 2> /dev/null || true)
118+ for _pid in $( pgrep -x cf-agent) ; do
119+ case " $_ancestors " in
120+ * " $_pid " * ) continue ;;
121+ esac
122+ if [ -z " $_ns " ] || [ " $( readlink /proc/$_pid /ns/mnt 2> /dev/null) " = " $_ns " ]; then
123+ echo " $_pid "
124+ fi
125+ done
126+ }
127+
128+ terminate_cf_agents () {
129+ # Call after stopping cf-execd. Stopping cf-execd doesn't stop an agent it
130+ # started (systemd KillMode=process), and that agent can keep changing
131+ # things, like permissions under state/pg (ENT-14899). Gives running agents
132+ # 1.5 times the average agent run time from promise_summary.log (150s if
133+ # unknown) to finish, then kills them. Does nothing without pgrep.
134+ command -v pgrep > /dev/null || return 0
135+ _pids=$( cf_agent_pids)
136+ if [ -z " $_pids " ]; then
137+ return 0
138+ fi
139+ _timeout=$( tail -n 20 " $PREFIX /promise_summary.log" 2> /dev/null |
140+ awk -F' [,:]' ' $2 >= $1 { s += $2 - $1; n++ } END { if (n) printf "%d", s / n * 1.5 }' )
141+ if [ " ${_timeout:- 0} " -le 0 ]; then
142+ _timeout=150
143+ fi
144+ cf_console echo " Waiting up to ${_timeout} s for cf-agent to finish:"
145+ cf_console ps -o pid,etime,args -p " $( echo $_pids | tr ' ' ' ,' ) " || true
146+ _waited=0
147+ while [ -n " $( cf_agent_pids) " ] && [ " $_waited " -lt " $_timeout " ]; do
148+ sleep 5
149+ _waited=$(( _waited + 5 ))
150+ done
151+ # Killing an agent can let the shell cf-execd started it from run the next
152+ # one (update.cf, then promises.cf), so check a few times.
153+ for _try in 1 2 3; do
154+ _pids=$( cf_agent_pids)
155+ if [ -z " $_pids " ]; then
156+ return 0
157+ fi
158+ cf_console echo " Warning: killing cf-agent still running after ${_timeout} s:"
159+ cf_console ps -o pid,etime,args -p " $( echo $_pids | tr ' ' ' ,' ) " || true
160+ kill -KILL $_pids 2> /dev/null || true
161+ sleep 1
162+ done
163+ }
164+
107165safe_cp () {
108166 # "safe" alternative to `cp`. Tries `cp -al` first, and if it fails - `cp -a`.
109167 # Deletes partially-copied files if copy operation fails.
@@ -136,6 +194,21 @@ safe_cp() {
136194 return 1
137195}
138196
197+ safe_cp_nolink () {
198+ # Like `safe_cp`, but never creates hardlinks, so the copy does not share
199+ # mode and owner with the source. Args are same as in safe_cp.
200+ test " $# " -eq 3 || return 2
201+ from=" $1 "
202+ name=" $2 "
203+ to=" $3 "
204+ if cp -a " $from /$name " " $to " ; then
205+ return 0
206+ fi
207+ echo " Copy failed, so removing partially-copied data and aborting"
208+ rm -rf " $to /$name "
209+ return 1
210+ }
211+
139212safe_mv () {
140213 # "safe" alternative to `mv`. Executes `safe_cp` and deletes source dir if
141214 # that succeeds.
0 commit comments