borgmatic run as a system service should not use /run/user/$UID
#934
Loadingβ¦
x
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why this could be a problem:
/run/user/$UID
is a tmpfs created by pam_systemd, meaning, if the user does not have any running sessions, it will not exist. Therefore, for example, it isn't possible to make this directory writable if usingProtectSystem=strict
.Suggested solution
Add
RuntimeDirectory=borgmatic
to the system service unit. This will make systemd create/run/borgmatic
, make it writable (even withProtectSystem=strict
), and setRUNTIME_DIRECTORY
to that path.In borgmatic, check if the
RUNTIME_DIRECTORY
environment variable is set, and if yes use that directory.Note: systemd will wipe any RuntimeDirectories when the unit finishes running, but I don't think this is a problem. See also the docs.
I ran into the same issue. It seems to have been introduced in borgmatic 1.9.0 through #562. The documentation for the new
user_runtime_directory
configuration setting describes the behaviour:When running from a systemd unit, none of these variables are set, so borgmatic falls back to
/run/user/$UID
. I think this is the actual bug: ifXDG_RUNTIME_DIR
does not point at this directory explicitly, borgmatic should not be trying to use or create it. Instead, borgmatic should fall back to/tmp
, which is acceptable in POSIX. However, if$XDG_RUNTIME_DIR
is set, there should be no harm in using it.@SimonPilkington's idea of adding
$RUNTIME_DIRECTORY
to support systemd'sRuntimeDirectory=
is a good one. I suspect most borgmatic users will be using systemd nowadays, and if not, it does little harm.So I think the order should be:
$XDG_RUNTIME_DIR
,$RUNTIME_DIRECTORY
,$TMPDIR
,$TEMP
,/tmp
.Workaround: tell systemd to create a runtime directory, then point
TMPDIR
at it:You can also just set
Environment="TMPDIR=/tmp"
in the systemd unit, oruser_runtime_directory: /tmp
in the borgmatic config, but then systemd won't clean up the directory automatically.Use cases
I'm going to co-opt this ticket to take into account both the use cases outlined here and the use cases from #928. So unless I'm missing any, here they are.
Running borgmatic as:
XDG_RUNTIME_DIR
is set and/run/user/$UID
exists (specific to that user).ProtectSystem=strict
.XDG_RUNTIME_DIR
isn't set and/run/user/$UID
doesn't exist. ButRUNTIME_DIRECTORY
could be set ifRuntimeDirectory
is configured in the systemd service. So ifRuntimeDircetory=borgmatic
, thenRUNTIME_DIRECTORY
will be/run/borgmatic
.TMPDIR
is set to an existent temporary directory specific to that user, something like/var/folders/g7/7du81ti_b7mm84n184fn3k910000lg/T/
.TMPDIR
isn't set, but runninggetconf DARWIN_USER_TEMP_DIR
may get a directory like/var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/T/
. But there's also maybe convention to using a path like~/Library/Caches/TemporaryItems/$appname/$version
?TMPDIR
may be set (but to a global directory like/tmp
)?TEMP
may be set?Some additional considerations:
/tmp
are not safe to write to without using something likemktemp
or Python'stempfile
. User-specific temp directories should be safe to write to with or without using that./borgmatic
to all user runtime directories. The rationale is that, this way, runtime files like database dumps end up stored in the Borg archive at a consistent path,/borgmatic
. (borgmatic uses the Borg 1.4+ path stripping feature so only that/borgmatic/...
portion of the path gets stored. That is, unless you're using Borg 1.2 or below.)Potential solutions
There is a Python platformdirs module that handles a lot of this, but it doesn't necessarily handle all of it and isn't customizable if needed. Additionally, it would introduce new Python dependencies to borgmatic.
So here's what I propose, riffing on @thomastc's ideas above. When constructing its runtime directory, borgmatic could probe for and use each of these in turn until finding one that is set:
user_runtime_directory
option.XDG_RUNTIME_DIR
RUNTIME_DIRECTORY
TMPDIR
+ random string (via Python'stempfile
)TEMP
+ random string"/tmp"
+ random stringThere could be the additional optimization that if the path already ends in
/borgmatic
(e.g. ifRUNTIME_DIRECTORY
is already/run/borgmatic
), then don't tack another/borgmatic
onto the end of it.I think this handles all of the use cases:
XDG_RUNTIME_DIR
.RUNTIME_DIRECTORY
(assumingRuntimeDirectory
is configured in the systemd service).TMPDIR
+ random string. The random string isn't strictly necessary for this use case, but see OpenBSD below./tmp
+ random string. And I guess/tmp
is a link to/private/tmp/
?TMPDIR
+ random string or/tmp
+ random string. The random string is needed in the first case becauseTMPDIR
can just be the global/tmp
.TEMP
+ random string.Again,
/borgmatic
implicitly gets tacked onto all of these. And with this particular approach, everything is done without having to perform platform probing or run external executables or probe for paths on the filesystems. (Although I guess doing the random string thing withtempfile
does hit the filesystem.)Phew.
Okay, what am I missing?
I think that covers everything.
I only speak for the Linux platform but
XDG_RUNTIME_DIR
for users andRUNTIME_DIRECTORY
for system unless overridden by borgmatic config LGTM. Falling back to/tmp
if nothing is set also LGTM. If borgmatic is creating a subdirectory it should have mode0700
to be XDG-compliant.However, now that I've seen mention of database dumps (which I don't use) I'm wondering if
XDG_RUNTIME_DIR
is actually suitable.The spec says:
And a database dump seems like it could potentially get pretty large. (For reference on my system
XDG_RUNTIME_DIR
is a ~6GiB tmpfs.)I believe an
endswith('/borgmatic')
check should be okay for this. A directory called borgmatic is probably intended to be used by borgmatic.Understood. It's certainly the case for anything created by
tempfile
.Good point. However in the common case, borgmatic doesn't put database dumps there; it puts named pipes there for streaming database dumps directly to Borg. And on this particular page about XDG, the description of
XDG_RUNTIME_DIR
says it's for (among other things) "non-essential, user-specific data files such as sockets, named pipes, etc."The one exception I can think of is for "directory" format databases, which by their nature can't be streamed directly to Borg and have to be dumped to disk. But most users don't use that format.
Oh I see, that's an implementation detail I didn't know. Pardon my nonsense then, pipes absolutely belong in
XDG_RUNTIME_DIR
.I suppose there is only the caveat of an increased chance of eating an
ENOSPC
with the directory format compared to dumping to$HOME/.borgmatic
. If you wish to mitigate this and be XDG-compliant I believeXDG_CACHE_HOME
would be the correct choice.Thanks, I'll consider that as part of this. But it may not be worth writing to different places for different dump formats given the additional complexity. And a user can always set their own "runtime" directory via the borgmatic configuration file option if they do run out of space.
Implemented in main, and will part of the next release. The updated documentation should be online here shortly: https://torsion.org/borgmatic/docs/how-to/backup-your-databases/#runtime-directory
Thanks to everyone for weighing in on this one!
Thank you for the amazing response time on this!
Released in borgmatic 1.9.2!