LCOV - code coverage report
Current view: top level - misc/kabi/lvm2.git/lib/config - config.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 303 642 47.2 %
Date: 2010-04-13 Functions: 31 58 53.4 %
Branches: 201 497 40.4 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
       3                 :            :  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
       4                 :            :  *
       5                 :            :  * This file is part of LVM2.
       6                 :            :  *
       7                 :            :  * This copyrighted material is made available to anyone wishing to use,
       8                 :            :  * modify, copy, or redistribute it subject to the terms and conditions
       9                 :            :  * of the GNU Lesser General Public License v.2.1.
      10                 :            :  *
      11                 :            :  * You should have received a copy of the GNU Lesser General Public License
      12                 :            :  * along with this program; if not, write to the Free Software Foundation,
      13                 :            :  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "lib.h"
      17                 :            : #include "config.h"
      18                 :            : #include "crc.h"
      19                 :            : #include "device.h"
      20                 :            : #include "str_list.h"
      21                 :            : #include "toolcontext.h"
      22                 :            : #include "lvm-string.h"
      23                 :            : #include "lvm-file.h"
      24                 :            : 
      25                 :            : #include <sys/stat.h>
      26                 :            : #include <sys/mman.h>
      27                 :            : #include <unistd.h>
      28                 :            : #include <fcntl.h>
      29                 :            : #include <ctype.h>
      30                 :            : 
      31                 :            : #define SECTION_B_CHAR '{'
      32                 :            : #define SECTION_E_CHAR '}'
      33                 :            : 
      34                 :            : enum {
      35                 :            :         TOK_INT,
      36                 :            :         TOK_FLOAT,
      37                 :            :         TOK_STRING,             /* Single quotes */
      38                 :            :         TOK_STRING_ESCAPED,     /* Double quotes */
      39                 :            :         TOK_EQ,
      40                 :            :         TOK_SECTION_B,
      41                 :            :         TOK_SECTION_E,
      42                 :            :         TOK_ARRAY_B,
      43                 :            :         TOK_ARRAY_E,
      44                 :            :         TOK_IDENTIFIER,
      45                 :            :         TOK_COMMA,
      46                 :            :         TOK_EOF
      47                 :            : };
      48                 :            : 
      49                 :            : struct parser {
      50                 :            :         const char *fb, *fe;            /* file limits */
      51                 :            : 
      52                 :            :         int t;                  /* token limits and type */
      53                 :            :         const char *tb, *te;
      54                 :            : 
      55                 :            :         int fd;                 /* descriptor for file being parsed */
      56                 :            :         int line;               /* line number we are on */
      57                 :            : 
      58                 :            :         struct dm_pool *mem;
      59                 :            : };
      60                 :            : 
      61                 :            : struct cs {
      62                 :            :         struct config_tree cft;
      63                 :            :         struct dm_pool *mem;
      64                 :            :         time_t timestamp;
      65                 :            :         char *filename;
      66                 :            :         int exists;
      67                 :            :         int keep_open;
      68                 :            :         struct device *dev;
      69                 :            : };
      70                 :            : 
      71                 :            : struct output_line {
      72                 :            :         FILE *fp;
      73                 :            :         struct dm_pool *mem;
      74                 :            :         putline_fn putline;
      75                 :            :         void *putline_baton;
      76                 :            : };
      77                 :            : 
      78                 :            : static void _get_token(struct parser *p, int tok_prev);
      79                 :            : static void _eat_space(struct parser *p);
      80                 :            : static struct config_node *_file(struct parser *p);
      81                 :            : static struct config_node *_section(struct parser *p);
      82                 :            : static struct config_value *_value(struct parser *p);
      83                 :            : static struct config_value *_type(struct parser *p);
      84                 :            : static int _match_aux(struct parser *p, int t);
      85                 :            : static struct config_value *_create_value(struct dm_pool *mem);
      86                 :            : static struct config_node *_create_node(struct dm_pool *mem);
      87                 :            : static char *_dup_tok(struct parser *p);
      88                 :            : 
      89                 :            : static const int sep = '/';
      90                 :            : 
      91                 :            : #define MAX_INDENT 32
      92                 :            : 
      93                 :            : #define match(t) do {\
      94                 :            :    if (!_match_aux(p, (t))) {\
      95                 :            :         log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
      96                 :            :                   p->tb - p->fb + 1, p->line); \
      97                 :            :       return 0;\
      98                 :            :    } \
      99                 :            : } while(0);
     100                 :            : 
     101                 :       2514 : static int _tok_match(const char *str, const char *b, const char *e)
     102                 :            : {
     103 [ +  + ][ +  + ]:       4547 :         while (*str && (b != e)) {
     104         [ +  + ]:       4319 :                 if (*str++ != *b++)
     105                 :       2286 :                         return 0;
     106                 :            :         }
     107                 :            : 
     108 [ +  + ][ +  + ]:       2514 :         return !(*str || (b != e));
     109                 :            : }
     110                 :            : 
     111                 :            : /*
     112                 :            :  * public interface
     113                 :            :  */
     114                 :          8 : struct config_tree *create_config_tree(const char *filename, int keep_open)
     115                 :            : {
     116                 :            :         struct cs *c;
     117                 :          8 :         struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
     118                 :            : 
     119         [ -  + ]:          8 :         if (!mem) {
     120                 :          0 :                 log_error("Failed to allocate config pool.");
     121                 :          0 :                 return 0;
     122                 :            :         }
     123                 :            : 
     124         [ -  + ]:          8 :         if (!(c = dm_pool_zalloc(mem, sizeof(*c)))) {
     125                 :          0 :                 log_error("Failed to allocate config tree.");
     126                 :          0 :                 dm_pool_destroy(mem);
     127                 :          0 :                 return 0;
     128                 :            :         }
     129                 :            : 
     130                 :          8 :         c->mem = mem;
     131                 :          8 :         c->cft.root = (struct config_node *) NULL;
     132                 :          8 :         c->timestamp = 0;
     133                 :          8 :         c->exists = 0;
     134                 :          8 :         c->keep_open = keep_open;
     135                 :          8 :         c->dev = 0;
     136         [ +  + ]:          8 :         if (filename)
     137                 :          4 :                 c->filename = dm_pool_strdup(c->mem, filename);
     138                 :          8 :         return &c->cft;
     139                 :            : }
     140                 :            : 
     141                 :          8 : void destroy_config_tree(struct config_tree *cft)
     142                 :            : {
     143                 :          8 :         struct cs *c = (struct cs *) cft;
     144                 :            : 
     145         [ +  + ]:          8 :         if (c->dev)
     146                 :          1 :                 dev_close(c->dev);
     147                 :            : 
     148                 :          8 :         dm_pool_destroy(c->mem);
     149                 :          8 : }
     150                 :            : 
     151                 :          5 : static int _parse_config_file(struct parser *p, struct config_tree *cft)
     152                 :            : {
     153                 :          5 :         p->tb = p->te = p->fb;
     154                 :          5 :         p->line = 1;
     155                 :          5 :         _get_token(p, TOK_SECTION_E);
     156         [ -  + ]:          5 :         if (!(cft->root = _file(p)))
     157                 :          0 :                 return_0;
     158                 :            : 
     159                 :          5 :         return 1;
     160                 :            : }
     161                 :            : 
     162                 :          1 : struct config_tree *create_config_tree_from_string(struct cmd_context *cmd __attribute((unused)),
     163                 :            :                                                    const char *config_settings)
     164                 :            : {
     165                 :            :         struct cs *c;
     166                 :            :         struct config_tree *cft;
     167                 :            :         struct parser *p;
     168                 :            : 
     169         [ -  + ]:          1 :         if (!(cft = create_config_tree(NULL, 0)))
     170                 :          0 :                 return_NULL;
     171                 :            : 
     172                 :          1 :         c = (struct cs *) cft;
     173         [ -  + ]:          1 :         if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) {
     174                 :          0 :                 log_error("Failed to allocate config tree parser.");
     175                 :          0 :                 destroy_config_tree(cft);
     176                 :          0 :                 return NULL;
     177                 :            :         }
     178                 :            : 
     179                 :          1 :         p->mem = c->mem;
     180                 :          1 :         p->fb = config_settings;
     181                 :          1 :         p->fe = config_settings + strlen(config_settings);
     182                 :            : 
     183         [ -  + ]:          1 :         if (!_parse_config_file(p, cft)) {
     184                 :          0 :                 destroy_config_tree(cft);
     185                 :          0 :                 return_NULL;
     186                 :            :         }
     187                 :            : 
     188                 :          1 :         return cft;
     189                 :            : }
     190                 :            : 
     191                 :          1 : int override_config_tree_from_string(struct cmd_context *cmd,
     192                 :            :                                      const char *config_settings)
     193                 :            : {
     194         [ -  + ]:          1 :         if (!(cmd->cft_override = create_config_tree_from_string(cmd,config_settings))) {
     195                 :          0 :                 log_error("Failed to set overridden configuration entries.");
     196                 :          0 :                 return 1;
     197                 :            :         }
     198                 :            : 
     199                 :          1 :         return 0;
     200                 :            : }
     201                 :            : 
     202                 :          4 : int read_config_fd(struct config_tree *cft, struct device *dev,
     203                 :            :                    off_t offset, size_t size, off_t offset2, size_t size2,
     204                 :            :                    checksum_fn_t checksum_fn, uint32_t checksum)
     205                 :            : {
     206                 :          4 :         struct cs *c = (struct cs *) cft;
     207                 :            :         struct parser *p;
     208                 :          4 :         int r = 0;
     209                 :          4 :         int use_mmap = 1;
     210                 :          4 :         off_t mmap_offset = 0;
     211                 :          4 :         char *buf = NULL;
     212                 :            : 
     213         [ -  + ]:          4 :         if (!(p = dm_pool_alloc(c->mem, sizeof(*p))))
     214                 :          0 :                 return_0;
     215                 :          4 :         p->mem = c->mem;
     216                 :            : 
     217                 :            :         /* Only use mmap with regular files */
     218 [ +  - ][ -  + ]:          4 :         if (!(dev->flags & DEV_REGULAR) || size2)
     219                 :          0 :                 use_mmap = 0;
     220                 :            : 
     221         [ +  - ]:          4 :         if (use_mmap) {
     222                 :          4 :                 mmap_offset = offset % lvm_getpagesize();
     223                 :            :                 /* memory map the file */
     224                 :          4 :                 p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
     225                 :            :                              MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
     226         [ -  + ]:          4 :                 if (p->fb == (caddr_t) (-1)) {
     227                 :          0 :                         log_sys_error("mmap", dev_name(dev));
     228                 :          0 :                         goto out;
     229                 :            :                 }
     230                 :          4 :                 p->fb = p->fb + mmap_offset;
     231                 :            :         } else {
     232         [ #  # ]:          0 :                 if (!(buf = dm_malloc(size + size2)))
     233                 :          0 :                         return_0;
     234         [ #  # ]:          0 :                 if (!dev_read_circular(dev, (uint64_t) offset, size,
     235                 :            :                                        (uint64_t) offset2, size2, buf)) {
     236                 :          0 :                         goto out;
     237                 :            :                 }
     238                 :          0 :                 p->fb = buf;
     239                 :            :         }
     240                 :            : 
     241   [ -  +  #  # ]:          4 :         if (checksum_fn && checksum !=
     242                 :          0 :             (checksum_fn(checksum_fn(INITIAL_CRC, p->fb, size),
     243                 :            :                          p->fb + size, size2))) {
     244                 :          0 :                 log_error("%s: Checksum error", dev_name(dev));
     245                 :          0 :                 goto out;
     246                 :            :         }
     247                 :            : 
     248                 :          4 :         p->fe = p->fb + size + size2;
     249                 :            : 
     250         [ -  + ]:          4 :         if (!_parse_config_file(p, cft))
     251                 :          0 :                 goto_out;
     252                 :            : 
     253                 :          4 :         r = 1;
     254                 :            : 
     255                 :            :       out:
     256         [ -  + ]:          4 :         if (!use_mmap)
     257                 :          0 :                 dm_free(buf);
     258                 :            :         else {
     259                 :            :                 /* unmap the file */
     260         [ -  + ]:          4 :                 if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) {
     261                 :          0 :                         log_sys_error("munmap", dev_name(dev));
     262                 :          0 :                         r = 0;
     263                 :            :                 }
     264                 :            :         }
     265                 :            : 
     266                 :          4 :         return r;
     267                 :            : }
     268                 :            : 
     269                 :          4 : int read_config_file(struct config_tree *cft)
     270                 :            : {
     271                 :          4 :         struct cs *c = (struct cs *) cft;
     272                 :            :         struct stat info;
     273                 :          4 :         int r = 1;
     274                 :            : 
     275         [ -  + ]:          4 :         if (stat(c->filename, &info)) {
     276                 :          0 :                 log_sys_error("stat", c->filename);
     277                 :          0 :                 c->exists = 0;
     278                 :          0 :                 return 0;
     279                 :            :         }
     280                 :            : 
     281         [ -  + ]:          4 :         if (!S_ISREG(info.st_mode)) {
     282                 :          0 :                 log_error("%s is not a regular file", c->filename);
     283                 :          0 :                 c->exists = 0;
     284                 :          0 :                 return 0;
     285                 :            :         }
     286                 :            : 
     287                 :          4 :         c->exists = 1;
     288                 :            : 
     289         [ -  + ]:          4 :         if (info.st_size == 0) {
     290                 :          0 :                 log_verbose("%s is empty", c->filename);
     291                 :          0 :                 return 1;
     292                 :            :         }
     293                 :            : 
     294         [ +  - ]:          4 :         if (!c->dev) {
     295         [ -  + ]:          4 :                 if (!(c->dev = dev_create_file(c->filename, NULL, NULL, 1)))
     296                 :          0 :                         return_0;
     297                 :            : 
     298         [ -  + ]:          4 :                 if (!dev_open_flags(c->dev, O_RDONLY, 0, 0)) {
     299                 :          0 :                         c->dev = 0;
     300                 :          0 :                         return_0;
     301                 :            :                 }
     302                 :            :         }
     303                 :            : 
     304                 :          4 :         r = read_config_fd(cft, c->dev, 0, (size_t) info.st_size, 0, 0,
     305                 :            :                            (checksum_fn_t) NULL, 0);
     306                 :            : 
     307         [ +  + ]:          4 :         if (!c->keep_open) {
     308                 :          3 :                 dev_close(c->dev);
     309                 :          3 :                 c->dev = 0;
     310                 :            :         }
     311                 :            : 
     312                 :          4 :         c->timestamp = info.st_ctime;
     313                 :            : 
     314                 :          4 :         return r;
     315                 :            : }
     316                 :            : 
     317                 :          1 : time_t config_file_timestamp(struct config_tree *cft)
     318                 :            : {
     319                 :          1 :         struct cs *c = (struct cs *) cft;
     320                 :            : 
     321                 :          1 :         return c->timestamp;
     322                 :            : }
     323                 :            : 
     324                 :            : /*
     325                 :            :  * Return 1 if config files ought to be reloaded
     326                 :            :  */
     327                 :          0 : int config_file_changed(struct config_tree *cft)
     328                 :            : {
     329                 :          0 :         struct cs *c = (struct cs *) cft;
     330                 :            :         struct stat info;
     331                 :            : 
     332         [ #  # ]:          0 :         if (!c->filename)
     333                 :          0 :                 return 0;
     334                 :            : 
     335         [ #  # ]:          0 :         if (stat(c->filename, &info) == -1) {
     336                 :            :                 /* Ignore a deleted config file: still use original data */
     337         [ #  # ]:          0 :                 if (errno == ENOENT) {
     338         [ #  # ]:          0 :                         if (!c->exists)
     339                 :          0 :                                 return 0;
     340                 :          0 :                         log_very_verbose("Config file %s has disappeared!",
     341                 :            :                                          c->filename);
     342                 :          0 :                         goto reload;
     343                 :            :                 }
     344                 :          0 :                 log_sys_error("stat", c->filename);
     345                 :          0 :                 log_error("Failed to reload configuration files");
     346                 :          0 :                 return 0;
     347                 :            :         }
     348                 :            : 
     349         [ #  # ]:          0 :         if (!S_ISREG(info.st_mode)) {
     350                 :          0 :                 log_error("Configuration file %s is not a regular file",
     351                 :            :                           c->filename);
     352                 :          0 :                 goto reload;
     353                 :            :         }
     354                 :            : 
     355                 :            :         /* Unchanged? */
     356         [ #  # ]:          0 :         if (c->timestamp == info.st_ctime)
     357                 :          0 :                 return 0;
     358                 :            : 
     359                 :            :       reload:
     360                 :          0 :         log_verbose("Detected config file change to %s", c->filename);
     361                 :          0 :         return 1;
     362                 :            : }
     363                 :            : 
     364                 :          0 : static int _line_start(struct output_line *outline)
     365                 :            : {
     366         [ #  # ]:          0 :         if (!dm_pool_begin_object(outline->mem, 128)) {
     367                 :          0 :                 log_error("dm_pool_begin_object failed for config line");
     368                 :          0 :                 return 0;
     369                 :            :         }
     370                 :            : 
     371                 :          0 :         return 1;
     372                 :            : }
     373                 :            : 
     374                 :            : static int _line_append(struct output_line *outline, const char *fmt, ...)
     375                 :            :   __attribute__ ((format(printf, 2, 3)));
     376                 :          0 : static int _line_append(struct output_line *outline, const char *fmt, ...)
     377                 :            : {
     378                 :            :         char buf[4096];
     379                 :            :         va_list ap;
     380                 :            :         int n;
     381                 :            : 
     382                 :          0 :         va_start(ap, fmt);
     383                 :          0 :         n = vsnprintf(&buf[0], sizeof buf - 1, fmt, ap);
     384   [ #  #  #  # ]:          0 :         if (n < 0 || n > (int) sizeof buf - 1) {
     385                 :          0 :                 log_error("vsnprintf failed for config line");
     386                 :          0 :                 return 0;
     387                 :            :         }
     388                 :          0 :         va_end(ap);
     389                 :            : 
     390         [ #  # ]:          0 :         if (!dm_pool_grow_object(outline->mem, &buf[0], strlen(buf))) {
     391                 :          0 :                 log_error("dm_pool_grow_object failed for config line");
     392                 :          0 :                 return 0;
     393                 :            :         }
     394                 :            : 
     395                 :          0 :         return 1;
     396                 :            : }
     397                 :            : 
     398                 :            : #define line_append(args...) do {if (!_line_append(outline, args)) {return_0;}} while (0)
     399                 :            : 
     400                 :          0 : static int _line_end(struct output_line *outline)
     401                 :            : {
     402                 :            :         const char *line;
     403                 :            : 
     404         [ #  # ]:          0 :         if (!dm_pool_grow_object(outline->mem, "\0", 1)) {
     405                 :          0 :                 log_error("dm_pool_grow_object failed for config line");
     406                 :          0 :                 return 0;
     407                 :            :         }
     408                 :            : 
     409                 :          0 :         line = dm_pool_end_object(outline->mem);
     410         [ #  # ]:          0 :         if (outline->putline)
     411                 :          0 :                 outline->putline(line, outline->putline_baton);
     412                 :            :         else {
     413         [ #  # ]:          0 :                 if (!outline->fp)
     414                 :          0 :                         log_print("%s", line);
     415                 :            :                 else
     416                 :          0 :                         fprintf(outline->fp, "%s\n", line);
     417                 :            :         }
     418                 :            : 
     419                 :          0 :         return 1;
     420                 :            : }
     421                 :            : 
     422                 :          0 : static int _write_value(struct output_line *outline, struct config_value *v)
     423                 :            : {
     424                 :            :         char *buf;
     425                 :            : 
     426   [ #  #  #  #  :          0 :         switch (v->type) {
                      # ]
     427                 :            :         case CFG_STRING:
     428                 :          0 :                 if (!(buf = alloca(escaped_len(v->v.str)))) {
     429                 :            :                         log_error("temporary stack allocation for a config "
     430                 :            :                                   "string failed");
     431                 :            :                         return 0;
     432                 :            :                 }
     433         [ #  # ]:          0 :                 line_append("\"%s\"", escape_double_quotes(buf, v->v.str));
     434                 :          0 :                 break;
     435                 :            : 
     436                 :            :         case CFG_FLOAT:
     437         [ #  # ]:          0 :                 line_append("%f", v->v.r);
     438                 :          0 :                 break;
     439                 :            : 
     440                 :            :         case CFG_INT:
     441         [ #  # ]:          0 :                 line_append("%" PRId64, v->v.i);
     442                 :          0 :                 break;
     443                 :            : 
     444                 :            :         case CFG_EMPTY_ARRAY:
     445         [ #  # ]:          0 :                 line_append("[]");
     446                 :          0 :                 break;
     447                 :            : 
     448                 :            :         default:
     449                 :          0 :                 log_error("_write_value: Unknown value type: %d", v->type);
     450                 :            : 
     451                 :            :         }
     452                 :            : 
     453                 :          0 :         return 1;
     454                 :            : }
     455                 :            : 
     456                 :          0 : static int _write_config(const struct config_node *n, int only_one,
     457                 :            :                          struct output_line *outline, int level)
     458                 :            : {
     459                 :            :         char space[MAX_INDENT + 1];
     460                 :          0 :         int l = (level < MAX_INDENT) ? level : MAX_INDENT;
     461                 :            :         int i;
     462                 :            : 
     463         [ #  # ]:          0 :         if (!n)
     464                 :          0 :                 return 1;
     465                 :            : 
     466         [ #  # ]:          0 :         for (i = 0; i < l; i++)
     467                 :          0 :                 space[i] = '\t';
     468                 :          0 :         space[i] = '\0';
     469                 :            : 
     470                 :            :         do {
     471         [ #  # ]:          0 :                 if (!_line_start(outline))
     472                 :          0 :                         return_0;
     473         [ #  # ]:          0 :                 line_append("%s%s", space, n->key);
     474         [ #  # ]:          0 :                 if (!n->v) {
     475                 :            :                         /* it's a sub section */
     476         [ #  # ]:          0 :                         line_append(" {");
     477         [ #  # ]:          0 :                         if (!_line_end(outline))
     478                 :          0 :                                 return_0;
     479                 :          0 :                         _write_config(n->child, 0, outline, level + 1);
     480         [ #  # ]:          0 :                         if (!_line_start(outline))
     481                 :          0 :                                 return_0;
     482         [ #  # ]:          0 :                         line_append("%s}", space);
     483                 :            :                 } else {
     484                 :            :                         /* it's a value */
     485                 :          0 :                         struct config_value *v = n->v;
     486         [ #  # ]:          0 :                         line_append("=");
     487         [ #  # ]:          0 :                         if (v->next) {
     488         [ #  # ]:          0 :                                 line_append("[");
     489         [ #  # ]:          0 :                                 while (v) {
     490         [ #  # ]:          0 :                                         if (!_write_value(outline, v))
     491                 :          0 :                                                 return_0;
     492                 :          0 :                                         v = v->next;
     493         [ #  # ]:          0 :                                         if (v)
     494         [ #  # ]:          0 :                                                 line_append(", ");
     495                 :            :                                 }
     496         [ #  # ]:          0 :                                 line_append("]");
     497                 :            :                         } else
     498         [ #  # ]:          0 :                                 if (!_write_value(outline, v))
     499                 :          0 :                                         return_0;
     500                 :            :                 }
     501         [ #  # ]:          0 :                 if (!_line_end(outline))
     502                 :          0 :                         return_0;
     503                 :          0 :                 n = n->sib;
     504 [ #  # ][ #  # ]:          0 :         } while (n && !only_one);
     505                 :            :         /* FIXME: add error checking */
     506                 :          0 :         return 1;
     507                 :            : }
     508                 :            : 
     509                 :          0 : int write_config_node(const struct config_node *cn, putline_fn putline, void *baton)
     510                 :            : {
     511                 :            :         struct output_line outline;
     512                 :          0 :         outline.fp = NULL;
     513                 :          0 :         outline.mem = dm_pool_create("config_line", 1024);
     514                 :          0 :         outline.putline = putline;
     515                 :          0 :         outline.putline_baton = baton;
     516         [ #  # ]:          0 :         if (!_write_config(cn, 0, &outline, 0)) {
     517                 :          0 :                 dm_pool_destroy(outline.mem);
     518                 :          0 :                 return_0;
     519                 :            :         }
     520                 :          0 :         dm_pool_destroy(outline.mem);
     521                 :          0 :         return 1;
     522                 :            : }
     523                 :            : 
     524                 :          0 : int write_config_file(struct config_tree *cft, const char *file,
     525                 :            :                       int argc, char **argv)
     526                 :            : {
     527                 :            :         struct config_node *cn;
     528                 :          0 :         int r = 1;
     529                 :            :         struct output_line outline;
     530                 :          0 :         outline.fp = NULL;
     531                 :          0 :         outline.putline = NULL;
     532                 :            : 
     533         [ #  # ]:          0 :         if (!file)
     534                 :          0 :                 file = "stdout";
     535         [ #  # ]:          0 :         else if (!(outline.fp = fopen(file, "w"))) {
     536                 :          0 :                 log_sys_error("open", file);
     537                 :          0 :                 return 0;
     538                 :            :         }
     539                 :            : 
     540                 :          0 :         outline.mem = dm_pool_create("config_line", 1024);
     541                 :            : 
     542                 :          0 :         log_verbose("Dumping configuration to %s", file);
     543         [ #  # ]:          0 :         if (!argc) {
     544         [ #  # ]:          0 :                 if (!_write_config(cft->root, 0, &outline, 0)) {
     545                 :          0 :                         log_error("Failure while writing to %s", file);
     546                 :          0 :                         r = 0;
     547                 :            :                 }
     548         [ #  # ]:          0 :         } else while (argc--) {
     549         [ #  # ]:          0 :                 if ((cn = find_config_node(cft->root, *argv))) {
     550         [ #  # ]:          0 :                         if (!_write_config(cn, 1, &outline, 0)) {
     551                 :          0 :                                 log_error("Failure while writing to %s", file);
     552                 :          0 :                                 r = 0;
     553                 :            :                         }
     554                 :            :                 } else {
     555                 :          0 :                         log_error("Configuration node %s not found", *argv);
     556                 :          0 :                         r = 0;
     557                 :            :                 }
     558                 :          0 :                 argv++;
     559                 :            :         }
     560                 :            : 
     561 [ #  # ][ #  # ]:          0 :         if (outline.fp && lvm_fclose(outline.fp, file)) {
     562                 :          0 :                 stack;
     563                 :          0 :                 r = 0;
     564                 :            :         }
     565                 :            : 
     566                 :          0 :         dm_pool_destroy(outline.mem);
     567                 :          0 :         return r;
     568                 :            : }
     569                 :            : 
     570                 :            : /*
     571                 :            :  * parser
     572                 :            :  */
     573                 :          5 : static struct config_node *_file(struct parser *p)
     574                 :            : {
     575                 :          5 :         struct config_node *root = NULL, *n, *l = NULL;
     576         [ +  + ]:         31 :         while (p->t != TOK_EOF) {
     577         [ -  + ]:         26 :                 if (!(n = _section(p)))
     578                 :          0 :                         return_0;
     579                 :            : 
     580         [ +  + ]:         26 :                 if (!root)
     581                 :          5 :                         root = n;
     582                 :            :                 else
     583                 :         21 :                         l->sib = n;
     584                 :         26 :                 n->parent = root;
     585                 :         26 :                 l = n;
     586                 :            :         }
     587                 :          5 :         return root;
     588                 :            : }
     589                 :            : 
     590                 :        157 : static struct config_node *_section(struct parser *p)
     591                 :            : {
     592                 :            :         /* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
     593                 :        157 :         struct config_node *root, *n, *l = NULL;
     594         [ -  + ]:        157 :         if (!(root = _create_node(p->mem)))
     595                 :          0 :                 return_0;
     596                 :            : 
     597         [ -  + ]:        157 :         if (!(root->key = _dup_tok(p)))
     598                 :          0 :                 return_0;
     599                 :            : 
     600         [ -  + ]:        157 :         match(TOK_IDENTIFIER);
     601                 :            : 
     602         [ +  + ]:        157 :         if (p->t == TOK_SECTION_B) {
     603         [ -  + ]:         20 :                 match(TOK_SECTION_B);
     604         [ +  + ]:        151 :                 while (p->t != TOK_SECTION_E) {
     605         [ -  + ]:        131 :                         if (!(n = _section(p)))
     606                 :          0 :                                 return_0;
     607                 :            : 
     608         [ +  + ]:        131 :                         if (!root->child)
     609                 :         20 :                                 root->child = n;
     610                 :            :                         else
     611                 :        111 :                                 l->sib = n;
     612                 :        131 :                         n->parent = root;
     613                 :        131 :                         l = n;
     614                 :            :                 }
     615         [ -  + ]:         20 :                 match(TOK_SECTION_E);
     616                 :            :         } else {
     617         [ -  + ]:        137 :                 match(TOK_EQ);
     618         [ -  + ]:        137 :                 if (!(root->v = _value(p)))
     619                 :          0 :                         return_0;
     620                 :            :         }
     621                 :            : 
     622                 :        157 :         return root;
     623                 :            : }
     624                 :            : 
     625                 :        137 : static struct config_value *_value(struct parser *p)
     626                 :            : {
     627                 :            :         /* '[' TYPE* ']' | TYPE */
     628                 :        137 :         struct config_value *h = NULL, *l, *ll = NULL;
     629         [ +  + ]:        137 :         if (p->t == TOK_ARRAY_B) {
     630         [ -  + ]:         14 :                 match(TOK_ARRAY_B);
     631         [ +  + ]:        356 :                 while (p->t != TOK_ARRAY_E) {
     632         [ -  + ]:        342 :                         if (!(l = _type(p)))
     633                 :          0 :                                 return_0;
     634                 :            : 
     635         [ +  + ]:        342 :                         if (!h)
     636                 :         11 :                                 h = l;
     637                 :            :                         else
     638                 :        331 :                                 ll->next = l;
     639                 :        342 :                         ll = l;
     640                 :            : 
     641         [ +  + ]:        342 :                         if (p->t == TOK_COMMA)
     642         [ -  + ]:        331 :                                 match(TOK_COMMA);
     643                 :            :                 }
     644         [ -  + ]:         14 :                 match(TOK_ARRAY_E);
     645                 :            :                 /*
     646                 :            :                  * Special case for an empty array.
     647                 :            :                  */
     648         [ +  + ]:         14 :                 if (!h) {
     649         [ -  + ]:          3 :                         if (!(h = _create_value(p->mem)))
     650                 :          0 :                                 return NULL;
     651                 :            : 
     652                 :         14 :                         h->type = CFG_EMPTY_ARRAY;
     653                 :            :                 }
     654                 :            : 
     655                 :            :         } else
     656                 :        123 :                 h = _type(p);
     657                 :            : 
     658                 :        137 :         return h;
     659                 :            : }
     660                 :            : 
     661                 :        465 : static struct config_value *_type(struct parser *p)
     662                 :            : {
     663                 :            :         /* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
     664                 :        465 :         struct config_value *v = _create_value(p->mem);
     665                 :            : 
     666         [ -  + ]:        465 :         if (!v)
     667                 :          0 :                 return NULL;
     668                 :            : 
     669   [ +  -  -  +  :        465 :         switch (p->t) {
                      - ]
     670                 :            :         case TOK_INT:
     671                 :         84 :                 v->type = CFG_INT;
     672                 :         84 :                 v->v.i = strtoll(p->tb, NULL, 0); /* FIXME: check error */
     673         [ -  + ]:         84 :                 match(TOK_INT);
     674                 :         84 :                 break;
     675                 :            : 
     676                 :            :         case TOK_FLOAT:
     677                 :          0 :                 v->type = CFG_FLOAT;
     678                 :          0 :                 v->v.r = strtod(p->tb, NULL);     /* FIXME: check error */
     679         [ #  # ]:          0 :                 match(TOK_FLOAT);
     680                 :          0 :                 break;
     681                 :            : 
     682                 :            :         case TOK_STRING:
     683                 :          0 :                 v->type = CFG_STRING;
     684                 :            : 
     685                 :          0 :                 p->tb++, p->te--; /* strip "'s */
     686         [ #  # ]:          0 :                 if (!(v->v.str = _dup_tok(p)))
     687                 :          0 :                         return_0;
     688                 :          0 :                 p->te++;
     689         [ #  # ]:          0 :                 match(TOK_STRING);
     690                 :          0 :                 break;
     691                 :            : 
     692                 :            :         case TOK_STRING_ESCAPED:
     693                 :        381 :                 v->type = CFG_STRING;
     694                 :            : 
     695                 :        381 :                 p->tb++, p->te--; /* strip "'s */
     696         [ -  + ]:        381 :                 if (!(v->v.str = _dup_tok(p)))
     697                 :          0 :                         return_0;
     698                 :        381 :                 unescape_double_quotes(v->v.str);
     699                 :        381 :                 p->te++;
     700         [ -  + ]:        381 :                 match(TOK_STRING_ESCAPED);
     701                 :        381 :                 break;
     702                 :            : 
     703                 :            :         default:
     704                 :          0 :                 log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
     705                 :            :                           p->tb - p->fb + 1, p->line);
     706                 :          0 :                 return 0;
     707                 :            :         }
     708                 :        465 :         return v;
     709                 :            : }
     710                 :            : 
     711                 :       1158 : static int _match_aux(struct parser *p, int t)
     712                 :            : {
     713         [ -  + ]:       1158 :         if (p->t != t)
     714                 :          0 :                 return 0;
     715                 :            : 
     716                 :       1158 :         _get_token(p, t);
     717                 :       1158 :         return 1;
     718                 :            : }
     719                 :            : 
     720                 :            : /*
     721                 :            :  * tokeniser
     722                 :            :  */
     723                 :       1163 : static void _get_token(struct parser *p, int tok_prev)
     724                 :            : {
     725                 :       1163 :         int values_allowed = 0;
     726                 :            : 
     727                 :       1163 :         p->tb = p->te;
     728                 :       1163 :         _eat_space(p);
     729   [ +  +  -  + ]:       1163 :         if (p->tb == p->fe || !*p->tb) {
     730                 :          5 :                 p->t = TOK_EOF;
     731                 :          5 :                 return;
     732                 :            :         }
     733                 :            : 
     734                 :            :         /* Should next token be interpreted as value instead of identifier? */
     735 [ +  + ][ +  + ]:       1158 :         if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
                 [ +  + ]
     736                 :            :             tok_prev == TOK_COMMA)
     737                 :        482 :                 values_allowed = 1;
     738                 :            : 
     739                 :       1158 :         p->t = TOK_INT;              /* fudge so the fall through for
     740                 :            :                                    floats works */
     741 [ +  +  +  +  + :       1158 :         switch (*p->te) {
          +  +  -  -  +  
                      + ]
     742                 :            :         case SECTION_B_CHAR:
     743                 :         20 :                 p->t = TOK_SECTION_B;
     744                 :         20 :                 p->te++;
     745                 :         20 :                 break;
     746                 :            : 
     747                 :            :         case SECTION_E_CHAR:
     748                 :         20 :                 p->t = TOK_SECTION_E;
     749                 :         20 :                 p->te++;
     750                 :         20 :                 break;
     751                 :            : 
     752                 :            :         case '[':
     753                 :         14 :                 p->t = TOK_ARRAY_B;
     754                 :         14 :                 p->te++;
     755                 :         14 :                 break;
     756                 :            : 
     757                 :            :         case ']':
     758                 :         14 :                 p->t = TOK_ARRAY_E;
     759                 :         14 :                 p->te++;
     760                 :         14 :                 break;
     761                 :            : 
     762                 :            :         case ',':
     763                 :        331 :                 p->t = TOK_COMMA;
     764                 :        331 :                 p->te++;
     765                 :        331 :                 break;
     766                 :            : 
     767                 :            :         case '=':
     768                 :        137 :                 p->t = TOK_EQ;
     769                 :        137 :                 p->te++;
     770                 :        137 :                 break;
     771                 :            : 
     772                 :            :         case '"':
     773                 :        381 :                 p->t = TOK_STRING_ESCAPED;
     774                 :        381 :                 p->te++;
     775 [ +  - ][ +  - ]:       5273 :                 while ((p->te != p->fe) && (*p->te) && (*p->te != '"')) {
                 [ +  + ]
     776 [ -  + ][ #  # ]:       4892 :                         if ((*p->te == '\\') && (p->te + 1 != p->fe) &&
                 [ #  # ]
     777                 :          0 :                             *(p->te + 1))
     778                 :          0 :                                 p->te++;
     779                 :       4892 :                         p->te++;
     780                 :            :                 }
     781                 :            : 
     782 [ +  - ][ +  - ]:        381 :                 if ((p->te != p->fe) && (*p->te))
     783                 :        381 :                         p->te++;
     784                 :        381 :                 break;
     785                 :            : 
     786                 :            :         case '\'':
     787                 :          0 :                 p->t = TOK_STRING;
     788                 :          0 :                 p->te++;
     789 [ #  # ][ #  # ]:          0 :                 while ((p->te != p->fe) && (*p->te) && (*p->te != '\''))
                 [ #  # ]
     790                 :          0 :                         p->te++;
     791                 :            : 
     792 [ #  # ][ #  # ]:          0 :                 if ((p->te != p->fe) && (*p->te))
     793                 :          0 :                         p->te++;
     794                 :          0 :                 break;
     795                 :            : 
     796                 :            :         case '.':
     797                 :          0 :                 p->t = TOK_FLOAT;
     798                 :            :         case '0':
     799                 :            :         case '1':
     800                 :            :         case '2':
     801                 :            :         case '3':
     802                 :            :         case '4':
     803                 :            :         case '5':
     804                 :            :         case '6':
     805                 :            :         case '7':
     806                 :            :         case '8':
     807                 :            :         case '9':
     808                 :            :         case '+':
     809                 :            :         case '-':
     810         [ +  - ]:         84 :                 if (values_allowed) {
     811                 :         84 :                         p->te++;
     812 [ +  - ][ +  - ]:        129 :                         while ((p->te != p->fe) && (*p->te)) {
     813         [ -  + ]:        129 :                                 if (*p->te == '.') {
     814         [ #  # ]:          0 :                                         if (p->t == TOK_FLOAT)
     815                 :          0 :                                                 break;
     816                 :          0 :                                         p->t = TOK_FLOAT;
     817         [ +  + ]:        129 :                                 } else if (!isdigit((int) *p->te))
     818                 :         84 :                                         break;
     819                 :         45 :                                 p->te++;
     820                 :            :                         }
     821                 :         84 :                         break;
     822                 :            :                 }
     823                 :            : 
     824                 :            :         default:
     825                 :        157 :                 p->t = TOK_IDENTIFIER;
     826 [ +  - ][ +  - ]:       2976 :                 while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
                 [ +  - ]
     827                 :       3628 :                        (*p->te != '#') && (*p->te != '=') &&
     828                 :       1813 :                        (*p->te != SECTION_B_CHAR) &&
     829                 :       1813 :                        (*p->te != SECTION_E_CHAR))
     830                 :       1813 :                         p->te++;
     831                 :            :                 break;
     832                 :            :         }
     833                 :            : }
     834                 :            : 
     835                 :       1163 : static void _eat_space(struct parser *p)
     836                 :            : {
     837 [ +  + ][ +  - ]:       4726 :         while ((p->tb != p->fe) && (*p->tb)) {
     838         [ +  + ]:       3563 :                 if (*p->te == '#')
     839 [ +  - ][ +  - ]:      40416 :                         while ((p->te != p->fe) && (*p->te) && (*p->te != '\n'))
                 [ +  + ]
     840                 :      39623 :                                 p->te++;
     841                 :            : 
     842         [ +  + ]:       2770 :                 else if (isspace(*p->te)) {
     843 [ +  + ][ +  - ]:       6910 :                         while ((p->te != p->fe) && (*p->te) && isspace(*p->te)) {
                 [ +  + ]
     844         [ +  + ]:       5298 :                                 if (*p->te == '\n')
     845                 :       1225 :                                         p->line++;
     846                 :       5298 :                                 p->te++;
     847                 :            :                         }
     848                 :            :                 }
     849                 :            : 
     850                 :            :                 else
     851                 :       1158 :                         return;
     852                 :            : 
     853                 :       2405 :                 p->tb = p->te;
     854                 :            :         }
     855                 :            : }
     856                 :            : 
     857                 :            : /*
     858                 :            :  * memory management
     859                 :            :  */
     860                 :        468 : static struct config_value *_create_value(struct dm_pool *mem)
     861                 :            : {
     862                 :        468 :         struct config_value *v = dm_pool_alloc(mem, sizeof(*v));
     863                 :            : 
     864         [ +  - ]:        468 :         if (v)
     865                 :        468 :                 memset(v, 0, sizeof(*v));
     866                 :            : 
     867                 :        468 :         return v;
     868                 :            : }
     869                 :            : 
     870                 :        157 : static struct config_node *_create_node(struct dm_pool *mem)
     871                 :            : {
     872                 :        157 :         struct config_node *n = dm_pool_alloc(mem, sizeof(*n));
     873                 :            : 
     874         [ +  - ]:        157 :         if (n)
     875                 :        157 :                 memset(n, 0, sizeof(*n));
     876                 :            : 
     877                 :        157 :         return n;
     878                 :            : }
     879                 :            : 
     880                 :        538 : static char *_dup_tok(struct parser *p)
     881                 :            : {
     882                 :        538 :         size_t len = p->te - p->tb;
     883                 :        538 :         char *str = dm_pool_alloc(p->mem, len + 1);
     884         [ -  + ]:        538 :         if (!str)
     885                 :          0 :                 return_0;
     886                 :        538 :         strncpy(str, p->tb, len);
     887                 :        538 :         str[len] = '\0';
     888                 :        538 :         return str;
     889                 :            : }
     890                 :            : 
     891                 :            : /*
     892                 :            :  * utility functions
     893                 :            :  */
     894                 :        247 : static struct config_node *_find_config_node(const struct config_node *cn,
     895                 :            :                                              const char *path)
     896                 :            : {
     897                 :            :         const char *e;
     898                 :        247 :         const struct config_node *cn_found = NULL;
     899                 :            : 
     900         [ +  + ]:        387 :         while (cn) {
     901                 :            :                 /* trim any leading slashes */
     902 [ +  - ][ +  + ]:        497 :                 while (*path && (*path == sep))
     903                 :        140 :                         path++;
     904                 :            : 
     905                 :            :                 /* find the end of this segment */
     906 [ +  + ][ +  + ]:       3183 :                 for (e = path; *e && (*e != sep); e++) ;
     907                 :            : 
     908                 :            :                 /* hunt for the node */
     909                 :        357 :                 cn_found = NULL;
     910         [ +  + ]:       2871 :                 while (cn) {
     911         [ +  + ]:       2514 :                         if (_tok_match(cn->key, path, e)) {
     912                 :            :                                 /* Inefficient */
     913         [ +  - ]:        224 :                                 if (!cn_found)
     914                 :        224 :                                         cn_found = cn;
     915                 :            :                                 else
     916                 :          0 :                                         log_warn("WARNING: Ignoring duplicate"
     917                 :            :                                                  " config node: %s ("
     918                 :            :                                                  "seeking %s)", cn->key, path);
     919                 :            :                         }
     920                 :            : 
     921                 :       2514 :                         cn = cn->sib;
     922                 :            :                 }
     923                 :            : 
     924 [ +  + ][ +  + ]:        357 :                 if (cn_found && *e)
     925                 :        140 :                         cn = cn_found->child;
     926                 :            :                 else
     927                 :            :                         break;  /* don't move into the last node */
     928                 :            : 
     929                 :        140 :                 path = e;
     930                 :            :         }
     931                 :            : 
     932                 :        247 :         return (struct config_node *) cn_found;
     933                 :            : }
     934                 :            : 
     935                 :        143 : static struct config_node *_find_first_config_node(const struct config_node *cn1,
     936                 :            :                                                    const struct config_node *cn2,
     937                 :            :                                                    const char *path)
     938                 :            : {
     939                 :            :         struct config_node *cn;
     940                 :            : 
     941 [ +  + ][ +  + ]:        143 :         if (cn1 && (cn = _find_config_node(cn1, path)))
     942                 :          1 :                 return cn;
     943                 :            : 
     944 [ +  - ][ +  + ]:        142 :         if (cn2 && (cn = _find_config_node(cn2, path)))
     945                 :         82 :                 return cn;
     946                 :            : 
     947                 :        143 :         return NULL;
     948                 :            : }
     949                 :            : 
     950                 :         52 : struct config_node *find_config_node(const struct config_node *cn,
     951                 :            :                                      const char *path)
     952                 :            : {
     953                 :         52 :         return _find_config_node(cn, path);
     954                 :            : }
     955                 :            : 
     956                 :         39 : static const char *_find_config_str(const struct config_node *cn1,
     957                 :            :                                     const struct config_node *cn2,
     958                 :            :                                     const char *path, const char *fail)
     959                 :            : {
     960                 :         39 :         const struct config_node *n = _find_first_config_node(cn1, cn2, path);
     961                 :            : 
     962                 :            :         /* Empty strings are ignored */
     963   [ +  +  +  - ]:         39 :         if ((n && n->v && n->v->type == CFG_STRING) && (*n->v->v.str)) {
         [ +  - ][ +  + ]
     964                 :         21 :                 log_very_verbose("Setting %s to %s", path, n->v->v.str);
     965                 :         21 :                 return n->v->v.str;
     966                 :            :         }
     967                 :            : 
     968         [ +  + ]:         18 :         if (fail)
     969                 :          9 :                 log_very_verbose("%s not found in config: defaulting to %s",
     970                 :            :                                  path, fail);
     971                 :         39 :         return fail;
     972                 :            : }
     973                 :            : 
     974                 :          0 : const char *find_config_str(const struct config_node *cn,
     975                 :            :                             const char *path, const char *fail)
     976                 :            : {
     977                 :          0 :         return _find_config_str(cn, NULL, path, fail);
     978                 :            : }
     979                 :            : 
     980                 :         65 : static int64_t _find_config_int64(const struct config_node *cn1,
     981                 :            :                                   const struct config_node *cn2,
     982                 :            :                                   const char *path, int64_t fail)
     983                 :            : {
     984                 :         65 :         const struct config_node *n = _find_first_config_node(cn1, cn2, path);
     985                 :            : 
     986   [ +  +  +  - ]:         65 :         if (n && n->v && n->v->type == CFG_INT) {
                 [ +  - ]
     987                 :         42 :                 log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
     988                 :         42 :                 return n->v->v.i;
     989                 :            :         }
     990                 :            : 
     991                 :         23 :         log_very_verbose("%s not found in config: defaulting to %" PRId64,
     992                 :            :                          path, fail);
     993                 :         65 :         return fail;
     994                 :            : }
     995                 :            : 
     996                 :          0 : int find_config_int(const struct config_node *cn, const char *path, int fail)
     997                 :            : {
     998                 :            :         /* FIXME Add log_error message on overflow */
     999                 :          0 :         return (int) _find_config_int64(cn, NULL, path, (int64_t) fail);
    1000                 :            : }
    1001                 :            : 
    1002                 :          0 : static float _find_config_float(const struct config_node *cn1,
    1003                 :            :                                 const struct config_node *cn2,
    1004                 :            :                                 const char *path, float fail)
    1005                 :            : {
    1006                 :          0 :         const struct config_node *n = _find_first_config_node(cn1, cn2, path);
    1007                 :            : 
    1008   [ #  #  #  # ]:          0 :         if (n && n->v && n->v->type == CFG_FLOAT) {
                 [ #  # ]
    1009                 :          0 :                 log_very_verbose("Setting %s to %f", path, n->v->v.r);
    1010                 :          0 :                 return n->v->v.r;
    1011                 :            :         }
    1012                 :            : 
    1013                 :          0 :         log_very_verbose("%s not found in config: defaulting to %f",
    1014                 :            :                          path, fail);
    1015                 :            : 
    1016                 :          0 :         return fail;
    1017                 :            : 
    1018                 :            : }
    1019                 :            : 
    1020                 :          0 : float find_config_float(const struct config_node *cn, const char *path,
    1021                 :            :                         float fail)
    1022                 :            : {
    1023                 :          0 :         return _find_config_float(cn, NULL, path, fail);
    1024                 :            : }
    1025                 :            : 
    1026                 :         30 : struct config_node *find_config_tree_node(struct cmd_context *cmd,
    1027                 :            :                                           const char *path)
    1028                 :            : {
    1029         [ +  + ]:         30 :         return _find_first_config_node(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path);
    1030                 :            : }
    1031                 :            : 
    1032                 :         39 : const char *find_config_tree_str(struct cmd_context *cmd,
    1033                 :            :                                  const char *path, const char *fail)
    1034                 :            : {
    1035         [ +  + ]:         39 :         return _find_config_str(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
    1036                 :            : }
    1037                 :            : 
    1038                 :         65 : int find_config_tree_int(struct cmd_context *cmd, const char *path,
    1039                 :            :                          int fail)
    1040                 :            : {
    1041                 :            :         /* FIXME Add log_error message on overflow */
    1042         [ +  + ]:         65 :         return (int) _find_config_int64(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, (int64_t) fail);
    1043                 :            : }
    1044                 :            : 
    1045                 :          0 : float find_config_tree_float(struct cmd_context *cmd, const char *path,
    1046                 :            :                              float fail)
    1047                 :            : {
    1048         [ #  # ]:          0 :         return _find_config_float(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
    1049                 :            : }
    1050                 :            : 
    1051                 :          0 : static int _str_in_array(const char *str, const char * const values[])
    1052                 :            : {
    1053                 :            :         int i;
    1054                 :            : 
    1055         [ #  # ]:          0 :         for (i = 0; values[i]; i++)
    1056         [ #  # ]:          0 :                 if (!strcasecmp(str, values[i]))
    1057                 :          0 :                         return 1;
    1058                 :            : 
    1059                 :          0 :         return 0;
    1060                 :            : }
    1061                 :            : 
    1062                 :          0 : static int _str_to_bool(const char *str, int fail)
    1063                 :            : {
    1064                 :          0 :         const char * const _true_values[]  = { "y", "yes", "on", "true", NULL };
    1065                 :          0 :         const char * const _false_values[] = { "n", "no", "off", "false", NULL };
    1066                 :            : 
    1067         [ #  # ]:          0 :         if (_str_in_array(str, _true_values))
    1068                 :          0 :                 return 1;
    1069                 :            : 
    1070         [ #  # ]:          0 :         if (_str_in_array(str, _false_values))
    1071                 :          0 :                 return 0;
    1072                 :            : 
    1073                 :          0 :         return fail;
    1074                 :            : }
    1075                 :            : 
    1076                 :          9 : static int _find_config_bool(const struct config_node *cn1,
    1077                 :            :                              const struct config_node *cn2,
    1078                 :            :                              const char *path, int fail)
    1079                 :            : {
    1080                 :          9 :         const struct config_node *n = _find_first_config_node(cn1, cn2, path);
    1081                 :            :         struct config_value *v;
    1082                 :            : 
    1083         [ +  + ]:          9 :         if (!n)
    1084                 :          1 :                 return fail;
    1085                 :            : 
    1086                 :          8 :         v = n->v;
    1087                 :            : 
    1088      [ +  -  - ]:          8 :         switch (v->type) {
    1089                 :            :         case CFG_INT:
    1090                 :          8 :                 return v->v.i ? 1 : 0;
    1091                 :            : 
    1092                 :            :         case CFG_STRING:
    1093                 :          0 :                 return _str_to_bool(v->v.str, fail);
    1094                 :            :         }
    1095                 :            : 
    1096                 :          9 :         return fail;
    1097                 :            : }
    1098                 :            : 
    1099                 :          0 : int find_config_bool(const struct config_node *cn, const char *path, int fail)
    1100                 :            : {
    1101                 :          0 :         return _find_config_bool(cn, NULL, path, fail);
    1102                 :            : }
    1103                 :            : 
    1104                 :          9 : int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail)
    1105                 :            : {
    1106         [ +  + ]:          9 :         return _find_config_bool(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
    1107                 :            : }
    1108                 :            : 
    1109                 :          0 : int get_config_uint32(const struct config_node *cn, const char *path,
    1110                 :            :                       uint32_t *result)
    1111                 :            : {
    1112                 :            :         const struct config_node *n;
    1113                 :            : 
    1114                 :          0 :         n = find_config_node(cn, path);
    1115                 :            : 
    1116   [ #  #  #  # ]:          0 :         if (!n || !n->v || n->v->type != CFG_INT)
                 [ #  # ]
    1117                 :          0 :                 return 0;
    1118                 :            : 
    1119                 :          0 :         *result = n->v->v.i;
    1120                 :          0 :         return 1;
    1121                 :            : }
    1122                 :            : 
    1123                 :          0 : int get_config_uint64(const struct config_node *cn, const char *path,
    1124                 :            :                       uint64_t *result)
    1125                 :            : {
    1126                 :            :         const struct config_node *n;
    1127                 :            : 
    1128                 :          0 :         n = find_config_node(cn, path);
    1129                 :            : 
    1130   [ #  #  #  # ]:          0 :         if (!n || !n->v || n->v->type != CFG_INT)
                 [ #  # ]
    1131                 :          0 :                 return 0;
    1132                 :            : 
    1133                 :          0 :         *result = (uint64_t) n->v->v.i;
    1134                 :          0 :         return 1;
    1135                 :            : }
    1136                 :            : 
    1137                 :          0 : int get_config_str(const struct config_node *cn, const char *path,
    1138                 :            :                    char **result)
    1139                 :            : {
    1140                 :            :         const struct config_node *n;
    1141                 :            : 
    1142                 :          0 :         n = find_config_node(cn, path);
    1143                 :            : 
    1144   [ #  #  #  # ]:          0 :         if (!n || !n->v || n->v->type != CFG_STRING)
                 [ #  # ]
    1145                 :          0 :                 return 0;
    1146                 :            : 
    1147                 :          0 :         *result = n->v->v.str;
    1148                 :          0 :         return 1;
    1149                 :            : }
    1150                 :            : 
    1151                 :            : /* Insert cn2 after cn1 */
    1152                 :         24 : static void _insert_config_node(struct config_node **cn1,
    1153                 :            :                                 struct config_node *cn2)
    1154                 :            : {
    1155         [ +  + ]:         24 :         if (!*cn1) {
    1156                 :          3 :                 *cn1 = cn2;
    1157                 :          3 :                 cn2->sib = NULL;
    1158                 :            :         } else {
    1159                 :         21 :                 cn2->sib = (*cn1)->sib;
    1160                 :         21 :                 (*cn1)->sib = cn2;
    1161                 :            :         }
    1162                 :         24 : }
    1163                 :            : 
    1164                 :            : /*
    1165                 :            :  * Merge section cn2 into section cn1 (which has the same name)
    1166                 :            :  * overwriting any existing cn1 nodes with matching names.
    1167                 :            :  */
    1168                 :          0 : static void _merge_section(struct config_node *cn1, struct config_node *cn2)
    1169                 :            : {
    1170                 :            :         struct config_node *cn, *nextn, *oldn;
    1171                 :            :         struct config_value *cv;
    1172                 :            : 
    1173         [ #  # ]:          0 :         for (cn = cn2->child; cn; cn = nextn) {
    1174                 :          0 :                 nextn = cn->sib;
    1175                 :            : 
    1176                 :            :                 /* Skip "tags" */
    1177         [ #  # ]:          0 :                 if (!strcmp(cn->key, "tags"))
    1178                 :          0 :                         continue;
    1179                 :            : 
    1180                 :            :                 /* Subsection? */
    1181         [ #  # ]:          0 :                 if (!cn->v)
    1182                 :            :                         /* Ignore - we don't have any of these yet */
    1183                 :          0 :                         continue;
    1184                 :            :                 /* Not already present? */
    1185         [ #  # ]:          0 :                 if (!(oldn = find_config_node(cn1->child, cn->key))) {
    1186                 :          0 :                         _insert_config_node(&cn1->child, cn);
    1187                 :          0 :                         continue;
    1188                 :            :                 }
    1189                 :            :                 /* Merge certain value lists */
    1190 [ #  # ][ #  # ]:          0 :                 if ((!strcmp(cn1->key, "activation") &&
         [ #  # ][ #  # ]
                 [ #  # ]
    1191                 :          0 :                      !strcmp(cn->key, "volume_list")) ||
    1192                 :          0 :                     (!strcmp(cn1->key, "devices") &&
    1193                 :          0 :                      (!strcmp(cn->key, "filter") || !strcmp(cn->key, "types")))) {
    1194                 :          0 :                         cv = cn->v;
    1195         [ #  # ]:          0 :                         while (cv->next)
    1196                 :          0 :                                 cv = cv->next;
    1197                 :          0 :                         cv->next = oldn->v;
    1198                 :            :                 }
    1199                 :            : 
    1200                 :            :                 /* Replace values */
    1201                 :          0 :                 oldn->v = cn->v;
    1202                 :            :         }
    1203                 :          0 : }
    1204                 :            : 
    1205                 :          0 : static int _match_host_tags(struct dm_list *tags, struct config_node *tn)
    1206                 :            : {
    1207                 :            :         struct config_value *tv;
    1208                 :            :         const char *str;
    1209                 :            : 
    1210         [ #  # ]:          0 :         for (tv = tn->v; tv; tv = tv->next) {
    1211         [ #  # ]:          0 :                 if (tv->type != CFG_STRING)
    1212                 :          0 :                         continue;
    1213                 :          0 :                 str = tv->v.str;
    1214         [ #  # ]:          0 :                 if (*str == '@')
    1215                 :          0 :                         str++;
    1216         [ #  # ]:          0 :                 if (!*str)
    1217                 :          0 :                         continue;
    1218         [ #  # ]:          0 :                 if (str_list_match_item(tags, str))
    1219                 :          0 :                         return 1;
    1220                 :            :         }
    1221                 :            : 
    1222                 :          0 :         return 0;
    1223                 :            : }
    1224                 :            : 
    1225                 :            : /* Destructively merge a new config tree into an existing one */
    1226                 :          3 : int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
    1227                 :            :                       struct config_tree *newdata)
    1228                 :            : {
    1229                 :          3 :         struct config_node *root = cft->root;
    1230                 :            :         struct config_node *cn, *nextn, *oldn, *tn, *cn2;
    1231                 :            : 
    1232         [ +  + ]:         27 :         for (cn = newdata->root; cn; cn = nextn) {
    1233                 :         24 :                 nextn = cn->sib;
    1234                 :            :                 /* Ignore tags section */
    1235         [ -  + ]:         24 :                 if (!strcmp(cn->key, "tags"))
    1236                 :          0 :                         continue;
    1237                 :            :                 /* If there's a tags node, skip if host tags don't match */
    1238         [ -  + ]:         24 :                 if ((tn = find_config_node(cn->child, "tags"))) {
    1239         [ #  # ]:          0 :                         if (!_match_host_tags(&cmd->tags, tn))
    1240                 :          0 :                                 continue;
    1241                 :            :                 }
    1242         [ +  - ]:         24 :                 if (!(oldn = find_config_node(root, cn->key))) {
    1243                 :         24 :                         _insert_config_node(&cft->root, cn);
    1244                 :            :                         /* Remove any "tags" nodes */
    1245         [ +  + ]:        153 :                         for (cn2 = cn->child; cn2; cn2 = cn2->sib) {
    1246         [ -  + ]:        129 :                                 if (!strcmp(cn2->key, "tags")) {
    1247                 :          0 :                                         cn->child = cn2->sib;
    1248                 :          0 :                                         continue;
    1249                 :            :                                 }
    1250 [ +  + ][ -  + ]:        129 :                                 if (cn2->sib && !strcmp(cn2->sib->key, "tags")) {
    1251                 :          0 :                                         cn2->sib = cn2->sib->sib;
    1252                 :          0 :                                         continue;
    1253                 :            :                                 }
    1254                 :            :                         }
    1255                 :         24 :                         continue;
    1256                 :            :                 }
    1257                 :          0 :                 _merge_section(oldn, cn);
    1258                 :            :         }
    1259                 :            : 
    1260                 :          3 :         return 1;
    1261                 :            : }
    1262                 :            : 
    1263                 :            : /*
    1264                 :            :  * Convert a token type to the char it represents.
    1265                 :            :  */
    1266                 :          0 : static char _token_type_to_char(int type)
    1267                 :            : {
    1268      [ #  #  # ]:          0 :         switch (type) {
    1269                 :            :                 case TOK_SECTION_B:
    1270                 :          0 :                         return SECTION_B_CHAR;
    1271                 :            :                 case TOK_SECTION_E:
    1272                 :          0 :                         return SECTION_E_CHAR;
    1273                 :            :                 default:
    1274                 :          0 :                         return 0;
    1275                 :            :         }
    1276                 :            : }
    1277                 :            : 
    1278                 :            : /*
    1279                 :            :  * Returns:
    1280                 :            :  *  # of 'type' tokens in 'str'.
    1281                 :            :  */
    1282                 :          0 : static unsigned _count_tokens(const char *str, unsigned len, int type)
    1283                 :            : {
    1284                 :            :         char c;
    1285                 :            : 
    1286                 :          0 :         c = _token_type_to_char(type);
    1287                 :            : 
    1288                 :          0 :         return count_chars(str, len, c);
    1289                 :            : }
    1290                 :            : 
    1291                 :          0 : const char *config_parent_name(const struct config_node *n)
    1292                 :            : {
    1293         [ #  # ]:          0 :         return (n->parent ? n->parent->key : "(root)");
    1294                 :            : }
    1295                 :            : /*
    1296                 :            :  * Heuristic function to make a quick guess as to whether a text
    1297                 :            :  * region probably contains a valid config "section".  (Useful for
    1298                 :            :  * scanning areas of the disk for old metadata.)
    1299                 :            :  * Config sections contain various tokens, may contain other sections
    1300                 :            :  * and strings, and are delimited by begin (type 'TOK_SECTION_B') and
    1301                 :            :  * end (type 'TOK_SECTION_E') tokens.  As a quick heuristic, we just
    1302                 :            :  * count the number of begin and end tokens, and see if they are
    1303                 :            :  * non-zero and the counts match.
    1304                 :            :  * Full validation of the section should be done with another function
    1305                 :            :  * (for example, read_config_fd).
    1306                 :            :  *
    1307                 :            :  * Returns:
    1308                 :            :  *  0 - probably is not a valid config section
    1309                 :            :  *  1 - probably _is_ a valid config section
    1310                 :            :  */
    1311                 :          0 : unsigned maybe_config_section(const char *str, unsigned len)
    1312                 :            : {
    1313                 :            :         int begin_count;
    1314                 :            :         int end_count;
    1315                 :            : 
    1316                 :          0 :         begin_count = _count_tokens(str, len, TOK_SECTION_B);
    1317                 :          0 :         end_count = _count_tokens(str, len, TOK_SECTION_E);
    1318                 :            : 
    1319   [ #  #  #  # ]:          0 :         if (begin_count && end_count && (begin_count == end_count))
                 [ #  # ]
    1320                 :          0 :                 return 1;
    1321                 :            :         else
    1322                 :          0 :                 return 0;
    1323                 :            : }
    1324                 :            : 
    1325                 :          0 : static struct config_value *_clone_config_value(struct dm_pool *mem, const struct config_value *v)
    1326                 :            : {
    1327         [ #  # ]:          0 :         if (!v)
    1328                 :          0 :                 return NULL;
    1329                 :          0 :         struct config_value *new = _create_value(mem);
    1330                 :          0 :         new->type = v->type;
    1331         [ #  # ]:          0 :         if (v->type == CFG_STRING)
    1332                 :          0 :                 new->v.str = dm_pool_strdup(mem, v->v.str);
    1333                 :            :         else
    1334                 :          0 :                 new->v = v->v;
    1335                 :          0 :         new->next = _clone_config_value(mem, v->next);
    1336                 :          0 :         return new;
    1337                 :            : }
    1338                 :            : 
    1339                 :          0 : struct config_node *clone_config_node(struct dm_pool *mem, const struct config_node *cn,
    1340                 :            :                                       int siblings)
    1341                 :            : {
    1342         [ #  # ]:          0 :         if (!cn)
    1343                 :          0 :                 return NULL;
    1344                 :          0 :         struct config_node *new = _create_node(mem);
    1345                 :          0 :         new->key = dm_pool_strdup(mem, cn->key);
    1346                 :          0 :         new->child = clone_config_node(mem, cn->child, 1);
    1347                 :          0 :         new->v = _clone_config_value(mem, cn->v);
    1348         [ #  # ]:          0 :         if (siblings)
    1349                 :          0 :                 new->sib = clone_config_node(mem, cn->sib, siblings);
    1350                 :            :         else
    1351                 :          0 :                 new->sib = NULL;
    1352                 :          0 :         return new;
    1353                 :            : }

Generated by: LCOV version 1.8