简短回答

简短回答

systemd菜鸟,在这里。

我一直在inotifywait监视一个文件夹,并在满足条件时运行一个脚本。我设置了一个systemd服务文件,以便在启动时将此脚本作为守护进程运行,但它以 root 身份运行该脚本。我想知道是否有办法让服务以当前用户身份运行(而不是在服务文件中指定用户),这样$HOME对于当前用户来说是正确的,允许我添加任意数量的用户,所有用户都可以访问该脚本。

我已经阅读过systemctl --user,和enable-linger,但老实说,我不知道最好的解决方案。

最终,我希望服务能够识别当前用户并以$HOME完整的用户身份运行本地脚本。

答案1

简短回答

我认为你想要做的是:

  1. 将 shell 脚本移动或链接到所有用户都可以访问的地方,并确保每个用户都有执行该脚本的权限。
  2. 对于每个用户,创建一个用户服务(使用 的类型systemctl --user)在启动时运行该脚本。

每个用户服务都是相同的;关键在于每个用户在启动时都有自己的服务为他们运行,链接到他们的"${HOME}"/.config/systemd/user/目录,并systemctl --user enable为他们服务。

用户服务以其用户身份(而非 root)运行,因此每个服务都将以其相应的用户身份运行并继承该用户的“环境”。该环境将传递给服务生成的任何进程 - 即您的 shell 脚本,$HOME当 foo 用户的服务运行该脚本时,它将扩展为“/home/foo”之类的内容。当 bar 的服务运行它时,$HOME它将扩展为“/home/bar”,依此类推。

更多信息

这是一些一般(和一些小众)信息,可能有助于理解正在发生的事情。

首先,系统服务和用户服务。

系统服务是“默认”类型的服务,您设置的服务可能是其中之一。

  • 他们的服务文件已链接/etc/systemd/system/
  • 它们默认以 root 身份运行。⚠️(因此,他们拥有 root 权限!)
  • 它们产生的进程不继承任何环境(例如,在服务运行的 shell 脚本中,$HOME实际上为空 --“”)。
  • 他们被控制了systemctl <command> <service>

用户服务与制作它们的用户有明确的联系。

  • 他们的服务文件已链接"${HOME}"/.config/systemd/user/(如果不存在则可能必须创建此目录)。
  • 它们默认以创建它们的用户身份运行(使用用户的权限,不是根权限)。
  • 它们产生的进程继承了该用户的环境(例如,在服务运行的 shell 脚本中,如果名为 foo 的用户创建了该服务,$HOME则会扩展为)。/home/foo
  • 他们被控制着systemctl --user <command> <service>
  • 当该用户的会话结束时,它们也会终止(这可以通过enable-linger您阅读的命令覆盖,但我认为这与您的问题无关)。

最终,我希望服务能够识别当前用户并以 $HOME 完整的用户身份运行本地脚本。

这句话单独询问如何将当前用户的环境(例如,像这样的变量$HOME)导入到由服务执行的脚本中。

导入环境的方法有很多种,从启动服务的命令的参数到 systemd 设置,再到服务文件中设置的选项。

这是我所知道的 3 个。

1. 简单地重新声明环境变量

这是最愚蠢的做法。

如果名为 foo 的用户想要$HOME扩展到“/home/foo”并$BARHOME扩展到“/home/bar”,他们可以将其放在脚本的顶部:

HOME=/home/foo
BARHOME=/home/bar

简单!当目录或文件路径发生变化时,维护工作将变成一场噩梦,所有执行此操作的脚本都需要更新以反映更改。

2. 使用系统服务中的User=和选项Group=

我认为这就是您在“在服务文件中指定用户”中提到的:

我想知道是否有办法让服务以当前用户身份运行(而不是在服务文件中指定用户)

为了系统服务以 root 身份运行并且没有默认环境,foo 用户可以将此部分放在服务的.service文件中:

[Service]
User=foo
Group=foo

这将导致系统服务以 foo(而非 root)身份运行,使用 foo 的权限(不再是 root 的权限)和 foo 的环境。因此,在服务执行的 shell 脚本中,$HOME将扩展为“/home/foo”,$USER将扩展为“foo”,依此类推。

如果您想知道,使用User=rootGroup=root仅具有导入 root 环境的效果($HOME将扩展为“/root”而不是“”,$USER将扩展为“root”等);系统服务仍然以 root 身份运行,具有 root 权限,就像默认情况下一样。

笔记:这些选项仅允许系统服务。如果用户服务在其部分中有这些选项[Service],运行时会出错。用户服务都是明确绑定到用户的,因此它们不支持以与创建和运行它们的用户不同的用户身份运行。

以这种方式将用户环境导入系统服务的缺点是 root 权限会丢失,并被该用户的权限取代。(如果服务不需要 root 权限,则不会造成任何损害,尽管它可能是一个用户服务。

另一个缺点是它根本无法实现你想要的“多用户”功能。(再次强调,用户为每个用户提供服务可能是实现这一目标的最佳方式。

3. 使用 systemd 的DefaultEnvironment变量

这是我导入环境变量的方式。这可能有点奇怪,但它有两个优点:

  1. 它独立于User=Group=选项工作,将服务环境与其用户分离。
  2. 它允许用户(例如root)使用他们的环境变量同时与其他用户的(例如,foo 的)环境变量。

我们假设 foo 用户在其 中声明了所有环境变量.profile(这是惯例)。作为额外的改动,foo 用户将其主目录硬编码在名为 的变量中$UHOME。因此,在 中/home/foo/.profile,我们有:

export UHOME="/home/foo"

类似地, foo 保存二进制文件,可以像这样$UBIN定义:/home/foo/.profile

export UBIN="${UHOME}"/bin

我们马上就会看到这会给我们带来什么。

在 中/etc/systemd/system.conf,取消注释DefaultEnvironment变量,并在其中声明一个名为$UPROFILEhardcoded 的环境变量来引用 foo 的.profile

DefaultEnvironment="UPROFILE=/home/foo/.profile"

现在,在任何服务的 shell 脚本中,甚至是系统服务中,我们都可以将其放在脚本的顶部:

# Get foo's env vars.
source "${UPROFILE}"

即使以 root 身份运行的系统服务执行此脚本,foo 也.profile将被获取,因此 foo 的环境变量将被加载,甚至与 root 的环境变量一起(假设系统服务使用User=rootGroup=root继承 root 的环境)。因此,在脚本中,$HOME将扩展到 root 的主目录(“/root”),而将扩展到 foo 的主目录(“/home/foo”)。这就是在 foo 中$UHOME命名变量给我们带来的好处;它不会与 root 的环境变量发生冲突!$UHOME.profile$HOME

我们不必担心哪个用户运行该服务或他们的环境变量是什么!foo 的环境变量始终正确,因此我们总能找到 foo 的内容。而且,由于 foo 的环境变量在一个地方(foo 的.profile)定义,因此对它们的更改会自动反映在系统脚本中,因为它们是 foo 的资源.profile——无需维护脚本。

这对于在以 root 身份运行的系统服务脚本中的非 root 用户环境非常有用。

但是,这与您的问题完全无关,您的问题是:

我想知道是否有办法让服务以当前用户身份运行(而不是在服务文件中指定用户),以便 $HOME 对于当前用户来说是正确的,允许我添加任意数量的用户,并且所有用户都可以访问该脚本。

...如果你能摆脱这种情况,并且不介意它有多荒唐,你可以让每个用户在他们的 s 中使用自己的环境变量命名方案.profile,这里的环境包含方法 #3 可以用来为每个用户在启动时做任何你想做的事情。用户启动。

例如,用户 foo 可以$FOOHOME在他们的中定义.profile;用户 bar 可以$BARHOME在他们的中定义.profile;等等。

在中/etc/systemd/system.conf,您可以引用每个用户的.profile

DefaultEnvironment="FOOPROFILE=/home/foo/.profile" "BARPROFILE=/home/bar/.profile"

然后,在 shell 脚本的顶部添加:

# Get all users' env vars.
source "${FOOPROFILE}"
source "${BARPROFILE}"

现在,当用户启动时,系统服务将在用户启动时运行该脚本,$FOOHOME将扩展为“/home/foo”,$BARHOME将扩展为“/home/bar”,依此类推。

但这只是疯狂的思考;听起来你真正想要的是我所说的简短回答部分。

如果您希望某个服务在任何用户启动时运行,并$HOME在服务运行的 shell 脚本中扩展到该用户的主目录,则不必使用DefaultEnvironment。创建一个用户为每个用户提供服务,并让所有用户服务都运行该脚本,该脚本位于他们都可以访问的位置。

相关内容