Files
hassio-addons/claude_desktop/rootfs/etc/cont-init.d/21-gpu_permissions.sh
alexbelgium ea46cbf8a5 fix(claude_desktop): address review nitpicks on PR #2893
- 21-gpu_permissions.sh: distinguish the expected getent exit 2
  (unnamed GID) from other getent failures, warning instead of
  silently masking unrelated NSS/database errors.
- SIGN_IN.md: state explicitly that --password-store=basic trades
  away OS-backed at-rest protection.

Addresses CodeRabbit nitpicks from the PR review. The symlink-following
concern on 85-openbox_autostart.sh raised by CodeRabbit and Codex is left
open for maintainer review (see PR comment).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 08:35:13 +02:00

68 lines
3.1 KiB
Bash
Executable File

#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
# Grant the shared desktop user (abc) access to the exposed GPU render nodes *before* the
# graphical services start.
#
# The LinuxServer base image already sets up /dev/dri group access, but it does so in its
# init-video s6 oneshot, which is NOT a dependency of svc-xorg/svc-selkies/svc-de. On Home
# Assistant those long-running services routinely start (as abc, via s6-setuidgid) before
# init-video has added abc to the render group, so Xorg/Selkies/pixelflux open the render
# device with the wrong credentials and fail:
#
# libEGL warning: failed to open /dev/dri/card0: Permission denied
#
# With no usable render node the video pipeline never produces frames, so the Selkies web
# client stays on "waiting for stream" indefinitely and Claude Desktop never appears.
#
# cont-init.d runs to completion before any s6-rc service is started, so preparing the DRI
# nodes here wins that race. Everything is best-effort: a host that exposes no GPU simply has
# no nodes to touch and this is a no-op.
shopt -s nullglob
dri_nodes=(/dev/dri/card* /dev/dri/render*)
if [ "${#dri_nodes[@]}" -eq 0 ]; then
bashio::log.info "No /dev/dri render nodes exposed; skipping GPU permission setup"
exit 0
fi
for node in "${dri_nodes[@]}"; do
[ -e "$node" ] || continue
# Mirror the base image's init-video logic (add abc to the node's owning group, creating
# the group when the GID is unnamed) but early enough that the s6-setuidgid at service
# start picks the membership up.
gid="$(stat -c '%g' "$node")"
# getent exits 2 when the gid has no named group, which is the common case here: this
# script deliberately runs before the base image's init-video/init-adduser have named the
# passed-through /dev/dri gids. Under bashio's `set -o pipefail` + this script's `set -e`,
# an unguarded pipeline would abort right here on that exit 2 — before the `-z "$gname"`
# fallback below (which exists precisely to handle an unnamed gid) ever runs. Confirmed by
# bashio manually re-running this script post-boot always "worked": by then the base
# image's own init-video oneshot had already named the group, so getent no longer hit its
# exit-2 path.
if gname="$(getent group "$gid" | awk -F: '{print $1}')"; then
rc=0
else
rc=$?
if [ "$rc" -ne 2 ]; then
bashio::log.warning "getent group ${gid} failed unexpectedly (exit ${rc}); falling back to a synthetic group"
fi
fi
if [ -z "$gname" ]; then
gname="dri${gid}"
groupadd -o -g "$gid" "$gname" 2> /dev/null || true
fi
if ! id -G abc 2> /dev/null | tr ' ' '\n' | grep -qx "$gid"; then
usermod -a -G "$gname" abc 2> /dev/null || true
fi
# Guarantee access even where group propagation is unreliable inside the add-on sandbox:
# this is a single-user desktop container, so world read/write on the local render node
# is acceptable and removes any dependency on group-membership timing.
chmod o+rw "$node" 2> /dev/null || true
bashio::log.info "GPU: prepared ${node} (group ${gname}:${gid}) for the desktop user"
done