我试图通过在桌面不活动时将其切换到挂起模式来节省电量。但许多桌面也由其所有者通过 SSH 访问。部署了一个 wakeonlan 解决方案以使所有者能够打开机器,但问题是即使 SSH 连接已打开,机器也会在 10 分钟后再次自动挂起。
我想要做的是将活动的 SSH 会话包含在“活动”定义中。
问题是,可以通过设置 polkit 规则来实现吗?可以通过放置一个在实际暂停之前运行的脚本来实现,如果发现 SSH 会话,则中止该脚本吗?我需要一种干净合法的方式来做到这一点。如果不是这样,那么黑客方法也是受欢迎的。
当前简单的黑客解决方案:编辑/usr/sbin/pm-suspend
:
#check for SSH sessions, and prevent suspending:
if [ "$(who | grep -cv "(:")" -gt 0 ]; then
echo "SSH session(s) are on. Not suspending."
exit 1
fi
这达到了目的。但我不知道更新何时会覆盖文件/usr/sbin/pm-suspend
。我也不知道这将如何与其他暂停实现(如 tuxonice)配合使用。
答案1
直到 Ubuntu 14.10 (基于 Upstart)
看一下pm-action(8)
并在“FILES”部分中搜索/etc/pm/sleep.d
。如果其中一个脚本返回非零退出状态,则会阻止暂停。
更新说明以提高清晰度:
因此创建一个文件
/etc/pm/sleep.d/05_ssh_keepawake
。放一个舍邦(
#!/bin/sh
)以及本文件中问题中提到的代码。为其设置执行权限:
chmod +x /etc/pm/sleep.d/05_ssh_keepawake
从 Ubuntu 15.04 开始(基于 systemd)
systemd不使用pm-实用程序来管理其电源状态挂钩,但有自己的基础设施来实现相同的目的。睡眠抑制器检查器不再在睡眠时执行,但必须设置通过抑制行动睡眠(见1)。
因此,你必须在 SSH 会话登录和注销中添加命令,使用 systemd 注册睡眠抑制器(例如通过systemd-inhibit(1)
) 随后释放了抑制剂。如果有人知道如何挂接 SSH 登录和注销,我欢迎发表评论或进行编辑,以便我们能够制定相关的步骤和命令。
以下部分正在进行中 – 仅当您知道自己在做什么时才使用它!
您可能能够编写一个 systemd 单元/etc/systemd/system/ssh-inhibit-sleep.service
,使其自身成为sleep.target
使用该RequiredBy
选项的依赖项。如果您的新单元失败(其调用的进程的退出状态为非零),它将执行sleep.target
后续的睡眠操作。
[Unit]
Description=Check for running SSH sessions and, if any, inhibit sleep
Before=sleep.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c '! who | grep -qv "\(:0\)"'
[Install]
RequiredBy=sleep.target
与往常一样,您需要激活 systemd 单元才能使它们生效:
sudo systemctl enable ssh-inhibit-sleep.service
欲了解更多信息,请参阅systemd.unit(5)
和systemd.service(5)
。
答案2
结合两个相关答案(这里和这里),这里有一个/etc/pam_session.sh
在 Ubuntu 19.10 上有效的方法(至少):
#!/bin/sh
#
# This script runs when an ssh session opens/closes, and masks/unmasks
# systemd sleep and hibernate targets, respectively.
#
# Inspired by: https://unix.stackexchange.com/a/136552/84197 and
# https://askubuntu.com/a/954943/388360
num_ssh=$(netstat -nt | awk '$4 ~ /:22$/ && $6 == "ESTABLISHED"' | wc -l)
case "$PAM_TYPE" in
open_session)
if [ "${num_ssh}" -gt 1 ]; then
exit
fi
command=mask
;;
close_session)
if [ "${num_ssh}" -ne 0 ]; then
exit
fi
command=unmask
;;
*)
exit
esac
logger "${command}ing sleep and suspend targets (num_ssh=${num_ssh})"
sudo systemctl ${command} sleep.target suspend.target
确保添加以下行:
session optional pam_exec.so quiet /etc/pam_session.sh
添加到/etc/pam.d/sshd
部分中session
,并使/etc/pam_session.sh
脚本可执行:
chmod +x /etc/pam_session.sh
请注意,该/etc/pam_session.sh
脚本似乎在用户登录或注销时运行,因此用户需要sudo
访问 mask/unmask systemd 目标。
答案3
在现代systemd系统,您还可以使用ssh.套接字服务systemd-抑制. 而不是像往常一样ssh 服务独立,你可以让systemd管理传入连接。现在每个打开的会话都由ssh.套接字创建基于以下项的实例单元[电子邮件保护],因此只需创建一个直接绑定到该服务即可。这还有额外的好处,即跟踪和记录每个 ssh 连接systemd。然后我们可以使用此标识符在阻止睡眠时提供更多有用的信息。此方法还可以防止降级systemd与其他一些例子一样,有一个失败的单元。
首先你需要检查以确保启用ssh.套接字如果您尚未使用它。
systemctl is-active ssh.socket
应该说积极的否则您将需要启用它:
sudo systemctl disable ssh
sudo systemctl stop ssh
sudo systemctl enable ssh.socket
sudo systemctl start ssh.socket
然后你只需要创建/etc/systemd/系统/[电子邮件保护]和
[Unit]
Description=ssh no sleep
BindsTo=ssh@%i.service
[Service]
ExecStart=/usr/bin/systemd-inhibit --mode block --what sleep --who "ssh session "%I --why "session still active" /usr/bin/sleep infinity
[Install]
[email protected]
并使用以下命令启用它:
sudo systemctl enable ssh-no-sleep@
为了[电子邮件保护]要触发别名(用 @ 表示),您必须确保您的 ssh.socket 服务具有[插座]环境接受=是,否则 no sleep 服务将永远不会为每个新连接触发。您可以通过运行以下命令来测试 systemd 默认设置:
sudo systemctl show --no-pager --property Accept ssh.socket
如果这返回不,你需要将其覆盖为是的通过创建一个 conf 文件/etc/systemd/system/ssh.socket.d/accept.conf和:
[Socket]
Accept=yes
如果您的系统缺少[电子邮件保护]或者ssh.套接字,下面是来自 Debian Bullseye 的一个示例,您可以参考它:
/etc/systemd/系统/[电子邮件保护]
[Unit]
Description=OpenBSD Secure Shell server per-connection daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=auditd.service
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStart=-/usr/sbin/sshd -i $SSHD_OPTS
StandardInput=socket
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
/etc/systemd/system/ssh.socket
[Unit]
Description=OpenBSD Secure Shell server socket
Before=sockets.target
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Socket]
ListenStream=22
Accept=no
[Install]
WantedBy=sockets.target
保存后,运行systemctl 守护进程重新加载和systemctl 重启 ssh.socket,您可以重新运行之前的 show 命令来确认接受=是
现在,当有人尝试暂停时,他们将收到所有阻塞 ssh 会话的有用消息
sudo systemctl suspend
然后将返回类似以下内容:
Operation inhibited by "ssh session 1/127.0.0.1:22/127.0.0.1:12345" (PID 12345 "systemd-inhibit", user root), reason is "session still active".
Operation inhibited by "ssh session 2/2001:db8:1::1:22/2001:db8:2::1:12345" (PID 54321 "systemd-inhibit", user root), reason is "session still active".
Please retry operation after closing inhibitors and logging out other users.
Alternatively, ignore inhibitors and users with 'systemctl suspend -i'.
额外的好处ssh.套接字您还可以使用:
systemctl status ssh.socket
返回活跃用户和系统统计信息:
* ssh.socket - OpenBSD Secure Shell server socket
Loaded: loaded (/lib/systemd/system/ssh.socket; enabled; vendor preset: enabled)
Active: active (listening) since Mon 2021-12-20 14:46:05 EST; 1h 6min ago
Triggers: * ssh@2-2001:db8:1::1:22-2001:db8:2::1:12345.service
* [email protected]:22-127.0.0.1:12345.service
Listen: [::]:22 (Stream)
Accepted: 2; Connected: 2;
Tasks: 0 (limit: 18775)
Memory: 16.0K
CPU: 2ms
CGroup: /system.slice/ssh.socket
答案4
我自己的解决方案是将以下内容添加到.bashrc
/ .zshrc
/...
if [ "$SSH_CLIENT" ] &&
! pstree -ps $$ |
grep -q -- '-systemd-inhibit(' >/dev/null; then
echo "Inhibit automatic standby"
exec /usr/bin/systemd-inhibit \
--what=idle --why='Interactive SSH Session' -- \
"$SHELL" "$@"
fi
它通过/使用在远程路由/包装 shell 来工作systemd-inhibit
(并且还确保调用链中只有一个systemd-inhibit
,因此在进入子 shell 时不会再次调用它)。
显然,它仅适用于带有 shell 的 SSH 会话。