É possível configurar o Ubuntu de forma que ele não seja encerrado antes de um script ser concluído?

16

Eu uso um script para fazer backups incrementais de uma partição btrfs de um disco para outro.

O script é iniciado cron.weekly aleatoriamente em um dia.

Se eu desligar o sistema enquanto o script estiver em execução, estou tendo problemas com backups antigos removidos e novos não criados.

Existe uma maneira de configurar o sistema para aguardar até o script terminar?

Estou usando o Ubuntu 16.04 com o systemd.

    
por Pilot6 22.07.2016 / 11:19

2 respostas

20

Para o Ubuntu 16.04+ usando o systemd (o padrão).

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

===

Teste:

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

===

Existem 7 bloqueios :

  • sleep inibe a suspensão do sistema e a hibernação solicitada por usuários (não privilegiados)
  • shutdown inibe o desligamento do sistema de alto nível e a reinicialização solicitada por usuários (não privilegiados)
  • idle inibe que o sistema entre no modo ocioso, possivelmente resultando na suspensão ou desligamento automático do sistema, dependendo da configuração.
  • handle-power-key inibe o tratamento de baixo nível (ou seja, o login interno) da chave de hardware de energia do sistema, permitindo que o código externo (possivelmente sem privilégios) manipule o evento.
  • handle-suspend-key inibe a manipulação de baixo nível da chave de suspensão de hardware do sistema.
  • handle-hibernate-key inibe a manipulação de baixo nível da chave de hibernação do hardware do sistema.
  • handle-lid-switch inibe o manuseio de baixo nível do switch da tampa do hardware do systemd.

Você provavelmente também deseja evitar suspend , idle e hibernate .

Exemplo de uso de "gerenciador de pacotes" :

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

Similar a isso, você pode codificar sua versão e adicionar um "desligamento" no final deste script (ou adicionar uma maneira de determinar se um desligamento precisa ser a próxima ação).

    
por Rinzwind 22.07.2016 / 11:36
2

Em BackInTime estou usando alguns métodos DBus diferentes para trabalhar em todos os principais DEs. A única desvantagem é que isso não funcionará para root porque root não tem 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)
    
por Germar 27.07.2016 / 02:20