Apakah mungkin untuk mengatur Ubuntu agar tidak dimatikan sebelum skrip selesai?

15

Saya menggunakan skrip untuk melakukan backup incremental dari partisi btrfs dari satu disk ke yang lain.

Script dimulai oleh cron. Setiap minggu secara acak dalam sehari.

Jika saya mematikan sistem saat skrip sedang berjalan, saya mendapat masalah dengan backup lama dihapus dan baru tidak dibuat.

Apakah ada cara untuk mengatur sistem untuk menunggu sampai skrip selesai?

Saya menggunakan Ubuntu 16.04 dengan systemd.

Pilot6
sumber
Ada cara untuk memblokir perintah GUI. Saya sudah pendekatan scripting untuk itu. Tetapi baris perintah tidak mungkin diblokir jika dilakukan oleh sudo pengguna. Saya akan menautkan jawaban masa lalu untuk GUI. Beri tahu saya jika Anda menginginkannya agar disesuaikan dengan kebutuhan Anda
Sergiy Kolodyazhnyy
1
@ByteCommander hati-hati: itu adalah pre-systemd.
Rinzwind
1
@Serg bagus sekali :) Tapi bukankah systemd-inhibitsedikit lebih mudah di mata? >: - D
Rinzwind
1
Apa yang terjadi jika skrip terkunci? Bukankah lebih baik tidak menghapus cadangan lama Anda sampai yang baru selesai? Meskipun Anda mungkin dapat mencegah shutdown, Anda tidak dapat mencegah situasi di mana ada kegagalan sistem atau kehilangan daya secara umum. Dalam kedua kasus Anda masih tertinggal dengan cadangan lama Anda dihapus dan yang baru tidak dibuat.
Joe W

Jawaban:

20

Untuk Ubuntu 16.04+ menggunakan systemd (default).

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

===

Uji:

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

===

Ada 7 kunci :

  • sleep menghambat penangguhan sistem dan hibernasi yang diminta oleh pengguna (yang tidak berhak)
  • shutdown menghambat pematian daya sistem tingkat tinggi dan reboot yang diminta oleh pengguna (yang tidak berhak)
  • idle menghambat bahwa sistem beralih ke mode siaga, mungkin mengakibatkan penangguhan atau shutdown sistem otomatis tergantung pada konfigurasi.
  • handle-power-key menghambat penanganan level rendah (mis. logind-internal) dari kunci perangkat keras daya sistem, sehingga memungkinkan kode eksternal (mungkin tidak terjangkau) untuk menangani peristiwa tersebut.
  • handle-suspend-key menghambat penanganan level rendah dari kunci penangguhan perangkat keras sistem.
  • handle-hibernate-key menghambat penanganan tingkat rendah dari tombol hibernate perangkat keras sistem.
  • handle-lid-switch menghambat penanganan sakelar tutup perangkat keras systemd tingkat rendah.

Anda mungkin juga ingin mencegah suspend, idledan hibernate.


Contoh menggunakan "manajer paket" :

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

Mirip dengan ini, Anda dapat mengkodekan versi Anda dan menambahkan "shutdown" di akhir skrip ini (atau menambahkan cara untuk menentukan shutdown yang perlu menjadi tindakan selanjutnya).

Rinzwind
sumber
Komentar bukan untuk diskusi panjang; percakapan yang terjadi di sini telah dipindahkan ke obrolan .
Thomas Ward
2

Dalam BackInTime saya menggunakan beberapa metode DBus berbeda untuk bekerja pada semua DEs utama. Satunya downside adalah ini tidak akan berhasil rootkarena roottidak memiliki 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
sumber