#!/usr/bin/python3

# Copyright (c) 2026, Oracle and/or its affiliates.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code 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
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, see <https://www.gnu.org/licenses/>.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.


# this is the command tool to communiate with kmon service to list/start/stop kernel monitors.

"""
kmonadm

A command-line client for the kmon service.

What it does:
  - Connects to the kmon daemon via a Unix domain socket.
  - Sends a command (and optional parameter) to list/start/stop kernel monitors.
  - Prints the daemon response and exits with the daemon-provided status code.

Communication:
  - Socket type: AF_UNIX stream socket
  - Request format (plain text):
        COMMAND=<subcommand>
        PARAM=<value>     (optional)
  - Response format:
        "<code>!!!<message>"
    where <code> is an integer exit code and <message> is human-readable output.

Operational requirements:
  - Must be run as root
  - The kmon systemd service must be active.
  - The socket path must exist (created/owned by the running kmon service).
"""

import sys
import os
import socket
import subprocess
import fcntl

CMD_NAME = "kmonadm"

# Unix domain socket path used by the kmon service
SOCKET_PATH = "/var/run/oled/kmon/kmon_socket"

# Supported subcommands accepted by this client and the daemon
valid_commands = ["list", "start", "stop", "stop_service"]

# kmon_server holds a lock on this file for its entire lifetime.
LOCK_FILE = "/var/run/oled/kmon/.kmon_lock"

def is_server_active() -> bool:
    """
    Check if kmon_server is running.

    kmon_server holds a lock on LOCK_FILE for its entire lifetime.
    If the file is not locked, kmon_server is not running.
    This function attempts to acquire the lock; if it succeeds, we know that
    kmon_server is not running.

    The opened file pointer and lock are automatically released when this
    function returns.

    Returns:
        True if kmon_server is running, otherwise False.
    """
    fp = open(LOCK_FILE, 'w', encoding="utf-8")
    try:
        fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
        return False # Lock acquired, kmon_server is NOT running
    except IOError:
        return  True # Lock failed, kmon_server IS running

# Maximum bytes to read from daemon response in one recv()
RECEIVE_SIZE = 1024 * 100

def command(cmd_in:str, param_in:str):
    """
    Send a command to the kmon service and print the response.

    Args:
      cmd_in:  Subcommand to execute (e.g., 'list', 'start', 'stop', 'stop_service')
      param_in: Optional parameter (e.g., monitor name for start/stop)

    Exits:
      - Exits with the status code returned by the service.
    """

    # Ensure the kmon service is active before attempting socket communication
    if not is_server_active():
        sys.stderr.write("kmon service is not running, please start it and try again\n")
        sys.exit(1)

    # Connect to kmon service over the Unix domain socket
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.connect(SOCKET_PATH)

    msg = f"COMMAND={cmd_in}"
    if param is not None:
        msg = msg + f"\nPARAM={param_in}"
    sock.send(msg.encode())
    backmsg = sock.recv(RECEIVE_SIZE).decode()
    sock.close()
    lines = backmsg.split("!!!")
    code = int(lines[0])
    msg = lines[1]
    print(msg)
    sys.exit(code)

HELP_MSG = f'''{CMD_NAME} communicates with kmon service to list, start or stop kernel monitors.

Valid subcommands:
    {CMD_NAME} list             -- list the status of all kernel monitors
    {CMD_NAME} start <kmon>     -- start the specified kernel monitor
    {CMD_NAME} stop <kmon>      -- stop the specified kernel monitor
'''
def my_help():
    """print help message and exit"""
    sys.stderr.write(HELP_MSG)
    sys.exit(1)

if os.geteuid() != 0:
    print("Please run kmonadm as root!")
    sys.exit(1)

if len(sys.argv) < 2:
    my_help()

cmd = sys.argv[1]
if not cmd in valid_commands:
    sys.stderr.write(f"Invalid command: {cmd}\n")
    my_help()

param = None
if len(sys.argv) >= 3:
    param = sys.argv[2]

command(cmd, param)
