Files
eco/docs/shared_files.md
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

68 lines
2.8 KiB
Markdown

# 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
```python
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.
```python
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.