Blame tools/fpgad/config_file.c

Packit Service 3975d1
// Copyright(c) 2018-2020, Intel Corporation
Packit Service 3975d1
//
Packit Service 3975d1
// Redistribution  and  use  in source  and  binary  forms,  with  or  without
Packit Service 3975d1
// modification, are permitted provided that the following conditions are met:
Packit Service 3975d1
//
Packit Service 3975d1
// * Redistributions of  source code  must retain the  above copyright notice,
Packit Service 3975d1
//   this list of conditions and the following disclaimer.
Packit Service 3975d1
// * Redistributions in binary form must reproduce the above copyright notice,
Packit Service 3975d1
//   this list of conditions and the following disclaimer in the documentation
Packit Service 3975d1
//   and/or other materials provided with the distribution.
Packit Service 3975d1
// * Neither the name  of Intel Corporation  nor the names of its contributors
Packit Service 3975d1
//   may be used to  endorse or promote  products derived  from this  software
Packit Service 3975d1
//   without specific prior written permission.
Packit Service 3975d1
//
Packit Service 3975d1
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit Service 3975d1
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
Packit Service 3975d1
// IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit Service 3975d1
// ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS BE
Packit Service 3975d1
// LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
Packit Service 3975d1
// CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT  OF
Packit Service 3975d1
// SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
Packit Service 3975d1
// INTERRUPTION)  HOWEVER CAUSED  AND ON ANY THEORY  OF LIABILITY,  WHETHER IN
Packit Service 3975d1
// CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
Packit Service 3975d1
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
Packit Service 3975d1
// POSSIBILITY OF SUCH DAMAGE.
Packit Service 3975d1
Packit Service 3975d1
#ifdef HAVE_CONFIG_H
Packit Service 3975d1
#include <config.h>
Packit Service 3975d1
#endif // HAVE_CONFIG_H
Packit Service 3975d1
Packit Service 3975d1
#include <sys/types.h>
Packit Service 3975d1
#include <pwd.h>
Packit Service 3975d1
#include "config_file.h"
Packit Service 3975d1
#include "monitored_device.h"
Packit Service 3975d1
#include "api/sysfs.h"
Packit Service 3975d1
Packit Service 3975d1
#include <json-c/json.h>
Packit Service 3975d1
Packit Service 3975d1
#ifdef LOG
Packit Service 3975d1
#undef LOG
Packit Service 3975d1
#endif
Packit Service 3975d1
#define LOG(format, ...) \
Packit Service 3975d1
log_printf("cfg: " format, ##__VA_ARGS__)
Packit Service 3975d1
Packit Service 3975d1
#define CFG_TRY_FILE(__f) \
Packit Service 3975d1
do { \
Packit Service 3975d1
	canon = canonicalize_file_name(__f); \
Packit Service 3975d1
	if (canon) { \
Packit Service 3975d1
 \
Packit Service 3975d1
		if (!cmd_path_is_symlink(__f)) { \
Packit Service 3975d1
			size_t len = strnlen(canon, \
Packit Service 3975d1
					sizeof(c->cfgfile) - 1); \
Packit Service 3975d1
			memcpy(c->cfgfile, \
Packit Service 3975d1
				canon, \
Packit Service 3975d1
				len); \
Packit Service 3975d1
			c->cfgfile[len] = '\0'; \
Packit Service 3975d1
			free(canon); \
Packit Service 3975d1
			return 0; \
Packit Service 3975d1
		} \
Packit Service 3975d1
 \
Packit Service 3975d1
		free(canon); \
Packit Service 3975d1
	} \
Packit Service 3975d1
} while (0)
Packit Service 3975d1
Packit Service 3975d1
int cfg_find_config_file(struct fpgad_config *c)
Packit Service 3975d1
{
Packit Service 3975d1
	char path[PATH_MAX];
Packit Service 3975d1
	char *e;
Packit Service 3975d1
	char *canon = NULL;
Packit Service 3975d1
	uid_t uid;
Packit Service 3975d1
	size_t len;
Packit Service 3975d1
Packit Service 3975d1
	uid = geteuid();
Packit Service 3975d1
Packit Service 3975d1
	e = getenv("FPGAD_CONFIG_FILE");
Packit Service 3975d1
	if (e) {
Packit Service 3975d1
		// try $FPGAD_CONFIG_FILE
Packit Service 3975d1
		len = strnlen(e, sizeof(path) - 1);
Packit Service 3975d1
		memcpy(path, e, len);
Packit Service 3975d1
		path[len] = '\0';
Packit Service 3975d1
Packit Service 3975d1
		CFG_TRY_FILE(path);
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!uid) {
Packit Service 3975d1
		CFG_TRY_FILE("/var/lib/opae/fpgad.cfg");
Packit Service 3975d1
	} else {
Packit Service 3975d1
		struct passwd *passwd;
Packit Service 3975d1
Packit Service 3975d1
		passwd = getpwuid(uid);
Packit Service 3975d1
Packit Service 3975d1
		// try $HOME/.opae/fpgad.cfg
Packit Service 3975d1
		snprintf(path, sizeof(path),
Packit Service 3975d1
			     "%s/.opae/fpgad.cfg", passwd->pw_dir);
Packit Service 3975d1
Packit Service 3975d1
		CFG_TRY_FILE(path);
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	CFG_TRY_FILE("/etc/opae/fpgad.cfg");
Packit Service 3975d1
Packit Service 3975d1
	return 1; // not found
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC char *cfg_read_file(const char *file)
Packit Service 3975d1
{
Packit Service 3975d1
	FILE *fp;
Packit Service 3975d1
	size_t len;
Packit Service 3975d1
	char *buf;
Packit Service 3975d1
Packit Service 3975d1
	fp = fopen(file, "r");
Packit Service 3975d1
	if (!fp) {
Packit Service 3975d1
		LOG("fopen failed.\n");
Packit Service 3975d1
		return NULL;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (fseek(fp, 0, SEEK_END)) {
Packit Service 3975d1
		LOG("fseek failed.\n");
Packit Service 3975d1
		fclose(fp);
Packit Service 3975d1
		return NULL;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	len = (size_t)ftell(fp);
Packit Service 3975d1
	++len; // for \0
Packit Service 3975d1
Packit Service 3975d1
	if (len == 1) {
Packit Service 3975d1
		LOG("%s is empty.\n", file);
Packit Service 3975d1
		fclose(fp);
Packit Service 3975d1
		return NULL;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (fseek(fp, 0, SEEK_SET)) {
Packit Service 3975d1
		LOG("fseek failed.\n");
Packit Service 3975d1
		fclose(fp);
Packit Service 3975d1
		return NULL;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	buf = (char *)malloc(len);
Packit Service 3975d1
	if (!buf) {
Packit Service 3975d1
		LOG("malloc failed.\n");
Packit Service 3975d1
		fclose(fp);
Packit Service 3975d1
		return NULL;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if ((fread(buf, 1, len - 1, fp) != len - 1) ||
Packit Service 3975d1
	    ferror(fp)) {
Packit Service 3975d1
		LOG("fread failed.\n");
Packit Service 3975d1
		fclose(fp);
Packit Service 3975d1
		free(buf);
Packit Service 3975d1
		return NULL;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	fclose(fp);
Packit Service 3975d1
	buf[len - 1] = '\0';
Packit Service 3975d1
Packit Service 3975d1
	return buf;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
typedef struct _cfg_vendor_device_id {
Packit Service 3975d1
	uint16_t vendor_id;
Packit Service 3975d1
	uint16_t device_id;
Packit Service 3975d1
	struct _cfg_vendor_device_id *next;
Packit Service 3975d1
} cfg_vendor_device_id;
Packit Service 3975d1
Packit Service 3975d1
typedef struct _cfg_plugin_configuration {
Packit Service 3975d1
	char *configuration;
Packit Service 3975d1
	bool enabled;
Packit Service 3975d1
	char *library;
Packit Service 3975d1
	cfg_vendor_device_id *devices;
Packit Service 3975d1
	struct _cfg_plugin_configuration *next;
Packit Service 3975d1
} cfg_plugin_configuration;
Packit Service 3975d1
Packit Service 3975d1
STATIC cfg_vendor_device_id *alloc_device(uint16_t vendor_id,
Packit Service 3975d1
					  uint16_t device_id)
Packit Service 3975d1
{
Packit Service 3975d1
	cfg_vendor_device_id *p;
Packit Service 3975d1
Packit Service 3975d1
	p = (cfg_vendor_device_id *)malloc(sizeof(cfg_vendor_device_id));
Packit Service 3975d1
	if (p) {
Packit Service 3975d1
		p->vendor_id = vendor_id;
Packit Service 3975d1
		p->device_id = device_id;
Packit Service 3975d1
		p->next = NULL;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	return p;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC cfg_plugin_configuration *alloc_configuration(char *configuration,
Packit Service 3975d1
						     bool enabled,
Packit Service 3975d1
						     char *library,
Packit Service 3975d1
						     cfg_vendor_device_id *devs)
Packit Service 3975d1
{
Packit Service 3975d1
	cfg_plugin_configuration *p;
Packit Service 3975d1
Packit Service 3975d1
	p = (cfg_plugin_configuration *)
Packit Service 3975d1
		malloc(sizeof(cfg_plugin_configuration));
Packit Service 3975d1
	if (p) {
Packit Service 3975d1
		p->configuration = configuration;
Packit Service 3975d1
		p->enabled = enabled;
Packit Service 3975d1
		p->library = library;
Packit Service 3975d1
		p->devices = devs;
Packit Service 3975d1
		p->next = NULL;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	return p;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC cfg_vendor_device_id *
Packit Service 3975d1
cfg_process_plugin_devices(const char *name,
Packit Service 3975d1
			   json_object *j_devices)
Packit Service 3975d1
{
Packit Service 3975d1
	int i;
Packit Service 3975d1
	int devs;
Packit Service 3975d1
	cfg_vendor_device_id *head = NULL;
Packit Service 3975d1
	cfg_vendor_device_id *id = NULL;
Packit Service 3975d1
	uint16_t vendor_id;
Packit Service 3975d1
	uint16_t device_id;
Packit Service 3975d1
	const char *s;
Packit Service 3975d1
	char *endptr;
Packit Service 3975d1
Packit Service 3975d1
	if (!json_object_is_type(j_devices, json_type_array)) {
Packit Service 3975d1
		LOG("'devices' JSON object not array.\n");
Packit Service 3975d1
		return NULL;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	devs = json_object_array_length(j_devices);
Packit Service 3975d1
	for (i = 0 ; i < devs ; ++i) {
Packit Service 3975d1
		json_object *j_dev = json_object_array_get_idx(j_devices, i);
Packit Service 3975d1
		json_object *j_vid;
Packit Service 3975d1
		json_object *j_did;
Packit Service 3975d1
Packit Service 3975d1
		if (!json_object_is_type(j_dev, json_type_array)) {
Packit Service 3975d1
			LOG("%s 'devices' entry %d not array.\n",
Packit Service 3975d1
				name, i);
Packit Service 3975d1
			goto out_free;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		if (json_object_array_length(j_dev) != 2) {
Packit Service 3975d1
			LOG("%s 'devices' entry %d not array[2].\n",
Packit Service 3975d1
				name, i);
Packit Service 3975d1
			goto out_free;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		j_vid = json_object_array_get_idx(j_dev, 0);
Packit Service 3975d1
		if (json_object_is_type(j_vid, json_type_string)) {
Packit Service 3975d1
			s = json_object_get_string(j_vid);
Packit Service 3975d1
			endptr = NULL;
Packit Service 3975d1
Packit Service 3975d1
			vendor_id = (uint16_t)strtoul(s, &endptr, 0);
Packit Service 3975d1
			if (*endptr != '\0') {
Packit Service 3975d1
				LOG("%s malformed Vendor ID at devices[%d]\n",
Packit Service 3975d1
					name, i);
Packit Service 3975d1
				goto out_free;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
		} else if (json_object_is_type(j_vid, json_type_int)) {
Packit Service 3975d1
			vendor_id = (uint16_t)json_object_get_int(j_vid);
Packit Service 3975d1
		} else {
Packit Service 3975d1
			LOG("%s invalid Vendor ID at devices[%d]\n",
Packit Service 3975d1
				name, i);
Packit Service 3975d1
			goto out_free;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		j_did = json_object_array_get_idx(j_dev, 1);
Packit Service 3975d1
		if (json_object_is_type(j_did, json_type_string)) {
Packit Service 3975d1
			s = json_object_get_string(j_did);
Packit Service 3975d1
			endptr = NULL;
Packit Service 3975d1
Packit Service 3975d1
			device_id = (uint16_t)strtoul(s, &endptr, 0);
Packit Service 3975d1
			if (*endptr != '\0') {
Packit Service 3975d1
				LOG("%s malformed Device ID at devices[%d]\n",
Packit Service 3975d1
					name, i);
Packit Service 3975d1
				goto out_free;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
		} else if (json_object_is_type(j_did, json_type_int)) {
Packit Service 3975d1
			device_id = (uint16_t)json_object_get_int(j_did);
Packit Service 3975d1
		} else {
Packit Service 3975d1
			LOG("%s invalid Device ID at devices[%d]\n",
Packit Service 3975d1
				name, i);
Packit Service 3975d1
			goto out_free;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		if (!head) {
Packit Service 3975d1
			head = alloc_device(vendor_id, device_id);
Packit Service 3975d1
			if (!head) {
Packit Service 3975d1
				LOG("malloc failed.\n");
Packit Service 3975d1
				goto out_free;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			id = head;
Packit Service 3975d1
		} else {
Packit Service 3975d1
			id->next = alloc_device(vendor_id, device_id);
Packit Service 3975d1
			if (!id->next) {
Packit Service 3975d1
				LOG("malloc failed.\n");
Packit Service 3975d1
				goto out_free;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			id = id->next;
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	return head;
Packit Service 3975d1
Packit Service 3975d1
out_free:
Packit Service 3975d1
	for (id = head ; id ; ) {
Packit Service 3975d1
		cfg_vendor_device_id *trash = id;
Packit Service 3975d1
		id = id->next;
Packit Service 3975d1
		free(trash);
Packit Service 3975d1
	}
Packit Service 3975d1
	return NULL;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC int cfg_process_plugin(const char *name,
Packit Service 3975d1
			      json_object *j_configurations,
Packit Service 3975d1
			      cfg_plugin_configuration **list)
Packit Service 3975d1
{
Packit Service 3975d1
	json_object *j_cfg_plugin = NULL;
Packit Service 3975d1
	json_object *j_cfg_plugin_configuration = NULL;
Packit Service 3975d1
	json_object *j_enabled = NULL;
Packit Service 3975d1
	json_object *j_plugin = NULL;
Packit Service 3975d1
	json_object *j_devices = NULL;
Packit Service 3975d1
	char *configuration = NULL;
Packit Service 3975d1
	bool enabled = false;
Packit Service 3975d1
	char *plugin = NULL;
Packit Service 3975d1
	cfg_plugin_configuration *c = NULL;
Packit Service 3975d1
Packit Service 3975d1
	if (!json_object_object_get_ex(j_configurations,
Packit Service 3975d1
				       name,
Packit Service 3975d1
				       &j_cfg_plugin)) {
Packit Service 3975d1
		LOG("couldn't find configurations section"
Packit Service 3975d1
		    " for %s.\n", name);
Packit Service 3975d1
		return 1;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!json_object_object_get_ex(j_cfg_plugin,
Packit Service 3975d1
				       "configuration",
Packit Service 3975d1
				       &j_cfg_plugin_configuration)) {
Packit Service 3975d1
		LOG("couldn't find %s configuration section.\n", name);
Packit Service 3975d1
		return 1;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	configuration = (char *)json_object_to_json_string_ext(
Packit Service 3975d1
				j_cfg_plugin_configuration,
Packit Service 3975d1
				JSON_C_TO_STRING_PLAIN);
Packit Service 3975d1
	if (!configuration) {
Packit Service 3975d1
		LOG("failed to parse configuration for %s.\n", name);
Packit Service 3975d1
		return 1;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	configuration = cstr_dup(configuration);
Packit Service 3975d1
	if (!configuration) {
Packit Service 3975d1
		LOG("cstr_dup failed.\n");
Packit Service 3975d1
		return 1;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!json_object_object_get_ex(j_cfg_plugin,
Packit Service 3975d1
				       "enabled",
Packit Service 3975d1
				       &j_enabled)) {
Packit Service 3975d1
		LOG("couldn't find enabled key"
Packit Service 3975d1
		    " for %s.\n", name);
Packit Service 3975d1
		goto out_free;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!json_object_is_type(j_enabled, json_type_boolean)) {
Packit Service 3975d1
		LOG("enabled key for %s not boolean.\n", name);
Packit Service 3975d1
		goto out_free;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	enabled = json_object_get_boolean(j_enabled);
Packit Service 3975d1
Packit Service 3975d1
	if (!json_object_object_get_ex(j_cfg_plugin,
Packit Service 3975d1
				       "plugin",
Packit Service 3975d1
				       &j_plugin)) {
Packit Service 3975d1
		LOG("couldn't find plugin key"
Packit Service 3975d1
		    " for %s.\n", name);
Packit Service 3975d1
		goto out_free;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!json_object_is_type(j_plugin, json_type_string)) {
Packit Service 3975d1
		LOG("plugin key for %s not string.\n", name);
Packit Service 3975d1
		goto out_free;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	plugin = cstr_dup(json_object_get_string(j_plugin));
Packit Service 3975d1
	if (!plugin) {
Packit Service 3975d1
		LOG("cstr_dup failed.\n");
Packit Service 3975d1
		goto out_free;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!json_object_object_get_ex(j_cfg_plugin,
Packit Service 3975d1
				       "devices",
Packit Service 3975d1
				       &j_devices)) {
Packit Service 3975d1
		LOG("couldn't find devices key"
Packit Service 3975d1
		    " for %s.\n", name);
Packit Service 3975d1
		goto out_free;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!(*list)) { // list is empty
Packit Service 3975d1
		c = alloc_configuration(configuration,
Packit Service 3975d1
					enabled,
Packit Service 3975d1
					plugin,
Packit Service 3975d1
					NULL);
Packit Service 3975d1
		if (!c) {
Packit Service 3975d1
			LOG("malloc failed.\n");
Packit Service 3975d1
			goto out_free;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		*list = c;
Packit Service 3975d1
	} else {
Packit Service 3975d1
		for (c = *list ; c->next ; c = c->next)
Packit Service 3975d1
		/* find the end of the list */ ;
Packit Service 3975d1
Packit Service 3975d1
		c->next = alloc_configuration(configuration,
Packit Service 3975d1
					      enabled,
Packit Service 3975d1
					      plugin,
Packit Service 3975d1
					      NULL);
Packit Service 3975d1
		if (!c->next) {
Packit Service 3975d1
			LOG("malloc failed.\n");
Packit Service 3975d1
			goto out_free;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		c = c->next;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	c->devices = cfg_process_plugin_devices(name, j_devices);
Packit Service 3975d1
Packit Service 3975d1
	return 0;
Packit Service 3975d1
Packit Service 3975d1
out_free:
Packit Service 3975d1
	if (configuration)
Packit Service 3975d1
		free(configuration);
Packit Service 3975d1
	if (plugin)
Packit Service 3975d1
		free(plugin);
Packit Service 3975d1
	if (c)
Packit Service 3975d1
		free(c);
Packit Service 3975d1
	return 1;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC fpgad_supported_device *
Packit Service 3975d1
cfg_json_to_supported(cfg_plugin_configuration *configurations)
Packit Service 3975d1
{
Packit Service 3975d1
	cfg_plugin_configuration *c;
Packit Service 3975d1
	cfg_vendor_device_id *d;
Packit Service 3975d1
	size_t num_devices = 0;
Packit Service 3975d1
	fpgad_supported_device *supported;
Packit Service 3975d1
	int i;
Packit Service 3975d1
Packit Service 3975d1
	// find the number of devices
Packit Service 3975d1
	for (c = configurations ; c ; c = c->next) {
Packit Service 3975d1
		if (!c->enabled) // skip it
Packit Service 3975d1
			continue;
Packit Service 3975d1
		for (d = c->devices ; d ; d = d->next) {
Packit Service 3975d1
			++num_devices;
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	++num_devices; // +1 for NULL terminator
Packit Service 3975d1
Packit Service 3975d1
	supported = calloc(num_devices, sizeof(fpgad_supported_device));
Packit Service 3975d1
	if (!supported) {
Packit Service 3975d1
		LOG("calloc failed.\n");
Packit Service 3975d1
		return NULL;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	i = 0;
Packit Service 3975d1
	for (c = configurations ; c ; c = c->next) {
Packit Service 3975d1
		if (!c->enabled) // skip it
Packit Service 3975d1
			continue;
Packit Service 3975d1
		for (d = c->devices ; d ; d = d->next) {
Packit Service 3975d1
			fpgad_supported_device *dev = &supported[i++];
Packit Service 3975d1
Packit Service 3975d1
			dev->vendor_id = d->vendor_id;
Packit Service 3975d1
			dev->device_id = d->device_id;
Packit Service 3975d1
			dev->library_path = cstr_dup(c->library);
Packit Service 3975d1
			dev->config = cstr_dup(c->configuration);
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	for (c = configurations ; c ; ) {
Packit Service 3975d1
		cfg_plugin_configuration *ctrash = c;
Packit Service 3975d1
Packit Service 3975d1
		for (d = c->devices ; d ; ) {
Packit Service 3975d1
			cfg_vendor_device_id *dtrash = d;
Packit Service 3975d1
			d = d->next;
Packit Service 3975d1
			free(dtrash);
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		c = c->next;
Packit Service 3975d1
Packit Service 3975d1
		if (ctrash->configuration)
Packit Service 3975d1
			free(ctrash->configuration);
Packit Service 3975d1
		if (ctrash->library)
Packit Service 3975d1
			free(ctrash->library);
Packit Service 3975d1
		free(ctrash);
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	return supported;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC bool cfg_verify_supported_devices(fpgad_supported_device *d)
Packit Service 3975d1
{
Packit Service 3975d1
	while (d->library_path) {
Packit Service 3975d1
		char *sub = NULL;
Packit Service 3975d1
Packit Service 3975d1
		if (d->library_path[0] == '/') {
Packit Service 3975d1
			LOG("plugin library paths may not "
Packit Service 3975d1
			    "be absolute paths: %s\n", d->library_path);
Packit Service 3975d1
			return false;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		if (cmd_path_is_symlink(d->library_path)) {
Packit Service 3975d1
			LOG("plugin library paths may not "
Packit Service 3975d1
			    "contain links: %s\n", d->library_path);
Packit Service 3975d1
			return false;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		sub = strstr((char *)d->library_path, "..");
Packit Service 3975d1
		if (sub) {
Packit Service 3975d1
			LOG("plugin library paths may not "
Packit Service 3975d1
			    "contain .. : %s\n", d->library_path);
Packit Service 3975d1
			return false;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		++d;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	return true;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
int cfg_load_config(struct fpgad_config *c)
Packit Service 3975d1
{
Packit Service 3975d1
	char *cfg_buf;
Packit Service 3975d1
	json_object *root = NULL;
Packit Service 3975d1
	json_object *j_configurations = NULL;
Packit Service 3975d1
	json_object *j_plugins = NULL;
Packit Service 3975d1
	enum json_tokener_error j_err = json_tokener_success;
Packit Service 3975d1
	int res = 1;
Packit Service 3975d1
	int num_plugins;
Packit Service 3975d1
	int i;
Packit Service 3975d1
	cfg_plugin_configuration *configurations = NULL;
Packit Service 3975d1
Packit Service 3975d1
	cfg_buf = cfg_read_file(c->cfgfile);
Packit Service 3975d1
	if (!cfg_buf)
Packit Service 3975d1
		return res;
Packit Service 3975d1
Packit Service 3975d1
	root = json_tokener_parse_verbose(cfg_buf, &j_err);
Packit Service 3975d1
	if (!root) {
Packit Service 3975d1
		LOG("error parsing %s: %s\n",
Packit Service 3975d1
		    c->cfgfile,
Packit Service 3975d1
		    json_tokener_error_desc(j_err));
Packit Service 3975d1
		goto out_free;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!json_object_object_get_ex(root,
Packit Service 3975d1
				       "configurations",
Packit Service 3975d1
				       &j_configurations)) {
Packit Service 3975d1
		LOG("failed to find configurations section in %s.\n",
Packit Service 3975d1
		    c->cfgfile);
Packit Service 3975d1
		goto out_put;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!json_object_object_get_ex(root, "plugins", &j_plugins)) {
Packit Service 3975d1
		LOG("failed to find plugins section in %s.\n", c->cfgfile);
Packit Service 3975d1
		goto out_put;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!json_object_is_type(j_plugins, json_type_array)) {
Packit Service 3975d1
		LOG("'plugins' JSON object not array.\n");
Packit Service 3975d1
		goto out_put;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	num_plugins = json_object_array_length(j_plugins);
Packit Service 3975d1
	for (i = 0 ; i < num_plugins ; ++i) {
Packit Service 3975d1
		json_object *j_plugin;
Packit Service 3975d1
		const char *plugin_name;
Packit Service 3975d1
Packit Service 3975d1
		j_plugin = json_object_array_get_idx(j_plugins, i);
Packit Service 3975d1
		plugin_name = json_object_get_string(j_plugin);
Packit Service 3975d1
Packit Service 3975d1
		if (cfg_process_plugin(plugin_name,
Packit Service 3975d1
				       j_configurations,
Packit Service 3975d1
				       &configurations))
Packit Service 3975d1
			goto out_put;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!configurations) {
Packit Service 3975d1
		LOG("no configurations found in %s.\n", c->cfgfile);
Packit Service 3975d1
		goto out_put;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	c->supported_devices = cfg_json_to_supported(configurations);
Packit Service 3975d1
Packit Service 3975d1
	if (c->supported_devices) {
Packit Service 3975d1
Packit Service 3975d1
		if (cfg_verify_supported_devices(c->supported_devices)) {
Packit Service 3975d1
			res = 0;
Packit Service 3975d1
		} else {
Packit Service 3975d1
			fpgad_supported_device *trash = c->supported_devices;
Packit Service 3975d1
Packit Service 3975d1
			LOG("invalid configuration file\n");
Packit Service 3975d1
Packit Service 3975d1
			while (trash->library_path) {
Packit Service 3975d1
				free((void *)trash->library_path);
Packit Service 3975d1
				if (trash->config)
Packit Service 3975d1
					free((void *)trash->config);
Packit Service 3975d1
Packit Service 3975d1
				++trash;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			free(c->supported_devices);
Packit Service 3975d1
			c->supported_devices = NULL;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
out_put:
Packit Service 3975d1
	json_object_put(root);
Packit Service 3975d1
out_free:
Packit Service 3975d1
	free(cfg_buf);
Packit Service 3975d1
	return res;
Packit Service 3975d1
}