// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef NETLINK_CLIENT_H
#define NETLINK_CLIENT_H

#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Netlink family and multicast group names */
#define DEEPIN_ERR_NOTIFY_FAMILY_NAME "DEEPIN_ENOTIFY"
#define MULTICAST_GROUP_ERR_EVENTS "err_events"

/* Commands - must match kernel module */
enum {
    DEEPIN_ERR_NOTIFY_CMD_UNSPEC,
    DEEPIN_ERR_NOTIFY_CMD_ERR_ROFS = 1,
    DEEPIN_ERR_NOTIFY_CMD_ENABLE = 2,
    DEEPIN_ERR_NOTIFY_CMD_DISABLE = 3,
    DEEPIN_ERR_NOTIFY_CMD_GET_STATUS = 4,
    __DEEPIN_ERR_NOTIFY_CMD_MAX,
};

/* Netlink attributes */
enum {
    DEEPIN_ERR_NOTIFY_ATTR_UNSPEC,
    DEEPIN_ERR_NOTIFY_ATTR_FILENAME = 1,     /* Filename (string) */
    DEEPIN_ERR_NOTIFY_ATTR_INODE = 2,        /* Inode (u64) */
    DEEPIN_ERR_NOTIFY_ATTR_INODE_PARENT = 3, /* Bool: inode from parent (u8) */
    DEEPIN_ERR_NOTIFY_ATTR_PID = 4,          /* Process ID (u32) */
    DEEPIN_ERR_NOTIFY_ATTR_PPID = 5,         /* Parent Process ID (u32) */
    DEEPIN_ERR_NOTIFY_ATTR_COMM = 6,         /* Process Short Name (string, 15 chars max) */
    DEEPIN_ERR_NOTIFY_ATTR_UID = 7,          /* User ID (u32) */
    DEEPIN_ERR_NOTIFY_ATTR_GID = 8,          /* Group ID (u32) */
    DEEPIN_ERR_NOTIFY_ATTR_STATUS = 9,       /* Enable/Disable Status (u8) */
    __DEEPIN_ERR_NOTIFY_ATTR_MAX,
};

#define DEEPIN_ERR_NOTIFY_ATTR_MAX (__DEEPIN_ERR_NOTIFY_ATTR_MAX - 1)

/* Opaque state structure */
struct err_notify_state;

/**
 * Error notification data structure
 */
struct err_notify_data
{
    const char **filenames; /* Array of filenames (may be NULL) */
    ino_t *inodes;          /* Array of inodes (may be NULL) */
    bool *inode_parents;    /* Array indicating if inode is from parent (may be NULL) */
    int inode_count;        /* Number of elements in filenames, inodes and inode_parents arrays */
    pid_t pid;              /* Process ID */
    pid_t ppid;             /* Parent Process ID */
    const char *comm;       /* Process short name (may be NULL) */
    uid_t uid;              /* User ID */
    gid_t gid;              /* Group ID */
};

/**
 * Callback function type for error notifications
 * @data: Pointer to error notification data structure
 * @userdata: User data pointer passed during registration
 */
typedef void (*err_notify_callback_t)(const struct err_notify_data *data, void *userdata);

/**
 * err_notify_init - Initialize Generic Netlink connection
 * @state: Pointer to state pointer (will be allocated)
 *
 * Returns: 0 on success, -1 on failure
 */
int err_notify_init(struct err_notify_state **state);

/**
 * err_notify_set_callback - Set callback function for error notifications
 * @state: State pointer
 * @callback: Callback function to call when error occurs (NULL to disable)
 * @userdata: User data to pass to callback
 */
void err_notify_set_callback(struct err_notify_state *state,
                             err_notify_callback_t callback,
                             void *userdata);

/**
 * err_notify_cleanup - Clean up Generic Netlink connection
 * @state: State pointer to clean up
 */
void err_notify_cleanup(struct err_notify_state *state);

/**
 * err_notify_enable - Enable error notification
 * @state: State pointer
 *
 * Returns: 0 on success, -1 on failure
 */
int err_notify_enable(struct err_notify_state *state);

/**
 * err_notify_disable - Disable error notification
 * @state: State pointer
 *
 * Returns: 0 on success, -1 on failure
 */
int err_notify_disable(struct err_notify_state *state);

/**
 * err_notify_get_status - Get error notification status
 * @state: State pointer
 *
 * Returns: 0 on success, -1 on failure
 */
int err_notify_get_status(struct err_notify_state *state);

/**
 * err_notify_set_verbose - Set verbose mode
 * @verbose: true for verbose output, false for normal output
 */
void err_notify_set_verbose(bool verbose);

/**
 * err_notify_monitor - Monitor multicast notifications
 * @state: State pointer
 *
 * Returns: 0 on success, -1 on failure
 * Note: This function blocks until interrupted by signal
 */
int err_notify_monitor(struct err_notify_state *state);

/**
 * err_notify_join_multicast - Join error notification multicast group
 * @state: State pointer
 *
 * Returns: 0 on success, -1 on failure
 * Note: Sets up callbacks and joins multicast group, preparing for event-driven processing
 */
int err_notify_join_multicast(struct err_notify_state *state);

/**
 * err_notify_process_one - Process one netlink message (non-blocking)
 * @state: State pointer
 *
 * Returns: 0 on success, -1 on failure, -NLE_AGAIN if no message available
 * Note: Used for sd-event integration, call this when fd is readable
 */
int err_notify_process_one(struct err_notify_state *state);

/**
 * err_notify_get_fd - Get the file descriptor for the netlink socket
 * @state: State pointer
 *
 * Returns: File descriptor on success, -1 on failure
 * Note: Used for integrating with event loops like sd-event
 */
int err_notify_get_fd(struct err_notify_state *state);

/* Process information helpers */
int get_process_cgroup(pid_t pid, char *buffer, size_t buffer_size);
int get_process_cmdline(pid_t pid, char *buffer, size_t buffer_size, const char *comm_fallback);

#ifdef __cplusplus
}
#endif

#endif /* NETLINK_CLIENT_H */
