Ist es möglich, Ubuntu so einzustellen, dass es nicht herunterfährt, bevor ein Skript fertig ist?

15

Ich verwende ein Skript, um inkrementelle Sicherungen einer btrfs-Partition von einer Festplatte auf eine andere zu erstellen.

Das Skript wird von cron.weekly zu einer beliebigen Tageszeit gestartet.

Wenn ich das System herunterfahre, während das Skript ausgeführt wird, treten Probleme auf, da alte Sicherungen entfernt und neue nicht erstellt wurden.

Gibt es eine Möglichkeit, das System so einzurichten, dass es wartet, bis das Skript beendet ist?

Ich benutze Ubuntu 16.04 mit systemd.

Pilot6
quelle
Es gibt eine Möglichkeit, GUI-Befehle zu blockieren. Dafür habe ich einen Scripting-Ansatz. Die Befehlszeile kann jedoch nicht blockiert werden, wenn dies vom sudo Benutzer vorgenommen wird. Ich werde eine frühere Antwort für GUI verknüpfen. Lassen Sie mich wissen, wenn Sie es an Ihre Bedürfnisse anpassen möchten
Sergiy Kolodyazhnyy
1
@ByteCommander Vorsicht: Diese sind vorinstalliert.
Rinzwind
1
@Serg schöner :) Aber ist das nicht systemd-inhibitein bisschen einfacher für die Augen? >: - D
Rinzwind
1
Was passiert, wenn das Skript abstürzt? Wäre es nicht besser, Ihre alten Backups nicht zu entfernen, bis die neuen sowieso fertig sind? Während Sie möglicherweise das Herunterfahren verhindern können, können Sie einen Systemausfall oder einen allgemeinen Stromausfall nicht verhindern. In beiden Fällen bleibt das alte Backup gelöscht und das neue nicht erstellt.
Joe W

Antworten:

20

Für Ubuntu 16.04+ mit systemd (Standardeinstellung).

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

===

Prüfung:

$ 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.

===

Es gibt 7 Schlösser :

  • sleep Verhindert das Anhalten des Systems und den Ruhezustand, die von (nicht privilegierten) Benutzern angefordert werden
  • shutdown Verhindert das Ausschalten und Neustarten des Systems auf hoher Ebene, das von (nicht privilegierten) Benutzern angefordert wird
  • idle verhindert, dass das System in den Leerlaufmodus wechselt, was je nach Konfiguration möglicherweise zu einem automatischen Anhalten oder Herunterfahren des Systems führt.
  • handle-power-key Verhindert die einfache (dh logind-interne) Behandlung des System-Power-Hardware-Schlüssels, sodass (möglicherweise nicht privilegierter) externer Code stattdessen das Ereignis behandeln kann.
  • handle-suspend-key sperrt die Low-Level-Behandlung des System-Hardware-Suspend-Schlüssels.
  • handle-hibernate-key sperrt die Low-Level-Behandlung des Systemhardware-Ruhezustandsschlüssels.
  • handle-lid-switch sperrt den Low-Level-Umgang mit dem System-Hardware-Deckelschalter.

Sie möchten wahrscheinlich auch verhindern suspend, idleund hibernate.


Beispiel mit "Paketmanager" :

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

Ähnlich können Sie Ihre Version codieren und am Ende dieses Skripts ein "Herunterfahren" hinzufügen (oder eine Möglichkeit hinzufügen, um zu bestimmen, dass das Herunterfahren die nächste Aktion sein muss).

Rinzwind
quelle
Kommentare sind nicht für längere Diskussionen gedacht. Das Gespräch, das hier stattfand, wurde in den Chat verschoben .
Thomas Ward
2

In BackInTime verwende ich verschiedene DBus-Methoden, um an allen wichtigen DEs zu arbeiten. Einziger Wermutstropfen ist, dass dies nicht funktioniert, rootda rootes keine gibt 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)
Germar
quelle