summaryrefslogtreecommitdiff
path: root/src/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/options.c')
-rw-r--r--src/options.c556
1 files changed, 556 insertions, 0 deletions
diff --git a/src/options.c b/src/options.c
new file mode 100644
index 0000000..7faa3ce
--- /dev/null
+++ b/src/options.c
@@ -0,0 +1,556 @@
+
+/*
+ * rhctl
+ *
+ * Copyright (C) 2009-2014 Christian Pointner <equinox@helsinki.at>
+ *
+ * This file is part of rhctl.
+ *
+ * rhctl is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * rhctl is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with rhctl. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "datatypes.h"
+
+#include "options.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "log.h"
+
+#define PARSE_BOOL_PARAM(SHORT, LONG, VALUE) \
+ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \
+ VALUE = 1;
+
+#define PARSE_INVERSE_BOOL_PARAM(SHORT, LONG, VALUE) \
+ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \
+ VALUE = 0;
+
+#define PARSE_INT_PARAM(SHORT, LONG, VALUE) \
+ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \
+ { \
+ if(argc < 1) \
+ return i; \
+ VALUE = atoi(argv[i+1]); \
+ argc--; \
+ i++; \
+ }
+
+#define PARSE_STRING_PARAM(SHORT, LONG, VALUE) \
+ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \
+ { \
+ if(argc < 1 || argv[i+1][0] == '-') \
+ return i; \
+ if(VALUE) free(VALUE); \
+ VALUE = strdup(argv[i+1]); \
+ if(!VALUE) \
+ return -2; \
+ argc--; \
+ i++; \
+ }
+
+#define PARSE_STRING_PARAM_SEC(SHORT, LONG, VALUE) \
+ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \
+ { \
+ if(argc < 1 || argv[i+1][0] == '-') \
+ return i; \
+ if(VALUE) free(VALUE); \
+ VALUE = strdup(argv[i+1]); \
+ if(!VALUE) \
+ return -2; \
+ size_t j; \
+ for(j=0; j < strlen(argv[i+1]); ++j) \
+ argv[i+1][j] = '#'; \
+ argc--; \
+ i++; \
+ }
+
+#define PARSE_HEXSTRING_PARAM_SEC(SHORT, LONG, VALUE) \
+ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \
+ { \
+ if(argc < 1 || argv[i+1][0] == '-') \
+ return i; \
+ int ret; \
+ ret = options_parse_hex_string(argv[i+1], &VALUE); \
+ if(ret > 0) \
+ return i+1; \
+ else if(ret < 0) \
+ return ret; \
+ size_t j; \
+ for(j=0; j < strlen(argv[i+1]); ++j) \
+ argv[i+1][j] = '#'; \
+ argc--; \
+ i++; \
+ }
+
+#define PARSE_STRING_LIST(SHORT, LONG, LIST) \
+ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \
+ { \
+ if(argc < 1 || argv[i+1][0] == '-') \
+ return i; \
+ int ret = string_list_add(&LIST, argv[i+1]); \
+ if(ret == -2) \
+ return ret; \
+ else if(ret) \
+ return i+1; \
+ argc--; \
+ i++; \
+ }
+
+int options_parse_hex_string(const char* hex, buffer_t* buffer)
+{
+ if(!hex || !buffer)
+ return -1;
+
+ u_int32_t hex_len = strlen(hex);
+ if(hex_len%2)
+ return 1;
+
+ if(buffer->buf_)
+ free(buffer->buf_);
+
+ buffer->length_ = hex_len/2;
+ buffer->buf_ = malloc(buffer->length_);
+ if(!buffer->buf_) {
+ buffer->length_ = 0;
+ return -2;
+ }
+
+ const char* ptr = hex;
+ int i;
+ for(i=0;i<buffer->length_;++i) {
+ u_int32_t tmp;
+ sscanf(ptr, "%2X", &tmp);
+ buffer->buf_[i] = (u_int8_t)tmp;
+ ptr += 2;
+ }
+
+ return 0;
+}
+
+
+
+int options_parse(options_t* opt, int argc, char* argv[])
+{
+ if(!opt)
+ return -1;
+
+ options_default(opt);
+
+ if(opt->progname_)
+ free(opt->progname_);
+ opt->progname_ = strdup(argv[0]);
+ if(!opt->progname_)
+ return -2;
+
+ argc--;
+
+ char* mode = NULL;
+ char* channel = NULL;
+ char* baudrate = NULL;
+
+ int i;
+ for(i=1; argc > 0; ++i)
+ {
+ char* str = argv[i];
+ argc--;
+
+ if(!strcmp(str,"-h") || !strcmp(str,"--help"))
+ return -1;
+#ifndef OPT_STDIOCLIENT
+ PARSE_INVERSE_BOOL_PARAM("-D","--nodaemonize", opt->daemonize_)
+ PARSE_STRING_PARAM("-u","--username", opt->username_)
+ PARSE_STRING_PARAM("-g","--groupname", opt->groupname_)
+ PARSE_STRING_PARAM("-C","--chroot", opt->chroot_dir_)
+ PARSE_STRING_PARAM("-P","--write-pid", opt->pid_file_)
+#endif
+ PARSE_STRING_LIST("-L","--log", opt->log_targets_)
+ PARSE_STRING_PARAM("-s","--command-sock", opt->command_sock_)
+#ifndef OPT_STDIOCLIENT
+ PARSE_STRING_PARAM("-b","--baudrate", baudrate)
+#endif
+#ifdef OPT_SWITCHCTL
+ PARSE_STRING_PARAM("-f","--config", opt->conf_file_)
+ PARSE_STRING_PARAM("-d","--device", opt->switch_dev_)
+ PARSE_STRING_PARAM("-m","--mode", mode)
+ PARSE_STRING_PARAM("-c","--channel", channel)
+#endif
+#ifdef OPT_SERIALCLIENT
+ PARSE_STRING_PARAM("-d","--device", opt->serial_dev_)
+ PARSE_STRING_PARAM("-t","--type", opt->type_)
+#endif
+#ifdef OPT_HEARTBEATCLIENT
+ PARSE_STRING_PARAM("-d","--device", opt->serial_dev_)
+ PARSE_INT_PARAM("-t","--timeout", opt->timeout_)
+ PARSE_STRING_PARAM("-l","--led", opt->led_filename_)
+#endif
+#ifdef OPT_LUACLIENT
+ PARSE_STRING_PARAM("-f","--lua-file", opt->lua_file_)
+#endif
+ else
+ return i;
+ }
+
+ if(mode) {
+ if(!strcmp(mode, "master"))
+ opt->mode_ = MODE_MASTER;
+ else if(!strcmp(mode, "standby"))
+ opt->mode_ = MODE_STANDBY;
+ else {
+ free(mode);
+ return -3;
+ }
+ free(mode);
+ }
+
+ if(channel) {
+ if(!strcmp(channel, "main")) {
+ opt->channel_master_ = CHAN_MAIN;
+ opt->channel_standby_ = CHAN_MAIN;
+ }
+ else if(!strcmp(channel, "music")) {
+ opt->channel_master_ = CHAN_MUSIC;
+ opt->channel_standby_ = CHAN_MUSIC;
+ }
+ else {
+ free(channel);
+ return -4;
+ }
+ free(channel);
+ }
+
+ if(baudrate) {
+ int b = atoi(baudrate);
+ free(baudrate);
+ switch(b) {
+ case 1200: opt->baudrate_ = B1200; break;
+ case 2400: opt->baudrate_ = B2400; break;
+ case 4800: opt->baudrate_ = B4800; break;
+ case 9600: opt->baudrate_ = B9600; break;
+ case 19200: opt->baudrate_ = B19200; break;
+ case 38400: opt->baudrate_ = B38400; break;
+ case 57600: opt->baudrate_ = B57600; break;
+ case 115200: opt->baudrate_ = B115200; break;
+ default: return -5;
+ }
+ }
+
+ return 0;
+}
+
+int options_parse_post(options_t* opt)
+{
+ if(!opt)
+ return -1;
+// nothing to do
+
+#ifdef OPT_SWITCHCTL
+ FILE* conf_file = fopen(opt->conf_file_, "r");
+ if(conf_file) {
+ char buf[100];
+ while(fgets(buf, 100, conf_file) != NULL) {
+ char* tmp, *key, *value;
+ for(tmp = buf;*tmp == ' '; ++tmp);
+ if(*(key = tmp) == 0) continue;
+ for(;*tmp != ' ' && *tmp != 0;++tmp);
+ if(*tmp == 0) continue;
+ *tmp=0;
+ ++tmp;
+ for(;*tmp == ' ';++tmp);
+ if(*(value = tmp) == 0) continue;
+ for(;*tmp != ' ' && *tmp != 0 && *tmp != '\n';++tmp);
+ *tmp = 0;
+
+ if(key_value_storage_add(&opt->alias_table_, key, value))
+ return -2;
+ }
+ fclose(conf_file);
+ }
+ else {
+ log_printf(ERROR,"unable to open conf file (%s): %s", opt->conf_file_, strerror(errno));
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+void options_default(options_t* opt)
+{
+ if(!opt)
+ return;
+
+#ifdef OPT_SWITCHCTL
+ opt->progname_ = strdup("switchctl");
+#endif
+#ifdef OPT_SERIALCLIENT
+ opt->progname_ = strdup("serialclient");
+#endif
+#ifdef OPT_STDIOCLIENT
+ opt->progname_ = strdup("stdioclient");
+#endif
+#ifdef OPT_HEARTBEATCLIENT
+ opt->progname_ = strdup("heartbeatclient");
+#endif
+#ifdef OPT_LUACLIENT
+ opt->progname_ = strdup("luaclient");
+#endif
+
+/* common */
+ opt->daemonize_ = 1;
+ opt->username_ = NULL;
+ opt->groupname_ = NULL;
+ opt->chroot_dir_ = NULL;
+ opt->pid_file_ = NULL;
+ string_list_init(&opt->log_targets_);
+
+ opt->command_sock_ = strdup("/var/run/rhctl/switchctl.sock");
+ opt->baudrate_ = B19200;
+
+/* switchctl */
+ opt->mode_ = MODE_MASTER;
+ opt->channel_master_ = CHAN_MAIN;
+ opt->channel_standby_ = CHAN_MAIN;
+ opt->conf_file_ = strdup("/etc/rhctl/switchctl.conf");
+ opt->switch_dev_ = strdup("/dev/audioswitch");
+ key_value_storage_init(&opt->alias_table_);
+
+/* serialclient and heartbeatclient */
+ opt->serial_dev_ = strdup("/dev/ttyUSB0");
+
+/* serialclient only */
+ opt->type_ = NULL;
+
+/* heartbeatclient only */
+ opt->timeout_ = 15;
+ opt->led_filename_ = NULL;
+
+/* luaclient only */
+ opt->lua_file_ = strdup("/usr/share/rhctl/mode-leds.lua");
+}
+
+#ifdef OPT_LUACLIENT
+void options_lua_push_string(lua_State* L, const int tidx, const char* key, const char* value)
+{
+ lua_pushstring(L, key);
+ lua_pushstring(L, value);
+ lua_settable(L, tidx);
+}
+
+void options_lua_push_int(lua_State* L, const int tidx, const char* key, const u_int32_t value)
+{
+ lua_pushstring(L, key);
+ lua_pushinteger(L, value);
+ lua_settable(L, tidx);
+}
+
+void options_lua_push_boolean(lua_State* L, const int tidx, const char* key, const u_int32_t value)
+{
+ lua_pushstring(L, key);
+ lua_pushboolean(L, value);
+ lua_settable(L, tidx);
+}
+
+void options_lua_push_string_list(lua_State* L, const int tidx, string_list_t* lst)
+{
+ if(!lst)
+ return;
+
+ string_list_element_t* tmp = lst->first_;
+ if(tmp) {
+ lua_pushstring(L, "log_targets");
+ lua_newtable(L);
+ int i = 1;
+ while(tmp) {
+ lua_pushinteger(L, i++);
+ lua_pushstring(L, tmp->string_);
+ lua_settable(L, -3);
+ tmp = tmp->next_;
+ }
+ lua_settable(L, tidx);
+ }
+}
+
+void options_lua_push(options_t* opt, lua_State* L)
+{
+ lua_newtable(L);
+
+ options_lua_push_string(L, -3, "progname", opt->progname_);
+ options_lua_push_boolean(L, -3, "daemonize", opt->daemonize_);
+ options_lua_push_string(L, -3, "username", opt->username_);
+ options_lua_push_string(L, -3, "groupname", opt->groupname_);
+ options_lua_push_string(L, -3, "chroot_dir", opt->chroot_dir_);
+ options_lua_push_string(L, -3, "pid_file", opt->pid_file_);
+ options_lua_push_string_list(L, -3, &(opt->log_targets_));
+ options_lua_push_string(L, -3, "command_sock", opt->command_sock_);
+ options_lua_push_string(L, -3, "lua_file", opt->lua_file_);
+}
+#endif
+
+void options_clear(options_t* opt)
+{
+ if(!opt)
+ return;
+
+/* common */
+ if(opt->progname_)
+ free(opt->progname_);
+ if(opt->username_)
+ free(opt->username_);
+ if(opt->groupname_)
+ free(opt->groupname_);
+ if(opt->chroot_dir_)
+ free(opt->chroot_dir_);
+ if(opt->pid_file_)
+ free(opt->pid_file_);
+ string_list_clear(&opt->log_targets_);
+
+ if(opt->command_sock_)
+ free(opt->command_sock_);
+
+/* switchctl */
+ if(opt->conf_file_)
+ free(opt->conf_file_);
+ if(opt->switch_dev_)
+ free(opt->switch_dev_);
+ key_value_storage_clear(&opt->alias_table_);
+
+/* serialclient and heartbeatclient */
+ if(opt->serial_dev_)
+ free(opt->serial_dev_);
+
+/* serialclient only */
+ if(opt->type_)
+ free(opt->type_);
+
+/* heartbeatcleint only */
+ if(opt->led_filename_)
+ free(opt->led_filename_);
+
+/* luaclient only */
+ if(opt->lua_file_)
+ free(opt->lua_file_);
+}
+
+void options_print_usage()
+{
+ printf("USAGE:\n");
+#ifdef OPT_SWITCHCTL
+ printf("switchctl\n");
+#endif
+#ifdef OPT_SERIALCLIENT
+ printf("serialclient\n");
+#endif
+#ifdef OPT_STDIOCLIENT
+ printf("serialclient\n");
+#endif
+#ifdef OPT_HEARTBEATCLIENT
+ printf("heartbeatclient\n");
+#endif
+ printf(" [-h|--help] prints this...\n");
+#ifndef OPT_STDIOCLIENT
+ printf(" [-D|--nodaemonize] don't run in background\n");
+ printf(" [-u|--username] <username> change to this user\n");
+ printf(" [-g|--groupname] <groupname> change to this group\n");
+ printf(" [-C|--chroot] <path> chroot to this directory\n");
+ printf(" [-P|--write-pid] <path> write pid to this file\n");
+#endif
+ printf(" [-L|--log] <target>:<level>[,<param1>[,<param2>..]]\n");
+ printf(" add a log target, can be invoked several times\n");
+ printf(" [-s|--command-sock] <unix sock> the command socket e.g. /var/run/rhctl/switchctl.sock\n");
+#ifndef OPT_STDIOCLIENT
+ printf(" [-b|--baudrate] <baudrate> the baudrate of the tty to use e.g. 19200\n");
+#endif
+#ifdef OPT_SWITCHCTL
+ printf(" [-d|--device] <tty> the tty the audio switch is connected to e.g. /dev/audioswitch\n");
+ printf(" [-f|--config] <file> the configuration file e.g. /etc/rhctl/switchctl.conf\n");
+ printf(" [-m|--mode] <mode> the initial mode to use e.g. master\n");
+ printf(" [-c|--channel] <channel> the initial channel to use e.g. main\n");
+#endif
+#ifdef OPT_SERIALCLIENT
+ printf(" [-d|--device] <tty> the tty to connect to e.g. /dev/ttyUSB0\n");
+ printf(" [-t|--type] <type> use this client type\n");
+#endif
+#ifdef OPT_HEARTBEATCLIENT
+ printf(" [-d|--device] <tty> the tty to connect to e.g. /dev/ttyUSB0\n");
+ printf(" [-t|--timeout] <timeout> heartbeat timeout in tenths of a second e.g. 15 -> 1.5s\n");
+ printf(" [-l|--led] <led filename> sysfs filename of led device to blink\n");
+#endif
+#ifdef OPT_LUACLIENT
+ printf(" [-f|--lua-file] <file> the configuration file e.g. /usr/share/rhctl/mode-leds.lua\n");
+#endif
+}
+
+void options_print(options_t* opt)
+{
+ if(!opt)
+ return;
+
+ printf("progname: '%s'\n", opt->progname_);
+#ifndef OPT_STDIOCLIENT
+ printf("daemonize: %d\n", opt->daemonize_);
+ printf("username: '%s'\n", opt->username_);
+ printf("groupname: '%s'\n", opt->groupname_);
+ printf("chroot_dir: '%s'\n", opt->chroot_dir_);
+ printf("pid_file: '%s'\n", opt->pid_file_);
+#endif
+ printf("log_targets: \n");
+ string_list_print(&opt->log_targets_, " '", "'\n");
+
+ printf("command_sock: '%s'\n", opt->command_sock_);
+
+#ifndef OPT_STDIOCLIENT
+ char* br;
+ switch(opt->baudrate_) {
+ case B1200: br = "1200"; break;
+ case B2400: br = "2400"; break;
+ case B4800: br = "4800"; break;
+ case B9600: br = "9600"; break;
+ case B19200: br = "19200"; break;
+ case B38400: br = "38400"; break;
+ case B57600: br = "57600"; break;
+ case B115200: br = "115200"; break;
+ default: br = "invalid"; break;
+ }
+ printf("baudrate: '%s'\n", br);
+#endif
+
+#ifdef OPT_SWITCHCTL
+ printf("mode: '%s'\n", opt->mode_ == MODE_MASTER ? "master" : "standby");
+ printf("channel_master: '%s'\n", opt->channel_master_ == CHAN_MAIN ? "main" : "music");
+ printf("channel_standby: '%s'\n", opt->channel_standby_ == CHAN_MAIN ? "main" : "music");
+ printf("conf_file: '%s'\n", opt->conf_file_);
+ printf("switch_dev: '%s'\n", opt->switch_dev_);
+ printf("alias_table: \n");
+ key_value_storage_print(&opt->alias_table_, " '", "' -> '", "'\n");
+#endif
+
+#ifdef OPT_SERIALCLIENT
+ printf("serial_dev: '%s'\n", opt->serial_dev_);
+ printf("type: '%s'\n", opt->type_);
+#endif
+
+#ifdef OPT_HEARTBEATCLIENT
+ printf("serial_dev: '%s'\n", opt->serial_dev_);
+ printf("timeout: %d\n", opt->timeout_);
+ printf("led_filename: '%s'\n", opt->led_filename_);
+#endif
+
+#ifdef OPT_LUACLIENT
+ printf("lua_file: '%s'\n", opt->lua_file_);
+#endif
+}