/* SPDX-License-Identifier: GPL-2.0 */
/*
 * bpf_glue.c:	BPF code to call both legacy and libbpf code
 * Authors:	Hangbin Liu <haliu@redhat.com>
 *
 */
#include <sys/syscall.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>

#include "bpf_util.h"
#ifdef HAVE_LIBBPF
#include <bpf/bpf.h>
#endif

int bpf(int cmd, union bpf_attr *attr, unsigned int size)
{
#ifdef __NR_bpf
	return syscall(__NR_bpf, cmd, attr, size);
#else
	fprintf(stderr, "No bpf syscall, kernel headers too old?\n");
	errno = ENOSYS;
	return -1;
#endif
}

int bpf_program_attach(int prog_fd, int target_fd, enum bpf_attach_type type)
{
#ifdef HAVE_LIBBPF
	return bpf_prog_attach(prog_fd, target_fd, type, 0);
#else
	return bpf_prog_attach_fd(prog_fd, target_fd, type);
#endif
}

#ifdef HAVE_LIBBPF
static const char *_libbpf_compile_version = LIBBPF_VERSION;
static char _libbpf_version[10] = {};

const char *get_libbpf_version(void)
{
	/* Start by copying compile-time version into buffer so we have a
	 * fallback value in case we are dynamically linked, or can't find a
	 * version in /proc/self/maps below.
	 */
	strncpy(_libbpf_version, _libbpf_compile_version,
		sizeof(_libbpf_version)-1);
#ifdef LIBBPF_DYNAMIC
	char buf[PATH_MAX], *s;
	bool found = false;
	FILE *fp;

	/* When dynamically linking against libbpf, we can't be sure that the
	 * version we discovered at compile time is actually the one we are
	 * using at runtime. This can lead to hard-to-debug errors, so we try to
	 * discover the correct version at runtime.
	 *
	 * The simple solution to this would be if libbpf itself exported a
	 * version in its API. But since it doesn't, we work around this by
	 * parsing the mappings of the binary at runtime, looking for the full
	 * filename of libbpf.so and using that.
	 */
	fp = fopen("/proc/self/maps", "r");
	if (fp == NULL)
		goto out;

	while (fgets(buf, sizeof(buf), fp) != NULL) {
		if ((s = strstr(buf, "libbpf.so.")) != NULL) {
			strncpy(_libbpf_version, s+10, sizeof(_libbpf_version)-1);
			strtok(_libbpf_version, "\n");
			found = true;
			break;
		}
	}

	fclose(fp);
out:
	if (!found)
		fprintf(stderr, "Couldn't find runtime libbpf version - falling back to compile-time value!\n");
#endif /* LIBBPF_DYNAMIC */

	_libbpf_version[sizeof(_libbpf_version)-1] = '\0';
	return _libbpf_version;
}
#else
const char *get_libbpf_version(void)
{
	return NULL;
}
#endif /* HAVE_LIBBPF */
