Files
eco/docs/shared_files.md
T
Henrik Lemke 98d8e4a0c5 docs: "Did you know?" tips, pages for recent features, and a docs-site job
- docs/did_you_know/: one short tip per feature added since May 2026
  (<date>-<slug>.md, YAML front matter: added/tags/details), listed
  newest first; index.md describes the format for adding more.
- New pages for features that had none: launching, command_history,
  tab_completion, live_gui, tweak, scanning, status_server,
  channel_access, shared_files, schematic_panels. Wired into index.rst
  together with the existing queues page.
- Fix archiver_stripchart/listening_monitor: the method is
  archiver.strip_plot (strip_chart does not exist on DataHub); document
  the per-device .strip_plot().
- NAMESPACE_MONITOR_FORMAT.md: scan monitoring is wired into Daq's scan
  callbacks since 2026-09-09.
- scripts/eco-docs (+ -install-user-service): build the docs from an own
  clone and serve them over HTTP as user systemd units, rebuilt by a
  timer; a failed build never replaces the served site.
2026-10-25 14:26:52 +01:00

2.8 KiB

Shared files: group permissions on results and configuration

Several accounts write to the same trees: the shared gac-bernina account and personal ones. That applies to the results under /sf/<instrument>/data/<pgroup>/res (run data, run tables, scan info, presets, ...) and to the shared configuration under /sf/<instrument>/code/<account>/. Everyone in the group must be able to add to and rewrite these, which needs directories at 2775 (group-writable plus setgid) and files at 664. Python's defaults (mkdir → 755, open(..., "w") → 644) silently produce files nobody else can change. Typically you only notice when the next person can't store a run.

eco now creates everything it writes with the right mode and group, and warns (without failing) when it meets something wrong. The warning names the account that owns the offending path, since only that account (or root) can fix it, and gives the chgrp/chmod command.

Finding out what is wrong

from eco.utilities import datafiles

datafiles.check_group_writable("/sf/bernina/data/p23415/res/run_data")

This lists every level that is not group-writable or has the wrong group, together with its owner. It changes nothing.

Repairing a tree

Run this as the account that owns the tree. A personal account cannot repair gac-bernina's directories.

datafiles.repair_tree("/sf/bernina/code/gac-bernina/eco_cnf_bernina/memory")

It fixes everything this account can fix below the path, and lists the owner of everything it cannot.

replace_unowned=True goes further: it replaces entries owned by another account with identical copies owned by this one. That changes ownership and cannot be undone without root, so try dry_run=True first. dry_run only affects that ownership step; the ordinary chmod/chgrp fixes are still applied.

Which group?

Inside a pgroup tree, the pgroup. Elsewhere, the group of the enclosing directory (what setgid would have given). Only groups this account belongs to can be set.

For code that writes files

Use these instead of the plain calls, rather than adding a chmod by hand:

Instead of Use
Path(p).mkdir(parents=True) datafiles.ensure_dir(p): applies 2775 to every level it creates
open(p, "w") datafiles.open_group_writable(p, "w")
a file written by another library (to_pickle, shutil.copyfile, ...) datafiles.ensure_group_writable(p) afterwards

Never chmod(0o775) a directory: that clears the setgid bit, after which new files get the creator's primary group instead of the pgroup.

If an existing file is not writable by this session but its directory is, open_group_writable replaces the file (write to a temporary file, then rename) instead of failing, so a second account can still store a value. This is reported once, since it changes the file's owner.