9

Today I was surprised to ssh into my box running Arch Linux and find that /run/user/$(id -u) didn't exist.

The XDG Base Directory Specification says:

$XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the user, and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.

The lifetime of the directory MUST be bound to the user being logged in. It MUST be created when the user first logs in and if the user fully logs out the directory MUST be removed. If the user logs in more than once he should get pointed to the same directory, and it is mandatory that the directory continues to exist from his first login to his last logout on the system, and not removed in between. Files in the directory MUST not survive reboot or a full logout/login cycle.

On a systemd box, is /run/user/$(id -u) the preferred place for $XDG_RUNTIME_DIR (even if it needs to be created?)

If not, what's best practice for creating $XDG_RUNTIME_DIR?

How do I ensure that that the directory is deleted only when I have "fully" logged out?

(Does "fully" mean that mean all processes created by login shells have exited? How to check for that?)

Tom Hale
  • 30,455

2 Answers2

8

The /run/user/N directory, the user@N service, and the XDG_RUNTIME_DIR environment variable are managed by a systemd-specific Pluggable Authentication Module and the logind service. On first log-on they create the directory, create the filesystem mounted there, and start the service; and on last log-off they stop the service, unmount the filesystem, and remove the directory. This behaviour changes when systemd's linger option is set for the account.

Other systems operate differently.

Further reading

JdeBP
  • 68,745
  • Thanks - I'm using mosh, and your 2nd last link explains why the /usr/run/N directory is not created.

    However, my question is about working around this, eg manually creating the directory that systemd would otherwise create from a shell login script.

    – Tom Hale Oct 22 '18 at 15:11
-1

Set / create $XDG_RUNTIME_DIR at login

  • Use existing $XDG_RUNTIME_DIR if it is set.
  • Else, use systemd's /run/user/$UID if it exists
  • Else, create and use /tmp/$USER-runtime

Check the ownership and permissions of $XDG_RUNTIME_DIR

  • Create and use /tmp/"$USER"-runtime-XXXXXX if permissions are not good.
if [ -z "$XDG_RUNTIME_DIR" ]; then  # It's not already set
  XDG_RUNTIME_DIR=/run/user/$UID  # Try systemd created path
  if [ ! -d "$XDG_RUNTIME_DIR" ]; then
    # systemd-created directory doesn't exist
    XDG_RUNTIME_DIR=/tmp/$USER-runtime
    if [ ! -d "$XDG_RUNTIME_DIR" ]; then  # Doesn't already exist
      mkdir -m 0700 "$XDG_RUNTIME_DIR"
    fi
  fi
fi
# Check dir has got the correct type, ownership, and permissions
if ! [[ -d "$XDG_RUNTIME_DIR" && -O "$XDG_RUNTIME_DIR" &&
    "$(stat -c '%a' "$XDG_RUNTIME_DIR")" = 700 ]]; then
  echo "\$XDG_RUNTIME_DIR: permissions problem with $XDG_RUNTIME_DIR:" >&2
  ls -ld "$XDG_RUNTIME_DIR" >&2
  XDG_RUNTIME_DIR=$(mktemp -d /tmp/"$USER"-runtime-XXXXXX)
  echo "Set \$XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR" >&2
fi
Tom Hale
  • 30,455