#!/usr/bin/python3
# This file is part of LTSP, https://ltsp.org
# Copyright 2019 the LTSP team, see AUTHORS
# SPDX-License-Identifier: GPL-3.0-or-later
"""
Usage: lockf <file> [message]

Try to lock <file>.
If it's locked by another process, display <message> in stderr and wait
until it's free. If the user interrupts the wait, return False.
When locking succeeds, unlock and spawn a child process that will immediately
re-acquire the lock and sleep until it's sent a TERM signal.
Then echo the pid of that child process to stdout and exit.
"""
import fcntl
import os
import subprocess
import sys
import time

def main(argv):
    """Run from the command line"""

    if len(argv) <= 1:
        print(__doc__)
        sys.exit(1)
    fname = argv[1]
    if len(argv) > 2:
        message = argv[2]
    else:
        message = (
            "A package management process is running, waiting for it"
            " to finish...\n"
            "Press Ctrl+C to abort")
    # The child is spawned with this undocumented parameter
    if message == " ":
        with open(fname, "w") as file:
            # There's a slight race condition here; if it wasn't locked for
            # the parent and is now locked for the child, the child will
            # wait without the parent having displayed the message
            fcntl.lockf(file, fcntl.LOCK_EX)
            while True:
                time.sleep(1000)
    with open(fname, "w") as file:
        try:
            fcntl.lockf(file, fcntl.LOCK_EX | fcntl.LOCK_NB)
        except OSError:
            print(message, file=sys.stderr)
        try:
            fcntl.lockf(file, fcntl.LOCK_EX)
        except KeyboardInterrupt:
            sys.exit(1)
        print(subprocess.Popen([argv[0], argv[1], " "],
            stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).pid)


if __name__ == "__main__":
    main(sys.argv)
