mirror of https://github.com/nirenjan/libx52.git
Add daemon framework
This change adds the daemon configuration parser and command line argument parser. This also adds the associated strings to the translation files, and integrates the daemon into the existing autotools build framework.reverse-scroll
parent
fc8e7b6b95
commit
cbe7f00a5a
|
@ -12,6 +12,7 @@ lib/libx52util/util_char_map.c
|
|||
util/x52charmapgen*
|
||||
lib/libusbx52/x52test*
|
||||
udev/*.rules
|
||||
daemon/x52d*
|
||||
x52pro-linux-*.tar.gz
|
||||
|
||||
# Module files
|
||||
|
|
|
@ -9,6 +9,7 @@ The format is based upon [Keep a Changelog].
|
|||
- IO library to read and parse events from a supported joystick.
|
||||
- Event test utility which displays the events similar to evtest.
|
||||
- Import pinelog library for daemon logging.
|
||||
- Daemon to control and update the X52 joystick.
|
||||
|
||||
### Changed
|
||||
- Linux kernel driver to correctly handle the X52/X52 Pro. This is not required
|
||||
|
|
|
@ -10,7 +10,7 @@ if USE_NLS
|
|||
po_SUBDIRS = po
|
||||
endif
|
||||
|
||||
SUBDIRS = $(po_SUBDIRS) lib utils tests udev
|
||||
SUBDIRS = $(po_SUBDIRS) lib utils daemon tests udev
|
||||
|
||||
# Extra files that need to be in the distribution
|
||||
EXTRA_DIST = \
|
||||
|
|
|
@ -33,7 +33,7 @@ AM_CONDITIONAL([LINUX], [test "x${build_linux}" = "xyes"])
|
|||
|
||||
# Internationalization
|
||||
AM_GNU_GETTEXT([external])
|
||||
AM_GNU_GETTEXT_VERSION(0.18)
|
||||
AM_GNU_GETTEXT_VERSION(0.19)
|
||||
AM_CONDITIONAL([USE_NLS], [test "x${USE_NLS}" == "xyes"])
|
||||
|
||||
# Check for libusb-1.0
|
||||
|
@ -129,6 +129,7 @@ AC_CONFIG_FILES([ po/Makefile.in
|
|||
utils/cli/Makefile
|
||||
utils/test/Makefile
|
||||
utils/evtest/Makefile
|
||||
daemon/Makefile
|
||||
tests/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# Automake for x52d
|
||||
#
|
||||
# Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
bin_PROGRAMS = x52d
|
||||
|
||||
# Service daemon that manages the X52 device
|
||||
x52d_SOURCES = \
|
||||
x52d_main.c x52d_config_parser.c x52d_config.c
|
||||
|
||||
x52d_CFLAGS = \
|
||||
-I $(top_srcdir) \
|
||||
-I $(top_srcdir)/lib/libx52io \
|
||||
-I $(top_srcdir)/lib/libx52 \
|
||||
-I $(top_srcdir)/lib/libx52util \
|
||||
-I $(top_srcdir)/lib/pinelog \
|
||||
-DSYSCONFDIR=\"$(sysconfdir)\" \
|
||||
-DLOCALEDIR=\"$(localedir)\" \
|
||||
-DLOGDIR=\"$(localstatedir)/log\" \
|
||||
-DRUNDIR=\"$(runstatedir)\" \
|
||||
@INIH_CFLAGS@ $(WARN_CFLAGS)
|
||||
|
||||
x52d_LDFLAGS = @INIH_LIBS@ $(WARN_LDFLAGS)
|
||||
x52d_LDADD = ../lib/pinelog/libpinelog.la
|
||||
|
||||
EXTRA_DIST = \
|
||||
x52d_config.def \
|
||||
x52d_config.h \
|
||||
x52d_const.h \
|
||||
x52d.conf
|
|
@ -0,0 +1,80 @@
|
|||
#######################################################################
|
||||
# X52 Daemon Configuration
|
||||
######################################################################
|
||||
|
||||
# The settings below are the defaults. Note that the section and key
|
||||
# strings are case insensitive, but the values are not necessarily so,
|
||||
# especially for those referring to paths or timezone names.
|
||||
|
||||
######################################################################
|
||||
# Clock Settings
|
||||
######################################################################
|
||||
[Clock]
|
||||
|
||||
# Enabled controls whether the clock is enabled or not. Set this to no to
|
||||
# disable the clock update. Keep in mind that if the clock was originally
|
||||
# enabled on the X52, then disabling it here won't make the clock disappear on
|
||||
# the MFD. You will need to unplug and reattach the X52 to make the clock
|
||||
# disappear
|
||||
Enabled=yes
|
||||
|
||||
# PrimaryIsLocal controls whether the primary clock displays local time or UTC.
|
||||
# Set this to yes to display local time, no for UTC.
|
||||
PrimaryIsLocal=yes
|
||||
|
||||
# Secondary controls the timezone of the secondary clock. Use the standard
|
||||
# timezone name as defined by the Olson time database.
|
||||
Secondary=UTC
|
||||
|
||||
# Tertiary controls the timezone of the tertiary clock. Use the standard
|
||||
# timezone name as defined by the Olson time database.
|
||||
Tertiary=UTC
|
||||
|
||||
######################################################################
|
||||
# LED Settings - only applicable to X52Pro
|
||||
######################################################################
|
||||
[LED]
|
||||
|
||||
# The LED settings map a color code or state to the corresponding LED.
|
||||
Fire=on
|
||||
Throttle=on
|
||||
A=green
|
||||
B=green
|
||||
D=green
|
||||
E=green
|
||||
T1=green
|
||||
T2=green
|
||||
T3=green
|
||||
POV=green
|
||||
Clutch=green
|
||||
|
||||
######################################################################
|
||||
# Brightness Settings
|
||||
######################################################################
|
||||
[Brightness]
|
||||
|
||||
# The brightness settings map the brightness value to the LEDs/MFD.
|
||||
MFD=128
|
||||
LED=128
|
||||
|
||||
######################################################################
|
||||
# Profiles - only valid on Linux
|
||||
######################################################################
|
||||
[Profiles]
|
||||
|
||||
# Directory is the location of the folder containing the individual profiles.
|
||||
Directory=/etc/x52d/profiles.d
|
||||
|
||||
# ClutchEnabled determines if the clutch button is treated specially
|
||||
ClutchEnabled=no
|
||||
|
||||
# ClutchLatched controls if the clutch button (if enabled) is a latched button
|
||||
# (press once to enter clutch mode, press again to exit clutch mode), or must
|
||||
# be held down to remain in clutch mode.
|
||||
ClutchLatched=no
|
||||
|
||||
##################
|
||||
#X52 Input Servic#
|
||||
#Version 0.2.2 #
|
||||
#OS: Linux #
|
||||
##################
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver - Configuration parser
|
||||
*
|
||||
* Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pinelog.h"
|
||||
#include "x52d_config.h"
|
||||
#include "x52d_const.h"
|
||||
|
||||
static struct x52d_config x52d_config;
|
||||
|
||||
void x52d_config_load(const char *cfg_file)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (cfg_file == NULL) {
|
||||
cfg_file = X52D_SYS_CFG_FILE;
|
||||
}
|
||||
|
||||
rc = x52d_config_set_defaults(&x52d_config);
|
||||
if (rc != 0) {
|
||||
PINELOG_FATAL(_("Error %d setting configuration defaults: %s"),
|
||||
rc, strerror(rc));
|
||||
}
|
||||
|
||||
rc = x52d_config_load_file(&x52d_config, cfg_file);
|
||||
if (rc != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Apply overrides
|
||||
rc = x52d_config_apply_overrides(&x52d_config);
|
||||
x52d_config_clear_overrides();
|
||||
if (rc != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/**********************************************************************
|
||||
* X52 Daemon Configuration
|
||||
*********************************************************************/
|
||||
|
||||
// The settings below are the defaults. Note that the section and key
|
||||
// strings are case insensitive, but the values are not necessarily so,
|
||||
// especially for those referring to paths or timezone names.
|
||||
|
||||
/* CFG(section, key, name, parser, default) */
|
||||
/**********************************************************************
|
||||
* Clock Settings
|
||||
*********************************************************************/
|
||||
|
||||
// Enabled controls whether the clock is enabled or not. Set this to no to
|
||||
// disable the clock update. Keep in mind that if the clock was originally
|
||||
// enabled on the X52, then disabling it here won't make the clock disappear
|
||||
// on the MFD. You will need to unplug and reattach the X52 to make the
|
||||
// clock disappear
|
||||
CFG(Clock, Enabled, clock_enabled, bool_parser, true)
|
||||
|
||||
// PrimaryIsLocal controls whether the primary clock displays local time or UTC.
|
||||
// Set this to yes to display local time, no for UTC.
|
||||
CFG(Clock, PrimaryIsLocal, primary_clock_local, bool_parser, true)
|
||||
|
||||
// Secondary controls the timezone of the secondary clock. Use the standard
|
||||
// timezone name as defined by the Olson time database.
|
||||
CFG(Clock, Secondary, clock_2_tz, string_parser, UTC)
|
||||
|
||||
// Tertiary controls the timezone of the tertiary clock. Use the standard
|
||||
// timezone name as defined by the Olson time database.
|
||||
CFG(Clock, Tertiary, clock_3_tz, string_parser, UTC)
|
||||
|
||||
/**********************************************************************
|
||||
* LED Settings - only applicable to X52Pro
|
||||
*********************************************************************/
|
||||
// The LED settings map a color code or state to the corresponding LED.
|
||||
CFG(LED, Fire, leds[LIBX52_LED_FIRE], led_parser, on)
|
||||
CFG(LED, Throttle, leds[LIBX52_LED_THROTTLE], led_parser, on)
|
||||
CFG(LED, A, leds[LIBX52_LED_A], led_parser, green)
|
||||
CFG(LED, B, leds[LIBX52_LED_B], led_parser, green)
|
||||
CFG(LED, D, leds[LIBX52_LED_D], led_parser, green)
|
||||
CFG(LED, E, leds[LIBX52_LED_E], led_parser, green)
|
||||
CFG(LED, T1, leds[LIBX52_LED_T1], led_parser, green)
|
||||
CFG(LED, T2, leds[LIBX52_LED_T2], led_parser, green)
|
||||
CFG(LED, T3, leds[LIBX52_LED_T3], led_parser, green)
|
||||
CFG(LED, POV, leds[LIBX52_LED_POV], led_parser, green)
|
||||
CFG(LED, Clutch, leds[LIBX52_LED_CLUTCH], led_parser, green)
|
||||
|
||||
/**********************************************************************
|
||||
* Brightness Settings
|
||||
*********************************************************************/
|
||||
// The brightness settings map the brightness value to the LEDs/MFD.
|
||||
CFG(Brightness, MFD, brightness[0], int_parser, 128)
|
||||
CFG(Brightness, LED, brightness[1], int_parser, 128)
|
||||
|
||||
/**********************************************************************
|
||||
* Profiles - only valid on Linux
|
||||
*********************************************************************/
|
||||
// Directory is the location of the folder containing the individual profiles.
|
||||
CFG(Profiles, Directory, profiles_dir, string_parser, /etc/x52d/profiles.d)
|
||||
|
||||
// ClutchEnabled determines if the clutch button is treated specially
|
||||
CFG(Profiles, ClutchEnabled, clutch_enabled, bool_parser, false)
|
||||
|
||||
// ClutchLatched controls if the clutch button (if enabled) is a latched button
|
||||
// (press once to enter clutch mode, press again to exit clutch mode), or must
|
||||
// be held down to remain in clutch mode.
|
||||
CFG(Profiles, ClutchLatched, clutch_latched, bool_parser, false)
|
||||
|
||||
#undef CFG
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver - Configuration parser header
|
||||
*
|
||||
* Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#ifndef X52D_CONFIG_H
|
||||
#define X52D_CONFIG_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include "libx52.h"
|
||||
|
||||
/**
|
||||
* @brief Configuration structure
|
||||
*
|
||||
* Keep this in sync with the sample configuration
|
||||
*/
|
||||
struct x52d_config {
|
||||
bool clock_enabled;
|
||||
bool primary_clock_local;
|
||||
char clock_2_tz[NAME_MAX];
|
||||
char clock_3_tz[NAME_MAX];
|
||||
|
||||
// Since we don't have a _MAX identifier for libx52_led_id, hardcode
|
||||
// the length in the following declaration.
|
||||
libx52_led_state leds[21];
|
||||
|
||||
uint16_t brightness[2];
|
||||
|
||||
bool clutch_enabled;
|
||||
bool clutch_latched;
|
||||
|
||||
char profiles_dir[NAME_MAX];
|
||||
};
|
||||
|
||||
int x52d_config_set_defaults(struct x52d_config *cfg);
|
||||
|
||||
int x52d_config_load_file(struct x52d_config *cfg, const char *cfg_file);
|
||||
|
||||
int x52d_config_save_override(const char *override_str);
|
||||
|
||||
int x52d_config_apply_overrides(struct x52d_config *cfg);
|
||||
|
||||
void x52d_config_clear_overrides(void);
|
||||
|
||||
void x52d_config_load(const char *cfg_file);
|
||||
|
||||
#endif // !defined X52D_CONFIG_H
|
|
@ -0,0 +1,323 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver - Configuration parser
|
||||
*
|
||||
* Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "ini.h"
|
||||
#include "pinelog.h"
|
||||
#include "x52d_config.h"
|
||||
#include "x52d_const.h"
|
||||
|
||||
/* Parser function typedef */
|
||||
typedef int (*parser_fn)(struct x52d_config *, size_t, const char *);
|
||||
|
||||
// Check if the parameters are all valid
|
||||
#define CHECK_PARAMS() do { if (cfg == NULL || value == NULL) { return EINVAL; } } while(0)
|
||||
|
||||
// Create a pointer "name" of type "type", which stores the pointer to the
|
||||
// corresponding element within the config struct.
|
||||
#define CONFIG_PTR(type, name) type name = (type)((uintptr_t)cfg + offset)
|
||||
|
||||
static int bool_parser(struct x52d_config *cfg, size_t offset, const char *value)
|
||||
{
|
||||
CONFIG_PTR(bool *, config);
|
||||
CHECK_PARAMS();
|
||||
|
||||
if (!strcasecmp(value, "yes") || !strcasecmp(value, "true")) {
|
||||
*config = true;
|
||||
} else if (!strcasecmp(value, "no") || !strcasecmp(value, "false")) {
|
||||
*config = false;
|
||||
} else {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int string_parser(struct x52d_config *cfg, size_t offset, const char *value)
|
||||
{
|
||||
CONFIG_PTR(char *, config);
|
||||
CHECK_PARAMS();
|
||||
|
||||
/* String parameters are all NAME_MAX len */
|
||||
strncpy(config, value, NAME_MAX-1);
|
||||
config[NAME_MAX-1] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int int_parser(struct x52d_config *cfg, size_t offset, const char *value)
|
||||
{
|
||||
CONFIG_PTR(int *, config);
|
||||
char *endptr;
|
||||
int retval;
|
||||
|
||||
CHECK_PARAMS();
|
||||
|
||||
errno = 0;
|
||||
retval = strtol(value, &endptr, 0);
|
||||
if (errno != 0) {
|
||||
return errno;
|
||||
}
|
||||
|
||||
*config = retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int led_parser(struct x52d_config *cfg, size_t offset, const char *value)
|
||||
{
|
||||
CONFIG_PTR(libx52_led_state *, config);
|
||||
CHECK_PARAMS();
|
||||
|
||||
#define MATCH_STATE(val) if (!strcasecmp(value, #val)) { *config = LIBX52_LED_STATE_ ## val ; }
|
||||
MATCH_STATE(OFF)
|
||||
else MATCH_STATE(ON)
|
||||
else MATCH_STATE(RED)
|
||||
else MATCH_STATE(AMBER)
|
||||
else MATCH_STATE(GREEN)
|
||||
else return EINVAL;
|
||||
#undef MATCH_STATE
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Map for config->param */
|
||||
#define CFG(section, key, name, parser, def) {#section, #key, parser, offsetof(struct x52d_config, name)},
|
||||
const struct config_map {
|
||||
const char *section;
|
||||
const char *key;
|
||||
parser_fn parser;
|
||||
size_t offset;
|
||||
} config_map[] = {
|
||||
#include "x52d_config.def"
|
||||
|
||||
// Terminating entry
|
||||
{NULL, NULL, NULL, 0}
|
||||
};
|
||||
|
||||
static int process_config_kv(void *user, const char *section, const char *key, const char *value)
|
||||
{
|
||||
int i;
|
||||
int rc = 0;
|
||||
bool found = false;
|
||||
struct x52d_config *cfg = (struct x52d_config*)user;
|
||||
|
||||
for (i = 0; config_map[i].key != NULL; i++) {
|
||||
rc = 0;
|
||||
if (!strcasecmp(config_map[i].key, key) &&
|
||||
!strcasecmp(config_map[i].section, section)) {
|
||||
found = true;
|
||||
PINELOG_TRACE("Setting '%s.%s'='%s'",
|
||||
config_map[i].section, config_map[i].key, value);
|
||||
rc = config_map[i].parser(cfg, config_map[i].offset, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
// Print error message, but continue
|
||||
PINELOG_INFO(_("Ignoring unknown key '%s.%s'"), section, key);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set configuration defaults
|
||||
*
|
||||
* @param[in] cfg Pointer to config struct
|
||||
*
|
||||
* @returns 0 on success, non-zero error code on failure
|
||||
*/
|
||||
int x52d_config_set_defaults(struct x52d_config *cfg) {
|
||||
int rc;
|
||||
|
||||
if (cfg == NULL) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
PINELOG_TRACE("Setting configuration defaults");
|
||||
#define CFG(section, key, name, parser, def) \
|
||||
rc = process_config_kv(cfg, #section, #key, #def); \
|
||||
if (rc != 0) { \
|
||||
return rc; \
|
||||
}
|
||||
#include "x52d_config.def"
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int x52d_config_load_file(struct x52d_config *cfg, const char *cfg_file)
|
||||
{
|
||||
int rc;
|
||||
if (cfg == NULL || cfg_file == NULL) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
PINELOG_TRACE("Loading configuration from file %s", cfg_file);
|
||||
rc = ini_parse(cfg_file, process_config_kv, cfg);
|
||||
if (rc < 0) {
|
||||
PINELOG_ERROR(_("Failed processing configuration file %s - code %d"),
|
||||
cfg_file, rc);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct x52d_config_override {
|
||||
char *section;
|
||||
char *key;
|
||||
char *value;
|
||||
struct x52d_config_override *next;
|
||||
};
|
||||
|
||||
static struct x52d_config_override *override_head;
|
||||
static struct x52d_config_override *override_tail;
|
||||
|
||||
int x52d_config_save_override(const char *override_str)
|
||||
{
|
||||
// Parse override string of the form section.key=value
|
||||
struct x52d_config_override *override;
|
||||
char *string = NULL;
|
||||
char *free_ptr = NULL;
|
||||
char *ptr;
|
||||
int rc;
|
||||
|
||||
PINELOG_TRACE("Allocating memory (%lu bytes) for override structure", sizeof(*override));
|
||||
override = calloc(1, sizeof(*override));
|
||||
if (override == NULL) {
|
||||
PINELOG_ERROR(_("Failed to allocate memory for override structure"));
|
||||
rc = ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
PINELOG_TRACE("Duplicating override string");
|
||||
string = strdup(override_str);
|
||||
if (string == NULL) {
|
||||
PINELOG_ERROR(_("Failed to allocate memory for override string"));
|
||||
rc = errno;
|
||||
goto cleanup;
|
||||
}
|
||||
free_ptr = string;
|
||||
|
||||
override->section = string;
|
||||
// Ensure that the string is of the form ([^.]+\.[^=]+=.*)
|
||||
ptr = strchr(string, '.');
|
||||
if (ptr == NULL || ptr == string) {
|
||||
// No section found
|
||||
PINELOG_ERROR(_("No section found in override string '%s'"), string);
|
||||
rc = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
// Reset the . to NUL
|
||||
*ptr = '\0';
|
||||
ptr++;
|
||||
PINELOG_TRACE("Splitting override string to '%s' and '%s'", string, ptr);
|
||||
string = ptr;
|
||||
|
||||
override->key = string;
|
||||
ptr = strchr(string, '=');
|
||||
if (ptr == NULL || ptr == string) {
|
||||
// No key found
|
||||
PINELOG_ERROR(_("No key found in override string '%s'"), string);
|
||||
rc = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
// Reset the = to NUL
|
||||
*ptr = '\0';
|
||||
ptr++;
|
||||
PINELOG_TRACE("Splitting override string to '%s' and '%s'", string, ptr);
|
||||
|
||||
if (*ptr == '\0') {
|
||||
// No value found
|
||||
PINELOG_ERROR(_("No value found in override string '%s'"), string);
|
||||
rc = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
override->value = ptr;
|
||||
|
||||
// Add the override to the linked list
|
||||
if (override_tail != NULL) {
|
||||
PINELOG_TRACE("Linking override to list tail");
|
||||
override_tail->next = override;
|
||||
}
|
||||
PINELOG_TRACE("Setting list tail to override");
|
||||
override_tail = override;
|
||||
|
||||
if (override_head == NULL) {
|
||||
PINELOG_TRACE("Setting list head to override");
|
||||
override_head = override;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
if (free_ptr != NULL) {
|
||||
free(free_ptr);
|
||||
}
|
||||
if (override != NULL) {
|
||||
free(override);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int x52d_config_apply_overrides(struct x52d_config *cfg)
|
||||
{
|
||||
int rc;
|
||||
struct x52d_config_override *tmp = override_head;
|
||||
|
||||
if (cfg == NULL) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
while (tmp != NULL) {
|
||||
PINELOG_TRACE("Processing override '%s.%s=%s'",
|
||||
tmp->section,
|
||||
tmp->key,
|
||||
tmp->value);
|
||||
rc = process_config_kv(cfg,
|
||||
tmp->section,
|
||||
tmp->key,
|
||||
tmp->value);
|
||||
if (rc != 0) {
|
||||
PINELOG_ERROR(_("Error processing override '%s.%s=%s'"),
|
||||
tmp->section,
|
||||
tmp->key,
|
||||
tmp->value);
|
||||
return rc;
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void x52d_config_clear_overrides(void)
|
||||
{
|
||||
struct x52d_config_override *tmp;
|
||||
while (override_head != NULL) {
|
||||
tmp = override_head;
|
||||
override_head = override_head->next;
|
||||
PINELOG_TRACE("Freeing override '%s.%s=%s'",
|
||||
tmp->section,
|
||||
tmp->key,
|
||||
tmp->value);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
override_tail = NULL;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver - Application constants
|
||||
*
|
||||
* Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#ifndef X52D_CONST_H
|
||||
#define X52D_CONST_H
|
||||
|
||||
#define X52D_APP_NAME "x52d"
|
||||
|
||||
#define X52D_LOG_FILE LOGDIR "/" X52D_APP_NAME ".log"
|
||||
|
||||
#define X52D_SYS_CFG_FILE SYSCONFDIR "/" X52D_APP_NAME "/" X52D_APP_NAME ".conf"
|
||||
|
||||
#include "gettext.h"
|
||||
#define _(x) gettext(x)
|
||||
|
||||
#endif // !defined X52D_CONST_H
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver - Service daemon
|
||||
* * Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "x52d_const.h"
|
||||
#include "x52d_config.h"
|
||||
#include "pinelog.h"
|
||||
|
||||
static void set_log_file(bool foreground, const char *log_file)
|
||||
{
|
||||
int rc = 0;
|
||||
if (log_file != NULL) {
|
||||
rc = pinelog_set_output_file(log_file);
|
||||
} else {
|
||||
if (foreground) {
|
||||
rc = pinelog_set_output_stream(stdout);
|
||||
} else {
|
||||
rc = pinelog_set_output_file(X52D_LOG_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, _("Error %d setting log file: %s\n"), rc, strerror(rc));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(int exit_code)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("Usage: %s [-f] [-v] [-q] [-l log-file] [-o override] [-c config-file]\n"),
|
||||
X52D_APP_NAME);
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int verbosity = 0;
|
||||
bool quiet = false;
|
||||
bool foreground = false;
|
||||
char *log_file = NULL;
|
||||
char *conf_file = NULL;
|
||||
int opt;
|
||||
|
||||
/* Initialize gettext */
|
||||
#if ENABLE_NLS
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
#endif
|
||||
|
||||
/* Set system defaults */
|
||||
pinelog_set_level(PINELOG_LVL_WARNING);
|
||||
|
||||
/*
|
||||
* Parse command line arguments
|
||||
*
|
||||
* -f run in foreground
|
||||
* -c path to config file
|
||||
* -o option overrides
|
||||
* -v verbose logging
|
||||
* -q silent behavior
|
||||
* -l path to log file
|
||||
*/
|
||||
while ((opt = getopt(argc, argv, "fvql:o:c:h")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
foreground = true;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
if (!quiet) {
|
||||
if (verbosity <= PINELOG_LVL_TRACE) {
|
||||
verbosity++;
|
||||
pinelog_set_level(pinelog_get_level() + 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
quiet = true;
|
||||
pinelog_set_level(PINELOG_LVL_ERROR);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
log_file = optarg;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (x52d_config_save_override(optarg)) {
|
||||
fprintf(stderr,
|
||||
_("Unable to parse configuration override '%s'\n"),
|
||||
optarg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
conf_file = optarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage(EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
default:
|
||||
usage(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Foreground = %s\n", foreground ? "true" : "false");
|
||||
printf("Quiet = %s\n", quiet ? "true" : "false");
|
||||
printf("Verbosity = %d\n", verbosity);
|
||||
printf("Log file = %s\n", log_file);
|
||||
printf("Config file = %s\n", conf_file);
|
||||
|
||||
set_log_file(foreground, log_file);
|
||||
x52d_config_load(conf_file);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -10,3 +10,7 @@ utils/test/x52_test_clock.c
|
|||
utils/test/x52_test_common.h
|
||||
utils/test/x52_test_led.c
|
||||
utils/test/x52_test_mfd.c
|
||||
|
||||
daemon/x52d_main.c
|
||||
daemon/x52d_config.c
|
||||
daemon/x52d_config_parser.c
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: x52pro-linux 0.2.1\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/nirenjan/x52pro-linux/issues\n"
|
||||
"POT-Creation-Date: 2020-07-16 04:24-0700\n"
|
||||
"POT-Creation-Date: 2021-07-15 15:08-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -369,3 +369,61 @@ msgstr ""
|
|||
#: utils/test/x52_test_mfd.c:96
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_main.c:32
|
||||
#, c-format
|
||||
msgid "Error %d setting log file: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_main.c:40
|
||||
#, c-format
|
||||
msgid "Usage: %s [-f] [-v] [-q] [-l log-file] [-o override] [-c config-file]\n"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_main.c:101
|
||||
#, c-format
|
||||
msgid "Unable to parse configuration override '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_config.c:26
|
||||
#, c-format
|
||||
msgid "Error %d setting configuration defaults: %s"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_config_parser.c:130
|
||||
#, c-format
|
||||
msgid "Ignoring unknown key '%s.%s'"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_config_parser.c:171
|
||||
#, c-format
|
||||
msgid "Failed processing configuration file %s - code %d"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_config_parser.c:201
|
||||
msgid "Failed to allocate memory for override structure"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_config_parser.c:210
|
||||
msgid "Failed to allocate memory for override string"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_config_parser.c:221
|
||||
#, c-format
|
||||
msgid "No section found in override string '%s'"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_config_parser.c:235
|
||||
#, c-format
|
||||
msgid "No key found in override string '%s'"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_config_parser.c:246
|
||||
#, c-format
|
||||
msgid "No value found in override string '%s'"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_config_parser.c:297
|
||||
#, c-format
|
||||
msgid "Error processing override '%s.%s=%s'"
|
||||
msgstr ""
|
||||
|
|
66
po/xx_PL.po
66
po/xx_PL.po
|
@ -7,15 +7,15 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: x52pro-linux 0.2.1\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/nirenjan/x52pro-linux/issues\n"
|
||||
"POT-Creation-Date: 2020-07-16 04:24-0700\n"
|
||||
"PO-Revision-Date: 2020-07-13 18:05-0700\n"
|
||||
"POT-Creation-Date: 2021-07-15 15:08-0700\n"
|
||||
"PO-Revision-Date: 2021-07-15 15:09-0700\n"
|
||||
"Last-Translator: Nirenjan Krishnan <nirenjan@gmail.com>\n"
|
||||
"Language-Team: Dummy Language for testing i18n\n"
|
||||
"Language: xx_PL\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 2.3.1\n"
|
||||
"X-Generator: Poedit 3.0\n"
|
||||
|
||||
#: lib/libx52/x52_strerror.c:25 lib/libx52io/io_strings.c:104
|
||||
msgid "Success"
|
||||
|
@ -412,3 +412,63 @@ msgstr "Estingtay aracterchay 0x%02x..."
|
|||
#: utils/test/x52_test_mfd.c:96
|
||||
msgid "OK"
|
||||
msgstr "OKay"
|
||||
|
||||
#: daemon/x52d_main.c:32
|
||||
#, c-format
|
||||
msgid "Error %d setting log file: %s\n"
|
||||
msgstr "Erroray %d ettingsay oglay ilefay: %s\n"
|
||||
|
||||
#: daemon/x52d_main.c:40
|
||||
#, c-format
|
||||
msgid "Usage: %s [-f] [-v] [-q] [-l log-file] [-o override] [-c config-file]\n"
|
||||
msgstr ""
|
||||
"Usageay: %s [-f] [-v] [-q] [-l oglay-ilefay] [-o overrideay] [-c onfigcay-"
|
||||
"ilefay]\n"
|
||||
|
||||
#: daemon/x52d_main.c:101
|
||||
#, c-format
|
||||
msgid "Unable to parse configuration override '%s'\n"
|
||||
msgstr "Unableay otay arsepay onfigurationcay overrideay '%s'\n"
|
||||
|
||||
#: daemon/x52d_config.c:26
|
||||
#, c-format
|
||||
msgid "Error %d setting configuration defaults: %s"
|
||||
msgstr "Erroray %d ettingsay onfigurationcay efaultsday: %s"
|
||||
|
||||
#: daemon/x52d_config_parser.c:130
|
||||
#, c-format
|
||||
msgid "Ignoring unknown key '%s.%s'"
|
||||
msgstr "Ignoringay unknownay eykay '%s.%s'"
|
||||
|
||||
#: daemon/x52d_config_parser.c:171
|
||||
#, c-format
|
||||
msgid "Failed processing configuration file %s - code %d"
|
||||
msgstr "Ailedfay ocessingpray onfigurationcay ilefay %s - odecay %d"
|
||||
|
||||
#: daemon/x52d_config_parser.c:201
|
||||
msgid "Failed to allocate memory for override structure"
|
||||
msgstr "Ailedfay otay allocateay emorymay orfay overrideay ucturestray"
|
||||
|
||||
#: daemon/x52d_config_parser.c:210
|
||||
msgid "Failed to allocate memory for override string"
|
||||
msgstr "Ailedfay otay allocateay emorymay orfay overrideay ingstray"
|
||||
|
||||
#: daemon/x52d_config_parser.c:221
|
||||
#, c-format
|
||||
msgid "No section found in override string '%s'"
|
||||
msgstr "Onay ectionsay oundfay inay overrideay ingstray '%s'"
|
||||
|
||||
#: daemon/x52d_config_parser.c:235
|
||||
#, c-format
|
||||
msgid "No key found in override string '%s'"
|
||||
msgstr "Onay eykay oundfay inay overrideay ingstray '%s'"
|
||||
|
||||
#: daemon/x52d_config_parser.c:246
|
||||
#, c-format
|
||||
msgid "No value found in override string '%s'"
|
||||
msgstr "Onay aluevay oundfay inay overrideay ingstray '%s'"
|
||||
|
||||
#: daemon/x52d_config_parser.c:297
|
||||
#, c-format
|
||||
msgid "Error processing override '%s.%s=%s'"
|
||||
msgstr "Erroray ocessingpray overriday '%s.%s=%s'"
|
||||
|
|
Loading…
Reference in New Issue