/*
 * vdev_ctrl — eudev-compatible udev control socket (/run/udev/control)
 *
 * Wire protocol derived from udev-ctrl.c in eudev (Kay Sievers, LGPL-2.1+).
 * Copyright (C) 2026  Aitor C.Z. <aitor_czr@gnuinos.org>
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#ifndef VDEV_CTRL_H
#define VDEV_CTRL_H

#include <stddef.h>
#include <sys/types.h>

#define VDEV_CTRL_MAGIC 0xdead1dea
#define VDEV_CTRL_DEFAULT_PATH "/run/udev/control"
#define VDEV_CTRL_QUEUE_PATH "/run/udev/queue"
#define VDEV_CTRL_VERSION_STR "vdev-1.4.7"

enum vdev_ctrl_msg_type {
	VDEV_CTRL_UNKNOWN,
	VDEV_CTRL_SET_LOG_LEVEL,
	VDEV_CTRL_STOP_EXEC_QUEUE,
	VDEV_CTRL_START_EXEC_QUEUE,
	VDEV_CTRL_RELOAD,
	VDEV_CTRL_SET_ENV,
	VDEV_CTRL_SET_CHILDREN_MAX,
	VDEV_CTRL_PING,
	VDEV_CTRL_EXIT,
	/* vdev extension: promote early listener to long-running config (buf = path/basename) */
	VDEV_CTRL_PROMOTE,
};

struct vdev_ctrl_msg_wire {
	char version[16];
	unsigned int magic;
	enum vdev_ctrl_msg_type type;
	union {
		int intval;
		char buf[256];
	};
};

struct vdev_ctrl;
struct vdev_ctrl_connection;
struct vdev_ctrl_msg;

struct vdev_ctrl *vdev_ctrl_new(const char *socket_path);
struct vdev_ctrl *vdev_ctrl_unref(struct vdev_ctrl *uctrl);

int vdev_ctrl_enable_receiving(struct vdev_ctrl *uctrl);
int vdev_ctrl_cleanup(struct vdev_ctrl *uctrl);
int vdev_ctrl_get_fd(struct vdev_ctrl *uctrl);
const char *vdev_ctrl_get_path(struct vdev_ctrl *uctrl);

/* Connect client socket if needed; timeout_sec <= 0 waits forever. */
int vdev_ctrl_connect(struct vdev_ctrl *uctrl, int timeout_sec);
/* Peer PID of the listening vdevd (SO_PEERCRED after connect). */
int vdev_ctrl_peer_pid(struct vdev_ctrl *uctrl, pid_t *pid_out, int timeout_sec);

struct vdev_ctrl_connection *vdev_ctrl_get_connection(struct vdev_ctrl *uctrl);
struct vdev_ctrl_connection *vdev_ctrl_connection_unref(
	struct vdev_ctrl_connection *conn);

struct vdev_ctrl_msg *vdev_ctrl_receive_msg(struct vdev_ctrl_connection *conn);
struct vdev_ctrl_msg *vdev_ctrl_msg_unref(struct vdev_ctrl_msg *msg);

enum vdev_ctrl_msg_type vdev_ctrl_msg_type(struct vdev_ctrl_msg *msg);
int vdev_ctrl_msg_intval(struct vdev_ctrl_msg *msg);
const char *vdev_ctrl_msg_buf(struct vdev_ctrl_msg *msg);

int vdev_ctrl_send_set_log_level(struct vdev_ctrl *uctrl, int priority,
								 int timeout_sec);
int vdev_ctrl_send_stop_exec_queue(struct vdev_ctrl *uctrl, int timeout_sec);
int vdev_ctrl_send_start_exec_queue(struct vdev_ctrl *uctrl, int timeout_sec);
int vdev_ctrl_send_reload(struct vdev_ctrl *uctrl, int timeout_sec);
int vdev_ctrl_send_set_env(struct vdev_ctrl *uctrl, const char *key,
						   int timeout_sec);
int vdev_ctrl_send_set_children_max(struct vdev_ctrl *uctrl, int count,
									int timeout_sec);
int vdev_ctrl_send_ping(struct vdev_ctrl *uctrl, int timeout_sec);
int vdev_ctrl_send_exit(struct vdev_ctrl *uctrl, int timeout_sec);
/* buf NULL/empty → daemon uses globals.long_running; else path or basename */
int vdev_ctrl_send_promote(struct vdev_ctrl *uctrl, const char *config_path,
						   int timeout_sec);

void vdev_ctrl_queue_update_busy(int busy);

#endif /* VDEV_CTRL_H */
