LCOV - code coverage report
Current view: top level - misc/kabi/lvm2.git/tools - lvmcmdline.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 280 725 38.6 %
Date: 2010-04-13 Functions: 31 66 47.0 %
Branches: 128 490 26.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
       3                 :            :  * Copyright (C) 2004-2009 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 "tools.h"
      17                 :            : #include "lvm2cmdline.h"
      18                 :            : #include "label.h"
      19                 :            : #include "lvm-version.h"
      20                 :            : 
      21                 :            : #include "stub.h"
      22                 :            : #include "lvm2cmd.h"
      23                 :            : #include "last-path-component.h"
      24                 :            : 
      25                 :            : #include <signal.h>
      26                 :            : #include <syslog.h>
      27                 :            : #include <libgen.h>
      28                 :            : #include <sys/stat.h>
      29                 :            : #include <time.h>
      30                 :            : #include <sys/resource.h>
      31                 :            : 
      32                 :            : #ifdef HAVE_GETOPTLONG
      33                 :            : #  include <getopt.h>
      34                 :            : #  define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e))
      35                 :            : #  define OPTIND_INIT 0
      36                 :            : #else
      37                 :            : struct option {
      38                 :            : };
      39                 :            : extern int optind;
      40                 :            : extern char *optarg;
      41                 :            : #  define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c))
      42                 :            : #  define OPTIND_INIT 1
      43                 :            : #endif
      44                 :            : 
      45                 :            : #ifdef UDEV_SYNC_SUPPORT
      46                 :            : #  define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
      47                 :            : #  include <libudev.h>
      48                 :            : #endif
      49                 :            : 
      50                 :            : /*
      51                 :            :  * Table of valid switches
      52                 :            :  */
      53                 :            : static struct arg _the_args[ARG_COUNT + 1] = {
      54                 :            : #define arg(a, b, c, d, e) {b, "", "--" c, d, e, 0, NULL, 0, 0, INT64_C(0), UINT64_C(0), SIGN_NONE, PERCENT_NONE, NULL},
      55                 :            : #include "args.h"
      56                 :            : #undef arg
      57                 :            : };
      58                 :            : 
      59                 :            : static struct cmdline_context _cmdline;
      60                 :            : 
      61                 :            : /* Command line args */
      62                 :            : /* FIXME: Move static _the_args into cmd? */
      63                 :         45 : unsigned arg_count(const struct cmd_context *cmd __attribute((unused)), int a)
      64                 :            : {
      65                 :         45 :         return _the_args[a].count;
      66                 :            : }
      67                 :            : 
      68                 :          0 : unsigned arg_is_set(const struct cmd_context *cmd, int a)
      69                 :            : {
      70                 :          0 :         return arg_count(cmd, a) ? 1 : 0;
      71                 :            : }
      72                 :            : 
      73                 :          0 : const char *arg_value(struct cmd_context *cmd __attribute((unused)), int a)
      74                 :            : {
      75                 :          0 :         return _the_args[a].value;
      76                 :            : }
      77                 :            : 
      78                 :          3 : const char *arg_str_value(struct cmd_context *cmd, int a, const char *def)
      79                 :            : {
      80         [ +  + ]:          3 :         return arg_count(cmd, a) ? _the_args[a].value : def;
      81                 :            : }
      82                 :            : 
      83                 :          2 : int32_t arg_int_value(struct cmd_context *cmd, int a, const int32_t def)
      84                 :            : {
      85         [ -  + ]:          2 :         return arg_count(cmd, a) ? _the_args[a].i_value : def;
      86                 :            : }
      87                 :            : 
      88                 :          0 : uint32_t arg_uint_value(struct cmd_context *cmd, int a, const uint32_t def)
      89                 :            : {
      90         [ #  # ]:          0 :         return arg_count(cmd, a) ? _the_args[a].ui_value : def;
      91                 :            : }
      92                 :            : 
      93                 :          0 : int64_t arg_int64_value(struct cmd_context *cmd, int a, const int64_t def)
      94                 :            : {
      95         [ #  # ]:          0 :         return arg_count(cmd, a) ? _the_args[a].i64_value : def;
      96                 :            : }
      97                 :            : 
      98                 :          0 : uint64_t arg_uint64_value(struct cmd_context *cmd, int a, const uint64_t def)
      99                 :            : {
     100         [ #  # ]:          0 :         return arg_count(cmd, a) ? _the_args[a].ui64_value : def;
     101                 :            : }
     102                 :            : 
     103                 :          2 : const void *arg_ptr_value(struct cmd_context *cmd, int a, const void *def)
     104                 :            : {
     105         [ -  + ]:          2 :         return arg_count(cmd, a) ? _the_args[a].ptr : def;
     106                 :            : }
     107                 :            : 
     108                 :          0 : sign_t arg_sign_value(struct cmd_context *cmd, int a, const sign_t def)
     109                 :            : {
     110         [ #  # ]:          0 :         return arg_count(cmd, a) ? _the_args[a].sign : def;
     111                 :            : }
     112                 :            : 
     113                 :          0 : percent_t arg_percent_value(struct cmd_context *cmd, int a, const percent_t def)
     114                 :            : {
     115         [ #  # ]:          0 :         return arg_count(cmd, a) ? _the_args[a].percent : def;
     116                 :            : }
     117                 :            : 
     118                 :          0 : int arg_count_increment(struct cmd_context *cmd __attribute((unused)), int a)
     119                 :            : {
     120                 :          0 :         return _the_args[a].count++;
     121                 :            : }
     122                 :            : 
     123                 :          0 : int yes_no_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
     124                 :            : {
     125                 :          0 :         a->sign = SIGN_NONE;
     126                 :          0 :         a->percent = PERCENT_NONE;
     127                 :            : 
     128         [ #  # ]:          0 :         if (!strcmp(a->value, "y")) {
     129                 :          0 :                 a->i_value = 1;
     130                 :          0 :                 a->ui_value = 1;
     131                 :            :         }
     132                 :            : 
     133         [ #  # ]:          0 :         else if (!strcmp(a->value, "n")) {
     134                 :          0 :                 a->i_value = 0;
     135                 :          0 :                 a->ui_value = 0;
     136                 :            :         }
     137                 :            : 
     138                 :            :         else
     139                 :          0 :                 return 0;
     140                 :            : 
     141                 :          0 :         return 1;
     142                 :            : }
     143                 :            : 
     144                 :          0 : int yes_no_excl_arg(struct cmd_context *cmd __attribute((unused)),
     145                 :            :                     struct arg *a)
     146                 :            : {
     147                 :          0 :         a->sign = SIGN_NONE;
     148                 :          0 :         a->percent = PERCENT_NONE;
     149                 :            : 
     150 [ #  # ][ #  # ]:          0 :         if (!strcmp(a->value, "e") || !strcmp(a->value, "ey") ||
                 [ #  # ]
     151                 :          0 :             !strcmp(a->value, "ye")) {
     152                 :          0 :                 a->i_value = CHANGE_AE;
     153                 :          0 :                 a->ui_value = CHANGE_AE;
     154                 :            :         }
     155                 :            : 
     156         [ #  # ]:          0 :         else if (!strcmp(a->value, "y")) {
     157                 :          0 :                 a->i_value = CHANGE_AY;
     158                 :          0 :                 a->ui_value = CHANGE_AY;
     159                 :            :         }
     160                 :            : 
     161 [ #  # ][ #  # ]:          0 :         else if (!strcmp(a->value, "n") || !strcmp(a->value, "en") ||
                 [ #  # ]
     162                 :          0 :                  !strcmp(a->value, "ne")) {
     163                 :          0 :                 a->i_value = CHANGE_AN;
     164                 :          0 :                 a->ui_value = CHANGE_AN;
     165                 :            :         }
     166                 :            : 
     167 [ #  # ][ #  # ]:          0 :         else if (!strcmp(a->value, "ln") || !strcmp(a->value, "nl")) {
     168                 :          0 :                 a->i_value = CHANGE_ALN;
     169                 :          0 :                 a->ui_value = CHANGE_ALN;
     170                 :            :         }
     171                 :            : 
     172 [ #  # ][ #  # ]:          0 :         else if (!strcmp(a->value, "ly") || !strcmp(a->value, "yl")) {
     173                 :          0 :                 a->i_value = CHANGE_ALY;
     174                 :          0 :                 a->ui_value = CHANGE_ALY;
     175                 :            :         }
     176                 :            : 
     177                 :            :         else
     178                 :          0 :                 return 0;
     179                 :            : 
     180                 :          0 :         return 1;
     181                 :            : }
     182                 :            : 
     183                 :          0 : int metadatatype_arg(struct cmd_context *cmd, struct arg *a)
     184                 :            : {
     185                 :            :         struct format_type *fmt;
     186                 :            :         char *format;
     187                 :            : 
     188                 :          0 :         format = a->value;
     189                 :            : 
     190         [ #  # ]:          0 :         dm_list_iterate_items(fmt, &cmd->formats) {
     191 [ #  # ][ #  # ]:          0 :                 if (!strcasecmp(fmt->name, format) ||
         [ #  # ][ #  # ]
     192                 :          0 :                     !strcasecmp(fmt->name + 3, format) ||
     193                 :          0 :                     (fmt->alias && !strcasecmp(fmt->alias, format))) {
     194                 :          0 :                         a->ptr = fmt;
     195                 :          0 :                         return 1;
     196                 :            :                 }
     197                 :            :         }
     198                 :            : 
     199                 :          0 :         return 0;
     200                 :            : }
     201                 :            : 
     202                 :          0 : static int _get_int_arg(struct arg *a, char **ptr)
     203                 :            : {
     204                 :            :         char *val;
     205                 :            :         long v;
     206                 :            : 
     207                 :          0 :         a->percent = PERCENT_NONE;
     208                 :            : 
     209                 :          0 :         val = a->value;
     210      [ #  #  # ]:          0 :         switch (*val) {
     211                 :            :         case '+':
     212                 :          0 :                 a->sign = SIGN_PLUS;
     213                 :          0 :                 val++;
     214                 :          0 :                 break;
     215                 :            :         case '-':
     216                 :          0 :                 a->sign = SIGN_MINUS;
     217                 :          0 :                 val++;
     218                 :          0 :                 break;
     219                 :            :         default:
     220                 :          0 :                 a->sign = SIGN_NONE;
     221                 :            :         }
     222                 :            : 
     223         [ #  # ]:          0 :         if (!isdigit(*val))
     224                 :          0 :                 return 0;
     225                 :            : 
     226                 :          0 :         v = strtol(val, ptr, 10);
     227                 :            : 
     228         [ #  # ]:          0 :         if (*ptr == val)
     229                 :          0 :                 return 0;
     230                 :            : 
     231                 :          0 :         a->i_value = (int32_t) v;
     232                 :          0 :         a->ui_value = (uint32_t) v;
     233                 :          0 :         a->i64_value = (int64_t) v;
     234                 :          0 :         a->ui64_value = (uint64_t) v;
     235                 :            : 
     236                 :          0 :         return 1;
     237                 :            : }
     238                 :            : 
     239                 :            : /* Size stored in sectors */
     240                 :          0 : static int _size_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a, int factor)
     241                 :            : {
     242                 :            :         char *ptr;
     243                 :            :         int i;
     244                 :            :         static const char *suffixes = "kmgtpebs";
     245                 :            :         char *val;
     246                 :            :         double v;
     247                 :            :         uint64_t v_tmp, adjustment;
     248                 :            : 
     249                 :          0 :         a->percent = PERCENT_NONE;
     250                 :            : 
     251                 :          0 :         val = a->value;
     252      [ #  #  # ]:          0 :         switch (*val) {
     253                 :            :         case '+':
     254                 :          0 :                 a->sign = SIGN_PLUS;
     255                 :          0 :                 val++;
     256                 :          0 :                 break;
     257                 :            :         case '-':
     258                 :          0 :                 a->sign = SIGN_MINUS;
     259                 :          0 :                 val++;
     260                 :          0 :                 break;
     261                 :            :         default:
     262                 :          0 :                 a->sign = SIGN_NONE;
     263                 :            :         }
     264                 :            : 
     265         [ #  # ]:          0 :         if (!isdigit(*val))
     266                 :          0 :                 return 0;
     267                 :            : 
     268                 :          0 :         v = strtod(val, &ptr);
     269                 :            : 
     270         [ #  # ]:          0 :         if (ptr == val)
     271                 :          0 :                 return 0;
     272                 :            : 
     273         [ #  # ]:          0 :         if (*ptr) {
     274         [ #  # ]:          0 :                 for (i = strlen(suffixes) - 1; i >= 0; i--)
     275         [ #  # ]:          0 :                         if (suffixes[i] == tolower((int) *ptr))
     276                 :          0 :                                 break;
     277                 :            : 
     278         [ #  # ]:          0 :                 if (i < 0) {
     279                 :          0 :                         return 0;
     280         [ #  # ]:          0 :                 } else if (i == 7) {
     281                 :            :                         /* sectors */
     282                 :          0 :                         v = v;
     283         [ #  # ]:          0 :                 } else if (i == 6) {
     284                 :            :                         /* bytes */
     285                 :          0 :                         v_tmp = (uint64_t) v;
     286                 :          0 :                         adjustment = v_tmp % 512;
     287         [ #  # ]:          0 :                         if (adjustment) {
     288                 :          0 :                                 v_tmp += (512 - adjustment);
     289                 :          0 :                                 log_error("Size is not a multiple of 512. "
     290                 :            :                                           "Try using %"PRIu64" or %"PRIu64".",
     291                 :            :                                           v_tmp - 512, v_tmp);
     292                 :          0 :                                 return 0;
     293                 :            :                         }
     294                 :          0 :                         v /= 512;
     295                 :            :                 } else {
     296                 :            :                         /* all other units: kmgtpe */
     297         [ #  # ]:          0 :                         while (i-- > 0)
     298                 :          0 :                                 v *= 1024;
     299                 :          0 :                         v *= 2;
     300                 :            :                 }
     301                 :            :         } else
     302                 :          0 :                 v *= factor;
     303                 :            : 
     304                 :          0 :         a->i_value = (int32_t) v;
     305                 :          0 :         a->ui_value = (uint32_t) v;
     306                 :          0 :         a->i64_value = (int64_t) v;
     307                 :          0 :         a->ui64_value = (uint64_t) v;
     308                 :            : 
     309                 :          0 :         return 1;
     310                 :            : }
     311                 :            : 
     312                 :          0 : int size_kb_arg(struct cmd_context *cmd, struct arg *a)
     313                 :            : {
     314                 :          0 :         return _size_arg(cmd, a, 2);
     315                 :            : }
     316                 :            : 
     317                 :          0 : int size_mb_arg(struct cmd_context *cmd, struct arg *a)
     318                 :            : {
     319                 :          0 :         return _size_arg(cmd, a, 2048);
     320                 :            : }
     321                 :            : 
     322                 :          0 : int int_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
     323                 :            : {
     324                 :            :         char *ptr;
     325                 :            : 
     326 [ #  # ][ #  # ]:          0 :         if (!_get_int_arg(a, &ptr) || (*ptr) || (a->sign == SIGN_MINUS))
                 [ #  # ]
     327                 :          0 :                 return 0;
     328                 :            : 
     329                 :          0 :         return 1;
     330                 :            : }
     331                 :            : 
     332                 :          0 : int int_arg_with_sign(struct cmd_context *cmd __attribute((unused)), struct arg *a)
     333                 :            : {
     334                 :            :         char *ptr;
     335                 :            : 
     336 [ #  # ][ #  # ]:          0 :         if (!_get_int_arg(a, &ptr) || (*ptr))
     337                 :          0 :                 return 0;
     338                 :            : 
     339                 :          0 :         return 1;
     340                 :            : }
     341                 :            : 
     342                 :          0 : int int_arg_with_sign_and_percent(struct cmd_context *cmd __attribute((unused)),
     343                 :            :                                   struct arg *a)
     344                 :            : {
     345                 :            :         char *ptr;
     346                 :            : 
     347         [ #  # ]:          0 :         if (!_get_int_arg(a, &ptr))
     348                 :          0 :                 return 0;
     349                 :            : 
     350         [ #  # ]:          0 :         if (!*ptr)
     351                 :          0 :                 return 1;
     352                 :            : 
     353         [ #  # ]:          0 :         if (*ptr++ != '%')
     354                 :          0 :                 return 0;
     355                 :            : 
     356 [ #  # ][ #  # ]:          0 :         if (!strcasecmp(ptr, "V") || !strcasecmp(ptr, "VG"))
     357                 :          0 :                 a->percent = PERCENT_VG;
     358 [ #  # ][ #  # ]:          0 :         else if (!strcasecmp(ptr, "L") || !strcasecmp(ptr, "LV"))
     359                 :          0 :                 a->percent = PERCENT_LV;
     360 [ #  # ][ #  # ]:          0 :         else if (!strcasecmp(ptr, "P") || !strcasecmp(ptr, "PV") ||
                 [ #  # ]
     361                 :          0 :                  !strcasecmp(ptr, "PVS"))
     362                 :          0 :                 a->percent = PERCENT_PVS;
     363 [ #  # ][ #  # ]:          0 :         else if (!strcasecmp(ptr, "F") || !strcasecmp(ptr, "FR") ||
                 [ #  # ]
     364                 :          0 :                  !strcasecmp(ptr, "FREE"))
     365                 :          0 :                 a->percent = PERCENT_FREE;
     366 [ #  # ][ #  # ]:          0 :         else if (!strcasecmp(ptr, "O") || !strcasecmp(ptr, "OR") ||
                 [ #  # ]
     367                 :          0 :                  !strcasecmp(ptr, "ORIGIN"))
     368                 :          0 :                 a->percent = PERCENT_ORIGIN;
     369                 :            :         else
     370                 :          0 :                 return 0;
     371                 :            : 
     372                 :          0 :         return 1;
     373                 :            : }
     374                 :            : 
     375                 :          0 : int minor_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
     376                 :            : {
     377                 :            :         char *ptr;
     378                 :            : 
     379 [ #  # ][ #  # ]:          0 :         if (!_get_int_arg(a, &ptr) || (*ptr) || (a->sign == SIGN_MINUS))
                 [ #  # ]
     380                 :          0 :                 return 0;
     381                 :            : 
     382         [ #  # ]:          0 :         if (a->i_value > 255) {
     383                 :          0 :                 log_error("Minor number outside range 0-255");
     384                 :          0 :                 return 0;
     385                 :            :         }
     386                 :            : 
     387                 :          0 :         return 1;
     388                 :            : }
     389                 :            : 
     390                 :          0 : int major_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
     391                 :            : {
     392                 :            :         char *ptr;
     393                 :            : 
     394 [ #  # ][ #  # ]:          0 :         if (!_get_int_arg(a, &ptr) || (*ptr) || (a->sign == SIGN_MINUS))
                 [ #  # ]
     395                 :          0 :                 return 0;
     396                 :            : 
     397         [ #  # ]:          0 :         if (a->i_value > 255) {
     398                 :          0 :                 log_error("Major number outside range 0-255");
     399                 :          0 :                 return 0;
     400                 :            :         }
     401                 :            : 
     402                 :            :         /* FIXME Also Check against /proc/devices */
     403                 :            : 
     404                 :          0 :         return 1;
     405                 :            : }
     406                 :            : 
     407                 :          1 : int string_arg(struct cmd_context *cmd __attribute((unused)),
     408                 :            :                struct arg *a __attribute((unused)))
     409                 :            : {
     410                 :          1 :         return 1;
     411                 :            : }
     412                 :            : 
     413                 :          0 : int tag_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
     414                 :            : {
     415                 :          0 :         char *pos = a->value;
     416                 :            : 
     417         [ #  # ]:          0 :         if (*pos == '@')
     418                 :          0 :                 pos++;
     419                 :            : 
     420         [ #  # ]:          0 :         if (!validate_name(pos))
     421                 :          0 :                 return 0;
     422                 :            : 
     423                 :          0 :         a->value = pos;
     424                 :            : 
     425                 :          0 :         return 1;
     426                 :            : }
     427                 :            : 
     428                 :          0 : int permission_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
     429                 :            : {
     430                 :          0 :         a->sign = SIGN_NONE;
     431                 :            : 
     432 [ #  # ][ #  # ]:          0 :         if ((!strcmp(a->value, "rw")) || (!strcmp(a->value, "wr")))
     433                 :          0 :                 a->ui_value = LVM_READ | LVM_WRITE;
     434                 :            : 
     435         [ #  # ]:          0 :         else if (!strcmp(a->value, "r"))
     436                 :          0 :                 a->ui_value = LVM_READ;
     437                 :            : 
     438                 :            :         else
     439                 :          0 :                 return 0;
     440                 :            : 
     441                 :          0 :         return 1;
     442                 :            : }
     443                 :            : 
     444                 :          0 : int alloc_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
     445                 :            : {
     446                 :            :         alloc_policy_t alloc;
     447                 :            : 
     448                 :          0 :         a->sign = SIGN_NONE;
     449                 :            : 
     450                 :          0 :         alloc = get_alloc_from_string(a->value);
     451         [ #  # ]:          0 :         if (alloc == ALLOC_INVALID)
     452                 :          0 :                 return 0;
     453                 :            : 
     454                 :          0 :         a->ui_value = (uint32_t) alloc;
     455                 :            : 
     456                 :          0 :         return 1;
     457                 :            : }
     458                 :            : 
     459                 :          0 : int segtype_arg(struct cmd_context *cmd, struct arg *a)
     460                 :            : {
     461         [ #  # ]:          0 :         if (!(a->ptr = (void *) get_segtype_from_string(cmd, a->value)))
     462                 :          0 :                 return 0;
     463                 :            : 
     464                 :          0 :         return 1;
     465                 :            : }
     466                 :            : 
     467                 :            : /*
     468                 :            :  * Positive integer, zero or "auto".
     469                 :            :  */
     470                 :          0 : int readahead_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
     471                 :            : {
     472         [ #  # ]:          0 :         if (!strcasecmp(a->value, "auto")) {
     473                 :          0 :                 a->ui_value = DM_READ_AHEAD_AUTO;
     474                 :          0 :                 return 1;
     475                 :            :         }
     476                 :            : 
     477         [ #  # ]:          0 :         if (!strcasecmp(a->value, "none")) {
     478                 :          0 :                 a->ui_value = DM_READ_AHEAD_NONE;
     479                 :          0 :                 return 1;
     480                 :            :         }
     481                 :            : 
     482         [ #  # ]:          0 :         if (!_size_arg(cmd, a, 1))
     483                 :          0 :                 return 0;
     484                 :            : 
     485         [ #  # ]:          0 :         if (a->sign == SIGN_MINUS)
     486                 :          0 :                 return 0;
     487                 :            : 
     488                 :          0 :         return 1;
     489                 :            : }
     490                 :            : 
     491                 :          0 : int site_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
     492                 :            : {
     493                 :          0 :         char *pos = a->value;
     494         [ #  # ]:          0 :         if (!validate_name(pos))
     495                 :          0 :                 return 0;
     496                 :            : 
     497                 :          0 :         return 1;
     498                 :            : }
     499                 :            : 
     500                 :          2 : static void __alloc(int size)
     501                 :            : {
     502         [ -  + ]:          2 :         if (!(_cmdline.commands = dm_realloc(_cmdline.commands, sizeof(*_cmdline.commands) * size))) {
     503                 :          0 :                 log_fatal("Couldn't allocate memory.");
     504                 :          0 :                 exit(ECMD_FAILED);
     505                 :            :         }
     506                 :            : 
     507                 :          2 :         _cmdline.commands_size = size;
     508                 :          2 : }
     509                 :            : 
     510                 :         48 : static void _alloc_command(void)
     511                 :            : {
     512         [ +  + ]:         48 :         if (!_cmdline.commands_size)
     513                 :          1 :                 __alloc(32);
     514                 :            : 
     515         [ +  + ]:         48 :         if (_cmdline.commands_size <= _cmdline.num_commands)
     516                 :          1 :                 __alloc(2 * _cmdline.commands_size);
     517                 :         48 : }
     518                 :            : 
     519                 :         48 : static void _create_new_command(const char *name, command_fn command,
     520                 :            :                                 unsigned flags,
     521                 :            :                                 const char *desc, const char *usagestr,
     522                 :            :                                 int nargs, int *args)
     523                 :            : {
     524                 :            :         struct command *nc;
     525                 :            : 
     526                 :         48 :         _alloc_command();
     527                 :            : 
     528                 :         48 :         nc = _cmdline.commands + _cmdline.num_commands++;
     529                 :            : 
     530                 :         48 :         nc->name = name;
     531                 :         48 :         nc->desc = desc;
     532                 :         48 :         nc->usage = usagestr;
     533                 :         48 :         nc->fn = command;
     534                 :         48 :         nc->flags = flags;
     535                 :         48 :         nc->num_args = nargs;
     536                 :         48 :         nc->valid_args = args;
     537                 :         48 : }
     538                 :            : 
     539                 :         48 : static void _register_command(const char *name, command_fn fn, const char *desc,
     540                 :            :                               unsigned flags, const char *usagestr, ...)
     541                 :            : {
     542                 :         48 :         int nargs = 0, i;
     543                 :            :         int *args;
     544                 :            :         va_list ap;
     545                 :            : 
     546                 :            :         /* count how many arguments we have */
     547                 :         48 :         va_start(ap, usagestr);
     548         [ +  + ]:        799 :         while (va_arg(ap, int) >= 0)
     549                 :        751 :                  nargs++;
     550                 :         48 :         va_end(ap);
     551                 :            : 
     552                 :            :         /* allocate space for them */
     553         [ -  + ]:         48 :         if (!(args = dm_malloc(sizeof(*args) * nargs))) {
     554                 :          0 :                 log_fatal("Out of memory.");
     555                 :          0 :                 exit(ECMD_FAILED);
     556                 :            :         }
     557                 :            : 
     558                 :            :         /* fill them in */
     559                 :         48 :         va_start(ap, usagestr);
     560         [ +  + ]:        799 :         for (i = 0; i < nargs; i++)
     561                 :        751 :                 args[i] = va_arg(ap, int);
     562                 :         48 :         va_end(ap);
     563                 :            : 
     564                 :            :         /* enter the command in the register */
     565                 :         48 :         _create_new_command(name, fn, flags, desc, usagestr, nargs, args);
     566                 :         48 : }
     567                 :            : 
     568                 :          1 : void lvm_register_commands(void)
     569                 :            : {
     570                 :            : #define xx(a, b, c, d...) _register_command(# a, a, b, c, ## d, \
     571                 :            :                                             driverloaded_ARG, \
     572                 :            :                                             debug_ARG, help_ARG, help2_ARG, \
     573                 :            :                                             version_ARG, verbose_ARG, \
     574                 :            :                                             quiet_ARG, config_ARG, -1);
     575                 :            : #include "commands.h"
     576                 :            : #undef xx
     577                 :          1 : }
     578                 :            : 
     579                 :          1 : static struct command *_find_command(const char *name)
     580                 :            : {
     581                 :            :         int i;
     582                 :            :         const char *base;
     583                 :            : 
     584                 :          1 :         base = last_path_component(name);
     585                 :            : 
     586         [ +  - ]:         27 :         for (i = 0; i < _cmdline.num_commands; i++) {
     587         [ +  + ]:         27 :                 if (!strcmp(base, _cmdline.commands[i].name))
     588                 :          1 :                         break;
     589                 :            :         }
     590                 :            : 
     591         [ -  + ]:          1 :         if (i >= _cmdline.num_commands)
     592                 :          0 :                 return 0;
     593                 :            : 
     594                 :          1 :         return _cmdline.commands + i;
     595                 :            : }
     596                 :            : 
     597                 :          0 : static void _short_usage(const char *name)
     598                 :            : {
     599                 :          0 :         log_error("Run `%s --help' for more information.", name);
     600                 :          0 : }
     601                 :            : 
     602                 :          0 : static int _usage(const char *name)
     603                 :            : {
     604                 :          0 :         struct command *com = _find_command(name);
     605                 :            : 
     606         [ #  # ]:          0 :         if (!com) {
     607                 :          0 :                 log_print("%s: no such command.", name);
     608                 :          0 :                 return 0;
     609                 :            :         }
     610                 :            : 
     611                 :          0 :         log_print("%s: %s\n\n%s", com->name, com->desc, com->usage);
     612                 :          0 :         return 1;
     613                 :            : }
     614                 :            : 
     615                 :            : /*
     616                 :            :  * Sets up the short and long argument.  If there
     617                 :            :  * is no short argument then the index of the
     618                 :            :  * argument in the the_args array is set as the
     619                 :            :  * long opt value.  Yuck.  Of course this means we
     620                 :            :  * can't have more than 'a' long arguments.
     621                 :            :  */
     622                 :         25 : static void _add_getopt_arg(int arg, char **ptr, struct option **o)
     623                 :            : {
     624                 :         25 :         struct arg *a = _cmdline.the_args + arg;
     625                 :            : 
     626         [ +  + ]:         25 :         if (a->short_arg) {
     627                 :          8 :                 *(*ptr)++ = a->short_arg;
     628                 :            : 
     629         [ +  + ]:          8 :                 if (a->fn)
     630                 :          2 :                         *(*ptr)++ = ':';
     631                 :            :         }
     632                 :            : #ifdef HAVE_GETOPTLONG
     633         [ +  + ]:         25 :         if (*(a->long_arg + 2)) {
     634                 :         24 :                 (*o)->name = a->long_arg + 2;
     635                 :         24 :                 (*o)->has_arg = a->fn ? 1 : 0;
     636                 :         24 :                 (*o)->flag = NULL;
     637         [ +  + ]:         24 :                 if (a->short_arg)
     638                 :          7 :                         (*o)->val = a->short_arg;
     639                 :            :                 else
     640                 :         17 :                         (*o)->val = arg;
     641                 :         24 :                 (*o)++;
     642                 :            :         }
     643                 :            : #endif
     644                 :         25 : }
     645                 :            : 
     646                 :          1 : static struct arg *_find_arg(struct command *com, int opt)
     647                 :            : {
     648                 :            :         struct arg *a;
     649                 :            :         int i, arg;
     650                 :            : 
     651         [ +  - ]:         25 :         for (i = 0; i < com->num_args; i++) {
     652                 :         25 :                 arg = com->valid_args[i];
     653                 :         25 :                 a = _cmdline.the_args + arg;
     654                 :            : 
     655                 :            :                 /*
     656                 :            :                  * opt should equal either the
     657                 :            :                  * short arg, or the index into
     658                 :            :                  * the_args.
     659                 :            :                  */
     660 [ +  + ][ +  - ]:         25 :                 if ((a->short_arg && (opt == a->short_arg)) ||
         [ +  + ][ +  + ]
     661                 :         25 :                     (!a->short_arg && (opt == arg)))
     662                 :          1 :                         return a;
     663                 :            :         }
     664                 :            : 
     665                 :          1 :         return 0;
     666                 :            : }
     667                 :            : 
     668                 :          1 : static int _process_command_line(struct cmd_context *cmd, int *argc,
     669                 :            :                                  char ***argv)
     670                 :            : {
     671                 :            :         int i, opt;
     672                 :          1 :         char str[((ARG_COUNT + 1) * 2) + 1], *ptr = str;
     673                 :          1 :         struct option opts[ARG_COUNT + 1], *o = opts;
     674                 :            :         struct arg *a;
     675                 :            : 
     676         [ +  + ]:        129 :         for (i = 0; i < ARG_COUNT; i++) {
     677                 :        128 :                 a = _cmdline.the_args + i;
     678                 :            : 
     679                 :            :                 /* zero the count and arg */
     680                 :        128 :                 a->count = 0;
     681                 :        128 :                 a->value = 0;
     682                 :        128 :                 a->i_value = 0;
     683                 :        128 :                 a->ui_value = 0;
     684                 :        128 :                 a->i64_value = 0;
     685                 :        128 :                 a->ui64_value = 0;
     686                 :            :         }
     687                 :            : 
     688                 :            :         /* fill in the short and long opts */
     689         [ +  + ]:         26 :         for (i = 0; i < cmd->command->num_args; i++)
     690                 :         25 :                 _add_getopt_arg(cmd->command->valid_args[i], &ptr, &o);
     691                 :            : 
     692                 :          1 :         *ptr = '\0';
     693                 :          1 :         memset(o, 0, sizeof(*o));
     694                 :            : 
     695                 :            :         /* initialise getopt_long & scan for command line switches */
     696                 :          1 :         optarg = 0;
     697                 :          1 :         optind = OPTIND_INIT;
     698         [ +  + ]:          2 :         while ((opt = GETOPTLONG_FN(*argc, *argv, str, opts, NULL)) >= 0) {
     699                 :            : 
     700         [ -  + ]:          1 :                 if (opt == '?')
     701                 :          0 :                         return 0;
     702                 :            : 
     703                 :          1 :                 a = _find_arg(cmd->command, opt);
     704                 :            : 
     705         [ -  + ]:          1 :                 if (!a) {
     706                 :          0 :                         log_fatal("Unrecognised option.");
     707                 :          0 :                         return 0;
     708                 :            :                 }
     709                 :            : 
     710 [ -  + ][ #  # ]:          1 :                 if (a->count && !(a->flags & ARG_REPEATABLE)) {
     711 [ #  # ][ #  # ]:          0 :                         log_error("Option%s%c%s%s may not be repeated",
         [ #  # ][ #  # ]
                 [ #  # ]
     712                 :            :                                   a->short_arg ? " -" : "",
     713                 :            :                                   a->short_arg ? : ' ',
     714                 :            :                                   (a->short_arg && a->long_arg) ?
     715                 :            :                                   "/" : "", a->long_arg ? : "");
     716                 :          0 :                         return 0;
     717                 :            :                 }
     718                 :            : 
     719         [ +  - ]:          1 :                 if (a->fn) {
     720         [ -  + ]:          1 :                         if (!optarg) {
     721                 :          0 :                                 log_error("Option requires argument.");
     722                 :          0 :                                 return 0;
     723                 :            :                         }
     724                 :            : 
     725                 :          1 :                         a->value = optarg;
     726                 :            : 
     727         [ -  + ]:          1 :                         if (!a->fn(cmd, a)) {
     728                 :          0 :                                 log_error("Invalid argument %s", optarg);
     729                 :          0 :                                 return 0;
     730                 :            :                         }
     731                 :            :                 }
     732                 :            : 
     733                 :          1 :                 a->count++;
     734                 :            :         }
     735                 :            : 
     736                 :          1 :         *argc -= optind;
     737                 :          1 :         *argv += optind;
     738                 :          1 :         return 1;
     739                 :            : }
     740                 :            : 
     741                 :          5 : static int _merge_synonym(struct cmd_context *cmd, int oldarg, int newarg)
     742                 :            : {
     743                 :            :         const struct arg *old;
     744                 :            :         struct arg *new;
     745                 :            : 
     746 [ -  + ][ #  # ]:          5 :         if (arg_count(cmd, oldarg) && arg_count(cmd, newarg)) {
     747                 :          0 :                 log_error("%s and %s are synonyms.  Please only supply one.",
     748                 :            :                           _cmdline.the_args[oldarg].long_arg, _cmdline.the_args[newarg].long_arg);
     749                 :          0 :                 return 0;
     750                 :            :         }
     751                 :            : 
     752         [ +  - ]:          5 :         if (!arg_count(cmd, oldarg))
     753                 :          5 :                 return 1;
     754                 :            : 
     755                 :          0 :         old = _cmdline.the_args + oldarg;
     756                 :          0 :         new = _cmdline.the_args + newarg;
     757                 :            : 
     758                 :          0 :         new->count = old->count;
     759                 :          0 :         new->value = old->value;
     760                 :          0 :         new->i_value = old->i_value;
     761                 :          0 :         new->ui_value = old->ui_value;
     762                 :          0 :         new->i64_value = old->i64_value;
     763                 :          0 :         new->ui64_value = old->ui64_value;
     764                 :          0 :         new->sign = old->sign;
     765                 :            : 
     766                 :          5 :         return 1;
     767                 :            : }
     768                 :            : 
     769                 :          0 : int version(struct cmd_context *cmd __attribute((unused)),
     770                 :            :             int argc __attribute((unused)),
     771                 :            :             char **argv __attribute((unused)))
     772                 :            : {
     773                 :            :         char vsn[80];
     774                 :            : 
     775                 :          0 :         log_print("LVM version:     %s", LVM_VERSION);
     776         [ #  # ]:          0 :         if (library_version(vsn, sizeof(vsn)))
     777                 :          0 :                 log_print("Library version: %s", vsn);
     778         [ #  # ]:          0 :         if (driver_version(vsn, sizeof(vsn)))
     779                 :          0 :                 log_print("Driver version:  %s", vsn);
     780                 :            : 
     781                 :          0 :         return ECMD_PROCESSED;
     782                 :            : }
     783                 :            : 
     784                 :          1 : static int _get_settings(struct cmd_context *cmd)
     785                 :            : {
     786                 :          1 :         cmd->current_settings = cmd->default_settings;
     787                 :            : 
     788         [ -  + ]:          1 :         if (arg_count(cmd, debug_ARG))
     789                 :          0 :                 cmd->current_settings.debug = _LOG_FATAL +
     790                 :            :                     (arg_count(cmd, debug_ARG) - 1);
     791                 :            : 
     792         [ -  + ]:          1 :         if (arg_count(cmd, verbose_ARG))
     793                 :          0 :                 cmd->current_settings.verbose = arg_count(cmd, verbose_ARG);
     794                 :            : 
     795         [ -  + ]:          1 :         if (arg_count(cmd, quiet_ARG)) {
     796                 :          0 :                 cmd->current_settings.debug = 0;
     797                 :          0 :                 cmd->current_settings.verbose = 0;
     798                 :            :         }
     799                 :            : 
     800         [ -  + ]:          1 :         if (arg_count(cmd, test_ARG))
     801                 :          0 :                 cmd->current_settings.test = arg_count(cmd, test_ARG);
     802                 :            : 
     803         [ -  + ]:          1 :         if (arg_count(cmd, driverloaded_ARG)) {
     804                 :          0 :                 cmd->current_settings.activation =
     805                 :          0 :                     arg_int_value(cmd, driverloaded_ARG,
     806                 :            :                                   cmd->default_settings.activation);
     807                 :            :         }
     808                 :            : 
     809                 :          1 :         cmd->current_settings.archive = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.archive);
     810                 :          1 :         cmd->current_settings.backup = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.backup);
     811                 :          1 :         cmd->current_settings.cache_vgmetadata = cmd->command->flags & CACHE_VGMETADATA ? 1 : 0;
     812                 :          1 :         cmd->partial_activation = 0;
     813                 :            : 
     814         [ -  + ]:          1 :         if (arg_count(cmd, partial_ARG)) {
     815                 :          0 :                 cmd->partial_activation = 1;
     816                 :          0 :                 log_print("Partial mode. Incomplete volume groups will "
     817                 :            :                           "be activated read-only.");
     818                 :            :         }
     819                 :            : 
     820         [ -  + ]:          1 :         if (arg_count(cmd, ignorelockingfailure_ARG))
     821                 :          0 :                 init_ignorelockingfailure(1);
     822                 :            :         else
     823                 :          1 :                 init_ignorelockingfailure(0);
     824                 :            : 
     825         [ -  + ]:          1 :         if (arg_count(cmd, nosuffix_ARG))
     826                 :          0 :                 cmd->current_settings.suffix = 0;
     827                 :            : 
     828         [ -  + ]:          1 :         if (arg_count(cmd, units_ARG))
     829         [ #  # ]:          0 :                 if (!(cmd->current_settings.unit_factor =
     830                 :          0 :                       units_to_bytes(arg_str_value(cmd, units_ARG, ""),
     831                 :            :                                      &cmd->current_settings.unit_type))) {
     832                 :          0 :                         log_error("Invalid units specification");
     833                 :          0 :                         return EINVALID_CMD_LINE;
     834                 :            :                 }
     835                 :            : 
     836         [ -  + ]:          1 :         if (arg_count(cmd, trustcache_ARG)) {
     837         [ #  # ]:          0 :                 if (arg_count(cmd, all_ARG)) {
     838                 :          0 :                         log_error("--trustcache is incompatible with --all");
     839                 :          0 :                         return EINVALID_CMD_LINE;
     840                 :            :                 }
     841                 :          0 :                 init_trust_cache(1);
     842                 :          0 :                 log_warn("WARNING: Cache file of PVs will be trusted.  "
     843                 :            :                           "New devices holding PVs may get ignored.");
     844                 :            :         } else
     845                 :          1 :                 init_trust_cache(0);
     846                 :            : 
     847         [ -  + ]:          1 :         if (arg_count(cmd, noudevsync_ARG))
     848                 :          0 :                 cmd->current_settings.udev_sync = 0;
     849                 :            : 
     850                 :            :         /* Handle synonyms */
     851 [ +  -  +  -  + :          5 :         if (!_merge_synonym(cmd, resizable_ARG, resizeable_ARG) ||
          -  +  -  -  + ]
     852                 :          1 :             !_merge_synonym(cmd, allocation_ARG, allocatable_ARG) ||
     853                 :          1 :             !_merge_synonym(cmd, allocation_ARG, resizeable_ARG) ||
     854                 :          1 :             !_merge_synonym(cmd, virtualoriginsize_ARG, virtualsize_ARG) ||
     855                 :          1 :             !_merge_synonym(cmd, metadatacopies_ARG, pvmetadatacopies_ARG))
     856                 :          0 :                 return EINVALID_CMD_LINE;
     857                 :            : 
     858                 :            :         /* Zero indicates success */
     859                 :          1 :         return 0;
     860                 :            : }
     861                 :            : 
     862                 :          1 : static int _process_common_commands(struct cmd_context *cmd)
     863                 :            : {
     864 [ +  - ][ -  + ]:          1 :         if (arg_count(cmd, help_ARG) || arg_count(cmd, help2_ARG)) {
     865                 :          0 :                 _usage(cmd->command->name);
     866                 :          0 :                 return ECMD_PROCESSED;
     867                 :            :         }
     868                 :            : 
     869         [ -  + ]:          1 :         if (arg_count(cmd, version_ARG)) {
     870                 :          0 :                 return version(cmd, 0, (char **) NULL);
     871                 :            :         }
     872                 :            : 
     873                 :            :         /* Zero indicates it's OK to continue processing this command */
     874                 :          1 :         return 0;
     875                 :            : }
     876                 :            : 
     877                 :          0 : static void _display_help(void)
     878                 :            : {
     879                 :            :         int i;
     880                 :            : 
     881                 :          0 :         log_error("Available lvm commands:");
     882                 :          0 :         log_error("Use 'lvm help <command>' for more information");
     883                 :          0 :         log_error(" ");
     884                 :            : 
     885         [ #  # ]:          0 :         for (i = 0; i < _cmdline.num_commands; i++) {
     886                 :          0 :                 struct command *com = _cmdline.commands + i;
     887                 :            : 
     888                 :          0 :                 log_error("%-16.16s%s", com->name, com->desc);
     889                 :            :         }
     890                 :          0 : }
     891                 :            : 
     892                 :          0 : int help(struct cmd_context *cmd __attribute((unused)), int argc, char **argv)
     893                 :            : {
     894                 :          0 :         int ret = ECMD_PROCESSED;
     895                 :            : 
     896         [ #  # ]:          0 :         if (!argc)
     897                 :          0 :                 _display_help();
     898                 :            :         else {
     899                 :            :                 int i;
     900         [ #  # ]:          0 :                 for (i = 0; i < argc; i++)
     901         [ #  # ]:          0 :                         if (!_usage(argv[i]))
     902                 :          0 :                                 ret = EINVALID_CMD_LINE;
     903                 :            :         }
     904                 :            : 
     905                 :          0 :         return ret;
     906                 :            : }
     907                 :            : 
     908                 :          2 : static void _apply_settings(struct cmd_context *cmd)
     909                 :            : {
     910                 :          2 :         init_debug(cmd->current_settings.debug);
     911                 :          2 :         init_verbose(cmd->current_settings.verbose + VERBOSE_BASE_LEVEL);
     912                 :          2 :         init_test(cmd->current_settings.test);
     913                 :          2 :         init_full_scan_done(0);
     914                 :          2 :         init_mirror_in_sync(0);
     915                 :            : 
     916                 :          2 :         init_msg_prefix(cmd->default_settings.msg_prefix);
     917                 :          2 :         init_cmd_name(cmd->default_settings.cmd_name);
     918                 :            : 
     919                 :          2 :         archive_enable(cmd, cmd->current_settings.archive);
     920                 :          2 :         backup_enable(cmd, cmd->current_settings.backup);
     921                 :            : 
     922                 :          2 :         set_activation(cmd->current_settings.activation);
     923                 :            : 
     924                 :          2 :         cmd->fmt = arg_ptr_value(cmd, metadatatype_ARG,
     925                 :          2 :                                  cmd->current_settings.fmt);
     926                 :          2 :         cmd->handles_missing_pvs = 0;
     927                 :          2 : }
     928                 :            : 
     929                 :          1 : static int _set_udev_checking(struct cmd_context *cmd)
     930                 :            : {
     931                 :            : #ifdef UDEV_SYNC_SUPPORT
     932                 :            :         struct udev *udev;
     933                 :            :         const char *udev_dev_dir;
     934                 :            :         size_t udev_dev_dir_len;
     935                 :            :         int dirs_diff;
     936                 :            : 
     937   [ +  -  +  - ]:          2 :         if (!(udev = udev_new()) ||
                 [ -  + ]
     938                 :          1 :             !(udev_dev_dir = udev_get_dev_path(udev)) ||
     939                 :          1 :             !*udev_dev_dir) {
     940                 :          0 :                 log_error("Could not get udev dev path.");
     941                 :          0 :                 return 0;
     942                 :            :         }
     943                 :          1 :         udev_dev_dir_len = strlen(udev_dev_dir);
     944                 :            : 
     945                 :            :         /* There's always a slash at the end of dev_dir. But check udev_dev_dir! */
     946         [ +  - ]:          1 :         if (udev_dev_dir[udev_dev_dir_len - 1] != '/')
     947                 :          1 :                 dirs_diff = strncmp(cmd->dev_dir, udev_dev_dir,
     948                 :            :                                     udev_dev_dir_len);
     949                 :            :         else
     950                 :          0 :                 dirs_diff = strcmp(cmd->dev_dir, udev_dev_dir);
     951                 :            : 
     952         [ -  + ]:          1 :         if (dirs_diff) {
     953                 :          0 :                 log_debug("The path %s used for creating device nodes and "
     954                 :            :                           "symlinks that is set in the configuration differs "
     955                 :            :                           "from the path %s that is used by udev. All warnings "
     956                 :            :                           "about udev not working correctly while processing "
     957                 :            :                           "particular nodes and symlinks will be suppressed. "
     958                 :            :                           "These nodes and symlinks will be managed in each "
     959                 :            :                           "directory separately.",
     960                 :            :                            cmd->dev_dir, udev_dev_dir);
     961                 :          0 :                 dm_udev_set_checking(0);
     962                 :          0 :                 init_udev_checking(0);
     963                 :            :         }
     964                 :            : 
     965                 :          1 :         udev_unref(udev);
     966                 :            : #endif
     967                 :          1 :         return 1;
     968                 :            : }
     969                 :            : 
     970                 :          1 : static const char *_copy_command_line(struct cmd_context *cmd, int argc, char **argv)
     971                 :            : {
     972                 :            :         int i, space;
     973                 :            : 
     974                 :            :         /*
     975                 :            :          * Build up the complete command line, used as a
     976                 :            :          * description for backups.
     977                 :            :          */
     978         [ -  + ]:          1 :         if (!dm_pool_begin_object(cmd->mem, 128))
     979                 :          0 :                 goto_bad;
     980                 :            : 
     981         [ +  + ]:          4 :         for (i = 0; i < argc; i++) {
     982                 :          3 :                 space = strchr(argv[i], ' ') ? 1 : 0;
     983                 :            : 
     984 [ +  + ][ -  + ]:          3 :                 if (space && !dm_pool_grow_object(cmd->mem, "'", 1))
     985                 :          0 :                         goto_bad;
     986                 :            : 
     987         [ -  + ]:          3 :                 if (!dm_pool_grow_object(cmd->mem, argv[i], strlen(argv[i])))
     988                 :          0 :                         goto_bad;
     989                 :            : 
     990 [ +  + ][ -  + ]:          3 :                 if (space && !dm_pool_grow_object(cmd->mem, "'", 1))
     991                 :          0 :                         goto_bad;
     992                 :            : 
     993         [ +  + ]:          3 :                 if (i < (argc - 1))
     994         [ -  + ]:          2 :                         if (!dm_pool_grow_object(cmd->mem, " ", 1))
     995                 :          0 :                                 goto_bad;
     996                 :            :         }
     997                 :            : 
     998                 :            :         /*
     999                 :            :          * Terminate.
    1000                 :            :          */
    1001         [ -  + ]:          1 :         if (!dm_pool_grow_object(cmd->mem, "\0", 1))
    1002                 :          0 :                 goto_bad;
    1003                 :            : 
    1004                 :          1 :         return dm_pool_end_object(cmd->mem);
    1005                 :            : 
    1006                 :            :       bad:
    1007                 :          0 :         log_error("Couldn't copy command line.");
    1008                 :          0 :         dm_pool_abandon_object(cmd->mem);
    1009                 :          1 :         return NULL;
    1010                 :            : }
    1011                 :            : 
    1012                 :          1 : int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
    1013                 :            : {
    1014                 :          1 :         int ret = 0;
    1015                 :            :         int locking_type;
    1016                 :            : 
    1017                 :          1 :         init_error_message_produced(0);
    1018                 :            : 
    1019                 :            :         /* each command should start out with sigint flag cleared */
    1020                 :          1 :         sigint_clear();
    1021                 :            : 
    1022         [ -  + ]:          1 :         if (!(cmd->cmd_line = _copy_command_line(cmd, argc, argv))) {
    1023                 :          0 :                 stack;
    1024                 :          0 :                 return ECMD_FAILED;
    1025                 :            :         }
    1026                 :            : 
    1027                 :          1 :         log_debug("Parsing: %s", cmd->cmd_line);
    1028                 :            : 
    1029         [ -  + ]:          1 :         if (!(cmd->command = _find_command(argv[0])))
    1030                 :          0 :                 return ENO_SUCH_CMD;
    1031                 :            : 
    1032         [ -  + ]:          1 :         if (!_process_command_line(cmd, &argc, &argv)) {
    1033                 :          0 :                 log_error("Error during parsing of command line.");
    1034                 :          0 :                 return EINVALID_CMD_LINE;
    1035                 :            :         }
    1036                 :            : 
    1037                 :          1 :         set_cmd_name(cmd->command->name);
    1038                 :            : 
    1039         [ +  - ]:          1 :         if (arg_count(cmd, config_ARG))
    1040         [ -  + ]:          1 :                 if ((ret = override_config_tree_from_string(cmd,
    1041                 :            :                              arg_str_value(cmd, config_ARG, "")))) {
    1042                 :          0 :                         ret = EINVALID_CMD_LINE;
    1043                 :          0 :                         goto_out;
    1044                 :            :                 }
    1045                 :            : 
    1046 [ -  + ][ #  # ]:          1 :         if (arg_count(cmd, config_ARG) || !cmd->config_valid || config_files_changed(cmd)) {
                 [ #  # ]
    1047                 :            :                 /* Reinitialise various settings inc. logging, filters */
    1048         [ -  + ]:          1 :                 if (!refresh_toolcontext(cmd)) {
    1049                 :          0 :                         log_error("Updated config file invalid. Aborting.");
    1050                 :          0 :                         return ECMD_FAILED;
    1051                 :            :                 }
    1052                 :            :         }
    1053                 :            : 
    1054         [ -  + ]:          1 :         if ((ret = _get_settings(cmd)))
    1055                 :          0 :                 goto_out;
    1056                 :          1 :         _apply_settings(cmd);
    1057                 :            : 
    1058                 :          1 :         log_debug("Processing: %s", cmd->cmd_line);
    1059                 :            : 
    1060                 :            : #ifdef O_DIRECT_SUPPORT
    1061                 :          1 :         log_debug("O_DIRECT will be used");
    1062                 :            : #endif
    1063                 :            : 
    1064         [ -  + ]:          1 :         if (!_set_udev_checking(cmd))
    1065                 :          0 :                 goto_out;
    1066                 :            : 
    1067         [ -  + ]:          1 :         if ((ret = _process_common_commands(cmd)))
    1068                 :          0 :                 goto_out;
    1069                 :            : 
    1070         [ -  + ]:          1 :         if (arg_count(cmd, nolocking_ARG))
    1071                 :          0 :                 locking_type = 0;
    1072                 :            :         else
    1073                 :          1 :                 locking_type = -1;
    1074                 :            : 
    1075         [ -  + ]:          1 :         if (!init_locking(locking_type, cmd)) {
    1076                 :          0 :                 ret = ECMD_FAILED;
    1077                 :          0 :                 goto out;
    1078                 :            :         }
    1079                 :            : 
    1080                 :          1 :         ret = cmd->command->fn(cmd, argc, argv);
    1081                 :            : 
    1082                 :          1 :         fin_locking();
    1083                 :            : 
    1084                 :            :       out:
    1085         [ -  + ]:          1 :         if (test_mode()) {
    1086                 :          0 :                 log_verbose("Test mode: Wiping internal cache");
    1087                 :          0 :                 lvmcache_destroy(cmd, 1);
    1088                 :            :         }
    1089                 :            : 
    1090         [ +  - ]:          1 :         if (cmd->cft_override) {
    1091                 :          1 :                 destroy_config_tree(cmd->cft_override);
    1092                 :          1 :                 cmd->cft_override = NULL;
    1093                 :            :                 /* Move this? */
    1094         [ -  + ]:          1 :                 if (!refresh_toolcontext(cmd))
    1095                 :          0 :                         stack;
    1096                 :            :         }
    1097                 :            : 
    1098                 :            :         /* FIXME Move this? */
    1099                 :          1 :         cmd->current_settings = cmd->default_settings;
    1100                 :          1 :         _apply_settings(cmd);
    1101                 :            : 
    1102   [ -  +  #  # ]:          1 :         if (ret == EINVALID_CMD_LINE && !_cmdline.interactive)
    1103                 :          0 :                 _short_usage(cmd->command->name);
    1104                 :            : 
    1105                 :          1 :         log_debug("Completed: %s", cmd->cmd_line);
    1106                 :            : 
    1107                 :            :         /*
    1108                 :            :          * free off any memory the command used.
    1109                 :            :          */
    1110                 :          1 :         dm_pool_empty(cmd->mem);
    1111                 :            : 
    1112                 :          1 :         reset_lvm_errno(1);
    1113                 :            : 
    1114                 :          1 :         return ret;
    1115                 :            : }
    1116                 :            : 
    1117                 :          1 : int lvm_return_code(int ret)
    1118                 :            : {
    1119         [ -  + ]:          1 :         return (ret == ECMD_PROCESSED ? 0 : ret);
    1120                 :            : }
    1121                 :            : 
    1122                 :          0 : int lvm_split(char *str, int *argc, char **argv, int max)
    1123                 :            : {
    1124                 :          0 :         char *b = str, *e;
    1125                 :          0 :         *argc = 0;
    1126                 :            : 
    1127         [ #  # ]:          0 :         while (*b) {
    1128 [ #  # ][ #  # ]:          0 :                 while (*b && isspace(*b))
    1129                 :          0 :                         b++;
    1130                 :            : 
    1131 [ #  # ][ #  # ]:          0 :                 if ((!*b) || (*b == '#'))
    1132                 :            :                         break;
    1133                 :            : 
    1134                 :          0 :                 e = b;
    1135 [ #  # ][ #  # ]:          0 :                 while (*e && !isspace(*e))
    1136                 :          0 :                         e++;
    1137                 :            : 
    1138                 :          0 :                 argv[(*argc)++] = b;
    1139         [ #  # ]:          0 :                 if (!*e)
    1140                 :          0 :                         break;
    1141                 :          0 :                 *e++ = '\0';
    1142                 :          0 :                 b = e;
    1143         [ #  # ]:          0 :                 if (*argc == max)
    1144                 :          0 :                         break;
    1145                 :            :         }
    1146                 :            : 
    1147                 :          0 :         return *argc;
    1148                 :            : }
    1149                 :            : 
    1150                 :          1 : static const char *_get_cmdline(pid_t pid)
    1151                 :            : {
    1152                 :            :         static char _proc_cmdline[32];
    1153                 :            :         char buf[256];
    1154                 :            :         int fd;
    1155                 :            : 
    1156                 :          1 :         snprintf(buf, sizeof(buf), DEFAULT_PROC_DIR "/%u/cmdline", pid);
    1157         [ +  - ]:          1 :         if ((fd = open(buf, O_RDONLY)) > 0) {
    1158                 :          1 :                 read(fd, _proc_cmdline, sizeof(_proc_cmdline) - 1);
    1159                 :          1 :                 _proc_cmdline[sizeof(_proc_cmdline) - 1] = '\0';
    1160                 :          1 :                 close(fd);
    1161                 :            :         } else
    1162                 :          0 :                 _proc_cmdline[0] = '\0';
    1163                 :            : 
    1164                 :          1 :         return _proc_cmdline;
    1165                 :            : }
    1166                 :            : 
    1167                 :          0 : static const char *_get_filename(int fd)
    1168                 :            : {
    1169                 :            :         static char filename[PATH_MAX];
    1170                 :            :         char buf[32];   /* Assumes short DEFAULT_PROC_DIR */
    1171                 :            :         int size;
    1172                 :            : 
    1173                 :          0 :         snprintf(buf, sizeof(buf), DEFAULT_PROC_DIR "/self/fd/%u", fd);
    1174                 :            : 
    1175         [ #  # ]:          0 :         if ((size = readlink(buf, filename, sizeof(filename) - 1)) == -1)
    1176                 :          0 :                 filename[0] = '\0';
    1177                 :            :         else
    1178                 :          0 :                 filename[size] = '\0';
    1179                 :            : 
    1180                 :          0 :         return filename;
    1181                 :            : }
    1182                 :            : 
    1183                 :       1021 : static void _close_descriptor(int fd, unsigned suppress_warnings,
    1184                 :            :                               const char *command, pid_t ppid,
    1185                 :            :                               const char *parent_cmdline)
    1186                 :            : {
    1187                 :            :         int r;
    1188                 :            :         const char *filename;
    1189                 :            : 
    1190                 :            :         /* Ignore bad file descriptors */
    1191 [ +  - ][ +  - ]:       1021 :         if (fcntl(fd, F_GETFD) == -1 && errno == EBADF)
    1192                 :       1021 :                 return;
    1193                 :            : 
    1194         [ #  # ]:          0 :         if (!suppress_warnings)
    1195                 :          0 :                 filename = _get_filename(fd);
    1196                 :            : 
    1197                 :          0 :         r = close(fd);
    1198         [ #  # ]:          0 :         if (suppress_warnings)
    1199                 :          0 :                 return;
    1200                 :            : 
    1201         [ #  # ]:          0 :         if (!r)
    1202                 :          0 :                 fprintf(stderr, "File descriptor %d (%s) leaked on "
    1203                 :            :                         "%s invocation.", fd, filename, command);
    1204         [ #  # ]:          0 :         else if (errno == EBADF)
    1205                 :          0 :                 return;
    1206                 :            :         else
    1207                 :          0 :                 fprintf(stderr, "Close failed on stray file descriptor "
    1208                 :            :                         "%d (%s): %s", fd, filename, strerror(errno));
    1209                 :            : 
    1210                 :       1021 :         fprintf(stderr, " Parent PID %" PRIpid_t ": %s\n", ppid, parent_cmdline);
    1211                 :            : }
    1212                 :            : 
    1213                 :          1 : static void _close_stray_fds(const char *command)
    1214                 :            : {
    1215                 :            :         struct rlimit rlim;
    1216                 :            :         int fd;
    1217                 :          1 :         unsigned suppress_warnings = 0;
    1218                 :          1 :         pid_t ppid = getppid();
    1219                 :          1 :         const char *parent_cmdline = _get_cmdline(ppid);
    1220                 :            : 
    1221         [ -  + ]:          1 :         if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
    1222                 :          0 :                 fprintf(stderr, "getrlimit(RLIMIT_NOFILE) failed: %s\n",
    1223                 :            :                         strerror(errno));
    1224                 :          0 :                 return;
    1225                 :            :         }
    1226                 :            : 
    1227         [ -  + ]:          1 :         if (getenv("LVM_SUPPRESS_FD_WARNINGS"))
    1228                 :          0 :                 suppress_warnings = 1;
    1229                 :            : 
    1230         [ +  + ]:       1022 :         for (fd = 3; fd < rlim.rlim_cur; fd++)
    1231                 :       1021 :                 _close_descriptor(fd, suppress_warnings, command, ppid,
    1232                 :            :                                   parent_cmdline);
    1233                 :            : }
    1234                 :            : 
    1235                 :          1 : struct cmd_context *init_lvm(void)
    1236                 :            : {
    1237                 :            :         struct cmd_context *cmd;
    1238                 :            : 
    1239                 :          1 :         _cmdline.the_args = &_the_args[0];
    1240                 :            : 
    1241         [ -  + ]:          1 :         if (!(cmd = create_toolcontext(0, NULL)))
    1242                 :          0 :                 return_NULL;
    1243                 :            : 
    1244         [ -  + ]:          1 :         if (stored_errno()) {
    1245                 :          0 :                 destroy_toolcontext(cmd);
    1246                 :          0 :                 return_NULL;
    1247                 :            :         }
    1248                 :            : 
    1249                 :          1 :         return cmd;
    1250                 :            : }
    1251                 :            : 
    1252                 :          1 : static void _fin_commands(void)
    1253                 :            : {
    1254                 :            :         int i;
    1255                 :            : 
    1256         [ +  + ]:         49 :         for (i = 0; i < _cmdline.num_commands; i++)
    1257                 :         48 :                 dm_free(_cmdline.commands[i].valid_args);
    1258                 :            : 
    1259                 :          1 :         dm_free(_cmdline.commands);
    1260                 :            : 
    1261                 :          1 :         _cmdline.commands = NULL;
    1262                 :          1 :         _cmdline.num_commands = 0;
    1263                 :          1 :         _cmdline.commands_size = 0;
    1264                 :          1 : }
    1265                 :            : 
    1266                 :          1 : void lvm_fin(struct cmd_context *cmd)
    1267                 :            : {
    1268                 :          1 :         _fin_commands();
    1269                 :          1 :         destroy_toolcontext(cmd);
    1270                 :          1 : }
    1271                 :            : 
    1272                 :          0 : static int _run_script(struct cmd_context *cmd, int argc, char **argv)
    1273                 :            : {
    1274                 :            :         FILE *script;
    1275                 :            : 
    1276                 :            :         char buffer[CMD_LEN];
    1277                 :          0 :         int ret = 0;
    1278                 :          0 :         int magic_number = 0;
    1279                 :          0 :         char *script_file = argv[0];
    1280                 :            : 
    1281         [ #  # ]:          0 :         if ((script = fopen(script_file, "r")) == NULL)
    1282                 :          0 :                 return ENO_SUCH_CMD;
    1283                 :            : 
    1284         [ #  # ]:          0 :         while (fgets(buffer, sizeof(buffer), script) != NULL) {
    1285         [ #  # ]:          0 :                 if (!magic_number) {
    1286 [ #  # ][ #  # ]:          0 :                         if (buffer[0] == '#' && buffer[1] == '!')
    1287                 :          0 :                                 magic_number = 1;
    1288                 :            :                         else {
    1289                 :          0 :                                 ret = ENO_SUCH_CMD;
    1290                 :          0 :                                 break;
    1291                 :            :                         }
    1292                 :            :                 }
    1293 [ #  # ][ #  # ]:          0 :                 if ((strlen(buffer) == sizeof(buffer) - 1)
    1294                 :          0 :                     && (buffer[sizeof(buffer) - 1] - 2 != '\n')) {
    1295                 :          0 :                         buffer[50] = '\0';
    1296                 :          0 :                         log_error("Line too long (max 255) beginning: %s",
    1297                 :            :                                   buffer);
    1298                 :          0 :                         ret = EINVALID_CMD_LINE;
    1299                 :          0 :                         break;
    1300                 :            :                 }
    1301         [ #  # ]:          0 :                 if (lvm_split(buffer, &argc, argv, MAX_ARGS) == MAX_ARGS) {
    1302                 :          0 :                         buffer[50] = '\0';
    1303                 :          0 :                         log_error("Too many arguments: %s", buffer);
    1304                 :          0 :                         ret = EINVALID_CMD_LINE;
    1305                 :          0 :                         break;
    1306                 :            :                 }
    1307         [ #  # ]:          0 :                 if (!argc)
    1308                 :          0 :                         continue;
    1309 [ #  # ][ #  # ]:          0 :                 if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit"))
    1310                 :            :                         break;
    1311                 :          0 :                 ret = lvm_run_command(cmd, argc, argv);
    1312         [ #  # ]:          0 :                 if (ret != ECMD_PROCESSED) {
    1313         [ #  # ]:          0 :                         if (!error_message_produced()) {
    1314                 :          0 :                                 log_debug(INTERNAL_ERROR "Failed command did not use log_error");
    1315                 :          0 :                                 log_error("Command failed with status code %d.", ret);
    1316                 :            :                         }
    1317                 :          0 :                         break;
    1318                 :            :                 }
    1319                 :            :         }
    1320                 :            : 
    1321         [ #  # ]:          0 :         if (fclose(script))
    1322                 :          0 :                 log_sys_error("fclose", script_file);
    1323                 :            : 
    1324                 :          0 :         return ret;
    1325                 :            : }
    1326                 :            : 
    1327                 :            : /*
    1328                 :            :  * Determine whether we should fall back and exec the equivalent LVM1 tool
    1329                 :            :  */
    1330                 :          1 : static int _lvm1_fallback(struct cmd_context *cmd)
    1331                 :            : {
    1332                 :            :         char vsn[80];
    1333                 :            :         int dm_present;
    1334                 :            : 
    1335 [ -  + ][ #  # ]:          1 :         if (!find_config_tree_int(cmd, "global/fallback_to_lvm1",
    1336                 :            :                              DEFAULT_FALLBACK_TO_LVM1) ||
    1337                 :          0 :             strncmp(cmd->kernel_vsn, "2.4.", 4))
    1338                 :          1 :                 return 0;
    1339                 :            : 
    1340                 :          0 :         log_suppress(1);
    1341                 :          0 :         dm_present = driver_version(vsn, sizeof(vsn));
    1342                 :          0 :         log_suppress(0);
    1343                 :            : 
    1344   [ #  #  #  # ]:          0 :         if (dm_present || !lvm1_present(cmd))
    1345                 :          0 :                 return 0;
    1346                 :            : 
    1347                 :          1 :         return 1;
    1348                 :            : }
    1349                 :            : 
    1350                 :          0 : static void _exec_lvm1_command(char **argv)
    1351                 :            : {
    1352                 :            :         char path[PATH_MAX];
    1353                 :            : 
    1354         [ #  # ]:          0 :         if (dm_snprintf(path, sizeof(path), "%s.lvm1", argv[0]) < 0) {
    1355                 :          0 :                 log_error("Failed to create LVM1 tool pathname");
    1356                 :          0 :                 return;
    1357                 :            :         }
    1358                 :            : 
    1359                 :          0 :         execvp(path, argv);
    1360                 :          0 :         log_sys_error("execvp", path);
    1361                 :            : }
    1362                 :            : 
    1363                 :          1 : static void _nonroot_warning(void)
    1364                 :            : {
    1365 [ +  - ][ -  + ]:          1 :         if (getuid() || geteuid())
    1366                 :          0 :                 log_warn("WARNING: Running as a non-root user. Functionality may be unavailable.");
    1367                 :          1 : }
    1368                 :            : 
    1369                 :          1 : int lvm2_main(int argc, char **argv)
    1370                 :            : {
    1371                 :            :         const char *base;
    1372                 :          1 :         int ret, alias = 0;
    1373                 :            :         struct cmd_context *cmd;
    1374                 :            : 
    1375                 :          1 :         base = last_path_component(argv[0]);
    1376   [ -  +  #  # ]:          1 :         if (strcmp(base, "lvm") && strcmp(base, "lvm.static") &&
                 [ #  # ]
    1377                 :          0 :             strcmp(base, "initrd-lvm"))
    1378                 :          0 :                 alias = 1;
    1379                 :            : 
    1380                 :          1 :         _close_stray_fds(base);
    1381                 :            : 
    1382 [ -  +  #  #  # :          1 :         if (is_static() && strcmp(base, "lvm.static") &&
                #  #  # ]
    1383                 :          0 :             path_exists(LVM_SHARED_PATH) &&
    1384                 :          0 :             !getenv("LVM_DID_EXEC")) {
    1385                 :          0 :                 setenv("LVM_DID_EXEC", base, 1);
    1386                 :          0 :                 execvp(LVM_SHARED_PATH, argv);
    1387                 :          0 :                 unsetenv("LVM_DID_EXEC");
    1388                 :            :         }
    1389                 :            : 
    1390         [ -  + ]:          1 :         if (!(cmd = init_lvm()))
    1391                 :          0 :                 return -1;
    1392                 :            : 
    1393                 :          1 :         cmd->argv = argv;
    1394                 :          1 :         lvm_register_commands();
    1395                 :            : 
    1396         [ -  + ]:          1 :         if (_lvm1_fallback(cmd)) {
    1397                 :            :                 /* Attempt to run equivalent LVM1 tool instead */
    1398         [ #  # ]:          0 :                 if (!alias) {
    1399                 :          0 :                         argv++;
    1400                 :          0 :                         argc--;
    1401                 :          0 :                         alias = 0;
    1402                 :            :                 }
    1403         [ #  # ]:          0 :                 if (!argc) {
    1404                 :          0 :                         log_error("Falling back to LVM1 tools, but no "
    1405                 :            :                                   "command specified.");
    1406                 :          0 :                         return ECMD_FAILED;
    1407                 :            :                 }
    1408                 :          0 :                 _exec_lvm1_command(argv);
    1409                 :          0 :                 return ECMD_FAILED;
    1410                 :            :         }
    1411                 :            : #ifdef READLINE_SUPPORT
    1412 [ +  - ][ -  + ]:          1 :         if (!alias && argc == 1) {
    1413                 :          0 :                 _nonroot_warning();
    1414                 :          0 :                 ret = lvm_shell(cmd, &_cmdline);
    1415                 :          0 :                 goto out;
    1416                 :            :         }
    1417                 :            : #endif
    1418                 :            : 
    1419         [ +  - ]:          1 :         if (!alias) {
    1420         [ -  + ]:          1 :                 if (argc < 2) {
    1421                 :          0 :                         log_fatal("Please supply an LVM command.");
    1422                 :          0 :                         _display_help();
    1423                 :          0 :                         ret = EINVALID_CMD_LINE;
    1424                 :          0 :                         goto out;
    1425                 :            :                 }
    1426                 :            : 
    1427                 :          1 :                 argc--;
    1428                 :          1 :                 argv++;
    1429                 :            :         }
    1430                 :            : 
    1431                 :          1 :         _nonroot_warning();
    1432                 :          1 :         ret = lvm_run_command(cmd, argc, argv);
    1433   [ -  +  #  # ]:          1 :         if ((ret == ENO_SUCH_CMD) && (!alias))
    1434                 :          0 :                 ret = _run_script(cmd, argc, argv);
    1435         [ -  + ]:          1 :         if (ret == ENO_SUCH_CMD)
    1436                 :          0 :                 log_error("No such command.  Try 'help'.");
    1437                 :            : 
    1438 [ -  + ][ #  # ]:          1 :         if ((ret != ECMD_PROCESSED) && !error_message_produced()) {
    1439                 :          0 :                 log_debug(INTERNAL_ERROR "Failed command did not use log_error");
    1440                 :          0 :                 log_error("Command failed with status code %d.", ret);
    1441                 :            :         }
    1442                 :            : 
    1443                 :            :       out:
    1444                 :          1 :         lvm_fin(cmd);
    1445                 :          1 :         return lvm_return_code(ret);
    1446                 :            : }

Generated by: LCOV version 1.8