summaryrefslogtreecommitdiff
path: root/src/system/uacctd_stop.py
blob: 7fbac056619b7083cd5c2fa282065e288cdd0e0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/env python3
#
# Copyright (C) 2023 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# Control pmacct daemons in a tricky way.
# Pmacct has signal processing in a main loop, together with packet
# processing. Because of this, while it is waiting for packets, it cannot
# handle the control signal. We need to start the systemctl command and then
# send some packets to pmacct to wake it up

from argparse import ArgumentParser
from socket import socket
from sys import exit
from time import sleep

from psutil import Process


def stop_process(pid: int, timeout: int) -> None:
    """Send a signal to uacctd
    and then send packets to special address predefined in a firewall
    to unlock main loop in uacctd and finish the process properly

    Args:
        pid (int): uacctd PID
        timeout (int): seconds to wait for a process end
    """
    # find a process
    uacctd = Process(pid)
    uacctd.terminate()

    # create a socket
    trigger = socket()

    first_cycle: bool = True
    while uacctd.is_running() and timeout:
        trigger.sendto(b'WAKEUP', ('127.0.254.0', 0))
        # do not sleep during first attempt
        if not first_cycle:
            sleep(1)
            timeout -= 1
        first_cycle = False


if __name__ == '__main__':
    parser = ArgumentParser()
    parser.add_argument('process_id',
                        type=int,
                        help='PID file of uacctd core process')
    parser.add_argument('timeout',
                        type=int,
                        help='time to wait for process end')
    args = parser.parse_args()
    stop_process(args.process_id, args.timeout)
    exit()