/*
 * vdevadm context — path resolution from environment / defaults
 */

#include "vdevadm.h"

#include "libvdev/misc.h"
#include "libvdev/util.h"
#include "libvdev/vdev_ctrl.h"

#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static void vdevadm_strlcpy(char *dst, const char *src, size_t len)
{
	if (len == 0)
		return;
	snprintf(dst, len, "%s", src);
}

static int vdevadm_path_join(char *out, size_t outlen, const char *a,
							 const char *b)
{
	int n;

	n = snprintf(out, outlen, "%s/%s", a, b);
	if (n < 0 || (size_t)n >= outlen)
		return -ENAMETOOLONG;
	return 0;
}

int vdevadm_ctx_init(struct vdevadm_ctx *ctx)
{
	const char *mount;
	const char *udev;
	const char *state;
	const char *sysfs;
	char linkbuf[PATH_MAX];
	ssize_t n;

	memset(ctx, 0, sizeof(*ctx));

	mount = getenv("VDEV_MOUNTPOINT");
	if (!mount || !mount[0])
		mount = "/dev";
	vdevadm_strlcpy(ctx->mountpoint, mount, sizeof(ctx->mountpoint));

	udev = getenv("VDEV_UDEV_ROOT");
	if (!udev || !udev[0]) {
		udev = getenv("VDEV_GLOBAL_METADATA");
		if (udev && udev[0]) {
			if (vdevadm_path_join(ctx->udev_root, sizeof(ctx->udev_root),
								  udev, "udev") != 0)
				return -ENAMETOOLONG;
		} else {
			n = readlink("/run/udev", linkbuf, sizeof(linkbuf) - 1);
			if (n > 0) {
				linkbuf[n] = '\0';
				vdevadm_strlcpy(ctx->udev_root, linkbuf,
								sizeof(ctx->udev_root));
			} else if (vdevadm_path_join(ctx->udev_root,
										 sizeof(ctx->udev_root),
										 ctx->mountpoint,
										 "metadata/udev") != 0) {
				return -ENAMETOOLONG;
			}
		}
	} else {
		vdevadm_strlcpy(ctx->udev_root, udev, sizeof(ctx->udev_root));
	}

	state = getenv("VDEV_STATE_DIR");
	if (!state || !state[0])
		state = getenv("VDEV_COLDPLUG_STAMP_DIR");
	if (!state || !state[0])
		state = "/run/vdev";
	vdevadm_strlcpy(ctx->state_dir, state, sizeof(ctx->state_dir));

	sysfs = getenv("VDEV_SYSFS");
	if (!sysfs || !sysfs[0])
		sysfs = "/sys";
	vdevadm_strlcpy(ctx->sysfs, sysfs, sizeof(ctx->sysfs));

	{
		const char *ctrl = getenv("VDEV_UDEV_CONTROL");

		if (ctrl && ctrl[0])
			vdevadm_strlcpy(ctx->ctrl_socket, ctrl,
							sizeof(ctx->ctrl_socket));
		else
			vdevadm_strlcpy(ctx->ctrl_socket, VDEV_CTRL_DEFAULT_PATH,
							sizeof(ctx->ctrl_socket));
	}

	return 0;
}

void vdevadm_ctx_dump(const struct vdevadm_ctx *ctx)
{
	fprintf(stderr, "mountpoint: %s\n", ctx->mountpoint);
	fprintf(stderr, "udev_root:  %s\n", ctx->udev_root);
	fprintf(stderr, "state_dir:  %s\n", ctx->state_dir);
	fprintf(stderr, "sysfs:      %s\n", ctx->sysfs);
	fprintf(stderr, "ctrl_sock:  %s\n", ctx->ctrl_socket);
}
