- Commands lose their .sh extension (create_personal_dir, gopass_bernina_setup, gopass_bernina_service_setup, kerberos_ticket_renew, migrate_to_network_drive, pixi_local_sync, pixi_rebuild_local, sync_personal_config); .sh now only marks files that are sourced. kerberos_ticket_renew.sh and pixi_local_sync.sh stay as links, since they are started at login. - Sourced files gain .sh (bpy-env, anaconda_env, anaconda_bernina_env, mm_bernina); the old names stay as links. - All references in scripts, the .desktop file and the docs updated; cheatsheet.md regenerated via list_bin_commands. - New pixi_pgroup_install: installs the shared bernina pixi env into a pgroup work folder (group-shared, with its own package cache) and makes it visible in JupyterHub as bernina-<exp>-<env>. - Fix '#/bin/bash' first lines (missing '!') in 11 scripts. - Stop tracking clutter (.nfs placeholders, __pycache__, vim swap file, .bak/_bak/~ copies, delme_*, empty 'me'); add .gitignore.
100 lines
3.9 KiB
Bash
Executable File
100 lines
3.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Create (or verify) a user's private directory under
|
|
# /sf/bernina/config/personal/<username> - the Bernina beamline convention
|
|
# for per-user storage on the shared NFS filesystem (a real NFS4 mount,
|
|
# unlike ~/network_drives which is SMB and can't hold a git repo - see
|
|
# gopass.md / migrate_to_network_drive.md, same directory).
|
|
#
|
|
# The per-user directory is locked to its owner only (mode 0700, setgid):
|
|
# nobody else, not even other team members, can list or read into it.
|
|
#
|
|
# Usage:
|
|
# create_personal_dir [username]
|
|
#
|
|
# Defaults to the current user. An admin can provision on someone else's
|
|
# behalf by passing their username explicitly (needs write access to the
|
|
# parent directory either way).
|
|
#
|
|
set -euo pipefail
|
|
|
|
PERSONAL_ROOT="/sf/bernina/config/personal"
|
|
GROUP="unx-sf_bernina_bs"
|
|
TARGET_USER="${1:-$(whoami)}"
|
|
TARGET_DIR="${PERSONAL_ROOT}/${TARGET_USER}"
|
|
|
|
log() { echo "==> $*"; }
|
|
ask() {
|
|
local reply
|
|
read -r -p "$1 [y/N] " reply
|
|
[[ "$reply" =~ ^[Yy]$ ]]
|
|
}
|
|
|
|
# --- the shared parent directory must itself allow self-service ------------
|
|
# (group-write so anyone in $GROUP can create their own subdirectory, plus
|
|
# the sticky bit so they can't rename/delete anyone else's - the same
|
|
# principle /tmp uses). This only needs fixing once, ever, since
|
|
# /sf/bernina is one NFS export shared by every Bernina host.
|
|
|
|
if [[ ! -d "${PERSONAL_ROOT}" ]]; then
|
|
echo "ERROR: ${PERSONAL_ROOT} does not exist - an admin needs to create it" >&2
|
|
echo " mkdir -p ${PERSONAL_ROOT} && chmod 3775 ${PERSONAL_ROOT} && chgrp ${GROUP} ${PERSONAL_ROOT}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
PARENT_MODE="$(stat -c '%a' "${PERSONAL_ROOT}")"
|
|
PARENT_GROUP_BIT="${PARENT_MODE: -2:1}"
|
|
if (( (PARENT_GROUP_BIT & 2) == 0 )); then
|
|
cat >&2 <<EOF
|
|
NOTE: ${PERSONAL_ROOT} (mode ${PARENT_MODE}) does not allow group members
|
|
to create their own subdirectory here - only its owner can right now.
|
|
EOF
|
|
if [[ "$(stat -c '%U' "${PERSONAL_ROOT}")" == "$(whoami)" ]]; then
|
|
if ask "You own it - fix it now (chmod 3775, group ${GROUP}: setgid+sticky+group-write, so people can add their own dir but not touch anyone else's)?"; then
|
|
chmod 3775 "${PERSONAL_ROOT}"
|
|
chgrp "${GROUP}" "${PERSONAL_ROOT}"
|
|
log "fixed: $(stat -c '%a %U %G' "${PERSONAL_ROOT}")"
|
|
else
|
|
echo "ERROR: cannot self-provision without this - aborting" >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "Ask the owner ($(stat -c '%U' "${PERSONAL_ROOT}")) to run this script once, or:" >&2
|
|
echo " chmod 3775 ${PERSONAL_ROOT} && chgrp ${GROUP} ${PERSONAL_ROOT}" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# --- create (or verify) the target user's own directory ---------------------
|
|
|
|
if [[ -e "${TARGET_DIR}" ]]; then
|
|
log "${TARGET_DIR} already exists"
|
|
CUR_MODE="$(stat -c '%a' "${TARGET_DIR}")"
|
|
CUR_OWNER="$(stat -c '%U' "${TARGET_DIR}")"
|
|
CUR_GROUP="$(stat -c '%G' "${TARGET_DIR}")"
|
|
if [[ "${CUR_MODE}" != "2700" || "${CUR_OWNER}" != "${TARGET_USER}" || "${CUR_GROUP}" != "${GROUP}" ]]; then
|
|
log "current: mode=${CUR_MODE} owner=${CUR_OWNER} group=${CUR_GROUP}"
|
|
log "expected: mode=2700 owner=${TARGET_USER} group=${GROUP}"
|
|
if [[ "${CUR_OWNER}" == "$(whoami)" || "$(whoami)" == "root" ]]; then
|
|
if ask "Fix permissions to match?"; then
|
|
chmod 2700 "${TARGET_DIR}"
|
|
[[ "$(whoami)" == "root" ]] && chown "${TARGET_USER}:${GROUP}" "${TARGET_DIR}"
|
|
log "fixed"
|
|
fi
|
|
else
|
|
echo "Not the owner - can't fix this from here." >&2
|
|
fi
|
|
else
|
|
log "permissions already correct (2700, ${TARGET_USER}:${GROUP})"
|
|
fi
|
|
else
|
|
mkdir "${TARGET_DIR}"
|
|
chmod 2700 "${TARGET_DIR}"
|
|
chgrp "${GROUP}" "${TARGET_DIR}" 2>/dev/null || true
|
|
log "created ${TARGET_DIR} ($(stat -c '%a %U %G' "${TARGET_DIR}"))"
|
|
fi
|
|
|
|
echo
|
|
log "done. Use this for anything that needs a real (non-SMB) network filesystem"
|
|
log "per user - e.g. a gopass store's --path (see gopass.md)."
|