From 74b1f415207eb441ce3f7b1fcc346455dcff62d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Wed, 10 Oct 2012 21:33:16 +0200 Subject: [PATCH 001/121] Initial conf library. Just parse tokens. --- common/Makefile.am | 4 +- common/nutconf.cpp | 774 +++++++++++++++++++++++++++++++++++++++++++++ include/nutconf.h | 279 ++++++++++++++++ tests/Makefile.am | 5 +- tests/nutconf.cpp | 132 ++++++++ 5 files changed, 1191 insertions(+), 3 deletions(-) create mode 100644 common/nutconf.cpp create mode 100644 include/nutconf.h create mode 100644 tests/nutconf.cpp diff --git a/common/Makefile.am b/common/Makefile.am index 6dda04acdd..ad667799e3 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -2,9 +2,11 @@ AM_CFLAGS = -I$(top_srcdir)/include -noinst_LTLIBRARIES = libparseconf.la libcommon.la +noinst_LTLIBRARIES = libparseconf.la libcommon.la libnutconf.la libparseconf_la_SOURCES = parseconf.c +libnutconf_la_SOURCES = nutconf.cpp + # do not hard depend on '../include/nut_version.h', since it blocks # 'dist', and is only required for actual build, in which case # BUILT_SOURCES (in ../include) will ensure nut_version.h will diff --git a/common/nutconf.cpp b/common/nutconf.cpp new file mode 100644 index 0000000000..b744085854 --- /dev/null +++ b/common/nutconf.cpp @@ -0,0 +1,774 @@ +/* nutconf.cpp - configuration API + + Copyright (C) + 2012 Emilien Kia + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include + +#include "nutconf.h" + + +namespace nut +{ + +// +// NutConfigParser +// + +NutConfigParser::NutConfigParser(const char* buffer): +_buffer(buffer), +_pos(0) +{ +} + +NutConfigParser::NutConfigParser(const std::string& buffer): +_buffer(buffer), +_pos(0) +{ +} + +char NutConfigParser::get() +{ + if(_pos>=_buffer.size()) + return 0; + else + return _buffer[_pos++]; +} + +char NutConfigParser::peek() +{ + return _buffer[_pos]; +} + +size_t NutConfigParser::getPos()const +{ + return _pos; +} + +void NutConfigParser::setPos(size_t pos) +{ + _pos = pos; +} + +char NutConfigParser::charAt(size_t pos)const +{ + return _buffer[pos]; +} + +void NutConfigParser::pushPos() +{ + _stack.push_back(_pos); +} + +size_t NutConfigParser::popPos() +{ + size_t pos = _stack.back(); + _stack.pop_back(); + return pos; +} + +void NutConfigParser::rewind() +{ + _pos = popPos(); +} + +void NutConfigParser::back() +{ + if(_pos>0) + --_pos; +} + + +/* Parse a string source for a CHARS and return its size if found or 0, if not. + * CHARS ::= CHAR+ + * CHAR ::= __ASCIICHAR__ - ( __SPACES__ | '\\' | '\"' | '#' ) + * | '\\' ( __SPACES__ | '\\' | '\"' | '#' ) + * TODO: accept "\t", "\s", "\r", "\n" ?? + */ +std::string NutConfigParser::parseCHARS() +{ + bool escaped = false; // Is char escaped ? + std::string res; // Stored string + + pushPos(); + + for (char c = get(); c != 0 /*EOF*/; c = get()) + { + if (escaped) + { + if (isspace(c) || c == '\\' || c == '"' || c == '#') + { + res += c; + } + else + { + /* WTF ??? */ + } + escaped = false; + } + else + { + if (c == '\\') + { + escaped = true; + } + else if (isgraph(c) /*&& c != '\\'*/ && c != '"' && c != '#') + { + res += c; + } + else + { + back(); + break; + } + } + } + + popPos(); + return res; +} + + + +/* Parse a string source for a STRCHARS and return its size if found or 0, if not. + * STRCHARS ::= STRCHAR+ + * STRCHAR ::= __ASCIICHAR__ - ( '\\' | '\"') + * | '\\' ( '\\' | '\"' ) + * TODO: accept "\t", "\s", "\r", "\n" ?? + */ +std::string NutConfigParser::parseSTRCHARS() +{ + bool escaped = false; // Is char escaped ? + std::string str; // Stored string + + pushPos(); + + for (char c = get(); c != 0 /*EOF*/; c = get()) + { + if (escaped) + { + if (isspace(c) || c == '\\' || c == '"') + { + str += c; + } + else + { + /* WTF ??? */ + } + escaped = false; + } + else + { + if (c == '\\') + { + escaped = true; + } + else if (isprint(c) && c != '\\' && c != '"') + { + str += c; + } + else + { + back(); + break; + } + } + } + + popPos(); + return str; +} + + + +/** Parse a string source for getting the next token, ignoring spaces. + * \return Token type. + */ +NutConfigParser::Token NutConfigParser::parseToken() +{ + /** Lexical parsing machine state enumeration.*/ + typedef enum { + LEXPARSING_STATE_DEFAULT, + LEXPARSING_STATE_QUOTED_STRING, + LEXPARSING_STATE_STRING, + LEXPARSING_STATE_COMMENT + }LEXPARSING_STATE_e; + LEXPARSING_STATE_e state = LEXPARSING_STATE_DEFAULT; + + Token token; + bool escaped = false; + + pushPos(); + + for (char c = get(); c != 0 /*EOF*/; c = get()) + { + switch (state) + { + case LEXPARSING_STATE_DEFAULT: /* Wait for a non-space char */ + { + if (c == ' ' || c == '\t') + { + /* Space : do nothing */ + } + else if (c == '[') + { + token = Token(Token::TOKEN_BRACKET_OPEN, c); + popPos(); + return token; + } + else if (c == ']') + { + token = Token(Token::TOKEN_BRACKET_CLOSE, c); + popPos(); + return token; + } + else if (c == ':') + { + token = Token(Token::TOKEN_COLON, c); + popPos(); + return token; + } + else if (c == '=') + { + token = Token(Token::TOKEN_EQUAL, c); + popPos(); + return token; + } + else if (c == '\r' || c == '\n') + { + token = Token(Token::TOKEN_EOL, c); + popPos(); + return token; + } + else if (c == '#') + { + token.type = Token::TOKEN_COMMENT; + state = LEXPARSING_STATE_COMMENT; + } + else if (c == '"') + { + /* Begin of QUOTED STRING */ + token.type = Token::TOKEN_QUOTED_STRING; + state = LEXPARSING_STATE_QUOTED_STRING; + } + else if (c == '\\') + { + /* Begin of STRING with escape */ + token.type = Token::TOKEN_STRING; + state = LEXPARSING_STATE_STRING; + escaped = true; + } + else if (isgraph(c)) + { + /* Begin of STRING */ + token.type = Token::TOKEN_STRING; + state = LEXPARSING_STATE_STRING; + token.str += c; + } + else + { + rewind(); + return Token(Token::TOKEN_UNKNOWN); + } + break; + } + case LEXPARSING_STATE_QUOTED_STRING: + { + if (c == '"') + { + if(escaped) + { + escaped = false; + token.str += '"'; + } + else + { + popPos(); + return token; + } + } + else if (c == '\\') + { + if (escaped) + { + escaped = false; + token.str += '\\'; + } + else + { + escaped = true; + } + } + else if (c == ' ' || c == '\t' || isgraph(c)) + { + token.str += c; + } + else if(c == 0) /* EOL */ + { + popPos(); + return token; + } + else /* Bad character ?? */ + { + /* WTF ? Keep, Ignore ? */ + } + /* TODO What about other escaped character ? */ + break; + } + case LEXPARSING_STATE_STRING: + { + if (c == ' ' || c == '"' || c == '#' || c == '[' || c == ']' || c == ':' || c == '=') + { + if (escaped) + { + escaped = false; + token.str += c; + } + else + { + back(); + popPos(); + return token; + } + } + else if (c == '\\') + { + if (escaped) + { + escaped = false; + token.str += c; + } + else + { + escaped = true; + } + } + /* else if (c == '\r' || c == '\n') */ + else if (isgraph(c)) + { + token.str += c; + } + else /* Bad character ?? */ + { + /* WTF ? Keep, Ignore ? */ + } + /* TODO What about escaped character ? */ + break; + } + case LEXPARSING_STATE_COMMENT: + { + if (c == '\r' || c == '\n') + { + return token; + } + else + { + token.str += c; + } + break; + } + default: + /* Must not occur. */ + break; + } + } + popPos(); + return token; +} + + +std::list NutConfigParser::parseLine() +{ + std::list res; + + while(true) + { + NutConfigParser::Token token = parseToken(); + + switch(token.type) + { + + } + } + + return res; +} + +} /* namespace nut */ + + + + + + + +#if 0 + +/** Parse a string source for a line. + * \param src Begin of text source to parse. + * \param len Size of text source to parse in byte. + * \param[out] rend Pointer where store end of line (address of byte following + * the last character of the line, so the size of line is end-src). + * \param[out] parsed_line Parsed line result. + * TODO Handle end-of-file + */ +void nutconf_parse_line(const char* src, unsigned int len, + const char** rend, SYNLINE_t* parsed_line) +{ + PARSING_TOKEN_e directive_separator = TOKEN_NONE; + SYNPARSING_STATE_e state = SYNPARSING_STATE_INIT; + SYNPARSING_LINETYPE_e line_type = SYNPARSING_LINETYPE_UNKNWON; + + LEXTOKEN_t current; + +/* Little macros (state-machine sub-functions) to reuse in this function: */ + +/* Add current token to arg list.*/ +#define nutconf_parse_line__PUSH_ARG() \ +{\ + if (parsed_line->arg_count < parsed_line->nb_args-1)\ + {\ + LEXTOKEN_copy(&parsed_line->args[parsed_line->arg_count], ¤t);\ + parsed_line->arg_count++;\ + }\ + /* TODO Add args overflow handling. */\ +} +/* Set comment and end state machine: */ +#define nutconf_parse_line__SET_COMMENT_AND_END_STM() \ +{\ + LEXTOKEN_copy(&parsed_line->comment, ¤t);\ + state = SYNPARSING_STATE_FINISHED;\ +} + + if (parsed_line == NULL) + { + return; /* TODO add error code. */ + } + /* Init returned values */ + parsed_line->line_type = SYNPARSING_LINETYPE_UNKNWON; + parsed_line->directive_separator = TOKEN_NONE; + parsed_line->arg_count = 0; + LEXTOKEN_set(&parsed_line->comment, NULL, NULL, TOKEN_NONE); + + /* Lets parse */ + while (TRUE) + { + nutconf_parse_token(src, len, ¤t); + switch (state) + { + case SYNPARSING_STATE_INIT: + switch (current.type) + { + case TOKEN_COMMENT: /* Line with only a comment. */ + line_type = SYNPARSING_LINETYPE_COMMENT; + nutconf_parse_line__SET_COMMENT_AND_END_STM(); + break; + case TOKEN_BRACKET_OPEN: /* Begin of a section. */ + state = SYNPARSING_STATE_SECTION_BEGIN; + break; + case TOKEN_STRING: /* Begin of a directive line. */ + case TOKEN_QUOTED_STRING: + nutconf_parse_line__PUSH_ARG(); + state = SYNPARSING_STATE_DIRECTIVE_BEGIN; + break; + default: + /* Must not occur. */ + /* TODO WTF ? .*/ + break; + } + break; + case SYNPARSING_STATE_SECTION_BEGIN: + switch (current.type) + { + case TOKEN_BRACKET_CLOSE: /* Empty section. */ + state = SYNPARSING_STATE_SECTION_END; + break; + case TOKEN_STRING: /* Section name. */ + case TOKEN_QUOTED_STRING: + nutconf_parse_line__PUSH_ARG(); + state = SYNPARSING_STATE_SECTION_NAME; + break; + default: + /* Must not occur. */ + /* TODO WTF ? .*/ + break; + } + break; + case SYNPARSING_STATE_SECTION_NAME: + switch (current.type) + { + case TOKEN_BRACKET_CLOSE: /* End of named section. */ + state = SYNPARSING_STATE_SECTION_END; + break; + default: + /* Must not occur. */ + /* TODO WTF ? .*/ + break; + } + break; + case SYNPARSING_STATE_SECTION_END: + switch (current.type) + { + case TOKEN_COMMENT: + line_type = SYNPARSING_LINETYPE_SECTION; + nutconf_parse_line__SET_COMMENT_AND_END_STM(); + break; + case TOKEN_EOL: + line_type = SYNPARSING_LINETYPE_SECTION; + state = SYNPARSING_STATE_FINISHED; + break; + default: + /* Must not occur. */ + /* TODO WTF ? .*/ + break; + } + break; + case SYNPARSING_STATE_DIRECTIVE_BEGIN: + switch (current.type) + { + case TOKEN_COLON: /* Directive with ':'.*/ + case TOKEN_EQUAL: /* Directive with '='.*/ + directive_separator = current.type; + state = SYNPARSING_STATE_DIRECTIVE_ARGUMENT; + break; + case TOKEN_STRING: /* Directive direct argument, no separator. */ + case TOKEN_QUOTED_STRING: + nutconf_parse_line__PUSH_ARG(); + state = SYNPARSING_STATE_DIRECTIVE_ARGUMENT; + break; + case TOKEN_COMMENT: + line_type = SYNPARSING_LINETYPE_DIRECTIVE_NOSEP; + nutconf_parse_line__SET_COMMENT_AND_END_STM(); + break; + case TOKEN_EOL: + line_type = SYNPARSING_LINETYPE_DIRECTIVE_NOSEP; + state = SYNPARSING_STATE_FINISHED; + break; + default: + /* Must not occur. */ + /* TODO WTF ? .*/ + break; + } + break; + case SYNPARSING_STATE_DIRECTIVE_ARGUMENT: + switch (current.type) + { + case TOKEN_STRING: /* Directive argument. */ + case TOKEN_QUOTED_STRING: + nutconf_parse_line__PUSH_ARG(); + /* Keep here, in SYNPARSING_STATE_DIRECTIVE_ARGUMENT state.*/ + break; + case TOKEN_COMMENT: + /* TODO signal directive with comment */ + nutconf_parse_line__SET_COMMENT_AND_END_STM(); + break; + case TOKEN_EOL: + line_type = SYNPARSING_LINETYPE_DIRECTIVE_NOSEP; + state = SYNPARSING_STATE_FINISHED; + break; + default: + /* Must not occur. */ + /* TODO WTF ? .*/ + break; + } + break; + default: + /* Must not occur. */ + /* TODO WTF ? .*/ + break; + } + + src = *rend = current.end; + if (state == SYNPARSING_STATE_FINISHED) + break; /* Go out infinite while loop. */ + } + + if (line_type == SYNPARSING_LINETYPE_DIRECTIVE_NOSEP) + { + if (directive_separator == TOKEN_COLON) + { + line_type = SYNPARSING_LINETYPE_DIRECTIVE_COLON; + } + else if (directive_separator == TOKEN_EQUAL) + { + line_type = SYNPARSING_LINETYPE_DIRECTIVE_EQUAL; + } + } + + /* End of process : save data for returning */ + parsed_line->line_type = line_type; + parsed_line->directive_separator = directive_separator; + +#undef nutconf_parse_line__PUSH_ARG +#undef nutconf_parse_line__SET_COMMENT_AND_END_STM +} + + +/* Parse a string source, memory mapping of a conf file. + * End the parsing at the end of file (ie null-char, specified size + * or error). + */ +void nutconf_parse_memory(const char* src, int len, + nutconf_parse_line_callback cb, void* user_data) +{ + const char* rend = src; + SYNLINE_t parsed_line; + LEXTOKEN_t tokens[16]; + + parsed_line.args = tokens; + parsed_line.nb_args = 16; + + while (len > 0) + { + nutconf_parse_line(src, len, &rend, &parsed_line); + + cb(&parsed_line, user_data); + + len -= rend - src; + src = rend; + } +} + + + + +typedef struct { + NUTCONF_t* conf; + NUTCONF_SECTION_t* current_section; + NUTCONF_ARG_t* current_arg; +}NUTCONF_CONF_PARSE_t; + +static void nutconf_conf_parse_callback(SYNLINE_t* line, void* user_data) +{ + NUTCONF_CONF_PARSE_t* parse = (NUTCONF_CONF_PARSE_t*)user_data; + int num; + + /* Verify parameters */ + if (parse==NULL) + { + return; + } + + /* Parsing state treatment */ + switch (line->line_type) + { + case SYNPARSING_LINETYPE_SECTION: + if (parse->current_section == NULL) + { + /* No current section - begin of the parsing.*/ + /* Use conf as section .*/ + parse->current_section = parse->conf; + } + else + { + /* Already have a section, add new one to chain. */ + parse->current_section->next = malloc(sizeof(NUTCONF_SECTION_t)); + parse->current_section = parse->current_section->next; + memset(parse->current_section, 0, sizeof(NUTCONF_SECTION_t)); + parse->current_arg = NULL; + } + /* Set the section name. */ + if (line->arg_count > 0) + { + parse->current_section->name = LEXTOKEN_chralloc(&line->args[0]); + } + break; + case SYNPARSING_LINETYPE_DIRECTIVE_COLON: + case SYNPARSING_LINETYPE_DIRECTIVE_EQUAL: + case SYNPARSING_LINETYPE_DIRECTIVE_NOSEP: + if (line->arg_count < 1) + { + /* No directive if no argument. */ + break; + } + + if (parse->current_section == NULL) + { + /* No current section - begin of the parsing.*/ + /* Use conf as section .*/ + parse->current_section = parse->conf; + } + + /* Add a new argument. */ + if (parse->current_arg != NULL) + { + parse->current_arg->next = malloc(sizeof(NUTCONF_ARG_t)); + parse->current_arg = parse->current_arg->next; + } + else + { + parse->current_arg = malloc(sizeof(NUTCONF_ARG_t)); + } + memset(parse->current_arg, 0, sizeof(NUTCONF_ARG_t)); + + /* Set directive name. */ + parse->current_arg->name = LEXTOKEN_chralloc(&line->args[0]); + + /* Set directive type. */ + switch(line->line_type) + { + case SYNPARSING_LINETYPE_DIRECTIVE_COLON: + parse->current_arg->type = NUTCONF_ARG_COLON; + break; + case SYNPARSING_LINETYPE_DIRECTIVE_EQUAL: + parse->current_arg->type = NUTCONF_ARG_EQUAL; + break; + default: + parse->current_arg->type = NUTCONF_ARG_NONE; + break; + } + + /* TODO Add directive values.*/ + for(num=1; numarg_count; num++) + { + /* ... */ + } + + break; + default: + /* Do nothing (unknown or comment. */ + break; + } +} + +NUTCONF_t* nutconf_conf_parse(const char* src, int len) +{ + NUTCONF_CONF_PARSE_t parse; + + /* Validate parameters */ + if (src==NULL || len <=0) + { + return NULL; + } + + /* Initialize working structures */ + memset(&parse.conf, 0, sizeof(NUTCONF_CONF_PARSE_t)); + parse.conf = malloc(sizeof(NUTCONF_t)); + memset(parse.conf, 0, sizeof(NUTCONF_t)); + + /* Do the parsing. */ + nutconf_parse_memory(src, len, nutconf_conf_parse_callback, &parse); + + /* TODO Test for successfull parsing. */ + return parse.conf; +} + + +#endif /* 0 */ \ No newline at end of file diff --git a/include/nutconf.h b/include/nutconf.h new file mode 100644 index 0000000000..a9575acb9e --- /dev/null +++ b/include/nutconf.h @@ -0,0 +1,279 @@ +/* nutconf.h - Nut configuration file manipulation API + + Copyright (C) + 2012 Emilien Kia + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef NUTCONF_H_SEEN +#define NUTCONF_H_SEEN 1 + +#include +#include +#include + +#include +#include +#include + +#ifdef __cplusplus + +namespace nut +{ + +/** + * NUT config parser. + */ +class NutConfigParser +{ +public: + NutConfigParser(const char* buffer = NULL); + NutConfigParser(const std::string& buffer); + + struct Token + { + enum TokenType { + TOKEN_UNKNOWN = -1, + TOKEN_NONE = 0, + TOKEN_STRING = 1, + TOKEN_QUOTED_STRING, + TOKEN_COMMENT, + TOKEN_BRACKET_OPEN, + TOKEN_BRACKET_CLOSE, + TOKEN_EQUAL, + TOKEN_COLON, + TOKEN_EOL + }type; + std::string str; + + Token():type(TOKEN_NONE),str(){} + Token(TokenType type, const std::string& str=""):type(type),str(str){} + Token(TokenType type, char c):type(type),str(1, c){} + Token(const Token& tok):type(tok.type),str(tok.str){} + + bool operator==(const Token& tok)const{return tok.type==type && tok.str==str;} + }; + + /** Parsing functions + * \{ */ + std::string parseCHARS(); + std::string parseSTRCHARS(); + Token parseToken(); + std::list parseLine(); + /** \} */ + +#ifndef UNITEST_MODE +protected: +#endif /* UNITEST_MODE */ + size_t getPos()const; + void setPos(size_t pos); + char charAt(size_t pos)const; + + void pushPos(); + size_t popPos(); + void rewind(); + + void back(); + + char get(); + char peek(); + +private: + std::string _buffer; + size_t _pos; + std::vector _stack; +}; + + +} /* namespace nut */ +#endif /* __cplusplus */ + + +#if 0 + +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + + +/** Token type enumeration.*/ +typedef enum{ + TOKEN_UNKNOWN = -1, + TOKEN_NONE = 0, + TOKEN_STRING = 1, + TOKEN_QUOTED_STRING, + TOKEN_COMMENT, + TOKEN_BRACKET_OPEN, + TOKEN_BRACKET_CLOSE, + TOKEN_EQUAL, + TOKEN_COLON, + TOKEN_EOL +}PARSING_TOKEN_e; + + + +/** Lexical token pointer. + * It is a fragment of a c-string represented by its first character (begin) and + * the byte after its last character. + * Empty token is represented by end==begin. + * Null token is represented by begin==end==NULL. + */ +typedef struct { + const char* begin; + const char* end; + PARSING_TOKEN_e type; +}LEXTOKEN_t; + +/** Helper to copy a token to another.*/ +inline void LEXTOKEN_copy(LEXTOKEN_t* tgt, LEXTOKEN_t* src) +{ + tgt->begin = src->begin; + tgt->end = src->end; + tgt->type = src->type; +} + +/** Helper to set token values.*/ +inline void LEXTOKEN_set(LEXTOKEN_t* tok, const char* begin, const char* end, + PARSING_TOKEN_e type) +{ + tok->begin = begin; + tok->end = end; + tok->type = type; +} + +/** Helper to copy a string in a dedicated allocated memory.*/ +inline char* LEXTOKEN_chralloc(LEXTOKEN_t* tok) +{ + if(tok->begin && tok->beginend) + { + size_t len = tok->end-tok->begin; + char* mem = (char*)malloc(len+1); + memcpy(mem, tok->begin, len); + mem[len] = 0; + return mem; + } + else + { + return 0; + } +} + + +/** Syntaxical parsing machine state enumeration.*/ +typedef enum { + SYNPARSING_STATE_INIT, + SYNPARSING_STATE_FINISHED, + SYNPARSING_STATE_SECTION_BEGIN, + SYNPARSING_STATE_SECTION_NAME, + SYNPARSING_STATE_SECTION_END, + SYNPARSING_STATE_DIRECTIVE_BEGIN, + SYNPARSING_STATE_DIRECTIVE_ARGUMENT +}SYNPARSING_STATE_e; + +/** Line type.*/ +typedef enum { + SYNPARSING_LINETYPE_UNKNWON = -1, + SYNPARSING_LINETYPE_COMMENT, + SYNPARSING_LINETYPE_SECTION, + SYNPARSING_LINETYPE_DIRECTIVE_COLON, + SYNPARSING_LINETYPE_DIRECTIVE_EQUAL, + SYNPARSING_LINETYPE_DIRECTIVE_NOSEP +}SYNPARSING_LINETYPE_e; + + +/** Syntaxic line parsing result structure. */ +typedef struct { + SYNPARSING_LINETYPE_e line_type; + PARSING_TOKEN_e directive_separator; + LEXTOKEN_t* args; /* Array of LEXTOKEN_t. */ + unsigned int nb_args; /* Size of array args. */ + unsigned int arg_count; /* Number of arg in array args. */ + LEXTOKEN_t comment; +}SYNLINE_t; + + + +int nutconf_parse_rule_CHARS(const char* src, unsigned int len); + +int nutconf_parse_rule_STRCHARS(const char* src, unsigned int len); + + +PARSING_TOKEN_e nutconf_parse_token(const char* src, unsigned int len, + LEXTOKEN_t* token); + +void nutconf_parse_line(const char* src, unsigned int len, + const char** rend, SYNLINE_t* parsed_line); + + +typedef void (*nutconf_parse_line_callback)(SYNLINE_t* line, void* user_data); + +void nutconf_parse_memory(const char* src, int len, + nutconf_parse_line_callback cb, void* user_data); + + + + + +/** Generic chaining node for values. */ +typedef struct NUTCONF_ARGVALUE_s{ + char* value; + struct NUTCONF_ARGVALUE_s* next; +}NUTCONF_ARGVALUE_t; + +/** Type of argument. + * TODO Change it to a more semantic naming scheme + */ +typedef enum { + NUTCONF_ARG_NONE, + NUTCONF_ARG_COLON, + NUTCONF_ARG_EQUAL +}NUTCONF_ARG_TYPE_e; + +/** Generic chaining node for names. */ +typedef struct NUTCONF_ARG_s{ + char* name; + NUTCONF_ARG_TYPE_e type; + NUTCONF_ARGVALUE_t* value; + struct NUTCONF_ARG_s* next; +}NUTCONF_ARG_t; + + +/** Generic nutconf storage structure. + * Bloc of values for one section of data. + * Have a pointer to an eventually following bloc. + */ +typedef struct NUTCONF_SECTION_s{ + char* name; + NUTCONF_ARG_t* args; + struct NUTCONF_SECTION_s* next; +}NUTCONF_SECTION_t, NUTCONF_t; + + +/** Generic configuration parsing. */ +NUTCONF_t* nutconf_conf_parse(const char* src, int len); + + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + +#endif /* 0 */ + +#endif /* NUTCONF_H_SEEN */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 3960ad8736..92e64ae6a8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -8,14 +8,15 @@ check_PROGRAMS = $(TESTS) cppunittest_CXXFLAGS = $(CPPUNIT_CFLAGS) cppunittest_LDFLAGS = $(CPPUNIT_LIBS) +cppunittest_LDADD = ../common/libnutconf.la # List of src files for CppUnit tests -CPPUNITTESTSRC = example.cpp +CPPUNITTESTSRC = example.cpp nutconf.cpp cppunittest_SOURCES = $(CPPUNITTESTSRC) cpputest.cpp else !HAVE_CPPUNIT -EXTRA_DIST = example.cpp cpputest.cpp +EXTRA_DIST = example.cpp nutconf.cpp cpputest.cpp endif !HAVE_CPPUNIT diff --git a/tests/nutconf.cpp b/tests/nutconf.cpp new file mode 100644 index 0000000000..ea9c36b9b5 --- /dev/null +++ b/tests/nutconf.cpp @@ -0,0 +1,132 @@ +/* example - CppUnit unit test example + + Copyright (C) + 2012 Emilien Kia + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include + +// Define to desactivate protection of parsing tool members: +#define UNITEST_MODE 1 + +#include "nutconf.h" +using namespace nut; + +#include +using namespace std; + +class NutConfTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( NutConfTest ); + CPPUNIT_TEST( testParseCHARS ); + CPPUNIT_TEST( testParseSTRCHARS ); + CPPUNIT_TEST( testPasreToken ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testParseCHARS(); + void testParseSTRCHARS(); + void testPasreToken(); +}; + +// Registers the fixture into the 'registry' +CPPUNIT_TEST_SUITE_REGISTRATION( NutConfTest ); + + +void NutConfTest::setUp() +{ +} + + +void NutConfTest::tearDown() +{ +} + + +void NutConfTest::testParseCHARS() +{ + { + NutConfigParser parse("Bonjour monde!"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find first string 'Bonjour'", string("Bonjour"), parse.parseCHARS()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot get a character ''", ' ', parse.get()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find second string 'monde!'", string("monde!"), parse.parseCHARS()); + } + + { + NutConfigParser parse("To\\ to"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find escaped string 'To to'", string("To to"), parse.parseCHARS()); + } + + { + NutConfigParser parse("To\"to"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find escaped string 'To'", string("To"), parse.parseCHARS()); + } + + { + NutConfigParser parse("To\\\"to"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find escaped string 'To\"to'", string("To\"to"), parse.parseCHARS()); + } + +} + + +void NutConfTest::testParseSTRCHARS() +{ + { + NutConfigParser parse("Bonjour\"monde!\""); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find first string 'Bonjour'", string("Bonjour"), parse.parseSTRCHARS()); + parse.get(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find second string 'monde!'", string("monde!"), parse.parseSTRCHARS()); + } + + { + NutConfigParser parse("To to"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find spaced string 'To tue de l’appareil qui se serait malencontreuo'", string("To to"), parse.parseSTRCHARS()); + } + + { + NutConfigParser parse("To\\\"to"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find quoted-escaped string 'To\"to'", string("To\"to"), parse.parseSTRCHARS()); + } +} + +void NutConfTest::testPasreToken() +{ + static const char* src = + "Bonjour monde\n" + "[ceci]# Plouf\n" + "\n" + "titi = \"tata toto\""; + NutConfigParser parse(src); + +// NutConfigParser::Token tok = parse.parseToken(); +// std::cout << "token = " << tok.type << " - " << tok.str << std::endl; + + CPPUNIT_ASSERT_MESSAGE("Cannot find 1st token 'Bonjour'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_STRING, "Bonjour")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 2nd token 'monde'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_STRING, "monde")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 3rd token '['", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_BRACKET_OPEN, "[")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 4th token 'ceci'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_STRING, "ceci")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 5th token ']'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_BRACKET_CLOSE, "]")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 6th token ' Plouf'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_COMMENT, " Plouf")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 7th token '\n'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_EOL, "\n")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 8th token 'titi'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_STRING, "titi")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 9th token '='", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_EQUAL, "=")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 10th token 'tata toto'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_QUOTED_STRING, "tata toto")); + +} \ No newline at end of file From 1360d0848ac771abd824e8fca405d1ca889ad09c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Mon, 15 Oct 2012 23:30:12 +0200 Subject: [PATCH 002/121] Implement abstract configuration parser. Rename NutConfParser in NutParser. Implement the abstract class NutConfParser based on NutParser for configuration file parsing. Remove old C sample code. --- common/nutconf.cpp | 522 +++++++++++++++++---------------------------- include/nutconf.h | 198 ++--------------- tests/nutconf.cpp | 36 ++-- 3 files changed, 234 insertions(+), 522 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index b744085854..0dca11c36c 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -29,22 +29,22 @@ namespace nut { // -// NutConfigParser +// NutParser // -NutConfigParser::NutConfigParser(const char* buffer): +NutParser::NutParser(const char* buffer): _buffer(buffer), _pos(0) { } -NutConfigParser::NutConfigParser(const std::string& buffer): +NutParser::NutParser(const std::string& buffer): _buffer(buffer), _pos(0) { } -char NutConfigParser::get() +char NutParser::get() { if(_pos>=_buffer.size()) return 0; @@ -52,44 +52,44 @@ char NutConfigParser::get() return _buffer[_pos++]; } -char NutConfigParser::peek() +char NutParser::peek() { return _buffer[_pos]; } -size_t NutConfigParser::getPos()const +size_t NutParser::getPos()const { return _pos; } -void NutConfigParser::setPos(size_t pos) +void NutParser::setPos(size_t pos) { _pos = pos; } -char NutConfigParser::charAt(size_t pos)const +char NutParser::charAt(size_t pos)const { return _buffer[pos]; } -void NutConfigParser::pushPos() +void NutParser::pushPos() { _stack.push_back(_pos); } -size_t NutConfigParser::popPos() +size_t NutParser::popPos() { size_t pos = _stack.back(); _stack.pop_back(); return pos; } -void NutConfigParser::rewind() +void NutParser::rewind() { _pos = popPos(); } -void NutConfigParser::back() +void NutParser::back() { if(_pos>0) --_pos; @@ -102,7 +102,7 @@ void NutConfigParser::back() * | '\\' ( __SPACES__ | '\\' | '\"' | '#' ) * TODO: accept "\t", "\s", "\r", "\n" ?? */ -std::string NutConfigParser::parseCHARS() +std::string NutParser::parseCHARS() { bool escaped = false; // Is char escaped ? std::string res; // Stored string @@ -153,7 +153,7 @@ std::string NutConfigParser::parseCHARS() * | '\\' ( '\\' | '\"' ) * TODO: accept "\t", "\s", "\r", "\n" ?? */ -std::string NutConfigParser::parseSTRCHARS() +std::string NutParser::parseSTRCHARS() { bool escaped = false; // Is char escaped ? std::string str; // Stored string @@ -201,7 +201,7 @@ std::string NutConfigParser::parseSTRCHARS() /** Parse a string source for getting the next token, ignoring spaces. * \return Token type. */ -NutConfigParser::Token NutConfigParser::parseToken() +NutParser::Token NutParser::parseToken() { /** Lexical parsing machine state enumeration.*/ typedef enum { @@ -394,381 +394,247 @@ NutConfigParser::Token NutConfigParser::parseToken() } -std::list NutConfigParser::parseLine() +std::list NutParser::parseLine() { - std::list res; + std::list res; while(true) { - NutConfigParser::Token token = parseToken(); + NutParser::Token token = parseToken(); switch(token.type) { - + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + case Token::TOKEN_BRACKET_OPEN: + case Token::TOKEN_BRACKET_CLOSE: + case Token::TOKEN_EQUAL: + case Token::TOKEN_COLON: + res.push_back(token); + break; + case Token::TOKEN_COMMENT: + res.push_back(token); + // Do not break, should return (EOL)Token::TOKEN_COMMENT: + case Token::TOKEN_UNKNOWN: + case Token::TOKEN_NONE: + case Token::TOKEN_EOL: + return res; } } - - return res; } -} /* namespace nut */ - - - - - - - -#if 0 +// +// NutConfigParser +// -/** Parse a string source for a line. - * \param src Begin of text source to parse. - * \param len Size of text source to parse in byte. - * \param[out] rend Pointer where store end of line (address of byte following - * the last character of the line, so the size of line is end-src). - * \param[out] parsed_line Parsed line result. - * TODO Handle end-of-file - */ -void nutconf_parse_line(const char* src, unsigned int len, - const char** rend, SYNLINE_t* parsed_line) +NutConfigParser::NutConfigParser(const char* buffer): +NutParser(buffer) { - PARSING_TOKEN_e directive_separator = TOKEN_NONE; - SYNPARSING_STATE_e state = SYNPARSING_STATE_INIT; - SYNPARSING_LINETYPE_e line_type = SYNPARSING_LINETYPE_UNKNWON; - - LEXTOKEN_t current; - -/* Little macros (state-machine sub-functions) to reuse in this function: */ - -/* Add current token to arg list.*/ -#define nutconf_parse_line__PUSH_ARG() \ -{\ - if (parsed_line->arg_count < parsed_line->nb_args-1)\ - {\ - LEXTOKEN_copy(&parsed_line->args[parsed_line->arg_count], ¤t);\ - parsed_line->arg_count++;\ - }\ - /* TODO Add args overflow handling. */\ } -/* Set comment and end state machine: */ -#define nutconf_parse_line__SET_COMMENT_AND_END_STM() \ -{\ - LEXTOKEN_copy(&parsed_line->comment, ¤t);\ - state = SYNPARSING_STATE_FINISHED;\ + +NutConfigParser::NutConfigParser(const std::string& buffer): +NutParser(buffer) +{ } - if (parsed_line == NULL) - { - return; /* TODO add error code. */ - } - /* Init returned values */ - parsed_line->line_type = SYNPARSING_LINETYPE_UNKNWON; - parsed_line->directive_separator = TOKEN_NONE; - parsed_line->arg_count = 0; - LEXTOKEN_set(&parsed_line->comment, NULL, NULL, TOKEN_NONE); - - /* Lets parse */ - while (TRUE) + +void NutConfigParser::parseConfig() +{ + onParseBegin(); + + enum ConfigParserState { + CPS_DEFAULT, + CPS_SECTION_OPENED, + CPS_SECTION_HAVE_NAME, + CPS_SECTION_CLOSED, + CPS_DIRECTIVE_HAVE_NAME, + CPS_DIRECTIVE_VALUES + }state = CPS_DEFAULT; + + Token tok; + std::string name; + std::list values; + char sep; + while(tok = parseToken()) { - nutconf_parse_token(src, len, ¤t); - switch (state) + switch(state) { - case SYNPARSING_STATE_INIT: - switch (current.type) + case CPS_DEFAULT: + switch(tok.type) { - case TOKEN_COMMENT: /* Line with only a comment. */ - line_type = SYNPARSING_LINETYPE_COMMENT; - nutconf_parse_line__SET_COMMENT_AND_END_STM(); + case Token::TOKEN_COMMENT: + onParseComment(tok.str); + /* Clean and return to default */ break; - case TOKEN_BRACKET_OPEN: /* Begin of a section. */ - state = SYNPARSING_STATE_SECTION_BEGIN; + case Token::TOKEN_BRACKET_OPEN: + state = CPS_SECTION_OPENED; break; - case TOKEN_STRING: /* Begin of a directive line. */ - case TOKEN_QUOTED_STRING: - nutconf_parse_line__PUSH_ARG(); - state = SYNPARSING_STATE_DIRECTIVE_BEGIN; + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + name = tok.str; + state = CPS_DIRECTIVE_HAVE_NAME; break; default: - /* Must not occur. */ - /* TODO WTF ? .*/ + /* WTF ? */ break; } break; - case SYNPARSING_STATE_SECTION_BEGIN: - switch (current.type) + case CPS_SECTION_OPENED: + switch(tok.type) { - case TOKEN_BRACKET_CLOSE: /* Empty section. */ - state = SYNPARSING_STATE_SECTION_END; + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + /* Should occur ! */ + name = tok.str; + state = CPS_SECTION_HAVE_NAME; break; - case TOKEN_STRING: /* Section name. */ - case TOKEN_QUOTED_STRING: - nutconf_parse_line__PUSH_ARG(); - state = SYNPARSING_STATE_SECTION_NAME; + case Token::TOKEN_BRACKET_CLOSE: + /* Empty section name */ + state = CPS_SECTION_CLOSED; + break; + case Token::TOKEN_COMMENT: + /* Lack of closing bracket !!! */ + onParseSectionName(name, tok.str); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + case Token::TOKEN_EOL: + case Token::TOKEN_NONE: + /* Lack of closing bracket !!! */ + onParseSectionName(name); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; break; default: - /* Must not occur. */ - /* TODO WTF ? .*/ - break; + /* WTF ? */ + break; } break; - case SYNPARSING_STATE_SECTION_NAME: - switch (current.type) + case CPS_SECTION_HAVE_NAME: + switch(tok.type) { - case TOKEN_BRACKET_CLOSE: /* End of named section. */ - state = SYNPARSING_STATE_SECTION_END; + case Token::TOKEN_BRACKET_CLOSE: + /* Must occur ! */ + state = CPS_SECTION_CLOSED; + break; + case Token::TOKEN_COMMENT: + /* Lack of closing bracket !!! */ + onParseSectionName(name, tok.str); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + case Token::TOKEN_EOL: + case Token::TOKEN_NONE: + /* Lack of closing bracket !!! */ + onParseSectionName(name); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; break; default: - /* Must not occur. */ - /* TODO WTF ? .*/ - break; + /* WTF ? */ + break; } break; - case SYNPARSING_STATE_SECTION_END: - switch (current.type) + case CPS_SECTION_CLOSED: + switch(tok.type) { - case TOKEN_COMMENT: - line_type = SYNPARSING_LINETYPE_SECTION; - nutconf_parse_line__SET_COMMENT_AND_END_STM(); + case Token::TOKEN_COMMENT: + /* Could occur ! */ + onParseSectionName(name, tok.str); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; break; - case TOKEN_EOL: - line_type = SYNPARSING_LINETYPE_SECTION; - state = SYNPARSING_STATE_FINISHED; + case Token::TOKEN_EOL: + case Token::TOKEN_NONE: + /* Could occur ! */ + onParseSectionName(name); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; break; default: - /* Must not occur. */ - /* TODO WTF ? .*/ - break; + /* WTF ? */ + break; } break; - case SYNPARSING_STATE_DIRECTIVE_BEGIN: - switch (current.type) + case CPS_DIRECTIVE_HAVE_NAME: + switch(tok.type) { - case TOKEN_COLON: /* Directive with ':'.*/ - case TOKEN_EQUAL: /* Directive with '='.*/ - directive_separator = current.type; - state = SYNPARSING_STATE_DIRECTIVE_ARGUMENT; + case Token::TOKEN_COMMENT: + /* Could occur ! */ + onParseDirective(name, 0, std::list(), tok.str); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; break; - case TOKEN_STRING: /* Directive direct argument, no separator. */ - case TOKEN_QUOTED_STRING: - nutconf_parse_line__PUSH_ARG(); - state = SYNPARSING_STATE_DIRECTIVE_ARGUMENT; + case Token::TOKEN_EOL: + case Token::TOKEN_NONE: + /* Could occur ! */ + onParseDirective(name); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; break; - case TOKEN_COMMENT: - line_type = SYNPARSING_LINETYPE_DIRECTIVE_NOSEP; - nutconf_parse_line__SET_COMMENT_AND_END_STM(); + case Token::TOKEN_COLON: + case Token::TOKEN_EQUAL: + /* Could occur ! */ + sep = tok.str[0]; + state = CPS_DIRECTIVE_VALUES; break; - case TOKEN_EOL: - line_type = SYNPARSING_LINETYPE_DIRECTIVE_NOSEP; - state = SYNPARSING_STATE_FINISHED; + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + /* Could occur ! */ + values.push_back(tok.str); + state = CPS_DIRECTIVE_VALUES; break; default: - /* Must not occur. */ - /* TODO WTF ? .*/ - break; + /* WTF ? */ + break; } break; - case SYNPARSING_STATE_DIRECTIVE_ARGUMENT: - switch (current.type) + case CPS_DIRECTIVE_VALUES: + switch(tok.type) { - case TOKEN_STRING: /* Directive argument. */ - case TOKEN_QUOTED_STRING: - nutconf_parse_line__PUSH_ARG(); - /* Keep here, in SYNPARSING_STATE_DIRECTIVE_ARGUMENT state.*/ + case Token::TOKEN_COMMENT: + /* Could occur ! */ + onParseDirective(name, sep, values, tok.str); + /* Clean and return to default */ + name.clear(); + values.clear(); + sep = 0; + state = CPS_DEFAULT; break; - case TOKEN_COMMENT: - /* TODO signal directive with comment */ - nutconf_parse_line__SET_COMMENT_AND_END_STM(); + case Token::TOKEN_EOL: + case Token::TOKEN_NONE: + /* Could occur ! */ + onParseDirective(name, sep, values); + /* Clean and return to default */ + name.clear(); + values.clear(); + sep = 0; + state = CPS_DEFAULT; break; - case TOKEN_EOL: - line_type = SYNPARSING_LINETYPE_DIRECTIVE_NOSEP; - state = SYNPARSING_STATE_FINISHED; + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + /* Could occur ! */ + values.push_back(tok.str); + state = CPS_DIRECTIVE_VALUES; break; default: - /* Must not occur. */ - /* TODO WTF ? .*/ + /* WTF ? */ break; } break; - default: - /* Must not occur. */ - /* TODO WTF ? .*/ - break; } - - src = *rend = current.end; - if (state == SYNPARSING_STATE_FINISHED) - break; /* Go out infinite while loop. */ } - if (line_type == SYNPARSING_LINETYPE_DIRECTIVE_NOSEP) - { - if (directive_separator == TOKEN_COLON) - { - line_type = SYNPARSING_LINETYPE_DIRECTIVE_COLON; - } - else if (directive_separator == TOKEN_EQUAL) - { - line_type = SYNPARSING_LINETYPE_DIRECTIVE_EQUAL; - } - } - - /* End of process : save data for returning */ - parsed_line->line_type = line_type; - parsed_line->directive_separator = directive_separator; - -#undef nutconf_parse_line__PUSH_ARG -#undef nutconf_parse_line__SET_COMMENT_AND_END_STM + onParseEnd(); } -/* Parse a string source, memory mapping of a conf file. - * End the parsing at the end of file (ie null-char, specified size - * or error). - */ -void nutconf_parse_memory(const char* src, int len, - nutconf_parse_line_callback cb, void* user_data) -{ - const char* rend = src; - SYNLINE_t parsed_line; - LEXTOKEN_t tokens[16]; - - parsed_line.args = tokens; - parsed_line.nb_args = 16; - - while (len > 0) - { - nutconf_parse_line(src, len, &rend, &parsed_line); - - cb(&parsed_line, user_data); - - len -= rend - src; - src = rend; - } -} - - - - -typedef struct { - NUTCONF_t* conf; - NUTCONF_SECTION_t* current_section; - NUTCONF_ARG_t* current_arg; -}NUTCONF_CONF_PARSE_t; - -static void nutconf_conf_parse_callback(SYNLINE_t* line, void* user_data) -{ - NUTCONF_CONF_PARSE_t* parse = (NUTCONF_CONF_PARSE_t*)user_data; - int num; - - /* Verify parameters */ - if (parse==NULL) - { - return; - } - - /* Parsing state treatment */ - switch (line->line_type) - { - case SYNPARSING_LINETYPE_SECTION: - if (parse->current_section == NULL) - { - /* No current section - begin of the parsing.*/ - /* Use conf as section .*/ - parse->current_section = parse->conf; - } - else - { - /* Already have a section, add new one to chain. */ - parse->current_section->next = malloc(sizeof(NUTCONF_SECTION_t)); - parse->current_section = parse->current_section->next; - memset(parse->current_section, 0, sizeof(NUTCONF_SECTION_t)); - parse->current_arg = NULL; - } - /* Set the section name. */ - if (line->arg_count > 0) - { - parse->current_section->name = LEXTOKEN_chralloc(&line->args[0]); - } - break; - case SYNPARSING_LINETYPE_DIRECTIVE_COLON: - case SYNPARSING_LINETYPE_DIRECTIVE_EQUAL: - case SYNPARSING_LINETYPE_DIRECTIVE_NOSEP: - if (line->arg_count < 1) - { - /* No directive if no argument. */ - break; - } - - if (parse->current_section == NULL) - { - /* No current section - begin of the parsing.*/ - /* Use conf as section .*/ - parse->current_section = parse->conf; - } - - /* Add a new argument. */ - if (parse->current_arg != NULL) - { - parse->current_arg->next = malloc(sizeof(NUTCONF_ARG_t)); - parse->current_arg = parse->current_arg->next; - } - else - { - parse->current_arg = malloc(sizeof(NUTCONF_ARG_t)); - } - memset(parse->current_arg, 0, sizeof(NUTCONF_ARG_t)); - - /* Set directive name. */ - parse->current_arg->name = LEXTOKEN_chralloc(&line->args[0]); - - /* Set directive type. */ - switch(line->line_type) - { - case SYNPARSING_LINETYPE_DIRECTIVE_COLON: - parse->current_arg->type = NUTCONF_ARG_COLON; - break; - case SYNPARSING_LINETYPE_DIRECTIVE_EQUAL: - parse->current_arg->type = NUTCONF_ARG_EQUAL; - break; - default: - parse->current_arg->type = NUTCONF_ARG_NONE; - break; - } - - /* TODO Add directive values.*/ - for(num=1; numarg_count; num++) - { - /* ... */ - } - - break; - default: - /* Do nothing (unknown or comment. */ - break; - } -} - -NUTCONF_t* nutconf_conf_parse(const char* src, int len) -{ - NUTCONF_CONF_PARSE_t parse; - - /* Validate parameters */ - if (src==NULL || len <=0) - { - return NULL; - } - - /* Initialize working structures */ - memset(&parse.conf, 0, sizeof(NUTCONF_CONF_PARSE_t)); - parse.conf = malloc(sizeof(NUTCONF_t)); - memset(parse.conf, 0, sizeof(NUTCONF_t)); - - /* Do the parsing. */ - nutconf_parse_memory(src, len, nutconf_conf_parse_callback, &parse); - - /* TODO Test for successfull parsing. */ - return parse.conf; -} - - -#endif /* 0 */ \ No newline at end of file +} /* namespace nut */ diff --git a/include/nutconf.h b/include/nutconf.h index a9575acb9e..1d4e333494 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -37,11 +37,11 @@ namespace nut /** * NUT config parser. */ -class NutConfigParser +class NutParser { public: - NutConfigParser(const char* buffer = NULL); - NutConfigParser(const std::string& buffer); + NutParser(const char* buffer = NULL); + NutParser(const std::string& buffer); struct Token { @@ -64,7 +64,11 @@ class NutConfigParser Token(TokenType type, char c):type(type),str(1, c){} Token(const Token& tok):type(tok.type),str(tok.str){} + bool is(TokenType type)const{return this->type==type;} + bool operator==(const Token& tok)const{return tok.type==type && tok.str==str;} + + operator bool()const{return type!=TOKEN_UNKNOWN && type!=TOKEN_NONE;} }; /** Parsing functions @@ -98,182 +102,24 @@ class NutConfigParser }; -} /* namespace nut */ -#endif /* __cplusplus */ - - -#if 0 - -#ifdef __cplusplus -/* *INDENT-OFF* */ -extern "C" { -/* *INDENT-ON* */ -#endif - - -/** Token type enumeration.*/ -typedef enum{ - TOKEN_UNKNOWN = -1, - TOKEN_NONE = 0, - TOKEN_STRING = 1, - TOKEN_QUOTED_STRING, - TOKEN_COMMENT, - TOKEN_BRACKET_OPEN, - TOKEN_BRACKET_CLOSE, - TOKEN_EQUAL, - TOKEN_COLON, - TOKEN_EOL -}PARSING_TOKEN_e; - - - -/** Lexical token pointer. - * It is a fragment of a c-string represented by its first character (begin) and - * the byte after its last character. - * Empty token is represented by end==begin. - * Null token is represented by begin==end==NULL. - */ -typedef struct { - const char* begin; - const char* end; - PARSING_TOKEN_e type; -}LEXTOKEN_t; - -/** Helper to copy a token to another.*/ -inline void LEXTOKEN_copy(LEXTOKEN_t* tgt, LEXTOKEN_t* src) -{ - tgt->begin = src->begin; - tgt->end = src->end; - tgt->type = src->type; -} - -/** Helper to set token values.*/ -inline void LEXTOKEN_set(LEXTOKEN_t* tok, const char* begin, const char* end, - PARSING_TOKEN_e type) -{ - tok->begin = begin; - tok->end = end; - tok->type = type; -} - -/** Helper to copy a string in a dedicated allocated memory.*/ -inline char* LEXTOKEN_chralloc(LEXTOKEN_t* tok) +class NutConfigParser : public NutParser { - if(tok->begin && tok->beginend) - { - size_t len = tok->end-tok->begin; - char* mem = (char*)malloc(len+1); - memcpy(mem, tok->begin, len); - mem[len] = 0; - return mem; - } - else - { - return 0; - } -} - - -/** Syntaxical parsing machine state enumeration.*/ -typedef enum { - SYNPARSING_STATE_INIT, - SYNPARSING_STATE_FINISHED, - SYNPARSING_STATE_SECTION_BEGIN, - SYNPARSING_STATE_SECTION_NAME, - SYNPARSING_STATE_SECTION_END, - SYNPARSING_STATE_DIRECTIVE_BEGIN, - SYNPARSING_STATE_DIRECTIVE_ARGUMENT -}SYNPARSING_STATE_e; - -/** Line type.*/ -typedef enum { - SYNPARSING_LINETYPE_UNKNWON = -1, - SYNPARSING_LINETYPE_COMMENT, - SYNPARSING_LINETYPE_SECTION, - SYNPARSING_LINETYPE_DIRECTIVE_COLON, - SYNPARSING_LINETYPE_DIRECTIVE_EQUAL, - SYNPARSING_LINETYPE_DIRECTIVE_NOSEP -}SYNPARSING_LINETYPE_e; - - -/** Syntaxic line parsing result structure. */ -typedef struct { - SYNPARSING_LINETYPE_e line_type; - PARSING_TOKEN_e directive_separator; - LEXTOKEN_t* args; /* Array of LEXTOKEN_t. */ - unsigned int nb_args; /* Size of array args. */ - unsigned int arg_count; /* Number of arg in array args. */ - LEXTOKEN_t comment; -}SYNLINE_t; - - - -int nutconf_parse_rule_CHARS(const char* src, unsigned int len); - -int nutconf_parse_rule_STRCHARS(const char* src, unsigned int len); - - -PARSING_TOKEN_e nutconf_parse_token(const char* src, unsigned int len, - LEXTOKEN_t* token); - -void nutconf_parse_line(const char* src, unsigned int len, - const char** rend, SYNLINE_t* parsed_line); - - -typedef void (*nutconf_parse_line_callback)(SYNLINE_t* line, void* user_data); - -void nutconf_parse_memory(const char* src, int len, - nutconf_parse_line_callback cb, void* user_data); - - - - - -/** Generic chaining node for values. */ -typedef struct NUTCONF_ARGVALUE_s{ - char* value; - struct NUTCONF_ARGVALUE_s* next; -}NUTCONF_ARGVALUE_t; - -/** Type of argument. - * TODO Change it to a more semantic naming scheme - */ -typedef enum { - NUTCONF_ARG_NONE, - NUTCONF_ARG_COLON, - NUTCONF_ARG_EQUAL -}NUTCONF_ARG_TYPE_e; - -/** Generic chaining node for names. */ -typedef struct NUTCONF_ARG_s{ - char* name; - NUTCONF_ARG_TYPE_e type; - NUTCONF_ARGVALUE_t* value; - struct NUTCONF_ARG_s* next; -}NUTCONF_ARG_t; - - -/** Generic nutconf storage structure. - * Bloc of values for one section of data. - * Have a pointer to an eventually following bloc. - */ -typedef struct NUTCONF_SECTION_s{ - char* name; - NUTCONF_ARG_t* args; - struct NUTCONF_SECTION_s* next; -}NUTCONF_SECTION_t, NUTCONF_t; - +public: + virtual void parseConfig(); -/** Generic configuration parsing. */ -NUTCONF_t* nutconf_conf_parse(const char* src, int len); +protected: + NutConfigParser(const char* buffer = NULL); + NutConfigParser(const std::string& buffer); + + virtual void onParseBegin()=0; + virtual void onParseComment(const std::string& comment)=0; + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "")=0; + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const std::list& values = std::list(), const std::string& comment = "")=0; + virtual void onParseEnd()=0; +}; -#ifdef __cplusplus -/* *INDENT-OFF* */ -} -/* *INDENT-ON* */ -#endif - -#endif /* 0 */ +} /* namespace nut */ +#endif /* __cplusplus */ #endif /* NUTCONF_H_SEEN */ diff --git a/tests/nutconf.cpp b/tests/nutconf.cpp index ea9c36b9b5..c78d74387f 100644 --- a/tests/nutconf.cpp +++ b/tests/nutconf.cpp @@ -62,24 +62,24 @@ void NutConfTest::tearDown() void NutConfTest::testParseCHARS() { { - NutConfigParser parse("Bonjour monde!"); + NutParser parse("Bonjour monde!"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find first string 'Bonjour'", string("Bonjour"), parse.parseCHARS()); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot get a character ''", ' ', parse.get()); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find second string 'monde!'", string("monde!"), parse.parseCHARS()); } { - NutConfigParser parse("To\\ to"); + NutParser parse("To\\ to"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find escaped string 'To to'", string("To to"), parse.parseCHARS()); } { - NutConfigParser parse("To\"to"); + NutParser parse("To\"to"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find escaped string 'To'", string("To"), parse.parseCHARS()); } { - NutConfigParser parse("To\\\"to"); + NutParser parse("To\\\"to"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find escaped string 'To\"to'", string("To\"to"), parse.parseCHARS()); } @@ -89,19 +89,19 @@ void NutConfTest::testParseCHARS() void NutConfTest::testParseSTRCHARS() { { - NutConfigParser parse("Bonjour\"monde!\""); + NutParser parse("Bonjour\"monde!\""); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find first string 'Bonjour'", string("Bonjour"), parse.parseSTRCHARS()); parse.get(); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find second string 'monde!'", string("monde!"), parse.parseSTRCHARS()); } { - NutConfigParser parse("To to"); + NutParser parse("To to"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find spaced string 'To tue de l’appareil qui se serait malencontreuo'", string("To to"), parse.parseSTRCHARS()); } { - NutConfigParser parse("To\\\"to"); + NutParser parse("To\\\"to"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find quoted-escaped string 'To\"to'", string("To\"to"), parse.parseSTRCHARS()); } } @@ -113,20 +113,20 @@ void NutConfTest::testPasreToken() "[ceci]# Plouf\n" "\n" "titi = \"tata toto\""; - NutConfigParser parse(src); + NutParser parse(src); // NutConfigParser::Token tok = parse.parseToken(); // std::cout << "token = " << tok.type << " - " << tok.str << std::endl; - CPPUNIT_ASSERT_MESSAGE("Cannot find 1st token 'Bonjour'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_STRING, "Bonjour")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 2nd token 'monde'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_STRING, "monde")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 3rd token '['", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_BRACKET_OPEN, "[")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 4th token 'ceci'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_STRING, "ceci")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 5th token ']'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_BRACKET_CLOSE, "]")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 6th token ' Plouf'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_COMMENT, " Plouf")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 7th token '\n'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_EOL, "\n")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 8th token 'titi'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_STRING, "titi")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 9th token '='", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_EQUAL, "=")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 10th token 'tata toto'", parse.parseToken() == NutConfigParser::Token(NutConfigParser::Token::TOKEN_QUOTED_STRING, "tata toto")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 1st token 'Bonjour'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "Bonjour")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 2nd token 'monde'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "monde")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 3rd token '['", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_BRACKET_OPEN, "[")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 4th token 'ceci'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "ceci")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 5th token ']'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_BRACKET_CLOSE, "]")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 6th token ' Plouf'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_COMMENT, " Plouf")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 7th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 8th token 'titi'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "titi")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 9th token '='", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EQUAL, "=")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 10th token 'tata toto'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_QUOTED_STRING, "tata toto")); } \ No newline at end of file From b2f95f91f5bdd4d10c4a047efd253862b88461c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Mon, 15 Oct 2012 23:39:31 +0200 Subject: [PATCH 003/121] Add stubs for DefaultConfigParser Add stubs for the default configuration file parser. Basic implementation will follow. --- common/nutconf.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ include/nutconf.h | 12 ++++++++++++ 2 files changed, 53 insertions(+) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 0dca11c36c..05857d516c 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -636,5 +636,46 @@ void NutConfigParser::parseConfig() onParseEnd(); } +// +// DefaultConfigParser +// + +DefaultConfigParser::DefaultConfigParser(const char* buffer): +NutConfigParser(buffer) +{ +} + +DefaultConfigParser::DefaultConfigParser(const std::string& buffer): +NutConfigParser(buffer) +{ +} + + +void DefaultConfigParser::onParseBegin() +{ + // TODO +} + +void DefaultConfigParser::onParseComment(const std::string& comment) +{ + // TODO +} + +void DefaultConfigParser::onParseSectionName(const std::string& sectionName, const std::string& comment) +{ + // TODO +} + +void DefaultConfigParser::onParseDirective(const std::string& directiveName, char sep, const std::list& values, const std::string& comment) +{ + // TODO +} + +void DefaultConfigParser::onParseEnd() +{ + // TODO +} + + } /* namespace nut */ diff --git a/include/nutconf.h b/include/nutconf.h index 1d4e333494..c8fe75fd50 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -118,7 +118,19 @@ class NutConfigParser : public NutParser virtual void onParseEnd()=0; }; +class DefaultConfigParser : public NutConfigParser +{ +public: + DefaultConfigParser(const char* buffer = NULL); + DefaultConfigParser(const std::string& buffer); +protected: + virtual void onParseBegin(); + virtual void onParseComment(const std::string& comment); + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const std::list& values = std::list(), const std::string& comment = ""); + virtual void onParseEnd(); +}; } /* namespace nut */ #endif /* __cplusplus */ From 0f885b0cdf0fa61f11ecfa9bc98d93421b1e84b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Fri, 19 Oct 2012 15:04:56 +0200 Subject: [PATCH 004/121] Define a typedef type to make function easier to understand. --- common/nutconf.cpp | 2 +- include/nutconf.h | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 05857d516c..8735f1bce1 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -666,7 +666,7 @@ void DefaultConfigParser::onParseSectionName(const std::string& sectionName, con // TODO } -void DefaultConfigParser::onParseDirective(const std::string& directiveName, char sep, const std::list& values, const std::string& comment) +void DefaultConfigParser::onParseDirective(const std::string& directiveName, char sep, const ConfigParamList& values, const std::string& comment) { // TODO } diff --git a/include/nutconf.h b/include/nutconf.h index c8fe75fd50..e2cdd2c9c4 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -102,6 +102,8 @@ class NutParser }; +typedef std::list ConfigParamList; + class NutConfigParser : public NutParser { public: @@ -114,10 +116,11 @@ class NutConfigParser : public NutParser virtual void onParseBegin()=0; virtual void onParseComment(const std::string& comment)=0; virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "")=0; - virtual void onParseDirective(const std::string& directiveName, char sep = 0, const std::list& values = std::list(), const std::string& comment = "")=0; + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "")=0; virtual void onParseEnd()=0; }; + class DefaultConfigParser : public NutConfigParser { public: @@ -125,13 +128,16 @@ class DefaultConfigParser : public NutConfigParser DefaultConfigParser(const std::string& buffer); protected: + virtual void onParseBegin(); virtual void onParseComment(const std::string& comment); virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); - virtual void onParseDirective(const std::string& directiveName, char sep = 0, const std::list& values = std::list(), const std::string& comment = ""); + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); virtual void onParseEnd(); }; + + } /* namespace nut */ #endif /* __cplusplus */ #endif /* NUTCONF_H_SEEN */ From 4798e59ede16a4fd9b1de9759eea1de30055bdc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Fri, 19 Oct 2012 16:25:29 +0200 Subject: [PATCH 005/121] Implement abstract class DefaultConfigParser --- common/nutconf.cpp | 828 ++++++++++++++++++++------------------------- include/nutconf.h | 20 ++ 2 files changed, 391 insertions(+), 457 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 8735f1bce1..27c3ef3681 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -1,7 +1,7 @@ /* nutconf.cpp - configuration API Copyright (C) - 2012 Emilien Kia + 2012 Emilien Kia This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ + */ #include #include @@ -25,400 +25,299 @@ #include "nutconf.h" -namespace nut -{ +namespace nut { // // NutParser // -NutParser::NutParser(const char* buffer): +NutParser::NutParser(const char* buffer) : _buffer(buffer), -_pos(0) -{ +_pos(0) { } -NutParser::NutParser(const std::string& buffer): +NutParser::NutParser(const std::string& buffer) : _buffer(buffer), -_pos(0) -{ +_pos(0) { } -char NutParser::get() -{ - if(_pos>=_buffer.size()) +char NutParser::get() { + if (_pos >= _buffer.size()) return 0; else return _buffer[_pos++]; } -char NutParser::peek() -{ +char NutParser::peek() { return _buffer[_pos]; } -size_t NutParser::getPos()const -{ +size_t NutParser::getPos()const { return _pos; } -void NutParser::setPos(size_t pos) -{ +void NutParser::setPos(size_t pos) { _pos = pos; } -char NutParser::charAt(size_t pos)const -{ +char NutParser::charAt(size_t pos)const { return _buffer[pos]; } -void NutParser::pushPos() -{ +void NutParser::pushPos() { _stack.push_back(_pos); } -size_t NutParser::popPos() -{ +size_t NutParser::popPos() { size_t pos = _stack.back(); _stack.pop_back(); return pos; } -void NutParser::rewind() -{ +void NutParser::rewind() { _pos = popPos(); } -void NutParser::back() -{ - if(_pos>0) +void NutParser::back() { + if (_pos > 0) --_pos; } - /* Parse a string source for a CHARS and return its size if found or 0, if not. * CHARS ::= CHAR+ * CHAR ::= __ASCIICHAR__ - ( __SPACES__ | '\\' | '\"' | '#' ) * | '\\' ( __SPACES__ | '\\' | '\"' | '#' ) * TODO: accept "\t", "\s", "\r", "\n" ?? */ -std::string NutParser::parseCHARS() -{ - bool escaped = false; // Is char escaped ? - std::string res; // Stored string +std::string NutParser::parseCHARS() { + bool escaped = false; // Is char escaped ? + std::string res; // Stored string pushPos(); - for (char c = get(); c != 0 /*EOF*/; c = get()) - { - if (escaped) - { - if (isspace(c) || c == '\\' || c == '"' || c == '#') - { + for (char c = get(); c != 0 /*EOF*/; c = get()) { + if (escaped) { + if (isspace(c) || c == '\\' || c == '"' || c == '#') { res += c; - } - else - { - /* WTF ??? */ - } - escaped = false; - } - else - { - if (c == '\\') - { - escaped = true; - } - else if (isgraph(c) /*&& c != '\\'*/ && c != '"' && c != '#') - { + } else { + /* WTF ??? */ + } + escaped = false; + } else { + if (c == '\\') { + escaped = true; + } else if (isgraph(c) /*&& c != '\\'*/ && c != '"' && c != '#') { res += c; - } - else - { + } else { back(); break; - } - } - } + } + } + } popPos(); return res; } - - /* Parse a string source for a STRCHARS and return its size if found or 0, if not. * STRCHARS ::= STRCHAR+ * STRCHAR ::= __ASCIICHAR__ - ( '\\' | '\"') * | '\\' ( '\\' | '\"' ) * TODO: accept "\t", "\s", "\r", "\n" ?? */ -std::string NutParser::parseSTRCHARS() -{ - bool escaped = false; // Is char escaped ? - std::string str; // Stored string +std::string NutParser::parseSTRCHARS() { + bool escaped = false; // Is char escaped ? + std::string str; // Stored string pushPos(); - for (char c = get(); c != 0 /*EOF*/; c = get()) - { - if (escaped) - { - if (isspace(c) || c == '\\' || c == '"') - { + for (char c = get(); c != 0 /*EOF*/; c = get()) { + if (escaped) { + if (isspace(c) || c == '\\' || c == '"') { str += c; - } - else - { - /* WTF ??? */ - } - escaped = false; - } - else - { - if (c == '\\') - { - escaped = true; - } - else if (isprint(c) && c != '\\' && c != '"') - { + } else { + /* WTF ??? */ + } + escaped = false; + } else { + if (c == '\\') { + escaped = true; + } else if (isprint(c) && c != '\\' && c != '"') { str += c; - } - else - { + } else { back(); break; - } - } - } + } + } + } popPos(); return str; } - - /** Parse a string source for getting the next token, ignoring spaces. * \return Token type. */ -NutParser::Token NutParser::parseToken() -{ +NutParser::Token NutParser::parseToken() { + /** Lexical parsing machine state enumeration.*/ typedef enum { LEXPARSING_STATE_DEFAULT, LEXPARSING_STATE_QUOTED_STRING, LEXPARSING_STATE_STRING, LEXPARSING_STATE_COMMENT - }LEXPARSING_STATE_e; - LEXPARSING_STATE_e state = LEXPARSING_STATE_DEFAULT; + } LEXPARSING_STATE_e; + LEXPARSING_STATE_e state = LEXPARSING_STATE_DEFAULT; Token token; - bool escaped = false; + bool escaped = false; pushPos(); - for (char c = get(); c != 0 /*EOF*/; c = get()) - { - switch (state) - { - case LEXPARSING_STATE_DEFAULT: /* Wait for a non-space char */ - { - if (c == ' ' || c == '\t') - { - /* Space : do nothing */ - } - else if (c == '[') - { + for (char c = get(); c != 0 /*EOF*/; c = get()) { + switch (state) { + case LEXPARSING_STATE_DEFAULT: /* Wait for a non-space char */ + { + if (c == ' ' || c == '\t') { + /* Space : do nothing */ + } else if (c == '[') { token = Token(Token::TOKEN_BRACKET_OPEN, c); popPos(); return token; - } - else if (c == ']') - { + } else if (c == ']') { token = Token(Token::TOKEN_BRACKET_CLOSE, c); popPos(); return token; - } - else if (c == ':') - { + } else if (c == ':') { token = Token(Token::TOKEN_COLON, c); popPos(); return token; - } - else if (c == '=') - { + } else if (c == '=') { token = Token(Token::TOKEN_EQUAL, c); popPos(); return token; - } - else if (c == '\r' || c == '\n') - { + } else if (c == '\r' || c == '\n') { token = Token(Token::TOKEN_EOL, c); popPos(); return token; - } - else if (c == '#') - { + } else if (c == '#') { token.type = Token::TOKEN_COMMENT; - state = LEXPARSING_STATE_COMMENT; - } - else if (c == '"') - { - /* Begin of QUOTED STRING */ + state = LEXPARSING_STATE_COMMENT; + } else if (c == '"') { + /* Begin of QUOTED STRING */ token.type = Token::TOKEN_QUOTED_STRING; - state = LEXPARSING_STATE_QUOTED_STRING; - } - else if (c == '\\') - { - /* Begin of STRING with escape */ + state = LEXPARSING_STATE_QUOTED_STRING; + } else if (c == '\\') { + /* Begin of STRING with escape */ token.type = Token::TOKEN_STRING; - state = LEXPARSING_STATE_STRING; - escaped = true; - } - else if (isgraph(c)) - { - /* Begin of STRING */ + state = LEXPARSING_STATE_STRING; + escaped = true; + } else if (isgraph(c)) { + /* Begin of STRING */ token.type = Token::TOKEN_STRING; - state = LEXPARSING_STATE_STRING; + state = LEXPARSING_STATE_STRING; token.str += c; - } - else - { + } else { rewind(); return Token(Token::TOKEN_UNKNOWN); - } - break; - } - case LEXPARSING_STATE_QUOTED_STRING: - { - if (c == '"') - { - if(escaped) - { - escaped = false; + } + break; + } + case LEXPARSING_STATE_QUOTED_STRING: + { + if (c == '"') { + if (escaped) { + escaped = false; token.str += '"'; - } - else - { + } else { popPos(); return token; - } - } - else if (c == '\\') - { - if (escaped) - { - escaped = false; + } + } else if (c == '\\') { + if (escaped) { + escaped = false; token.str += '\\'; - } - else - { - escaped = true; - } - } - else if (c == ' ' || c == '\t' || isgraph(c)) - { + } else { + escaped = true; + } + } else if (c == ' ' || c == '\t' || isgraph(c)) { token.str += c; - } - else if(c == 0) /* EOL */ - { + } else if (c == 0) /* EOL */ { popPos(); return token; - } - else /* Bad character ?? */ - { + } else /* Bad character ?? */ { /* WTF ? Keep, Ignore ? */ } - /* TODO What about other escaped character ? */ - break; - } - case LEXPARSING_STATE_STRING: - { - if (c == ' ' || c == '"' || c == '#' || c == '[' || c == ']' || c == ':' || c == '=') - { - if (escaped) - { - escaped = false; + /* TODO What about other escaped character ? */ + break; + } + case LEXPARSING_STATE_STRING: + { + if (c == ' ' || c == '"' || c == '#' || c == '[' || c == ']' || c == ':' || c == '=') { + if (escaped) { + escaped = false; token.str += c; - } - else - { + } else { back(); popPos(); return token; - } - } - else if (c == '\\') - { - if (escaped) - { - escaped = false; + } + } else if (c == '\\') { + if (escaped) { + escaped = false; token.str += c; - } - else - { - escaped = true; - } - } - /* else if (c == '\r' || c == '\n') */ - else if (isgraph(c)) - { + } else { + escaped = true; + } + } /* else if (c == '\r' || c == '\n') */ + else if (isgraph(c)) { token.str += c; - } - else /* Bad character ?? */ - { + } else /* Bad character ?? */ { /* WTF ? Keep, Ignore ? */ - } - /* TODO What about escaped character ? */ - break; - } - case LEXPARSING_STATE_COMMENT: - { - if (c == '\r' || c == '\n') - { + } + /* TODO What about escaped character ? */ + break; + } + case LEXPARSING_STATE_COMMENT: + { + if (c == '\r' || c == '\n') { return token; - } - else - { + } else { token.str += c; } - break; - } - default: - /* Must not occur. */ - break; - } - } + break; + } + default: + /* Must not occur. */ + break; + } + } popPos(); return token; } - -std::list NutParser::parseLine() -{ +std::list NutParser::parseLine() { std::list res; - while(true) - { + while (true) { NutParser::Token token = parseToken(); - - switch(token.type) - { - case Token::TOKEN_STRING: - case Token::TOKEN_QUOTED_STRING: - case Token::TOKEN_BRACKET_OPEN: - case Token::TOKEN_BRACKET_CLOSE: - case Token::TOKEN_EQUAL: - case Token::TOKEN_COLON: - res.push_back(token); - break; - case Token::TOKEN_COMMENT: - res.push_back(token); - // Do not break, should return (EOL)Token::TOKEN_COMMENT: - case Token::TOKEN_UNKNOWN: - case Token::TOKEN_NONE: - case Token::TOKEN_EOL: - return res; + + switch (token.type) { + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + case Token::TOKEN_BRACKET_OPEN: + case Token::TOKEN_BRACKET_CLOSE: + case Token::TOKEN_EQUAL: + case Token::TOKEN_COLON: + res.push_back(token); + break; + case Token::TOKEN_COMMENT: + res.push_back(token); + // Do not break, should return (EOL)Token::TOKEN_COMMENT: + case Token::TOKEN_UNKNOWN: + case Token::TOKEN_NONE: + case Token::TOKEN_EOL: + return res; } } } @@ -427,19 +326,15 @@ std::list NutParser::parseLine() // NutConfigParser // -NutConfigParser::NutConfigParser(const char* buffer): -NutParser(buffer) -{ +NutConfigParser::NutConfigParser(const char* buffer) : +NutParser(buffer) { } -NutConfigParser::NutConfigParser(const std::string& buffer): -NutParser(buffer) -{ +NutConfigParser::NutConfigParser(const std::string& buffer) : +NutParser(buffer) { } - -void NutConfigParser::parseConfig() -{ +void NutConfigParser::parseConfig() { onParseBegin(); enum ConfigParserState { @@ -449,231 +344,250 @@ void NutConfigParser::parseConfig() CPS_SECTION_CLOSED, CPS_DIRECTIVE_HAVE_NAME, CPS_DIRECTIVE_VALUES - }state = CPS_DEFAULT; + } state = CPS_DEFAULT; Token tok; std::string name; std::list values; char sep; - while(tok = parseToken()) - { - switch(state) - { - case CPS_DEFAULT: - switch(tok.type) - { - case Token::TOKEN_COMMENT: - onParseComment(tok.str); - /* Clean and return to default */ - break; - case Token::TOKEN_BRACKET_OPEN: - state = CPS_SECTION_OPENED; - break; - case Token::TOKEN_STRING: - case Token::TOKEN_QUOTED_STRING: - name = tok.str; - state = CPS_DIRECTIVE_HAVE_NAME; - break; - default: - /* WTF ? */ - break; - } - break; - case CPS_SECTION_OPENED: - switch(tok.type) - { - case Token::TOKEN_STRING: - case Token::TOKEN_QUOTED_STRING: - /* Should occur ! */ - name = tok.str; - state = CPS_SECTION_HAVE_NAME; - break; - case Token::TOKEN_BRACKET_CLOSE: - /* Empty section name */ - state = CPS_SECTION_CLOSED; - break; - case Token::TOKEN_COMMENT: - /* Lack of closing bracket !!! */ - onParseSectionName(name, tok.str); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - case Token::TOKEN_EOL: - case Token::TOKEN_NONE: - /* Lack of closing bracket !!! */ - onParseSectionName(name); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - default: - /* WTF ? */ - break; - } - break; - case CPS_SECTION_HAVE_NAME: - switch(tok.type) - { - case Token::TOKEN_BRACKET_CLOSE: - /* Must occur ! */ - state = CPS_SECTION_CLOSED; - break; - case Token::TOKEN_COMMENT: - /* Lack of closing bracket !!! */ - onParseSectionName(name, tok.str); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - case Token::TOKEN_EOL: - case Token::TOKEN_NONE: - /* Lack of closing bracket !!! */ - onParseSectionName(name); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - default: - /* WTF ? */ - break; - } - break; - case CPS_SECTION_CLOSED: - switch(tok.type) - { - case Token::TOKEN_COMMENT: - /* Could occur ! */ - onParseSectionName(name, tok.str); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - case Token::TOKEN_EOL: - case Token::TOKEN_NONE: - /* Could occur ! */ - onParseSectionName(name); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - default: - /* WTF ? */ - break; - } - break; - case CPS_DIRECTIVE_HAVE_NAME: - switch(tok.type) - { - case Token::TOKEN_COMMENT: - /* Could occur ! */ - onParseDirective(name, 0, std::list(), tok.str); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - case Token::TOKEN_EOL: - case Token::TOKEN_NONE: - /* Could occur ! */ - onParseDirective(name); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - case Token::TOKEN_COLON: - case Token::TOKEN_EQUAL: - /* Could occur ! */ - sep = tok.str[0]; - state = CPS_DIRECTIVE_VALUES; - break; - case Token::TOKEN_STRING: - case Token::TOKEN_QUOTED_STRING: - /* Could occur ! */ - values.push_back(tok.str); - state = CPS_DIRECTIVE_VALUES; + while (tok = parseToken()) { + switch (state) { + case CPS_DEFAULT: + switch (tok.type) { + case Token::TOKEN_COMMENT: + onParseComment(tok.str); + /* Clean and return to default */ + break; + case Token::TOKEN_BRACKET_OPEN: + state = CPS_SECTION_OPENED; + break; + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + name = tok.str; + state = CPS_DIRECTIVE_HAVE_NAME; + break; + default: + /* WTF ? */ + break; + } break; - default: - /* WTF ? */ + case CPS_SECTION_OPENED: + switch (tok.type) { + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + /* Should occur ! */ + name = tok.str; + state = CPS_SECTION_HAVE_NAME; + break; + case Token::TOKEN_BRACKET_CLOSE: + /* Empty section name */ + state = CPS_SECTION_CLOSED; + break; + case Token::TOKEN_COMMENT: + /* Lack of closing bracket !!! */ + onParseSectionName(name, tok.str); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + case Token::TOKEN_EOL: + case Token::TOKEN_NONE: + /* Lack of closing bracket !!! */ + onParseSectionName(name); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + default: + /* WTF ? */ + break; + } break; - } - break; - case CPS_DIRECTIVE_VALUES: - switch(tok.type) - { - case Token::TOKEN_COMMENT: - /* Could occur ! */ - onParseDirective(name, sep, values, tok.str); - /* Clean and return to default */ - name.clear(); - values.clear(); - sep = 0; - state = CPS_DEFAULT; + case CPS_SECTION_HAVE_NAME: + switch (tok.type) { + case Token::TOKEN_BRACKET_CLOSE: + /* Must occur ! */ + state = CPS_SECTION_CLOSED; + break; + case Token::TOKEN_COMMENT: + /* Lack of closing bracket !!! */ + onParseSectionName(name, tok.str); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + case Token::TOKEN_EOL: + case Token::TOKEN_NONE: + /* Lack of closing bracket !!! */ + onParseSectionName(name); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + default: + /* WTF ? */ + break; + } break; - case Token::TOKEN_EOL: - case Token::TOKEN_NONE: - /* Could occur ! */ - onParseDirective(name, sep, values); - /* Clean and return to default */ - name.clear(); - values.clear(); - sep = 0; - state = CPS_DEFAULT; + case CPS_SECTION_CLOSED: + switch (tok.type) { + case Token::TOKEN_COMMENT: + /* Could occur ! */ + onParseSectionName(name, tok.str); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + case Token::TOKEN_EOL: + case Token::TOKEN_NONE: + /* Could occur ! */ + onParseSectionName(name); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + default: + /* WTF ? */ + break; + } break; - case Token::TOKEN_STRING: - case Token::TOKEN_QUOTED_STRING: - /* Could occur ! */ - values.push_back(tok.str); - state = CPS_DIRECTIVE_VALUES; + case CPS_DIRECTIVE_HAVE_NAME: + switch (tok.type) { + case Token::TOKEN_COMMENT: + /* Could occur ! */ + onParseDirective(name, 0, std::list (), tok.str); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + case Token::TOKEN_EOL: + case Token::TOKEN_NONE: + /* Could occur ! */ + onParseDirective(name); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + case Token::TOKEN_COLON: + case Token::TOKEN_EQUAL: + /* Could occur ! */ + sep = tok.str[0]; + state = CPS_DIRECTIVE_VALUES; + break; + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + /* Could occur ! */ + values.push_back(tok.str); + state = CPS_DIRECTIVE_VALUES; + break; + default: + /* WTF ? */ + break; + } break; - default: - /* WTF ? */ + case CPS_DIRECTIVE_VALUES: + switch (tok.type) { + case Token::TOKEN_COMMENT: + /* Could occur ! */ + onParseDirective(name, sep, values, tok.str); + /* Clean and return to default */ + name.clear(); + values.clear(); + sep = 0; + state = CPS_DEFAULT; + break; + case Token::TOKEN_EOL: + case Token::TOKEN_NONE: + /* Could occur ! */ + onParseDirective(name, sep, values); + /* Clean and return to default */ + name.clear(); + values.clear(); + sep = 0; + state = CPS_DEFAULT; + break; + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + /* Could occur ! */ + values.push_back(tok.str); + state = CPS_DIRECTIVE_VALUES; + break; + default: + /* WTF ? */ + break; + } break; - } - break; } } onParseEnd(); } + // -// DefaultConfigParser +// GenericConfigSection // -DefaultConfigParser::DefaultConfigParser(const char* buffer): -NutConfigParser(buffer) -{ +bool GenericConfigSection::empty()const { + return name.empty() && entries.empty(); +} + +void GenericConfigSection::clear() { + name.clear(); + entries.clear(); } -DefaultConfigParser::DefaultConfigParser(const std::string& buffer): -NutConfigParser(buffer) -{ +// +// DefaultConfigParser +// + +DefaultConfigParser::DefaultConfigParser(const char* buffer) : +NutConfigParser(buffer) { } +DefaultConfigParser::DefaultConfigParser(const std::string& buffer) : +NutConfigParser(buffer) { +} -void DefaultConfigParser::onParseBegin() -{ - // TODO +void DefaultConfigParser::onParseBegin() { + // Start with empty section (ie global one) + _section.clear(); } -void DefaultConfigParser::onParseComment(const std::string& comment) -{ - // TODO +void DefaultConfigParser::onParseComment(const std::string& /*comment*/) { + // Comment are ignored for now } -void DefaultConfigParser::onParseSectionName(const std::string& sectionName, const std::string& comment) -{ - // TODO +void DefaultConfigParser::onParseSectionName(const std::string& sectionName, const std::string& /*comment*/) { + // Comment are ignored for now + + // Process current section. + if (!_section.empty()) { + onParseSection(_section); + _section.clear(); + } + + // Start a new section + _section.name = sectionName; } -void DefaultConfigParser::onParseDirective(const std::string& directiveName, char sep, const ConfigParamList& values, const std::string& comment) -{ - // TODO +void DefaultConfigParser::onParseDirective(const std::string& directiveName, char /*sep*/, const ConfigParamList& values, const std::string& /*comment*/) { + // Comment are ignored for now + // Separator has no specific semantic in this context + + // Save values + _section.entries[directiveName].name = directiveName; + _section.entries[directiveName].values = values; + + // TODO Can probably be optimized. } -void DefaultConfigParser::onParseEnd() -{ - // TODO +void DefaultConfigParser::onParseEnd() { + // Process current (last) section + if (!_section.empty()) { + onParseSection(_section); + _section.clear(); + } } diff --git a/include/nutconf.h b/include/nutconf.h index e2cdd2c9c4..4adb23197a 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef __cplusplus @@ -120,6 +121,22 @@ class NutConfigParser : public NutParser virtual void onParseEnd()=0; }; +struct GenericConfigSectionEntry +{ + std::string name; + ConfigParamList values; + // std::string comment; +}; + +struct GenericConfigSection +{ + std::string name; + // std::string comment; + std::map entries; + + bool empty()const; + void clear(); +}; class DefaultConfigParser : public NutConfigParser { @@ -128,12 +145,15 @@ class DefaultConfigParser : public NutConfigParser DefaultConfigParser(const std::string& buffer); protected: + virtual void onParseSection(const GenericConfigSection& section)=0; virtual void onParseBegin(); virtual void onParseComment(const std::string& comment); virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); virtual void onParseEnd(); + + GenericConfigSection _section; ///> Currently parsed section }; From 501cdb0cc78bff14ac6bd1a089d57af0c480fe26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Fri, 19 Oct 2012 16:37:10 +0200 Subject: [PATCH 006/121] Implement GenericConfigParser and related. --- common/nutconf.cpp | 33 +++++++++++++++++++++++++++++++++ include/nutconf.h | 16 ++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 27c3ef3681..4aa9d55924 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -590,6 +590,39 @@ void DefaultConfigParser::onParseEnd() { } } +// +// GenericConfigParser +// + +GenericConfigParser::GenericConfigParser(const char* buffer): +DefaultConfigParser(buffer), +_config(NULL) +{ +} + +GenericConfigParser::GenericConfigParser(const std::string& buffer): +DefaultConfigParser(buffer), +_config(NULL) +{ +} + +void GenericConfigParser::onParseSection(const GenericConfigSection& section) +{ + if(_config!=NULL) + { + (*_config)[section.name] = section; + } +} + +void GenericConfigParser::parseGenericConfig(GenericConfiguration* config) +{ + if(config!=NULL) + { + _config = config; + parseConfig(); + _config = NULL; + } +} } /* namespace nut */ diff --git a/include/nutconf.h b/include/nutconf.h index 4adb23197a..cac3c5e247 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -157,6 +157,22 @@ class DefaultConfigParser : public NutConfigParser }; +typedef std::map GenericConfiguration; + +class GenericConfigParser : public DefaultConfigParser +{ +public: + GenericConfigParser(const char* buffer = NULL); + GenericConfigParser(const std::string& buffer); + + virtual void parseGenericConfig(GenericConfiguration* config); + +protected: + virtual void onParseSection(const GenericConfigSection& section); + + GenericConfiguration* _config; +}; + } /* namespace nut */ #endif /* __cplusplus */ From eb363e4826d864dcd76e2d542e2b5b1ef5f00d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Fri, 19 Oct 2012 17:24:46 +0200 Subject: [PATCH 007/121] Virtualize GenericConfiguration with BaseConfiguration to really allow specialized versions of config class. --- common/nutconf.cpp | 51 ++++++++++++++++++++++++++++------------------ include/nutconf.h | 34 ++++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 23 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 4aa9d55924..c709c70dc5 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -524,18 +524,6 @@ void NutConfigParser::parseConfig() { } -// -// GenericConfigSection -// - -bool GenericConfigSection::empty()const { - return name.empty() && entries.empty(); -} - -void GenericConfigSection::clear() { - name.clear(); - entries.clear(); -} // // DefaultConfigParser @@ -590,6 +578,20 @@ void DefaultConfigParser::onParseEnd() { } } + +// +// GenericConfigSection +// + +bool GenericConfigSection::empty()const { + return name.empty() && entries.empty(); +} + +void GenericConfigSection::clear() { + name.clear(); + entries.clear(); +} + // // GenericConfigParser // @@ -606,23 +608,32 @@ _config(NULL) { } -void GenericConfigParser::onParseSection(const GenericConfigSection& section) +void GenericConfigParser::parseConfig(BaseConfiguration* config) { - if(_config!=NULL) + if(config!=NULL) { - (*_config)[section.name] = section; + _config = config; + NutConfigParser::parseConfig(); + _config = NULL; } } -void GenericConfigParser::parseGenericConfig(GenericConfiguration* config) + +void GenericConfigParser::onParseSection(const GenericConfigSection& section) { - if(config!=NULL) + if(_config!=NULL) { - _config = config; - parseConfig(); - _config = NULL; + _config->setGenericConfigSection(section); } } +// +// GenericConfiguration +// +void GenericConfiguration::setGenericConfigSection(const GenericConfigSection& section) +{ + sections[section.name] = section; +} + } /* namespace nut */ diff --git a/include/nutconf.h b/include/nutconf.h index cac3c5e247..bb50c69db1 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -35,6 +35,13 @@ namespace nut { +class NutParser; +class NutConfigParser; +class DefaultConfigParser; +class GenericConfigParser; + + + /** * NUT config parser. */ @@ -157,7 +164,12 @@ class DefaultConfigParser : public NutConfigParser }; -typedef std::map GenericConfiguration; +class BaseConfiguration +{ + friend class GenericConfigParser; +protected: + virtual void setGenericConfigSection(const GenericConfigSection& section) = 0; +}; class GenericConfigParser : public DefaultConfigParser { @@ -165,15 +177,31 @@ class GenericConfigParser : public DefaultConfigParser GenericConfigParser(const char* buffer = NULL); GenericConfigParser(const std::string& buffer); - virtual void parseGenericConfig(GenericConfiguration* config); + virtual void parseConfig(BaseConfiguration* config); protected: virtual void onParseSection(const GenericConfigSection& section); - GenericConfiguration* _config; + BaseConfiguration* _config; }; +class GenericConfiguration : public BaseConfiguration +{ +public: + GenericConfiguration(){} + + // FIXME Let me public or set it as protected with public accessors ? + std::map sections; + +protected: + virtual void setGenericConfigSection(const GenericConfigSection& section); +}; + + + + + } /* namespace nut */ #endif /* __cplusplus */ #endif /* NUTCONF_H_SEEN */ From 86e32623003890bb5cd29e3f73f6e3a330a99844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Fri, 19 Oct 2012 17:41:36 +0200 Subject: [PATCH 008/121] Add GenericConfiguration function to parse from string (use GenericConfigParser). --- common/nutconf.cpp | 8 ++++++++ include/nutconf.h | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index c709c70dc5..645c40c224 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -630,10 +630,18 @@ void GenericConfigParser::onParseSection(const GenericConfigSection& section) // // GenericConfiguration // + void GenericConfiguration::setGenericConfigSection(const GenericConfigSection& section) { sections[section.name] = section; } +void GenericConfiguration::parseFromString(const std::string& str) +{ + GenericConfigParser parser(str); + parser.parseConfig(this); +} + + } /* namespace nut */ diff --git a/include/nutconf.h b/include/nutconf.h index bb50c69db1..9665a902fa 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -191,6 +191,10 @@ class GenericConfiguration : public BaseConfiguration public: GenericConfiguration(){} + void parseFromString(const std::string& str); + + // TODO Add functions to write to string or files (Vasek ?) + // FIXME Let me public or set it as protected with public accessors ? std::map sections; From bae95f7fed92e03e0e3cb315585c4d597fa43b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Mon, 22 Oct 2012 11:21:58 +0200 Subject: [PATCH 009/121] Add unit test for GenericConfiguration parsing. Add UT for GenericConfiguration (validate GenericConfigParser and all the stack). Fix some errors found with UT. --- common/nutconf.cpp | 43 ++++++++++++++++++++++++++------- include/nutconf.h | 9 +++++++ tests/nutconf.cpp | 59 ++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 93 insertions(+), 18 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 645c40c224..cb0561eda9 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -242,7 +242,12 @@ NutParser::Token NutParser::parseToken() { } } else if (c == ' ' || c == '\t' || isgraph(c)) { token.str += c; - } else if (c == 0) /* EOL */ { + } else if (c == '\r' || c == '\n') /* EOL */{ + /* WTF ? consider it as correct ? */ + back(); + popPos(); + return token; + } else if (c == 0) /* EOF */ { popPos(); return token; } else /* Bad character ?? */ { @@ -269,8 +274,14 @@ NutParser::Token NutParser::parseToken() { } else { escaped = true; } - } /* else if (c == '\r' || c == '\n') */ - else if (isgraph(c)) { + } else if (c == '\r' || c == '\n') /* EOL */{ + back(); + popPos(); + return token; + } else if (c == 0) /* EOF */ { + popPos(); + return token; + }else if (isgraph(c)) { token.str += c; } else /* Bad character ?? */ { /* WTF ? Keep, Ignore ? */ @@ -391,7 +402,6 @@ void NutConfigParser::parseConfig() { state = CPS_DEFAULT; break; case Token::TOKEN_EOL: - case Token::TOKEN_NONE: /* Lack of closing bracket !!! */ onParseSectionName(name); /* Clean and return to default */ @@ -417,7 +427,6 @@ void NutConfigParser::parseConfig() { state = CPS_DEFAULT; break; case Token::TOKEN_EOL: - case Token::TOKEN_NONE: /* Lack of closing bracket !!! */ onParseSectionName(name); /* Clean and return to default */ @@ -439,7 +448,6 @@ void NutConfigParser::parseConfig() { state = CPS_DEFAULT; break; case Token::TOKEN_EOL: - case Token::TOKEN_NONE: /* Could occur ! */ onParseSectionName(name); /* Clean and return to default */ @@ -461,7 +469,6 @@ void NutConfigParser::parseConfig() { state = CPS_DEFAULT; break; case Token::TOKEN_EOL: - case Token::TOKEN_NONE: /* Could occur ! */ onParseDirective(name); /* Clean and return to default */ @@ -497,7 +504,6 @@ void NutConfigParser::parseConfig() { state = CPS_DEFAULT; break; case Token::TOKEN_EOL: - case Token::TOKEN_NONE: /* Could occur ! */ onParseDirective(name, sep, values); /* Clean and return to default */ @@ -520,6 +526,27 @@ void NutConfigParser::parseConfig() { } } + switch(state) + { + case CPS_SECTION_OPENED: + case CPS_SECTION_HAVE_NAME: + /* Lack of closing bracket !!! */ + onParseSectionName(name); + break; + case CPS_SECTION_CLOSED: + /* Could occur ! */ + onParseSectionName(name); + break; + case CPS_DIRECTIVE_HAVE_NAME: + /* Could occur ! */ + onParseDirective(name); + break; + case CPS_DIRECTIVE_VALUES: + /* Could occur ! */ + onParseDirective(name, sep, values); + break; + } + onParseEnd(); } diff --git a/include/nutconf.h b/include/nutconf.h index 9665a902fa..fa99e576ac 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -133,6 +133,7 @@ struct GenericConfigSectionEntry std::string name; ConfigParamList values; // std::string comment; + }; struct GenericConfigSection @@ -141,6 +142,9 @@ struct GenericConfigSection // std::string comment; std::map entries; + const GenericConfigSectionEntry& operator [] (const std::string& varname)const{return entries.find(varname)->second;} + GenericConfigSectionEntry& operator [] (const std::string& varname){return entries[varname];} + bool empty()const; void clear(); }; @@ -195,9 +199,14 @@ class GenericConfiguration : public BaseConfiguration // TODO Add functions to write to string or files (Vasek ?) + // FIXME Let me public or set it as protected with public accessors ? std::map sections; + const GenericConfigSection& operator[](const std::string& secname)const{return sections.find(secname)->second;} + GenericConfigSection& operator[](const std::string& secname){return sections[secname];} + + protected: virtual void setGenericConfigSection(const GenericConfigSection& section); }; diff --git a/tests/nutconf.cpp b/tests/nutconf.cpp index c78d74387f..439997ec69 100644 --- a/tests/nutconf.cpp +++ b/tests/nutconf.cpp @@ -34,6 +34,7 @@ class NutConfTest : public CppUnit::TestFixture CPPUNIT_TEST( testParseCHARS ); CPPUNIT_TEST( testParseSTRCHARS ); CPPUNIT_TEST( testPasreToken ); + CPPUNIT_TEST( testGenericConfigParser ); CPPUNIT_TEST_SUITE_END(); public: @@ -43,6 +44,8 @@ class NutConfTest : public CppUnit::TestFixture void testParseCHARS(); void testParseSTRCHARS(); void testPasreToken(); + + void testGenericConfigParser(); }; // Registers the fixture into the 'registry' @@ -120,13 +123,49 @@ void NutConfTest::testPasreToken() CPPUNIT_ASSERT_MESSAGE("Cannot find 1st token 'Bonjour'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "Bonjour")); CPPUNIT_ASSERT_MESSAGE("Cannot find 2nd token 'monde'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "monde")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 3rd token '['", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_BRACKET_OPEN, "[")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 4th token 'ceci'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "ceci")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 5th token ']'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_BRACKET_CLOSE, "]")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 6th token ' Plouf'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_COMMENT, " Plouf")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 7th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 8th token 'titi'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "titi")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 9th token '='", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EQUAL, "=")); - CPPUNIT_ASSERT_MESSAGE("Cannot find 10th token 'tata toto'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_QUOTED_STRING, "tata toto")); - -} \ No newline at end of file + CPPUNIT_ASSERT_MESSAGE("Cannot find 3th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 4rd token '['", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_BRACKET_OPEN, "[")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 5th token 'ceci'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "ceci")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 6th token ']'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_BRACKET_CLOSE, "]")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 7th token ' Plouf'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_COMMENT, " Plouf")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 8th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 9th token 'titi'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "titi")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 10th token '='", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EQUAL, "=")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 11th token 'tata toto'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_QUOTED_STRING, "tata toto")); + +} + +void NutConfTest::testGenericConfigParser() +{ + static const char* src = + "glovar1 = toto\n" + "glovar2 = \"truc bidule\"\n" + "\n" + "[section1] # One section\n" + "var1 = \"one value\"\n" + " \n" + "var2\n" + "\n" + "[section2]\n" + "var1 = other value\n" + "var toto"; + + GenericConfiguration conf; + conf.parseFromString(src); + + CPPUNIT_ASSERT_MESSAGE("Cannot find a global section", conf.sections.find("") != conf.sections.end() ); + CPPUNIT_ASSERT_MESSAGE("Cannot find global section's glovar1 variable", conf.sections[""]["glovar1"].values.front() == "toto" ); + CPPUNIT_ASSERT_MESSAGE("Cannot find global section's glovar2 variable", conf.sections[""]["glovar2"].values.front() == "truc bidule" ); + + CPPUNIT_ASSERT_MESSAGE("Cannot find section1", conf.sections.find("section1") != conf.sections.end() ); + CPPUNIT_ASSERT_MESSAGE("Cannot find section1's var1 variable", conf.sections["section1"]["var1"].values.front() == "one value" ); + CPPUNIT_ASSERT_MESSAGE("Cannot find section1's var2 variable", conf.sections["section1"]["var2"].values.size() == 0 ); + + CPPUNIT_ASSERT_MESSAGE("Cannot find section2", conf.sections.find("section2") != conf.sections.end() ); + CPPUNIT_ASSERT_MESSAGE("Cannot find section2's var1 variable", conf.sections["section2"]["var1"].values.front() == "other" ); + CPPUNIT_ASSERT_MESSAGE("Cannot find section2's var1 variable", *(++(conf.sections["section2"]["var1"].values.begin())) == "value" ); + CPPUNIT_ASSERT_MESSAGE("Cannot find section2's var variable", conf.sections["section2"]["var"].values.front() == "toto" ); + +} + + From 31fc32c5e7718c50058b3d03b20b350fb8ccb0a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Mon, 22 Oct 2012 23:47:58 +0200 Subject: [PATCH 010/121] Add stubs for upsmon.conf parser and config structure. --- common/nutconf.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++++ include/nutconf.h | 65 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index cb0561eda9..e439eeb474 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -669,6 +669,74 @@ void GenericConfiguration::parseFromString(const std::string& str) parser.parseConfig(this); } +// +// UpsmonConfiguration +// + +UpsmonConfiguration::UpsmonConfiguration(): +minSupplies(0), poolFreq(0), poolFreqAlert(0), hotSync(0), +deadTime(0), rbWarnTime(0), noCommWarnTime(0), finalDelay(0) +{ +} + +void UpsmonConfiguration::parseFromString(const std::string& str) +{ + UpsmonConfigParser parser(str); + parser.parseUpsmonConfig(this); +} + +// +// UpsmonConfigParser +// + +UpsmonConfigParser::UpsmonConfigParser(const char* buffer): +NutConfigParser(buffer) +{ +} + +UpsmonConfigParser::UpsmonConfigParser(const std::string& buffer): +NutConfigParser(buffer) +{ +} + +void UpsmonConfigParser::parseUpsmonConfig(UpsmonConfiguration* config) +{ + if(config!=NULL) + { + _config = config; + NutConfigParser::parseConfig(); + _config = NULL; + } +} + +void UpsmonConfigParser::onParseBegin() +{ + // Do nothing +} + +void UpsmonConfigParser::onParseComment(const std::string& comment) +{ + // Comment are ignored for now +} + +void UpsmonConfigParser::onParseSectionName(const std::string& sectionName, const std::string& comment) +{ + // There must not have sections in upsm.conf. + // Ignore it + // TODO Add error reporting ? +} + +void UpsmonConfigParser::onParseDirective(const std::string& directiveName, char sep, const ConfigParamList& values, const std::string& comment) +{ + // TODO +} + +void UpsmonConfigParser::onParseEnd() +{ + // Do nothing +} + + } /* namespace nut */ diff --git a/include/nutconf.h b/include/nutconf.h index fa99e576ac..54e8b01717 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -214,6 +214,71 @@ class GenericConfiguration : public BaseConfiguration +class UpsmonConfiguration +{ +public: + UpsmonConfiguration(); + void parseFromString(const std::string& str); + + std::string runAsUser, shutdownCmd, notifyCmd, powerDownFlag; + unsigned int minSupplies, poolFreq, poolFreqAlert, hotSync; + unsigned int deadTime, rbWarnTime, noCommWarnTime, finalDelay; + + enum NotifyFlag { + NOTIFY_IGNORE = 0, + NOTIFY_SYSLOG = 1, + NOTIFY_WALL = 1 << 1, + NOTIFY_EXEC = 1 << 2 + }; + + enum NotifyType { + NOTIFY_ONLINE, + NOTIFY_ONBATT, + NOTIFY_LOWBATT, + NOTIFY_FSD, + NOTIFY_COMMOK, + NOTIFY_COMMBAD, + NOTIFY_SHUTDOWN, + NOTIFY_REPLBATT, + NOTIFY_NOCOMM, + NOTIFY_NOPARENT, + NOTIFY_TYPE_MAX + }; + + unsigned short notifyFlags[NOTIFY_TYPE_MAX]; + + struct Monitor { + std::string upsname, hostname; + unsigned short port; + unsigned int powerValue; + std::string username, password; + bool isMaster; + }; + + std::list monitors; + +}; + + + +class UpsmonConfigParser : public NutConfigParser +{ +public: + UpsmonConfigParser(const char* buffer = NULL); + UpsmonConfigParser(const std::string& buffer); + + void parseUpsmonConfig(UpsmonConfiguration* config); +protected: + virtual void onParseBegin(); + virtual void onParseComment(const std::string& comment); + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); + virtual void onParseEnd(); + + UpsmonConfiguration* _config; +}; + + } /* namespace nut */ #endif /* __cplusplus */ From bf53b02aa9310be0302a2b0e299071f0a2d014fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Tue, 23 Oct 2012 08:26:31 +0200 Subject: [PATCH 011/121] Add notify messages array in UpsmonConfiguration (oups !). --- include/nutconf.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/nutconf.h b/include/nutconf.h index 54e8b01717..31fe63a70e 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -246,6 +246,7 @@ class UpsmonConfiguration }; unsigned short notifyFlags[NOTIFY_TYPE_MAX]; + std::string notifyMessages[NOTIFY_TYPE_MAX]; struct Monitor { std::string upsname, hostname; From 513bb4378fa3c3d89b478820bf3b09a816665cb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Tue, 23 Oct 2012 08:50:16 +0200 Subject: [PATCH 012/121] Create and use a Settable helper which indicate if a parameter is set or not. --- include/nutconf.h | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/include/nutconf.h b/include/nutconf.h index 31fe63a70e..3bc28a72db 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -41,6 +41,33 @@ class DefaultConfigParser; class GenericConfigParser; +/** + * Helper to specify if a configuration variable is set or not. + * In addition of its value. + */ +template +class Settable +{ +protected: + Type _value; + bool _set; +public: + Settable():_set(false){} + Settable(const Settable& val):_value(val._value), _set(val._set){} + Settable(const Type& val):_value(val), _set(true){} + + bool set()const{return _set;} + void clear(){_set = false;} + + operator const Type&()const{return _value;} + operator Type&(){return _value;} + + const Type& operator *()const{return _value;} + Type& operator *(){return _value;} + + Settable& operator=(const Type& val){_value = val; _set = true;} +}; + /** * NUT config parser. @@ -213,16 +240,15 @@ class GenericConfiguration : public BaseConfiguration - class UpsmonConfiguration { public: UpsmonConfiguration(); void parseFromString(const std::string& str); - std::string runAsUser, shutdownCmd, notifyCmd, powerDownFlag; - unsigned int minSupplies, poolFreq, poolFreqAlert, hotSync; - unsigned int deadTime, rbWarnTime, noCommWarnTime, finalDelay; + Settable runAsUser, shutdownCmd, notifyCmd, powerDownFlag; + Settable minSupplies, poolFreq, poolFreqAlert, hotSync; + Settable deadTime, rbWarnTime, noCommWarnTime, finalDelay; enum NotifyFlag { NOTIFY_IGNORE = 0, From 5e6487ff0cc404fd50199f1688c1c110db7e715d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Tue, 23 Oct 2012 11:40:25 +0200 Subject: [PATCH 013/121] Implement UpsmonConfigParser and related. --- common/nutconf.cpp | 222 +++++++++++++++++++++++++++++++++++++++++++-- include/nutconf.h | 7 +- tests/nutconf.cpp | 68 +++++++++++++- 3 files changed, 285 insertions(+), 12 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index e439eeb474..757e765cc9 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -22,11 +22,39 @@ #include #include +#include +#include + #include "nutconf.h" namespace nut { +// +// Tool functions +// + +/** + * Parse a specified type from a string and set it as Settable if success. + */ +template +Settable StringToSettableNumber(const std::string & src) +{ + std::stringstream ss(src); + T result; + if(ss >> result) + { + return Settable(result); + } + else + { + return Settable(); + } +} + + + + // // NutParser // @@ -673,9 +701,7 @@ void GenericConfiguration::parseFromString(const std::string& str) // UpsmonConfiguration // -UpsmonConfiguration::UpsmonConfiguration(): -minSupplies(0), poolFreq(0), poolFreqAlert(0), hotSync(0), -deadTime(0), rbWarnTime(0), noCommWarnTime(0), finalDelay(0) +UpsmonConfiguration::UpsmonConfiguration() { } @@ -685,6 +711,46 @@ void UpsmonConfiguration::parseFromString(const std::string& str) parser.parseUpsmonConfig(this); } +UpsmonConfiguration::NotifyFlag UpsmonConfiguration::NotifyFlagFromString(const std::string& str) +{ + if(str=="SYSLOG") + return NOTIFY_SYSLOG; + else if(str=="WALL") + return NOTIFY_WALL; + else if(str=="EXEC") + return NOTIFY_EXEC; + else if(str=="IGNORE") + return NOTIFY_IGNORE; + else + return NOTIFY_IGNORE; +} + +UpsmonConfiguration::NotifyType UpsmonConfiguration::NotifyTypeFromString(const std::string& str) +{ + if(str=="ONLINE") + return NOTIFY_ONLINE; + else if(str=="ONBATT") + return NOTIFY_ONBATT; + else if(str=="LOWBATT") + return NOTIFY_LOWBATT; + else if(str=="FSD") + return NOTIFY_FSD; + else if(str=="COMMOK") + return NOTIFY_COMMOK; + else if(str=="COMMBAD") + return NOTIFY_COMMBAD; + else if(str=="SHUTDOWN") + return NOTIFY_SHUTDOWN; + else if(str=="REPLBATT") + return NOTIFY_REPLBATT; + else if(str=="NOCOMM") + return NOTIFY_NOCOMM; + else if(str=="NOPARENT") + return NOTIFY_NOPARENT; + else + return NOTIFY_TYPE_MAX; +} + // // UpsmonConfigParser // @@ -714,21 +780,161 @@ void UpsmonConfigParser::onParseBegin() // Do nothing } -void UpsmonConfigParser::onParseComment(const std::string& comment) +void UpsmonConfigParser::onParseComment(const std::string& /*comment*/) { // Comment are ignored for now } -void UpsmonConfigParser::onParseSectionName(const std::string& sectionName, const std::string& comment) +void UpsmonConfigParser::onParseSectionName(const std::string& /*sectionName*/, const std::string& /*comment*/) { // There must not have sections in upsm.conf. // Ignore it // TODO Add error reporting ? } -void UpsmonConfigParser::onParseDirective(const std::string& directiveName, char sep, const ConfigParamList& values, const std::string& comment) + +void UpsmonConfigParser::onParseDirective(const std::string& directiveName, char /*sep*/, const ConfigParamList& values, const std::string& /*comment*/) { - // TODO + // NOTE: separators are always ignored + + if(_config) + { + if(directiveName == "RUN_AS_USER") + { + if(values.size()>0) + { + _config->runAsUser = values.front(); + } + } + else if(directiveName == "MONITOR") + { + if(values.size()==5) + { + UpsmonConfiguration::Monitor monitor; + ConfigParamList::const_iterator it = values.begin(); + std::stringstream system(*it++); + std::string word; + monitor.upsname = (getline(system, word, '@'), word); + monitor.hostname = (getline(system, word, ':'), word); + monitor.port = (getline(system, word) ? *StringToSettableNumber(word) : 0u); + monitor.powerValue = StringToSettableNumber(*it++); + monitor.username = *it++; + monitor.password = *it++; + monitor.isMaster = (*it) == "master"; + _config->monitors.push_back(monitor); + } + } + else if(directiveName == "MINSUPPLIES") + { + if(values.size()>0) + { + _config->minSupplies = StringToSettableNumber(values.front()); + } + } + else if(directiveName == "SHUTDOWNCMD") + { + if(values.size()>0) + { + _config->shutdownCmd = values.front(); + } + } + else if(directiveName == "NOTIFYCMD") + { + if(values.size()>0) + { + _config->notifyCmd = values.front(); + } + } + else if(directiveName == "POLLFREQ") + { + if(values.size()>0) + { + _config->poolFreq = StringToSettableNumber(values.front()); + } + } + else if(directiveName == "POLLFREQALERT") + { + if(values.size()>0) + { + _config->poolFreqAlert = StringToSettableNumber(values.front()); + } + } + else if(directiveName == "HOSTSYNC") + { + if(values.size()>0) + { + _config->hotSync = StringToSettableNumber(values.front()); + } + } + else if(directiveName == "DEADTIME") + { + if(values.size()>0) + { + _config->deadTime = StringToSettableNumber(values.front()); + } + } + else if(directiveName == "POWERDOWNFLAG") + { + if(values.size()>0) + { + _config->powerDownFlag = values.front(); + } + } + else if(directiveName == "NOTIFYMSG") + { + if(values.size()==2) + { + UpsmonConfiguration::NotifyType type = UpsmonConfiguration::NotifyTypeFromString(values.front()); + if(type!=UpsmonConfiguration::NOTIFY_TYPE_MAX) + { + _config->notifyMessages[(unsigned int)type] = *(++values.begin()); + } + } + } + else if(directiveName == "NOTIFYFLAG") + { + if(values.size()==2) + { + UpsmonConfiguration::NotifyType type = UpsmonConfiguration::NotifyTypeFromString(values.front()); + if(type!=UpsmonConfiguration::NOTIFY_TYPE_MAX) + { + unsigned int flags = 0; + std::string word; + std::stringstream stream(*(++values.begin())); + while( getline(stream, word, '+') ) + { + flags |= UpsmonConfiguration::NotifyFlagFromString(word); + } + _config->notifyFlags[(unsigned int)type] = flags; + } + } + } + else if(directiveName == "RBWARNTIME") + { + if(values.size()>0) + { + _config->rbWarnTime = StringToSettableNumber(values.front()); + } + } + else if(directiveName == "NOCOMMWARNTIME") + { + if(values.size()>0) + { + _config->noCommWarnTime = StringToSettableNumber(values.front()); + } + } + else if(directiveName == "FINALDELAY") + { + if(values.size()>0) + { + _config->finalDelay = StringToSettableNumber(values.front()); + } + } + else + { + // TODO WTF with unknown commands ? + } + } } void UpsmonConfigParser::onParseEnd() @@ -737,6 +943,4 @@ void UpsmonConfigParser::onParseEnd() } - - } /* namespace nut */ diff --git a/include/nutconf.h b/include/nutconf.h index 3bc28a72db..a98ba53d7b 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -271,8 +271,11 @@ class UpsmonConfiguration NOTIFY_TYPE_MAX }; - unsigned short notifyFlags[NOTIFY_TYPE_MAX]; - std::string notifyMessages[NOTIFY_TYPE_MAX]; + static NotifyFlag NotifyFlagFromString(const std::string& str); + static NotifyType NotifyTypeFromString(const std::string& str); + + Settable notifyFlags[NOTIFY_TYPE_MAX]; + Settable notifyMessages[NOTIFY_TYPE_MAX]; struct Monitor { std::string upsname, hostname; diff --git a/tests/nutconf.cpp b/tests/nutconf.cpp index 439997ec69..e3f393c28f 100644 --- a/tests/nutconf.cpp +++ b/tests/nutconf.cpp @@ -35,6 +35,7 @@ class NutConfTest : public CppUnit::TestFixture CPPUNIT_TEST( testParseSTRCHARS ); CPPUNIT_TEST( testPasreToken ); CPPUNIT_TEST( testGenericConfigParser ); + CPPUNIT_TEST( testUpsmonConfigParser ); CPPUNIT_TEST_SUITE_END(); public: @@ -46,6 +47,7 @@ class NutConfTest : public CppUnit::TestFixture void testPasreToken(); void testGenericConfigParser(); + void testUpsmonConfigParser(); }; // Registers the fixture into the 'registry' @@ -115,7 +117,9 @@ void NutConfTest::testPasreToken() "Bonjour monde\n" "[ceci]# Plouf\n" "\n" - "titi = \"tata toto\""; + "titi = \"tata toto\"\n" + "NOTIFYFLAG LOWBATT SYSLOG+WALL" + ; NutParser parse(src); // NutConfigParser::Token tok = parse.parseToken(); @@ -132,6 +136,10 @@ void NutConfTest::testPasreToken() CPPUNIT_ASSERT_MESSAGE("Cannot find 9th token 'titi'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "titi")); CPPUNIT_ASSERT_MESSAGE("Cannot find 10th token '='", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EQUAL, "=")); CPPUNIT_ASSERT_MESSAGE("Cannot find 11th token 'tata toto'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_QUOTED_STRING, "tata toto")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 12th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 13th token 'NOTIFYFLAG'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "NOTIFYFLAG")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 14th token 'LOWBATT'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "LOWBATT")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 15th token 'SYSLOG+WALL'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "SYSLOG+WALL")); } @@ -168,4 +176,62 @@ void NutConfTest::testGenericConfigParser() } +void NutConfTest::testUpsmonConfigParser() +{ + static const char* src = + "RUN_AS_USER nutmon\n" + "MONITOR myups@bigserver 1 monmaster blah master\n" + "MONITOR su700@server.example.com 1 upsmon secretpass slave\n" + "MONITOR myups@localhost 1 upsmon pass master\n" + "MINSUPPLIES 1\n" + "\n" + "# MINSUPPLIES 25\n" + "SHUTDOWNCMD \"/sbin/shutdown -h +0\"\n" + "NOTIFYCMD /usr/local/ups/bin/notifyme\n" + "POLLFREQ 30\n" + "POLLFREQALERT 5\n" + "HOSTSYNC 15\n" + "DEADTIME 15\n" + "POWERDOWNFLAG /etc/killpower\n" + "NOTIFYMSG ONLINE \"UPS %s on line power\"\n" + "NOTIFYFLAG LOWBATT SYSLOG+WALL\n" + "RBWARNTIME 43200\n" + "NOCOMMWARNTIME 300\n" + "FINALDELAY 5" + ; + + UpsmonConfiguration conf; + conf.parseFromString(src); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find RUN_AS_USER 'nutmon'", string("nutmon"), *conf.runAsUser); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find MINSUPPLIES 1", 1u, *conf.minSupplies); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find SHUTDOWNCMD '/sbin/shutdown -h +0'", string("/sbin/shutdown -h +0"), *conf.shutdownCmd); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find NOTIFYCMD '/usr/local/ups/bin/notifyme'", string("/usr/local/ups/bin/notifyme"), *conf.notifyCmd); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find POWERDOWNFLAG '/etc/killpower'", string("/etc/killpower"), *conf.powerDownFlag); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find POLLFREQ 30", 30u, *conf.poolFreq); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find POLLFREQALERT 5", 5u, *conf.poolFreqAlert); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find HOSTSYNC 15", 15u, *conf.hotSync); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find DEADTIME 15", 15u, *conf.deadTime); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find RBWARNTIME 43200", 43200u, *conf.rbWarnTime); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find NOCOMMWARNTIME 300", 300u, *conf.noCommWarnTime); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find FINALDELAY 5", 5u, *conf.finalDelay); + + CPPUNIT_ASSERT_MESSAGE("Find a NOTIFYFLAG ONLINE", !conf.notifyFlags[nut::UpsmonConfiguration::NOTIFY_ONLINE].set()); + CPPUNIT_ASSERT_MESSAGE("Cannot find a NOTIFYFLAG LOWBATT", conf.notifyFlags[nut::UpsmonConfiguration::NOTIFY_LOWBATT].set()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find a NOTIFYFLAG LOWBATT SYSLOG+WALL", 3u, (unsigned int)conf.notifyFlags[nut::UpsmonConfiguration::NOTIFY_LOWBATT]); + + + CPPUNIT_ASSERT_MESSAGE("Find a NOTIFYMSG LOWBATT", !conf.notifyMessages[nut::UpsmonConfiguration::NOTIFY_LOWBATT].set()); + CPPUNIT_ASSERT_MESSAGE("Cannot find a NOTIFYMSG ONLINE", conf.notifyMessages[nut::UpsmonConfiguration::NOTIFY_ONLINE].set()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find a NOTIFYMSG ONLINE \"UPS %s on line power\"", string("UPS %s on line power"), *conf.notifyMessages[nut::UpsmonConfiguration::NOTIFY_ONLINE]); + + +} + + + + + + + From c69305dc7a138af9ece3855c16a03061020415c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Tue, 23 Oct 2012 15:17:14 +0200 Subject: [PATCH 014/121] Implement nut.conf NutConfiguration parser. --- common/nutconf.cpp | 94 +++++++++++++++++++++++++++++++++++++++++++++- include/nutconf.h | 37 ++++++++++++++++++ tests/nutconf.cpp | 14 ++++++- 3 files changed, 143 insertions(+), 2 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 757e765cc9..5bd4b60ca6 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -798,7 +798,7 @@ void UpsmonConfigParser::onParseDirective(const std::string& directiveName, char // NOTE: separators are always ignored if(_config) - { + { if(directiveName == "RUN_AS_USER") { if(values.size()>0) @@ -942,5 +942,97 @@ void UpsmonConfigParser::onParseEnd() // Do nothing } +// +// NutConfiguration +// + +NutConfiguration::NutConfiguration() +{ +} + +void NutConfiguration::parseFromString(const std::string& str) +{ + NutConfConfigParser parser(str); + parser.parseNutConfConfig(this); +} + +NutConfiguration::NutMode NutConfiguration::NutModeFromString(const std::string& str) +{ + if(str == "none") + return MODE_NONE; + else if(str == "standalone") + return MODE_STANDALONE; + else if(str == "netserver") + return MODE_NETSERVER; + else if(str == "netclient") + return MODE_NETCLIENT; + else + return MODE_UNKNOWN; +} + + +// +// NutConfConfigParser +// + +NutConfConfigParser::NutConfConfigParser(const char* buffer): +NutConfigParser(buffer) +{ +} + +NutConfConfigParser::NutConfConfigParser(const std::string& buffer): +NutConfigParser(buffer) +{ +} + +void NutConfConfigParser::parseNutConfConfig(NutConfiguration* config) +{ + if(config!=NULL) + { + _config = config; + NutConfigParser::parseConfig(); + _config = NULL; + } +} + +void NutConfConfigParser::onParseBegin() +{ + // Do nothing +} + +void NutConfConfigParser::onParseComment(const std::string& /*comment*/) +{ + // Comment are ignored for now +} + +void NutConfConfigParser::onParseSectionName(const std::string& /*sectionName*/, const std::string& /*comment*/) +{ + // There must not have sections in upsm.conf. + // Ignore it + // TODO Add error reporting ? +} + +void NutConfConfigParser::onParseDirective(const std::string& directiveName, char /*sep*/, const ConfigParamList& values, const std::string& /*comment*/) +{ + // Comment are ignored for now + // NOTE: although sep must be '=', sep is not verified. + if(_config && directiveName=="MODE" && values.size()==1) + { + std::string val = values.front(); + NutConfiguration::NutMode mode = NutConfiguration::NutModeFromString(val); + if(mode != NutConfiguration::MODE_UNKNOWN) + _config->mode = mode; + } + else + { + // TODO WTF with errors ? + } +} + +void NutConfConfigParser::onParseEnd() +{ + // Do nothing +} + } /* namespace nut */ diff --git a/include/nutconf.h b/include/nutconf.h index a98ba53d7b..378cddb55f 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -309,6 +309,43 @@ class UpsmonConfigParser : public NutConfigParser }; +class NutConfiguration +{ +public: + NutConfiguration(); + void parseFromString(const std::string& str); + + enum NutMode { + MODE_UNKNOWN = -1, + MODE_NONE = 0, + MODE_STANDALONE, + MODE_NETSERVER, + MODE_NETCLIENT + }; + + Settable mode; + + static NutMode NutModeFromString(const std::string& str); +}; + + +class NutConfConfigParser : public NutConfigParser +{ +public: + NutConfConfigParser(const char* buffer = NULL); + NutConfConfigParser(const std::string& buffer); + + void parseNutConfConfig(NutConfiguration* config); +protected: + virtual void onParseBegin(); + virtual void onParseComment(const std::string& comment); + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); + virtual void onParseEnd(); + + NutConfiguration* _config; +}; + } /* namespace nut */ #endif /* __cplusplus */ diff --git a/tests/nutconf.cpp b/tests/nutconf.cpp index e3f393c28f..a6845d8581 100644 --- a/tests/nutconf.cpp +++ b/tests/nutconf.cpp @@ -36,6 +36,7 @@ class NutConfTest : public CppUnit::TestFixture CPPUNIT_TEST( testPasreToken ); CPPUNIT_TEST( testGenericConfigParser ); CPPUNIT_TEST( testUpsmonConfigParser ); + CPPUNIT_TEST( testNutConfConfigParser ); CPPUNIT_TEST_SUITE_END(); public: @@ -48,6 +49,7 @@ class NutConfTest : public CppUnit::TestFixture void testGenericConfigParser(); void testUpsmonConfigParser(); + void testNutConfConfigParser(); }; // Registers the fixture into the 'registry' @@ -224,11 +226,21 @@ void NutConfTest::testUpsmonConfigParser() CPPUNIT_ASSERT_MESSAGE("Find a NOTIFYMSG LOWBATT", !conf.notifyMessages[nut::UpsmonConfiguration::NOTIFY_LOWBATT].set()); CPPUNIT_ASSERT_MESSAGE("Cannot find a NOTIFYMSG ONLINE", conf.notifyMessages[nut::UpsmonConfiguration::NOTIFY_ONLINE].set()); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find a NOTIFYMSG ONLINE \"UPS %s on line power\"", string("UPS %s on line power"), *conf.notifyMessages[nut::UpsmonConfiguration::NOTIFY_ONLINE]); +} -} +void NutConfTest::testNutConfConfigParser() +{ + static const char* src = + "\n\nMODE=standalone\n"; + NutConfiguration conf; + conf.parseFromString(src); + CPPUNIT_ASSERT_MESSAGE("Cannot find a MODE", conf.mode.set()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find a MODE=standalone", nut::NutConfiguration::MODE_STANDALONE, *conf.mode); + +} From ba516e7d4dd8bfd26a545acdcffce22ebb3ea3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Tue, 23 Oct 2012 16:49:37 +0200 Subject: [PATCH 015/121] Implement upsd.conf UpsdConfigParser. Test pending. A bug is pending: IPv6 format must be in quoted string because of ':'. --- common/nutconf.cpp | 115 +++++++++++++++++++++++++++++++++++++++++++++ include/nutconf.h | 35 ++++++++++++++ 2 files changed, 150 insertions(+) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 5bd4b60ca6..f4a9ece65c 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -1035,4 +1035,119 @@ void NutConfConfigParser::onParseEnd() } +// +// UpsdConfiguration +// + +UpsdConfiguration::UpsdConfiguration() +{ +} + +void UpsdConfiguration::parseFromString(const std::string& str) +{ + UpsdConfigParser parser(str); + parser.parseUpsdConfig(this); +} + +// +// UpsdConfigParser +// + +UpsdConfigParser::UpsdConfigParser(const char* buffer): +NutConfigParser(buffer) +{ +} + +UpsdConfigParser::UpsdConfigParser(const std::string& buffer): +NutConfigParser(buffer) +{ +} + +void UpsdConfigParser::parseUpsdConfig(UpsdConfiguration* config) +{ + if(config!=NULL) + { + _config = config; + NutConfigParser::parseConfig(); + _config = NULL; + } +} + +void UpsdConfigParser::onParseBegin() +{ + // Do nothing +} + +void UpsdConfigParser::onParseComment(const std::string& comment) +{ + // Comment are ignored for now +} + +void UpsdConfigParser::onParseSectionName(const std::string& sectionName, const std::string& comment) +{ + // There must not have sections in upsm.conf. + // Ignore it + // TODO Add error reporting ? +} + +void UpsdConfigParser::onParseDirective(const std::string& directiveName, char sep, const ConfigParamList& values, const std::string& comment) +{ + // NOTE: separators are always ignored + + if(_config) + { + if(directiveName == "MAXAGE") + { + if(values.size()>0) + { + _config->maxAge = StringToSettableNumber(values.front()); + } + } + else if(directiveName == "STATEPATH") + { + if(values.size()>0) + { + _config->statePath = values.front(); + } + } + else if(directiveName == "MAXCONN") + { + if(values.size()>0) + { + _config->maxConn = StringToSettableNumber(values.front()); + } + } + else if(directiveName == "CERTFILE") + { + if(values.size()>0) + { + _config->certFile = values.front(); + } + } + else if(directiveName == "LISTEN") + { + if(values.size()==1 || values.size()==2) + { + UpsdConfiguration::Listen listen; + listen.address = values.front(); + if(values.size()==2) + { + listen.port = StringToSettableNumber(*(++values.begin())); + } + _config->listens.push_back(listen); + } + } + else + { + // TODO WTF with unknown commands ? + } + } +} + +void UpsdConfigParser::onParseEnd() +{ + // Do nothing +} + + } /* namespace nut */ diff --git a/include/nutconf.h b/include/nutconf.h index 378cddb55f..9edb2b970b 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -347,6 +347,41 @@ class NutConfConfigParser : public NutConfigParser }; +class UpsdConfiguration +{ +public: + UpsdConfiguration(); + void parseFromString(const std::string& str); + + Settable maxAge, maxConn; + Settable statePath, certFile; + + struct Listen + { + std::string address; + Settable port; + }; + std::list listens; +}; + + +class UpsdConfigParser : public NutConfigParser +{ +public: + UpsdConfigParser(const char* buffer = NULL); + UpsdConfigParser(const std::string& buffer); + + void parseUpsdConfig(UpsdConfiguration* config); +protected: + virtual void onParseBegin(); + virtual void onParseComment(const std::string& comment); + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); + virtual void onParseEnd(); + + UpsdConfiguration* _config; +}; + } /* namespace nut */ #endif /* __cplusplus */ #endif /* NUTCONF_H_SEEN */ From 4decf0831bd062f2af1799f1876a91adc6efc367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Wed, 24 Oct 2012 08:33:24 +0200 Subject: [PATCH 016/121] Add equality test operators for Settable and UpsdConfiguration::Listen. --- include/nutconf.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/nutconf.h b/include/nutconf.h index 9edb2b970b..23ab1c4369 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -66,6 +66,23 @@ class Settable Type& operator *(){return _value;} Settable& operator=(const Type& val){_value = val; _set = true;} + + bool operator==(const Settable& val)const + { + if(!set() && !val.set()) + return false; + else + return (set() && val.set() && _value==val._value); + } + + bool operator==(const Type& val)const + { + if(!set()) + return false; + else + return _value == val; + } + }; @@ -360,11 +377,18 @@ class UpsdConfiguration { std::string address; Settable port; + + inline bool operator==(const Listen& listen)const + { + return address == listen.address && port == listen.port; + } }; std::list listens; }; + + class UpsdConfigParser : public NutConfigParser { public: From e1a76f3460a86c87606287970d090717e52fbd47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Wed, 24 Oct 2012 08:34:22 +0200 Subject: [PATCH 017/121] Add test for UpsdConfiguration parsing. --- tests/nutconf.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/nutconf.cpp b/tests/nutconf.cpp index a6845d8581..95a70163d6 100644 --- a/tests/nutconf.cpp +++ b/tests/nutconf.cpp @@ -26,6 +26,7 @@ using namespace nut; #include +#include using namespace std; class NutConfTest : public CppUnit::TestFixture @@ -37,6 +38,7 @@ class NutConfTest : public CppUnit::TestFixture CPPUNIT_TEST( testGenericConfigParser ); CPPUNIT_TEST( testUpsmonConfigParser ); CPPUNIT_TEST( testNutConfConfigParser ); + CPPUNIT_TEST( testUpsdConfigParser ); CPPUNIT_TEST_SUITE_END(); public: @@ -50,6 +52,7 @@ class NutConfTest : public CppUnit::TestFixture void testGenericConfigParser(); void testUpsmonConfigParser(); void testNutConfConfigParser(); + void testUpsdConfigParser(); }; // Registers the fixture into the 'registry' @@ -242,7 +245,30 @@ void NutConfTest::testNutConfConfigParser() } +void NutConfTest::testUpsdConfigParser() +{ + static const char* src = + "MAXAGE 15\n" + "STATEPATH /var/run/nut\n" + "LISTEN 127.0.0.1 3493\n" + "MAXCONN 1024\n" + "CERTFILE /home/toto/cert.file" + ; + UpsdConfiguration conf; + conf.parseFromString(src); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find MAXAGE 15", 15u, *conf.maxAge); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find MAXCONN 1024", 1024u, *conf.maxConn); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find STATEPATH /var/run/nut", string("/var/run/nut"), *conf.statePath); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find CERTFILE /home/toto/cert.file", string("/home/toto/cert.file"), *conf.certFile); + + // Find Listen 127.0.0.1 3493 + typedef std::list ListenList; + UpsdConfiguration::Listen listen = {"127.0.0.1", 3493}; + ListenList::const_iterator it = find(conf.listens.begin(), conf.listens.end(), listen); + CPPUNIT_ASSERT_MESSAGE("LISTEN 127.0.0.1 3493", it != conf.listens.end()); +} From d9f652d745dc567bfc0d2fc0a7e8c31bcbe712ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Wed, 24 Oct 2012 10:56:10 +0200 Subject: [PATCH 018/121] Add parsing options and allow ':' to be interpreted as normal character. Add parsing option to NutParser. Add a first option OPTION_IGNORE_COLON to parse ':' as a normal character and not as token. Use it to allow parsing "::1" IPv6-like as string without having to quote them (upsd.conf). --- common/nutconf.cpp | 38 ++++++++++++------ include/nutconf.h | 99 +++++++++++++++++++++++++++------------------- tests/nutconf.cpp | 81 ++++++++++++++++++++++++++++++++++--- 3 files changed, 161 insertions(+), 57 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index f4a9ece65c..a401862ab8 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -53,22 +53,34 @@ Settable StringToSettableNumber(const std::string & src) } - - // // NutParser // -NutParser::NutParser(const char* buffer) : +NutParser::NutParser(const char* buffer, unsigned int options) : +_options(options), _buffer(buffer), _pos(0) { } -NutParser::NutParser(const std::string& buffer) : +NutParser::NutParser(const std::string& buffer, unsigned int options) : +_options(options), _buffer(buffer), _pos(0) { } +void NutParser::setOptions(unsigned int options, bool set) +{ + if(set) + { + _options |= options; + } + else + { + _options &= ~options; + } +} + char NutParser::get() { if (_pos >= _buffer.size()) return 0; @@ -216,7 +228,7 @@ NutParser::Token NutParser::parseToken() { token = Token(Token::TOKEN_BRACKET_CLOSE, c); popPos(); return token; - } else if (c == ':') { + } else if (c == ':' && !hasOptions(OPTION_IGNORE_COLON)) { token = Token(Token::TOKEN_COLON, c); popPos(); return token; @@ -286,7 +298,9 @@ NutParser::Token NutParser::parseToken() { } case LEXPARSING_STATE_STRING: { - if (c == ' ' || c == '"' || c == '#' || c == '[' || c == ']' || c == ':' || c == '=') { + if (c == ' ' || c == '"' || c == '#' || c == '[' || c == ']' || + (c == ':' && !hasOptions(OPTION_IGNORE_COLON)) || + c == '=') { if (escaped) { escaped = false; token.str += c; @@ -365,12 +379,12 @@ std::list NutParser::parseLine() { // NutConfigParser // -NutConfigParser::NutConfigParser(const char* buffer) : -NutParser(buffer) { +NutConfigParser::NutConfigParser(const char* buffer, unsigned int options) : +NutParser(buffer, options) { } -NutConfigParser::NutConfigParser(const std::string& buffer) : -NutParser(buffer) { +NutConfigParser::NutConfigParser(const std::string& buffer, unsigned int options) : +NutParser(buffer, options) { } void NutConfigParser::parseConfig() { @@ -1054,12 +1068,12 @@ void UpsdConfiguration::parseFromString(const std::string& str) // UpsdConfigParser::UpsdConfigParser(const char* buffer): -NutConfigParser(buffer) +NutConfigParser(buffer, NutParser::OPTION_IGNORE_COLON) { } UpsdConfigParser::UpsdConfigParser(const std::string& buffer): -NutConfigParser(buffer) +NutConfigParser(buffer, NutParser::OPTION_IGNORE_COLON) { } diff --git a/include/nutconf.h b/include/nutconf.h index 23ab1c4369..76c3d2b2b3 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -92,44 +92,61 @@ class Settable class NutParser { public: - NutParser(const char* buffer = NULL); - NutParser(const std::string& buffer); - - struct Token - { - enum TokenType { - TOKEN_UNKNOWN = -1, - TOKEN_NONE = 0, - TOKEN_STRING = 1, - TOKEN_QUOTED_STRING, - TOKEN_COMMENT, - TOKEN_BRACKET_OPEN, - TOKEN_BRACKET_CLOSE, - TOKEN_EQUAL, - TOKEN_COLON, - TOKEN_EOL - }type; - std::string str; - - Token():type(TOKEN_NONE),str(){} - Token(TokenType type, const std::string& str=""):type(type),str(str){} - Token(TokenType type, char c):type(type),str(1, c){} - Token(const Token& tok):type(tok.type),str(tok.str){} - - bool is(TokenType type)const{return this->type==type;} - - bool operator==(const Token& tok)const{return tok.type==type && tok.str==str;} - - operator bool()const{return type!=TOKEN_UNKNOWN && type!=TOKEN_NONE;} - }; - - /** Parsing functions - * \{ */ - std::string parseCHARS(); - std::string parseSTRCHARS(); - Token parseToken(); - std::list parseLine(); - /** \} */ + enum ParsingOption + { + OPTION_DEFAULT = 0, + /** Colon character is considered as string character and not as specific token. + Usefull for IPv6 addresses */ + OPTION_IGNORE_COLON = 1 + }; + + NutParser(const char* buffer = NULL, unsigned int options = OPTION_DEFAULT); + NutParser(const std::string& buffer, unsigned int options = OPTION_DEFAULT); + + /** Parsing configuration functions + * \{ */ + void setOptions(unsigned int options){_options = options;} + unsigned int getOptions()const{return _options;} + void setOptions(unsigned int options, bool set = true); + void unsetOptions(unsigned int options){setOptions(options, false);} + bool hasOptions(unsigned int options)const{return (_options&options) == options;} + /** \} */ + + struct Token + { + enum TokenType { + TOKEN_UNKNOWN = -1, + TOKEN_NONE = 0, + TOKEN_STRING = 1, + TOKEN_QUOTED_STRING, + TOKEN_COMMENT, + TOKEN_BRACKET_OPEN, + TOKEN_BRACKET_CLOSE, + TOKEN_EQUAL, + TOKEN_COLON, + TOKEN_EOL + }type; + std::string str; + + Token():type(TOKEN_NONE),str(){} + Token(TokenType type, const std::string& str=""):type(type),str(str){} + Token(TokenType type, char c):type(type),str(1, c){} + Token(const Token& tok):type(tok.type),str(tok.str){} + + bool is(TokenType type)const{return this->type==type;} + + bool operator==(const Token& tok)const{return tok.type==type && tok.str==str;} + + operator bool()const{return type!=TOKEN_UNKNOWN && type!=TOKEN_NONE;} + }; + + /** Parsing functions + * \{ */ + std::string parseCHARS(); + std::string parseSTRCHARS(); + Token parseToken(); + std::list parseLine(); + /** \} */ #ifndef UNITEST_MODE protected: @@ -148,6 +165,8 @@ class NutParser char peek(); private: + unsigned int _options; + std::string _buffer; size_t _pos; std::vector _stack; @@ -162,8 +181,8 @@ class NutConfigParser : public NutParser virtual void parseConfig(); protected: - NutConfigParser(const char* buffer = NULL); - NutConfigParser(const std::string& buffer); + NutConfigParser(const char* buffer = NULL, unsigned int options = OPTION_DEFAULT); + NutConfigParser(const std::string& buffer, unsigned int options = OPTION_DEFAULT); virtual void onParseBegin()=0; virtual void onParseComment(const std::string& comment)=0; diff --git a/tests/nutconf.cpp b/tests/nutconf.cpp index 95a70163d6..3af0cccfa3 100644 --- a/tests/nutconf.cpp +++ b/tests/nutconf.cpp @@ -32,9 +32,11 @@ using namespace std; class NutConfTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( NutConfTest ); + CPPUNIT_TEST( testOptions ); CPPUNIT_TEST( testParseCHARS ); CPPUNIT_TEST( testParseSTRCHARS ); CPPUNIT_TEST( testPasreToken ); + CPPUNIT_TEST( testPasreTokenWithoutColon ); CPPUNIT_TEST( testGenericConfigParser ); CPPUNIT_TEST( testUpsmonConfigParser ); CPPUNIT_TEST( testNutConfConfigParser ); @@ -45,9 +47,11 @@ class NutConfTest : public CppUnit::TestFixture void setUp(); void tearDown(); + void testOptions(); void testParseCHARS(); void testParseSTRCHARS(); void testPasreToken(); + void testPasreTokenWithoutColon(); void testGenericConfigParser(); void testUpsmonConfigParser(); @@ -68,6 +72,21 @@ void NutConfTest::tearDown() { } +void NutConfTest::testOptions() +{ + { + NutParser parse("Bonjour monde!", NutParser::OPTION_DEFAULT); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Has parsing options", 0u, parse.getOptions()); + CPPUNIT_ASSERT_MESSAGE("Has OPTION_IGNORE_COLON parsing option", !parse.hasOptions(NutParser::OPTION_IGNORE_COLON)); + } + + { + NutParser parse("Bonjour monde!", NutParser::OPTION_IGNORE_COLON); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Has bad parsing options", (unsigned int)NutParser::OPTION_IGNORE_COLON, parse.getOptions()); + CPPUNIT_ASSERT_MESSAGE("Has not OPTION_IGNORE_COLON parsing option", parse.hasOptions(NutParser::OPTION_IGNORE_COLON)); + } + +} void NutConfTest::testParseCHARS() { @@ -123,7 +142,8 @@ void NutConfTest::testPasreToken() "[ceci]# Plouf\n" "\n" "titi = \"tata toto\"\n" - "NOTIFYFLAG LOWBATT SYSLOG+WALL" + "NOTIFYFLAG LOWBATT SYSLOG+WALL\n" + "::1" ; NutParser parse(src); @@ -145,6 +165,45 @@ void NutConfTest::testPasreToken() CPPUNIT_ASSERT_MESSAGE("Cannot find 13th token 'NOTIFYFLAG'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "NOTIFYFLAG")); CPPUNIT_ASSERT_MESSAGE("Cannot find 14th token 'LOWBATT'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "LOWBATT")); CPPUNIT_ASSERT_MESSAGE("Cannot find 15th token 'SYSLOG+WALL'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "SYSLOG+WALL")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 16th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 17th token ':'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_COLON, ":")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 18th token ':'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_COLON, ":")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 19th token '1'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "1")); + +} + +void NutConfTest::testPasreTokenWithoutColon() +{ + static const char* src = + "Bonjour monde\n" + "[ceci]# Plouf\n" + "\n" + "titi = \"tata toto\"\n" + "NOTIFYFLAG LOWBATT SYSLOG+WALL\n" + "::1" + ; + NutParser parse(src, NutParser::OPTION_IGNORE_COLON); + +// NutConfigParser::Token tok = parse.parseToken(); +// std::cout << "token = " << tok.type << " - " << tok.str << std::endl; + + CPPUNIT_ASSERT_MESSAGE("Cannot find 1st token 'Bonjour'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "Bonjour")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 2nd token 'monde'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "monde")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 3th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 4rd token '['", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_BRACKET_OPEN, "[")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 5th token 'ceci'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "ceci")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 6th token ']'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_BRACKET_CLOSE, "]")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 7th token ' Plouf'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_COMMENT, " Plouf")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 8th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 9th token 'titi'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "titi")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 10th token '='", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EQUAL, "=")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 11th token 'tata toto'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_QUOTED_STRING, "tata toto")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 12th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 13th token 'NOTIFYFLAG'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "NOTIFYFLAG")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 14th token 'LOWBATT'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "LOWBATT")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 15th token 'SYSLOG+WALL'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "SYSLOG+WALL")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 16th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); + CPPUNIT_ASSERT_MESSAGE("Cannot find 17th token '::1'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "::1")); } @@ -251,6 +310,7 @@ void NutConfTest::testUpsdConfigParser() "MAXAGE 15\n" "STATEPATH /var/run/nut\n" "LISTEN 127.0.0.1 3493\n" + "LISTEN ::1 3493\n" "MAXCONN 1024\n" "CERTFILE /home/toto/cert.file" ; @@ -264,10 +324,21 @@ void NutConfTest::testUpsdConfigParser() CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find CERTFILE /home/toto/cert.file", string("/home/toto/cert.file"), *conf.certFile); // Find Listen 127.0.0.1 3493 - typedef std::list ListenList; - UpsdConfiguration::Listen listen = {"127.0.0.1", 3493}; - ListenList::const_iterator it = find(conf.listens.begin(), conf.listens.end(), listen); - CPPUNIT_ASSERT_MESSAGE("LISTEN 127.0.0.1 3493", it != conf.listens.end()); + { + typedef std::list ListenList; + UpsdConfiguration::Listen listen = {"127.0.0.1", 3493}; + ListenList::const_iterator it = find(conf.listens.begin(), conf.listens.end(), listen); + CPPUNIT_ASSERT_MESSAGE("LISTEN 127.0.0.1 3493", it != conf.listens.end()); + } + + // Find Listen ::1 3493 + { + typedef std::list ListenList; + UpsdConfiguration::Listen listen = {"::1", 3493}; + ListenList::const_iterator it = find(conf.listens.begin(), conf.listens.end(), listen); + CPPUNIT_ASSERT_MESSAGE("LISTEN ::1 3493", it != conf.listens.end()); + } + } From 3c15b9a87fc271af0f11bc8e419407af9e37cac8 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Fri, 16 Nov 2012 14:35:38 +0100 Subject: [PATCH 019/121] Initial implementation of nut::NutStream sub-tree nut::NutMemory (memory-based stream) nut::NutFile (file-stream) nut::NutSocket with nut::NutSocket::Address (UNIX domain, IPv4, IPv6) --- common/nutstream.cpp | 628 +++++++++++++++++++++++++++++++++ include/nutstream.h | 807 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1435 insertions(+) create mode 100644 common/nutstream.cpp create mode 100644 include/nutstream.h diff --git a/common/nutstream.cpp b/common/nutstream.cpp new file mode 100644 index 0000000000..47d632b2a4 --- /dev/null +++ b/common/nutstream.cpp @@ -0,0 +1,628 @@ +/* nutdata.cpp - NUT stream + + Copyright (C) + 2012 Vaclav Krpec + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "nutstream.h" + +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +#include +} + + +namespace nut { + +NutStream::status_t NutMemory::getChar(char & ch) { + if (m_pos == m_impl.size()) + return NUTS_EOF; + + if (m_pos > m_impl.size()) + return NUTS_ERROR; + + ch = m_impl.at(m_pos); + + return NUTS_OK; +} + + +void NutMemory::readChar() { + if (m_pos < m_impl.size()) + ++m_pos; +} + + +NutStream::status_t NutMemory::putChar(char ch) { + m_impl += ch; + + return NUTS_OK; +} + + +NutStream::status_t NutMemory::putString(const std::string & str) { + m_impl += str; + + return NUTS_OK; +} + + +NutStream::status_t NutMemory::putData(const std::string & data) { + return putString(data); +} + + +bool NutFile::open(access_t mode, int & err_code, std::string & err_msg) throw() { + static const char *read_only = "r"; + static const char *write_only = "w"; + static const char *read_write = "r+"; + static const char *read_write_clear = "w+"; + static const char *append_only = "a"; + static const char *read_append = "a+"; + + const char *mode_str = NULL; + + switch (mode) { + case READ_ONLY: + mode_str = read_only; + break; + case WRITE_ONLY: + mode_str = write_only; + break; + case READ_WRITE: + mode_str = read_write; + break; + case READ_WRITE_CLEAR: + mode_str = read_write_clear; + break; + case READ_APPEND: + mode_str = read_append; + break; + case APPEND_ONLY: + mode_str = append_only; + break; + } + + assert(NULL != mode_str); + + m_impl = ::fopen(m_name.c_str(), mode_str); + + if (NULL != m_impl) + return true; + + err_code = errno; + err_msg = std::string(::strerror(err_code)); + + return false; +} + + +bool NutFile::close(int & err_code, std::string & err_msg) throw() { + err_code = fclose(m_impl); + + if (0 != err_code) { + err_msg = std::string(::strerror(err_code)); + + return false; + } + + m_impl = NULL; + + return true; +} + + +NutFile::NutFile(const std::string & name, access_t mode): + m_name(name), + m_impl(NULL), + m_current_ch('\0'), + m_current_ch_valid(false) +{ + openx(mode); +} + + +NutStream::status_t NutFile::getChar(char & ch) throw() { + int c; + + if (m_current_ch_valid) { + ch = m_current_ch; + + return NUTS_OK; + } + + if (NULL == m_impl) + return NUTS_ERROR; + + errno = 0; + + c = ::fgetc(m_impl); + + if (EOF == c) { + int erno = errno; + + if (0 == erno) + return NUTS_EOF; + + return NUTS_ERROR; + } + + ch = static_cast(c); + + // Cache the character for future reference + m_current_ch = ch; + m_current_ch_valid = true; + + return NUTS_OK; +} + + +void NutFile::readChar() throw() { + m_current_ch_valid = false; +} + + +NutStream::status_t NutFile::putChar(char ch) throw() { + int c; + + if (NULL == m_impl) + return NUTS_ERROR; + + c = ::fputc(static_cast(ch), m_impl); + + return EOF == c ? NUTS_ERROR : NUTS_OK; +} + + +NutStream::status_t NutFile::putString(const std::string & str) throw() { + int c; + + if (NULL == m_impl) + return NUTS_ERROR; + + c = ::fputs(str.c_str(), m_impl); + + return EOF == c ? NUTS_ERROR : NUTS_OK; +} + + +NutStream::status_t NutFile::putData(const std::string & data) throw() { + // Unfortunately, C FILE interface doesn't have non C-string + // put function (i.e. function for raw data output with size specifier + for (size_t i = 0; i < data.size(); ++i) { + status_t st = putChar(data.at(i)); + + if (NUTS_ERROR == st) + return NUTS_ERROR; + } + + return NUTS_OK; +} + + +NutFile::~NutFile() { + if (NULL != m_impl) + closex(); +} + + +void NutSocket::Address::init_unix(Address & addr, const std::string & path) { + struct sockaddr_un * un_addr = new struct sockaddr_un; + + un_addr->sun_family = AF_UNIX; + + assert(sizeof(un_addr->sun_path) / sizeof(char) > path.size()); + + for (size_t i = 0; i < path.size(); ++i) + un_addr->sun_path[i] = path.at(i); + + un_addr->sun_path[path.size()] = '\0'; + + addr.m_sock_addr = reinterpret_cast(un_addr); + addr.m_length = sizeof(*un_addr); +} + + +void NutSocket::Address::init_ipv4(Address & addr, const std::vector & qb, uint16_t port) { + assert(4 == qb.size()); + + uint32_t packed_qb = 0; + + struct sockaddr_in * in4_addr = new struct sockaddr_in; + + packed_qb = static_cast(qb.at(0)); + packed_qb |= static_cast(qb.at(1)) << 8; + packed_qb |= static_cast(qb.at(2)) << 16; + packed_qb |= static_cast(qb.at(3)) << 24; + + in4_addr->sin_family = AF_INET; + in4_addr->sin_port = static_cast(port); + in4_addr->sin_addr.s_addr = packed_qb; + + addr.m_sock_addr = reinterpret_cast(in4_addr); + addr.m_length = sizeof(*in4_addr); +} + + +void NutSocket::Address::init_ipv6(Address & addr, const std::vector & hb, uint16_t port) { + assert(16 == hb.size()); + + struct sockaddr_in6 * in6_addr = new struct sockaddr_in6; + + in6_addr->sin6_family = AF_INET6; + in6_addr->sin6_port = static_cast(port); + in6_addr->sin6_flowinfo = 0; // TODO: check that + in6_addr->sin6_scope_id = 0; // TODO: check that + + for (size_t i = 0; i < 16; ++i) + in6_addr->sin6_addr.s6_addr[i] = hb.at(i); + + addr.m_sock_addr = reinterpret_cast(in6_addr); + addr.m_length = sizeof(*in6_addr); +} + + +NutSocket::Address::Address( + unsigned char msb, + unsigned char msb2, + unsigned char lsb2, + unsigned char lsb, + uint16_t port) +{ + std::vector qb; + + qb.reserve(4); + qb.push_back(msb); + qb.push_back(msb2); + qb.push_back(lsb2); + qb.push_back(lsb); + + init_ipv4(*this, qb, port); +} + + +NutSocket::Address::Address(const std::vector & bytes, uint16_t port) throw(std::logic_error) { + switch (bytes.size()) { + case 4: + init_ipv4(*this, bytes, port); + break; + + case 16: + init_ipv6(*this, bytes, port); + break; + + default: { + std::stringstream e("Unsupported IP address size: "); + e << bytes.size(); + + throw std::logic_error(e.str()); + } + } +} + + +/** + * \brief Format IPv4 address + * + * \param packed 4 bytes in network byte order + * + * \return IPv4 address string + */ +static std::string formatIPv4addr(uint32_t packed) { + std::stringstream ss; + + ss << (packed && 0x000000ff) << "."; + ss << (packed >> 8 && 0x000000ff) << "."; + ss << (packed >> 16 && 0x000000ff) << "."; + ss << (packed >> 24 && 0x000000ff); + + return ss.str(); +} + + +/** + * \brief Format IPv6 address + * + * \param bytes 16 bytes in network byte order + * + * \return IPv6 address string + */ +static std::string formatIPv6addr(unsigned char const bytes[16]) { + // Check for special form addresses + bool zero_at_0_9 = true; + bool zero_at_0_14 = false; + + for (size_t i = 0; zero_at_0_9 && i < 10; ++i) + zero_at_0_9 = 0 == bytes[i]; + + if (zero_at_0_9) { + zero_at_0_14 = true; + + for (size_t i = 10; zero_at_0_14 && i < 15; ++i) + zero_at_0_14 = 0 == bytes[i]; + } + + // Loopback + if (zero_at_0_14 && 1 == bytes[15]) + return "::1"; + + std::stringstream ss; + + // IPv4 mapped on IPv6 address + if (zero_at_0_9 && 0xff == bytes[10] && 0xff == bytes[11]) { + ss << "::FFFF:"; + ss << bytes[12] << '.' << bytes[13] << '.'; + ss << bytes[14] << '.' << bytes[15]; + + return ss.str(); + } + + // Standard form + // TODO: ommition of lengthy zero word strings + ss << std::uppercase << std::hex << std::setfill('0'); + + for (size_t i = 0; ; ) { + uint16_t w = ((uint16_t)(bytes[2 * i]) << 8) || bytes[2 * i + 1]; + + ss << std::setw(4) << w; + + if (8 == ++i) + break; + + ss << ':'; + } + + return ss.str(); +} + + +std::string NutSocket::Address::str() const { + assert(NULL != m_sock_addr); + + sa_family_t family = m_sock_addr->sa_family; + + std::stringstream ss("nut::NutSocket::Address(family: "); + ss << family; + + switch (family) { + case AF_UNIX: { + struct sockaddr_un * addr = reinterpret_cast(m_sock_addr); + + ss << " (UNIX domain socket), file: " << addr->sun_path; + + break; + } + + case AF_INET: { + struct sockaddr_in * addr = reinterpret_cast(m_sock_addr); + + ss << " (IPv4 address), " << formatIPv4addr(addr->sin_addr.s_addr) << ":" << addr->sin_port; + + break; + } + + case AF_INET6: { + struct sockaddr_in6 * addr = reinterpret_cast(m_sock_addr); + + ss << " (IPv6 address), " << formatIPv6addr(addr->sin6_addr.s6_addr) << ":" << addr->sin6_port; + + break; + } + + default: { + std::stringstream e("NOT IMPLEMENTED: "); + e << "Socket address family " << family << " unsupported"; + + throw std::logic_error(e.str()); + } + } + + ss << ")"; + + return ss.str(); +} + + +NutSocket::Address::~Address() { + delete m_sock_addr; +} + + +bool NutSocket::accept( + NutSocket & sock, + const NutSocket & listen_sock, + int & err_code, + std::string & err_msg) throw(std::logic_error) +{ + assert(-1 == sock.m_impl); + + struct sockaddr sock_addr; + socklen_t sock_addr_size = sizeof(sock_addr); + + sock.m_impl = ::accept(listen_sock.m_impl, &sock_addr, &sock_addr_size); + + if (-1 != sock.m_impl) + return true; + + err_code = errno; + err_msg = std::string(::strerror(err_code)); + + // The following reasons of unsuccessful termination are non-exceptional + switch (err_code) { + case EAGAIN: // Non-blocking listen socket, no conn. pending + case ECONNABORTED: // Connection has been aborted + case EINTR: // Interrupted by a signal + case EMFILE: // Open file descriptors per-process limit was reached + case ENFILE: // Open file descriptors per-system limit was reached + case EPROTO: // Protocol error + return false; + } + + std::stringstream e("Failed to accept connection: "); + e << err_code << ": " << err_msg; + + throw std::logic_error(e.str()); +} + + +NutSocket::NutSocket(domain_t dom, type_t type, proto_t proto): + m_impl(-1), + m_current_ch('\0'), + m_current_ch_valid(false) +{ + int cdom = static_cast(dom); + int ctype = static_cast(type); + int cproto = static_cast(proto); + + m_impl = ::socket(cdom, ctype, cproto); + + if (-1 == m_impl) { + int erno = errno; + + std::stringstream e("Failed to create socket domain: "); + e << cdom << ", type: " << ctype << ", proto: " << cproto; + e << ": " << erno << ": " << ::strerror(erno); + + throw std::runtime_error(e.str()); + } +} + + +bool NutSocket::bind(const Address & addr, int & err_code, std::string & err_msg) throw() { + err_code = ::bind(m_impl, addr.m_sock_addr, addr.m_length); + + if (0 == err_code) + return true; + + err_code = errno; + err_msg = std::string(::strerror(err_code)); + + return false; +} + + +bool NutSocket::listen(int backlog, int & err_code, std::string & err_msg) throw() { + err_code = ::listen(m_impl, backlog); + + if (0 == err_code) + return true; + + err_code = errno; + err_msg = std::string(::strerror(err_code)); + + return false; +} + + +bool NutSocket::connect(const Address & addr, int & err_code, std::string & err_msg) throw() { + err_code = ::connect(m_impl, addr.m_sock_addr, addr.m_length); + + if (0 == err_code) + return true; + + err_code = errno; + err_msg = std::string(::strerror(err_code)); + + return false; +} + + +NutStream::status_t NutSocket::getChar(char & ch) throw() { + if (m_current_ch_valid) { + ch = m_current_ch; + + return NUTS_OK; + } + + // TBD: Perhaps we should buffer more bytes at once + // However, buffering is already done in kernel space, + // so unless we need greater reading efficiency, char-by-char + // reading should be sufficient + + ssize_t read_cnt = ::read(m_impl, &ch, 1); + + if (1 == read_cnt) { + m_current_ch = ch; + m_current_ch_valid = true; + + return NUTS_OK; + } + + if (0 == read_cnt) + return NUTS_EOF; + + assert(-1 == read_cnt); + + // TODO: At least logging of the error (errno), if not propagation + + return NUTS_ERROR; +} + + +void NutSocket::readChar() throw() { + m_current_ch_valid = false; +} + + +NutStream::status_t NutSocket::putChar(char ch) throw() { + ssize_t write_cnt = ::write(m_impl, &ch, 1); + + if (1 == write_cnt) + return NUTS_OK; + + assert(-1 == write_cnt); + + // TODO: At least logging of the error (errno), if not propagation + + return NUTS_ERROR; +} + + +NutStream::status_t NutSocket::putString(const std::string & str) throw() { + ssize_t str_len = str.size(); + + // Avoid the costly system call unless necessary + if (0 == str_len) + return NUTS_OK; + + ssize_t write_cnt = ::write(m_impl, str.data(), str_len); + + if (write_cnt == str_len) + return NUTS_OK; + + // TODO: Under certain circumstances, less than the whole + // string might be written + // Review the code if async. I/O is supported (in which case + // the function shall have to implement the blocking using + // select/ poll/ epoll on its own (probably select for portability) + + assert(-1 == write_cnt); + + // TODO: At least logging of the error (errno), if not propagation + + return NUTS_ERROR; +} + +} // end of namespace nut diff --git a/include/nutstream.h b/include/nutstream.h new file mode 100644 index 0000000000..6681817a2d --- /dev/null +++ b/include/nutstream.h @@ -0,0 +1,807 @@ +/* nutdata.h - NUT stream + + Copyright (C) + 2012 Vaclav Krpec + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef nut_nutstream_h +#define nut_nutstream_h + +#ifdef __cplusplus + +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +} + + +namespace nut +{ + +/** + * \brief Data stream interface + * + * The intarface provides character-based streamed I/O. + */ +class NutStream { + public: + + /** Data store status */ + typedef enum { + NUTS_OK = 0, /** Operation successful */ + NUTS_EOF, /** End of stream reached */ + NUTS_ERROR, /** Error ocurred */ + } status_t; + + protected: + + /** Formal constructor */ + NutStream() {} + + public: + + /** + * \brief Get one character from current position + * + * The method provides character from current position + * in the data store. + * The position is not shifted (see \ref readChar for + * current character consumption). + * + * The operation is synchronous (the call blocks if necessary). + * + * \param[out] ch Character + * + * \retval NUTS_OK on success, + * \retval NUTS_EOF on end of stream, + * \retval NUTS_ERROR on read error + */ + virtual status_t getChar(char & ch) = 0; + + /** + * \brief Consume current character + * + * The method shifts position in the stream. + * It shall never block (if the position gets + * past-the-end of currently available data, + * subsequent call to \ref getChar will block). + */ + virtual void readChar() = 0; + + /** + * \brief Put one character to the stream end + * + * \param[in] ch Character + * + * \retval NUTS_OK on success, + * \retval NUTS_ERROR on write error + */ + virtual status_t putChar(char ch) = 0; + + /** + * \brief Put string to the stream end + * + * \param[in] str String + * + * \retval NUTS_OK on success, + * \retval NUTS_ERROR on write error + */ + virtual status_t putString(const std::string & str) = 0; + + /** + * \brief Put data to the stream end + * + * The difference between \ref putString and this method + * is that it is able to serialise also data containing + * null characters. + * + * \param[in] data Data + * + * \retval NUTS_OK on success, + * \retval NUTS_ERROR on write error + */ + virtual status_t putData(const std::string & data) = 0; + + virtual ~NutStream() {} // private destructor for an iface + +}; // end of class NutStream + + +/** Memory stream */ +class NutMemory: public NutStream { + private: + + /** Implementation */ + std::string m_impl; + + /** Position in implementation */ + size_t m_pos; + + public: + + /** Constructor */ + NutMemory(): m_pos(0) {} + + /** + * \brief Constructor + * + * \param str Init value + */ + NutMemory(const std::string & str): m_impl(str), m_pos(0) {} + + // NutStream interface implementation + status_t getChar(char & ch); + void readChar(); + status_t putChar(char ch); + status_t putString(const std::string & str); + status_t putData(const std::string & data); + +}; // end of class NutMemory + + +/** File stream */ +class NutFile: public NutStream { + public: + + /** Access mode */ + typedef enum { + /** Read-only, initial pos. is at the beginning */ + READ_ONLY = 0, + + /** Write-only, with creation, clears the file if exists */ + WRITE_ONLY, + + /** Read-write, initial pos. is at the beginning */ + READ_WRITE, + + /** As previous, but with creation, clears the file if exists */ + READ_WRITE_CLEAR, + + /** Read & write to end, with creation, init. pos: beginning/end for r/w */ + READ_APPEND, + + /** Write only, with creation, initial position is at the end */ + APPEND_ONLY, + } access_t; + + private: + + /** File name */ + const std::string m_name; + + /** Implementation */ + FILE *m_impl; + + /** Current character cache */ + char m_current_ch; + + /** Current character cache status */ + bool m_current_ch_valid; + + public: + + /** Constructor + * + * \param[in] name File name + */ + NutFile(const std::string & name): + m_name(name), + m_impl(NULL), + m_current_ch('\0'), + m_current_ch_valid(false) {} + + /** + * \brief Open file + * + * \param[in] mode File open mode + * \param[out] err_code Error code + * \param[out] err-msg Error message + * + * \retval true if open succeeded + * \retval false if open failed + */ + bool open(access_t mode, int & err_code, std::string & err_msg) throw(); + + /** + * \brief Open file + * + * \param[in] mode File open mode (read-only by default) + * + * \retval true if open succeeded + * \retval false if open failed + */ + inline bool open(access_t mode = READ_ONLY) { + int ec; + std::string em; + + return open(mode, ec, em); + } + + /** + * \brief Open file (or throw exception) + * + * \param[in] mode File open mode (read-only by default) + * + * \retval true if open succeeded + * \retval false if open failed + */ + inline void openx(access_t mode = READ_ONLY) throw(std::runtime_error) { + int ec; + std::string em; + + if (open(mode, ec, em)) + return; + + std::stringstream e("Failed to open file "); + e << m_name << ": " << ec << ": " << em; + + throw std::runtime_error(e.str()); + } + + /** + * \brief Close file + * + * \param[out] err_code Error code + * \param[out] err-msg Error message + * + * \retval true if close succeeded + * \retval false if close failed + */ + bool close(int & err_code, std::string & err_msg) throw(); + + /** + * \brief Close file + * + * \retval true if close succeeded + * \retval false if close failed + */ + inline bool close() throw() { + int ec; + std::string em; + + return close(ec, em); + } + + /** Close file (or throw exception) */ + inline void closex() throw(std::runtime_error) { + int ec; + std::string em; + + if (close(ec, em)) + return; + + std::stringstream e("Failed to close file "); + e << m_name << ": " << ec << ": " << em; + + throw std::runtime_error(e.str()); + } + + /** + * \brief Constructor (with open) + * + * Opens the file, throws exception on open error. + * + * \param[in] name File name + * \param[in] mode File open mode + */ + NutFile(const std::string & name, access_t mode); + + // NutStream interface implementation + status_t getChar(char & ch) throw(); + void readChar() throw(); + status_t putChar(char ch) throw(); + status_t putString(const std::string & str) throw(); + status_t putData(const std::string & data) throw(); + + /** Destructor (closes the file) */ + ~NutFile(); + + private: + + /** + * \brief Copy constructor + * + * TODO: Copying is forbidden (for now). + * If required, it may be enabled, using fdup. + * + * \param orig Original file + */ + NutFile(const NutFile & orig) { + throw std::logic_error("NOT IMPLEMENTED"); + } + + /** + * \brief Assignment + * + * TODO: Assignment is forbidden (for now). + * See copy constructor for implementation notes + * (and don't forget to destroy left value, properly). + * + * \param rval Right value + */ + NutFile & operator = (const NutFile & rval) { + throw std::logic_error("NOT IMPLEMENTED"); + } + +}; // end of class NutFile + + +/** Socket stream */ +class NutSocket: public NutStream { + public: + + /** Socket domain */ + typedef enum { + NUTSOCKD_UNIX = AF_UNIX, /** Unix */ + NUTSOCKD_INET4 = AF_INET, /** IPv4 */ + NUTSOCKD_INETv6 = AF_INET6, /** IPv6 */ + } domain_t; + + /** Socket type */ + typedef enum { + NUTSOCKT_STREAM = SOCK_STREAM, /** Stream */ + NUTSOCKT_DGRAM = SOCK_DGRAM, /** Datagram */ + } type_t; + + /** Socket protocol */ + typedef enum { + NUTSOCKP_IMPLICIT = 0, /** Implicit protocol for chosen type */ + } proto_t; + + /** Socket address */ + class Address { + friend class NutSocket; + + private: + + /** Implementation */ + struct sockaddr *m_sock_addr; + + /** Length */ + socklen_t m_length; + + /** + * \brief Invalid address constructor + * + * Invalid address may be produced e.g. by failed DNS resolving. + */ + Address(): m_sock_addr(NULL), m_length(0) {} + + /** + * \brief Initialise UNIX socket address + * + * \param addr UNIX socket address + * \param path Pathname + */ + static void init_unix(Address & addr, const std::string & path); + + /** + * \brief Initialise IPv4 address + * + * \param addr IPv4 address + * \param qb Byte quadruplet (MSB is at index 0) + * \param port Port number + */ + static void init_ipv4(Address & addr, const std::vector & qb, uint16_t port); + + /** + * \brief Initialise IPv6 address + * + * \param addr IPv6 address + * \param hb 16 bytes of the address (MSB is at index 0) + * \param port Port number + */ + static void init_ipv6(Address & addr, const std::vector & hb, uint16_t port); + + public: + + /** + * \brief Check address validity + * + * \retval true if the address is valid + * \retval false otherwise + */ + inline bool valid() throw() { + return NULL != m_sock_addr; + } + + /** + * \brief UNIX socket address constructor + * + * \param path Pathname + */ + Address(const std::string & path) { + init_unix(*this, path); + } + + /** + * \brief IPv4 address constructor + * + * \param msb Most significant byte + * \param msb2 2nd most significant byte + * \param lsb2 2nd least significant byte + * \param lsb Least significant byte + * \param port Port number + */ + Address(unsigned char msb, + unsigned char msb2, + unsigned char lsb2, + unsigned char lsb, + uint16_t port); + + /** + * \brief IP address constructor + * + * Creates either IPv4 or IPv6 address (depending on + * how many bytes are provided bia the \c bytes argument). + * Throws an exception if the bytecount is invalid. + * + * \param bytes 4 or 16 address bytes (MSB is at index 0) + * \param port Port number + */ + Address(const std::vector & bytes, uint16_t port) throw(std::logic_error); + + /** + * \brief Stringifisation + * + * \return String representation of the address + */ + std::string str() const; + + /** Stringifisation */ + inline operator std::string() const { + return str(); + } + + /** Destructor */ + ~Address(); + + }; // end of class Address + + /** Flag for socket constructor of accepted connection */ + typedef enum { + ACCEPT /** Accept flag */ + } accept_flag_t; + + private: + + /** Socket implementation */ + int m_impl; + + /** Current character cache */ + char m_current_ch; + + /** Current character cache status */ + bool m_current_ch_valid; + + /** + * \brief Constructor for an uninitialised socket + * + * Uninitialised socket is used with client connection + * socket constructor if the listen socket is closed. + */ + NutSocket(): + m_impl(-1), + m_current_ch('\0'), + m_current_ch_valid(false) + {} + + /** + * \brief Accept client connection on a listen socket + * + * \param[out] sock Socket + * \param[in] listen_sock Listen socket + * \param[out] err_code Error code + * \param[out] err_msg Error message + * + * \retval true on success + * \retval false otherwise + */ + static bool accept( + NutSocket & sock, + const NutSocket & listen_sock, + int & err_code, + std::string & err_msg) throw(std::logic_error); + + /** + * \brief Accept client connection on a listen socket + * + * \param[out] sock Socket + * \param[in] listen_sock Listen socket + * + * \retval true on success + * \retval false otherwise + */ + inline static bool accept( + NutSocket & sock, + const NutSocket & listen_sock) throw(std::logic_error) + { + int ec; + std::string em; + + return accept(sock, listen_sock, ec, em); + } + + /** + * \brief Accept client connection (or throw exception) + * + * \param[out] sock Socket + * \param[in] listen_sock Listen socket + */ + inline static void acceptx( + NutSocket & sock, + const NutSocket & listen_sock) throw(std::logic_error, std::runtime_error) + { + int ec; + std::string em; + + if (accept(sock, listen_sock, ec, em)) + return; + + std::stringstream e("Failed to accept connection: "); + e << ec << ": " << em; + + throw std::runtime_error(e.str()); + } + + public: + + /** + * \brief Socket valid check + * + * \retval true if the socket is initialised + * \retval false otherwise + */ + inline bool valid() throw() { + return -1 != m_impl; + } + + /** + * \brief Constructor + * + * \param dom Socket domain + * \param type Socket type + * \param proto Socket protocol + */ + NutSocket( + domain_t dom = NUTSOCKD_INET4, + type_t type = NUTSOCKT_STREAM, + proto_t proto = NUTSOCKP_IMPLICIT); + + /** + * \brief Accepted client socket constructor + * + * Accepts connection on a listen socket. + * If the argument isn't a listen socket, exception is thrown. + * The call will block until either there's an incoming connection + * or the listening socket is closed or there's an error. + * + * \param listen_sock Listening socket + */ + NutSocket(accept_flag_t, const NutSocket & listen_sock, int & err_code, std::string & err_msg): + m_impl(-1), + m_current_ch('\0'), + m_current_ch_valid(false) + { + accept(*this, listen_sock, err_code, err_msg); + } + + /** + * \brief Accepted client socket constructor + * + * Accepts connection on a listen socket. + * + * \param listen_sock Listening socket + */ + NutSocket(accept_flag_t, const NutSocket & listen_sock): + m_impl(-1), + m_current_ch('\0'), + m_current_ch_valid(false) + { + accept(*this, listen_sock); + } + + /** + * \brief Bind socket to an address + * + * \param[in] addr Socket address + * \param[out] err_code Error code + * \param[out] err_msg Error message + * + * \retval true on success + * \retval false on error + */ + bool bind(const Address & addr, int & err_code, std::string & err_msg) throw(); + + /** + * \brief Bind socket to an address + * + * \param addr Socket address + * + * \retval true on success + * \retval false on error + */ + inline bool bind(const Address & addr) throw() { + int ec; + std::string em; + + return bind(addr, ec, em); + } + + /** + * \brief Bind socket to an address (or throw exception) + * + * \param addr Socket address + */ + inline void bindx(const Address & addr) throw(std::runtime_error) { + int ec; + std::string em; + + if (bind(addr, ec, em)) + return; + + std::stringstream e("Failed to bind socket to address "); + e << addr.str() << ": " << ec << ": " << em; + + throw std::runtime_error(e.str()); + } + + /** + * \brief Listen on a socket + * + * The function sets TCP listen socket. + * + * \param[in] backlog Limit of pending connections + * \param[out] err_code Error code + * \param[out] err_msg Error message + * + * \retval true on success + * \retval false on error + */ + bool listen(int backlog, int & err_code, std::string & err_msg) throw(); + + /** + * \brief Listen on socket + * + * \param[in] backlog Limit of pending connections + * + * \retval true on success + * \retval false on error + */ + inline bool listen(int backlog) throw() { + int ec; + std::string em; + + return listen(backlog, ec, em); + } + + /** + * \brief Listen on socket (or throw an exception) + * + * \param[in] backlog Limit of pending connections + */ + inline void listenx(int backlog) throw(std::runtime_error) { + int ec; + std::string em; + + if (listen(backlog, ec, em)) + return; + + std::stringstream e("Failed to listen on socket: "); + e << ec << ": " << em; + + throw std::runtime_error(e.str()); + } + + /** + * \brief Connect to a listen socket + * + * \param[in] addr Remote address + * \param[out] err_code Error code + * \param[out] err_msg Error message + * + * \retval true on success + * \retval false on error + */ + bool connect(const Address & addr, int & err_code, std::string & err_msg) throw(); + + /** + * \brief Connect to a listen socket + * + * \param[in] addr Remote address + * + * \retval true on success + * \retval false on error + */ + inline bool connect(const Address & addr) throw() { + int ec; + std::string em; + + return connect(addr, ec, em); + } + + /** + * \brief Connect to a listen socket (or throw an exception) + * + * \param[in] addr Remote address + */ + inline void connectx(const Address & addr) throw(std::runtime_error) { + int ec; + std::string em; + + if (connect(addr, ec, em)) + return; + + std::stringstream e("Failed to connect socket: "); + e << ec << ": " << em; + + throw std::runtime_error(e.str()); + } + + // NutStream interface implementation + status_t getChar(char & ch) throw(); + void readChar() throw(); + status_t putChar(char ch) throw(); + status_t putString(const std::string & str) throw(); + inline status_t putData(const std::string & data) { + return putString(data); // no difference on sockets + } + + /** Destructor (closes socket if necessary) */ + ~NutSocket(); + + private: + + /** + * \brief Copy constructor + * + * TODO: Copying is forbidden (for now). + * If required, it may be enabled, using dup. + * + * \param orig Original file + */ + NutSocket(const NutSocket & orig) { + throw std::logic_error("NOT IMPLEMENTED"); + } + + /** + * \brief Assignment + * + * TODO: Assignment is forbidden (for now). + * See copy constructor for implementation notes + * (and don't forget to destroy left value, properly). + * + * \param rval Right value + */ + NutSocket & operator = (const NutSocket & rval) { + throw std::logic_error("NOT IMPLEMENTED"); + } + +}; // end of class NutSocket + +} // end of namespace nut + +#endif /* __cplusplus */ + +#endif /* end of #ifndef nut_nutstream_h */ From b5b7cbc2e2a5516d595dc9b883880b729875dd97 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Thu, 22 Nov 2012 15:18:37 +0100 Subject: [PATCH 020/121] Unit tests for nut::NutStream subtree Basic unit tests plus a few minor changes and updates to the code --- common/Makefile.am | 2 +- common/nutstream.cpp | 103 +++++++++++++++++++++++++++++++++++++--- include/Makefile.am | 4 +- include/nutstream.h | 110 +++++++++++++++++++++++++++++++++++++------ tests/Makefile.am | 6 +-- 5 files changed, 198 insertions(+), 27 deletions(-) diff --git a/common/Makefile.am b/common/Makefile.am index ad667799e3..d15d795a71 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -5,7 +5,7 @@ AM_CFLAGS = -I$(top_srcdir)/include noinst_LTLIBRARIES = libparseconf.la libcommon.la libnutconf.la libparseconf_la_SOURCES = parseconf.c -libnutconf_la_SOURCES = nutconf.cpp +libnutconf_la_SOURCES = nutconf.cpp nutstream.cpp # do not hard depend on '../include/nut_version.h', since it blocks # 'dist', and is only required for actual build, in which case diff --git a/common/nutstream.cpp b/common/nutstream.cpp index 47d632b2a4..760850e587 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -21,6 +21,7 @@ #include "nutstream.h" #include +#include #include #include #include @@ -31,6 +32,7 @@ extern "C" { #include #include #include +#include } @@ -74,6 +76,27 @@ NutStream::status_t NutMemory::putData(const std::string & data) { } +const std::string NutFile::m_tmp_dir("/var/tmp"); + + +NutFile::NutFile(anonymous_t): + m_impl(NULL), + m_current_ch('\0'), + m_current_ch_valid(false) +{ + m_impl = ::tmpfile(); + + if (NULL == m_impl) { + int err_code = errno; + + std::stringstream e("Failed to create temporary file: "); + e << err_code << ": " << ::strerror(err_code); + + throw std::runtime_error(e.str()); + } +} + + bool NutFile::open(access_t mode, int & err_code, std::string & err_msg) throw() { static const char *read_only = "r"; static const char *write_only = "w"; @@ -144,6 +167,31 @@ NutFile::NutFile(const std::string & name, access_t mode): } +std::string NutFile::tmpName() throw(std::runtime_error) { + char *tmp_name = ::tempnam(m_tmp_dir.c_str(), NULL); + + if (NULL == tmp_name) + throw std::runtime_error( + "Failed to create temporary file name"); + + std::string tmp_name_str(tmp_name); + + ::free(tmp_name); + + return tmp_name_str; +} + + +NutFile::NutFile(access_t mode): + m_name(tmpName()), + m_impl(NULL), + m_current_ch('\0'), + m_current_ch_valid(false) +{ + openx(mode); +} + + NutStream::status_t NutFile::getChar(char & ch) throw() { int c; @@ -229,7 +277,10 @@ NutFile::~NutFile() { void NutSocket::Address::init_unix(Address & addr, const std::string & path) { - struct sockaddr_un * un_addr = new struct sockaddr_un; + struct sockaddr_un * un_addr = (struct sockaddr_un *)::malloc(sizeof(struct sockaddr_un)); + + if (NULL == un_addr) + throw std::bad_alloc(); un_addr->sun_family = AF_UNIX; @@ -250,7 +301,10 @@ void NutSocket::Address::init_ipv4(Address & addr, const std::vector(qb.at(0)); packed_qb |= static_cast(qb.at(1)) << 8; @@ -258,7 +312,7 @@ void NutSocket::Address::init_ipv4(Address & addr, const std::vector(qb.at(3)) << 24; in4_addr->sin_family = AF_INET; - in4_addr->sin_port = static_cast(port); + in4_addr->sin_port = htons(port); in4_addr->sin_addr.s_addr = packed_qb; addr.m_sock_addr = reinterpret_cast(in4_addr); @@ -269,10 +323,13 @@ void NutSocket::Address::init_ipv4(Address & addr, const std::vector & hb, uint16_t port) { assert(16 == hb.size()); - struct sockaddr_in6 * in6_addr = new struct sockaddr_in6; + struct sockaddr_in6 * in6_addr = (struct sockaddr_in6 *)::malloc(sizeof(struct sockaddr_in6)); + + if (NULL == in6_addr) + throw std::bad_alloc(); in6_addr->sin6_family = AF_INET6; - in6_addr->sin6_port = static_cast(port); + in6_addr->sin6_port = htons(port); in6_addr->sin6_flowinfo = 0; // TODO: check that in6_addr->sin6_scope_id = 0; // TODO: check that @@ -323,6 +380,18 @@ NutSocket::Address::Address(const std::vector & bytes, uint16_t p } +NutSocket::Address::Address(const Address & orig): m_sock_addr(NULL), m_length(orig.m_length) { + void * copy = ::malloc(m_length); + + if (NULL == copy) + throw std::bad_alloc(); + + ::memcpy(copy, orig.m_sock_addr, m_length); + + m_sock_addr = reinterpret_cast(copy); +} + + /** * \brief Format IPv4 address * @@ -446,7 +515,7 @@ std::string NutSocket::Address::str() const { NutSocket::Address::~Address() { - delete m_sock_addr; + ::free(m_sock_addr); } @@ -549,6 +618,28 @@ bool NutSocket::connect(const Address & addr, int & err_code, std::string & err_ } +bool NutSocket::close(int & err_code, std::string & err_msg) throw() { + err_code = ::close(m_impl); + + if (0 == err_code) { + m_impl = -1; + + return true; + } + + err_code = errno; + err_msg = std::string(::strerror(err_code)); + + return false; +} + + +NutSocket::~NutSocket() { + if (-1 != m_impl) + closex(); +} + + NutStream::status_t NutSocket::getChar(char & ch) throw() { if (m_current_ch_valid) { ch = m_current_ch; diff --git a/include/Makefile.am b/include/Makefile.am index 5ed42d9bfb..0ea350f6bf 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,5 +1,5 @@ -EXTRA_DIST = attribute.h common.h extstate.h parseconf.h proto.h \ - state.h timehead.h upsconf.h nut_stdint.h +dist_noinst_HEADERS = attribute.h common.h extstate.h parseconf.h proto.h \ + state.h timehead.h upsconf.h nut_stdint.h nut_platform.h nutstream.h # http://www.gnu.org/software/automake/manual/automake.html#Clean BUILT_SOURCES = nut_version.h diff --git a/include/nutstream.h b/include/nutstream.h index 6681817a2d..e856228f85 100644 --- a/include/nutstream.h +++ b/include/nutstream.h @@ -123,7 +123,8 @@ class NutStream { */ virtual status_t putData(const std::string & data) = 0; - virtual ~NutStream() {} // private destructor for an iface + /** Formal destructor */ + virtual ~NutStream() {} }; // end of class NutStream @@ -185,8 +186,16 @@ class NutFile: public NutStream { APPEND_ONLY, } access_t; + /** Unnamed temp. file constructor flag */ + typedef enum { + ANONYMOUS, /** Anonymous temp. file flag */ + } anonymous_t; + private: + /** Temporary files directory */ + static const std::string m_tmp_dir; + /** File name */ const std::string m_name; @@ -199,6 +208,15 @@ class NutFile: public NutStream { /** Current character cache status */ bool m_current_ch_valid; + /** + * \brief Generate temporary file name + * + * Throws an exception on file name generation error. + * + * \return Temporary file name + */ + std::string tmpName() throw(std::runtime_error); + public: /** Constructor @@ -211,6 +229,22 @@ class NutFile: public NutStream { m_current_ch('\0'), m_current_ch_valid(false) {} + /** + * \brief Temporary file constructor (with open) + * + * Anonymous temp. file (with automatic destruction) will be created. + */ + NutFile(anonymous_t); + + /** + * \brief File name getter + * + * \return File name + */ + inline const std::string & name() const { + return m_name; + } + /** * \brief Open file * @@ -307,6 +341,19 @@ class NutFile: public NutStream { */ NutFile(const std::string & name, access_t mode); + /** + * \brief Temporary file constructor (with open) + * + * Opens file in \ref m_tmp_dir. + * Throws exception on open error. + * Note that for temporary files, non-creation modes + * don't make sense (and will result in throwing an exception). + * + * \param[in] name File name + * \param[in] mode File open mode (r/w by default) + */ + NutFile(access_t mode = READ_WRITE_CLEAR); + // NutStream interface implementation status_t getChar(char & ch) throw(); void readChar() throw(); @@ -354,7 +401,7 @@ class NutSocket: public NutStream { /** Socket domain */ typedef enum { NUTSOCKD_UNIX = AF_UNIX, /** Unix */ - NUTSOCKD_INET4 = AF_INET, /** IPv4 */ + NUTSOCKD_INETv4 = AF_INET, /** IPv4 */ NUTSOCKD_INETv6 = AF_INET6, /** IPv6 */ } domain_t; @@ -462,6 +509,13 @@ class NutSocket: public NutStream { */ Address(const std::vector & bytes, uint16_t port) throw(std::logic_error); + /** + * \brief Copy constructor + * + * \param orig Original address + */ + Address(const Address & orig); + /** * \brief Stringifisation * @@ -495,18 +549,6 @@ class NutSocket: public NutStream { /** Current character cache status */ bool m_current_ch_valid; - /** - * \brief Constructor for an uninitialised socket - * - * Uninitialised socket is used with client connection - * socket constructor if the listen socket is closed. - */ - NutSocket(): - m_impl(-1), - m_current_ch('\0'), - m_current_ch_valid(false) - {} - /** * \brief Accept client connection on a listen socket * @@ -585,7 +627,7 @@ class NutSocket: public NutStream { * \param proto Socket protocol */ NutSocket( - domain_t dom = NUTSOCKD_INET4, + domain_t dom = NUTSOCKD_INETv4, type_t type = NUTSOCKT_STREAM, proto_t proto = NUTSOCKP_IMPLICIT); @@ -759,6 +801,44 @@ class NutSocket: public NutStream { throw std::runtime_error(e.str()); } + /** + * \brief Close socket + * + * \param[out] err_code Error code + * \param[out] err-msg Error message + * + * \retval true if close succeeded + * \retval false if close failed + */ + bool close(int & err_code, std::string & err_msg) throw(); + + /** + * \brief Close socket + * + * \retval true if close succeeded + * \retval false if close failed + */ + inline bool close() throw() { + int ec; + std::string em; + + return close(ec, em); + } + + /** Close socket (or throw exception) */ + inline void closex() throw(std::runtime_error) { + int ec; + std::string em; + + if (close(ec, em)) + return; + + std::stringstream e("Failed to close socket "); + e << m_impl << ": " << ec << ": " << em; + + throw std::runtime_error(e.str()); + } + // NutStream interface implementation status_t getChar(char & ch) throw(); void readChar() throw(); diff --git a/tests/Makefile.am b/tests/Makefile.am index 92e64ae6a8..2746181e73 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -6,17 +6,17 @@ TESTS = cppunittest check_PROGRAMS = $(TESTS) -cppunittest_CXXFLAGS = $(CPPUNIT_CFLAGS) +cppunittest_CXXFLAGS = $(CPPUNIT_CFLAGS) -I$(top_srcdir)/include cppunittest_LDFLAGS = $(CPPUNIT_LIBS) cppunittest_LDADD = ../common/libnutconf.la # List of src files for CppUnit tests -CPPUNITTESTSRC = example.cpp nutconf.cpp +CPPUNITTESTSRC = example.cpp nutconf.cpp nutstream_ut.cpp cppunittest_SOURCES = $(CPPUNITTESTSRC) cpputest.cpp else !HAVE_CPPUNIT -EXTRA_DIST = example.cpp nutconf.cpp cpputest.cpp +EXTRA_DIST = example.cpp nutconf.cpp cpputest.cpp nutstream_ut.cpp endif !HAVE_CPPUNIT From e95e289f6ce3d6d2587d7eb14a161a5fa809e713 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Thu, 22 Nov 2012 15:21:51 +0100 Subject: [PATCH 021/121] Forgotten UT source from prev. commit --- tests/nutstream_ut.cpp | 331 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 tests/nutstream_ut.cpp diff --git a/tests/nutstream_ut.cpp b/tests/nutstream_ut.cpp new file mode 100644 index 0000000000..6f578f930f --- /dev/null +++ b/tests/nutstream_ut.cpp @@ -0,0 +1,331 @@ +/* +NUT stream unit test + +Copyright (C) +2012 Vaclav Krpec + +This program 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 2 of the License, or +(at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "nutstream.h" + +#include + +#include +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +} + + +/** Test data */ +static const std::string test_data( + "And the mother of Jesus said unto the Lord, ""They have no more wine.""\n" + "And Jesus said unto the servants, ""Fill six water pots with water.""\n" + "And they did so.\n" + "And when the steward of the feast did taste of the water from the pots, it had become wine.\n" + "And he knew not whence it had come.\n" + "But the servants did know, and they applauded loudly in the kitchen.\n" + "And they said unto the Lord, ""How the Hell did you do that!?""\n" + "And inquired of him ""Do you do children’s parties?""\n" + "And the Lord said ""No.""\n" + ); + + +/** + * \brief Read and check test data from a stream + * + * \param stream Input stream + * + * \retval true in case of success + * \retval false in case of failure + */ +static bool readTestData(nut::NutStream * stream) { + assert(NULL != stream); + + // Read characters from the stream + for (size_t pos = 0, iter = 0; ; ++iter) { + char ch; + + nut::NutStream::status_t status = stream->getChar(ch); + + if (nut::NutStream::NUTS_ERROR == status) + return false; + + if (nut::NutStream::NUTS_EOF == status) + break; + + if (nut::NutStream::NUTS_OK != status) + return false; + + if (ch != test_data.at(pos)) + return false; + + // Every other character shall be checked twice + if (0 == iter % 8) + continue; + + // Consume current character + stream->readChar(); + + ++pos; + } + + return true; +} + + +/** + * \brief Write test data to a stream + * + * \param stream Output stream + * + * \retval true in case of success + * \retval false in case of failure + */ +static bool writeTestData(nut::NutStream * stream) { + assert(NULL != stream); + + size_t pivot = 0.5 * test_data.size(); + + // Write characters to the stream + for (size_t i = 0; i < pivot; ++i) { + char ch = test_data.at(i); + + nut::NutStream::status_t status = stream->putChar(ch); + + if (nut::NutStream::NUTS_OK != status) + return false; + } + + // Write string to the stream + const std::string str = test_data.substr(pivot); + + nut::NutStream::status_t status = stream->putString(str); + + CPPUNIT_ASSERT(nut::NutStream::NUTS_OK == status); + + return true; +} + + +/** + * \brief NUT stream unit test suite (abstract) + */ +class NutStreamUnitTest: public CppUnit::TestFixture { + protected: + + /** + * \brief Read test data from stream + * + * \c CPPUNIT_ASSERT macro is used to resolve error. + * + * \param stream Input stream + */ + inline void readx(nut::NutStream * stream) { + CPPUNIT_ASSERT(readTestData(stream)); + } + + /** + * \brief Write test data to stream + * + * \c CPPUNIT_ASSERT macro is used to resolve error. + * + * \param stream Output stream + */ + inline void writex(nut::NutStream * stream) { + CPPUNIT_ASSERT(writeTestData(stream)); + } + +}; // end of class NutStreamUnitTest + + +/** + * \brief NUT memory stream unit test suite + */ +class NutMemoryUnitTest: public NutStreamUnitTest { + private: + + CPPUNIT_TEST_SUITE(NutMemoryUnitTest); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); + + public: + + inline void setUp() {} + inline void tearDown() {} + + void test(); + +}; // end of class NutMemoryUnitTest + + +void NutMemoryUnitTest::test() { + nut::NutMemory input_mstream(test_data); + nut::NutMemory output_mstream; + + readx(&input_mstream); + writex(&output_mstream); + readx(&output_mstream); +} + + +/** + * \brief NUT file stream unit test suite + */ +class NutFileUnitTest: public NutStreamUnitTest { + private: + + CPPUNIT_TEST_SUITE(NutFileUnitTest); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); + + public: + + inline void setUp() {} + inline void tearDown() {} + + void test(); + +}; // end of class NutFileUnitTest + + +void NutFileUnitTest::test() { + nut::NutFile fstream(nut::NutFile::ANONYMOUS); + + writex(&fstream); + readx(&fstream); +} + + +/** + * \brief NUT socket stream unit test suite + */ +class NutSocketUnitTest: public NutStreamUnitTest { + private: + + /** NUT socket stream unit test: writer */ + class Writer { + private: + + /** Remote listen address */ + nut::NutSocket::Address m_remote_address; + + public: + + /** + * \brief Constructor + * + * \param addr Remote address + */ + Writer(const nut::NutSocket::Address & addr): + m_remote_address(addr) + {} + + /** + * \brief Writer routine + * + * Writer shall write contents of the test data + * to its connection socket. + * + * \retval true in case of success + * \retval false otherwise + */ + bool run(); + + }; // end of class Writer + + /** TCP listen address IPv4 */ + static const nut::NutSocket::Address m_listen_address; + + CPPUNIT_TEST_SUITE(NutSocketUnitTest); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); + + public: + + inline void setUp() {}; + inline void tearDown() {} + + void test(); + +}; // end of class NutSocketUnitTest + + +const nut::NutSocket::Address NutSocketUnitTest::m_listen_address(127, 0, 0, 1, 10000); + + +bool NutSocketUnitTest::Writer::run() { + nut::NutSocket conn_sock; + + if (!conn_sock.connect(m_remote_address)) + return false; + + if (!writeTestData(&conn_sock)) + return false; + + if (!conn_sock.close()) + return false; + + return true; +} + + +void NutSocketUnitTest::test() { + // Fork writer + pid_t writer_pid = ::fork(); + + if (!writer_pid) { + // Wait for listen socket + ::sleep(1); + + // Run writer + CPPUNIT_ASSERT(Writer(m_listen_address).run()); + + return; + } + + // Listen + nut::NutSocket listen_sock; + + CPPUNIT_ASSERT(listen_sock.bind(m_listen_address)); + CPPUNIT_ASSERT(listen_sock.listen(10)); + + // Accept connection + nut::NutSocket conn_sock(nut::NutSocket::ACCEPT, listen_sock); + + // Read the test data + readx(&conn_sock); + + // Wait for writer + int writer_exit; + pid_t wpid = ::waitpid(writer_pid, &writer_exit, 0); + + CPPUNIT_ASSERT(wpid == writer_pid); + CPPUNIT_ASSERT(0 == writer_exit); +} + + +// Register the test suite +CPPUNIT_TEST_SUITE_REGISTRATION(NutMemoryUnitTest); +CPPUNIT_TEST_SUITE_REGISTRATION(NutFileUnitTest); +CPPUNIT_TEST_SUITE_REGISTRATION(NutSocketUnitTest); From 003e345859ab792ad9ed42ea02203dbf2cf043ff Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Wed, 28 Nov 2012 10:17:12 +0100 Subject: [PATCH 022/121] Partial implementation on NutWriter subtree General serialisers implemented Several TBDs and TODOs left for review tbc... --- common/Makefile.am | 2 +- common/nutstream.cpp | 2 +- common/nutwriter.cpp | 206 ++++++++++++++++++++++++++++ include/Makefile.am | 3 +- include/nutconf.h | 10 +- include/nutstream.h | 2 +- include/nutwriter.h | 312 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 531 insertions(+), 6 deletions(-) create mode 100644 common/nutwriter.cpp create mode 100644 include/nutwriter.h diff --git a/common/Makefile.am b/common/Makefile.am index d15d795a71..f031ea6c5c 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -5,7 +5,7 @@ AM_CFLAGS = -I$(top_srcdir)/include noinst_LTLIBRARIES = libparseconf.la libcommon.la libnutconf.la libparseconf_la_SOURCES = parseconf.c -libnutconf_la_SOURCES = nutconf.cpp nutstream.cpp +libnutconf_la_SOURCES = nutconf.cpp nutstream.cpp nutwriter.cpp # do not hard depend on '../include/nut_version.h', since it blocks # 'dist', and is only required for actual build, in which case diff --git a/common/nutstream.cpp b/common/nutstream.cpp index 760850e587..b65911d44c 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -1,4 +1,4 @@ -/* nutdata.cpp - NUT stream +/* nutstream.cpp - NUT stream Copyright (C) 2012 Vaclav Krpec diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp new file mode 100644 index 0000000000..37395fe1a2 --- /dev/null +++ b/common/nutwriter.cpp @@ -0,0 +1,206 @@ +/* nutwriter.cpp - NUT writer + + Copyright (C) + 2012 Vaclav Krpec + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "nutwriter.h" + +#include +#include + + +namespace nut { + +// End-of-Line separators (arch. dependent) + +/** UNIX style EoL */ +static const std::string LF("\n"); + +// TODO: Make a compile-time selection +#if (0) +// M$ Windows EoL +static const std::string CRLF("\r\n"); + +// Apple MAC EoL +static const std::string CR("\r"); +#endif // end of #if (0) + + +const std::string & NutWriter::eol(LF); + + +NutWriter::status_t NutWriter::writeEachLine(const std::string & str, const std::string & pref) { + for (size_t pos = 0; pos < str.size(); ) { + // Prefix every line + status_t status = write(pref); + + if (NUTW_OK != status) + return status; + + // Write up to the next EoL (or till the end) + size_t eol_pos = str.find(eol, pos); + + if (str.npos == eol_pos) + return write(str.substr(pos) + eol); + + eol_pos += eol.size(); + + status = write(str.substr(pos, eol_pos)); + + if (NUTW_OK != status) + return status; + + // Update position + pos = eol_pos; + } + + return NUTW_OK; +} + + +NutWriter::status_t SectionlessConfigWriter::writeDirective(const std::string & str) { + return write(str + eol); +} + + +NutWriter::status_t SectionlessConfigWriter::writeComment(const std::string & str) { + return writeEachLine(str, "# "); +} + + +NutWriter::status_t SectionlessConfigWriter::writeSectionName(const std::string & name) { + std::string e("INTERNAL ERROR: Attempt to write section name "); + e += name + " to a section-less configuration file"; + + throw std::logic_error(e); +} + + +NutWriter::status_t NutConfConfigWriter::writeConfig(const NutConfiguration & config) { + // TODO + + throw std::logic_error("FIXME: Not implemented, yet"); +} + + +NutWriter::status_t UpsmonConfigWriter::writeConfig(const UpsmonConfiguration & config) { + // TODO + + throw std::logic_error("FIXME: Not implemented, yet"); +} + + +NutWriter::status_t UpsdConfigWriter::writeConfig(const UpsdConfiguration & config) { + // TODO + + throw std::logic_error("FIXME: Not implemented, yet"); +} + + +NutWriter::status_t DefaultConfigWriter::writeComment(const std::string & str) { + return writeEachLine(str, "# "); +} + + +NutWriter::status_t DefaultConfigWriter::writeSectionName(const std::string & name) { + std::string section_line("["); + section_line += name + "]" + eol; + + return write(section_line); +} + + +NutWriter::status_t DefaultConfigWriter::writeDirective(const std::string & str) { + return write(str + eol); +} + + +NutWriter::status_t GenericConfigWriter::writeSection(const GenericConfigSection & section) { + // TBD: Shouldn't this be somewhere else? + // The parser has to use this, either... + static const std::string value_separator(", "); + + status_t status; + + // Note that global scope definitions are in section + // with an empty name + // The section name won't be written and the assignments + // won't be indented + std::string indent; + + if (!section.name.empty()) { + status = writeSectionName(section.name); + + if (NUTW_OK != status) + return status; + + indent += "\t"; + } + + // Write section name/value pairs + GenericConfigSection::EntryMap::const_iterator entry_iter = section.entries.begin(); + + for (; entry_iter != section.entries.end(); ++entry_iter) { + std::string assign(indent); + assign += entry_iter->second.name + " = "; + + const ConfigParamList & values(entry_iter->second.values); + + ConfigParamList::const_iterator value_iter = values.begin(); + + for (; value_iter != values.end(); ++value_iter) { + if (value_iter != values.begin()) + assign += value_separator; + + assign += *value_iter; + } + + status = writeDirective(assign); + + if (NUTW_OK != status) + return status; + } + + return NUTW_OK; +} + + +NutWriter::status_t GenericConfigWriter::writeConfig(const GenericConfiguration & config) { + // Write sections + // Note that lexicographic ordering places the global + // (i.e. empty-name) section as the 1st one + GenericConfiguration::SectionMap::const_iterator section_iter = config.sections.begin(); + + for (; section_iter != config.sections.end(); ++section_iter) { + status_t status = writeSection(section_iter->second); + + if (NUTW_OK != status) + return status; + + // TBD: Write one empty line as section separator + status = write(eol); + + if (NUTW_OK != status) + return status; + } + + return NUTW_OK; +} + + +} // end of namespace nut diff --git a/include/Makefile.am b/include/Makefile.am index 0ea350f6bf..6f066dd487 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,5 +1,6 @@ dist_noinst_HEADERS = attribute.h common.h extstate.h parseconf.h proto.h \ - state.h timehead.h upsconf.h nut_stdint.h nut_platform.h nutstream.h + state.h timehead.h upsconf.h nut_stdint.h nut_platform.h nutstream.h \ + nutwriter.h # http://www.gnu.org/software/automake/manual/automake.html#Clean BUILT_SOURCES = nut_version.h diff --git a/include/nutconf.h b/include/nutconf.h index 76c3d2b2b3..6fae3ccb41 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -201,9 +201,12 @@ struct GenericConfigSectionEntry struct GenericConfigSection { + /** Section entries map */ + typedef std::map EntryMap; + std::string name; // std::string comment; - std::map entries; + EntryMap entries; const GenericConfigSectionEntry& operator [] (const std::string& varname)const{return entries.find(varname)->second;} GenericConfigSectionEntry& operator [] (const std::string& varname){return entries[varname];} @@ -256,6 +259,9 @@ class GenericConfigParser : public DefaultConfigParser class GenericConfiguration : public BaseConfiguration { public: + /** Sections map */ + typedef std::map SectionMap; + GenericConfiguration(){} void parseFromString(const std::string& str); @@ -264,7 +270,7 @@ class GenericConfiguration : public BaseConfiguration // FIXME Let me public or set it as protected with public accessors ? - std::map sections; + SectionMap sections; const GenericConfigSection& operator[](const std::string& secname)const{return sections.find(secname)->second;} GenericConfigSection& operator[](const std::string& secname){return sections[secname];} diff --git a/include/nutstream.h b/include/nutstream.h index e856228f85..0ef340f686 100644 --- a/include/nutstream.h +++ b/include/nutstream.h @@ -1,4 +1,4 @@ -/* nutdata.h - NUT stream +/* nutstream.h - NUT stream Copyright (C) 2012 Vaclav Krpec diff --git a/include/nutwriter.h b/include/nutwriter.h new file mode 100644 index 0000000000..6e89fa12fe --- /dev/null +++ b/include/nutwriter.h @@ -0,0 +1,312 @@ +/* nutwriter.h - NUT writer + + Copyright (C) + 2012 Vaclav Krpec + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef nut_nutwriter_h +#define nut_nutwriter_h + +#ifdef __cplusplus + +#include "nutstream.h" +#include "nutconf.h" + +#include + + +namespace nut +{ + +/** + * \brief NUT stream writer + */ +class NutWriter { + public: + + /** NUT writer status */ + typedef enum { + NUTW_OK = 0, /** Writing successful */ + NUTW_ERROR, /** Writing failed */ + } status_t; // end of typedef enum */ + + protected: + + /** EoL separator */ + static const std::string & eol; + + /** Output stream (by reference) */ + NutStream & m_output_stream; + + public: + + /** + * \brief Constructor + * + * Creates the writer. + * The \c ostream parameter provides the writer reference + * to an existing output stream; note that the stream + * must exist throughout whole the writer's life. + * + * TBD: + * The stream might actually be passed either by value + * (\c NutStream implementations would have to support + * copying, though, which is not implemented at the moment) + * or using reference counting mechanism (smart pointers etc). + * The latter is perhaps a better choice (if the stream existence + * dependency is a considerable issue). + * + * \param ostream Output stream + */ + NutWriter(NutStream & ostream): m_output_stream(ostream) {} + + /** + * \brief Write to output stream + * + * The method writes the provided string to the output stream. + * + * \retval NUTW_OK on success + * \retval NUTW_ERROR otherwise + */ + inline status_t write(const std::string & str) { + NutStream::status_t status = m_output_stream.putString(str); + + return NutStream::NUTS_OK == status ? NUTW_OK : NUTW_ERROR; + } + + /** + * \brief Write to output stream + * + * The method writes the provided string to the output stream. + * An exception is thrown on error. + */ + inline void writex(const std::string & str) { + NutStream::status_t status = m_output_stream.putString(str); + + if (NutStream::NUTS_OK != status) { + std::stringstream e("Failed to write to output stream: "); + e << status; + + throw std::runtime_error(e.str()); + } + } + + protected: + + /** + * \brief Write (prefixed) lines + * + * The method splits string to lines (by EoL) and prefix them + * with specified string upon writing. + * + * \param str String (multi-line) + * \param pref Prefix + * + * \retval NUTW_OK on success + * \retval NUTW_ERROR otherwise + */ + status_t writeEachLine(const std::string & str, const std::string & pref); + +}; // end of class NutWriter + + +/** + * \brief NUT consfiguration writer interface + */ +class NutConfigWriter: public NutWriter { + protected: + + /** Formal constructor */ + NutConfigWriter(NutStream & ostream): NutWriter(ostream) {} + + public: + + /** + * \brief Write comment + * + * \param str Comment string + * + * \retval NUTW_OK on success + * \retval NUTW_ERROR otherwise + */ + virtual status_t writeComment(const std::string & str) = 0; + + /** + * \brief Write section name + * + * \param name Section name + * + * \retval NUTW_OK on success + * \retval NUTW_ERROR otherwise + */ + virtual status_t writeSectionName(const std::string & name) = 0; + + /** + * \brief Write directive + * + * \param str Directive string + * + * \retval NUTW_OK on success + * \retval NUTW_ERROR otherwise + */ + virtual status_t writeDirective(const std::string & str) = 0; + + /** Virtual destructor */ + virtual ~NutConfigWriter() {} + +}; // end of class NutConfigWriter + + +/** + * \brief NUT section-less configuration writer specialisation + * + * Partial implementaton of \ref NutConfigWriter for section-less + * configuration files. + */ +class SectionlessConfigWriter: public NutConfigWriter { + public: + + // Partial \ref NutConfigWriter interface implementation + status_t writeDirective(const std::string & str); + status_t writeComment(const std::string & str); + + private: + + // Section name writing is forbidden (no sections) + status_t writeSectionName(const std::string & name); + +}; // end of class SectionlessConfigWriter + + +/** + * \brief \c nut.conf configuration file serialiser + */ +class NutConfConfigWriter: public SectionlessConfigWriter { + public: + + /** + * \brief Serialise configuration container + * + * \param config Configuration + * + * \retval NUTW_OK on success + * \retval NUTW_ERROR otherwise + */ + status_t writeConfig(const NutConfiguration & config); + +}; // end of class NutConfConfigWriter + + +/** + * \brief \c upsmon.conf configuration file serialiser + */ +class UpsmonConfigWriter: public SectionlessConfigWriter { + public: + + /** + * \brief Serialise configuration container + * + * \param config Configuration + * + * \retval NUTW_OK on success + * \retval NUTW_ERROR otherwise + */ + status_t writeConfig(const UpsmonConfiguration & config); + +}; // end of class UpsmonConfigWriter + + +/** + * \brief \c upsd.conf configuration file serialiser + */ +class UpsdConfigWriter: public SectionlessConfigWriter { + public: + + /** + * \brief Serialise configuration container + * + * \param config Configuration + * + * \retval NUTW_OK on success + * \retval NUTW_ERROR otherwise + */ + status_t writeConfig(const UpsdConfiguration & config); + +}; // end of class UpsdConfigWriter + + +/** + * \brief NUT default configuration writer ancestor + * + * Implements the \ref NutConfigWriter interface + * and adds \c writeSection prototype to be implemented + * by descendants. + */ +class DefaultConfigWriter: public NutConfigWriter { + public: + + // \ref NutConfigWriter interface implementation + status_t writeComment(const std::string & str); + status_t writeSectionName(const std::string & name); + status_t writeDirective(const std::string & str); + + /** + * \brief Write configuration section + * + * Serialise generic configuration section. + * + * \param section Configuration section + * + * \retval NUTW_OK on success + * \retval NUTW_ERROR otherwise + */ + virtual status_t writeSection(const GenericConfigSection & section) = 0; + +}; // end of class DefaultConfigWriter + + +/** + * \brief NUT generic configuration writer + * + * Base configuration file serialiser. + * Implements the \ref DefaultConfigWriter \c writeSection method + * and adds \c writeConfig routine for configuration file serialisation. + */ +class GenericConfigWriter: public DefaultConfigWriter { + public: + + // Section serialiser implementation + status_t writeSection(const GenericConfigSection & section); + + /** + * \brief Base configuration serialiser + * + * \param config Base configuration + * + * \retval NUTW_OK on success + * \retval NUTW_ERROR otherwise + */ + status_t writeConfig(const GenericConfiguration & config); + +}; // end of class GenericConfigWriter + + +} // end of namespace nut + +#endif /* __cplusplus */ + +#endif /* end of #ifndef nut_nutwriter_h */ From 2e54e2da20fc498c7403728d6c143bd0e773c280 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Fri, 30 Nov 2012 09:47:44 +0100 Subject: [PATCH 023/121] NutWriter: ups.conf upsmon.conf upsd.conf support --- common/nutwriter.cpp | 410 ++++++++++++++++++++++++++++++++++++++++++- include/nutconf.h | 2 +- 2 files changed, 405 insertions(+), 7 deletions(-) diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index 37395fe1a2..35ec1d04c3 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -22,6 +22,43 @@ #include #include +#include +#include +#include +#include + + +/** + * \brief NUT configuration directive generator + * + * The macro is used to simplify generation of + * NUT config. directives. + * + * IMPORTANT NOTE: + * In case of writing error, the macro causes immediate + * return from the calling function (propagating the writing status). + * + * \param name Directive name + * \param arg_t Directive argument implementation type + * \param arg Directive argument + * \param quote_arg Boolean flag; check to quote the argument + */ +#define CONFIG_DIRECTIVEX(name, arg_t, arg, quote_arg) \ + do { \ + if ((arg).set()) { \ + const arg_t & arg_val = (arg); \ + std::stringstream ss(name); \ + ss << ' '; \ + if (quote_arg) \ + ss << '"'; \ + ss << arg_val; \ + if (quote_arg) \ + ss << '"'; \ + status_t status = writeDirective(ss.str()); \ + if (NUTW_OK != status) \ + return status; \ + } \ + } while (0) namespace nut { @@ -92,23 +129,384 @@ NutWriter::status_t SectionlessConfigWriter::writeSectionName(const std::string NutWriter::status_t NutConfConfigWriter::writeConfig(const NutConfiguration & config) { - // TODO + status_t status; + + // Mode + // TBD: How should I serialise an unknown mode? + if (config.mode.set()) { + std::string mode_str; + + NutConfiguration::NutMode mode = config.mode; + + switch (mode) { + case NutConfiguration::MODE_UNKNOWN: + // BEWARE! Intentional fall-through to MODE_NONE branch + + case NutConfiguration::MODE_NONE: + mode_str = "none"; + break; + + case NutConfiguration::MODE_STANDALONE: + mode_str = "standalone"; + break; + + case NutConfiguration::MODE_NETSERVER: + mode_str = "netserver"; + break; + + case NutConfiguration::MODE_NETCLIENT: + mode_str = "netclient"; + break; + } + + status = writeDirective("MODE=" + mode_str); + + if (NUTW_OK != status) + return status; + } + + return NUTW_OK; +} + + +/** Notify types & flags strings */ +struct NotifyFlagsStrings { + // TBD: Shouldn't this mapping be shared with the parser? + // This is an obvious redundancy... + + /** Notify type strings list */ + typedef const char * TypeStrings[UpsmonConfiguration::NOTIFY_TYPE_MAX]; + + /** Notify flag strings map */ + typedef std::map FlagStrings; + + /** Notify type strings */ + static const TypeStrings type_str; + + /** Notify flag strings */ + static const FlagStrings flag_str; + + /** + * \brief Initialise notify flag strings + * + * \return Notify flag strings map + */ + static FlagStrings initFlagStrings() { + FlagStrings str; + + str[UpsmonConfiguration::NOTIFY_IGNORE] = "IGNORE"; + str[UpsmonConfiguration::NOTIFY_SYSLOG] = "SYSLOG"; + str[UpsmonConfiguration::NOTIFY_WALL] = "WALL"; + str[UpsmonConfiguration::NOTIFY_EXEC] = "EXEC"; + + return str; + } + +}; // end of struct NotifyFlagsStrings + + +const NotifyFlagsStrings::TypeStrings NotifyFlagsStrings::type_str = { + "ONLINE", // NOTIFY_ONLINE + "ONBATT", // NOTIFY_ONBATT + "LOWBATT", // NOTIFY_LOWBATT + "FSD\t", // NOTIFY_FSD (including padding) + "COMMOK", // NOTIFY_COMMOK + "COMMBAD", // NOTIFY_COMMBAD + "SHUTDOWN", // NOTIFY_SHUTDOWN + "REPLBATT", // NOTIFY_REPLBATT + "NOCOMM", // NOTIFY_NOCOMM + "NOPARENT", // NOTIFY_NOPARENT +}; + + +const NotifyFlagsStrings::FlagStrings NotifyFlagsStrings::flag_str = + NotifyFlagsStrings::initFlagStrings(); + + +/** + * \brief upsmon notify flags serialiser + * + * \param type Notification type + * \param flags Notification flags + * + * \return NOTIFYFLAG directive string + */ +static std::string serialiseNotifyFlags(UpsmonConfiguration::NotifyType type, unsigned short flags) { + static const std::string ignore_str( + NotifyFlagsStrings::flag_str.at(UpsmonConfiguration::NOTIFY_IGNORE)); + + assert(type < UpsmonConfiguration::NOTIFY_TYPE_MAX); + + std::string directive("NOTIFYFLAG "); + + directive += NotifyFlagsStrings::type_str[type]; + + char separator = '\t'; + + // The IGNORE flag is actually no-flag case + if (UpsmonConfiguration::NOTIFY_IGNORE == flags) { + directive += separator; + directive += ignore_str; + + return directive; + } + + NotifyFlagsStrings::FlagStrings::const_iterator fl_iter = + NotifyFlagsStrings::flag_str.begin(); + + for (; fl_iter != NotifyFlagsStrings::flag_str.end(); ++fl_iter) { + if (fl_iter->first & flags) { + directive += separator; + directive += fl_iter->second; + + separator = '+'; + } + } + + return directive; +} + + +/** + * \brief upsmon notify messages serialiser + * + * \param type Notification type + * \param msg Notification message + * + * \return NOTIFYMSG directive string + */ +static std::string serialiseNotifyMessage(UpsmonConfiguration::NotifyType type, const std::string & msg) { + assert(type < UpsmonConfiguration::NOTIFY_TYPE_MAX); + + std::string directive("NOTIFYMSG "); + + directive += NotifyFlagsStrings::type_str[type]; + directive += '\t'; + directive += '"' + msg + '"'; - throw std::logic_error("FIXME: Not implemented, yet"); + return directive; +} + + +/** + * \brief Get notify type successor + * + * TBD: Should be in nutconf.h + * + * \param type Notify type + * + * \return Notify type successor + */ +inline static UpsmonConfiguration::NotifyType nextNotifyType(UpsmonConfiguration::NotifyType type) { + assert(type < UpsmonConfiguration::NOTIFY_TYPE_MAX); + + int type_ord = static_cast(type); + + return static_cast(type_ord + 1); +} + + +/** + * \brief Notify type pre-incrementation + * + * TBD: Should be in nutconf.h + * + * \param[in,out] type Notify type + * + * \return \c type successor + */ +inline static UpsmonConfiguration::NotifyType operator ++(UpsmonConfiguration::NotifyType & type) { + return type = nextNotifyType(type); +} + + +/** + * \brief Notify type post-incrementation + * + * TBD: Should be in nutconf.h + * + * \param[in,out] type Notify type + * + * \return \c type + */ +inline static UpsmonConfiguration::NotifyType operator ++(UpsmonConfiguration::NotifyType & type, int) { + UpsmonConfiguration::NotifyType type_copy = type; + + type = nextNotifyType(type); + + return type_copy; +} + + +/** + * \brief UPS monitor definition serialiser + * + * \param monitor Monitor + * + * \return Monitor config. directive + */ +static std::string serialiseMonitor(const UpsmonConfiguration::Monitor & monitor) { + std::stringstream directive("MONITOR "); + + // System + directive << monitor.upsname << '@' << monitor.hostname; + + if (monitor.port) + directive << ':' << monitor.port; + + directive << ' '; + + // Power value + directive << monitor.powerValue << ' '; + + // Username & password + directive << monitor.username << ' ' << monitor.password << ' '; + + // Master/slave + directive << (monitor.isMaster ? "master" : "slave"); + + return directive.str(); } NutWriter::status_t UpsmonConfigWriter::writeConfig(const UpsmonConfiguration & config) { - // TODO + /** + * \brief upsmon directive generator + * + * The macro is locally used to simplify generation of + * upsmon config. directives (except those with enumerated + * arguments). + * + * NOTE that the macro may cause return from the function + * (upon writing error). + * See \ref CONFIG_DIRECTIVEX for more information. + * + * \param name Directive name + * \param arg_t Directive argument implementation type + * \param arg Directive argument + * \param quote_arg Boolean flag; check to quote the argument + */ + #define UPSMON_DIRECTIVEX(name, arg_t, arg, quote_arg) \ + CONFIG_DIRECTIVEX(name, arg_t, arg, quote_arg) + + UPSMON_DIRECTIVEX("RUN_AS_USER", std::string, config.runAsUser, false); + UPSMON_DIRECTIVEX("SHUTDOWNCMD", std::string, config.shutdownCmd, true); + UPSMON_DIRECTIVEX("NOTIFYCMD", std::string, config.notifyCmd, true); + UPSMON_DIRECTIVEX("POWERDOWNFLAG", std::string, config.powerDownFlag, false); + UPSMON_DIRECTIVEX("MINSUPPLIES", unsigned int, config.minSupplies, false); + UPSMON_DIRECTIVEX("POLLFREQ", unsigned int, config.poolFreq, false); + UPSMON_DIRECTIVEX("POLLFREQALERT", unsigned int, config.poolFreqAlert, false); + UPSMON_DIRECTIVEX("HOSTSYNC", unsigned int, config.hotSync, false); + UPSMON_DIRECTIVEX("DEADTIME", unsigned int, config.deadTime, false); + UPSMON_DIRECTIVEX("RBWARNTIME", unsigned int, config.rbWarnTime, false); + UPSMON_DIRECTIVEX("NOCOMMWARNTIME", unsigned int, config.noCommWarnTime, false); + UPSMON_DIRECTIVEX("FINALDELAY", unsigned int, config.finalDelay, false); + + #undef UPSMON_DIRECTIVEX + + UpsmonConfiguration::NotifyType type; + + // Notify flags + type = UpsmonConfiguration::NOTIFY_ONLINE; + + for (; type < UpsmonConfiguration::NOTIFY_TYPE_MAX; ++type) { + if (config.notifyFlags[type].set()) { + std::string directive = serialiseNotifyFlags(type, config.notifyFlags[type]); + + status_t status = writeDirective(directive); + + if (NUTW_OK != status) + return status; + } + } + + // Notify messages + type = UpsmonConfiguration::NOTIFY_ONLINE; + + for (; type < UpsmonConfiguration::NOTIFY_TYPE_MAX; ++type) { + if (config.notifyMessages[type].set()) { + std::string directive = serialiseNotifyMessage(type, config.notifyMessages[type]); + + status_t status = writeDirective(directive); + + if (NUTW_OK != status) + return status; + } + } + + // Monitors + std::list::const_iterator mon_iter = config.monitors.begin(); + + for (; mon_iter != config.monitors.end(); ++mon_iter) { + std::string directive = serialiseMonitor(*mon_iter); + + status_t status = writeDirective(directive); + + if (NUTW_OK != status) + return status; + } - throw std::logic_error("FIXME: Not implemented, yet"); + return NUTW_OK; +} + + +/** + * \brief upsd listen address serialiser + * + * \param address Listen address + * + * \return Serialised listen address + */ +static std::string serialiseUpsdListenAddress(const UpsdConfiguration::Listen & address) { + std::stringstream directive("LISTEN "); + + directive << address.address; + + if (address.port.set()) + directive << ' ' << static_cast(address.port); + + return directive.str(); } NutWriter::status_t UpsdConfigWriter::writeConfig(const UpsdConfiguration & config) { - // TODO + /** + * \brief upsd directive generator + * + * The macro is locally used to simplify generation of + * upsd config. directives (except the listen addresses). + * + * NOTE that the macro may cause return from the function + * (upon writing error). + * See \ref CONFIG_DIRECTIVEX for more information. + * + * \param name Directive name + * \param arg_t Directive argument implementation type + * \param arg Directive argument + */ + #define UPSD_DIRECTIVEX(name, arg_t, arg) \ + CONFIG_DIRECTIVEX(name, arg_t, arg, false) + + UPSD_DIRECTIVEX("MAXAGE", unsigned int, config.maxAge); + UPSD_DIRECTIVEX("MAXCONN", unsigned int, config.maxConn); + UPSD_DIRECTIVEX("STATEPATH", std::string, config.statePath); + UPSD_DIRECTIVEX("CERTFILE", std::string, config.certFile); + + #undef UPSD_DIRECTIVEX + + // Listen addresses + std::list::const_iterator la_iter = config.listens.begin(); + + for (; la_iter != config.listens.end(); ++la_iter) { + std::string directive = serialiseUpsdListenAddress(*la_iter); + + status_t status = writeDirective(directive); + + if (NUTW_OK != status) + return status; + } - throw std::logic_error("FIXME: Not implemented, yet"); + return NUTW_OK; } diff --git a/include/nutconf.h b/include/nutconf.h index 6fae3ccb41..29e642cfeb 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -359,7 +359,7 @@ class NutConfiguration enum NutMode { MODE_UNKNOWN = -1, - MODE_NONE = 0, + MODE_NONE = 0, MODE_STANDALONE, MODE_NETSERVER, MODE_NETCLIENT From 5e9ae9235fe1a2cde0729fa16d0291f75a3e08bb Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Wed, 5 Dec 2012 14:12:17 +0100 Subject: [PATCH 024/121] UpsConfiguration class added to libnutconf Getters/setters for all UPS config. attributes added The getters/setters need further checking for type correctness Generic support for the above implemented in GenericConfiguration class --- common/nutconf.cpp | 172 +++++++++++++- common/nutwriter.cpp | 1 - include/nutconf.h | 522 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 692 insertions(+), 3 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index a401862ab8..d082633740 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -705,12 +705,183 @@ void GenericConfiguration::setGenericConfigSection(const GenericConfigSection& s sections[section.name] = section; } + void GenericConfiguration::parseFromString(const std::string& str) { GenericConfigParser parser(str); parser.parseConfig(this); } + +bool GenericConfiguration::get(const std::string & section, const std::string & entry, ConfigParamList & params) const +{ + // Get section + SectionMap::const_iterator section_iter = sections.find(section); + if (section_iter == sections.end()) + return false; + + // Get entry + const GenericConfigSection::EntryMap & entries = section_iter->second.entries; + + GenericConfigSection::EntryMap::const_iterator entry_iter = entries.find(entry); + if (entry_iter == entries.end()) + return false; + + // Provide parameters values + params = entry_iter->second.values; + + return true; +} + + +void GenericConfiguration::set(const std::string & section, const std::string & entry, const ConfigParamList & params) +{ + // Get section + SectionMap::iterator section_iter = sections.lower_bound(section); + if (sections.end() == section_iter || section_iter->first != section) { + section_iter = sections.insert(section_iter, + std::pair(section, GenericConfigSection())); + + section_iter->second.name = section; + } + + // Get entry + GenericConfigSection::EntryMap & entries = section_iter->second.entries; + + GenericConfigSection::EntryMap::iterator entry_iter = entries.lower_bound(entry); + if (entries.end() == entry_iter || entry_iter->first != entry) { + entry_iter = entries.insert(entry_iter, + std::pair(entry, GenericConfigSectionEntry())); + + entry_iter->second.name = entry; + } + + // Set parameters values + entry_iter->second.values = params; +} + + +void GenericConfiguration::remove(const std::string & section, const std::string & entry) +{ + // Get section + SectionMap::iterator section_iter = sections.find(section); + if (sections.end() == section_iter) + return; + + // Get entry + GenericConfigSection::EntryMap & entries = section_iter->second.entries; + + GenericConfigSection::EntryMap::iterator entry_iter = entries.find(entry); + if (entries.end() == entry_iter) + return; + + entries.erase(entry_iter); +} + + +void GenericConfiguration::removeSection(const std::string & section) +{ + // Get section + SectionMap::iterator section_iter = sections.find(section); + if (sections.end() == section_iter) + return; + + sections.erase(section_iter); +} + + +std::string GenericConfiguration::getStr(const std::string & section, const std::string & entry, bool quoted) const +{ + std::string str; + + ConfigParamList params; + + if (!get(section, entry, params)) + return str; + + if (params.empty()) + return str; + + str = params.front(); + + // Remove quotes + // TBD: what if they are not there? + if (quoted) { + if ('"' == str[0]) + str.erase(0, 1); + + if ('"' == str[str.size() - 1]) + str.erase(str.size() - 1); + } + + return str; +} + + +void GenericConfiguration::setStr( + const std::string & section, + const std::string & entry, + const std::string & value, + bool quoted) +{ + ConfigParamList param; + + // Add quotes if required + param.push_back(quoted ? '"' + value + '"' : value); + + set(section, entry, param); +} + + +long long int GenericConfiguration::getInt(const std::string & section, const std::string & entry, long long int val) const +{ + ConfigParamList params; + + if (!get(section, entry, params)) + return val; + + if (params.empty()) + return val; + + // TBD: What if there are multiple values? + std::stringstream val_str(params.front()); + + val_str >> val; + + return val; +} + + +void GenericConfiguration::setInt(const std::string & section, const std::string & entry, long long int val) +{ + std::stringstream val_str; + val_str << val; + + set(section, entry, ConfigParamList(1, val_str.str())); +} + + +bool GenericConfiguration::str2bool(const std::string & str) +{ + if ("true" == str) return true; + if ("on" == str) return true; + if ("1" == str) return true; + if ("yes" == str) return true; + if ("ok" == str) return true; + + return false; +} + + +const std::string & GenericConfiguration::bool2str(bool val) +{ + static const std::string b0("off"); + static const std::string b1("on"); + + return val ? b1 : b0; +} + + // // UpsmonConfiguration // @@ -1163,5 +1334,4 @@ void UpsdConfigParser::onParseEnd() // Do nothing } - } /* namespace nut */ diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index 35ec1d04c3..9a80b1e08a 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -600,5 +600,4 @@ NutWriter::status_t GenericConfigWriter::writeConfig(const GenericConfiguration return NUTW_OK; } - } // end of namespace nut diff --git a/include/nutconf.h b/include/nutconf.h index 29e642cfeb..49d63a7e3e 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -24,11 +24,13 @@ #include #include #include +#include #include #include #include #include +#include #ifdef __cplusplus @@ -278,7 +280,261 @@ class GenericConfiguration : public BaseConfiguration protected: virtual void setGenericConfigSection(const GenericConfigSection& section); -}; + + /** + * \brief Configuration parameters getter + * + * \param[in] section Section name + * \param[in] entry Entry name + * \param[out] params Configuration parameters + * + * \retval true if the entry was found + * \retval false otherwise + */ + bool get(const std::string & section, const std::string & entry, ConfigParamList & params) const; + + /** + * \brief Global scope configuration parameters getter + * + * \param[in] entry Entry name + * \param[out] params Configuration parameters + * + * \retval true if the entry was found + * \retval false otherwise + */ + inline bool get(const std::string & entry, ConfigParamList & params) const + { + return get("", entry, params); + } + + /** + * \brief Configuration parameters setter + * + * The section and entry are created unless they already exist. + * + * \param[in] section Section name + * \param[in] entry Entry name + * \param[in] params Configuration parameters + */ + void set(const std::string & section, const std::string & entry, const ConfigParamList & params); + + /** + * \brief Global scope configuration parameters setter + * + * The entry is created unless it already exists. + * + * \param[in] entry Entry name + * \param[in] params Configuration parameters + */ + inline void set(const std::string & entry, const ConfigParamList & params) + { + set("", entry, params); + } + + /** + * \brief Configuration parameters removal + * + * Removes the entry, only. + * Does nothing if the section or the entry don't exist. + * + * \param section Section name + * \param entry Entry name + */ + void remove(const std::string & section, const std::string & entry); + + /** + * \brief Global scope configuration parameters removal + * + * Removes the entry, only. + * Does nothing if the entry don't exist. + * + * \param entry Entry name + */ + inline void remove(const std::string & entry) + { + remove("", entry); + } + + /** + * \brief Configuration section removal + * + * Removes entire section (if exists). + * + * \param section Section name + */ + void removeSection(const std::string & section); + + /** Global scope configuration removal */ + inline void removeGlobal() + { + removeSection(""); + } + + /** + * \brief Configuration string getter + * + * Empty string is returned if the section or entry doesn't exist. + * + * \param section Section name + * \param entry Entry name + * \param quoted \c true iff the value is quoted + * + * \return Configuration parameter as string + */ + std::string getStr( + const std::string & section, + const std::string & entry, + bool quoted = false) const; + + /** + * \brief Global scope configuration string getter + * + * Empty string is returned if the entry doesn't exist. + * + * \param entry Entry name + * \param quoted \c true iff the value is quoted + * + * \return Configuration parameter as string + */ + inline std::string getStr(const std::string & entry, bool quoted = false) const + { + return getStr("", entry, quoted); + } + + /** + * \brief Configuration string setter + * + * \param section Section name + * \param entry Entry name + * \param value Parameter value + * \param quoted \c true iff the value is quoted + */ + void setStr( + const std::string & section, + const std::string & entry, + const std::string & value, + bool quoted = false); + + /** + * \brief Global scope configuration string setter + * + * \param entry Entry name + * \param value Parameter value + * \param quoted \c true iff the value is quoted + */ + inline void setStr( + const std::string & entry, + const std::string & value, + bool quoted = false) + { + setStr("", entry, value, quoted); + } + + /** + * \brief Configuration number getter + * + * \param section Section name + * \param entry Entry name + * \param val Default value + * + * \return Configuration parameter as number (or the default if not defined) + */ + long long int getInt( + const std::string & section, + const std::string & entry, + long long int val = 0) const; + + /** + * \brief Global scope configuration number getter + * + * \param entry Entry name + * \param val Default value + * + * \return Configuration parameter as number (or the default if not defined) + */ + inline long long int getInt(const std::string & entry, long long int val = 0) const + { + return getInt("", entry, val); + } + + /** + * \brief Configuration number setter + * + * \param section Section name + * \param entry Entry name + * \param val Default value + */ + void setInt( + const std::string & section, + const std::string & entry, + long long int val); + + /** + * \brief Global scope configuration number setter + * + * \param entry Entry name + * \param val Default value + */ + inline void setInt( + const std::string & entry, + long long int val) + { + setInt("", entry, val); + } + + /** + * \brief Cast numeric type with range check + * + * Throws an exception on cast error. + * + * \param number Number + * \param min Minimum + * \param max Maximum + * + * \return \c number casted to target type + */ + template + static T range_cast(long long int number, long long int min, long long int max) throw(std::range_error) + { + if (number < min) + { + std::stringstream e; + e << "Failed to range-cast " << number << " (underflows " << min << ')'; + + throw std::range_error(e.str()); + } + + if (number > max) + { + std::stringstream e; + e << "Failed to range-cast " << number << " (overflows " << max << ')'; + + throw std::range_error(e.str()); + } + + return static_cast(number); + } + + /** + * \brief Resolve string as Boolean value + * + * \param str String + * + * \retval true iff the string expresses a known true value + * \retval false otherwise + */ + static bool str2bool(const std::string & str); + + /** + * \brief Convert boolean value to string + * + * \param val Boolean value + * + * \return \c vla as string + */ + static const std::string & bool2str(bool val); + +}; // end of class GenericConfiguration @@ -431,6 +687,270 @@ class UpsdConfigParser : public NutConfigParser UpsdConfiguration* _config; }; + +/** UPS configuration */ +class UpsConfiguration : public GenericConfiguration +{ +public: + /** Global configuration attributes getters and setters \{ */ + + inline std::string getChroot() const { return getStr("chroot", true); } + inline std::string getDriverPath() const { return getStr("driverpath", true); } + inline std::string getUser() const { return getStr("user", false); } + + inline long long int getMaxStartDelay() const { return getInt("maxstartdelay"); } + inline long long int getPollInterval() const { return getInt("pollinterval", 5); } // TODO: check the default + + inline void setChroot(const std::string & path) { setStr("chroot", path, true); } + inline void setDriverPath(const std::string & path) { setStr("driverpath", path, true); } + inline void setUser(const std::string & user) { setStr("user", user, false); } + + inline void setMaxStartDelay(long long int delay) { setInt("maxstartdelay", delay); } + inline void setPollInterval(long long int interval) { setInt("pollinterval", interval); } + + /** \} */ + + /** UPS-specific configuration attributes getters and setters \{ */ + inline std::string getDriver(const std::string & ups) const { return getStr(ups, "driver", false); } + inline std::string getDescription(const std::string & ups) const { return getStr(ups, "desc", true); } + inline std::string getCP(const std::string & ups) const { return getStr(ups, "CP", false); } + inline std::string getCS(const std::string & ups) const { return getStr(ups, "CS", false); } + inline std::string getID(const std::string & ups) const { return getStr(ups, "ID", false); } + inline std::string getLB(const std::string & ups) const { return getStr(ups, "LB", false); } + inline std::string getLowBatt(const std::string & ups) const { return getStr(ups, "LowBatt", false); } // CHECKME + inline std::string getOL(const std::string & ups) const { return getStr(ups, "OL", false); } // CHECKME + inline std::string getSD(const std::string & ups) const { return getStr(ups, "SD", false); } // CHECKME + inline std::string getAuthPassword(const std::string & ups) const { return getStr(ups, "authPassword", false); } // CHECKME + inline std::string getAuthProtocol(const std::string & ups) const { return getStr(ups, "authProtocol", false); } // CHECKME + inline std::string getAuthType(const std::string & ups) const { return getStr(ups, "authtype", false); } // CHECKME + inline std::string getAWD(const std::string & ups) const { return getStr(ups, "awd", false); } // CHECKME + inline std::string getBatText(const std::string & ups) const { return getStr(ups, "battext", true); } // CHECKME + inline std::string getBus(const std::string & ups) const { return getStr(ups, "bus", false); } // CHECKME + inline std::string getCommunity(const std::string & ups) const { return getStr(ups, "community", false); } // CHECKME + inline std::string getFRUID(const std::string & ups) const { return getStr(ups, "fruid", false); } // CHECKME + inline std::string getLoadStatus(const std::string & ups) const { return getStr(ups, "load.status", false); } // CHECKME + inline std::string getLogin(const std::string & ups) const { return getStr(ups, "login", false); } // CHECKME + inline std::string getLowbatt(const std::string & ups) const { return getStr(ups, "lowbatt", false); } // CHECKME + inline std::string getManufacturer(const std::string & ups) const { return getStr(ups, "manufacturer", true); } // CHECKME + inline std::string getMethodOfFlowControl(const std::string & ups) const { return getStr(ups, "methodOfFlowControl", false); } // CHECKME + inline std::string getMIBs(const std::string & ups) const { return getStr(ups, "mibs", false); } // CHECKME + inline std::string getModel(const std::string & ups) const { return getStr(ups, "model", true); } // CHECKME + inline std::string getModelName(const std::string & ups) const { return getStr(ups, "modelname", true); } // CHECKME + inline std::string getNotification(const std::string & ups) const { return getStr(ups, "notification", false); } // CHECKME + inline std::string getOldMAC(const std::string & ups) const { return getStr(ups, "oldmac", false); } // CHECKME + inline std::string getPassword(const std::string & ups) const { return getStr(ups, "password", false); } // CHECKME + inline std::string getPrefix(const std::string & ups) const { return getStr(ups, "prefix", true); } // CHECKME + inline std::string getPrivPassword(const std::string & ups) const { return getStr(ups, "privPassword", false); } // CHECKME + inline std::string getPrivProtocol(const std::string & ups) const { return getStr(ups, "privProtocol", false); } // CHECKME + inline std::string getProduct(const std::string & ups) const { return getStr(ups, "product", true); } // CHECKME + inline std::string getProductID(const std::string & ups) const { return getStr(ups, "productid", false); } // CHECKME + inline std::string getProtocol(const std::string & ups) const { return getStr(ups, "protocol", false); } // CHECKME + inline std::string getRuntimeCal(const std::string & ups) const { return getStr(ups, "runtimecal", false); } // CHECKME + inline std::string getSDType(const std::string & ups) const { return getStr(ups, "sdtype", false); } // CHECKME + inline std::string getSecLevel(const std::string & ups) const { return getStr(ups, "secLevel", false); } // CHECKME + inline std::string getSecName(const std::string & ups) const { return getStr(ups, "secName", true); } // CHECKME + inline std::string getSensorID(const std::string & ups) const { return getStr(ups, "sensorid", false); } // CHECKME + inline std::string getSerial(const std::string & ups) const { return getStr(ups, "serial", false); } // CHECKME + inline std::string getSerialNumber(const std::string & ups) const { return getStr(ups, "serialnumber", false); } // CHECKME + inline std::string getShutdownArguments(const std::string & ups) const { return getStr(ups, "shutdownArguments", false); } // CHECKME + inline std::string getSNMPversion(const std::string & ups) const { return getStr(ups, "snmp_version", false); } // CHECKME + inline std::string getSubdriver(const std::string & ups) const { return getStr(ups, "subdriver", false); } // CHECKME + inline std::string getType(const std::string & ups) const { return getStr(ups, "type", false); } // CHECKME + inline std::string getUPStype(const std::string & ups) const { return getStr(ups, "upstype", false); } // CHECKME + inline std::string getUSD(const std::string & ups) const { return getStr(ups, "usd", false); } // CHECKME + inline std::string getUsername(const std::string & ups) const { return getStr(ups, "username", false); } // CHECKME + inline std::string getValidationSequence(const std::string & ups) const { return getStr(ups, "validationSequence", false); } // CHECKME + inline std::string getVendor(const std::string & ups) const { return getStr(ups, "vendor", true); } // CHECKME + inline std::string getVendorID(const std::string & ups) const { return getStr(ups, "vendorid", false); } // CHECKME + inline std::string getWUGrace(const std::string & ups) const { return getStr(ups, "wugrace", false); } // CHECKME + + + inline uint16_t getPort(const std::string & ups) const { return range_cast(getInt(ups, "port"), 0, 65535); } // TBD: Any default? + inline long long int getSDOrder(const std::string & ups) const { return getInt(ups, "sdorder"); } // TODO: Is that a number? + inline long long int getMaxStartDelay(const std::string & ups) const { return getInt(ups, "maxstartdelay"); } + inline long long int getAdvOrder(const std::string & ups) const { return getInt(ups, "advorder"); } // CHECKME + inline long long int getBatteryPercentage(const std::string & ups) const { return getInt(ups, "batteryPercentage"); } // CHECKME + inline long long int getOffDelay(const std::string & ups) const { return getInt(ups, "OffDelay"); } // CHECKME + inline long long int getOnDelay(const std::string & ups) const { return getInt(ups, "OnDelay"); } // CHECKME + inline long long int getBattVoltMult(const std::string & ups) const { return getInt(ups, "battvoltmult"); } // CHECKME + inline long long int getBaudRate(const std::string & ups) const { return getInt(ups, "baud_rate"); } // CHECKME + inline long long int getBaudrate(const std::string & ups) const { return getInt(ups, "baudrate"); } // CHECKME + inline long long int getCablePower(const std::string & ups) const { return getInt(ups, "cablepower"); } // CHECKME + inline long long int getChargeTime(const std::string & ups) const { return getInt(ups, "chargetime"); } // CHECKME + inline long long int getDaysOff(const std::string & ups) const { return getInt(ups, "daysoff"); } // CHECKME + inline long long int getDaySweek(const std::string & ups) const { return getInt(ups, "daysweek"); } // CHECKME + inline long long int getFrequency(const std::string & ups) const { return getInt(ups, "frequency"); } // CHECKME + inline long long int getHourOff(const std::string & ups) const { return getInt(ups, "houroff"); } // CHECKME + inline long long int getHourOn(const std::string & ups) const { return getInt(ups, "houron"); } // CHECKME + inline long long int getIdleLoad(const std::string & ups) const { return getInt(ups, "idleload"); } // CHECKME + inline long long int getInputTimeout(const std::string & ups) const { return getInt(ups, "input_timeout"); } // CHECKME + inline long long int getLineVoltage(const std::string & ups) const { return getInt(ups, "linevoltage"); } // CHECKME + inline long long int getLoadpercentage(const std::string & ups) const { return getInt(ups, "loadPercentage"); } // CHECKME + inline long long int getMaxLoad(const std::string & ups) const { return getInt(ups, "max_load"); } // CHECKME + inline long long int getMFR(const std::string & ups) const { return getInt(ups, "mfr"); } // CHECKME + inline long long int getMinCharge(const std::string & ups) const { return getInt(ups, "mincharge"); } // CHECKME + inline long long int getMinRuntime(const std::string & ups) const { return getInt(ups, "minruntime"); } // CHECKME + inline long long int getNomBattVolt(const std::string & ups) const { return getInt(ups, "nombattvolt"); } // CHECKME + inline long long int getNumOfBytesFromUPS(const std::string & ups) const { return getInt(ups, "numOfBytesFromUPS"); } // CHECKME + inline long long int getOffdelay(const std::string & ups) const { return getInt(ups, "offdelay"); } // CHECKME + inline long long int getOndelay(const std::string & ups) const { return getInt(ups, "ondelay"); } // CHECKME + inline long long int getOutputPace(const std::string & ups) const { return getInt(ups, "output_pace"); } // CHECKME + inline long long int getPollFreq(const std::string & ups) const { return getInt(ups, "pollfreq"); } // CHECKME + inline long long int getPowerUp(const std::string & ups) const { return getInt(ups, "powerup"); } // CHECKME + inline long long int getPrgShut(const std::string & ups) const { return getInt(ups, "prgshut"); } // CHECKME + inline long long int getRebootDelay(const std::string & ups) const { return getInt(ups, "rebootdelay"); } // CHECKME + inline long long int getSDtime(const std::string & ups) const { return getInt(ups, "sdtime"); } // CHECKME + inline long long int getShutdownDelay(const std::string & ups) const { return getInt(ups, "shutdown_delay"); } // CHECKME + inline long long int getStartDelay(const std::string & ups) const { return getInt(ups, "startdelay"); } // CHECKME + inline long long int getTestTime(const std::string & ups) const { return getInt(ups, "testtime"); } // CHECKME + inline long long int getTimeout(const std::string & ups) const { return getInt(ups, "timeout"); } // CHECKME + inline long long int getUPSdelayShutdown(const std::string & ups) const { return getInt(ups, "ups.delay.shutdown"); } // CHECKME + inline long long int getUPSdelayStart(const std::string & ups) const { return getInt(ups, "ups.delay.start"); } // CHECKME + inline long long int getVoltage(const std::string & ups) const { return getInt(ups, "voltage"); } // CHECKME + inline long long int getWait(const std::string & ups) const { return getInt(ups, "wait"); } // CHECKME + + inline bool getNolock(const std::string & ups) const { return str2bool(getStr(ups, "nolock", false)); } // TODO: check whether it's indeed boolean + inline bool getCable(const std::string & ups) const { return str2bool(getStr(ups, "cable", false)); } // CHECKME + inline bool getDumbTerm(const std::string & ups) const { return str2bool(getStr(ups, "dumbterm", false)); } // CHECKME + inline bool getExplore(const std::string & ups) const { return str2bool(getStr(ups, "explore", false)); } // CHECKME + inline bool getFakeLowBatt(const std::string & ups) const { return str2bool(getStr(ups, "fake_lowbatt", false)); } // CHECKME + inline bool getFlash(const std::string & ups) const { return str2bool(getStr(ups, "flash", false)); } // CHECKME + inline bool getFullUpdate(const std::string & ups) const { return str2bool(getStr(ups, "full_update", false)); } // CHECKME + inline bool getLangIDfix(const std::string & ups) const { return str2bool(getStr(ups, "langid_fix", false)); } // CHECKME + inline bool getLoadOff(const std::string & ups) const { return str2bool(getStr(ups, "load.off", false)); } // CHECKME + inline bool getLoadOn(const std::string & ups) const { return str2bool(getStr(ups, "load.on", false)); } // CHECKME + inline bool getNoHang(const std::string & ups) const { return str2bool(getStr(ups, "nohang", false)); } // CHECKME + inline bool getNoRating(const std::string & ups) const { return str2bool(getStr(ups, "norating", false)); } // CHECKME + inline bool getNoTransferOIDs(const std::string & ups) const { return str2bool(getStr(ups, "notransferoids", false)); } // CHECKME + inline bool getNoVendor(const std::string & ups) const { return str2bool(getStr(ups, "novendor", false)); } // CHECKME + inline bool getNoWarnNoImp(const std::string & ups) const { return str2bool(getStr(ups, "nowarn_noimp", false)); } // CHECKME + inline bool getPollOnly(const std::string & ups) const { return str2bool(getStr(ups, "pollonly", false)); } // CHECKME + inline bool getSilent(const std::string & ups) const { return str2bool(getStr(ups, "silent", false)); } // CHECKME + inline bool getStatusOnly(const std::string & ups) const { return str2bool(getStr(ups, "status_only", false)); } // CHECKME + inline bool getSubscribe(const std::string & ups) const { return str2bool(getStr(ups, "subscribe", false)); } // CHECKME + inline bool getUseCRLF(const std::string & ups) const { return str2bool(getStr(ups, "use_crlf", false)); } // CHECKME + inline bool getUsePreLF(const std::string & ups) const { return str2bool(getStr(ups, "use_pre_lf", false)); } // CHECKME + + + inline void setDriver(const std::string & ups, const std::string & driver) { setStr(ups, "driver", driver, false); } + inline void setDescription(const std::string & ups, const std::string & desc) { setStr(ups, "desc", desc, true); } + inline void setLowBatt(const std::string & ups, const std::string & lowbatt) { setStr(ups, "LowBatt", lowbatt, false); } // CHECKME + inline void setOL(const std::string & ups, const std::string & ol) { setStr(ups, "OL", ol, false); } // CHECKME + inline void setSD(const std::string & ups, const std::string & sd) { setStr(ups, "SD", sd, false); } // CHECKME + inline void setAuthPassword(const std::string & ups, const std::string & auth_passwd) { setStr(ups, "authPassword", auth_passwd, false); } // CHECKME + inline void setAuthProtocol(const std::string & ups, const std::string & auth_proto) { setStr(ups, "authProtocol", auth_proto, false); } // CHECKME + inline void setAuthType(const std::string & ups, const std::string & authtype) { setStr(ups, "authtype", authtype, false); } // CHECKME + inline void setAWD(const std::string & ups, const std::string & awd) { setStr(ups, "awd", awd, false); } // CHECKME + inline void setBatText(const std::string & ups, const std::string & battext) { setStr(ups, "battext", battext, false); } // CHECKME + inline void setBus(const std::string & ups, const std::string & bus) { setStr(ups, "bus", bus, false); } // CHECKME + inline void setCommunity(const std::string & ups, const std::string & community) { setStr(ups, "community", community, false); } // CHECKME + inline void setFRUID(const std::string & ups, const std::string & fruid) { setStr(ups, "fruid", fruid, false); } // CHECKME + inline void setLoadStatus(const std::string & ups, const std::string & load_status) { setStr(ups, "load.status", load_status, false); } // CHECKME + inline void setLogin(const std::string & ups, const std::string & login) { setStr(ups, "login", login, false); } // CHECKME + inline void setLowbatt(const std::string & ups, const std::string & lowbatt) { setStr(ups, "lowbatt", lowbatt, false); } // CHECKME + inline void setManufacturer(const std::string & ups, const std::string & manufacturer) { setStr(ups, "manufacturer", manufacturer, false); } // CHECKME + inline void setMethodOfFlowControl(const std::string & ups, const std::string & method) { setStr(ups, "methodOfFlowControl", method, false); } // CHECKME + inline void setMIBs(const std::string & ups, const std::string & mibs) { setStr(ups, "mibs", mibs, false); } // CHECKME + inline void setModel(const std::string & ups, const std::string & model) { setStr(ups, "model", model, false); } // CHECKME + inline void setModelName(const std::string & ups, const std::string & modelname) { setStr(ups, "modelname", modelname, false); } // CHECKME + inline void setNotification(const std::string & ups, const std::string & notification) { setStr(ups, "notification", notification, false); } // CHECKME + inline void setOldMAC(const std::string & ups, const std::string & oldmac) { setStr(ups, "oldmac", oldmac, false); } // CHECKME + inline void setPassword(const std::string & ups, const std::string & password) { setStr(ups, "password", password, false); } // CHECKME + inline void setPrefix(const std::string & ups, const std::string & prefix) { setStr(ups, "prefix", prefix, false); } // CHECKME + inline void setPrivPassword(const std::string & ups, const std::string & priv_passwd) { setStr(ups, "privPassword", priv_passwd, false); } // CHECKME + inline void setPrivProtocol(const std::string & ups, const std::string & priv_proto) { setStr(ups, "privProtocol", priv_proto, false); } // CHECKME + inline void setProduct(const std::string & ups, const std::string & product) { setStr(ups, "product", product, false); } // CHECKME + inline void setProductID(const std::string & ups, const std::string & productid) { setStr(ups, "productid", productid, false); } // CHECKME + inline void setProtocol(const std::string & ups, const std::string & protocol) { setStr(ups, "protocol", protocol, false); } // CHECKME + inline void setRuntimeCal(const std::string & ups, const std::string & runtimecal) { setStr(ups, "runtimecal", runtimecal, false); } // CHECKME + inline void setSDtype(const std::string & ups, const std::string & sdtype) { setStr(ups, "sdtype", sdtype, false); } // CHECKME + inline void setSecLevel(const std::string & ups, const std::string & sec_level) { setStr(ups, "secLevel", sec_level, false); } // CHECKME + inline void setSecName(const std::string & ups, const std::string & sec_name) { setStr(ups, "secName", sec_name, false); } // CHECKME + inline void setSensorID(const std::string & ups, const std::string & sensorid) { setStr(ups, "sensorid", sensorid, false); } // CHECKME + inline void setSerial(const std::string & ups, const std::string & serial) { setStr(ups, "serial", serial, false); } // CHECKME + inline void setSerialNumber(const std::string & ups, const std::string & serialnumber) { setStr(ups, "serialnumber", serialnumber, false); } // CHECKME + inline void setShutdownArguments(const std::string & ups, const std::string & sd_args) { setStr(ups, "shutdownArguments", sd_args, false); } // CHECKME + inline void setSNMPversion(const std::string & ups, const std::string & snmp_version) { setStr(ups, "snmp_version", snmp_version, false); } // CHECKME + inline void setSubdriver(const std::string & ups, const std::string & subdriver) { setStr(ups, "subdriver", subdriver, false); } // CHECKME + inline void setType(const std::string & ups, const std::string & type) { setStr(ups, "type", type, false); } // CHECKME + inline void setUPStype(const std::string & ups, const std::string & upstype) { setStr(ups, "upstype", upstype, false); } // CHECKME + inline void setUSD(const std::string & ups, const std::string & usd) { setStr(ups, "usd", usd, false); } // CHECKME + inline void setUsername(const std::string & ups, const std::string & username) { setStr(ups, "username", username, false); } // CHECKME + inline void setValidationSequence(const std::string & ups, const std::string & valid_seq) { setStr(ups, "validationSequence", valid_seq, false); } // CHECKME + inline void setVendor(const std::string & ups, const std::string & vendor) { setStr(ups, "vendor", vendor, false); } // CHECKME + inline void setVendorID(const std::string & ups, const std::string & vendorid) { setStr(ups, "vendorid", vendorid, false); } // CHECKME + inline void setWUGrace(const std::string & ups, const std::string & wugrace) { setStr(ups, "wugrace", wugrace, false); } // CHECKME + + inline void setPort(const std::string & ups, uint16_t port) { setInt(ups, "port", port); } + inline void setSDOrder(const std::string & ups, long long int ord) { setInt(ups, "sdorder", ord); } + inline void setMaxStartDelay(const std::string & ups, long long int delay) { setInt(ups, "maxstartdelay", delay); } + inline void setADVorder(const std::string & ups, long long int advorder) { setInt(ups, "advorder", advorder); } // CHECKME + inline void setBatteryPercentage(const std::string & ups, long long int batt) { setInt(ups, "batteryPercentage", batt); } // CHECKME + inline void setOffDelay(const std::string & ups, long long int offdelay) { setInt(ups, "OffDelay", offdelay); } // CHECKME + inline void setOnDelay(const std::string & ups, long long int ondelay) { setInt(ups, "OnDelay", ondelay); } // CHECKME + inline void setBattVoltMult(const std::string & ups, long long int mult) { setInt(ups, "battvoltmult", mult); } // CHECKME + inline void setBaudRate(const std::string & ups, long long int baud_rate) { setInt(ups, "baud_rate", baud_rate); } // CHECKME + inline void setBaudrate(const std::string & ups, long long int baudrate) { setInt(ups, "baudrate", baudrate); } // CHECKME + inline void setCablePower(const std::string & ups, long long int cablepower) { setInt(ups, "cablepower", cablepower); } // CHECKME + inline void setChargeTime(const std::string & ups, long long int chargetime) { setInt(ups, "chargetime", chargetime); } // CHECKME + inline void setDaysOff(const std::string & ups, long long int daysoff) { setInt(ups, "daysoff", daysoff); } // CHECKME + inline void setDaysWeek(const std::string & ups, long long int daysweek) { setInt(ups, "daysweek", daysweek); } // CHECKME + inline void setFrequency(const std::string & ups, long long int frequency) { setInt(ups, "frequency", frequency); } // CHECKME + inline void setHourOff(const std::string & ups, long long int houroff) { setInt(ups, "houroff", houroff); } // CHECKME + inline void setHourOn(const std::string & ups, long long int houron) { setInt(ups, "houron", houron); } // CHECKME + inline void setIdleLoad(const std::string & ups, long long int idleload) { setInt(ups, "idleload", idleload); } // CHECKME + inline void setInputTimeout(const std::string & ups, long long int timeout) { setInt(ups, "input_timeout", timeout); } // CHECKME + inline void setLineVoltage(const std::string & ups, long long int linevoltage) { setInt(ups, "linevoltage", linevoltage); } // CHECKME + inline void setLoadpercentage(const std::string & ups, long long int load) { setInt(ups, "loadPercentage", load); } // CHECKME + inline void setMaxLoad(const std::string & ups, long long int max_load) { setInt(ups, "max_load", max_load); } // CHECKME + inline void setMFR(const std::string & ups, long long int mfr) { setInt(ups, "mfr", mfr); } // CHECKME + inline void setMinCharge(const std::string & ups, long long int mincharge) { setInt(ups, "mincharge", mincharge); } // CHECKME + inline void setMinRuntime(const std::string & ups, long long int minruntime) { setInt(ups, "minruntime", minruntime); } // CHECKME + inline void setNomBattVolt(const std::string & ups, long long int nombattvolt) { setInt(ups, "nombattvolt", nombattvolt); } // CHECKME + inline void setNumOfBytesFromUPS(const std::string & ups, long long int bytes) { setInt(ups, "numOfBytesFromUPS", bytes); } // CHECKME + inline void setOffdelay(const std::string & ups, long long int offdelay) { setInt(ups, "offdelay", offdelay); } // CHECKME + inline void setOndelay(const std::string & ups, long long int ondelay) { setInt(ups, "ondelay", ondelay); } // CHECKME + inline void setOutputPace(const std::string & ups, long long int output_pace) { setInt(ups, "output_pace", output_pace); } // CHECKME + inline void setPollFreq(const std::string & ups, long long int pollfreq) { setInt(ups, "pollfreq", pollfreq); } // CHECKME + inline void setPowerUp(const std::string & ups, long long int powerup) { setInt(ups, "powerup", powerup); } // CHECKME + inline void setPrgShut(const std::string & ups, long long int prgshut) { setInt(ups, "prgshut", prgshut); } // CHECKME + inline void setRebootDelay(const std::string & ups, long long int delay) { setInt(ups, "rebootdelay", delay); } // CHECKME + inline void setSDtime(const std::string & ups, long long int sdtime) { setInt(ups, "sdtime", sdtime); } // CHECKME + inline void setShutdownDelay(const std::string & ups, long long int delay) { setInt(ups, "shutdown_delay", delay); } // CHECKME + inline void setStartDelay(const std::string & ups, long long int delay) { setInt(ups, "startdelay", delay); } // CHECKME + inline void setTestTime(const std::string & ups, long long int testtime) { setInt(ups, "testtime", testtime); } // CHECKME + inline void setTimeout(const std::string & ups, long long int timeout) { setInt(ups, "timeout", timeout); } // CHECKME + inline void setUPSdelayShutdown(const std::string & ups, long long int delay) { setInt(ups, "ups.delay.shutdown", delay); } // CHECKME + inline void setUPSdelayStart(const std::string & ups, long long int delay) { setInt(ups, "ups.delay.start", delay); } // CHECKME + inline void setVoltage(const std::string & ups, long long int voltage) { setInt(ups, "voltage", voltage); } // CHECKME + inline void setWait(const std::string & ups, long long int wait) { setInt(ups, "wait", wait); } // CHECKME + + inline void setNolock(const std::string & ups, bool set = true) { setStr(ups, "nolock", bool2str(set), false); } + inline void setCable(const std::string & ups, bool set = true) { setStr(ups, "cable", bool2str(set), false); } // CHECKME + inline void setDumbTerm(const std::string & ups, bool set = true) { setStr(ups, "dumbterm", bool2str(set), false); } // CHECKME + inline void setExplore(const std::string & ups, bool set = true) { setStr(ups, "explore", bool2str(set), false); } // CHECKME + inline void setFakeLowBatt(const std::string & ups, bool set = true) { setStr(ups, "fake_lowbatt", bool2str(set), false); } // CHECKME + inline void setFlash(const std::string & ups, bool set = true) { setStr(ups, "flash", bool2str(set), false); } // CHECKME + inline void setFullUpdate(const std::string & ups, bool set = true) { setStr(ups, "full_update", bool2str(set), false); } // CHECKME + inline void setLangIDfix(const std::string & ups, bool set = true) { setStr(ups, "langid_fix", bool2str(set), false); } // CHECKME + inline void setLoadOff(const std::string & ups, bool set = true) { setStr(ups, "load.off", bool2str(set), false); } // CHECKME + inline void setLoadOn(const std::string & ups, bool set = true) { setStr(ups, "load.on", bool2str(set), false); } // CHECKME + inline void setNoHang(const std::string & ups, bool set = true) { setStr(ups, "nohang", bool2str(set), false); } // CHECKME + inline void setNoRating(const std::string & ups, bool set = true) { setStr(ups, "norating", bool2str(set), false); } // CHECKME + inline void setNoTransferOIDs(const std::string & ups, bool set = true) { setStr(ups, "notransferoids", bool2str(set), false); } // CHECKME + inline void setNoVendor(const std::string & ups, bool set = true) { setStr(ups, "novendor", bool2str(set), false); } // CHECKME + inline void setNoWarnNoImp(const std::string & ups, bool set = true) { setStr(ups, "nowarn_noimp", bool2str(set), false); } // CHECKME + inline void setPollOnly(const std::string & ups, bool set = true) { setStr(ups, "pollonly", bool2str(set), false); } // CHECKME + inline void setSilent(const std::string & ups, bool set = true) { setStr(ups, "silent", bool2str(set), false); } // CHECKME + inline void setStatusOnly(const std::string & ups, bool set = true) { setStr(ups, "status_only", bool2str(set), false); } // CHECKME + inline void setSubscribe(const std::string & ups, bool set = true) { setStr(ups, "subscribe", bool2str(set), false); } // CHECKME + inline void setUseCRLF(const std::string & ups, bool set = true) { setStr(ups, "use_crlf", bool2str(set), false); } // CHECKME + inline void setUsePreLF(const std::string & ups, bool set = true) { setStr(ups, "use_pre_lf", bool2str(set), false); } // CHECKME + + /** \} */ + +}; // end of class UpsConfiguration + } /* namespace nut */ #endif /* __cplusplus */ #endif /* NUTCONF_H_SEEN */ From a5da45639c9522e5b57d16b5885e321d577a8b69 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Thu, 6 Dec 2012 13:34:32 +0100 Subject: [PATCH 025/121] Special serialiser for upsd.users config file The special serialiser is needed because of the [upsmon]::upsmon directive (which doesn't use the standard = key/ value separator). Also, serialisation of section entry value list was fixed (so that multiple entries are produced rather than a list of values). --- common/nutwriter.cpp | 76 +++++++++++++++++++++++++++++++++----------- include/nutwriter.h | 38 ++++++++++++++++++++++ 2 files changed, 95 insertions(+), 19 deletions(-) diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index 9a80b1e08a..ef5892105d 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -528,11 +528,25 @@ NutWriter::status_t DefaultConfigWriter::writeDirective(const std::string & str) } -NutWriter::status_t GenericConfigWriter::writeSection(const GenericConfigSection & section) { - // TBD: Shouldn't this be somewhere else? - // The parser has to use this, either... - static const std::string value_separator(", "); +NutWriter::status_t GenericConfigWriter::writeSectionEntry( + const GenericConfigSectionEntry & entry, + const std::string & indent, + const std::string & kv_sep) +{ + ConfigParamList::const_iterator value_iter = entry.values.begin(); + + for (; value_iter != entry.values.end(); ++value_iter) { + status_t status = writeDirective(indent + entry.name + kv_sep + *value_iter); + + if (NUTW_OK != status) + return status; + } + + return NUTW_OK; +} + +NutWriter::status_t GenericConfigWriter::writeSection(const GenericConfigSection & section) { status_t status; // Note that global scope definitions are in section @@ -554,21 +568,7 @@ NutWriter::status_t GenericConfigWriter::writeSection(const GenericConfigSection GenericConfigSection::EntryMap::const_iterator entry_iter = section.entries.begin(); for (; entry_iter != section.entries.end(); ++entry_iter) { - std::string assign(indent); - assign += entry_iter->second.name + " = "; - - const ConfigParamList & values(entry_iter->second.values); - - ConfigParamList::const_iterator value_iter = values.begin(); - - for (; value_iter != values.end(); ++value_iter) { - if (value_iter != values.begin()) - assign += value_separator; - - assign += *value_iter; - } - - status = writeDirective(assign); + status = writeSectionEntry(entry_iter->second, indent); if (NUTW_OK != status) return status; @@ -600,4 +600,42 @@ NutWriter::status_t GenericConfigWriter::writeConfig(const GenericConfiguration return NUTW_OK; } + +NutWriter::status_t UpsdUsersConfigWriter::writeSection(const GenericConfigSection & section) { + static const std::string upsmon_entry_separator(" "); + + status_t status; + + // upsmon section requires special handling because of the upsmon (master|slave) directive + if ("upsmon" != section.name) + return GenericConfigWriter::writeSection(section); + + status = writeSectionName(section.name); + + if (NUTW_OK != status) + return status; + + // Write section name/value pairs + GenericConfigSection::EntryMap::const_iterator entry_iter = section.entries.begin(); + + for (; entry_iter != section.entries.end(); ++entry_iter) { + // Special case of upsmon parameter + if ("upsmon" == entry_iter->second.name) { + status = writeSectionEntry(entry_iter->second, + s_default_section_entry_indent, + upsmon_entry_separator); + } + + // Standard entry serialisation + else { + status = writeSectionEntry(entry_iter->second); + } + + if (NUTW_OK != status) + return status; + } + + return NUTW_OK; +} + } // end of namespace nut diff --git a/include/nutwriter.h b/include/nutwriter.h index 6e89fa12fe..3ad9f72d7b 100644 --- a/include/nutwriter.h +++ b/include/nutwriter.h @@ -287,6 +287,29 @@ class DefaultConfigWriter: public NutConfigWriter { * and adds \c writeConfig routine for configuration file serialisation. */ class GenericConfigWriter: public DefaultConfigWriter { + protected: + + /** Default indentation of the key/ value pair in section entry */ + static const std::string s_default_section_entry_indent; + + /** Default separator of the key/ value pair in section entry */ + static const std::string s_default_section_entry_separator; + + /** + * \brief Section entry serialiser + * + * \param entry Section entry + * \param indent Indentation + * \param kv_sep Key/ value separator + * + * \retval NUTW_OK on success + * \retval NUTW_ERROR otherwise + */ + status_t writeSectionEntry( + const GenericConfigSectionEntry & entry, + const std::string & indent = s_default_section_entry_indent, + const std::string & kv_sep = s_default_section_entry_separator); + public: // Section serialiser implementation @@ -305,6 +328,21 @@ class GenericConfigWriter: public DefaultConfigWriter { }; // end of class GenericConfigWriter +/** + * \brief NUT upsd.users configuration file writer + * + * upsd.users configuration file serialiser. + * Overloads the generic section serialiser because of the upsmon section, + * which contains anomal upsmon (master|slave) directive. + */ +class UpsdUsersConfigWriter: public GenericConfigWriter { + public: + + // Section serialiser overload + status_t writeSection(const GenericConfigSection & section); + +}; // end of class UpsdUsersConfigWriter + } // end of namespace nut #endif /* __cplusplus */ From 3d8c92c41839df17e9b3b075a61607134887ceaf Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Thu, 6 Dec 2012 14:02:14 +0100 Subject: [PATCH 026/121] Bugfix: out. std::stringstream constr. arg ignored --- common/nutstream.cpp | 23 ++++++++++++----------- common/nutwriter.cpp | 12 +++++++----- include/nutstream.h | 28 ++++++++++++++-------------- include/nutwriter.h | 4 ++-- 4 files changed, 35 insertions(+), 32 deletions(-) diff --git a/common/nutstream.cpp b/common/nutstream.cpp index b65911d44c..c7d0a45e3d 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -89,8 +89,8 @@ NutFile::NutFile(anonymous_t): if (NULL == m_impl) { int err_code = errno; - std::stringstream e("Failed to create temporary file: "); - e << err_code << ": " << ::strerror(err_code); + std::stringstream e; + e << "Failed to create temporary file: " << err_code << ": " << ::strerror(err_code); throw std::runtime_error(e.str()); } @@ -371,8 +371,8 @@ NutSocket::Address::Address(const std::vector & bytes, uint16_t p break; default: { - std::stringstream e("Unsupported IP address size: "); - e << bytes.size(); + std::stringstream e; + e << "Unsupported IP address size: " << bytes.size(); throw std::logic_error(e.str()); } @@ -472,8 +472,8 @@ std::string NutSocket::Address::str() const { sa_family_t family = m_sock_addr->sa_family; - std::stringstream ss("nut::NutSocket::Address(family: "); - ss << family; + std::stringstream ss; + ss << "nut::NutSocket::Address(family: " << family; switch (family) { case AF_UNIX: { @@ -501,8 +501,8 @@ std::string NutSocket::Address::str() const { } default: { - std::stringstream e("NOT IMPLEMENTED: "); - e << "Socket address family " << family << " unsupported"; + std::stringstream e; + e << "NOT IMPLEMENTED: Socket address family " << family << " unsupported"; throw std::logic_error(e.str()); } @@ -549,8 +549,8 @@ bool NutSocket::accept( return false; } - std::stringstream e("Failed to accept connection: "); - e << err_code << ": " << err_msg; + std::stringstream e; + e << "Failed to accept connection: " << err_code << ": " << err_msg; throw std::logic_error(e.str()); } @@ -570,7 +570,8 @@ NutSocket::NutSocket(domain_t dom, type_t type, proto_t proto): if (-1 == m_impl) { int erno = errno; - std::stringstream e("Failed to create socket domain: "); + std::stringstream e; + e << "Failed to create socket domain: "; e << cdom << ", type: " << ctype << ", proto: " << cproto; e << ": " << erno << ": " << ::strerror(erno); diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index ef5892105d..3cf0655ac6 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -47,8 +47,8 @@ do { \ if ((arg).set()) { \ const arg_t & arg_val = (arg); \ - std::stringstream ss(name); \ - ss << ' '; \ + std::stringstream ss; \ + ss << name << ' '; \ if (quote_arg) \ ss << '"'; \ ss << arg_val; \ @@ -346,7 +346,9 @@ inline static UpsmonConfiguration::NotifyType operator ++(UpsmonConfiguration::N * \return Monitor config. directive */ static std::string serialiseMonitor(const UpsmonConfiguration::Monitor & monitor) { - std::stringstream directive("MONITOR "); + std::stringstream directive; + + directive << "MONITOR "; // System directive << monitor.upsname << '@' << monitor.hostname; @@ -458,9 +460,9 @@ NutWriter::status_t UpsmonConfigWriter::writeConfig(const UpsmonConfiguration & * \return Serialised listen address */ static std::string serialiseUpsdListenAddress(const UpsdConfiguration::Listen & address) { - std::stringstream directive("LISTEN "); + std::stringstream directive; - directive << address.address; + directive << "LISTEN " << address.address; if (address.port.set()) directive << ' ' << static_cast(address.port); diff --git a/include/nutstream.h b/include/nutstream.h index 0ef340f686..78f7af4182 100644 --- a/include/nutstream.h +++ b/include/nutstream.h @@ -287,8 +287,8 @@ class NutFile: public NutStream { if (open(mode, ec, em)) return; - std::stringstream e("Failed to open file "); - e << m_name << ": " << ec << ": " << em; + std::stringstream e; + e << "Failed to open file " << m_name << ": " << ec << ": " << em; throw std::runtime_error(e.str()); } @@ -325,8 +325,8 @@ class NutFile: public NutStream { if (close(ec, em)) return; - std::stringstream e("Failed to close file "); - e << m_name << ": " << ec << ": " << em; + std::stringstream e; + e << "Failed to close file " << m_name << ": " << ec << ": " << em; throw std::runtime_error(e.str()); } @@ -601,8 +601,8 @@ class NutSocket: public NutStream { if (accept(sock, listen_sock, ec, em)) return; - std::stringstream e("Failed to accept connection: "); - e << ec << ": " << em; + std::stringstream e; + e << "Failed to accept connection: " << ec << ": " << em; throw std::runtime_error(e.str()); } @@ -703,8 +703,8 @@ class NutSocket: public NutStream { if (bind(addr, ec, em)) return; - std::stringstream e("Failed to bind socket to address "); - e << addr.str() << ": " << ec << ": " << em; + std::stringstream e; + e << "Failed to bind socket to address " << addr.str() << ": " << ec << ": " << em; throw std::runtime_error(e.str()); } @@ -750,8 +750,8 @@ class NutSocket: public NutStream { if (listen(backlog, ec, em)) return; - std::stringstream e("Failed to listen on socket: "); - e << ec << ": " << em; + std::stringstream e; + e << "Failed to listen on socket: " << ec << ": " << em; throw std::runtime_error(e.str()); } @@ -795,8 +795,8 @@ class NutSocket: public NutStream { if (connect(addr, ec, em)) return; - std::stringstream e("Failed to connect socket: "); - e << ec << ": " << em; + std::stringstream e; + e << "Failed to connect socket: " << ec << ": " << em; throw std::runtime_error(e.str()); } @@ -833,8 +833,8 @@ class NutSocket: public NutStream { if (close(ec, em)) return; - std::stringstream e("Failed to close socket "); - e << m_impl << ": " << ec << ": " << em; + std::stringstream e; + e << "Failed to close socket " << m_impl << ": " << ec << ": " << em; throw std::runtime_error(e.str()); } diff --git a/include/nutwriter.h b/include/nutwriter.h index 3ad9f72d7b..07ca453a11 100644 --- a/include/nutwriter.h +++ b/include/nutwriter.h @@ -98,8 +98,8 @@ class NutWriter { NutStream::status_t status = m_output_stream.putString(str); if (NutStream::NUTS_OK != status) { - std::stringstream e("Failed to write to output stream: "); - e << status; + std::stringstream e; + e << "Failed to write to output stream: " << status; throw std::runtime_error(e.str()); } From 754036cf6fcadd37b3ac2de1461035526b8ab909 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Thu, 6 Dec 2012 14:43:03 +0100 Subject: [PATCH 027/121] Support for upsd.users config. file added --- common/nutconf.cpp | 21 ++++++++++++++++ include/nutconf.h | 61 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index d082633740..560a7797b1 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -761,6 +761,27 @@ void GenericConfiguration::set(const std::string & section, const std::string & } +void GenericConfiguration::add(const std::string & section, const std::string & entry, const ConfigParamList & params) +{ + // No job is another job well done + if (params.empty()) + return; + + // Note that the implementation is quite naive and inefficient. + // However, efficiency isn't our aim at the moment. + + // Get current parameters + ConfigParamList current_params; + + get(section, entry, current_params); + + // Add the provided parameters + current_params.insert(current_params.end(), params.begin(), params.end()); + + set(section, entry, current_params); +} + + void GenericConfiguration::remove(const std::string & section, const std::string & entry) { // Get section diff --git a/include/nutconf.h b/include/nutconf.h index 49d63a7e3e..0899d9b589 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -331,6 +331,32 @@ class GenericConfiguration : public BaseConfiguration set("", entry, params); } + /** + * \brief Add configuration parameters + * + * The section and entry are created unless they already exist. + * Current parameters are kept, the provided are added to the list end. + * + * \param[in] section Section name + * \param[in] entry Entry name + * \param[in] params Configuration parameters + */ + void add(const std::string & section, const std::string & entry, const ConfigParamList & params); + + /** + * \brief Add global scope configuration parameters + * + * The entry is created unless they already exists. + * Current parameters are kept, the provided are added to the list end. + * + * \param[in] entry Entry name + * \param[in] params Configuration parameters + */ + inline void add(const std::string & entry, const ConfigParamList & params) + { + add("", entry, params); + } + /** * \brief Configuration parameters removal * @@ -951,6 +977,41 @@ class UpsConfiguration : public GenericConfiguration }; // end of class UpsConfiguration + +/** upsd users configuration */ +class UpsdUsersConfiguration : public GenericConfiguration +{ +public: + /** User-specific configuration attributes getters and setters \{ */ + + inline std::string getPassword(const std::string & user) const { return getStr(user, "password", false); } + + inline ConfigParamList getActions(const std::string & user) const + { + ConfigParamList actions; + get(user, "actions", actions); + return actions; + } + + inline ConfigParamList getInstantCommands(const std::string & user) const + { + ConfigParamList cmds; + get(user, "instcmds", cmds); + return cmds; + } + + inline void setPassword(const std::string & user, const std::string & passwd) { setStr(user, "password", passwd, false); } + + inline void setActions(const std::string & user, const ConfigParamList & actions) { set(user, "actions", actions); } + inline void setInstantCommands(const std::string & user, const ConfigParamList & cmds) { set(user, "instcmds", cmds); } + + inline void addActions(const std::string & user, const ConfigParamList & actions) { add(user, "actions", actions); } + inline void addInstantCommands(const std::string & user, const ConfigParamList & cmds) { add(user, "instcmds", cmds); } + + /** \} */ + +}; // end of class UpsdUsersConfiguration + } /* namespace nut */ #endif /* __cplusplus */ #endif /* NUTCONF_H_SEEN */ From 89a534cdd2f4945fd9f7e343fd5bcecd38dedb8c Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Fri, 7 Dec 2012 14:08:54 +0100 Subject: [PATCH 028/121] (De)serialisation methods added to config. classes All existing NUT configuration classes now implement Serialisable interface (parseFrom and writeTo methods). Note that the parseFrom implementations are very naive (they simply read whole source stream to memory and call existing parseFromString method). That's enough for now, however, in future the parsres should directly use NutStream interface. --- common/nutconf.cpp | 121 ++++++++++++++++++++++++++++++++++++++++++- common/nutstream.cpp | 106 +++++++++++++++++++++++++++++++------ common/nutwriter.cpp | 3 ++ include/nutconf.h | 77 ++++++++++++++++++++++++--- include/nutstream.h | 15 ++++++ include/nutwriter.h | 53 +++++++++++++++++++ 6 files changed, 352 insertions(+), 23 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 560a7797b1..37ec1dc83a 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "nutconf.h" +#include "nutwriter.h" + #include #include #include @@ -25,8 +28,6 @@ #include #include -#include "nutconf.h" - namespace nut { @@ -713,6 +714,28 @@ void GenericConfiguration::parseFromString(const std::string& str) } +bool GenericConfiguration::parseFrom(NutStream & istream) +{ + // TODO: The parser is highly inefficient, it should use NutStream, directly + std::string str; + + if (NutStream::NUTS_OK != istream.getString(str)) + return false; + + parseFromString(str); + + return true; +} + + +bool GenericConfiguration::writeTo(NutStream & ostream) +{ + GenericConfigWriter writer(ostream); + + return NutWriter::NUTW_OK == writer.writeConfig(*this); +} + + bool GenericConfiguration::get(const std::string & section, const std::string & entry, ConfigParamList & params) const { // Get section @@ -957,6 +980,29 @@ UpsmonConfiguration::NotifyType UpsmonConfiguration::NotifyTypeFromString(const return NOTIFY_TYPE_MAX; } + +bool UpsmonConfiguration::parseFrom(NutStream & istream) +{ + // TODO: The parser is highly inefficient, it should use NutStream, directly + std::string str; + + if (NutStream::NUTS_OK != istream.getString(str)) + return false; + + parseFromString(str); + + return true; +} + + +bool UpsmonConfiguration::writeTo(NutStream & ostream) +{ + UpsmonConfigWriter writer(ostream); + + return NutWriter::NUTW_OK == writer.writeConfig(*this); +} + + // // UpsmonConfigParser // @@ -1177,6 +1223,28 @@ NutConfiguration::NutMode NutConfiguration::NutModeFromString(const std::string& } +bool NutConfiguration::parseFrom(NutStream & istream) +{ + // TODO: The parser is highly inefficient, it should use NutStream, directly + std::string str; + + if (NutStream::NUTS_OK != istream.getString(str)) + return false; + + parseFromString(str); + + return true; +} + + +bool NutConfiguration::writeTo(NutStream & ostream) +{ + NutConfConfigWriter writer(ostream); + + return NutWriter::NUTW_OK == writer.writeConfig(*this); +} + + // // NutConfConfigParser // @@ -1255,6 +1323,29 @@ void UpsdConfiguration::parseFromString(const std::string& str) parser.parseUpsdConfig(this); } + +bool UpsdConfiguration::parseFrom(NutStream & istream) +{ + // TODO: The parser is highly inefficient, it should use NutStream, directly + std::string str; + + if (NutStream::NUTS_OK != istream.getString(str)) + return false; + + parseFromString(str); + + return true; +} + + +bool UpsdConfiguration::writeTo(NutStream & ostream) +{ + UpsdConfigWriter writer(ostream); + + return NutWriter::NUTW_OK == writer.writeConfig(*this); +} + + // // UpsdConfigParser // @@ -1355,4 +1446,30 @@ void UpsdConfigParser::onParseEnd() // Do nothing } + +// +// UpsdUsersConfiguration +// + +bool UpsdUsersConfiguration::parseFrom(NutStream & istream) +{ + // TODO: The parser is highly inefficient, it should use NutStream, directly + std::string str; + + if (NutStream::NUTS_OK != istream.getString(str)) + return false; + + parseFromString(str); + + return true; +} + + +bool UpsdUsersConfiguration::writeTo(NutStream & ostream) +{ + UpsdUsersConfigWriter writer(ostream); + + return NutWriter::NUTW_OK == writer.writeConfig(*this); +} + } /* namespace nut */ diff --git a/common/nutstream.cpp b/common/nutstream.cpp index c7d0a45e3d..0f020fdf2d 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -57,6 +57,15 @@ void NutMemory::readChar() { } +NutStream::status_t NutMemory::getString(std::string & str) { + str = m_impl.substr(m_pos); + + m_pos = m_impl.size(); + + return NUTS_OK; +} + + NutStream::status_t NutMemory::putChar(char ch) { m_impl += ch; @@ -192,32 +201,50 @@ NutFile::NutFile(access_t mode): } -NutStream::status_t NutFile::getChar(char & ch) throw() { - int c; +/** + * \brief C fgetc wrapper + * + * \param[in] file File + * \param[out] ch Character + * + * \retval NUTS_OK on success + * \retval NUTS_EOF on end-of-file + * \retval NUTS_ERROR on read error + */ +inline static NutStream::status_t fgetcWrapper(FILE * file, char & ch) { + assert(NULL != file); - if (m_current_ch_valid) { - ch = m_current_ch; + errno = 0; - return NUTS_OK; + int c = ::fgetc(file); + + if (EOF == c) { + if (0 == errno) + return NutStream::NUTS_EOF; + + return NutStream::NUTS_ERROR; } - if (NULL == m_impl) - return NUTS_ERROR; + ch = static_cast(c); - errno = 0; + return NutStream::NUTS_OK; +} - c = ::fgetc(m_impl); - if (EOF == c) { - int erno = errno; +NutStream::status_t NutFile::getChar(char & ch) throw() { + if (m_current_ch_valid) { + ch = m_current_ch; - if (0 == erno) - return NUTS_EOF; + return NUTS_OK; + } + if (NULL == m_impl) return NUTS_ERROR; - } - ch = static_cast(c); + status_t status = fgetcWrapper(m_impl, ch); + + if (NUTS_OK != status) + return status; // Cache the character for future reference m_current_ch = ch; @@ -232,6 +259,33 @@ void NutFile::readChar() throw() { } +NutStream::status_t NutFile::getString(std::string & str) throw() { + if (m_current_ch_valid) + str += m_current_ch; + + m_current_ch_valid = false; + + if (NULL == m_impl) + return NUTS_ERROR; + + // Note that ::fgetc is used instead of ::fgets + // That's because of \0 char. support + for (;;) { + char ch; + + status_t status = fgetcWrapper(m_impl, ch); + + if (NUTS_ERROR == status) + return status; + + if (NUTS_EOF == status) + return NUTS_OK; + + str += ch; + } +} + + NutStream::status_t NutFile::putChar(char ch) throw() { int c; @@ -678,6 +732,28 @@ void NutSocket::readChar() throw() { } +NutStream::status_t NutSocket::getString(std::string & str) throw() { + if (m_current_ch_valid) + str += m_current_ch; + + m_current_ch_valid = false; + + char buffer[512]; + + for (;;) { + ssize_t read_cnt = ::read(m_impl, buffer, sizeof(buffer) / sizeof(buffer[0])); + + if (-1 == read_cnt) + return NUTS_ERROR; + + if (0 == read_cnt) + return NUTS_OK; + + str.append(buffer, read_cnt); + } +} + + NutStream::status_t NutSocket::putChar(char ch) throw() { ssize_t write_cnt = ::write(m_impl, &ch, 1); diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index 3cf0655ac6..9ff88ff316 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -80,6 +80,9 @@ static const std::string CR("\r"); const std::string & NutWriter::eol(LF); +const std::string GenericConfigWriter::s_default_section_entry_indent("\t"); +const std::string GenericConfigWriter::s_default_section_entry_separator(" = "); + NutWriter::status_t NutWriter::writeEachLine(const std::string & str, const std::string & pref) { for (size_t pos = 0; pos < str.size(); ) { diff --git a/include/nutconf.h b/include/nutconf.h index 0899d9b589..1298a9a684 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -21,6 +21,8 @@ #ifndef NUTCONF_H_SEEN #define NUTCONF_H_SEEN 1 +#include "nutstream.h" + #include #include #include @@ -88,6 +90,47 @@ class Settable }; +/** + * \brief Serialisable interface + * + * Classes that implement this iface provide way to serialise + * and deserialise instances to/from streams. + */ +class Serialisable +{ +protected: + + /** Formal constructor */ + Serialisable() {} + +public: + + /** + * \brief Deserialiser + * + * \param istream Input stream + * + * \retval true in case of success + * \retval false in case of read error + */ + virtual bool parseFrom(NutStream & istream) = 0; + + /** + * \brief Serialiser + * + * \param ostream Output stream + * + * \retval true in case of success + * \retval false in case of write error + */ + virtual bool writeTo(NutStream & ostream) = 0; + + /** Destructor */ + virtual ~Serialisable() {} + +}; // end of class Serialisable + + /** * NUT config parser. */ @@ -258,7 +301,7 @@ class GenericConfigParser : public DefaultConfigParser }; -class GenericConfiguration : public BaseConfiguration +class GenericConfiguration : public BaseConfiguration, public Serialisable { public: /** Sections map */ @@ -268,8 +311,10 @@ class GenericConfiguration : public BaseConfiguration void parseFromString(const std::string& str); - // TODO Add functions to write to string or files (Vasek ?) - + /** Serialisable interface implementation \{ */ + bool parseFrom(NutStream & istream); + bool writeTo(NutStream & ostream); + /** \} */ // FIXME Let me public or set it as protected with public accessors ? SectionMap sections; @@ -564,7 +609,7 @@ class GenericConfiguration : public BaseConfiguration -class UpsmonConfiguration +class UpsmonConfiguration : public Serialisable { public: UpsmonConfiguration(); @@ -611,7 +656,12 @@ class UpsmonConfiguration std::list monitors; -}; + /** Serialisable interface implementation \{ */ + bool parseFrom(NutStream & istream); + bool writeTo(NutStream & ostream); + /** \} */ + +}; // end of class UpsmonConfiguration @@ -650,6 +700,11 @@ class NutConfiguration Settable mode; static NutMode NutModeFromString(const std::string& str); + + /** Serialisable interface implementation \{ */ + bool parseFrom(NutStream & istream); + bool writeTo(NutStream & ostream); + /** \} */ }; @@ -671,7 +726,7 @@ class NutConfConfigParser : public NutConfigParser }; -class UpsdConfiguration +class UpsdConfiguration : public Serialisable { public: UpsdConfiguration(); @@ -691,6 +746,11 @@ class UpsdConfiguration } }; std::list listens; + + /** Serialisable interface implementation \{ */ + bool parseFrom(NutStream & istream); + bool writeTo(NutStream & ostream); + /** \} */ }; @@ -1010,6 +1070,11 @@ class UpsdUsersConfiguration : public GenericConfiguration /** \} */ + /** Serialisable interface implementation overload \{ */ + bool parseFrom(NutStream & istream); + bool writeTo(NutStream & ostream); + /** \} */ + }; // end of class UpsdUsersConfiguration } /* namespace nut */ diff --git a/include/nutstream.h b/include/nutstream.h index 78f7af4182..9243ab4fa6 100644 --- a/include/nutstream.h +++ b/include/nutstream.h @@ -89,6 +89,18 @@ class NutStream { */ virtual void readChar() = 0; + /** + * \brief Read characters from the stream till EoF + * + * The method may be used to synchronously read + * whole (rest of) stream. + * Note that implementation may block flow. + * + * \retval NUTS_OK on success, + * \retval NUTS_ERROR on read error + */ + virtual status_t getString(std::string & str) = 0; + /** * \brief Put one character to the stream end * @@ -154,6 +166,7 @@ class NutMemory: public NutStream { // NutStream interface implementation status_t getChar(char & ch); void readChar(); + status_t getString(std::string & str); status_t putChar(char ch); status_t putString(const std::string & str); status_t putData(const std::string & data); @@ -357,6 +370,7 @@ class NutFile: public NutStream { // NutStream interface implementation status_t getChar(char & ch) throw(); void readChar() throw(); + status_t getString(std::string & str) throw(); status_t putChar(char ch) throw(); status_t putString(const std::string & str) throw(); status_t putData(const std::string & data) throw(); @@ -842,6 +856,7 @@ class NutSocket: public NutStream { // NutStream interface implementation status_t getChar(char & ch) throw(); void readChar() throw(); + status_t getString(std::string & str) throw(); status_t putChar(char ch) throw(); status_t putString(const std::string & str) throw(); inline status_t putData(const std::string & data) { diff --git a/include/nutwriter.h b/include/nutwriter.h index 07ca453a11..a98ba82909 100644 --- a/include/nutwriter.h +++ b/include/nutwriter.h @@ -178,6 +178,15 @@ class NutConfigWriter: public NutWriter { * configuration files. */ class SectionlessConfigWriter: public NutConfigWriter { + protected: + + /** + * \brief Constructor + * + * \param ostream Output stream + */ + SectionlessConfigWriter(NutStream & ostream): NutConfigWriter(ostream) {} + public: // Partial \ref NutConfigWriter interface implementation @@ -198,6 +207,13 @@ class SectionlessConfigWriter: public NutConfigWriter { class NutConfConfigWriter: public SectionlessConfigWriter { public: + /** + * \brief Constructor + * + * \param ostream Output stream + */ + NutConfConfigWriter(NutStream & ostream): SectionlessConfigWriter(ostream) {} + /** * \brief Serialise configuration container * @@ -217,6 +233,13 @@ class NutConfConfigWriter: public SectionlessConfigWriter { class UpsmonConfigWriter: public SectionlessConfigWriter { public: + /** + * \brief Constructor + * + * \param ostream Output stream + */ + UpsmonConfigWriter(NutStream & ostream): SectionlessConfigWriter(ostream) {} + /** * \brief Serialise configuration container * @@ -236,6 +259,13 @@ class UpsmonConfigWriter: public SectionlessConfigWriter { class UpsdConfigWriter: public SectionlessConfigWriter { public: + /** + * \brief Constructor + * + * \param ostream Output stream + */ + UpsdConfigWriter(NutStream & ostream): SectionlessConfigWriter(ostream) {} + /** * \brief Serialise configuration container * @@ -257,6 +287,15 @@ class UpsdConfigWriter: public SectionlessConfigWriter { * by descendants. */ class DefaultConfigWriter: public NutConfigWriter { + protected: + + /** + * \brief Constructor + * + * \param ostream Output stream + */ + DefaultConfigWriter(NutStream & ostream): NutConfigWriter(ostream) {} + public: // \ref NutConfigWriter interface implementation @@ -312,6 +351,13 @@ class GenericConfigWriter: public DefaultConfigWriter { public: + /** + * \brief Constructor + * + * \param ostream Output stream + */ + GenericConfigWriter(NutStream & ostream): DefaultConfigWriter(ostream) {} + // Section serialiser implementation status_t writeSection(const GenericConfigSection & section); @@ -338,6 +384,13 @@ class GenericConfigWriter: public DefaultConfigWriter { class UpsdUsersConfigWriter: public GenericConfigWriter { public: + /** + * \brief Constructor + * + * \param ostream Output stream + */ + UpsdUsersConfigWriter(NutStream & ostream): GenericConfigWriter(ostream) {} + // Section serialiser overload status_t writeSection(const GenericConfigSection & section); From 38c993401842f091665fd28e3161adcf868a2018 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Tue, 11 Dec 2012 18:28:53 +0100 Subject: [PATCH 029/121] Basic unit tests for libnutconf UTs with focus on basic configuration settings and serialisation were added for nut.conf, upsmon.conf, upsd.conf ups.conf and upsd.users. Note that the tests are not exhaustive; they only parse configuration files samples, change a few randomly selected parameters, serialise the result back and check it. --- common/nutconf.cpp | 33 ++++++- include/nutconf.h | 37 +++++-- tests/Makefile.am | 4 +- tests/nutconf_ut.cpp | 231 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 289 insertions(+), 16 deletions(-) create mode 100644 tests/nutconf_ut.cpp diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 37ec1dc83a..fb478d14c7 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -27,6 +27,7 @@ #include #include +#include namespace nut { @@ -728,7 +729,7 @@ bool GenericConfiguration::parseFrom(NutStream & istream) } -bool GenericConfiguration::writeTo(NutStream & ostream) +bool GenericConfiguration::writeTo(NutStream & ostream) const { GenericConfigWriter writer(ostream); @@ -995,7 +996,7 @@ bool UpsmonConfiguration::parseFrom(NutStream & istream) } -bool UpsmonConfiguration::writeTo(NutStream & ostream) +bool UpsmonConfiguration::writeTo(NutStream & ostream) const { UpsmonConfigWriter writer(ostream); @@ -1237,7 +1238,7 @@ bool NutConfiguration::parseFrom(NutStream & istream) } -bool NutConfiguration::writeTo(NutStream & ostream) +bool NutConfiguration::writeTo(NutStream & ostream) const { NutConfConfigWriter writer(ostream); @@ -1338,7 +1339,7 @@ bool UpsdConfiguration::parseFrom(NutStream & istream) } -bool UpsdConfiguration::writeTo(NutStream & ostream) +bool UpsdConfiguration::writeTo(NutStream & ostream) const { UpsdConfigWriter writer(ostream); @@ -1451,6 +1452,28 @@ void UpsdConfigParser::onParseEnd() // UpsdUsersConfiguration // +UpsdUsersConfiguration::upsmon_mode_t UpsdUsersConfiguration::getUpsmonMode() const +{ + std::string mode_str = getStr("upsmon", "upsmon", false); + + if ("master" == mode_str) + return UPSMON_MASTER; + + if ("slave" == mode_str) + return UPSMON_SLAVE; + + return UPSMON_UNDEF; +} + + +void UpsdUsersConfiguration::setUpsmonMode(upsmon_mode_t mode) +{ + assert(UPSMON_UNDEF != mode); + + setStr("upsmon", "upsmon", (UPSMON_MASTER == mode ? "master" : "slave"), false); +} + + bool UpsdUsersConfiguration::parseFrom(NutStream & istream) { // TODO: The parser is highly inefficient, it should use NutStream, directly @@ -1465,7 +1488,7 @@ bool UpsdUsersConfiguration::parseFrom(NutStream & istream) } -bool UpsdUsersConfiguration::writeTo(NutStream & ostream) +bool UpsdUsersConfiguration::writeTo(NutStream & ostream) const { UpsdUsersConfigWriter writer(ostream); diff --git a/include/nutconf.h b/include/nutconf.h index 1298a9a684..4962b8bf28 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -123,7 +123,7 @@ class Serialisable * \retval true in case of success * \retval false in case of write error */ - virtual bool writeTo(NutStream & ostream) = 0; + virtual bool writeTo(NutStream & ostream) const = 0; /** Destructor */ virtual ~Serialisable() {} @@ -313,7 +313,7 @@ class GenericConfiguration : public BaseConfiguration, public Serialisable /** Serialisable interface implementation \{ */ bool parseFrom(NutStream & istream); - bool writeTo(NutStream & ostream); + bool writeTo(NutStream & ostream) const; /** \} */ // FIXME Let me public or set it as protected with public accessors ? @@ -658,7 +658,7 @@ class UpsmonConfiguration : public Serialisable /** Serialisable interface implementation \{ */ bool parseFrom(NutStream & istream); - bool writeTo(NutStream & ostream); + bool writeTo(NutStream & ostream) const; /** \} */ }; // end of class UpsmonConfiguration @@ -683,7 +683,7 @@ class UpsmonConfigParser : public NutConfigParser }; -class NutConfiguration +class NutConfiguration: public Serialisable { public: NutConfiguration(); @@ -703,7 +703,7 @@ class NutConfiguration /** Serialisable interface implementation \{ */ bool parseFrom(NutStream & istream); - bool writeTo(NutStream & ostream); + bool writeTo(NutStream & ostream) const; /** \} */ }; @@ -749,7 +749,7 @@ class UpsdConfiguration : public Serialisable /** Serialisable interface implementation \{ */ bool parseFrom(NutStream & istream); - bool writeTo(NutStream & ostream); + bool writeTo(NutStream & ostream) const; /** \} */ }; @@ -825,6 +825,7 @@ class UpsConfiguration : public GenericConfiguration inline std::string getNotification(const std::string & ups) const { return getStr(ups, "notification", false); } // CHECKME inline std::string getOldMAC(const std::string & ups) const { return getStr(ups, "oldmac", false); } // CHECKME inline std::string getPassword(const std::string & ups) const { return getStr(ups, "password", false); } // CHECKME + inline std::string getPort(const std::string & ups) const { return getStr(ups, "port", false); } inline std::string getPrefix(const std::string & ups) const { return getStr(ups, "prefix", true); } // CHECKME inline std::string getPrivPassword(const std::string & ups) const { return getStr(ups, "privPassword", false); } // CHECKME inline std::string getPrivProtocol(const std::string & ups) const { return getStr(ups, "privProtocol", false); } // CHECKME @@ -851,7 +852,6 @@ class UpsConfiguration : public GenericConfiguration inline std::string getWUGrace(const std::string & ups) const { return getStr(ups, "wugrace", false); } // CHECKME - inline uint16_t getPort(const std::string & ups) const { return range_cast(getInt(ups, "port"), 0, 65535); } // TBD: Any default? inline long long int getSDOrder(const std::string & ups) const { return getInt(ups, "sdorder"); } // TODO: Is that a number? inline long long int getMaxStartDelay(const std::string & ups) const { return getInt(ups, "maxstartdelay"); } inline long long int getAdvOrder(const std::string & ups) const { return getInt(ups, "advorder"); } // CHECKME @@ -942,6 +942,7 @@ class UpsConfiguration : public GenericConfiguration inline void setNotification(const std::string & ups, const std::string & notification) { setStr(ups, "notification", notification, false); } // CHECKME inline void setOldMAC(const std::string & ups, const std::string & oldmac) { setStr(ups, "oldmac", oldmac, false); } // CHECKME inline void setPassword(const std::string & ups, const std::string & password) { setStr(ups, "password", password, false); } // CHECKME + inline void setPort(const std::string & ups, const std::string & port) { setStr(ups, "port", port, false); } inline void setPrefix(const std::string & ups, const std::string & prefix) { setStr(ups, "prefix", prefix, false); } // CHECKME inline void setPrivPassword(const std::string & ups, const std::string & priv_passwd) { setStr(ups, "privPassword", priv_passwd, false); } // CHECKME inline void setPrivProtocol(const std::string & ups, const std::string & priv_proto) { setStr(ups, "privProtocol", priv_proto, false); } // CHECKME @@ -967,7 +968,6 @@ class UpsConfiguration : public GenericConfiguration inline void setVendorID(const std::string & ups, const std::string & vendorid) { setStr(ups, "vendorid", vendorid, false); } // CHECKME inline void setWUGrace(const std::string & ups, const std::string & wugrace) { setStr(ups, "wugrace", wugrace, false); } // CHECKME - inline void setPort(const std::string & ups, uint16_t port) { setInt(ups, "port", port); } inline void setSDOrder(const std::string & ups, long long int ord) { setInt(ups, "sdorder", ord); } inline void setMaxStartDelay(const std::string & ups, long long int delay) { setInt(ups, "maxstartdelay", delay); } inline void setADVorder(const std::string & ups, long long int advorder) { setInt(ups, "advorder", advorder); } // CHECKME @@ -1042,6 +1042,13 @@ class UpsConfiguration : public GenericConfiguration class UpsdUsersConfiguration : public GenericConfiguration { public: + /** upsmon mode */ + typedef enum { + UPSMON_UNDEF = 0, /**< Unknown mode */ + UPSMON_MASTER, /**< Master mode */ + UPSMON_SLAVE, /**< Slave mode */ + } upsmon_mode_t; + /** User-specific configuration attributes getters and setters \{ */ inline std::string getPassword(const std::string & user) const { return getStr(user, "password", false); } @@ -1060,6 +1067,8 @@ class UpsdUsersConfiguration : public GenericConfiguration return cmds; } + upsmon_mode_t getUpsmonMode() const; + inline void setPassword(const std::string & user, const std::string & passwd) { setStr(user, "password", passwd, false); } inline void setActions(const std::string & user, const ConfigParamList & actions) { set(user, "actions", actions); } @@ -1068,11 +1077,21 @@ class UpsdUsersConfiguration : public GenericConfiguration inline void addActions(const std::string & user, const ConfigParamList & actions) { add(user, "actions", actions); } inline void addInstantCommands(const std::string & user, const ConfigParamList & cmds) { add(user, "instcmds", cmds); } + /** + * \brief upsmon mode setter + * + * Note that the UPSMON_UNDEF mode isn't allowed as parameter + * (logically, if you set something, it shall be defined...) + * + * \param mode Mode + */ + void setUpsmonMode(upsmon_mode_t mode); + /** \} */ /** Serialisable interface implementation overload \{ */ bool parseFrom(NutStream & istream); - bool writeTo(NutStream & ostream); + bool writeTo(NutStream & ostream) const; /** \} */ }; // end of class UpsdUsersConfiguration diff --git a/tests/Makefile.am b/tests/Makefile.am index 2746181e73..5729d4de01 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -11,12 +11,12 @@ cppunittest_LDFLAGS = $(CPPUNIT_LIBS) cppunittest_LDADD = ../common/libnutconf.la # List of src files for CppUnit tests -CPPUNITTESTSRC = example.cpp nutconf.cpp nutstream_ut.cpp +CPPUNITTESTSRC = example.cpp nutconf.cpp nutstream_ut.cpp nutconf_ut.cpp cppunittest_SOURCES = $(CPPUNITTESTSRC) cpputest.cpp else !HAVE_CPPUNIT -EXTRA_DIST = example.cpp nutconf.cpp cpputest.cpp nutstream_ut.cpp +EXTRA_DIST = example.cpp nutconf.cpp cpputest.cpp nutstream_ut.cpp nutconf_ut.cpp endif !HAVE_CPPUNIT diff --git a/tests/nutconf_ut.cpp b/tests/nutconf_ut.cpp new file mode 100644 index 0000000000..430dcbb961 --- /dev/null +++ b/tests/nutconf_ut.cpp @@ -0,0 +1,231 @@ +/* +NUT configuration unit test + +Copyright (C) +2012 Vaclav Krpec + +This program 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 2 of the License, or +(at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "nutstream.h" +#include "nutconf.h" +#include "nutwriter.h" + +#include + + +/** + * \brief NUT configuration unit test + */ +class NutConfigUnitTest: public CppUnit::TestFixture { + private: + + CPPUNIT_TEST_SUITE(NutConfigUnitTest); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); + + /** + * \brief Load configuration from file + * + * \param config Configuration object + * \param file_name Configuration file name + */ + void load(nut::Serialisable * config, const std::string & file_name); + + /** + * \brief Check configuration serialisation contents + * + * \param config Configuration object + * \param content Expected serialisation + */ + void check(const nut::Serialisable * config, const std::string & content); + + /** nut.conf test */ + void testNutConfiguration(); + + /** upsmon.conf test */ + void testUpsmonConfiguration(); + + /** upsd.conf test */ + void testUpsdConfiguration(); + + /** ups.conf test */ + void testUpsConfiguration(); + + /** upsd.users test */ + void testUpsdUsersConfiguration(); + + public: + + inline void setUp() {} + inline void tearDown() {} + + inline void test() { + testNutConfiguration(); + testUpsmonConfiguration(); + testUpsdConfiguration(); + testUpsConfiguration(); + testUpsdUsersConfiguration(); + } + +}; // end of class NutConfigUnitTest + + +// Register the test suite +CPPUNIT_TEST_SUITE_REGISTRATION(NutConfigUnitTest); + + +void NutConfigUnitTest::load(nut::Serialisable * config, const std::string & file_name) { + nut::NutFile file(file_name, nut::NutFile::READ_ONLY); + + CPPUNIT_ASSERT(config->parseFrom(file)); +} + + +void NutConfigUnitTest::check(const nut::Serialisable * config, const std::string & content) { + nut::NutMemory mem; + + CPPUNIT_ASSERT(config->writeTo(mem)); + + std::string str; + + nut::NutStream::status_t status = mem.getString(str); + + CPPUNIT_ASSERT(nut::NutStream::NUTS_OK == status); + + if (content != str) { + std::cerr << "--- expected ---" << std::endl << content << "--- end ---" << std::endl; + std::cerr << "--- serialised ---" << std::endl << str << "--- end ---" << std::endl; + + CPPUNIT_ASSERT_MESSAGE("Configuration serialisation check failed", 0); + } +} + + +void NutConfigUnitTest::testNutConfiguration() { + nut::NutConfiguration config; + + load(static_cast(&config), "../conf/nut.conf.sample"); + + config.mode = nut::NutConfiguration::MODE_STANDALONE; + + check(static_cast(&config), + "MODE=standalone\n" + ); +} + + +void NutConfigUnitTest::testUpsmonConfiguration() { + nut::UpsmonConfiguration config; + + load(static_cast(&config), "../conf/upsmon.conf.sample"); + + config.shutdownCmd = "/sbin/shutdown -h +2 'System shutdown in 2 minutes!'"; + config.poolFreqAlert = 10; + config.deadTime = 30; + + check(static_cast(&config), + "SHUTDOWNCMD \"/sbin/shutdown -h +2 'System shutdown in 2 minutes!'\"\n" + "POWERDOWNFLAG /etc/killpower\n" + "MINSUPPLIES 1\n" + "POLLFREQ 5\n" + "POLLFREQALERT 10\n" + "HOSTSYNC 15\n" + "DEADTIME 30\n" + "RBWARNTIME 43200\n" + "NOCOMMWARNTIME 300\n" + "FINALDELAY 5\n" + ); +} + + +void NutConfigUnitTest::testUpsdConfiguration() { + nut::UpsdConfiguration config; + + load(static_cast(&config), "../conf/upsd.conf.sample"); + + config.maxAge = 15; + config.statePath = "/var/run/nut"; + config.maxConn = 1024; + config.certFile = "/usr/share/ssl-cert/ssleay.cnf"; + + nut::UpsdConfiguration::Listen listen; + + listen.address = "127.0.0.1"; + listen.port = 3493; + + config.listens.push_back(listen); + + listen.address = "::1"; + + config.listens.push_back(listen); + + check(static_cast(&config), + "MAXAGE 15\n" + "MAXCONN 1024\n" + "STATEPATH /var/run/nut\n" + "CERTFILE /usr/share/ssl-cert/ssleay.cnf\n" + "LISTEN 127.0.0.1 3493\n" + "LISTEN ::1 3493\n" + ); +} + + +void NutConfigUnitTest::testUpsConfiguration() { + nut::UpsConfiguration config; + + load(static_cast(&config), "../conf/ups.conf.sample"); + + static const std::string my_ups("powerpal"); + + config.setDriver(my_ups, "blazer_ser"); + config.setPort(my_ups, "/dev/ttyS0"); + config.setDescription(my_ups, "Web server"); + + check(static_cast(&config), + "[powerpal]\n" + "\tdesc = \"Web server\"\n" + "\tdriver = blazer_ser\n" + "\tport = /dev/ttyS0\n" + "\n" + ); +} + + +void NutConfigUnitTest::testUpsdUsersConfiguration() { + nut::UpsdUsersConfiguration config; + + load(static_cast(&config), "../conf/upsd.users.sample"); + + config.setPassword("upsmon", "ytrewq"); + config.setUpsmonMode(nut::UpsdUsersConfiguration::UPSMON_MASTER); + + config.setPassword("admin", "qwerty"); + config.setActions("admin", nut::ConfigParamList(1, "SET")); + config.setInstantCommands("admin", nut::ConfigParamList(1, "ALL")); + + check(static_cast(&config), + "[admin]\n" + "\tactions = SET\n" + "\tinstcmds = ALL\n" + "\tpassword = qwerty\n" + "\n" + "[upsmon]\n" + "\tpassword = ytrewq\n" + "\tupsmon master\n" + "\n" + ); +} From ff401e538bcbead62a3532887135518ef9e779df Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Fri, 14 Dec 2012 15:12:05 +0100 Subject: [PATCH 030/121] NUT IPC module introduction A non-complete implementation of NUT IPC support module. Certain functions are just outlined, for now. Deals with signal handling and execution of external commands. I commit this partial implementation because I'll be on holiday for certain amount of time and it's IMO better to have the code comitted. --- common/Makefile.am | 2 +- common/nutipc.cpp | 362 ++++++++++++++++++++++++++++++++++++++ include/Makefile.am | 2 +- include/nutipc.hpp | 415 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 779 insertions(+), 2 deletions(-) create mode 100644 common/nutipc.cpp create mode 100644 include/nutipc.hpp diff --git a/common/Makefile.am b/common/Makefile.am index f031ea6c5c..2fe226c4fa 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -5,7 +5,7 @@ AM_CFLAGS = -I$(top_srcdir)/include noinst_LTLIBRARIES = libparseconf.la libcommon.la libnutconf.la libparseconf_la_SOURCES = parseconf.c -libnutconf_la_SOURCES = nutconf.cpp nutstream.cpp nutwriter.cpp +libnutconf_la_SOURCES = nutconf.cpp nutstream.cpp nutwriter.cpp nutipc.cpp # do not hard depend on '../include/nut_version.h', since it blocks # 'dist', and is only required for actual build, in which case diff --git a/common/nutipc.cpp b/common/nutipc.cpp new file mode 100644 index 0000000000..28f7b89d88 --- /dev/null +++ b/common/nutipc.cpp @@ -0,0 +1,362 @@ +/* nutipc.cpp - NUT IPC + + Copyright (C) 2012 Eaton + + Author: Vaclav Krpec + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "nutipc.hpp" + +#include + +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +} + + +namespace nut { + +pid_t Process::getPID() throw() { + return getpid(); +} + + +pid_t Process::getPPID() throw() { + return getppid(); +} + + +template +Process::Child::Child(M main) throw(std::runtime_error): + m_pid(0), + m_exited(false), + m_exit_code(0) +{ + m_pid = ::fork(); + + if (!m_pid) + ::exit(main()); +} + + +template +int Process::Child::wait() throw(std::logic_error) { + int exit_code; + pid_t wpid = ::waitpid(m_pid, &exit_code, 0); + + if (-1 == m_pid) { + int erno = errno; + + std::stringstream e; + + e << "Failed to wait for process " << m_pid << ": "; + e << erno << ": " << strerror(erno); + + throw std::logic_error(e.str()); + } + + return exit_code; +} + + +Process::Executor::Executor(const std::string & command) { + //m_bin m_args + throw std::runtime_error("TODO: Not implemented, yet"); +} + + +int Process::Executor::operator () () throw(std::runtime_error) { + const char ** args_c_str = new const char *[m_args.size()]; + + Arguments::const_iterator arg = m_args.begin(); + + for (size_t i = 0; arg != m_args.end(); ++arg, ++i) { + args_c_str[i] = (*arg).c_str(); + } + + int status = ::execvp(m_bin.c_str(), (char * const *)args_c_str); + + // Upon successful execution, the execvp function never returns + // (since the process context is replaced, completely) + + delete args_c_str; + + std::stringstream e; + + e << "Failed to execute binary " << m_bin << ": " << status; + + throw std::runtime_error(e.str()); +} + + +template +void * Signal::HandlerThread::main(void * comm_pipe_read_end) { + int rfd = *(int *)comm_pipe_read_end; + + H handler; + + for (;;) { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(rfd, &rfds); + + // Poll on signal pipe + // Note that direct blocking read could be also used; + // however, select allows timeout specification + // which might come handy... + int fdno = ::select(1, &rfds, NULL, NULL, NULL); + + // TBD: Die or recover on error? + if (-1 == fdno) { + std::stringstream e; + + e << "Poll on communication pipe read end "; + e << rfd << " failed: " << errno; + + throw std::runtime_error(e.str()); + } + + assert(1 == fdno); + assert(FD_ISSET(rfd, &rfds)); + + // Read command + int word; + + ssize_t read_out = ::read(rfd, &word, sizeof(word)); + + // TBD: again, how should we treat read error? + if (-1 == read_out) { + std::stringstream e; + + e << "Failed to read command from the command pipe: "; + e << errno; + + throw std::runtime_error(e.str()); + } + + assert(sizeof(word) == read_out); + + command_t command = reinterpret_cast(word); + + switch (command) { + case QUIT: + pthread_exit(NULL); + + case SIGNAL: + // Read signal number + read_out = ::read(rfd, &word, sizeof(word)); + + // TBD: again, how should we treat read error? + if (-1 == read_out) { + std::stringstream e; + + e << "Failed to read signal number "; + e << "from the command pipe: " << errno; + + throw std::runtime_error(e.str()); + } + + assert(sizeof(word) == read_out); + + Signal::enum_t sig = reinterpret_cast(word); + + // Handle signal + handler(sig); + } + } + + // Pro-forma exception + throw std::logic_error("INTERNAL ERROR: Unreachable code reached"); +} + + +/** + * \brief Write command to command pipe + * + * \param fh Pipe writing end + * \param cmd Command + * \param cmd_size Comand size + * + * \retval 0 on success + * \retval errno on error + */ +static int writeCommand(int fh, void * cmd, size_t cmd_size) throw(std::runtime_error) { + char * cmd_bytes = reinterpret_cast(cmd); + + do { + ssize_t written = write(fh, cmd_bytes, cmd_size); + + if (-1 == written) + return errno; + + cmd_bytes += written; + cmd_size -= written; + + } while (cmd_size); + + return 0; +} + + +template +void Signal::HandlerThread::signalNotifier(int signal) { + int sig[2] = { + reinterpret_cast(Signal::HandlerThread::SIGNAL), + }; + + sig[1] = signal; + + // TBD: The return value is silently ignored. + // Either the write should've succeeded or the handling + // thread is already comming down... + writeCommand(s_comm_pipe[1], sig, sizeof(sig)); +} + + +template +Signal::HandlerThread::HandlerThread(const Signal::List & siglist) throw(std::logic_error, std::runtime_error) { + /* + * IMPLEMENTATION NOTES: + * 0/ Check whether comm. pipe is valid; throw std::logic_error if so + * 1/ Comm. pipe creation (or an exception) + * 2/ Start the thread: pthread_create(m_impl, , ) + * 3/ Register the signals: sigaction( ) + */ + throw std::runtime_error("TODO: Signal handler thread is not implemented, yet"); + + if (-1 != s_comm_pipe[1]) + throw std::logic_error("Attempt to start a duplicate of signal handling thread detected"); + + // Create communication pipe + if (::pipe(s_comm_pipe)) { + std::stringstream e; + + e << "Failed to create communication pipe: " << errno; + + throw std::runtime_error(e.str()); + } + + // TODO: +#if (0) + // Start the thread + int status = ::pthread_create(&m_impl, NULL, main, s_comm_pipe); + + if (status) { + std::stringstream e; + + e << "Failed to start the thread: " << status; + + throw std::runtime_error(e.str()); + } + + // Register signals + Signal::List::const_iterator sig = siglist.begin(); + + for (; sig != siglist.end(); ++sig) { + struct sigaction action; + + action.sa_handler = signalNotifier; + action.sa_sigaction = NULL; // guess we don't need signal info + action.sa_mask = 0; // shouldn't we mask signals while handling them? + action.sa_flags = 0; // any flags? + action.sa_restorer = NULL; // obsolete + + int signo = static_cast(*sig); + + // TBD: We might want to save the old handlers... + status = ::sigaction(signo, &action, NULL); + + if (status) { + std::stringstream e; + + e << "Failed to register signal handler for signal "; + e << signo << ": " << errno; + + throw std::runtime_error(e.str()); + } + } +#endif +} + + +template +void Signal::HandlerThread::quit() throw(std::runtime_error) { + static int quit = reinterpret_cast(Signal::HandlerThread::QUIT); + + writeCommand(s_comm_pipe[1], quit, sizeof(quit)); + + // TODO: +#if (0) + int status = ::pthread_join(m_impl); + + if (status) { + std::stringstream e; + + e << "Failed to joint signal handling thread: " << status; + + throw std::runtime_error(e.str()); + } + + if (::close(s_comm_pipe[1])) { + std::stringstream e; + + e << "Failed to close communication pipe: " << errno; + + throw std::runtime_error(e.str()); + } + + s_comm_pipe[1] = -1; +#endif +} + + +template +Signal::HandlerThread::~HandlerThread() throw(std::runtime_error) { + // Stop the thread unless already stopped + if (-1 != s_comm_pipe[1]) + quit(); +} + + +int Signal::send(Signal::enum_t signame, pid_t pid) throw(std::logic_error) { + int sig = (int)signame; + + int status = ::kill(pid, sig); + + if (0 == status) + return 0; + + if (EINVAL != errno) + return errno; + + std::stringstream e; + + e << "Can't send invalid signal " << sig; + + throw std::logic_error(e.str()); +} + +} // end of namespace nut diff --git a/include/Makefile.am b/include/Makefile.am index 6f066dd487..eea95ee0ad 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,6 @@ dist_noinst_HEADERS = attribute.h common.h extstate.h parseconf.h proto.h \ state.h timehead.h upsconf.h nut_stdint.h nut_platform.h nutstream.h \ - nutwriter.h + nutwriter.h nutipc.hpp # http://www.gnu.org/software/automake/manual/automake.html#Clean BUILT_SOURCES = nut_version.h diff --git a/include/nutipc.hpp b/include/nutipc.hpp new file mode 100644 index 0000000000..227ef51e8d --- /dev/null +++ b/include/nutipc.hpp @@ -0,0 +1,415 @@ +/* nutipc.hpp - NUT IPC + + Copyright (C) 2012 Eaton + + Author: Vaclav Krpec + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef NUT_NUTIPC_HPP +#define NUT_NUTIPC_HPP + +#include +#include + +extern "C" { +#include +#include +#include +} + + +namespace nut { + +/** + * Process-related information + */ +class Process { + private: + + /** The type yields no instances */ + Process() {} + + public: + + /** Get current process ID */ + static pid_t getPID() throw(); + + /** Get parent process ID */ + static pid_t getPPID() throw(); + + /** + * Process main routine functor prototype + */ + class Main { + protected: + + /** Formal constructor */ + Main() {} + + public: + + /** Routine */ + virtual int operator () () = 0; + + }; // end of class Main + + /** + * Child process + */ + template + class Child { + private: + + pid_t m_pid; /**< Child PID */ + bool m_exited; /**< Exited flag */ + int m_exit_code; /**< Exit code */ + + public: + + /** + * \brief Constructor of child process + * + * The constructor calls \c ::fork to create another child process. + * The child executes \ref m_main functor instance operator \c (). + * When the functor's \c () operator returns, the returned value + * shall be used as the child exit code (and the child will exit). + * + * \param main Child process main routine + */ + Child(M main) throw(std::runtime_error); + + /** + * \brief Wait for child process to exit + * + * The method blocks as long as the child runs. + * It returns the child's exit code. + * It throws an exception if executed twice + * (or on other illogical usage). + * + * \return Child process exit code + */ + int wait() throw(std::logic_error); + + /** + * \brief Child exit code getter + * + * \return Child exit code + */ + inline int exitCode() { + if (!m_exited) { + m_exit_code = wait(); + + m_exited = true; + } + + return m_exit_code; + } + + /** + * \brief Destructor + * + * The destructor shall wait for the child process + * (unless already exited). + */ + ~Child() { + if (!m_exited) + wait(); + } + + }; // end of class Child + + /** + * External command executor + */ + class Executor: public Main { + public: + + /** Command line arguments list */ + typedef std::list Arguments; + + private: + + const std::string m_bin; + const Arguments m_args; + + public: + + /** + * \brief Constructor + * + * The binary path may be omitted; the implementation shall perform + * the actions shell would do to search for the binary (i.e. check \c PATH + * environment variable); + * + * Note that even option switches are command line arguments; + * e.g. "tail -n 20" command has 2 arguments: "-n" and "20". + * + * \brief bin Binary to be executed + * \brief args Command-line arguments to the binary + */ + Executor(const std::string & bin, const Arguments & args): + m_bin(bin), m_args(args) {} + + /** + * \brief Constructor + * + * This constructor form splits the command string specified + * to the binary and its cmd-line arguments for the caller (by spaces). + * + * Note however, that the command must be a binary execution; if you want + * to run a shell command, you must execute the shell, explicitly; e.g: + * "/bin/sh -c ''" shall probably be what you want. + * + * \param command Command to be executed + */ + Executor(const std::string & command); + + /** Execution of the binary */ + int operator () () throw(std::runtime_error); + + }; // end of class Executor + + /** + * External command execution + */ + class Execution: public Child { + public: + + /** + * Constructor + * + * The binary path may be omitted; the implementation shall perform + * the actions shell would do to search for the binary (i.e. check \c PATH + * environment variable); + * + * \brief binary Binary to be executed + * \brief arguments Command-line arguments to the binary + */ + Execution(const std::string & binary, const Executor::Arguments & arguments): + Child(Executor(binary, arguments)) {} + + /** + * Constructor + * + * This form of the constructor splits the command string specified + * to the binary and its cmd-line arguments for the caller (by spaces). + * + * Note however, that the command must be a binary execution; if you want + * to run a shell command, you must execute the shell, explicitly; e.g: + * "/bin/sh -c ''" shall probably be what you want. + * + * \param command Command to be executed + */ + Execution(const std::string & command): Child(Executor(command)) {} + + }; // end of class Execution + +}; // end of class Process + + +/** + * POSIX signal + * + * For portability reasons, only mostly common subset of POSIX.1-2001 signals are supported. + */ +class Signal { + public: + + /** Signals */ + typedef enum { + HUP = SIGHUP, /** Hangup */ + INT = SIGINT, /** Interrupt */ + QUIT = SIGQUIT, /** Quit */ + ILL = SIGILL, /** Illegal Instruction */ + TRAP = SIGTRAP, /** Trace/breakpoint trap */ + ABORT = SIGABRT, /** Abort */ + BUS = SIGBUS, /** Bus error (bad memory access) */ + FPE = SIGFPE, /** Floating point exception */ + KILL = SIGKILL, /** Kill (unmaskable) */ + SEGV = SIGSEGV, /** Invalid memory reference */ + PIPE = SIGPIPE, /** Broken pipe */ + ALARM = SIGALRM, /** Alarm */ + TERM = SIGTERM, /** Termination */ + USER1 = SIGUSR1, /** User-defined signal 1 */ + USER2 = SIGUSR1, /** User-defined signal 2 */ + CHILD = SIGCHLD, /** Child stopped or terminated */ + CONT = SIGCONT, /** Continue if stopped */ + STOP = SIGSTOP, /** Stop process (unmaskable) */ + TSTOP = SIGTSTP, /** Stop typed at tty */ + TTYIN = SIGTTIN, /** tty input for background process */ + TTYOUT = SIGTTOU, /** tty output for background process */ + PROF = SIGPROF, /** Profiling timer expired */ + SYS = SIGSYS, /** Bad argument to routine */ + URG = SIGURG, /** Urgent condition on socket */ + VTALRM = SIGVTALRM, /** Virtual alarm clock */ + XCPU = SIGXCPU, /** CPU time limit exceeded */ + XFSZ = SIGXFSZ, /** File size limit exceeded */ + } enum_t; // end of typedef enum + + /** Signal list */ + typedef std::list List; + + /** + * \brief Signal handler + * + * Signal handler interface. + */ + class Handler { + protected: + + /** Formal constructor */ + Handler() {} + + public: + + /** + * \brief Signal handler routine + * + * \param signal Signal + */ + virtual void operator () (enum_t signal) = 0; + + /** Formal destructor */ + virtual ~Handler() {} + + }; // end of class Handler + + private: + + /** Formal constructor */ + Signal() {} + + public: + + /** Signal handler thread handle */ + template + class HandlerThread { + friend class Signal; + + private: + + /** Control commands */ + typedef enum { + QUIT = 0, /**< Shutdown the thread */ + SIGNAL = 1, /**< Signal obtained */ + } command_t; + + /** Communication pipe */ + static int s_comm_pipe[2]; + + /** + * \brief Signal handler thread main routine + * + * The function synchronously read commands from the communication pipe. + * It processes control commands on its own (e.g. the quit command). + * It passes all signals to signal handler instance of \ref H + * Which must implement the \ref Signal::Handler interface. + * The handler is instantiated in scope of the routine. + * It closes the communication pipe read end in reaction to \ref QUIT command. + * + * \param comm_pipe_read_end Communication pipe read end + * + * \retval N/A (the function never returns) + */ + static void * main(void * comm_pipe_read_end); + + /** + * \brief Signal handler routine + * + * The actual signal handler routine executed by the OS when the process + * obtains signal to be handled. + * The function simply writes the signal number to the signal handler + * thread communication pipe (as parameter of the \ref SIGNAL command). + * The signal handling itself (whatever necessary) shall be done + * by the dedicated thread (to avoid possible re-entrancy issues). + * + * Note that \c ::write is required to be an async-signal-safe function by + * POSIX.1-2004; also note that up to \c PIPE_BUF bytes are written atomicaly + * as required by IEEE Std 1003.1, 2004 Edition,\c PIPE_BUF being typically + * hundreds of bytes at least (POSIX requires 512B, Linux provides whole 4KiB + * page). + * + * \param signal Signal + */ + static void signalNotifier(int signal); + + /** + * \brief Constructor + * + * The threads are only created by the (friend) Signal class + * functions. + * At most one thread per handler instance may be created. + * This limitation is both due sanity reasons (it wouldn't + * make much sense to handle the same signal by multiple threads) + * and because of the signal handler routine only has access + * to one communication pipe write end (the static member). + * This is actually the only technical reason of having the class + * template (so that every instance has its own static comm. queue). + * However, for different handler classes, multiple handling threads + * may be created (if it makes sense) since these will be different + * template instances and therefore will use different static + * communication pipes. + * If more than 1 instance creation is attempted, an exception is thrown. + * + * \param siglist List of signals that shall be handled by the thread + */ + HandlerThread(const Signal::List & siglist) throw(std::logic_error, std::runtime_error); + + public: + + /** + * \brief Terminate the thread + * + * The method sends the signal handler thread the \ref QUIT signal. + * It blocks until the thread is joined. + * Closes the communication pipe write end. + */ + void quit() throw(std::runtime_error); + + /** + * \brief Destructor + * + * Forces the signal handler thread termination (unless already down). + */ + ~HandlerThread() throw(std::runtime_error); + + }; // end of HandlerThread + + /** + * \brief Send signal to a process + * + * An exception is thrown if the signal isn't implemented. + * + * \param signame Signal name + * \param pid Process ID + * + * \retval 0 in case of success + * \retval EPERM if the process doesn't have permission to send the signal + * \retval ESRCH if the process (group) identified doesn't exist + */ + static int send(enum_t signame, pid_t pid) throw(std::logic_error); + +}; // end of class Signal + + +/** Initialisation of the communication pipes */ +template +int Signal::HandlerThread::s_comm_pipe[2] = { -1, -1 }; + +} // end of namespace nut + +#endif /* end of #ifndef NUT_NUTIPC_H */ From f364e223b277432a61ba2f9468be2450c51f1fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Kia?= Date: Thu, 20 Dec 2012 14:41:51 +0100 Subject: [PATCH 031/121] Add a little sample to use libconf. Special dedicace to Fred. --- common/Makefile.am | 5 +++ common/nutconfbin.cpp | 74 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 common/nutconfbin.cpp diff --git a/common/Makefile.am b/common/Makefile.am index 2fe226c4fa..910018c47d 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -15,3 +15,8 @@ libcommon_la_SOURCES = common.c state.c upsconf.c # ensure inclusion of local implementation of missing systems functions # using LTLIBOBJS. Refer to configure.in -> AC_REPLACE_FUNCS libcommon_la_LIBADD = libparseconf.la @LTLIBOBJS@ + +#EKI : libconf example program +noinst_PROGRAMS = nutconf +nutconf_SOURCES = nutconfbin.cpp +nutconf_LDADD = libnutconf.la libcommon.la diff --git a/common/nutconfbin.cpp b/common/nutconfbin.cpp new file mode 100644 index 0000000000..0c4624b0ee --- /dev/null +++ b/common/nutconfbin.cpp @@ -0,0 +1,74 @@ + +#include "nutconf.h" +#include "nutstream.h" +using namespace nut; + +#include +using namespace std; + +int main(int argc, char** argv) +{ + cout << "nutconf testing program" << endl; + + if(argc<2) + { + cout << "Usage: nutconf {ups.conf path}" << endl; + return 0; + } + + // + // UPS.CONF + // + if(argc>=2) + { + cout << endl << "ups.conf:" << endl << endl; + + GenericConfiguration ups_conf; + NutFile file(argv[1]); + file.open(); + ups_conf.parseFrom(file); + + for(std::map::iterator it = ups_conf.sections.begin(); + it != ups_conf.sections.end(); ++it) + { + GenericConfigSection& section = it->second; + cout << "[" << section.name << "]" << endl; + + for(GenericConfigSection::EntryMap::iterator iter = section.entries.begin(); + iter != section.entries.end(); ++iter) + { + cout << " " << iter->first << " = " << iter->second.values.front() << endl; + } + } + } + + // + // UPSD.CONF + // + if(argc>=3) + { + cout << endl << "upsd.conf:" << endl << endl; + + UpsdConfiguration upsd_conf; + NutFile file(argv[2]); + file.open(); + upsd_conf.parseFrom(file); + + cout << "maxAge: " << upsd_conf.maxAge << endl; + cout << "maxConn: " << upsd_conf.maxConn << endl; + cout << "statePath: " << *upsd_conf.statePath << endl; + cout << "certFile: " << *upsd_conf.certFile << endl; + cout << "listen:" << endl; + + for(std::list::iterator it=upsd_conf.listens.begin(); + it!=upsd_conf.listens.end(); ++it) + { + cout << " - " << it->address << ":" << it->port << endl; + } + } + + return 0; + + +} + From e9e07521267f6e8f1179df4948f5fc59639307ca Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Mon, 7 Jan 2013 12:33:06 +0100 Subject: [PATCH 032/121] nutipc: linking cleanup & exec UT --- common/nutipc.cpp | 275 ++------------------------------------------ include/nutipc.hpp | 271 +++++++++++++++++++++++++++++++++++++++++-- tests/Makefile.am | 4 +- tests/nutipc_ut.cpp | 69 +++++++++++ 4 files changed, 345 insertions(+), 274 deletions(-) create mode 100644 tests/nutipc_ut.cpp diff --git a/common/nutipc.cpp b/common/nutipc.cpp index 28f7b89d88..49b4084073 100644 --- a/common/nutipc.cpp +++ b/common/nutipc.cpp @@ -21,21 +21,6 @@ #include "nutipc.hpp" -#include - -#include -#include -#include -#include - -extern "C" { -#include -#include -#include -#include -#include -} - namespace nut { @@ -49,39 +34,6 @@ pid_t Process::getPPID() throw() { } -template -Process::Child::Child(M main) throw(std::runtime_error): - m_pid(0), - m_exited(false), - m_exit_code(0) -{ - m_pid = ::fork(); - - if (!m_pid) - ::exit(main()); -} - - -template -int Process::Child::wait() throw(std::logic_error) { - int exit_code; - pid_t wpid = ::waitpid(m_pid, &exit_code, 0); - - if (-1 == m_pid) { - int erno = errno; - - std::stringstream e; - - e << "Failed to wait for process " << m_pid << ": "; - e << erno << ": " << strerror(erno); - - throw std::logic_error(e.str()); - } - - return exit_code; -} - - Process::Executor::Executor(const std::string & command) { //m_bin m_args throw std::runtime_error("TODO: Not implemented, yet"); @@ -89,15 +41,23 @@ Process::Executor::Executor(const std::string & command) { int Process::Executor::operator () () throw(std::runtime_error) { - const char ** args_c_str = new const char *[m_args.size()]; + const char ** args_c_str = new const char *[m_args.size() + 2]; + + const char * bin_c_str = m_bin.c_str(); + + args_c_str[0] = bin_c_str; Arguments::const_iterator arg = m_args.begin(); - for (size_t i = 0; arg != m_args.end(); ++arg, ++i) { + size_t i = 1; + + for (; arg != m_args.end(); ++arg, ++i) { args_c_str[i] = (*arg).c_str(); } - int status = ::execvp(m_bin.c_str(), (char * const *)args_c_str); + args_c_str[i] = NULL; + + int status = ::execvp(bin_c_str, (char * const *)args_c_str); // Upon successful execution, the execvp function never returns // (since the process context is replaced, completely) @@ -112,98 +72,7 @@ int Process::Executor::operator () () throw(std::runtime_error) { } -template -void * Signal::HandlerThread::main(void * comm_pipe_read_end) { - int rfd = *(int *)comm_pipe_read_end; - - H handler; - - for (;;) { - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(rfd, &rfds); - - // Poll on signal pipe - // Note that direct blocking read could be also used; - // however, select allows timeout specification - // which might come handy... - int fdno = ::select(1, &rfds, NULL, NULL, NULL); - - // TBD: Die or recover on error? - if (-1 == fdno) { - std::stringstream e; - - e << "Poll on communication pipe read end "; - e << rfd << " failed: " << errno; - - throw std::runtime_error(e.str()); - } - - assert(1 == fdno); - assert(FD_ISSET(rfd, &rfds)); - - // Read command - int word; - - ssize_t read_out = ::read(rfd, &word, sizeof(word)); - - // TBD: again, how should we treat read error? - if (-1 == read_out) { - std::stringstream e; - - e << "Failed to read command from the command pipe: "; - e << errno; - - throw std::runtime_error(e.str()); - } - - assert(sizeof(word) == read_out); - - command_t command = reinterpret_cast(word); - - switch (command) { - case QUIT: - pthread_exit(NULL); - - case SIGNAL: - // Read signal number - read_out = ::read(rfd, &word, sizeof(word)); - - // TBD: again, how should we treat read error? - if (-1 == read_out) { - std::stringstream e; - - e << "Failed to read signal number "; - e << "from the command pipe: " << errno; - - throw std::runtime_error(e.str()); - } - - assert(sizeof(word) == read_out); - - Signal::enum_t sig = reinterpret_cast(word); - - // Handle signal - handler(sig); - } - } - - // Pro-forma exception - throw std::logic_error("INTERNAL ERROR: Unreachable code reached"); -} - - -/** - * \brief Write command to command pipe - * - * \param fh Pipe writing end - * \param cmd Command - * \param cmd_size Comand size - * - * \retval 0 on success - * \retval errno on error - */ -static int writeCommand(int fh, void * cmd, size_t cmd_size) throw(std::runtime_error) { +int writeCommand(int fh, void * cmd, size_t cmd_size) throw(std::runtime_error) { char * cmd_bytes = reinterpret_cast(cmd); do { @@ -221,126 +90,6 @@ static int writeCommand(int fh, void * cmd, size_t cmd_size) throw(std::runtime_ } -template -void Signal::HandlerThread::signalNotifier(int signal) { - int sig[2] = { - reinterpret_cast(Signal::HandlerThread::SIGNAL), - }; - - sig[1] = signal; - - // TBD: The return value is silently ignored. - // Either the write should've succeeded or the handling - // thread is already comming down... - writeCommand(s_comm_pipe[1], sig, sizeof(sig)); -} - - -template -Signal::HandlerThread::HandlerThread(const Signal::List & siglist) throw(std::logic_error, std::runtime_error) { - /* - * IMPLEMENTATION NOTES: - * 0/ Check whether comm. pipe is valid; throw std::logic_error if so - * 1/ Comm. pipe creation (or an exception) - * 2/ Start the thread: pthread_create(m_impl, , ) - * 3/ Register the signals: sigaction( ) - */ - throw std::runtime_error("TODO: Signal handler thread is not implemented, yet"); - - if (-1 != s_comm_pipe[1]) - throw std::logic_error("Attempt to start a duplicate of signal handling thread detected"); - - // Create communication pipe - if (::pipe(s_comm_pipe)) { - std::stringstream e; - - e << "Failed to create communication pipe: " << errno; - - throw std::runtime_error(e.str()); - } - - // TODO: -#if (0) - // Start the thread - int status = ::pthread_create(&m_impl, NULL, main, s_comm_pipe); - - if (status) { - std::stringstream e; - - e << "Failed to start the thread: " << status; - - throw std::runtime_error(e.str()); - } - - // Register signals - Signal::List::const_iterator sig = siglist.begin(); - - for (; sig != siglist.end(); ++sig) { - struct sigaction action; - - action.sa_handler = signalNotifier; - action.sa_sigaction = NULL; // guess we don't need signal info - action.sa_mask = 0; // shouldn't we mask signals while handling them? - action.sa_flags = 0; // any flags? - action.sa_restorer = NULL; // obsolete - - int signo = static_cast(*sig); - - // TBD: We might want to save the old handlers... - status = ::sigaction(signo, &action, NULL); - - if (status) { - std::stringstream e; - - e << "Failed to register signal handler for signal "; - e << signo << ": " << errno; - - throw std::runtime_error(e.str()); - } - } -#endif -} - - -template -void Signal::HandlerThread::quit() throw(std::runtime_error) { - static int quit = reinterpret_cast(Signal::HandlerThread::QUIT); - - writeCommand(s_comm_pipe[1], quit, sizeof(quit)); - - // TODO: -#if (0) - int status = ::pthread_join(m_impl); - - if (status) { - std::stringstream e; - - e << "Failed to joint signal handling thread: " << status; - - throw std::runtime_error(e.str()); - } - - if (::close(s_comm_pipe[1])) { - std::stringstream e; - - e << "Failed to close communication pipe: " << errno; - - throw std::runtime_error(e.str()); - } - - s_comm_pipe[1] = -1; -#endif -} - - -template -Signal::HandlerThread::~HandlerThread() throw(std::runtime_error) { - // Stop the thread unless already stopped - if (-1 != s_comm_pipe[1]) - quit(); -} - - int Signal::send(Signal::enum_t signame, pid_t pid) throw(std::logic_error) { int sig = (int)signame; diff --git a/include/nutipc.hpp b/include/nutipc.hpp index 227ef51e8d..c415db8b2b 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -24,11 +24,19 @@ #include #include +#include + +#include +#include +#include +#include extern "C" { #include #include #include +#include +#include } @@ -110,13 +118,7 @@ class Process { * \return Child exit code */ inline int exitCode() { - if (!m_exited) { - m_exit_code = wait(); - - m_exited = true; - } - - return m_exit_code; + return wait(); } /** @@ -126,8 +128,7 @@ class Process { * (unless already exited). */ ~Child() { - if (!m_exited) - wait(); + wait(); } }; // end of class Child @@ -221,6 +222,44 @@ class Process { }; // end of class Process +template +Process::Child::Child(M main) throw(std::runtime_error): + m_pid(0), + m_exited(false), + m_exit_code(0) +{ + m_pid = ::fork(); + + if (!m_pid) + ::exit(main()); +} + + +template +int Process::Child::wait() throw(std::logic_error) { + if (m_exited) + return m_exit_code; + + pid_t wpid = ::waitpid(m_pid, &m_exit_code, 0); + + if (-1 == m_pid) { + int erno = errno; + + std::stringstream e; + + e << "Failed to wait for process " << m_pid << ": "; + e << erno << ": " << strerror(erno); + + throw std::logic_error(e.str()); + } + + m_exited = true; + m_exit_code = WEXITSTATUS(m_exit_code); + + return m_exit_code; +} + + /** * POSIX signal * @@ -410,6 +449,220 @@ class Signal { template int Signal::HandlerThread::s_comm_pipe[2] = { -1, -1 }; + +template +void * Signal::HandlerThread::main(void * comm_pipe_read_end) { + int rfd = *(int *)comm_pipe_read_end; + + H handler; + + for (;;) { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(rfd, &rfds); + + // Poll on signal pipe + // Note that direct blocking read could be also used; + // however, select allows timeout specification + // which might come handy... + int fdno = ::select(1, &rfds, NULL, NULL, NULL); + + // TBD: Die or recover on error? + if (-1 == fdno) { + std::stringstream e; + + e << "Poll on communication pipe read end "; + e << rfd << " failed: " << errno; + + throw std::runtime_error(e.str()); + } + + assert(1 == fdno); + assert(FD_ISSET(rfd, &rfds)); + + // Read command + int word; + + ssize_t read_out = ::read(rfd, &word, sizeof(word)); + + // TBD: again, how should we treat read error? + if (-1 == read_out) { + std::stringstream e; + + e << "Failed to read command from the command pipe: "; + e << errno; + + throw std::runtime_error(e.str()); + } + + assert(sizeof(word) == read_out); + + command_t command = reinterpret_cast(word); + + switch (command) { + case QUIT: + pthread_exit(NULL); + + case SIGNAL: + // Read signal number + read_out = ::read(rfd, &word, sizeof(word)); + + // TBD: again, how should we treat read error? + if (-1 == read_out) { + std::stringstream e; + + e << "Failed to read signal number "; + e << "from the command pipe: " << errno; + + throw std::runtime_error(e.str()); + } + + assert(sizeof(word) == read_out); + + Signal::enum_t sig = reinterpret_cast(word); + + // Handle signal + handler(sig); + } + } + + // Pro-forma exception + throw std::logic_error("INTERNAL ERROR: Unreachable code reached"); +} + + +/** + * \brief Write command to command pipe + * + * \param fh Pipe writing end + * \param cmd Command + * \param cmd_size Comand size + * + * \retval 0 on success + * \retval errno on error + */ +int writeCommand(int fh, void * cmd, size_t cmd_size) throw(std::runtime_error); + + +template +void Signal::HandlerThread::signalNotifier(int signal) { + int sig[2] = { + reinterpret_cast(Signal::HandlerThread::SIGNAL), + }; + + sig[1] = signal; + + // TBD: The return value is silently ignored. + // Either the write should've succeeded or the handling + // thread is already comming down... + writeCommand(s_comm_pipe[1], sig, sizeof(sig)); +} + + +template +Signal::HandlerThread::HandlerThread(const Signal::List & siglist) throw(std::logic_error, std::runtime_error) { + /* + * IMPLEMENTATION NOTES: + * 0/ Check whether comm. pipe is valid; throw std::logic_error if so + * 1/ Comm. pipe creation (or an exception) + * 2/ Start the thread: pthread_create(m_impl, , ) + * 3/ Register the signals: sigaction( ) + */ + throw std::runtime_error("TODO: Signal handler thread is not implemented, yet"); + + if (-1 != s_comm_pipe[1]) + throw std::logic_error("Attempt to start a duplicate of signal handling thread detected"); + + // Create communication pipe + if (::pipe(s_comm_pipe)) { + std::stringstream e; + + e << "Failed to create communication pipe: " << errno; + + throw std::runtime_error(e.str()); + } + + // TODO: +#if (0) + // Start the thread + int status = ::pthread_create(&m_impl, NULL, main, s_comm_pipe); + + if (status) { + std::stringstream e; + + e << "Failed to start the thread: " << status; + + throw std::runtime_error(e.str()); + } + + // Register signals + Signal::List::const_iterator sig = siglist.begin(); + + for (; sig != siglist.end(); ++sig) { + struct sigaction action; + + action.sa_handler = signalNotifier; + action.sa_sigaction = NULL; // guess we don't need signal info + action.sa_mask = 0; // shouldn't we mask signals while handling them? + action.sa_flags = 0; // any flags? + action.sa_restorer = NULL; // obsolete + + int signo = static_cast(*sig); + + // TBD: We might want to save the old handlers... + status = ::sigaction(signo, &action, NULL); + + if (status) { + std::stringstream e; + + e << "Failed to register signal handler for signal "; + e << signo << ": " << errno; + + throw std::runtime_error(e.str()); + } + } +#endif +} + + +template +void Signal::HandlerThread::quit() throw(std::runtime_error) { + static int quit = reinterpret_cast(Signal::HandlerThread::QUIT); + + writeCommand(s_comm_pipe[1], quit, sizeof(quit)); + + // TODO: +#if (0) + int status = ::pthread_join(m_impl); + + if (status) { + std::stringstream e; + + e << "Failed to joint signal handling thread: " << status; + + throw std::runtime_error(e.str()); + } + + if (::close(s_comm_pipe[1])) { + std::stringstream e; + + e << "Failed to close communication pipe: " << errno; + + throw std::runtime_error(e.str()); + } + + s_comm_pipe[1] = -1; +#endif +} + + +template +Signal::HandlerThread::~HandlerThread() throw(std::runtime_error) { + // Stop the thread unless already stopped + if (-1 != s_comm_pipe[1]) + quit(); +} + } // end of namespace nut #endif /* end of #ifndef NUT_NUTIPC_H */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 5729d4de01..663a5af21e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -11,12 +11,12 @@ cppunittest_LDFLAGS = $(CPPUNIT_LIBS) cppunittest_LDADD = ../common/libnutconf.la # List of src files for CppUnit tests -CPPUNITTESTSRC = example.cpp nutconf.cpp nutstream_ut.cpp nutconf_ut.cpp +CPPUNITTESTSRC = example.cpp nutconf.cpp nutstream_ut.cpp nutconf_ut.cpp nutipc_ut.cpp cppunittest_SOURCES = $(CPPUNITTESTSRC) cpputest.cpp else !HAVE_CPPUNIT -EXTRA_DIST = example.cpp nutconf.cpp cpputest.cpp nutstream_ut.cpp nutconf_ut.cpp +EXTRA_DIST = example.cpp nutconf.cpp cpputest.cpp nutstream_ut.cpp nutconf_ut.cpp mnutipc_ut.cpp endif !HAVE_CPPUNIT diff --git a/tests/nutipc_ut.cpp b/tests/nutipc_ut.cpp new file mode 100644 index 0000000000..35d1ca4fa5 --- /dev/null +++ b/tests/nutipc_ut.cpp @@ -0,0 +1,69 @@ +/* +NUT IPC unit test + +Copyright (C) 2012 + +\author Vaclav Krpec + +This program 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 2 of the License, or +(at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "nutipc.hpp" + +#include + + +/** + * \brief NUT IPC module unit test + */ +class NutIPCUnitTest: public CppUnit::TestFixture { + private: + + CPPUNIT_TEST_SUITE(NutIPCUnitTest); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); + + /** External command execution test */ + void testExec(); + + public: + + inline void setUp() {} + inline void tearDown() {} + + inline void test() { + testExec(); + } + +}; // end of class NutIPCUnitTest + + +// Register the test suite +CPPUNIT_TEST_SUITE_REGISTRATION(NutIPCUnitTest); + + +void NutIPCUnitTest::testExec() { + static const std::string bin = "/bin/sh"; + + static nut::Process::Executor::Arguments bin_args; + + bin_args.push_back("-c"); + bin_args.push_back("exit 123"); + + nut::Process::Execution child(bin, bin_args); + + CPPUNIT_ASSERT(123 == child.wait()); +} From 475580a7a132574825a76c42502e52a163652c50 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Mon, 7 Jan 2013 15:40:59 +0100 Subject: [PATCH 033/121] nutipc: ext. command execution improvements The command line segmentation is finally implemented. nut::Process::execute static functions added for simplicity of usage. --- common/nutipc.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++++- include/nutipc.hpp | 31 ++++++++++++++- tests/nutipc_ut.cpp | 2 + 3 files changed, 123 insertions(+), 4 deletions(-) diff --git a/common/nutipc.cpp b/common/nutipc.cpp index 49b4084073..793b8128ca 100644 --- a/common/nutipc.cpp +++ b/common/nutipc.cpp @@ -21,6 +21,8 @@ #include "nutipc.hpp" +#include + namespace nut { @@ -34,9 +36,97 @@ pid_t Process::getPPID() throw() { } +/** + * \brief Command line segmentation + * + * The function parses the \c command and chops off (and return) + * the first command line word (i.e. does segmentation based + * on white spaces, unless quoted). + * White spaces are removed from the returned words. + * + * \param[in,out] command Command line + * + * \return Command line word + */ +static std::string getCmdLineWord(std::string & command) { + size_t len = 0; + + // Remove initial whitespace + while (len < command.size()) { + if (' ' != command[len] && '\t' != command[len]) + break; + + ++len; + } + + command.erase(0, len); + + // Seek word end + bool bslsh = false; + char quote = 0; + + for (len = 0; len < command.size(); ++len) { + char ch = command[len]; + + // White space (may be inside quotes) + if (' ' == ch || '\t' == ch) { + if (!quote) + break; + } + + // Backspace (second one cancels the first) + else if ('\\' == ch) { + bslsh = bslsh ? false : true; + } + + // Double quote (may be escaped or nested) + else if ('"' == ch) { + if (!bslsh) { + if (!quote) + quote = '"'; + + // Final double quote + else if ('"' == quote) + quote = 0; + } + } + + // Single quote (can't be escaped) + else if ('\'' == ch) { + if (!quote) + quote = '\''; + + else if ('\'' == quote) + quote = 0; + } + + // Cancel backslash + if ('\\' != ch) + bslsh = false; + } + + // Extract the word + std::string word = command.substr(0, len); + + command.erase(0, len); + + return word; +} + + Process::Executor::Executor(const std::string & command) { - //m_bin m_args - throw std::runtime_error("TODO: Not implemented, yet"); + std::string cmd(command); + + m_bin = getCmdLineWord(cmd); + + for (;;) { + std::string arg = getCmdLineWord(cmd); + + if (arg.empty()) + break; + + m_args.push_back(arg); + } } diff --git a/include/nutipc.hpp b/include/nutipc.hpp index c415db8b2b..939e57c719 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -144,8 +144,8 @@ class Process { private: - const std::string m_bin; - const Arguments m_args; + std::string m_bin; + Arguments m_args; public: @@ -219,6 +219,33 @@ class Process { }; // end of class Execution + /** + * \brief Execute command and wait for exit code + * + * \param binary Binary to be executed + * \param arguments Command-line arguments to the binary + * + * \return Exit code + */ + static inline int execute(const std::string & binary, const Executor::Arguments & arguments) { + Execution child(binary, arguments); + + return child.wait(); + } + + /** + * \brief Execute command and wait for exit code + * + * \param command Command to be executed + * + * \return Exit code + */ + static inline int execute(const std::string & command) { + Execution child(command); + + return child.wait(); + } + }; // end of class Process diff --git a/tests/nutipc_ut.cpp b/tests/nutipc_ut.cpp index 35d1ca4fa5..f99bd40380 100644 --- a/tests/nutipc_ut.cpp +++ b/tests/nutipc_ut.cpp @@ -66,4 +66,6 @@ void NutIPCUnitTest::testExec() { nut::Process::Execution child(bin, bin_args); CPPUNIT_ASSERT(123 == child.wait()); + + CPPUNIT_ASSERT(0 == nut::Process::execute("test 'Hello world' == 'Hello world'")); } From 6d6e56aca4c9e96e169e46bfdef9e2b98c010531 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Tue, 8 Jan 2013 13:48:28 +0100 Subject: [PATCH 034/121] nutipc: signal sending UTs nut::Signal::send via PIDfile and nut::NutSignal::send via process name added, too. Minor backwards-compatible changes in nutstream (file removal methods). --- common/nutconf.cpp | 2 +- common/nutconfbin.cpp | 2 +- common/nutipc.cpp | 46 +++++++++++++++ common/nutstream.cpp | 19 +++++- common/nutwriter.cpp | 2 +- include/Makefile.am | 4 +- include/nutconf.h | 2 +- include/nutipc.hpp | 43 ++++++++++++++ include/{nutstream.h => nutstream.hpp} | 40 ++++++++++++- include/{nutwriter.h => nutwriter.hpp} | 4 +- tests/nutconf_ut.cpp | 4 +- tests/nutipc_ut.cpp | 81 ++++++++++++++++++++++++-- tests/nutstream_ut.cpp | 2 +- 13 files changed, 233 insertions(+), 18 deletions(-) rename include/{nutstream.h => nutstream.hpp} (96%) rename include/{nutwriter.h => nutwriter.hpp} (99%) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index fb478d14c7..3e7d91c1d8 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -19,7 +19,7 @@ */ #include "nutconf.h" -#include "nutwriter.h" +#include "nutwriter.hpp" #include #include diff --git a/common/nutconfbin.cpp b/common/nutconfbin.cpp index 0c4624b0ee..a1b21bdee7 100644 --- a/common/nutconfbin.cpp +++ b/common/nutconfbin.cpp @@ -1,6 +1,6 @@ #include "nutconf.h" -#include "nutstream.h" +#include "nutstream.hpp" using namespace nut; #include diff --git a/common/nutipc.cpp b/common/nutipc.cpp index 793b8128ca..f9dfca035d 100644 --- a/common/nutipc.cpp +++ b/common/nutipc.cpp @@ -20,6 +20,8 @@ */ #include "nutipc.hpp" +#include "nutstream.hpp" +#include "config.h" #include @@ -198,4 +200,48 @@ int Signal::send(Signal::enum_t signame, pid_t pid) throw(std::logic_error) { throw std::logic_error(e.str()); } + +int Signal::send(Signal::enum_t signame, const std::string & pid_file) { + NutFile file(pid_file, NutFile::READ_ONLY); + + std::string pid_str; + + NutStream::status_t read_st = file.getString(pid_str); + + if (NutStream::NUTS_OK != read_st) { + std::stringstream e; + + e << "Failed to read PID from " << pid_file << ": " << read_st; + + throw std::runtime_error(e.str()); + } + + std::stringstream pid_conv(pid_str); + + pid_t pid; + + if (!(pid_conv >> pid)) { + std::stringstream e; + + e << "Failed to convert contents of " << pid_file << " to PID"; + + throw std::runtime_error(e.str()); + } + + return send(signame, pid); +} + + +int NutSignal::send(NutSignal::enum_t signame, const std::string & process) { + std::string pid_file; + + // TBD: What's ALTPIDPATH and shouldn't we also consider it? + pid_file += PIDPATH; + pid_file += '/'; + pid_file += process; + pid_file += ".pid"; + + return Signal::send(signame, pid_file); +} + } // end of namespace nut diff --git a/common/nutstream.cpp b/common/nutstream.cpp index 0f020fdf2d..34286a7fef 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "nutstream.h" +#include "nutstream.hpp" #include #include @@ -152,7 +152,7 @@ bool NutFile::open(access_t mode, int & err_code, std::string & err_msg) throw() bool NutFile::close(int & err_code, std::string & err_msg) throw() { - err_code = fclose(m_impl); + err_code = ::fclose(m_impl); if (0 != err_code) { err_msg = std::string(::strerror(err_code)); @@ -166,6 +166,21 @@ bool NutFile::close(int & err_code, std::string & err_msg) throw() { } +bool NutFile::remove(int & err_code, std::string & err_msg) throw() { + err_code = ::unlink(m_name.c_str()); + + if (0 != err_code) { + err_code = errno; + + err_msg = std::string(::strerror(err_code)); + + return false; + } + + return true; +} + + NutFile::NutFile(const std::string & name, access_t mode): m_name(name), m_impl(NULL), diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index 9ff88ff316..ee330dc7fa 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "nutwriter.h" +#include "nutwriter.hpp" #include #include diff --git a/include/Makefile.am b/include/Makefile.am index eea95ee0ad..c722f8a934 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,6 @@ dist_noinst_HEADERS = attribute.h common.h extstate.h parseconf.h proto.h \ - state.h timehead.h upsconf.h nut_stdint.h nut_platform.h nutstream.h \ - nutwriter.h nutipc.hpp + state.h timehead.h upsconf.h nut_stdint.h nut_platform.h nutstream.hpp \ + nutwriter.hpp nutipc.hpp # http://www.gnu.org/software/automake/manual/automake.html#Clean BUILT_SOURCES = nut_version.h diff --git a/include/nutconf.h b/include/nutconf.h index 4962b8bf28..2ef4ab39d4 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -21,7 +21,7 @@ #ifndef NUTCONF_H_SEEN #define NUTCONF_H_SEEN 1 -#include "nutstream.h" +#include "nutstream.hpp" #include #include diff --git a/include/nutipc.hpp b/include/nutipc.hpp index 939e57c719..75392d4c08 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -100,6 +100,9 @@ class Process { */ Child(M main) throw(std::runtime_error); + /** Child PID */ + inline pid_t getPID() const { return m_pid; } + /** * \brief Wait for child process to exit * @@ -469,6 +472,21 @@ class Signal { */ static int send(enum_t signame, pid_t pid) throw(std::logic_error); + /** + * \brief Send signal to a process identified via PID file + * + * An exception is thrown if the signal isn't implemented + * or PID file read fails. + * + * \param signame Signal name + * \param pid_file File containing process PID + * + * \retval 0 in case of success + * \retval EPERM if the process doesn't have permission to send the signal + * \retval ESRCH if the process (group) identified doesn't exist + */ + static int send(enum_t signame, const std::string & pid_file); + }; // end of class Signal @@ -690,6 +708,31 @@ Signal::HandlerThread::~HandlerThread() throw(std::runtime_error) { quit(); } + +/** NUT-specific signal handling */ +class NutSignal: public Signal { + public: + + /** + * \brief Send signal to a NUT process + * + * The function assembles process-specific PID file name and path + * and calls \ref Signal::send. + * + * An exception is thrown if the signal isn't implemented + * or PID file read fails. + * + * \param signame Signal name + * \param process File containing process PID + * + * \retval 0 in case of success + * \retval EPERM if the process doesn't have permission to send the signal + * \retval ESRCH if the process (group) identified doesn't exist + */ + static int send(enum_t signame, const std::string & process); + +}; // end of class NutSignal + } // end of namespace nut #endif /* end of #ifndef NUT_NUTIPC_H */ diff --git a/include/nutstream.h b/include/nutstream.hpp similarity index 96% rename from include/nutstream.h rename to include/nutstream.hpp index 9243ab4fa6..16cea7ec7e 100644 --- a/include/nutstream.h +++ b/include/nutstream.hpp @@ -1,4 +1,4 @@ -/* nutstream.h - NUT stream +/* nutstream.hpp - NUT stream Copyright (C) 2012 Vaclav Krpec @@ -344,6 +344,44 @@ class NutFile: public NutStream { throw std::runtime_error(e.str()); } + /** + * \brief Remove file + * + * \param[out] err_code Error code + * \param[out] err-msg Error message + * + * \retval true if \c unlink succeeded + * \retval false if \c unlink failed + */ + bool remove(int & err_code, std::string & err_msg) throw(); + + /** + * \brief Remove file + * + * \retval true if \c unlink succeeded + * \retval false if \c unlink failed + */ + inline bool remove() throw() { + int ec; + std::string em; + + return remove(ec, em); + } + + /** Remove file (or throw exception) */ + inline void removex() throw(std::runtime_error) { + int ec; + std::string em; + + if (remove(ec, em)) + return; + + std::stringstream e; + e << "Failed to remove file " << m_name << ": " << ec << ": " << em; + + throw std::runtime_error(e.str()); + } + /** * \brief Constructor (with open) * diff --git a/include/nutwriter.h b/include/nutwriter.hpp similarity index 99% rename from include/nutwriter.h rename to include/nutwriter.hpp index a98ba82909..ccb50a1605 100644 --- a/include/nutwriter.h +++ b/include/nutwriter.hpp @@ -1,4 +1,4 @@ -/* nutwriter.h - NUT writer +/* nutwriter.hpp - NUT writer Copyright (C) 2012 Vaclav Krpec @@ -23,7 +23,7 @@ #ifdef __cplusplus -#include "nutstream.h" +#include "nutstream.hpp" #include "nutconf.h" #include diff --git a/tests/nutconf_ut.cpp b/tests/nutconf_ut.cpp index 430dcbb961..8f91763197 100644 --- a/tests/nutconf_ut.cpp +++ b/tests/nutconf_ut.cpp @@ -20,9 +20,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "nutstream.h" +#include "nutstream.hpp" #include "nutconf.h" -#include "nutwriter.h" +#include "nutwriter.hpp" #include diff --git a/tests/nutipc_ut.cpp b/tests/nutipc_ut.cpp index f99bd40380..600feeb10a 100644 --- a/tests/nutipc_ut.cpp +++ b/tests/nutipc_ut.cpp @@ -22,9 +22,19 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "nutipc.hpp" +#include "nutstream.hpp" +#include "config.h" #include +#include + +extern "C" { +#include +#include +#include +} + /** * \brief NUT IPC module unit test @@ -39,6 +49,16 @@ class NutIPCUnitTest: public CppUnit::TestFixture { /** External command execution test */ void testExec(); + /** + * \brief Test signal handler + * + * \param signal Signal caught + */ + static void testSignalHandler(int signal); + + /** Signal sending test */ + void testSignalSend(); + public: inline void setUp() {} @@ -46,6 +66,7 @@ class NutIPCUnitTest: public CppUnit::TestFixture { inline void test() { testExec(); + testSignalSend(); } }; // end of class NutIPCUnitTest @@ -58,14 +79,66 @@ CPPUNIT_TEST_SUITE_REGISTRATION(NutIPCUnitTest); void NutIPCUnitTest::testExec() { static const std::string bin = "/bin/sh"; - static nut::Process::Executor::Arguments bin_args; + nut::Process::Executor::Arguments args; - bin_args.push_back("-c"); - bin_args.push_back("exit 123"); + args.push_back("-c"); + args.push_back("exit 123"); - nut::Process::Execution child(bin, bin_args); + nut::Process::Execution child(bin, args); CPPUNIT_ASSERT(123 == child.wait()); CPPUNIT_ASSERT(0 == nut::Process::execute("test 'Hello world' == 'Hello world'")); } + + +/** Last signal caught */ +static int signal_caught = 0; + +void NutIPCUnitTest::testSignalHandler(int signal) { + signal_caught = signal; +} + + +void NutIPCUnitTest::testSignalSend() { + struct sigaction action; + + pid_t my_pid = nut::Process::getPID(); + + // Set SIGUSR1 signal handler + ::memset(&action, 0, sizeof(action)); + ::sigemptyset(&action.sa_mask); + + action.sa_handler = &testSignalHandler; + + CPPUNIT_ASSERT(0 == ::sigaction((int)nut::Signal::USER1, &action, NULL)); + + // Send signal directly + CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, my_pid)); + + CPPUNIT_ASSERT((int)nut::Signal::USER1 == signal_caught); + + signal_caught = 0; + + // Save PID to a PIDfile + static const std::string pid_file_name("/tmp/foobar.pid"); + + std::stringstream my_pid_ss; + + my_pid_ss << my_pid; + + nut::NutFile pid_file(pid_file_name, nut::NutFile::WRITE_ONLY); + + pid_file.putString(my_pid_ss.str()); + + pid_file.closex(); + + // Send signal to process via the PIDfile + CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, pid_file_name)); + + CPPUNIT_ASSERT((int)nut::Signal::USER1 == signal_caught); + + pid_file.removex(); + + signal_caught = 0; +} diff --git a/tests/nutstream_ut.cpp b/tests/nutstream_ut.cpp index 6f578f930f..11d1d374a1 100644 --- a/tests/nutstream_ut.cpp +++ b/tests/nutstream_ut.cpp @@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "nutstream.h" +#include "nutstream.hpp" #include From 0cf62c55416f33f726a6b8c177d9909e2c4ab37b Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Tue, 8 Jan 2013 14:59:51 +0100 Subject: [PATCH 035/121] nutconf: fix of misplaced value quoting Value quoting/escaping is now done generically in nutwriter. --- common/nutconf.cpp | 26 +--- common/nutwriter.cpp | 49 ++++++- include/nutconf.h | 329 +++++++++++++++++++++---------------------- tests/nutconf_ut.cpp | 4 +- 4 files changed, 217 insertions(+), 191 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 3e7d91c1d8..2a5e7bf004 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -835,7 +835,7 @@ void GenericConfiguration::removeSection(const std::string & section) } -std::string GenericConfiguration::getStr(const std::string & section, const std::string & entry, bool quoted) const +std::string GenericConfiguration::getStr(const std::string & section, const std::string & entry) const { std::string str; @@ -847,32 +847,18 @@ std::string GenericConfiguration::getStr(const std::string & section, const std: if (params.empty()) return str; - str = params.front(); - - // Remove quotes - // TBD: what if they are not there? - if (quoted) { - if ('"' == str[0]) - str.erase(0, 1); - - if ('"' == str[str.size() - 1]) - str.erase(str.size() - 1); - } - - return str; + return params.front(); } void GenericConfiguration::setStr( const std::string & section, const std::string & entry, - const std::string & value, - bool quoted) + const std::string & value) { ConfigParamList param; - // Add quotes if required - param.push_back(quoted ? '"' + value + '"' : value); + param.push_back(value); set(section, entry, param); } @@ -1454,7 +1440,7 @@ void UpsdConfigParser::onParseEnd() UpsdUsersConfiguration::upsmon_mode_t UpsdUsersConfiguration::getUpsmonMode() const { - std::string mode_str = getStr("upsmon", "upsmon", false); + std::string mode_str = getStr("upsmon", "upsmon"); if ("master" == mode_str) return UPSMON_MASTER; @@ -1470,7 +1456,7 @@ void UpsdUsersConfiguration::setUpsmonMode(upsmon_mode_t mode) { assert(UPSMON_UNDEF != mode); - setStr("upsmon", "upsmon", (UPSMON_MASTER == mode ? "master" : "slave"), false); + setStr("upsmon", "upsmon", (UPSMON_MASTER == mode ? "master" : "slave")); } diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index ee330dc7fa..918afc2998 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -533,6 +533,51 @@ NutWriter::status_t DefaultConfigWriter::writeDirective(const std::string & str) } +/** + * \brief Value quoting and escaping + * + * The function checks whether the value string contains + * any spaces and/or '=' characters. + * If so, the result is double-quoted and all inner double + * quotes shall be escaped using backslash. + * + * \param val Value string + * + * \return Value string ready for serialisation + */ +static std::string encodeValue(const std::string & val) { + // Check the string for spaces and '=' + bool quote = false; + + for (size_t i = 0; i < val.size() && !quote; ++i) { + char ch = val[i]; + + quote = ' ' == ch || '=' == ch; + } + + if (!quote) + return val; + + // Quote value and escape inner quotes + std::string qval; + + qval += '"'; + + for (size_t i = 0; i < val.size(); ++i) { + char ch = val[i]; + + if ('"' == ch) + qval += '\\'; + + qval += ch; + } + + qval += '"'; + + return qval; +} + + NutWriter::status_t GenericConfigWriter::writeSectionEntry( const GenericConfigSectionEntry & entry, const std::string & indent, @@ -541,7 +586,9 @@ NutWriter::status_t GenericConfigWriter::writeSectionEntry( ConfigParamList::const_iterator value_iter = entry.values.begin(); for (; value_iter != entry.values.end(); ++value_iter) { - status_t status = writeDirective(indent + entry.name + kv_sep + *value_iter); + std::string value = encodeValue(*value_iter); + + status_t status = writeDirective(indent + entry.name + kv_sep + value); if (NUTW_OK != status) return status; diff --git a/include/nutconf.h b/include/nutconf.h index 2ef4ab39d4..4e332ae6a4 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -448,28 +448,25 @@ class GenericConfiguration : public BaseConfiguration, public Serialisable * * \param section Section name * \param entry Entry name - * \param quoted \c true iff the value is quoted * * \return Configuration parameter as string */ std::string getStr( const std::string & section, - const std::string & entry, - bool quoted = false) const; + const std::string & entry) const; /** * \brief Global scope configuration string getter * * Empty string is returned if the entry doesn't exist. * - * \param entry Entry name - * \param quoted \c true iff the value is quoted + * \param entry Entry name * * \return Configuration parameter as string */ - inline std::string getStr(const std::string & entry, bool quoted = false) const + inline std::string getStr(const std::string & entry) const { - return getStr("", entry, quoted); + return getStr("", entry); } /** @@ -478,27 +475,23 @@ class GenericConfiguration : public BaseConfiguration, public Serialisable * \param section Section name * \param entry Entry name * \param value Parameter value - * \param quoted \c true iff the value is quoted */ void setStr( const std::string & section, const std::string & entry, - const std::string & value, - bool quoted = false); + const std::string & value); /** * \brief Global scope configuration string setter * * \param entry Entry name * \param value Parameter value - * \param quoted \c true iff the value is quoted */ inline void setStr( const std::string & entry, - const std::string & value, - bool quoted = false) + const std::string & value) { - setStr("", entry, value, quoted); + setStr("", entry, value); } /** @@ -780,16 +773,16 @@ class UpsConfiguration : public GenericConfiguration public: /** Global configuration attributes getters and setters \{ */ - inline std::string getChroot() const { return getStr("chroot", true); } - inline std::string getDriverPath() const { return getStr("driverpath", true); } - inline std::string getUser() const { return getStr("user", false); } + inline std::string getChroot() const { return getStr("chroot"); } + inline std::string getDriverPath() const { return getStr("driverpath"); } + inline std::string getUser() const { return getStr("user"); } inline long long int getMaxStartDelay() const { return getInt("maxstartdelay"); } inline long long int getPollInterval() const { return getInt("pollinterval", 5); } // TODO: check the default - inline void setChroot(const std::string & path) { setStr("chroot", path, true); } - inline void setDriverPath(const std::string & path) { setStr("driverpath", path, true); } - inline void setUser(const std::string & user) { setStr("user", user, false); } + inline void setChroot(const std::string & path) { setStr("chroot", path); } + inline void setDriverPath(const std::string & path) { setStr("driverpath", path); } + inline void setUser(const std::string & user) { setStr("user", user); } inline void setMaxStartDelay(long long int delay) { setInt("maxstartdelay", delay); } inline void setPollInterval(long long int interval) { setInt("pollinterval", interval); } @@ -797,59 +790,59 @@ class UpsConfiguration : public GenericConfiguration /** \} */ /** UPS-specific configuration attributes getters and setters \{ */ - inline std::string getDriver(const std::string & ups) const { return getStr(ups, "driver", false); } - inline std::string getDescription(const std::string & ups) const { return getStr(ups, "desc", true); } - inline std::string getCP(const std::string & ups) const { return getStr(ups, "CP", false); } - inline std::string getCS(const std::string & ups) const { return getStr(ups, "CS", false); } - inline std::string getID(const std::string & ups) const { return getStr(ups, "ID", false); } - inline std::string getLB(const std::string & ups) const { return getStr(ups, "LB", false); } - inline std::string getLowBatt(const std::string & ups) const { return getStr(ups, "LowBatt", false); } // CHECKME - inline std::string getOL(const std::string & ups) const { return getStr(ups, "OL", false); } // CHECKME - inline std::string getSD(const std::string & ups) const { return getStr(ups, "SD", false); } // CHECKME - inline std::string getAuthPassword(const std::string & ups) const { return getStr(ups, "authPassword", false); } // CHECKME - inline std::string getAuthProtocol(const std::string & ups) const { return getStr(ups, "authProtocol", false); } // CHECKME - inline std::string getAuthType(const std::string & ups) const { return getStr(ups, "authtype", false); } // CHECKME - inline std::string getAWD(const std::string & ups) const { return getStr(ups, "awd", false); } // CHECKME - inline std::string getBatText(const std::string & ups) const { return getStr(ups, "battext", true); } // CHECKME - inline std::string getBus(const std::string & ups) const { return getStr(ups, "bus", false); } // CHECKME - inline std::string getCommunity(const std::string & ups) const { return getStr(ups, "community", false); } // CHECKME - inline std::string getFRUID(const std::string & ups) const { return getStr(ups, "fruid", false); } // CHECKME - inline std::string getLoadStatus(const std::string & ups) const { return getStr(ups, "load.status", false); } // CHECKME - inline std::string getLogin(const std::string & ups) const { return getStr(ups, "login", false); } // CHECKME - inline std::string getLowbatt(const std::string & ups) const { return getStr(ups, "lowbatt", false); } // CHECKME - inline std::string getManufacturer(const std::string & ups) const { return getStr(ups, "manufacturer", true); } // CHECKME - inline std::string getMethodOfFlowControl(const std::string & ups) const { return getStr(ups, "methodOfFlowControl", false); } // CHECKME - inline std::string getMIBs(const std::string & ups) const { return getStr(ups, "mibs", false); } // CHECKME - inline std::string getModel(const std::string & ups) const { return getStr(ups, "model", true); } // CHECKME - inline std::string getModelName(const std::string & ups) const { return getStr(ups, "modelname", true); } // CHECKME - inline std::string getNotification(const std::string & ups) const { return getStr(ups, "notification", false); } // CHECKME - inline std::string getOldMAC(const std::string & ups) const { return getStr(ups, "oldmac", false); } // CHECKME - inline std::string getPassword(const std::string & ups) const { return getStr(ups, "password", false); } // CHECKME - inline std::string getPort(const std::string & ups) const { return getStr(ups, "port", false); } - inline std::string getPrefix(const std::string & ups) const { return getStr(ups, "prefix", true); } // CHECKME - inline std::string getPrivPassword(const std::string & ups) const { return getStr(ups, "privPassword", false); } // CHECKME - inline std::string getPrivProtocol(const std::string & ups) const { return getStr(ups, "privProtocol", false); } // CHECKME - inline std::string getProduct(const std::string & ups) const { return getStr(ups, "product", true); } // CHECKME - inline std::string getProductID(const std::string & ups) const { return getStr(ups, "productid", false); } // CHECKME - inline std::string getProtocol(const std::string & ups) const { return getStr(ups, "protocol", false); } // CHECKME - inline std::string getRuntimeCal(const std::string & ups) const { return getStr(ups, "runtimecal", false); } // CHECKME - inline std::string getSDType(const std::string & ups) const { return getStr(ups, "sdtype", false); } // CHECKME - inline std::string getSecLevel(const std::string & ups) const { return getStr(ups, "secLevel", false); } // CHECKME - inline std::string getSecName(const std::string & ups) const { return getStr(ups, "secName", true); } // CHECKME - inline std::string getSensorID(const std::string & ups) const { return getStr(ups, "sensorid", false); } // CHECKME - inline std::string getSerial(const std::string & ups) const { return getStr(ups, "serial", false); } // CHECKME - inline std::string getSerialNumber(const std::string & ups) const { return getStr(ups, "serialnumber", false); } // CHECKME - inline std::string getShutdownArguments(const std::string & ups) const { return getStr(ups, "shutdownArguments", false); } // CHECKME - inline std::string getSNMPversion(const std::string & ups) const { return getStr(ups, "snmp_version", false); } // CHECKME - inline std::string getSubdriver(const std::string & ups) const { return getStr(ups, "subdriver", false); } // CHECKME - inline std::string getType(const std::string & ups) const { return getStr(ups, "type", false); } // CHECKME - inline std::string getUPStype(const std::string & ups) const { return getStr(ups, "upstype", false); } // CHECKME - inline std::string getUSD(const std::string & ups) const { return getStr(ups, "usd", false); } // CHECKME - inline std::string getUsername(const std::string & ups) const { return getStr(ups, "username", false); } // CHECKME - inline std::string getValidationSequence(const std::string & ups) const { return getStr(ups, "validationSequence", false); } // CHECKME - inline std::string getVendor(const std::string & ups) const { return getStr(ups, "vendor", true); } // CHECKME - inline std::string getVendorID(const std::string & ups) const { return getStr(ups, "vendorid", false); } // CHECKME - inline std::string getWUGrace(const std::string & ups) const { return getStr(ups, "wugrace", false); } // CHECKME + inline std::string getDriver(const std::string & ups) const { return getStr(ups, "driver"); } + inline std::string getDescription(const std::string & ups) const { return getStr(ups, "desc"); } + inline std::string getCP(const std::string & ups) const { return getStr(ups, "CP"); } + inline std::string getCS(const std::string & ups) const { return getStr(ups, "CS"); } + inline std::string getID(const std::string & ups) const { return getStr(ups, "ID"); } + inline std::string getLB(const std::string & ups) const { return getStr(ups, "LB"); } + inline std::string getLowBatt(const std::string & ups) const { return getStr(ups, "LowBatt"); } + inline std::string getOL(const std::string & ups) const { return getStr(ups, "OL"); } + inline std::string getSD(const std::string & ups) const { return getStr(ups, "SD"); } + inline std::string getAuthPassword(const std::string & ups) const { return getStr(ups, "authPassword"); } + inline std::string getAuthProtocol(const std::string & ups) const { return getStr(ups, "authProtocol"); } + inline std::string getAuthType(const std::string & ups) const { return getStr(ups, "authtype"); } + inline std::string getAWD(const std::string & ups) const { return getStr(ups, "awd"); } + inline std::string getBatText(const std::string & ups) const { return getStr(ups, "battext"); } + inline std::string getBus(const std::string & ups) const { return getStr(ups, "bus"); } + inline std::string getCommunity(const std::string & ups) const { return getStr(ups, "community"); } + inline std::string getFRUID(const std::string & ups) const { return getStr(ups, "fruid"); } + inline std::string getLoadStatus(const std::string & ups) const { return getStr(ups, "load.status"); } + inline std::string getLogin(const std::string & ups) const { return getStr(ups, "login"); } + inline std::string getLowbatt(const std::string & ups) const { return getStr(ups, "lowbatt"); } + inline std::string getManufacturer(const std::string & ups) const { return getStr(ups, "manufacturer"); } + inline std::string getMethodOfFlowControl(const std::string & ups) const { return getStr(ups, "methodOfFlowControl"); } + inline std::string getMIBs(const std::string & ups) const { return getStr(ups, "mibs"); } + inline std::string getModel(const std::string & ups) const { return getStr(ups, "model"); } + inline std::string getModelName(const std::string & ups) const { return getStr(ups, "modelname"); } + inline std::string getNotification(const std::string & ups) const { return getStr(ups, "notification"); } + inline std::string getOldMAC(const std::string & ups) const { return getStr(ups, "oldmac"); } + inline std::string getPassword(const std::string & ups) const { return getStr(ups, "password"); } + inline std::string getPort(const std::string & ups) const { return getStr(ups, "port"); } + inline std::string getPrefix(const std::string & ups) const { return getStr(ups, "prefix"); } + inline std::string getPrivPassword(const std::string & ups) const { return getStr(ups, "privPassword"); } + inline std::string getPrivProtocol(const std::string & ups) const { return getStr(ups, "privProtocol"); } + inline std::string getProduct(const std::string & ups) const { return getStr(ups, "product"); } + inline std::string getProductID(const std::string & ups) const { return getStr(ups, "productid"); } + inline std::string getProtocol(const std::string & ups) const { return getStr(ups, "protocol"); } + inline std::string getRuntimeCal(const std::string & ups) const { return getStr(ups, "runtimecal"); } + inline std::string getSDType(const std::string & ups) const { return getStr(ups, "sdtype"); } + inline std::string getSecLevel(const std::string & ups) const { return getStr(ups, "secLevel"); } + inline std::string getSecName(const std::string & ups) const { return getStr(ups, "secName"); } + inline std::string getSensorID(const std::string & ups) const { return getStr(ups, "sensorid"); } + inline std::string getSerial(const std::string & ups) const { return getStr(ups, "serial"); } + inline std::string getSerialNumber(const std::string & ups) const { return getStr(ups, "serialnumber"); } + inline std::string getShutdownArguments(const std::string & ups) const { return getStr(ups, "shutdownArguments"); } + inline std::string getSNMPversion(const std::string & ups) const { return getStr(ups, "snmp_version"); } + inline std::string getSubdriver(const std::string & ups) const { return getStr(ups, "subdriver"); } + inline std::string getType(const std::string & ups) const { return getStr(ups, "type"); } + inline std::string getUPStype(const std::string & ups) const { return getStr(ups, "upstype"); } + inline std::string getUSD(const std::string & ups) const { return getStr(ups, "usd"); } + inline std::string getUsername(const std::string & ups) const { return getStr(ups, "username"); } + inline std::string getValidationSequence(const std::string & ups) const { return getStr(ups, "validationSequence"); } + inline std::string getVendor(const std::string & ups) const { return getStr(ups, "vendor"); } + inline std::string getVendorID(const std::string & ups) const { return getStr(ups, "vendorid"); } + inline std::string getWUGrace(const std::string & ups) const { return getStr(ups, "wugrace"); } inline long long int getSDOrder(const std::string & ups) const { return getInt(ups, "sdorder"); } // TODO: Is that a number? @@ -895,78 +888,78 @@ class UpsConfiguration : public GenericConfiguration inline long long int getVoltage(const std::string & ups) const { return getInt(ups, "voltage"); } // CHECKME inline long long int getWait(const std::string & ups) const { return getInt(ups, "wait"); } // CHECKME - inline bool getNolock(const std::string & ups) const { return str2bool(getStr(ups, "nolock", false)); } // TODO: check whether it's indeed boolean - inline bool getCable(const std::string & ups) const { return str2bool(getStr(ups, "cable", false)); } // CHECKME - inline bool getDumbTerm(const std::string & ups) const { return str2bool(getStr(ups, "dumbterm", false)); } // CHECKME - inline bool getExplore(const std::string & ups) const { return str2bool(getStr(ups, "explore", false)); } // CHECKME - inline bool getFakeLowBatt(const std::string & ups) const { return str2bool(getStr(ups, "fake_lowbatt", false)); } // CHECKME - inline bool getFlash(const std::string & ups) const { return str2bool(getStr(ups, "flash", false)); } // CHECKME - inline bool getFullUpdate(const std::string & ups) const { return str2bool(getStr(ups, "full_update", false)); } // CHECKME - inline bool getLangIDfix(const std::string & ups) const { return str2bool(getStr(ups, "langid_fix", false)); } // CHECKME - inline bool getLoadOff(const std::string & ups) const { return str2bool(getStr(ups, "load.off", false)); } // CHECKME - inline bool getLoadOn(const std::string & ups) const { return str2bool(getStr(ups, "load.on", false)); } // CHECKME - inline bool getNoHang(const std::string & ups) const { return str2bool(getStr(ups, "nohang", false)); } // CHECKME - inline bool getNoRating(const std::string & ups) const { return str2bool(getStr(ups, "norating", false)); } // CHECKME - inline bool getNoTransferOIDs(const std::string & ups) const { return str2bool(getStr(ups, "notransferoids", false)); } // CHECKME - inline bool getNoVendor(const std::string & ups) const { return str2bool(getStr(ups, "novendor", false)); } // CHECKME - inline bool getNoWarnNoImp(const std::string & ups) const { return str2bool(getStr(ups, "nowarn_noimp", false)); } // CHECKME - inline bool getPollOnly(const std::string & ups) const { return str2bool(getStr(ups, "pollonly", false)); } // CHECKME - inline bool getSilent(const std::string & ups) const { return str2bool(getStr(ups, "silent", false)); } // CHECKME - inline bool getStatusOnly(const std::string & ups) const { return str2bool(getStr(ups, "status_only", false)); } // CHECKME - inline bool getSubscribe(const std::string & ups) const { return str2bool(getStr(ups, "subscribe", false)); } // CHECKME - inline bool getUseCRLF(const std::string & ups) const { return str2bool(getStr(ups, "use_crlf", false)); } // CHECKME - inline bool getUsePreLF(const std::string & ups) const { return str2bool(getStr(ups, "use_pre_lf", false)); } // CHECKME - - - inline void setDriver(const std::string & ups, const std::string & driver) { setStr(ups, "driver", driver, false); } - inline void setDescription(const std::string & ups, const std::string & desc) { setStr(ups, "desc", desc, true); } - inline void setLowBatt(const std::string & ups, const std::string & lowbatt) { setStr(ups, "LowBatt", lowbatt, false); } // CHECKME - inline void setOL(const std::string & ups, const std::string & ol) { setStr(ups, "OL", ol, false); } // CHECKME - inline void setSD(const std::string & ups, const std::string & sd) { setStr(ups, "SD", sd, false); } // CHECKME - inline void setAuthPassword(const std::string & ups, const std::string & auth_passwd) { setStr(ups, "authPassword", auth_passwd, false); } // CHECKME - inline void setAuthProtocol(const std::string & ups, const std::string & auth_proto) { setStr(ups, "authProtocol", auth_proto, false); } // CHECKME - inline void setAuthType(const std::string & ups, const std::string & authtype) { setStr(ups, "authtype", authtype, false); } // CHECKME - inline void setAWD(const std::string & ups, const std::string & awd) { setStr(ups, "awd", awd, false); } // CHECKME - inline void setBatText(const std::string & ups, const std::string & battext) { setStr(ups, "battext", battext, false); } // CHECKME - inline void setBus(const std::string & ups, const std::string & bus) { setStr(ups, "bus", bus, false); } // CHECKME - inline void setCommunity(const std::string & ups, const std::string & community) { setStr(ups, "community", community, false); } // CHECKME - inline void setFRUID(const std::string & ups, const std::string & fruid) { setStr(ups, "fruid", fruid, false); } // CHECKME - inline void setLoadStatus(const std::string & ups, const std::string & load_status) { setStr(ups, "load.status", load_status, false); } // CHECKME - inline void setLogin(const std::string & ups, const std::string & login) { setStr(ups, "login", login, false); } // CHECKME - inline void setLowbatt(const std::string & ups, const std::string & lowbatt) { setStr(ups, "lowbatt", lowbatt, false); } // CHECKME - inline void setManufacturer(const std::string & ups, const std::string & manufacturer) { setStr(ups, "manufacturer", manufacturer, false); } // CHECKME - inline void setMethodOfFlowControl(const std::string & ups, const std::string & method) { setStr(ups, "methodOfFlowControl", method, false); } // CHECKME - inline void setMIBs(const std::string & ups, const std::string & mibs) { setStr(ups, "mibs", mibs, false); } // CHECKME - inline void setModel(const std::string & ups, const std::string & model) { setStr(ups, "model", model, false); } // CHECKME - inline void setModelName(const std::string & ups, const std::string & modelname) { setStr(ups, "modelname", modelname, false); } // CHECKME - inline void setNotification(const std::string & ups, const std::string & notification) { setStr(ups, "notification", notification, false); } // CHECKME - inline void setOldMAC(const std::string & ups, const std::string & oldmac) { setStr(ups, "oldmac", oldmac, false); } // CHECKME - inline void setPassword(const std::string & ups, const std::string & password) { setStr(ups, "password", password, false); } // CHECKME - inline void setPort(const std::string & ups, const std::string & port) { setStr(ups, "port", port, false); } - inline void setPrefix(const std::string & ups, const std::string & prefix) { setStr(ups, "prefix", prefix, false); } // CHECKME - inline void setPrivPassword(const std::string & ups, const std::string & priv_passwd) { setStr(ups, "privPassword", priv_passwd, false); } // CHECKME - inline void setPrivProtocol(const std::string & ups, const std::string & priv_proto) { setStr(ups, "privProtocol", priv_proto, false); } // CHECKME - inline void setProduct(const std::string & ups, const std::string & product) { setStr(ups, "product", product, false); } // CHECKME - inline void setProductID(const std::string & ups, const std::string & productid) { setStr(ups, "productid", productid, false); } // CHECKME - inline void setProtocol(const std::string & ups, const std::string & protocol) { setStr(ups, "protocol", protocol, false); } // CHECKME - inline void setRuntimeCal(const std::string & ups, const std::string & runtimecal) { setStr(ups, "runtimecal", runtimecal, false); } // CHECKME - inline void setSDtype(const std::string & ups, const std::string & sdtype) { setStr(ups, "sdtype", sdtype, false); } // CHECKME - inline void setSecLevel(const std::string & ups, const std::string & sec_level) { setStr(ups, "secLevel", sec_level, false); } // CHECKME - inline void setSecName(const std::string & ups, const std::string & sec_name) { setStr(ups, "secName", sec_name, false); } // CHECKME - inline void setSensorID(const std::string & ups, const std::string & sensorid) { setStr(ups, "sensorid", sensorid, false); } // CHECKME - inline void setSerial(const std::string & ups, const std::string & serial) { setStr(ups, "serial", serial, false); } // CHECKME - inline void setSerialNumber(const std::string & ups, const std::string & serialnumber) { setStr(ups, "serialnumber", serialnumber, false); } // CHECKME - inline void setShutdownArguments(const std::string & ups, const std::string & sd_args) { setStr(ups, "shutdownArguments", sd_args, false); } // CHECKME - inline void setSNMPversion(const std::string & ups, const std::string & snmp_version) { setStr(ups, "snmp_version", snmp_version, false); } // CHECKME - inline void setSubdriver(const std::string & ups, const std::string & subdriver) { setStr(ups, "subdriver", subdriver, false); } // CHECKME - inline void setType(const std::string & ups, const std::string & type) { setStr(ups, "type", type, false); } // CHECKME - inline void setUPStype(const std::string & ups, const std::string & upstype) { setStr(ups, "upstype", upstype, false); } // CHECKME - inline void setUSD(const std::string & ups, const std::string & usd) { setStr(ups, "usd", usd, false); } // CHECKME - inline void setUsername(const std::string & ups, const std::string & username) { setStr(ups, "username", username, false); } // CHECKME - inline void setValidationSequence(const std::string & ups, const std::string & valid_seq) { setStr(ups, "validationSequence", valid_seq, false); } // CHECKME - inline void setVendor(const std::string & ups, const std::string & vendor) { setStr(ups, "vendor", vendor, false); } // CHECKME - inline void setVendorID(const std::string & ups, const std::string & vendorid) { setStr(ups, "vendorid", vendorid, false); } // CHECKME - inline void setWUGrace(const std::string & ups, const std::string & wugrace) { setStr(ups, "wugrace", wugrace, false); } // CHECKME + inline bool getNolock(const std::string & ups) const { return str2bool(getStr(ups, "nolock")); } + inline bool getCable(const std::string & ups) const { return str2bool(getStr(ups, "cable")); } + inline bool getDumbTerm(const std::string & ups) const { return str2bool(getStr(ups, "dumbterm")); } + inline bool getExplore(const std::string & ups) const { return str2bool(getStr(ups, "explore")); } + inline bool getFakeLowBatt(const std::string & ups) const { return str2bool(getStr(ups, "fake_lowbatt")); } + inline bool getFlash(const std::string & ups) const { return str2bool(getStr(ups, "flash")); } + inline bool getFullUpdate(const std::string & ups) const { return str2bool(getStr(ups, "full_update")); } + inline bool getLangIDfix(const std::string & ups) const { return str2bool(getStr(ups, "langid_fix")); } + inline bool getLoadOff(const std::string & ups) const { return str2bool(getStr(ups, "load.off")); } + inline bool getLoadOn(const std::string & ups) const { return str2bool(getStr(ups, "load.on")); } + inline bool getNoHang(const std::string & ups) const { return str2bool(getStr(ups, "nohang")); } + inline bool getNoRating(const std::string & ups) const { return str2bool(getStr(ups, "norating")); } + inline bool getNoTransferOIDs(const std::string & ups) const { return str2bool(getStr(ups, "notransferoids")); } + inline bool getNoVendor(const std::string & ups) const { return str2bool(getStr(ups, "novendor")); } + inline bool getNoWarnNoImp(const std::string & ups) const { return str2bool(getStr(ups, "nowarn_noimp")); } + inline bool getPollOnly(const std::string & ups) const { return str2bool(getStr(ups, "pollonly")); } + inline bool getSilent(const std::string & ups) const { return str2bool(getStr(ups, "silent")); } + inline bool getStatusOnly(const std::string & ups) const { return str2bool(getStr(ups, "status_only")); } + inline bool getSubscribe(const std::string & ups) const { return str2bool(getStr(ups, "subscribe")); } + inline bool getUseCRLF(const std::string & ups) const { return str2bool(getStr(ups, "use_crlf")); } + inline bool getUsePreLF(const std::string & ups) const { return str2bool(getStr(ups, "use_pre_lf")); } + + + inline void setDriver(const std::string & ups, const std::string & driver) { setStr(ups, "driver", driver); } + inline void setDescription(const std::string & ups, const std::string & desc) { setStr(ups, "desc", desc); } + inline void setLowBatt(const std::string & ups, const std::string & lowbatt) { setStr(ups, "LowBatt", lowbatt); } + inline void setOL(const std::string & ups, const std::string & ol) { setStr(ups, "OL", ol); } + inline void setSD(const std::string & ups, const std::string & sd) { setStr(ups, "SD", sd); } + inline void setAuthPassword(const std::string & ups, const std::string & auth_passwd) { setStr(ups, "authPassword", auth_passwd); } + inline void setAuthProtocol(const std::string & ups, const std::string & auth_proto) { setStr(ups, "authProtocol", auth_proto); } + inline void setAuthType(const std::string & ups, const std::string & authtype) { setStr(ups, "authtype", authtype); } + inline void setAWD(const std::string & ups, const std::string & awd) { setStr(ups, "awd", awd); } + inline void setBatText(const std::string & ups, const std::string & battext) { setStr(ups, "battext", battext); } + inline void setBus(const std::string & ups, const std::string & bus) { setStr(ups, "bus", bus); } + inline void setCommunity(const std::string & ups, const std::string & community) { setStr(ups, "community", community); } + inline void setFRUID(const std::string & ups, const std::string & fruid) { setStr(ups, "fruid", fruid); } + inline void setLoadStatus(const std::string & ups, const std::string & load_status) { setStr(ups, "load.status", load_status); } + inline void setLogin(const std::string & ups, const std::string & login) { setStr(ups, "login", login); } + inline void setLowbatt(const std::string & ups, const std::string & lowbatt) { setStr(ups, "lowbatt", lowbatt); } + inline void setManufacturer(const std::string & ups, const std::string & manufacturer) { setStr(ups, "manufacturer", manufacturer); } + inline void setMethodOfFlowControl(const std::string & ups, const std::string & method) { setStr(ups, "methodOfFlowControl", method); } + inline void setMIBs(const std::string & ups, const std::string & mibs) { setStr(ups, "mibs", mibs); } + inline void setModel(const std::string & ups, const std::string & model) { setStr(ups, "model", model); } + inline void setModelName(const std::string & ups, const std::string & modelname) { setStr(ups, "modelname", modelname); } + inline void setNotification(const std::string & ups, const std::string & notification) { setStr(ups, "notification", notification); } + inline void setOldMAC(const std::string & ups, const std::string & oldmac) { setStr(ups, "oldmac", oldmac); } + inline void setPassword(const std::string & ups, const std::string & password) { setStr(ups, "password", password); } + inline void setPort(const std::string & ups, const std::string & port) { setStr(ups, "port", port); } + inline void setPrefix(const std::string & ups, const std::string & prefix) { setStr(ups, "prefix", prefix); } + inline void setPrivPassword(const std::string & ups, const std::string & priv_passwd) { setStr(ups, "privPassword", priv_passwd); } + inline void setPrivProtocol(const std::string & ups, const std::string & priv_proto) { setStr(ups, "privProtocol", priv_proto); } + inline void setProduct(const std::string & ups, const std::string & product) { setStr(ups, "product", product); } + inline void setProductID(const std::string & ups, const std::string & productid) { setStr(ups, "productid", productid); } + inline void setProtocol(const std::string & ups, const std::string & protocol) { setStr(ups, "protocol", protocol); } + inline void setRuntimeCal(const std::string & ups, const std::string & runtimecal) { setStr(ups, "runtimecal", runtimecal); } + inline void setSDtype(const std::string & ups, const std::string & sdtype) { setStr(ups, "sdtype", sdtype); } + inline void setSecLevel(const std::string & ups, const std::string & sec_level) { setStr(ups, "secLevel", sec_level); } + inline void setSecName(const std::string & ups, const std::string & sec_name) { setStr(ups, "secName", sec_name); } + inline void setSensorID(const std::string & ups, const std::string & sensorid) { setStr(ups, "sensorid", sensorid); } + inline void setSerial(const std::string & ups, const std::string & serial) { setStr(ups, "serial", serial); } + inline void setSerialNumber(const std::string & ups, const std::string & serialnumber) { setStr(ups, "serialnumber", serialnumber); } + inline void setShutdownArguments(const std::string & ups, const std::string & sd_args) { setStr(ups, "shutdownArguments", sd_args); } + inline void setSNMPversion(const std::string & ups, const std::string & snmp_version) { setStr(ups, "snmp_version", snmp_version); } + inline void setSubdriver(const std::string & ups, const std::string & subdriver) { setStr(ups, "subdriver", subdriver); } + inline void setType(const std::string & ups, const std::string & type) { setStr(ups, "type", type); } + inline void setUPStype(const std::string & ups, const std::string & upstype) { setStr(ups, "upstype", upstype); } + inline void setUSD(const std::string & ups, const std::string & usd) { setStr(ups, "usd", usd); } + inline void setUsername(const std::string & ups, const std::string & username) { setStr(ups, "username", username); } + inline void setValidationSequence(const std::string & ups, const std::string & valid_seq) { setStr(ups, "validationSequence", valid_seq); } + inline void setVendor(const std::string & ups, const std::string & vendor) { setStr(ups, "vendor", vendor); } + inline void setVendorID(const std::string & ups, const std::string & vendorid) { setStr(ups, "vendorid", vendorid); } + inline void setWUGrace(const std::string & ups, const std::string & wugrace) { setStr(ups, "wugrace", wugrace); } inline void setSDOrder(const std::string & ups, long long int ord) { setInt(ups, "sdorder", ord); } inline void setMaxStartDelay(const std::string & ups, long long int delay) { setInt(ups, "maxstartdelay", delay); } @@ -1011,27 +1004,27 @@ class UpsConfiguration : public GenericConfiguration inline void setVoltage(const std::string & ups, long long int voltage) { setInt(ups, "voltage", voltage); } // CHECKME inline void setWait(const std::string & ups, long long int wait) { setInt(ups, "wait", wait); } // CHECKME - inline void setNolock(const std::string & ups, bool set = true) { setStr(ups, "nolock", bool2str(set), false); } - inline void setCable(const std::string & ups, bool set = true) { setStr(ups, "cable", bool2str(set), false); } // CHECKME - inline void setDumbTerm(const std::string & ups, bool set = true) { setStr(ups, "dumbterm", bool2str(set), false); } // CHECKME - inline void setExplore(const std::string & ups, bool set = true) { setStr(ups, "explore", bool2str(set), false); } // CHECKME - inline void setFakeLowBatt(const std::string & ups, bool set = true) { setStr(ups, "fake_lowbatt", bool2str(set), false); } // CHECKME - inline void setFlash(const std::string & ups, bool set = true) { setStr(ups, "flash", bool2str(set), false); } // CHECKME - inline void setFullUpdate(const std::string & ups, bool set = true) { setStr(ups, "full_update", bool2str(set), false); } // CHECKME - inline void setLangIDfix(const std::string & ups, bool set = true) { setStr(ups, "langid_fix", bool2str(set), false); } // CHECKME - inline void setLoadOff(const std::string & ups, bool set = true) { setStr(ups, "load.off", bool2str(set), false); } // CHECKME - inline void setLoadOn(const std::string & ups, bool set = true) { setStr(ups, "load.on", bool2str(set), false); } // CHECKME - inline void setNoHang(const std::string & ups, bool set = true) { setStr(ups, "nohang", bool2str(set), false); } // CHECKME - inline void setNoRating(const std::string & ups, bool set = true) { setStr(ups, "norating", bool2str(set), false); } // CHECKME - inline void setNoTransferOIDs(const std::string & ups, bool set = true) { setStr(ups, "notransferoids", bool2str(set), false); } // CHECKME - inline void setNoVendor(const std::string & ups, bool set = true) { setStr(ups, "novendor", bool2str(set), false); } // CHECKME - inline void setNoWarnNoImp(const std::string & ups, bool set = true) { setStr(ups, "nowarn_noimp", bool2str(set), false); } // CHECKME - inline void setPollOnly(const std::string & ups, bool set = true) { setStr(ups, "pollonly", bool2str(set), false); } // CHECKME - inline void setSilent(const std::string & ups, bool set = true) { setStr(ups, "silent", bool2str(set), false); } // CHECKME - inline void setStatusOnly(const std::string & ups, bool set = true) { setStr(ups, "status_only", bool2str(set), false); } // CHECKME - inline void setSubscribe(const std::string & ups, bool set = true) { setStr(ups, "subscribe", bool2str(set), false); } // CHECKME - inline void setUseCRLF(const std::string & ups, bool set = true) { setStr(ups, "use_crlf", bool2str(set), false); } // CHECKME - inline void setUsePreLF(const std::string & ups, bool set = true) { setStr(ups, "use_pre_lf", bool2str(set), false); } // CHECKME + inline void setNolock(const std::string & ups, bool set = true) { setStr(ups, "nolock", bool2str(set)); } + inline void setCable(const std::string & ups, bool set = true) { setStr(ups, "cable", bool2str(set)); } + inline void setDumbTerm(const std::string & ups, bool set = true) { setStr(ups, "dumbterm", bool2str(set)); } + inline void setExplore(const std::string & ups, bool set = true) { setStr(ups, "explore", bool2str(set)); } + inline void setFakeLowBatt(const std::string & ups, bool set = true) { setStr(ups, "fake_lowbatt", bool2str(set)); } + inline void setFlash(const std::string & ups, bool set = true) { setStr(ups, "flash", bool2str(set)); } + inline void setFullUpdate(const std::string & ups, bool set = true) { setStr(ups, "full_update", bool2str(set)); } + inline void setLangIDfix(const std::string & ups, bool set = true) { setStr(ups, "langid_fix", bool2str(set)); } + inline void setLoadOff(const std::string & ups, bool set = true) { setStr(ups, "load.off", bool2str(set)); } + inline void setLoadOn(const std::string & ups, bool set = true) { setStr(ups, "load.on", bool2str(set)); } + inline void setNoHang(const std::string & ups, bool set = true) { setStr(ups, "nohang", bool2str(set)); } + inline void setNoRating(const std::string & ups, bool set = true) { setStr(ups, "norating", bool2str(set)); } + inline void setNoTransferOIDs(const std::string & ups, bool set = true) { setStr(ups, "notransferoids", bool2str(set)); } + inline void setNoVendor(const std::string & ups, bool set = true) { setStr(ups, "novendor", bool2str(set)); } + inline void setNoWarnNoImp(const std::string & ups, bool set = true) { setStr(ups, "nowarn_noimp", bool2str(set)); } + inline void setPollOnly(const std::string & ups, bool set = true) { setStr(ups, "pollonly", bool2str(set)); } + inline void setSilent(const std::string & ups, bool set = true) { setStr(ups, "silent", bool2str(set)); } + inline void setStatusOnly(const std::string & ups, bool set = true) { setStr(ups, "status_only", bool2str(set)); } + inline void setSubscribe(const std::string & ups, bool set = true) { setStr(ups, "subscribe", bool2str(set)); } + inline void setUseCRLF(const std::string & ups, bool set = true) { setStr(ups, "use_crlf", bool2str(set)); } + inline void setUsePreLF(const std::string & ups, bool set = true) { setStr(ups, "use_pre_lf", bool2str(set)); } /** \} */ @@ -1051,7 +1044,7 @@ class UpsdUsersConfiguration : public GenericConfiguration /** User-specific configuration attributes getters and setters \{ */ - inline std::string getPassword(const std::string & user) const { return getStr(user, "password", false); } + inline std::string getPassword(const std::string & user) const { return getStr(user, "password"); } inline ConfigParamList getActions(const std::string & user) const { @@ -1069,7 +1062,7 @@ class UpsdUsersConfiguration : public GenericConfiguration upsmon_mode_t getUpsmonMode() const; - inline void setPassword(const std::string & user, const std::string & passwd) { setStr(user, "password", passwd, false); } + inline void setPassword(const std::string & user, const std::string & passwd) { setStr(user, "password", passwd); } inline void setActions(const std::string & user, const ConfigParamList & actions) { set(user, "actions", actions); } inline void setInstantCommands(const std::string & user, const ConfigParamList & cmds) { set(user, "instcmds", cmds); } diff --git a/tests/nutconf_ut.cpp b/tests/nutconf_ut.cpp index 8f91763197..edbfee2e52 100644 --- a/tests/nutconf_ut.cpp +++ b/tests/nutconf_ut.cpp @@ -213,7 +213,7 @@ void NutConfigUnitTest::testUpsdUsersConfiguration() { config.setPassword("upsmon", "ytrewq"); config.setUpsmonMode(nut::UpsdUsersConfiguration::UPSMON_MASTER); - config.setPassword("admin", "qwerty"); + config.setPassword("admin", "qwerty=ui"); config.setActions("admin", nut::ConfigParamList(1, "SET")); config.setInstantCommands("admin", nut::ConfigParamList(1, "ALL")); @@ -221,7 +221,7 @@ void NutConfigUnitTest::testUpsdUsersConfiguration() { "[admin]\n" "\tactions = SET\n" "\tinstcmds = ALL\n" - "\tpassword = qwerty\n" + "\tpassword = \"qwerty=ui\"\n" "\n" "[upsmon]\n" "\tpassword = ytrewq\n" From b6ffc878d74bb03e07f2e67ed6b532022466b58e Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Wed, 9 Jan 2013 12:01:48 +0100 Subject: [PATCH 036/121] nutipc: signal handling UT added --- common/nutipc.cpp | 4 +-- include/nutipc.hpp | 63 +++++++++++++++++++-------------------------- tests/nutipc_ut.cpp | 50 ++++++++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 39 deletions(-) diff --git a/common/nutipc.cpp b/common/nutipc.cpp index f9dfca035d..becf53bfe5 100644 --- a/common/nutipc.cpp +++ b/common/nutipc.cpp @@ -164,11 +164,11 @@ int Process::Executor::operator () () throw(std::runtime_error) { } -int writeCommand(int fh, void * cmd, size_t cmd_size) throw(std::runtime_error) { +int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) throw(std::runtime_error) { char * cmd_bytes = reinterpret_cast(cmd); do { - ssize_t written = write(fh, cmd_bytes, cmd_size); + ssize_t written = ::write(fh, cmd_bytes, cmd_size); if (-1 == written) return errno; diff --git a/include/nutipc.hpp b/include/nutipc.hpp index 75392d4c08..b3fca5f588 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -314,7 +314,7 @@ class Signal { ALARM = SIGALRM, /** Alarm */ TERM = SIGTERM, /** Termination */ USER1 = SIGUSR1, /** User-defined signal 1 */ - USER2 = SIGUSR1, /** User-defined signal 2 */ + USER2 = SIGUSR2, /** User-defined signal 2 */ CHILD = SIGCHLD, /** Child stopped or terminated */ CONT = SIGCONT, /** Continue if stopped */ STOP = SIGSTOP, /** Stop process (unmaskable) */ @@ -380,6 +380,9 @@ class Signal { /** Communication pipe */ static int s_comm_pipe[2]; + /** POSIX thread */ + pthread_t m_impl; + /** * \brief Signal handler thread main routine * @@ -416,11 +419,11 @@ class Signal { */ static void signalNotifier(int signal); + public: + /** * \brief Constructor * - * The threads are only created by the (friend) Signal class - * functions. * At most one thread per handler instance may be created. * This limitation is both due sanity reasons (it wouldn't * make much sense to handle the same signal by multiple threads) @@ -438,8 +441,6 @@ class Signal { */ HandlerThread(const Signal::List & siglist) throw(std::logic_error, std::runtime_error); - public: - /** * \brief Terminate the thread * @@ -510,7 +511,7 @@ void * Signal::HandlerThread::main(void * comm_pipe_read_end) { // Note that direct blocking read could be also used; // however, select allows timeout specification // which might come handy... - int fdno = ::select(1, &rfds, NULL, NULL, NULL); + int fdno = ::select(FD_SETSIZE, &rfds, NULL, NULL, NULL); // TBD: Die or recover on error? if (-1 == fdno) { @@ -542,10 +543,14 @@ void * Signal::HandlerThread::main(void * comm_pipe_read_end) { assert(sizeof(word) == read_out); - command_t command = reinterpret_cast(word); + command_t command = (command_t)word; switch (command) { case QUIT: + // Close comm. pipe read end + ::close(rfd); + + // Terminate thread pthread_exit(NULL); case SIGNAL: @@ -564,7 +569,7 @@ void * Signal::HandlerThread::main(void * comm_pipe_read_end) { assert(sizeof(word) == read_out); - Signal::enum_t sig = reinterpret_cast(word); + Signal::enum_t sig = (Signal::enum_t)word; // Handle signal handler(sig); @@ -586,13 +591,13 @@ void * Signal::HandlerThread::main(void * comm_pipe_read_end) { * \retval 0 on success * \retval errno on error */ -int writeCommand(int fh, void * cmd, size_t cmd_size) throw(std::runtime_error); +int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) throw(std::runtime_error); template void Signal::HandlerThread::signalNotifier(int signal) { int sig[2] = { - reinterpret_cast(Signal::HandlerThread::SIGNAL), + (int)Signal::HandlerThread::SIGNAL, }; sig[1] = signal; @@ -600,23 +605,16 @@ void Signal::HandlerThread::signalNotifier(int signal) { // TBD: The return value is silently ignored. // Either the write should've succeeded or the handling // thread is already comming down... - writeCommand(s_comm_pipe[1], sig, sizeof(sig)); + sigPipeWriteCmd(s_comm_pipe[1], sig, sizeof(sig)); } template Signal::HandlerThread::HandlerThread(const Signal::List & siglist) throw(std::logic_error, std::runtime_error) { - /* - * IMPLEMENTATION NOTES: - * 0/ Check whether comm. pipe is valid; throw std::logic_error if so - * 1/ Comm. pipe creation (or an exception) - * 2/ Start the thread: pthread_create(m_impl, , ) - * 3/ Register the signals: sigaction( ) - */ - throw std::runtime_error("TODO: Signal handler thread is not implemented, yet"); - + // At most one instance per process allowed if (-1 != s_comm_pipe[1]) - throw std::logic_error("Attempt to start a duplicate of signal handling thread detected"); + throw std::logic_error( + "Attempt to start a duplicate of signal handling thread detected"); // Create communication pipe if (::pipe(s_comm_pipe)) { @@ -627,10 +625,8 @@ Signal::HandlerThread::HandlerThread(const Signal::List & siglist) throw(std: throw std::runtime_error(e.str()); } - // TODO: -#if (0) // Start the thread - int status = ::pthread_create(&m_impl, NULL, main, s_comm_pipe); + int status = ::pthread_create(&m_impl, NULL, &main, s_comm_pipe); if (status) { std::stringstream e; @@ -646,11 +642,10 @@ Signal::HandlerThread::HandlerThread(const Signal::List & siglist) throw(std: for (; sig != siglist.end(); ++sig) { struct sigaction action; - action.sa_handler = signalNotifier; - action.sa_sigaction = NULL; // guess we don't need signal info - action.sa_mask = 0; // shouldn't we mask signals while handling them? - action.sa_flags = 0; // any flags? - action.sa_restorer = NULL; // obsolete + ::memset(&action, 0, sizeof(action)); + ::sigemptyset(&action.sa_mask); + + action.sa_handler = &signalNotifier; int signo = static_cast(*sig); @@ -666,19 +661,16 @@ Signal::HandlerThread::HandlerThread(const Signal::List & siglist) throw(std: throw std::runtime_error(e.str()); } } -#endif } template void Signal::HandlerThread::quit() throw(std::runtime_error) { - static int quit = reinterpret_cast(Signal::HandlerThread::QUIT); + static int quit = (int)Signal::HandlerThread::QUIT; - writeCommand(s_comm_pipe[1], quit, sizeof(quit)); + sigPipeWriteCmd(s_comm_pipe[1], &quit, sizeof(quit)); - // TODO: -#if (0) - int status = ::pthread_join(m_impl); + int status = ::pthread_join(m_impl, NULL); if (status) { std::stringstream e; @@ -697,7 +689,6 @@ void Signal::HandlerThread::quit() throw(std::runtime_error) { } s_comm_pipe[1] = -1; -#endif } diff --git a/tests/nutipc_ut.cpp b/tests/nutipc_ut.cpp index 600feeb10a..eb3a83fec0 100644 --- a/tests/nutipc_ut.cpp +++ b/tests/nutipc_ut.cpp @@ -59,6 +59,9 @@ class NutIPCUnitTest: public CppUnit::TestFixture { /** Signal sending test */ void testSignalSend(); + /** Signal receiving test */ + void testSignalRecv(); + public: inline void setUp() {} @@ -67,6 +70,7 @@ class NutIPCUnitTest: public CppUnit::TestFixture { inline void test() { testExec(); testSignalSend(); + testSignalRecv(); } }; // end of class NutIPCUnitTest @@ -99,7 +103,6 @@ void NutIPCUnitTest::testSignalHandler(int signal) { signal_caught = signal; } - void NutIPCUnitTest::testSignalSend() { struct sigaction action; @@ -142,3 +145,48 @@ void NutIPCUnitTest::testSignalSend() { signal_caught = 0; } + + +/** Caught signal list */ +static nut::Signal::List caught_signals; + +/** Signal handler routine */ +class TestSignalHandler: public nut::Signal::Handler { + public: + + void operator () (nut::Signal::enum_t signal) { + caught_signals.push_back(signal); + } + +}; // end of class TestSignalHandler + +void NutIPCUnitTest::testSignalRecv() { + // Create signal handler thread + nut::Signal::List signals; + + signals.push_back(nut::Signal::USER1); + signals.push_back(nut::Signal::USER2); + + nut::Signal::HandlerThread sig_handler(signals); + + pid_t my_pid = nut::Process::getPID(); + + CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER2, my_pid)); + CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, my_pid)); + CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, my_pid)); + + // Let the sig. handler thread finish... + ::sleep(1); + + CPPUNIT_ASSERT(caught_signals.size() == 3); + + CPPUNIT_ASSERT(caught_signals.front() == nut::Signal::USER2); + + caught_signals.pop_front(); + + CPPUNIT_ASSERT(caught_signals.front() == nut::Signal::USER1); + + caught_signals.pop_front(); + + CPPUNIT_ASSERT(caught_signals.front() == nut::Signal::USER1); +} From 46a3a4566345a7b508b270926612d9e4d6e0da3f Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Mon, 21 Jan 2013 13:27:55 +0100 Subject: [PATCH 037/121] C++11 code removed due platform compatibility --- common/nutwriter.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index 918afc2998..98b8f796de 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -235,8 +235,10 @@ const NotifyFlagsStrings::FlagStrings NotifyFlagsStrings::flag_str = * \return NOTIFYFLAG directive string */ static std::string serialiseNotifyFlags(UpsmonConfiguration::NotifyType type, unsigned short flags) { - static const std::string ignore_str( - NotifyFlagsStrings::flag_str.at(UpsmonConfiguration::NOTIFY_IGNORE)); + static const NotifyFlagsStrings::FlagStrings::const_iterator ignore_str_iter = + NotifyFlagsStrings::flag_str.find(UpsmonConfiguration::NOTIFY_IGNORE); + + static const std::string ignore_str(ignore_str_iter->second); assert(type < UpsmonConfiguration::NOTIFY_TYPE_MAX); From 897a05bfce2e0ff0027774ae5b060e496af5be4d Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Tue, 22 Jan 2013 18:26:15 +0100 Subject: [PATCH 038/121] The very 1st nutconf tool stub For now, only cmd. options parsing and usage works. --- common/nutconfbin.cpp | 510 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 450 insertions(+), 60 deletions(-) diff --git a/common/nutconfbin.cpp b/common/nutconfbin.cpp index a1b21bdee7..bed503f648 100644 --- a/common/nutconfbin.cpp +++ b/common/nutconfbin.cpp @@ -1,74 +1,464 @@ - #include "nutconf.h" #include "nutstream.hpp" -using namespace nut; #include -using namespace std; +#include +#include -int main(int argc, char** argv) -{ - cout << "nutconf testing program" << endl; - - if(argc<2) - { - cout << "Usage: nutconf {ups.conf path}" << endl; - return 0; - } - - // - // UPS.CONF - // - if(argc>=2) - { - cout << endl << "ups.conf:" << endl << endl; - - GenericConfiguration ups_conf; - NutFile file(argv[1]); - file.open(); - ups_conf.parseFrom(file); - - for(std::map::iterator it = ups_conf.sections.begin(); - it != ups_conf.sections.end(); ++it) - { - GenericConfigSection& section = it->second; - cout << "[" << section.name << "]" << endl; - - for(GenericConfigSection::EntryMap::iterator iter = section.entries.begin(); - iter != section.entries.end(); ++iter) - { - cout << " " << iter->first << " = " << iter->second.values.front() << endl; - } + +class Usage { + private: + + /** Usage text */ + static const char * s_text[]; + + /** Private constructor (no instances) */ + Usage() {} + + public: + + /** Print usage */ + static void print(const std::string & bin); + +}; // end of class usage + + +const char * Usage::s_text[] = { + " --help Display this help and exit", + " --autoconfigure Perform autoconfiguration", +}; + + +void Usage::print(const std::string & bin) { + std::cerr + << "Usage: " << bin << " [OPTIONS]" << std::endl + << std::endl + << "OPTIONS:" << std::endl; + + for (size_t i = 0; i < sizeof(s_text) / sizeof(char *); ++i) { + std::cerr << s_text[i] << std::endl; + } + + std::cerr << std::endl; +} + + +/** Command line options */ +class Options { + public: + + /** Options list */ + typedef std::list List; + + protected: + + /** Option type */ + typedef enum { + binaryArgument, /**< Argument of the binary itself */ + singleDash, /**< Single-dash prefixed option */ + doubleDash, /**< Double-dash prefixed option */ + } type_t; + + /** Option arguments list */ + typedef std::list Arguments; + + /** Options map */ + typedef std::map Map; + + private: + + /** Binary arguments */ + Arguments m_args; + + /** Single-dashed options */ + Map m_single; + + /** Double-dashed options */ + Map m_double; + + /** + * \brief Add option + * + * If the option already exists, the arguments are added + * to the existing (if any). + * + * \param type Option type + * \param opt Option (ignored if type is \c binaryArgument) + * \param args Option arguments + */ + void add(type_t type, const std::string & opt, const Arguments & args); + + /** + * \brief Add option without arguments + * + * \param type Option type + * \param opt Option + */ + inline void add(type_t type, const std::string & opt) { + add(type, opt, Arguments()); + } + + /** + * \brief Add option argument + * + * \param type Option type + * \param opt Option + * \param arg Argument + */ + inline void addArg(type_t type, const std::string & opt, const std::string & arg) { + add(type, opt, Arguments(1, arg)); + } + + /** + * \brief Check option existence + * + * \param map Option map + * \param opt Option + * + * \retval true iff the option was specified on the command line + * \retval false otherwise + */ + inline bool exists(const Map & map, const std::string & opt) const { + return map.end() != map.find(opt); + } + + /** + * \brief Get option arguments + * + * \param[in] map Option map + * \param[in] opt Option + * \param[out] args Option arguments + * + * \retval true iff the option was specified on the command line + * \retval false otherwise + */ + bool get(const Map & map, const std::string & opt, Arguments & args) const; + + /** + * \brief Get options list + * + * \param[in] map Option map + * \param[out] list Option list + * + * \return List of options + */ + void strings(const Map & map, List & list) const; + + public: + + /** + * \brief Constructor (from \c main routine arguments) + * + * \param argv Argument list + * \param argc Argument count + */ + Options(char * const argv[], int argc); + + /** + * \brief Check single-dashed option existence + * + * \param opt Option + * + * \retval true iff the option was specified on the command line + * \retval false otherwise + */ + inline bool existsSingle(const std::string & opt) const { + return exists(m_single, opt); + } + + /** + * \brief Check double-dashed option existence + * + * \param opt Option + * + * \retval true iff the option was specified on the command line + * \retval false otherwise + */ + inline bool existsDouble(const std::string & opt) const { + return exists(m_double, opt); + } + + /** + * \brief Check option existence (single or double dashed) + * + * \param opt Option + * + * \retval true iff the option was specified on the command line + * \retval false otherwise + */ + inline bool exists(const std::string & opt) const { + return existsSingle(opt) || existsDouble(opt); + } + + /** + * \brief Get single-dashed option arguments + * + * \param[in] opt Option + * \param[out] args Option arguments + * + * \retval true iff the option was specified on the command line + * \retval false otherwise + */ + inline bool getSingle(const std::string & opt, Arguments & args) const { + return get(m_single, opt, args); + } + + /** + * \brief Get double-dashed option arguments + * + * \param[in] opt Option + * \param[out] args Option arguments + * + * \retval true iff the option was specified on the command line + * \retval false otherwise + */ + inline bool getDouble(const std::string & opt, Arguments & args) const { + return get(m_single, opt, args); + } + + /** + * \brief Get binary arguments + * + * \return Arguments of the binary itself + */ + inline const Arguments & get() const { return m_args; } + + /** + * \brief Get single-dashed options list + * + * \return List of single-dashed options + */ + inline List stringsSingle() const { + List list; + + strings(m_single, list); + + return list; + } + + /** + * \brief Get double-dashed options list + * + * \return List of double-dashed options + */ + inline List stringsDouble() const { + List list; + + strings(m_double, list); + + return list; + } + + /** + * \brief Get all options list + * + * \return List of single or double-dashed options + */ + inline List strings() const; + +}; // end of class Options + + +void Options::add(Options::type_t type, const std::string & opt, const Arguments & args) { + Arguments * arguments = &m_args; + + switch (type) { + case binaryArgument: + + break;; + + case singleDash: + arguments = &m_single[opt]; + + break; + + case doubleDash: + arguments = &m_double[opt]; + + break; + } + + Arguments::const_iterator arg = args.begin(); + + for (; arg != args.end(); ++arg) { + arguments->push_back(*arg); + } +} + + +bool Options::get(const Options::Map & map, const std::string & opt, Arguments & args) const { + Map::const_iterator entry = map.find(opt); + + if (map.end() == entry) + return false; + + args = entry->second; + + return true; +} + + +void Options::strings(const Map & map, List & list) const { + for (Map::const_iterator opt = map.begin(); opt != map.end(); ++opt) + list.push_back(opt->first); +} + + +Options::Options(char * const argv[], int argc) { + type_t current_type = binaryArgument; + std::string current_opt; + + for (int i = 1; i < argc; ++i) { + const std::string arg(argv[i]); + + // Empty string is the current option argument, too + // '-' alone is also an option argument // (like stdout placeholder etc) + if (arg.empty() || '-' != arg[0] || 1 == arg.size()) { + addArg(current_type, current_opt, arg); + + continue; + } + + // Single-dashed option + if ('-' != arg[1]) { + current_type = singleDash; + current_opt = arg.substr(1); + + add(current_type, current_opt); + + continue; } + + // "--" alone is valid as it means that what follows + // belongs to the binary ("empty" option arguments) + if (2 == arg.size()) { + current_type = binaryArgument; + + continue; + } + + // Double-dashed option + if ('-' != arg[2]) { + current_type = doubleDash; + current_opt = arg.substr(2); + + add(current_type, current_opt); + + continue; + } + + // "---" prefix means an option argument + addArg(current_type, current_opt, arg); + } +} + + +Options::List Options::strings() const { + List list = stringsSingle(); + + strings(m_double, list); + + return list; +} + + +/** nutconf tool specific options */ +class NutConfOptions: public Options { + private: + + /** Unknown options */ + List m_unknown; + + public: + + /** --autoconfigure */ + bool autoconfigure; + + NutConfOptions(char * const argv[], int argc); + + inline bool valid() const { + // We don't accept any direct arguments + if (!get().empty()) + return false; + + return m_unknown.empty(); + } + + void reportInvalid() const; + +}; // end of class NutConfOptions + + +NutConfOptions::NutConfOptions(char * const argv[], int argc): + Options(argv, argc), + autoconfigure(false) +{ + static const std::string sDash("-"); + static const std::string dDash("--"); + + // No single-dashed options used + List list = stringsSingle(); + + for (List::const_iterator opt = list.begin(); opt != list.end(); ++opt) { + m_unknown.push_back(sDash + *opt); } - // - // UPSD.CONF - // - if(argc>=3) - { - cout << endl << "upsd.conf:" << endl << endl; - - UpsdConfiguration upsd_conf; - NutFile file(argv[2]); - file.open(); - upsd_conf.parseFrom(file); - - cout << "maxAge: " << upsd_conf.maxAge << endl; - cout << "maxConn: " << upsd_conf.maxConn << endl; - cout << "statePath: " << *upsd_conf.statePath << endl; - cout << "certFile: " << *upsd_conf.certFile << endl; - cout << "listen:" << endl; - - for(std::list::iterator it=upsd_conf.listens.begin(); - it!=upsd_conf.listens.end(); ++it) - { - cout << " - " << it->address << ":" << it->port << endl; + // Specificate double-dashed options + list = stringsDouble(); + + for (List::const_iterator opt = list.begin(); opt != list.end(); ++opt) { + // Known options + if ("autoconfigure" == *opt) { + autoconfigure = true; } + + // TODO + + // Unknown option + else { + m_unknown.push_back(dDash + *opt); + } + } +} + + +void NutConfOptions::reportInvalid() const { + List::const_iterator unknown_opt = m_unknown.begin(); + + for (; unknown_opt != m_unknown.end(); ++unknown_opt) { + std::cerr << "Unknown option: " << *unknown_opt << std::endl; } - return 0; - + // No direct arguments expected + const Arguments & args = get(); + Arguments::const_iterator arg = args.begin(); + + for (; arg != args.end(); ++arg) { + std::cerr << "Unexpected argument: " << *arg << std::endl; + } } + +int main(int argc, char * const argv[]) { + // Get options + NutConfOptions options(argv, argc); + + // Usage + if (options.exists("help")) { + Usage::print(argv[0]); + + ::exit(0); + } + + // Check that command-line options validity + if (!options.valid()) { + options.reportInvalid(); + + Usage::print(argv[0]); + + ::exit(1); + } + + return 0; +} From 62a3586aa166b7d491b969c1ac8e395d8f6a149b Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Wed, 23 Jan 2013 13:14:59 +0100 Subject: [PATCH 039/121] nutconf: --is-configured option introduced The option causes nut.conf::MODE being checked; if not "none" (and if the file exists at all), it pronounces NUT as configured. --- common/nutconfbin.cpp | 83 +++++++++++++++++++++++++++++++++++-------- common/nutstream.cpp | 17 +++++++++ include/nutstream.hpp | 49 ++++++++++++++++++++++++- 3 files changed, 133 insertions(+), 16 deletions(-) diff --git a/common/nutconfbin.cpp b/common/nutconfbin.cpp index bed503f648..c4f8f59188 100644 --- a/common/nutconfbin.cpp +++ b/common/nutconfbin.cpp @@ -1,9 +1,11 @@ +#include "config.h" #include "nutconf.h" #include "nutstream.hpp" #include #include #include +#include class Usage { @@ -26,6 +28,7 @@ class Usage { const char * Usage::s_text[] = { " --help Display this help and exit", " --autoconfigure Perform autoconfiguration", + " --is-configured Checks whether NUT is configured", }; @@ -265,7 +268,7 @@ void Options::add(Options::type_t type, const std::string & opt, const Arguments switch (type) { case binaryArgument: - break;; + break; case singleDash: arguments = &m_single[opt]; @@ -371,27 +374,34 @@ class NutConfOptions: public Options { public: + /** Options are valid */ + bool valid; + /** --autoconfigure */ bool autoconfigure; - NutConfOptions(char * const argv[], int argc); - - inline bool valid() const { - // We don't accept any direct arguments - if (!get().empty()) - return false; + /** --is-configured */ + bool is_configured; - return m_unknown.empty(); - } + /** Constructor */ + NutConfOptions(char * const argv[], int argc); - void reportInvalid() const; + /** + * \brief Report invalid options to STDERR + * + * BEWARE: throws an exception if options are valid. + * Check that using the \ref valid flag. + */ + void reportInvalid() const throw(std::logic_error); }; // end of class NutConfOptions NutConfOptions::NutConfOptions(char * const argv[], int argc): Options(argv, argc), - autoconfigure(false) + valid(true), + autoconfigure(false), + is_configured(false) { static const std::string sDash("-"); static const std::string dDash("--"); @@ -411,18 +421,26 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): if ("autoconfigure" == *opt) { autoconfigure = true; } - - // TODO + else if ("is-configured" == *opt) { + is_configured = true; + } // Unknown option else { m_unknown.push_back(dDash + *opt); } } + + // Options are valid iff we know all of them + // and there are no direct binary arguments + valid = m_unknown.empty() && get().empty(); } -void NutConfOptions::reportInvalid() const { +void NutConfOptions::reportInvalid() const throw(std::logic_error) { + if (valid) + throw std::logic_error("No invalid options to report"); + List::const_iterator unknown_opt = m_unknown.begin(); for (; unknown_opt != m_unknown.end(); ++unknown_opt) { @@ -440,6 +458,30 @@ void NutConfOptions::reportInvalid() const { } +/** + * \brief Check whether NUT was configured + * + * \param etc Configuration directory + * + * \retval true iff nut.conf exists and MODE != none + * \retval false otherwise + */ +bool isConfigured(const std::string & etc) { + nut::NutFile nut_conf_file(etc + "/nut.conf"); + + if (!nut_conf_file.existsx()) + return false; + + nut_conf_file.openx(); + + nut::NutConfiguration nut_conf; + + nut_conf.parseFrom(nut_conf_file); + + return nut::NutConfiguration::MODE_NONE != nut_conf.mode; +} + + int main(int argc, char * const argv[]) { // Get options NutConfOptions options(argv, argc); @@ -452,7 +494,7 @@ int main(int argc, char * const argv[]) { } // Check that command-line options validity - if (!options.valid()) { + if (!options.valid) { options.reportInvalid(); Usage::print(argv[0]); @@ -460,5 +502,16 @@ int main(int argc, char * const argv[]) { ::exit(1); } + // --is-configured query + if (options.is_configured) { + std::string etc(CONFPATH); + + bool is_configured = isConfigured(etc); + + std::cout << (is_configured ? "true" : "false") << std::endl; + + return 0; + } + return 0; } diff --git a/common/nutstream.cpp b/common/nutstream.cpp index 34286a7fef..e326982818 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -31,6 +31,8 @@ extern "C" { #include #include #include +#include +#include #include #include } @@ -106,6 +108,21 @@ NutFile::NutFile(anonymous_t): } +bool NutFile::exists(int & err_code, std::string & err_msg) const throw() { + struct stat info; + + int status = ::stat(m_name.c_str(), &info); + + if (!status) + return true; + + err_code = errno; + err_msg = std::string(::strerror(err_code)); + + return false; +} + + bool NutFile::open(access_t mode, int & err_code, std::string & err_msg) throw() { static const char *read_only = "r"; static const char *write_only = "w"; diff --git a/include/nutstream.hpp b/include/nutstream.hpp index 16cea7ec7e..c2d5f5db46 100644 --- a/include/nutstream.hpp +++ b/include/nutstream.hpp @@ -30,6 +30,7 @@ #include extern "C" { +#include #include #include #include @@ -258,6 +259,52 @@ class NutFile: public NutStream { return m_name; } + /** + * \brief Check whether file exists + * + * \param[out] err_code Error code + * \param[out] err_msg Error message + * + * \retval true iff the file exists + * \retval false otherwise + */ + bool exists(int & err_code, std::string & err_msg) const throw(); + + /** + * \brief Check whether file exists + * + * \retval true iff the file exists + * \retval false otherwise + */ + inline bool exists() const throw() { + int ec; + std::string em; + + return exists(ec, em); + } + + /** + * \brief Check whether file exists (or throw exception) + * + * \retval true iff the file exists + * \retval false otherwise + */ + inline bool existsx() const throw(std::runtime_error) { + int ec; + std::string em; + + if (exists(ec, em)) + return true; + + if (ENOENT == ec || ENOTDIR == ec) + return false; + + std::stringstream e; + e << "Failed to check file " << m_name << " existence: " << ec << ": " << em; + + throw std::runtime_error(e.str()); + } + /** * \brief Open file * @@ -310,7 +357,7 @@ class NutFile: public NutStream { * \brief Close file * * \param[out] err_code Error code - * \param[out] err-msg Error message + * \param[out] err_msg Error message * * \retval true if close succeeded * \retval false if close failed From b0efd21a6469ff42e50c0f75a3a5f46296a9e958 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Thu, 24 Jan 2013 19:06:28 +0100 Subject: [PATCH 040/121] nutconf: daily commit Changes: --is-configured option added (checks existence of nut.conf and the MODE) --local and --system options added to set config. directory --mode option added (so far it only stores the required mode, TODO) --set-monitor multi-option added, allows to set (add actually) MONITORs --- common/nutconf.cpp | 6 +- common/nutconfbin.cpp | 639 +++++++++++++++++++++++++++++++++++------- 2 files changed, 540 insertions(+), 105 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 2a5e7bf004..e4e2f6f3ac 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -1047,15 +1047,15 @@ void UpsmonConfigParser::onParseDirective(const std::string& directiveName, char } else if(directiveName == "MONITOR") { - if(values.size()==5) + if (values.size() == 5 || values.size() == 6) { UpsmonConfiguration::Monitor monitor; ConfigParamList::const_iterator it = values.begin(); std::stringstream system(*it++); std::string word; monitor.upsname = (getline(system, word, '@'), word); - monitor.hostname = (getline(system, word, ':'), word); - monitor.port = (getline(system, word) ? *StringToSettableNumber(word) : 0u); + monitor.hostname = (getline(system, word), word); + monitor.port = (values.size() == 6 ? *StringToSettableNumber(*it++) : 0u); monitor.powerValue = StringToSettableNumber(*it++); monitor.username = *it++; monitor.password = *it++; diff --git a/common/nutconfbin.cpp b/common/nutconfbin.cpp index c4f8f59188..4b782edb62 100644 --- a/common/nutconfbin.cpp +++ b/common/nutconfbin.cpp @@ -4,8 +4,10 @@ #include #include +#include #include #include +#include class Usage { @@ -26,9 +28,19 @@ class Usage { const char * Usage::s_text[] = { - " --help Display this help and exit", - " --autoconfigure Perform autoconfiguration", - " --is-configured Checks whether NUT is configured", +" --help Display this help and exit", +" --autoconfigure Perform autoconfiguration", +" --is-configured Checks whether NUT is configured", +" --local Sets configuration directory", +" --system Sets configuration directory to " CONFPATH, +" --mode Sets NUT mode (see below)", +" --set-monitor Configures one monitor (see below)", +" May be used multiple times", +"", +"NUT modes: standalone, netserver, netclient, controlled, manual, none", +"Monitor is specified by the following sequence:", +" [:] (\"master\"|\"slave\")", +"", }; @@ -41,8 +53,6 @@ void Usage::print(const std::string & bin) { for (size_t i = 0; i < sizeof(s_text) / sizeof(char *); ++i) { std::cerr << s_text[i] << std::endl; } - - std::cerr << std::endl; } @@ -53,23 +63,27 @@ class Options { /** Options list */ typedef std::list List; - protected: + private: /** Option type */ typedef enum { - binaryArgument, /**< Argument of the binary itself */ - singleDash, /**< Single-dash prefixed option */ - doubleDash, /**< Double-dash prefixed option */ + singleDash, /**< Single-dash prefixed option */ + doubleDash, /**< Double-dash prefixed option */ } type_t; + protected: + /** Option arguments list */ typedef std::list Arguments; /** Options map */ - typedef std::map Map; + typedef std::multimap Map; private: + /** Arguments of the last option processed (\c NULL means bin. args) */ + Arguments * m_last; + /** Binary arguments */ Arguments m_args; @@ -82,60 +96,44 @@ class Options { /** * \brief Add option * - * If the option already exists, the arguments are added - * to the existing (if any). - * - * \param type Option type - * \param opt Option (ignored if type is \c binaryArgument) - * \param args Option arguments - */ - void add(type_t type, const std::string & opt, const Arguments & args); - - /** - * \brief Add option without arguments - * * \param type Option type * \param opt Option */ - inline void add(type_t type, const std::string & opt) { - add(type, opt, Arguments()); - } + void add(type_t type, const std::string & opt); /** - * \brief Add option argument + * \brief Add argument to the last option * - * \param type Option type - * \param opt Option - * \param arg Argument + * \param arg Argument */ - inline void addArg(type_t type, const std::string & opt, const std::string & arg) { - add(type, opt, Arguments(1, arg)); + inline void addArg(const std::string & arg) { + Arguments * args = NULL != m_last ? m_last : &m_args; + + args->push_back(arg); } /** - * \brief Check option existence + * \brief Count options * * \param map Option map * \param opt Option * - * \retval true iff the option was specified on the command line - * \retval false otherwise + * \return Options count */ - inline bool exists(const Map & map, const std::string & opt) const { - return map.end() != map.find(opt); - } + size_t count(const Map & map, const std::string & opt) const; /** * \brief Get option arguments * - * \param[in] map Option map - * \param[in] opt Option - * \param[out] args Option arguments + * \param[in] map Option map + * \param[in] opt Option + * \param[out] args Option arguments + * \param[in] order Option order (1st by default) * * \retval true iff the option was specified on the command line * \retval false otherwise */ - bool get(const Map & map, const std::string & opt, Arguments & args) const; + bool get(const Map & map, const std::string & opt, Arguments & args, size_t order = 0) const; /** * \brief Get options list @@ -157,6 +155,39 @@ class Options { */ Options(char * const argv[], int argc); + /** + * \brief Count single-dashed options + * + * \param opt Option + * + * \return Options count + */ + inline size_t countSingle(const std::string & opt) const { + return count(m_single, opt); + } + + /** + * \brief Count double-dashed options + * + * \param opt Option + * + * \return Options count + */ + inline size_t countDouble(const std::string & opt) const { + return count(m_double, opt); + } + + /** + * \brief Count options (single or double dashed) + * + * \param opt Option + * + * \return Options count + */ + inline bool count(const std::string & opt) const { + return countSingle(opt) + countDouble(opt); + } + /** * \brief Check single-dashed option existence * @@ -166,7 +197,7 @@ class Options { * \retval false otherwise */ inline bool existsSingle(const std::string & opt) const { - return exists(m_single, opt); + return countSingle(opt) > 0; } /** @@ -178,7 +209,7 @@ class Options { * \retval false otherwise */ inline bool existsDouble(const std::string & opt) const { - return exists(m_double, opt); + return countDouble(opt) > 0; } /** @@ -196,14 +227,15 @@ class Options { /** * \brief Get single-dashed option arguments * - * \param[in] opt Option - * \param[out] args Option arguments + * \param[in] opt Option + * \param[out] args Option arguments + * \param[in] order Option order (1st by default) * * \retval true iff the option was specified on the command line * \retval false otherwise */ - inline bool getSingle(const std::string & opt, Arguments & args) const { - return get(m_single, opt, args); + inline bool getSingle(const std::string & opt, Arguments & args, size_t order = 0) const { + return get(m_single, opt, args, order); } /** @@ -211,12 +243,13 @@ class Options { * * \param[in] opt Option * \param[out] args Option arguments + * \param[in] order Option order (1st by default) * * \retval true iff the option was specified on the command line * \retval false otherwise */ - inline bool getDouble(const std::string & opt, Arguments & args) const { - return get(m_single, opt, args); + inline bool getDouble(const std::string & opt, Arguments & args, size_t order = 0) const { + return get(m_double, opt, args, order); } /** @@ -262,39 +295,56 @@ class Options { }; // end of class Options -void Options::add(Options::type_t type, const std::string & opt, const Arguments & args) { - Arguments * arguments = &m_args; +void Options::add(Options::type_t type, const std::string & opt) { + Map * map; switch (type) { - case binaryArgument: - - break; - case singleDash: - arguments = &m_single[opt]; + map = &m_single; break; case doubleDash: - arguments = &m_double[opt]; + map = &m_double; break; } - Arguments::const_iterator arg = args.begin(); + Map::iterator entry = map->insert(Map::value_type(opt, Arguments())); - for (; arg != args.end(); ++arg) { - arguments->push_back(*arg); - } + m_last = &entry->second; } -bool Options::get(const Options::Map & map, const std::string & opt, Arguments & args) const { +size_t Options::count(const Options::Map & map, const std::string & opt) const { + size_t cnt = 0; + + Map::const_iterator entry = map.find(opt); + + for (; entry != map.end() && entry->first == opt; ++entry) + ++cnt; + + return cnt; +} + + +bool Options::get(const Options::Map & map, const std::string & opt, Arguments & args, size_t order) const { Map::const_iterator entry = map.find(opt); if (map.end() == entry) return false; + for (; order; --order) { + Map::const_iterator next = entry; + + ++next; + + if (map.end() == next || next->first != opt) + return false; + + entry = next; + } + args = entry->second; return true; @@ -307,51 +357,31 @@ void Options::strings(const Map & map, List & list) const { } -Options::Options(char * const argv[], int argc) { - type_t current_type = binaryArgument; - std::string current_opt; - +Options::Options(char * const argv[], int argc): m_last(NULL) { for (int i = 1; i < argc; ++i) { const std::string arg(argv[i]); // Empty string is the current option argument, too // '-' alone is also an option argument // (like stdout placeholder etc) - if (arg.empty() || '-' != arg[0] || 1 == arg.size()) { - addArg(current_type, current_opt, arg); - - continue; - } + if (arg.empty() || '-' != arg[0] || 1 == arg.size()) + addArg(arg); // Single-dashed option - if ('-' != arg[1]) { - current_type = singleDash; - current_opt = arg.substr(1); - - add(current_type, current_opt); - - continue; - } + else if ('-' != arg[1]) + add(singleDash, arg.substr(1)); // "--" alone is valid as it means that what follows // belongs to the binary ("empty" option arguments) - if (2 == arg.size()) { - current_type = binaryArgument; - - continue; - } + else if (2 == arg.size()) + m_last = NULL; // Double-dashed option - if ('-' != arg[2]) { - current_type = doubleDash; - current_opt = arg.substr(2); - - add(current_type, current_opt); - - continue; - } + else if ('-' != arg[2]) + add(doubleDash, arg.substr(2)); // "---" prefix means an option argument - addArg(current_type, current_opt, arg); + else + addArg(arg); } } @@ -367,11 +397,59 @@ Options::List Options::strings() const { /** nutconf tool specific options */ class NutConfOptions: public Options { + public: + + /** + * \brief Option mode (getter/setter) + * + * The mode is typically used for options that act as a value (info) + * getter when specified without arguments while if given arguments, + * it sets the value (info). + */ + typedef enum { + NOT_SPECIFIED, /**< Option not specified on command line */ + GETTER, /**< Option is a getter */ + SETTER, /**< Option is a setter */ + } mode_t; + private: /** Unknown options */ List m_unknown; + /** Option specification errors */ + std::list m_errors; + + /** + * \brief Option mode getter (including arguments for setters) + * + * \param[in] opt Option + * \param[out] args Option arguments + * \param[in] order Option order (1st by default) + * + * \retval NOT_SPECIFIED if the option was not specified on the command line + * \retval GETTER if the option has no arguments + * \retval SETTER otherwise (option specified with arguments) + */ + mode_t optMode(const std::string & opt, Arguments & args, size_t order = 0) const; + + + /** + * \brief Option mode getter + * + * \param opt Option + * \param order Option order (1st by default) + * + * \retval NOT_SPECIFIED if the option was not specified on the command line + * \retval GETTER if the option has no arguments + * \retval SETTER otherwise (option specified with arguments) + */ + mode_t optMode(const std::string & opt, size_t order = 0) const { + Arguments args; + + return optMode(opt, args, order); + } + public: /** Options are valid */ @@ -383,6 +461,21 @@ class NutConfOptions: public Options { /** --is-configured */ bool is_configured; + /** -- local argument */ + std::string local; + + /** --system */ + bool system; + + /** --mode argument */ + std::string mode; + + /** --set-monitor arguments (all the monitors) */ + std::vector monitors; + + /** Monitors count */ + size_t monitor_cnt; + /** Constructor */ NutConfOptions(char * const argv[], int argc); @@ -394,14 +487,75 @@ class NutConfOptions: public Options { */ void reportInvalid() const throw(std::logic_error); + /** + * \brief Get NUT mode + * + * \return NUT mode (if --mode option was specified with an argument) + */ + inline std::string getMode() const { + Arguments args; + + if (SETTER != optMode("mode", args)) + return ""; + + assert(!args.empty()); + + return args.front(); + } + + /** + * \brief Get monitor definition + * + * \param[out] ups UPS name + * \param[out] host_port Host (possibly including port specification) + * \param[out] pwr_val Power value + * \param[out] user Username + * \param[out] passwd User password + * \param[out] mode Monitor mode + * \param[in] which Monitor order (1st by default) + */ + void getMonitor( + std::string & ups, + std::string & host_port, + std::string & pwr_val, + std::string & user, + std::string & passwd, + std::string & mode, + size_t which = 0) const throw(std::range_error); + + private: + + /** + * \brief Check --mode argument validity + * + * \param mode Mode argument + * + * \retval true iff the mode is set correctly + * \retval false otherwise + */ + static bool checkMode(const std::string & mode); + }; // end of class NutConfOptions +NutConfOptions::mode_t NutConfOptions::optMode(const std::string & opt, Arguments & args, size_t order) const { + if (!getDouble(opt, args, order)) + return NOT_SPECIFIED; + + if (args.empty()) + return GETTER; + + return SETTER; +} + + NutConfOptions::NutConfOptions(char * const argv[], int argc): Options(argv, argc), valid(true), autoconfigure(false), - is_configured(false) + is_configured(false), + system(false), + monitor_cnt(0) { static const std::string sDash("-"); static const std::string dDash("--"); @@ -419,10 +573,70 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): for (List::const_iterator opt = list.begin(); opt != list.end(); ++opt) { // Known options if ("autoconfigure" == *opt) { - autoconfigure = true; + if (autoconfigure) + m_errors.push_back("--autoconfigure option specified more than once"); + else + autoconfigure = true; } else if ("is-configured" == *opt) { - is_configured = true; + if (is_configured) + m_errors.push_back("--is-configured option specified more than once"); + else + is_configured = true; + } + else if ("local" == *opt) { + Arguments args; + + if (!local.empty()) + m_errors.push_back("--local option specified more than once"); + + else if (NutConfOptions::SETTER != optMode("local", args)) + m_errors.push_back("--local option requires an argument"); + + else if (args.size() > 1) + m_errors.push_back("Only one directory may be specified with the --local option"); + + else + local = args.front(); + } + else if ("system" == *opt) { + if (system) + m_errors.push_back("--system option specified more than once"); + else + system = true; + } + else if ("mode" == *opt) { + Arguments args; + + if (!mode.empty()) + m_errors.push_back("--mode option specified more than once"); + + else if (NutConfOptions::SETTER != optMode("mode", args)) + m_errors.push_back("--mode option requires an argument"); + + else if (args.size() > 1) + m_errors.push_back("Only one argument allowed for the --mode option"); + + else if (args.size() == 1 && !checkMode(args.front())) + m_errors.push_back("Unknown NUT mode: \"" + args.front() + "\""); + + else + mode = args.front(); + } + else if ("set-monitor" == *opt) { + Arguments args; + + if (NutConfOptions::SETTER != optMode("set-monitor", args, monitor_cnt)) + m_errors.push_back("--set-monitor option requires arguments"); + + else if (args.size() != 6) + m_errors.push_back("--set-monitor option requires exactly 6 arguments"); + + else + for (Arguments::const_iterator arg = args.begin(); arg != args.end(); ++arg) + monitors.push_back(*arg); + + ++monitor_cnt; } // Unknown option @@ -433,7 +647,7 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): // Options are valid iff we know all of them // and there are no direct binary arguments - valid = m_unknown.empty() && get().empty(); + valid = m_unknown.empty() && m_errors.empty() && get().empty(); } @@ -447,6 +661,12 @@ void NutConfOptions::reportInvalid() const throw(std::logic_error) { std::cerr << "Unknown option: " << *unknown_opt << std::endl; } + std::list::const_iterator error = m_errors.begin(); + + for (; error != m_errors.end(); ++error) { + std::cerr << "Option error: " << *error << std::endl; + } + // No direct arguments expected const Arguments & args = get(); @@ -458,6 +678,43 @@ void NutConfOptions::reportInvalid() const throw(std::logic_error) { } +bool NutConfOptions::checkMode(const std::string & mode) { + if ("standalone" == mode) return true; + if ("netserver" == mode) return true; + if ("netclient" == mode) return true; + if ("controlled" == mode) return true; + if ("manual" == mode) return true; + if ("none" == mode) return true; + + return false; +} + + +void NutConfOptions::getMonitor( + std::string & ups, + std::string & host_port, + std::string & pwr_val, + std::string & user, + std::string & passwd, + std::string & mode, + size_t which) const throw(std::range_error) +{ + if (which >= monitor_cnt) + throw std::range_error("INTERNAL ERROR: monitors index overflow"); + + size_t base_idx = 6 * which; + + assert(monitors.size() >= base_idx + 6); + + ups = monitors[base_idx]; + host_port = monitors[base_idx + 1]; + pwr_val = monitors[base_idx + 2]; + user = monitors[base_idx + 3]; + passwd = monitors[base_idx + 4]; + mode = monitors[base_idx + 5]; +} + + /** * \brief Check whether NUT was configured * @@ -469,7 +726,7 @@ void NutConfOptions::reportInvalid() const throw(std::logic_error) { bool isConfigured(const std::string & etc) { nut::NutFile nut_conf_file(etc + "/nut.conf"); - if (!nut_conf_file.existsx()) + if (!nut_conf_file.exists()) return false; nut_conf_file.openx(); @@ -482,7 +739,130 @@ bool isConfigured(const std::string & etc) { } -int main(int argc, char * const argv[]) { +/** + * \brief Transform monitor specification from cmd. line to monitor configuration + * + * \param i Monitor index + * \param options nutconf options + * + * \return Monitor configuration + */ +nut::UpsmonConfiguration::Monitor getMonitor( + size_t i, + const NutConfOptions & options) +{ + nut::UpsmonConfiguration::Monitor monitor; + + std::string host_port, pwr_val, mode; + + options.getMonitor( + monitor.upsname, host_port, pwr_val, + monitor.username, monitor.password, mode, + i); + + // Parse host[:port] + unsigned short port = 0; + + size_t colon_idx = host_port.rfind(':'); + + if (std::string::npos != colon_idx) { + std::stringstream ss(host_port.substr(colon_idx + 1)); + + if ((ss >> port).fail()) { + std::cerr + << "Error: failed to parse host specification \"" + << host_port << '"' << std::endl; + + ::exit(1); + } + } + + // Parse power value + unsigned int power_value; + + std::stringstream ss(pwr_val); + + if ((ss >> power_value).fail()) { + std::cerr + << "Error: failed to parse power value \"" + << pwr_val << '"' << std::endl; + + ::exit(1); + } + + monitor.hostname = host_port.substr(0, colon_idx); + monitor.port = port; + monitor.powerValue = power_value; + monitor.isMaster = "master" == mode; + + return monitor; +} + + +/** + * \brief Set monitors in upsmon.conf + * + * \param monitors Monitor list + * \param etc Configuration directory + */ +void setMonitors( + const std::list & monitors, + const std::string & etc) +{ + nut::NutFile upsmon_conf_file(etc + "/upsmon.conf"); + + nut::UpsmonConfiguration upsmon_conf; + + // Source previous configuration (if any) + if (upsmon_conf_file.exists()) { + upsmon_conf_file.openx(); + + bool parsed_ok = upsmon_conf.parseFrom(upsmon_conf_file); + + upsmon_conf_file.closex(); + + if (!parsed_ok) { + std::cerr + << "Error: Failed to parse existing " + << upsmon_conf_file.name() << std::endl; + + ::exit(1); + } + } + + // Add monitors to the current ones (if any) + std::list::const_iterator + monitor = monitors.begin(); + + for (; monitor != monitors.end(); ++monitor) + upsmon_conf.monitors.push_back(*monitor); + + // Store configuration + upsmon_conf_file.openx(nut::NutFile::WRITE_ONLY); + + bool written_ok = upsmon_conf.writeTo(upsmon_conf_file); + + upsmon_conf_file.closex(); + + if (!written_ok) { + std::cerr + << "Error: Failed to write " + << upsmon_conf_file.name() << std::endl; + + ::exit(1); + } +} + + +/** + * \brief Main routine (exceptions unsafe) + * + * \param argc Argument count + * \param argv Arguments + * + * \return 0 always (exits on error) + */ +int mainx(int argc, char * const argv[]) { // Get options NutConfOptions options(argv, argc); @@ -502,16 +882,71 @@ int main(int argc, char * const argv[]) { ::exit(1); } + // Set configuration directory + std::string etc; + + if (options.system) { + etc = CONFPATH; + } + else if (options.local.empty()) { + std::cerr << "Error: Configuration directory wasn't specified" << std::endl; + + Usage::print(argv[0]); + + ::exit(1); + } + else { + etc = options.local; + } + + // Check configuration directory availability + nut::NutFile etc_dir(etc); + + if (!etc_dir.exists()) { + std::cerr << "Error: Configuration directory " << etc << " isn't available" << std::endl; + + ::exit(1); + } + // --is-configured query if (options.is_configured) { - std::string etc(CONFPATH); - bool is_configured = isConfigured(etc); std::cout << (is_configured ? "true" : "false") << std::endl; - return 0; + ::exit(is_configured ? 0 : 1); + } + + // Monitors were set by --set-monitor + if (options.monitor_cnt) { + std::list monitors; + + for (size_t i = 0; i < options.monitor_cnt; ++i) { + monitors.push_back(getMonitor(i, options)); + } + + setMonitors(monitors, etc); } return 0; } + + +/** + * \brief Main routine exception-safe wrapper + * + * Exceptions should never leak... + * + * \param argc Argument count + * \param argv Arguments + */ +int main(int argc, char * const argv[]) { + try { + return mainx(argc, argv); + } + catch (const std::exception & e) { + std::cerr << "Error: " << e.what() << std::endl; + } + + ::exit(128); +} From 1de379fcb3c7a7f5f7c5ce133b0bb26c74d9a256 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Fri, 25 Jan 2013 13:04:43 +0100 Subject: [PATCH 041/121] nutconf: daily commit Changes: Merged with changes/bugfixes suggested by Arnaud --set-monitor option discards existing entries --add-monitor option added --set-listen and --add-listen options added --- common/nutconf.cpp | 3 +- common/nutconfbin.cpp | 380 +++++++++++++++++++++++++++++++++++------- 2 files changed, 321 insertions(+), 62 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index e4e2f6f3ac..6ddd3cecc4 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -1185,7 +1185,8 @@ void UpsmonConfigParser::onParseEnd() // NutConfiguration // -NutConfiguration::NutConfiguration() +NutConfiguration::NutConfiguration(): + mode(MODE_UNKNOWN) { } diff --git a/common/nutconfbin.cpp b/common/nutconfbin.cpp index 4b782edb62..7c06548716 100644 --- a/common/nutconfbin.cpp +++ b/common/nutconfbin.cpp @@ -28,14 +28,22 @@ class Usage { const char * Usage::s_text[] = { -" --help Display this help and exit", -" --autoconfigure Perform autoconfiguration", -" --is-configured Checks whether NUT is configured", -" --local Sets configuration directory", -" --system Sets configuration directory to " CONFPATH, -" --mode Sets NUT mode (see below)", -" --set-monitor Configures one monitor (see below)", -" May be used multiple times", +" --help Display this help and exit", +" --autoconfigure Perform autoconfiguration", +" --is-configured Checks whether NUT is configured", +" --local Sets configuration directory", +" --system Sets configuration directory to " CONFPATH " (default)", +" --mode Sets NUT mode (see below)", +" --set-monitor Configures one monitor (see below)", +" All existing entries are removed; however, it may be", +" specified multiple times to set multiple entries", +" --add-monitor Same as --set-monitor, but keeps existing entries", +" The two options are mutually exclusive", +" --set-listen [] Configures one listen address for the NUT daemon", +" All existing entries are removed; however, it may be", +" specified multiple times to set multiple entries", +" --add-listen [] Same as --set-listen, but keeps existing entries", +" The two options are mutually exclusive", "", "NUT modes: standalone, netserver, netclient, controlled, manual, none", "Monitor is specified by the following sequence:", @@ -145,6 +153,13 @@ class Options { */ void strings(const Map & map, List & list) const; + /** + * \brief Dump options (for debugging reasons) + * + * \param stream Output stream + */ + void dump(std::ostream & stream) const; + public: /** @@ -357,6 +372,40 @@ void Options::strings(const Map & map, List & list) const { } +void Options::dump(std::ostream & stream) const { + stream << "----- Options dump begin -----" << std::endl; + + Map::const_iterator opt; + + Arguments::const_iterator arg; + + for (opt = m_single.begin(); opt != m_single.end(); ++opt) { + stream << '-' << opt->first << ' '; + + for (arg = opt->second.begin(); arg != opt->second.end(); ++arg) + stream << *arg << ' '; + + stream << std::endl; + } + + for (opt = m_double.begin(); opt != m_double.end(); ++opt) { + stream << "--" << opt->first << ' '; + + for (arg = opt->second.begin(); arg != opt->second.end(); ++arg) + stream << *arg << ' '; + + stream << std::endl; + } + + stream << "-- "; + + for (arg = m_args.begin(); arg != m_args.end(); ++arg) + stream << *arg; + + stream << std::endl << "----- Options dump end -----" << std::endl; +} + + Options::Options(char * const argv[], int argc): m_last(NULL) { for (int i = 1; i < argc; ++i) { const std::string arg(argv[i]); @@ -383,6 +432,9 @@ Options::Options(char * const argv[], int argc): m_last(NULL) { else addArg(arg); } + + // Options debugging + //dump(std::cerr); } @@ -412,6 +464,9 @@ class NutConfOptions: public Options { SETTER, /**< Option is a setter */ } mode_t; + /** Listen address specification */ + typedef std::pair ListenAddrSpec; + private: /** Unknown options */ @@ -470,11 +525,23 @@ class NutConfOptions: public Options { /** --mode argument */ std::string mode; - /** --set-monitor arguments (all the monitors) */ + /** --{add|set}-monitor arguments (all the monitors) */ std::vector monitors; - /** Monitors count */ - size_t monitor_cnt; + /** Set monitor options count */ + size_t set_monitor_cnt; + + /** Added monitor options count */ + size_t add_monitor_cnt; + + /** --{add|set}-listen arguments (all the addresses) */ + std::vector listen_addrs; + + /** Set listen address options count */ + size_t set_listen_cnt; + + /** Added listen address options count */ + size_t add_listen_cnt; /** Constructor */ NutConfOptions(char * const argv[], int argc); @@ -555,7 +622,10 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): autoconfigure(false), is_configured(false), system(false), - monitor_cnt(0) + set_monitor_cnt(0), + add_monitor_cnt(0), + set_listen_cnt(0), + add_listen_cnt(0) { static const std::string sDash("-"); static const std::string dDash("--"); @@ -626,7 +696,7 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): else if ("set-monitor" == *opt) { Arguments args; - if (NutConfOptions::SETTER != optMode("set-monitor", args, monitor_cnt)) + if (NutConfOptions::SETTER != optMode("set-monitor", args, set_monitor_cnt)) m_errors.push_back("--set-monitor option requires arguments"); else if (args.size() != 6) @@ -636,7 +706,56 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): for (Arguments::const_iterator arg = args.begin(); arg != args.end(); ++arg) monitors.push_back(*arg); - ++monitor_cnt; + ++set_monitor_cnt; + } + else if ("add-monitor" == *opt) { + Arguments args; + + if (NutConfOptions::SETTER != optMode("add-monitor", args, add_monitor_cnt)) + m_errors.push_back("--add-monitor option requires arguments"); + + else if (args.size() != 6) + m_errors.push_back("--add-monitor option requires exactly 6 arguments"); + + else + for (Arguments::const_iterator arg = args.begin(); arg != args.end(); ++arg) + monitors.push_back(*arg); + + ++add_monitor_cnt; + } + else if ("set-listen" == *opt) { + Arguments args; + + if (NutConfOptions::SETTER != optMode("set-listen", args, set_listen_cnt)) + m_errors.push_back("--set-listen option requires arguments"); + + else if (args.size() < 1 || args.size() > 2) + m_errors.push_back("--set-listen option requires 1 or 2 arguments"); + + else { + ListenAddrSpec addr_port(args.front(), args.size() > 1 ? args.back() : ""); + + listen_addrs.push_back(addr_port); + } + + ++set_listen_cnt; + } + else if ("add-listen" == *opt) { + Arguments args; + + if (NutConfOptions::SETTER != optMode("add-listen", args, add_listen_cnt)) + m_errors.push_back("--add-listen option requires arguments"); + + else if (args.size() < 1 || args.size() > 2) + m_errors.push_back("--add-listen option requires 1 or 2 arguments"); + + else { + ListenAddrSpec addr_port(args.front(), args.size() > 1 ? args.back() : ""); + + listen_addrs.push_back(addr_port); + } + + ++add_listen_cnt; } // Unknown option @@ -648,6 +767,20 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): // Options are valid iff we know all of them // and there are no direct binary arguments valid = m_unknown.empty() && m_errors.empty() && get().empty(); + + // --set-monitor and --add-monitor are mutually exclusive + if (existsDouble("set-monitor") && existsDouble("add-monitor")) { + m_errors.push_back("--set-monitor and --add-monitor options can't both be specified"); + + valid = false; + } + + // --set-listen and --add-listen are mutually exclusive + if (existsDouble("set-listen") && existsDouble("add-listen")) { + m_errors.push_back("--set-listen and --add-listen options can't both be specified"); + + valid = false; + } } @@ -699,7 +832,7 @@ void NutConfOptions::getMonitor( std::string & mode, size_t which) const throw(std::range_error) { - if (which >= monitor_cnt) + if (which >= monitors.size() / 6) throw std::range_error("INTERNAL ERROR: monitors index overflow"); size_t base_idx = 6 * which; @@ -715,6 +848,65 @@ void NutConfOptions::getMonitor( } +/** + * \brief Sources configuration object from file (if exists) + * + * If the file doesn't exist, the conf. object is unchanged + * (and the result is indicated by the return value). + * If the file exists, but can't be parsed, an error is reported + * and the execution is terminated. + * + * \param config Configuration object + * \param file_name File name + * + * \retval true if the configuration file was sourced + * \retval false if the file doesn't exist + */ +bool source(nut::Serialisable * config, const std::string & file_name) { + nut::NutFile file(file_name); + + if (!file.exists()) + return false; + + file.openx(); + + bool parsed_ok = config->parseFrom(file); + + file.closex(); + + if (parsed_ok) + return true; + + std::cerr << "Error: Failed to parse " << file_name << std::endl; + + ::exit(1); +} + + +/** + * \brief Store configuration object to file + * + * If the file exists, it's rewritten. + * + * \param config Configuration object + * \param file_name File name + */ +void store(nut::Serialisable * config, const std::string & file_name) { + nut::NutFile file(file_name, nut::NutFile::WRITE_ONLY); + + bool written_ok = config->writeTo(file); + + file.closex(); + + if (written_ok) + return; + + std::cerr << "Error: Failed to write " << file_name << std::endl; + + ::exit(1); +} + + /** * \brief Check whether NUT was configured * @@ -735,20 +927,24 @@ bool isConfigured(const std::string & etc) { nut_conf.parseFrom(nut_conf_file); - return nut::NutConfiguration::MODE_NONE != nut_conf.mode; + return + nut::NutConfiguration::MODE_UNKNOWN != nut_conf.mode && + nut::NutConfiguration::MODE_NONE != nut_conf.mode; } /** - * \brief Transform monitor specification from cmd. line to monitor configuration + * \brief Transform monitor specification + * + * Transform monitor specification from cmd. line to monitor configuration. * * \param i Monitor index * \param options nutconf options * * \return Monitor configuration */ -nut::UpsmonConfiguration::Monitor getMonitor( - size_t i, +nut::UpsmonConfiguration::Monitor monitor( + size_t i, const NutConfOptions & options) { nut::UpsmonConfiguration::Monitor monitor; @@ -804,31 +1000,22 @@ nut::UpsmonConfiguration::Monitor getMonitor( * * \param monitors Monitor list * \param etc Configuration directory + * \param keep_ex Keep existing entries (discard by default) */ void setMonitors( const std::list & monitors, - const std::string & etc) + const std::string & etc, bool keep_ex = false) { - nut::NutFile upsmon_conf_file(etc + "/upsmon.conf"); + std::string upsmon_conf_file(etc + "/upsmon.conf"); nut::UpsmonConfiguration upsmon_conf; // Source previous configuration (if any) - if (upsmon_conf_file.exists()) { - upsmon_conf_file.openx(); - - bool parsed_ok = upsmon_conf.parseFrom(upsmon_conf_file); - - upsmon_conf_file.closex(); - - if (!parsed_ok) { - std::cerr - << "Error: Failed to parse existing " - << upsmon_conf_file.name() << std::endl; + source(&upsmon_conf, upsmon_conf_file); - ::exit(1); - } - } + // Remove existing monitors (unless we want to keep them) + if (!keep_ex) + upsmon_conf.monitors.clear(); // Add monitors to the current ones (if any) std::list::const_iterator @@ -838,19 +1025,82 @@ void setMonitors( upsmon_conf.monitors.push_back(*monitor); // Store configuration - upsmon_conf_file.openx(nut::NutFile::WRITE_ONLY); + store(&upsmon_conf, upsmon_conf_file); +} + + +/** + * \brief Transform listen address specification + * + * Transform listen address specification from cmd. line to listen address configuration. + * + * \param i Listen address index + * \param options nutconf options + * + * \return Listen address configuration + */ +nut::UpsdConfiguration::Listen listenAddr( + size_t i, + const NutConfOptions & options) +{ + nut::UpsdConfiguration::Listen listen_addr; - bool written_ok = upsmon_conf.writeTo(upsmon_conf_file); + const NutConfOptions::ListenAddrSpec & addr_spec = options.listen_addrs[i]; - upsmon_conf_file.closex(); + listen_addr.address = addr_spec.first; - if (!written_ok) { - std::cerr - << "Error: Failed to write " - << upsmon_conf_file.name() << std::endl; + // Parse port + if (!addr_spec.second.empty()) { + unsigned short port = 0; - ::exit(1); + std::stringstream ss(addr_spec.second); + + if ((ss >> port).fail()) { + std::cerr + << "Error: failed to parse port specification \"" + << addr_spec.second << '"' << std::endl; + + ::exit(1); + } + + listen_addr.port = port; } + + return listen_addr; +} + + +/** + * \brief Set listen addresses in upsd.conf + * + * \param listen_addrs Address list + * \param etc Configuration directory + * \param keep_ex Keep existing entries (discard by default) + */ +void setListenAddrs( + const std::list & listen_addrs, + const std::string & etc, bool keep_ex = false) +{ + std::string upsd_conf_file(etc + "/upsd.conf"); + + nut::UpsdConfiguration upsd_conf; + + // Source previous configuration (if any) + source(&upsd_conf, upsd_conf_file); + + // Remove existing listen addresses (unless we want to keep them) + if (!keep_ex) + upsd_conf.listens.clear(); + + // Add listen addresses to the current ones (if any) + std::list::const_iterator + listen = listen_addrs.begin(); + + for (; listen != listen_addrs.end(); ++listen) + upsd_conf.listens.push_back(*listen); + + // Store configuration + store(&upsd_conf, upsd_conf_file); } @@ -883,19 +1133,9 @@ int mainx(int argc, char * const argv[]) { } // Set configuration directory - std::string etc; - - if (options.system) { - etc = CONFPATH; - } - else if (options.local.empty()) { - std::cerr << "Error: Configuration directory wasn't specified" << std::endl; + std::string etc(CONFPATH); - Usage::print(argv[0]); - - ::exit(1); - } - else { + if (!options.local.empty()) { etc = options.local; } @@ -917,15 +1157,26 @@ int mainx(int argc, char * const argv[]) { ::exit(is_configured ? 0 : 1); } - // Monitors were set by --set-monitor - if (options.monitor_cnt) { + // Monitors were set + if (!options.monitors.empty()) { std::list monitors; - for (size_t i = 0; i < options.monitor_cnt; ++i) { - monitors.push_back(getMonitor(i, options)); + for (size_t n = options.monitors.size() / 6, i = 0; i < n; ++i) { + monitors.push_back(monitor(i, options)); } - setMonitors(monitors, etc); + setMonitors(monitors, etc, options.existsDouble("add-monitor")); + } + + // Listen addresses were set + if (!options.listen_addrs.empty()) { + std::list listen_addrs; + + for (size_t i = 0; i < options.listen_addrs.size(); ++i) { + listen_addrs.push_back(listenAddr(i, options)); + } + + setListenAddrs(listen_addrs, etc, options.existsDouble("add-listen")); } return 0; @@ -945,7 +1196,14 @@ int main(int argc, char * const argv[]) { return mainx(argc, argv); } catch (const std::exception & e) { - std::cerr << "Error: " << e.what() << std::endl; + std::cerr + << "Error: " << e.what() << std::endl; + } + catch (...) { + std::cerr + << "INTERNAL ERROR: exception of unknown origin caught" << std::endl + << "Please issue a bugreport to nut-upsdev@lists.alioth.debian.org" + << std::endl; } ::exit(128); From 0b00605c1d35ef2b11e1972f195881add823f015 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Fri, 25 Jan 2013 17:44:03 +0100 Subject: [PATCH 042/121] nutconf: --{set|add}-device options added --- common/nutconfbin.cpp | 170 +++++++++++++++++++++++++++++++++--------- 1 file changed, 133 insertions(+), 37 deletions(-) diff --git a/common/nutconfbin.cpp b/common/nutconfbin.cpp index 7c06548716..b8474e5a4f 100644 --- a/common/nutconfbin.cpp +++ b/common/nutconfbin.cpp @@ -44,10 +44,17 @@ const char * Usage::s_text[] = { " specified multiple times to set multiple entries", " --add-listen [] Same as --set-listen, but keeps existing entries", " The two options are mutually exclusive", +" --set-device Configures one UPS device (see below)", +" All existing devices are removed; however, it may be", +" specified multiple times to set multiple devices", +" --add-device Same as --set-device, but keeps existing devices", +" The two options are mutually exclusive", "", "NUT modes: standalone, netserver, netclient, controlled, manual, none", "Monitor is specified by the following sequence:", " [:] (\"master\"|\"slave\")", +"UPS device is specified by the following sequence:", +" []", "", }; @@ -467,6 +474,14 @@ class NutConfOptions: public Options { /** Listen address specification */ typedef std::pair ListenAddrSpec; + /** Device specification */ + struct DeviceSpec { + std::string id; /**< Device ID */ + std::string driver; /**< Device driver */ + std::string port; /**< Device port */ + std::string desc; /**< Device description */ + }; // end of struct DeviceSpec + private: /** Unknown options */ @@ -543,6 +558,15 @@ class NutConfOptions: public Options { /** Added listen address options count */ size_t add_listen_cnt; + /** Device specifications */ + std::vector devices; + + /** Set devices options count */ + size_t set_device_cnt; + + /** Added devices options count */ + size_t add_device_cnt; + /** Constructor */ NutConfOptions(char * const argv[], int argc); @@ -625,7 +649,9 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): set_monitor_cnt(0), add_monitor_cnt(0), set_listen_cnt(0), - add_listen_cnt(0) + add_listen_cnt(0), + set_device_cnt(0), + add_device_cnt(0) { static const std::string sDash("-"); static const std::string dDash("--"); @@ -693,44 +719,33 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): else mode = args.front(); } - else if ("set-monitor" == *opt) { - Arguments args; - - if (NutConfOptions::SETTER != optMode("set-monitor", args, set_monitor_cnt)) - m_errors.push_back("--set-monitor option requires arguments"); + else if ("set-monitor" == *opt || "add-monitor" == *opt) { + size_t * cnt = ('s' == (*opt)[0] ? &set_monitor_cnt : &add_monitor_cnt); - else if (args.size() != 6) - m_errors.push_back("--set-monitor option requires exactly 6 arguments"); - - else - for (Arguments::const_iterator arg = args.begin(); arg != args.end(); ++arg) - monitors.push_back(*arg); - - ++set_monitor_cnt; - } - else if ("add-monitor" == *opt) { Arguments args; - if (NutConfOptions::SETTER != optMode("add-monitor", args, add_monitor_cnt)) - m_errors.push_back("--add-monitor option requires arguments"); + if (NutConfOptions::SETTER != optMode(*opt, args, *cnt)) + m_errors.push_back("--" + *opt + " option requires arguments"); else if (args.size() != 6) - m_errors.push_back("--add-monitor option requires exactly 6 arguments"); + m_errors.push_back("--" + *opt + " option requires exactly 6 arguments"); else for (Arguments::const_iterator arg = args.begin(); arg != args.end(); ++arg) monitors.push_back(*arg); - ++add_monitor_cnt; + ++*cnt; } - else if ("set-listen" == *opt) { + else if ("set-listen" == *opt || "add-listen" == *opt) { + size_t * cnt = ('s' == (*opt)[0] ? &set_listen_cnt : &add_listen_cnt); + Arguments args; - if (NutConfOptions::SETTER != optMode("set-listen", args, set_listen_cnt)) - m_errors.push_back("--set-listen option requires arguments"); + if (NutConfOptions::SETTER != optMode(*opt, args, *cnt)) + m_errors.push_back("--" + *opt + " option requires arguments"); else if (args.size() < 1 || args.size() > 2) - m_errors.push_back("--set-listen option requires 1 or 2 arguments"); + m_errors.push_back("--" + *opt + " option requires 1 or 2 arguments"); else { ListenAddrSpec addr_port(args.front(), args.size() > 1 ? args.back() : ""); @@ -738,24 +753,42 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): listen_addrs.push_back(addr_port); } - ++set_listen_cnt; + ++*cnt; } - else if ("add-listen" == *opt) { + else if ("set-device" == *opt || "add-device" == *opt) { + size_t * cnt = ('s' == (*opt)[0] ? &set_device_cnt : &add_device_cnt); + Arguments args; - if (NutConfOptions::SETTER != optMode("add-listen", args, add_listen_cnt)) - m_errors.push_back("--add-listen option requires arguments"); + if (NutConfOptions::SETTER != optMode(*opt, args, *cnt)) + m_errors.push_back("--" + *opt + " option requires arguments"); - else if (args.size() < 1 || args.size() > 2) - m_errors.push_back("--add-listen option requires 1 or 2 arguments"); + else if (args.size() < 3) + m_errors.push_back("--" + *opt + " option requires at least 3 arguments"); + + else if (args.size() > 4) { + m_errors.push_back("--" + *opt + " option takes at most 4 arguments"); + m_errors.push_back(" (perhaps you need to quote description?)"); + } else { - ListenAddrSpec addr_port(args.front(), args.size() > 1 ? args.back() : ""); + DeviceSpec dev; - listen_addrs.push_back(addr_port); + Arguments::const_iterator arg = args.begin(); + + assert(args.size() >= 3); + + dev.id = *arg++; + dev.driver = *arg++; + dev.port = *arg++; + + if (arg != args.end()) + dev.desc = *arg; + + devices.push_back(dev); } - ++add_listen_cnt; + ++*cnt; } // Unknown option @@ -769,18 +802,25 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): valid = m_unknown.empty() && m_errors.empty() && get().empty(); // --set-monitor and --add-monitor are mutually exclusive - if (existsDouble("set-monitor") && existsDouble("add-monitor")) { + if (set_monitor_cnt > 0 && add_monitor_cnt > 0) { m_errors.push_back("--set-monitor and --add-monitor options can't both be specified"); valid = false; } // --set-listen and --add-listen are mutually exclusive - if (existsDouble("set-listen") && existsDouble("add-listen")) { + if (set_listen_cnt > 0 && add_listen_cnt > 0) { m_errors.push_back("--set-listen and --add-listen options can't both be specified"); valid = false; } + + // --set-device and --add-device are mutually exclusive + if (set_device_cnt > 0 && add_device_cnt > 0) { + m_errors.push_back("--set-device and --add-device options can't both be specified"); + + valid = false; + } } @@ -1104,6 +1144,57 @@ void setListenAddrs( } +/** + * \brief Set devices in ups.conf + * + * \param devices Device list + * \param etc Configuration directory + * \param keep_ex Keep existing entries (discard by default) + */ +void setDevices( + const std::vector & devices, + const std::string & etc, bool keep_ex = false) +{ + std::string ups_conf_file(etc + "/ups.conf"); + + nut::UpsConfiguration ups_conf; + + // Source previous configuration (if any) + source(&ups_conf, ups_conf_file); + + // Remove existing devices (unless we want to keep them) + if (!keep_ex) { + nut::UpsConfiguration::SectionMap::iterator + ups = ups_conf.sections.begin(); + + for (; ups != ups_conf.sections.end(); ++ups) { + // Keep global section + if (ups->first.empty()) + continue; + + ups_conf.sections.erase(ups); + } + } + + // Add devices to the current ones (if any) + std::vector::const_iterator + dev = devices.begin(); + + for (; dev != devices.end(); ++dev) { + const std::string & id = (*dev).id; + + ups_conf.setDriver(id, (*dev).driver); + ups_conf.setPort(id, (*dev).port); + + if (!(*dev).desc.empty()) + ups_conf.setDescription(id, (*dev).desc); + } + + // Store configuration + store(&ups_conf, ups_conf_file); +} + + /** * \brief Main routine (exceptions unsafe) * @@ -1165,7 +1256,7 @@ int mainx(int argc, char * const argv[]) { monitors.push_back(monitor(i, options)); } - setMonitors(monitors, etc, options.existsDouble("add-monitor")); + setMonitors(monitors, etc, options.add_monitor_cnt > 0); } // Listen addresses were set @@ -1176,7 +1267,12 @@ int mainx(int argc, char * const argv[]) { listen_addrs.push_back(listenAddr(i, options)); } - setListenAddrs(listen_addrs, etc, options.existsDouble("add-listen")); + setListenAddrs(listen_addrs, etc, options.add_listen_cnt > 0); + } + + // Devices were set + if (!options.devices.empty()) { + setDevices(options.devices, etc, options.add_device_cnt > 0); } return 0; From b5a4db0002ad2fd380412097da2f1b20bae04adb Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Mon, 28 Jan 2013 16:38:59 +0100 Subject: [PATCH 043/121] nutconf: --{set|add}-notifyflags options added --- common/nutconf.cpp | 2 +- common/nutconfbin.cpp | 161 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 140 insertions(+), 23 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 6ddd3cecc4..ba4377f68c 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -300,7 +300,7 @@ NutParser::Token NutParser::parseToken() { } case LEXPARSING_STATE_STRING: { - if (c == ' ' || c == '"' || c == '#' || c == '[' || c == ']' || + if (c == ' ' || c == '\t' || c == '"' || c == '#' || c == '[' || c == ']' || (c == ':' && !hasOptions(OPTION_IGNORE_COLON)) || c == '=') { if (escaped) { diff --git a/common/nutconfbin.cpp b/common/nutconfbin.cpp index b8474e5a4f..9ff20cc482 100644 --- a/common/nutconfbin.cpp +++ b/common/nutconfbin.cpp @@ -28,27 +28,30 @@ class Usage { const char * Usage::s_text[] = { -" --help Display this help and exit", -" --autoconfigure Perform autoconfiguration", -" --is-configured Checks whether NUT is configured", -" --local Sets configuration directory", -" --system Sets configuration directory to " CONFPATH " (default)", -" --mode Sets NUT mode (see below)", -" --set-monitor Configures one monitor (see below)", -" All existing entries are removed; however, it may be", -" specified multiple times to set multiple entries", -" --add-monitor Same as --set-monitor, but keeps existing entries", -" The two options are mutually exclusive", -" --set-listen [] Configures one listen address for the NUT daemon", -" All existing entries are removed; however, it may be", -" specified multiple times to set multiple entries", -" --add-listen [] Same as --set-listen, but keeps existing entries", -" The two options are mutually exclusive", -" --set-device Configures one UPS device (see below)", -" All existing devices are removed; however, it may be", -" specified multiple times to set multiple devices", -" --add-device Same as --set-device, but keeps existing devices", -" The two options are mutually exclusive", +" --help Display this help and exit", +" --autoconfigure Perform autoconfiguration", +" --is-configured Checks whether NUT is configured", +" --local Sets configuration directory", +" --system Sets configuration directory to " CONFPATH " (default)", +" --mode Sets NUT mode (see below)", +" --set-monitor Configures one monitor (see below)", +" All existing entries are removed; however, it may be", +" specified multiple times to set multiple entries", +" --add-monitor Same as --set-monitor, but keeps existing entries", +" The two options are mutually exclusive", +" --set-listen [] Configures one listen address for the NUT daemon", +" All existing entries are removed; however, it may be", +" specified multiple times to set multiple entries", +" --add-listen [] Same as --set-listen, but keeps existing entries", +" The two options are mutually exclusive", +" --set-device Configures one UPS device (see below)", +" All existing devices are removed; however, it may be", +" specified multiple times to set multiple devices", +" --add-device Same as --set-device, but keeps existing devices", +" The two options are mutually exclusive", +" --set-notifyflags + Configures notify flags for notification type", +" Existing flags are replaced", +" --add-notifyflags + Same as --set-notifyflags, but keeps existing flags", "", "NUT modes: standalone, netserver, netclient, controlled, manual, none", "Monitor is specified by the following sequence:", @@ -482,6 +485,12 @@ class NutConfOptions: public Options { std::string desc; /**< Device description */ }; // end of struct DeviceSpec + /** Notify flags specification */ + typedef std::pair > NotifyFlagsSpec; + + /** Notify flags specifications */ + typedef std::map NotifyFlagsSpecs; + private: /** Unknown options */ @@ -567,6 +576,15 @@ class NutConfOptions: public Options { /** Added devices options count */ size_t add_device_cnt; + /** Notify flags specifications */ + NotifyFlagsSpecs notify_flags; + + /** Set notify flags options count */ + size_t set_notify_flags_cnt; + + /** Added notify flags options count */ + size_t add_notify_flags_cnt; + /** Constructor */ NutConfOptions(char * const argv[], int argc); @@ -651,7 +669,9 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): set_listen_cnt(0), add_listen_cnt(0), set_device_cnt(0), - add_device_cnt(0) + add_device_cnt(0), + set_notify_flags_cnt(0), + add_notify_flags_cnt(0) { static const std::string sDash("-"); static const std::string dDash("--"); @@ -790,6 +810,43 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): ++*cnt; } + else if ("set-notifyflags" == *opt || "add-notifyflags" == *opt) { + bool set = 's' == (*opt)[0]; + size_t * cnt = (set ? &set_notify_flags_cnt : &add_notify_flags_cnt); + + Arguments args; + + if (NutConfOptions::SETTER != optMode(*opt, args, *cnt)) + m_errors.push_back("--" + *opt + " option requires arguments"); + + else if (args.size() < 2) + m_errors.push_back("--" + *opt + " option requires at least 2 arguments"); + + else { + Arguments::const_iterator arg = args.begin(); + + const std::string & type = *arg++; + + NotifyFlagsSpecs::iterator flags = notify_flags.lower_bound(type); + + if (flags != notify_flags.end() && flags->first == type) + m_errors.push_back( + "--" + *opt + " option: conflicting specifications " + + "for notification type " + type); + + else { + flags = notify_flags.insert(flags, + NotifyFlagsSpecs::value_type( + type, + NotifyFlagsSpec(set, std::list()))); + + for (; arg != args.end(); ++arg) + flags->second.second.push_back(*arg); + } + } + + ++*cnt; + } // Unknown option else { @@ -1195,6 +1252,61 @@ void setDevices( } +/** + * \brief Set notify flags in upsmon.conf + * + * \param flags Notify flags specifications + * \param etc Configuration directory + */ +void setNotifyFlags( + const NutConfOptions::NotifyFlagsSpecs & flags, + const std::string & etc) +{ + std::string upsmon_conf_file(etc + "/upsmon.conf"); + + nut::UpsmonConfiguration upsmon_conf; + + // Source previous configuration (if any) + source(&upsmon_conf, upsmon_conf_file); + + NutConfOptions::NotifyFlagsSpecs::const_iterator specs = flags.begin(); + + for (; specs != flags.end(); ++specs) { + // Resolve notification type + nut::UpsmonConfiguration::NotifyType type = + nut::UpsmonConfiguration::NotifyTypeFromString(specs->first); + + if (nut::UpsmonConfiguration::NOTIFY_TYPE_MAX == type) { + std::cerr + << "Error: failed to parse notification type specification \"" + << specs->first << '"' << std::endl; + + ::exit(1); + } + + nut::Settable & sum = + upsmon_conf.notifyFlags[type]; + + // Clear current flags (unless we want to keep them) + if (specs->second.first || !sum.set()) + sum = nut::UpsmonConfiguration::NOTIFY_IGNORE; + + // Assemble flags + std::list::const_iterator spec = specs->second.second.begin(); + + for (; spec != specs->second.second.end(); ++spec) { + nut::UpsmonConfiguration::NotifyFlag flag = + nut::UpsmonConfiguration::NotifyFlagFromString(*spec); + + sum |= (unsigned short)flag; + } + } + + // Store configuration + store(&upsmon_conf, upsmon_conf_file); +} + + /** * \brief Main routine (exceptions unsafe) * @@ -1275,6 +1387,11 @@ int mainx(int argc, char * const argv[]) { setDevices(options.devices, etc, options.add_device_cnt > 0); } + // Notify flags were set + if (!options.notify_flags.empty()) { + setNotifyFlags(options.notify_flags, etc); + } + return 0; } From 2c94e251bc079d5183d14e0ab36f911876522faa Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Mon, 28 Jan 2013 17:50:16 +0100 Subject: [PATCH 044/121] nutconf: --set-notifymsg option added --- common/nutconfbin.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/common/nutconfbin.cpp b/common/nutconfbin.cpp index 9ff20cc482..905b49cf9e 100644 --- a/common/nutconfbin.cpp +++ b/common/nutconfbin.cpp @@ -50,14 +50,20 @@ const char * Usage::s_text[] = { " --add-device Same as --set-device, but keeps existing devices", " The two options are mutually exclusive", " --set-notifyflags + Configures notify flags for notification type", +" See below for the types and supported flags", " Existing flags are replaced", " --add-notifyflags + Same as --set-notifyflags, but keeps existing flags", +" --set-notifymsg Configures notification message for the type", "", "NUT modes: standalone, netserver, netclient, controlled, manual, none", "Monitor is specified by the following sequence:", " [:] (\"master\"|\"slave\")", "UPS device is specified by the following sequence:", " []", +"Notification types:", +" ONLINE, ONBATT, LOWBATT, FSD, COMMOK, COMMBAD, SHUTDOWN, REPLBATT, NOCOMM, NOPARENT", +"Notification flags:", +" SYSLOG, WALL, EXEC, IGNORE", "", }; @@ -491,6 +497,9 @@ class NutConfOptions: public Options { /** Notify flags specifications */ typedef std::map NotifyFlagsSpecs; + /** Notify messages specifications */ + typedef std::map NotifyMsgSpecs; + private: /** Unknown options */ @@ -585,6 +594,12 @@ class NutConfOptions: public Options { /** Added notify flags options count */ size_t add_notify_flags_cnt; + /** Notify messages specifications */ + NotifyMsgSpecs notify_msgs; + + /** Set notify message options count */ + size_t set_notify_msg_cnt; + /** Constructor */ NutConfOptions(char * const argv[], int argc); @@ -671,7 +686,8 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): set_device_cnt(0), add_device_cnt(0), set_notify_flags_cnt(0), - add_notify_flags_cnt(0) + add_notify_flags_cnt(0), + set_notify_msg_cnt(0) { static const std::string sDash("-"); static const std::string dDash("--"); @@ -847,6 +863,23 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): ++*cnt; } + else if ("set-notifymsg" == *opt) { + Arguments args; + + if (NutConfOptions::SETTER != optMode(*opt, args, set_notify_msg_cnt)) + m_errors.push_back("--" + *opt + " option requires arguments"); + + else if (args.size() != 2) { + m_errors.push_back("--" + *opt + " option requires 2 arguments"); + m_errors.push_back(" (perhaps you need to quote the message?)"); + } + + else { + notify_msgs[args.front()] = args.back(); + } + + ++set_notify_msg_cnt; + } // Unknown option else { @@ -1307,6 +1340,47 @@ void setNotifyFlags( } +/** + * \brief Set notify messages in upsmon.conf + * + * \param msgs Notify messages specifications + * \param etc Configuration directory + */ +void setNotifyMsgs( + const NutConfOptions::NotifyMsgSpecs & msgs, + const std::string & etc) +{ + std::string upsmon_conf_file(etc + "/upsmon.conf"); + + nut::UpsmonConfiguration upsmon_conf; + + // Source previous configuration (if any) + source(&upsmon_conf, upsmon_conf_file); + + NutConfOptions::NotifyMsgSpecs::const_iterator spec = msgs.begin(); + + for (; spec != msgs.end(); ++spec) { + // Resolve notification type + nut::UpsmonConfiguration::NotifyType type = + nut::UpsmonConfiguration::NotifyTypeFromString(spec->first); + + if (nut::UpsmonConfiguration::NOTIFY_TYPE_MAX == type) { + std::cerr + << "Error: failed to parse notification type specification \"" + << spec->first << '"' << std::endl; + + ::exit(1); + } + + // Set message + upsmon_conf.notifyMessages[type] = spec->second; + } + + // Store configuration + store(&upsmon_conf, upsmon_conf_file); +} + + /** * \brief Main routine (exceptions unsafe) * @@ -1392,6 +1466,11 @@ int mainx(int argc, char * const argv[]) { setNotifyFlags(options.notify_flags, etc); } + // Notify messages were set + if (!options.notify_msgs.empty()) { + setNotifyMsgs(options.notify_msgs, etc); + } + return 0; } From 12143f599ed79c4cc9315c9d7992f3de0f2c4acd Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Mon, 28 Jan 2013 18:09:11 +0100 Subject: [PATCH 045/121] nutconf: --set-shutdowncmd option added --- common/nutconfbin.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/common/nutconfbin.cpp b/common/nutconfbin.cpp index 905b49cf9e..d5a393b6e3 100644 --- a/common/nutconfbin.cpp +++ b/common/nutconfbin.cpp @@ -54,6 +54,7 @@ const char * Usage::s_text[] = { " Existing flags are replaced", " --add-notifyflags + Same as --set-notifyflags, but keeps existing flags", " --set-notifymsg Configures notification message for the type", +" --set-shutdowncmd Configures shutdown command", "", "NUT modes: standalone, netserver, netclient, controlled, manual, none", "Monitor is specified by the following sequence:", @@ -600,6 +601,9 @@ class NutConfOptions: public Options { /** Set notify message options count */ size_t set_notify_msg_cnt; + /** Shutdown command */ + std::string shutdown_cmd; + /** Constructor */ NutConfOptions(char * const argv[], int argc); @@ -880,6 +884,23 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): ++set_notify_msg_cnt; } + else if ("set-shutdowncmd" == *opt) { + Arguments args; + + if (!shutdown_cmd.empty()) + m_errors.push_back("--set-shutdowncmd option specified more than once"); + + else if (NutConfOptions::SETTER != optMode("set-shutdowncmd", args)) + m_errors.push_back("--set-shutdowncmd option requires an argument"); + + else if (args.size() > 1) { + m_errors.push_back("Too many arguments for the --set-shutdowncmd option"); + m_errors.push_back(" (perhaps you need to quote the command?)"); + } + + else + shutdown_cmd = args.front(); + } // Unknown option else { @@ -1381,6 +1402,28 @@ void setNotifyMsgs( } +/** + * \brief Set shutdown command in upsmon.conf + * + * \param cmd Shutdown command + * \param etc Configuration directory + */ +void setShutdownCmd(const std::string & cmd, const std::string & etc) +{ + std::string upsmon_conf_file(etc + "/upsmon.conf"); + + nut::UpsmonConfiguration upsmon_conf; + + // Source previous configuration (if any) + source(&upsmon_conf, upsmon_conf_file); + + upsmon_conf.shutdownCmd = cmd; + + // Store configuration + store(&upsmon_conf, upsmon_conf_file); +} + + /** * \brief Main routine (exceptions unsafe) * @@ -1471,6 +1514,11 @@ int mainx(int argc, char * const argv[]) { setNotifyMsgs(options.notify_msgs, etc); } + // Shutdown command was set + if (!options.shutdown_cmd.empty()) { + setShutdownCmd(options.shutdown_cmd, etc); + } + return 0; } From 40f0b6962429a5cd3f6851049bea14cc3501ad73 Mon Sep 17 00:00:00 2001 From: Arnaud Quette Date: Wed, 19 Sep 2012 19:35:45 +0000 Subject: [PATCH 046/121] Support for FreeIPMI 1.1.x and 1.2.x (#2) Prepare for supporting API changes in FreeIPMI 1.1.x and 1.2.x. This 2nd patch, which completes [[SVN:3675]], addresses FRU API changes, and removes code redundancy. This code has been tested with FreeIPMI 0.8.12 and the latest [[FreeIPMI SVN]] trunk r9505 (reported as 1.2.0.beta2 by pkgconfig) [[SVN:3675]] = 2012-07-16T13:18:18Z!arnaud.quette@free.fr Fossil-ID: SVN r3733 --- drivers/nut-libfreeipmi.c | 375 ++++++++++++---------------------- m4/nut_check_libfreeipmi.m4 | 1 - tools/nut-scanner/scan_ipmi.c | 103 ++++++---- 3 files changed, 192 insertions(+), 287 deletions(-) diff --git a/drivers/nut-libfreeipmi.c b/drivers/nut-libfreeipmi.c index 1539e75251..dd063695c1 100644 --- a/drivers/nut-libfreeipmi.c +++ b/drivers/nut-libfreeipmi.c @@ -42,10 +42,12 @@ #include #include #include "timehead.h" +#include "common.h" #include #include +#if HAVE_FREEIPMI_MONITORING #include -#include "common.h" +#endif #include "nut-ipmi.h" #include "dstate.h" @@ -57,18 +59,46 @@ /* FreeIPMI contexts and configuration*/ ipmi_ctx_t ipmi_ctx = NULL; -ipmi_fru_parse_ctx_t fru_parse_ctx = NULL; ipmi_monitoring_ctx_t mon_ctx = NULL; struct ipmi_monitoring_ipmi_config ipmi_config; + /* SDR management API has changed with 1.1.X and later */ #ifdef HAVE_FREEIPMI_11X_12X ipmi_sdr_ctx_t sdr_ctx = NULL; + ipmi_fru_ctx_t fru_ctx = NULL; + #define SDR_PARSE_CTX sdr_ctx #else - ipmi_sdr_cache_ctx_t sdr_cache_ctx = NULL; + ipmi_sdr_cache_ctx_t sdr_ctx = NULL; ipmi_sdr_parse_ctx_t sdr_parse_ctx = NULL; -#ifndef IPMI_SDR_MAX_RECORD_LENGTH - #define IPMI_SDR_MAX_RECORD_LENGTH IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH -#endif + #define SDR_PARSE_CTX sdr_parse_ctx + ipmi_fru_parse_ctx_t fru_ctx = NULL; + /* Functions remapping */ + #define ipmi_sdr_ctx_create ipmi_sdr_cache_ctx_create + #define ipmi_sdr_ctx_destroy ipmi_sdr_cache_ctx_destroy + #define ipmi_sdr_ctx_errnum ipmi_sdr_cache_ctx_errnum + #define ipmi_sdr_ctx_errormsg ipmi_sdr_cache_ctx_errormsg + #define ipmi_fru_ctx_create ipmi_fru_parse_ctx_create + #define ipmi_fru_ctx_destroy ipmi_fru_parse_ctx_destroy + #define ipmi_fru_ctx_set_flags ipmi_fru_parse_ctx_set_flags + #define ipmi_fru_ctx_strerror ipmi_fru_parse_ctx_strerror + #define ipmi_fru_ctx_errnum ipmi_fru_parse_ctx_errnum + #define ipmi_fru_open_device_id ipmi_fru_parse_open_device_id + #define ipmi_fru_close_device_id ipmi_fru_parse_close_device_id + #define ipmi_fru_ctx_errormsg ipmi_fru_parse_ctx_errormsg + #define ipmi_fru_read_data_area ipmi_fru_parse_read_data_area + #define ipmi_fru_next ipmi_fru_parse_next + #define ipmi_fru_type_length_field_to_string ipmi_fru_parse_type_length_field_to_string + #define ipmi_fru_multirecord_power_supply_information ipmi_fru_parse_multirecord_power_supply_information + #define ipmi_fru_board_info_area ipmi_fru_parse_board_info_area + #define ipmi_fru_field_t ipmi_fru_parse_field_t + /* Constants */ + #define IPMI_SDR_MAX_RECORD_LENGTH IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH + #define IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST + #define IPMI_FRU_AREA_SIZE_MAX IPMI_FRU_PARSE_AREA_SIZE_MAX + #define IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS IPMI_FRU_PARSE_FLAGS_SKIP_CHECKSUM_CHECKS + #define IPMI_FRU_AREA_TYPE_BOARD_INFO_AREA IPMI_FRU_PARSE_AREA_TYPE_BOARD_INFO_AREA + #define IPMI_FRU_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION + #define IPMI_FRU_AREA_STRING_MAX IPMI_FRU_PARSE_AREA_STRING_MAX #endif /* HAVE_FREEIPMI_11X_12X */ /* FIXME: freeipmi auto selects a cache based on the hostname you are @@ -78,7 +108,7 @@ struct ipmi_monitoring_ipmi_config ipmi_config; /* Support functions */ static const char* libfreeipmi_getfield (uint8_t language_code, - ipmi_fru_parse_field_t *field); + ipmi_fru_field_t *field); static void libfreeipmi_cleanup(); @@ -97,7 +127,7 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev); int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) { int ret = -1; - uint8_t areabuf[IPMI_FRU_PARSE_AREA_SIZE_MAX+1]; + uint8_t areabuf[IPMI_FRU_AREA_SIZE_MAX+1]; unsigned int area_type = 0; unsigned int area_length = 0; @@ -134,26 +164,26 @@ int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) upsdebugx(1, "FreeIPMI initialized..."); /* Parse FRU information */ - if (!(fru_parse_ctx = ipmi_fru_parse_ctx_create (ipmi_ctx))) + if (!(fru_ctx = ipmi_fru_ctx_create (ipmi_ctx))) { libfreeipmi_cleanup(); - fatal_with_errno(EXIT_FAILURE, "ipmi_fru_parse_ctx_create()"); + fatal_with_errno(EXIT_FAILURE, "ipmi_fru_ctx_create()"); } /* lots of motherboards calculate checksums incorrectly */ - if (ipmi_fru_parse_ctx_set_flags (fru_parse_ctx, IPMI_FRU_PARSE_FLAGS_SKIP_CHECKSUM_CHECKS) < 0) + if (ipmi_fru_ctx_set_flags (fru_ctx, IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS) < 0) { libfreeipmi_cleanup(); - fatalx(EXIT_FAILURE, "ipmi_fru_parse_ctx_set_flags: %s\n", - ipmi_fru_parse_ctx_strerror (ipmi_fru_parse_ctx_errnum (fru_parse_ctx))); + fatalx(EXIT_FAILURE, "ipmi_fru_ctx_set_flags: %s\n", + ipmi_fru_ctx_strerror (ipmi_fru_ctx_errnum (fru_ctx))); } /* Now open the requested (local) PSU */ - if (ipmi_fru_parse_open_device_id (fru_parse_ctx, ipmi_id) < 0) + if (ipmi_fru_open_device_id (fru_ctx, ipmi_id) < 0) { libfreeipmi_cleanup(); - fatalx(EXIT_FAILURE, "ipmi_fru_parse_open_device_id: %s\n", - ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); + fatalx(EXIT_FAILURE, "ipmi_fru_open_device_id: %s\n", + ipmi_fru_ctx_errormsg (fru_ctx)); } /* Set IPMI identifier */ @@ -164,19 +194,19 @@ int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) /* clear fields */ area_type = 0; area_length = 0; - memset (areabuf, '\0', IPMI_FRU_PARSE_AREA_SIZE_MAX + 1); + memset (areabuf, '\0', IPMI_FRU_AREA_SIZE_MAX + 1); /* parse FRU buffer */ - if (ipmi_fru_parse_read_data_area (fru_parse_ctx, + if (ipmi_fru_read_data_area (fru_ctx, &area_type, &area_length, areabuf, - IPMI_FRU_PARSE_AREA_SIZE_MAX) < 0) + IPMI_FRU_AREA_SIZE_MAX) < 0) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, - "ipmi_fru_parse_open_device_id: %s\n", - ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); + "ipmi_fru_read_data_area: %s\n", + ipmi_fru_ctx_errormsg (fru_ctx)); } if (area_length) @@ -184,7 +214,7 @@ int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) switch (area_type) { /* get generic board information */ - case IPMI_FRU_PARSE_AREA_TYPE_BOARD_INFO_AREA: + case IPMI_FRU_AREA_TYPE_BOARD_INFO_AREA: if(libfreeipmi_get_board_info (areabuf, area_length, ipmi_dev) < 0) @@ -193,7 +223,7 @@ int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) } break; /* get specific PSU information */ - case IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION: + case IPMI_FRU_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION: if(libfreeipmi_get_psu_info (areabuf, area_length, ipmi_dev) < 0) { @@ -205,13 +235,13 @@ int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) break; } } - } while ((ret = ipmi_fru_parse_next (fru_parse_ctx)) == 1); + } while ((ret = ipmi_fru_next (fru_ctx)) == 1); /* check for errors */ if (ret < 0) { libfreeipmi_cleanup(); - fatal_with_errno(EXIT_FAILURE, "ipmi_fru_parse_next: %s", - ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); + fatal_with_errno(EXIT_FAILURE, "ipmi_fru_next: %s", + ipmi_fru_ctx_errormsg (fru_ctx)); } else { /* Get all related sensors information */ @@ -232,25 +262,25 @@ void nut_ipmi_close(void) } static const char* libfreeipmi_getfield (uint8_t language_code, - ipmi_fru_parse_field_t *field) + ipmi_fru_field_t *field) { - static char strbuf[IPMI_FRU_PARSE_AREA_STRING_MAX + 1]; - unsigned int strbuflen = IPMI_FRU_PARSE_AREA_STRING_MAX; + static char strbuf[IPMI_FRU_AREA_STRING_MAX + 1]; + unsigned int strbuflen = IPMI_FRU_AREA_STRING_MAX; if (!field->type_length_field_length) return NULL; - memset (strbuf, '\0', IPMI_FRU_PARSE_AREA_STRING_MAX + 1); + memset (strbuf, '\0', IPMI_FRU_AREA_STRING_MAX + 1); - if (ipmi_fru_parse_type_length_field_to_string (fru_parse_ctx, + if (ipmi_fru_type_length_field_to_string (fru_ctx, field->type_length_field, field->type_length_field_length, language_code, strbuf, &strbuflen) < 0) { - upsdebugx (2, "ipmi_fru_parse_type_length_field_to_string: %s", - ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); + upsdebugx (2, "ipmi_fru_type_length_field_to_string: %s", + ipmi_fru_ctx_errormsg (fru_ctx)); return NULL; } @@ -279,24 +309,20 @@ static float libfreeipmi_get_voltage (uint8_t voltage_code) static void libfreeipmi_cleanup() { /* cleanup */ - if (fru_parse_ctx) { - ipmi_fru_parse_close_device_id (fru_parse_ctx); - ipmi_fru_parse_ctx_destroy (fru_parse_ctx); + if (fru_ctx) { + ipmi_fru_close_device_id (fru_ctx); + ipmi_fru_ctx_destroy (fru_ctx); } -#ifdef HAVE_FREEIPMI_11X_12X if (sdr_ctx) { ipmi_sdr_ctx_destroy (sdr_ctx); } -#else /* HAVE_FREEIPMI_11X_12X */ - if (sdr_cache_ctx) { - ipmi_sdr_cache_ctx_destroy (sdr_cache_ctx); - } +#ifndef HAVE_FREEIPMI_11X_12X if (sdr_parse_ctx) { ipmi_sdr_parse_ctx_destroy (sdr_parse_ctx); } -#endif /* HAVE_FREEIPMI_11X_12X */ +#endif if (ipmi_ctx) { ipmi_ctx_close (ipmi_ctx); @@ -342,7 +368,7 @@ static int libfreeipmi_get_psu_info (const void *areabuf, upsdebugx(1, "entering libfreeipmi_get_psu_info()"); - if (ipmi_fru_parse_multirecord_power_supply_information (fru_parse_ctx, + if (ipmi_fru_multirecord_power_supply_information (fru_ctx, areabuf, area_length, &overall_capacity, @@ -368,8 +394,8 @@ static int libfreeipmi_get_psu_info (const void *areabuf, &total_combined_wattage, &predictive_fail_tachometer_lower_threshold) < 0) { - fatalx(EXIT_FAILURE, "ipmi_fru_parse_multirecord_power_supply_information: %s", - ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); + fatalx(EXIT_FAILURE, "ipmi_fru_multirecord_power_supply_information: %s", + ipmi_fru_ctx_errormsg (fru_ctx)); } ipmi_dev->overall_capacity = overall_capacity; @@ -383,6 +409,8 @@ static int libfreeipmi_get_psu_info (const void *areabuf, ipmi_dev->voltage = libfreeipmi_get_voltage(voltage_1); + upsdebugx(1, "libfreeipmi_get_psu_info() retrieved successfully"); + return (0); } @@ -392,12 +420,12 @@ static int libfreeipmi_get_board_info (const void *areabuf, { uint8_t language_code; uint32_t mfg_date_time; - ipmi_fru_parse_field_t board_manufacturer; - ipmi_fru_parse_field_t board_product_name; - ipmi_fru_parse_field_t board_serial_number; - ipmi_fru_parse_field_t board_part_number; - ipmi_fru_parse_field_t board_fru_file_id; - ipmi_fru_parse_field_t board_custom_fields[IPMI_FRU_CUSTOM_FIELDS]; + ipmi_fru_field_t board_manufacturer; + ipmi_fru_field_t board_product_name; + ipmi_fru_field_t board_serial_number; + ipmi_fru_field_t board_part_number; + ipmi_fru_field_t board_fru_file_id; + ipmi_fru_field_t board_custom_fields[IPMI_FRU_CUSTOM_FIELDS]; const char *string = NULL; time_t timetmp; struct tm mfg_date_time_tm; @@ -406,15 +434,15 @@ static int libfreeipmi_get_board_info (const void *areabuf, upsdebugx(1, "entering libfreeipmi_get_board_info()"); /* clear fields */ - memset (&board_manufacturer, '\0', sizeof (ipmi_fru_parse_field_t)); - memset (&board_product_name, '\0', sizeof (ipmi_fru_parse_field_t)); - memset (&board_serial_number, '\0', sizeof (ipmi_fru_parse_field_t)); - memset (&board_fru_file_id, '\0', sizeof (ipmi_fru_parse_field_t)); + memset (&board_manufacturer, '\0', sizeof (ipmi_fru_field_t)); + memset (&board_product_name, '\0', sizeof (ipmi_fru_field_t)); + memset (&board_serial_number, '\0', sizeof (ipmi_fru_field_t)); + memset (&board_fru_file_id, '\0', sizeof (ipmi_fru_field_t)); memset (&board_custom_fields[0], '\0', - sizeof (ipmi_fru_parse_field_t) * IPMI_FRU_CUSTOM_FIELDS); + sizeof (ipmi_fru_field_t) * IPMI_FRU_CUSTOM_FIELDS); /* parse FRU buffer */ - if (ipmi_fru_parse_board_info_area (fru_parse_ctx, + if (ipmi_fru_board_info_area (fru_ctx, areabuf, area_length, &language_code, @@ -428,8 +456,8 @@ static int libfreeipmi_get_board_info (const void *areabuf, IPMI_FRU_CUSTOM_FIELDS) < 0) { libfreeipmi_cleanup(); - fatalx(EXIT_FAILURE, "ipmi_fru_parse_board_info_area: %s", - ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); + fatalx(EXIT_FAILURE, "ipmi_fru_board_info_area: %s", + ipmi_fru_ctx_errormsg (fru_ctx)); } @@ -498,113 +526,64 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) ipmi_dev->sensors_count = 0; memset(ipmi_dev->sensors_id_list, 0, sizeof(ipmi_dev->sensors_id_list)); -#ifdef HAVE_FREEIPMI_11X_12X if (!(sdr_ctx = ipmi_sdr_ctx_create ())) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_ctx_create()"); } - if (ipmi_sdr_cache_open (sdr_ctx, ipmi_ctx, CACHE_LOCATION) < 0) - { - if (ipmi_sdr_ctx_errnum (sdr_ctx) != IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) - { - libfreeipmi_cleanup(); - fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s", - ipmi_sdr_ctx_errormsg (sdr_ctx)); - } - } -#else /* HAVE_FREEIPMI_11X_12X */ - if (!(sdr_cache_ctx = ipmi_sdr_cache_ctx_create ())) - { - libfreeipmi_cleanup(); - fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_ctx_create()"); - } - +#ifndef HAVE_FREEIPMI_11X_12X if (!(sdr_parse_ctx = ipmi_sdr_parse_ctx_create ())) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_parse_ctx_create()"); } +#endif - if (ipmi_sdr_cache_open (sdr_cache_ctx, ipmi_ctx, CACHE_LOCATION) < 0) + if (ipmi_sdr_cache_open (sdr_ctx, ipmi_ctx, CACHE_LOCATION) < 0) { - if (ipmi_sdr_cache_ctx_errnum (sdr_cache_ctx) != IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) + if (ipmi_sdr_ctx_errnum (sdr_ctx) != IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s", - ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); + ipmi_sdr_ctx_errormsg (sdr_ctx)); } } -#endif /* HAVE_FREEIPMI_11X_12X */ -#ifdef HAVE_FREEIPMI_11X_12X if (ipmi_sdr_ctx_errnum (sdr_ctx) == IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) { if (ipmi_sdr_cache_create (sdr_ctx, ipmi_ctx, CACHE_LOCATION, IPMI_SDR_CACHE_CREATE_FLAGS_DEFAULT, +#ifndef HAVE_FREEIPMI_11X_12X + IPMI_SDR_CACHE_VALIDATION_FLAGS_DEFAULT, +#endif NULL, NULL) < 0) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_create: %s", ipmi_sdr_ctx_errormsg (sdr_ctx)); } - if (ipmi_sdr_cache_open (sdr_ctx, - ipmi_ctx, CACHE_LOCATION) < 0) + if (ipmi_sdr_cache_open (sdr_ctx, ipmi_ctx, CACHE_LOCATION) < 0) { if (ipmi_sdr_ctx_errnum (sdr_ctx) != IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) { - libfreeipmi_cleanup(); - fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s", - ipmi_sdr_ctx_errormsg (sdr_ctx)); - } - } - } -#else /* HAVE_FREEIPMI_11X_12X */ - if (ipmi_sdr_cache_ctx_errnum (sdr_cache_ctx) == IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) - { - if (ipmi_sdr_cache_create (sdr_cache_ctx, - ipmi_ctx, CACHE_LOCATION, - IPMI_SDR_CACHE_CREATE_FLAGS_DEFAULT, - IPMI_SDR_CACHE_VALIDATION_FLAGS_DEFAULT, - NULL, NULL) < 0) - { - libfreeipmi_cleanup(); - fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_create: %s", - ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); - } - if (ipmi_sdr_cache_open (sdr_cache_ctx, - ipmi_ctx, CACHE_LOCATION) < 0) - { - if (ipmi_sdr_cache_ctx_errnum (sdr_cache_ctx) != IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) - { - libfreeipmi_cleanup(); - fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s", - ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); + libfreeipmi_cleanup(); + fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s", + ipmi_sdr_ctx_errormsg (sdr_ctx)); } } } -#endif /* HAVE_FREEIPMI_11X_12X */ -#ifdef HAVE_FREEIPMI_11X_12X - if (ipmi_sdr_cache_record_count (sdr_ctx, &record_count) < 0) { + if (ipmi_sdr_cache_record_count (sdr_ctx, &record_count) < 0) { fprintf (stderr, - "ipmi_sdr_cache_record_count: %s", + "ipmi_sdr_cache_record_count: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } -#else - if (ipmi_sdr_cache_record_count (sdr_cache_ctx, &record_count) < 0) - { - fprintf (stderr, - "ipmi_sdr_cache_record_count: %s", - ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); - goto cleanup; - } -#endif /* HAVE_FREEIPMI_11X_12X */ -#ifdef HAVE_FREEIPMI_11X_12X + upsdebugx(3, "Found %i records in SDR cache", record_count); + for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_ctx)) { memset (sdr_record, '\0', IPMI_SDR_MAX_RECORD_LENGTH); @@ -613,50 +592,29 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) sdr_record, IPMI_SDR_MAX_RECORD_LENGTH)) < 0) { - fprintf (stderr, "ipmi_sdr_cache_record_read: %s", + fprintf (stderr, "ipmi_sdr_cache_record_read: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } - if (ipmi_sdr_parse_record_id_and_type (sdr_ctx, + if (ipmi_sdr_parse_record_id_and_type (SDR_PARSE_CTX, sdr_record, sdr_record_len, NULL, &record_type) < 0) { - fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s", + fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } -#else - for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_cache_ctx)) - { - memset (sdr_record, '\0', IPMI_SDR_MAX_RECORD_LENGTH); - if ((sdr_record_len = ipmi_sdr_cache_record_read (sdr_cache_ctx, - sdr_record, - IPMI_SDR_MAX_RECORD_LENGTH)) < 0) - { - fprintf (stderr, "ipmi_sdr_cache_record_read: %s", - ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); - goto cleanup; - } - if (ipmi_sdr_parse_record_id_and_type (sdr_parse_ctx, - sdr_record, - sdr_record_len, - NULL, - &record_type) < 0) - { - fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s", - ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx)); - goto cleanup; - } -#endif /* HAVE_FREEIPMI_11X_12X */ + upsdebugx (5, "Checking record %i (/%i)", i, record_count); - if (record_type != IPMI_SDR_FORMAT_FRU_DEVICE_LOCATOR_RECORD) + if (record_type != IPMI_SDR_FORMAT_FRU_DEVICE_LOCATOR_RECORD) { + upsdebugx(1, "=======> not device locator (%i)!!", record_type); continue; + } -#ifdef HAVE_FREEIPMI_11X_12X - if (ipmi_sdr_parse_fru_device_locator_parameters (sdr_ctx, + if (ipmi_sdr_parse_fru_device_locator_parameters (SDR_PARSE_CTX, sdr_record, sdr_record_len, NULL, @@ -666,86 +624,49 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) &logical_physical_fru_device, NULL) < 0) { - fprintf (stderr, "ipmi_sdr_parse_fru_device_locator_parameters: %s", + fprintf (stderr, "ipmi_sdr_parse_fru_device_locator_parameters: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } -#else /* HAVE_FREEIPMI_11X_12X */ - if (ipmi_sdr_parse_fru_device_locator_parameters (sdr_parse_ctx, - sdr_record, - sdr_record_len, - NULL, - &logical_fru_device_device_slave_address, - NULL, - NULL, - &logical_physical_fru_device, - NULL) < 0) - { - fprintf (stderr, "ipmi_sdr_parse_fru_device_locator_parameters: %s", - ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx)); - goto cleanup; - } -#endif /* HAVE_FREEIPMI_11X_12X */ + + upsdebugx(2, "Checking device %i/%i", logical_physical_fru_device, + logical_fru_device_device_slave_address); if (logical_physical_fru_device && logical_fru_device_device_slave_address == ipmi_dev->ipmi_id) { found_device_id++; -#ifdef HAVE_FREEIPMI_11X_12X - if (ipmi_sdr_parse_fru_entity_id_and_instance (sdr_ctx, + if (ipmi_sdr_parse_fru_entity_id_and_instance (SDR_PARSE_CTX, sdr_record, sdr_record_len, &entity_id, &entity_instance) < 0) { fprintf (stderr, - "ipmi_sdr_parse_fru_entity_id_and_instance: %s", + "ipmi_sdr_parse_fru_entity_id_and_instance: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } -#else /* HAVE_FREEIPMI_11X_12X */ - if (ipmi_sdr_parse_fru_entity_id_and_instance (sdr_parse_ctx, - sdr_record, - sdr_record_len, - &entity_id, - &entity_instance) < 0) - { - fprintf (stderr, - "ipmi_sdr_parse_fru_entity_id_and_instance: %s", - ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx)); - goto cleanup; - } -#endif /* HAVE_FREEIPMI_11X_12X */ break; } } if (!found_device_id) { - fprintf (stderr, "Couldn't find device id %d", ipmi_dev->ipmi_id); + fprintf (stderr, "Couldn't find device id %d\n", ipmi_dev->ipmi_id); goto cleanup; } else upsdebugx(1, "Found device id %d", ipmi_dev->ipmi_id); -#ifdef HAVE_FREEIPMI_11X_12X if (ipmi_sdr_cache_first (sdr_ctx) < 0) { - fprintf (stderr, "ipmi_sdr_cache_first: %s", + fprintf (stderr, "ipmi_sdr_cache_first: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } -#else /* HAVE_FREEIPMI_11X_12X */ - if (ipmi_sdr_cache_first (sdr_cache_ctx) < 0) - { - fprintf (stderr, "ipmi_sdr_cache_first: %s", - ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); - goto cleanup; - } -#endif /* HAVE_FREEIPMI_11X_12X */ -#ifdef HAVE_FREEIPMI_11X_12X for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_ctx)) { /* uint8_t sdr_record[IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH]; @@ -757,49 +678,21 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) sdr_record, IPMI_SDR_MAX_RECORD_LENGTH)) < 0) { - fprintf (stderr, "ipmi_sdr_cache_record_read: %s", + fprintf (stderr, "ipmi_sdr_cache_record_read: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } - if (ipmi_sdr_parse_record_id_and_type (sdr_ctx, + if (ipmi_sdr_parse_record_id_and_type (SDR_PARSE_CTX, sdr_record, sdr_record_len, &record_id, &record_type) < 0) { - fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s", + fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } -#else /* HAVE_FREEIPMI_11X_12X */ - for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_cache_ctx)) - { - /* uint8_t sdr_record[IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH]; - uint8_t record_type, tmp_entity_id, tmp_entity_instance; - int sdr_record_len; */ - - memset (sdr_record, '\0', IPMI_SDR_MAX_RECORD_LENGTH); - if ((sdr_record_len = ipmi_sdr_cache_record_read (sdr_cache_ctx, - sdr_record, - IPMI_SDR_MAX_RECORD_LENGTH)) < 0) - { - fprintf (stderr, "ipmi_sdr_cache_record_read: %s", - ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); - goto cleanup; - } - - if (ipmi_sdr_parse_record_id_and_type (sdr_parse_ctx, - sdr_record, - sdr_record_len, - &record_id, - &record_type) < 0) - { - fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s", - ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx)); - goto cleanup; - } -#endif /* HAVE_FREEIPMI_11X_12X */ upsdebugx (5, "Checking record %i (/%i)", record_id, record_count); @@ -809,31 +702,17 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) continue; } -#ifdef HAVE_FREEIPMI_11X_12X - if (ipmi_sdr_parse_entity_id_instance_type (sdr_ctx, + if (ipmi_sdr_parse_entity_id_instance_type (SDR_PARSE_CTX, sdr_record, sdr_record_len, &tmp_entity_id, &tmp_entity_instance, NULL) < 0) { - fprintf (stderr, "ipmi_sdr_parse_entity_instance_type: %s", + fprintf (stderr, "ipmi_sdr_parse_entity_instance_type: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } -#else /* HAVE_FREEIPMI_11X_12X */ - if (ipmi_sdr_parse_entity_id_instance_type (sdr_parse_ctx, - sdr_record, - sdr_record_len, - &tmp_entity_id, - &tmp_entity_instance, - NULL) < 0) - { - fprintf (stderr, "ipmi_sdr_parse_entity_instance_type: %s", - ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx)); - goto cleanup; - } -#endif /* HAVE_FREEIPMI_11X_12X */ if (tmp_entity_id == entity_id && tmp_entity_instance == entity_instance) @@ -850,15 +729,11 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) cleanup: /* Cleanup */ -#ifdef HAVE_FREEIPMI_11X_12X if (sdr_ctx) { ipmi_sdr_ctx_destroy (sdr_ctx); } -#else /* HAVE_FREEIPMI_11X_12X */ - if (sdr_cache_ctx) { - ipmi_sdr_cache_ctx_destroy (sdr_cache_ctx); - } +#ifndef HAVE_FREEIPMI_11X_12X if (sdr_parse_ctx) { ipmi_sdr_parse_ctx_destroy (sdr_parse_ctx); } diff --git a/m4/nut_check_libfreeipmi.m4 b/m4/nut_check_libfreeipmi.m4 index 72e781947a..5b2eae9e77 100644 --- a/m4/nut_check_libfreeipmi.m4 +++ b/m4/nut_check_libfreeipmi.m4 @@ -66,7 +66,6 @@ if test -z "${nut_have_libfreeipmi_seen}"; then dnl when version cannot be tested (prior to 1.0.5, with no pkg-config) dnl we have to check for some specific functions AC_SEARCH_LIBS([ipmi_ctx_find_inband], [freeipmi], [], [nut_have_freeipmi=no]) - AC_SEARCH_LIBS([ipmi_fru_parse_ctx_create], [freeipmi], [], [nut_have_freeipmi=no]) AC_SEARCH_LIBS([ipmi_monitoring_init], [ipmimonitoring], [nut_have_freeipmi_monitoring=yes], [nut_have_freeipmi_monitoring=no]) AC_SEARCH_LIBS([ipmi_monitoring_sensor_read_record_id], [ipmimonitoring], [], [nut_have_freeipmi_monitoring=no]) diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c index d650efa872..c1ec78a9d6 100644 --- a/tools/nut-scanner/scan_ipmi.c +++ b/tools/nut-scanner/scan_ipmi.c @@ -34,24 +34,51 @@ static char * libname = "libfreeipmi"; static lt_dlhandle dl_handle = NULL; static const char *dl_error = NULL; -static int (*nut_ipmi_fru_parse_close_device_id) (ipmi_fru_parse_ctx_t ctx); -static void (*nut_ipmi_fru_parse_ctx_destroy) (ipmi_fru_parse_ctx_t ctx); #ifdef HAVE_FREEIPMI_11X_12X -static void (*nut_ipmi_sdr_ctx_destroy) (ipmi_sdr_ctx_t ctx); + /* Functions symbols remapping */ + #define IPMI_FRU_CLOSE_DEVICE_ID "ipmi_fru_close_device_id" + #define IPMI_FRU_CTX_DESTROY "ipmi_fru_ctx_destroy" + #define IPMI_FRU_CTX_CREATE "ipmi_fru_ctx_create" + #define IPMI_FRU_CTX_SET_FLAGS "ipmi_fru_ctx_set_flags" + #define IPMI_FRU_OPEN_DEVICE_ID "ipmi_fru_open_device_id" + #define IPMI_FRU_CTX_ERRORMSG "ipmi_fru_ctx_errormsg" + #define IPMI_FRU_READ_DATA_AREA "ipmi_fru_read_data_area" + #define IPMI_FRU_PARSE_NEXT "ipmi_fru_next" + typedef ipmi_fru_ctx_t ipmi_fru_parse_ctx_t; + typedef ipmi_sdr_ctx_t ipmi_sdr_cache_ctx_t; + /* Functions remapping */ + static void (*nut_ipmi_sdr_ctx_destroy) (ipmi_sdr_ctx_t ctx); #else /* HAVE_FREEIPMI_11X_12X */ -static void (*nut_ipmi_sdr_cache_ctx_destroy) (ipmi_sdr_cache_ctx_t ctx); -static void (*nut_ipmi_sdr_parse_ctx_destroy) (ipmi_sdr_parse_ctx_t ctx); + #define IPMI_FRU_AREA_SIZE_MAX IPMI_FRU_PARSE_AREA_SIZE_MAX + #define IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS IPMI_FRU_PARSE_FLAGS_SKIP_CHECKSUM_CHECKS + #define IPMI_FRU_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION + /* Functions symbols remapping */ + #define IPMI_FRU_CLOSE_DEVICE_ID "ipmi_fru_parse_close_device_id" + #define IPMI_FRU_CTX_DESTROY "ipmi_fru_parse_ctx_destroy" + #define IPMI_FRU_CTX_CREATE "ipmi_fru_parse_ctx_create" + #define IPMI_FRU_CTX_SET_FLAGS "ipmi_fru_parse_ctx_set_flags" + #define IPMI_FRU_OPEN_DEVICE_ID "ipmi_fru_parse_open_device_id" + #define IPMI_FRU_CTX_ERRORMSG "ipmi_fru_parse_ctx_errormsg" + #define IPMI_FRU_READ_DATA_AREA "ipmi_fru_parse_read_data_area" + #define IPMI_FRU_PARSE_NEXT "ipmi_fru_parse_next" + /* Functions remapping */ + static void (*nut_ipmi_sdr_cache_ctx_destroy) (ipmi_sdr_cache_ctx_t ctx); + static void (*nut_ipmi_sdr_parse_ctx_destroy) (ipmi_sdr_parse_ctx_t ctx); #endif /* HAVE_FREEIPMI_11X_12X */ -static ipmi_fru_parse_ctx_t (*nut_ipmi_fru_parse_ctx_create) (ipmi_ctx_t ipmi_ctx); -static int (*nut_ipmi_fru_parse_ctx_set_flags) (ipmi_fru_parse_ctx_t ctx, unsigned int flags); -static int (*nut_ipmi_fru_parse_open_device_id) (ipmi_fru_parse_ctx_t ctx, uint8_t fru_device_id); -static char * (*nut_ipmi_fru_parse_ctx_errormsg) (ipmi_fru_parse_ctx_t ctx); -static int (*nut_ipmi_fru_parse_read_data_area) (ipmi_fru_parse_ctx_t ctx, + + +static int (*nut_ipmi_fru_close_device_id) (ipmi_fru_parse_ctx_t ctx); +static void (*nut_ipmi_fru_ctx_destroy) (ipmi_fru_parse_ctx_t ctx); +static ipmi_fru_parse_ctx_t (*nut_ipmi_fru_ctx_create) (ipmi_ctx_t ipmi_ctx); +static int (*nut_ipmi_fru_ctx_set_flags) (ipmi_fru_parse_ctx_t ctx, unsigned int flags); +static int (*nut_ipmi_fru_open_device_id) (ipmi_fru_parse_ctx_t ctx, uint8_t fru_device_id); +static char * (*nut_ipmi_fru_ctx_errormsg) (ipmi_fru_parse_ctx_t ctx); +static int (*nut_ipmi_fru_read_data_area) (ipmi_fru_parse_ctx_t ctx, unsigned int *area_type, unsigned int *area_length, void *areabuf, unsigned int areabuflen); -static int (*nut_ipmi_fru_parse_next) (ipmi_fru_parse_ctx_t ctx); +static int (*nut_ipmi_fru_next) (ipmi_fru_parse_ctx_t ctx); static ipmi_ctx_t (*nut_ipmi_ctx_create) (void); static int (*nut_ipmi_ctx_find_inband) (ipmi_ctx_t ctx, ipmi_driver_type_t *driver_type, @@ -92,12 +119,12 @@ int nutscan_load_ipmi_library() /* Clear any existing error */ lt_dlerror(); - *(void **) (&nut_ipmi_fru_parse_close_device_id) = lt_dlsym(dl_handle, "ipmi_fru_parse_close_device_id"); + *(void **) (&nut_ipmi_fru_close_device_id) = lt_dlsym(dl_handle, IPMI_FRU_CLOSE_DEVICE_ID); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_ipmi_fru_parse_ctx_destroy) = lt_dlsym(dl_handle, "ipmi_fru_parse_ctx_destroy"); + *(void **) (&nut_ipmi_fru_ctx_destroy) = lt_dlsym(dl_handle, IPMI_FRU_CTX_DESTROY); if ((dl_error = lt_dlerror()) != NULL) { goto err; } @@ -122,32 +149,32 @@ int nutscan_load_ipmi_library() } #endif /* HAVE_FREEIPMI_11X_12X */ - *(void **) (&nut_ipmi_fru_parse_ctx_create) = lt_dlsym(dl_handle, "ipmi_fru_parse_ctx_create"); + *(void **) (&nut_ipmi_fru_ctx_create) = lt_dlsym(dl_handle, IPMI_FRU_CTX_CREATE); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_ipmi_fru_parse_ctx_set_flags) = lt_dlsym(dl_handle, "ipmi_fru_parse_ctx_set_flags"); + *(void **) (&nut_ipmi_fru_ctx_set_flags) = lt_dlsym(dl_handle, IPMI_FRU_CTX_SET_FLAGS); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_ipmi_fru_parse_open_device_id) = lt_dlsym(dl_handle, "ipmi_fru_parse_open_device_id"); + *(void **) (&nut_ipmi_fru_open_device_id) = lt_dlsym(dl_handle, IPMI_FRU_OPEN_DEVICE_ID); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_ipmi_fru_parse_ctx_errormsg) = lt_dlsym(dl_handle, "ipmi_fru_parse_ctx_errormsg"); + *(void **) (&nut_ipmi_fru_ctx_errormsg) = lt_dlsym(dl_handle, IPMI_FRU_CTX_ERRORMSG); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_ipmi_fru_parse_read_data_area) = lt_dlsym(dl_handle, "ipmi_fru_parse_read_data_area"); + *(void **) (&nut_ipmi_fru_read_data_area) = lt_dlsym(dl_handle, IPMI_FRU_READ_DATA_AREA); if ((dl_error = lt_dlerror()) != NULL) { goto err; } - *(void **) (&nut_ipmi_fru_parse_next) = lt_dlsym(dl_handle, "ipmi_fru_parse_next"); + *(void **) (&nut_ipmi_fru_next) = lt_dlsym(dl_handle, IPMI_FRU_PARSE_NEXT); if ((dl_error = lt_dlerror()) != NULL) { goto err; } @@ -179,7 +206,7 @@ int nutscan_load_ipmi_library() return 1; err: - fprintf(stderr, "Cannot load IPMI library (%s) : %s. IPMI search disabled.\n", libname, dl_error); + fprintf(stderr, "Cannot load IPMI library (%s) : %s. IPMI search disabled.\n", libname, dl_error); dl_handle = (void *)1; lt_dlexit(); return 0; @@ -197,8 +224,8 @@ static void nut_freeipmi_cleanup(ipmi_fru_parse_ctx_t fru_parse_ctx, #endif /* HAVE_FREEIPMI_11X_12X */ { if (fru_parse_ctx) { - (*nut_ipmi_fru_parse_close_device_id) (fru_parse_ctx); - (*nut_ipmi_fru_parse_ctx_destroy) (fru_parse_ctx); + (*nut_ipmi_fru_close_device_id) (fru_parse_ctx); + (*nut_ipmi_fru_ctx_destroy) (fru_parse_ctx); } #ifdef HAVE_FREEIPMI_11X_12X @@ -226,7 +253,7 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) int ret = -1; unsigned int area_type = 0; unsigned int area_length = 0; - uint8_t areabuf[IPMI_FRU_PARSE_AREA_SIZE_MAX+1]; + uint8_t areabuf[IPMI_FRU_AREA_SIZE_MAX+1]; ipmi_fru_parse_ctx_t fru_parse_ctx = NULL; #ifdef HAVE_FREEIPMI_11X_12X ipmi_sdr_ctx_t sdr_ctx = NULL; @@ -236,14 +263,14 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) #endif /* HAVE_FREEIPMI_11X_12X */ /* Parse FRU information */ - if (!(fru_parse_ctx = (*nut_ipmi_fru_parse_ctx_create) (ipmi_ctx))) + if (!(fru_parse_ctx = (*nut_ipmi_fru_ctx_create) (ipmi_ctx))) { fprintf(stderr, "ipmi_fru_parse_ctx_create()\n"); return 0; } - +fprintf(stdout, "There.1\n"); /* lots of motherboards calculate checksums incorrectly */ - if ((*nut_ipmi_fru_parse_ctx_set_flags) (fru_parse_ctx, IPMI_FRU_PARSE_FLAGS_SKIP_CHECKSUM_CHECKS) < 0) + if ((*nut_ipmi_fru_ctx_set_flags) (fru_parse_ctx, IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS) < 0) { #ifdef HAVE_FREEIPMI_11X_12X nut_freeipmi_cleanup(fru_parse_ctx, sdr_ctx); @@ -252,8 +279,8 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) #endif /* HAVE_FREEIPMI_11X_12X */ return 0; } - - if ((*nut_ipmi_fru_parse_open_device_id) (fru_parse_ctx, ipmi_id) < 0) +fprintf(stdout, "There.2\n"); + if ((*nut_ipmi_fru_open_device_id) (fru_parse_ctx, ipmi_id) < 0) { #ifdef HAVE_FREEIPMI_11X_12X nut_freeipmi_cleanup(fru_parse_ctx, sdr_ctx); @@ -265,17 +292,18 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) do { +fprintf(stdout, "There.3\n"); /* clear fields */ area_type = 0; area_length = 0; - memset (areabuf, '\0', IPMI_FRU_PARSE_AREA_SIZE_MAX + 1); + memset (areabuf, '\0', IPMI_FRU_AREA_SIZE_MAX + 1); /* parse FRU buffer */ - if ((*nut_ipmi_fru_parse_read_data_area) (fru_parse_ctx, + if ((*nut_ipmi_fru_read_data_area) (fru_parse_ctx, &area_type, &area_length, areabuf, - IPMI_FRU_PARSE_AREA_SIZE_MAX) < 0) + IPMI_FRU_AREA_SIZE_MAX) < 0) { #ifdef HAVE_FREEIPMI_11X_12X nut_freeipmi_cleanup(fru_parse_ctx, sdr_ctx); @@ -287,7 +315,7 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) if (area_length) { - if (area_type == IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION) + if (area_type == IPMI_FRU_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION) { /* Found a POWER_SUPPLY record */ #ifdef HAVE_FREEIPMI_11X_12X @@ -298,7 +326,7 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) return 1; } } - } while ((ret = (*nut_ipmi_fru_parse_next) (fru_parse_ctx)) == 1); + } while ((ret = (*nut_ipmi_fru_next) (fru_parse_ctx)) == 1); /* No need for further errors checking */ #ifdef HAVE_FREEIPMI_11X_12X @@ -322,7 +350,7 @@ nutscan_device_t * nutscan_scan_ipmi() if( !nutscan_avail_ipmi ) { return NULL; } - +fprintf(stdout, "There1\n"); /* Initialize the FreeIPMI library. */ if (!(ipmi_ctx = (*nut_ipmi_ctx_create) ())) { @@ -331,6 +359,7 @@ nutscan_device_t * nutscan_scan_ipmi() return NULL; } +fprintf(stdout, "There2\n"); if ((ret = (*nut_ipmi_ctx_find_inband) (ipmi_ctx, NULL, 0, /* don't disable auto-probe */ @@ -338,7 +367,7 @@ nutscan_device_t * nutscan_scan_ipmi() 0, NULL, 0, /* workaround flags, none by default */ - 0 /* flags */ + IPMI_FLAGS_NONBLOCKING /* flags */ )) < 0) { fprintf(stderr, "ipmi_ctx_find_inband: %s\n", @@ -350,12 +379,14 @@ nutscan_device_t * nutscan_scan_ipmi() /* No local IPMI device detected */ return NULL; } +fprintf(stdout, "There3 (ret = %i)\n", ret); /* Loop through all possible components */ for (ipmi_id = 0 ; ipmi_id <= IPMI_FRU_DEVICE_ID_MAX ; ipmi_id++) { - +fprintf(stdout, "There4\n"); if (is_ipmi_device_supported(ipmi_ctx, ipmi_id)) { +fprintf(stdout, "There4.%i\n", ipmi_id); if ( (nut_dev = nutscan_new_device()) == NULL ) { fprintf(stderr,"Memory allocation error\n"); nutscan_free_device(current_nut_dev); From 606663e034eac44ab44381827dc709ebfba174be Mon Sep 17 00:00:00 2001 From: Arnaud Quette Date: Thu, 4 Oct 2012 22:50:52 +0000 Subject: [PATCH 047/121] Support power supplies scan over the network nut-scanner can now scan for power supplies with IPMI over LAN. This is currently limited to IPMI 1.5 only Fossil-ID: SVN r3739 --- docs/man/nut-scanner.txt | 108 ++++++++------ drivers/nut-ipmipsu.c | 15 +- tools/nut-scanner/nut-scan.h | 39 ++++- tools/nut-scanner/nut-scanner.c | 74 +++++++++- tools/nut-scanner/scan_ipmi.c | 243 ++++++++++++++++++++++++++++---- 5 files changed, 388 insertions(+), 91 deletions(-) diff --git a/docs/man/nut-scanner.txt b/docs/man/nut-scanner.txt index 6948449fb1..efe0e58d18 100644 --- a/docs/man/nut-scanner.txt +++ b/docs/man/nut-scanner.txt @@ -36,118 +36,128 @@ DISPLAY OPTIONS --------------- *-N* | *--disp_nut_conf*:: - - Display result in the 'ups.conf' format. +Display result in the 'ups.conf' format. *-P* | *--disp_parsable*:: - - Display result in a parsable format. +Display result in a parsable format. BUS OPTIONS ----------- *-C* | *--complete_scan*:: - - Scan all available communication buses (default behavior) +Scan all available communication buses (default behavior) *-U* | *--usb_scan*:: - - List all NUT-compatible USB devices currently plugged in. +List all NUT-compatible USB devices currently plugged in. *-S* | *--snmp_scan*:: - - Scan SNMP devices. Requires at least a 'start IP', and optionally, an 'end IP'. See specific SNMP OPTIONS for community and security settings. +Scan SNMP devices. Requires at least a 'start IP', and optionally, an 'end IP'. See specific SNMP OPTIONS for community and security settings. *-M* | *--xml_scan*:: - - Scan XML/HTTP devices. Broadcast a network message on the current network interfaces to retrieve XML/HTTP capable devices. No IP required. +Scan XML/HTTP devices. Broadcast a network message on the current network interfaces to retrieve XML/HTTP capable devices. No IP required. *-O* | *--oldnut_scan*:: - - Scan NUT devices (i.e. upsd daemon) on IP ranging from 'start IP' to 'end IP'. +Scan NUT devices (i.e. upsd daemon) on IP ranging from 'start IP' to 'end IP'. *-A* | *--avahi_scan*:: - - Scan NUT servers using Avahi request on the current network interfaces. No IP required. +Scan NUT servers using Avahi request on the current network interfaces. No IP required. *-I* | *--ipmi_scan*:: - - Scan NUT compatible devices available via IPMI on the current host. +Scan NUT compatible power supplies available via IPMI on the current host, or over the network. NETWORK OPTIONS --------------- *-t* | *--timeout* 'timeout':: - - Set the network timeout in seconds. Default timeout is 5 seconds. +Set the network timeout in seconds. Default timeout is 5 seconds. *-s* | *--start_ip* 'start IP':: - - Set the first IP (IPv4 or IPv6) when a range of IP is required (SNMP, old_nut). +Set the first IP (IPv4 or IPv6) when a range of IP is required (SNMP, old_nut). *-e* | *--end_ip* 'end IP':: - - Set the last IP (IPv4 or IPv6) when a range of IP is required (SNMP, old_nut). If this parameter is omitted, only the 'start IP' is scanned. If 'end IP' is less than 'start IP', both parameters are internally permuted. +Set the last IP (IPv4 or IPv6) when a range of IP is required (SNMP, old_nut). If this parameter is omitted, only the 'start IP' is scanned. If 'end IP' is less than 'start IP', both parameters are internally permuted. *-m* | *--mask_cidr* 'IP address/mask':: - - Set a range of IP using CIDR notation. +Set a range of IP using CIDR notation. NUT DEVICE OPTION ----------------- *-p* | *--port* 'port number':: - - Set the port number of scanned NUT devices (default 3493). +Set the port number of scanned NUT devices (default 3493). SNMP V1 OPTION -------------- *-c* | *--community* 'community':: - - Set SNMP v1 community name (default = public). +Set SNMP v1 community name (default = public). SNMP V3 OPTIONS --------------- *-l* | *--secLevel* 'security level':: - - Set the 'security level' used for SNMPv3 messages. Allowed values are: noAuthNoPriv, authNoPriv and authPriv. +Set the 'security level' used for SNMPv3 messages. Allowed values are: noAuthNoPriv, authNoPriv and authPriv. *-u* | *--secName* 'security name':: - - Set the 'security name' used for authenticated SNMPv3 messages. This parameter is mandatory if you set 'security level'. +Set the 'security name' used for authenticated SNMPv3 messages. This parameter is mandatory if you set 'security level'. *-w* | *--authProtocol* 'authentication protocol':: - - Set the 'authentication protocol' used for authenticated SNMPv3 messages. Allowed values are MD5 or SHA. Default value is MD5. +Set the 'authentication protocol' used for authenticated SNMPv3 messages. Allowed values are MD5 or SHA. Default value is MD5. *-W* | *--authPassword* 'authentication pass phrase':: - - Set the 'authentication pass phrase' used for authenticated SNMPv3 messages. This parameter is mandatory if you set 'security level' to authNoPriv or authPriv. +Set the 'authentication pass phrase' used for authenticated SNMPv3 messages. This parameter is mandatory if you set 'security level' to authNoPriv or authPriv. *-x* | *--privProtocol* 'privacy protocol':: - - Set the 'privacy protocol' used for encrypted SNMPv3 messages. Allowed values are DES or AES. Default value is DES. +Set the 'privacy protocol' used for encrypted SNMPv3 messages. Allowed values are DES or AES. Default value is DES. *-X* | *--privPassword* 'privacy pass phrase':: +Set the 'privacy pass phrase' used for encrypted SNMPv3 messages. This parameter is mandatory if you set 'security level' to authPriv. - Set the 'privacy pass phrase' used for encrypted SNMPv3 messages. This parameter is mandatory if you set 'security level' to authPriv. +IPMI OPTIONS +------------ + +*-b* | *--username* 'username':: +Set the username used for authenticating IPMI over LAN connections (mandatory for IPMI over LAN. No default). + +*-B* | *--password* 'password':: +Specify the password to use when authenticationg with the remote host (mandatory for IPMI over LAN. No default). + +*-d* | *--authType* 'authentication type':: +Specify the IPMI 1.5 authentication type to use (NONE, STRAIGHT_PASSWORD_KEY, MD2, and MD5) with the remote host (default=MD5). +This forces connection through the 'lan' IPMI interface , thus in IPMI 1.5 mode. + +*-D* | *--cipher_suite_id* 'cipher suite identifier':: +Specify the IPMI 2.0 cipher suite ID to use. The Cipher Suite ID identifies a set of authentication, integrity, and +confidentiality algorithms to use for IPMI 2.0 communication. The authentication algorithm identifies the algorithm +to use for session setup, the integrity algorithm identifies the algorithm to use for session packet signatures, and the +confidentiality algorithm identifies the algorithm to use for payload encryption (default=3). ++ +The following cipher suite ids are currently supported (Authentication; Integrity; Confidentiality): + +- *0*: None; None; None +- *1*: HMAC-SHA1; None; None +- *2*: HMAC-SHA1; HMAC-SHA1-96; None +- *3*: HMAC-SHA1; HMAC-SHA1-96; AES-CBC-128 +- *6*: HMAC-MD5; None; None +- *7*: HMAC-MD5; HMAC-MD5-128; None +- *8*: HMAC-MD5; HMAC-MD5-128; AES-CBC-128 +- *11*: HMAC-MD5; MD5-128; None +- *12*: HMAC-MD5; MD5-128; AES-CBC-128 +- *15*: HMAC-SHA256; None; None +- *16*: HMAC-SHA256; HMAC_SHA256_128; None +- *17*: HMAC-SHA256; HMAC_SHA256_128; AES-CBC-128 MISCELLANEOUS OPTIONS --------------------- *-V* | *--version*:: - - Display NUT version. +Display NUT version. *-a* | *--available*:: - - Display available bus that can be scanned , depending on how the binary has been compiled. (OLDNUT, USB, SNMP, XML, AVAHI, IPMI). +Display available bus that can be scanned , depending on how the binary has been compiled. (OLDNUT, USB, SNMP, XML, AVAHI, IPMI). *-q* | *--quiet*:: - - Display only scan result. No information on currently scanned bus is displayed. +Display only scan result. No information on currently scanned bus is displayed. EXAMPLES -------- @@ -168,6 +178,10 @@ To scan NUT servers with a timeout of 10 seconds on IP range 192.168.0.0 to 192. *nut-scanner -O -t 10 -m 192.168.0.0/25* +To scan for power supplies, through IPMI (1.5 mode) over the network, on address range 192.168.0.0 to 192.168.0.255: + +*nut-scanner -I -m 192.168.0.0/24 -b username -B password* + SEE ALSO -------- diff --git a/drivers/nut-ipmipsu.c b/drivers/nut-ipmipsu.c index b7382a845f..2991cfc3c8 100644 --- a/drivers/nut-ipmipsu.c +++ b/drivers/nut-ipmipsu.c @@ -27,7 +27,7 @@ #include "nut-ipmi.h" #define DRIVER_NAME "IPMI PSU driver" -#define DRIVER_VERSION "0.07" +#define DRIVER_VERSION "0.30" /* driver description structure */ upsdrv_info_t upsdrv_info = { @@ -183,17 +183,20 @@ void upsdrv_makevartable(void) "Type of the device to match ('psu' for \"Power Supply\")"); addvar(VAR_VALUE, "serial", "Serial number to match a specific device"); - addvar(VAR_VALUE, "fruid", "FRU identifier to match a specific device"); - addvar(VAR_VALUE, "sensorid", "Sensor identifier to match a specific device"); */ + addvar(VAR_VALUE, "fruid", "FRU identifier to match a specific device"); */ } void upsdrv_initups(void) { upsdebugx(1, "upsdrv_initups..."); - /* port can be expressed using: - * "id?" for device (FRU) ID 0x? - * "psu?" for PSU number ? + /* port can be expressed in various forms: + * - inband: + * "id?" for device (FRU) ID 0x? + * "psu?" for PSU number ? + * - out of band + * "id?@host" + * "host" => requires serial or ... */ if (!strncmp( device_path, "id", 2)) { diff --git a/tools/nut-scanner/nut-scan.h b/tools/nut-scanner/nut-scan.h index affcc773fe..8b9f1abb95 100644 --- a/tools/nut-scanner/nut-scan.h +++ b/tools/nut-scanner/nut-scan.h @@ -1,6 +1,8 @@ /* nut-scan.h: detect NUT services * - * Copyright (C) 2011 - Frederic Bohe + * Copyright (C) + * 2011 - Frederic Bohe + * 2012 - Arnaud Quette * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,6 +18,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef NUT_SCAN_H #define NUT_SCAN_H @@ -23,6 +26,10 @@ #include #include +#ifdef WITH_IPMI +#include +#endif + /* SNMP structure */ typedef struct nutscan_snmp { char * community; @@ -36,8 +43,34 @@ typedef struct nutscan_snmp { void * handle; } nutscan_snmp_t; +/* IPMI structure */ +/* Settings for OutofBand (remote) connection */ +typedef struct nutscan_ipmi { + char* username; /* IPMI 1.5 and 2.0 */ + char* password; /* IPMI 1.5 and 2.0 */ + int authentication_type; /* IPMI 1.5 */ + int cipher_suite_id; /* IPMI 2.0 */ + char* K_g_BMC_key; /* IPMI 2.0, optional key for 2 key auth. */ + int privilege_level; /* for both */ + unsigned int workaround_flags; /* for both */ + int ipmi_version; /* IPMI 1.5 or 2.0? */ +} nutscan_ipmi_t; + +/* IPMI auth defines, simply using FreeIPMI defines */ +#ifndef IPMI_AUTHENTICATION_TYPE_NONE + #define IPMI_AUTHENTICATION_TYPE_NONE 0x00 + #define IPMI_AUTHENTICATION_TYPE_MD2 0x01 + #define IPMI_AUTHENTICATION_TYPE_MD5 0x02 + #define IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY 0x04 + #define IPMI_AUTHENTICATION_TYPE_OEM_PROP 0x05 + #define IPMI_AUTHENTICATION_TYPE_RMCPPLUS 0x06 +#endif /* IPMI_AUTHENTICATION_TYPE_NONE */ + +#define IPMI_1_5 1 +#define IPMI_2_0 0 + /* Scanning */ -nutscan_device_t * nutscan_scan_snmp(const char * start_ip,const char * stop_ip,long usec_timeout, nutscan_snmp_t * sec); +nutscan_device_t * nutscan_scan_snmp(const char * start_ip, const char * stop_ip, long usec_timeout, nutscan_snmp_t * sec); nutscan_device_t * nutscan_scan_usb(); @@ -47,7 +80,7 @@ nutscan_device_t * nutscan_scan_nut(const char * startIP, const char * stopIP, c nutscan_device_t * nutscan_scan_avahi(long usec_timeout); -nutscan_device_t * nutscan_scan_ipmi(void); +nutscan_device_t * nutscan_scan_ipmi(const char * startIP, const char * stopIP, nutscan_ipmi_t * sec); /* Display functions */ void nutscan_display_ups_conf(nutscan_device_t * device); diff --git a/tools/nut-scanner/nut-scanner.c b/tools/nut-scanner/nut-scanner.c index db582beb72..e372d39fd3 100644 --- a/tools/nut-scanner/nut-scanner.c +++ b/tools/nut-scanner/nut-scanner.c @@ -35,7 +35,7 @@ #define ERR_BAD_OPTION (-1) -const char optstring[] = "?ht:s:e:c:l:u:W:X:w:x:p:CUSMOAm:NPqIVa"; +const char optstring[] = "?ht:s:e:c:l:u:W:X:w:x:p:b:B:d:D:CUSMOAm:NPqIVa"; #ifdef HAVE_GETOPT_LONG const struct option longopts[] = @@ -50,6 +50,10 @@ const struct option longopts[] = { "privPassword",required_argument,NULL,'X' }, { "authProtocol",required_argument,NULL,'w' }, { "privProtocol",required_argument,NULL,'x' }, + { "username",required_argument,NULL,'b' }, + { "password",required_argument,NULL,'B' }, + { "authType",required_argument,NULL,'d' }, + { "cipher_suite_id",required_argument,NULL,'D' }, { "port",required_argument,NULL,'p' }, { "complete_scan",no_argument,NULL,'C' }, { "usb_scan",no_argument,NULL,'U' }, @@ -110,7 +114,9 @@ static void * run_avahi(void * arg) } static void * run_ipmi(void * arg) { - dev[TYPE_IPMI] = nutscan_scan_ipmi(); + nutscan_ipmi_t * sec = (nutscan_ipmi_t *)arg; + + dev[TYPE_IPMI] = nutscan_scan_ipmi(start_ip,end_ip,sec); return NULL; } #endif /* HAVE_PTHREAD */ @@ -133,6 +139,7 @@ static int printq(int quiet,const char *fmt, ...) int main(int argc, char *argv[]) { nutscan_snmp_t snmp_sec; + nutscan_ipmi_t ipmi_sec; int opt_ret; char * cidr = NULL; int allow_all = 0; @@ -147,6 +154,12 @@ int main(int argc, char *argv[]) int ret_code = EXIT_SUCCESS; memset(&snmp_sec, 0, sizeof(snmp_sec)); + memset(&ipmi_sec, 0, sizeof(ipmi_sec)); + /* Set the default values for IPMI */ + ipmi_sec.authentication_type = IPMI_AUTHENTICATION_TYPE_MD5; + ipmi_sec.ipmi_version = IPMI_1_5; /* default to IPMI 1.5, if not otherwise specified */ + ipmi_sec.cipher_suite_id = 3; /* default to HMAC-SHA1; HMAC-SHA1-96; AES-CBC-128 */ + ipmi_sec.privilege_level = IPMI_PRIVILEGE_LEVEL_ADMIN; /* should be sufficient */ nutscan_init(); @@ -220,6 +233,45 @@ int main(int argc, char *argv[]) } allow_snmp = 1; break; + case 'b': + if(!nutscan_avail_ipmi) { + goto display_help; + } + ipmi_sec.username = strdup(optarg); + break; + case 'B': + if(!nutscan_avail_ipmi) { + goto display_help; + } + ipmi_sec.password = strdup(optarg); + break; + case 'd': + if(!nutscan_avail_ipmi) { + goto display_help; + } + if (!strcmp(optarg, "NONE")) { + ipmi_sec.authentication_type = IPMI_AUTHENTICATION_TYPE_NONE; + } + else if (!strcmp(optarg, "STRAIGHT_PASSWORD_KEY")) { + ipmi_sec.authentication_type = IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY; + } + else if (!strcmp(optarg, "MD2")) { + ipmi_sec.authentication_type = IPMI_AUTHENTICATION_TYPE_MD2; + } + else if (!strcmp(optarg, "MD5")) { + ipmi_sec.authentication_type = IPMI_AUTHENTICATION_TYPE_MD5; + } + else { + fprintf(stderr,"Unknown authentication type (%s). Defaulting to MD5\n", optarg); + } + break; + case 'D': + if(!nutscan_avail_ipmi) { + goto display_help; + } + ipmi_sec.cipher_suite_id = atoi(optarg); + /* Force IPMI 2.0! */ + ipmi_sec.ipmi_version = IPMI_2_0; case 'p': port = strdup(optarg); break; @@ -307,6 +359,8 @@ int main(int argc, char *argv[]) if( nutscan_avail_ipmi ) { printf(" -I, --ipmi_scan: Scan IPMI devices.\n"); } + + printf("\nNetwork specific options:\n"); printf(" -t, --timeout : network operation timeout (default %d).\n",DEFAULT_TIMEOUT); printf(" -s, --start_ip : First IP address to scan.\n"); printf(" -e, --end_ip : Last IP address to scan.\n"); @@ -325,6 +379,18 @@ int main(int argc, char *argv[]) printf(" -X, --privPassword : Set the privacy pass phrase used for encrypted SNMPv3 messages (mandatory if you set secLevel to authPriv)\n"); } + if( nutscan_avail_ipmi ) { + printf("\nIPMI over LAN specific options:\n"); + printf(" -b, --username : Set the username used for authenticating IPMI over LAN connections (mandatory for IPMI over LAN. No default)\n"); + /* Specify the username to use when authenticating with the remote host. If not specified, a null (i.e. anonymous) username is assumed. The user must have + * at least ADMIN privileges in order for this tool to operate fully. */ + printf(" -B, --password : Specify the password to use when authenticationg with the remote host (mandatory for IPMI over LAN. No default)\n"); + /* Specify the password to use when authenticationg with the remote host. If not specified, a null password is assumed. Maximum password length is 16 for IPMI + * 1.5 and 20 for IPMI 2.0. */ + printf(" -d, --authType : Specify the IPMI 1.5 authentication type to use (NONE, STRAIGHT_PASSWORD_KEY, MD2, and MD5) with the remote host (default=MD5)\n"); + printf(" -D, --cipher_suite_id : Specify the IPMI 2.0 cipher suite ID to use, for authentication, integrity, and confidentiality (default=3)\n"); + } + printf("\nNUT specific options:\n"); printf(" -p, --port : Port number of remote NUT upsd\n"); printf("\ndisplay specific options:\n"); @@ -425,11 +491,11 @@ int main(int argc, char *argv[]) if( allow_ipmi && nutscan_avail_ipmi) { printq(quiet,"Scanning IPMI bus.\n"); #ifdef HAVE_PTHREAD - if(pthread_create(&thread[TYPE_IPMI],NULL,run_ipmi,NULL)) { + if(pthread_create(&thread[TYPE_IPMI],NULL,run_ipmi,&ipmi_sec)) { nutscan_avail_ipmi = 0; } #else - dev[TYPE_IPMI] = nutscan_scan_ipmi(); + dev[TYPE_IPMI] = nutscan_scan_ipmi(start_ip,end_ip,timeout,&ipmi_sec); #endif /* HAVE_PTHREAD */ } diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c index c1ec78a9d6..0288ad46b2 100644 --- a/tools/nut-scanner/scan_ipmi.c +++ b/tools/nut-scanner/scan_ipmi.c @@ -29,6 +29,11 @@ #define NUT_IPMI_DRV_NAME "nut-ipmipsu" +/* IPMI defines */ +/* 5 seconds for establishing an IPMI connection */ +#define IPMI_SESSION_TIMEOUT_LENGTH_DEFAULT 5000 +#define IPMI_RETRANSMISSION_TIMEOUT_LENGTH_DEFAULT 250 + /* dynamic link library stuff */ static char * libname = "libfreeipmi"; static lt_dlhandle dl_handle = NULL; @@ -88,10 +93,23 @@ static int (*nut_ipmi_ctx_find_inband) (ipmi_ctx_t ctx, const char *driver_device, unsigned int workaround_flags, unsigned int flags); +static int (*nut_ipmi_ctx_open_outofband) (ipmi_ctx_t ctx, + const char *hostname, + const char *username, + const char *password, + uint8_t authentication_type, + uint8_t privilege_level, + unsigned int session_timeout, + unsigned int retransmission_timeout, + unsigned int workaround_flags, + unsigned int flags); +static int (*nut_ipmi_ctx_errnum) (ipmi_ctx_t ctx); static char * (*nut_ipmi_ctx_errormsg) (ipmi_ctx_t ctx); static int (*nut_ipmi_ctx_close) (ipmi_ctx_t ctx); static void (*nut_ipmi_ctx_destroy) (ipmi_ctx_t ctx); +/* Internal functions */ +static nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t * sec); /* Return 0 on error */ int nutscan_load_ipmi_library() @@ -189,6 +207,16 @@ int nutscan_load_ipmi_library() goto err; } + *(void **) (&nut_ipmi_ctx_open_outofband) = lt_dlsym(dl_handle, "ipmi_ctx_open_outofband"); + if ((dl_error = lt_dlerror()) != NULL) { + goto err; + } + + *(void **) (&nut_ipmi_ctx_errnum) = lt_dlsym(dl_handle, "ipmi_ctx_errnum"); + if ((dl_error = lt_dlerror()) != NULL) { + goto err; + } + *(void **) (&nut_ipmi_ctx_errormsg) = lt_dlsym(dl_handle, "ipmi_ctx_errormsg"); if ((dl_error = lt_dlerror()) != NULL) { goto err; @@ -265,10 +293,10 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) /* Parse FRU information */ if (!(fru_parse_ctx = (*nut_ipmi_fru_ctx_create) (ipmi_ctx))) { - fprintf(stderr, "ipmi_fru_parse_ctx_create()\n"); + fprintf(stderr, "Error with %s(): %s\n", IPMI_FRU_CTX_CREATE, (*nut_ipmi_ctx_errormsg)(ipmi_ctx)); return 0; } -fprintf(stdout, "There.1\n"); + /* lots of motherboards calculate checksums incorrectly */ if ((*nut_ipmi_fru_ctx_set_flags) (fru_parse_ctx, IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS) < 0) { @@ -279,7 +307,7 @@ fprintf(stdout, "There.1\n"); #endif /* HAVE_FREEIPMI_11X_12X */ return 0; } -fprintf(stdout, "There.2\n"); + if ((*nut_ipmi_fru_open_device_id) (fru_parse_ctx, ipmi_id) < 0) { #ifdef HAVE_FREEIPMI_11X_12X @@ -292,7 +320,6 @@ fprintf(stdout, "There.2\n"); do { -fprintf(stdout, "There.3\n"); /* clear fields */ area_type = 0; area_length = 0; @@ -337,20 +364,21 @@ fprintf(stdout, "There.3\n"); return 0; } -/* return NULL on error */ -nutscan_device_t * nutscan_scan_ipmi() +/* Check for IPMI support on a specific (local or remote) system + * Return NULL on error, or a valid nutscan_device_t otherwise */ +nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t * ipmi_sec) { ipmi_ctx_t ipmi_ctx = NULL; nutscan_device_t * nut_dev = NULL; nutscan_device_t * current_nut_dev = NULL; int ret = -1; int ipmi_id = 0; - char port_id[10]; + char port_id[64]; if( !nutscan_avail_ipmi ) { return NULL; } -fprintf(stdout, "There1\n"); + /* Initialize the FreeIPMI library. */ if (!(ipmi_ctx = (*nut_ipmi_ctx_create) ())) { @@ -359,34 +387,138 @@ fprintf(stdout, "There1\n"); return NULL; } -fprintf(stdout, "There2\n"); - if ((ret = (*nut_ipmi_ctx_find_inband) (ipmi_ctx, - NULL, - 0, /* don't disable auto-probe */ - 0, - 0, - NULL, - 0, /* workaround flags, none by default */ - IPMI_FLAGS_NONBLOCKING /* flags */ - )) < 0) + /* Are we scanning locally, or over the network? */ + if (IPaddr == NULL) { - fprintf(stderr, "ipmi_ctx_find_inband: %s\n", - (*nut_ipmi_ctx_errormsg) (ipmi_ctx)); - return NULL; + /* FIXME: we need root right to access local IPMI! + if (!ipmi_is_root ()) { + fprintf(stderr, "IPMI scan: %s\n", ipmi_ctx_strerror (IPMI_ERR_PERMISSION)); + } */ + + if ((ret = (*nut_ipmi_ctx_find_inband) (ipmi_ctx, + NULL, + 0, /* don't disable auto-probe */ + 0, + 0, + NULL, + 0, /* workaround flags, none by default */ + 0 /* flags */ + )) < 0) + { + fprintf(stderr, "ipmi_ctx_find_inband: %s\n", + (*nut_ipmi_ctx_errormsg) (ipmi_ctx)); + return NULL; + } + if (!ret) + { + /* No local IPMI device detected */ + return NULL; + } } - if (!ret) - { - /* No local IPMI device detected */ - return NULL; + else { + +#if 0 + if (ipmi_sec->ipmi_version == IPMI_2_0) { + + /* FIXME: need processing?! + * int parse_kg (void *out, unsigned int outlen, const char *in) + * if ((rv = parse_kg (common_cmd_args_config->k_g, IPMI_MAX_K_G_LENGTH + 1, data->string)) < 0) + * { + * fprintf (stderr, "Config File Error: k_g input formatted incorrectly\n"); + * exit (EXIT_FAILURE); + * }*/ + if ((ret = (*nut_ipmi_ctx_open_outofband_2_0) (ipmi_ctx, + IPaddr, + ipmi_sec->username, + ipmi_sec->password, + ipmi_sec->K_g_BMC_key, +??? (ipmi_sec->K_g_BMC_key) ? config->k_g_len : 0, + ipmi_sec->privilege_level, + ipmi_sec->cipher_suite_id, + IPMI_SESSION_TIMEOUT_LENGTH_DEFAULT, + IPMI_RETRANSMISSION_TIMEOUT_LENGTH_DEFAULT, + ipmi_dev->workaround_flags, + flags) < 0) + { + IPMI_MONITORING_DEBUG (("ipmi_ctx_open_outofband_2_0: %s", ipmi_ctx_errormsg (c->ipmi_ctx))); + if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_USERNAME_INVALID) + c->errnum = IPMI_MONITORING_ERR_USERNAME_INVALID; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_PASSWORD_INVALID) + c->errnum = IPMI_MONITORING_ERR_PASSWORD_INVALID; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_PRIVILEGE_LEVEL_INSUFFICIENT) + c->errnum = IPMI_MONITORING_ERR_PRIVILEGE_LEVEL_INSUFFICIENT; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_PRIVILEGE_LEVEL_CANNOT_BE_OBTAINED) + c->errnum = IPMI_MONITORING_ERR_PRIVILEGEL_LEVEL_CANNOT_BE_OBTAINED; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_K_G_INVALID) + c->errnum = IPMI_MONITORING_ERR_K_G_INVALID; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_CIPHER_SUITE_ID_UNAVAILABLE) + c->errnum = IPMI_MONITORING_ERR_CIPHER_SUITE_ID_UNAVAILABLE; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_PASSWORD_VERIFICATION_TIMEOUT) + c->errnum = IPMI_MONITORING_ERR_PASSWORD_VERIFICATION_TIMEOUT; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_IPMI_2_0_UNAVAILABLE) + c->errnum = IPMI_MONITORING_ERR_IPMI_2_0_UNAVAILABLE; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_CONNECTION_TIMEOUT) + c->errnum = IPMI_MONITORING_ERR_CONNECTION_TIMEOUT; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_SESSION_TIMEOUT) + c->errnum = IPMI_MONITORING_ERR_SESSION_TIMEOUT; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE + || ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_IPMI_ERROR) + c->errnum = IPMI_MONITORING_ERR_IPMI_ERROR; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_BMC_BUSY) + c->errnum = IPMI_MONITORING_ERR_BMC_BUSY; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_OUT_OF_MEMORY) + c->errnum = IPMI_MONITORING_ERR_OUT_OF_MEMORY; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_HOSTNAME_INVALID) + c->errnum = IPMI_MONITORING_ERR_HOSTNAME_INVALID; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_PARAMETERS) + c->errnum = IPMI_MONITORING_ERR_PARAMETERS; + else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_SYSTEM_ERROR) + c->errnum = IPMI_MONITORING_ERR_SYSTEM_ERROR; + else + c->errnum = IPMI_MONITORING_ERR_INTERNAL_ERROR; + return (-1); + } + } + else { /* Not IPMI 2.0 */ + +#endif /* 0 */ + + /* Fall back to IPMI 1.5 */ + if ((ret = (*nut_ipmi_ctx_open_outofband) (ipmi_ctx, + IPaddr, + ipmi_sec->username, + ipmi_sec->password, + ipmi_sec->authentication_type, + ipmi_sec->privilege_level, + IPMI_SESSION_TIMEOUT_LENGTH_DEFAULT, + IPMI_RETRANSMISSION_TIMEOUT_LENGTH_DEFAULT, + ipmi_sec->workaround_flags, + IPMI_FLAGS_DEFAULT + )) < 0) + { + /* No IPMI device detected on this host! + if ((*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_USERNAME_INVALID + || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_PASSWORD_INVALID + || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_PRIVILEGE_LEVEL_INSUFFICIENT + || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_PRIVILEGE_LEVEL_CANNOT_BE_OBTAINED + || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_AUTHENTICATION_TYPE_UNAVAILABLE + || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_PASSWORD_VERIFICATION_TIMEOUT + || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_HOSTNAME_INVALID + || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_CONNECTION_TIMEOUT) { */ + + /* FIXME: don't log timeout errors */ + fprintf(stderr, "nut_ipmi_ctx_open_outofband: %s\n", + (*nut_ipmi_ctx_errormsg) (ipmi_ctx)); + return NULL; + /*}*/ + } } -fprintf(stdout, "There3 (ret = %i)\n", ret); /* Loop through all possible components */ for (ipmi_id = 0 ; ipmi_id <= IPMI_FRU_DEVICE_ID_MAX ; ipmi_id++) { -fprintf(stdout, "There4\n"); + if (is_ipmi_device_supported(ipmi_ctx, ipmi_id)) { -fprintf(stdout, "There4.%i\n", ipmi_id); if ( (nut_dev = nutscan_new_device()) == NULL ) { fprintf(stderr,"Memory allocation error\n"); nutscan_free_device(current_nut_dev); @@ -396,9 +528,17 @@ fprintf(stdout, "There4.%i\n", ipmi_id); /* Fill the device structure (sufficient with driver and port) */ nut_dev->type = TYPE_IPMI; nut_dev->driver = strdup(NUT_IPMI_DRV_NAME); - sprintf(port_id, "id%x", ipmi_id); + if (IPaddr == NULL) { + sprintf(port_id, "id%x", ipmi_id); + } + else { + /* FIXME: also check against "localhost" and its IPv{4,6} */ + sprintf(port_id, "id%x@%s", ipmi_id, IPaddr); + } nut_dev->port = strdup(port_id); - + /* FIXME: also dump device.serial? + * using drivers/libfreeipmi_get_board_info() */ + current_nut_dev = nutscan_add_device_to_device( current_nut_dev, nut_dev); @@ -415,9 +555,50 @@ fprintf(stdout, "There4.%i\n", ipmi_id); return current_nut_dev; } + +/* General IPMI scan entry point: scan 1 to n devices, local or remote, + * for IPMI support + * Return NULL on error, or a valid nutscan_device_t otherwise */ +nutscan_device_t * nutscan_scan_ipmi(const char * start_ip, const char * stop_ip, nutscan_ipmi_t * sec) +{ + nutscan_ip_iter_t ip; + char * ip_str = NULL; + nutscan_ipmi_t * tmp_sec; + nutscan_device_t * nut_dev = NULL; + nutscan_device_t * current_nut_dev = NULL; + + if( !nutscan_avail_ipmi ) { + return NULL; + } + + + /* Are we scanning locally, or through the network? */ + if (start_ip == NULL) + { + /* Local PSU scan */ + current_nut_dev = nutscan_scan_ipmi_device(NULL, NULL); + } + else { + ip_str = nutscan_ip_iter_init(&ip, start_ip, stop_ip); + + while(ip_str != NULL) { + tmp_sec = malloc(sizeof(nutscan_ipmi_t)); + memcpy(tmp_sec, sec, sizeof(nutscan_ipmi_t)); + + if ((current_nut_dev = nutscan_scan_ipmi_device(ip_str, tmp_sec)) != NULL) { + /* Store the positive result */ + current_nut_dev = nutscan_add_device_to_device(current_nut_dev, nut_dev); + } + /* Prepare the next iteration */ + ip_str = nutscan_ip_iter_inc(&ip); + }; + } + + return current_nut_dev; +} #else /* WITH_IPMI */ /* stub function */ -nutscan_device_t * nutscan_scan_ipmi() +nutscan_device_t * nutscan_scan_ipmi(const char * startIP, const char * stopIP, nutscan_ipmi_t * sec) { return NULL; } From 601c46d0d74eafb7020f6bac4179fd468b1ac9df Mon Sep 17 00:00:00 2001 From: Arnaud Quette Date: Tue, 22 Jan 2013 22:22:40 +0000 Subject: [PATCH 048/121] Add nut-scanner support for Eaton serial units nut-scanner and libnutscan now provides respectively an option and functions to detect Eaton serial devices. The following protocols are supported: SHUT, XCP and Q1 (patch from Frederic Bohe, with parts from Arnaud Quette, both for Eaton) Fossil-ID: SVN r3843 --- docs/man/.gitignore | 62 +++ docs/man/Makefile.am | 9 + docs/man/index.txt | 1 + docs/man/nut-scanner.txt | 23 ++ docs/man/nutscan_get_serial_ports_list.txt | 40 ++ docs/man/nutscan_scan_avahi.txt | 1 + docs/man/nutscan_scan_eaton_serial.txt | 40 ++ docs/man/nutscan_scan_ipmi.txt | 3 +- docs/man/nutscan_scan_nut.txt | 3 +- docs/man/nutscan_scan_snmp.txt | 3 +- docs/man/nutscan_scan_usb.txt | 2 +- docs/man/nutscan_scan_xml_http.txt | 2 +- include/nut_platform.h | 125 ++++++ tools/nut-scanner/Makefile.am | 12 +- tools/nut-scanner/nut-scan.h | 2 + tools/nut-scanner/nut-scanner.c | 44 ++- tools/nut-scanner/nutscan-device.h | 1 + tools/nut-scanner/nutscan-display.c | 5 +- tools/nut-scanner/nutscan-serial.c | 196 +++++++++ tools/nut-scanner/nutscan-serial.h | 24 ++ tools/nut-scanner/scan_eaton_serial.c | 439 +++++++++++++++++++++ tools/nut-scanner/scan_nut.c | 2 +- 22 files changed, 1023 insertions(+), 16 deletions(-) create mode 100644 docs/man/nutscan_get_serial_ports_list.txt create mode 100644 docs/man/nutscan_scan_eaton_serial.txt create mode 100644 include/nut_platform.h create mode 100644 tools/nut-scanner/nutscan-serial.c create mode 100644 tools/nut-scanner/nutscan-serial.h create mode 100644 tools/nut-scanner/scan_eaton_serial.c diff --git a/docs/man/.gitignore b/docs/man/.gitignore index dfe58c7e0b..21f9d6a6f0 100644 --- a/docs/man/.gitignore +++ b/docs/man/.gitignore @@ -202,3 +202,65 @@ nutscan_init.3 nutscan_init.html nut-recorder.8 nut-recorder.html +macosx-ups.8 +macosx-ups.html +blazer_ser.8 +blazer_usb.8 +libnutclient.3 +libnutclient_commands.3 +libnutclient_devices.3 +libnutclient_general.3 +libnutclient_misc.3 +libnutclient_tcp.3 +libnutclient_tpc.3 +libnutclient_variables.3 +nutclient_authenticate.3 +nutclient_destroy.3 +nutclient_device_forced_shutdown.3 +nutclient_device_login.3 +nutclient_device_master.3 +nutclient_execute_device_command.3 +nutclient_get_device_command_description.3 +nutclient_get_device_commands.3 +nutclient_get_device_description.3 +nutclient_get_device_num_logins.3 +nutclient_get_device_rw_variables.3 +nutclient_get_device_variable_description.3 +nutclient_get_device_variable_values.3 +nutclient_get_device_variables.3 +nutclient_get_devices.3 +nutclient_has_device.3 +nutclient_logout.3 +nutclient_has_device_command.3 +nutclient_has_device_variable.3 +nutclient_set_device_variable_value.3 +nutclient_set_device_variable_values.3 +nutclient_tcp_create_client.3 +nutclient_tcp_disconnect.3 +nutclient_tcp_get_timeout.3 +nutclient_tcp_is_connected.3 +nutclient_tcp_reconnect.3 +nutclient_tcp_set_timeout.3 +strarr_alloc.3 +strarr_free.3 +upscli_add_host_cert.3 +upscli_cleanup.3 +upscli_init.3 +libnutclient.html +libnutclient_commands.html +libnutclient_devices.html +libnutclient_general.html +libnutclient_misc.html +libnutclient_tcp.html +libnutclient_variables.html +upscli_add_host_cert.html +upscli_cleanup.html +upscli_init.html +riello_ser.8 +riello_usb.8 +riello_ser.html +riello_usb.html +nutscan_get_serial_ports_list.3 +nutscan_scan_eaton_serial.3 +nutscan_get_serial_ports_list.html +nutscan_scan_eaton_serial.html diff --git a/docs/man/Makefile.am b/docs/man/Makefile.am index 46c0a9f35b..24df5fceae 100644 --- a/docs/man/Makefile.am +++ b/docs/man/Makefile.am @@ -139,6 +139,7 @@ SRC_DEV_PAGES = \ nutscan_scan_nut.txt \ nutscan_scan_avahi.txt \ nutscan_scan_ipmi.txt \ + nutscan_scan_eaton_serial.txt \ nutscan_display_ups_conf.txt \ nutscan_display_parsable.txt \ nutscan_cidr_to_ip.txt \ @@ -147,6 +148,8 @@ SRC_DEV_PAGES = \ nutscan_add_option_to_device.txt \ nutscan_add_device_to_device.txt \ nutscan_init.txt \ + nutscan_scan_eaton_serial.txt \ + nutscan_get_serial_ports_list.txt \ libupsclient-config.txt \ skel.txt @@ -172,6 +175,7 @@ MAN3_DEV_PAGES = \ nutscan_scan_nut.3 \ nutscan_scan_avahi.3 \ nutscan_scan_ipmi.3 \ + nutscan_scan_eaton_serial.3 \ nutscan_display_ups_conf.3 \ nutscan_display_parsable.3 \ nutscan_cidr_to_ip.3 \ @@ -179,6 +183,8 @@ MAN3_DEV_PAGES = \ nutscan_free_device.3 \ nutscan_add_option_to_device.3 \ nutscan_add_device_to_device.3 \ + nutscan_scan_eaton_serial.3 \ + nutscan_get_serial_ports_list.3 \ nutscan_init.3 MAN1_DEV_PAGES = \ @@ -215,6 +221,7 @@ HTML_DEV_MANS = \ nutscan_scan_nut.html \ nutscan_scan_avahi.html \ nutscan_scan_ipmi.html \ + nutscan_scan_eaton_serial.html \ nutscan_display_ups_conf.html \ nutscan_display_parsable.html \ nutscan_cidr_to_ip.html \ @@ -222,6 +229,8 @@ HTML_DEV_MANS = \ nutscan_free_device.html \ nutscan_add_option_to_device.html \ nutscan_add_device_to_device.html \ + nutscan_scan_eaton_serial.html \ + nutscan_get_serial_ports_list.html \ nutscan_init.html \ libupsclient-config.html \ skel.html diff --git a/docs/man/index.txt b/docs/man/index.txt index e56d43e696..b27f954555 100644 --- a/docs/man/index.txt +++ b/docs/man/index.txt @@ -134,6 +134,7 @@ Device discovery library - linkman:nutscan_scan_nut[3] - linkman:nutscan_scan_avahi[3] - linkman:nutscan_scan_ipmi[3] +- linkman:nutscan_scan_eaton_serial[3] - linkman:nutscan_display_parsable[3] - linkman:nutscan_display_ups_conf[3] - linkman:nutscan_new_device[3] diff --git a/docs/man/nut-scanner.txt b/docs/man/nut-scanner.txt index efe0e58d18..359806fa75 100644 --- a/docs/man/nut-scanner.txt +++ b/docs/man/nut-scanner.txt @@ -65,6 +65,20 @@ Scan NUT servers using Avahi request on the current network interfaces. No IP re *-I* | *--ipmi_scan*:: Scan NUT compatible power supplies available via IPMI on the current host, or over the network. +*-E* | *--eaton_serial* 'serial ports':: +Scan Eaton devices (XCP and SHUT) available via serial bus on the current host. +This option must be requested explicitely, even for a complete scan. +'serial ports' can be expressed in various forms: + +- 'auto' to scan all serial ports. +- a single charcater indicating a port number ('0' (zero) for /dev/ttyS0 and +/dev/ttyUSB0 on Linux, '1' for COM1 on Windows, 'a' for /dev/ttya on Solaris...) +- a range of N characters, hyphen separated, describing the range of +ports using 'X-Y', where X and Y are characters refering to the port number. +- a single port name. +- a list of ports name, coma separated, like '/dev/ttyS1,/dev/ttyS4'. + + NETWORK OPTIONS --------------- @@ -182,6 +196,15 @@ To scan for power supplies, through IPMI (1.5 mode) over the network, on address *nut-scanner -I -m 192.168.0.0/24 -b username -B password* +To scan for Eaton serial devices on ports 0 and 1 (/dev/ttyS0, +/dev/ttyUSB0, /dev/ttyS1 and /dev/ttyUSB1 on Linux): + +*nut-scanner --eaton_serial 0-1* + +To scan for Eaton serial devices on ports 1 and 2 (COM1 and COM2 on Windows): + +*nut-scanner --eaton_serial 1-2* + SEE ALSO -------- diff --git a/docs/man/nutscan_get_serial_ports_list.txt b/docs/man/nutscan_get_serial_ports_list.txt new file mode 100644 index 0000000000..dfe0d65c5c --- /dev/null +++ b/docs/man/nutscan_get_serial_ports_list.txt @@ -0,0 +1,40 @@ +NUTSCAN_GET_SERIAL_PORTS_LIST(3) +================================ + +NAME +---- + +nutscan_get_serial_ports_list - Get a port list name from a range of port. + +SYNOPSIS +-------- + + #include + + char ** nutscan_get_serial_ports_list(const char *ports_range); + +DESCRIPTION +----------- + +The *nutscan_get_serial_ports_list()* function returns a null terminated array of string generated from a port range. +'ports_range' may be one of: + + - a single character from 0 to 9 or a to z representing a serial communication port depending on the operating system. For instance "0" is converted to /dev/ttyS0 and /dev/ttyUSB0 on Linux; "1" is converted to COM1 on Windows; "c" is converted to /dev/ttyc on solaris... + - a range of character in the form "X-Y". For instance "0-1" will be converted to /dev/ttyS0, /dev/ttyS1, /dev/ttyUSB0 and /dev/ttyUSB1 on Linux; "1-3" will be converted to COM1, COM2 and COM3 on Windows; "a-c" will be converted to /dev/ttya, /dev/ttyb and /dev/ttyc on Solaris. + - a single port name (/dev/ttyS5, COM4...). + - a list of port names separated with comas : "/dev/ttyS0,/dev/ttyS2,/dev/ttyS4" or "COM1,COM3"... + +The returned array can be used in a call to *nutscan_scan_eaton_serial* to get the serial device on a system. + +RETURN VALUE +------------ + +The *nutscan_get_serial_ports_list()* function returns NULL if an error occured (invalid port range) or a pointer to a nll terminated array of string on success. + +SEE ALSO +-------- +linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http[3], +linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], +linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], +linkman:nutscan_scan_eaton_serial[3], +linkman:nutscan_display_parsable[3], linkman:nutscan_display_ups_conf[3] diff --git a/docs/man/nutscan_scan_avahi.txt b/docs/man/nutscan_scan_avahi.txt index 32c39e742c..fe82e12cd5 100644 --- a/docs/man/nutscan_scan_avahi.txt +++ b/docs/man/nutscan_scan_avahi.txt @@ -40,4 +40,5 @@ linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3], +linkman:nutscan_scan_eaton_serial[3], http://avahi.org/ diff --git a/docs/man/nutscan_scan_eaton_serial.txt b/docs/man/nutscan_scan_eaton_serial.txt new file mode 100644 index 0000000000..7a3817234e --- /dev/null +++ b/docs/man/nutscan_scan_eaton_serial.txt @@ -0,0 +1,40 @@ +NUTSCAN_SCAN_EATON_SERIAL(3) +============================ + +NAME +---- + +nutscan_scan_eaton_serial - Scan serial ports for Eaton devices (XCP, SHUT and Q1). + +SYNOPSIS +-------- + + #include + + nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_list); + +DESCRIPTION +----------- + +The *nutscan_scan_eaton_serial()* function tries to detect NUT devices which are +compatible with Eaton's serial device protocols (SHUT, XCP and Q1 (aka blazer)). +'ports_list' is a NULL terminated array of pointers to strings containing +serial device name (/dev/ttyS0, COM1, /dev/ttya...) + +You MUST call linkman:nutscan_init[3] before using this function. + +RETURN VALUE +------------ + +The *nutscan_scan_eaton_serial()* function returns a pointer to a `nutscan_device_t` structure containing all found devices or NULL if an error occurs or no device is found. + +SEE ALSO +-------- +linkman:nutscan_init[3], +linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http[3], +linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_avahi[3], +linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], +linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], +linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], +linkman:nutscan_add_device_to_device[3], +linkman:nutscan_get_serial_ports_list[3] diff --git a/docs/man/nutscan_scan_ipmi.txt b/docs/man/nutscan_scan_ipmi.txt index 345e573003..a5ee61c2d3 100644 --- a/docs/man/nutscan_scan_ipmi.txt +++ b/docs/man/nutscan_scan_ipmi.txt @@ -33,4 +33,5 @@ linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], -linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] +linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3], +linkman:nutscan_cidr_to_ip[3] diff --git a/docs/man/nutscan_scan_nut.txt b/docs/man/nutscan_scan_nut.txt index a2d09598a6..367a8197f2 100644 --- a/docs/man/nutscan_scan_nut.txt +++ b/docs/man/nutscan_scan_nut.txt @@ -37,4 +37,5 @@ linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], -linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] +linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3], +linkman:nutscan_cidr_to_ip[3] diff --git a/docs/man/nutscan_scan_snmp.txt b/docs/man/nutscan_scan_snmp.txt index 366bf3f089..4dbec4b102 100644 --- a/docs/man/nutscan_scan_snmp.txt +++ b/docs/man/nutscan_scan_snmp.txt @@ -63,4 +63,5 @@ linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], -linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] +linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3], +linkman:nutscan_cidr_to_ip[3] diff --git a/docs/man/nutscan_scan_usb.txt b/docs/man/nutscan_scan_usb.txt index d828bda35a..a48009ccc5 100644 --- a/docs/man/nutscan_scan_usb.txt +++ b/docs/man/nutscan_scan_usb.txt @@ -33,4 +33,4 @@ linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], -linkman:nutscan_add_device_to_device[3] +linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3] diff --git a/docs/man/nutscan_scan_xml_http.txt b/docs/man/nutscan_scan_xml_http.txt index 4ebd51063f..42bfe84b03 100644 --- a/docs/man/nutscan_scan_xml_http.txt +++ b/docs/man/nutscan_scan_xml_http.txt @@ -33,4 +33,4 @@ linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], -linkman:nutscan_add_device_to_device[3] +linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3] diff --git a/include/nut_platform.h b/include/nut_platform.h new file mode 100644 index 0000000000..b7bf93734b --- /dev/null +++ b/include/nut_platform.h @@ -0,0 +1,125 @@ +#ifndef nut_platform_h +#define nut_platform_h + +/** + * \brief Platform-specific checks + * + * The header performs checks to resolve the actual build platform. + * It defines macra that may be later used to produce platform-tailored + * code. + * + * Be careful when writing platform-specific code; avoid that if possible. + * + * References: + * http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system + * + * \author Vaclav Krpec + * \date 2012/10/12 + */ + +/* + * In case doxygen source doc isn't generated + * (which is the case at time of writing this), + * just check the doxygen-documented (i.e. "**" + * prefixed) NUT_PLATFORM_* macra, below. + */ + +/* Apple Mac OS X, iOS and Darwin */ +#if (defined __APPLE__ && defined __MACH__) + /** Apple OS based on Mach ukernel */ + #define NUT_PLATFORM_APPLE_MACH + + #include + + #if (defined TARGET_OS_EMBEDDED) + /** iOS (implies \ref NUT_PLATFORM_APPLE_MACH) */ + #define NUT_PLATFORM_APPLE_IOS + #endif + #if (defined TARGET_IPHONE_SIMULATOR) + /** iOS simulator (implies \ref NUT_PLATFORM_APPLE_MACH) */ + #define NUT_PLATFORM_APPLE_IOS_SIMULATOR + #endif + #if (defined TARGET_OS_IPHONE) + /** iPhone (implies \ref NUT_PLATFORM_APPLE_MACH) */ + #define NUT_PLATFORM_APPLE_IPHONE + #endif + #if (defined TARGET_OS_MAC) + /** Mac OS X (implies \ref NUT_PLATFORM_APPLE_MACH) */ + #define NUT_PLATFORM_APPLE_OSX + #endif +#endif + +/* + * GCC AIX issue: __unix__ nor __unix are not defined in older GCC + * Addressed in GCC 4.7.0, see + * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39950 + * Remove if no longer necessary + */ +#if (defined _AIX && !defined __unix__) + #define __unix__ +#endif + +/* Microsoft Windows */ +#if (defined _WIN32 || defined _WIN64) + /** Windows */ + #define NUT_PLATFORM_MS_WINDOWS + + #if (defined NTDDI_WIN8 && NTDDI_VERSION >= NTDDI_WIN8) + /** Windows 8 */ + #define NUT_PLATFORM_MS_WINDOWS8 + #endif + +/* UNIX */ +/* Note that Apple OSX doesn't define __unix__ nor __unix; are they ashamed or something? */ +#elif (defined __unix__ || defined __unix || defined NUT_PLATFORM_APPLE_MACH) + #include + #include + + /** UNIX */ + #define NUT_PLATFORM_UNIX + + #if (defined _POSIX_VERSION) + /** POSIX (implies \ref NUT_PLATFORM_UNIX), expands to POSIX version */ + #define NUT_PLATFORM_POSIX _POSIX_VERSION + #endif + + #if (defined __linux__) + /** Linux (implies \ref NUT_PLATFORM_UNIX) */ + #define NUT_PLATFORM_LINUX + #endif + #if (defined __sun && defined __SVR4) + /** Solaris (implies \ref NUT_PLATFORM_UNIX) */ + #define NUT_PLATFORM_SOLARIS + #endif + #if (defined __hpux) + /** Hewlett-Packard HP-UX (implies \ref NUT_PLATFORM_UNIX) */ + #define NUT_PLATFORM_HPUX + #endif + #if (defined _AIX) + /** AIX (implies \ref NUT_PLATFORM_UNIX) */ + #define NUT_PLATFORM_AIX + #endif + + /* Note that BSD is defined in sys/param.h */ + #if (defined BSD) + /** BSD (implies \ref NUT_PLATFORM_UNIX) */ + #define NUT_PLATFORM_BSD + + #if (defined __DragonFly__) + /** DragonFly (implies \ref NUT_PLATFORM_UNIX, \ref NUT_PLATFORM_BSD) */ + #define NUT_PLATFORM_DRAGONFLY + #elif (defined __FreeBSD__) + /** FreeBSD (implies \ref NUT_PLATFORM_UNIX, \ref NUT_PLATFORM_BSD) */ + #define NUT_PLATFORM_FREEBSD + #elif (defined __OpenBSD__) + /** OpenBSD (implies \ref NUT_PLATFORM_UNIX, \ref NUT_PLATFORM_BSD) */ + #define NUT_PLATFORM_OPENBSD + #elif (defined __NetBSD__) + /** NetBSD (implies \ref NUT_PLATFORM_UNIX, \ref NUT_PLATFORM_BSD) */ + #define NUT_PLATFORM_NETBSD + #endif + #endif +#endif + +#endif /* end of #ifndef nut_platform_h */ + diff --git a/tools/nut-scanner/Makefile.am b/tools/nut-scanner/Makefile.am index d4066d25d2..f7c2e1aa0d 100644 --- a/tools/nut-scanner/Makefile.am +++ b/tools/nut-scanner/Makefile.am @@ -9,11 +9,15 @@ if WITH_LIBLTDL lib_LTLIBRARIES = libnutscan.la endif libnutscan_la_SOURCES = scan_nut.c scan_ipmi.c \ - nutscan-device.c nutscan-ip.c nutscan-display.c nutscan-init.c \ - scan_usb.c scan_snmp.c scan_xml_http.c scan_avahi.c + nutscan-device.c nutscan-ip.c nutscan-display.c \ + nutscan-init.c scan_usb.c scan_snmp.c scan_xml_http.c \ + scan_avahi.c scan_eaton_serial.c nutscan-serial.c \ + $(top_srcdir)/drivers/serial.c \ + $(top_srcdir)/drivers/bcmxcp_ser.c \ + $(top_srcdir)/common/common.c libnutscan_la_LIBADD = $(NETLIBS) $(LIBLTDL_LIBS) -libnutscan_la_LDFLAGS = -version-info 1:0:0 -libnutscan_la_CFLAGS = -I$(top_srcdir)/clients -I$(top_srcdir)/include $(LIBLTDL_CFLAGS) +libnutscan_la_LDFLAGS = $(SERLIBS) -version-info 1:0:0 +libnutscan_la_CFLAGS = -I$(top_srcdir)/clients -I$(top_srcdir)/include $(LIBLTDL_CFLAGS) -I$(top_srcdir)/drivers nut_scanner_SOURCES = nut-scanner.c nut_scanner_CFLAGS = -I$(top_srcdir)/clients -I$(top_srcdir)/include diff --git a/tools/nut-scanner/nut-scan.h b/tools/nut-scanner/nut-scan.h index 8b9f1abb95..e3bbac82f7 100644 --- a/tools/nut-scanner/nut-scan.h +++ b/tools/nut-scanner/nut-scan.h @@ -82,6 +82,8 @@ nutscan_device_t * nutscan_scan_avahi(long usec_timeout); nutscan_device_t * nutscan_scan_ipmi(const char * startIP, const char * stopIP, nutscan_ipmi_t * sec); +nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_list); + /* Display functions */ void nutscan_display_ups_conf(nutscan_device_t * device); void nutscan_display_parsable(nutscan_device_t * device); diff --git a/tools/nut-scanner/nut-scanner.c b/tools/nut-scanner/nut-scanner.c index e372d39fd3..78e5b0a788 100644 --- a/tools/nut-scanner/nut-scanner.c +++ b/tools/nut-scanner/nut-scanner.c @@ -35,13 +35,14 @@ #define ERR_BAD_OPTION (-1) -const char optstring[] = "?ht:s:e:c:l:u:W:X:w:x:p:b:B:d:D:CUSMOAm:NPqIVa"; +const char optstring[] = "?ht:s:e:E:c:l:u:W:X:w:x:p:b:B:d:D:CUSMOAm:NPqIVa"; #ifdef HAVE_GETOPT_LONG const struct option longopts[] = {{ "timeout",required_argument,NULL,'t' }, { "start_ip",required_argument,NULL,'s' }, { "end_ip",required_argument,NULL,'e' }, + { "eaton_serial",required_argument,NULL,'E' }, { "mask_cidr",required_argument,NULL,'m' }, { "community",required_argument,NULL,'c' }, { "secLevel",required_argument,NULL,'l' }, @@ -79,6 +80,7 @@ static long timeout = DEFAULT_TIMEOUT*1000*1000; /* in usec */ static char * start_ip = NULL; static char * end_ip = NULL; static char * port = NULL; +static char * serial_ports = NULL; #ifdef HAVE_PTHREAD static pthread_t thread[TYPE_END]; @@ -119,8 +121,15 @@ static void * run_ipmi(void * arg) dev[TYPE_IPMI] = nutscan_scan_ipmi(start_ip,end_ip,sec); return NULL; } + +static void * run_eaton_serial(void * arg) +{ + dev[TYPE_EATON_SERIAL] = nutscan_scan_eaton_serial (serial_ports); + return NULL; +} + #endif /* HAVE_PTHREAD */ -static int printq(int quiet,const char *fmt, ...) +int printq(int quiet,const char *fmt, ...) { va_list ap; int ret; @@ -149,6 +158,7 @@ int main(int argc, char *argv[]) int allow_oldnut = 0; int allow_avahi = 0; int allow_ipmi = 0; + int allow_eaton_serial = 0; /* MUST be requested explicitely! */ int quiet = 0; void (*display_func)(nutscan_device_t * device); int ret_code = EXIT_SUCCESS; @@ -182,6 +192,10 @@ int main(int argc, char *argv[]) case 'e': end_ip = strdup(optarg); break; + case 'E': + serial_ports = strdup(optarg); + allow_eaton_serial = 1; + break; case 'm': cidr = strdup(optarg); break; @@ -272,6 +286,7 @@ int main(int argc, char *argv[]) ipmi_sec.cipher_suite_id = atoi(optarg); /* Force IPMI 2.0! */ ipmi_sec.ipmi_version = IPMI_2_0; + break; case 'p': port = strdup(optarg); break; @@ -332,8 +347,9 @@ int main(int argc, char *argv[]) printf("AVAHI\n"); } if(nutscan_avail_ipmi) { - printf("IPMI\n"); + printf("IPMI\n"); } + printf("EATON_SERIAL\n"); exit(EXIT_SUCCESS); case '?': ret_code = ERR_BAD_OPTION; @@ -360,6 +376,8 @@ int main(int argc, char *argv[]) printf(" -I, --ipmi_scan: Scan IPMI devices.\n"); } + printf(" -E, --eaton_serial : Scan serial Eaton devices (XCP, SHUT and Q1).\n"); + printf("\nNetwork specific options:\n"); printf(" -t, --timeout : network operation timeout (default %d).\n",DEFAULT_TIMEOUT); printf(" -s, --start_ip : First IP address to scan.\n"); @@ -410,7 +428,7 @@ int main(int argc, char *argv[]) } if( !allow_usb && !allow_snmp && !allow_xml && !allow_oldnut && - !allow_avahi && !allow_ipmi ) { + !allow_avahi && !allow_ipmi && !allow_eaton_serial) { allow_all = 1; } @@ -421,6 +439,7 @@ int main(int argc, char *argv[]) allow_oldnut = 1; allow_avahi = 1; allow_ipmi = 1; + /* BEWARE: allow_all does not include allow_eaton_serial! */ } if( allow_usb && nutscan_avail_usb ) { @@ -499,6 +518,17 @@ int main(int argc, char *argv[]) #endif /* HAVE_PTHREAD */ } + /* Eaton serial scan */ + if (allow_eaton_serial) { + printq(quiet,"Scanning serial bus for Eaton devices.\n"); +#ifdef HAVE_PTHREAD + pthread_create(&thread[TYPE_EATON_SERIAL], NULL, run_eaton_serial, serial_ports); + /* FIXME: check return code */ +#else + dev[TYPE_EATON_SERIAL] = nutscan_scan_eaton_serial (serial_ports); +#endif /* HAVE_PTHREAD */ + } + #ifdef HAVE_PTHREAD if( allow_usb && nutscan_avail_usb ) { pthread_join(thread[TYPE_USB],NULL); @@ -518,6 +548,9 @@ int main(int argc, char *argv[]) if( allow_ipmi && nutscan_avail_ipmi ) { pthread_join(thread[TYPE_IPMI],NULL); } + if (allow_eaton_serial) { + pthread_join(thread[TYPE_EATON_SERIAL],NULL); + } #endif /* HAVE_PTHREAD */ display_func(dev[TYPE_USB]); @@ -538,6 +571,9 @@ int main(int argc, char *argv[]) display_func(dev[TYPE_IPMI]); nutscan_free_device(dev[TYPE_IPMI]); + display_func(dev[TYPE_EATON_SERIAL]); + nutscan_free_device(dev[TYPE_EATON_SERIAL]); + nutscan_free(); return EXIT_SUCCESS; diff --git a/tools/nut-scanner/nutscan-device.h b/tools/nut-scanner/nutscan-device.h index d96f9f353f..884b58d516 100644 --- a/tools/nut-scanner/nutscan-device.h +++ b/tools/nut-scanner/nutscan-device.h @@ -27,6 +27,7 @@ typedef enum nutscan_device_type { TYPE_NUT, TYPE_IPMI, TYPE_AVAHI, + TYPE_EATON_SERIAL, TYPE_END } nutscan_device_type_t; diff --git a/tools/nut-scanner/nutscan-display.c b/tools/nut-scanner/nutscan-display.c index 1cbbfc8a56..07c28dbc14 100644 --- a/tools/nut-scanner/nutscan-display.c +++ b/tools/nut-scanner/nutscan-display.c @@ -21,14 +21,15 @@ #include #include "nutscan-device.h" -char nutscan_device_type_string[TYPE_END][6] = { +char * nutscan_device_type_string[TYPE_END]= { "NONE", "USB", "SNMP", "XML", "NUT", "IPMI", - "AVAHI" }; + "AVAHI", + "EATON_SERIAL" }; void nutscan_display_ups_conf(nutscan_device_t * device) { diff --git a/tools/nut-scanner/nutscan-serial.c b/tools/nut-scanner/nutscan-serial.c new file mode 100644 index 0000000000..65e0c03788 --- /dev/null +++ b/tools/nut-scanner/nutscan-serial.c @@ -0,0 +1,196 @@ +/* nutscan-serial.c: helper functions to get serial devices name + * + * Copyright (C) 2011 - Frederic Bohe + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "nutscan-serial.h" +#include +#include +#include +#include "nut_platform.h" + +#ifdef WIN32 +/* Windows: all serial port names start with "COM" */ +#define SERIAL_PORT_PREFIX "COM" +#else +/* Unix: all serial port names start with "/dev/tty" */ +#define SERIAL_PORT_PREFIX "/dev/tty" +#endif + +#define ERR_OUT_OF_BOUND "Serial port range out of bound (must be 0 to 9 or a to z depending on your system)\n" + +typedef struct { + char * name; + char auto_start_port; + char auto_stop_port; +} device_portname_t; + +device_portname_t device_portname[] = { +#ifdef NUT_PLATFORM_HPUX + /* the first number seems to be a card instance, the second number seems + to be a port number */ + { "/dev/tty0p%c", '0', '9' }, + { "/dev/tty1p%c", '0', '9' }, + /* osf/1 and Digital UNIX style */ + { "/dev/tty0%c", '0', '9' }, +#endif +#ifdef NUT_PLATFORM_SOLARIS + { "/dev/tty%c", 'a', 'z' }, +#endif +#ifdef NUT_PLATFORM_AIX + { "/dev/tty%c", '0', '9' }, +#endif +#ifdef NUT_PLATFORM_LINUX + { "/dev/ttyS%c", '0', '9' }, + { "/dev/ttyUSB%c", '0', '9' }, +#endif +#ifdef NUT_PLATFORM_MS_WINDOWS + { "COM%c", '1', '9'}, +#endif + /* SGI IRIX */ + /* { "/dev/ttyd%i", "=" }, */ + /* { "/dev/ttyf%i", "=" }, */ + /* FIXME: Mac OS X has no serial port, but maybe ttyUSB? */ + { NULL, 0 } +}; + +/* Return 1 if port_name is a full path name to a serial port, + * as per SERIAL_PORT_PREFIX */ +static int is_serial_port_path(const char * port_name) +{ + if (!strncmp(port_name, SERIAL_PORT_PREFIX, strlen(SERIAL_PORT_PREFIX))) { + return 1; + } + return 0; +} + +/* Add "port" to "list" */ +static char ** add_port(char ** list, char * port) +{ + char ** res; + int count = 0; + + if(list == NULL) { + count = 0; + } + else { + while(list[count] != NULL) { + count++; + } + } + + /*+1 to get the number of port from the index nb_ports*/ + /*+1 for the terminal NULL */ + res = realloc(list,(count+1+1)*sizeof(char*)); + if( res == NULL ) { + return NULL; + } + res[count] = strdup(port); + res[count+1] = NULL; + + return res; +} + +/* Return a list of serial ports name, in 'ports_list', according to the OS, + * the provided 'ports_range', and the number of available ports */ +char ** nutscan_get_serial_ports_list(const char *ports_range) +{ + char start_port = 0; + char stop_port = 0; + char current_port = 0; + char * list_sep_ptr = NULL; + char ** ports_list = NULL; + char str_tmp[128]; + char * tok; + device_portname_t *cur_device = NULL; + char * saveptr = NULL; + char * range; + int flag_auto = 0; + + /* 1) check ports_list */ + if ((ports_range == NULL) || (!strncmp(ports_range, "auto", 4))) { + flag_auto = 1; + } + else { + range = strdup(ports_range); + /* we have a list: + * - single element: X (digit) or port name (COM1, /dev/ttyS0, ...) + * - range list: X-Y + * - multiple elements (coma separated): /dev/ttyS0,/dev/ttyUSB0 */ + if ( (list_sep_ptr = strchr(range, '-')) != NULL ) { + tok = strtok_r(range,"-",&saveptr); + if( tok[1] != 0 ) { + fprintf(stderr,ERR_OUT_OF_BOUND); + free(range); + return NULL; + } + start_port = tok[0]; + tok = strtok_r(NULL,"-",&saveptr); + if( tok != NULL ) { + if( tok[1] != 0 ) { + fprintf(stderr,ERR_OUT_OF_BOUND); + free(range); + return NULL; + } + stop_port = tok[0]; + } + else { + stop_port = start_port; + } + } + else if ( ((list_sep_ptr = strchr(ports_range, ',')) != NULL ) + && (is_serial_port_path(ports_range)) ) { + tok = strtok_r(range,",",&saveptr); + while( tok != NULL ) { + ports_list = add_port(ports_list,tok); + tok = strtok_r(NULL,",",&saveptr); + } + } + else { + /* we have been provided a single port name */ + /* it's a full device name */ + if( ports_range[1] != 0 ) { + ports_list = add_port(ports_list,range); + } + /* it's device number */ + else { + start_port = stop_port = ports_range[0]; + } + } + free(range); + } + + + if( start_port == 0 && !flag_auto) { + return ports_list; + } + + for (cur_device=device_portname;cur_device->name!= NULL;cur_device++) { + if( flag_auto ) { + start_port = cur_device->auto_start_port; + stop_port = cur_device->auto_stop_port; + } + for( current_port=start_port; current_port <= stop_port; + current_port++){ + snprintf(str_tmp, sizeof(str_tmp),cur_device->name, + current_port); + ports_list = add_port(ports_list,str_tmp); + } + } + return ports_list; +} + diff --git a/tools/nut-scanner/nutscan-serial.h b/tools/nut-scanner/nutscan-serial.h new file mode 100644 index 0000000000..175b1d75bd --- /dev/null +++ b/tools/nut-scanner/nutscan-serial.h @@ -0,0 +1,24 @@ +/* nutscan-serial.h: helper functions to get serial devices name + * + * Copyright (C) 2011 - Frederic Bohe + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef SCAN_SERIAL +#define SCAN_SERIAL + +char ** nutscan_get_serial_ports_list(const char *ports_range); + +#endif diff --git a/tools/nut-scanner/scan_eaton_serial.c b/tools/nut-scanner/scan_eaton_serial.c new file mode 100644 index 0000000000..303214aa9f --- /dev/null +++ b/tools/nut-scanner/scan_eaton_serial.c @@ -0,0 +1,439 @@ +/* scan_eaton_serial.c: detect Eaton serial XCP, SHUT and Q1 devices + * + * Copyright (C) 2012 Arnaud Quette + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "common.h" + +/* Need this on AIX when using xlc to get alloca */ +#ifdef _AIX +#pragma alloca +#endif /* _AIX */ + +#include +#include +#include +#include +#include +#include +#include "nut-scan.h" +#include "serial.h" +#include "bcmxcp_io.h" +#include "bcmxcp.h" +#include "nutscan-serial.h" + +#ifdef HAVE_PTHREAD +#include +#endif + +/* SHUT header */ +#define SHUT_SYNC 0x16 +#define MAX_TRY 4 + +/* BCMXCP header */ +extern unsigned char AUT[4]; +extern struct pw_baud_rate { + int rate; + int name; +} pw_baud_rates[]; + +/* Local list of found devices */ +static nutscan_device_t * dev_ret = NULL; + +/* Remap some functions to avoid undesired behavior (drivers/main.c) */ +char *getval(const char *var) { return NULL; } + +#ifdef HAVE_PTHREAD +static pthread_mutex_t dev_mutex; +#endif + +/* Drivers name */ +#define SHUT_DRIVER_NAME "mge-shut" +#define XCP_DRIVER_NAME "bcmxcp" +#define Q1_DRIVER_NAME "blazer_ser" + +/* Fake driver main, for using serial functions, needed for bcmxcp_ser.c */ +char *device_path; +int upsfd; +int exit_flag = 0; +int do_lock_port; + +/* Functions extracted from drivers/bcmxcp.c, to avoid pulling too many things + * lightweight function to calculate the 8-bit + * two's complement checksum of buf, using XCP data length (including header) + * the result must be 0 for the sequence data to be valid */ +int checksum_test(const unsigned char *buf) +{ + unsigned char checksum = 0; + int i, length; + /* buf[2] is the length of the XCP frame ; add 5 for the header */ + length = (int)(buf[2]) + 5; + + for (i = 0; i < length; i++) { + checksum += buf[i]; + } + /* Compute the 8-bit, Two's Complement checksum now and return it */ + checksum = ((0x100 - checksum) & 0xFF); + return (checksum == 0); +} + + +unsigned char calc_checksum(const unsigned char *buf) +{ + unsigned char c; + int i; + + c = 0; + for(i = 0; i < 2 + buf[1]; i++) + c -= buf[i]; + + return c; +} + +/******************************************************************************* + * SHUT functions (MGE legacy, but Eaton path forward) + ******************************************************************************/ + +/* Light version of of drivers/libshut.c->shut_synchronise() + * return 1 if OK, 0 otherwise */ +int shut_synchronise(int upsfd) +{ + int try; + u_char reply = '\0'; + + /* Sync with the UPS according to notification */ + for (try = 0; try < MAX_TRY; try++) { + if ((ser_send_char(upsfd, SHUT_SYNC)) == -1) { + continue; + } + + ser_get_char(upsfd, &reply, 1, 0); + if (reply == SHUT_SYNC) { + return 1; + } + } + return 0; +} + +/* SHUT scan: + * send SYNC token (0x16) and receive the SYNC token back + * FIXME: maybe try to get device descriptor?! + */ +nutscan_device_t * nutscan_scan_eaton_serial_shut(const char* port_name) +{ + nutscan_device_t * dev = NULL; + int devfd = -1; + + if ( (devfd = ser_open_nf(port_name)) != -1 ) { + /* set RTS to on and DTR to off first, as these are not fatal + * and allow to test the port */ + if (ser_set_dtr(devfd, 0) != -1) { + + ser_set_rts(devfd, 1); + ser_set_speed_nf(devfd, port_name, B2400); + + if (shut_synchronise(devfd)) { + + /* Communication established successfully! */ + dev = nutscan_new_device(); + dev->type = TYPE_EATON_SERIAL; + dev->driver = strdup(SHUT_DRIVER_NAME); + dev->port = strdup(port_name); +#ifdef HAVE_PTHREAD + pthread_mutex_lock(&dev_mutex); +#endif + dev_ret = nutscan_add_device_to_device(dev_ret, dev); +#ifdef HAVE_PTHREAD + pthread_mutex_unlock(&dev_mutex); +#endif + } + } + /* Close the device */ + ser_close(devfd, NULL); + } + + return dev; +} + +/******************************************************************************* + * XCP functions (Eaton Powerware legacy) + ******************************************************************************/ + +/* XCP scan: + * baudrate nego (...) + * Send ESC to take it out of menu + * Wait 90ms + * Send auth command (AUTHOR[4] = {0xCF, 0x69, 0xE8, 0xD5};) + * Wait 500ms (or less?) + * Send PW_SET_REQ_ONLY_MODE command (0xA0) and wait for response + * [Get ID Block (PW_ID_BLOCK_REQ) (0x31)] + */ +nutscan_device_t * nutscan_scan_eaton_serial_xcp(const char* port_name) +{ + nutscan_device_t * dev = NULL; + int i, ret, devfd = -1; + unsigned char answer[256]; + unsigned char sbuf[128]; + + memset(sbuf, 0, 128); + + if ( (devfd = ser_open_nf(port_name)) != -1 ) { +#ifdef HAVE_PTHREAD + pthread_mutex_lock(&dev_mutex); +#endif + upsfd = devfd; +#ifdef HAVE_PTHREAD + pthread_mutex_unlock(&dev_mutex); +#endif + + for (i=0; (pw_baud_rates[i].rate != 0) && (dev == NULL); i++) + { + memset(answer, 0, 256); + + if (ser_set_speed_nf(devfd, port_name, pw_baud_rates[i].rate) == -1) + break; + + ret = ser_send_char(devfd, 0x1d); /* send ESC to take it out of menu */ + if (ret <= 0) + break; + + usleep(90000); + send_write_command(AUT, 4); + usleep(500000); + + /* Discovery with Baud Hunting (XCP protocol spec. §4.1.2) + * sending PW_SET_REQ_ONLY_MODE should be enough, since + * the unit should send back Identification block */ + sbuf[0] = PW_COMMAND_START_BYTE; + sbuf[1] = (unsigned char)1; + sbuf[2] = PW_SET_REQ_ONLY_MODE; + sbuf[3] = calc_checksum(sbuf); + ret = ser_send_buf_pace(devfd, 1000, sbuf, 4); + + /* Read PW_COMMAND_START_BYTE byte */ + ret = ser_get_char(devfd, answer, 1, 0); + +#if 0 + /* FIXME: seems not needed, but requires testing with more devices! */ + if (ret <= 0) { + usleep(250000); /* 500000? */ + memset(answer, 0, 256); + ret = command_sequence(&id_command, 1, answer); + } +#endif + + if ( (ret > 0) && (answer[0] == PW_COMMAND_START_BYTE) ) { + dev = nutscan_new_device(); + dev->type = TYPE_EATON_SERIAL; + dev->driver = strdup(XCP_DRIVER_NAME); + dev->port = strdup(port_name); +#ifdef HAVE_PTHREAD + pthread_mutex_lock(&dev_mutex); +#endif + dev_ret = nutscan_add_device_to_device(dev_ret, dev); +#ifdef HAVE_PTHREAD + pthread_mutex_unlock(&dev_mutex); +#endif + break; + } + usleep(100000); + } + /* Close the device */ + ser_close(devfd, NULL); + } + + return dev; +} + +/******************************************************************************* + * Q1 functions (Phoenixtec/Centralion/Santak, still Eaton path forward) + ******************************************************************************/ + +#define SER_WAIT_SEC 1 /* 3 seconds for Best UPS */ +#define MAXTRIES 3 + +/* Q1 scan: + * - open the serial port and set the speed to 2400 baud + * - simply try to get Q1 (status) string + * - check its size and first char. which should be '(' + */ +nutscan_device_t * nutscan_scan_eaton_serial_q1(const char* port_name) +{ + nutscan_device_t * dev = NULL; + struct termios tio; + int ret = 0, retry; + int devfd = -1; + char buf[128]; + + if ( (devfd = ser_open_nf(port_name)) != -1 ) { + if (ser_set_speed_nf(devfd, port_name, B2400) != -1) { + + if (!tcgetattr(devfd, &tio)) { + + /* Use canonical mode input processing (to read reply line) */ + tio.c_lflag |= ICANON; /* Canonical input (erase and kill processing) */ + + tio.c_cc[VEOF] = _POSIX_VDISABLE; + tio.c_cc[VEOL] = '\r'; + tio.c_cc[VERASE] = _POSIX_VDISABLE; + tio.c_cc[VINTR] = _POSIX_VDISABLE; + tio.c_cc[VKILL] = _POSIX_VDISABLE; + tio.c_cc[VQUIT] = _POSIX_VDISABLE; + tio.c_cc[VSUSP] = _POSIX_VDISABLE; + tio.c_cc[VSTART] = _POSIX_VDISABLE; + tio.c_cc[VSTOP] = _POSIX_VDISABLE; + + if (!tcsetattr(devfd, TCSANOW, &tio)) { + + /* Set the default (normal) cablepower */ + ser_set_dtr(devfd, 1); + ser_set_rts(devfd, 0); + + /* Allow some time to settle for the cablepower */ + usleep(100000); + + /* Only try pure 'Q1', not older ones like 'D' or 'QS' + * > [Q1\r] + * < [(226.0 195.0 226.0 014 49.0 27.5 30.0 00001000\r] + */ + for (retry = 1; retry <= MAXTRIES; retry++) { + + /* simplified code */ + ser_flush_io(devfd); + if ( (ret = ser_send(devfd, "Q1\r")) > 0) { + + /* Get Q1 reply */ + if ( (ret = ser_get_buf(devfd, buf, sizeof(buf), SER_WAIT_SEC, 0)) > 0) { + + /* Check answer */ + /* should at least (and most) be 46 chars */ + if (ret >= 46) { + if (buf[0] == '(') { + + dev = nutscan_new_device(); + dev->type = TYPE_EATON_SERIAL; + dev->driver = strdup(Q1_DRIVER_NAME); + dev->port = strdup(port_name); +#ifdef HAVE_PTHREAD + pthread_mutex_lock(&dev_mutex); +#endif + dev_ret = nutscan_add_device_to_device(dev_ret, dev); +#ifdef HAVE_PTHREAD + pthread_mutex_unlock(&dev_mutex); +#endif + break; + } + } + } + } + } + } + } + } + /* Close the device */ + ser_close(devfd, NULL); + } + return dev; +} + +static void * nutscan_scan_eaton_serial_device(void * port_arg) +{ + nutscan_device_t * dev = NULL; + char* port_name = (char*) port_arg; + + /* Try SHUT first */ + if ( (dev = nutscan_scan_eaton_serial_shut(port_name)) == NULL) { + usleep(100000); + /* Else, try XCP */ + if ( (dev = nutscan_scan_eaton_serial_xcp(port_name)) == NULL) { + /* Else, try Q1 */ + usleep(100000); + dev = nutscan_scan_eaton_serial_q1(port_name); + } + /* Else try UTalk? */ + } + return dev; +} + +nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) +{ + struct sigaction oldact; + int change_action_handler = 0; + char *current_port_name = NULL; + char **serial_ports_list; + int current_port_nb; + int i; +#ifdef HAVE_PTHREAD + pthread_t thread; + pthread_t * thread_array = NULL; + int thread_count = 0; + + pthread_mutex_init(&dev_mutex,NULL); +#endif + + /* 1) Get ports_list */ + serial_ports_list = nutscan_get_serial_ports_list(ports_range); + if( serial_ports_list == NULL ) { + return NULL; + } + + /* Ignore SIGPIPE if the caller hasn't set a handler for it yet */ + if( sigaction(SIGPIPE, NULL, &oldact) == 0 ) { + if( oldact.sa_handler == SIG_DFL ) { + change_action_handler = 1; + signal(SIGPIPE,SIG_IGN); + } + } + + /* port(s) iterator */ + current_port_nb = 0; + while(serial_ports_list[current_port_nb] != NULL) { + current_port_name = serial_ports_list[current_port_nb]; +#ifdef HAVE_PTHREAD + if (pthread_create(&thread, NULL, nutscan_scan_eaton_serial_device, (void*)current_port_name) == 0){ + thread_count++; + thread_array = realloc(thread_array, + thread_count*sizeof(pthread_t)); + thread_array[thread_count-1] = thread; + } +#else + nutscan_scan_eaton_serial_device(current_port_name); +#endif + current_port_nb++; + } + +#ifdef HAVE_PTHREAD + for ( i = 0; i < thread_count ; i++) { + pthread_join(thread_array[i],NULL); + } + pthread_mutex_destroy(&dev_mutex); + free(thread_array); +#endif + + if(change_action_handler) { + signal(SIGPIPE,SIG_DFL); + } + + /* free everything... */ + i=0; + while(serial_ports_list[i] != NULL) { + free(serial_ports_list[i]); + i++; + } + free( serial_ports_list); + return dev_ret; +} diff --git a/tools/nut-scanner/scan_nut.c b/tools/nut-scanner/scan_nut.c index 55df68caad..c1b16f206e 100644 --- a/tools/nut-scanner/scan_nut.c +++ b/tools/nut-scanner/scan_nut.c @@ -164,7 +164,7 @@ static void * list_nut_devices(void * arg) dev = nutscan_new_device(); dev->type = TYPE_NUT; dev->driver = strdup("nutclient"); - /* +1+1 is for '@' character and terminnating 0 */ + /* +1+1 is for '@' character and terminating 0 */ buf_size = strlen(answer[1])+strlen(hostname)+1+1; dev->port = malloc(buf_size); if( dev->port ) { From 1c6b2b2b170f73352bc320f7c4a004c0ef8426e0 Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Sun, 13 Jan 2013 17:47:26 +0000 Subject: [PATCH 049/121] Protect header files for C++ inclusion. Fossil-ID: SVN r3838 --- clients/cgilib.h | 12 ++++++++++ clients/status.h | 13 ++++++++++ clients/upsimagearg.h | 13 ++++++++++ clients/upslog.h | 13 ++++++++++ clients/upsmon.h | 12 ++++++++++ clients/upssched.h | 13 ++++++++++ clients/upsstats.h | 13 ++++++++++ include/common.h | 12 ++++++++++ include/extstate.h | 12 ++++++++++ include/proto.h | 12 ++++++++++ include/state.h | 12 ++++++++++ include/upsconf.h | 12 ++++++++++ server/conf.h | 15 +++++++++++- server/desc.h | 14 +++++++++++ server/netcmds.h | 13 ++++++++++ server/netget.h | 13 ++++++++++ server/netinstcmd.h | 13 ++++++++++ server/netlist.h | 13 ++++++++++ server/netmisc.h | 13 ++++++++++ server/netset.h | 13 ++++++++++ server/netssl.h | 38 +++++++++++++++++++++++------- server/netuser.h | 13 ++++++++++ server/sstate.h | 12 ++++++++++ server/stype.h | 12 ++++++++++ server/upsd.h | 12 ++++++++++ server/upstype.h | 12 ++++++++++ server/user-data.h | 13 ++++++++++ server/user.h | 13 ++++++++++ tools/nut-scanner/nut-scan.h | 12 ++++++++++ tools/nut-scanner/nutscan-device.h | 13 ++++++++++ tools/nut-scanner/nutscan-init.h | 13 ++++++++++ tools/nut-scanner/nutscan-ip.h | 13 ++++++++++ 32 files changed, 423 insertions(+), 9 deletions(-) diff --git a/clients/cgilib.h b/clients/cgilib.h index 328184dec7..1b620c3a77 100644 --- a/clients/cgilib.h +++ b/clients/cgilib.h @@ -17,6 +17,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + /* other programs that link to this should provide parsearg() ... */ void parsearg(char *var, char *value); @@ -29,3 +35,9 @@ void extractpostargs(void); /* see if a host is allowed per the hosts.conf */ int checkhost(const char *host, char **desc); +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/clients/status.h b/clients/status.h index 20cb858357..c98c489a93 100644 --- a/clients/status.h +++ b/clients/status.h @@ -17,6 +17,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + struct { char *name; char *desc; @@ -35,3 +41,10 @@ struct { { "BYPASS", "BYPASS", 2 }, { NULL, NULL, 0 } }; + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/clients/upsimagearg.h b/clients/upsimagearg.h index 6bd5f0859a..9483d8d6ed 100644 --- a/clients/upsimagearg.h +++ b/clients/upsimagearg.h @@ -17,6 +17,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + struct { char *name; int val; /* hex digits, ala HTML */ @@ -58,3 +64,10 @@ typedef struct { } imgvar_t; extern imgvar_t imgvar[]; + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/clients/upslog.h b/clients/upslog.h index cf06e01e2e..4d0596f7ae 100644 --- a/clients/upslog.h +++ b/clients/upslog.h @@ -1,5 +1,11 @@ /* upslog.h - table of functions for handling various logging functions */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + /* function list */ typedef struct flist_s { void (*fptr)(const char *arg); @@ -27,3 +33,10 @@ struct { { "ETIME", do_etime }, { NULL, (void(*)())(NULL) } }; + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/clients/upsmon.h b/clients/upsmon.h index 3193027e68..2504370cf1 100644 --- a/clients/upsmon.h +++ b/clients/upsmon.h @@ -30,6 +30,12 @@ /* required contents of flag file */ #define SDMAGIC "upsmon-shutdown-file" +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + /* UPS tracking structure */ typedef struct { @@ -110,3 +116,9 @@ struct { /* various constants */ #define NET_TIMEOUT 10 /* wait 10 seconds max for upsd to respond */ + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif diff --git a/clients/upssched.h b/clients/upssched.h index c9aca9f2f7..db0c25df4f 100644 --- a/clients/upssched.h +++ b/clients/upssched.h @@ -6,9 +6,22 @@ #define SERIALIZE_SET 2 #define SERIALIZE_WAIT 3 +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + /* track client connections */ typedef struct conn_s { int fd; PCONF_CTX_t ctx; struct conn_s *next; } conn_t; + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/clients/upsstats.h b/clients/upsstats.h index 1628810e09..84ca8ade87 100644 --- a/clients/upsstats.h +++ b/clients/upsstats.h @@ -17,8 +17,21 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + typedef struct { char *sys; char *desc; void *next; } ulist_t; + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/include/common.h b/include/common.h index d044d52d68..4de85044a3 100644 --- a/include/common.h +++ b/include/common.h @@ -44,6 +44,12 @@ #include "attribute.h" #include "proto.h" +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + extern const char *UPS_VERSION; /* get the syslog ready for us */ @@ -144,4 +150,10 @@ extern int optind; # define setegid(x) setresgid(-1,x,-1) /* Works for HP-UX 10.20 */ #endif +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + #endif /* NUT_COMMON_H */ diff --git a/include/extstate.h b/include/extstate.h index e54e8e934f..c4cc973295 100644 --- a/include/extstate.h +++ b/include/extstate.h @@ -3,6 +3,12 @@ #ifndef EXTSTATE_H_SEEN #define EXTSTATE_H_SEEN 1 +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + /* this could be made dynamic if someone really needs more than this... */ #define ST_MAX_VALUE_LEN 256 @@ -30,4 +36,10 @@ typedef struct cmdlist_s { struct cmdlist_s *next; } cmdlist_t; +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + #endif /* EXTSTATE_H_SEEN */ diff --git a/include/proto.h b/include/proto.h index 2a7d6548a7..fb73968b12 100644 --- a/include/proto.h +++ b/include/proto.h @@ -33,6 +33,12 @@ # endif #endif +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + #if !defined (HAVE_SNPRINTF) || defined (__Lynx__) int snprintf (char *str, size_t count, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); @@ -79,4 +85,10 @@ int vprintf(const char *, va_list); int putenv(char *); #endif +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + #endif /* PROTO_H */ diff --git a/include/state.h b/include/state.h index 5b1e71314a..c6ea555f0c 100644 --- a/include/state.h +++ b/include/state.h @@ -24,6 +24,12 @@ #include "extstate.h" +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + #define ST_SOCK_BUF_LEN 512 typedef struct st_tree_s { @@ -65,4 +71,10 @@ int state_delenum(st_tree_t *root, const char *var, const char *val); int state_delrange(st_tree_t *root, const char *var, const int min, const int max); st_tree_t *state_tree_find(st_tree_t *node, const char *var); +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + #endif /* STATE_H_SEEN */ diff --git a/include/upsconf.h b/include/upsconf.h index 89c90ed5ee..4667593e97 100644 --- a/include/upsconf.h +++ b/include/upsconf.h @@ -1,7 +1,19 @@ + +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + /* callback function from read_upsconf */ void do_upsconf_args(char *upsname, char *var, char *val); /* open the ups.conf, parse it, and call back do_upsconf_args() */ void read_upsconf(void); +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif diff --git a/server/conf.h b/server/conf.h index 46633681e8..e6b207a3a5 100644 --- a/server/conf.h +++ b/server/conf.h @@ -19,6 +19,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + /* read upsd.conf */ void load_upsdconf(int reloading); @@ -40,4 +46,11 @@ typedef struct ups_s { void delete_acls(void); void delete_access(void); - extern int num_ups; +extern int num_ups; + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/server/desc.h b/server/desc.h index 5343056cff..00b413d18d 100644 --- a/server/desc.h +++ b/server/desc.h @@ -1,4 +1,18 @@ + +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + void desc_load(void); void desc_free(void); const char *desc_get_cmd(const char *name); const char *desc_get_var(const char *name); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/server/netcmds.h b/server/netcmds.h index 613ef446ba..20bc464f3d 100644 --- a/server/netcmds.h +++ b/server/netcmds.h @@ -29,6 +29,12 @@ #define FLAG_USER 0x0001 /* username and password must be set */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + struct { const char *name; void (*func)(nut_ctype_t *client, int numargs, const char **arg); @@ -56,3 +62,10 @@ struct { { NULL, (void(*)())(NULL), 0 } }; + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/server/netget.h b/server/netget.h index f1209d2ac9..eb98b990c4 100644 --- a/server/netget.h +++ b/server/netget.h @@ -1 +1,14 @@ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + void net_get(nut_ctype_t *client, int numarg, const char **arg); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/server/netinstcmd.h b/server/netinstcmd.h index 10159310b3..d8ef7e2968 100644 --- a/server/netinstcmd.h +++ b/server/netinstcmd.h @@ -1 +1,14 @@ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + void net_instcmd(nut_ctype_t *client, int numarg, const char **arg); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/server/netlist.h b/server/netlist.h index d3b7776171..535af2a6a7 100644 --- a/server/netlist.h +++ b/server/netlist.h @@ -1 +1,14 @@ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + void net_list(nut_ctype_t *client, int numarg, const char **arg); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/server/netmisc.h b/server/netmisc.h index e48f6f4f21..7e69c3824a 100644 --- a/server/netmisc.h +++ b/server/netmisc.h @@ -1,4 +1,17 @@ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + void net_ver(nut_ctype_t *client, int numarg, const char **arg); void net_netver(nut_ctype_t *client, int numarg, const char **arg); void net_help(nut_ctype_t *client, int numarg, const char **arg); void net_fsd(nut_ctype_t *client, int numarg, const char **arg); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/server/netset.h b/server/netset.h index 81068dd301..afcde0f261 100644 --- a/server/netset.h +++ b/server/netset.h @@ -1 +1,14 @@ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + void net_set(nut_ctype_t *client, int numarg, const char **arg); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/server/netssl.h b/server/netssl.h index 2d6224e6b1..8f68168969 100644 --- a/server/netssl.h +++ b/server/netssl.h @@ -17,24 +17,46 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef SSL_H_SEEN -#define SSL_H_SEEN 1 - -#ifdef HAVE_SSL -#include -#include -#endif +#ifndef NETSSL_H_SEEN +#define NETSSL_H_SEEN 1 #include "nut_ctype.h" +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + extern char *certfile; +extern char *certname; +extern char *certpasswd; +#ifdef WITH_CLIENT_CERTIFICATE_VALIDATION +extern int certrequest; +#endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */ + +/* List possible values for certrequested */ +/* No request */ +#define NETSSL_CERTREQ_NO 0 +/* Requested (cnx failed if no certificate) */ +#define NETSSL_CERTREQ_REQUEST 1 +/* Required (cnx failed if no certificate or invalid CA chain) */ +#define NETSSL_CERTREQ_REQUIRE 2 + void ssl_init(void); void ssl_finish(nut_ctype_t *client); +void ssl_cleanup(void); int ssl_read(nut_ctype_t *client, char *buf, size_t buflen); int ssl_write(nut_ctype_t *client, const char *buf, size_t buflen); void net_starttls(nut_ctype_t *client, int numarg, const char **arg); -#endif /* SSL_H_SEEN */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + +#endif /* NETSSL_H_SEEN */ diff --git a/server/netuser.h b/server/netuser.h index 5f7e047bdc..af227b9584 100644 --- a/server/netuser.h +++ b/server/netuser.h @@ -1,5 +1,18 @@ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + void net_login(nut_ctype_t *client, int numarg, const char **arg); void net_logout(nut_ctype_t *client, int numarg, const char **arg); void net_master(nut_ctype_t *client, int numarg, const char **arg); void net_username(nut_ctype_t *client, int numarg, const char **arg); void net_password(nut_ctype_t *client, int numarg, const char **arg); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/server/sstate.h b/server/sstate.h index bfb5ae6854..fe8485ced3 100644 --- a/server/sstate.h +++ b/server/sstate.h @@ -29,6 +29,12 @@ #define SS_CONNFAIL_INT 300 /* complain about a dead driver every 5 mins */ #define SS_MAX_READ 256 /* don't let drivers tie us up in read() */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + int sstate_connect(upstype_t *ups); void sstate_disconnect(upstype_t *ups); void sstate_readline(upstype_t *ups); @@ -47,4 +53,10 @@ void sstate_cmdfree(upstype_t *ups); int sstate_sendline(upstype_t *ups, const char *buf); const st_tree_t *sstate_getnode(const upstype_t *ups, const char *varname); +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + #endif /* SSTATE_H_SEEN */ diff --git a/server/stype.h b/server/stype.h index 0ad185da22..c143018743 100644 --- a/server/stype.h +++ b/server/stype.h @@ -31,6 +31,12 @@ #define NI_MAXSERV 32 #endif +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + typedef struct stype_s { char *addr; char *port; @@ -38,4 +44,10 @@ typedef struct stype_s { struct stype_s *next; } stype_t; +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + #endif /* STYPE_H_SEEN */ diff --git a/server/upsd.h b/server/upsd.h index 2df9fc0b35..2b3a3a74d1 100644 --- a/server/upsd.h +++ b/server/upsd.h @@ -45,6 +45,12 @@ #define NUT_NET_ANSWER_MAX SMALLBUF +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + /* prototypes from upsd.c */ upstype_t *get_ups_ptr(const char *upsname); @@ -85,4 +91,10 @@ extern nut_ctype_t *firstclient; #define shutdown_how 2 #endif +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + #endif /* UPSD_H_SEEN */ diff --git a/server/upstype.h b/server/upstype.h index 18c0c4217d..bbadd500ad 100644 --- a/server/upstype.h +++ b/server/upstype.h @@ -24,6 +24,12 @@ #include "parseconf.h" +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + /* structure for the linked list of each UPS that we track */ typedef struct upstype_s { char *name; @@ -52,4 +58,10 @@ typedef struct upstype_s { extern upstype_t *firstups; +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + #endif /* UPSTYPE_H_SEEN */ diff --git a/server/user-data.h b/server/user-data.h index d4ef5be815..5cc1e99f34 100644 --- a/server/user-data.h +++ b/server/user-data.h @@ -17,6 +17,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + typedef struct { char *cmd; void *next; @@ -34,3 +40,10 @@ typedef struct { actionlist_t *firstaction; void *next; } ulist_t; + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/server/user.h b/server/user.h index df10eb27dd..48b7004b73 100644 --- a/server/user.h +++ b/server/user.h @@ -17,6 +17,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + void user_load(void); int user_checkinstcmd(const char *un, const char *pw, const char *cmd); @@ -26,3 +32,10 @@ void user_flush(void); /* cheat - we don't want the full upsd.h included here */ void check_perms(const char *fn); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + diff --git a/tools/nut-scanner/nut-scan.h b/tools/nut-scanner/nut-scan.h index e3bbac82f7..613776ec33 100644 --- a/tools/nut-scanner/nut-scan.h +++ b/tools/nut-scanner/nut-scan.h @@ -30,6 +30,12 @@ #include #endif +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + /* SNMP structure */ typedef struct nutscan_snmp { char * community; @@ -88,4 +94,10 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_list); void nutscan_display_ups_conf(nutscan_device_t * device); void nutscan_display_parsable(nutscan_device_t * device); +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + #endif diff --git a/tools/nut-scanner/nutscan-device.h b/tools/nut-scanner/nutscan-device.h index 884b58d516..8e2d89dd38 100644 --- a/tools/nut-scanner/nutscan-device.h +++ b/tools/nut-scanner/nutscan-device.h @@ -19,6 +19,12 @@ #ifndef SCAN_DEVICE #define SCAN_DEVICE +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + typedef enum nutscan_device_type { TYPE_NONE=0, TYPE_USB, @@ -50,4 +56,11 @@ nutscan_device_t * nutscan_new_device(); void nutscan_free_device(nutscan_device_t * device); void nutscan_add_option_to_device(nutscan_device_t * device,char * option, char * value); nutscan_device_t * nutscan_add_device_to_device(nutscan_device_t * first, nutscan_device_t * second); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + #endif diff --git a/tools/nut-scanner/nutscan-init.h b/tools/nut-scanner/nutscan-init.h index f72e14e6fe..daf13588e0 100644 --- a/tools/nut-scanner/nutscan-init.h +++ b/tools/nut-scanner/nutscan-init.h @@ -19,6 +19,12 @@ #ifndef SCAN_INIT #define SCAN_INIT +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + extern int nutscan_avail_avahi; extern int nutscan_avail_ipmi; extern int nutscan_avail_nut; @@ -28,4 +34,11 @@ extern int nutscan_avail_xml_http; void nutscan_init(void); void nutscan_free(void); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + #endif diff --git a/tools/nut-scanner/nutscan-ip.h b/tools/nut-scanner/nutscan-ip.h index fbae00bced..b28ff0062b 100644 --- a/tools/nut-scanner/nutscan-ip.h +++ b/tools/nut-scanner/nutscan-ip.h @@ -22,6 +22,12 @@ #include #include +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + enum network_type { IPv4, IPv6 @@ -38,4 +44,11 @@ typedef struct nutscan_ip_iter { char * nutscan_ip_iter_init(nutscan_ip_iter_t *, const char * startIP, const char * stopIP); char * nutscan_ip_iter_inc(nutscan_ip_iter_t *); int nutscan_cidr_to_ip(const char * cidr, char ** start_ip, char ** stop_ip); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + #endif From 3c5a63f62a44d4de56d45ffeda192634bc17b9f6 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Tue, 29 Jan 2013 12:42:41 +0100 Subject: [PATCH 050/121] nutconf: --{set|add}-user options added NOTE: The options ONLY manipulate upsd.users configuration file. It shall have to be discussed how upsmon.conf shall be kept in sync with the upsmon user settings (TODO). --- common/nutconfbin.cpp | 338 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 333 insertions(+), 5 deletions(-) diff --git a/common/nutconfbin.cpp b/common/nutconfbin.cpp index d5a393b6e3..203c3641ee 100644 --- a/common/nutconfbin.cpp +++ b/common/nutconfbin.cpp @@ -55,6 +55,11 @@ const char * Usage::s_text[] = { " --add-notifyflags + Same as --set-notifyflags, but keeps existing flags", " --set-notifymsg Configures notification message for the type", " --set-shutdowncmd Configures shutdown command", +" --set-user Configures one user (see below)", +" All existing users are removed; however, it may be", +" specified multiple times to set multiple users", +" --add-user Same as --set-user, but keeps existing users", +" The two options are mutually exclusive", "", "NUT modes: standalone, netserver, netclient, controlled, manual, none", "Monitor is specified by the following sequence:", @@ -65,6 +70,13 @@ const char * Usage::s_text[] = { " ONLINE, ONBATT, LOWBATT, FSD, COMMOK, COMMBAD, SHUTDOWN, REPLBATT, NOCOMM, NOPARENT", "Notification flags:", " SYSLOG, WALL, EXEC, IGNORE", +"User specification:", +"The very 1st argument is the username (but see the upsmon exception, below).", +"Next arguments use scheme of key/value pairs in form =", +"Known keys are:", +" password, actions (from {SET,FSD}), instcmds (accepted multiple times)", +"Specially, for the upsmon user, the 1st argument takes form of", +" upsmon={master|slave}", "", }; @@ -501,6 +513,22 @@ class NutConfOptions: public Options { /** Notify messages specifications */ typedef std::map NotifyMsgSpecs; + /** User specification */ + struct UserSpec { + std::string name; /**< Username */ + std::string passwd; /**< Password */ + std::list actions; /**< Actions */ + std::list instcmds; /**< Instant commands */ + }; // end of struct UserSpec + + /** upsmon user specification */ + struct UpsmonUserSpec: public UserSpec { + std::string mode; /**< upsmon mode (master/slave) */ + }; // end of struct UpsmonUserSpec + + /** User specification list */ + typedef std::list UserSpecs; + private: /** Unknown options */ @@ -565,7 +593,7 @@ class NutConfOptions: public Options { /** Set monitor options count */ size_t set_monitor_cnt; - /** Added monitor options count */ + /** Add monitor options count */ size_t add_monitor_cnt; /** --{add|set}-listen arguments (all the addresses) */ @@ -574,7 +602,7 @@ class NutConfOptions: public Options { /** Set listen address options count */ size_t set_listen_cnt; - /** Added listen address options count */ + /** Add listen address options count */ size_t add_listen_cnt; /** Device specifications */ @@ -583,7 +611,7 @@ class NutConfOptions: public Options { /** Set devices options count */ size_t set_device_cnt; - /** Added devices options count */ + /** Add devices options count */ size_t add_device_cnt; /** Notify flags specifications */ @@ -592,7 +620,7 @@ class NutConfOptions: public Options { /** Set notify flags options count */ size_t set_notify_flags_cnt; - /** Added notify flags options count */ + /** Add notify flags options count */ size_t add_notify_flags_cnt; /** Notify messages specifications */ @@ -604,9 +632,21 @@ class NutConfOptions: public Options { /** Shutdown command */ std::string shutdown_cmd; + /** Users specifications */ + UserSpecs users; + + /** Set user options count */ + size_t set_user_cnt; + + /** Add user options count */ + size_t add_user_cnt; + /** Constructor */ NutConfOptions(char * const argv[], int argc); + /** Destructor */ + ~NutConfOptions(); + /** * \brief Report invalid options to STDERR * @@ -663,6 +703,16 @@ class NutConfOptions: public Options { */ static bool checkMode(const std::string & mode); + /** + * \brief Add another user specification + * + * The method is responsible for parsing --{set|add}-user option arguments + * and storing the user specification in \ref users list. + * + * \param args User specification (raw) + */ + void addUser(const Arguments & args); + }; // end of class NutConfOptions @@ -691,7 +741,9 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): add_device_cnt(0), set_notify_flags_cnt(0), add_notify_flags_cnt(0), - set_notify_msg_cnt(0) + set_notify_msg_cnt(0), + set_user_cnt(0), + add_user_cnt(0) { static const std::string sDash("-"); static const std::string dDash("--"); @@ -901,6 +953,19 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): else shutdown_cmd = args.front(); } + else if ("set-user" == *opt || "add-user" == *opt) { + size_t * cnt = ('s' == (*opt)[0] ? &set_user_cnt : &add_user_cnt); + + Arguments args; + + if (NutConfOptions::SETTER != optMode(*opt, args, *cnt)) + m_errors.push_back("--" + *opt + " option requires arguments"); + + else + addUser(args); + + ++*cnt; + } // Unknown option else { @@ -932,6 +997,23 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): valid = false; } + + // --set-user and --add-user are mutually exclusive + if (set_user_cnt > 0 && add_user_cnt > 0) { + m_errors.push_back("--set-user and --add-user options can't both be specified"); + + valid = false; + } +} + + +NutConfOptions::~NutConfOptions() { + UserSpecs::iterator user = users.begin(); + + for (; user != users.end(); ++user) { + delete *user; + *user = NULL; + } } @@ -974,6 +1056,158 @@ bool NutConfOptions::checkMode(const std::string & mode) { } +/** + * \brief Automatically destroyed dynamic object pointer + * + * The template class is useful in situation where you need to + * create a dynamic object, process its attributes and automatically + * destroy it in case of error simply by leaving the scope + * (i.e. not having to warry about calling \c delete by hand). + */ +template +class autodelete_ptr { + private: + + T * m_impl; + + /** Cleanup */ + inline void cleanup() { + if (NULL != m_impl) + delete m_impl; + + m_impl = NULL; + } + + public: + + /** Constructor (unset) */ + autodelete_ptr(): m_impl(NULL) {} + + /** Constructor */ + autodelete_ptr(T * ptr): m_impl(ptr) {} + + /** Setter */ + inline autodelete_ptr & operator = (T * ptr) { + cleanup(); + + m_impl = ptr; + } + + /** Pointer accessor */ + inline operator T * () const { return m_impl; } + + /** Pointer accessor */ + inline T * operator -> () const { return m_impl; } + + /** Pointer overtake (invalidates the object) */ + inline T * give() { + T * ptr = m_impl; + + m_impl = NULL; + + return ptr; + } + + /** Destructor */ + ~autodelete_ptr() { + cleanup(); + } + + private: + + /** Copying is forbidden */ + autodelete_ptr(const autodelete_ptr & orig) {} + + /** Assignment is forbidden */ + autodelete_ptr & operator = (const autodelete_ptr & orig) {} + +}; // end of template class autodelete_ptr + + +void NutConfOptions::addUser(const Options::Arguments & args) { + assert(args.size() > 0); + + Arguments::const_iterator arg_iter = args.begin(); + + // Create new user specification + autodelete_ptr user; + + const std::string & name = *arg_iter; + + // upsmon user (apparently) + // Note that we use pragmatic do ... while (0) loop to enable break + do if (6 <= name.size() && name.substr(0, 6) == "upsmon") { + if (6 == name.size()) { + m_errors.push_back("upsmon user specification requires monitor mode"); + + return; + } + + // Fall-through to ordinary user specification + if ('=' != name[6]) + break; + + UpsmonUserSpec * upsmon_user = new UpsmonUserSpec; + + upsmon_user->name = "upsmon"; + upsmon_user->mode = name.substr(7); + + user = upsmon_user; + + } while (0); // end of pragmatic do ... while (0) loop + + // Ordinary user + if (NULL == user) { + user = new UserSpec; + + user->name = name; + } + + assert(NULL != user); + + // Set user attributes + bool errors = false; + + for (++arg_iter; arg_iter != args.end(); ++arg_iter) { + const std::string & arg = *arg_iter; + + size_t eq_pos = arg.find('='); + + if (std::string::npos == eq_pos) { + m_errors.push_back("Illegal user attribute specification: \"" + arg + '"'); + + errors = true; + + continue; + } + + const std::string attr = arg.substr(0, eq_pos); + const std::string val = arg.substr(eq_pos + 1); + + if ("password" == attr) + user->passwd = val; + + else if ("actions" == attr) + user->actions.push_back(val); + + else if ("instcmds" == attr) + user->instcmds.push_back(val); + + else { + m_errors.push_back("Unknown user attribute: \"" + attr + '"'); + + errors = true; + } + } + + if (errors) + return; + + // Store user specification + users.push_back(user.give()); +} + + void NutConfOptions::getMonitor( std::string & ups, std::string & host_port, @@ -1424,6 +1658,95 @@ void setShutdownCmd(const std::string & cmd, const std::string & etc) } +/** + * \brief Set users in upsd.users + * + * \param users User list + * \param etc Configuration directory + * \param keep_ex Keep existing entries (discard by default) + */ +void setUsers( + const NutConfOptions::UserSpecs & users, + const std::string & etc, bool keep_ex = false) +{ + std::string upsd_users_file(etc + "/upsd.users"); + + nut::UpsdUsersConfiguration upsd_users; + + // Source previous configuration (if any) + source(&upsd_users, upsd_users_file); + + // Remove existing users (unless we want to keep them) + if (!keep_ex) { + nut::UpsdUsersConfiguration::SectionMap::iterator + user = upsd_users.sections.begin(); + + for (; user != upsd_users.sections.end(); ++user) { + // Keep global section + if (user->first.empty()) + continue; + + upsd_users.sections.erase(user); + } + } + + // Set/add users and/or their attributes + NutConfOptions::UserSpecs::const_iterator + user_iter = users.begin(); + + for (; user_iter != users.end(); ++user_iter) { + const NutConfOptions::UserSpec * user = *user_iter; + + const std::string & username = user->name; + + // Set password + if (!user->passwd.empty()) + upsd_users.setPassword(username, user->passwd); + + // Set actions + std::list::const_iterator action = user->actions.begin(); + + for (; action != user->actions.end(); ++action) + upsd_users.addActions(username, nut::ConfigParamList(1, *action)); + + // Set instant commands + std::list::const_iterator cmd = user->instcmds.begin(); + + for (; cmd != user->instcmds.end(); ++cmd) + upsd_users.addInstantCommands(username, nut::ConfigParamList(1, *cmd)); + + // upsmon user-specific settings + if ("upsmon" == username) { + const NutConfOptions::UpsmonUserSpec * upsmon_user = + static_cast(user); + + // Set upsmon mode + nut::UpsdUsersConfiguration::upsmon_mode_t mode = + nut::UpsdUsersConfiguration::UPSMON_UNDEF; + + if ("master" == upsmon_user->mode) + mode = nut::UpsdUsersConfiguration::UPSMON_MASTER; + + else if ("slave" == upsmon_user->mode) + mode = nut::UpsdUsersConfiguration::UPSMON_SLAVE; + + else { + std::cerr + << "Error: Invalid upsmon mode specification: \"" + << upsmon_user->mode << '"' << std::endl; + + ::exit(1); + } + + upsd_users.setUpsmonMode(mode); + } + } + + // Store configuration + store(&upsd_users, upsd_users_file); +} + + /** * \brief Main routine (exceptions unsafe) * @@ -1519,6 +1842,11 @@ int mainx(int argc, char * const argv[]) { setShutdownCmd(options.shutdown_cmd, etc); } + // Users were set + if (!options.users.empty()) { + setUsers(options.users, etc, options.add_user_cnt > 0); + } + return 0; } From 14bfefbb72579068c55190fc438c1494c675c49a Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Wed, 30 Jan 2013 16:55:35 +0100 Subject: [PATCH 051/121] nutconf: --scan-* options added --scan-snmp is still not implemented, TODO --scan-serial is missing, too All other device protocols should work as long as libnutscan works. --- common/Makefile.am | 5 - configure.in | 1 + tools/Makefile.am | 2 +- tools/nut-scanner/nutscan-device.c | 9 + tools/nut-scanner/nutscan-device.h | 13 + tools/nutconf/Makefile.am | 7 + .../nutconf/nutconf.cpp | 516 +++++++++++++++++- 7 files changed, 533 insertions(+), 20 deletions(-) create mode 100644 tools/nutconf/Makefile.am rename common/nutconfbin.cpp => tools/nutconf/nutconf.cpp (81%) diff --git a/common/Makefile.am b/common/Makefile.am index 910018c47d..2fe226c4fa 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -15,8 +15,3 @@ libcommon_la_SOURCES = common.c state.c upsconf.c # ensure inclusion of local implementation of missing systems functions # using LTLIBOBJS. Refer to configure.in -> AC_REPLACE_FUNCS libcommon_la_LIBADD = libparseconf.la @LTLIBOBJS@ - -#EKI : libconf example program -noinst_PROGRAMS = nutconf -nutconf_SOURCES = nutconfbin.cpp -nutconf_LDADD = libnutconf.la libcommon.la diff --git a/configure.in b/configure.in index ed2d3e88d7..2bf2d99295 100644 --- a/configure.in +++ b/configure.in @@ -1184,6 +1184,7 @@ AC_OUTPUT([ server/Makefile tools/Makefile tools/nut-scanner/Makefile + tools/nutconf/Makefile tests/Makefile Makefile ]) diff --git a/tools/Makefile.am b/tools/Makefile.am index ed280a9e98..afb2daf44b 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -14,7 +14,7 @@ # Anyway, for the time being, we force build in ./ before nut-scanner, # to have nutscan-{usb,snmp}.h built before going into the nut-scanner # sub-directory -SUBDIRS = . nut-scanner +SUBDIRS = . nut-scanner nutconf EXTRA_DIST = nut-usbinfo.pl nut-hclinfo.py nut-recorder.sh svn2cl.authors nut-snmpinfo.py diff --git a/tools/nut-scanner/nutscan-device.c b/tools/nut-scanner/nutscan-device.c index b536398ac9..6fed0c9ca8 100644 --- a/tools/nut-scanner/nutscan-device.c +++ b/tools/nut-scanner/nutscan-device.c @@ -20,6 +20,15 @@ #include #include +const char * nutscan_device_type_strings[TYPE_END] = { + "USB", + "SNMP", + "XML", + "NUT", + "IPMI", + "Avahi", + }; + nutscan_device_t * nutscan_new_device() { nutscan_device_t * device; diff --git a/tools/nut-scanner/nutscan-device.h b/tools/nut-scanner/nutscan-device.h index 8e2d89dd38..be7e3c651b 100644 --- a/tools/nut-scanner/nutscan-device.h +++ b/tools/nut-scanner/nutscan-device.h @@ -25,6 +25,16 @@ extern "C" { /* *INDENT-ON* */ #endif +/** + * \brief Device type string getter + * + * \param type Device type + * + * \return Type string + */ +#define nutscan_device_type_string(type) \ + (assert(0 < (type) && (type) < TYPE_END), nutscan_device_type_strings[type - 1]) + typedef enum nutscan_device_type { TYPE_NONE=0, TYPE_USB, @@ -37,6 +47,9 @@ typedef enum nutscan_device_type { TYPE_END } nutscan_device_type_t; +/** Device type -> string mapping */ +extern const char * nutscan_device_type_strings[TYPE_END]; + typedef struct nutscan_options { char * option; char * value; diff --git a/tools/nutconf/Makefile.am b/tools/nutconf/Makefile.am new file mode 100644 index 0000000000..fdf6941877 --- /dev/null +++ b/tools/nutconf/Makefile.am @@ -0,0 +1,7 @@ +noinst_PROGRAMS = nutconf +nutconf_SOURCES = nutconf.cpp +nutconf_CXXFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/tools/nut-scanner +#nutconf_LDFLAGS = -L$(top_srcdir)/tools/nut-scanner +nutconf_LDADD = $(top_srcdir)/common/libcommon.la \ + $(top_srcdir)/common/libnutconf.la \ + $(top_srcdir)/tools/nut-scanner/libnutscan.la diff --git a/common/nutconfbin.cpp b/tools/nutconf/nutconf.cpp similarity index 81% rename from common/nutconfbin.cpp rename to tools/nutconf/nutconf.cpp index 203c3641ee..af27426da9 100644 --- a/common/nutconfbin.cpp +++ b/tools/nutconf/nutconf.cpp @@ -2,6 +2,12 @@ #include "nutconf.h" #include "nutstream.hpp" +extern "C" { +#include "nut-scan.h" +#include "nutscan-init.h" +#include "nutscan-device.h" +} + #include #include #include @@ -60,6 +66,15 @@ const char * Usage::s_text[] = { " specified multiple times to set multiple users", " --add-user Same as --set-user, but keeps existing users", " The two options are mutually exclusive", +" -v", +" --verbose Increase verbosity of output one level", +" May be specified multiple times", +" --scan-usb Scan USB devices", +" --scan-xml-http [] Scan XML/HTTP devices (optional timeout in us)", +" --scan-nut Scan NUT devices (see below for the specs)", +" May be specified multiple times", +" --scan-avahi [] Scan Avahi devices (optional timeout in us)", +" --scan-ipmi Scan IPMI devices", "", "NUT modes: standalone, netserver, netclient, controlled, manual, none", "Monitor is specified by the following sequence:", @@ -77,6 +92,8 @@ const char * Usage::s_text[] = { " password, actions (from {SET,FSD}), instcmds (accepted multiple times)", "Specially, for the upsmon user, the 1st argument takes form of", " upsmon={master|slave}", +"NUT device scan specification:", +" []", "", }; @@ -100,24 +117,22 @@ class Options { /** Options list */ typedef std::list List; - private: - - /** Option type */ - typedef enum { - singleDash, /**< Single-dash prefixed option */ - doubleDash, /**< Double-dash prefixed option */ - } type_t; - - protected: - /** Option arguments list */ typedef std::list Arguments; + protected: + /** Options map */ typedef std::multimap Map; private: + /** Option type */ + typedef enum { + singleDash, /**< Single-dash prefixed option */ + doubleDash, /**< Double-dash prefixed option */ + } type_t; + /** Arguments of the last option processed (\c NULL means bin. args) */ Arguments * m_last; @@ -476,6 +491,203 @@ Options::List Options::strings() const { } +/** NUT scanner wrapper */ +class NutScanner { + public: + + /** Device info */ + class Device { + friend class NutScanner; + + public: + + /** Device type */ + typedef nutscan_device_type_t type_t; + + /** Device options */ + typedef std::map options_t; + + public: + + const std::string type; /**< Type */ + const std::string driver; /**< Driver */ + const std::string port; /**< Port */ + const options_t options; /**< Options */ + + private: + + static options_t createOptions(nutscan_device_t * dev); + + /** Constructor */ + Device(nutscan_device_t * dev); + + }; // end of class Device + + /** Device list */ + typedef std::list devices_t; + + private: + + /** NUT scanner initialisation/finalisation */ + struct InitFinal { + /** Initialisation */ + InitFinal() { nutscan_init(); } + + /** Finalisation */ + ~InitFinal() { nutscan_free(); } + + }; // end of struct InitFinal + + /** Initialiser / finaliser */ + static InitFinal s_init_final; + + /** + * \brief Transform nut-scan provided devices into list of device info + * + * The nut-scan provided device list is destroyed. + * + * \param dev_list nut-scan provided device list + * + * \return Dvice info list + */ + static devices_t dev2list(nutscan_device_t * dev_list); + + /** Instantiation forbidden */ + NutScanner() {} + + public: + + /** + * \brief Scan for SNMP devices + * + * \param start_ip Address range left border + * \param stop_ip Address range right border + * \param us_timeout Device scan timeout + * \param attrs SNMP attributes + * + * TODO + */ +#if (0) + devices_t devicesSNMP( + const std::string & start_ip, + const std::string & stop_ip, + long us_timeout, + SNMPAttributes & attrs); +#endif + + /** + * \brief Scan for USB devices + * + * \return Device list + */ + inline static devices_t devicesUSB() { + nutscan_device_t * dev = nutscan_scan_usb(); + + return dev2list(dev); + } + + /** + * \brief Scan for XML/HTTP devices + * + * \param us_timeout Scan timeout + * + * \return Device list + */ + inline static devices_t devicesXMLHTTP(long us_timeout) { + nutscan_device_t * dev = nutscan_scan_xml_http(us_timeout); + + return dev2list(dev); + } + + /** + * \brief Scan for NUT (pseudo-)devices + * + * \param start_ip Address range left border + * \param stop_ip Address range right border + * \param port Port + * \param us_timeout Device scan timeout + * + * \return Device list + */ + inline static devices_t devicesNUT( + const std::string & start_ip, + const std::string & stop_ip, + const std::string & port, + long us_timeout) + { + nutscan_device_t * dev = nutscan_scan_nut( + start_ip.c_str(), stop_ip.c_str(), port.c_str(), us_timeout); + + return dev2list(dev); + } + + /** + * \brief Scan for Avahi devices + * + * \param us_timeout Scan timeout + * + * \return Device list + */ + inline static devices_t devicesAvahi(long us_timeout) { + nutscan_device_t * dev = nutscan_scan_avahi(us_timeout); + + return dev2list(dev); + } + + /** + * \brief Scan for IPMI devices + * + * \return Device list + */ + inline static devices_t devicesIPMI() { + nutscan_device_t * dev = nutscan_scan_ipmi(); + + return dev2list(dev); + } + +}; // end of class NutScanner + + +NutScanner::InitFinal NutScanner::s_init_final; + + +NutScanner::Device::options_t NutScanner::Device::createOptions(nutscan_device_t * dev) { + assert(NULL != dev); + + options_t options; + + // Create options + nutscan_options_t * opt = &dev->opt; + + for (; NULL != opt; opt = opt->next) + options.insert(options_t::value_type(opt->option, opt->value)); + + return options; +} + + +NutScanner::Device::Device(nutscan_device_t * dev): + type(nutscan_device_type_string(dev->type)), + driver(dev->driver), + port(dev->port), + options(createOptions(dev)) +{} + + +NutScanner::devices_t NutScanner::dev2list(nutscan_device_t * dev_list) { + devices_t list; + + nutscan_device_t * dev = dev_list; + + for (; dev != NULL; dev = dev->next) + list.push_back(Device(dev)); + + nutscan_free_device(dev); + + return list; +} + + /** nutconf tool specific options */ class NutConfOptions: public Options { public: @@ -641,6 +853,24 @@ class NutConfOptions: public Options { /** Add user options count */ size_t add_user_cnt; + /** Verbosity level */ + unsigned int verbose; + + /** Scan NUT devices */ + size_t scan_nut_cnt; + + /** Scan USB devices */ + bool scan_usb; + + /** Scan xml_http_devices */ + bool scan_xml_http; + + /** Scan Avahi devices */ + bool scan_avahi; + + /** Scan IPMI devices */ + bool scan_ipmi; + /** Constructor */ NutConfOptions(char * const argv[], int argc); @@ -743,16 +973,30 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): add_notify_flags_cnt(0), set_notify_msg_cnt(0), set_user_cnt(0), - add_user_cnt(0) + add_user_cnt(0), + verbose(0), + scan_nut_cnt(0), + scan_usb(false), + scan_xml_http(false), + scan_avahi(false), + scan_ipmi(false) { static const std::string sDash("-"); static const std::string dDash("--"); - // No single-dashed options used + // Specificate single-dashed options List list = stringsSingle(); for (List::const_iterator opt = list.begin(); opt != list.end(); ++opt) { - m_unknown.push_back(sDash + *opt); + // Known options + if ("v" == *opt) { + ++verbose; + } + + // Unknown option + else { + m_unknown.push_back(sDash + *opt); + } } // Specificate double-dashed options @@ -966,6 +1210,62 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): ++*cnt; } + else if ("verbose" == *opt) { + ++verbose; + } + else if ("scan-usb" == *opt) { + if (scan_usb) + m_errors.push_back("--scan-usb option specified more than once"); + else + scan_usb = true; + } + else if ("scan-nut" == *opt) { + Arguments args; + + getDouble(*opt, args, scan_nut_cnt); + + if (args.size() < 3) + m_errors.push_back("--scan-nut option requires at least 3 arguments"); + + else if (args.size() > 4) + m_errors.push_back("--scan-nut option requires at most 4 arguments"); + + ++scan_nut_cnt; + } + else if ("scan-xml-http" == *opt) { + if (scan_xml_http) + m_errors.push_back("--scan-xml-http option specified more than once"); + else { + Arguments args; + + getDouble(*opt, args); + + if (args.size() > 1) + m_errors.push_back("--scan-xml-http option accepts only one argument"); + + scan_xml_http = true; + } + } + else if ("scan-avahi" == *opt) { + if (scan_avahi) + m_errors.push_back("--scan-avahi option specified more than once"); + else { + Arguments args; + + getDouble(*opt, args); + + if (args.size() > 1) + m_errors.push_back("--scan-avahi option accepts only one argument"); + + scan_avahi = true; + } + } + else if ("scan-ipmi" == *opt) { + if (scan_ipmi) + m_errors.push_back("--scan-ipmi option specified more than once"); + else + scan_ipmi = true; + } // Unknown option else { @@ -1136,7 +1436,7 @@ void NutConfOptions::addUser(const Options::Arguments & args) { // upsmon user (apparently) // Note that we use pragmatic do ... while (0) loop to enable break - do if (6 <= name.size() && name.substr(0, 6) == "upsmon") { + do if (name.size() >= 6 && name.substr(0, 6) == "upsmon") { if (6 == name.size()) { m_errors.push_back("upsmon user specification requires monitor mode"); @@ -1747,6 +2047,169 @@ void setUsers( } +/** + * \brief Print devices info + * + * \param devices Device list + * \param verbose Verbosity level + */ +void printDevicesInfo(const NutScanner::devices_t & devices, unsigned int verbose = 0) { + NutScanner::devices_t::const_iterator dev_iter = devices.begin(); + + unsigned int dev_no = 1; + + for (; dev_iter != devices.end(); ++dev_iter, ++dev_no) { + const NutScanner::Device & dev = *dev_iter; + + // Print just plain list + if (verbose == 0) + std::cout + << dev.type << ' ' + << dev.driver << ' ' + << dev.port << std::endl; + + // Print full info + else { + std::cout + << "[device_type_" << dev.type + << "_no_" << dev_no << ']' << std::endl + << "\tdriver = " << dev.driver << std::endl + << "\tport = " << dev.port << std::endl; + + NutScanner::Device::options_t::const_iterator + opt = dev.options.begin(); + + for (; opt != dev.options.end(); ++opt) + std::cout + << '\t' << opt->first + << " = " << opt->second + << std::endl; + + std::cout << std::endl; + } + } +} + + +/** + * \brief Scan for USB devices + * + * \param options Options + */ +void scanUSBdevices(const NutConfOptions & options) { + NutScanner::devices_t devices = NutScanner::devicesUSB(); + + printDevicesInfo(devices, options.verbose); +} + + +/** + * \brief Scan for NUT devices + * + * \param options Options + */ +void scanNUTdevices(const NutConfOptions & options) { + for (size_t i = 0; ; ++i) { + NutConfOptions::Arguments args; + + bool ok = options.getDouble("scan-nut", args, i); + + if (!ok) break; + + // Sanity checks + assert(args.size() >= 3); + + NutConfOptions::Arguments::const_iterator arg = args.begin(); + + const std::string & start_ip = *arg++; + const std::string & stop_ip = *arg++; + const std::string & port = *arg++; + + // TBD: where should we get the default? + long us_timeout = 1000000; + + if (arg != args.end()) { + std::stringstream ss(*arg); + + ss >> us_timeout; + } + + NutScanner::devices_t devices = NutScanner::devicesNUT( + start_ip, stop_ip, port, us_timeout); + + printDevicesInfo(devices, options.verbose); + } +} + + +/** + * \brief Scan for XML/HTTP devices + * + * \param options Options + */ +void scanXMLHTTPdevices(const NutConfOptions & options) { + NutConfOptions::Arguments args; + + bool ok = options.getDouble("scan-xml-http", args); + + // Sanity checks + assert(ok); + + // TBD: where should we get the default? + long us_timeout = 1000000; + + if (!args.empty()) { + std::stringstream ss(args.front()); + + ss >> us_timeout; + } + + NutScanner::devices_t devices = NutScanner::devicesXMLHTTP(us_timeout); + + printDevicesInfo(devices, options.verbose); +} + + +/** + * \brief Scan for Avahi devices + * + * \param options Options + */ +void scanAvahiDevices(const NutConfOptions & options) { + NutConfOptions::Arguments args; + + bool ok = options.getDouble("scan-avahi", args); + + // Sanity checks + assert(ok); + + // TBD: where should we get the default? + long us_timeout = 1000000; + + if (!args.empty()) { + std::stringstream ss(args.front()); + + ss >> us_timeout; + } + + NutScanner::devices_t devices = NutScanner::devicesAvahi(us_timeout); + + printDevicesInfo(devices, options.verbose); +} + + +/** + * \brief Scan for IPMI devices + * + * \param options Options + */ +void scanIPMIdevices(const NutConfOptions & options) { + NutScanner::devices_t devices = NutScanner::devicesIPMI(); + + printDevicesInfo(devices, options.verbose); +} + + /** * \brief Main routine (exceptions unsafe) * @@ -1847,6 +2310,31 @@ int mainx(int argc, char * const argv[]) { setUsers(options.users, etc, options.add_user_cnt > 0); } + // USB devices scan + if (options.scan_usb) { + scanUSBdevices(options); + } + + // NUT devices scan + if (options.scan_nut_cnt) { + scanNUTdevices(options); + } + + // XML/HTTP devices scan + if (options.scan_xml_http) { + scanXMLHTTPdevices(options); + } + + // Avahi devices scan + if (options.scan_avahi) { + scanAvahiDevices(options); + } + + // IPMI devices scan + if (options.scan_ipmi) { + scanIPMIdevices(options); + } + return 0; } From db64fe78a88e25f3ea5ab614037c5acce536df61 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Thu, 31 Jan 2013 11:36:10 +0100 Subject: [PATCH 052/121] nutconf: --scan-snmp option added --- tools/nutconf/nutconf.cpp | 205 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 194 insertions(+), 11 deletions(-) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index af27426da9..6e46431131 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -14,6 +14,7 @@ extern "C" { #include #include #include +#include class Usage { @@ -69,6 +70,8 @@ const char * Usage::s_text[] = { " -v", " --verbose Increase verbosity of output one level", " May be specified multiple times", +" --scan-snmp Scan SNMP devices (see below)", +" May be specified multiple times", " --scan-usb Scan USB devices", " --scan-xml-http [] Scan XML/HTTP devices (optional timeout in us)", " --scan-nut Scan NUT devices (see below for the specs)", @@ -92,6 +95,11 @@ const char * Usage::s_text[] = { " password, actions (from {SET,FSD}), instcmds (accepted multiple times)", "Specially, for the upsmon user, the 1st argument takes form of", " upsmon={master|slave}", +"SNMP device scan specification:", +" [=]*", +"Known attributes are:", +" timeout (in us), community, sec-level, sec-name, auth-password, priv-password,", +" auth-protocol, priv-protocol, peer-name", "NUT device scan specification:", " []", "", @@ -526,6 +534,18 @@ class NutScanner { /** Device list */ typedef std::list devices_t; + /** SNMP attributes */ + struct SNMPAttributes { + std::string community; + std::string sec_level; + std::string sec_name; + std::string auth_passwd; + std::string priv_passwd; + std::string auth_proto; + std::string priv_proto; + std::string peer_name; + }; // end of class SNMPAttributes + private: /** NUT scanner initialisation/finalisation */ @@ -565,15 +585,13 @@ class NutScanner { * \param us_timeout Device scan timeout * \param attrs SNMP attributes * - * TODO + * \return Device list */ -#if (0) - devices_t devicesSNMP( - const std::string & start_ip, - const std::string & stop_ip, - long us_timeout, - SNMPAttributes & attrs); -#endif + static devices_t devicesSNMP( + const std::string & start_ip, + const std::string & stop_ip, + long us_timeout, + const SNMPAttributes & attrs); /** * \brief Scan for USB devices @@ -679,7 +697,7 @@ NutScanner::devices_t NutScanner::dev2list(nutscan_device_t * dev_list) { nutscan_device_t * dev = dev_list; - for (; dev != NULL; dev = dev->next) + for (; dev != NULL; dev = dev->prev) list.push_back(Device(dev)); nutscan_free_device(dev); @@ -688,6 +706,50 @@ NutScanner::devices_t NutScanner::dev2list(nutscan_device_t * dev_list) { } +NutScanner::devices_t NutScanner::devicesSNMP( + const std::string & start_ip, + const std::string & stop_ip, + long us_timeout, + const SNMPAttributes & attrs) +{ + nutscan_snmp_t snmp_attrs; + + ::memset(&snmp_attrs, 0, sizeof(snmp_attrs)); + + // TBD: const casting is necessery + // Shouldn't the nutscan_snmp_t items be constant? + + if (!attrs.community.empty()) + snmp_attrs.community = const_cast(attrs.community.c_str()); + + if (!attrs.sec_level.empty()) + snmp_attrs.secLevel = const_cast(attrs.sec_level.c_str()); + + if (!attrs.sec_name.empty()) + snmp_attrs.secName = const_cast(attrs.sec_name.c_str()); + + if (!attrs.auth_passwd.empty()) + snmp_attrs.authPassword = const_cast(attrs.auth_passwd.c_str()); + + if (!attrs.priv_passwd.empty()) + snmp_attrs.privPassword = const_cast(attrs.priv_passwd.c_str()); + + if (!attrs.auth_proto.empty()) + snmp_attrs.authProtocol = const_cast(attrs.auth_proto.c_str()); + + if (!attrs.priv_proto.empty()) + snmp_attrs.privProtocol = const_cast(attrs.priv_proto.c_str()); + + if (!attrs.peer_name.empty()) + snmp_attrs.peername = const_cast(attrs.peer_name.c_str()); + + nutscan_device_t * dev = nutscan_scan_snmp( + start_ip.c_str(), stop_ip.c_str(), us_timeout, &snmp_attrs); + + return dev2list(dev); +} + + /** nutconf tool specific options */ class NutConfOptions: public Options { public: @@ -856,7 +918,7 @@ class NutConfOptions: public Options { /** Verbosity level */ unsigned int verbose; - /** Scan NUT devices */ + /** Scan NUT devices options count */ size_t scan_nut_cnt; /** Scan USB devices */ @@ -871,6 +933,9 @@ class NutConfOptions: public Options { /** Scan IPMI devices */ bool scan_ipmi; + /** Scan SNMP devices options count */ + size_t scan_snmp_cnt; + /** Constructor */ NutConfOptions(char * const argv[], int argc); @@ -979,7 +1044,8 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): scan_usb(false), scan_xml_http(false), scan_avahi(false), - scan_ipmi(false) + scan_ipmi(false), + scan_snmp_cnt(0) { static const std::string sDash("-"); static const std::string dDash("--"); @@ -1266,6 +1332,16 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): else scan_ipmi = true; } + else if ("scan-snmp" == *opt) { + Arguments args; + + getDouble(*opt, args, scan_nut_cnt); + + if (args.size() < 2) + m_errors.push_back("--scan-nut option requires at least 2 arguments"); + + ++scan_snmp_cnt; + } // Unknown option else { @@ -2091,6 +2167,108 @@ void printDevicesInfo(const NutScanner::devices_t & devices, unsigned int verbos } +/** + * \brief Scan for SNMP devices + * + * \param options Options + */ +void scanSNMPdevices(const NutConfOptions & options) { + for (size_t i = 0; ; ++i) { + NutConfOptions::Arguments args; + + bool ok = options.getDouble("scan-snmp", args, i); + + if (!ok) break; + + // Sanity checks + assert(args.size() >= 2); + + NutConfOptions::Arguments::const_iterator arg = args.begin(); + + const std::string & start_ip = *arg++; + const std::string & stop_ip = *arg++; + + // TBD: where should we get the default? + long us_timeout = 1000000; + + NutScanner::SNMPAttributes attrs; + + // Parse = pairs + bool errors = false; + + for (; arg != args.end(); ++arg) { + size_t eq_pos = (*arg).find('='); + + if (std::string::npos == eq_pos) { + std::cerr + << "Error: Invalid SNMP attribute specification: \"" + << *arg << '"' << std::endl; + + errors = true; + + continue; + } + + std::string attr = (*arg).substr(0, eq_pos); + std::string val = (*arg).substr(eq_pos + 1); + + if ("timeout" == attr) { + std::stringstream ss(val); + + if ((ss >> us_timeout).fail()) { + std::cerr + << "Error: Invalid timeout specification: \"" + << val << '"' << std::endl; + + errors = true; + + continue; + } + } + else if ("community" == attr) { + attrs.community = val; + } + else if ("sec-level" == attr) { + attrs.sec_level = val; + } + else if ("sec-name" == attr) { + attrs.sec_name = val; + } + else if ("auth-password" == attr) { + attrs.auth_passwd = val; + } + else if ("priv-password" == attr) { + attrs.priv_passwd = val; + } + else if ("auth-protocol" == attr) { + attrs.auth_proto = val; + } + else if ("priv-protocol" == attr) { + attrs.priv_proto = val; + } + else if ("peer-name" == attr) { + attrs.peer_name = val; + } + + else { + std::cerr + << "Error: Unknown SNMP attribute: \"" + << attr << '"' << std::endl; + + errors = true; + } + } + + if (errors) continue; + + NutScanner::devices_t devices = NutScanner::devicesSNMP( + start_ip, stop_ip, us_timeout, attrs); + + printDevicesInfo(devices, options.verbose); + } +} + + /** * \brief Scan for USB devices * @@ -2310,6 +2488,11 @@ int mainx(int argc, char * const argv[]) { setUsers(options.users, etc, options.add_user_cnt > 0); } + // SNMP devices scan + if (options.scan_snmp_cnt) { + scanSNMPdevices(options); + } + // USB devices scan if (options.scan_usb) { scanUSBdevices(options); From 1ec2f7138aab08a62646ddc1d7c714b30d1fd597 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Fri, 1 Feb 2013 13:36:17 +0100 Subject: [PATCH 053/121] nutconf: added --scan-serial option Piggybacking: IPMI devices scanning updated Fixed nutconf UT --- tests/nutconf_ut.cpp | 3 +- tools/nutconf/nutconf.cpp | 316 ++++++++++++++++++++++++++++++++++---- 2 files changed, 292 insertions(+), 27 deletions(-) diff --git a/tests/nutconf_ut.cpp b/tests/nutconf_ut.cpp index edbfee2e52..8614d90b9d 100644 --- a/tests/nutconf_ut.cpp +++ b/tests/nutconf_ut.cpp @@ -134,12 +134,13 @@ void NutConfigUnitTest::testUpsmonConfiguration() { load(static_cast(&config), "../conf/upsmon.conf.sample"); config.shutdownCmd = "/sbin/shutdown -h +2 'System shutdown in 2 minutes!'"; + config.powerDownFlag = "/run/nut/killpower"; config.poolFreqAlert = 10; config.deadTime = 30; check(static_cast(&config), "SHUTDOWNCMD \"/sbin/shutdown -h +2 'System shutdown in 2 minutes!'\"\n" - "POWERDOWNFLAG /etc/killpower\n" + "POWERDOWNFLAG /run/nut/killpower\n" "MINSUPPLIES 1\n" "POLLFREQ 5\n" "POLLFREQALERT 10\n" diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 6e46431131..0e585eb018 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -35,6 +35,7 @@ class Usage { const char * Usage::s_text[] = { +" -h -help", " --help Display this help and exit", " --autoconfigure Perform autoconfiguration", " --is-configured Checks whether NUT is configured", @@ -77,7 +78,9 @@ const char * Usage::s_text[] = { " --scan-nut Scan NUT devices (see below for the specs)", " May be specified multiple times", " --scan-avahi [] Scan Avahi devices (optional timeout in us)", -" --scan-ipmi Scan IPMI devices", +" --scan-ipmi Scan IPMI devices (see below)", +" May be specified multiple times", +" --scan-serial * Scan for serial devices on specified ports", "", "NUT modes: standalone, netserver, netclient, controlled, manual, none", "Monitor is specified by the following sequence:", @@ -102,6 +105,11 @@ const char * Usage::s_text[] = { " auth-protocol, priv-protocol, peer-name", "NUT device scan specification:", " []", +"IMPI device scan specification:", +" [=]*", +"Known attributes are:", +" username, password, auth-type, cipher-suite-id, K-g-BMC-key, priv-level,", +" workaround-flags, version", "", }; @@ -536,16 +544,38 @@ class NutScanner { /** SNMP attributes */ struct SNMPAttributes { - std::string community; - std::string sec_level; - std::string sec_name; - std::string auth_passwd; - std::string priv_passwd; - std::string auth_proto; - std::string priv_proto; - std::string peer_name; + std::string community; /**< Community */ + std::string sec_level; /**< Sec. level */ + std::string sec_name; /**< Sec. name */ + std::string auth_passwd; /**< Authentication password */ + std::string priv_passwd; /**< Priv. password */ + std::string auth_proto; /**< Authentication protocol */ + std::string priv_proto; /**< Priv. protocol */ + std::string peer_name; /**< Peer name */ }; // end of class SNMPAttributes + /** IMPI attributes */ + struct IPMIAttributes { + std::string username; /**< Username */ + std::string passwd; /**< Password */ + int auth_type; /**< Authentication type */ + int cipher_suite_id; /**< Cipher suite ID */ + std::string K_g_BMC_key; /**< Optional 2nd key */ + int priv_level; /**< Priviledge level */ + unsigned wa_flags; /**< Workaround flags */ + int version; /**< IPMI protocol version */ + + /** Constructor */ + IPMIAttributes(): + auth_type(IPMI_AUTHENTICATION_TYPE_MD5), + cipher_suite_id(3), + priv_level(IPMI_PRIVILEGE_LEVEL_ADMIN), + wa_flags(0), + version(IPMI_1_5) + {} + + }; // end of struct IMPIAttributes + private: /** NUT scanner initialisation/finalisation */ @@ -657,11 +687,19 @@ class NutScanner { * * \return Device list */ - inline static devices_t devicesIPMI() { - nutscan_device_t * dev = nutscan_scan_ipmi(); + static devices_t devicesIPMI( + const std::string & start_ip, + const std::string & stop_ip, + const IPMIAttributes & attrs); - return dev2list(dev); - } + /** + * \brief Scan for Eaton serial devices + * + * \param ports List of serial ports + * + * \return Device list + */ + static devices_t devicesEatonSerial(const std::list & ports); }; // end of class NutScanner @@ -750,6 +788,57 @@ NutScanner::devices_t NutScanner::devicesSNMP( } +NutScanner::devices_t NutScanner::devicesIPMI( + const std::string & start_ip, + const std::string & stop_ip, + const IPMIAttributes & attrs) +{ + nutscan_ipmi_t ipmi_attrs; + + ::memset(&ipmi_attrs, 0, sizeof(ipmi_attrs)); + + // TBD: const casting is necessery + // Shouldn't the nutscan_ipmi_t C-string items be constant? + + if (!attrs.username.empty()) + ipmi_attrs.username = const_cast(attrs.username.c_str()); + + if (!attrs.passwd.empty()) + ipmi_attrs.password = const_cast(attrs.passwd.c_str()); + + ipmi_attrs.authentication_type = attrs.auth_type; + ipmi_attrs.cipher_suite_id = attrs.cipher_suite_id; + + if (!attrs.K_g_BMC_key.empty()) + ipmi_attrs.K_g_BMC_key = const_cast(attrs.K_g_BMC_key.c_str()); + + ipmi_attrs.privilege_level = attrs.priv_level; + ipmi_attrs.workaround_flags = attrs.wa_flags; + ipmi_attrs.ipmi_version = attrs.version; + + nutscan_device_t * dev = nutscan_scan_ipmi( + start_ip.c_str(), stop_ip.c_str(), &ipmi_attrs); + + return dev2list(dev); +} + + +NutScanner::devices_t NutScanner::devicesEatonSerial(const std::list & ports) { + std::string port_list; + + std::list::const_iterator port = ports.begin(); + + for (; port != ports.end(); ++port) { + port_list += *port; + port_list += ' '; + } + + nutscan_device_t * dev = nutscan_scan_eaton_serial(port_list.c_str()); + + return dev2list(dev); +} + + /** nutconf tool specific options */ class NutConfOptions: public Options { public: @@ -931,11 +1020,14 @@ class NutConfOptions: public Options { bool scan_avahi; /** Scan IPMI devices */ - bool scan_ipmi; + size_t scan_ipmi_cnt; /** Scan SNMP devices options count */ size_t scan_snmp_cnt; + /** Scan Eaton serial devices */ + bool scan_serial; + /** Constructor */ NutConfOptions(char * const argv[], int argc); @@ -1044,8 +1136,9 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): scan_usb(false), scan_xml_http(false), scan_avahi(false), - scan_ipmi(false), - scan_snmp_cnt(0) + scan_ipmi_cnt(0), + scan_snmp_cnt(0), + scan_serial(false) { static const std::string sDash("-"); static const std::string dDash("--"); @@ -1327,21 +1420,31 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): } } else if ("scan-ipmi" == *opt) { - if (scan_ipmi) - m_errors.push_back("--scan-ipmi option specified more than once"); - else - scan_ipmi = true; + Arguments args; + + getDouble(*opt, args, scan_ipmi_cnt); + + if (args.size() < 2) + m_errors.push_back("--scan-ipmi option requires at least 2 arguments"); + + ++scan_ipmi_cnt; } else if ("scan-snmp" == *opt) { Arguments args; - getDouble(*opt, args, scan_nut_cnt); + getDouble(*opt, args, scan_snmp_cnt); if (args.size() < 2) - m_errors.push_back("--scan-nut option requires at least 2 arguments"); + m_errors.push_back("--scan-snmp option requires at least 2 arguments"); ++scan_snmp_cnt; } + else if ("scan-serial" == *opt) { + if (scan_serial) + m_errors.push_back("--scan-serial option specified more than once"); + else + scan_serial = true; + } // Unknown option else { @@ -2217,7 +2320,7 @@ void scanSNMPdevices(const NutConfOptions & options) { if ((ss >> us_timeout).fail()) { std::cerr - << "Error: Invalid timeout specification: \"" + << "Error: Invalid SNMP timeout specification: \"" << val << '"' << std::endl; errors = true; @@ -2382,7 +2485,163 @@ void scanAvahiDevices(const NutConfOptions & options) { * \param options Options */ void scanIPMIdevices(const NutConfOptions & options) { - NutScanner::devices_t devices = NutScanner::devicesIPMI(); + for (size_t i = 0; ; ++i) { + NutConfOptions::Arguments args; + + bool ok = options.getDouble("scan-ipmi", args, i); + + if (!ok) break; + + // Sanity checks + assert(args.size() >= 2); + + NutConfOptions::Arguments::const_iterator arg = args.begin(); + + const std::string & start_ip = *arg++; + const std::string & stop_ip = *arg++; + + NutScanner::IPMIAttributes attrs; + + // Parse = pairs + bool errors = false; + + for (; arg != args.end(); ++arg) { + size_t eq_pos = (*arg).find('='); + + if (std::string::npos == eq_pos) { + std::cerr + << "Error: Invalid IPMI attribute specification: \"" + << *arg << '"' << std::endl; + + errors = true; + + continue; + } + + std::string attr = (*arg).substr(0, eq_pos); + std::string val = (*arg).substr(eq_pos + 1); + + if ("username" == attr) { + attrs.username = val; + } + else if ("password" == attr) { + attrs.passwd = val; + } + else if ("auth-type" == attr) { + if ("none" == val) + attrs.auth_type = IPMI_AUTHENTICATION_TYPE_NONE; + else if ("MD2" == val) + attrs.auth_type = IPMI_AUTHENTICATION_TYPE_MD2; + else if ("MD5" == val) + attrs.auth_type = IPMI_AUTHENTICATION_TYPE_MD5; + else if ("plain-password" == val) + attrs.auth_type = IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY; + else if ("OEM" == val) + attrs.auth_type = IPMI_AUTHENTICATION_TYPE_OEM_PROP; + else if ("RMCPplus" == val) + attrs.auth_type = IPMI_AUTHENTICATION_TYPE_RMCPPLUS; + else { + std::cerr + << "Error: Invalid IPMI auth. type: \"" + << val << '"' << std::endl; + + errors = true; + + continue; + } + } + else if ("cipher-suite-id" == attr) { + std::stringstream ss(val); + + if ((ss >> attrs.cipher_suite_id).fail()) { + std::cerr + << "Error: Invalid IPMI cipher suite ID: \"" + << val << '"' << std::endl; + + errors = true; + + continue; + } + } + else if ("K-g-BMC-key" == attr) { + attrs.K_g_BMC_key = val; + } + else if ("priv-level" == attr) { + std::stringstream ss(val); + + if ((ss >> attrs.priv_level).fail()) { + std::cerr + << "Error: Invalid IPMI priv. level: \"" + << val << '"' << std::endl; + + errors = true; + + continue; + } + } + else if ("workaround-flags" == attr) { + std::stringstream ss(val); + + if ((ss >> attrs.wa_flags).fail()) { + std::cerr + << "Error: Invalid IPMI workaround flags: \"" + << val << '"' << std::endl; + + errors = true; + + continue; + } + } + + else if ("version" == attr) { + if ("1.5" == val) + attrs.version = IPMI_1_5; + else if ("2.0" == val) + attrs.version = IPMI_2_0; + else { + std::cerr + << "Error: Unsupported IPMI version " + << val << std::endl; + + errors = true; + + continue; + } + } + + else { + std::cerr + << "Error: Unknown IPMI attribute: \"" + << attr << '"' << std::endl; + + errors = true; + } + } + + if (errors) continue; + + NutScanner::devices_t devices = NutScanner::devicesIPMI( + start_ip, stop_ip, attrs); + + printDevicesInfo(devices, options.verbose); + } +} + + +/** + * \brief Scan for serial devices devices + * + * \param options Options + */ +void scanSerialDevices(const NutConfOptions & options) { + NutConfOptions::Arguments args; + + bool ok = options.getDouble("scan-serial", args); + + // Sanity checks + assert(ok); + + NutScanner::devices_t devices = NutScanner::devicesEatonSerial(args); printDevicesInfo(devices, options.verbose); } @@ -2401,7 +2660,7 @@ int mainx(int argc, char * const argv[]) { NutConfOptions options(argv, argc); // Usage - if (options.exists("help")) { + if (options.exists("help") || options.existsSingle("h")) { Usage::print(argv[0]); ::exit(0); @@ -2514,10 +2773,15 @@ int mainx(int argc, char * const argv[]) { } // IPMI devices scan - if (options.scan_ipmi) { + if (options.scan_ipmi_cnt) { scanIPMIdevices(options); } + // Serial devices scan + if (options.scan_serial) { + scanSerialDevices(options); + } + return 0; } From 7122acd630ec8e5e98fdafc0c2dd568383696695 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Fri, 1 Feb 2013 17:19:47 +0100 Subject: [PATCH 054/121] nutconf: manpage added --- docs/man/Makefile.am | 4 +- docs/man/nutconf.txt | 219 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 docs/man/nutconf.txt diff --git a/docs/man/Makefile.am b/docs/man/Makefile.am index 24df5fceae..a1a78c5239 100644 --- a/docs/man/Makefile.am +++ b/docs/man/Makefile.am @@ -74,9 +74,9 @@ HTML_CLIENT_MANS = \ upsrw.html \ upssched.html -SRC_TOOL_PAGES = nut-scanner.txt nut-recorder.txt +SRC_TOOL_PAGES = nut-scanner.txt nut-recorder.txt nutconf.txt -MAN_TOOL_PAGES = nut-scanner.8 nut-recorder.8 +MAN_TOOL_PAGES = nut-scanner.8 nut-recorder.8 nutconf.8 man8_MANS += $(MAN_TOOL_PAGES) diff --git a/docs/man/nutconf.txt b/docs/man/nutconf.txt new file mode 100644 index 0000000000..68262a6b97 --- /dev/null +++ b/docs/man/nutconf.txt @@ -0,0 +1,219 @@ +NUTCONF(8) +========== + + +NAME +---- +nutconf - NUT configuration tool + +SYNOPSIS +-------- +*nutconf* --help + +*nutconf* ['OPTIONS'] + +DESCRIPTION +----------- + +*nutconf* tool is used to create and manipulate NUT configuration files. +It also supports device scanning (to suggest configuration of devices). + +INSTALLATION +------------ + +The scanning feature depends on the very same compile time and run time +dependencies as the *nut-scanner*. + +OPTIONS +------- + +*-h* | *-help* | *--help*:: +Display the help text. + +*-v* | *--verbose*:: +Increase output verbosity (may be used multiple times). + +*--is-configured*:: +Checks whether NUT was configured, before. + +*--system*:: +System configuration directory shall be used. + +*--local* 'directory':: +Sets alternative configuration directory. + +*--mode* 'mode':: +Sets NUT configuration mode. + + :: +Known modes are: + +- standalone +- netserver +- netclient +- controlled +- manual +- none + +CONFIGURATION ENTRY SET/ADD OPTIONS +----------------------------------- + +These options mostly have 2 forms: '--set-...' or '--add-...'. + +The difference is that the set options discard previous settings +while the add options keep them. + +Note that such options may be specified multiple times for one run +(to enable setting multiple entries at once). + +*--set-monitor* | *--add-monitor* '':: +Sets/adds a NUT monitor. + +Arguments: +'' '[:]' '' '' '' '(\"master\"|\"slave\")' + +*--set-listen* | *--add-listen* '
' '[]':: +Sets/adds 'nutd' daemon listen address + +*--set-device* | *--add-device* '':: +Sets/adds a device (typically a UPS). + +Arguments: +'' '' '' '[]' + +*--set-notifyflags* | *--add-notifyflags* '' '+':: +Sets/adds notification flags for the notification type. + + :: +Notification types are: +'TODO': check the semantics. + +- 'ONLINE' (mains is present) +- 'ONBATT' (mains is gone) +- 'LOWBATT' (battery is getting empty) +- 'FSD' (shutdown was forced) +- 'COMMOK' (regained communication with device) +- 'COMMBAD' (lost communication with device) +- 'SHUTDOWN' (system is going down) +- 'REPLBATT' (UPS battery is failing) +- 'NOCOMM' (have no communication with a device) +- 'NOPARENT' (???) + + :: +Notification flags: + +- 'SYSLOG' (use syslogd to log the notification) +- 'WALL' (push a message to usres' terminals) +- 'EXEC' (execute a command) +- 'IGNORE' (don't act) + +*--set-notifymsg* '' '':: +Sets message for the specified notification type. + +*--set-shutdowncmd* '':: +Sets command used to shut the system down. + +*--set-user* | *--add-user* '':: +Sets/adds NUT user. + + :: +Arguments: + +- '' (specifies user name). +For 'upsmon' user, it has a special form of +'upsmon=(master|slave)' which specifies the moniutoring mode. +- 'password=' sets password for the user +- 'actions=' sets actions ('SET', 'FSD' are supported) +- 'instcmds=' sets instan commands allowed for the user +(may be used multiple times) + +SCANNING OPTIONS +---------------- + +All timeouts are in microseconds. + +*--scan-snmp* '' '' '[=]*':: +Scans for SNMP devices on IP addresses from the specified range. + + :: +Known attributes are: +'TODO' check these: + +- 'timeout' device scan timeout +- 'community' SNMP community +- 'sec-level' sec. level +- 'sec-name' sec. name +- 'auth-password' authentication password +- 'priv-password' priv. password +- 'auth-protocol' authentication protocol +- 'priv-protocol' priv. protocol +- 'peer-name' peer name + +*--scan-usb*:: +Scans the USB bus for known devices + +*--scan-xml-http* '[]':: +Scans for XML/HTTP devices on the network. + +*--scan-nut* '' '' '' '[]':: +Scans for NUT (pseudo-)devices on the network. + +*--scan-avahi* '[]':: +Scans for Avahi devices. + +*--scan-ipmi* '' '' '[=]'*:: +Scans for IPMI devices on IP addresses from the specified range. + + :: +Known attributes are: +'TODO' check these: + +- 'username' username +- 'password' user password +- 'auth-type' authentication type (see below) +- 'cipher-suite-id' cipher suite ID +- 'K-g-BMC-key' optional second key (???) +- 'priv-level' priv. level +- 'workaround-flags' (???) +- 'version' (1.5 or 2.0) + + :: +Authentication types: +'TODO" check these: + +- 'none' (authentication is disabled) +- 'MD2' +- 'MD5' +- 'plain-password' (no ciphering used for password sending) +- 'OEM' (???) +- 'RMCPplus' (???) + +*--scan-serial* ''*:: +Scans for serial devices (of supported types) on the specified +serial ports. + +EXAMPLES +-------- + +To set alternative directory for configuration files: + +*nutconf --local ~/test/nut/etc* + +To add another user (keeping the existing ones): + +*nutconf --add-user bart password=qwerty* + +To scan USB devices and serial devices (on the 1st two ports): + +*nutconf --scan-usb --scan-serial /dev/ttyS1 /dev/ttyS2* + +SEE ALSO +-------- + +linkman:ups.conf[5] +linkman:nut-scanner[8] + +INTERNET RESOURCES +------------------ + +The NUT (Network UPS Tools) home page: http://www.networkupstools.org/ From 930a000d576b1d8d8e521a04e27b847fa171adea Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Mon, 4 Feb 2013 15:30:32 +0100 Subject: [PATCH 055/121] nutconf: compilation & finishing touches --- common/Makefile.am | 1 + docs/man/nutconf.txt | 76 ++++++++++++++++++++++++++------------- include/Makefile.am | 2 +- tests/Makefile.am | 2 +- tests/nutconf_ut.cpp | 10 +++--- tools/nutconf/Makefile.am | 14 +++++--- tools/nutconf/nutconf.cpp | 47 ++++++++++++++++++++++++ 7 files changed, 116 insertions(+), 36 deletions(-) diff --git a/common/Makefile.am b/common/Makefile.am index 2fe226c4fa..4693b24ca3 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -1,6 +1,7 @@ # Network UPS Tools: common AM_CFLAGS = -I$(top_srcdir)/include +AM_CXXFLAGS = -I$(top_srcdir)/include noinst_LTLIBRARIES = libparseconf.la libcommon.la libnutconf.la libparseconf_la_SOURCES = parseconf.c diff --git a/docs/man/nutconf.txt b/docs/man/nutconf.txt index 68262a6b97..c891c2bbd4 100644 --- a/docs/man/nutconf.txt +++ b/docs/man/nutconf.txt @@ -86,18 +86,17 @@ Sets/adds notification flags for the notification type. :: Notification types are: -'TODO': check the semantics. - 'ONLINE' (mains is present) - 'ONBATT' (mains is gone) -- 'LOWBATT' (battery is getting empty) +- 'LOWBATT' (remaining battery capacity is low) - 'FSD' (shutdown was forced) -- 'COMMOK' (regained communication with device) +- 'COMMOK' (communication with device established) - 'COMMBAD' (lost communication with device) -- 'SHUTDOWN' (system is going down) -- 'REPLBATT' (UPS battery is failing) -- 'NOCOMM' (have no communication with a device) -- 'NOPARENT' (???) +- 'SHUTDOWN' (system is going down, now) +- 'REPLBATT' (UPS battery needs replacing) +- 'NOCOMM' (device is unavailable) +- 'NOPARENT' (upsmon parent process died, shutdown is impossible) :: Notification flags: @@ -130,6 +129,12 @@ For 'upsmon' user, it has a special form of SCANNING OPTIONS ---------------- +Availability of each scanning option depends on availability of +various 3rd-party libraries both at compile time and run time. + +Issue the tool with the *--help* option to check which of the +*--scan-...* options are actually supported. + All timeouts are in microseconds. *--scan-snmp* '' '' '[=]*':: @@ -137,16 +142,15 @@ Scans for SNMP devices on IP addresses from the specified range. :: Known attributes are: -'TODO' check these: - 'timeout' device scan timeout -- 'community' SNMP community -- 'sec-level' sec. level -- 'sec-name' sec. name -- 'auth-password' authentication password -- 'priv-password' priv. password -- 'auth-protocol' authentication protocol -- 'priv-protocol' priv. protocol +- 'community' SNMP community (default: *public*) +- 'sec-level' security level (SNMPv3); one of *noAuthNoPriv* *authNoPriv*, *authPriv* +- 'sec-name' security name (NMSPv3); mandatory companion of *sec-level* +- 'auth-password' authentication password (SNMPv3); mandatory for *authNoPriv* and *authPriv* +- 'priv-password' privacy password (SNMPv3); mandatory for *authPriv* +- 'auth-protocol' authentication protocol (SNMPv3): *MD5* or *SHA*, *MD5* is the default +- 'priv-protocol' priv. protocol (SNMPv3): *DES* or *AES*, *DES* is the default - 'peer-name' peer name *--scan-usb*:: @@ -166,27 +170,51 @@ Scans for IPMI devices on IP addresses from the specified range. :: Known attributes are: -'TODO' check these: -- 'username' username -- 'password' user password +- 'username' username (mandatory for IPMI/LAN) +- 'password' user password (mandatory for IPMI/LAN) - 'auth-type' authentication type (see below) -- 'cipher-suite-id' cipher suite ID +- 'cipher-suite-id' cipher suite ID (see below) - 'K-g-BMC-key' optional second key (???) - 'priv-level' priv. level -- 'workaround-flags' (???) +- 'workaround-flags' - 'version' (1.5 or 2.0) :: Authentication types: -'TODO" check these: + :: +Specifies the IPMI 1.5 authentication type to use (NONE, STRAIGHT_PASSWORD_KEY, MD2, and MD5) with the remote host (default=MD5). +This forces connection through the 'lan' IPMI interface , thus in IPMI 1.5 mode. - 'none' (authentication is disabled) - 'MD2' -- 'MD5' +- 'MD5' (default) - 'plain-password' (no ciphering used for password sending) -- 'OEM' (???) -- 'RMCPplus' (???) +- 'OEM' +- 'RMCPplus' + + :: +Cipher suite IDs: + :: +Specifies the IPMI 2.0 cipher suite ID to use. The Cipher Suite ID identifies a set of authentication, integrity, and +confidentiality algorithms to use for IPMI 2.0 communication. The authentication algorithm identifies the algorithm +to use for session setup, the integrity algorithm identifies the algorithm to use for session packet signatures, and the +confidentiality algorithm identifies the algorithm to use for payload encryption (default=3). + :: +The following cipher suite ids are currently supported (Authentication; Integrity; Confidentiality): + +- '0': None; None; None +- '1': HMAC-SHA1; None; None +- '2': HMAC-SHA1; HMAC-SHA1-96; None +- '3': HMAC-SHA1; HMAC-SHA1-96; AES-CBC-128 +- '6': HMAC-MD5; None; None +- '7': HMAC-MD5; HMAC-MD5-128; None +- '8': HMAC-MD5; HMAC-MD5-128; AES-CBC-128 +- '11': HMAC-MD5; MD5-128; None +- '12': HMAC-MD5; MD5-128; AES-CBC-128 +- '15': HMAC-SHA256; None; None +- '16': HMAC-SHA256; HMAC_SHA256_128; None +- '17': HMAC-SHA256; HMAC_SHA256_128; AES-CBC-128 *--scan-serial* ''*:: Scans for serial devices (of supported types) on the specified diff --git a/include/Makefile.am b/include/Makefile.am index c722f8a934..76698803f4 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,6 @@ dist_noinst_HEADERS = attribute.h common.h extstate.h parseconf.h proto.h \ state.h timehead.h upsconf.h nut_stdint.h nut_platform.h nutstream.hpp \ - nutwriter.hpp nutipc.hpp + nutwriter.hpp nutipc.hpp nutconf.h # http://www.gnu.org/software/automake/manual/automake.html#Clean BUILT_SOURCES = nut_version.h diff --git a/tests/Makefile.am b/tests/Makefile.am index 663a5af21e..e96cc4d411 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -6,7 +6,7 @@ TESTS = cppunittest check_PROGRAMS = $(TESTS) -cppunittest_CXXFLAGS = $(CPPUNIT_CFLAGS) -I$(top_srcdir)/include +cppunittest_CXXFLAGS = $(CPPUNIT_CFLAGS) -I$(top_srcdir)/include -DTOP_SRCDIR="\"$(top_srcdir)\"" cppunittest_LDFLAGS = $(CPPUNIT_LIBS) cppunittest_LDADD = ../common/libnutconf.la diff --git a/tests/nutconf_ut.cpp b/tests/nutconf_ut.cpp index 8614d90b9d..3fc4b2fcdf 100644 --- a/tests/nutconf_ut.cpp +++ b/tests/nutconf_ut.cpp @@ -118,7 +118,7 @@ void NutConfigUnitTest::check(const nut::Serialisable * config, const std::strin void NutConfigUnitTest::testNutConfiguration() { nut::NutConfiguration config; - load(static_cast(&config), "../conf/nut.conf.sample"); + load(static_cast(&config), TOP_SRCDIR "/conf/nut.conf.sample"); config.mode = nut::NutConfiguration::MODE_STANDALONE; @@ -131,7 +131,7 @@ void NutConfigUnitTest::testNutConfiguration() { void NutConfigUnitTest::testUpsmonConfiguration() { nut::UpsmonConfiguration config; - load(static_cast(&config), "../conf/upsmon.conf.sample"); + load(static_cast(&config), TOP_SRCDIR "/conf/upsmon.conf.sample"); config.shutdownCmd = "/sbin/shutdown -h +2 'System shutdown in 2 minutes!'"; config.powerDownFlag = "/run/nut/killpower"; @@ -156,7 +156,7 @@ void NutConfigUnitTest::testUpsmonConfiguration() { void NutConfigUnitTest::testUpsdConfiguration() { nut::UpsdConfiguration config; - load(static_cast(&config), "../conf/upsd.conf.sample"); + load(static_cast(&config), TOP_SRCDIR "/conf/upsd.conf.sample"); config.maxAge = 15; config.statePath = "/var/run/nut"; @@ -188,7 +188,7 @@ void NutConfigUnitTest::testUpsdConfiguration() { void NutConfigUnitTest::testUpsConfiguration() { nut::UpsConfiguration config; - load(static_cast(&config), "../conf/ups.conf.sample"); + load(static_cast(&config), TOP_SRCDIR "/conf/ups.conf.sample"); static const std::string my_ups("powerpal"); @@ -209,7 +209,7 @@ void NutConfigUnitTest::testUpsConfiguration() { void NutConfigUnitTest::testUpsdUsersConfiguration() { nut::UpsdUsersConfiguration config; - load(static_cast(&config), "../conf/upsd.users.sample"); + load(static_cast(&config), TOP_SRCDIR "/conf/upsd.users.sample"); config.setPassword("upsmon", "ytrewq"); config.setUpsmonMode(nut::UpsdUsersConfiguration::UPSMON_MASTER); diff --git a/tools/nutconf/Makefile.am b/tools/nutconf/Makefile.am index fdf6941877..681cd1c875 100644 --- a/tools/nutconf/Makefile.am +++ b/tools/nutconf/Makefile.am @@ -1,7 +1,11 @@ noinst_PROGRAMS = nutconf nutconf_SOURCES = nutconf.cpp -nutconf_CXXFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/tools/nut-scanner -#nutconf_LDFLAGS = -L$(top_srcdir)/tools/nut-scanner -nutconf_LDADD = $(top_srcdir)/common/libcommon.la \ - $(top_srcdir)/common/libnutconf.la \ - $(top_srcdir)/tools/nut-scanner/libnutscan.la +nutconf_CXXFLAGS = -I$(top_srcdir)/include +nutconf_LDADD = ../../common/libcommon.la \ + ../../common/libnutconf.la + +# Add support for device scanning +if WITH_LIBLTDL +nutconf_CXXFLAGS += -DWITH_NUTSCANNER -I$(top_srcdir)/tools/nut-scanner +nutconf_LDADD += ../nut-scanner/libnutscan.la +endif diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 0e585eb018..bbf26126d2 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -3,9 +3,11 @@ #include "nutstream.hpp" extern "C" { +#if (defined WITH_NUTSCANNER) #include "nut-scan.h" #include "nutscan-init.h" #include "nutscan-device.h" +#endif // defined WITH_NUTSCANNER } #include @@ -71,16 +73,28 @@ const char * Usage::s_text[] = { " -v", " --verbose Increase verbosity of output one level", " May be specified multiple times", +#if (defined WITH_NUTSCANNER) +#if (defined WITH_SNMP) " --scan-snmp Scan SNMP devices (see below)", " May be specified multiple times", +#endif // defined WITH_SNMP +#if (defined WITH_USB) " --scan-usb Scan USB devices", +#endif // defined WITH_USB +#if (defined WITH_NEON) " --scan-xml-http [] Scan XML/HTTP devices (optional timeout in us)", +#endif // defined WITH_NEON " --scan-nut Scan NUT devices (see below for the specs)", " May be specified multiple times", +#if (defined WITH_AVAHI) " --scan-avahi [] Scan Avahi devices (optional timeout in us)", +#endif // defined WITH_AVAHI +#if (defined WITH_IPMI) " --scan-ipmi Scan IPMI devices (see below)", " May be specified multiple times", +#endif // defined WITH_IPMI " --scan-serial * Scan for serial devices on specified ports", +#endif // defined WITH_NUTSCANNER "", "NUT modes: standalone, netserver, netclient, controlled, manual, none", "Monitor is specified by the following sequence:", @@ -98,18 +112,24 @@ const char * Usage::s_text[] = { " password, actions (from {SET,FSD}), instcmds (accepted multiple times)", "Specially, for the upsmon user, the 1st argument takes form of", " upsmon={master|slave}", +#if (defined WITH_NUTSCANNER) +#if (defined WITH_SNMP) "SNMP device scan specification:", " [=]*", "Known attributes are:", " timeout (in us), community, sec-level, sec-name, auth-password, priv-password,", " auth-protocol, priv-protocol, peer-name", +#endif // defined WITH_SNMP "NUT device scan specification:", " []", +#if (defined WITH_IPMI) "IMPI device scan specification:", " [=]*", "Known attributes are:", " username, password, auth-type, cipher-suite-id, K-g-BMC-key, priv-level,", " workaround-flags, version", +#endif // defined WITH_IPMI +#endif // defined WITH_NUTSCANNER "", }; @@ -507,6 +527,8 @@ Options::List Options::strings() const { } +#if (defined WITH_NUTSCANNER) + /** NUT scanner wrapper */ class NutScanner { public: @@ -838,6 +860,8 @@ NutScanner::devices_t NutScanner::devicesEatonSerial(const std::list 0); } +#if (defined WITH_NUTSCANNER) + // SNMP devices scan if (options.scan_snmp_cnt) { scanSNMPdevices(options); @@ -2782,6 +2827,8 @@ int mainx(int argc, char * const argv[]) { scanSerialDevices(options); } +#endif // defined WITH_NUTSCANNER + return 0; } From a2caf289c96b971c205ae82bbdd1c598e931c1a2 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Tue, 5 Feb 2013 10:49:17 +0100 Subject: [PATCH 056/121] nutconf: bugfixes + HTML manpage --- docs/man/Makefile.am | 2 +- tools/nutconf/nutconf.cpp | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/man/Makefile.am b/docs/man/Makefile.am index a1a78c5239..70ac9dbd7d 100644 --- a/docs/man/Makefile.am +++ b/docs/man/Makefile.am @@ -80,7 +80,7 @@ MAN_TOOL_PAGES = nut-scanner.8 nut-recorder.8 nutconf.8 man8_MANS += $(MAN_TOOL_PAGES) -HTML_TOOL_MANS = nut-scanner.html nut-recorder.html +HTML_TOOL_MANS = nut-scanner.html nut-recorder.html nutconf.html # CGI (--with-cgi) related manpages SRC_CGI_PAGES = \ diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index bbf26126d2..ccee52d682 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -737,8 +737,13 @@ NutScanner::Device::options_t NutScanner::Device::createOptions(nutscan_device_t // Create options nutscan_options_t * opt = &dev->opt; - for (; NULL != opt; opt = opt->next) - options.insert(options_t::value_type(opt->option, opt->value)); + for (; NULL != opt; opt = opt->next) { + assert(NULL != opt->option); + + options.insert( + options_t::value_type(opt->option, + NULL != opt->value ? opt->value : "")); + } return options; } @@ -746,8 +751,8 @@ NutScanner::Device::options_t NutScanner::Device::createOptions(nutscan_device_t NutScanner::Device::Device(nutscan_device_t * dev): type(nutscan_device_type_string(dev->type)), - driver(dev->driver), - port(dev->port), + driver(NULL != dev->driver ? dev->driver : ""), + port(NULL != dev->port ? dev->port : ""), options(createOptions(dev)) {} From 78cb35cef057d4b15ef4288626a61965708b8149 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Tue, 5 Feb 2013 11:19:31 +0100 Subject: [PATCH 057/121] nutconf: device with no options bugfix --- tools/nutconf/nutconf.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index ccee52d682..75153a4821 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -737,6 +737,15 @@ NutScanner::Device::options_t NutScanner::Device::createOptions(nutscan_device_t // Create options nutscan_options_t * opt = &dev->opt; + assert(NULL != opt); + + // TBD: Why does the device always have the 1st option? + // Why isn't it just a pointer? + // The fact that the head of the option list isn't dynamic + // like the other items unnecessarily complicates things... :-( + if (NULL == opt->option) + return options; + for (; NULL != opt; opt = opt->next) { assert(NULL != opt->option); @@ -765,7 +774,7 @@ NutScanner::devices_t NutScanner::dev2list(nutscan_device_t * dev_list) { for (; dev != NULL; dev = dev->prev) list.push_back(Device(dev)); - nutscan_free_device(dev); + nutscan_free_device(dev_list); return list; } From 7be963446f9ae9e913075843d62dc0a968e77101 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Tue, 5 Feb 2013 12:04:13 +0100 Subject: [PATCH 058/121] nutconf: proper device config dump --- tools/nutconf/nutconf.cpp | 53 ++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 75153a4821..9b8da0ccf5 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -2290,6 +2290,8 @@ void setUsers( void printDevicesInfo(const NutScanner::devices_t & devices, unsigned int verbose = 0) { NutScanner::devices_t::const_iterator dev_iter = devices.begin(); + nut::GenericConfiguration devices_conf; + unsigned int dev_no = 1; for (; dev_iter != devices.end(); ++dev_iter, ++dev_no) { @@ -2302,26 +2304,53 @@ void printDevicesInfo(const NutScanner::devices_t & devices, unsigned int verbos << dev.driver << ' ' << dev.port << std::endl; - // Print full info + // Assemble full info else { - std::cout - << "[device_type_" << dev.type - << "_no_" << dev_no << ']' << std::endl - << "\tdriver = " << dev.driver << std::endl - << "\tport = " << dev.port << std::endl; + std::stringstream name; + + name << "device_type_" << dev.type << "_no_" << dev_no; + + nut::GenericConfigSection & device_conf = devices_conf[name.str()]; + + device_conf.name = name.str(); + + // Set driver + nut::GenericConfigSectionEntry & driver = device_conf["driver"]; + + driver.name = "driver"; + driver.values.push_back(dev.driver); + + // Set port + nut::GenericConfigSectionEntry & port = device_conf["port"]; + port.name = "port"; + port.values.push_back(dev.port); + + // Set options NutScanner::Device::options_t::const_iterator opt = dev.options.begin(); - for (; opt != dev.options.end(); ++opt) - std::cout - << '\t' << opt->first - << " = " << opt->second - << std::endl; + for (; opt != dev.options.end(); ++opt) { + nut::GenericConfigSectionEntry & option = device_conf[opt->first]; - std::cout << std::endl; + option.name = opt->first; + option.values.push_back(opt->second); + } } } + + // Print full info + if (0 != verbose) { + nut::NutMemory info; + + devices_conf.writeTo(info); + + std::string info_str; + + assert(nut::NutStream::NUTS_OK == info.getString(info_str)); + + std::cout << info_str; + } } From 04d5903add8c1327870df0e06bc360cd3d5c701b Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Tue, 5 Feb 2013 16:58:42 +0100 Subject: [PATCH 059/121] nutconf: another round of bugfixes --{get|set}-mode options have replaced --mode option --set-mode option actually sets the mode in nut.conf libnutscan provides devices list rewinded (i.e. handled by the head) libnutscan options fixed (so that the 1st is dynamic, too) --- common/nutconf.cpp | 4 + common/nutwriter.cpp | 8 ++ docs/man/nutconf.txt | 5 +- include/nutconf.h | 4 +- tools/nut-scanner/nutscan-device.c | 63 +++++++------ tools/nut-scanner/nutscan-device.h | 11 ++- tools/nut-scanner/nutscan-display.c | 13 +-- tools/nut-scanner/scan_avahi.c | 2 +- tools/nut-scanner/scan_eaton_serial.c | 2 +- tools/nut-scanner/scan_ipmi.c | 2 +- tools/nut-scanner/scan_nut.c | 2 +- tools/nut-scanner/scan_snmp.c | 2 +- tools/nut-scanner/scan_usb.c | 2 +- tools/nut-scanner/scan_xml_http.c | 2 +- tools/nutconf/nutconf.cpp | 127 +++++++++++++++++++++----- 15 files changed, 178 insertions(+), 71 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index ba4377f68c..2166ea1624 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -1206,6 +1206,10 @@ NutConfiguration::NutMode NutConfiguration::NutModeFromString(const std::string& return MODE_NETSERVER; else if(str == "netclient") return MODE_NETCLIENT; + else if(str == "controlled") + return MODE_CONTROLLED; + else if(str == "manual") + return MODE_MANUAL; else return MODE_UNKNOWN; } diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index 98b8f796de..3a0f540957 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -160,6 +160,14 @@ NutWriter::status_t NutConfConfigWriter::writeConfig(const NutConfiguration & co case NutConfiguration::MODE_NETCLIENT: mode_str = "netclient"; break; + + case NutConfiguration::MODE_CONTROLLED: + mode_str = "controlled"; + break; + + case NutConfiguration::MODE_MANUAL: + mode_str = "manual"; + break; } status = writeDirective("MODE=" + mode_str); diff --git a/docs/man/nutconf.txt b/docs/man/nutconf.txt index c891c2bbd4..f889fad575 100644 --- a/docs/man/nutconf.txt +++ b/docs/man/nutconf.txt @@ -42,7 +42,10 @@ System configuration directory shall be used. *--local* 'directory':: Sets alternative configuration directory. -*--mode* 'mode':: +*--get-mode*:: +Prints current NUT configuration mode + +*--set-mode* 'mode':: Sets NUT configuration mode. :: diff --git a/include/nutconf.h b/include/nutconf.h index 4e332ae6a4..7816d79293 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -687,7 +687,9 @@ class NutConfiguration: public Serialisable MODE_NONE = 0, MODE_STANDALONE, MODE_NETSERVER, - MODE_NETCLIENT + MODE_NETCLIENT, + MODE_CONTROLLED, + MODE_MANUAL, }; Settable mode; diff --git a/tools/nut-scanner/nutscan-device.c b/tools/nut-scanner/nutscan-device.c index 6fed0c9ca8..5cfe5fa6df 100644 --- a/tools/nut-scanner/nutscan-device.c +++ b/tools/nut-scanner/nutscan-device.c @@ -19,6 +19,7 @@ #include "nutscan-device.h" #include #include +#include const char * nutscan_device_type_strings[TYPE_END] = { "USB", @@ -46,7 +47,6 @@ nutscan_device_t * nutscan_new_device() static void deep_free_device(nutscan_device_t * device) { nutscan_options_t * current; - nutscan_options_t * old; if(device==NULL) { return; @@ -58,18 +58,10 @@ static void deep_free_device(nutscan_device_t * device) free(device->port); } - current = &device->opt; + while (device->opt != NULL) { + current = device->opt; + device->opt = current->next; - if(current->option != NULL) { - free(current->option); - } - - if(current->value != NULL) { - free(current->value); - } - - current = current->next; - while (current != NULL) { if(current->option != NULL) { free(current->option); } @@ -77,9 +69,8 @@ static void deep_free_device(nutscan_device_t * device) if(current->value != NULL) { free(current->value); } - old = current; - current = current->next; - free(old); + + free(current); }; if(device->prev) { @@ -107,34 +98,35 @@ void nutscan_free_device(nutscan_device_t * device) free(device); } -void nutscan_add_option_to_device(nutscan_device_t * device,char * option, char * value) +void nutscan_add_option_to_device(nutscan_device_t * device, char * option, char * value) { - nutscan_options_t * opt; + nutscan_options_t **opt; - opt = &(device->opt); /* search for last entry */ - if( opt->option != NULL ) { - while( opt->next != NULL ) { - opt = opt->next; - } + opt = &device->opt; - opt->next = malloc(sizeof(nutscan_options_t)); - opt = opt->next; - memset(opt,0,sizeof(nutscan_options_t)); - } + while (NULL != *opt) + opt = &(*opt)->next; + + *opt = (nutscan_options_t *)malloc(sizeof(nutscan_options_t)); + + // TBD: A gracefull way to propagate memory failure would be nice + assert(NULL != *opt); + + memset(*opt, 0, sizeof(nutscan_options_t)); if( option != NULL ) { - opt->option = strdup(option); + (*opt)->option = strdup(option); } else { - opt->option = NULL; + (*opt)->option = NULL; } if( value != NULL ) { - opt->value = strdup(value); + (*opt)->value = strdup(value); } else { - opt->value = NULL; + (*opt)->value = NULL; } } @@ -190,3 +182,14 @@ nutscan_device_t * nutscan_add_device_to_device(nutscan_device_t * first, nutsca return dev2; } + +nutscan_device_t * nutscan_rewind_device(nutscan_device_t * device) +{ + if (NULL == device) + return NULL; + + while (NULL != device->prev) + device = device->prev; + + return device; +} diff --git a/tools/nut-scanner/nutscan-device.h b/tools/nut-scanner/nutscan-device.h index be7e3c651b..446b019a8a 100644 --- a/tools/nut-scanner/nutscan-device.h +++ b/tools/nut-scanner/nutscan-device.h @@ -60,7 +60,7 @@ typedef struct nutscan_device { nutscan_device_type_t type; char * driver; char * port; - nutscan_options_t opt; + nutscan_options_t * opt; struct nutscan_device * prev; struct nutscan_device * next; } nutscan_device_t; @@ -70,6 +70,15 @@ void nutscan_free_device(nutscan_device_t * device); void nutscan_add_option_to_device(nutscan_device_t * device,char * option, char * value); nutscan_device_t * nutscan_add_device_to_device(nutscan_device_t * first, nutscan_device_t * second); +/** + * \brief Rewind device list + * + * \param device Device list item + * + * \return Device list head + */ +nutscan_device_t * nutscan_rewind_device(nutscan_device_t * device); + #ifdef __cplusplus /* *INDENT-OFF* */ } diff --git a/tools/nut-scanner/nutscan-display.c b/tools/nut-scanner/nutscan-display.c index 07c28dbc14..411ed258aa 100644 --- a/tools/nut-scanner/nutscan-display.c +++ b/tools/nut-scanner/nutscan-display.c @@ -52,9 +52,9 @@ void nutscan_display_ups_conf(nutscan_device_t * device) nutdev_num, current_dev->driver, current_dev->port); - opt = &(current_dev->opt); + opt = current_dev->opt; - do { + while (NULL != opt) { if( opt->option != NULL ) { printf("\t%s",opt->option); if( opt->value != NULL ) { @@ -63,7 +63,7 @@ void nutscan_display_ups_conf(nutscan_device_t * device) printf("\n"); } opt = opt->next; - } while( opt != NULL ); + } nutdev_num++; @@ -93,9 +93,9 @@ void nutscan_display_parsable(nutscan_device_t * device) current_dev->driver, current_dev->port); - opt = &(current_dev->opt); + opt = current_dev->opt; - do { + while (NULL != opt) { if( opt->option != NULL ) { printf(",%s",opt->option); if( opt->value != NULL ) { @@ -103,7 +103,8 @@ void nutscan_display_parsable(nutscan_device_t * device) } } opt = opt->next; - } while( opt != NULL ); + } + printf("\n"); current_dev = current_dev->next; diff --git a/tools/nut-scanner/scan_avahi.c b/tools/nut-scanner/scan_avahi.c index 6e337241f0..198e1f223f 100644 --- a/tools/nut-scanner/scan_avahi.c +++ b/tools/nut-scanner/scan_avahi.c @@ -506,7 +506,7 @@ nutscan_device_t * nutscan_scan_avahi(long usec_timeout) if (simple_poll) (*nut_avahi_simple_poll_free)(simple_poll); - return dev_ret; + return nutscan_rewind_device(dev_ret); } #else /* WITH_AVAHI */ /* stub function */ diff --git a/tools/nut-scanner/scan_eaton_serial.c b/tools/nut-scanner/scan_eaton_serial.c index 303214aa9f..82fba6c6b7 100644 --- a/tools/nut-scanner/scan_eaton_serial.c +++ b/tools/nut-scanner/scan_eaton_serial.c @@ -435,5 +435,5 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range) i++; } free( serial_ports_list); - return dev_ret; + return nutscan_rewind_device(dev_ret); } diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c index 0288ad46b2..4da3dcd68f 100644 --- a/tools/nut-scanner/scan_ipmi.c +++ b/tools/nut-scanner/scan_ipmi.c @@ -594,7 +594,7 @@ nutscan_device_t * nutscan_scan_ipmi(const char * start_ip, const char * stop_ip }; } - return current_nut_dev; + return nutscan_rewind_device(current_nut_dev); } #else /* WITH_IPMI */ /* stub function */ diff --git a/tools/nut-scanner/scan_nut.c b/tools/nut-scanner/scan_nut.c index c1b16f206e..47d4323986 100644 --- a/tools/nut-scanner/scan_nut.c +++ b/tools/nut-scanner/scan_nut.c @@ -269,5 +269,5 @@ nutscan_device_t * nutscan_scan_nut(const char* startIP, const char* stopIP, con signal(SIGPIPE,SIG_DFL); } - return dev_ret; + return nutscan_rewind_device(dev_ret); } diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c index cba4c46084..0fcb9a6d8c 100644 --- a/tools/nut-scanner/scan_snmp.c +++ b/tools/nut-scanner/scan_snmp.c @@ -697,7 +697,7 @@ nutscan_device_t * nutscan_scan_snmp(const char * start_ip, const char * stop_ip free(thread_array); #endif - return dev_ret; + return nutscan_rewind_device(dev_ret); } #else /* WITH_SNMP */ nutscan_device_t * nutscan_scan_snmp(const char * start_ip, const char * stop_ip,long usec_timeout, nutscan_snmp_t * sec) diff --git a/tools/nut-scanner/scan_usb.c b/tools/nut-scanner/scan_usb.c index d6e1e4e1ca..b44b70a141 100644 --- a/tools/nut-scanner/scan_usb.c +++ b/tools/nut-scanner/scan_usb.c @@ -255,7 +255,7 @@ nutscan_device_t * nutscan_scan_usb() } } - return current_nut_dev; + return nutscan_rewind_device(current_nut_dev); } #else /* WITH_USB */ nutscan_device_t * nutscan_scan_usb() diff --git a/tools/nut-scanner/scan_xml_http.c b/tools/nut-scanner/scan_xml_http.c index d4bd22037c..ee713e4543 100644 --- a/tools/nut-scanner/scan_xml_http.c +++ b/tools/nut-scanner/scan_xml_http.c @@ -231,7 +231,7 @@ nutscan_device_t * nutscan_scan_xml_http(long usec_timeout) } - return current_nut_dev; + return nutscan_rewind_device(current_nut_dev); } #else /* WITH_NEON */ nutscan_device_t * nutscan_scan_xml_http(long usec_timeout) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 9b8da0ccf5..e531282323 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -43,7 +43,8 @@ const char * Usage::s_text[] = { " --is-configured Checks whether NUT is configured", " --local Sets configuration directory", " --system Sets configuration directory to " CONFPATH " (default)", -" --mode Sets NUT mode (see below)", +" --get-mode Gets NUT mode (see below)", +" --set-mode Sets NUT mode (see below)", " --set-monitor Configures one monitor (see below)", " All existing entries are removed; however, it may be", " specified multiple times to set multiple entries", @@ -554,7 +555,14 @@ class NutScanner { private: - static options_t createOptions(nutscan_device_t * dev); + /** + * \brief Create options + * + * \param opt libnutscan device options + * + * \return Device option list + */ + static options_t createOptions(nutscan_options_t * opt); /** Constructor */ Device(nutscan_device_t * dev); @@ -729,23 +737,10 @@ class NutScanner { NutScanner::InitFinal NutScanner::s_init_final; -NutScanner::Device::options_t NutScanner::Device::createOptions(nutscan_device_t * dev) { - assert(NULL != dev); - +NutScanner::Device::options_t NutScanner::Device::createOptions(nutscan_options_t * opt) { options_t options; // Create options - nutscan_options_t * opt = &dev->opt; - - assert(NULL != opt); - - // TBD: Why does the device always have the 1st option? - // Why isn't it just a pointer? - // The fact that the head of the option list isn't dynamic - // like the other items unnecessarily complicates things... :-( - if (NULL == opt->option) - return options; - for (; NULL != opt; opt = opt->next) { assert(NULL != opt->option); @@ -762,7 +757,7 @@ NutScanner::Device::Device(nutscan_device_t * dev): type(nutscan_device_type_string(dev->type)), driver(NULL != dev->driver ? dev->driver : ""), port(NULL != dev->port ? dev->port : ""), - options(createOptions(dev)) + options(createOptions(dev->opt)) {} @@ -771,7 +766,7 @@ NutScanner::devices_t NutScanner::dev2list(nutscan_device_t * dev_list) { nutscan_device_t * dev = dev_list; - for (; dev != NULL; dev = dev->prev) + for (; dev != NULL; dev = dev->next) list.push_back(Device(dev)); nutscan_free_device(dev_list); @@ -985,7 +980,10 @@ class NutConfOptions: public Options { /** --system */ bool system; - /** --mode argument */ + /** --get-mode */ + bool get_mode; + + /** --set-mode argument */ std::string mode; /** --{add|set}-monitor arguments (all the monitors) */ @@ -1158,6 +1156,7 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): autoconfigure(false), is_configured(false), system(false), + get_mode(false), set_monitor_cnt(0), add_monitor_cnt(0), set_listen_cnt(0), @@ -1234,17 +1233,23 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): else system = true; } - else if ("mode" == *opt) { + else if ("get-mode" == *opt) { + if (get_mode) + m_errors.push_back("--get-mode option specified more than once"); + else + get_mode = true; + } + else if ("set-mode" == *opt) { Arguments args; if (!mode.empty()) - m_errors.push_back("--mode option specified more than once"); + m_errors.push_back("--set-mode option specified more than once"); - else if (NutConfOptions::SETTER != optMode("mode", args)) - m_errors.push_back("--mode option requires an argument"); + else if (NutConfOptions::SETTER != optMode(*opt, args)) + m_errors.push_back("--set-mode option requires an argument"); else if (args.size() > 1) - m_errors.push_back("Only one argument allowed for the --mode option"); + m_errors.push_back("Only one argument allowed for the --set-mode option"); else if (args.size() == 1 && !checkMode(args.front())) m_errors.push_back("Unknown NUT mode: \"" + args.front() + "\""); @@ -1912,6 +1917,63 @@ nut::UpsmonConfiguration::Monitor monitor( } +/** + * \brief NUT mode getter + * + * \param etc Configuration directory + * + * \return NUT mode (as string) + */ +std::string getMode(const std::string & etc) { + std::string nut_conf_file(etc + "/nut.conf"); + + nut::NutConfiguration nut_conf; + + // Source previous configuration + source(&nut_conf, nut_conf_file); + + nut::NutConfiguration::NutMode mode = nut_conf.mode; + + switch (mode) { + case nut::NutConfiguration::MODE_UNKNOWN: return "unknown"; + case nut::NutConfiguration::MODE_NONE: return "none"; + case nut::NutConfiguration::MODE_STANDALONE: return "standalone"; + case nut::NutConfiguration::MODE_NETSERVER: return "netserver"; + case nut::NutConfiguration::MODE_NETCLIENT: return "netclient"; + case nut::NutConfiguration::MODE_CONTROLLED: return "controlled"; + case nut::NutConfiguration::MODE_MANUAL: return "manual"; + } + + std::stringstream e; + + e << "INTERNAL ERROR: Unknown NUT mode: " << mode; + + throw std::logic_error(e.str()); +} + + +/** + * \brief NUT mode setter + * + * \param mode Mode + * \param etc Configuration directory + */ +void setMode(const std::string & mode, const std::string & etc) { + std::string nut_conf_file(etc + "/nut.conf"); + + nut::NutConfiguration nut_conf; + + // Source previous configuration (if any) + source(&nut_conf, nut_conf_file); + + // Set mode + nut_conf.mode = nut::NutConfiguration::NutModeFromString(mode); + + // Store configuration + store(&nut_conf, nut_conf_file); +} + + /** * \brief Set monitors in upsmon.conf * @@ -2308,7 +2370,12 @@ void printDevicesInfo(const NutScanner::devices_t & devices, unsigned int verbos else { std::stringstream name; - name << "device_type_" << dev.type << "_no_" << dev_no; + name << "device_type_" << dev.type << "_no_"; + + name.width(3); + name.fill('0'); + + name << dev_no; nut::GenericConfigSection & device_conf = devices_conf[name.str()]; @@ -2786,6 +2853,16 @@ int mainx(int argc, char * const argv[]) { ::exit(is_configured ? 0 : 1); } + // --get-mode + if (options.get_mode) { + std::cout << getMode(etc) << std::endl; + } + + // --set-mode + if (!options.mode.empty()) { + setMode(options.mode, etc); + } + // Monitors were set if (!options.monitors.empty()) { std::list monitors; From 0320875ce00f35baa92b0c98da394b360c88a37a Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Thu, 7 Feb 2013 14:50:07 +0100 Subject: [PATCH 060/121] libnutscan: serial device type string undefined --- tools/nut-scanner/nutscan-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/nut-scanner/nutscan-device.c b/tools/nut-scanner/nutscan-device.c index 5cfe5fa6df..fd6c08fee0 100644 --- a/tools/nut-scanner/nutscan-device.c +++ b/tools/nut-scanner/nutscan-device.c @@ -28,6 +28,7 @@ const char * nutscan_device_type_strings[TYPE_END] = { "NUT", "IPMI", "Avahi", + "serial", }; nutscan_device_t * nutscan_new_device() From 9362bada53758181f9bfcc33f82b1760df765e02 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Fri, 8 Feb 2013 13:12:03 +0100 Subject: [PATCH 061/121] libnutscan: dev. type strings array size fixed --- tools/nut-scanner/nutscan-device.c | 2 +- tools/nut-scanner/nutscan-device.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/nut-scanner/nutscan-device.c b/tools/nut-scanner/nutscan-device.c index fd6c08fee0..f815842ef2 100644 --- a/tools/nut-scanner/nutscan-device.c +++ b/tools/nut-scanner/nutscan-device.c @@ -21,7 +21,7 @@ #include #include -const char * nutscan_device_type_strings[TYPE_END] = { +const char * nutscan_device_type_strings[TYPE_END - 1] = { "USB", "SNMP", "XML", diff --git a/tools/nut-scanner/nutscan-device.h b/tools/nut-scanner/nutscan-device.h index 446b019a8a..8960410b55 100644 --- a/tools/nut-scanner/nutscan-device.h +++ b/tools/nut-scanner/nutscan-device.h @@ -48,7 +48,7 @@ typedef enum nutscan_device_type { } nutscan_device_type_t; /** Device type -> string mapping */ -extern const char * nutscan_device_type_strings[TYPE_END]; +extern const char * nutscan_device_type_strings[TYPE_END - 1]; typedef struct nutscan_options { char * option; From 1be6bd4a7e8391ad786358df15c2393cee9d7e26 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Fri, 8 Feb 2013 15:23:56 +0100 Subject: [PATCH 062/121] nutconf: --scan-serial port list bugfix Piggybacking: added device type check to skip invalid devices returned from libnutscan --- tools/nutconf/nutconf.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index e531282323..60b90d4c77 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -766,8 +766,15 @@ NutScanner::devices_t NutScanner::dev2list(nutscan_device_t * dev_list) { nutscan_device_t * dev = dev_list; - for (; dev != NULL; dev = dev->next) + for (; dev != NULL; dev = dev->next) { + // Skip devices of type NONE + // TBD: This happens with the serial scan on an invalid device + // Should be fixed in libnutscan I think + if (TYPE_NONE == dev->type) + continue; + list.push_back(Device(dev)); + } nutscan_free_device(dev_list); @@ -859,8 +866,14 @@ NutScanner::devices_t NutScanner::devicesEatonSerial(const std::list::const_iterator port = ports.begin(); - for (; port != ports.end(); ++port) { + while (port != ports.end()) { port_list += *port; + + ++port; + + if (port == ports.end()) + break; + port_list += ' '; } From 6104c9a693e3f64cbb25fc46476a2c0761c49ac4 Mon Sep 17 00:00:00 2001 From: Charles Lepple Date: Sun, 10 Mar 2013 10:20:41 -0400 Subject: [PATCH 063/121] tests: Fix build without libcppunit --- tests/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index e96cc4d411..5b77bbef86 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -17,6 +17,6 @@ cppunittest_SOURCES = $(CPPUNITTESTSRC) cpputest.cpp else !HAVE_CPPUNIT -EXTRA_DIST = example.cpp nutconf.cpp cpputest.cpp nutstream_ut.cpp nutconf_ut.cpp mnutipc_ut.cpp +EXTRA_DIST = example.cpp nutconf.cpp cpputest.cpp nutstream_ut.cpp nutconf_ut.cpp nutipc_ut.cpp endif !HAVE_CPPUNIT From 417fbfc10bfd093f3bfe8c753916f7ad47f74444 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Mon, 18 Mar 2013 13:16:28 +0100 Subject: [PATCH 064/121] nutconf: reintroduction of funcs lost in trans. --set-notifycmd, --set-minsupplies & --set-powerdownflag options reintroduced after being lost in recent multi-step transition to git --- tools/nutconf/nutconf.cpp | 152 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 60b90d4c77..d572637cf9 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -65,7 +65,10 @@ const char * Usage::s_text[] = { " Existing flags are replaced", " --add-notifyflags + Same as --set-notifyflags, but keeps existing flags", " --set-notifymsg Configures notification message for the type", +" --set-notifycmd Configures notification command", " --set-shutdowncmd Configures shutdown command", +" --set-minsupplies Configures minimum of required power supplies", +" --set-powerdownflag Configures powerdown flag file", " --set-user Configures one user (see below)", " All existing users are removed; however, it may be", " specified multiple times to set multiple users", @@ -1041,9 +1044,18 @@ class NutConfOptions: public Options { /** Set notify message options count */ size_t set_notify_msg_cnt; + /** Notify command */ + std::string notify_cmd; + /** Shutdown command */ std::string shutdown_cmd; + /** Min. supplies */ + std::string min_supplies; + + /** Powerdown flag */ + std::string powerdown_flag; + /** Users specifications */ UserSpecs users; @@ -1395,6 +1407,23 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): ++set_notify_msg_cnt; } + else if ("set-notifycmd" == *opt) { + Arguments args; + + if (!notify_cmd.empty()) + m_errors.push_back("--set-notifycmd option specified more than once"); + + else if (NutConfOptions::SETTER != optMode("set-notifycmd", args)) + m_errors.push_back("--set-notifycmd option requires an argument"); + + else if (args.size() > 1) { + m_errors.push_back("Too many arguments for the --set-notifycmd option"); + m_errors.push_back(" (perhaps you need to quote the command?)"); + } + + else + notify_cmd = args.front(); + } else if ("set-shutdowncmd" == *opt) { Arguments args; @@ -1412,6 +1441,38 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): else shutdown_cmd = args.front(); } + else if ("set-minsupplies" == *opt) { + Arguments args; + + if (!min_supplies.empty()) + m_errors.push_back("--set-minsupplies option specified more than once"); + + else if (NutConfOptions::SETTER != optMode("set-minsupplies", args)) + m_errors.push_back("--set-minsupplies option requires an argument"); + + else if (args.size() > 1) { + m_errors.push_back("Too many arguments for the --set-minsupplies option"); + } + + else + min_supplies = args.front(); + } + else if ("set-powerdownflag" == *opt) { + Arguments args; + + if (!powerdown_flag.empty()) + m_errors.push_back("--set-powerdownflag option specified more than once"); + + else if (NutConfOptions::SETTER != optMode("set-powerdownflag", args)) + m_errors.push_back("--set-powerdownflag option requires an argument"); + + else if (args.size() > 1) { + m_errors.push_back("Too many arguments for the --set-powerdownflag option"); + } + + else + powerdown_flag = args.front(); + } else if ("set-user" == *opt || "add-user" == *opt) { size_t * cnt = ('s' == (*opt)[0] ? &set_user_cnt : &add_user_cnt); @@ -2243,6 +2304,28 @@ void setNotifyMsgs( } +/** + * \brief Set notify command in upsmon.conf + * + * \param cmd otify command + * \param etc Configuration directory + */ +void setNotifyCmd(const std::string & cmd, const std::string & etc) +{ + std::string upsmon_conf_file(etc + "/upsmon.conf"); + + nut::UpsmonConfiguration upsmon_conf; + + // Source previous configuration (if any) + source(&upsmon_conf, upsmon_conf_file); + + upsmon_conf.notifyCmd = cmd; + + // Store configuration + store(&upsmon_conf, upsmon_conf_file); +} + + /** * \brief Set shutdown command in upsmon.conf * @@ -2265,6 +2348,60 @@ void setShutdownCmd(const std::string & cmd, const std::string & etc) } +/** + * \brief Set minimum of power supplies in upsmon.conf + * + * \param min_supplies Minimum of power supplies + * \param etc Configuration directory + */ +void setMinSupplies(const std::string & min_supplies, const std::string & etc) { + std::string upsmon_conf_file(etc + "/upsmon.conf"); + + nut::UpsmonConfiguration upsmon_conf; + + // Source previous configuration (if any) + source(&upsmon_conf, upsmon_conf_file); + + unsigned int min; + + std::stringstream ss(min_supplies); + + if ((ss >> min).fail()) { + std::cerr + << "Error: invalid min. power supplies specification: \"" + << min_supplies << '"' << std::endl; + + ::exit(1); + } + + upsmon_conf.minSupplies = min; + + // Store configuration + store(&upsmon_conf, upsmon_conf_file); +} + + +/** + * \brief Set powerdown flag file in upsmon.conf + * + * \param powerdown_flag Powerdown flag file + * \param etc Configuration directory + */ +void setPowerdownFlag(const std::string & powerdown_flag, const std::string & etc) { + std::string upsmon_conf_file(etc + "/upsmon.conf"); + + nut::UpsmonConfiguration upsmon_conf; + + // Source previous configuration (if any) + source(&upsmon_conf, upsmon_conf_file); + + upsmon_conf.powerDownFlag = powerdown_flag; + + // Store configuration + store(&upsmon_conf, upsmon_conf_file); +} + + /** * \brief Set users in upsd.users * @@ -2913,11 +3050,26 @@ int mainx(int argc, char * const argv[]) { setNotifyMsgs(options.notify_msgs, etc); } + // Notify command was set + if (!options.notify_cmd.empty()) { + setNotifyCmd(options.notify_cmd, etc); + } + // Shutdown command was set if (!options.shutdown_cmd.empty()) { setShutdownCmd(options.shutdown_cmd, etc); } + // Min. of power supplies was set + if (!options.min_supplies.empty()) { + setMinSupplies(options.min_supplies, etc); + } + + // Powerdown flag file was set + if (!options.powerdown_flag.empty()) { + setPowerdownFlag(options.powerdown_flag, etc); + } + // Users were set if (!options.users.empty()) { setUsers(options.users, etc, options.add_user_cnt > 0); From 345980b29c520799a3476715ec13c1c1bfd2f7c7 Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Fri, 29 Mar 2013 15:44:02 +0100 Subject: [PATCH 065/121] nutconf: --{add|set}-device: = support Added support for setting virtually any = pairs for devices by the above options. Now, the synopsis of the options argument lists is: []* (i.e. description is set as desc="blah blah blah") --- include/nutconf.h | 8 +++++++ tools/nutconf/nutconf.cpp | 45 ++++++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/include/nutconf.h b/include/nutconf.h index 7816d79293..9a11df4d53 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -791,6 +791,14 @@ class UpsConfiguration : public GenericConfiguration /** \} */ + /** Generic = getter */ + inline std::string getKey(const std::string & ups, const std::string & key) const { return getStr(ups, key); } + + /** Generic = setter */ + inline void setKey(const std::string & ups, const std::string & key, const std::string & val) { + setStr(ups, key, val); + } + /** UPS-specific configuration attributes getters and setters \{ */ inline std::string getDriver(const std::string & ups) const { return getStr(ups, "driver"); } inline std::string getDescription(const std::string & ups) const { return getStr(ups, "desc"); } diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index d572637cf9..19aa8f0f18 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -104,7 +104,7 @@ const char * Usage::s_text[] = { "Monitor is specified by the following sequence:", " [:] (\"master\"|\"slave\")", "UPS device is specified by the following sequence:", -" []", +" [=]*", "Notification types:", " ONLINE, ONBATT, LOWBATT, FSD, COMMOK, COMMBAD, SHUTDOWN, REPLBATT, NOCOMM, NOPARENT", "Notification flags:", @@ -910,10 +910,11 @@ class NutConfOptions: public Options { /** Device specification */ struct DeviceSpec { - std::string id; /**< Device ID */ - std::string driver; /**< Device driver */ - std::string port; /**< Device port */ - std::string desc; /**< Device description */ + /** Device settings map */ + typedef std::map Map; + + std::string id; /**< Device identifier */ + Map settings; /**< Device settings */ }; // end of struct DeviceSpec /** Notify flags specification */ @@ -1329,11 +1330,6 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): else if (args.size() < 3) m_errors.push_back("--" + *opt + " option requires at least 3 arguments"); - else if (args.size() > 4) { - m_errors.push_back("--" + *opt + " option takes at most 4 arguments"); - m_errors.push_back(" (perhaps you need to quote description?)"); - } - else { DeviceSpec dev; @@ -1341,12 +1337,23 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): assert(args.size() >= 3); - dev.id = *arg++; - dev.driver = *arg++; - dev.port = *arg++; + dev.id = *arg++; + + dev.settings["driver"] = *arg++; + dev.settings["port"] = *arg++; - if (arg != args.end()) - dev.desc = *arg; + for (; arg != args.end(); ++arg) { + size_t eq_pos = (*arg).find('='); + + if (std::string::npos == eq_pos) + m_errors.push_back("--" + *opt + + " option extra argument '" + + *arg + "' is illegal"); + + else + dev.settings[(*arg).substr(0, eq_pos)] = + (*arg).substr(eq_pos + 1); + } devices.push_back(dev); } @@ -2196,11 +2203,11 @@ void setDevices( for (; dev != devices.end(); ++dev) { const std::string & id = (*dev).id; - ups_conf.setDriver(id, (*dev).driver); - ups_conf.setPort(id, (*dev).port); + NutConfOptions::DeviceSpec::Map::const_iterator + setting = (*dev).settings.begin(); - if (!(*dev).desc.empty()) - ups_conf.setDescription(id, (*dev).desc); + for (; setting != (*dev).settings.end(); ++setting) + ups_conf.setKey(id, setting->first, setting->second); } // Store configuration From f6a29ec5f8aa1f5256f0d0c94a2f8ae30f1bb3dd Mon Sep 17 00:00:00 2001 From: Vaclav Krpec Date: Fri, 12 Apr 2013 09:47:34 +0200 Subject: [PATCH 066/121] nutconf man page update --- docs/man/nutconf.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/man/nutconf.txt b/docs/man/nutconf.txt index f889fad575..a81383643b 100644 --- a/docs/man/nutconf.txt +++ b/docs/man/nutconf.txt @@ -72,6 +72,7 @@ Note that such options may be specified multiple times for one run *--set-monitor* | *--add-monitor* '':: Sets/adds a NUT monitor. + :: Arguments: '' '[:]' '' '' '' '(\"master\"|\"slave\")' @@ -81,8 +82,14 @@ Sets/adds 'nutd' daemon listen address *--set-device* | *--add-device* '':: Sets/adds a device (typically a UPS). + :: Arguments: -'' '' '' '[]' +'' '' '' '[=]*' + + :: +The attribute/value pairs follow device configuration syntax. +Devices may have very different configuration attributes depending on the driver. +Exhaustive description of them is beyond this man page and may be found in NUT documentation. *--set-notifyflags* | *--add-notifyflags* '' '+':: Sets/adds notification flags for the notification type. From 0e19ab11455a0c359e66fb9b0f2f240ccae0d0e5 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 14 Jan 2022 14:49:17 +0100 Subject: [PATCH 067/121] Import NUT source changes for nutconf tool from 42ITy (initial set) --- common/Makefile.am | 4 ++-- common/nutwriter.cpp | 2 +- tests/Makefile.am | 5 +++-- tools/nutconf/Makefile.am | 4 +++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/common/Makefile.am b/common/Makefile.am index bdb251af81..11ffbe958c 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -1,7 +1,7 @@ # Network UPS Tools: common -AM_CFLAGS = -I$(top_srcdir)/include -AM_CXXFLAGS = -I$(top_srcdir)/include +AM_CFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include +AM_CXXFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include AM_LDFLAGS = -no-undefined EXTRA_DIST = diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index 3a0f540957..590cde54a2 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -562,7 +562,7 @@ static std::string encodeValue(const std::string & val) { for (size_t i = 0; i < val.size() && !quote; ++i) { char ch = val[i]; - quote = ' ' == ch || '=' == ch; + quote = ' ' == ch || '=' == ch || ':' == ch; } if (!quote) diff --git a/tests/Makefile.am b/tests/Makefile.am index ccf65898c0..9bbaab66a6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -96,7 +96,6 @@ $(top_builddir)/common/libcommon.la: dummy # List of src files for CppUnit tests CPPUNITTESTSRC = example.cpp nutclienttest.cpp CPPUNITTESTSRC += nutconf.cpp nutstream_ut.cpp nutconf_ut.cpp nutipc_ut.cpp - # The test driver which orchestrates running those tests above CPPUNITTESTERSRC = cpputest.cpp @@ -122,7 +121,9 @@ endif cppunittest_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) ###cppunittest_CXXFLAGS += -I$(top_srcdir)/include -DTOP_SRCDIR="\"$(top_srcdir)\"" cppunittest_LDFLAGS = $(CPPUNIT_LDFLAGS) $(CPPUNIT_LIBS) -cppunittest_LDADD = $(top_builddir)/clients/libnutclient.la $(top_builddir)/clients/libnutclientstub.la +cppunittest_LDADD = $(top_builddir)/clients/libnutclient.la +cppunittest_LDADD += $(top_builddir)/clients/libnutclientstub.la +cppunittest_LDADD += $(top_builddir)/common/libnutconf.la cppunittest_SOURCES = $(CPPUNITTESTSRC) $(CPPUNITTESTERSRC) cppnit_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) diff --git a/tools/nutconf/Makefile.am b/tools/nutconf/Makefile.am index 681cd1c875..6e1ad58fd1 100644 --- a/tools/nutconf/Makefile.am +++ b/tools/nutconf/Makefile.am @@ -1,4 +1,6 @@ -noinst_PROGRAMS = nutconf +# Network UPS Tools: NUT configuration tool + +bin_PROGRAMS = nutconf nutconf_SOURCES = nutconf.cpp nutconf_CXXFLAGS = -I$(top_srcdir)/include nutconf_LDADD = ../../common/libcommon.la \ From f5da712b2413c2818cb5ee72c8bffdfffff79330 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 14 Jan 2022 21:20:09 +0100 Subject: [PATCH 068/121] tools/nutconf/Makefile.am: modernize --- tools/nutconf/Makefile.am | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tools/nutconf/Makefile.am b/tools/nutconf/Makefile.am index 6e1ad58fd1..116299492d 100644 --- a/tools/nutconf/Makefile.am +++ b/tools/nutconf/Makefile.am @@ -1,13 +1,25 @@ # Network UPS Tools: NUT configuration tool +all: $(bin_PROGRAMS) + bin_PROGRAMS = nutconf nutconf_SOURCES = nutconf.cpp -nutconf_CXXFLAGS = -I$(top_srcdir)/include -nutconf_LDADD = ../../common/libcommon.la \ - ../../common/libnutconf.la +nutconf_CXXFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include +nutconf_LDADD = $(top_builddir)/common/libcommon.la \ + $(top_builddir)/common/libnutconf.la # Add support for device scanning if WITH_LIBLTDL nutconf_CXXFLAGS += -DWITH_NUTSCANNER -I$(top_srcdir)/tools/nut-scanner -nutconf_LDADD += ../nut-scanner/libnutscan.la +nutconf_LDADD += $(top_builddir)/tools/nut-scanner/libnutscan.la endif + +# Make sure out-of-dir dependencies exist (especially when dev-building parts): +$(top_builddir)/common/libcommon.la \ +$(top_builddir)/common/libnutconf.la \ +$(top_builddir)/tools/nut-scanner/libnutscan.la: dummy + @cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) + +dummy: + +MAINTAINERCLEANFILES = Makefile.in .dirstamp From 49702270da3e8170617d1fbea90617345dc7caf2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 14 Jan 2022 21:15:40 +0100 Subject: [PATCH 069/121] tools/nutconf/nutconf.cpp: add (C) header --- tools/nutconf/nutconf.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 19aa8f0f18..bdae2672f7 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -1,3 +1,27 @@ +/* + * Copyright (C) 2013 - EATON + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*! \file nutscan-display.c + \brief format and display scanned devices + \author Frederic Bohe + \author Vaclav Krpec +*/ + #include "config.h" #include "nutconf.h" #include "nutstream.hpp" From 3a722d615363b043d513eb74fce22ac52c08e16e Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 14 Jan 2022 21:15:20 +0100 Subject: [PATCH 070/121] Add tools/nutconf/.gitignore --- tools/nutconf/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tools/nutconf/.gitignore diff --git a/tools/nutconf/.gitignore b/tools/nutconf/.gitignore new file mode 100644 index 0000000000..95548aa108 --- /dev/null +++ b/tools/nutconf/.gitignore @@ -0,0 +1,2 @@ +nutconf + From 78535658f7da48725a4e720d9fe048afed3bcd16 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 14 Jan 2022 22:02:59 +0100 Subject: [PATCH 071/121] tools/nutconf/nutconf.cpp: adjust to changed API for nutscan_scan_xml_http() => nutscan_scan_xml_http_range() --- tools/nutconf/nutconf.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index bdae2672f7..afe5416914 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -692,14 +692,23 @@ class NutScanner { } /** - * \brief Scan for XML/HTTP devices + * \brief Scan for XML/HTTP devices (broadcast) * * \param us_timeout Scan timeout * * \return Device list */ inline static devices_t devicesXMLHTTP(long us_timeout) { - nutscan_device_t * dev = nutscan_scan_xml_http(us_timeout); + nutscan_xml_t xml_sec; + nutscan_device_t * dev; + + memset(&xml_sec, 0, sizeof(xml_sec)); + /* Set the default values for XML HTTP (run_xml()) */ + xml_sec.port_http = 80; + xml_sec.port_udp = 4679; + xml_sec.usec_timeout = us_timeout; + xml_sec.peername = NULL; + dev = nutscan_scan_xml_http_range(NULL, NULL, us_timeout, &xml_sec); return dev2list(dev); } From f30fbb31496aed2690cd6aed0efa8d9574b32404 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 14 Jan 2022 22:24:07 +0100 Subject: [PATCH 072/121] Spellcheck manpage for nutconf tool --- docs/man/nutconf.txt | 10 +++++----- docs/nut.dict | 12 +++++++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/man/nutconf.txt b/docs/man/nutconf.txt index a81383643b..2485f94aaa 100644 --- a/docs/man/nutconf.txt +++ b/docs/man/nutconf.txt @@ -77,7 +77,7 @@ Arguments: '' '[:]' '' '' '' '(\"master\"|\"slave\")' *--set-listen* | *--add-listen* '
' '[]':: -Sets/adds 'nutd' daemon listen address +Sets/adds 'upsd' daemon listen address *--set-device* | *--add-device* '':: Sets/adds a device (typically a UPS). @@ -112,7 +112,7 @@ Notification types are: Notification flags: - 'SYSLOG' (use syslogd to log the notification) -- 'WALL' (push a message to usres' terminals) +- 'WALL' (push a message to users' terminals) - 'EXEC' (execute a command) - 'IGNORE' (don't act) @@ -130,10 +130,10 @@ Arguments: - '' (specifies user name). For 'upsmon' user, it has a special form of -'upsmon=(master|slave)' which specifies the moniutoring mode. +'upsmon=(master|slave)' which specifies the monitoring mode. - 'password=' sets password for the user - 'actions=' sets actions ('SET', 'FSD' are supported) -- 'instcmds=' sets instan commands allowed for the user +- 'instcmds=' sets instant commands allowed for the user (may be used multiple times) SCANNING OPTIONS @@ -156,7 +156,7 @@ Known attributes are: - 'timeout' device scan timeout - 'community' SNMP community (default: *public*) - 'sec-level' security level (SNMPv3); one of *noAuthNoPriv* *authNoPriv*, *authPriv* -- 'sec-name' security name (NMSPv3); mandatory companion of *sec-level* +- 'sec-name' security name (SNMPv3); mandatory companion of *sec-level* - 'auth-password' authentication password (SNMPv3); mandatory for *authNoPriv* and *authPriv* - 'priv-password' privacy password (SNMPv3); mandatory for *authPriv* - 'auth-protocol' authentication protocol (SNMPv3): *MD5* or *SHA*, *MD5* is the default diff --git a/docs/nut.dict b/docs/nut.dict index b36830c4f6..3f97a7bc64 100644 --- a/docs/nut.dict +++ b/docs/nut.dict @@ -1,4 +1,4 @@ -personal_ws-1.1 en 3258 utf-8 +personal_ws-1.1 en 3268 utf-8 AAC AAS ABI @@ -100,6 +100,7 @@ BCD BCHARGE BCM BD +BMC BNT BOH BP @@ -785,6 +786,7 @@ NQA NTP NUT's NUTClient +NUTCONF NUTSRC NUTServer NVA @@ -1038,6 +1040,7 @@ RETPCT REXX RK RMCARD +RMCPplus RMXL RNF RNG @@ -1590,6 +1593,7 @@ backported backports backupspro badpassword +bart baseurl bashrc batchable @@ -2493,7 +2497,9 @@ norating noro noscanlangid notAfter +notifyflags notifyme +notifymsg notifytype notransferoids novendor @@ -2509,6 +2515,7 @@ numlogins numq nutclient nutclientmem +nutconf nutdev nutdrv nutmon @@ -2658,6 +2665,7 @@ prereqs pretentiousVariableNamingSchemes prgshut printf +priv privPassword privProtocol problemMatcher @@ -2822,6 +2830,7 @@ sgs sha shm shutdownArguments +shutdowncmd shutdowndebounce shutdowndelay shutdownpolarity @@ -2953,6 +2962,7 @@ syscalls sysconfdir sysconfig syslog +syslogd systemctl systemd systemdshutdowndir From 231e4e27d441f7656d0384af6cdabd06d827305b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 15 Jan 2022 03:15:52 +0100 Subject: [PATCH 073/121] nutconf codebase: fix C++17 warnings - dynamic throw() declaration --- common/nutipc.cpp | 20 ++++++++-- common/nutstream.cpp | 17 +++++++-- include/nutconf.h | 5 ++- include/nutipc.hpp | 78 ++++++++++++++++++++++++++++++++------- include/nutstream.hpp | 76 +++++++++++++++++++++++++++++++------- tools/nutconf/nutconf.cpp | 23 ++++++++++-- 6 files changed, 181 insertions(+), 38 deletions(-) diff --git a/common/nutipc.cpp b/common/nutipc.cpp index becf53bfe5..0b75632193 100644 --- a/common/nutipc.cpp +++ b/common/nutipc.cpp @@ -132,8 +132,12 @@ Process::Executor::Executor(const std::string & command) { } -int Process::Executor::operator () () throw(std::runtime_error) { - const char ** args_c_str = new const char *[m_args.size() + 2]; +int Process::Executor::operator () () +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif +{ + const char ** args_c_str = new const char *[m_args.size() + 2]; const char * bin_c_str = m_bin.c_str(); @@ -164,7 +168,11 @@ int Process::Executor::operator () () throw(std::runtime_error) { } -int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) throw(std::runtime_error) { +int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif +{ char * cmd_bytes = reinterpret_cast(cmd); do { @@ -182,7 +190,11 @@ int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) throw(std::runtime_erro } -int Signal::send(Signal::enum_t signame, pid_t pid) throw(std::logic_error) { +int Signal::send(Signal::enum_t signame, pid_t pid) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error) +#endif +{ int sig = (int)signame; int status = ::kill(pid, sig); diff --git a/common/nutstream.cpp b/common/nutstream.cpp index e326982818..c713c6e39c 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -208,7 +208,11 @@ NutFile::NutFile(const std::string & name, access_t mode): } -std::string NutFile::tmpName() throw(std::runtime_error) { +std::string NutFile::tmpName() +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif +{ char *tmp_name = ::tempnam(m_tmp_dir.c_str(), NULL); if (NULL == tmp_name) @@ -446,7 +450,11 @@ NutSocket::Address::Address( } -NutSocket::Address::Address(const std::vector & bytes, uint16_t port) throw(std::logic_error) { +NutSocket::Address::Address(const std::vector & bytes, uint16_t port) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error) +#endif +{ switch (bytes.size()) { case 4: init_ipv4(*this, bytes, port); @@ -609,7 +617,10 @@ bool NutSocket::accept( NutSocket & sock, const NutSocket & listen_sock, int & err_code, - std::string & err_msg) throw(std::logic_error) + std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error) +#endif { assert(-1 == sock.m_impl); diff --git a/include/nutconf.h b/include/nutconf.h index 9a11df4d53..e3feb8a727 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -558,7 +558,10 @@ class GenericConfiguration : public BaseConfiguration, public Serialisable * \return \c number casted to target type */ template - static T range_cast(long long int number, long long int min, long long int max) throw(std::range_error) + static T range_cast(long long int number, long long int min, long long int max) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::range_error) +#endif { if (number < min) { diff --git a/include/nutipc.hpp b/include/nutipc.hpp index b3fca5f588..29537f90de 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -98,7 +98,11 @@ class Process { * * \param main Child process main routine */ - Child(M main) throw(std::runtime_error); + Child(M main) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + ; /** Child PID */ inline pid_t getPID() const { return m_pid; } @@ -113,7 +117,11 @@ class Process { * * \return Child process exit code */ - int wait() throw(std::logic_error); + int wait() +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error) +#endif + ; /** * \brief Child exit code getter @@ -183,7 +191,11 @@ class Process { Executor(const std::string & command); /** Execution of the binary */ - int operator () () throw(std::runtime_error); + int operator () () +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + ; }; // end of class Executor @@ -253,7 +265,11 @@ class Process { template -Process::Child::Child(M main) throw(std::runtime_error): +Process::Child::Child(M main) +#if (defined __cplusplus) && (__cplusplus < 201700) +throw(std::runtime_error) +#endif + : m_pid(0), m_exited(false), m_exit_code(0) @@ -266,7 +282,11 @@ Process::Child::Child(M main) throw(std::runtime_error): template -int Process::Child::wait() throw(std::logic_error) { +int Process::Child::wait() +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error) +#endif +{ if (m_exited) return m_exit_code; @@ -439,7 +459,11 @@ class Signal { * * \param siglist List of signals that shall be handled by the thread */ - HandlerThread(const Signal::List & siglist) throw(std::logic_error, std::runtime_error); + HandlerThread(const Signal::List & siglist) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error, std::runtime_error) +#endif + ; /** * \brief Terminate the thread @@ -448,14 +472,22 @@ class Signal { * It blocks until the thread is joined. * Closes the communication pipe write end. */ - void quit() throw(std::runtime_error); + void quit() +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + ; /** * \brief Destructor * * Forces the signal handler thread termination (unless already down). */ - ~HandlerThread() throw(std::runtime_error); + ~HandlerThread() +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + ; }; // end of HandlerThread @@ -471,7 +503,11 @@ class Signal { * \retval EPERM if the process doesn't have permission to send the signal * \retval ESRCH if the process (group) identified doesn't exist */ - static int send(enum_t signame, pid_t pid) throw(std::logic_error); + static int send(enum_t signame, pid_t pid) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error) +#endif + ; /** * \brief Send signal to a process identified via PID file @@ -591,7 +627,11 @@ void * Signal::HandlerThread::main(void * comm_pipe_read_end) { * \retval 0 on success * \retval errno on error */ -int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) throw(std::runtime_error); +int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + ; template @@ -610,7 +650,11 @@ void Signal::HandlerThread::signalNotifier(int signal) { template -Signal::HandlerThread::HandlerThread(const Signal::List & siglist) throw(std::logic_error, std::runtime_error) { +Signal::HandlerThread::HandlerThread(const Signal::List & siglist) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error, std::runtime_error) +#endif +{ // At most one instance per process allowed if (-1 != s_comm_pipe[1]) throw std::logic_error( @@ -665,7 +709,11 @@ Signal::HandlerThread::HandlerThread(const Signal::List & siglist) throw(std: template -void Signal::HandlerThread::quit() throw(std::runtime_error) { +void Signal::HandlerThread::quit() +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif +{ static int quit = (int)Signal::HandlerThread::QUIT; sigPipeWriteCmd(s_comm_pipe[1], &quit, sizeof(quit)); @@ -693,7 +741,11 @@ void Signal::HandlerThread::quit() throw(std::runtime_error) { template -Signal::HandlerThread::~HandlerThread() throw(std::runtime_error) { +Signal::HandlerThread::~HandlerThread() +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif +{ // Stop the thread unless already stopped if (-1 != s_comm_pipe[1]) quit(); diff --git a/include/nutstream.hpp b/include/nutstream.hpp index c2d5f5db46..0b1eb06d3c 100644 --- a/include/nutstream.hpp +++ b/include/nutstream.hpp @@ -229,7 +229,11 @@ class NutFile: public NutStream { * * \return Temporary file name */ - std::string tmpName() throw(std::runtime_error); + std::string tmpName() +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + ; public: @@ -289,7 +293,11 @@ class NutFile: public NutStream { * \retval true iff the file exists * \retval false otherwise */ - inline bool existsx() const throw(std::runtime_error) { + inline bool existsx() const +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + { int ec; std::string em; @@ -340,7 +348,11 @@ class NutFile: public NutStream { * \retval true if open succeeded * \retval false if open failed */ - inline void openx(access_t mode = READ_ONLY) throw(std::runtime_error) { + inline void openx(access_t mode = READ_ONLY) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + { int ec; std::string em; @@ -378,7 +390,11 @@ class NutFile: public NutStream { } /** Close file (or throw exception) */ - inline void closex() throw(std::runtime_error) { + inline void closex() +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + { int ec; std::string em; @@ -416,7 +432,11 @@ class NutFile: public NutStream { } /** Remove file (or throw exception) */ - inline void removex() throw(std::runtime_error) { + inline void removex() +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + { int ec; std::string em; @@ -606,7 +626,11 @@ class NutSocket: public NutStream { * \param bytes 4 or 16 address bytes (MSB is at index 0) * \param port Port number */ - Address(const std::vector & bytes, uint16_t port) throw(std::logic_error); + Address(const std::vector & bytes, uint16_t port) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error) +#endif + ; /** * \brief Copy constructor @@ -663,7 +687,11 @@ class NutSocket: public NutStream { NutSocket & sock, const NutSocket & listen_sock, int & err_code, - std::string & err_msg) throw(std::logic_error); + std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error) +#endif + ; /** * \brief Accept client connection on a listen socket @@ -676,7 +704,10 @@ class NutSocket: public NutStream { */ inline static bool accept( NutSocket & sock, - const NutSocket & listen_sock) throw(std::logic_error) + const NutSocket & listen_sock) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error) +#endif { int ec; std::string em; @@ -692,7 +723,10 @@ class NutSocket: public NutStream { */ inline static void acceptx( NutSocket & sock, - const NutSocket & listen_sock) throw(std::logic_error, std::runtime_error) + const NutSocket & listen_sock) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error, std::runtime_error) +#endif { int ec; std::string em; @@ -795,7 +829,11 @@ class NutSocket: public NutStream { * * \param addr Socket address */ - inline void bindx(const Address & addr) throw(std::runtime_error) { + inline void bindx(const Address & addr) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + { int ec; std::string em; @@ -842,7 +880,11 @@ class NutSocket: public NutStream { * * \param[in] backlog Limit of pending connections */ - inline void listenx(int backlog) throw(std::runtime_error) { + inline void listenx(int backlog) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + { int ec; std::string em; @@ -887,7 +929,11 @@ class NutSocket: public NutStream { * * \param[in] addr Remote address */ - inline void connectx(const Address & addr) throw(std::runtime_error) { + inline void connectx(const Address & addr) +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + { int ec; std::string em; @@ -925,7 +971,11 @@ class NutSocket: public NutStream { } /** Close socket (or throw exception) */ - inline void closex() throw(std::runtime_error) { + inline void closex() +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::runtime_error) +#endif + { int ec; std::string em; diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index afe5416914..9c21a421e5 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -1135,7 +1135,11 @@ class NutConfOptions: public Options { * BEWARE: throws an exception if options are valid. * Check that using the \ref valid flag. */ - void reportInvalid() const throw(std::logic_error); + void reportInvalid() const +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error) +#endif + ; /** * \brief Get NUT mode @@ -1171,7 +1175,11 @@ class NutConfOptions: public Options { std::string & user, std::string & passwd, std::string & mode, - size_t which = 0) const throw(std::range_error); + size_t which = 0) const +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::range_error) +#endif + ; private: @@ -1668,7 +1676,11 @@ NutConfOptions::~NutConfOptions() { } -void NutConfOptions::reportInvalid() const throw(std::logic_error) { +void NutConfOptions::reportInvalid() const +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::logic_error) +#endif +{ if (valid) throw std::logic_error("No invalid options to report"); @@ -1866,7 +1878,10 @@ void NutConfOptions::getMonitor( std::string & user, std::string & passwd, std::string & mode, - size_t which) const throw(std::range_error) + size_t which) const +#if (defined __cplusplus) && (__cplusplus < 201700) + throw(std::range_error) +#endif { if (which >= monitors.size() / 6) throw std::range_error("INTERNAL ERROR: monitors index overflow"); From 1593273f8369ea14a0cc0a1b3e53784f3e75e905 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 15 Jan 2022 03:36:32 +0100 Subject: [PATCH 074/121] nutconf codebase: fix C++17 warnings - equality operators should return *this --- include/nutconf.h | 2 +- tools/nutconf/nutconf.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/nutconf.h b/include/nutconf.h index e3feb8a727..b79b11c11b 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -69,7 +69,7 @@ class Settable const Type& operator *()const{return _value;} Type& operator *(){return _value;} - Settable& operator=(const Type& val){_value = val; _set = true;} + Settable& operator=(const Type& val){_value = val; _set = true; return *this;} bool operator==(const Settable& val)const { diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 9c21a421e5..8f2feb4ef5 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -1754,6 +1754,8 @@ class autodelete_ptr { cleanup(); m_impl = ptr; + + return *this; } /** Pointer accessor */ From f92941cf9dfe5c6615f1ed8c1fe7e2edf4cab185 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 15 Jan 2022 11:34:44 +0100 Subject: [PATCH 075/121] tools/nutconf/Makefile.am, tests/Makefile.am, configure.ac: limit the impact of nutconf codebase quality by default --- common/Makefile.am | 8 +++++++- configure.ac | 13 +++++++++++++ tests/Makefile.am | 29 ++++++++++++++++++----------- tools/nutconf/Makefile.am | 10 +++++++++- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/common/Makefile.am b/common/Makefile.am index 11ffbe958c..81cae3fbb8 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -5,7 +5,13 @@ AM_CXXFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include AM_LDFLAGS = -no-undefined EXTRA_DIST = -noinst_LTLIBRARIES = libparseconf.la libcommon.la libcommonclient.la libnutconf.la +noinst_LTLIBRARIES = libparseconf.la libcommon.la libcommonclient.la +if WITH_NUTCONF +# We define the recipe below in any case, but only activate it by default +# if the build configuration tells us to: +noinst_LTLIBRARIES += libnutconf.la +endif + libparseconf_la_SOURCES = parseconf.c libnutconf_la_SOURCES = nutconf.cpp nutstream.cpp nutwriter.cpp nutipc.cpp diff --git a/configure.ac b/configure.ac index c0cd53a598..9c528d95d4 100644 --- a/configure.ac +++ b/configure.ac @@ -1577,6 +1577,12 @@ dnl they are listed near the top by "./configure --help"; however, dnl note that options with further investigation methods are listed dnl a bit below to be grouped with their additional with/enable help. +dnl While the contribution is being absorbed into the NUT codebase, +dnl we don't want the CI farm to build it by default and so block NUT +dnl packaging. This toggle may be removed or switched to "yes" later. +dnl Until then, also this is not activated by --with-all flag. +NUT_ARG_WITH([nutconf], [build and install the nutconf tool (experimental, has compiler/coverage warnings)], [no]) + NUT_ARG_WITH([dev], [build and install the development files], [no]) dnl Activate WITH_UNMAPPED_DATA_POINTS for troubleshooting and evolution? @@ -2775,6 +2781,13 @@ NUT_REPORT_FEATURE([build and install the development files], [${nut_with_dev}], [WITH_DEV], [Define to enable development files support]) dnl ---------------------------------------------------------------------- +AM_CONDITIONAL(WITH_NUTCONF, test "${nut_with_nutconf}" = "yes") +NUT_REPORT_FEATURE([build and install the nutconf tool (experimental, has compiler/coverage warnings)], + [${nut_with_nutconf}], [], + [WITH_NUTCONF], [Define to enable nutconf tool support]) + +dnl ---------------------------------------------------------------------- + dnl checks related to MS Windows support (MingW) AC_CHECK_TOOL([WINDMC], [windmc], [none]) diff --git a/tests/Makefile.am b/tests/Makefile.am index 9bbaab66a6..c057477747 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -36,9 +36,9 @@ nutlogtest-nofail.sh: nutlogtest$(EXEEXT) @chmod +x $@ # NOTE: Keep the line above empty! -else +else !REQUIRE_NUT_STRARG TESTS += nutlogtest$(EXEEXT) -endif +endif !REQUIRE_NUT_STRARG TESTS += nuttimetest nuttimetest_SOURCES = nuttimetest.c @@ -60,9 +60,9 @@ nodist_getvaluetest_SOURCES = hidparser.c # Pull the right include path for chosen libusb version: getvaluetest_CFLAGS = $(AM_CFLAGS) $(LIBUSB_CFLAGS) getvaluetest_LDADD = $(top_builddir)/common/libcommon.la -else +else !WITH_USB EXTRA_DIST += getvaluetest.c hidparser.c -endif +endif !WITH_USB if WITH_GPIO TESTS += gpiotest @@ -79,9 +79,9 @@ gpiotest_SOURCES = generic_gpio_utest.c generic_gpio_liblocal.c nodist_gpiotest_SOURCES = generic_gpio_libgpiod.c generic_gpio_common.c gpiotest_LDADD = $(top_builddir)/drivers/libdummy_mockdrv.la gpiotest_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/tests -DDRIVERS_MAIN_WITHOUT_MAIN=1 -else +else !WITH_GPIO EXTRA_DIST += generic_gpio_utest.c generic_gpio_liblocal.c -endif +endif !WITH_GPIO CLEANFILES += generic_gpio_libgpiod.c generic_gpio_common.c EXTRA_DIST += generic_gpio_utest.h generic_gpio_test.txt @@ -95,7 +95,8 @@ $(top_builddir)/common/libcommon.la: dummy ### Optional tests which can not be built everywhere # List of src files for CppUnit tests CPPUNITTESTSRC = example.cpp nutclienttest.cpp -CPPUNITTESTSRC += nutconf.cpp nutstream_ut.cpp nutconf_ut.cpp nutipc_ut.cpp +# These are an optional part of cppunittest, if building WITH_NUTCONF +CPPUNITTESTSRC_NUTCONF = nutconf.cpp nutstream_ut.cpp nutconf_ut.cpp nutipc_ut.cpp # The test driver which orchestrates running those tests above CPPUNITTESTERSRC = cpputest.cpp @@ -116,16 +117,22 @@ check_PROGRAMS += cppnit if WITH_VALGRIND check-local: $(check_PROGRAMS) RES=0; for P in $^ ; do $(VALGRIND) ./$$P || { RES=$$? ; echo "FAILED: $(VALGRIND) ./$$P" >&2; }; done; exit $$RES -endif +endif WITH_VALGRIND cppunittest_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) ###cppunittest_CXXFLAGS += -I$(top_srcdir)/include -DTOP_SRCDIR="\"$(top_srcdir)\"" cppunittest_LDFLAGS = $(CPPUNIT_LDFLAGS) $(CPPUNIT_LIBS) cppunittest_LDADD = $(top_builddir)/clients/libnutclient.la cppunittest_LDADD += $(top_builddir)/clients/libnutclientstub.la -cppunittest_LDADD += $(top_builddir)/common/libnutconf.la cppunittest_SOURCES = $(CPPUNITTESTSRC) $(CPPUNITTESTERSRC) +# Currently nutconf and related codebase causes woes for static analysis +# so we do not build it unless explicitly asked to. +if WITH_NUTCONF +cppunittest_SOURCES += $(CPPUNITTESTSRC_NUTCONF) +cppunittest_LDADD += $(top_builddir)/common/libnutconf.la +endif WITH_NUTCONF + cppnit_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) cppnit_LDFLAGS = $(CPPUNIT_LDFLAGS) $(CPPUNIT_LIBS) cppnit_LDADD = $(top_builddir)/clients/libnutclient.la $(top_builddir)/clients/libnutclientstub.la @@ -140,7 +147,7 @@ $(top_builddir)/clients/libnutclientstub.la: dummy else !HAVE_CPPUNIT # Just redistribute test source into tarball if not building tests -EXTRA_DIST += $(CPPUNITTESTSRC) $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) +EXTRA_DIST += $(CPPUNITTESTSRC) $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) $(CPPUNITTESTSRC_NUTCONF) cppnit: @echo "SKIP: $@ not implemented without C++11 and CPPUNIT enabled" >&2 ; exit 1 @@ -150,7 +157,7 @@ endif !HAVE_CPPUNIT else !HAVE_CXX11 # Just redistribute test source into tarball if not building C++ at all -EXTRA_DIST += $(CPPUNITTESTSRC) $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) +EXTRA_DIST += $(CPPUNITTESTSRC) $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) $(CPPUNITTESTSRC_NUTCONF) cppnit: @echo "SKIP: $@ not implemented without C++11 and CPPUNIT enabled" >&2 ; exit 1 diff --git a/tools/nutconf/Makefile.am b/tools/nutconf/Makefile.am index 116299492d..60e4bc0612 100644 --- a/tools/nutconf/Makefile.am +++ b/tools/nutconf/Makefile.am @@ -2,7 +2,12 @@ all: $(bin_PROGRAMS) -bin_PROGRAMS = nutconf +bin_PROGRAMS = + +# Currently nutconf and related codebase causes woes for static analysis +# so we do not build it unless explicitly asked to. +if WITH_NUTCONF +bin_PROGRAMS += nutconf nutconf_SOURCES = nutconf.cpp nutconf_CXXFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include nutconf_LDADD = $(top_builddir)/common/libcommon.la \ @@ -14,6 +19,9 @@ nutconf_CXXFLAGS += -DWITH_NUTSCANNER -I$(top_srcdir)/tools/nut-scanner nutconf_LDADD += $(top_builddir)/tools/nut-scanner/libnutscan.la endif +# End of WITH_NUTCONF +endif + # Make sure out-of-dir dependencies exist (especially when dev-building parts): $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libnutconf.la \ From cc5e3161baf353fbe7f18b61decfbdf9606b3e28 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 12:10:52 +0100 Subject: [PATCH 076/121] tools/nutconf/Makefile.am: update Makefile markup and comments Signed-off-by: Jim Klimov --- tools/nutconf/Makefile.am | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/nutconf/Makefile.am b/tools/nutconf/Makefile.am index 60e4bc0612..f5bbbd5e95 100644 --- a/tools/nutconf/Makefile.am +++ b/tools/nutconf/Makefile.am @@ -17,10 +17,9 @@ nutconf_LDADD = $(top_builddir)/common/libcommon.la \ if WITH_LIBLTDL nutconf_CXXFLAGS += -DWITH_NUTSCANNER -I$(top_srcdir)/tools/nut-scanner nutconf_LDADD += $(top_builddir)/tools/nut-scanner/libnutscan.la -endif +endif WITH_LIBLTDL -# End of WITH_NUTCONF -endif +endif WITH_NUTCONF # Make sure out-of-dir dependencies exist (especially when dev-building parts): $(top_builddir)/common/libcommon.la \ From d423987286b0a7e376e8b6aa2c91ee15ede71d30 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 12:11:20 +0100 Subject: [PATCH 077/121] tools/nutconf/nutconf.cpp: fix file description Signed-off-by: Jim Klimov --- tools/nutconf/nutconf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 8f2feb4ef5..b7bc2ab04f 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/*! \file nutscan-display.c - \brief format and display scanned devices +/*! \file nutconf.cpp + \brief NUT configuration tool \author Frederic Bohe \author Vaclav Krpec */ From 87d5f043a1da16197d46a8352896efd9936876b8 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 12:12:12 +0100 Subject: [PATCH 078/121] nutconf related sources: fix whitespace style Signed-off-by: Jim Klimov --- common/nutconf.cpp | 994 +++++++++++++++++++------------------- common/nutipc.cpp | 29 +- common/nutstream.cpp | 27 +- common/nutwriter.cpp | 27 +- include/nutconf.h | 229 ++++----- include/nutipc.hpp | 29 +- include/nutstream.hpp | 27 +- include/nutwriter.hpp | 27 +- tests/nutconf.cpp | 33 +- tests/nutconf_ut.cpp | 28 +- tests/nutipc_ut.cpp | 28 +- tests/nutstream_ut.cpp | 28 +- tools/nutconf/nutconf.cpp | 162 +++---- 13 files changed, 837 insertions(+), 831 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 2166ea1624..644e1b40ba 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -1,21 +1,22 @@ -/* nutconf.cpp - configuration API +/* + nutconf.cpp - configuration API - Copyright (C) + Copyright (C) 2012 Emilien Kia - This program 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 2 of the License, or - (at your option) any later version. + This program 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 2 of the License, or + (at your option) any later version. - This program 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. + This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "nutconf.h" @@ -84,45 +85,45 @@ void NutParser::setOptions(unsigned int options, bool set) } char NutParser::get() { - if (_pos >= _buffer.size()) - return 0; - else - return _buffer[_pos++]; + if (_pos >= _buffer.size()) + return 0; + else + return _buffer[_pos++]; } char NutParser::peek() { - return _buffer[_pos]; + return _buffer[_pos]; } size_t NutParser::getPos()const { - return _pos; + return _pos; } void NutParser::setPos(size_t pos) { - _pos = pos; + _pos = pos; } char NutParser::charAt(size_t pos)const { - return _buffer[pos]; + return _buffer[pos]; } void NutParser::pushPos() { - _stack.push_back(_pos); + _stack.push_back(_pos); } size_t NutParser::popPos() { - size_t pos = _stack.back(); - _stack.pop_back(); - return pos; + size_t pos = _stack.back(); + _stack.pop_back(); + return pos; } void NutParser::rewind() { - _pos = popPos(); + _pos = popPos(); } void NutParser::back() { - if (_pos > 0) - --_pos; + if (_pos > 0) + --_pos; } /* Parse a string source for a CHARS and return its size if found or 0, if not. @@ -132,33 +133,33 @@ void NutParser::back() { * TODO: accept "\t", "\s", "\r", "\n" ?? */ std::string NutParser::parseCHARS() { - bool escaped = false; // Is char escaped ? - std::string res; // Stored string - - pushPos(); - - for (char c = get(); c != 0 /*EOF*/; c = get()) { - if (escaped) { - if (isspace(c) || c == '\\' || c == '"' || c == '#') { - res += c; - } else { - /* WTF ??? */ - } - escaped = false; - } else { - if (c == '\\') { - escaped = true; - } else if (isgraph(c) /*&& c != '\\'*/ && c != '"' && c != '#') { - res += c; - } else { - back(); - break; - } - } - } - - popPos(); - return res; + bool escaped = false; // Is char escaped ? + std::string res; // Stored string + + pushPos(); + + for (char c = get(); c != 0 /*EOF*/; c = get()) { + if (escaped) { + if (isspace(c) || c == '\\' || c == '"' || c == '#') { + res += c; + } else { + /* WTF ??? */ + } + escaped = false; + } else { + if (c == '\\') { + escaped = true; + } else if (isgraph(c) /*&& c != '\\'*/ && c != '"' && c != '#') { + res += c; + } else { + back(); + break; + } + } + } + + popPos(); + return res; } /* Parse a string source for a STRCHARS and return its size if found or 0, if not. @@ -168,33 +169,33 @@ std::string NutParser::parseCHARS() { * TODO: accept "\t", "\s", "\r", "\n" ?? */ std::string NutParser::parseSTRCHARS() { - bool escaped = false; // Is char escaped ? - std::string str; // Stored string - - pushPos(); - - for (char c = get(); c != 0 /*EOF*/; c = get()) { - if (escaped) { - if (isspace(c) || c == '\\' || c == '"') { - str += c; - } else { - /* WTF ??? */ - } - escaped = false; - } else { - if (c == '\\') { - escaped = true; - } else if (isprint(c) && c != '\\' && c != '"') { - str += c; - } else { - back(); - break; - } - } - } - - popPos(); - return str; + bool escaped = false; // Is char escaped ? + std::string str; // Stored string + + pushPos(); + + for (char c = get(); c != 0 /*EOF*/; c = get()) { + if (escaped) { + if (isspace(c) || c == '\\' || c == '"') { + str += c; + } else { + /* WTF ??? */ + } + escaped = false; + } else { + if (c == '\\') { + escaped = true; + } else if (isprint(c) && c != '\\' && c != '"') { + str += c; + } else { + back(); + break; + } + } + } + + popPos(); + return str; } /** Parse a string source for getting the next token, ignoring spaces. @@ -202,179 +203,180 @@ std::string NutParser::parseSTRCHARS() { */ NutParser::Token NutParser::parseToken() { - /** Lexical parsing machine state enumeration.*/ - typedef enum { - LEXPARSING_STATE_DEFAULT, - LEXPARSING_STATE_QUOTED_STRING, - LEXPARSING_STATE_STRING, - LEXPARSING_STATE_COMMENT - } LEXPARSING_STATE_e; - LEXPARSING_STATE_e state = LEXPARSING_STATE_DEFAULT; - - Token token; - bool escaped = false; - - pushPos(); - - for (char c = get(); c != 0 /*EOF*/; c = get()) { - switch (state) { - case LEXPARSING_STATE_DEFAULT: /* Wait for a non-space char */ - { - if (c == ' ' || c == '\t') { - /* Space : do nothing */ - } else if (c == '[') { - token = Token(Token::TOKEN_BRACKET_OPEN, c); - popPos(); - return token; - } else if (c == ']') { - token = Token(Token::TOKEN_BRACKET_CLOSE, c); - popPos(); - return token; - } else if (c == ':' && !hasOptions(OPTION_IGNORE_COLON)) { - token = Token(Token::TOKEN_COLON, c); - popPos(); - return token; - } else if (c == '=') { - token = Token(Token::TOKEN_EQUAL, c); - popPos(); - return token; - } else if (c == '\r' || c == '\n') { - token = Token(Token::TOKEN_EOL, c); - popPos(); - return token; - } else if (c == '#') { - token.type = Token::TOKEN_COMMENT; - state = LEXPARSING_STATE_COMMENT; - } else if (c == '"') { - /* Begin of QUOTED STRING */ - token.type = Token::TOKEN_QUOTED_STRING; - state = LEXPARSING_STATE_QUOTED_STRING; - } else if (c == '\\') { - /* Begin of STRING with escape */ - token.type = Token::TOKEN_STRING; - state = LEXPARSING_STATE_STRING; - escaped = true; - } else if (isgraph(c)) { - /* Begin of STRING */ - token.type = Token::TOKEN_STRING; - state = LEXPARSING_STATE_STRING; - token.str += c; - } else { - rewind(); - return Token(Token::TOKEN_UNKNOWN); - } - break; - } - case LEXPARSING_STATE_QUOTED_STRING: - { - if (c == '"') { - if (escaped) { - escaped = false; - token.str += '"'; - } else { - popPos(); - return token; - } - } else if (c == '\\') { - if (escaped) { - escaped = false; - token.str += '\\'; - } else { - escaped = true; - } - } else if (c == ' ' || c == '\t' || isgraph(c)) { - token.str += c; - } else if (c == '\r' || c == '\n') /* EOL */{ + /** Lexical parsing machine state enumeration.*/ + typedef enum { + LEXPARSING_STATE_DEFAULT, + LEXPARSING_STATE_QUOTED_STRING, + LEXPARSING_STATE_STRING, + LEXPARSING_STATE_COMMENT + } LEXPARSING_STATE_e; + LEXPARSING_STATE_e state = LEXPARSING_STATE_DEFAULT; + + Token token; + bool escaped = false; + + pushPos(); + + for (char c = get(); c != 0 /*EOF*/; c = get()) { + switch (state) { + case LEXPARSING_STATE_DEFAULT: /* Wait for a non-space char */ + { + if (c == ' ' || c == '\t') { + /* Space : do nothing */ + } else if (c == '[') { + token = Token(Token::TOKEN_BRACKET_OPEN, c); + popPos(); + return token; + } else if (c == ']') { + token = Token(Token::TOKEN_BRACKET_CLOSE, c); + popPos(); + return token; + } else if (c == ':' && !hasOptions(OPTION_IGNORE_COLON)) { + token = Token(Token::TOKEN_COLON, c); + popPos(); + return token; + } else if (c == '=') { + token = Token(Token::TOKEN_EQUAL, c); + popPos(); + return token; + } else if (c == '\r' || c == '\n') { + token = Token(Token::TOKEN_EOL, c); + popPos(); + return token; + } else if (c == '#') { + token.type = Token::TOKEN_COMMENT; + state = LEXPARSING_STATE_COMMENT; + } else if (c == '"') { + /* Begin of QUOTED STRING */ + token.type = Token::TOKEN_QUOTED_STRING; + state = LEXPARSING_STATE_QUOTED_STRING; + } else if (c == '\\') { + /* Begin of STRING with escape */ + token.type = Token::TOKEN_STRING; + state = LEXPARSING_STATE_STRING; + escaped = true; + } else if (isgraph(c)) { + /* Begin of STRING */ + token.type = Token::TOKEN_STRING; + state = LEXPARSING_STATE_STRING; + token.str += c; + } else { + rewind(); + return Token(Token::TOKEN_UNKNOWN); + } + break; + } + case LEXPARSING_STATE_QUOTED_STRING: + { + if (c == '"') { + if (escaped) { + escaped = false; + token.str += '"'; + } else { + popPos(); + return token; + } + } else if (c == '\\') { + if (escaped) { + escaped = false; + token.str += '\\'; + } else { + escaped = true; + } + } else if (c == ' ' || c == '\t' || isgraph(c)) { + token.str += c; + } else if (c == '\r' || c == '\n') /* EOL */{ /* WTF ? consider it as correct ? */ back(); - popPos(); - return token; - } else if (c == 0) /* EOF */ { - popPos(); - return token; - } else /* Bad character ?? */ { - /* WTF ? Keep, Ignore ? */ - } - /* TODO What about other escaped character ? */ - break; - } - case LEXPARSING_STATE_STRING: - { - if (c == ' ' || c == '\t' || c == '"' || c == '#' || c == '[' || c == ']' || - (c == ':' && !hasOptions(OPTION_IGNORE_COLON)) || - c == '=') { - if (escaped) { - escaped = false; - token.str += c; - } else { - back(); - popPos(); - return token; - } - } else if (c == '\\') { - if (escaped) { - escaped = false; - token.str += c; - } else { - escaped = true; - } - } else if (c == '\r' || c == '\n') /* EOL */{ + popPos(); + return token; + } else if (c == 0) /* EOF */ { + popPos(); + return token; + } else /* Bad character ?? */ { + /* WTF ? Keep, Ignore ? */ + } + /* TODO What about other escaped character ? */ + break; + } + case LEXPARSING_STATE_STRING: + { + if (c == ' ' || c == '\t' || c == '"' || c == '#' || c == '[' || c == ']' + || (c == ':' && !hasOptions(OPTION_IGNORE_COLON)) + || c == '=' + ) { + if (escaped) { + escaped = false; + token.str += c; + } else { + back(); + popPos(); + return token; + } + } else if (c == '\\') { + if (escaped) { + escaped = false; + token.str += c; + } else { + escaped = true; + } + } else if (c == '\r' || c == '\n') /* EOL */{ back(); - popPos(); - return token; - } else if (c == 0) /* EOF */ { - popPos(); - return token; - }else if (isgraph(c)) { - token.str += c; - } else /* Bad character ?? */ { - /* WTF ? Keep, Ignore ? */ - } - /* TODO What about escaped character ? */ - break; - } - case LEXPARSING_STATE_COMMENT: - { - if (c == '\r' || c == '\n') { - return token; - } else { - token.str += c; - } - break; - } - default: - /* Must not occur. */ - break; - } - } - popPos(); - return token; + popPos(); + return token; + } else if (c == 0) /* EOF */ { + popPos(); + return token; + }else if (isgraph(c)) { + token.str += c; + } else /* Bad character ?? */ { + /* WTF ? Keep, Ignore ? */ + } + /* TODO What about escaped character ? */ + break; + } + case LEXPARSING_STATE_COMMENT: + { + if (c == '\r' || c == '\n') { + return token; + } else { + token.str += c; + } + break; + } + default: + /* Must not occur. */ + break; + } + } + popPos(); + return token; } std::list NutParser::parseLine() { - std::list res; - - while (true) { - NutParser::Token token = parseToken(); - - switch (token.type) { - case Token::TOKEN_STRING: - case Token::TOKEN_QUOTED_STRING: - case Token::TOKEN_BRACKET_OPEN: - case Token::TOKEN_BRACKET_CLOSE: - case Token::TOKEN_EQUAL: - case Token::TOKEN_COLON: - res.push_back(token); - break; - case Token::TOKEN_COMMENT: - res.push_back(token); - // Do not break, should return (EOL)Token::TOKEN_COMMENT: - case Token::TOKEN_UNKNOWN: - case Token::TOKEN_NONE: - case Token::TOKEN_EOL: - return res; - } - } + std::list res; + + while (true) { + NutParser::Token token = parseToken(); + + switch (token.type) { + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + case Token::TOKEN_BRACKET_OPEN: + case Token::TOKEN_BRACKET_CLOSE: + case Token::TOKEN_EQUAL: + case Token::TOKEN_COLON: + res.push_back(token); + break; + case Token::TOKEN_COMMENT: + res.push_back(token); + // Do not break, should return (EOL)Token::TOKEN_COMMENT: + case Token::TOKEN_UNKNOWN: + case Token::TOKEN_NONE: + case Token::TOKEN_EOL: + return res; + } + } } // @@ -390,208 +392,208 @@ NutParser(buffer, options) { } void NutConfigParser::parseConfig() { - onParseBegin(); - - enum ConfigParserState { - CPS_DEFAULT, - CPS_SECTION_OPENED, - CPS_SECTION_HAVE_NAME, - CPS_SECTION_CLOSED, - CPS_DIRECTIVE_HAVE_NAME, - CPS_DIRECTIVE_VALUES - } state = CPS_DEFAULT; - - Token tok; - std::string name; - std::list values; - char sep; - while (tok = parseToken()) { - switch (state) { - case CPS_DEFAULT: - switch (tok.type) { - case Token::TOKEN_COMMENT: - onParseComment(tok.str); - /* Clean and return to default */ - break; - case Token::TOKEN_BRACKET_OPEN: - state = CPS_SECTION_OPENED; - break; - case Token::TOKEN_STRING: - case Token::TOKEN_QUOTED_STRING: - name = tok.str; - state = CPS_DIRECTIVE_HAVE_NAME; - break; - default: - /* WTF ? */ - break; - } - break; - case CPS_SECTION_OPENED: - switch (tok.type) { - case Token::TOKEN_STRING: - case Token::TOKEN_QUOTED_STRING: - /* Should occur ! */ - name = tok.str; - state = CPS_SECTION_HAVE_NAME; - break; - case Token::TOKEN_BRACKET_CLOSE: - /* Empty section name */ - state = CPS_SECTION_CLOSED; - break; - case Token::TOKEN_COMMENT: - /* Lack of closing bracket !!! */ - onParseSectionName(name, tok.str); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - case Token::TOKEN_EOL: - /* Lack of closing bracket !!! */ - onParseSectionName(name); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - default: - /* WTF ? */ - break; - } - break; - case CPS_SECTION_HAVE_NAME: - switch (tok.type) { - case Token::TOKEN_BRACKET_CLOSE: - /* Must occur ! */ - state = CPS_SECTION_CLOSED; - break; - case Token::TOKEN_COMMENT: - /* Lack of closing bracket !!! */ - onParseSectionName(name, tok.str); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - case Token::TOKEN_EOL: - /* Lack of closing bracket !!! */ - onParseSectionName(name); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - default: - /* WTF ? */ - break; - } - break; - case CPS_SECTION_CLOSED: - switch (tok.type) { - case Token::TOKEN_COMMENT: - /* Could occur ! */ - onParseSectionName(name, tok.str); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - case Token::TOKEN_EOL: - /* Could occur ! */ - onParseSectionName(name); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - default: - /* WTF ? */ - break; - } - break; - case CPS_DIRECTIVE_HAVE_NAME: - switch (tok.type) { - case Token::TOKEN_COMMENT: - /* Could occur ! */ - onParseDirective(name, 0, std::list (), tok.str); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - case Token::TOKEN_EOL: - /* Could occur ! */ - onParseDirective(name); - /* Clean and return to default */ - name.clear(); - state = CPS_DEFAULT; - break; - case Token::TOKEN_COLON: - case Token::TOKEN_EQUAL: - /* Could occur ! */ - sep = tok.str[0]; - state = CPS_DIRECTIVE_VALUES; - break; - case Token::TOKEN_STRING: - case Token::TOKEN_QUOTED_STRING: - /* Could occur ! */ - values.push_back(tok.str); - state = CPS_DIRECTIVE_VALUES; - break; - default: - /* WTF ? */ - break; - } - break; - case CPS_DIRECTIVE_VALUES: - switch (tok.type) { - case Token::TOKEN_COMMENT: - /* Could occur ! */ - onParseDirective(name, sep, values, tok.str); - /* Clean and return to default */ - name.clear(); - values.clear(); - sep = 0; - state = CPS_DEFAULT; - break; - case Token::TOKEN_EOL: - /* Could occur ! */ - onParseDirective(name, sep, values); - /* Clean and return to default */ - name.clear(); - values.clear(); - sep = 0; - state = CPS_DEFAULT; - break; - case Token::TOKEN_STRING: - case Token::TOKEN_QUOTED_STRING: - /* Could occur ! */ - values.push_back(tok.str); - state = CPS_DIRECTIVE_VALUES; - break; - default: - /* WTF ? */ - break; - } - break; - } - } + onParseBegin(); + + enum ConfigParserState { + CPS_DEFAULT, + CPS_SECTION_OPENED, + CPS_SECTION_HAVE_NAME, + CPS_SECTION_CLOSED, + CPS_DIRECTIVE_HAVE_NAME, + CPS_DIRECTIVE_VALUES + } state = CPS_DEFAULT; + + Token tok; + std::string name; + std::list values; + char sep; + while (tok = parseToken()) { + switch (state) { + case CPS_DEFAULT: + switch (tok.type) { + case Token::TOKEN_COMMENT: + onParseComment(tok.str); + /* Clean and return to default */ + break; + case Token::TOKEN_BRACKET_OPEN: + state = CPS_SECTION_OPENED; + break; + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + name = tok.str; + state = CPS_DIRECTIVE_HAVE_NAME; + break; + default: + /* WTF ? */ + break; + } + break; + case CPS_SECTION_OPENED: + switch (tok.type) { + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + /* Should occur ! */ + name = tok.str; + state = CPS_SECTION_HAVE_NAME; + break; + case Token::TOKEN_BRACKET_CLOSE: + /* Empty section name */ + state = CPS_SECTION_CLOSED; + break; + case Token::TOKEN_COMMENT: + /* Lack of closing bracket !!! */ + onParseSectionName(name, tok.str); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + case Token::TOKEN_EOL: + /* Lack of closing bracket !!! */ + onParseSectionName(name); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + default: + /* WTF ? */ + break; + } + break; + case CPS_SECTION_HAVE_NAME: + switch (tok.type) { + case Token::TOKEN_BRACKET_CLOSE: + /* Must occur ! */ + state = CPS_SECTION_CLOSED; + break; + case Token::TOKEN_COMMENT: + /* Lack of closing bracket !!! */ + onParseSectionName(name, tok.str); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + case Token::TOKEN_EOL: + /* Lack of closing bracket !!! */ + onParseSectionName(name); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + default: + /* WTF ? */ + break; + } + break; + case CPS_SECTION_CLOSED: + switch (tok.type) { + case Token::TOKEN_COMMENT: + /* Could occur ! */ + onParseSectionName(name, tok.str); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + case Token::TOKEN_EOL: + /* Could occur ! */ + onParseSectionName(name); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + default: + /* WTF ? */ + break; + } + break; + case CPS_DIRECTIVE_HAVE_NAME: + switch (tok.type) { + case Token::TOKEN_COMMENT: + /* Could occur ! */ + onParseDirective(name, 0, std::list (), tok.str); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + case Token::TOKEN_EOL: + /* Could occur ! */ + onParseDirective(name); + /* Clean and return to default */ + name.clear(); + state = CPS_DEFAULT; + break; + case Token::TOKEN_COLON: + case Token::TOKEN_EQUAL: + /* Could occur ! */ + sep = tok.str[0]; + state = CPS_DIRECTIVE_VALUES; + break; + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + /* Could occur ! */ + values.push_back(tok.str); + state = CPS_DIRECTIVE_VALUES; + break; + default: + /* WTF ? */ + break; + } + break; + case CPS_DIRECTIVE_VALUES: + switch (tok.type) { + case Token::TOKEN_COMMENT: + /* Could occur ! */ + onParseDirective(name, sep, values, tok.str); + /* Clean and return to default */ + name.clear(); + values.clear(); + sep = 0; + state = CPS_DEFAULT; + break; + case Token::TOKEN_EOL: + /* Could occur ! */ + onParseDirective(name, sep, values); + /* Clean and return to default */ + name.clear(); + values.clear(); + sep = 0; + state = CPS_DEFAULT; + break; + case Token::TOKEN_STRING: + case Token::TOKEN_QUOTED_STRING: + /* Could occur ! */ + values.push_back(tok.str); + state = CPS_DIRECTIVE_VALUES; + break; + default: + /* WTF ? */ + break; + } + break; + } + } switch(state) { - case CPS_SECTION_OPENED: - case CPS_SECTION_HAVE_NAME: - /* Lack of closing bracket !!! */ - onParseSectionName(name); - break; - case CPS_SECTION_CLOSED: - /* Could occur ! */ - onParseSectionName(name); - break; - case CPS_DIRECTIVE_HAVE_NAME: - /* Could occur ! */ - onParseDirective(name); - break; - case CPS_DIRECTIVE_VALUES: - /* Could occur ! */ - onParseDirective(name, sep, values); - break; + case CPS_SECTION_OPENED: + case CPS_SECTION_HAVE_NAME: + /* Lack of closing bracket !!! */ + onParseSectionName(name); + break; + case CPS_SECTION_CLOSED: + /* Could occur ! */ + onParseSectionName(name); + break; + case CPS_DIRECTIVE_HAVE_NAME: + /* Could occur ! */ + onParseDirective(name); + break; + case CPS_DIRECTIVE_VALUES: + /* Could occur ! */ + onParseDirective(name, sep, values); + break; } - onParseEnd(); + onParseEnd(); } @@ -609,44 +611,44 @@ NutConfigParser(buffer) { } void DefaultConfigParser::onParseBegin() { - // Start with empty section (ie global one) - _section.clear(); + // Start with empty section (ie global one) + _section.clear(); } void DefaultConfigParser::onParseComment(const std::string& /*comment*/) { - // Comment are ignored for now + // Comment are ignored for now } void DefaultConfigParser::onParseSectionName(const std::string& sectionName, const std::string& /*comment*/) { - // Comment are ignored for now + // Comment are ignored for now - // Process current section. - if (!_section.empty()) { - onParseSection(_section); - _section.clear(); - } + // Process current section. + if (!_section.empty()) { + onParseSection(_section); + _section.clear(); + } - // Start a new section - _section.name = sectionName; + // Start a new section + _section.name = sectionName; } void DefaultConfigParser::onParseDirective(const std::string& directiveName, char /*sep*/, const ConfigParamList& values, const std::string& /*comment*/) { - // Comment are ignored for now - // Separator has no specific semantic in this context + // Comment are ignored for now + // Separator has no specific semantic in this context - // Save values - _section.entries[directiveName].name = directiveName; - _section.entries[directiveName].values = values; + // Save values + _section.entries[directiveName].name = directiveName; + _section.entries[directiveName].values = values; // TODO Can probably be optimized. } void DefaultConfigParser::onParseEnd() { - // Process current (last) section - if (!_section.empty()) { - onParseSection(_section); - _section.clear(); - } + // Process current (last) section + if (!_section.empty()) { + onParseSection(_section); + _section.clear(); + } } @@ -655,12 +657,12 @@ void DefaultConfigParser::onParseEnd() { // bool GenericConfigSection::empty()const { - return name.empty() && entries.empty(); + return name.empty() && entries.empty(); } void GenericConfigSection::clear() { - name.clear(); - entries.clear(); + name.clear(); + entries.clear(); } // @@ -896,7 +898,7 @@ bool GenericConfiguration::str2bool(const std::string & str) { if ("true" == str) return true; if ("on" == str) return true; - if ("1" == str) return true; + if ("1" == str) return true; if ("yes" == str) return true; if ("ok" == str) return true; @@ -923,8 +925,8 @@ UpsmonConfiguration::UpsmonConfiguration() void UpsmonConfiguration::parseFromString(const std::string& str) { - UpsmonConfigParser parser(str); - parser.parseUpsmonConfig(this); + UpsmonConfigParser parser(str); + parser.parseUpsmonConfig(this); } UpsmonConfiguration::NotifyFlag UpsmonConfiguration::NotifyFlagFromString(const std::string& str) @@ -1016,19 +1018,19 @@ void UpsmonConfigParser::parseUpsmonConfig(UpsmonConfiguration* config) void UpsmonConfigParser::onParseBegin() { - // Do nothing + // Do nothing } void UpsmonConfigParser::onParseComment(const std::string& /*comment*/) { - // Comment are ignored for now + // Comment are ignored for now } void UpsmonConfigParser::onParseSectionName(const std::string& /*sectionName*/, const std::string& /*comment*/) { - // There must not have sections in upsm.conf. - // Ignore it - // TODO Add error reporting ? + // There must not have sections in upsm.conf. + // Ignore it + // TODO Add error reporting ? } @@ -1178,7 +1180,7 @@ void UpsmonConfigParser::onParseDirective(const std::string& directiveName, char void UpsmonConfigParser::onParseEnd() { - // Do nothing + // Do nothing } // @@ -1192,8 +1194,8 @@ NutConfiguration::NutConfiguration(): void NutConfiguration::parseFromString(const std::string& str) { - NutConfConfigParser parser(str); - parser.parseNutConfConfig(this); + NutConfConfigParser parser(str); + parser.parseNutConfConfig(this); } NutConfiguration::NutMode NutConfiguration::NutModeFromString(const std::string& str) @@ -1263,24 +1265,24 @@ void NutConfConfigParser::parseNutConfConfig(NutConfiguration* config) void NutConfConfigParser::onParseBegin() { - // Do nothing + // Do nothing } void NutConfConfigParser::onParseComment(const std::string& /*comment*/) { - // Comment are ignored for now + // Comment are ignored for now } void NutConfConfigParser::onParseSectionName(const std::string& /*sectionName*/, const std::string& /*comment*/) { - // There must not have sections in upsm.conf. - // Ignore it - // TODO Add error reporting ? + // There must not have sections in upsm.conf. + // Ignore it + // TODO Add error reporting ? } void NutConfConfigParser::onParseDirective(const std::string& directiveName, char /*sep*/, const ConfigParamList& values, const std::string& /*comment*/) { - // Comment are ignored for now + // Comment are ignored for now // NOTE: although sep must be '=', sep is not verified. if(_config && directiveName=="MODE" && values.size()==1) { @@ -1297,7 +1299,7 @@ void NutConfConfigParser::onParseDirective(const std::string& directiveName, cha void NutConfConfigParser::onParseEnd() { - // Do nothing + // Do nothing } @@ -1311,8 +1313,8 @@ UpsdConfiguration::UpsdConfiguration() void UpsdConfiguration::parseFromString(const std::string& str) { - UpsdConfigParser parser(str); - parser.parseUpsdConfig(this); + UpsdConfigParser parser(str); + parser.parseUpsdConfig(this); } @@ -1364,19 +1366,19 @@ void UpsdConfigParser::parseUpsdConfig(UpsdConfiguration* config) void UpsdConfigParser::onParseBegin() { - // Do nothing + // Do nothing } void UpsdConfigParser::onParseComment(const std::string& comment) { - // Comment are ignored for now + // Comment are ignored for now } void UpsdConfigParser::onParseSectionName(const std::string& sectionName, const std::string& comment) { - // There must not have sections in upsm.conf. - // Ignore it - // TODO Add error reporting ? + // There must not have sections in upsm.conf. + // Ignore it + // TODO Add error reporting ? } void UpsdConfigParser::onParseDirective(const std::string& directiveName, char sep, const ConfigParamList& values, const std::string& comment) @@ -1435,7 +1437,7 @@ void UpsdConfigParser::onParseDirective(const std::string& directiveName, char s void UpsdConfigParser::onParseEnd() { - // Do nothing + // Do nothing } diff --git a/common/nutipc.cpp b/common/nutipc.cpp index 0b75632193..5e7759d4f0 100644 --- a/common/nutipc.cpp +++ b/common/nutipc.cpp @@ -1,22 +1,23 @@ -/* nutipc.cpp - NUT IPC +/* + nutipc.cpp - NUT IPC - Copyright (C) 2012 Eaton + Copyright (C) 2012 Eaton - Author: Vaclav Krpec + Author: Vaclav Krpec - This program 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 2 of the License, or - (at your option) any later version. + This program 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 2 of the License, or + (at your option) any later version. - This program 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. + This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "nutipc.hpp" diff --git a/common/nutstream.cpp b/common/nutstream.cpp index c713c6e39c..d096ec8725 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -1,21 +1,22 @@ -/* nutstream.cpp - NUT stream +/* + nutstream.cpp - NUT stream - Copyright (C) + Copyright (C) 2012 Vaclav Krpec - This program 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 2 of the License, or - (at your option) any later version. + This program 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 2 of the License, or + (at your option) any later version. - This program 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. + This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "nutstream.hpp" diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index 590cde54a2..ee5a352816 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -1,21 +1,22 @@ -/* nutwriter.cpp - NUT writer +/* + nutwriter.cpp - NUT writer - Copyright (C) + Copyright (C) 2012 Vaclav Krpec - This program 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 2 of the License, or - (at your option) any later version. + This program 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 2 of the License, or + (at your option) any later version. - This program 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. + This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "nutwriter.hpp" diff --git a/include/nutconf.h b/include/nutconf.h index b79b11c11b..dcfa52992e 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -1,21 +1,22 @@ -/* nutconf.h - Nut configuration file manipulation API +/* + nutconf.h - Nut configuration file manipulation API - Copyright (C) + Copyright (C) 2012 Emilien Kia - This program 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 2 of the License, or - (at your option) any later version. + This program 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 2 of the License, or + (at your option) any later version. - This program 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. + This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUTCONF_H_SEEN @@ -75,7 +76,7 @@ class Settable { if(!set() && !val.set()) return false; - else + else return (set() && val.set() && _value==val._value); } @@ -196,25 +197,25 @@ class NutParser #ifndef UNITEST_MODE protected: #endif /* UNITEST_MODE */ - size_t getPos()const; - void setPos(size_t pos); - char charAt(size_t pos)const; + size_t getPos()const; + void setPos(size_t pos); + char charAt(size_t pos)const; - void pushPos(); - size_t popPos(); - void rewind(); + void pushPos(); + size_t popPos(); + void rewind(); - void back(); + void back(); - char get(); - char peek(); + char get(); + char peek(); private: unsigned int _options; - std::string _buffer; - size_t _pos; - std::vector _stack; + std::string _buffer; + size_t _pos; + std::vector _stack; }; @@ -223,17 +224,17 @@ typedef std::list ConfigParamList; class NutConfigParser : public NutParser { public: - virtual void parseConfig(); + virtual void parseConfig(); protected: - NutConfigParser(const char* buffer = NULL, unsigned int options = OPTION_DEFAULT); - NutConfigParser(const std::string& buffer, unsigned int options = OPTION_DEFAULT); - - virtual void onParseBegin()=0; - virtual void onParseComment(const std::string& comment)=0; - virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "")=0; - virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "")=0; - virtual void onParseEnd()=0; + NutConfigParser(const char* buffer = NULL, unsigned int options = OPTION_DEFAULT); + NutConfigParser(const std::string& buffer, unsigned int options = OPTION_DEFAULT); + + virtual void onParseBegin()=0; + virtual void onParseComment(const std::string& comment)=0; + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "")=0; + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "")=0; + virtual void onParseEnd()=0; }; struct GenericConfigSectionEntry @@ -263,17 +264,17 @@ struct GenericConfigSection class DefaultConfigParser : public NutConfigParser { public: - DefaultConfigParser(const char* buffer = NULL); - DefaultConfigParser(const std::string& buffer); + DefaultConfigParser(const char* buffer = NULL); + DefaultConfigParser(const std::string& buffer); protected: virtual void onParseSection(const GenericConfigSection& section)=0; - virtual void onParseBegin(); - virtual void onParseComment(const std::string& comment); - virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); - virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); - virtual void onParseEnd(); + virtual void onParseBegin(); + virtual void onParseComment(const std::string& comment); + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); + virtual void onParseEnd(); GenericConfigSection _section; ///> Currently parsed section }; @@ -289,8 +290,8 @@ class BaseConfiguration class GenericConfigParser : public DefaultConfigParser { public: - GenericConfigParser(const char* buffer = NULL); - GenericConfigParser(const std::string& buffer); + GenericConfigParser(const char* buffer = NULL); + GenericConfigParser(const std::string& buffer); virtual void parseConfig(BaseConfiguration* config); @@ -608,49 +609,49 @@ class GenericConfiguration : public BaseConfiguration, public Serialisable class UpsmonConfiguration : public Serialisable { public: - UpsmonConfiguration(); - void parseFromString(const std::string& str); - - Settable runAsUser, shutdownCmd, notifyCmd, powerDownFlag; - Settable minSupplies, poolFreq, poolFreqAlert, hotSync; - Settable deadTime, rbWarnTime, noCommWarnTime, finalDelay; - - enum NotifyFlag { - NOTIFY_IGNORE = 0, - NOTIFY_SYSLOG = 1, - NOTIFY_WALL = 1 << 1, - NOTIFY_EXEC = 1 << 2 - }; - - enum NotifyType { - NOTIFY_ONLINE, - NOTIFY_ONBATT, - NOTIFY_LOWBATT, - NOTIFY_FSD, - NOTIFY_COMMOK, - NOTIFY_COMMBAD, - NOTIFY_SHUTDOWN, - NOTIFY_REPLBATT, - NOTIFY_NOCOMM, - NOTIFY_NOPARENT, - NOTIFY_TYPE_MAX - }; + UpsmonConfiguration(); + void parseFromString(const std::string& str); + + Settable runAsUser, shutdownCmd, notifyCmd, powerDownFlag; + Settable minSupplies, poolFreq, poolFreqAlert, hotSync; + Settable deadTime, rbWarnTime, noCommWarnTime, finalDelay; + + enum NotifyFlag { + NOTIFY_IGNORE = 0, + NOTIFY_SYSLOG = 1, + NOTIFY_WALL = 1 << 1, + NOTIFY_EXEC = 1 << 2 + }; + + enum NotifyType { + NOTIFY_ONLINE, + NOTIFY_ONBATT, + NOTIFY_LOWBATT, + NOTIFY_FSD, + NOTIFY_COMMOK, + NOTIFY_COMMBAD, + NOTIFY_SHUTDOWN, + NOTIFY_REPLBATT, + NOTIFY_NOCOMM, + NOTIFY_NOPARENT, + NOTIFY_TYPE_MAX + }; static NotifyFlag NotifyFlagFromString(const std::string& str); static NotifyType NotifyTypeFromString(const std::string& str); - Settable notifyFlags[NOTIFY_TYPE_MAX]; + Settable notifyFlags[NOTIFY_TYPE_MAX]; Settable notifyMessages[NOTIFY_TYPE_MAX]; - struct Monitor { - std::string upsname, hostname; - unsigned short port; - unsigned int powerValue; - std::string username, password; - bool isMaster; - }; + struct Monitor { + std::string upsname, hostname; + unsigned short port; + unsigned int powerValue; + std::string username, password; + bool isMaster; + }; - std::list monitors; + std::list monitors; /** Serialisable interface implementation \{ */ bool parseFrom(NutStream & istream); @@ -664,28 +665,28 @@ class UpsmonConfiguration : public Serialisable class UpsmonConfigParser : public NutConfigParser { public: - UpsmonConfigParser(const char* buffer = NULL); - UpsmonConfigParser(const std::string& buffer); + UpsmonConfigParser(const char* buffer = NULL); + UpsmonConfigParser(const std::string& buffer); - void parseUpsmonConfig(UpsmonConfiguration* config); + void parseUpsmonConfig(UpsmonConfiguration* config); protected: - virtual void onParseBegin(); - virtual void onParseComment(const std::string& comment); - virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); - virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); - virtual void onParseEnd(); + virtual void onParseBegin(); + virtual void onParseComment(const std::string& comment); + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); + virtual void onParseEnd(); - UpsmonConfiguration* _config; + UpsmonConfiguration* _config; }; class NutConfiguration: public Serialisable { public: - NutConfiguration(); - void parseFromString(const std::string& str); + NutConfiguration(); + void parseFromString(const std::string& str); - enum NutMode { + enum NutMode { MODE_UNKNOWN = -1, MODE_NONE = 0, MODE_STANDALONE, @@ -693,7 +694,7 @@ class NutConfiguration: public Serialisable MODE_NETCLIENT, MODE_CONTROLLED, MODE_MANUAL, - }; + }; Settable mode; @@ -709,18 +710,18 @@ class NutConfiguration: public Serialisable class NutConfConfigParser : public NutConfigParser { public: - NutConfConfigParser(const char* buffer = NULL); - NutConfConfigParser(const std::string& buffer); + NutConfConfigParser(const char* buffer = NULL); + NutConfConfigParser(const std::string& buffer); - void parseNutConfConfig(NutConfiguration* config); + void parseNutConfConfig(NutConfiguration* config); protected: - virtual void onParseBegin(); - virtual void onParseComment(const std::string& comment); - virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); - virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); - virtual void onParseEnd(); + virtual void onParseBegin(); + virtual void onParseComment(const std::string& comment); + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); + virtual void onParseEnd(); - NutConfiguration* _config; + NutConfiguration* _config; }; @@ -728,10 +729,10 @@ class UpsdConfiguration : public Serialisable { public: UpsdConfiguration(); - void parseFromString(const std::string& str); + void parseFromString(const std::string& str); - Settable maxAge, maxConn; - Settable statePath, certFile; + Settable maxAge, maxConn; + Settable statePath, certFile; struct Listen { @@ -757,18 +758,18 @@ class UpsdConfiguration : public Serialisable class UpsdConfigParser : public NutConfigParser { public: - UpsdConfigParser(const char* buffer = NULL); - UpsdConfigParser(const std::string& buffer); + UpsdConfigParser(const char* buffer = NULL); + UpsdConfigParser(const std::string& buffer); - void parseUpsdConfig(UpsdConfiguration* config); + void parseUpsdConfig(UpsdConfiguration* config); protected: - virtual void onParseBegin(); - virtual void onParseComment(const std::string& comment); - virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); - virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); - virtual void onParseEnd(); + virtual void onParseBegin(); + virtual void onParseComment(const std::string& comment); + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); + virtual void onParseEnd(); - UpsdConfiguration* _config; + UpsdConfiguration* _config; }; diff --git a/include/nutipc.hpp b/include/nutipc.hpp index 29537f90de..daf6a24e5f 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -1,22 +1,23 @@ -/* nutipc.hpp - NUT IPC +/* + nutipc.hpp - NUT IPC - Copyright (C) 2012 Eaton + Copyright (C) 2012 Eaton - Author: Vaclav Krpec + Author: Vaclav Krpec - This program 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 2 of the License, or - (at your option) any later version. + This program 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 2 of the License, or + (at your option) any later version. - This program 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. + This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_NUTIPC_HPP diff --git a/include/nutstream.hpp b/include/nutstream.hpp index 0b1eb06d3c..553ba591dd 100644 --- a/include/nutstream.hpp +++ b/include/nutstream.hpp @@ -1,21 +1,22 @@ -/* nutstream.hpp - NUT stream +/* + nutstream.hpp - NUT stream - Copyright (C) + Copyright (C) 2012 Vaclav Krpec - This program 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 2 of the License, or - (at your option) any later version. + This program 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 2 of the License, or + (at your option) any later version. - This program 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. + This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef nut_nutstream_h diff --git a/include/nutwriter.hpp b/include/nutwriter.hpp index ccb50a1605..7a60f4ab39 100644 --- a/include/nutwriter.hpp +++ b/include/nutwriter.hpp @@ -1,21 +1,22 @@ -/* nutwriter.hpp - NUT writer +/* + nutwriter.hpp - NUT writer - Copyright (C) + Copyright (C) 2012 Vaclav Krpec - This program 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 2 of the License, or - (at your option) any later version. + This program 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 2 of the License, or + (at your option) any later version. - This program 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. + This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef nut_nutwriter_h diff --git a/tests/nutconf.cpp b/tests/nutconf.cpp index 3af0cccfa3..028b8bd58b 100644 --- a/tests/nutconf.cpp +++ b/tests/nutconf.cpp @@ -1,22 +1,24 @@ -/* example - CppUnit unit test example +/* + tests/nutconf.cpp - based on CppUnit unit test example - Copyright (C) + Copyright (C) 2012 Emilien Kia - This program 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 2 of the License, or - (at your option) any later version. + This program 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 2 of the License, or + (at your option) any later version. - This program 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. + This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include // Define to desactivate protection of parsing tool members: @@ -301,7 +303,6 @@ void NutConfTest::testNutConfConfigParser() CPPUNIT_ASSERT_MESSAGE("Cannot find a MODE", conf.mode.set()); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find a MODE=standalone", nut::NutConfiguration::MODE_STANDALONE, *conf.mode); - } void NutConfTest::testUpsdConfigParser() @@ -340,7 +341,3 @@ void NutConfTest::testUpsdConfigParser() } } - - - - diff --git a/tests/nutconf_ut.cpp b/tests/nutconf_ut.cpp index 3fc4b2fcdf..a7d7532faf 100644 --- a/tests/nutconf_ut.cpp +++ b/tests/nutconf_ut.cpp @@ -1,22 +1,22 @@ /* -NUT configuration unit test + NUT configuration unit test -Copyright (C) -2012 Vaclav Krpec + Copyright (C) + 2012 Vaclav Krpec -This program 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 2 of the License, or -(at your option) any later version. + This program 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 2 of the License, or + (at your option) any later version. -This program 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. + This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/tests/nutipc_ut.cpp b/tests/nutipc_ut.cpp index eb3a83fec0..aae80a8b18 100644 --- a/tests/nutipc_ut.cpp +++ b/tests/nutipc_ut.cpp @@ -1,23 +1,23 @@ /* -NUT IPC unit test + NUT IPC unit test -Copyright (C) 2012 + Copyright (C) 2012 -\author Vaclav Krpec + \author Vaclav Krpec -This program 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 2 of the License, or -(at your option) any later version. + This program 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 2 of the License, or + (at your option) any later version. -This program 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. + This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/tests/nutstream_ut.cpp b/tests/nutstream_ut.cpp index 11d1d374a1..fabef325ca 100644 --- a/tests/nutstream_ut.cpp +++ b/tests/nutstream_ut.cpp @@ -1,22 +1,22 @@ /* -NUT stream unit test + NUT stream unit test -Copyright (C) -2012 Vaclav Krpec + Copyright (C) + 2012 Vaclav Krpec -This program 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 2 of the License, or -(at your option) any later version. + This program 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 2 of the License, or + (at your option) any later version. -This program 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. + This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index b7bc2ab04f..cc15b4ac1f 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -61,104 +61,104 @@ class Usage { const char * Usage::s_text[] = { -" -h -help", -" --help Display this help and exit", -" --autoconfigure Perform autoconfiguration", -" --is-configured Checks whether NUT is configured", -" --local Sets configuration directory", -" --system Sets configuration directory to " CONFPATH " (default)", -" --get-mode Gets NUT mode (see below)", -" --set-mode Sets NUT mode (see below)", -" --set-monitor Configures one monitor (see below)", -" All existing entries are removed; however, it may be", -" specified multiple times to set multiple entries", -" --add-monitor Same as --set-monitor, but keeps existing entries", -" The two options are mutually exclusive", -" --set-listen [] Configures one listen address for the NUT daemon", -" All existing entries are removed; however, it may be", -" specified multiple times to set multiple entries", -" --add-listen [] Same as --set-listen, but keeps existing entries", -" The two options are mutually exclusive", -" --set-device Configures one UPS device (see below)", -" All existing devices are removed; however, it may be", -" specified multiple times to set multiple devices", -" --add-device Same as --set-device, but keeps existing devices", -" The two options are mutually exclusive", -" --set-notifyflags + Configures notify flags for notification type", -" See below for the types and supported flags", -" Existing flags are replaced", -" --add-notifyflags + Same as --set-notifyflags, but keeps existing flags", -" --set-notifymsg Configures notification message for the type", -" --set-notifycmd Configures notification command", -" --set-shutdowncmd Configures shutdown command", -" --set-minsupplies Configures minimum of required power supplies", -" --set-powerdownflag Configures powerdown flag file", -" --set-user Configures one user (see below)", -" All existing users are removed; however, it may be", -" specified multiple times to set multiple users", -" --add-user Same as --set-user, but keeps existing users", -" The two options are mutually exclusive", -" -v", -" --verbose Increase verbosity of output one level", -" May be specified multiple times", + " -h -help", + " --help Display this help and exit", + " --autoconfigure Perform autoconfiguration", + " --is-configured Checks whether NUT is configured", + " --local Sets configuration directory", + " --system Sets configuration directory to " CONFPATH " (default)", + " --get-mode Gets NUT mode (see below)", + " --set-mode Sets NUT mode (see below)", + " --set-monitor Configures one monitor (see below)", + " All existing entries are removed; however, it may be", + " specified multiple times to set multiple entries", + " --add-monitor Same as --set-monitor, but keeps existing entries", + " The two options are mutually exclusive", + " --set-listen [] Configures one listen address for the NUT daemon", + " All existing entries are removed; however, it may be", + " specified multiple times to set multiple entries", + " --add-listen [] Same as --set-listen, but keeps existing entries", + " The two options are mutually exclusive", + " --set-device Configures one UPS device (see below)", + " All existing devices are removed; however, it may be", + " specified multiple times to set multiple devices", + " --add-device Same as --set-device, but keeps existing devices", + " The two options are mutually exclusive", + " --set-notifyflags + Configures notify flags for notification type", + " See below for the types and supported flags", + " Existing flags are replaced", + " --add-notifyflags + Same as --set-notifyflags, but keeps existing flags", + " --set-notifymsg Configures notification message for the type", + " --set-notifycmd Configures notification command", + " --set-shutdowncmd Configures shutdown command", + " --set-minsupplies Configures minimum of required power supplies", + " --set-powerdownflag Configures powerdown flag file", + " --set-user Configures one user (see below)", + " All existing users are removed; however, it may be", + " specified multiple times to set multiple users", + " --add-user Same as --set-user, but keeps existing users", + " The two options are mutually exclusive", + " -v", + " --verbose Increase verbosity of output one level", + " May be specified multiple times", #if (defined WITH_NUTSCANNER) #if (defined WITH_SNMP) -" --scan-snmp Scan SNMP devices (see below)", -" May be specified multiple times", + " --scan-snmp Scan SNMP devices (see below)", + " May be specified multiple times", #endif // defined WITH_SNMP #if (defined WITH_USB) -" --scan-usb Scan USB devices", + " --scan-usb Scan USB devices", #endif // defined WITH_USB #if (defined WITH_NEON) -" --scan-xml-http [] Scan XML/HTTP devices (optional timeout in us)", + " --scan-xml-http [] Scan XML/HTTP devices (optional timeout in us)", #endif // defined WITH_NEON -" --scan-nut Scan NUT devices (see below for the specs)", -" May be specified multiple times", + " --scan-nut Scan NUT devices (see below for the specs)", + " May be specified multiple times", #if (defined WITH_AVAHI) -" --scan-avahi [] Scan Avahi devices (optional timeout in us)", + " --scan-avahi [] Scan Avahi devices (optional timeout in us)", #endif // defined WITH_AVAHI #if (defined WITH_IPMI) -" --scan-ipmi Scan IPMI devices (see below)", -" May be specified multiple times", + " --scan-ipmi Scan IPMI devices (see below)", + " May be specified multiple times", #endif // defined WITH_IPMI -" --scan-serial * Scan for serial devices on specified ports", + " --scan-serial * Scan for serial devices on specified ports", #endif // defined WITH_NUTSCANNER -"", -"NUT modes: standalone, netserver, netclient, controlled, manual, none", -"Monitor is specified by the following sequence:", -" [:] (\"master\"|\"slave\")", -"UPS device is specified by the following sequence:", -" [=]*", -"Notification types:", -" ONLINE, ONBATT, LOWBATT, FSD, COMMOK, COMMBAD, SHUTDOWN, REPLBATT, NOCOMM, NOPARENT", -"Notification flags:", -" SYSLOG, WALL, EXEC, IGNORE", -"User specification:", -"The very 1st argument is the username (but see the upsmon exception, below).", -"Next arguments use scheme of key/value pairs in form =", -"Known keys are:", -" password, actions (from {SET,FSD}), instcmds (accepted multiple times)", -"Specially, for the upsmon user, the 1st argument takes form of", -" upsmon={master|slave}", + "", + "NUT modes: standalone, netserver, netclient, controlled, manual, none", + "Monitor is specified by the following sequence:", + " [:] (\"master\"|\"slave\")", + "UPS device is specified by the following sequence:", + " [=]*", + "Notification types:", + " ONLINE, ONBATT, LOWBATT, FSD, COMMOK, COMMBAD, SHUTDOWN, REPLBATT, NOCOMM, NOPARENT", + "Notification flags:", + " SYSLOG, WALL, EXEC, IGNORE", + "User specification:", + "The very 1st argument is the username (but see the upsmon exception, below).", + "Next arguments use scheme of key/value pairs in form =", + "Known keys are:", + " password, actions (from {SET,FSD}), instcmds (accepted multiple times)", + "Specially, for the upsmon user, the 1st argument takes form of", + " upsmon={master|slave}", #if (defined WITH_NUTSCANNER) #if (defined WITH_SNMP) -"SNMP device scan specification:", -" [=]*", -"Known attributes are:", -" timeout (in us), community, sec-level, sec-name, auth-password, priv-password,", -" auth-protocol, priv-protocol, peer-name", + "SNMP device scan specification:", + " [=]*", + "Known attributes are:", + " timeout (in us), community, sec-level, sec-name, auth-password, priv-password,", + " auth-protocol, priv-protocol, peer-name", #endif // defined WITH_SNMP -"NUT device scan specification:", -" []", + "NUT device scan specification:", + " []", #if (defined WITH_IPMI) -"IMPI device scan specification:", -" [=]*", -"Known attributes are:", -" username, password, auth-type, cipher-suite-id, K-g-BMC-key, priv-level,", -" workaround-flags, version", + "IMPI device scan specification:", + " [=]*", + "Known attributes are:", + " username, password, auth-type, cipher-suite-id, K-g-BMC-key, priv-level,", + " workaround-flags, version", #endif // defined WITH_IPMI #endif // defined WITH_NUTSCANNER -"", + "", }; @@ -996,7 +996,7 @@ class NutConfOptions: public Options { */ mode_t optMode(const std::string & opt, Arguments & args, size_t order = 0) const; - + /** * \brief Option mode getter * From 84d35177b1dfdb73712aec72a4629bb10fd5f2f4 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 12:20:37 +0100 Subject: [PATCH 079/121] common/nutconf.cpp: NutConfigParser::parseConfig(): pre-initialize "sep" to avoid surporises Signed-off-by: Jim Klimov --- common/nutconf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 644e1b40ba..f3ce0af114 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -406,7 +406,7 @@ void NutConfigParser::parseConfig() { Token tok; std::string name; std::list values; - char sep; + char sep = 0; while (tok = parseToken()) { switch (state) { case CPS_DEFAULT: From ee19b55f11b1553407c48c4a54e8ca620636aa30 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 12:30:03 +0100 Subject: [PATCH 080/121] nutconf related sources: fix deprecated throw() declarations to not be used since C++11 They are invalid in C++17 as the code did fence against; however C++11 already shows them as deprecated, and with "fatal warnings" this bites! Signed-off-by: Jim Klimov --- common/nutipc.cpp | 18 +++- common/nutstream.cpp | 120 +++++++++++++++++---- include/nutconf.h | 2 +- include/nutipc.hpp | 40 ++++--- include/nutstream.hpp | 218 +++++++++++++++++++++++++++++--------- tools/nutconf/nutconf.cpp | 8 +- 6 files changed, 308 insertions(+), 98 deletions(-) diff --git a/common/nutipc.cpp b/common/nutipc.cpp index 5e7759d4f0..8e928a5bf6 100644 --- a/common/nutipc.cpp +++ b/common/nutipc.cpp @@ -29,12 +29,20 @@ namespace nut { -pid_t Process::getPID() throw() { +pid_t Process::getPID() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ return getpid(); } -pid_t Process::getPPID() throw() { +pid_t Process::getPPID() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ return getppid(); } @@ -134,7 +142,7 @@ Process::Executor::Executor(const std::string & command) { int Process::Executor::operator () () -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { @@ -170,7 +178,7 @@ int Process::Executor::operator () () int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { @@ -192,7 +200,7 @@ int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) int Signal::send(Signal::enum_t signame, pid_t pid) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif { diff --git a/common/nutstream.cpp b/common/nutstream.cpp index d096ec8725..1dd4f30118 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -109,7 +109,11 @@ NutFile::NutFile(anonymous_t): } -bool NutFile::exists(int & err_code, std::string & err_msg) const throw() { +bool NutFile::exists(int & err_code, std::string & err_msg) const +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ struct stat info; int status = ::stat(m_name.c_str(), &info); @@ -124,7 +128,11 @@ bool NutFile::exists(int & err_code, std::string & err_msg) const throw() { } -bool NutFile::open(access_t mode, int & err_code, std::string & err_msg) throw() { +bool NutFile::open(access_t mode, int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ static const char *read_only = "r"; static const char *write_only = "w"; static const char *read_write = "r+"; @@ -169,7 +177,11 @@ bool NutFile::open(access_t mode, int & err_code, std::string & err_msg) throw() } -bool NutFile::close(int & err_code, std::string & err_msg) throw() { +bool NutFile::close(int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ err_code = ::fclose(m_impl); if (0 != err_code) { @@ -184,7 +196,11 @@ bool NutFile::close(int & err_code, std::string & err_msg) throw() { } -bool NutFile::remove(int & err_code, std::string & err_msg) throw() { +bool NutFile::remove(int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ err_code = ::unlink(m_name.c_str()); if (0 != err_code) { @@ -210,7 +226,7 @@ NutFile::NutFile(const std::string & name, access_t mode): std::string NutFile::tmpName() -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { @@ -268,7 +284,11 @@ inline static NutStream::status_t fgetcWrapper(FILE * file, char & ch) { } -NutStream::status_t NutFile::getChar(char & ch) throw() { +NutStream::status_t NutFile::getChar(char & ch) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ if (m_current_ch_valid) { ch = m_current_ch; @@ -291,12 +311,20 @@ NutStream::status_t NutFile::getChar(char & ch) throw() { } -void NutFile::readChar() throw() { +void NutFile::readChar() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ m_current_ch_valid = false; } -NutStream::status_t NutFile::getString(std::string & str) throw() { +NutStream::status_t NutFile::getString(std::string & str) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ if (m_current_ch_valid) str += m_current_ch; @@ -323,7 +351,11 @@ NutStream::status_t NutFile::getString(std::string & str) throw() { } -NutStream::status_t NutFile::putChar(char ch) throw() { +NutStream::status_t NutFile::putChar(char ch) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ int c; if (NULL == m_impl) @@ -335,7 +367,11 @@ NutStream::status_t NutFile::putChar(char ch) throw() { } -NutStream::status_t NutFile::putString(const std::string & str) throw() { +NutStream::status_t NutFile::putString(const std::string & str) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ int c; if (NULL == m_impl) @@ -347,7 +383,11 @@ NutStream::status_t NutFile::putString(const std::string & str) throw() { } -NutStream::status_t NutFile::putData(const std::string & data) throw() { +NutStream::status_t NutFile::putData(const std::string & data) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ // Unfortunately, C FILE interface doesn't have non C-string // put function (i.e. function for raw data output with size specifier for (size_t i = 0; i < data.size(); ++i) { @@ -452,7 +492,7 @@ NutSocket::Address::Address( NutSocket::Address::Address(const std::vector & bytes, uint16_t port) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif { @@ -619,7 +659,7 @@ bool NutSocket::accept( const NutSocket & listen_sock, int & err_code, std::string & err_msg) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif { @@ -678,7 +718,11 @@ NutSocket::NutSocket(domain_t dom, type_t type, proto_t proto): } -bool NutSocket::bind(const Address & addr, int & err_code, std::string & err_msg) throw() { +bool NutSocket::bind(const Address & addr, int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ err_code = ::bind(m_impl, addr.m_sock_addr, addr.m_length); if (0 == err_code) @@ -691,7 +735,11 @@ bool NutSocket::bind(const Address & addr, int & err_code, std::string & err_msg } -bool NutSocket::listen(int backlog, int & err_code, std::string & err_msg) throw() { +bool NutSocket::listen(int backlog, int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ err_code = ::listen(m_impl, backlog); if (0 == err_code) @@ -704,7 +752,11 @@ bool NutSocket::listen(int backlog, int & err_code, std::string & err_msg) throw } -bool NutSocket::connect(const Address & addr, int & err_code, std::string & err_msg) throw() { +bool NutSocket::connect(const Address & addr, int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ err_code = ::connect(m_impl, addr.m_sock_addr, addr.m_length); if (0 == err_code) @@ -717,7 +769,11 @@ bool NutSocket::connect(const Address & addr, int & err_code, std::string & err_ } -bool NutSocket::close(int & err_code, std::string & err_msg) throw() { +bool NutSocket::close(int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ err_code = ::close(m_impl); if (0 == err_code) { @@ -739,7 +795,11 @@ NutSocket::~NutSocket() { } -NutStream::status_t NutSocket::getChar(char & ch) throw() { +NutStream::status_t NutSocket::getChar(char & ch) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ if (m_current_ch_valid) { ch = m_current_ch; @@ -771,12 +831,20 @@ NutStream::status_t NutSocket::getChar(char & ch) throw() { } -void NutSocket::readChar() throw() { +void NutSocket::readChar() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ m_current_ch_valid = false; } -NutStream::status_t NutSocket::getString(std::string & str) throw() { +NutStream::status_t NutSocket::getString(std::string & str) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ if (m_current_ch_valid) str += m_current_ch; @@ -798,7 +866,11 @@ NutStream::status_t NutSocket::getString(std::string & str) throw() { } -NutStream::status_t NutSocket::putChar(char ch) throw() { +NutStream::status_t NutSocket::putChar(char ch) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ ssize_t write_cnt = ::write(m_impl, &ch, 1); if (1 == write_cnt) @@ -812,7 +884,11 @@ NutStream::status_t NutSocket::putChar(char ch) throw() { } -NutStream::status_t NutSocket::putString(const std::string & str) throw() { +NutStream::status_t NutSocket::putString(const std::string & str) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif +{ ssize_t str_len = str.size(); // Avoid the costly system call unless necessary diff --git a/include/nutconf.h b/include/nutconf.h index dcfa52992e..bad6ac6f10 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -560,7 +560,7 @@ class GenericConfiguration : public BaseConfiguration, public Serialisable */ template static T range_cast(long long int number, long long int min, long long int max) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::range_error) #endif { diff --git a/include/nutipc.hpp b/include/nutipc.hpp index daf6a24e5f..db7bb16f99 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -55,10 +55,18 @@ class Process { public: /** Get current process ID */ - static pid_t getPID() throw(); + static pid_t getPID() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; /** Get parent process ID */ - static pid_t getPPID() throw(); + static pid_t getPPID() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; /** * Process main routine functor prototype @@ -100,7 +108,7 @@ class Process { * \param main Child process main routine */ Child(M main) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif ; @@ -119,7 +127,7 @@ class Process { * \return Child process exit code */ int wait() -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif ; @@ -193,7 +201,7 @@ class Process { /** Execution of the binary */ int operator () () -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif ; @@ -267,8 +275,8 @@ class Process { template Process::Child::Child(M main) -#if (defined __cplusplus) && (__cplusplus < 201700) -throw(std::runtime_error) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw(std::runtime_error) #endif : m_pid(0), @@ -284,7 +292,7 @@ throw(std::runtime_error) template int Process::Child::wait() -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif { @@ -461,7 +469,7 @@ class Signal { * \param siglist List of signals that shall be handled by the thread */ HandlerThread(const Signal::List & siglist) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error, std::runtime_error) #endif ; @@ -474,7 +482,7 @@ class Signal { * Closes the communication pipe write end. */ void quit() -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif ; @@ -485,7 +493,7 @@ class Signal { * Forces the signal handler thread termination (unless already down). */ ~HandlerThread() -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif ; @@ -505,7 +513,7 @@ class Signal { * \retval ESRCH if the process (group) identified doesn't exist */ static int send(enum_t signame, pid_t pid) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif ; @@ -629,7 +637,7 @@ void * Signal::HandlerThread::main(void * comm_pipe_read_end) { * \retval errno on error */ int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif ; @@ -652,7 +660,7 @@ void Signal::HandlerThread::signalNotifier(int signal) { template Signal::HandlerThread::HandlerThread(const Signal::List & siglist) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error, std::runtime_error) #endif { @@ -711,7 +719,7 @@ Signal::HandlerThread::HandlerThread(const Signal::List & siglist) template void Signal::HandlerThread::quit() -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { @@ -743,7 +751,7 @@ void Signal::HandlerThread::quit() template Signal::HandlerThread::~HandlerThread() -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { diff --git a/include/nutstream.hpp b/include/nutstream.hpp index 553ba591dd..1ec242640a 100644 --- a/include/nutstream.hpp +++ b/include/nutstream.hpp @@ -231,7 +231,7 @@ class NutFile: public NutStream { * \return Temporary file name */ std::string tmpName() -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif ; @@ -273,7 +273,11 @@ class NutFile: public NutStream { * \retval true iff the file exists * \retval false otherwise */ - bool exists(int & err_code, std::string & err_msg) const throw(); + bool exists(int & err_code, std::string & err_msg) const +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; /** * \brief Check whether file exists @@ -281,7 +285,11 @@ class NutFile: public NutStream { * \retval true iff the file exists * \retval false otherwise */ - inline bool exists() const throw() { + inline bool exists() const +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + { int ec; std::string em; @@ -295,7 +303,7 @@ class NutFile: public NutStream { * \retval false otherwise */ inline bool existsx() const -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { @@ -324,7 +332,11 @@ class NutFile: public NutStream { * \retval true if open succeeded * \retval false if open failed */ - bool open(access_t mode, int & err_code, std::string & err_msg) throw(); + bool open(access_t mode, int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; /** * \brief Open file @@ -350,8 +362,8 @@ class NutFile: public NutStream { * \retval false if open failed */ inline void openx(access_t mode = READ_ONLY) -#if (defined __cplusplus) && (__cplusplus < 201700) - throw(std::runtime_error) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw(std::runtime_error) #endif { int ec; @@ -375,7 +387,11 @@ class NutFile: public NutStream { * \retval true if close succeeded * \retval false if close failed */ - bool close(int & err_code, std::string & err_msg) throw(); + bool close(int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; /** * \brief Close file @@ -383,7 +399,11 @@ class NutFile: public NutStream { * \retval true if close succeeded * \retval false if close failed */ - inline bool close() throw() { + inline bool close() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + { int ec; std::string em; @@ -392,8 +412,8 @@ class NutFile: public NutStream { /** Close file (or throw exception) */ inline void closex() -#if (defined __cplusplus) && (__cplusplus < 201700) - throw(std::runtime_error) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw(std::runtime_error) #endif { int ec; @@ -417,7 +437,11 @@ class NutFile: public NutStream { * \retval true if \c unlink succeeded * \retval false if \c unlink failed */ - bool remove(int & err_code, std::string & err_msg) throw(); + bool remove(int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; /** * \brief Remove file @@ -425,7 +449,11 @@ class NutFile: public NutStream { * \retval true if \c unlink succeeded * \retval false if \c unlink failed */ - inline bool remove() throw() { + inline bool remove() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + { int ec; std::string em; @@ -434,8 +462,8 @@ class NutFile: public NutStream { /** Remove file (or throw exception) */ inline void removex() -#if (defined __cplusplus) && (__cplusplus < 201700) - throw(std::runtime_error) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw(std::runtime_error) #endif { int ec; @@ -474,12 +502,41 @@ class NutFile: public NutStream { NutFile(access_t mode = READ_WRITE_CLEAR); // NutStream interface implementation - status_t getChar(char & ch) throw(); - void readChar() throw(); - status_t getString(std::string & str) throw(); - status_t putChar(char ch) throw(); - status_t putString(const std::string & str) throw(); - status_t putData(const std::string & data) throw(); + status_t getChar(char & ch) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; + + void readChar() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; + + status_t getString(std::string & str) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; + + status_t putChar(char ch) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; + + status_t putString(const std::string & str) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; + + status_t putData(const std::string & data) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; /** Destructor (closes the file) */ ~NutFile(); @@ -589,7 +646,11 @@ class NutSocket: public NutStream { * \retval true if the address is valid * \retval false otherwise */ - inline bool valid() throw() { + inline bool valid() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + { return NULL != m_sock_addr; } @@ -628,7 +689,7 @@ class NutSocket: public NutStream { * \param port Port number */ Address(const std::vector & bytes, uint16_t port) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif ; @@ -689,10 +750,10 @@ class NutSocket: public NutStream { const NutSocket & listen_sock, int & err_code, std::string & err_msg) -#if (defined __cplusplus) && (__cplusplus < 201700) - throw(std::logic_error) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw(std::logic_error) #endif - ; + ; /** * \brief Accept client connection on a listen socket @@ -706,7 +767,7 @@ class NutSocket: public NutStream { inline static bool accept( NutSocket & sock, const NutSocket & listen_sock) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif { @@ -725,7 +786,7 @@ class NutSocket: public NutStream { inline static void acceptx( NutSocket & sock, const NutSocket & listen_sock) -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error, std::runtime_error) #endif { @@ -749,7 +810,11 @@ class NutSocket: public NutStream { * \retval true if the socket is initialised * \retval false otherwise */ - inline bool valid() throw() { + inline bool valid() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + { return -1 != m_impl; } @@ -808,7 +873,11 @@ class NutSocket: public NutStream { * \retval true on success * \retval false on error */ - bool bind(const Address & addr, int & err_code, std::string & err_msg) throw(); + bool bind(const Address & addr, int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; /** * \brief Bind socket to an address @@ -818,7 +887,11 @@ class NutSocket: public NutStream { * \retval true on success * \retval false on error */ - inline bool bind(const Address & addr) throw() { + inline bool bind(const Address & addr) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + { int ec; std::string em; @@ -831,8 +904,8 @@ class NutSocket: public NutStream { * \param addr Socket address */ inline void bindx(const Address & addr) -#if (defined __cplusplus) && (__cplusplus < 201700) - throw(std::runtime_error) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw(std::runtime_error) #endif { int ec; @@ -859,7 +932,11 @@ class NutSocket: public NutStream { * \retval true on success * \retval false on error */ - bool listen(int backlog, int & err_code, std::string & err_msg) throw(); + bool listen(int backlog, int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; /** * \brief Listen on socket @@ -869,7 +946,11 @@ class NutSocket: public NutStream { * \retval true on success * \retval false on error */ - inline bool listen(int backlog) throw() { + inline bool listen(int backlog) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + { int ec; std::string em; @@ -882,8 +963,8 @@ class NutSocket: public NutStream { * \param[in] backlog Limit of pending connections */ inline void listenx(int backlog) -#if (defined __cplusplus) && (__cplusplus < 201700) - throw(std::runtime_error) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw(std::runtime_error) #endif { int ec; @@ -908,7 +989,11 @@ class NutSocket: public NutStream { * \retval true on success * \retval false on error */ - bool connect(const Address & addr, int & err_code, std::string & err_msg) throw(); + bool connect(const Address & addr, int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; /** * \brief Connect to a listen socket @@ -918,7 +1003,11 @@ class NutSocket: public NutStream { * \retval true on success * \retval false on error */ - inline bool connect(const Address & addr) throw() { + inline bool connect(const Address & addr) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + { int ec; std::string em; @@ -931,8 +1020,8 @@ class NutSocket: public NutStream { * \param[in] addr Remote address */ inline void connectx(const Address & addr) -#if (defined __cplusplus) && (__cplusplus < 201700) - throw(std::runtime_error) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw(std::runtime_error) #endif { int ec; @@ -956,7 +1045,11 @@ class NutSocket: public NutStream { * \retval true if close succeeded * \retval false if close failed */ - bool close(int & err_code, std::string & err_msg) throw(); + bool close(int & err_code, std::string & err_msg) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; /** * \brief Close socket @@ -964,7 +1057,11 @@ class NutSocket: public NutStream { * \retval true if close succeeded * \retval false if close failed */ - inline bool close() throw() { + inline bool close() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + { int ec; std::string em; @@ -973,8 +1070,8 @@ class NutSocket: public NutStream { /** Close socket (or throw exception) */ inline void closex() -#if (defined __cplusplus) && (__cplusplus < 201700) - throw(std::runtime_error) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw(std::runtime_error) #endif { int ec; @@ -990,11 +1087,32 @@ class NutSocket: public NutStream { } // NutStream interface implementation - status_t getChar(char & ch) throw(); - void readChar() throw(); - status_t getString(std::string & str) throw(); - status_t putChar(char ch) throw(); - status_t putString(const std::string & str) throw(); + status_t getChar(char & ch) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; + void readChar() +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; + status_t getString(std::string & str) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; + status_t putChar(char ch) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; + status_t putString(const std::string & str) +#if (defined __cplusplus) && (__cplusplus < 201100) + throw() +#endif + ; + inline status_t putData(const std::string & data) { return putString(data); // no difference on sockets } diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index cc15b4ac1f..afa61765b8 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -1136,7 +1136,7 @@ class NutConfOptions: public Options { * Check that using the \ref valid flag. */ void reportInvalid() const -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif ; @@ -1176,7 +1176,7 @@ class NutConfOptions: public Options { std::string & passwd, std::string & mode, size_t which = 0) const -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::range_error) #endif ; @@ -1677,7 +1677,7 @@ NutConfOptions::~NutConfOptions() { void NutConfOptions::reportInvalid() const -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif { @@ -1881,7 +1881,7 @@ void NutConfOptions::getMonitor( std::string & passwd, std::string & mode, size_t which) const -#if (defined __cplusplus) && (__cplusplus < 201700) +#if (defined __cplusplus) && (__cplusplus < 201100) throw(std::range_error) #endif { From 248d893ce9072b65504d3b1bd87b566b37b8e817 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 13:23:00 +0100 Subject: [PATCH 081/121] nutconf related sources: fix typos and wording in comments Signed-off-by: Jim Klimov --- common/nutconf.cpp | 22 +++++++++---------- common/nutstream.cpp | 4 ++-- common/nutwriter.cpp | 40 +++++++++++++++++----------------- include/nutconf.h | 20 ++++++++--------- include/nutipc.hpp | 18 ++++++++-------- include/nutstream.hpp | 30 +++++++++++++------------- include/nutwriter.hpp | 44 +++++++++++++++++++------------------- tests/nutconf.cpp | 2 +- tests/nutconf_ut.cpp | 10 ++++----- tools/nutconf/nutconf.cpp | 45 ++++++++++++++++++++------------------- 10 files changed, 117 insertions(+), 118 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index f3ce0af114..edb9ce6468 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -611,16 +611,16 @@ NutConfigParser(buffer) { } void DefaultConfigParser::onParseBegin() { - // Start with empty section (ie global one) + // Start with empty section (i.e. global one) _section.clear(); } void DefaultConfigParser::onParseComment(const std::string& /*comment*/) { - // Comment are ignored for now + // Comments are ignored for now } void DefaultConfigParser::onParseSectionName(const std::string& sectionName, const std::string& /*comment*/) { - // Comment are ignored for now + // Comments are ignored for now // Process current section. if (!_section.empty()) { @@ -633,7 +633,7 @@ void DefaultConfigParser::onParseSectionName(const std::string& sectionName, con } void DefaultConfigParser::onParseDirective(const std::string& directiveName, char /*sep*/, const ConfigParamList& values, const std::string& /*comment*/) { - // Comment are ignored for now + // Comments are ignored for now // Separator has no specific semantic in this context // Save values @@ -1023,12 +1023,12 @@ void UpsmonConfigParser::onParseBegin() void UpsmonConfigParser::onParseComment(const std::string& /*comment*/) { - // Comment are ignored for now + // Comments are ignored for now } void UpsmonConfigParser::onParseSectionName(const std::string& /*sectionName*/, const std::string& /*comment*/) { - // There must not have sections in upsm.conf. + // There must not be sections in upsmon.conf. // Ignore it // TODO Add error reporting ? } @@ -1270,19 +1270,19 @@ void NutConfConfigParser::onParseBegin() void NutConfConfigParser::onParseComment(const std::string& /*comment*/) { - // Comment are ignored for now + // Comments are ignored for now } void NutConfConfigParser::onParseSectionName(const std::string& /*sectionName*/, const std::string& /*comment*/) { - // There must not have sections in upsm.conf. + // There must not be sections in nutconf.conf. // Ignore it // TODO Add error reporting ? } void NutConfConfigParser::onParseDirective(const std::string& directiveName, char /*sep*/, const ConfigParamList& values, const std::string& /*comment*/) { - // Comment are ignored for now + // Comments are ignored for now // NOTE: although sep must be '=', sep is not verified. if(_config && directiveName=="MODE" && values.size()==1) { @@ -1371,12 +1371,12 @@ void UpsdConfigParser::onParseBegin() void UpsdConfigParser::onParseComment(const std::string& comment) { - // Comment are ignored for now + // Comments are ignored for now } void UpsdConfigParser::onParseSectionName(const std::string& sectionName, const std::string& comment) { - // There must not have sections in upsm.conf. + // There must not be sections in upsd.conf. // Ignore it // TODO Add error reporting ? } diff --git a/common/nutstream.cpp b/common/nutstream.cpp index 1dd4f30118..f44a8b25a6 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -584,7 +584,7 @@ static std::string formatIPv6addr(unsigned char const bytes[16]) { } // Standard form - // TODO: ommition of lengthy zero word strings + // TODO: ommition (REVIEW: omission?) of lengthy zero word strings ss << std::uppercase << std::hex << std::setfill('0'); for (size_t i = 0; ; ) { @@ -904,7 +904,7 @@ NutStream::status_t NutSocket::putString(const std::string & str) // string might be written // Review the code if async. I/O is supported (in which case // the function shall have to implement the blocking using - // select/ poll/ epoll on its own (probably select for portability) + // select/poll/epoll on its own (probably select for portability) assert(-1 == write_cnt); diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index ee5a352816..ec640e38ee 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -136,7 +136,7 @@ NutWriter::status_t NutConfConfigWriter::writeConfig(const NutConfiguration & co status_t status; // Mode - // TBD: How should I serialise an unknown mode? + // TBD: How should I serialize an unknown mode? if (config.mode.set()) { std::string mode_str; @@ -199,7 +199,7 @@ struct NotifyFlagsStrings { static const FlagStrings flag_str; /** - * \brief Initialise notify flag strings + * \brief Initialize notify flag strings * * \return Notify flag strings map */ @@ -236,14 +236,14 @@ const NotifyFlagsStrings::FlagStrings NotifyFlagsStrings::flag_str = /** - * \brief upsmon notify flags serialiser + * \brief upsmon notify flags serializer * * \param type Notification type * \param flags Notification flags * * \return NOTIFYFLAG directive string */ -static std::string serialiseNotifyFlags(UpsmonConfiguration::NotifyType type, unsigned short flags) { +static std::string serializeNotifyFlags(UpsmonConfiguration::NotifyType type, unsigned short flags) { static const NotifyFlagsStrings::FlagStrings::const_iterator ignore_str_iter = NotifyFlagsStrings::flag_str.find(UpsmonConfiguration::NOTIFY_IGNORE); @@ -282,14 +282,14 @@ static std::string serialiseNotifyFlags(UpsmonConfiguration::NotifyType type, un /** - * \brief upsmon notify messages serialiser + * \brief upsmon notify messages serializer * * \param type Notification type * \param msg Notification message * * \return NOTIFYMSG directive string */ -static std::string serialiseNotifyMessage(UpsmonConfiguration::NotifyType type, const std::string & msg) { +static std::string serializeNotifyMessage(UpsmonConfiguration::NotifyType type, const std::string & msg) { assert(type < UpsmonConfiguration::NOTIFY_TYPE_MAX); std::string directive("NOTIFYMSG "); @@ -321,7 +321,7 @@ inline static UpsmonConfiguration::NotifyType nextNotifyType(UpsmonConfiguration /** - * \brief Notify type pre-incrementation + * \brief Notify type pre-increment * * TBD: Should be in nutconf.h * @@ -335,7 +335,7 @@ inline static UpsmonConfiguration::NotifyType operator ++(UpsmonConfiguration::N /** - * \brief Notify type post-incrementation + * \brief Notify type post-increment * * TBD: Should be in nutconf.h * @@ -353,13 +353,13 @@ inline static UpsmonConfiguration::NotifyType operator ++(UpsmonConfiguration::N /** - * \brief UPS monitor definition serialiser + * \brief UPS monitor definition serializer * * \param monitor Monitor * * \return Monitor config. directive */ -static std::string serialiseMonitor(const UpsmonConfiguration::Monitor & monitor) { +static std::string serializeMonitor(const UpsmonConfiguration::Monitor & monitor) { std::stringstream directive; directive << "MONITOR "; @@ -427,7 +427,7 @@ NutWriter::status_t UpsmonConfigWriter::writeConfig(const UpsmonConfiguration & for (; type < UpsmonConfiguration::NOTIFY_TYPE_MAX; ++type) { if (config.notifyFlags[type].set()) { - std::string directive = serialiseNotifyFlags(type, config.notifyFlags[type]); + std::string directive = serializeNotifyFlags(type, config.notifyFlags[type]); status_t status = writeDirective(directive); @@ -441,7 +441,7 @@ NutWriter::status_t UpsmonConfigWriter::writeConfig(const UpsmonConfiguration & for (; type < UpsmonConfiguration::NOTIFY_TYPE_MAX; ++type) { if (config.notifyMessages[type].set()) { - std::string directive = serialiseNotifyMessage(type, config.notifyMessages[type]); + std::string directive = serializeNotifyMessage(type, config.notifyMessages[type]); status_t status = writeDirective(directive); @@ -454,7 +454,7 @@ NutWriter::status_t UpsmonConfigWriter::writeConfig(const UpsmonConfiguration & std::list::const_iterator mon_iter = config.monitors.begin(); for (; mon_iter != config.monitors.end(); ++mon_iter) { - std::string directive = serialiseMonitor(*mon_iter); + std::string directive = serializeMonitor(*mon_iter); status_t status = writeDirective(directive); @@ -467,13 +467,13 @@ NutWriter::status_t UpsmonConfigWriter::writeConfig(const UpsmonConfiguration & /** - * \brief upsd listen address serialiser + * \brief upsd listen address serializer * * \param address Listen address * - * \return Serialised listen address + * \return Serialized listen address */ -static std::string serialiseUpsdListenAddress(const UpsdConfiguration::Listen & address) { +static std::string serializeUpsdListenAddress(const UpsdConfiguration::Listen & address) { std::stringstream directive; directive << "LISTEN " << address.address; @@ -514,7 +514,7 @@ NutWriter::status_t UpsdConfigWriter::writeConfig(const UpsdConfiguration & conf std::list::const_iterator la_iter = config.listens.begin(); for (; la_iter != config.listens.end(); ++la_iter) { - std::string directive = serialiseUpsdListenAddress(*la_iter); + std::string directive = serializeUpsdListenAddress(*la_iter); status_t status = writeDirective(directive); @@ -554,7 +554,7 @@ NutWriter::status_t DefaultConfigWriter::writeDirective(const std::string & str) * * \param val Value string * - * \return Value string ready for serialisation + * \return Value string ready for serialization */ static std::string encodeValue(const std::string & val) { // Check the string for spaces and '=' @@ -644,7 +644,7 @@ NutWriter::status_t GenericConfigWriter::writeSection(const GenericConfigSection NutWriter::status_t GenericConfigWriter::writeConfig(const GenericConfiguration & config) { // Write sections // Note that lexicographic ordering places the global - // (i.e. empty-name) section as the 1st one + // (i.e. empty-name) section as the first one GenericConfiguration::SectionMap::const_iterator section_iter = config.sections.begin(); for (; section_iter != config.sections.end(); ++section_iter) { @@ -689,7 +689,7 @@ NutWriter::status_t UpsdUsersConfigWriter::writeSection(const GenericConfigSecti upsmon_entry_separator); } - // Standard entry serialisation + // Standard entry serialization else { status = writeSectionEntry(entry_iter->second); } diff --git a/include/nutconf.h b/include/nutconf.h index bad6ac6f10..f4b02a0bad 100644 --- a/include/nutconf.h +++ b/include/nutconf.h @@ -94,8 +94,8 @@ class Settable /** * \brief Serialisable interface * - * Classes that implement this iface provide way to serialise - * and deserialise instances to/from streams. + * Classes that implement this interface provide way to serialize + * and deserialize instances to/from streams. */ class Serialisable { @@ -107,7 +107,7 @@ class Serialisable public: /** - * \brief Deserialiser + * \brief Deserializer * * \param istream Input stream * @@ -117,7 +117,7 @@ class Serialisable virtual bool parseFrom(NutStream & istream) = 0; /** - * \brief Serialiser + * \brief Serializer * * \param ostream Output stream * @@ -142,7 +142,7 @@ class NutParser { OPTION_DEFAULT = 0, /** Colon character is considered as string character and not as specific token. - Usefull for IPv6 addresses */ + Useful for IPv6 addresses */ OPTION_IGNORE_COLON = 1 }; @@ -317,7 +317,7 @@ class GenericConfiguration : public BaseConfiguration, public Serialisable bool writeTo(NutStream & ostream) const; /** \} */ - // FIXME Let me public or set it as protected with public accessors ? + // FIXME Let be public or set it as protected with public accessors ? SectionMap sections; const GenericConfigSection& operator[](const std::string& secname)const{return sections.find(secname)->second;} @@ -556,7 +556,7 @@ class GenericConfiguration : public BaseConfiguration, public Serialisable * \param min Minimum * \param max Maximum * - * \return \c number casted to target type + * \return \c number which was cast to target type */ template static T range_cast(long long int number, long long int min, long long int max) @@ -588,17 +588,17 @@ class GenericConfiguration : public BaseConfiguration, public Serialisable * * \param str String * - * \retval true iff the string expresses a known true value + * \retval true IFF the string expresses a known true value * \retval false otherwise */ static bool str2bool(const std::string & str); /** - * \brief Convert boolean value to string + * \brief Convert Boolean value to string * * \param val Boolean value * - * \return \c vla as string + * \return \c val as string */ static const std::string & bool2str(bool val); diff --git a/include/nutipc.hpp b/include/nutipc.hpp index db7bb16f99..72d87711c4 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -347,9 +347,9 @@ class Signal { CHILD = SIGCHLD, /** Child stopped or terminated */ CONT = SIGCONT, /** Continue if stopped */ STOP = SIGSTOP, /** Stop process (unmaskable) */ - TSTOP = SIGTSTP, /** Stop typed at tty */ - TTYIN = SIGTTIN, /** tty input for background process */ - TTYOUT = SIGTTOU, /** tty output for background process */ + TSTOP = SIGTSTP, /** Stop typed at TTY */ + TTYIN = SIGTTIN, /** TTY input for background process */ + TTYOUT = SIGTTOU, /** TTY output for background process */ PROF = SIGPROF, /** Profiling timer expired */ SYS = SIGSYS, /** Bad argument to routine */ URG = SIGURG, /** Urgent condition on socket */ @@ -436,10 +436,10 @@ class Signal { * The function simply writes the signal number to the signal handler * thread communication pipe (as parameter of the \ref SIGNAL command). * The signal handling itself (whatever necessary) shall be done - * by the dedicated thread (to avoid possible re-entrancy issues). + * by the dedicated thread (to avoid possible re-entrance issues). * * Note that \c ::write is required to be an async-signal-safe function by - * POSIX.1-2004; also note that up to \c PIPE_BUF bytes are written atomicaly + * POSIX.1-2004; also note that up to \c PIPE_BUF bytes are written atomically * as required by IEEE Std 1003.1, 2004 Edition,\c PIPE_BUF being typically * hundreds of bytes at least (POSIX requires 512B, Linux provides whole 4KiB * page). @@ -536,7 +536,7 @@ class Signal { }; // end of class Signal -/** Initialisation of the communication pipes */ +/** Initialization of the communication pipes */ template int Signal::HandlerThread::s_comm_pipe[2] = { -1, -1 }; @@ -629,9 +629,9 @@ void * Signal::HandlerThread::main(void * comm_pipe_read_end) { /** * \brief Write command to command pipe * - * \param fh Pipe writing end + * \param fh Pipe writing end (file handle) * \param cmd Command - * \param cmd_size Comand size + * \param cmd_size Command size * * \retval 0 on success * \retval errno on error @@ -653,7 +653,7 @@ void Signal::HandlerThread::signalNotifier(int signal) { // TBD: The return value is silently ignored. // Either the write should've succeeded or the handling - // thread is already comming down... + // thread is already coming down... sigPipeWriteCmd(s_comm_pipe[1], sig, sizeof(sig)); } diff --git a/include/nutstream.hpp b/include/nutstream.hpp index 1ec242640a..83a7f22750 100644 --- a/include/nutstream.hpp +++ b/include/nutstream.hpp @@ -44,7 +44,7 @@ namespace nut /** * \brief Data stream interface * - * The intarface provides character-based streamed I/O. + * The interface provides character-based streamed I/O. */ class NutStream { public: @@ -53,7 +53,7 @@ class NutStream { typedef enum { NUTS_OK = 0, /** Operation successful */ NUTS_EOF, /** End of stream reached */ - NUTS_ERROR, /** Error ocurred */ + NUTS_ERROR, /** Error occurred */ } status_t; protected: @@ -127,7 +127,7 @@ class NutStream { * \brief Put data to the stream end * * The difference between \ref putString and this method - * is that it is able to serialise also data containing + * is that it is able to serialize also data containing * null characters. * * \param[in] data Data @@ -270,7 +270,7 @@ class NutFile: public NutStream { * \param[out] err_code Error code * \param[out] err_msg Error message * - * \retval true iff the file exists + * \retval true IFF the file exists * \retval false otherwise */ bool exists(int & err_code, std::string & err_msg) const @@ -282,7 +282,7 @@ class NutFile: public NutStream { /** * \brief Check whether file exists * - * \retval true iff the file exists + * \retval true IFF the file exists * \retval false otherwise */ inline bool exists() const @@ -299,7 +299,7 @@ class NutFile: public NutStream { /** * \brief Check whether file exists (or throw exception) * - * \retval true iff the file exists + * \retval true IFF the file exists * \retval false otherwise */ inline bool existsx() const @@ -613,7 +613,7 @@ class NutSocket: public NutStream { Address(): m_sock_addr(NULL), m_length(0) {} /** - * \brief Initialise UNIX socket address + * \brief Initialize UNIX socket address * * \param addr UNIX socket address * \param path Pathname @@ -621,7 +621,7 @@ class NutSocket: public NutStream { static void init_unix(Address & addr, const std::string & path); /** - * \brief Initialise IPv4 address + * \brief Initialize IPv4 address * * \param addr IPv4 address * \param qb Byte quadruplet (MSB is at index 0) @@ -630,7 +630,7 @@ class NutSocket: public NutStream { static void init_ipv4(Address & addr, const std::vector & qb, uint16_t port); /** - * \brief Initialise IPv6 address + * \brief Initialize IPv6 address * * \param addr IPv6 address * \param hb 16 bytes of the address (MSB is at index 0) @@ -667,8 +667,8 @@ class NutSocket: public NutStream { * \brief IPv4 address constructor * * \param msb Most significant byte - * \param msb2 2nd most significant byte - * \param lsb2 2nd least significant byte + * \param msb2 Second most significant byte + * \param lsb2 Second least significant byte * \param lsb Least significant byte * \param port Port number */ @@ -682,8 +682,8 @@ class NutSocket: public NutStream { * \brief IP address constructor * * Creates either IPv4 or IPv6 address (depending on - * how many bytes are provided bia the \c bytes argument). - * Throws an exception if the bytecount is invalid. + * how many bytes are provided via the \c bytes argument). + * Throws an exception if the byte-count is invalid. * * \param bytes 4 or 16 address bytes (MSB is at index 0) * \param port Port number @@ -708,7 +708,7 @@ class NutSocket: public NutStream { */ std::string str() const; - /** Stringifisation */ + /** Stringification */ inline operator std::string() const { return str(); } @@ -807,7 +807,7 @@ class NutSocket: public NutStream { /** * \brief Socket valid check * - * \retval true if the socket is initialised + * \retval true if the socket is initialized * \retval false otherwise */ inline bool valid() diff --git a/include/nutwriter.hpp b/include/nutwriter.hpp index 7a60f4ab39..e2db9fb221 100644 --- a/include/nutwriter.hpp +++ b/include/nutwriter.hpp @@ -126,7 +126,7 @@ class NutWriter { /** - * \brief NUT consfiguration writer interface + * \brief NUT configuration writer interface */ class NutConfigWriter: public NutWriter { protected: @@ -173,9 +173,9 @@ class NutConfigWriter: public NutWriter { /** - * \brief NUT section-less configuration writer specialisation + * \brief NUT section-less configuration writer specialization * - * Partial implementaton of \ref NutConfigWriter for section-less + * Partial implementation of \ref NutConfigWriter for section-less * configuration files. */ class SectionlessConfigWriter: public NutConfigWriter { @@ -203,7 +203,7 @@ class SectionlessConfigWriter: public NutConfigWriter { /** - * \brief \c nut.conf configuration file serialiser + * \brief \c nut.conf configuration file serializer */ class NutConfConfigWriter: public SectionlessConfigWriter { public: @@ -216,7 +216,7 @@ class NutConfConfigWriter: public SectionlessConfigWriter { NutConfConfigWriter(NutStream & ostream): SectionlessConfigWriter(ostream) {} /** - * \brief Serialise configuration container + * \brief Serialize configuration container * * \param config Configuration * @@ -229,7 +229,7 @@ class NutConfConfigWriter: public SectionlessConfigWriter { /** - * \brief \c upsmon.conf configuration file serialiser + * \brief \c upsmon.conf configuration file serializer */ class UpsmonConfigWriter: public SectionlessConfigWriter { public: @@ -242,7 +242,7 @@ class UpsmonConfigWriter: public SectionlessConfigWriter { UpsmonConfigWriter(NutStream & ostream): SectionlessConfigWriter(ostream) {} /** - * \brief Serialise configuration container + * \brief Serialize configuration container * * \param config Configuration * @@ -255,7 +255,7 @@ class UpsmonConfigWriter: public SectionlessConfigWriter { /** - * \brief \c upsd.conf configuration file serialiser + * \brief \c upsd.conf configuration file serializer */ class UpsdConfigWriter: public SectionlessConfigWriter { public: @@ -268,7 +268,7 @@ class UpsdConfigWriter: public SectionlessConfigWriter { UpsdConfigWriter(NutStream & ostream): SectionlessConfigWriter(ostream) {} /** - * \brief Serialise configuration container + * \brief Serialize configuration container * * \param config Configuration * @@ -307,7 +307,7 @@ class DefaultConfigWriter: public NutConfigWriter { /** * \brief Write configuration section * - * Serialise generic configuration section. + * Serialize generic configuration section. * * \param section Configuration section * @@ -322,25 +322,25 @@ class DefaultConfigWriter: public NutConfigWriter { /** * \brief NUT generic configuration writer * - * Base configuration file serialiser. + * Base configuration file serializer. * Implements the \ref DefaultConfigWriter \c writeSection method - * and adds \c writeConfig routine for configuration file serialisation. + * and adds \c writeConfig routine for configuration file serialization. */ class GenericConfigWriter: public DefaultConfigWriter { protected: - /** Default indentation of the key/ value pair in section entry */ + /** Default indentation of the key/value pair in section entry */ static const std::string s_default_section_entry_indent; - /** Default separator of the key/ value pair in section entry */ + /** Default separator of the key/value pair in section entry */ static const std::string s_default_section_entry_separator; /** - * \brief Section entry serialiser + * \brief Section entry serializer * * \param entry Section entry * \param indent Indentation - * \param kv_sep Key/ value separator + * \param kv_sep Key/value separator * * \retval NUTW_OK on success * \retval NUTW_ERROR otherwise @@ -359,11 +359,11 @@ class GenericConfigWriter: public DefaultConfigWriter { */ GenericConfigWriter(NutStream & ostream): DefaultConfigWriter(ostream) {} - // Section serialiser implementation + // Section serializer implementation status_t writeSection(const GenericConfigSection & section); /** - * \brief Base configuration serialiser + * \brief Base configuration serializer * * \param config Base configuration * @@ -378,9 +378,9 @@ class GenericConfigWriter: public DefaultConfigWriter { /** * \brief NUT upsd.users configuration file writer * - * upsd.users configuration file serialiser. - * Overloads the generic section serialiser because of the upsmon section, - * which contains anomal upsmon (master|slave) directive. + * upsd.users configuration file serializer. + * Overloads the generic section serializer because of the upsmon section, + * which contains an anomalous upsmon (master|slave) directive. */ class UpsdUsersConfigWriter: public GenericConfigWriter { public: @@ -392,7 +392,7 @@ class UpsdUsersConfigWriter: public GenericConfigWriter { */ UpsdUsersConfigWriter(NutStream & ostream): GenericConfigWriter(ostream) {} - // Section serialiser overload + // Section serializer overload status_t writeSection(const GenericConfigSection & section); }; // end of class UpsdUsersConfigWriter diff --git a/tests/nutconf.cpp b/tests/nutconf.cpp index 028b8bd58b..18029b6432 100644 --- a/tests/nutconf.cpp +++ b/tests/nutconf.cpp @@ -21,7 +21,7 @@ #include -// Define to desactivate protection of parsing tool members: +// Define to de-activate protection of parsing tool members: #define UNITEST_MODE 1 #include "nutconf.h" diff --git a/tests/nutconf_ut.cpp b/tests/nutconf_ut.cpp index a7d7532faf..1ee8f24ade 100644 --- a/tests/nutconf_ut.cpp +++ b/tests/nutconf_ut.cpp @@ -19,14 +19,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - #include "nutstream.hpp" #include "nutconf.h" #include "nutwriter.hpp" #include - /** * \brief NUT configuration unit test */ @@ -46,10 +44,10 @@ class NutConfigUnitTest: public CppUnit::TestFixture { void load(nut::Serialisable * config, const std::string & file_name); /** - * \brief Check configuration serialisation contents + * \brief Check configuration serialization contents * * \param config Configuration object - * \param content Expected serialisation + * \param content Expected serialization */ void check(const nut::Serialisable * config, const std::string & content); @@ -108,9 +106,9 @@ void NutConfigUnitTest::check(const nut::Serialisable * config, const std::strin if (content != str) { std::cerr << "--- expected ---" << std::endl << content << "--- end ---" << std::endl; - std::cerr << "--- serialised ---" << std::endl << str << "--- end ---" << std::endl; + std::cerr << "--- serialized ---" << std::endl << str << "--- end ---" << std::endl; - CPPUNIT_ASSERT_MESSAGE("Configuration serialisation check failed", 0); + CPPUNIT_ASSERT_MESSAGE("Configuration serialization check failed", 0); } } diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index afa61765b8..369451e4f3 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -63,7 +63,7 @@ class Usage { const char * Usage::s_text[] = { " -h -help", " --help Display this help and exit", - " --autoconfigure Perform autoconfiguration", + " --autoconfigure Perform automatic configuration", " --is-configured Checks whether NUT is configured", " --local Sets configuration directory", " --system Sets configuration directory to " CONFPATH " (default)", @@ -246,7 +246,7 @@ class Options { * \param[out] args Option arguments * \param[in] order Option order (1st by default) * - * \retval true iff the option was specified on the command line + * \retval true IFF the option was specified on the command line * \retval false otherwise */ bool get(const Map & map, const std::string & opt, Arguments & args, size_t order = 0) const; @@ -316,7 +316,7 @@ class Options { * * \param opt Option * - * \retval true iff the option was specified on the command line + * \retval true IFF the option was specified on the command line * \retval false otherwise */ inline bool existsSingle(const std::string & opt) const { @@ -328,7 +328,7 @@ class Options { * * \param opt Option * - * \retval true iff the option was specified on the command line + * \retval true IFF the option was specified on the command line * \retval false otherwise */ inline bool existsDouble(const std::string & opt) const { @@ -340,7 +340,7 @@ class Options { * * \param opt Option * - * \retval true iff the option was specified on the command line + * \retval true IFF the option was specified on the command line * \retval false otherwise */ inline bool exists(const std::string & opt) const { @@ -354,7 +354,7 @@ class Options { * \param[out] args Option arguments * \param[in] order Option order (1st by default) * - * \retval true iff the option was specified on the command line + * \retval true IFF the option was specified on the command line * \retval false otherwise */ inline bool getSingle(const std::string & opt, Arguments & args, size_t order = 0) const { @@ -368,7 +368,7 @@ class Options { * \param[out] args Option arguments * \param[in] order Option order (1st by default) * - * \retval true iff the option was specified on the command line + * \retval true IFF the option was specified on the command line * \retval false otherwise */ inline bool getDouble(const std::string & opt, Arguments & args, size_t order = 0) const { @@ -519,7 +519,8 @@ Options::Options(char * const argv[], int argc): m_last(NULL) { const std::string arg(argv[i]); // Empty string is the current option argument, too - // '-' alone is also an option argument // (like stdout placeholder etc) + // '-' alone is also an option argument + // (like stdout placeholder etc) if (arg.empty() || '-' != arg[0] || 1 == arg.size()) addArg(arg); @@ -635,17 +636,17 @@ class NutScanner { private: - /** NUT scanner initialisation/finalisation */ + /** NUT scanner initialization/finalization */ struct InitFinal { - /** Initialisation */ + /** Initialization */ InitFinal() { nutscan_init(); } - /** Finalisation */ + /** Finalization */ ~InitFinal() { nutscan_free(); } }; // end of struct InitFinal - /** Initialiser / finaliser */ + /** Initializer / finalizer */ static InitFinal s_init_final; /** @@ -655,7 +656,7 @@ class NutScanner { * * \param dev_list nut-scan provided device list * - * \return Dvice info list + * \return Device info list */ static devices_t dev2list(nutscan_device_t * dev_list); @@ -871,7 +872,7 @@ NutScanner::devices_t NutScanner::devicesIPMI( ::memset(&ipmi_attrs, 0, sizeof(ipmi_attrs)); - // TBD: const casting is necessery + // TBD: const casting is necessary // Shouldn't the nutscan_ipmi_t C-string items be constant? if (!attrs.username.empty()) @@ -1188,7 +1189,7 @@ class NutConfOptions: public Options { * * \param mode Mode argument * - * \retval true iff the mode is set correctly + * \retval true IFF the mode is set correctly * \retval false otherwise */ static bool checkMode(const std::string & mode); @@ -1247,7 +1248,7 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): static const std::string sDash("-"); static const std::string dDash("--"); - // Specificate single-dashed options + // Specify single-dashed options List list = stringsSingle(); for (List::const_iterator opt = list.begin(); opt != list.end(); ++opt) { @@ -1262,7 +1263,7 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): } } - // Specificate double-dashed options + // Specify double-dashed options list = stringsDouble(); for (List::const_iterator opt = list.begin(); opt != list.end(); ++opt) { @@ -1632,7 +1633,7 @@ NutConfOptions::NutConfOptions(char * const argv[], int argc): } } - // Options are valid iff we know all of them + // Options are valid IFF we know all of them // and there are no direct binary arguments valid = m_unknown.empty() && m_errors.empty() && get().empty(); @@ -1725,7 +1726,7 @@ bool NutConfOptions::checkMode(const std::string & mode) { * The template class is useful in situation where you need to * create a dynamic object, process its attributes and automatically * destroy it in case of error simply by leaving the scope - * (i.e. not having to warry about calling \c delete by hand). + * (i.e. not having to worry about calling \c delete by hand). */ template class autodelete_ptr { @@ -1965,7 +1966,7 @@ void store(nut::Serialisable * config, const std::string & file_name) { * * \param etc Configuration directory * - * \retval true iff nut.conf exists and MODE != none + * \retval true IFF nut.conf exists and MODE != none * \retval false otherwise */ bool isConfigured(const std::string & etc) { @@ -2364,7 +2365,7 @@ void setNotifyMsgs( /** * \brief Set notify command in upsmon.conf * - * \param cmd otify command + * \param cmd Notify command * \param etc Configuration directory */ void setNotifyCmd(const std::string & cmd, const std::string & etc) @@ -3194,7 +3195,7 @@ int main(int argc, char * const argv[]) { catch (...) { std::cerr << "INTERNAL ERROR: exception of unknown origin caught" << std::endl - << "Please issue a bugreport to nut-upsdev@lists.alioth.debian.org" + << "Please issue a bug report to nut-upsdev@lists.alioth.debian.org" << std::endl; } From b0732a5833497209bec87f36aafdc394d97ce766 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 13:36:03 +0100 Subject: [PATCH 082/121] Rename include/nutconf.h => .hpp as a C++ specific source file Signed-off-by: Jim Klimov --- common/nutconf.cpp | 2 +- common/nutwriter.cpp | 6 +++--- include/Makefile.am | 2 +- include/{nutconf.h => nutconf.hpp} | 2 +- include/nutwriter.hpp | 2 +- tests/nutconf.cpp | 2 +- tests/nutconf_ut.cpp | 2 +- tools/nutconf/nutconf.cpp | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) rename include/{nutconf.h => nutconf.hpp} (99%) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index edb9ce6468..812eff9c9a 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "nutconf.h" +#include "nutconf.hpp" #include "nutwriter.hpp" #include diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index ec640e38ee..d78cedf825 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -305,7 +305,7 @@ static std::string serializeNotifyMessage(UpsmonConfiguration::NotifyType type, /** * \brief Get notify type successor * - * TBD: Should be in nutconf.h + * TBD: Should be in nutconf.hpp * * \param type Notify type * @@ -323,7 +323,7 @@ inline static UpsmonConfiguration::NotifyType nextNotifyType(UpsmonConfiguration /** * \brief Notify type pre-increment * - * TBD: Should be in nutconf.h + * TBD: Should be in nutconf.hpp * * \param[in,out] type Notify type * @@ -337,7 +337,7 @@ inline static UpsmonConfiguration::NotifyType operator ++(UpsmonConfiguration::N /** * \brief Notify type post-increment * - * TBD: Should be in nutconf.h + * TBD: Should be in nutconf.hpp * * \param[in,out] type Notify type * diff --git a/include/Makefile.am b/include/Makefile.am index 27104e0308..cb5a13f4ea 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,6 @@ dist_noinst_HEADERS = attribute.h common.h extstate.h proto.h \ state.h str.h timehead.h upsconf.h nut_float.h nut_stdint.h nut_platform.h \ - nutstream.hpp nutwriter.hpp nutipc.hpp nutconf.h \ + nutstream.hpp nutwriter.hpp nutipc.hpp nutconf.hpp \ wincompat.h # Optionally deliverable as part of NUT public API: diff --git a/include/nutconf.h b/include/nutconf.hpp similarity index 99% rename from include/nutconf.h rename to include/nutconf.hpp index f4b02a0bad..014f93982c 100644 --- a/include/nutconf.h +++ b/include/nutconf.hpp @@ -1,5 +1,5 @@ /* - nutconf.h - Nut configuration file manipulation API + nutconf.hpp - Nut configuration file manipulation API Copyright (C) 2012 Emilien Kia diff --git a/include/nutwriter.hpp b/include/nutwriter.hpp index e2db9fb221..cd5782200b 100644 --- a/include/nutwriter.hpp +++ b/include/nutwriter.hpp @@ -25,7 +25,7 @@ #ifdef __cplusplus #include "nutstream.hpp" -#include "nutconf.h" +#include "nutconf.hpp" #include diff --git a/tests/nutconf.cpp b/tests/nutconf.cpp index 18029b6432..1000acdac2 100644 --- a/tests/nutconf.cpp +++ b/tests/nutconf.cpp @@ -24,7 +24,7 @@ // Define to de-activate protection of parsing tool members: #define UNITEST_MODE 1 -#include "nutconf.h" +#include "nutconf.hpp" using namespace nut; #include diff --git a/tests/nutconf_ut.cpp b/tests/nutconf_ut.cpp index 1ee8f24ade..2d6d414351 100644 --- a/tests/nutconf_ut.cpp +++ b/tests/nutconf_ut.cpp @@ -20,7 +20,7 @@ */ #include "nutstream.hpp" -#include "nutconf.h" +#include "nutconf.hpp" #include "nutwriter.hpp" #include diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 369451e4f3..164d7ccc85 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -23,7 +23,7 @@ */ #include "config.h" -#include "nutconf.h" +#include "nutconf.hpp" #include "nutstream.hpp" extern "C" { From 892e578400240c3575164c43d29848421ea24cab Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 14:04:33 +0100 Subject: [PATCH 083/121] nutconf related sources: use NUT_UNUSED_VARIABLE() to decorate the code where needed Signed-off-by: Jim Klimov --- common/nutconf.cpp | 5 +++++ include/nutconf.hpp | 5 +++++ include/nutipc.hpp | 4 ++++ include/nutstream.hpp | 8 ++++++++ tools/nutconf/nutconf.cpp | 8 ++++++-- 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 812eff9c9a..a47288e7ef 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -1372,6 +1372,7 @@ void UpsdConfigParser::onParseBegin() void UpsdConfigParser::onParseComment(const std::string& comment) { // Comments are ignored for now + NUT_UNUSED_VARIABLE(comment); } void UpsdConfigParser::onParseSectionName(const std::string& sectionName, const std::string& comment) @@ -1379,11 +1380,15 @@ void UpsdConfigParser::onParseSectionName(const std::string& sectionName, const // There must not be sections in upsd.conf. // Ignore it // TODO Add error reporting ? + NUT_UNUSED_VARIABLE(sectionName); + NUT_UNUSED_VARIABLE(comment); } void UpsdConfigParser::onParseDirective(const std::string& directiveName, char sep, const ConfigParamList& values, const std::string& comment) { // NOTE: separators are always ignored + NUT_UNUSED_VARIABLE(sep); + NUT_UNUSED_VARIABLE(comment); if(_config) { diff --git a/include/nutconf.hpp b/include/nutconf.hpp index 014f93982c..31139449cd 100644 --- a/include/nutconf.hpp +++ b/include/nutconf.hpp @@ -35,6 +35,11 @@ #include #include +/* See include/common.h for details behind this */ +#ifndef NUT_UNUSED_VARIABLE +#define NUT_UNUSED_VARIABLE(x) (void)(x) +#endif + #ifdef __cplusplus namespace nut diff --git a/include/nutipc.hpp b/include/nutipc.hpp index 72d87711c4..97713917cd 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -40,6 +40,10 @@ extern "C" { #include } +/* See include/common.h for details behind this */ +#ifndef NUT_UNUSED_VARIABLE +#define NUT_UNUSED_VARIABLE(x) (void)(x) +#endif namespace nut { diff --git a/include/nutstream.hpp b/include/nutstream.hpp index 83a7f22750..a0ea976157 100644 --- a/include/nutstream.hpp +++ b/include/nutstream.hpp @@ -37,6 +37,10 @@ extern "C" { #include } +/* See include/common.h for details behind this */ +#ifndef NUT_UNUSED_VARIABLE +#define NUT_UNUSED_VARIABLE(x) (void)(x) +#endif namespace nut { @@ -552,6 +556,7 @@ class NutFile: public NutStream { * \param orig Original file */ NutFile(const NutFile & orig) { + NUT_UNUSED_VARIABLE(orig); throw std::logic_error("NOT IMPLEMENTED"); } @@ -565,6 +570,7 @@ class NutFile: public NutStream { * \param rval Right value */ NutFile & operator = (const NutFile & rval) { + NUT_UNUSED_VARIABLE(rval); throw std::logic_error("NOT IMPLEMENTED"); } @@ -1131,6 +1137,7 @@ class NutSocket: public NutStream { * \param orig Original file */ NutSocket(const NutSocket & orig) { + NUT_UNUSED_VARIABLE(orig); throw std::logic_error("NOT IMPLEMENTED"); } @@ -1144,6 +1151,7 @@ class NutSocket: public NutStream { * \param rval Right value */ NutSocket & operator = (const NutSocket & rval) { + NUT_UNUSED_VARIABLE(rval); throw std::logic_error("NOT IMPLEMENTED"); } diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 164d7ccc85..1a4a6ce79a 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -1782,10 +1782,14 @@ class autodelete_ptr { private: /** Copying is forbidden */ - autodelete_ptr(const autodelete_ptr & orig) {} + autodelete_ptr(const autodelete_ptr & orig) { + NUT_UNUSED_VARIABLE(orig); + } /** Assignment is forbidden */ - autodelete_ptr & operator = (const autodelete_ptr & orig) {} + autodelete_ptr & operator = (const autodelete_ptr & orig) { + NUT_UNUSED_VARIABLE(orig); + } }; // end of template class autodelete_ptr From abe7c1aff3d15a4266644c92f146d0142050ad0b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 14:09:46 +0100 Subject: [PATCH 084/121] common/nutconf.cpp: NutConfigParser::parseConfig(): fix switch/case that did not check all enum values Signed-off-by: Jim Klimov --- common/nutconf.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index a47288e7ef..34be5adf8d 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -591,6 +591,9 @@ void NutConfigParser::parseConfig() { /* Could occur ! */ onParseDirective(name, sep, values); break; + case CPS_DEFAULT: + /* TOTHINK: no-op? */ + break; } onParseEnd(); From 7d75e187d2025419c0284103103182481977c19e Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 14:22:56 +0100 Subject: [PATCH 085/121] nutconf related sources: fix implicit copy/move operator warnings - use explicit defaults, destructors, and clarify overrides Signed-off-by: Jim Klimov --- common/nutconf.cpp | 6 ++ include/nutconf.hpp | 133 ++++++++++++++++++++++++------------------ include/nutipc.hpp | 9 ++- include/nutstream.hpp | 45 +++++++------- include/nutwriter.hpp | 16 ++--- 5 files changed, 122 insertions(+), 87 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 34be5adf8d..618638acd9 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -392,6 +392,12 @@ NutParser(buffer, options) { } void NutConfigParser::parseConfig() { + parseConfig(nullptr); +} + +void NutConfigParser::parseConfig(BaseConfiguration* config) { + NUT_UNUSED_VARIABLE(config); + onParseBegin(); enum ConfigParserState { diff --git a/include/nutconf.hpp b/include/nutconf.hpp index 31139449cd..3cd4407849 100644 --- a/include/nutconf.hpp +++ b/include/nutconf.hpp @@ -66,6 +66,11 @@ class Settable Settable(const Settable& val):_value(val._value), _set(val._set){} Settable(const Type& val):_value(val), _set(true){} + /* Avoid implicit copy/move operator declarations */ + Settable(Settable&&) = default; + Settable& operator=(const Settable&) = default; + Settable& operator=(Settable&&) = default; + bool set()const{return _set;} void clear(){_set = false;} @@ -154,6 +159,8 @@ class NutParser NutParser(const char* buffer = NULL, unsigned int options = OPTION_DEFAULT); NutParser(const std::string& buffer, unsigned int options = OPTION_DEFAULT); + virtual ~NutParser() {} + /** Parsing configuration functions * \{ */ void setOptions(unsigned int options){_options = options;} @@ -176,7 +183,7 @@ class NutParser TOKEN_EQUAL, TOKEN_COLON, TOKEN_EOL - }type; + } type; std::string str; Token():type(TOKEN_NONE),str(){} @@ -184,6 +191,11 @@ class NutParser Token(TokenType type, char c):type(type),str(1, c){} Token(const Token& tok):type(tok.type),str(tok.str){} + /* Avoid implicit copy/move operator declarations */ + Token(Token&&) = default; + Token& operator=(const Token&) = default; + Token& operator=(Token&&) = default; + bool is(TokenType type)const{return this->type==type;} bool operator==(const Token& tok)const{return tok.type==type && tok.str==str;} @@ -226,22 +238,6 @@ class NutParser typedef std::list ConfigParamList; -class NutConfigParser : public NutParser -{ -public: - virtual void parseConfig(); - -protected: - NutConfigParser(const char* buffer = NULL, unsigned int options = OPTION_DEFAULT); - NutConfigParser(const std::string& buffer, unsigned int options = OPTION_DEFAULT); - - virtual void onParseBegin()=0; - virtual void onParseComment(const std::string& comment)=0; - virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "")=0; - virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "")=0; - virtual void onParseEnd()=0; -}; - struct GenericConfigSectionEntry { std::string name; @@ -266,6 +262,34 @@ struct GenericConfigSection void clear(); }; +class BaseConfiguration +{ + friend class GenericConfigParser; +public: + virtual ~BaseConfiguration() {} +protected: + virtual void setGenericConfigSection(const GenericConfigSection& section) = 0; +}; + +class NutConfigParser : public NutParser +{ +public: + virtual void parseConfig(); + + /* Declared for cleaner overrides; arg ignored in current class */ + virtual void parseConfig(BaseConfiguration* config); + +protected: + NutConfigParser(const char* buffer = NULL, unsigned int options = OPTION_DEFAULT); + NutConfigParser(const std::string& buffer, unsigned int options = OPTION_DEFAULT); + + virtual void onParseBegin()=0; + virtual void onParseComment(const std::string& comment)=0; + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "")=0; + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "")=0; + virtual void onParseEnd()=0; +}; + class DefaultConfigParser : public NutConfigParser { public: @@ -275,33 +299,26 @@ class DefaultConfigParser : public NutConfigParser protected: virtual void onParseSection(const GenericConfigSection& section)=0; - virtual void onParseBegin(); - virtual void onParseComment(const std::string& comment); - virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); - virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); - virtual void onParseEnd(); + virtual void onParseBegin() override; + virtual void onParseComment(const std::string& comment) override; + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "") override; + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "") override; + virtual void onParseEnd() override; GenericConfigSection _section; ///> Currently parsed section }; -class BaseConfiguration -{ - friend class GenericConfigParser; -protected: - virtual void setGenericConfigSection(const GenericConfigSection& section) = 0; -}; - class GenericConfigParser : public DefaultConfigParser { public: GenericConfigParser(const char* buffer = NULL); GenericConfigParser(const std::string& buffer); - virtual void parseConfig(BaseConfiguration* config); + virtual void parseConfig(BaseConfiguration* config) override; protected: - virtual void onParseSection(const GenericConfigSection& section); + virtual void onParseSection(const GenericConfigSection& section) override; BaseConfiguration* _config; }; @@ -315,11 +332,13 @@ class GenericConfiguration : public BaseConfiguration, public Serialisable GenericConfiguration(){} + virtual ~GenericConfiguration() override; + void parseFromString(const std::string& str); /** Serialisable interface implementation \{ */ - bool parseFrom(NutStream & istream); - bool writeTo(NutStream & ostream) const; + bool parseFrom(NutStream & istream) override; + bool writeTo(NutStream & ostream) const override; /** \} */ // FIXME Let be public or set it as protected with public accessors ? @@ -330,7 +349,7 @@ class GenericConfiguration : public BaseConfiguration, public Serialisable protected: - virtual void setGenericConfigSection(const GenericConfigSection& section); + virtual void setGenericConfigSection(const GenericConfigSection& section) override; /** * \brief Configuration parameters getter @@ -659,8 +678,8 @@ class UpsmonConfiguration : public Serialisable std::list monitors; /** Serialisable interface implementation \{ */ - bool parseFrom(NutStream & istream); - bool writeTo(NutStream & ostream) const; + bool parseFrom(NutStream & istream) override; + bool writeTo(NutStream & ostream) const override; /** \} */ }; // end of class UpsmonConfiguration @@ -675,11 +694,11 @@ class UpsmonConfigParser : public NutConfigParser void parseUpsmonConfig(UpsmonConfiguration* config); protected: - virtual void onParseBegin(); - virtual void onParseComment(const std::string& comment); - virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); - virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); - virtual void onParseEnd(); + virtual void onParseBegin() override; + virtual void onParseComment(const std::string& comment) override; + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "") override; + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "") override; + virtual void onParseEnd() override; UpsmonConfiguration* _config; }; @@ -706,8 +725,8 @@ class NutConfiguration: public Serialisable static NutMode NutModeFromString(const std::string& str); /** Serialisable interface implementation \{ */ - bool parseFrom(NutStream & istream); - bool writeTo(NutStream & ostream) const; + bool parseFrom(NutStream & istream) override; + bool writeTo(NutStream & ostream) const override; /** \} */ }; @@ -720,11 +739,11 @@ class NutConfConfigParser : public NutConfigParser void parseNutConfConfig(NutConfiguration* config); protected: - virtual void onParseBegin(); - virtual void onParseComment(const std::string& comment); - virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); - virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); - virtual void onParseEnd(); + virtual void onParseBegin() override; + virtual void onParseComment(const std::string& comment) override; + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "") override; + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "") override; + virtual void onParseEnd() override; NutConfiguration* _config; }; @@ -752,8 +771,8 @@ class UpsdConfiguration : public Serialisable std::list listens; /** Serialisable interface implementation \{ */ - bool parseFrom(NutStream & istream); - bool writeTo(NutStream & ostream) const; + bool parseFrom(NutStream & istream) override; + bool writeTo(NutStream & ostream) const override; /** \} */ }; @@ -768,11 +787,11 @@ class UpsdConfigParser : public NutConfigParser void parseUpsdConfig(UpsdConfiguration* config); protected: - virtual void onParseBegin(); - virtual void onParseComment(const std::string& comment); - virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = ""); - virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = ""); - virtual void onParseEnd(); + virtual void onParseBegin() override; + virtual void onParseComment(const std::string& comment) override; + virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "") override; + virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "") override; + virtual void onParseEnd() override; UpsdConfiguration* _config; }; @@ -1102,8 +1121,8 @@ class UpsdUsersConfiguration : public GenericConfiguration /** \} */ /** Serialisable interface implementation overload \{ */ - bool parseFrom(NutStream & istream); - bool writeTo(NutStream & ostream) const; + bool parseFrom(NutStream & istream) override; + bool writeTo(NutStream & ostream) const override; /** \} */ }; // end of class UpsdUsersConfiguration diff --git a/include/nutipc.hpp b/include/nutipc.hpp index 97713917cd..a2abe7670e 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -80,9 +80,15 @@ class Process { /** Formal constructor */ Main() {} + virtual ~Main() = default; public: + /* Avoid implicit copy/move operator declarations */ + Main(Main&&) = default; + Main& operator=(const Main&) = default; + //Main& operator=(Main&&) = default; + /** Routine */ virtual int operator () () = 0; @@ -208,8 +214,7 @@ class Process { #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif - ; - + override; }; // end of class Executor /** diff --git a/include/nutstream.hpp b/include/nutstream.hpp index a0ea976157..8d9c5adbe9 100644 --- a/include/nutstream.hpp +++ b/include/nutstream.hpp @@ -170,12 +170,12 @@ class NutMemory: public NutStream { NutMemory(const std::string & str): m_impl(str), m_pos(0) {} // NutStream interface implementation - status_t getChar(char & ch); - void readChar(); - status_t getString(std::string & str); - status_t putChar(char ch); - status_t putString(const std::string & str); - status_t putData(const std::string & data); + status_t getChar(char & ch) override; + void readChar() override; + status_t getString(std::string & str) override; + status_t putChar(char ch) override; + status_t putString(const std::string & str) override; + status_t putData(const std::string & data) override; }; // end of class NutMemory @@ -510,40 +510,40 @@ class NutFile: public NutStream { #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif - ; + override; void readChar() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif - ; + override; status_t getString(std::string & str) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif - ; + override; status_t putChar(char ch) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif - ; + override; status_t putString(const std::string & str) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif - ; + override; status_t putData(const std::string & data) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif - ; + override; /** Destructor (closes the file) */ - ~NutFile(); + ~NutFile() override; private: @@ -1097,34 +1097,39 @@ class NutSocket: public NutStream { #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif - ; + override; + void readChar() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif - ; + override; + status_t getString(std::string & str) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif - ; + override; + status_t putChar(char ch) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif - ; + override; + status_t putString(const std::string & str) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif - ; + override; + - inline status_t putData(const std::string & data) { + inline status_t putData(const std::string & data) override { return putString(data); // no difference on sockets } /** Destructor (closes socket if necessary) */ - ~NutSocket(); + ~NutSocket() override; private: diff --git a/include/nutwriter.hpp b/include/nutwriter.hpp index cd5782200b..d86309a073 100644 --- a/include/nutwriter.hpp +++ b/include/nutwriter.hpp @@ -191,13 +191,13 @@ class SectionlessConfigWriter: public NutConfigWriter { public: // Partial \ref NutConfigWriter interface implementation - status_t writeDirective(const std::string & str); - status_t writeComment(const std::string & str); + status_t writeDirective(const std::string & str) override; + status_t writeComment(const std::string & str) override; private: // Section name writing is forbidden (no sections) - status_t writeSectionName(const std::string & name); + status_t writeSectionName(const std::string & name) override; }; // end of class SectionlessConfigWriter @@ -300,9 +300,9 @@ class DefaultConfigWriter: public NutConfigWriter { public: // \ref NutConfigWriter interface implementation - status_t writeComment(const std::string & str); - status_t writeSectionName(const std::string & name); - status_t writeDirective(const std::string & str); + status_t writeComment(const std::string & str) override; + status_t writeSectionName(const std::string & name) override; + status_t writeDirective(const std::string & str) override; /** * \brief Write configuration section @@ -360,7 +360,7 @@ class GenericConfigWriter: public DefaultConfigWriter { GenericConfigWriter(NutStream & ostream): DefaultConfigWriter(ostream) {} // Section serializer implementation - status_t writeSection(const GenericConfigSection & section); + status_t writeSection(const GenericConfigSection & section) override; /** * \brief Base configuration serializer @@ -393,7 +393,7 @@ class UpsdUsersConfigWriter: public GenericConfigWriter { UpsdUsersConfigWriter(NutStream & ostream): GenericConfigWriter(ostream) {} // Section serializer overload - status_t writeSection(const GenericConfigSection & section); + status_t writeSection(const GenericConfigSection & section) override; }; // end of class UpsdUsersConfigWriter From 2b9a5462ab55a66ad3b392dbe2422127dfbc9c25 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 27 Jan 2024 15:37:35 +0100 Subject: [PATCH 086/121] common/nutconf.cpp: NutConfigParser::parseConfig(): reshuffle base vs. overridden call for parser to work again Fine piece of C++ magic and inheritance. Wrong call got called. Signed-off-by: Jim Klimov --- common/nutconf.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 618638acd9..a796707945 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -391,13 +391,12 @@ NutConfigParser::NutConfigParser(const std::string& buffer, unsigned int options NutParser(buffer, options) { } -void NutConfigParser::parseConfig() { - parseConfig(nullptr); -} - void NutConfigParser::parseConfig(BaseConfiguration* config) { NUT_UNUSED_VARIABLE(config); + parseConfig(); +} +void NutConfigParser::parseConfig() { onParseBegin(); enum ConfigParserState { From bc1269ccec4c0a9105661675fbc5404fb09e4167 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 15:11:33 +0100 Subject: [PATCH 087/121] include/nutipc.hpp: avoid naming clash for QUIT signal and command Signed-off-by: Jim Klimov --- include/nutipc.hpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/include/nutipc.hpp b/include/nutipc.hpp index a2abe7670e..716727c55a 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -411,8 +411,8 @@ class Signal { /** Control commands */ typedef enum { - QUIT = 0, /**< Shutdown the thread */ - SIGNAL = 1, /**< Signal obtained */ + HT_QUIT = 0, /**< Shutdown the thread */ + HT_SIGNAL = 1, /**< Signal obtained */ } command_t; /** Communication pipe */ @@ -429,7 +429,8 @@ class Signal { * It passes all signals to signal handler instance of \ref H * Which must implement the \ref Signal::Handler interface. * The handler is instantiated in scope of the routine. - * It closes the communication pipe read end in reaction to \ref QUIT command. + * It closes the communication pipe read end in reaction to + * \ref HT_QUIT command. * * \param comm_pipe_read_end Communication pipe read end * @@ -443,7 +444,7 @@ class Signal { * The actual signal handler routine executed by the OS when the process * obtains signal to be handled. * The function simply writes the signal number to the signal handler - * thread communication pipe (as parameter of the \ref SIGNAL command). + * thread communication pipe (as parameter of the \ref HT_SIGNAL command). * The signal handling itself (whatever necessary) shall be done * by the dedicated thread (to avoid possible re-entrance issues). * @@ -600,14 +601,14 @@ void * Signal::HandlerThread::main(void * comm_pipe_read_end) { command_t command = (command_t)word; switch (command) { - case QUIT: + case HT_QUIT: // Close comm. pipe read end ::close(rfd); // Terminate thread pthread_exit(NULL); - case SIGNAL: + case HT_SIGNAL: // Read signal number read_out = ::read(rfd, &word, sizeof(word)); @@ -655,7 +656,7 @@ int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) template void Signal::HandlerThread::signalNotifier(int signal) { int sig[2] = { - (int)Signal::HandlerThread::SIGNAL, + (int)Signal::HandlerThread::HT_SIGNAL, }; sig[1] = signal; @@ -732,7 +733,7 @@ void Signal::HandlerThread::quit() throw(std::runtime_error) #endif { - static int quit = (int)Signal::HandlerThread::QUIT; + static int quit = (int)Signal::HandlerThread::HT_QUIT; sigPipeWriteCmd(s_comm_pipe[1], &quit, sizeof(quit)); From 90a93b32485f13e00a3800eed6a0962e2beac1b8 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 14:06:28 +0100 Subject: [PATCH 088/121] common/nutstream.cpp: formatIPv{4,6}addr(): code typo fix (bit maths, not boolean expressions!) Signed-off-by: Jim Klimov --- common/nutstream.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/nutstream.cpp b/common/nutstream.cpp index f44a8b25a6..8d8c5181d3 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -537,10 +537,10 @@ NutSocket::Address::Address(const Address & orig): m_sock_addr(NULL), m_length(o static std::string formatIPv4addr(uint32_t packed) { std::stringstream ss; - ss << (packed && 0x000000ff) << "."; - ss << (packed >> 8 && 0x000000ff) << "."; - ss << (packed >> 16 && 0x000000ff) << "."; - ss << (packed >> 24 && 0x000000ff); + ss << (packed & 0x000000ff) << "."; + ss << (packed >> 8 & 0x000000ff) << "."; + ss << (packed >> 16 & 0x000000ff) << "."; + ss << (packed >> 24 & 0x000000ff); return ss.str(); } @@ -588,7 +588,7 @@ static std::string formatIPv6addr(unsigned char const bytes[16]) { ss << std::uppercase << std::hex << std::setfill('0'); for (size_t i = 0; ; ) { - uint16_t w = ((uint16_t)(bytes[2 * i]) << 8) || bytes[2 * i + 1]; + uint16_t w = static_cast(static_cast(bytes[2 * i]) << 8) | static_cast(bytes[2 * i + 1]); ss << std::setw(4) << w; From 256f6a0446b00b4503c5a607e6c5fe58bf382783 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 14:08:04 +0100 Subject: [PATCH 089/121] include/nutipc.hpp: Process::Child::wait(): fix error-case check Signed-off-by: Jim Klimov --- include/nutipc.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nutipc.hpp b/include/nutipc.hpp index 716727c55a..95f1e3d35e 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -310,7 +310,7 @@ int Process::Child::wait() pid_t wpid = ::waitpid(m_pid, &m_exit_code, 0); - if (-1 == m_pid) { + if (-1 == wpid) { int erno = errno; std::stringstream e; From 8ff7e53874c6ad3b9d756d24d3c2f5cdad7d62ea Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 15:06:44 +0100 Subject: [PATCH 090/121] common/nutstream.cpp: address a run-time warning about tempnam() Signed-off-by: Jim Klimov --- common/nutstream.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/common/nutstream.cpp b/common/nutstream.cpp index 8d8c5181d3..0468ebc908 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -230,6 +230,14 @@ std::string NutFile::tmpName() throw(std::runtime_error) #endif { + // Note: in many systems' implementations this claims a warning like: + // the use of `tempnam' is dangerous, better use `mkstemp' + // or + // These functions are deprecated because more secure versions + // are available; see tmpnam_s, _wtmpnam_s. + // but it seems the alternatives are different for various platforms + // and so a replacement is not quite portable (stack of ifdef's?), per + // https://stackoverflow.com/questions/3299881/tmpnam-warning-saying-it-is-dangerous char *tmp_name = ::tempnam(m_tmp_dir.c_str(), NULL); if (NULL == tmp_name) From 0ae8eca7007b68ac58024732fb6a076524519b0f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 14:25:39 +0100 Subject: [PATCH 091/121] tools/nutconf/nutconf.cpp: adapt nutscan_scan_usb() to libnutscan API evolution Signed-off-by: Jim Klimov --- tools/nutconf/nutconf.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 1a4a6ce79a..2437c2a5e9 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -687,7 +687,12 @@ class NutScanner { * \return Device list */ inline static devices_t devicesUSB() { - nutscan_device_t * dev = nutscan_scan_usb(); + // FIXME: Since NUT v2.8.2 nutscan_scan_usb accepts + // a `nutscan_usb_t * scanopts` to tweak what values + // it reports -- make use of it in this class. + // A NULL value causes safe defaults to be used, + // as decided by the library. + nutscan_device_t * dev = nutscan_scan_usb(NULL); return dev2list(dev); } From e8331866c2b7d44167c66a7b0202f3c7d06333fb Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 14:37:00 +0100 Subject: [PATCH 092/121] configure.ac, tests/nutconf_ut.cpp: rearrange to use ABS_TOP_SRCDIR and ABS_TOP_BUILDDIR in the test program Signed-off-by: Jim Klimov --- configure.ac | 4 ++++ tests/nutconf_ut.cpp | 13 ++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 9c528d95d4..d5d68d2982 100644 --- a/configure.ac +++ b/configure.ac @@ -4451,6 +4451,10 @@ ABS_TOP_BUILDDIR="`cd "${TOP_BUILDDIR}" && pwd`" || AC_MSG_ERROR([Can not detect ABS_TOP_SRCDIR="`cd "${abs_srcdir}" && pwd`" || AC_MSG_ERROR([Can not detect ABS_TOP_SRCDIR]) AM_CONDITIONAL([BUILDING_IN_TREE], [test "${ABS_TOP_BUILDDIR}" = "${ABS_TOP_SRCDIR}"]) +dnl Use these at best for tests (e.g. nutconf), not production code: +AC_DEFINE_UNQUOTED([ABS_TOP_SRCDIR], ["${ABS_TOP_SRCDIR}"], [NUT source directory when the build was configured]) +AC_DEFINE_UNQUOTED([ABS_TOP_BUILDDIR], ["${ABS_TOP_BUILDDIR}"], [NUT build directory when the build was configured]) + AC_MSG_CHECKING([whether to customize ${TOP_BUILDDIR}/scripts/systemd/nut-common-tmpfiles.conf.in for this system]) dnl TOTHINK: Some distributions make the directories below owned dnl by "root:${RUN_AS_GROUP}" with 77x permissions. Is it safer?.. diff --git a/tests/nutconf_ut.cpp b/tests/nutconf_ut.cpp index 2d6d414351..4cf5545642 100644 --- a/tests/nutconf_ut.cpp +++ b/tests/nutconf_ut.cpp @@ -19,6 +19,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "config.h" + #include "nutstream.hpp" #include "nutconf.hpp" #include "nutwriter.hpp" @@ -116,7 +118,7 @@ void NutConfigUnitTest::check(const nut::Serialisable * config, const std::strin void NutConfigUnitTest::testNutConfiguration() { nut::NutConfiguration config; - load(static_cast(&config), TOP_SRCDIR "/conf/nut.conf.sample"); + load(static_cast(&config), ABS_TOP_SRCDIR "/conf/nut.conf.sample"); config.mode = nut::NutConfiguration::MODE_STANDALONE; @@ -129,7 +131,8 @@ void NutConfigUnitTest::testNutConfiguration() { void NutConfigUnitTest::testUpsmonConfiguration() { nut::UpsmonConfiguration config; - load(static_cast(&config), TOP_SRCDIR "/conf/upsmon.conf.sample"); + // Note: this file gets generated from a .in template + load(static_cast(&config), ABS_BUILD_SRCDIR "/conf/upsmon.conf.sample"); config.shutdownCmd = "/sbin/shutdown -h +2 'System shutdown in 2 minutes!'"; config.powerDownFlag = "/run/nut/killpower"; @@ -154,7 +157,7 @@ void NutConfigUnitTest::testUpsmonConfiguration() { void NutConfigUnitTest::testUpsdConfiguration() { nut::UpsdConfiguration config; - load(static_cast(&config), TOP_SRCDIR "/conf/upsd.conf.sample"); + load(static_cast(&config), ABS_TOP_SRCDIR "/conf/upsd.conf.sample"); config.maxAge = 15; config.statePath = "/var/run/nut"; @@ -186,7 +189,7 @@ void NutConfigUnitTest::testUpsdConfiguration() { void NutConfigUnitTest::testUpsConfiguration() { nut::UpsConfiguration config; - load(static_cast(&config), TOP_SRCDIR "/conf/ups.conf.sample"); + load(static_cast(&config), ABS_TOP_SRCDIR "/conf/ups.conf.sample"); static const std::string my_ups("powerpal"); @@ -207,7 +210,7 @@ void NutConfigUnitTest::testUpsConfiguration() { void NutConfigUnitTest::testUpsdUsersConfiguration() { nut::UpsdUsersConfiguration config; - load(static_cast(&config), TOP_SRCDIR "/conf/upsd.users.sample"); + load(static_cast(&config), ABS_TOP_SRCDIR "/conf/upsd.users.sample"); config.setPassword("upsmon", "ytrewq"); config.setUpsmonMode(nut::UpsdUsersConfiguration::UPSMON_MASTER); From 6d791a4e6d64ff632f707dde06a661fa3fd5ca1f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 24 Jan 2024 14:58:54 +0100 Subject: [PATCH 093/121] tests/nutconf_ut.cpp: update expectations for current ups.conf.sample default contents Signed-off-by: Jim Klimov --- tests/nutconf_ut.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/nutconf_ut.cpp b/tests/nutconf_ut.cpp index 4cf5545642..37d1866595 100644 --- a/tests/nutconf_ut.cpp +++ b/tests/nutconf_ut.cpp @@ -132,7 +132,7 @@ void NutConfigUnitTest::testUpsmonConfiguration() { nut::UpsmonConfiguration config; // Note: this file gets generated from a .in template - load(static_cast(&config), ABS_BUILD_SRCDIR "/conf/upsmon.conf.sample"); + load(static_cast(&config), ABS_TOP_BUILDDIR "/conf/upsmon.conf.sample"); config.shutdownCmd = "/sbin/shutdown -h +2 'System shutdown in 2 minutes!'"; config.powerDownFlag = "/run/nut/killpower"; @@ -197,7 +197,9 @@ void NutConfigUnitTest::testUpsConfiguration() { config.setPort(my_ups, "/dev/ttyS0"); config.setDescription(my_ups, "Web server"); + // Note: "maxretry = 3" comes from current ups.conf.sample non-comment lines check(static_cast(&config), + "maxretry = 3\n\n" "[powerpal]\n" "\tdesc = \"Web server\"\n" "\tdriver = blazer_ser\n" From 1683379a07df2335af1f4af44460909155c797bf Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 12:46:37 +0100 Subject: [PATCH 094/121] nutconf related changes: avoid NULL ("zero as null pointer constant"), use "::" prefix for C methods Signed-off-by: Jim Klimov --- common/nutconf.cpp | 22 +++++++-------- common/nutipc.cpp | 2 +- common/nutstream.cpp | 44 +++++++++++++++--------------- include/nutconf.hpp | 14 +++++----- include/nutipc.hpp | 10 +++---- include/nutstream.hpp | 6 ++--- tests/nutipc_ut.cpp | 2 +- tests/nutstream_ut.cpp | 4 +-- tools/nutconf/nutconf.cpp | 56 +++++++++++++++++++-------------------- 9 files changed, 80 insertions(+), 80 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index a796707945..75bd13587c 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -679,30 +679,30 @@ void GenericConfigSection::clear() { GenericConfigParser::GenericConfigParser(const char* buffer): DefaultConfigParser(buffer), -_config(NULL) +_config(nullptr) { } GenericConfigParser::GenericConfigParser(const std::string& buffer): DefaultConfigParser(buffer), -_config(NULL) +_config(nullptr) { } void GenericConfigParser::parseConfig(BaseConfiguration* config) { - if(config!=NULL) + if(config!=nullptr) { _config = config; NutConfigParser::parseConfig(); - _config = NULL; + _config = nullptr; } } void GenericConfigParser::onParseSection(const GenericConfigSection& section) { - if(_config!=NULL) + if(_config!=nullptr) { _config->setGenericConfigSection(section); } @@ -1016,11 +1016,11 @@ NutConfigParser(buffer) void UpsmonConfigParser::parseUpsmonConfig(UpsmonConfiguration* config) { - if(config!=NULL) + if(config!=nullptr) { _config = config; NutConfigParser::parseConfig(); - _config = NULL; + _config = nullptr; } } @@ -1263,11 +1263,11 @@ NutConfigParser(buffer) void NutConfConfigParser::parseNutConfConfig(NutConfiguration* config) { - if(config!=NULL) + if(config!=nullptr) { _config = config; NutConfigParser::parseConfig(); - _config = NULL; + _config = nullptr; } } @@ -1364,11 +1364,11 @@ NutConfigParser(buffer, NutParser::OPTION_IGNORE_COLON) void UpsdConfigParser::parseUpsdConfig(UpsdConfiguration* config) { - if(config!=NULL) + if(config!=nullptr) { _config = config; NutConfigParser::parseConfig(); - _config = NULL; + _config = nullptr; } } diff --git a/common/nutipc.cpp b/common/nutipc.cpp index 8e928a5bf6..ecda3c3b12 100644 --- a/common/nutipc.cpp +++ b/common/nutipc.cpp @@ -160,7 +160,7 @@ int Process::Executor::operator () () args_c_str[i] = (*arg).c_str(); } - args_c_str[i] = NULL; + args_c_str[i] = nullptr; int status = ::execvp(bin_c_str, (char * const *)args_c_str); diff --git a/common/nutstream.cpp b/common/nutstream.cpp index 0468ebc908..ab08f7c5d3 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -92,13 +92,13 @@ const std::string NutFile::m_tmp_dir("/var/tmp"); NutFile::NutFile(anonymous_t): - m_impl(NULL), + m_impl(nullptr), m_current_ch('\0'), m_current_ch_valid(false) { m_impl = ::tmpfile(); - if (NULL == m_impl) { + if (nullptr == m_impl) { int err_code = errno; std::stringstream e; @@ -140,7 +140,7 @@ bool NutFile::open(access_t mode, int & err_code, std::string & err_msg) static const char *append_only = "a"; static const char *read_append = "a+"; - const char *mode_str = NULL; + const char *mode_str = nullptr; switch (mode) { case READ_ONLY: @@ -163,11 +163,11 @@ bool NutFile::open(access_t mode, int & err_code, std::string & err_msg) break; } - assert(NULL != mode_str); + assert(nullptr != mode_str); m_impl = ::fopen(m_name.c_str(), mode_str); - if (NULL != m_impl) + if (nullptr != m_impl) return true; err_code = errno; @@ -190,7 +190,7 @@ bool NutFile::close(int & err_code, std::string & err_msg) return false; } - m_impl = NULL; + m_impl = nullptr; return true; } @@ -217,7 +217,7 @@ bool NutFile::remove(int & err_code, std::string & err_msg) NutFile::NutFile(const std::string & name, access_t mode): m_name(name), - m_impl(NULL), + m_impl(nullptr), m_current_ch('\0'), m_current_ch_valid(false) { @@ -238,9 +238,9 @@ std::string NutFile::tmpName() // but it seems the alternatives are different for various platforms // and so a replacement is not quite portable (stack of ifdef's?), per // https://stackoverflow.com/questions/3299881/tmpnam-warning-saying-it-is-dangerous - char *tmp_name = ::tempnam(m_tmp_dir.c_str(), NULL); + char *tmp_name = ::tempnam(m_tmp_dir.c_str(), nullptr); - if (NULL == tmp_name) + if (nullptr == tmp_name) throw std::runtime_error( "Failed to create temporary file name"); @@ -254,7 +254,7 @@ std::string NutFile::tmpName() NutFile::NutFile(access_t mode): m_name(tmpName()), - m_impl(NULL), + m_impl(nullptr), m_current_ch('\0'), m_current_ch_valid(false) { @@ -273,7 +273,7 @@ NutFile::NutFile(access_t mode): * \retval NUTS_ERROR on read error */ inline static NutStream::status_t fgetcWrapper(FILE * file, char & ch) { - assert(NULL != file); + assert(nullptr != file); errno = 0; @@ -303,7 +303,7 @@ NutStream::status_t NutFile::getChar(char & ch) return NUTS_OK; } - if (NULL == m_impl) + if (nullptr == m_impl) return NUTS_ERROR; status_t status = fgetcWrapper(m_impl, ch); @@ -338,7 +338,7 @@ NutStream::status_t NutFile::getString(std::string & str) m_current_ch_valid = false; - if (NULL == m_impl) + if (nullptr == m_impl) return NUTS_ERROR; // Note that ::fgetc is used instead of ::fgets @@ -366,7 +366,7 @@ NutStream::status_t NutFile::putChar(char ch) { int c; - if (NULL == m_impl) + if (nullptr == m_impl) return NUTS_ERROR; c = ::fputc(static_cast(ch), m_impl); @@ -382,7 +382,7 @@ NutStream::status_t NutFile::putString(const std::string & str) { int c; - if (NULL == m_impl) + if (nullptr == m_impl) return NUTS_ERROR; c = ::fputs(str.c_str(), m_impl); @@ -410,7 +410,7 @@ NutStream::status_t NutFile::putData(const std::string & data) NutFile::~NutFile() { - if (NULL != m_impl) + if (nullptr != m_impl) closex(); } @@ -418,7 +418,7 @@ NutFile::~NutFile() { void NutSocket::Address::init_unix(Address & addr, const std::string & path) { struct sockaddr_un * un_addr = (struct sockaddr_un *)::malloc(sizeof(struct sockaddr_un)); - if (NULL == un_addr) + if (nullptr == un_addr) throw std::bad_alloc(); un_addr->sun_family = AF_UNIX; @@ -442,7 +442,7 @@ void NutSocket::Address::init_ipv4(Address & addr, const std::vector(qb.at(0)); @@ -464,7 +464,7 @@ void NutSocket::Address::init_ipv6(Address & addr, const std::vectorsin6_family = AF_INET6; @@ -523,10 +523,10 @@ NutSocket::Address::Address(const std::vector & bytes, uint16_t p } -NutSocket::Address::Address(const Address & orig): m_sock_addr(NULL), m_length(orig.m_length) { +NutSocket::Address::Address(const Address & orig): m_sock_addr(nullptr), m_length(orig.m_length) { void * copy = ::malloc(m_length); - if (NULL == copy) + if (nullptr == copy) throw std::bad_alloc(); ::memcpy(copy, orig.m_sock_addr, m_length); @@ -611,7 +611,7 @@ static std::string formatIPv6addr(unsigned char const bytes[16]) { std::string NutSocket::Address::str() const { - assert(NULL != m_sock_addr); + assert(nullptr != m_sock_addr); sa_family_t family = m_sock_addr->sa_family; diff --git a/include/nutconf.hpp b/include/nutconf.hpp index 3cd4407849..dbc02e6b10 100644 --- a/include/nutconf.hpp +++ b/include/nutconf.hpp @@ -156,7 +156,7 @@ class NutParser OPTION_IGNORE_COLON = 1 }; - NutParser(const char* buffer = NULL, unsigned int options = OPTION_DEFAULT); + NutParser(const char* buffer = nullptr, unsigned int options = OPTION_DEFAULT); NutParser(const std::string& buffer, unsigned int options = OPTION_DEFAULT); virtual ~NutParser() {} @@ -280,7 +280,7 @@ class NutConfigParser : public NutParser virtual void parseConfig(BaseConfiguration* config); protected: - NutConfigParser(const char* buffer = NULL, unsigned int options = OPTION_DEFAULT); + NutConfigParser(const char* buffer = nullptr, unsigned int options = OPTION_DEFAULT); NutConfigParser(const std::string& buffer, unsigned int options = OPTION_DEFAULT); virtual void onParseBegin()=0; @@ -293,7 +293,7 @@ class NutConfigParser : public NutParser class DefaultConfigParser : public NutConfigParser { public: - DefaultConfigParser(const char* buffer = NULL); + DefaultConfigParser(const char* buffer = nullptr); DefaultConfigParser(const std::string& buffer); protected: @@ -312,7 +312,7 @@ class DefaultConfigParser : public NutConfigParser class GenericConfigParser : public DefaultConfigParser { public: - GenericConfigParser(const char* buffer = NULL); + GenericConfigParser(const char* buffer = nullptr); GenericConfigParser(const std::string& buffer); virtual void parseConfig(BaseConfiguration* config) override; @@ -689,7 +689,7 @@ class UpsmonConfiguration : public Serialisable class UpsmonConfigParser : public NutConfigParser { public: - UpsmonConfigParser(const char* buffer = NULL); + UpsmonConfigParser(const char* buffer = nullptr); UpsmonConfigParser(const std::string& buffer); void parseUpsmonConfig(UpsmonConfiguration* config); @@ -734,7 +734,7 @@ class NutConfiguration: public Serialisable class NutConfConfigParser : public NutConfigParser { public: - NutConfConfigParser(const char* buffer = NULL); + NutConfConfigParser(const char* buffer = nullptr); NutConfConfigParser(const std::string& buffer); void parseNutConfConfig(NutConfiguration* config); @@ -782,7 +782,7 @@ class UpsdConfiguration : public Serialisable class UpsdConfigParser : public NutConfigParser { public: - UpsdConfigParser(const char* buffer = NULL); + UpsdConfigParser(const char* buffer = nullptr); UpsdConfigParser(const std::string& buffer); void parseUpsdConfig(UpsdConfiguration* config); diff --git a/include/nutipc.hpp b/include/nutipc.hpp index 95f1e3d35e..7799c7cd7e 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -566,7 +566,7 @@ void * Signal::HandlerThread::main(void * comm_pipe_read_end) { // Note that direct blocking read could be also used; // however, select allows timeout specification // which might come handy... - int fdno = ::select(FD_SETSIZE, &rfds, NULL, NULL, NULL); + int fdno = ::select(FD_SETSIZE, &rfds, nullptr, nullptr, nullptr); // TBD: Die or recover on error? if (-1 == fdno) { @@ -606,7 +606,7 @@ void * Signal::HandlerThread::main(void * comm_pipe_read_end) { ::close(rfd); // Terminate thread - pthread_exit(NULL); + ::pthread_exit(nullptr); case HT_SIGNAL: // Read signal number @@ -689,7 +689,7 @@ Signal::HandlerThread::HandlerThread(const Signal::List & siglist) } // Start the thread - int status = ::pthread_create(&m_impl, NULL, &main, s_comm_pipe); + int status = ::pthread_create(&m_impl, nullptr, &main, s_comm_pipe); if (status) { std::stringstream e; @@ -713,7 +713,7 @@ Signal::HandlerThread::HandlerThread(const Signal::List & siglist) int signo = static_cast(*sig); // TBD: We might want to save the old handlers... - status = ::sigaction(signo, &action, NULL); + status = ::sigaction(signo, &action, nullptr); if (status) { std::stringstream e; @@ -737,7 +737,7 @@ void Signal::HandlerThread::quit() sigPipeWriteCmd(s_comm_pipe[1], &quit, sizeof(quit)); - int status = ::pthread_join(m_impl, NULL); + int status = ::pthread_join(m_impl, nullptr); if (status) { std::stringstream e; diff --git a/include/nutstream.hpp b/include/nutstream.hpp index 8d9c5adbe9..db14170a5b 100644 --- a/include/nutstream.hpp +++ b/include/nutstream.hpp @@ -248,7 +248,7 @@ class NutFile: public NutStream { */ NutFile(const std::string & name): m_name(name), - m_impl(NULL), + m_impl(nullptr), m_current_ch('\0'), m_current_ch_valid(false) {} @@ -616,7 +616,7 @@ class NutSocket: public NutStream { * * Invalid address may be produced e.g. by failed DNS resolving. */ - Address(): m_sock_addr(NULL), m_length(0) {} + Address(): m_sock_addr(nullptr), m_length(0) {} /** * \brief Initialize UNIX socket address @@ -657,7 +657,7 @@ class NutSocket: public NutStream { throw() #endif { - return NULL != m_sock_addr; + return nullptr != m_sock_addr; } /** diff --git a/tests/nutipc_ut.cpp b/tests/nutipc_ut.cpp index aae80a8b18..d548ec414a 100644 --- a/tests/nutipc_ut.cpp +++ b/tests/nutipc_ut.cpp @@ -114,7 +114,7 @@ void NutIPCUnitTest::testSignalSend() { action.sa_handler = &testSignalHandler; - CPPUNIT_ASSERT(0 == ::sigaction((int)nut::Signal::USER1, &action, NULL)); + CPPUNIT_ASSERT(0 == ::sigaction((int)nut::Signal::USER1, &action, nullptr)); // Send signal directly CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, my_pid)); diff --git a/tests/nutstream_ut.cpp b/tests/nutstream_ut.cpp index fabef325ca..0d93c72ff7 100644 --- a/tests/nutstream_ut.cpp +++ b/tests/nutstream_ut.cpp @@ -60,7 +60,7 @@ static const std::string test_data( * \retval false in case of failure */ static bool readTestData(nut::NutStream * stream) { - assert(NULL != stream); + assert(nullptr != stream); // Read characters from the stream for (size_t pos = 0, iter = 0; ; ++iter) { @@ -103,7 +103,7 @@ static bool readTestData(nut::NutStream * stream) { * \retval false in case of failure */ static bool writeTestData(nut::NutStream * stream) { - assert(NULL != stream); + assert(nullptr != stream); size_t pivot = 0.5 * test_data.size(); diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 2437c2a5e9..6c23ca6376 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -197,7 +197,7 @@ class Options { doubleDash, /**< Double-dash prefixed option */ } type_t; - /** Arguments of the last option processed (\c NULL means bin. args) */ + /** Arguments of the last option processed (\c nullptr means bin. args) */ Arguments * m_last; /** Binary arguments */ @@ -223,7 +223,7 @@ class Options { * \param arg Argument */ inline void addArg(const std::string & arg) { - Arguments * args = NULL != m_last ? m_last : &m_args; + Arguments * args = nullptr != m_last ? m_last : &m_args; args->push_back(arg); } @@ -514,7 +514,7 @@ void Options::dump(std::ostream & stream) const { } -Options::Options(char * const argv[], int argc): m_last(NULL) { +Options::Options(char * const argv[], int argc): m_last(nullptr) { for (int i = 1; i < argc; ++i) { const std::string arg(argv[i]); @@ -531,7 +531,7 @@ Options::Options(char * const argv[], int argc): m_last(NULL) { // "--" alone is valid as it means that what follows // belongs to the binary ("empty" option arguments) else if (2 == arg.size()) - m_last = NULL; + m_last = nullptr; // Double-dashed option else if ('-' != arg[2]) @@ -690,9 +690,9 @@ class NutScanner { // FIXME: Since NUT v2.8.2 nutscan_scan_usb accepts // a `nutscan_usb_t * scanopts` to tweak what values // it reports -- make use of it in this class. - // A NULL value causes safe defaults to be used, + // A nullptr value causes safe defaults to be used, // as decided by the library. - nutscan_device_t * dev = nutscan_scan_usb(NULL); + nutscan_device_t * dev = ::nutscan_scan_usb(nullptr); return dev2list(dev); } @@ -708,13 +708,13 @@ class NutScanner { nutscan_xml_t xml_sec; nutscan_device_t * dev; - memset(&xml_sec, 0, sizeof(xml_sec)); + ::memset(&xml_sec, 0, sizeof(xml_sec)); /* Set the default values for XML HTTP (run_xml()) */ xml_sec.port_http = 80; xml_sec.port_udp = 4679; xml_sec.usec_timeout = us_timeout; - xml_sec.peername = NULL; - dev = nutscan_scan_xml_http_range(NULL, NULL, us_timeout, &xml_sec); + xml_sec.peername = nullptr; + dev = ::nutscan_scan_xml_http_range(nullptr, nullptr, us_timeout, &xml_sec); return dev2list(dev); } @@ -735,7 +735,7 @@ class NutScanner { const std::string & port, long us_timeout) { - nutscan_device_t * dev = nutscan_scan_nut( + nutscan_device_t * dev = ::nutscan_scan_nut( start_ip.c_str(), stop_ip.c_str(), port.c_str(), us_timeout); return dev2list(dev); @@ -749,7 +749,7 @@ class NutScanner { * \return Device list */ inline static devices_t devicesAvahi(long us_timeout) { - nutscan_device_t * dev = nutscan_scan_avahi(us_timeout); + nutscan_device_t * dev = ::nutscan_scan_avahi(us_timeout); return dev2list(dev); } @@ -783,12 +783,12 @@ NutScanner::Device::options_t NutScanner::Device::createOptions(nutscan_options_ options_t options; // Create options - for (; NULL != opt; opt = opt->next) { - assert(NULL != opt->option); + for (; nullptr != opt; opt = opt->next) { + assert(nullptr != opt->option); options.insert( options_t::value_type(opt->option, - NULL != opt->value ? opt->value : "")); + nullptr != opt->value ? opt->value : "")); } return options; @@ -797,8 +797,8 @@ NutScanner::Device::options_t NutScanner::Device::createOptions(nutscan_options_ NutScanner::Device::Device(nutscan_device_t * dev): type(nutscan_device_type_string(dev->type)), - driver(NULL != dev->driver ? dev->driver : ""), - port(NULL != dev->port ? dev->port : ""), + driver(nullptr != dev->driver ? dev->driver : ""), + port(nullptr != dev->port ? dev->port : ""), options(createOptions(dev->opt)) {} @@ -808,7 +808,7 @@ NutScanner::devices_t NutScanner::dev2list(nutscan_device_t * dev_list) { nutscan_device_t * dev = dev_list; - for (; dev != NULL; dev = dev->next) { + for (; dev != nullptr; dev = dev->next) { // Skip devices of type NONE // TBD: This happens with the serial scan on an invalid device // Should be fixed in libnutscan I think @@ -818,7 +818,7 @@ NutScanner::devices_t NutScanner::dev2list(nutscan_device_t * dev_list) { list.push_back(Device(dev)); } - nutscan_free_device(dev_list); + ::nutscan_free_device(dev_list); return list; } @@ -861,7 +861,7 @@ NutScanner::devices_t NutScanner::devicesSNMP( if (!attrs.peer_name.empty()) snmp_attrs.peername = const_cast(attrs.peer_name.c_str()); - nutscan_device_t * dev = nutscan_scan_snmp( + nutscan_device_t * dev = ::nutscan_scan_snmp( start_ip.c_str(), stop_ip.c_str(), us_timeout, &snmp_attrs); return dev2list(dev); @@ -896,7 +896,7 @@ NutScanner::devices_t NutScanner::devicesIPMI( ipmi_attrs.workaround_flags = attrs.wa_flags; ipmi_attrs.ipmi_version = attrs.version; - nutscan_device_t * dev = nutscan_scan_ipmi( + nutscan_device_t * dev = ::nutscan_scan_ipmi( start_ip.c_str(), stop_ip.c_str(), &ipmi_attrs); return dev2list(dev); @@ -919,7 +919,7 @@ NutScanner::devices_t NutScanner::devicesEatonSerial(const std::listname = name; } - assert(NULL != user); + assert(nullptr != user); // Set user attributes bool errors = false; From 56b4d6f8a82bfb65eb62acff3e3376a3daf156ba Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 15:02:04 +0100 Subject: [PATCH 095/121] nutconf related sources: avoid "no out-of-line virtual method definitions" (weak-vtables) Signed-off-by: Jim Klimov --- common/nutconf.cpp | 10 ++++++++++ common/nutipc.cpp | 7 +++++++ common/nutstream.cpp | 6 ++++++ common/nutwriter.cpp | 10 ++++++++++ include/nutconf.hpp | 7 ++++--- include/nutipc.hpp | 4 ++-- include/nutstream.hpp | 2 +- include/nutwriter.hpp | 8 +++++++- 8 files changed, 47 insertions(+), 7 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 75bd13587c..4451083ea5 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -33,6 +33,16 @@ namespace nut { +/* Trivial implementations out of class declaration to avoid + * error: 'ClassName' has no out-of-line virtual method definitions; its vtable + * will be emitted in every translation unit [-Werror,-Wweak-vtables] + */ +Serialisable::~Serialisable() {} +BaseConfiguration::~BaseConfiguration() {} +GenericConfiguration::~GenericConfiguration() {} +UpsConfiguration::~UpsConfiguration() {} +NutParser::~NutParser() {} + // // Tool functions // diff --git a/common/nutipc.cpp b/common/nutipc.cpp index ecda3c3b12..bb0e3f1b4b 100644 --- a/common/nutipc.cpp +++ b/common/nutipc.cpp @@ -29,6 +29,13 @@ namespace nut { +/* Trivial implementations out of class declaration to avoid + * error: 'ClassName' has no out-of-line virtual method definitions; its vtable + * will be emitted in every translation unit [-Werror,-Wweak-vtables] + */ +Process::Main::~Main() {} +Signal::Handler::~Handler() {} + pid_t Process::getPID() #if (defined __cplusplus) && (__cplusplus < 201100) throw() diff --git a/common/nutstream.cpp b/common/nutstream.cpp index ab08f7c5d3..97b672d8e5 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -41,6 +41,12 @@ extern "C" { namespace nut { +/* Trivial implementation out of class declaration to avoid + * error: 'ClassName' has no out-of-line virtual method definitions; its vtable + * will be emitted in every translation unit [-Werror,-Wweak-vtables] + */ +NutStream::~NutStream() {} + NutStream::status_t NutMemory::getChar(char & ch) { if (m_pos == m_impl.size()) return NUTS_EOF; diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index d78cedf825..5fb2acbcd3 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -64,6 +64,16 @@ namespace nut { + +/* Trivial implementations out of class declaration to avoid + * error: 'ClassName' has no out-of-line virtual method definitions; its vtable + * will be emitted in every translation unit [-Werror,-Wweak-vtables] + */ +NutConfigWriter::~NutConfigWriter() {} +NutConfConfigWriter::~NutConfConfigWriter() {} +UpsmonConfigWriter::~UpsmonConfigWriter() {} +UpsdConfigWriter::~UpsdConfigWriter() {} + // End-of-Line separators (arch. dependent) /** UNIX style EoL */ diff --git a/include/nutconf.hpp b/include/nutconf.hpp index dbc02e6b10..9e2b0ef4f9 100644 --- a/include/nutconf.hpp +++ b/include/nutconf.hpp @@ -137,7 +137,7 @@ class Serialisable virtual bool writeTo(NutStream & ostream) const = 0; /** Destructor */ - virtual ~Serialisable() {} + virtual ~Serialisable(); }; // end of class Serialisable @@ -159,7 +159,7 @@ class NutParser NutParser(const char* buffer = nullptr, unsigned int options = OPTION_DEFAULT); NutParser(const std::string& buffer, unsigned int options = OPTION_DEFAULT); - virtual ~NutParser() {} + virtual ~NutParser(); /** Parsing configuration functions * \{ */ @@ -266,7 +266,7 @@ class BaseConfiguration { friend class GenericConfigParser; public: - virtual ~BaseConfiguration() {} + virtual ~BaseConfiguration(); protected: virtual void setGenericConfigSection(const GenericConfigSection& section) = 0; }; @@ -1066,6 +1066,7 @@ class UpsConfiguration : public GenericConfiguration /** \} */ + virtual ~UpsConfiguration() override; }; // end of class UpsConfiguration diff --git a/include/nutipc.hpp b/include/nutipc.hpp index 7799c7cd7e..8f0899eb74 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -80,7 +80,7 @@ class Process { /** Formal constructor */ Main() {} - virtual ~Main() = default; + virtual ~Main(); public: @@ -391,7 +391,7 @@ class Signal { virtual void operator () (enum_t signal) = 0; /** Formal destructor */ - virtual ~Handler() {} + virtual ~Handler(); }; // end of class Handler diff --git a/include/nutstream.hpp b/include/nutstream.hpp index db14170a5b..ddc1993e9a 100644 --- a/include/nutstream.hpp +++ b/include/nutstream.hpp @@ -142,7 +142,7 @@ class NutStream { virtual status_t putData(const std::string & data) = 0; /** Formal destructor */ - virtual ~NutStream() {} + virtual ~NutStream(); }; // end of class NutStream diff --git a/include/nutwriter.hpp b/include/nutwriter.hpp index d86309a073..b04c44acbb 100644 --- a/include/nutwriter.hpp +++ b/include/nutwriter.hpp @@ -167,7 +167,7 @@ class NutConfigWriter: public NutWriter { virtual status_t writeDirective(const std::string & str) = 0; /** Virtual destructor */ - virtual ~NutConfigWriter() {} + virtual ~NutConfigWriter(); }; // end of class NutConfigWriter @@ -225,6 +225,8 @@ class NutConfConfigWriter: public SectionlessConfigWriter { */ status_t writeConfig(const NutConfiguration & config); + /* Ensure an out-of-line method to avoid "weak-vtables" warning */ + virtual ~NutConfConfigWriter() override; }; // end of class NutConfConfigWriter @@ -251,6 +253,8 @@ class UpsmonConfigWriter: public SectionlessConfigWriter { */ status_t writeConfig(const UpsmonConfiguration & config); + /* Ensure an out-of-line method to avoid "weak-vtables" warning */ + virtual ~UpsmonConfigWriter() override; }; // end of class UpsmonConfigWriter @@ -277,6 +281,8 @@ class UpsdConfigWriter: public SectionlessConfigWriter { */ status_t writeConfig(const UpsdConfiguration & config); + /* Ensure an out-of-line method to avoid "weak-vtables" warning */ + virtual ~UpsdConfigWriter() override; }; // end of class UpsdConfigWriter From 81b3216876c1b99545ce386f46fade4d0f9bdd79 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 15:15:49 +0100 Subject: [PATCH 096/121] include/nutconf.hpp: avoid naming clash for Token "type" and "str" properties vs. method args Signed-off-by: Jim Klimov --- include/nutconf.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/nutconf.hpp b/include/nutconf.hpp index 9e2b0ef4f9..6af2bff2ce 100644 --- a/include/nutconf.hpp +++ b/include/nutconf.hpp @@ -187,8 +187,8 @@ class NutParser std::string str; Token():type(TOKEN_NONE),str(){} - Token(TokenType type, const std::string& str=""):type(type),str(str){} - Token(TokenType type, char c):type(type),str(1, c){} + Token(TokenType type_arg, const std::string& str_arg=""):type(type_arg),str(str_arg){} + Token(TokenType type_arg, char c):type(type_arg),str(1, c){} Token(const Token& tok):type(tok.type),str(tok.str){} /* Avoid implicit copy/move operator declarations */ @@ -196,7 +196,7 @@ class NutParser Token& operator=(const Token&) = default; Token& operator=(Token&&) = default; - bool is(TokenType type)const{return this->type==type;} + bool is(TokenType type_arg)const{return this->type==type_arg;} bool operator==(const Token& tok)const{return tok.type==type && tok.str==str;} From 92910d2b5ddbf5bdeda25519b6934481f543f489 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 15:35:20 +0100 Subject: [PATCH 097/121] nutconf related sources: avoid "old-style cast" usage Signed-off-by: Jim Klimov --- common/nutconf.cpp | 4 ++-- common/nutipc.cpp | 4 ++-- common/nutstream.cpp | 6 +++--- include/nutipc.hpp | 10 +++++----- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 4451083ea5..c874afbccf 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -1146,7 +1146,7 @@ void UpsmonConfigParser::onParseDirective(const std::string& directiveName, char UpsmonConfiguration::NotifyType type = UpsmonConfiguration::NotifyTypeFromString(values.front()); if(type!=UpsmonConfiguration::NOTIFY_TYPE_MAX) { - _config->notifyMessages[(unsigned int)type] = *(++values.begin()); + _config->notifyMessages[static_cast(type)] = *(++values.begin()); } } } @@ -1164,7 +1164,7 @@ void UpsmonConfigParser::onParseDirective(const std::string& directiveName, char { flags |= UpsmonConfiguration::NotifyFlagFromString(word); } - _config->notifyFlags[(unsigned int)type] = flags; + _config->notifyFlags[static_cast(type)] = flags; } } } diff --git a/common/nutipc.cpp b/common/nutipc.cpp index bb0e3f1b4b..05cd1bd0ba 100644 --- a/common/nutipc.cpp +++ b/common/nutipc.cpp @@ -169,7 +169,7 @@ int Process::Executor::operator () () args_c_str[i] = nullptr; - int status = ::execvp(bin_c_str, (char * const *)args_c_str); + int status = ::execvp(bin_c_str, const_cast(args_c_str)); // Upon successful execution, the execvp function never returns // (since the process context is replaced, completely) @@ -211,7 +211,7 @@ int Signal::send(Signal::enum_t signame, pid_t pid) throw(std::logic_error) #endif { - int sig = (int)signame; + int sig = static_cast(signame); int status = ::kill(pid, sig); diff --git a/common/nutstream.cpp b/common/nutstream.cpp index 97b672d8e5..39316138c7 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -422,7 +422,7 @@ NutFile::~NutFile() { void NutSocket::Address::init_unix(Address & addr, const std::string & path) { - struct sockaddr_un * un_addr = (struct sockaddr_un *)::malloc(sizeof(struct sockaddr_un)); + struct sockaddr_un * un_addr = reinterpret_cast(::malloc(sizeof(struct sockaddr_un))); if (nullptr == un_addr) throw std::bad_alloc(); @@ -446,7 +446,7 @@ void NutSocket::Address::init_ipv4(Address & addr, const std::vector(::malloc(sizeof(struct sockaddr_in))); if (nullptr == in4_addr) throw std::bad_alloc(); @@ -468,7 +468,7 @@ void NutSocket::Address::init_ipv4(Address & addr, const std::vector & hb, uint16_t port) { assert(16 == hb.size()); - struct sockaddr_in6 * in6_addr = (struct sockaddr_in6 *)::malloc(sizeof(struct sockaddr_in6)); + struct sockaddr_in6 * in6_addr = reinterpret_cast(::malloc(sizeof(struct sockaddr_in6))); if (nullptr == in6_addr) throw std::bad_alloc(); diff --git a/include/nutipc.hpp b/include/nutipc.hpp index 8f0899eb74..a3fbb4cb54 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -553,7 +553,7 @@ int Signal::HandlerThread::s_comm_pipe[2] = { -1, -1 }; template void * Signal::HandlerThread::main(void * comm_pipe_read_end) { - int rfd = *(int *)comm_pipe_read_end; + int rfd = *(reinterpret_cast(comm_pipe_read_end)); H handler; @@ -598,7 +598,7 @@ void * Signal::HandlerThread::main(void * comm_pipe_read_end) { assert(sizeof(word) == read_out); - command_t command = (command_t)word; + command_t command = static_cast(word); switch (command) { case HT_QUIT: @@ -624,7 +624,7 @@ void * Signal::HandlerThread::main(void * comm_pipe_read_end) { assert(sizeof(word) == read_out); - Signal::enum_t sig = (Signal::enum_t)word; + Signal::enum_t sig = static_cast(word); // Handle signal handler(sig); @@ -656,7 +656,7 @@ int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) template void Signal::HandlerThread::signalNotifier(int signal) { int sig[2] = { - (int)Signal::HandlerThread::HT_SIGNAL, + static_cast(Signal::HandlerThread::HT_SIGNAL), }; sig[1] = signal; @@ -733,7 +733,7 @@ void Signal::HandlerThread::quit() throw(std::runtime_error) #endif { - static int quit = (int)Signal::HandlerThread::HT_QUIT; + static int quit = static_cast(Signal::HandlerThread::HT_QUIT); sigPipeWriteCmd(s_comm_pipe[1], &quit, sizeof(quit)); From b178b6ccde913824b16061fbd647931df626e2e8 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 15:55:25 +0100 Subject: [PATCH 098/121] include/nutconf.hpp: err on the safe side by having a default handler in a currently exhaustive switch(enum) Signed-off-by: Jim Klimov --- common/nutconf.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index c874afbccf..223967f73f 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -354,9 +354,27 @@ NutParser::Token NutParser::parseToken() { } break; } + +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) +# pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT +# pragma GCC diagnostic ignored "-Wcovered-switch-default" +#endif +/* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wcovered-switch-default" +#endif default: /* Must not occur. */ break; +#ifdef __clang__ +# pragma clang diagnostic pop +#endif +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) +# pragma GCC diagnostic pop +#endif } } popPos(); From 4992258bb1a1e5bd59fd019d6c10d68bcfb2902a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 15:57:30 +0100 Subject: [PATCH 099/121] include/nutconf.cpp: avoid annotating a switch/case fallthrough Signed-off-by: Jim Klimov --- common/nutconf.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 223967f73f..623c3cce72 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -398,7 +398,8 @@ std::list NutParser::parseLine() { break; case Token::TOKEN_COMMENT: res.push_back(token); - // Do not break, should return (EOL)Token::TOKEN_COMMENT: + // Should return (EOL)Token::TOKEN_COMMENT: + return res; case Token::TOKEN_UNKNOWN: case Token::TOKEN_NONE: case Token::TOKEN_EOL: From c6b9ca5852abe5b75b490df5281e6edebc232c71 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 16:00:52 +0100 Subject: [PATCH 100/121] include/nutconf.cpp: NutConfigParser::parseConfig(): be explicit about the infinite loop Assignment of tok=parseToken() does not return a boolean (nor even a nullptr) so should not be a while(...) condition by itself. Signed-off-by: Jim Klimov --- common/nutconf.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 623c3cce72..fa6701caf4 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -441,7 +441,10 @@ void NutConfigParser::parseConfig() { std::string name; std::list values; char sep = 0; - while (tok = parseToken()) { + while (1) { + tok = parseToken(); + if (!tok) + break; switch (state) { case CPS_DEFAULT: switch (tok.type) { From b6eb8b340f443c9729b78effbd29ee767af74c75 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 16:16:35 +0100 Subject: [PATCH 101/121] include/nutconf.cpp: NutConfigParser::parseConfig(): explicitly handle all enum values in switch/case (and allow "default" to be safe) Signed-off-by: Jim Klimov --- common/nutconf.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index fa6701caf4..48313601e6 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -441,6 +441,18 @@ void NutConfigParser::parseConfig() { std::string name; std::list values; char sep = 0; + +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) +# pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT +# pragma GCC diagnostic ignored "-Wcovered-switch-default" +#endif +/* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcovered-switch-default" +#endif while (1) { tok = parseToken(); if (!tok) @@ -460,6 +472,13 @@ void NutConfigParser::parseConfig() { name = tok.str; state = CPS_DIRECTIVE_HAVE_NAME; break; + + case Token::TOKEN_UNKNOWN: + case Token::TOKEN_NONE: + case Token::TOKEN_BRACKET_CLOSE: + case Token::TOKEN_EQUAL: + case Token::TOKEN_COLON: + case Token::TOKEN_EOL: default: /* WTF ? */ break; @@ -491,6 +510,12 @@ void NutConfigParser::parseConfig() { name.clear(); state = CPS_DEFAULT; break; + + case Token::TOKEN_UNKNOWN: + case Token::TOKEN_NONE: + case Token::TOKEN_BRACKET_OPEN: + case Token::TOKEN_EQUAL: + case Token::TOKEN_COLON: default: /* WTF ? */ break; @@ -516,6 +541,14 @@ void NutConfigParser::parseConfig() { name.clear(); state = CPS_DEFAULT; break; + + case Token::TOKEN_QUOTED_STRING: + case Token::TOKEN_BRACKET_OPEN: + case Token::TOKEN_COLON: + case Token::TOKEN_EQUAL: + case Token::TOKEN_UNKNOWN: + case Token::TOKEN_NONE: + case Token::TOKEN_STRING: default: /* WTF ? */ break; @@ -537,6 +570,15 @@ void NutConfigParser::parseConfig() { name.clear(); state = CPS_DEFAULT; break; + + case Token::TOKEN_QUOTED_STRING: + case Token::TOKEN_BRACKET_OPEN: + case Token::TOKEN_BRACKET_CLOSE: + case Token::TOKEN_UNKNOWN: + case Token::TOKEN_NONE: + case Token::TOKEN_STRING: + case Token::TOKEN_COLON: + case Token::TOKEN_EQUAL: default: /* WTF ? */ break; @@ -570,6 +612,11 @@ void NutConfigParser::parseConfig() { values.push_back(tok.str); state = CPS_DIRECTIVE_VALUES; break; + + case Token::TOKEN_UNKNOWN: + case Token::TOKEN_NONE: + case Token::TOKEN_BRACKET_OPEN: + case Token::TOKEN_BRACKET_CLOSE: default: /* WTF ? */ break; @@ -601,6 +648,13 @@ void NutConfigParser::parseConfig() { values.push_back(tok.str); state = CPS_DIRECTIVE_VALUES; break; + + case Token::TOKEN_UNKNOWN: + case Token::TOKEN_NONE: + case Token::TOKEN_BRACKET_OPEN: + case Token::TOKEN_BRACKET_CLOSE: + case Token::TOKEN_EQUAL: + case Token::TOKEN_COLON: default: /* WTF ? */ break; @@ -632,6 +686,12 @@ void NutConfigParser::parseConfig() { /* TOTHINK: no-op? */ break; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) +# pragma GCC diagnostic pop +#endif onParseEnd(); } From edd72d1079cf90bf02321256ddb0e7237faf2bbd Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 16:25:13 +0100 Subject: [PATCH 102/121] include/nutconf.hpp: align UpsmonConfiguration::notifyFlags type with clients/upsmon.h (notifylist->flags) Note that here we have "unsigned int" and there a plain "int" at the moment; but even with short signed ints we currently do not have too many values :) This fix also drops a warning about shortening the cast when assigning from a temporary "unsigned int flags" in UpsmonConfigParser::onParseDirective() Signed-off-by: Jim Klimov --- common/nutwriter.cpp | 2 +- include/nutconf.hpp | 2 +- tools/nutconf/nutconf.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index 5fb2acbcd3..4432eacde1 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -253,7 +253,7 @@ const NotifyFlagsStrings::FlagStrings NotifyFlagsStrings::flag_str = * * \return NOTIFYFLAG directive string */ -static std::string serializeNotifyFlags(UpsmonConfiguration::NotifyType type, unsigned short flags) { +static std::string serializeNotifyFlags(UpsmonConfiguration::NotifyType type, unsigned int flags) { static const NotifyFlagsStrings::FlagStrings::const_iterator ignore_str_iter = NotifyFlagsStrings::flag_str.find(UpsmonConfiguration::NOTIFY_IGNORE); diff --git a/include/nutconf.hpp b/include/nutconf.hpp index 6af2bff2ce..2ec8c93db4 100644 --- a/include/nutconf.hpp +++ b/include/nutconf.hpp @@ -664,7 +664,7 @@ class UpsmonConfiguration : public Serialisable static NotifyFlag NotifyFlagFromString(const std::string& str); static NotifyType NotifyTypeFromString(const std::string& str); - Settable notifyFlags[NOTIFY_TYPE_MAX]; + Settable notifyFlags[NOTIFY_TYPE_MAX]; Settable notifyMessages[NOTIFY_TYPE_MAX]; struct Monitor { diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 6c23ca6376..e9fa54194c 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -2307,7 +2307,7 @@ void setNotifyFlags( ::exit(1); } - nut::Settable & sum = + nut::Settable & sum = upsmon_conf.notifyFlags[type]; // Clear current flags (unless we want to keep them) @@ -2321,7 +2321,7 @@ void setNotifyFlags( nut::UpsmonConfiguration::NotifyFlag flag = nut::UpsmonConfiguration::NotifyFlagFromString(*spec); - sum |= (unsigned short)flag; + sum |= static_cast(flag); } } From 1a8fd30cb40494e4094d869025fb444b9e3978a2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 13:50:39 +0100 Subject: [PATCH 103/121] include/nutstream.hpp: decorate unimplemented methods which only throw with noreturn (for C++11 and newer) Signed-off-by: Jim Klimov --- include/nutstream.hpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/include/nutstream.hpp b/include/nutstream.hpp index ddc1993e9a..f5f5ca86c8 100644 --- a/include/nutstream.hpp +++ b/include/nutstream.hpp @@ -555,7 +555,11 @@ class NutFile: public NutStream { * * \param orig Original file */ - NutFile(const NutFile & orig) { + NutFile(const NutFile & orig) +#if (defined __cplusplus) && (__cplusplus >= 201100) + __attribute__((noreturn)) +#endif + { NUT_UNUSED_VARIABLE(orig); throw std::logic_error("NOT IMPLEMENTED"); } @@ -569,7 +573,11 @@ class NutFile: public NutStream { * * \param rval Right value */ - NutFile & operator = (const NutFile & rval) { + NutFile & operator = (const NutFile & rval) +#if (defined __cplusplus) && (__cplusplus >= 201100) + __attribute__((noreturn)) +#endif + { NUT_UNUSED_VARIABLE(rval); throw std::logic_error("NOT IMPLEMENTED"); } @@ -1141,7 +1149,11 @@ class NutSocket: public NutStream { * * \param orig Original file */ - NutSocket(const NutSocket & orig) { + NutSocket(const NutSocket & orig) +#if (defined __cplusplus) && (__cplusplus >= 201100) + __attribute__((noreturn)) +#endif + { NUT_UNUSED_VARIABLE(orig); throw std::logic_error("NOT IMPLEMENTED"); } From 7eb561db2ab2ae8afc8ddea087253a636d5c2052 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 15:35:51 +0100 Subject: [PATCH 104/121] include/nutipc.hpp: align templated class destructor name with class name Signed-off-by: Jim Klimov --- include/nutipc.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nutipc.hpp b/include/nutipc.hpp index a3fbb4cb54..c3f339bb25 100644 --- a/include/nutipc.hpp +++ b/include/nutipc.hpp @@ -760,7 +760,7 @@ void Signal::HandlerThread::quit() template -Signal::HandlerThread::~HandlerThread() +Signal::HandlerThread::~HandlerThread() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif From 10506cb83f56329de77def5e5efc86b1ef22c922 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 15:37:40 +0100 Subject: [PATCH 105/121] include/nutipc.hpp: align array deleter with allocator Signed-off-by: Jim Klimov --- common/nutipc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/nutipc.cpp b/common/nutipc.cpp index 05cd1bd0ba..3587c79106 100644 --- a/common/nutipc.cpp +++ b/common/nutipc.cpp @@ -174,7 +174,7 @@ int Process::Executor::operator () () // Upon successful execution, the execvp function never returns // (since the process context is replaced, completely) - delete args_c_str; + delete[] args_c_str; std::stringstream e; From 5b31da5e0c2899512e73b7461b005e5da38eae41 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 15:39:43 +0100 Subject: [PATCH 106/121] include/nutipc.hpp: align size_t vs ssize_t maths Signed-off-by: Jim Klimov --- common/nutipc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/nutipc.cpp b/common/nutipc.cpp index 3587c79106..cf33e02309 100644 --- a/common/nutipc.cpp +++ b/common/nutipc.cpp @@ -194,11 +194,11 @@ int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) do { ssize_t written = ::write(fh, cmd_bytes, cmd_size); - if (-1 == written) + if (written < 0) return errno; cmd_bytes += written; - cmd_size -= written; + cmd_size -= static_cast(written); } while (cmd_size); From a03f1511ead8878057c86998c6b2f9eca1aae557 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 15:46:51 +0100 Subject: [PATCH 107/121] include/nutstream.hpp: align size_t vs ssize_t maths Signed-off-by: Jim Klimov --- common/nutstream.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common/nutstream.cpp b/common/nutstream.cpp index 39316138c7..8e861ac08c 100644 --- a/common/nutstream.cpp +++ b/common/nutstream.cpp @@ -869,13 +869,13 @@ NutStream::status_t NutSocket::getString(std::string & str) for (;;) { ssize_t read_cnt = ::read(m_impl, buffer, sizeof(buffer) / sizeof(buffer[0])); - if (-1 == read_cnt) + if (read_cnt < 0) return NUTS_ERROR; if (0 == read_cnt) return NUTS_OK; - str.append(buffer, read_cnt); + str.append(buffer, static_cast(read_cnt)); } } @@ -903,7 +903,7 @@ NutStream::status_t NutSocket::putString(const std::string & str) throw() #endif { - ssize_t str_len = str.size(); + size_t str_len = str.size(); // Avoid the costly system call unless necessary if (0 == str_len) @@ -911,16 +911,16 @@ NutStream::status_t NutSocket::putString(const std::string & str) ssize_t write_cnt = ::write(m_impl, str.data(), str_len); - if (write_cnt == str_len) - return NUTS_OK; - // TODO: Under certain circumstances, less than the whole // string might be written // Review the code if async. I/O is supported (in which case // the function shall have to implement the blocking using // select/poll/epoll on its own (probably select for portability) - assert(-1 == write_cnt); + assert(write_cnt > 0); + + if (static_cast(write_cnt) == str_len) + return NUTS_OK; // TODO: At least logging of the error (errno), if not propagation From 031c0f0ea8876b702c807219c3ab81bc4fc9096b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 15:55:50 +0100 Subject: [PATCH 108/121] include/nutwriter.hpp: comment away a currently unused static method Signed-off-by: Jim Klimov --- common/nutwriter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/nutwriter.cpp b/common/nutwriter.cpp index 4432eacde1..51afed5820 100644 --- a/common/nutwriter.cpp +++ b/common/nutwriter.cpp @@ -353,6 +353,7 @@ inline static UpsmonConfiguration::NotifyType operator ++(UpsmonConfiguration::N * * \return \c type */ +/* // CURRENTLY UNUSED inline static UpsmonConfiguration::NotifyType operator ++(UpsmonConfiguration::NotifyType & type, int) { UpsmonConfiguration::NotifyType type_copy = type; @@ -360,7 +361,7 @@ inline static UpsmonConfiguration::NotifyType operator ++(UpsmonConfiguration::N return type_copy; } - +*/ /** * \brief UPS monitor definition serializer From fbd05cd739004a2d2455eb3c002a0947346dd2c4 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 16:32:35 +0100 Subject: [PATCH 109/121] include/nutconf.{c,h}pp: align port type to uint16_t (not plain or short int as mismatched in older code) Signed-off-by: Jim Klimov --- common/nutconf.cpp | 4 ++-- include/nutconf.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index 48313601e6..e33e98a152 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -1157,7 +1157,7 @@ void UpsmonConfigParser::onParseDirective(const std::string& directiveName, char std::string word; monitor.upsname = (getline(system, word, '@'), word); monitor.hostname = (getline(system, word), word); - monitor.port = (values.size() == 6 ? *StringToSettableNumber(*it++) : 0u); + monitor.port = (values.size() == 6 ? *StringToSettableNumber(*it++) : 0u); monitor.powerValue = StringToSettableNumber(*it++); monitor.username = *it++; monitor.password = *it++; @@ -1528,7 +1528,7 @@ void UpsdConfigParser::onParseDirective(const std::string& directiveName, char s listen.address = values.front(); if(values.size()==2) { - listen.port = StringToSettableNumber(*(++values.begin())); + listen.port = StringToSettableNumber(*(++values.begin())); } _config->listens.push_back(listen); } diff --git a/include/nutconf.hpp b/include/nutconf.hpp index 2ec8c93db4..086db17e23 100644 --- a/include/nutconf.hpp +++ b/include/nutconf.hpp @@ -669,7 +669,7 @@ class UpsmonConfiguration : public Serialisable struct Monitor { std::string upsname, hostname; - unsigned short port; + uint16_t port; unsigned int powerValue; std::string username, password; bool isMaster; @@ -761,7 +761,7 @@ class UpsdConfiguration : public Serialisable struct Listen { std::string address; - Settable port; + Settable port; inline bool operator==(const Listen& listen)const { From 040f58674ecc5f5998e8a808374a5f44c3d9f804 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 16:41:38 +0100 Subject: [PATCH 110/121] common/nutconf.cpp: cast around std::getline() for parenthesized syntax Why didn't the original author just receive the word into target string?.. e.g.: std::getline(system, monitor.upsname, '@'); std::getline(system, monitor.hostname); Signed-off-by: Jim Klimov --- common/nutconf.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/common/nutconf.cpp b/common/nutconf.cpp index e33e98a152..6f6b884aad 100644 --- a/common/nutconf.cpp +++ b/common/nutconf.cpp @@ -1155,8 +1155,14 @@ void UpsmonConfigParser::onParseDirective(const std::string& directiveName, char ConfigParamList::const_iterator it = values.begin(); std::stringstream system(*it++); std::string word; - monitor.upsname = (getline(system, word, '@'), word); - monitor.hostname = (getline(system, word), word); + /* + * Why didn't the original author just receive the words + * into their target strings?.. e.g.: + * std::getline(system, monitor.upsname, '@'); + * std::getline(system, monitor.hostname); + */ + monitor.upsname = (static_cast(std::getline(system, word, '@')), word); + monitor.hostname = (static_cast(std::getline(system, word)), word); monitor.port = (values.size() == 6 ? *StringToSettableNumber(*it++) : 0u); monitor.powerValue = StringToSettableNumber(*it++); monitor.username = *it++; @@ -1242,7 +1248,7 @@ void UpsmonConfigParser::onParseDirective(const std::string& directiveName, char unsigned int flags = 0; std::string word; std::stringstream stream(*(++values.begin())); - while( getline(stream, word, '+') ) + while( std::getline(stream, word, '+') ) { flags |= UpsmonConfiguration::NotifyFlagFromString(word); } From c3c850ccaccd64d67af39697e4f067e4cc5e121c Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 16:47:42 +0100 Subject: [PATCH 111/121] tools/nutconf/nutconf.cpp: align "us_timeout" to be "useconds_t" not "long" (per libnutscan API evolution) Signed-off-by: Jim Klimov --- tools/nutconf/nutconf.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index e9fa54194c..cd9e99b51e 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -678,7 +678,7 @@ class NutScanner { static devices_t devicesSNMP( const std::string & start_ip, const std::string & stop_ip, - long us_timeout, + useconds_t us_timeout, const SNMPAttributes & attrs); /** @@ -704,7 +704,7 @@ class NutScanner { * * \return Device list */ - inline static devices_t devicesXMLHTTP(long us_timeout) { + inline static devices_t devicesXMLHTTP(useconds_t us_timeout) { nutscan_xml_t xml_sec; nutscan_device_t * dev; @@ -733,7 +733,7 @@ class NutScanner { const std::string & start_ip, const std::string & stop_ip, const std::string & port, - long us_timeout) + useconds_t us_timeout) { nutscan_device_t * dev = ::nutscan_scan_nut( start_ip.c_str(), stop_ip.c_str(), port.c_str(), us_timeout); @@ -748,7 +748,7 @@ class NutScanner { * * \return Device list */ - inline static devices_t devicesAvahi(long us_timeout) { + inline static devices_t devicesAvahi(useconds_t us_timeout) { nutscan_device_t * dev = ::nutscan_scan_avahi(us_timeout); return dev2list(dev); @@ -827,7 +827,7 @@ NutScanner::devices_t NutScanner::dev2list(nutscan_device_t * dev_list) { NutScanner::devices_t NutScanner::devicesSNMP( const std::string & start_ip, const std::string & stop_ip, - long us_timeout, + useconds_t us_timeout, const SNMPAttributes & attrs) { nutscan_snmp_t snmp_attrs; @@ -2660,7 +2660,7 @@ void scanSNMPdevices(const NutConfOptions & options) { const std::string & stop_ip = *arg++; // TBD: where should we get the default? - long us_timeout = 1000000; + useconds_t us_timeout = 1000000; NutScanner::SNMPAttributes attrs; @@ -2775,7 +2775,7 @@ void scanNUTdevices(const NutConfOptions & options) { const std::string & port = *arg++; // TBD: where should we get the default? - long us_timeout = 1000000; + useconds_t us_timeout = 1000000; if (arg != args.end()) { std::stringstream ss(*arg); @@ -2805,7 +2805,7 @@ void scanXMLHTTPdevices(const NutConfOptions & options) { assert(ok); // TBD: where should we get the default? - long us_timeout = 1000000; + useconds_t us_timeout = 1000000; if (!args.empty()) { std::stringstream ss(args.front()); @@ -2833,7 +2833,7 @@ void scanAvahiDevices(const NutConfOptions & options) { assert(ok); // TBD: where should we get the default? - long us_timeout = 1000000; + useconds_t us_timeout = 1000000; if (!args.empty()) { std::stringstream ss(args.front()); From cb5344fecbe4ddc285af430c77bded9e86fada1e Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 16:49:44 +0100 Subject: [PATCH 112/121] tools/nutconf/nutconf.cpp: mark almost all methods in the tool as static Signed-off-by: Jim Klimov --- tools/nutconf/nutconf.cpp | 52 +++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index cd9e99b51e..1a82648bf1 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -1925,7 +1925,7 @@ void NutConfOptions::getMonitor( * \retval true if the configuration file was sourced * \retval false if the file doesn't exist */ -bool source(nut::Serialisable * config, const std::string & file_name) { +static bool source(nut::Serialisable * config, const std::string & file_name) { nut::NutFile file(file_name); if (!file.exists()) @@ -1954,7 +1954,7 @@ bool source(nut::Serialisable * config, const std::string & file_name) { * \param config Configuration object * \param file_name File name */ -void store(nut::Serialisable * config, const std::string & file_name) { +static void store(nut::Serialisable * config, const std::string & file_name) { nut::NutFile file(file_name, nut::NutFile::WRITE_ONLY); bool written_ok = config->writeTo(file); @@ -1978,7 +1978,7 @@ void store(nut::Serialisable * config, const std::string & file_name) { * \retval true IFF nut.conf exists and MODE != none * \retval false otherwise */ -bool isConfigured(const std::string & etc) { +static bool isConfigured(const std::string & etc) { nut::NutFile nut_conf_file(etc + "/nut.conf"); if (!nut_conf_file.exists()) @@ -2006,7 +2006,7 @@ bool isConfigured(const std::string & etc) { * * \return Monitor configuration */ -nut::UpsmonConfiguration::Monitor monitor( +static nut::UpsmonConfiguration::Monitor monitor( size_t i, const NutConfOptions & options) { @@ -2065,7 +2065,7 @@ nut::UpsmonConfiguration::Monitor monitor( * * \return NUT mode (as string) */ -std::string getMode(const std::string & etc) { +static std::string getMode(const std::string & etc) { std::string nut_conf_file(etc + "/nut.conf"); nut::NutConfiguration nut_conf; @@ -2099,7 +2099,7 @@ std::string getMode(const std::string & etc) { * \param mode Mode * \param etc Configuration directory */ -void setMode(const std::string & mode, const std::string & etc) { +static void setMode(const std::string & mode, const std::string & etc) { std::string nut_conf_file(etc + "/nut.conf"); nut::NutConfiguration nut_conf; @@ -2122,7 +2122,7 @@ void setMode(const std::string & mode, const std::string & etc) { * \param etc Configuration directory * \param keep_ex Keep existing entries (discard by default) */ -void setMonitors( +static void setMonitors( const std::list & monitors, const std::string & etc, bool keep_ex = false) { @@ -2159,7 +2159,7 @@ void setMonitors( * * \return Listen address configuration */ -nut::UpsdConfiguration::Listen listenAddr( +static nut::UpsdConfiguration::Listen listenAddr( size_t i, const NutConfOptions & options) { @@ -2197,7 +2197,7 @@ nut::UpsdConfiguration::Listen listenAddr( * \param etc Configuration directory * \param keep_ex Keep existing entries (discard by default) */ -void setListenAddrs( +static void setListenAddrs( const std::list & listen_addrs, const std::string & etc, bool keep_ex = false) { @@ -2231,7 +2231,7 @@ void setListenAddrs( * \param etc Configuration directory * \param keep_ex Keep existing entries (discard by default) */ -void setDevices( +static void setDevices( const std::vector & devices, const std::string & etc, bool keep_ex = false) { @@ -2281,7 +2281,7 @@ void setDevices( * \param flags Notify flags specifications * \param etc Configuration directory */ -void setNotifyFlags( +static void setNotifyFlags( const NutConfOptions::NotifyFlagsSpecs & flags, const std::string & etc) { @@ -2336,7 +2336,7 @@ void setNotifyFlags( * \param msgs Notify messages specifications * \param etc Configuration directory */ -void setNotifyMsgs( +static void setNotifyMsgs( const NutConfOptions::NotifyMsgSpecs & msgs, const std::string & etc) { @@ -2377,7 +2377,7 @@ void setNotifyMsgs( * \param cmd Notify command * \param etc Configuration directory */ -void setNotifyCmd(const std::string & cmd, const std::string & etc) +static void setNotifyCmd(const std::string & cmd, const std::string & etc) { std::string upsmon_conf_file(etc + "/upsmon.conf"); @@ -2399,7 +2399,7 @@ void setNotifyCmd(const std::string & cmd, const std::string & etc) * \param cmd Shutdown command * \param etc Configuration directory */ -void setShutdownCmd(const std::string & cmd, const std::string & etc) +static void setShutdownCmd(const std::string & cmd, const std::string & etc) { std::string upsmon_conf_file(etc + "/upsmon.conf"); @@ -2421,7 +2421,7 @@ void setShutdownCmd(const std::string & cmd, const std::string & etc) * \param min_supplies Minimum of power supplies * \param etc Configuration directory */ -void setMinSupplies(const std::string & min_supplies, const std::string & etc) { +static void setMinSupplies(const std::string & min_supplies, const std::string & etc) { std::string upsmon_conf_file(etc + "/upsmon.conf"); nut::UpsmonConfiguration upsmon_conf; @@ -2454,7 +2454,7 @@ void setMinSupplies(const std::string & min_supplies, const std::string & etc) { * \param powerdown_flag Powerdown flag file * \param etc Configuration directory */ -void setPowerdownFlag(const std::string & powerdown_flag, const std::string & etc) { +static void setPowerdownFlag(const std::string & powerdown_flag, const std::string & etc) { std::string upsmon_conf_file(etc + "/upsmon.conf"); nut::UpsmonConfiguration upsmon_conf; @@ -2476,7 +2476,7 @@ void setPowerdownFlag(const std::string & powerdown_flag, const std::string & et * \param etc Configuration directory * \param keep_ex Keep existing entries (discard by default) */ -void setUsers( +static void setUsers( const NutConfOptions::UserSpecs & users, const std::string & etc, bool keep_ex = false) { @@ -2566,7 +2566,7 @@ void setUsers( * \param devices Device list * \param verbose Verbosity level */ -void printDevicesInfo(const NutScanner::devices_t & devices, unsigned int verbose = 0) { +static void printDevicesInfo(const NutScanner::devices_t & devices, unsigned int verbose = 0) { NutScanner::devices_t::const_iterator dev_iter = devices.begin(); nut::GenericConfiguration devices_conf; @@ -2643,7 +2643,7 @@ void printDevicesInfo(const NutScanner::devices_t & devices, unsigned int verbos * * \param options Options */ -void scanSNMPdevices(const NutConfOptions & options) { +static void scanSNMPdevices(const NutConfOptions & options) { for (size_t i = 0; ; ++i) { NutConfOptions::Arguments args; @@ -2745,7 +2745,7 @@ void scanSNMPdevices(const NutConfOptions & options) { * * \param options Options */ -void scanUSBdevices(const NutConfOptions & options) { +static void scanUSBdevices(const NutConfOptions & options) { NutScanner::devices_t devices = NutScanner::devicesUSB(); printDevicesInfo(devices, options.verbose); @@ -2757,7 +2757,7 @@ void scanUSBdevices(const NutConfOptions & options) { * * \param options Options */ -void scanNUTdevices(const NutConfOptions & options) { +static void scanNUTdevices(const NutConfOptions & options) { for (size_t i = 0; ; ++i) { NutConfOptions::Arguments args; @@ -2796,7 +2796,7 @@ void scanNUTdevices(const NutConfOptions & options) { * * \param options Options */ -void scanXMLHTTPdevices(const NutConfOptions & options) { +static void scanXMLHTTPdevices(const NutConfOptions & options) { NutConfOptions::Arguments args; bool ok = options.getDouble("scan-xml-http", args); @@ -2824,7 +2824,7 @@ void scanXMLHTTPdevices(const NutConfOptions & options) { * * \param options Options */ -void scanAvahiDevices(const NutConfOptions & options) { +static void scanAvahiDevices(const NutConfOptions & options) { NutConfOptions::Arguments args; bool ok = options.getDouble("scan-avahi", args); @@ -2852,7 +2852,7 @@ void scanAvahiDevices(const NutConfOptions & options) { * * \param options Options */ -void scanIPMIdevices(const NutConfOptions & options) { +static void scanIPMIdevices(const NutConfOptions & options) { for (size_t i = 0; ; ++i) { NutConfOptions::Arguments args; @@ -3001,7 +3001,7 @@ void scanIPMIdevices(const NutConfOptions & options) { * * \param options Options */ -void scanSerialDevices(const NutConfOptions & options) { +static void scanSerialDevices(const NutConfOptions & options) { NutConfOptions::Arguments args; bool ok = options.getDouble("scan-serial", args); @@ -3025,7 +3025,7 @@ void scanSerialDevices(const NutConfOptions & options) { * * \return 0 always (exits on error) */ -int mainx(int argc, char * const argv[]) { +static int mainx(int argc, char * const argv[]) { // Get options NutConfOptions options(argv, argc); From d5685d8187e98a9b3703cb250bb286aa002941d0 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 17:02:44 +0100 Subject: [PATCH 113/121] tools/nutconf/nutconf.cpp: avoid shadowing a class property with method arg name Signed-off-by: Jim Klimov --- tools/nutconf/nutconf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/nutconf/nutconf.cpp b/tools/nutconf/nutconf.cpp index 1a82648bf1..15d37ac4a4 100644 --- a/tools/nutconf/nutconf.cpp +++ b/tools/nutconf/nutconf.cpp @@ -1889,7 +1889,7 @@ void NutConfOptions::getMonitor( std::string & pwr_val, std::string & user, std::string & passwd, - std::string & mode, + std::string & mode_arg, size_t which) const #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::range_error) @@ -1907,7 +1907,7 @@ void NutConfOptions::getMonitor( pwr_val = monitors[base_idx + 2]; user = monitors[base_idx + 3]; passwd = monitors[base_idx + 4]; - mode = monitors[base_idx + 5]; + mode_arg = monitors[base_idx + 5]; } From 685ae0ec8ee4355d9a0e8134b5e0d0d872cd033a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 17:20:06 +0100 Subject: [PATCH 114/121] tests/nutstream_ut.cpp: fix cast of size_t vs. double for "pivot" Signed-off-by: Jim Klimov --- tests/nutstream_ut.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/nutstream_ut.cpp b/tests/nutstream_ut.cpp index 0d93c72ff7..9a14dca504 100644 --- a/tests/nutstream_ut.cpp +++ b/tests/nutstream_ut.cpp @@ -105,7 +105,7 @@ static bool readTestData(nut::NutStream * stream) { static bool writeTestData(nut::NutStream * stream) { assert(nullptr != stream); - size_t pivot = 0.5 * test_data.size(); + size_t pivot = static_cast(0.5 * static_cast(test_data.size())); // Write characters to the stream for (size_t i = 0; i < pivot; ++i) { From f5a01d998f4af6f76fc2f24515aa32768f709121 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 17:21:05 +0100 Subject: [PATCH 115/121] nutconf related tests: declare the override of CPPUNIT methods Signed-off-by: Jim Klimov --- tests/nutconf.cpp | 4 ++-- tests/nutconf_ut.cpp | 4 ++-- tests/nutipc_ut.cpp | 4 ++-- tests/nutstream_ut.cpp | 12 ++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/nutconf.cpp b/tests/nutconf.cpp index 1000acdac2..84f4bda9e4 100644 --- a/tests/nutconf.cpp +++ b/tests/nutconf.cpp @@ -46,8 +46,8 @@ class NutConfTest : public CppUnit::TestFixture CPPUNIT_TEST_SUITE_END(); public: - void setUp(); - void tearDown(); + void setUp() override; + void tearDown() override; void testOptions(); void testParseCHARS(); diff --git a/tests/nutconf_ut.cpp b/tests/nutconf_ut.cpp index 37d1866595..e78abea9cf 100644 --- a/tests/nutconf_ut.cpp +++ b/tests/nutconf_ut.cpp @@ -70,8 +70,8 @@ class NutConfigUnitTest: public CppUnit::TestFixture { public: - inline void setUp() {} - inline void tearDown() {} + inline void setUp() override {} + inline void tearDown() override {} inline void test() { testNutConfiguration(); diff --git a/tests/nutipc_ut.cpp b/tests/nutipc_ut.cpp index d548ec414a..eec14b8f70 100644 --- a/tests/nutipc_ut.cpp +++ b/tests/nutipc_ut.cpp @@ -64,8 +64,8 @@ class NutIPCUnitTest: public CppUnit::TestFixture { public: - inline void setUp() {} - inline void tearDown() {} + inline void setUp() override {} + inline void tearDown() override {} inline void test() { testExec(); diff --git a/tests/nutstream_ut.cpp b/tests/nutstream_ut.cpp index 9a14dca504..de960b3362 100644 --- a/tests/nutstream_ut.cpp +++ b/tests/nutstream_ut.cpp @@ -171,8 +171,8 @@ class NutMemoryUnitTest: public NutStreamUnitTest { public: - inline void setUp() {} - inline void tearDown() {} + inline void setUp() override {} + inline void tearDown() override {} void test(); @@ -201,8 +201,8 @@ class NutFileUnitTest: public NutStreamUnitTest { public: - inline void setUp() {} - inline void tearDown() {} + inline void setUp() override {} + inline void tearDown() override {} void test(); @@ -263,8 +263,8 @@ class NutSocketUnitTest: public NutStreamUnitTest { public: - inline void setUp() {}; - inline void tearDown() {} + inline void setUp() override {} + inline void tearDown() override {} void test(); From 94efa11b57c2776682501c2399ac2274b70c6f7a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 17:26:24 +0100 Subject: [PATCH 116/121] tests/nutipc_ut.cpp: declare the override of nut::Signal::Handler methods Signed-off-by: Jim Klimov --- tests/nutipc_ut.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/nutipc_ut.cpp b/tests/nutipc_ut.cpp index eec14b8f70..a5441f34e3 100644 --- a/tests/nutipc_ut.cpp +++ b/tests/nutipc_ut.cpp @@ -154,7 +154,7 @@ static nut::Signal::List caught_signals; class TestSignalHandler: public nut::Signal::Handler { public: - void operator () (nut::Signal::enum_t signal) { + void operator () (nut::Signal::enum_t signal) override { caught_signals.push_back(signal); } From bc65ae2b307171786114fe89aab4f7a50198c880 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 17:41:13 +0100 Subject: [PATCH 117/121] nutconf related tests: avoid "no out-of-line virtual method definitions" (weak-vtables) Signed-off-by: Jim Klimov --- tests/nutconf_ut.cpp | 8 +++++++- tests/nutipc_ut.cpp | 10 +++++++++- tests/nutstream_ut.cpp | 13 ++++++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/tests/nutconf_ut.cpp b/tests/nutconf_ut.cpp index e78abea9cf..b5b29d0474 100644 --- a/tests/nutconf_ut.cpp +++ b/tests/nutconf_ut.cpp @@ -81,9 +81,9 @@ class NutConfigUnitTest: public CppUnit::TestFixture { testUpsdUsersConfiguration(); } + virtual ~NutConfigUnitTest() override; }; // end of class NutConfigUnitTest - // Register the test suite CPPUNIT_TEST_SUITE_REGISTRATION(NutConfigUnitTest); @@ -233,3 +233,9 @@ void NutConfigUnitTest::testUpsdUsersConfiguration() { "\n" ); } + +// Implement out of class declaration to avoid +// error: 'SomeClass' has no out-of-line virtual method +// definitions; its vtable will be emitted in every translation unit +// [-Werror,-Wweak-vtables] +NutConfigUnitTest::~NutConfigUnitTest() {} diff --git a/tests/nutipc_ut.cpp b/tests/nutipc_ut.cpp index a5441f34e3..cdbcc6adee 100644 --- a/tests/nutipc_ut.cpp +++ b/tests/nutipc_ut.cpp @@ -73,9 +73,9 @@ class NutIPCUnitTest: public CppUnit::TestFixture { testSignalRecv(); } + virtual ~NutIPCUnitTest() override; }; // end of class NutIPCUnitTest - // Register the test suite CPPUNIT_TEST_SUITE_REGISTRATION(NutIPCUnitTest); @@ -158,6 +158,7 @@ class TestSignalHandler: public nut::Signal::Handler { caught_signals.push_back(signal); } + virtual ~TestSignalHandler() override; }; // end of class TestSignalHandler void NutIPCUnitTest::testSignalRecv() { @@ -190,3 +191,10 @@ void NutIPCUnitTest::testSignalRecv() { CPPUNIT_ASSERT(caught_signals.front() == nut::Signal::USER1); } + +// Implement out of class declaration to avoid +// error: 'SomeClass' has no out-of-line virtual method +// definitions; its vtable will be emitted in every translation unit +// [-Werror,-Wweak-vtables] +TestSignalHandler::~TestSignalHandler() {} +NutIPCUnitTest::~NutIPCUnitTest() {} diff --git a/tests/nutstream_ut.cpp b/tests/nutstream_ut.cpp index de960b3362..2a18075b7f 100644 --- a/tests/nutstream_ut.cpp +++ b/tests/nutstream_ut.cpp @@ -156,6 +156,7 @@ class NutStreamUnitTest: public CppUnit::TestFixture { CPPUNIT_ASSERT(writeTestData(stream)); } + virtual ~NutStreamUnitTest() override; }; // end of class NutStreamUnitTest @@ -174,7 +175,7 @@ class NutMemoryUnitTest: public NutStreamUnitTest { inline void setUp() override {} inline void tearDown() override {} - void test(); + virtual void test(); }; // end of class NutMemoryUnitTest @@ -204,7 +205,7 @@ class NutFileUnitTest: public NutStreamUnitTest { inline void setUp() override {} inline void tearDown() override {} - void test(); + virtual void test(); }; // end of class NutFileUnitTest @@ -266,7 +267,7 @@ class NutSocketUnitTest: public NutStreamUnitTest { inline void setUp() override {} inline void tearDown() override {} - void test(); + virtual void test(); }; // end of class NutSocketUnitTest @@ -329,3 +330,9 @@ void NutSocketUnitTest::test() { CPPUNIT_TEST_SUITE_REGISTRATION(NutMemoryUnitTest); CPPUNIT_TEST_SUITE_REGISTRATION(NutFileUnitTest); CPPUNIT_TEST_SUITE_REGISTRATION(NutSocketUnitTest); + +// Implement out of class declaration to avoid +// error: 'SomeClass' has no out-of-line virtual method +// definitions; its vtable will be emitted in every translation unit +// [-Werror,-Wweak-vtables] +NutStreamUnitTest::~NutStreamUnitTest() {} From 12739f0e083ecc9b2ede214aa7ced003137a737a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 17:49:05 +0100 Subject: [PATCH 118/121] nutconf related tests: avoid "old-style cast" usage Signed-off-by: Jim Klimov --- tests/nutconf.cpp | 4 ++-- tests/nutipc_ut.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/nutconf.cpp b/tests/nutconf.cpp index 84f4bda9e4..4f4e3edb46 100644 --- a/tests/nutconf.cpp +++ b/tests/nutconf.cpp @@ -84,7 +84,7 @@ void NutConfTest::testOptions() { NutParser parse("Bonjour monde!", NutParser::OPTION_IGNORE_COLON); - CPPUNIT_ASSERT_EQUAL_MESSAGE("Has bad parsing options", (unsigned int)NutParser::OPTION_IGNORE_COLON, parse.getOptions()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Has bad parsing options", static_cast(NutParser::OPTION_IGNORE_COLON), parse.getOptions()); CPPUNIT_ASSERT_MESSAGE("Has not OPTION_IGNORE_COLON parsing option", parse.hasOptions(NutParser::OPTION_IGNORE_COLON)); } @@ -284,7 +284,7 @@ void NutConfTest::testUpsmonConfigParser() CPPUNIT_ASSERT_MESSAGE("Find a NOTIFYFLAG ONLINE", !conf.notifyFlags[nut::UpsmonConfiguration::NOTIFY_ONLINE].set()); CPPUNIT_ASSERT_MESSAGE("Cannot find a NOTIFYFLAG LOWBATT", conf.notifyFlags[nut::UpsmonConfiguration::NOTIFY_LOWBATT].set()); - CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find a NOTIFYFLAG LOWBATT SYSLOG+WALL", 3u, (unsigned int)conf.notifyFlags[nut::UpsmonConfiguration::NOTIFY_LOWBATT]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find a NOTIFYFLAG LOWBATT SYSLOG+WALL", 3u, static_cast(conf.notifyFlags[nut::UpsmonConfiguration::NOTIFY_LOWBATT])); CPPUNIT_ASSERT_MESSAGE("Find a NOTIFYMSG LOWBATT", !conf.notifyMessages[nut::UpsmonConfiguration::NOTIFY_LOWBATT].set()); diff --git a/tests/nutipc_ut.cpp b/tests/nutipc_ut.cpp index cdbcc6adee..273e0a2eec 100644 --- a/tests/nutipc_ut.cpp +++ b/tests/nutipc_ut.cpp @@ -114,12 +114,12 @@ void NutIPCUnitTest::testSignalSend() { action.sa_handler = &testSignalHandler; - CPPUNIT_ASSERT(0 == ::sigaction((int)nut::Signal::USER1, &action, nullptr)); + CPPUNIT_ASSERT(0 == ::sigaction(static_cast(nut::Signal::USER1), &action, nullptr)); // Send signal directly CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, my_pid)); - CPPUNIT_ASSERT((int)nut::Signal::USER1 == signal_caught); + CPPUNIT_ASSERT(static_cast(nut::Signal::USER1) == signal_caught); signal_caught = 0; @@ -139,7 +139,7 @@ void NutIPCUnitTest::testSignalSend() { // Send signal to process via the PIDfile CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, pid_file_name)); - CPPUNIT_ASSERT((int)nut::Signal::USER1 == signal_caught); + CPPUNIT_ASSERT(static_cast(nut::Signal::USER1) == signal_caught); pid_file.removex(); From bf217eef0a0c7f79192db256bc361ed98e74c07c Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 25 Jan 2024 14:36:43 +0100 Subject: [PATCH 119/121] configure.ac: use -Wno-exit-time-destructors and -Wno-global-constructors with clang++ to not worry about "(static) const something" variables Signed-off-by: Jim Klimov --- configure.ac | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index f274a9ee59..9893c52fb9 100644 --- a/configure.ac +++ b/configure.ac @@ -4313,6 +4313,9 @@ dnl # -Wno-padded -- NSPR and NSS headers get to issue lots of that dnl # -Wno-c++98-compat-pedantic -Wno-c++98-compat -- our C++ code uses nullptr dnl # as requested by newer linters, and C++98 does not. We require C++11 dnl # or newer anyway, and skip building C++ library and test otherwise. +dnl # -Wno-exit-time-destructors -- "(static) const something" items would be +dnl # de-allocated en-masse when the program exits, not GC'ed at run-time. +dnl # Oh well... dnl # -Wno-fuse-ld-path -- not much in our control what recipes the autotools dnl # on the build host generate... this tries to avoid failures due to: dnl # clang-13: error: '-fuse-ld=' taking a path is deprecated. @@ -4322,6 +4325,9 @@ dnl # its own good. It detects use of pointer aritmetics as arrays are dnl # walked, which is indeed potentially dangerous. And also is nearly dnl # unavoidable in C (at least not without major rewrites of the world). dnl ### Special exclusion picks for clang-medium (same as hard, plus...): +dnl # -Wno-global-constructors -- using "const something" out of method context +dnl # potentially impacts start-up time and may be prone to race conditions +dnl # (for non-trivial interconnected objects), better be re-architected. dnl # -Wno-float-conversion -Wno-double-promotion -Wno-implicit-float-conversion dnl # -- reduce noise due to floating-point literals like "3.14" being a C dnl # double type (a "3.14f" literal is a C float) cast implicitly into @@ -4359,11 +4365,11 @@ AS_CASE(["${nut_enable_warnings}"], ], [clang-hard], [ CFLAGS="${CFLAGS} -ferror-limit=0 -Wno-system-headers -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -Wno-cast-qual -pedantic -Wno-fuse-ld-path -Wno-unsafe-buffer-usage" - CXXFLAGS="${CXXFLAGS} -ferror-limit=0 -Wno-system-headers -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-fuse-ld-path -Wno-unsafe-buffer-usage" + CXXFLAGS="${CXXFLAGS} -ferror-limit=0 -Wno-system-headers -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-exit-time-destructors -Wno-fuse-ld-path -Wno-unsafe-buffer-usage" ], [clang-medium], [ CFLAGS="${CFLAGS} -ferror-limit=0 -Wno-system-headers -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -Wno-cast-qual -pedantic -Wno-fuse-ld-path -Wno-unsafe-buffer-usage -Wno-float-conversion -Wno-double-promotion -Wno-implicit-float-conversion -Wno-conversion -Wno-incompatible-pointer-types-discards-qualifiers -Wno-incompatible-function-pointer-types-strict" - CXXFLAGS="${CXXFLAGS} -ferror-limit=0 -Wno-system-headers -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-fuse-ld-path -Wno-unsafe-buffer-usage" + CXXFLAGS="${CXXFLAGS} -ferror-limit=0 -Wno-system-headers -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-exit-time-destructors -Wno-global-constructors -Wno-fuse-ld-path -Wno-unsafe-buffer-usage" ], [clang-minimal], [ CFLAGS="${CFLAGS} -ferror-limit=0 -Wall -Wextra -Wno-documentation" From 7567b499a7258b0a6c826c6c376b35e447af3bfc Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 15 Jan 2022 11:43:44 +0100 Subject: [PATCH 120/121] ci_build.sh: add support for CANBUILD_NUTCONF toggle (NUT_BUILD_CAPS=nutconf... for CI farm) --- ci_build.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ci_build.sh b/ci_build.sh index 3658a61555..f930c181a3 100755 --- a/ci_build.sh +++ b/ci_build.sh @@ -293,6 +293,19 @@ for L in $NODE_LABELS ; do "NUT_BUILD_CAPS=cppunit"|"NUT_BUILD_CAPS=cppunit=yes") [ -n "$CANBUILD_CPPUNIT_TESTS" ] || CANBUILD_CPPUNIT_TESTS=yes ;; + # Currently we don't build --with-nutconf" by default, unless desired + # explicitly by developers' local workflow (or NUT CI farm recipes), + # that codebase needs some clean-up first... This should cover both + # the tool and the cppunit tests for it (if active per above). + "NUT_BUILD_CAPS=nutconf=no") + [ -n "$CANBUILD_NUTCONF" ] || CANBUILD_NUTCONF=no ;; + "NUT_BUILD_CAPS=nutconf=no-gcc") + [ -n "$CANBUILD_NUTCONF" ] || CANBUILD_NUTCONF=no-gcc ;; + "NUT_BUILD_CAPS=nutconf=no-clang") + [ -n "$CANBUILD_NUTCONF" ] || CANBUILD_NUTCONF=no-clang ;; + "NUT_BUILD_CAPS=nutconf"|"NUT_BUILD_CAPS=nutconf=yes") + [ -n "$CANBUILD_NUTCONF" ] || CANBUILD_NUTCONF=yes ;; + # Some (QEMU) builders have issues running valgrind as a tool "NUT_BUILD_CAPS=valgrind=no") [ -n "$CANBUILD_VALGRIND_TESTS" ] || CANBUILD_VALGRIND_TESTS=no ;; @@ -1060,6 +1073,21 @@ default|default-alldrv|default-alldrv:no-distcheck|default-all-errors|default-sp CONFIG_OPTS+=("--enable-cppunit=no") fi + if [ -z "${CANBUILD_NUTCONF-}" ] \ + || ( [ "${CANBUILD_NUTCONF-}" = "no-gcc" ] && [ "$COMPILER_FAMILY" = "GCC" ] ) \ + || ( [ "${CANBUILD_NUTCONF-}" = "no-clang" ] && [ "$COMPILER_FAMILY" = "CLANG" ] ) \ + ; then + CANBUILD_NUTCONF=no + fi + + if [ "${CANBUILD_NUTCONF-}" = yes ] ; then + echo "WARNING: Build agent says it can build nutconf, enabling the experimental feature" >&2 + CONFIG_OPTS+=("--with-nutconf=yes") + elif [ "${CANBUILD_NUTCONF-}" = no ] ; then + echo "WARNING: Build agent says it can not build nutconf (or did not say anything), disabling the feature" >&2 + CONFIG_OPTS+=("--with-nutconf=no") + fi + if [ "${CANBUILD_VALGRIND_TESTS-}" = no ] ; then echo "WARNING: Build agent says it has a broken valgrind, adding configure option to skip tests with it" >&2 CONFIG_OPTS+=("--with-valgrind=no") From 79327f91414d4ff59d0ffa7e02b98cdbbe8363be Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 29 Jan 2024 00:01:17 +0100 Subject: [PATCH 121/121] tests/nutstream_ut.cpp: Randomize bind(port) to try avoiding collisions in parallel testing Signed-off-by: Jim Klimov --- tests/nutstream_ut.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/nutstream_ut.cpp b/tests/nutstream_ut.cpp index 2a18075b7f..29f507e68b 100644 --- a/tests/nutstream_ut.cpp +++ b/tests/nutstream_ut.cpp @@ -272,7 +272,8 @@ class NutSocketUnitTest: public NutStreamUnitTest { }; // end of class NutSocketUnitTest -const nut::NutSocket::Address NutSocketUnitTest::m_listen_address(127, 0, 0, 1, 10000); +/* Randomize to try avoiding collisions in parallel testing */ +const nut::NutSocket::Address NutSocketUnitTest::m_listen_address(127, 0, 0, 1, 10000 + (::random() % 40000)); bool NutSocketUnitTest::Writer::run() {