Blame tools/fpgad/command_line.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
#define _GNU_SOURCE
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 <getopt.h>
Packit Service 3975d1
#include <fcntl.h>
Packit Service 3975d1
#include <sys/stat.h>
Packit Service 3975d1
#include <sys/types.h>
Packit Service 3975d1
#include <pwd.h>
Packit Service 3975d1
#include "command_line.h"
Packit Service 3975d1
#include "config_file.h"
Packit Service 3975d1
#include "monitored_device.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("args: " format, ##__VA_ARGS__)
Packit Service 3975d1
Packit Service 3975d1
extern fpgad_supported_device default_supported_devices_table[];
Packit Service 3975d1
Packit Service 3975d1
#define OPT_STR ":hdl:p:s:n:c:v"
Packit Service 3975d1
Packit Service 3975d1
STATIC struct option longopts[] = {
Packit Service 3975d1
	{ "help",           no_argument,       NULL, 'h' },
Packit Service 3975d1
	{ "daemon",         no_argument,       NULL, 'd' },
Packit Service 3975d1
	{ "logfile",        required_argument, NULL, 'l' },
Packit Service 3975d1
	{ "pidfile",        required_argument, NULL, 'p' },
Packit Service 3975d1
	{ "socket",         required_argument, NULL, 's' },
Packit Service 3975d1
	{ "null-bitstream", required_argument, NULL, 'n' },
Packit Service 3975d1
	{ "config",         required_argument, NULL, 'c' },
Packit Service 3975d1
	{ "version",        no_argument,       NULL, 'v' },
Packit Service 3975d1
Packit Service 3975d1
	{ 0, 0, 0, 0 }
Packit Service 3975d1
};
Packit Service 3975d1
Packit Service 3975d1
#define DEFAULT_DIR_ROOT      "/var/lib/opae"
Packit Service 3975d1
#define DEFAULT_DIR_ROOT_SIZE 13
Packit Service 3975d1
#define DEFAULT_LOG           "fpgad.log"
Packit Service 3975d1
#define DEFAULT_PID           "fpgad.pid"
Packit Service 3975d1
#define DEFAULT_CFG           "fpgad.cfg"
Packit Service 3975d1
Packit Service 3975d1
void cmd_show_help(FILE *fptr)
Packit Service 3975d1
{
Packit Service 3975d1
	fprintf(fptr, "Usage: fpgad <options>\n");
Packit Service 3975d1
	fprintf(fptr, "\n");
Packit Service 3975d1
	fprintf(fptr, "\t-d,--daemon                 run as daemon process.\n");
Packit Service 3975d1
	fprintf(fptr, "\t-l,--logfile <file>         the log file for daemon mode [%s].\n", DEFAULT_LOG);
Packit Service 3975d1
	fprintf(fptr, "\t-p,--pidfile <file>         the pid file for daemon mode [%s].\n", DEFAULT_PID);
Packit Service 3975d1
	fprintf(fptr, "\t-s,--socket <sock>          the unix domain socket [/tmp/fpga_event_socket].\n");
Packit Service 3975d1
	fprintf(fptr, "\t-n,--null-bitstream <file>  NULL bitstream (for AP6 handling, may be\n"
Packit Service 3975d1
		      "\t                            given multiple times).\n");
Packit Service 3975d1
	fprintf(fptr, "\t-c,--config <file>          the configuration file [%s].\n", DEFAULT_CFG);
Packit Service 3975d1
	fprintf(fptr, "\t-v,--version                display the version and exit.\n");
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC bool cmd_register_null_gbs(struct fpgad_config *c, char *null_gbs_path)
Packit Service 3975d1
{
Packit Service 3975d1
	char *canon_path = NULL;
Packit Service 3975d1
Packit Service 3975d1
	if (c->num_null_gbs < (sizeof(c->null_gbs) / sizeof(c->null_gbs[0]))) {
Packit Service 3975d1
		canon_path = canonicalize_file_name(null_gbs_path);
Packit Service 3975d1
Packit Service 3975d1
		if (canon_path) {
Packit Service 3975d1
Packit Service 3975d1
			memset(&c->null_gbs[c->num_null_gbs], 0,
Packit Service 3975d1
				 sizeof(opae_bitstream_info));
Packit Service 3975d1
Packit Service 3975d1
			if (opae_load_bitstream(canon_path,
Packit Service 3975d1
						&c->null_gbs[c->num_null_gbs])) {
Packit Service 3975d1
				LOG("failed to load NULL GBS \"%s\"\n", canon_path);
Packit Service 3975d1
				opae_unload_bitstream(&c->null_gbs[c->num_null_gbs]);
Packit Service 3975d1
				free(canon_path);
Packit Service 3975d1
				return false;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			c->num_null_gbs++;
Packit Service 3975d1
Packit Service 3975d1
			LOG("registering NULL bitstream \"%s\"\n", canon_path);
Packit Service 3975d1
Packit Service 3975d1
		} else {
Packit Service 3975d1
			LOG("error with NULL GBS argument: %s\n", strerror(errno));
Packit Service 3975d1
			return false;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
	} else {
Packit Service 3975d1
		LOG("maximum number of NULL bitstreams exceeded. Ignoring -n option.\n");
Packit Service 3975d1
	}
Packit Service 3975d1
	return true;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
int cmd_parse_args(struct fpgad_config *c, int argc, char *argv[])
Packit Service 3975d1
{
Packit Service 3975d1
	int getopt_ret;
Packit Service 3975d1
	int option_index;
Packit Service 3975d1
	size_t len;
Packit Service 3975d1
Packit Service 3975d1
	while (-1 != (getopt_ret = getopt_long(argc, argv, OPT_STR, longopts, &option_index))) {
Packit Service 3975d1
		const char *tmp_optarg = optarg;
Packit Service 3975d1
Packit Service 3975d1
		if (optarg && ('=' == *tmp_optarg))
Packit Service 3975d1
			++tmp_optarg;
Packit Service 3975d1
Packit Service 3975d1
		if (!optarg && (optind < argc) &&
Packit Service 3975d1
			(NULL != argv[optind]) &&
Packit Service 3975d1
			('-' != argv[optind][0]))
Packit Service 3975d1
			tmp_optarg = argv[optind++];
Packit Service 3975d1
Packit Service 3975d1
		switch (getopt_ret) {
Packit Service 3975d1
		case 'h':
Packit Service 3975d1
			cmd_show_help(stdout);
Packit Service 3975d1
			return -2;
Packit Service 3975d1
			break;
Packit Service 3975d1
Packit Service 3975d1
		case 'd':
Packit Service 3975d1
			c->daemon = 1;
Packit Service 3975d1
			LOG("daemon requested\n");
Packit Service 3975d1
			break;
Packit Service 3975d1
Packit Service 3975d1
		case 'l':
Packit Service 3975d1
			if (tmp_optarg) {
Packit Service 3975d1
				len = strnlen(tmp_optarg, PATH_MAX - 1);
Packit Service 3975d1
				memcpy(c->logfile, tmp_optarg, len);
Packit Service 3975d1
				c->logfile[len] = '\0';
Packit Service 3975d1
			} else {
Packit Service 3975d1
				LOG("missing logfile parameter.\n");
Packit Service 3975d1
				return 1;
Packit Service 3975d1
			}
Packit Service 3975d1
			break;
Packit Service 3975d1
Packit Service 3975d1
		case 'p':
Packit Service 3975d1
			if (tmp_optarg) {
Packit Service 3975d1
				len = strnlen(tmp_optarg, PATH_MAX - 1);
Packit Service 3975d1
				memcpy(c->pidfile, tmp_optarg, len);
Packit Service 3975d1
				c->pidfile[len] = '\0';
Packit Service 3975d1
			} else {
Packit Service 3975d1
				LOG("missing pidfile parameter.\n");
Packit Service 3975d1
				return 1;
Packit Service 3975d1
			}
Packit Service 3975d1
			break;
Packit Service 3975d1
Packit Service 3975d1
		case 'n':
Packit Service 3975d1
			if (tmp_optarg) {
Packit Service 3975d1
				if (!cmd_register_null_gbs(c, (char *)tmp_optarg)) {
Packit Service 3975d1
					LOG("invalid null gbs path: \"%s\"\n", tmp_optarg);
Packit Service 3975d1
					return 1;
Packit Service 3975d1
				}
Packit Service 3975d1
			} else {
Packit Service 3975d1
				LOG("missing bitstream parameter.\n");
Packit Service 3975d1
				return 1;
Packit Service 3975d1
			}
Packit Service 3975d1
			break;
Packit Service 3975d1
Packit Service 3975d1
		case 's':
Packit Service 3975d1
			if (tmp_optarg) {
Packit Service 3975d1
				c->api_socket = tmp_optarg;
Packit Service 3975d1
				LOG("daemon socket is %s\n", c->api_socket);
Packit Service 3975d1
			} else {
Packit Service 3975d1
				LOG("missing socket parameter.\n");
Packit Service 3975d1
				return 1;
Packit Service 3975d1
			}
Packit Service 3975d1
			break;
Packit Service 3975d1
Packit Service 3975d1
		case 'c':
Packit Service 3975d1
			if (tmp_optarg) {
Packit Service 3975d1
				len = strnlen(tmp_optarg, PATH_MAX - 1);
Packit Service 3975d1
				memcpy(c->cfgfile, tmp_optarg, len);
Packit Service 3975d1
				c->cfgfile[len] = '\0';
Packit Service 3975d1
			} else {
Packit Service 3975d1
				LOG("missing cfgfile parameter.\n");
Packit Service 3975d1
				return 1;
Packit Service 3975d1
			}
Packit Service 3975d1
			break;
Packit Service 3975d1
Packit Service 3975d1
		case 'v':
Packit Service 3975d1
			fprintf(stdout, "fpgad %s %s%s\n",
Packit Service 3975d1
					OPAE_VERSION,
Packit Service 3975d1
					OPAE_GIT_COMMIT_HASH,
Packit Service 3975d1
					OPAE_GIT_SRC_TREE_DIRTY ? "*":"");
Packit Service 3975d1
			return -2;
Packit Service 3975d1
			break;
Packit Service 3975d1
Packit Service 3975d1
		case ':':
Packit Service 3975d1
			LOG("Missing option argument.\n");
Packit Service 3975d1
			return 1;
Packit Service 3975d1
Packit Service 3975d1
		case '?':
Packit Service 3975d1
			LOG("Invalid command option.\n");
Packit Service 3975d1
			return 1;
Packit Service 3975d1
Packit Service 3975d1
		default:
Packit Service 3975d1
			LOG("Invalid command option.\n");
Packit Service 3975d1
			return 1;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	return 0;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
int cmd_canonicalize_paths(struct fpgad_config *c)
Packit Service 3975d1
{
Packit Service 3975d1
	char *sub;
Packit Service 3975d1
	bool def;
Packit Service 3975d1
	mode_t mode;
Packit Service 3975d1
	struct stat stat_buf;
Packit Service 3975d1
	bool search = true;
Packit Service 3975d1
	char buf[PATH_MAX];
Packit Service 3975d1
	char *canon_path;
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
	if (!uid) {
Packit Service 3975d1
		// If we're being run as root, then use DEFAULT_DIR_ROOT
Packit Service 3975d1
		// as the working directory.
Packit Service 3975d1
		memcpy(c->directory, DEFAULT_DIR_ROOT, sizeof(DEFAULT_DIR_ROOT));
Packit Service 3975d1
		c->directory[sizeof(DEFAULT_DIR_ROOT)] = '\0';
Packit Service 3975d1
		mode = 0755;
Packit Service 3975d1
		c->filemode = 0026;
Packit Service 3975d1
	} else {
Packit Service 3975d1
		// We're not root. Try to use ${HOME}/.opae
Packit Service 3975d1
		struct passwd *passwd;
Packit Service 3975d1
Packit Service 3975d1
		passwd = getpwuid(uid);
Packit Service 3975d1
Packit Service 3975d1
		canon_path = canonicalize_file_name(passwd->pw_dir);
Packit Service 3975d1
Packit Service 3975d1
		if (canon_path) {
Packit Service 3975d1
			snprintf(c->directory, sizeof(c->directory),
Packit Service 3975d1
					"%s/.opae", canon_path);
Packit Service 3975d1
			free(canon_path);
Packit Service 3975d1
		} else {
Packit Service 3975d1
			// ${HOME} not found or invalid - use current dir.
Packit Service 3975d1
			if (getcwd(buf, sizeof(buf))) {
Packit Service 3975d1
				if (snprintf(c->directory, sizeof(c->directory),
Packit Service 3975d1
					     "%s/.opae", buf) < 0) {
Packit Service 3975d1
					len = strnlen("./.opae",
Packit Service 3975d1
						sizeof(c->directory) - 1);
Packit Service 3975d1
					memcpy(c->directory, "./.opae", len);
Packit Service 3975d1
					c->directory[len] = '\0';
Packit Service 3975d1
				}
Packit Service 3975d1
			} else {
Packit Service 3975d1
				// Current directory not found - use /
Packit Service 3975d1
				len = strnlen("/.opae", sizeof(c->directory) - 1);
Packit Service 3975d1
				memcpy(c->directory, "/.opae", len);
Packit Service 3975d1
				c->directory[len] = '\0';
Packit Service 3975d1
			}
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		mode = 0775;
Packit Service 3975d1
		c->filemode = 0022;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (cmd_path_is_symlink(c->directory)) {
Packit Service 3975d1
		LOG("Aborting - working directory contains a link: %s\n.",
Packit Service 3975d1
		    c->directory);
Packit Service 3975d1
		return 1;
Packit Service 3975d1
	}
Packit Service 3975d1
	LOG("daemon working directory is %s\n", c->directory);
Packit Service 3975d1
Packit Service 3975d1
	// Create the directory if it doesn't exist.
Packit Service 3975d1
	if (lstat(c->directory, &stat_buf) && (errno == ENOENT)) {
Packit Service 3975d1
		if (mkdir(c->directory, mode)) {
Packit Service 3975d1
			LOG("mkdir failed\n");
Packit Service 3975d1
			return 1;
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	// Verify logfile and pidfile do not contain ".."
Packit Service 3975d1
	// nor "/".
Packit Service 3975d1
	def = false;
Packit Service 3975d1
	sub = strstr(c->logfile, "..");
Packit Service 3975d1
	if (sub)
Packit Service 3975d1
		def = true;
Packit Service 3975d1
Packit Service 3975d1
	sub = strstr(c->logfile, "/");
Packit Service 3975d1
	if (sub)
Packit Service 3975d1
		def = true;
Packit Service 3975d1
Packit Service 3975d1
	if (def || (c->logfile[0] == '\0')) {
Packit Service 3975d1
		if (snprintf(c->logfile, sizeof(c->logfile),
Packit Service 3975d1
			     "%s/%s", c->directory, DEFAULT_LOG) < 0) {
Packit Service 3975d1
			len = strnlen("./" DEFAULT_LOG,
Packit Service 3975d1
					sizeof(c->logfile) - 1);
Packit Service 3975d1
			memcpy(c->logfile, "./" DEFAULT_LOG, len);
Packit Service 3975d1
			c->logfile[len] = '\0';
Packit Service 3975d1
		}
Packit Service 3975d1
	} else {
Packit Service 3975d1
		len = strnlen(c->logfile, sizeof(buf) - 1);
Packit Service 3975d1
		memcpy(buf, c->logfile, len);
Packit Service 3975d1
		buf[len] = '\0';
Packit Service 3975d1
Packit Service 3975d1
		if (snprintf(c->logfile, sizeof(c->logfile),
Packit Service 3975d1
			     "%s/%s", c->directory, buf) < 0) {
Packit Service 3975d1
			len = strnlen("./" DEFAULT_LOG,
Packit Service 3975d1
					sizeof(c->logfile) - 1);
Packit Service 3975d1
			memcpy(c->logfile, "./" DEFAULT_LOG, len);
Packit Service 3975d1
			c->logfile[len] = '\0';
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (cmd_path_is_symlink(c->logfile)) {
Packit Service 3975d1
		LOG("Aborting - log file path contains a link: %s\n.",
Packit Service 3975d1
		    c->logfile);
Packit Service 3975d1
		return 1;
Packit Service 3975d1
	}
Packit Service 3975d1
	LOG("daemon log file is %s\n", c->logfile);
Packit Service 3975d1
Packit Service 3975d1
	def = false;
Packit Service 3975d1
	sub = strstr(c->pidfile, "..");
Packit Service 3975d1
	if (sub)
Packit Service 3975d1
		def = true;
Packit Service 3975d1
Packit Service 3975d1
	sub = strstr(c->pidfile, "/");
Packit Service 3975d1
	if (sub)
Packit Service 3975d1
		def = true;
Packit Service 3975d1
Packit Service 3975d1
	if (def || (c->pidfile[0] == '\0')) {
Packit Service 3975d1
Packit Service 3975d1
		if (snprintf(c->pidfile, sizeof(c->pidfile),
Packit Service 3975d1
			     "%s/%s", c->directory, DEFAULT_PID) < 0) {
Packit Service 3975d1
			len = strnlen("./" DEFAULT_PID,
Packit Service 3975d1
					sizeof(c->pidfile) - 1);
Packit Service 3975d1
			memcpy(c->pidfile, "./" DEFAULT_PID, len);
Packit Service 3975d1
			c->pidfile[len] = '\0';
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
	} else {
Packit Service 3975d1
		len = strnlen(c->pidfile, sizeof(buf) - 1);
Packit Service 3975d1
		memcpy(buf, c->pidfile, len);
Packit Service 3975d1
		buf[len] = '\0';
Packit Service 3975d1
Packit Service 3975d1
		if (snprintf(c->pidfile, sizeof(c->pidfile),
Packit Service 3975d1
			     "%s/%s", c->directory, buf) < 0) {
Packit Service 3975d1
			len = strnlen("./" DEFAULT_PID,
Packit Service 3975d1
					sizeof(c->pidfile) - 1);
Packit Service 3975d1
			memcpy(c->pidfile, "./" DEFAULT_PID, len);
Packit Service 3975d1
			c->pidfile[len] = '\0';
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (cmd_path_is_symlink(c->pidfile)) {
Packit Service 3975d1
		LOG("Aborting - pid file path contains a link: %s\n.",
Packit Service 3975d1
		    c->pidfile);
Packit Service 3975d1
		return 1;
Packit Service 3975d1
	}
Packit Service 3975d1
	LOG("daemon pid file is %s\n", c->pidfile);
Packit Service 3975d1
Packit Service 3975d1
	// Verify cfgfile doesn't contain ".."
Packit Service 3975d1
	def = false;
Packit Service 3975d1
	sub = strstr(c->cfgfile, "..");
Packit Service 3975d1
	if (sub)
Packit Service 3975d1
		def = true;
Packit Service 3975d1
Packit Service 3975d1
	if (def || (c->cfgfile[0] == '\0')) {
Packit Service 3975d1
		search = true;
Packit Service 3975d1
	} else {
Packit Service 3975d1
		canon_path = canonicalize_file_name(c->cfgfile);
Packit Service 3975d1
		if (canon_path) {
Packit Service 3975d1
Packit Service 3975d1
			if (!cmd_path_is_symlink(c->cfgfile)) {
Packit Service 3975d1
Packit Service 3975d1
				len = strnlen(canon_path,
Packit Service 3975d1
					      sizeof(c->cfgfile) - 1);
Packit Service 3975d1
				memcpy(c->cfgfile,
Packit Service 3975d1
					  canon_path,
Packit Service 3975d1
					  len);
Packit Service 3975d1
				c->cfgfile[len] = '\0';
Packit Service 3975d1
Packit Service 3975d1
				if (!cfg_load_config(c)) {
Packit Service 3975d1
					LOG("daemon cfg file is %s\n",
Packit Service 3975d1
					    c->cfgfile);
Packit Service 3975d1
					search = false; // found and loaded it
Packit Service 3975d1
				}
Packit Service 3975d1
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			free(canon_path);
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (search) {
Packit Service 3975d1
		c->cfgfile[0] = '\0';
Packit Service 3975d1
		if (cfg_find_config_file(c))
Packit Service 3975d1
			LOG("failed to find config file.\n");
Packit Service 3975d1
		else {
Packit Service 3975d1
			if (cfg_load_config(c))
Packit Service 3975d1
				LOG("failed to load config file %s\n",
Packit Service 3975d1
				    c->cfgfile);
Packit Service 3975d1
			else
Packit Service 3975d1
				LOG("daemon cfg file is %s\n", c->cfgfile);
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!c->supported_devices) {
Packit Service 3975d1
		LOG("using default configuration.\n");
Packit Service 3975d1
		c->cfgfile[0] = '\0';
Packit Service 3975d1
		c->supported_devices = default_supported_devices_table;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	return 0;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
void cmd_destroy(struct fpgad_config *c)
Packit Service 3975d1
{
Packit Service 3975d1
	unsigned i;
Packit Service 3975d1
Packit Service 3975d1
	if (c->daemon)
Packit Service 3975d1
		unlink(c->pidfile);
Packit Service 3975d1
Packit Service 3975d1
	for (i = 0 ; i < c->num_null_gbs ; ++i) {
Packit Service 3975d1
		if (c->null_gbs[i].filename)
Packit Service 3975d1
			free((char *)c->null_gbs[i].filename);
Packit Service 3975d1
		opae_unload_bitstream(&c->null_gbs[i]);
Packit Service 3975d1
	}
Packit Service 3975d1
	c->num_null_gbs = 0;
Packit Service 3975d1
Packit Service 3975d1
	if (c->supported_devices &&
Packit Service 3975d1
	    (c->supported_devices != default_supported_devices_table)) {
Packit Service 3975d1
Packit Service 3975d1
		for (i = 0 ; c->supported_devices[i].library_path ; ++i) {
Packit Service 3975d1
			fpgad_supported_device *d = &c->supported_devices[i];
Packit Service 3975d1
			if (d->library_path)
Packit Service 3975d1
				free((void *)d->library_path);
Packit Service 3975d1
			if (d->config)
Packit Service 3975d1
				free((void *)d->config);
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		free(c->supported_devices);
Packit Service 3975d1
	}
Packit Service 3975d1
	c->supported_devices = NULL;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
bool cmd_path_is_symlink(const char *path)
Packit Service 3975d1
{
Packit Service 3975d1
	char component[PATH_MAX];
Packit Service 3975d1
	struct stat stat_buf;
Packit Service 3975d1
	size_t len;
Packit Service 3975d1
	char *pslash;
Packit Service 3975d1
Packit Service 3975d1
	len = strnlen(path, PATH_MAX - 1);
Packit Service 3975d1
	if (!len) // empty path
Packit Service 3975d1
		return false;
Packit Service 3975d1
Packit Service 3975d1
	memcpy(component, path, len);
Packit Service 3975d1
	component[len] = '\0';
Packit Service 3975d1
Packit Service 3975d1
	if (component[0] == '/') {
Packit Service 3975d1
		// absolute path
Packit Service 3975d1
Packit Service 3975d1
		pslash = realpath(path, component);
Packit Service 3975d1
Packit Service 3975d1
		if (strcmp(component, path))
Packit Service 3975d1
			return true;
Packit Service 3975d1
Packit Service 3975d1
Packit Service 3975d1
	} else {
Packit Service 3975d1
		// relative path
Packit Service 3975d1
Packit Service 3975d1
		pslash = strrchr(component, '/');
Packit Service 3975d1
Packit Service 3975d1
		while (pslash) {
Packit Service 3975d1
Packit Service 3975d1
			if (fstatat(AT_FDCWD, component,
Packit Service 3975d1
				    &stat_buf, AT_SYMLINK_NOFOLLOW)) {
Packit Service 3975d1
				return false;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			if (S_ISLNK(stat_buf.st_mode))
Packit Service 3975d1
				return true;
Packit Service 3975d1
Packit Service 3975d1
			*pslash = '\0';
Packit Service 3975d1
			pslash = strrchr(component, '/');
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		if (fstatat(AT_FDCWD, component,
Packit Service 3975d1
			    &stat_buf, AT_SYMLINK_NOFOLLOW)) {
Packit Service 3975d1
			return false;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		if (S_ISLNK(stat_buf.st_mode))
Packit Service 3975d1
			return true;
Packit Service 3975d1
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	return false;
Packit Service 3975d1
}