diff --git a/party b/party
index 3fbe308..10fd8ae 100755
--- a/party
+++ b/party
@@ -879,6 +879,40 @@ EOF
echo "Party '$name' started. Attach from a fresh shell with: party join $name"
}
+# Rescue
/log to $HOME/party--.log before the
+# per-party dir is removed. When drain=1 (cmd_close, right after
+# kill-server), the pipe-pane `cat` children may still be draining
+# their last bytes, so poll for two equal size samples (bounded,
+# integer sleeps only) before moving; cmd_clean's dead-server check
+# already confirmed nothing is still writing, so it passes drain=0. A
+# same-filesystem mv is a rename and would keep catching late writes
+# regardless, but $HOME and PARTY_SOCKET_DIR are commonly different
+# filesystems (tmpfs /tmp vs a home partition), where mv is copy+unlink
+# and tail bytes written after the copy started would be lost from the
+# copy.
+#
+# Sets _rt_dest to the destination path on a successful move, or to ''
+# when there was nothing to rescue. Returns 0 in both those cases; 2
+# when HOME is unset; 1 when mv failed.
+rescue_transcript() {
+ _rt_dir="$1" _rt_name="$2" _rt_drain="$3"
+ _rt_dest=''
+ [ -s "$_rt_dir/log" ] || return 0
+ [ -n "$HOME" ] || return 2
+ if [ "$_rt_drain" = 1 ]; then
+ _rt_prev=-1
+ for _rt_i in 1 2 3; do
+ _rt_size=$(wc -c < "$_rt_dir/log")
+ [ "$_rt_size" -eq "$_rt_prev" ] && break
+ _rt_prev="$_rt_size"
+ sleep 1
+ done
+ fi
+ _rt_dest="$HOME/party-$_rt_name-$(date -u '+%Y%m%d-%H%M%S').log"
+ mv "$_rt_dir/log" "$_rt_dest" 2>/dev/null || { _rt_dest=''; return 1; }
+ return 0
+}
+
cmd_close() {
name=
while [ $# -gt 0 ]; do
@@ -955,38 +989,21 @@ cmd_close() {
# Rescue a transcript before the dir vanishes: losing the night's
# log to a routine close is exactly the accident class the threat
- # model says to prevent. After kill-server the pipe-pane `cat`
- # children are exiting but may still be draining their last bytes,
- # so poll for two equal size samples (bounded, integer sleeps only)
- # before moving it. A same-filesystem mv is a rename and would keep
- # catching late writes regardless, but $HOME and PARTY_SOCKET_DIR
- # are commonly different filesystems (tmpfs /tmp vs a home
- # partition), where mv is copy+unlink and tail bytes written after
- # the copy started would be lost from the copy. A failed rescue
- # (HOME unset, mv error) leaves the party dir in place rather than
- # deleting it out from under a promise the message just made;
- # kill-server already ran, so the party is dead either way, and
- # `party close` (or `party clean`) can be re-run once the transcript
- # is off to safety.
- if [ -s "$expected_dir/log" ]; then
- if [ -z "$HOME" ]; then
+ # model says to prevent. A failed rescue (HOME unset, mv error)
+ # leaves the party dir in place rather than deleting it out from
+ # under a promise the message just made; kill-server already ran,
+ # so the party is dead either way, and `party close` (or `party
+ # clean`) can be re-run once the transcript is off to safety.
+ if rescue_transcript "$expected_dir" "$name" 1; then
+ [ -z "$_rt_dest" ] || echo "party close: transcript saved to $_rt_dest"
+ else
+ _rt_rc=$?
+ if [ "$_rt_rc" -eq 2 ]; then
echo "party close: HOME is unset; transcript kept, party dir left in place ($expected_dir/log); re-run close after fixing." >&2
- exit 1
- fi
- _cl_prev=-1
- for _cl_i in 1 2 3; do
- _cl_size=$(wc -c < "$expected_dir/log")
- [ "$_cl_size" -eq "$_cl_prev" ] && break
- _cl_prev="$_cl_size"
- sleep 1
- done
- _cl_dest="$HOME/party-$name-$(date -u '+%Y%m%d-%H%M%S').log"
- if mv "$expected_dir/log" "$_cl_dest" 2>/dev/null; then
- echo "party close: transcript saved to $_cl_dest"
else
echo "party close: could not save transcript; party dir left in place ($expected_dir/log); re-run close after fixing." >&2
- exit 1
fi
+ exit 1
fi
rm -rf "$expected_dir"
@@ -1029,20 +1046,18 @@ EOF
# already confirmed dead by the liveness check above, so unlike
# close there's no pipe-pane `cat` still draining and no
# quiescence poll is needed before moving it.
- if [ -s "$d/log" ]; then
- if [ -z "$HOME" ]; then
+ _cn_name=${d##*"party-$USER:"}
+ _cn_name=${_cn_name%.d}
+ if rescue_transcript "$d" "$_cn_name" 0; then
+ [ -z "$_rt_dest" ] || echo "party clean: transcript saved to $_rt_dest"
+ else
+ _rt_rc=$?
+ if [ "$_rt_rc" -eq 2 ]; then
echo "party clean: skipping $d (HOME is unset; leaving transcript)" >&2
- continue
- fi
- _cn_name=${d##*"party-$USER:"}
- _cn_name=${_cn_name%.d}
- _cn_dest="$HOME/party-$_cn_name-$(date -u '+%Y%m%d-%H%M%S').log"
- if mv "$d/log" "$_cn_dest" 2>/dev/null; then
- echo "party clean: transcript saved to $_cn_dest"
else
echo "party clean: skipping $d (could not save transcript)" >&2
- continue
fi
+ continue
fi
rm -rf "$d"