diff options
Diffstat (limited to 'src/options.c')
-rw-r--r-- | src/options.c | 556 |
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 +} |