diff --git a/__pycache__/cheatsheet_overlaycpython-39.pyc b/__pycache__/cheatsheet_overlaycpython-39.pyc index 1a11ef7..a6dd946 100644 Binary files a/__pycache__/cheatsheet_overlaycpython-39.pyc and b/__pycache__/cheatsheet_overlaycpython-39.pyc differ diff --git a/aramis-home b/aramis-home index d4da7cf..fad612b 100755 --- a/aramis-home +++ b/aramis-home @@ -1,5 +1,5 @@ #!/bin/bash -source /opt/gfa/python +source bpy-env cd /afs/psi.ch/intranet/SF/Photonics/AramisOverview caqtdm -stylefile sfop.qss -macro chargelim=15,ES-DISPLAY=SAROP-CPCL-ARAMIS-UI:ARAMIS-ES.BB S_PH_Aramis_Overview.ui diff --git a/cheatsheet_overlay b/cheatsheet_overlay index 6dda391..40340b8 100755 --- a/cheatsheet_overlay +++ b/cheatsheet_overlay @@ -6,10 +6,14 @@ there's no "brand-new extension not recognized until Shell restarts" risk: this is just a normal process, like any other keybinding here. Toggle behavior: running this while an instance is already showing closes -it instead of opening a second one (tracked via a PID file). +it instead of opening a second one (tracked via a PID file). That PID file +is verified against /proc before ever being trusted or signaled -- on a +host where its directory isn't cleared across reboots (confirmed: some +hosts' /tmp isn't, which the PID file falls back to when XDG_RUNTIME_DIR +isn't set), a stale PID number could otherwise get reused by a completely +unrelated process after reboot. -Dismiss: Escape, clicking outside the panel, or pressing the trigger key -again. +Dismiss: Escape, the close button, or pressing the trigger key again. """ import json import os @@ -17,6 +21,7 @@ import signal import subprocess import sys import tempfile +import time import gi @@ -96,15 +101,32 @@ def load_categories(): pass +def _is_our_process(pid): + """True only if `pid` is actually still running *this* script -- not + just any process that happens to exist. Without this check, a PID + file surviving somewhere that isn't cleared across reboots (confirmed: + /tmp isn't, on at least one host here) could have its old PID number + reused by a completely unrelated process, which we'd otherwise + mistakenly SIGTERM and treat as "still showing".""" + try: + with open(f"/proc/{pid}/cmdline", "rb") as f: + return b"cheatsheet_overlay" in f.read() + except OSError: + return False + + def already_showing(): """If a live instance is already up, kill it and return True (caller should then just exit, giving Super+F1 toggle-to-close behavior).""" try: with open(PID_FILE, encoding="utf-8") as f: pid = int(f.read().strip()) - os.kill(pid, signal.SIGTERM) + if _is_our_process(pid): + os.kill(pid, signal.SIGTERM) + os.unlink(PID_FILE) + return True os.unlink(PID_FILE) - return True + return False except (FileNotFoundError, ValueError, ProcessLookupError): try: os.unlink(PID_FILE) @@ -226,7 +248,23 @@ def _on_key_press(widget, event): return False +def wait_for_source(timeout=10): + """Block until MD_PATH is actually readable, up to `timeout` seconds. + /sf/bernina is a real NFS mount (not autofs) so it's normally already + up by login, but this is cheap insurance against a race at boot, and + means the file always gets read fresh from the network filesystem on + every call -- no local copy to ever go stale.""" + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + if os.access(MD_PATH, os.R_OK): + return True + time.sleep(0.2) + return os.access(MD_PATH, os.R_OK) + + def main(): + wait_for_source() + if already_showing(): return diff --git a/check_kerberos_renewal b/check_kerberos_renewal new file mode 100755 index 0000000..4d5c660 --- /dev/null +++ b/check_kerberos_renewal @@ -0,0 +1,70 @@ +#!/bin/bash +# Read-only diagnostic for "kerberos_ticket_renew.sh renews/prompts too +# often" on the gac-bernina account. Checks the things that would make +# `kinit -R` fail more than it should (forcing the interactive password +# fallback instead of silent renewal), and looks for anything else that +# might already be renewing/touching this account's ticket independently. +# Makes no changes -- run it, read the output, nothing to clean up after. +# +# Usage: check_kerberos_renewal [principal] (default: gac-bernina) + +set -uo pipefail + +PRINCIPAL="${1:-gac-bernina}" + +section() { echo; echo "=== $* ==="; } + +section "Current ticket(s) + renewable flag (this krb5 build only supports klist -f, not -v)" +klist -f 2>&1 +echo +echo "Looking for an 'R' (renewable) flag on the krbtgt ticket in the output above" +echo "(e.g. 'Flags: FRIA' -- R present). If it's missing, kinit -R can NEVER" +echo "succeed for this ticket no matter how recently it was issued -- every" +echo "renewal attempt would fall straight through to the interactive password" +echo "prompt, which is exactly what over-frequent PROMPTING would look like." +echo +echo "Also compare 'Valid starting' -> 'Expires' (actual ticket lifetime) against" +echo "kerberos_ticket_renew.sh's RENEW_THRESHOLD (default 86400s = 24h): if the" +echo "real lifetime is shorter than the threshold -- e.g. PSI issuing ~10h" +echo "tickets renewable for 7 days is normal here -- every single hourly check" +echo "will always conclude renewal is needed and fire kinit -R, succeeding" +echo "silently but notifying every time. That's over-frequent NOTIFYING (not" +echo "prompting), and doesn't need anything external renewing to explain it." + +section "Any process already touching Kerberos for this account" +ps -eo pid,ppid,user,lstart,cmd 2>/dev/null | grep -iE "kinit|krb5|kerberos.?ticket.?renew|k5start|krenew" | grep -v grep + +section "Our own renewer: how many instances, and is the singleton lock actually working" +echo "-- process(es):" +pgrep -fa kerberos_ticket_renew.sh || echo "(none running right now)" +echo +echo "-- lock file (should be exactly one holder; if XDG_RUNTIME_DIR is unset or" +echo " inconsistent between invocations -- seen elsewhere this session -- the" +echo " lock could silently end up in different places, defeating the" +echo " single-instance guard and letting multiple copies run concurrently):" +echo "XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-}" +for f in "${XDG_RUNTIME_DIR:-}/kerberos_ticket_renew.lock" "/tmp/kerberos_ticket_renew.lock"; do + [ -n "$f" ] && [ -e "$f" ] && echo "found: $f" && lsof "$f" 2>/dev/null +done + +section "Cron / systemd --user timers or services that might also renew this ticket" +echo "-- crontab:" +crontab -l 2>&1 +echo +echo "-- systemd --user timers:" +systemctl --user list-timers --all 2>&1 +echo +echo "-- systemd --user services with kerberos/krb in the name:" +systemctl --user list-units --type=service --all 2>&1 | grep -iE "krb|kerberos" + +section "KDC-side policy for this principal, if we're allowed to see it" +echo "(requires admin rights on the realm -- expected to fail for a normal" +echo " principal querying itself; worth trying anyway, costs nothing)" +kadmin -q "getprinc ${PRINCIPAL}" 2>&1 | grep -iE "maximum ticket life|maximum renewable life|attributes" || \ + echo "(no admin rights to query this, or kadmin unavailable -- expected)" + +section "Done" +echo "Send back everything above. The 'Renewable flag check' and 'lifetime vs" +echo "renewable window' sections are the most likely to show the actual cause;" +echo "the process/cron/timer sections rule in or out something else already" +echo "renewing independently, per your suspicion." diff --git a/eco_from b/eco_from deleted file mode 100755 index 36c0dc7..0000000 --- a/eco_from +++ /dev/null @@ -1,9 +0,0 @@ -#/bin/bash -#source /opt/gfa/python -source anaconda_env bernina37_dev - -ipython --pylab --profile=eco --no-banner -i -c "run $1 -l -s bernina" - - -#python /sf/bernina/config/src/python/eco/startup.py -s bernina "$@" -l - diff --git a/kerberos_ticket_renew.sh b/kerberos_ticket_renew.sh index 2cbe959..e80f980 100755 --- a/kerberos_ticket_renew.sh +++ b/kerberos_ticket_renew.sh @@ -13,12 +13,20 @@ # # Defaults to the generic gac-bernina account; override with # KRB_PRINCIPAL or -p to manage a different one. +# +# RENEW_THRESHOLD default: confirmed via check_kerberos_renewal that PSI's +# actual ticket lifetime here is only ~10h (renewable for 7 days) -- the +# old 24h default was longer than that entire lifetime, so every single +# hourly check always concluded "renewal needed" and silently renewed + +# notified every hour forever. 2h leaves several retry cycles of buffer +# before real expiry while only actually renewing (and notifying) roughly +# once per ticket lifetime instead of on every check. set -uo pipefail # no -e: one failed klist/kinit must not kill the loop PRINCIPAL="${KRB_PRINCIPAL:-gac-bernina}" -CHECK_INTERVAL="${KRB_CHECK_INTERVAL:-3600}" # seconds between checks (1h) -RENEW_THRESHOLD="${KRB_RENEW_THRESHOLD:-86400}" # renew once <24h remain +CHECK_INTERVAL="${KRB_CHECK_INTERVAL:-3600}" # seconds between checks (1h) +RENEW_THRESHOLD="${KRB_RENEW_THRESHOLD:-7200}" # renew once <2h remain ONCE=0 usage() { @@ -27,7 +35,7 @@ Usage: $(basename "$0") [-p principal] [-i check-interval-s] [-t renew-threshold -p Kerberos principal to manage (default: \$KRB_PRINCIPAL or gac-bernina) -i seconds between validity checks (default: \$KRB_CHECK_INTERVAL or 3600) - -t renew once fewer than this many seconds remain (default: \$KRB_RENEW_THRESHOLD or 86400) + -t renew once fewer than this many seconds remain (default: \$KRB_RENEW_THRESHOLD or 7200) -1 check once and exit instead of looping (for testing) EOF exit 1 diff --git a/snapshot_bernina b/snapshot_bernina deleted file mode 100755 index e5e046d..0000000 --- a/snapshot_bernina +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -source /opt/gfa/python 3.5 -snapshot -b /sf/bernina/config/snapshot/req \ - -d /sf/bernina/config/snapshot \ - --config /sf/bernina/config/snapshot/cfg/config_bernina_snapshot \ - $@ diff --git a/startup_bernina_terminal b/startup_bernina_terminal index f71d207..b6ac847 100755 --- a/startup_bernina_terminal +++ b/startup_bernina_terminal @@ -1,8 +1,5 @@ #!/bin/bash -# default controls python environment -source /opt/gfa/python - # make firefox with host-individual profile as default (important for gac-bernina account) xdg-settings set default-web-browser bernifox.desktop @@ -128,6 +125,24 @@ include "%L" : "Ζ" U0396 GREEK CAPITAL LETTER ZETA EOF +# Defensive cleanup: this script used to install and enable the "Shortcuts" +# gnome-shell extension (Shortcuts@kyle.aims.ac.za) for the cheat sheet +# overlay, bound to its own internal Super+F1 toggle, before switching to +# the current standalone cheatsheet_overlay script. Extension enabled-state +# is per-host/per-login and isn't touched by this script's own updates, so +# any host gac-bernina logged into during that period is still silently +# running it, intercepting Super+F1 before the custom-keybinding below ever +# gets a chance (confirmed on saresb-cons-05: the extension was still +# enabled and still bound, showing its own old-style overlay with no title +# bar, while ps showed no matching process at all -- because it renders +# inside gnome-shell itself, not as a separate process). Safe/idempotent if +# already disabled or never installed. +if gnome-extensions list --enabled 2>/dev/null | grep -qx "Shortcuts@kyle.aims.ac.za"; then + gnome-extensions disable "Shortcuts@kyle.aims.ac.za" + echo "Disabled leftover Shortcuts@kyle.aims.ac.za gnome-shell extension (superseded by cheatsheet_overlay)" +fi +rm -rf "$HOME/.local/share/gnome-shell/extensions/Shortcuts@kyle.aims.ac.za" + #custom bernina keyboard shortcuts gsettings reset org.gnome.settings-daemon.plugins.media-keys custom-keybindings if [ "$(hostname)" = "saresb-cons-03.psi.ch" ] || [ "$(hostname)" = "saresb-cons-04.psi.ch" ] || [ "$(hostname)" = "saresb-cons-05.psi.ch" ] || [ "$(hostname)" = "saresb-cons-08.psi.ch" ] || [ "$(hostname)" = "saresb-cons-09.psi.ch" ] || [ "$(hostname)" = "saresb-cons-10.psi.ch" ]; then