是否可以将Ubuntu设置为在脚本完成之前不关闭的方式?


15

我使用脚本来将btrfs分区从一个磁盘增量备份到另一个磁盘。

该脚本由cron.weekly在每天的随机时间启动。

如果我在脚本运行时关闭了系统,则将遇到麻烦,即删除旧备份而未创建新备份。

有没有一种方法可以将系统设置为等待脚本完成?

我正在将Ubuntu 16.04与systemd一起使用。


有一种方法可以阻止GUI命令。我有一个脚本方法。但是如果由sudo 用户执行,则命令行无法阻塞。我将链接GUI的过去答案。让我知道是否要根据您的需求对其进行定制
Sergiy Kolodyazhnyy


1
@ByteCommander小心:这些是预先系统化的。
Rinzwind '16

1
@Serg不错的一个:)但是systemd-inhibit,在眼睛上难道不是很轻松吗?>:-D
Rinzwind '16

1
如果脚本锁定,会发生什么?在新备份完成之前不删除旧备份会更好吗?虽然您可以防止关机,但无法防止系统故障或一般掉电的情况。无论哪种情况,您都将旧备份删除而未创建新备份。
乔W

Answers:


20

对于使用systemd的Ubuntu 16.04+(默认)。

systemd-inhibit --why="Wait for this script to finish" bash script.sh

===

测试:

$ systemctl poweroff
Operation inhibited by "bash script.sh" (PID 23912 "systemd-inhibit", user rinzwind),
reason is "Wait for this script to finish".
Please retry operation after closing inhibitors and logging out other users.

===

有7把锁

  • sleep 禁止(非特权)用户请求系统挂起和休眠
  • shutdown 禁止(非特权)用户请求高级系统关机和重新引导
  • idle 禁止系统进入空闲模式,这可能导致系统根据配置自动挂起或关闭。
  • handle-power-key 禁止对系统电源硬件密钥进行低级(即内部登录)处理,从而允许(可能没有特权)外部代码来处理事件。
  • handle-suspend-key 禁止对系统硬件挂起键进行低级处理。
  • handle-hibernate-key 禁止对系统硬件休眠密钥进行低级处理。
  • handle-lid-switch 禁止对系统硬件盖开关进行低级处理。

你可能也想阻止suspendidlehibernate


使用“包管理器”的示例

fd = Inhibit("shutdown:idle", "Package Manager", "Upgrade in progress...", "block");
/* ...
      do your work
                 ... */
close(fd);

与此类似,您可以对版本进行编码,并在此脚本的末尾添加“ shutdown”(或添加一种方法来确定需要执行下一步操作的shutdown)。


评论不作进一步讨论;在这里进行的对话已转移到聊天中
托马斯·沃德

2

BackInTime中,我使用了几种不同的DBus方法来处理所有主要的DE。唯一的缺点是,root因为root没有,这是行不通的dbus.SessionBus

#!/usr/bin/env python3
import sys
import dbus
from time import sleep

INHIBIT_LOGGING_OUT = 1
INHIBIT_USER_SWITCHING = 2
INHIBIT_SUSPENDING = 4
INHIBIT_IDLE = 8

INHIBIT_DBUS = (
               {'service':      'org.gnome.SessionManager',
                'objectPath':   '/org/gnome/SessionManager',
                'methodSet':    'Inhibit',
                'methodUnSet':  'Uninhibit',
                'interface':    'org.gnome.SessionManager',
                'arguments':    (0, 1, 2, 3)
               },
               {'service':      'org.mate.SessionManager',
                'objectPath':   '/org/mate/SessionManager',
                'methodSet':    'Inhibit',
                'methodUnSet':  'Uninhibit',
                'interface':    'org.mate.SessionManager',
                'arguments':    (0, 1, 2, 3)
               },
               {'service':      'org.freedesktop.PowerManagement',
                'objectPath':   '/org/freedesktop/PowerManagement/Inhibit',
                'methodSet':    'Inhibit',
                'methodUnSet':  'UnInhibit',
                'interface':    'org.freedesktop.PowerManagement.Inhibit',
                'arguments':    (0, 2)
               })

def inhibitSuspend(app_id = sys.argv[0],
                    toplevel_xid = None,
                    reason = 'take snapshot',
                    flags = INHIBIT_SUSPENDING | INHIBIT_IDLE):
    """
    Prevent machine to go to suspend or hibernate.
    Returns the inhibit cookie which is used to end the inhibitor.
    """
    if not app_id:
        app_id = 'backintime'
    if not toplevel_xid:
        toplevel_xid = 0

    for dbus_props in INHIBIT_DBUS:
        try:
            bus = dbus.SessionBus()
            interface = bus.get_object(dbus_props['service'], dbus_props['objectPath'])
            proxy = interface.get_dbus_method(dbus_props['methodSet'], dbus_props['interface'])
            cookie = proxy(*[(app_id, dbus.UInt32(toplevel_xid), reason, dbus.UInt32(flags))[i] for i in dbus_props['arguments']])
            print('Inhibit Suspend started. Reason: %s' % reason)
            return (cookie, bus, dbus_props)
        except dbus.exceptions.DBusException:
            pass
    print('Inhibit Suspend failed.')

def unInhibitSuspend(cookie, bus, dbus_props):
    """
    Release inhibit.
    """
    assert isinstance(cookie, int), 'cookie is not int type: %s' % cookie
    assert isinstance(bus, dbus.bus.BusConnection), 'bus is not dbus.bus.BusConnection type: %s' % bus
    assert isinstance(dbus_props, dict), 'dbus_props is not dict type: %s' % dbus_props
    try:
        interface = bus.get_object(dbus_props['service'], dbus_props['objectPath'])
        proxy = interface.get_dbus_method(dbus_props['methodUnSet'], dbus_props['interface'])
        proxy(cookie)
        print('Release inhibit Suspend')
        return None
    except dbus.exceptions.DBusException:
        print('Release inhibit Suspend failed.')
        return (cookie, bus, dbus_props)

if __name__ == '__main__':
    cookie, bus, dbus_props = inhibitSuspend()
    print('do something here')
    sleep(10)
    unInhibitSuspend(cookie, bus, dbus_props)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.