È possibile impostare Ubuntu in modo che non si spenga prima che uno script sia finito?


15

Uso uno script per eseguire backup incrementali di una partizione btrfs da un disco a un altro.

Lo script viene avviato da cron.weekly all'ora casuale di un giorno.

Se chiudo il sistema mentre lo script è in esecuzione, mi trovo nei guai con i vecchi backup rimossi e nuovi non creati.

C'è un modo per configurare il sistema in modo che attenda il completamento dello script?

Sto usando Ubuntu 16.04 con systemd.


C'è un modo per bloccare i comandi della GUI. Ho un approccio di scripting per questo. Ma la riga di comando non è possibile bloccare se eseguita sudo dall'utente. Collegherò una risposta passata per la GUI. Fammi sapere se lo desideri personalizzato per soddisfare le tue esigenze
Sergiy Kolodyazhnyy


1
@ByteCommander attento: quelli sono pre-sistemati.
Rinzwind,

1
@Serg bello :) Ma non è systemd-inhibitun po 'più facile per gli occhi? >: - D
Rinzwind,

1
Cosa succede se lo script si blocca? Non sarebbe meglio non rimuovere i tuoi vecchi backup fino a quando quelli nuovi non sono finiti comunque? Sebbene sia possibile impedire l'arresto, non è possibile impedire una situazione in cui si verifica un errore del sistema o un'interruzione dell'alimentazione generale. In entrambi i casi, il backup precedente viene comunque eliminato e quello nuovo non creato.
Joe W,

Risposte:


20

Per Ubuntu 16.04+ usando systemd (impostazione predefinita).

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.

===

Ci sono 7 blocchi :

  • sleep inibisce la sospensione e l'ibernazione del sistema richieste dagli utenti (non privilegiati)
  • shutdown inibisce lo spegnimento e il riavvio del sistema di alto livello richiesti dagli utenti (senza privilegi)
  • idle impedisce che il sistema vada in modalità di inattività, con conseguente possibile sospensione o arresto automatico del sistema a seconda della configurazione.
  • handle-power-key inibisce la gestione di basso livello (cioè logind-internal) della chiave hardware di alimentazione del sistema, consentendo invece al codice esterno (possibilmente non privilegiato) di gestire l'evento.
  • handle-suspend-key inibisce la gestione a basso livello della chiave di sospensione hardware del sistema.
  • handle-hibernate-key inibisce la gestione a basso livello della chiave di sospensione hardware del sistema.
  • handle-lid-switch inibisce la gestione a basso livello dell'interruttore del coperchio hardware del sistema.

Probabilmente vuoi anche prevenire suspend, idlee hibernate.


Esempio usando "gestore pacchetti" :

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

Allo stesso modo puoi codificare la tua versione e aggiungere un "arresto" alla fine di questo script (o aggiungere un modo per determinare un arresto deve essere l'azione successiva).


I commenti non sono per una discussione estesa; la conversazione che si stava svolgendo qui è stata spostata in chat .
Thomas Ward

2

In BackInTime sto usando due diversi metodi DBus per lavorare su tutti i principali DE. L'unico aspetto negativo è che questo non funzionerà rootperché rootnon ha 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.