Blame src/config_file.c

Packit 7e09eb
/*
Packit 7e09eb
 * Intel(R) Enclosure LED Utilities
Packit 7e09eb
 *
Packit Service cb68d2
 * Copyright (C) 2017-2021 Intel Corporation.
Packit 7e09eb
 * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
Packit 7e09eb
 *
Packit 7e09eb
 * SPDX-License-Identifier: GPL-2.0
Packit 7e09eb
 *
Packit 7e09eb
 * Contains code from util-linux/libblkid/src/config.c
Packit 7e09eb
 * originally released under LGPL.
Packit 7e09eb
*/
Packit 7e09eb
Packit 7e09eb
#include <stdio.h>
Packit 7e09eb
#include <string.h>
Packit 7e09eb
#include <stdlib.h>
Packit 7e09eb
#include <unistd.h>
Packit 7e09eb
#include <fcntl.h>
Packit 7e09eb
#include <ctype.h>
Packit 7e09eb
#include <sys/mman.h>
Packit 7e09eb
#include <sys/types.h>
Packit 7e09eb
#include <errno.h>
Packit 7e09eb
#include <stdint.h>
Packit 7e09eb
#include <stdarg.h>
Packit 7e09eb
Packit 7e09eb
#include "config_file.h"
Packit 7e09eb
#include "utils.h"
Packit 7e09eb
#include "status.h"
Packit 7e09eb
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief Pointer to global ledmon configuration.
Packit 7e09eb
 *
Packit 7e09eb
 * This is a pointer to structure that contains settings of ledmon behavior
Packit 7e09eb
 * read from configuration file.
Packit 7e09eb
 */
Packit 7e09eb
struct ledmon_conf conf;
Packit 7e09eb
Packit 7e09eb
const char *log_level_map[] = {
Packit 7e09eb
	[LOG_LEVEL_QUIET]   = "QUIET",
Packit 7e09eb
	[LOG_LEVEL_ERROR]   = "ERROR",
Packit 7e09eb
	[LOG_LEVEL_WARNING] = "WARNING",
Packit 7e09eb
	[LOG_LEVEL_INFO]    = "INFO",
Packit 7e09eb
	[LOG_LEVEL_DEBUG]   = "DEBUG",
Packit 7e09eb
	[LOG_LEVEL_ALL]     = "ALL"
Packit 7e09eb
};
Packit 7e09eb
Packit 7e09eb
static int parse_bool(char *s)
Packit 7e09eb
{
Packit 7e09eb
	if (*s && (!strcasecmp(s, "enabled") ||
Packit 7e09eb
		   !strcasecmp(s, "true") ||
Packit 7e09eb
		   !strcasecmp(s, "yes") ||
Packit 7e09eb
		   !strcasecmp(s, "1")))
Packit 7e09eb
		return 1;
Packit 7e09eb
	else if (*s && (!strcasecmp(s, "disabled") ||
Packit 7e09eb
		       !strcasecmp(s, "false") ||
Packit 7e09eb
		       !strcasecmp(s, "no") ||
Packit 7e09eb
		       !strcasecmp(s, "0")))
Packit 7e09eb
		return 0;
Packit 7e09eb
Packit 7e09eb
	fprintf(stderr, "Unknown bool value: %s\n", s);
Packit 7e09eb
	return -1;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static void parse_list(struct list *list, char *s)
Packit 7e09eb
{
Packit 7e09eb
	list_erase(list);
Packit 7e09eb
Packit 7e09eb
	while (s && *s) {
Packit 7e09eb
		char *sep;
Packit 7e09eb
Packit 7e09eb
		sep = strchr(s, ',');
Packit 7e09eb
		if (sep)
Packit 7e09eb
			*sep = '\0';
Packit 7e09eb
Packit 7e09eb
		list_append(list, str_dup(s));
Packit 7e09eb
Packit 7e09eb
		if (sep)
Packit 7e09eb
			s = sep + 1;
Packit 7e09eb
		else
Packit 7e09eb
			break;
Packit 7e09eb
	}
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
int _map_log_level(char *conf_log_level)
Packit 7e09eb
{
Packit 7e09eb
	size_t i = 1;
Packit 7e09eb
Packit 7e09eb
	while (i < sizeof(log_level_map)/sizeof(char *)) {
Packit 7e09eb
		if (strcasecmp(log_level_map[i], conf_log_level) == 0)
Packit 7e09eb
			return i;
Packit 7e09eb
		i++;
Packit 7e09eb
	}
Packit 7e09eb
	return 0;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
void _set_log_level(char *s)
Packit 7e09eb
{
Packit 7e09eb
	int log_level;
Packit 7e09eb
Packit 7e09eb
	log_level = _map_log_level(s);
Packit 7e09eb
	if (log_level)
Packit 7e09eb
		conf.log_level = log_level;
Packit 7e09eb
	else if (sscanf(s, "%d", &log_level) == 1 &&
Packit 7e09eb
			log_level >= LOG_LEVEL_QUIET &&
Packit 7e09eb
			log_level <= LOG_LEVEL_ALL)
Packit 7e09eb
		conf.log_level = log_level;
Packit 7e09eb
	else
Packit 7e09eb
		log_warning("Log level given in config file (%s) is incorrect! Using default log level: %s",
Packit 7e09eb
			s, log_level_map[conf.log_level]);
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static int parse_next(FILE *fd)
Packit 7e09eb
{
Packit 7e09eb
	char buf[BUFSIZ];
Packit 7e09eb
	char *s;
Packit 7e09eb
Packit 7e09eb
	/* read the next non-blank non-comment line */
Packit 7e09eb
	do {
Packit 7e09eb
		if (fgets(buf, sizeof(buf), fd) == NULL)
Packit 7e09eb
			return feof(fd) ? 0 : -1;
Packit 7e09eb
		s = strchr(buf, '\n');
Packit 7e09eb
		if (!s) {
Packit 7e09eb
			/* Missing final newline?  Otherwise extremely */
Packit 7e09eb
			/* long line - assume file was corrupted */
Packit 7e09eb
			if (feof(fd))
Packit 7e09eb
				s = strchr(buf, '\0');
Packit 7e09eb
			else {
Packit 7e09eb
				fprintf(stderr, "config file: missing newline at line '%s'.",
Packit 7e09eb
					buf);
Packit 7e09eb
				return -1;
Packit 7e09eb
			}
Packit 7e09eb
		}
Packit 7e09eb
		*s = '\0';
Packit 7e09eb
		if (--s >= buf && *s == '\r')
Packit 7e09eb
			*s = '\0';
Packit 7e09eb
Packit 7e09eb
		s = buf;
Packit 7e09eb
		while (*s == ' ' || *s == '\t')		/* skip space */
Packit 7e09eb
			s++;
Packit 7e09eb
Packit 7e09eb
	} while (*s == '\0' || *s == '#');
Packit 7e09eb
Packit 7e09eb
	if (!strncmp(s, "INTERVAL=", 9)) {
Packit 7e09eb
		s += 9;
Packit 7e09eb
		if (*s) {
Packit 7e09eb
			if (sscanf(s, "%d", &conf.scan_interval) != 1 ||
Packit 7e09eb
			    conf.scan_interval < LEDMON_MIN_SLEEP_INTERVAL)
Packit 7e09eb
				conf.scan_interval = LEDMON_MIN_SLEEP_INTERVAL;
Packit 7e09eb
		}
Packit 7e09eb
	} else if (!strncmp(s, "LOG_LEVEL=", 10)) {
Packit 7e09eb
		s += 10;
Packit 7e09eb
		_set_log_level(s);
Packit 7e09eb
	} else if (!strncmp(s, "LOG_PATH=", 9)) {
Packit 7e09eb
		s += 9;
Packit 7e09eb
		if (*s)
Packit 7e09eb
			set_log_path(s);
Packit 7e09eb
	} else if (!strncmp(s, "BLINK_ON_MIGR=", 14)) {
Packit 7e09eb
		s += 14;
Packit 7e09eb
		conf.blink_on_migration = parse_bool(s);
Packit 7e09eb
		if (conf.blink_on_migration < 0)
Packit 7e09eb
			return -1;
Packit 7e09eb
	} else if (!strncmp(s, "BLINK_ON_INIT=", 14)) {
Packit 7e09eb
		s += 14;
Packit 7e09eb
		conf.blink_on_init = parse_bool(s);
Packit 7e09eb
		if (conf.blink_on_init < 0)
Packit 7e09eb
			return -1;
Packit 7e09eb
	} else if (!strncmp(s, "REBUILD_BLINK_ON_ALL=", 21)) {
Packit 7e09eb
		s += 21;
Packit 7e09eb
		conf.rebuild_blink_on_all = parse_bool(s);
Packit 7e09eb
		if (conf.rebuild_blink_on_all < 0)
Packit 7e09eb
			return -1;
Packit 7e09eb
	} else if (!strncmp(s, "RAID_MEMBERS_ONLY=", 18)) {
Packit 7e09eb
		s += 18;
Packit 7e09eb
		conf.raid_members_only = parse_bool(s);
Packit 7e09eb
		if (conf.raid_members_only < 0)
Packit 7e09eb
			return -1;
Packit 7e09eb
	} else if (!strncmp(s, "WHITELIST=", 10)) {
Packit 7e09eb
		s += 10;
Packit 7e09eb
		if (*s)
Packit 7e09eb
			parse_list(&conf.cntrls_whitelist, s);
Packit 7e09eb
	} else if (!strncmp(s, "BLACKLIST=", 10)) {
Packit 7e09eb
		s += 10;
Packit 7e09eb
		if (*s)
Packit 7e09eb
			parse_list(&conf.cntrls_blacklist, s);
Packit 7e09eb
	} else {
Packit 7e09eb
		fprintf(stderr, "config file: unknown option '%s'.\n", s);
Packit 7e09eb
		return -1;
Packit 7e09eb
	}
Packit 7e09eb
	return 0;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
void ledmon_free_config(void)
Packit 7e09eb
{
Packit 7e09eb
	list_erase(&conf.cntrls_blacklist);
Packit 7e09eb
	list_erase(&conf.cntrls_whitelist);
Packit 7e09eb
Packit 7e09eb
	if (conf.log_path)
Packit 7e09eb
		free(conf.log_path);
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/* return real config data or built-in default */
Packit 7e09eb
int ledmon_read_config(const char *filename)
Packit 7e09eb
{
Packit 7e09eb
	FILE *f;
Packit 7e09eb
Packit 7e09eb
	if (!filename || (filename && access(filename, F_OK) < 0)) {
Packit 7e09eb
		if (filename)
Packit 7e09eb
			fprintf(stdout, "%s: does not exist, using global config file\n",
Packit 7e09eb
				filename);
Packit 7e09eb
		filename = LEDMON_DEF_CONF_FILE;
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	f = fopen(filename, "re");
Packit 7e09eb
	if (!f) {
Packit 7e09eb
		fprintf(stdout, "%s: does not exist, using built-in defaults\n",
Packit 7e09eb
			filename);
Packit 7e09eb
	} else {
Packit 7e09eb
		while (!feof(f)) {
Packit 7e09eb
			if (parse_next(f)) {
Packit 7e09eb
				fprintf(stderr, "%s: parse error\n", filename);
Packit 7e09eb
				ledmon_free_config();
Packit 7e09eb
				fclose(f);
Packit 7e09eb
				return STATUS_CONFIG_FILE_ERROR;
Packit 7e09eb
			}
Packit 7e09eb
		}
Packit 7e09eb
		fclose(f);
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	if (!list_is_empty(&conf.cntrls_whitelist) &&
Packit 7e09eb
	    !list_is_empty(&conf.cntrls_blacklist))
Packit 7e09eb
		fprintf(stdout, "Both whitelist and blacklist are specified - ignoring blacklist.");
Packit 7e09eb
Packit 7e09eb
	return STATUS_SUCCESS;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static char *conf_list_to_str(struct list *list)
Packit 7e09eb
{
Packit 7e09eb
	char buf[BUFSIZ];
Packit 7e09eb
	char *elem;
Packit 7e09eb
Packit 7e09eb
	memset(buf, 0, sizeof(buf));
Packit 7e09eb
	list_for_each(list, elem) {
Packit 7e09eb
		if (elem) {
Packit 7e09eb
			int curr = strlen(buf);
Packit 7e09eb
Packit 7e09eb
			snprintf(buf + curr, sizeof(buf) - curr, "%s,", elem);
Packit 7e09eb
		}
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	return str_dup(buf);
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
int ledmon_write_shared_conf(void)
Packit 7e09eb
{
Packit 7e09eb
	char buf[BUFSIZ];
Packit 7e09eb
	char *whitelist = NULL;
Packit 7e09eb
	char *blacklist = NULL;
Packit 7e09eb
	void *shared_mem_ptr;
Packit 7e09eb
	int fd = shm_open(LEDMON_SHARE_MEM_FILE, O_RDWR | O_CREAT, 0644);
Packit 7e09eb
Packit 7e09eb
	if (fd == -1)
Packit 7e09eb
		return STATUS_FILE_OPEN_ERROR;
Packit 7e09eb
Packit 7e09eb
	if (ftruncate(fd, sizeof(buf)) != 0) {
Packit 7e09eb
		close(fd);
Packit 7e09eb
		return STATUS_FILE_WRITE_ERROR;
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	shared_mem_ptr = mmap(NULL, sizeof(buf), PROT_WRITE, MAP_SHARED, fd, 0);
Packit 7e09eb
	if (shared_mem_ptr == MAP_FAILED) {
Packit 7e09eb
		close(fd);
Packit 7e09eb
		return STATUS_FILE_WRITE_ERROR;
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	snprintf(buf, sizeof(buf),
Packit 7e09eb
		 "BLINK_ON_INIT=%d\n", conf.blink_on_init);
Packit 7e09eb
	snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
Packit 7e09eb
		 "BLINK_ON_MIGR=%d\n", conf.blink_on_migration);
Packit 7e09eb
	snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
Packit 7e09eb
		 "LOG_LEVEL=%u\n", conf.log_level);
Packit 7e09eb
	snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
Packit 7e09eb
		 "LOG_PATH=%s\n", conf.log_path);
Packit 7e09eb
	snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
Packit 7e09eb
		 "RAID_MEMBERS_ONLY=%d\n", conf.raid_members_only);
Packit 7e09eb
	snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
Packit 7e09eb
		 "REBUILD_BLINK_ON_ALL=%d\n", conf.rebuild_blink_on_all);
Packit 7e09eb
	snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
Packit 7e09eb
		 "INTERVAL=%d\n", conf.scan_interval);
Packit 7e09eb
	whitelist = conf_list_to_str(&conf.cntrls_whitelist);
Packit 7e09eb
	if (whitelist) {
Packit 7e09eb
		snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
Packit 7e09eb
			 "WHITELIST=%s\n", whitelist);
Packit 7e09eb
		free(whitelist);
Packit 7e09eb
	}
Packit 7e09eb
	blacklist = conf_list_to_str(&conf.cntrls_blacklist);
Packit 7e09eb
	if (blacklist) {
Packit 7e09eb
		snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
Packit 7e09eb
			 "BLACKLIST=%s\n", blacklist);
Packit 7e09eb
		free(blacklist);
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	memcpy(shared_mem_ptr, buf, strlen(buf));
Packit 7e09eb
	munmap(shared_mem_ptr, strlen(buf));
Packit 7e09eb
	close(fd);
Packit 7e09eb
Packit 7e09eb
	return STATUS_SUCCESS;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
int ledmon_remove_shared_conf(void)
Packit 7e09eb
{
Packit 7e09eb
	return shm_unlink(LEDMON_SHARE_MEM_FILE);
Packit 7e09eb
}
Packit 7e09eb