#!/usr/bin/python3

# Copyright © 2024, Oracle and/or its affiliates.  All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/

import fcntl
import json
import os
import re
import subprocess
import sys
import time

if os.path.exists('/etc/oci-fss-utils.d/prefix.txt') is False:
    sys.exit(0)

with open('/etc/oci-fss-utils.d/prefix.txt') as fp:
    PREFIX = fp.readline().strip()

if re.match("^[a-zA-Z0-9:]+::/64$", PREFIX):
    PROTOCOL = "ipv6"
elif re.match("^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.0/24$", PREFIX):
    PROTOCOL = "ipv4"
else:
    raise Exception("Invalid prefix in /etc/oci-fss-utils.d/prefix.txt.")

if PROTOCOL == "ipv6":
    PREFIX = PREFIX.replace("::/64", "")
    MOUNT_PATTERN = "^\[%s::([0-9a-z]{1,4})\]" % PREFIX
elif PROTOCOL == "ipv4":
    PREFIX = PREFIX.replace(".0/24", "")
    MOUNT_PATTERN = "^%s.([0-9]{1,3})" % PREFIX
else:
    raise Exception("Invalid prefix in /etc/oci-fss-utils.d/prefix.txt.")

MOUNT_PATTERN_LEGACY = "^192\.168\.([0-9]+)\.2:/"

class MountLock:
    def __init__(self):
        self.fd = open("/tmp/oci-fss-mount.lck", "w+")

    def acquire(self):
        fcntl.flock(self.fd, fcntl.LOCK_EX)

def run_cmd(cmd):
    print(cmd)
    return subprocess.run(cmd.split(' '))

def dump_mounts():
    mounts = []
    mounts_legacy = []

    with open("/proc/mounts") as rf:
        for line in rf:
            words = line.strip().split(" ")
            m = re.match(MOUNT_PATTERN, words[0])
            if m and PROTOCOL == "ipv6":
                mounts.append(int(m.group(1), 16))
            if m and PROTOCOL == "ipv4":
                mounts.append(int(m.group(1)))
            m = re.match(MOUNT_PATTERN_LEGACY, words[0])
            if m:
                mounts_legacy.append(int(m.group(1)))
    return mounts, mounts_legacy

if __name__ == "__main__":
    lck = MountLock()
    lck.acquire()

    now = time.time()
    mounts, mounts_legacy = dump_mounts()
    gc_count = 0
    live_count = 0

    # Mount targets follow this scheme: oci-fss-{i:04}
    for i in range(1, 255):
        service = f"/etc/systemd/system/oci-fss-{i:04}.service"
        if os.path.isfile(service):
            associated = mounts.count(i)
            if associated > 0:
                print(f"oci-fss-{i:04} has {associated} associated mount...")
                live_count += 1
            else:
                run_cmd(f"/usr/bin/systemctl stop oci-fss-{i:04}")
                os.unlink(service)

                with open(f"/tmp/oci-fss-utils.d/slot-{i}.txt", "r") as slotfp:
                    mt = slotfp.readlines()[0].strip()
                    with open(f"/tmp/oci-fss-utils.d/mt-{mt}.txt", "r") as mtfp:
                        addr = mtfp.readlines()[0].strip()
                        os.unlink(f"/tmp/oci-fss-utils.d/addr-{addr}.txt")
                    os.unlink(f"/tmp/oci-fss-utils.d/mt-{mt}.txt")
                os.unlink(f"/tmp/oci-fss-utils.d/slot-{i}.txt")

                print(f"removed oci-fss-{i:04}...")
                gc_count += 1

    # Legacy mount targets follow this scheme: oci-fss-{i}
    for i in range(1, 255):
        legacy_service_path = f"/etc/systemd/system/oci-fss-{i}.service"
        ng_service_path = f"/usr/lib/systemd/system/oci-fss-{i}.service"

        for service in (legacy_service_path, ng_service_path):
            if os.path.isfile(service):
                associated = mounts_legacy.count(i)
                if associated > 0:
                    print(f"oci-fss-{i} has {associated} associated mount...")
                    live_count += 1
                else:
                    run_cmd(f"/usr/bin/systemctl stop oci-fss-{i}")
                    os.unlink(service)
                    print(f"removed oci-fss-{i}..")
                    gc_count += 1

    if gc_count > 0:
        run_cmd("/usr/bin/systemctl daemon-reload")

    print(f"live count: {live_count}")
