From patchwork Sun Aug 22 20:30:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: QI Fuli X-Patchwork-Id: 12451673 Received: from mail-pg1-f177.google.com (mail-pg1-f177.google.com [209.85.215.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D5BF2FAF for ; Sun, 22 Aug 2021 20:30:55 +0000 (UTC) Received: by mail-pg1-f177.google.com with SMTP id k24so14691678pgh.8 for ; Sun, 22 Aug 2021 13:30:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=TsA80+qagPheopBvZQRdIPQYCjP+BpcwYggVjiGwGvo=; b=fbAQ+QAgWjBSajOfjbcAXBumu7Z0xrmIXwjRaQJrzdoyMVxAjOfmEI+ecAEmzEsYWg vdeC8YgRWaG1lxNOLIIESpwQrmvk5RAJIOo+h/ZSzXYiR6hO9DNAJ5kHH0qNujoT3qul Fj0yrbD/OUicCwDT8pKo6A4mEJv07XHBq26Q2NQuOYpOofNXo08pOvY0OM9DPBNuHl/B KavdKytnRyAwatpcZ2Y7r8vQo+EwI2tIWQEhlM6eA0ulyrmbKshOlswCuTOW7pl+x/d7 lwEXgkuFknteeJ9MM8jW4GYOjxOqyzwTXAL0bp2netzqZYAosgiqK3CEb3WZT5VO01jk UqEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=TsA80+qagPheopBvZQRdIPQYCjP+BpcwYggVjiGwGvo=; b=kLvB3vXz5+su9bcD4S7cOO1KUVp2E2P0FOJcF7EfBuQEXhXMMNY3djqZvI5+S0J6Y9 sAA73+CMTlxW4kZdrPjc4LyKwXPYFXaWxgq6CWk5CQpE4cdlTh1bNhGnCejjCs97blBM 7amgX9l5UiieLkcCreXzSuAq0go/+fPe22QUDYqctF3LvFBzFQQ1FjKfxR7XRLW1ss/K oNvFN8gAteJkn84Ml+eGq1n4uV9luOBMQXKIPZxxRNjsEn/h6cFKvasGCD4rVwL+7346 ym6EkyY2w/2VhfXXIqs2b9xRkOaqOc9uFLhbuRbH1RHbGYoqcYXlz8y87ZMgO+cqbl4R 4U6A== X-Gm-Message-State: AOAM533MK267+3ieg9/gh1Mso4KZpMSZ91s5ETOKcGxvYRa9NSDlzl02 /ZImZO33JUHp4BtEjyiagIVyE7RBQwPRhQ== X-Google-Smtp-Source: ABdhPJwmX+ynC9oqi9A8Jdo8xBE3Y2Ulz5BfWJme6d786nH/5Glk3QxBm85Mo7/8hsc3+GzCrcTuxw== X-Received: by 2002:a65:4682:: with SMTP id h2mr29289186pgr.409.1629664254421; Sun, 22 Aug 2021 13:30:54 -0700 (PDT) Received: from localhost.localdomain (125x103x255x1.ap125.ftth.ucom.ne.jp. [125.103.255.1]) by smtp.gmail.com with ESMTPSA id n30sm13587804pfv.87.2021.08.22.13.30.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Aug 2021 13:30:54 -0700 (PDT) From: QI Fuli X-Google-Original-From: QI Fuli To: nvdimm@lists.linux.dev Cc: QI Fuli Subject: [ndctl PATCH 1/5] ndctl, ccan: import ciniparser Date: Mon, 23 Aug 2021 05:30:11 +0900 Message-Id: <20210822203015.528438-2-qi.fuli@fujitsu.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210822203015.528438-1-qi.fuli@fujitsu.com> References: <20210822203015.528438-1-qi.fuli@fujitsu.com> Precedence: bulk X-Mailing-List: nvdimm@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Import ciniparser from ccan[1]. [1] https://ccodearchive.net/info/ciniparser.html Signed-off-by: QI Fuli --- Makefile.am | 6 +- ccan/ciniparser/ciniparser.c | 480 +++++++++++++++++++++++++++++++++++ ccan/ciniparser/ciniparser.h | 262 +++++++++++++++++++ ccan/ciniparser/dictionary.c | 266 +++++++++++++++++++ ccan/ciniparser/dictionary.h | 166 ++++++++++++ 5 files changed, 1179 insertions(+), 1 deletion(-) create mode 100644 ccan/ciniparser/ciniparser.c create mode 100644 ccan/ciniparser/ciniparser.h create mode 100644 ccan/ciniparser/dictionary.c create mode 100644 ccan/ciniparser/dictionary.h diff --git a/Makefile.am b/Makefile.am index 60a1998..960b5e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,7 +64,11 @@ libccan_a_SOURCES = \ ccan/array_size/array_size.h \ ccan/minmax/minmax.h \ ccan/short_types/short_types.h \ - ccan/endian/endian.h + ccan/endian/endian.h \ + ccan/ciniparser/ciniparser.h \ + ccan/ciniparser/ciniparser.c \ + ccan/ciniparser/dictionary.h \ + ccan/ciniparser/dictionary.c noinst_LIBRARIES += libutil.a libutil_a_SOURCES = \ diff --git a/ccan/ciniparser/ciniparser.c b/ccan/ciniparser/ciniparser.c new file mode 100644 index 0000000..527f837 --- /dev/null +++ b/ccan/ciniparser/ciniparser.c @@ -0,0 +1,480 @@ +/* Copyright (c) 2000-2007 by Nicolas Devillard. + * Copyright (x) 2009 by Tim Post + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** @addtogroup ciniparser + * @{ + */ +/** + * @file ciniparser.c + * @author N. Devillard + * @date Sep 2007 + * @version 3.0 + * @brief Parser for ini files. + */ + +#include +#include + +#define ASCIILINESZ (1024) +#define INI_INVALID_KEY ((char*) NULL) + +/** + * This enum stores the status for each parsed line (internal use only). + */ +typedef enum _line_status_ { + LINE_UNPROCESSED, + LINE_ERROR, + LINE_EMPTY, + LINE_COMMENT, + LINE_SECTION, + LINE_VALUE +} line_status; + + +/** + * @brief Convert a string to lowercase. + * @param s String to convert. + * @return ptr to statically allocated string. + * + * This function returns a pointer to a statically allocated string + * containing a lowercased version of the input string. Do not free + * or modify the returned string! Since the returned string is statically + * allocated, it will be modified at each function call (not re-entrant). + */ +static char *strlwc(const char *s) +{ + static char l[ASCIILINESZ+1]; + int i; + + if (s == NULL) + return NULL; + + for (i = 0; s[i] && i < ASCIILINESZ; i++) + l[i] = tolower(s[i]); + l[i] = '\0'; + return l; +} + +/** + * @brief Remove blanks at the beginning and the end of a string. + * @param s String to parse. + * @return ptr to statically allocated string. + * + * This function returns a pointer to a statically allocated string, + * which is identical to the input string, except that all blank + * characters at the end and the beg. of the string have been removed. + * Do not free or modify the returned string! Since the returned string + * is statically allocated, it will be modified at each function call + * (not re-entrant). + */ +static char *strstrip(const char *s) +{ + static char l[ASCIILINESZ+1]; + unsigned int i, numspc; + + if (s == NULL) + return NULL; + + while (isspace(*s)) + s++; + + for (i = numspc = 0; s[i] && i < ASCIILINESZ; i++) { + l[i] = s[i]; + if (isspace(l[i])) + numspc++; + else + numspc = 0; + } + l[i - numspc] = '\0'; + return l; +} + +/** + * @brief Load a single line from an INI file + * @param input_line Input line, may be concatenated multi-line input + * @param section Output space to store section + * @param key Output space to store key + * @param value Output space to store value + * @return line_status value + */ +static +line_status ciniparser_line(char *input_line, char *section, + char *key, char *value) +{ + line_status sta; + char line[ASCIILINESZ+1]; + int len; + + strcpy(line, strstrip(input_line)); + len = (int) strlen(line); + + if (len < 1) { + /* Empty line */ + sta = LINE_EMPTY; + } else if (line[0] == '#') { + /* Comment line */ + sta = LINE_COMMENT; + } else if (line[0] == '[' && line[len-1] == ']') { + /* Section name */ + sscanf(line, "[%[^]]", section); + strcpy(section, strstrip(section)); + strcpy(section, strlwc(section)); + sta = LINE_SECTION; + } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2 + || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2 + || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) { + /* Usual key=value, with or without comments */ + strcpy(key, strstrip(key)); + strcpy(key, strlwc(key)); + strcpy(value, strstrip(value)); + /* + * sscanf cannot handle '' or "" as empty values + * this is done here + */ + if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) { + value[0] = 0; + } + sta = LINE_VALUE; + } else if (sscanf(line, "%[^=] = %[;#]", key, value) == 2 + || sscanf(line, "%[^=] %[=]", key, value) == 2) { + /* + * Special cases: + * key= + * key=; + * key=# + */ + strcpy(key, strstrip(key)); + strcpy(key, strlwc(key)); + value[0] = 0; + sta = LINE_VALUE; + } else { + /* Generate syntax error */ + sta = LINE_ERROR; + } + return sta; +} + +/* The remaining public functions are documented in ciniparser.h */ + +int ciniparser_getnsec(dictionary *d) +{ + int i; + int nsec; + + if (d == NULL) + return -1; + + nsec = 0; + for (i = 0; i < d->size; i++) { + if (d->key[i] == NULL) + continue; + if (strchr(d->key[i], ':') == NULL) { + nsec ++; + } + } + + return nsec; +} + +char *ciniparser_getsecname(dictionary *d, int n) +{ + int i; + int foundsec; + + if (d == NULL || n < 0) + return NULL; + + if (n == 0) + n ++; + + foundsec = 0; + + for (i = 0; i < d->size; i++) { + if (d->key[i] == NULL) + continue; + if (! strchr(d->key[i], ':')) { + foundsec++; + if (foundsec >= n) + break; + } + } + + if (foundsec == n) { + return d->key[i]; + } + + return (char *) NULL; +} + +void ciniparser_dump(dictionary *d, FILE *f) +{ + int i; + + if (d == NULL || f == NULL) + return; + + for (i = 0; i < d->size; i++) { + if (d->key[i] == NULL) + continue; + if (d->val[i] != NULL) { + fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); + } else { + fprintf(f, "[%s]=UNDEF\n", d->key[i]); + } + } + + return; +} + +void ciniparser_dump_ini(dictionary *d, FILE *f) +{ + int i, j; + char keym[ASCIILINESZ+1]; + int nsec; + char *secname; + int seclen; + + if (d == NULL || f == NULL) + return; + + memset(keym, 0, ASCIILINESZ + 1); + + nsec = ciniparser_getnsec(d); + if (nsec < 1) { + /* No section in file: dump all keys as they are */ + for (i = 0; i < d->size; i++) { + if (d->key[i] == NULL) + continue; + fprintf(f, "%s = %s\n", d->key[i], d->val[i]); + } + return; + } + + for (i = 0; i < nsec; i++) { + secname = ciniparser_getsecname(d, i); + seclen = (int)strlen(secname); + fprintf(f, "\n[%s]\n", secname); + snprintf(keym, ASCIILINESZ + 1, "%s:", secname); + for (j = 0; j < d->size; j++) { + if (d->key[j] == NULL) + continue; + if (!strncmp(d->key[j], keym, seclen+1)) { + fprintf(f, "%-30s = %s\n", + d->key[j]+seclen+1, + d->val[j] ? d->val[j] : ""); + } + } + } + fprintf(f, "\n"); + + return; +} + +char *ciniparser_getstring(dictionary *d, const char *key, char *def) +{ + char *lc_key; + char *sval; + + if (d == NULL || key == NULL) + return def; + + lc_key = strlwc(key); + sval = dictionary_get(d, lc_key, def); + + return sval; +} + +int ciniparser_getint(dictionary *d, const char *key, int notfound) +{ + char *str; + + str = ciniparser_getstring(d, key, INI_INVALID_KEY); + + if (str == INI_INVALID_KEY) + return notfound; + + return (int) strtol(str, NULL, 10); +} + +double ciniparser_getdouble(dictionary *d, const char *key, double notfound) +{ + char *str; + + str = ciniparser_getstring(d, key, INI_INVALID_KEY); + + if (str == INI_INVALID_KEY) + return notfound; + + return atof(str); +} + +int ciniparser_getboolean(dictionary *d, const char *key, int notfound) +{ + char *c; + int ret; + + c = ciniparser_getstring(d, key, INI_INVALID_KEY); + if (c == INI_INVALID_KEY) + return notfound; + + switch(c[0]) { + case 'y': case 'Y': case '1': case 't': case 'T': + ret = 1; + break; + case 'n': case 'N': case '0': case 'f': case 'F': + ret = 0; + break; + default: + ret = notfound; + break; + } + + return ret; +} + +int ciniparser_find_entry(dictionary *ini, char *entry) +{ + int found = 0; + + if (ciniparser_getstring(ini, entry, INI_INVALID_KEY) != INI_INVALID_KEY) { + found = 1; + } + + return found; +} + +int ciniparser_set(dictionary *d, char *entry, char *val) +{ + return dictionary_set(d, strlwc(entry), val); +} + +void ciniparser_unset(dictionary *ini, char *entry) +{ + dictionary_unset(ini, strlwc(entry)); +} + +dictionary *ciniparser_load(const char *ininame) +{ + FILE *in; + char line[ASCIILINESZ+1]; + char section[ASCIILINESZ+1]; + char key[ASCIILINESZ+1]; + char tmp[ASCIILINESZ+1]; + char val[ASCIILINESZ+1]; + int last = 0, len, lineno = 0, errs = 0; + dictionary *dict; + + if ((in = fopen(ininame, "r")) == NULL) { + fprintf(stderr, "ciniparser: cannot open %s\n", ininame); + return NULL; + } + + dict = dictionary_new(0); + if (!dict) { + fclose(in); + return NULL; + } + + memset(line, 0, ASCIILINESZ + 1); + memset(section, 0, ASCIILINESZ + 1); + memset(key, 0, ASCIILINESZ + 1); + memset(val, 0, ASCIILINESZ + 1); + last = 0; + + while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) { + lineno++; + len = (int) strlen(line)-1; + /* Safety check against buffer overflows */ + if (line[len] != '\n') { + fprintf(stderr, + "ciniparser: input line too long in %s (%d)\n", + ininame, + lineno); + dictionary_del(dict); + fclose(in); + return NULL; + } + + /* Get rid of \n and spaces at end of line */ + while ((len >= 0) && + ((line[len] == '\n') || (isspace(line[len])))) { + line[len] = 0; + len--; + } + + /* Detect multi-line */ + if (len >= 0 && line[len] == '\\') { + /* Multi-line value */ + last = len; + continue; + } + + switch (ciniparser_line(line, section, key, val)) { + case LINE_EMPTY: + case LINE_COMMENT: + break; + + case LINE_SECTION: + errs = dictionary_set(dict, section, NULL); + break; + + case LINE_VALUE: + snprintf(tmp, ASCIILINESZ + 1, "%s:%s", section, key); + errs = dictionary_set(dict, tmp, val); + break; + + case LINE_ERROR: + fprintf(stderr, "ciniparser: syntax error in %s (%d):\n", + ininame, lineno); + fprintf(stderr, "-> %s\n", line); + errs++; + break; + + default: + break; + } + memset(line, 0, ASCIILINESZ); + last = 0; + if (errs < 0) { + fprintf(stderr, "ciniparser: memory allocation failure\n"); + break; + } + } + + if (errs) { + dictionary_del(dict); + dict = NULL; + } + + fclose(in); + + return dict; +} + +void ciniparser_freedict(dictionary *d) +{ + dictionary_del(d); +} + +/** @} + */ diff --git a/ccan/ciniparser/ciniparser.h b/ccan/ciniparser/ciniparser.h new file mode 100644 index 0000000..b61c1d6 --- /dev/null +++ b/ccan/ciniparser/ciniparser.h @@ -0,0 +1,262 @@ +#ifndef _INIPARSER_H_ +#define _INIPARSER_H_ + +/* Copyright (c) 2000-2007 by Nicolas Devillard. + * Copyright (x) 2009 by Tim Post + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** @addtogroup ciniparser + * @{ + */ + +/** + * @file ciniparser.h + * @author N. Devillard + * @date Sep 2007 + * @version 3.0 + * @brief Parser for ini files. + */ + +#include +#include +#include +#include + +#include "dictionary.h" + +#define ciniparser_getstr(d, k) ciniparser_getstring(d, k, NULL) +#define ciniparser_setstr ciniparser_setstring + +/** + * @brief Get number of sections in a dictionary + * @param d Dictionary to examine + * @return int Number of sections found in dictionary, -1 on error + * + * This function returns the number of sections found in a dictionary. + * The test to recognize sections is done on the string stored in the + * dictionary: a section name is given as "section" whereas a key is + * stored as "section:key", thus the test looks for entries that do not + * contain a colon. + * + * This clearly fails in the case a section name contains a colon, but + * this should simply be avoided. + */ +int ciniparser_getnsec(dictionary *d); + +/** + * @brief Get name for section n in a dictionary. + * @param d Dictionary to examine + * @param n Section number (from 0 to nsec-1). + * @return Pointer to char string, NULL on error + * + * This function locates the n-th section in a dictionary and returns + * its name as a pointer to a string statically allocated inside the + * dictionary. Do not free or modify the returned string! + */ +char *ciniparser_getsecname(dictionary *d, int n); + +/** + * @brief Save a dictionary to a loadable ini file + * @param d Dictionary to dump + * @param f Opened file pointer to dump to + * @return void + * + * This function dumps a given dictionary into a loadable ini file. + * It is Ok to specify @c stderr or @c stdout as output files. + */ +void ciniparser_dump_ini(dictionary *d, FILE *f); + +/** + * @brief Dump a dictionary to an opened file pointer. + * @param d Dictionary to dump. + * @param f Opened file pointer to dump to. + * @return void + * + * This function prints out the contents of a dictionary, one element by + * line, onto the provided file pointer. It is OK to specify @c stderr + * or @c stdout as output files. This function is meant for debugging + * purposes mostly. + */ +void ciniparser_dump(dictionary *d, FILE *f); + +/** + * @brief Get the string associated to a key + * @param d Dictionary to search + * @param key Key string to look for + * @param def Default value to return if key not found. + * @return pointer to statically allocated character string + * + * This function queries a dictionary for a key. A key as read from an + * ini file is given as "section:key". If the key cannot be found, + * the pointer passed as 'def' is returned. + * The returned char pointer is pointing to a string allocated in + * the dictionary, do not free or modify it. + */ +char *ciniparser_getstring(dictionary *d, const char *key, char *def); + +/** + * @brief Get the string associated to a key, convert to an int + * @param d Dictionary to search + * @param key Key string to look for + * @param notfound Value to return in case of error + * @return integer + * + * This function queries a dictionary for a key. A key as read from an + * ini file is given as "section:key". If the key cannot be found, + * the notfound value is returned. + * + * Supported values for integers include the usual C notation + * so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + * are supported. Examples: + * + * - "42" -> 42 + * - "042" -> 34 (octal -> decimal) + * - "0x42" -> 66 (hexa -> decimal) + * + * Warning: the conversion may overflow in various ways. Conversion is + * totally outsourced to strtol(), see the associated man page for overflow + * handling. + * + * Credits: Thanks to A. Becker for suggesting strtol() + */ +int ciniparser_getint(dictionary *d, const char *key, int notfound); + +/** + * @brief Get the string associated to a key, convert to a double + * @param d Dictionary to search + * @param key Key string to look for + * @param notfound Value to return in case of error + * @return double + * + * This function queries a dictionary for a key. A key as read from an + * ini file is given as "section:key". If the key cannot be found, + * the notfound value is returned. + */ +double ciniparser_getdouble(dictionary *d, const char *key, double notfound); + +/** + * @brief Get the string associated to a key, convert to a boolean + * @param d Dictionary to search + * @param key Key string to look for + * @param notfound Value to return in case of error + * @return integer + * + * This function queries a dictionary for a key. A key as read from an + * ini file is given as "section:key". If the key cannot be found, + * the notfound value is returned. + * + * A true boolean is found if one of the following is matched: + * + * - A string starting with 'y' + * - A string starting with 'Y' + * - A string starting with 't' + * - A string starting with 'T' + * - A string starting with '1' + * + * A false boolean is found if one of the following is matched: + * + * - A string starting with 'n' + * - A string starting with 'N' + * - A string starting with 'f' + * - A string starting with 'F' + * - A string starting with '0' + * + * The notfound value returned if no boolean is identified, does not + * necessarily have to be 0 or 1. + */ +int ciniparser_getboolean(dictionary *d, const char *key, int notfound); + +/** + * @brief Set an entry in a dictionary. + * @param ini Dictionary to modify. + * @param entry Entry to modify (entry name) + * @param val New value to associate to the entry. + * @return int 0 if Ok, -1 otherwise. + * + * If the given entry can be found in the dictionary, it is modified to + * contain the provided value. If it cannot be found, -1 is returned. + * It is Ok to set val to NULL. + */ +int ciniparser_setstring(dictionary *ini, char *entry, char *val); + +/** + * @brief Delete an entry in a dictionary + * @param ini Dictionary to modify + * @param entry Entry to delete (entry name) + * @return void + * + * If the given entry can be found, it is deleted from the dictionary. + */ +void ciniparser_unset(dictionary *ini, char *entry); + +/** + * @brief Finds out if a given entry exists in a dictionary + * @param ini Dictionary to search + * @param entry Name of the entry to look for + * @return integer 1 if entry exists, 0 otherwise + * + * Finds out if a given entry exists in the dictionary. Since sections + * are stored as keys with NULL associated values, this is the only way + * of querying for the presence of sections in a dictionary. + */ +int ciniparser_find_entry(dictionary *ini, char *entry) ; + +/** + * @brief Parse an ini file and return an allocated dictionary object + * @param ininame Name of the ini file to read. + * @return Pointer to newly allocated dictionary + * + * This is the parser for ini files. This function is called, providing + * the name of the file to be read. It returns a dictionary object that + * should not be accessed directly, but through accessor functions + * instead. + * + * The returned dictionary must be freed using ciniparser_freedict(). + */ +dictionary *ciniparser_load(const char *ininame); + +/** + * @brief Free all memory associated to an ini dictionary + * @param d Dictionary to free + * @return void + * + * Free all memory associated to an ini dictionary. + * It is mandatory to call this function before the dictionary object + * gets out of the current context. + */ +void ciniparser_freedict(dictionary *d); + +/** + * @brief Set an item in the dictionary + * @param d Dictionary object created by ciniparser_load() + * @param entry Entry in the dictionary to manipulate + * @param val Value to assign to the entry + * @return 0 on success, -1 on error + * + * Remember that string values are converted by ciniparser_getboolean(), + * ciniparser_getdouble(), etc. It is also OK to set an entry to NULL. + */ +int ciniparser_set(dictionary *d, char *entry, char *val); + +#endif +/** @} + */ diff --git a/ccan/ciniparser/dictionary.c b/ccan/ciniparser/dictionary.c new file mode 100644 index 0000000..19dd641 --- /dev/null +++ b/ccan/ciniparser/dictionary.c @@ -0,0 +1,266 @@ +/* Copyright (c) 2000-2007 by Nicolas Devillard. + * Copyright (x) 2009 by Tim Post + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** @addtogroup ciniparser + * @{ + */ +/** + * @file dictionary.c + * @author N. Devillard + * @date Sep 2007 + * @version $Revision: 1.27 $ + * @brief Implements a dictionary for string variables. + * + * This module implements a simple dictionary object, i.e. a list + * of string/string associations. This object is useful to store e.g. + * information retrieved from a configuration file (ini files). + */ + +#include "dictionary.h" + +#include +#include +#include +#include + +/** Maximum value size for integers and doubles. */ +#define MAXVALSZ 1024 + +/** Minimal allocated number of entries in a dictionary */ +#define DICTMINSZ 128 + +/** Invalid key token */ +#define DICT_INVALID_KEY ((char*)-1) + +/** + * @brief Double the allocated size associated to a pointer + * @param size the current allocated size + * @return re-allocated pointer on success, NULL on failure + */ +static void *mem_double(void *ptr, int size) +{ + void *newptr; + + newptr = calloc(2 * size, 1); + if (newptr == NULL) { + return NULL; + } + memcpy(newptr, ptr, size); + free(ptr); + return newptr; +} + +/* The remaining exposed functions are documented in dictionary.h */ + +unsigned dictionary_hash(const char *key) +{ + int len; + unsigned hash; + int i; + + len = strlen(key); + for (hash = 0, i = 0; i < len; i++) { + hash += (unsigned) key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; +} + +dictionary *dictionary_new(int size) +{ + dictionary *d; + + /* If no size was specified, allocate space for DICTMINSZ */ + if (sizesize = size; + d->val = (char **) calloc(size, sizeof(char *)); + d->key = (char **) calloc(size, sizeof(char *)); + d->hash = (unsigned int *) calloc(size, sizeof(unsigned)); + return d; +} + +void dictionary_del(dictionary *d) +{ + int i; + + if (d == NULL) + return; + for (i = 0; i < d->size; i++) { + if (d->key[i] != NULL) + free(d->key[i]); + if (d->val[i] != NULL) + free(d->val[i]); + } + free(d->val); + free(d->key); + free(d->hash); + free(d); + return; +} + +char *dictionary_get(dictionary *d, const char *key, char *def) +{ + unsigned hash; + int i; + + hash = dictionary_hash(key); + for (i=0; i < d->size; i++) { + if (d->key[i] == NULL) + continue; + /* Compare hash */ + if (hash == d->hash[i]) { + /* Compare string, to avoid hash collisions */ + if (!strcmp(key, d->key[i])) { + return d->val[i]; + } + } + } + return def; +} + +int dictionary_set(dictionary *d, const char *key, char *val) +{ + int i; + unsigned hash; + + if (d==NULL || key==NULL) + return -1; + + /* Compute hash for this key */ + hash = dictionary_hash(key); + /* Find if value is already in dictionary */ + if (d->n > 0) { + for (i = 0; i < d->size; i++) { + if (d->key[i] == NULL) + continue; + /* Same hash value */ + if (hash == d->hash[i]) { + /* Same key */ + if (!strcmp(key, d->key[i])) { + /* Found a value: modify and return */ + if (d->val[i] != NULL) + free(d->val[i]); + d->val[i] = val ? strdup(val) : NULL; + /* Value has been modified: return */ + return 0; + } + } + } + } + + /* Add a new value + * See if dictionary needs to grow */ + if (d->n == d->size) { + /* Reached maximum size: reallocate dictionary */ + d->val = (char **) mem_double(d->val, d->size * sizeof(char *)); + d->key = (char **) mem_double(d->key, d->size * sizeof(char *)); + d->hash = (unsigned int *) + mem_double(d->hash, d->size * sizeof(unsigned)); + if ((d->val == NULL) || (d->key == NULL) || (d->hash == NULL)) + /* Cannot grow dictionary */ + return -1; + /* Double size */ + d->size *= 2; + } + + /* Insert key in the first empty slot */ + for (i = 0; i < d->size; i++) { + if (d->key[i] == NULL) { + /* Add key here */ + break; + } + } + /* Copy key */ + d->key[i] = strdup(key); + d->val[i] = val ? strdup(val) : NULL; + d->hash[i] = hash; + d->n ++; + return 0; +} + +void dictionary_unset(dictionary *d, const char *key) +{ + unsigned hash; + int i; + + if (key == NULL) + return; + + hash = dictionary_hash(key); + for (i = 0; i < d->size; i++) { + if (d->key[i] == NULL) + continue; + /* Compare hash */ + if (hash == d->hash[i]) { + /* Compare string, to avoid hash collisions */ + if (!strcmp(key, d->key[i])) { + /* Found key */ + break; + } + } + } + if (i >= d->size) + /* Key not found */ + return; + + free(d->key[i]); + d->key[i] = NULL; + if (d->val[i]!=NULL) { + free(d->val[i]); + d->val[i] = NULL; + } + d->hash[i] = 0; + d->n --; + return; +} + +void dictionary_dump(dictionary *d, FILE *out) +{ + int i; + + if (d == NULL || out == NULL) + return; + if (d->n < 1) { + fprintf(out, "empty dictionary\n"); + return; + } + for (i = 0; i < d->size; i++) { + if (d->key[i]) { + fprintf(out, "%20s\t[%s]\n", + d->key[i], + d->val[i] ? d->val[i] : "UNDEF"); + } + } + return; +} + +/** @} + */ diff --git a/ccan/ciniparser/dictionary.h b/ccan/ciniparser/dictionary.h new file mode 100644 index 0000000..a94ea1a --- /dev/null +++ b/ccan/ciniparser/dictionary.h @@ -0,0 +1,166 @@ +#ifndef _DICTIONARY_H_ +#define _DICTIONARY_H_ + +/* Copyright (c) 2000-2007 by Nicolas Devillard. + * Copyright (x) 2009 by Tim Post + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +/** @addtogroup ciniparser + * @{ + */ +/** + * @file dictionary.h + * @author N. Devillard + * @date Sep 2007 + * @version $Revision: 1.12 $ + * @brief Implements a dictionary for string variables. + * + * This module implements a simple dictionary object, i.e. a list + * of string/string associations. This object is useful to store e.g. + * information retrieved from a configuration file (ini files). + */ + + +/** + * @brief Dictionary object + * @param n Number of entries in the dictionary + * @param size Storage size + * @param val List of string values + * @param key List of string keys + * @param hash List of hash values for keys + * + * This object contains a list of string/string associations. Each + * association is identified by a unique string key. Looking up values + * in the dictionary is speeded up by the use of a (hopefully collision-free) + * hash function. + */ +typedef struct _dictionary_ { + int n; + int size; + char **val; + char **key; + unsigned *hash; +} dictionary; + +/** + * @brief Compute the hash key for a string. + * @param key Character string to use for key. + * @return 1 unsigned int on at least 32 bits. + * + * This hash function has been taken from an Article in Dr Dobbs Journal. + * This is normally a collision-free function, distributing keys evenly. + * The key is stored anyway in the struct so that collision can be avoided + * by comparing the key itself in last resort. + */ +unsigned dictionary_hash(const char *key); + +/** + * @brief Create a new dictionary object. + * @param size Optional initial size of the dictionary. + * @return allocated dictionary object on success, NULL on failure + * + * This function allocates a new dictionary object of given size and returns + * it. If you do not know in advance (roughly) the number of entries in the + * dictionary, give size=0. + */ +dictionary *dictionary_new(int size); + +/** + * @brief Delete a dictionary object + * @param d dictionary object to deallocate. + * @return void + * + * Deallocate a dictionary object and all memory associated to it. + */ +void dictionary_del(dictionary *vd); + +/** + * @brief Get a value from a dictionary. + * @param d dictionary object to search. + * @param key Key to look for in the dictionary. + * @param def Default value to return if key not found. + * @return 1 pointer to internally allocated character string. + * + * This function locates a key in a dictionary and returns a pointer to its + * value, or the passed 'def' pointer if no such key can be found in + * dictionary. The returned character pointer points to data internal to the + * dictionary object, you should not try to free it or modify it. + */ +char *dictionary_get(dictionary *d, const char *key, char *def); + +/** + * @brief Set a value in a dictionary. + * @param d dictionary object to modify. + * @param key Key to modify or add. + * @param val Value to add. + * @return int 0 if Ok, anything else otherwise + * + * If the given key is found in the dictionary, the associated value is + * replaced by the provided one. If the key cannot be found in the + * dictionary, it is added to it. + * + * It is Ok to provide a NULL value for val, but NULL values for the dictionary + * or the key are considered as errors: the function will return immediately + * in such a case. + * + * Notice that if you dictionary_set a variable to NULL, a call to + * dictionary_get will return a NULL value: the variable will be found, and + * its value (NULL) is returned. In other words, setting the variable + * content to NULL is equivalent to deleting the variable from the + * dictionary. It is not possible (in this implementation) to have a key in + * the dictionary without value. + * + * This function returns non-zero in case of failure. + */ +int dictionary_set(dictionary *vd, const char *key, char *val); + +/** + * @brief Delete a key in a dictionary + * @param d dictionary object to modify. + * @param key Key to remove. + * @return void + * + * This function deletes a key in a dictionary. Nothing is done if the + * key cannot be found. + */ +void dictionary_unset(dictionary *d, const char *key); + +/** + * @brief Dump a dictionary to an opened file pointer. + * @param d Dictionary to dump + * @param out Opened file pointer + * @return void + * + * Dumps a dictionary onto an opened file pointer. Key pairs are printed out + * as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as + * output file pointers. + */ +void dictionary_dump(dictionary *d, FILE *out); + +#endif +/** @} + */ From patchwork Sun Aug 22 20:30:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: QI Fuli X-Patchwork-Id: 12451675 Received: from mail-pf1-f169.google.com (mail-pf1-f169.google.com [209.85.210.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0AC3B2FB2 for ; Sun, 22 Aug 2021 20:30:56 +0000 (UTC) Received: by mail-pf1-f169.google.com with SMTP id i21so13555865pfd.8 for ; Sun, 22 Aug 2021 13:30:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=rikSzHpM7yOtnJuTI3+qXW0xoDeiFf+FgQN+/yDLogs=; b=oxsXJc5H3T37oRoUfdnwSt0k7nXSonRTbVuZL2UVOvnF7nr1j3WlvTEtdPy21fO7iC xpVOPfPTeM/tJIOiqyyE1QRP8tmqCP05P3Kcjf/7eKhj+Zx76F42UvWy4SDRLPtgwcA0 X9h/Pl8MaSrzIDLvoKHe1q5mwn5cy4PSs7xuTUaLwspkZ5D2AtRY4SMen7FBJR+0ep7y 5flLO8HsUWo0E4RYJM2qCOc/1TqrBuu5MvFZl5shLKxHyLy+IM3CzdQoGlhYuWD4QsSU qmUDYLPJLbXFskDRJ3LFMxTuv1D7ZRo/9/WHVbqg9f9B1MgTgpk4R0X9xbs7y6bnJWbe +Wuw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=rikSzHpM7yOtnJuTI3+qXW0xoDeiFf+FgQN+/yDLogs=; b=tH1N0iUeQkABldeknqMb5ve2sr1hPTzClWdrgipYgTTqMjZFnKJ2fdRLEW6GzRu91h RZIM97JnRNT4NUmvU9w+74foRGm/QlTIMFt+f6Plwd+XAEIYyJ8t/90hj2+z2OxbJb8u 6tkh3fdm3WoDefJQ4agiYIMutqMXKG33wFHxZSNVJ61GWMmX2SlSGQGveWgRLNSi1RKL U4lwfaLnvZnkEOZC8aDGeojy9pvsGYwgdXzkSS7xBGiKqQYYygLqcxwhq6v9ZQGDCi3j Y2aI3N+Weg6Ivm1RvrJGJ82TnkSGGYu0FTRaSe0oOJ8awekcZ4jtmYjJfM17fOfXeuY1 o6pg== X-Gm-Message-State: AOAM533vHUwY1Jlyp9flNbamanGHtjWmxx/8URMgvIF6dDyNy0SineK1 E9qo+MmQoJTklen8ZNjmxjj1zJUuhKJM6Q== X-Google-Smtp-Source: ABdhPJxsggJTmSxnReLcmZvvzQwwjsI0ZxlQa5W+s4wVlPAD0uwK3ALe++HzFuGTN5xQ+AHmLMZp6w== X-Received: by 2002:a63:7cb:: with SMTP id 194mr29253951pgh.308.1629664255651; Sun, 22 Aug 2021 13:30:55 -0700 (PDT) Received: from localhost.localdomain (125x103x255x1.ap125.ftth.ucom.ne.jp. [125.103.255.1]) by smtp.gmail.com with ESMTPSA id n30sm13587804pfv.87.2021.08.22.13.30.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Aug 2021 13:30:55 -0700 (PDT) From: QI Fuli X-Google-Original-From: QI Fuli To: nvdimm@lists.linux.dev Cc: QI Fuli Subject: [ndctl PATCH 2/5] ndctl, util: add parse-configs helper Date: Mon, 23 Aug 2021 05:30:12 +0900 Message-Id: <20210822203015.528438-3-qi.fuli@fujitsu.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210822203015.528438-1-qi.fuli@fujitsu.com> References: <20210822203015.528438-1-qi.fuli@fujitsu.com> Precedence: bulk X-Mailing-List: nvdimm@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: QI Fuli Add parse-config util to help ndctl commands parse ndctl global configuration file(s). Signed-off-by: QI Fuli --- Makefile.am | 2 ++ util/parse-configs.c | 82 ++++++++++++++++++++++++++++++++++++++++++++ util/parse-configs.h | 34 ++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 util/parse-configs.c create mode 100644 util/parse-configs.h diff --git a/Makefile.am b/Makefile.am index 960b5e9..6e50741 100644 --- a/Makefile.am +++ b/Makefile.am @@ -74,6 +74,8 @@ noinst_LIBRARIES += libutil.a libutil_a_SOURCES = \ util/parse-options.c \ util/parse-options.h \ + util/parse-configs.c \ + util/parse-configs.h \ util/usage.c \ util/size.c \ util/main.c \ diff --git a/util/parse-configs.c b/util/parse-configs.c new file mode 100644 index 0000000..b7ae1f0 --- /dev/null +++ b/util/parse-configs.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2021, FUJITSU LIMITED. ALL rights reserved. + +#include +#include +#include +#include + +static void set_str_val(const char **value, char *val) +{ + struct strbuf buf = STRBUF_INIT; + size_t len = *value ? strlen(*value) : 0; + + if (!val) + return; + + if (len) { + strbuf_add(&buf, *value, len); + strbuf_addstr(&buf, " "); + } + strbuf_addstr(&buf, val); + *value = strbuf_detach(&buf, NULL); +} + +static int parse_config_file(const char *config_file, + const struct config *configs) +{ + dictionary *dic; + + dic = ciniparser_load(config_file); + if (!dic) + return -errno; + + for (; configs->type != CONFIG_END; configs++) { + switch (configs->type) { + case CONFIG_STRING: + set_str_val((const char **)configs->value, + ciniparser_getstring(dic, + configs->key, configs->defval)); + break; + case MONITOR_CALLBACK: + case CONFIG_END: + break; + } + } + + ciniparser_freedict(dic); + return 0; +} + +int parse_configs_prefix(const char *__config_files, const char *prefix, + const struct config *configs) +{ + char *config_files, *save; + const char *config_file; + int rc; + + config_files = strdup(__config_files); + if (!config_files) + return -ENOMEM; + + for (config_file = strtok_r(config_files, " ", &save); config_file; + config_file = strtok_r(NULL, " ", &save)) { + + if (strncmp(config_file, "./", 2) != 0) + fix_filename(prefix, &config_file); + + if ((configs->type == MONITOR_CALLBACK) && + (strcmp(config_file, configs->key) == 0)) + rc = configs->callback(configs, configs->key); + else + rc = parse_config_file(config_file, configs); + + if (rc) + goto end; + } + + end: + free(config_files); + return rc; + +} diff --git a/util/parse-configs.h b/util/parse-configs.h new file mode 100644 index 0000000..f70f58f --- /dev/null +++ b/util/parse-configs.h @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2021, FUJITSU LIMITED. ALL rights reserved. + +#include +#include +#include + +enum parse_conf_type { + CONFIG_STRING, + CONFIG_END, + MONITOR_CALLBACK, +}; + +struct config; +typedef int parse_conf_cb(const struct config *, const char *config_file); + +struct config { + enum parse_conf_type type; + const char *key; + void *value; + void *defval; + parse_conf_cb *callback; +}; + +#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) + +#define CONF_END() { .type = CONFIG_END } +#define CONF_STR(k,v,d) \ + { .type = CONFIG_STRING, .key = (k), .value = check_vtype(v, const char **), .defval = (d) } +#define CONF_MONITOR(k,f) \ + { .type = MONITOR_CALLBACK, .key = (k), .callback = (f)} + +int parse_configs_prefix(const char *__config_file, const char *prefix, + const struct config *configs); From patchwork Sun Aug 22 20:30:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: QI Fuli X-Patchwork-Id: 12451679 Received: from mail-pg1-f179.google.com (mail-pg1-f179.google.com [209.85.215.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 51E1D3FC3 for ; Sun, 22 Aug 2021 20:30:57 +0000 (UTC) Received: by mail-pg1-f179.google.com with SMTP id k24so14691736pgh.8 for ; Sun, 22 Aug 2021 13:30:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=D/kZ7nj5OSKqyqEdhRE0ol6CHYKkXXRPvDyFtr0Z+us=; b=gEytaoyVPSWgFbX+IBo2okK7N56FWUYyYe5i3Cg7j1PGaRjfgXAL0l3tbI/cpwFkMl 7MMzBAPY+g7WgVN7zHve2a6HwYG/tk3aZXULbN/9pRr5QTdXNYUxJUBhIUH/sL+ls8Lp 1EL8b2VfqkLGZHFQJ5ViEDc9xw2tA2HxHe62pZdi/HS4WCUvA7jBYbprO+whtxnWS3yj goAKV95p6BVccwrznp5KznU4Hy3BghUMHvqRqodGtx/jxHflWOYwW1NbS8Qe3vk+3yop KnRn9PgZz1dJV4/Aa8ddheQA93mGxUvYbMXK7rFuCFSDuG3528s+e0RAFnXVlk5CvUz+ QRoA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=D/kZ7nj5OSKqyqEdhRE0ol6CHYKkXXRPvDyFtr0Z+us=; b=Ao4LfvE6kzyokiY4qjjw4eX/PPY+C/9OUdXzlYYrI6I8fvtxeD99Vg78Y3bGZgwddR Q5UujekEJu4aFpZtH8pCbywg0qhdDmP/cbrlq91JnX4lNnCGEhbAJscjqKfSRVY1oZOj tVsdx7t4eNwrFs+2dJRl5YlMpIYowX3fK/zmvUE0ZwIG0hwzt6EkR1PAXp+RNnHYZtxK WBFqLgPnE2uOi17tS/L84CT0/6FpKuQgPNeM8sMS/0W2Tl4VOuqjUrFsE0OpcWSq95ii Euofc4ZIqCI7bRYgLmezvcnXKSGJ7uf8E4iW2QUeav5CAnFsRx5mGlrE91puDv3FmU7X XcJw== X-Gm-Message-State: AOAM532fU1LSuxzZW8BSzGJQDIbi4VmncavER5xw10WhR5kHGiWxwPDj eeTdCRlgWrrdBWTAAYkJvxq7KSp7XuEoZg== X-Google-Smtp-Source: ABdhPJzHsWu3KALLLhClWPJCTDtsWuq4crfsyGe8+oP/dsxVRZve52qnt0fkdDyDRzwVqP/0o3Kr0Q== X-Received: by 2002:a62:8491:0:b029:3dd:a29a:a1e4 with SMTP id k139-20020a6284910000b02903dda29aa1e4mr30316866pfd.13.1629664256926; Sun, 22 Aug 2021 13:30:56 -0700 (PDT) Received: from localhost.localdomain (125x103x255x1.ap125.ftth.ucom.ne.jp. [125.103.255.1]) by smtp.gmail.com with ESMTPSA id n30sm13587804pfv.87.2021.08.22.13.30.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Aug 2021 13:30:56 -0700 (PDT) From: QI Fuli X-Google-Original-From: QI Fuli To: nvdimm@lists.linux.dev Cc: QI Fuli Subject: [ndctl PATCH 3/5] ndctl: make ndctl support configuration files Date: Mon, 23 Aug 2021 05:30:13 +0900 Message-Id: <20210822203015.528438-4-qi.fuli@fujitsu.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210822203015.528438-1-qi.fuli@fujitsu.com> References: <20210822203015.528438-1-qi.fuli@fujitsu.com> Precedence: bulk X-Mailing-List: nvdimm@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: QI Fuli Add ndctl_configs to ndctl_ctx for supporting ndctl global configuration files. All files with .conf suffix under {sysconfdir}/ndctl can be regarded as global configuration files that all ndctl commands can refer to. Add ndctl_set_configs() public function for setting ndctl default configuration files. Add ndctl_get_configs() public function for reading configuration files from ndctl_ctx. Signed-off-by: QI Fuli --- configure.ac | 4 ++-- ndctl/Makefile.am | 5 ++-- ndctl/lib/Makefile.am | 4 ++++ ndctl/lib/libndctl.c | 52 ++++++++++++++++++++++++++++++++++++++++++ ndctl/lib/libndctl.sym | 2 ++ ndctl/lib/private.h | 1 + ndctl/libndctl.h | 2 ++ ndctl/ndctl.c | 1 + 8 files changed, 67 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index dc39dbe..42a66e1 100644 --- a/configure.ac +++ b/configure.ac @@ -171,9 +171,9 @@ fi AC_SUBST([systemd_unitdir]) AM_CONDITIONAL([ENABLE_SYSTEMD_UNITS], [test "x$with_systemd" = "xyes"]) -ndctl_monitorconfdir=${sysconfdir}/ndctl +ndctl_confdir=${sysconfdir}/ndctl ndctl_monitorconf=monitor.conf -AC_SUBST([ndctl_monitorconfdir]) +AC_SUBST([ndctl_confdir]) AC_SUBST([ndctl_monitorconf]) daxctl_modprobe_datadir=${datadir}/daxctl diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am index a63b1e0..1caa031 100644 --- a/ndctl/Makefile.am +++ b/ndctl/Makefile.am @@ -7,8 +7,9 @@ BUILT_SOURCES = config.h config.h: $(srcdir)/Makefile.am $(AM_V_GEN) echo "/* Autogenerated by ndctl/Makefile.am */" >$@ && \ echo '#define NDCTL_CONF_FILE \ - "$(ndctl_monitorconfdir)/$(ndctl_monitorconf)"' >>$@ + "$(ndctl_confdir)/$(ndctl_monitorconf)"' >>$@ $(AM_V_GEN) echo '#define NDCTL_KEYS_DIR "$(ndctl_keysdir)"' >>$@ + $(AM_V_GEN) echo '#define NDCTL_CONF_DIR "$(ndctl_confdir)"' >>$@ ndctl_SOURCES = ndctl.c \ builtin.h \ @@ -73,7 +74,7 @@ ndctl_SOURCES += ../test/libndctl.c \ test.c endif -monitor_configdir = $(ndctl_monitorconfdir) +monitor_configdir = $(ndctl_confdir) monitor_config_DATA = $(ndctl_monitorconf) if ENABLE_SYSTEMD_UNITS diff --git a/ndctl/lib/Makefile.am b/ndctl/lib/Makefile.am index e15bb22..f741c44 100644 --- a/ndctl/lib/Makefile.am +++ b/ndctl/lib/Makefile.am @@ -14,6 +14,10 @@ libndctl_la_SOURCES =\ ../../util/log.h \ ../../util/sysfs.c \ ../../util/sysfs.h \ + ../../util/strbuf.h \ + ../../util/strbuf.c \ + ../../util/wrapper.c \ + ../../util/usage.c \ ../../util/fletcher.h \ dimm.c \ inject.c \ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c index 536e142..db2e38b 100644 --- a/ndctl/lib/libndctl.c +++ b/ndctl/lib/libndctl.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -265,6 +266,56 @@ NDCTL_EXPORT void ndctl_set_userdata(struct ndctl_ctx *ctx, void *userdata) ctx->userdata = userdata; } +static int filter_conf(const struct dirent *dir) +{ + if (!dir) + return 0; + + if (dir->d_type == DT_REG) { + const char *ext = strrchr(dir->d_name, '.'); + if ((!ext) || (ext == dir->d_name)) + return 0; + if (strcmp(ext, ".conf") == 0) + return 1; + } + + return 0; +} + +NDCTL_EXPORT void ndctl_set_configs(struct ndctl_ctx **ctx, char *conf_dir) +{ + struct dirent **namelist; + struct strbuf value = STRBUF_INIT; + int rc; + + if ((!ctx) || (!conf_dir)) + return; + + rc = scandir(conf_dir, &namelist, filter_conf, alphasort); + if (rc == -1) { + perror("scandir"); + return; + } + + while (rc--) { + if (value.len) + strbuf_addstr(&value, " "); + strbuf_addstr(&value, conf_dir); + strbuf_addstr(&value, "/"); + strbuf_addstr(&value, namelist[rc]->d_name); + free(namelist[rc]); + } + (*ctx)->configs = strbuf_detach(&value, NULL); + free(namelist); +} + +NDCTL_EXPORT const char *ndctl_get_configs(struct ndctl_ctx *ctx) +{ + if (ctx == NULL) + return NULL; + return ctx->configs; +} + /** * ndctl_new - instantiate a new library context * @ctx: context to establish @@ -331,6 +382,7 @@ NDCTL_EXPORT int ndctl_new(struct ndctl_ctx **ctx) c->daxctl_ctx = daxctl_ctx; return 0; + err_ctx: daxctl_unref(daxctl_ctx); err_daxctl: diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index 58afb74..5bd867d 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -454,4 +454,6 @@ LIBNDCTL_25 { LIBNDCTL_26 { ndctl_bus_nfit_translate_spa; + ndctl_set_configs; + ndctl_get_configs; } LIBNDCTL_25; diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h index 8f4510e..f4ca71f 100644 --- a/ndctl/lib/private.h +++ b/ndctl/lib/private.h @@ -129,6 +129,7 @@ struct ndctl_ctx { int regions_init; void *userdata; struct list_head busses; + const char *configs; int busses_init; struct udev *udev; struct udev_queue *udev_queue; diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index 87d07b7..7ab7691 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -92,6 +92,8 @@ int ndctl_get_log_priority(struct ndctl_ctx *ctx); void ndctl_set_log_priority(struct ndctl_ctx *ctx, int priority); void ndctl_set_userdata(struct ndctl_ctx *ctx, void *userdata); void *ndctl_get_userdata(struct ndctl_ctx *ctx); +void ndctl_set_configs(struct ndctl_ctx **ctx, char *conf_dir); +const char *ndctl_get_configs(struct ndctl_ctx *ctx); enum ndctl_persistence_domain { PERSISTENCE_NONE = 0, diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c index 31d2c5e..0f00b04 100644 --- a/ndctl/ndctl.c +++ b/ndctl/ndctl.c @@ -125,6 +125,7 @@ int main(int argc, const char **argv) rc = ndctl_new(&ctx); if (rc) goto out; + ndctl_set_configs(&ctx, NDCTL_CONF_DIR); main_handle_internal_command(argc, argv, ctx, commands, ARRAY_SIZE(commands), PROG_NDCTL); ndctl_unref(ctx); From patchwork Sun Aug 22 20:30:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: QI Fuli X-Patchwork-Id: 12451683 Received: from mail-pj1-f47.google.com (mail-pj1-f47.google.com [209.85.216.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 89ACD3FCA for ; Sun, 22 Aug 2021 20:30:58 +0000 (UTC) Received: by mail-pj1-f47.google.com with SMTP id n13-20020a17090a4e0d00b0017946980d8dso17248421pjh.5 for ; Sun, 22 Aug 2021 13:30:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=/3zXirtye3zGCxHNCsVbPjqEs0jJVuY2N98o8Afa5Cw=; b=HzP6P0kio6MyXxia2TZD6JJgsHXBwxT7GrrX3jdTPLPjWLeGW99aueobOFbUx/Z1rg JO6x1j5RzK8LBQovmN8CJbxjo0DmU1Vg19YV7KXIHnjuJKxSAwOx0hVNE4RJYHNk9ybx mDQ5xYkuG7NqjJu/We/OXsFZUe8Sdub3pMY5RNE/7MYNMDyVnRG7pPBMBySj7BiP5a9v OEHZIil0j97ms2nxNdGcRQEpgp0uFK+rPcgDJgeceFuoVveHIeQ4+l+gDzEGoi+eqQJX ymfrdoQ061ZupBl0MndafUCej6l6nBHMwNVs0phqgQKV9b1874yFc6GfcIfGE8FWKtKH gGlQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=/3zXirtye3zGCxHNCsVbPjqEs0jJVuY2N98o8Afa5Cw=; b=pOnMk0rDt+H8VCBaWZcT4WX4nZWIXZQaGcoRbIFq2cyPyuKTt00vkHNvN52DEuqJ6p hjwIXKB9oNBPbUf/IM3OeBoY/z5xONmepy7U+ifEqpsS4PWX+UF6vX6ufZ2pIk6pqqvy 7/JFlOG2zW/7WJ4Urh58sIP16ITu0fVBUl7bIWnwwiy74PmA7SYJs1FMA1Ue+5c9uDuH FOUJJNehMl49mZdEk1abxLowMbmiuOUAOch1cWkVpDF9oNUGi/XI5oFpyVUOFMLNGRSv dSiDHdXtZFgoORgDPMu9Pk0WtSD5tGRrT05GLll2Ng78cX1ypIRlL6tO4G10Wp2R1IYk Au2g== X-Gm-Message-State: AOAM530JN9IcsPNAX9ieoKN6BiSMUa0B6fDQLjPdVMX1/7hAbkQ0E13b ioXQBhNvuvUpoQGe+qziDqwGhte0dnbCKA== X-Google-Smtp-Source: ABdhPJyn3BxaNrFX//vSS2DydoE1vq+wR7DDD6Mg6XUXugRHhc8MtHAgtB1y+82yPD4zy/XCGHW+nA== X-Received: by 2002:a17:90a:1282:: with SMTP id g2mr16741926pja.230.1629664258189; Sun, 22 Aug 2021 13:30:58 -0700 (PDT) Received: from localhost.localdomain (125x103x255x1.ap125.ftth.ucom.ne.jp. [125.103.255.1]) by smtp.gmail.com with ESMTPSA id n30sm13587804pfv.87.2021.08.22.13.30.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Aug 2021 13:30:57 -0700 (PDT) From: QI Fuli X-Google-Original-From: QI Fuli To: nvdimm@lists.linux.dev Cc: QI Fuli Subject: [ndctl PATCH 4/5] ndctl, config: add the default ndctl configuration file Date: Mon, 23 Aug 2021 05:30:14 +0900 Message-Id: <20210822203015.528438-5-qi.fuli@fujitsu.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210822203015.528438-1-qi.fuli@fujitsu.com> References: <20210822203015.528438-1-qi.fuli@fujitsu.com> Precedence: bulk X-Mailing-List: nvdimm@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: QI Fuli Install ndctl/ndctl.conf as the default ndctl configuration file. Signed-off-by: QI Fuli --- configure.ac | 2 ++ ndctl/Makefile.am | 4 +++- ndctl/ndctl.conf | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 ndctl/ndctl.conf diff --git a/configure.ac b/configure.ac index 42a66e1..9e1c6db 100644 --- a/configure.ac +++ b/configure.ac @@ -172,8 +172,10 @@ AC_SUBST([systemd_unitdir]) AM_CONDITIONAL([ENABLE_SYSTEMD_UNITS], [test "x$with_systemd" = "xyes"]) ndctl_confdir=${sysconfdir}/ndctl +ndctl_conf=ndctl.conf ndctl_monitorconf=monitor.conf AC_SUBST([ndctl_confdir]) +AC_SUBST([ndctl_conf]) AC_SUBST([ndctl_monitorconf]) daxctl_modprobe_datadir=${datadir}/daxctl diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am index 1caa031..fceb3ab 100644 --- a/ndctl/Makefile.am +++ b/ndctl/Makefile.am @@ -43,7 +43,7 @@ keys_configdir = $(ndctl_keysdir) keys_config_DATA = $(ndctl_keysreadme) endif -EXTRA_DIST += keys.readme monitor.conf ndctl-monitor.service +EXTRA_DIST += keys.readme monitor.conf ndctl-monitor.service ndctl.conf if ENABLE_DESTRUCTIVE ndctl_SOURCES += ../test/blk_namespaces.c \ @@ -74,6 +74,8 @@ ndctl_SOURCES += ../test/libndctl.c \ test.c endif +ndctl_configdir = $(ndctl_confdir) +ndctl_config_DATA = $(ndctl_conf) monitor_configdir = $(ndctl_confdir) monitor_config_DATA = $(ndctl_monitorconf) diff --git a/ndctl/ndctl.conf b/ndctl/ndctl.conf new file mode 100644 index 0000000..4b3eb7e --- /dev/null +++ b/ndctl/ndctl.conf @@ -0,0 +1,56 @@ +# This is the default ndctl configuration file. It contains the +# configuration directives that give ndctl instructions. +# Ndctl supports multiple configuration files. All files with the +# .conf suffix under "sysconfdir/ndctl/" can be regarded as ndctl +# configuration files. + +# In this file, lines starting with a hash (#) are comments. +# The configurations should be in a [section] and follow = +# style. Multiple space-separated values are allowed, but except the +# following characters: : ? / \ % " ' $ & ! * { } [ ] ( ) = < > @ + +[core] +# The values in [core] section work for all ndctl sub commands. +# dimm = all +# bus = all +# region = all +# namespace = all + +[monitor] +# The values in [monitor] section work for ndctl monitor. +# You can change the configuration of ndctl monitor by editing this +# file or use [--config-file=] option to override this one. +# The changed value will work after restart ndctl monitor service. + +# The objects to monitor are filtered via dimm's name by setting key "dimm". +# If this value is different from the value of [--dimm=] option, +# both of the values will work. +# dimm = all + +# The objects to monitor are filtered via its parent bus by setting key "bus". +# If this value is different from the value of [--bus=] option, +# both of the values will work. +# bus = all + +# The objects to monitor are filtered via region by setting key "region". +# If this value is different from the value of [--region=] option, +# both of the values will work. +# region = all + +# The objects to monitor are filtered via namespace by setting key "namespace". +# If this value is different from the value of [--namespace=] option, +# both of the values will work. +# namespace = all + +# The DIMM events to monitor are filtered via event type by setting key +# "dimm-event". If this value is different from the value of +# [--dimm-event=] option, both of the values will work. +# dimm-event = all + +# Users can choose to output the notifications to syslog (log=syslog), +# to standard output (log=standard) or to write into a special file (log=) +# by setting key "log". If this value is in conflict with the value of +# [--log=] option, this value will be ignored. +# Note: Setting value to "standard" or relative path for will not work +# when running moniotr as a daemon. +# log = /var/log/ndctl/monitor.log From patchwork Sun Aug 22 20:30:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: QI Fuli X-Patchwork-Id: 12451681 Received: from mail-pg1-f172.google.com (mail-pg1-f172.google.com [209.85.215.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D7E773FC3 for ; Sun, 22 Aug 2021 20:30:59 +0000 (UTC) Received: by mail-pg1-f172.google.com with SMTP id k24so14691863pgh.8 for ; Sun, 22 Aug 2021 13:30:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=CCjMEjtReEZhcF8HyF8lnL8RuIHQrRWYKAQ9ulEmCzo=; b=qWtK2N3e9Bdo+lEyFWOrbT9K9PUI+dCxDg6IraGgdIFqLUxP8dhs31847Q1rFObIS2 6M5vg/pphzNWINvW2Dt2jXQzQBP1k7wKthavMjsbQV7qGh6i2H4zjsbJKTW8/CJohoei 31a/W5pCAgViepAPBqjubjQN1kMiq7OsNzxxR6m4VJSNVa9XegxkRup3X3W9jLvyIXF4 B3Xe7/ysO7cSFCr8XGWO/dnf2YK0OvgssHGyIYkFKCsyHjDClGsOcAKJF1ygr0Kjt7ic vilN6asB0Z5/DL2iRjyOeLKSuPp6zsISPu3GCUi101r5H8c6nvvB9gkX9j1N1aDAUa8+ BrBQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=CCjMEjtReEZhcF8HyF8lnL8RuIHQrRWYKAQ9ulEmCzo=; b=B5tEjmh52AzhF4QG0cl3FzT9m3qDqdkNE62QABeCEfBHuWNjGQ/WTlPzjEqIGXSnPr DRH2pSrGOjYJ3Gr4yU1N4vWJGb+AyBif/oJtTgZr+hIaYO+wLFujQ8WOWU+qOlwqu7su xWezJ716X49cA8fXXsrzBXC2Ym2EuUBktuG4zRJfXau8aS0HmwVSv+1WT0ZX+EkzqqAL +9mAl/esqItPK6ho9NaE54ulJUjJzDI3sICU2qgAXaENggfGGZhgaXm6mh+KQLp0AiJg m1H0h8tLqXIQ8hanFrWR7+zP64empC9+HQFJCqWDqkL2t10ejYp7yxgVgSh3XpTcHKmb 40Ow== X-Gm-Message-State: AOAM530s/sW+pK3a7mDsq028GE4kpcb9gnWttR52iAzSkJ7R2JjquRBh iUwodzPnQZoznwLo25DCInamuJOM5Eodag== X-Google-Smtp-Source: ABdhPJwR+s17nc1PTcEpbcwnTyi0i1q/xPpJnSUhFWKMBgSlCYz8CCN/OFJBAqlhR/cekfexUlFlmg== X-Received: by 2002:a62:5543:0:b0:3eb:22a3:bb5c with SMTP id j64-20020a625543000000b003eb22a3bb5cmr4307917pfb.61.1629664259476; Sun, 22 Aug 2021 13:30:59 -0700 (PDT) Received: from localhost.localdomain (125x103x255x1.ap125.ftth.ucom.ne.jp. [125.103.255.1]) by smtp.gmail.com with ESMTPSA id n30sm13587804pfv.87.2021.08.22.13.30.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Aug 2021 13:30:59 -0700 (PDT) From: QI Fuli X-Google-Original-From: QI Fuli To: nvdimm@lists.linux.dev Cc: QI Fuli Subject: [ndctl PATCH 5/5] ndctl, monitor: refactor monitor for supporting multiple config files Date: Mon, 23 Aug 2021 05:30:15 +0900 Message-Id: <20210822203015.528438-6-qi.fuli@fujitsu.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210822203015.528438-1-qi.fuli@fujitsu.com> References: <20210822203015.528438-1-qi.fuli@fujitsu.com> Precedence: bulk X-Mailing-List: nvdimm@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: QI Fuli In order to support multiple configration files, refactor ndctl monitor by using parse-configs helper. Signed-off-by: QI Fuli --- Documentation/ndctl/Makefile.am | 2 +- Documentation/ndctl/ndctl-monitor.txt | 8 ++-- ndctl/Makefile.am | 1 + ndctl/monitor.c | 69 ++++++++++++++------------- 4 files changed, 42 insertions(+), 38 deletions(-) diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am index f0d5b21..37855cc 100644 --- a/Documentation/ndctl/Makefile.am +++ b/Documentation/ndctl/Makefile.am @@ -59,7 +59,7 @@ CLEANFILES = $(man1_MANS) .ONESHELL: attrs.adoc: $(srcdir)/Makefile.am $(AM_V_GEN) cat <<- EOF >$@ - :ndctl_monitorconfdir: $(ndctl_monitorconfdir) + :ndctl_confdir: $(ndctl_confdir) :ndctl_monitorconf: $(ndctl_monitorconf) :ndctl_keysdir: $(ndctl_keysdir) EOF diff --git a/Documentation/ndctl/ndctl-monitor.txt b/Documentation/ndctl/ndctl-monitor.txt index dbc9070..8c8c35b 100644 --- a/Documentation/ndctl/ndctl-monitor.txt +++ b/Documentation/ndctl/ndctl-monitor.txt @@ -21,8 +21,8 @@ objects and dumping the json format notifications to syslog, standard output or a logfile. The objects to monitor and smart events to notify can be selected by -setting options and/or the configuration file at -{ndctl_monitorconfdir}/{ndctl_monitorconf} +setting options and/or configuration files with .conf suffix under +{ndctl_confdir} Both, the values in configuration file and in options will work. If there is a conflict, the values in options will override the values in @@ -81,8 +81,8 @@ will not work if "--daemon" is specified. -c:: --config-file=:: - Provide the config file to use. This overrides the default config - typically found in {ndctl_monitorconfdir} + Provide the config file(s) to use. This overrides the default config + typically found in {ndctl_confdir} --daemon:: Run a monitor as a daemon. diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am index fceb3ab..3c59aa7 100644 --- a/ndctl/Makefile.am +++ b/ndctl/Makefile.am @@ -55,6 +55,7 @@ ndctl_LDADD =\ lib/libndctl.la \ ../daxctl/lib/libdaxctl.la \ ../libutil.a \ + ../libccan.a \ $(UUID_LIBS) \ $(KMOD_LIBS) \ $(JSON_LIBS) diff --git a/ndctl/monitor.c b/ndctl/monitor.c index ca36179..e944c90 100644 --- a/ndctl/monitor.c +++ b/ndctl/monitor.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +29,7 @@ static struct monitor { const char *log; - const char *config_file; + const char *configs; const char *dimm_event; FILE *log_file; bool daemon; @@ -463,7 +464,7 @@ out: return rc; } -static void parse_config(const char **arg, char *key, char *val, char *ident) +static void set_monitor_conf(const char **arg, char *key, char *val, char *ident) { struct strbuf value = STRBUF_INIT; size_t arg_len = *arg ? strlen(*arg) : 0; @@ -479,39 +480,25 @@ static void parse_config(const char **arg, char *key, char *val, char *ident) *arg = strbuf_detach(&value, NULL); } -static int read_config_file(struct ndctl_ctx *ctx, struct monitor *_monitor, - struct util_filter_params *_param) +static int parse_monitor_config(const struct config *configs, + const char *config_file) { FILE *f; size_t len = 0; int line = 0, rc = 0; - char *buf = NULL, *seek, *value, *config_file; - - if (_monitor->config_file) - config_file = strdup(_monitor->config_file); - else - config_file = strdup(NDCTL_CONF_FILE); - if (!config_file) { - fail("strdup default config file failed\n"); - rc = -ENOMEM; - goto out; - } + char *buf = NULL, *seek, *value; buf = malloc(BUF_SIZE); if (!buf) { fail("malloc read config-file buf error\n"); - rc = -ENOMEM; - goto out; + return -ENOMEM; } seek = buf; f = fopen(config_file, "r"); if (!f) { - if (_monitor->config_file) { - err(&monitor, "config-file: %s cannot be opened\n", - config_file); - rc = -errno; - } + err(&monitor, "%s cannot be opened\n", config_file); + rc = -errno; goto out; } @@ -554,19 +541,18 @@ static int read_config_file(struct ndctl_ctx *ctx, struct monitor *_monitor, if (len == 0) continue; - parse_config(&_param->bus, "bus", value, seek); - parse_config(&_param->dimm, "dimm", value, seek); - parse_config(&_param->region, "region", value, seek); - parse_config(&_param->namespace, "namespace", value, seek); - parse_config(&_monitor->dimm_event, "dimm-event", value, seek); + set_monitor_conf(¶m.bus, "bus", value, seek); + set_monitor_conf(¶m.dimm, "dimm", value, seek); + set_monitor_conf(¶m.region, "region", value, seek); + set_monitor_conf(¶m.namespace, "namespace", value, seek); + set_monitor_conf(&monitor.dimm_event, "dimm-event", value, seek); - if (!_monitor->log) - parse_config(&_monitor->log, "log", value, seek); + if (!monitor.log) + set_monitor_conf(&monitor.log, "log", value, seek); } fclose(f); out: free(buf); - free(config_file); return rc; } @@ -585,8 +571,8 @@ int cmd_monitor(int argc, const char **argv, struct ndctl_ctx *ctx) OPT_FILENAME('l', "log", &monitor.log, " | syslog | standard", "where to output the monitor's notification"), - OPT_FILENAME('c', "config-file", &monitor.config_file, - "config-file", "override the default config"), + OPT_STRING('c', "config-file", &monitor.configs, + "config-file", "override default configs"), OPT_BOOLEAN('\0', "daemon", &monitor.daemon, "run ndctl monitor as a daemon"), OPT_BOOLEAN('u', "human", &monitor.human, @@ -601,6 +587,19 @@ int cmd_monitor(int argc, const char **argv, struct ndctl_ctx *ctx) "ndctl monitor []", NULL }; + const struct config configs[] = { + CONF_MONITOR(NDCTL_CONF_FILE, parse_monitor_config), + CONF_STR("core:bus", ¶m.bus, NULL), + CONF_STR("core:region", ¶m.region, NULL), + CONF_STR("core:dimm", ¶m.dimm, NULL), + CONF_STR("core:namespace", ¶m.namespace, NULL), + CONF_STR("monitor:bus", ¶m.bus, NULL), + CONF_STR("monitor:region", ¶m.region, NULL), + CONF_STR("monitor:dimm", ¶m.dimm, NULL), + CONF_STR("monitor:namespace", ¶m.namespace, NULL), + CONF_STR("monitor:dimm-event", &monitor.dimm_event, NULL), + CONF_END(), + }; const char *prefix = "./"; struct util_filter_ctx fctx = { 0 }; struct monitor_filter_arg mfa = { 0 }; @@ -621,7 +620,11 @@ int cmd_monitor(int argc, const char **argv, struct ndctl_ctx *ctx) else monitor.ctx.log_priority = LOG_INFO; - rc = read_config_file(ctx, &monitor, ¶m); + if (monitor.configs) + rc = parse_configs_prefix(monitor.configs, prefix, configs); + else + rc = parse_configs_prefix( + ndctl_get_configs(ctx), prefix, configs); if (rc) goto out;