Czy można ustawić Ubuntu tak, aby nie wyłączał się przed zakończeniem skryptu?

15

Używam skryptu do tworzenia przyrostowych kopii zapasowych partycji btrfs z jednego dysku na drugi.

Skrypt jest uruchamiany przez cron.weekly o losowej porze dnia.

Jeśli zamknę system podczas działania skryptu, mam problem ze starymi kopiami zapasowymi usuniętymi i nowymi, które nie zostały utworzone.

Czy istnieje sposób na skonfigurowanie systemu tak, aby czekał na zakończenie skryptu?

Używam Ubuntu 16.04 z systemd.

Pilot 6
źródło
Istnieje sposób na blokowanie poleceń GUI. Mam do tego podejście skryptowe. Ale nie można zablokować wiersza poleceń, jeśli jest wykonywany przez sudo użytkownika. Łączę przeszłą odpowiedź dla GUI. Daj mi znać, jeśli chcesz dostosować go do swoich potrzeb
Sergiy Kolodyazhnyy
1
@ByteCommander ostrożnie: są wstępnie skonfigurowane.
Rinzwind
1
@Serg fajny :) Ale czy to nie systemd-inhibitjest trochę łatwiejsze dla oczu? >: - D
Rinzwind
1
Co się stanie, jeśli skrypt się zablokuje? Czy nie lepiej byłoby nie usuwać starych kopii zapasowych, dopóki nowe nie zostaną ukończone? Chociaż można zapobiec wyłączeniu, nie można zapobiec sytuacji, w której wystąpiła awaria systemu lub ogólna utrata zasilania. W obu przypadkach nadal pozostaje usunięta stara kopia zapasowa, a nowa nie została utworzona.
Joe W

Odpowiedzi:

20

W systemie Ubuntu 16.04+ korzystającym z systemd (domyślnie).

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

===

Test:

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

===

Istnieje 7 zamków :

  • sleep hamuje zawieszanie systemu i hibernację wymagane przez (nieuprzywilejowanych) użytkowników
  • shutdown hamuje wyłączenie systemu wysokiego poziomu i ponowne uruchomienie wymagane przez (nieuprzywilejowanych) użytkowników
  • idle hamuje przejście systemu w tryb bezczynności, co może spowodować automatyczne zawieszenie lub wyłączenie systemu w zależności od konfiguracji.
  • handle-power-key hamuje obsługę niskiego poziomu (tj. logind-wewnętrzny) klucza sprzętowego zasilania systemu, umożliwiając (prawdopodobnie nieuprzywilejowany) zewnętrzny kod do obsługi zdarzenia.
  • handle-suspend-key hamuje obsługę niskiego poziomu klucza zawieszenia sprzętowego systemu.
  • handle-hibernate-key hamuje obsługę niskiego poziomu klucza hibernacji sprzętowej systemu.
  • handle-lid-switch hamuje obsługę niskiego poziomu systemowego przełącznika pokrywy urządzenia.

Prawdopodobnie chcesz również zapobiec suspend, idlei hibernate.


Przykład użycia „menedżera pakietów” :

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

Podobnie do tego możesz zakodować swoją wersję i dodać „zamknięcie” na końcu tego skryptu (lub dodać sposób, aby ustalić, że zamknięcie musi być następną czynnością).

Rinzwind
źródło
Komentarze nie są przeznaczone do rozszerzonej dyskusji; rozmowa, która się tutaj odbywa, została przeniesiona na czat .
Thomas Ward
2

W BackInTime używam kilku różnych metod DBus do pracy na wszystkich głównych DE. Jedynym minusem jest to, że to nie zadziała, rootponieważ rootnie ma 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
źródło