Est-il possible de définir Ubuntu de manière à ce qu'il ne s'arrête pas avant la fin d'un script?

15

J'utilise un script pour faire des sauvegardes incrémentielles d'une partition btrfs d'un disque à un autre.

Le script est lancé par cron.weekly à une heure aléatoire d'une journée.

Si j'arrête le système pendant l'exécution du script, je rencontre des problèmes avec les anciennes sauvegardes supprimées et les nouvelles non créées.

Existe-t-il un moyen de configurer le système pour attendre la fin du script?

J'utilise Ubuntu 16.04 avec systemd.

Pilot6
la source
Il existe un moyen de bloquer les commandes GUI. J'ai une approche de script pour cela. Mais la ligne de commande n'est pas possible de bloquer si elle est effectuée par l' sudo utilisateur. Je lierai une réponse antérieure à l'interface graphique. Faites-moi savoir si vous souhaitez qu'il soit personnalisé en fonction de vos besoins
Sergiy Kolodyazhnyy
1
@ByteCommander attention: ce sont pré-systemd.
Rinzwind
1
@Serg nice one :) Mais n'est-ce pas systemd-inhibitun peu plus agréable pour les yeux? >: - D
Rinzwind
1
Que se passe-t-il si le script se bloque? Ne serait-il pas préférable de ne pas supprimer vos anciennes sauvegardes avant la fin des nouvelles? Bien que vous puissiez empêcher l'arrêt, vous ne pouvez pas empêcher une situation où il y a une panne du système ou une perte d'alimentation générale. Dans les deux cas, vous vous retrouvez toujours avec votre ancienne sauvegarde supprimée et la nouvelle non créée.
Joe W

Réponses:

20

Pour Ubuntu 16.04+ utilisant systemd (par défaut).

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

===

Tester:

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

===

Il y a 7 serrures :

  • sleep inhibe la suspension et l'hibernation du système demandées par les utilisateurs (non privilégiés)
  • shutdown inhibe la mise hors tension et le redémarrage du système de haut niveau demandés par les utilisateurs (non privilégiés)
  • idle empêche que le système passe en mode veille, ce qui peut entraîner une suspension ou un arrêt automatique du système en fonction de la configuration.
  • handle-power-key inhibe la gestion de bas niveau (c'est-à-dire interne à la connexion) de la clé matérielle d'alimentation du système, permettant à un code externe (éventuellement non privilégié) de gérer l'événement à la place.
  • handle-suspend-key empêche la gestion de bas niveau de la clé de suspension matérielle du système.
  • handle-hibernate-key empêche la gestion de bas niveau de la clé de mise en veille prolongée du matériel du système.
  • handle-lid-switch empêche la manipulation de bas niveau du commutateur de capot matériel systemd.

Vous voulez probablement aussi prévenir suspend, idleet hibernate.


Exemple d'utilisation du "gestionnaire de packages" :

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

Semblable à cela, vous pouvez coder votre version et ajouter un «arrêt» à la fin de ce script (ou ajouter un moyen de déterminer qu'un arrêt doit être la prochaine action).

Rinzwind
la source
Les commentaires ne sont pas pour une discussion approfondie; la conversation qui se déroulait ici a été déplacée vers le chat .
Thomas Ward
2

Dans BackInTime, j'utilise plusieurs méthodes DBus différentes pour travailler sur tous les principaux DE. Le seul inconvénient est que cela ne fonctionnera pas rootcar rootil n'y en a pas 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
la source