LCOV - code coverage report
Current view: top level - src - parse_arguments.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 89.8 % 225 202
Test Date: 2026-01-12 05:34:38 Functions: 100.0 % 2 2

            Line data    Source code
       1              : #include "precizer.h"
       2              : #include <sysexits.h>
       3              : 
       4              : #ifdef TESTITALL
       5              : static bool missing_arguments = false;
       6              : #endif
       7              : 
       8              : /**
       9              :  *
      10              :  * @brief Parse arguments with argp lib
      11              :  *
      12              :  */
      13              : 
      14              : const char *argp_program_version = APP_NAME " " APP_VERSION;
      15              : 
      16              : /* Program documentation. */
      17              : static char doc[] =
      18              :         "\n" APP_NAME " " APP_VERSION " — verify file checksums at scale\n\n"
      19              :         BOLD APP_NAME RESET " is a lightweight and blazing-fast CLI application designed for file integrity verification and comparison, making it particularly useful for checking synchronization results. The program recursively traverses directories, generating a database of files and their checksums for quick and efficient comparisons.\n"
      20              :         "\n"
      21              :         "Built for both embedded platforms and large-scale clustered mainframes, " BOLD APP_NAME RESET " helps detect synchronization errors by comparing files and their checksums across different sources. It can also be used to analyze historical changes by comparing databases generated at different points in time from the same source.\n"
      22              :         "\n"
      23              :         "Glory to Ukraine!\n"
      24              :         "\vSIMPLE EXAMPLE\n"
      25              :         "\n"
      26              :         "Consider two hosts with large disks containing identical content mounted at /mnt1 and /mnt2 respectively. The task is to verify content identity and identify any differences.\n"
      27              :         "\n"
      28              :         "1. Run the program on the first machine with host name, for example “host1”:\n"
      29              :         "\n"
      30              :         APP_NAME " --progress /mnt1\n"
      31              :         "\n"
      32              :         "The program recursively traverses all directories starting from /mnt1 and the host1.db database will be created in the current directory. The --progress option visualizes progress and will show the amount of space and the number of files being examined.\n"
      33              :         "\n"
      34              :         "2. Run the program on a second machine with a host name, for example host2:\n"
      35              :         "\n"
      36              :         APP_NAME " --progress /mnt2\n"
      37              :         "\n"
      38              :         "As a result, the host2.db database will be created in the current directory.\n"
      39              :         "\n"
      40              :         "3. Transfer the host1.db and host2.db files to either machine and run the program with the appropriate parameters to compare the databases:\n"
      41              :         "\n"
      42              :         APP_NAME " --compare host1.db host2.db\n"
      43              :         "\n"
      44              :         "The following information will be displayed on the screen:\n"
      45              :         "\n"
      46              :         "* Which files are missing on “host1” but present on “host2” and vice versa.\n"
      47              :         "* For which files, present on both hosts, the checksums do NOT match.\n"
      48              :         "\n"
      49              :         "Note that " APP_NAME " writes only relative paths to the database. The example file “/mnt1/abc/def/aaa.txt” will be written to the database as “abc/def/aaa.txt” without /mnt1. The same thing will happen with the file “/mnt2/abc/def/aaa.txt”. Despite different mount points and different sources the files can be compared with each other under the same names “abc/def/aaa.txt” with the corresponding checksums.\n"
      50              :         "\n"
      51              :         "All other technical details could be found in README file of the project";
      52              : 
      53              : /* A description of the arguments we accept. */
      54              : static char args_doc[] = "PATH";
      55              : 
      56              : /* The options we understand. */
      57              : static struct argp_option options[] = {
      58              :         { 0,0,0,0,"Build database options:",2},
      59              :         {"lock-checksum",'k',"PCRE2_REGEXP",0,"Relative path to be treated as immutable archival data. PCRE2 regular expressions can be used to "
      60              :          "select files or directories whose checksums are written once to the database and never updated "
      61              :          "again. If no matching files exist in the database yet, their entries and checksums will still be "
      62              :          "created normally when they are scanned for the first time. All paths for the regular expression "
      63              :          "must be specified as relative, the same way as for the "
      64              :          BOLD "--ignore" RESET " option. For these entries, the "
      65              :          BOLD "--update" RESET " option will not recalculate checksums; any difference in file size, timestamps, or content will "
      66              :          "always be reported as data corruption instead of a reason to generate a new checksum. Multiple "
      67              :          "regular expressions can be specified using multiple "
      68              :          BOLD "--lock-checksum" RESET " options.\n"
      69              :          "Example:\n"
      70              :          BOLD APP_NAME " --update --lock-checksum=\"^archive/2077/.*\" /mnt/storage" RESET "\n",0},
      71              :         {"rehash-locked",'h',0,0,"Force a full SHA512 rehash for every file that is already stored "
      72              :          "in the database and protected by any "
      73              :          BOLD "--lock-checksum" RESET " pattern. "
      74              :          "This option must always be used together with "
      75              :          BOLD "--lock-checksum" RESET "; it has no effect otherwise. During an update pass, "
      76              :          "every locked entry found on disk is read again, its checksum is recomputed, and the "
      77              :          "result is compared with the value stored in the database. This provides an extra "
      78              :          "validation layer for immutable archives at the cost of additional I/O and CPU time, "
      79              :          "ensuring that frozen records are validated even when file size or timestamps alone are "
      80              :          "not sufficient indicators. "
      81              :          "The option purposefully ignores "
      82              :          BOLD "--watch-timestamps" RESET " — timestamp tracking can be on or off, the rehash will "
      83              :          "still take place. If the recomputed checksum and file size match the database entry, "
      84              :          "the record stays consistent but differing ctime/mtime values in the database are "
      85              :          "synchronized with the on-disk timestamps. If the checksum differs, the file is "
      86              :          "reported as corrupted just like any other locked entry.\n"
      87              :          "Example:\n"
      88              :          BOLD APP_NAME " --update --lock-checksum=\"^archive/2024/.*\" --rehash-locked /mnt/storage" RESET "\n",0},
      89              :         {"ignore",'e',"PCRE2_REGEXP",0,"Relative path to ignore. PCRE2 regular expressions could be used to specify "
      90              :          "a pattern to ignore files or directories. Attention! All paths for the regular expression must be specified as relative. To understand what a relative path looks like, just run traverses without the "
      91              :          BOLD "--ignore" RESET " option and look how the terminal will display "
      92              :          "relative paths that are written to the database.\n"
      93              :          "Example:\n"
      94              :          BOLD APP_NAME " --ignore=\"^diff2/1/.*\" tests/examples/diffs" RESET "\n"
      95              :          "In this example, the starting path for the traversing "
      96              :          "is ./tests/examples/diffs and the relative path to ignore will "
      97              :          "be ./tests/examples/diffs/diff2/1/ and all subdirectories (/.*).\n"
      98              :          "Multiple regular expressions for ignore could be specified using many "
      99              :          BOLD "--ignore" RESET " options at once.\n"
     100              :          "Example:\n"
     101              :          BOLD APP_NAME " --ignore=\"diff2/1/.*\" --ignore=\"diff2/2/.*\" tests/examples/diffs" RESET "\n",0 },
     102              :         {"include",'i',"PCRE2_REGEXP",0,"Relative path to be included. PCRE2 regular expressions. Include these relative paths even if they were excluded via the " BOLD "--ignore" RESET " option. Multiple regular expressions could be specified.\n",0 },
     103              :         {"db-clean-ignored",'C',0,0,"The database is protected from accidental changes by default. The option " BOLD "--db-clean-ignored" RESET " must be specified additionally in order to remove from the database mention of files that matches the regular expression passed through the " BOLD "--ignore=PCRE2_REGEXP" RESET " option(s).\n",0},
     104              :         {"watch-timestamps",'T',0,0,"Consider file metadata changes (creation and modification timestamps) in addition to file size when detecting changes. By default, only file size changes trigger rescanning. When this option is enabled, any changes to file timestamps or size will cause the file to be rescanned and its checksum updated in the primary database.\n",0},
     105              :         {"maxdepth",'m',"NUMBER",0,"Recursion depth limit. The depth of the traversal, numbered from 0 to N, where a file could be found. Representing the maximum of the starting point (from root) of the traversal. The root itself is numbered 0. " BOLD "--maxdepth=0" RESET " completely disable recursion.\n",0},
     106              :         {"dry-run",'n',0,0,"Perform a trial run with no changes made. The option will not affect " BOLD "--compare" RESET "\n",0},
     107              :         {"start-device-only",'o',0,0,"This option prevents directory traversal from descending into directories that have a different device number than the file from which the descent began.\n",0 },
     108              :         {"force",'f',0,0,"Use this option only in case when the PATHs that were written into the database as a result of the last scanning really need to be renewed. Warning! If this option will be used in incorrect way, information about files and their checksums against the database would be lost.\n",0},
     109              :         {"update",'u',0,0,"Updates the database to reflect file system changes (new, modified and deleted files). Must be used with the same initial PATH that was used when creating the database, as existing records will be replaced with data from the specified location. This option modifies database consistency. Use with caution, especially in automated scripts, as incorrect usage may lead to loss of file checksums and metadata.\n",0 },
     110              :         {"database",'d',"FILE",0,"Database filename. Defaults to ${HOST}.db, where HOST is the local hostname.\n",0 },
     111              :         {"check-level",'l',"FULL|QUICK",0,"Select database validation level: 'quick' for basic structure check, 'full' (default) for comprehensive integrity verification.\n",0 },
     112              :         { 0,0,0,0,"Compare databases options:",1},
     113              :         {"compare",'c',0,0,"Compare two databases from different sources. Requires two additional arguments specifying paths to database files, e.g.:\n" BOLD APP_NAME " --compare database1.db database2.db" RESET "\n",0 },
     114              :         { 0,0,0,0,"Visualizations options:\n",-1},
     115              :         {"silent",'s',0,0,"Don't produce any output. The option will not affect " BOLD "--compare" RESET,0 },
     116              :         {"verbose",'v',0,0,"Produce verbose output.",0 },
     117              :         {"progress",'p',0,0,"Enabling this option displays progress information but requires an initial count of files and the space they occupy to estimate execution time. The program first traverses all specified directories, counting files, folders, and symlinks before proceeding with file analysis. This initial traversal may take a significant amount of time. It is strongly recommended not to use this option when calling the program from a script.",0 },
     118              :         {0}
     119              : };
     120              : 
     121              : /* Parse a single option. */
     122         1460 : static error_t parse_opt(
     123              :         int               key,
     124              :         char              *arg,
     125              :         struct argp_state *state)
     126              : {
     127         1460 :         char *ptr = NULL;
     128         1460 :         long int argument_value = -1;
     129              : 
     130         1460 :         switch(key)
     131              :         {
     132          148 :                 case 'd':
     133              :                         // Full path to DB file
     134          148 :                         config->db_primary_file_path = strdup(arg);
     135              : 
     136          148 :                         if(config->db_primary_file_path == NULL)
     137              :                         {
     138            0 :                                 argp_failure(state,1,0,"ERROR: Memory allocation for db_file_path failed!");
     139            0 :                                 exit(ARGP_ERR_UNKNOWN);
     140              :                         }
     141              : 
     142              :                         // Name of DB file only
     143          148 :                         config->db_file_name = strdup(basename(arg));
     144              : 
     145          148 :                         if(config->db_file_name == NULL)
     146              :                         {
     147            0 :                                 free(config->db_primary_file_path);  // Free previously allocated memory
     148            0 :                                 config->db_primary_file_path = NULL; // Set to NULL after freeing
     149            0 :                                 argp_failure(state,1,0,"ERROR: Memory allocation for db_file_name failed!");
     150            0 :                                 exit(ARGP_ERR_UNKNOWN);
     151              :                         }
     152          148 :                         break;
     153           22 :                 case 'e':
     154           22 :                         (void)add_string_to_array(&config->ignore,arg);
     155           22 :                         break;
     156           10 :                 case 'n':
     157           10 :                         config->dry_run = true;
     158           10 :                         break;
     159            4 :                 case 'i':
     160            4 :                         (void)add_string_to_array(&config->include,arg);
     161            4 :                         break;
     162           28 :                 case 'k':
     163           28 :                         (void)add_string_to_array(&config->lock_checksum,arg);
     164           28 :                         break;
     165            4 :                 case 'h':
     166            4 :                         config->rehash_locked = true;
     167            4 :                         break;
     168           36 :                 case 'c':
     169           36 :                         config->compare = true;
     170           36 :                         break;
     171            2 :                 case 'o':
     172            2 :                         config->start_device_only = true;
     173            2 :                         break;
     174           12 :                 case 'C':
     175           12 :                         config->db_clean_ignored = true;
     176           12 :                         break;
     177            4 :                 case 'm':
     178            4 :                         argument_value = strtol(arg,&ptr,10);
     179              : 
     180              :                         // Validate if lont int could be casted to short int
     181              :                         // and the argument contains a digit only
     182            4 :                         if(argument_value >= 0 && argument_value <= 32767 && *ptr == '\0')
     183              :                         {
     184            4 :                                 config->maxdepth = (short int)argument_value;
     185              :                         } else {
     186            0 :                                 argp_failure(state,1,0,"ERROR: Wrong --maxdepth (-m) value. Should be an integer from 0 to 32767. See --help for more information");
     187            0 :                                 exit(ARGP_ERR_UNKNOWN);
     188              :                         }
     189            4 :                         break;
     190           40 :                 case 'p':
     191           40 :                         config->progress = true;
     192           40 :                         break;
     193           16 :                 case 'T':
     194           16 :                         config->watch_timestamps = true;
     195           16 :                         break;
     196           88 :                 case 'u':
     197           88 :                         config->update = true;
     198           88 :                         break;
     199            2 :                 case 'f':
     200            2 :                         config->force = true;
     201            2 :                         break;
     202            2 :                 case 'l':
     203              : 
     204            2 :                         if(0 == strncasecmp(arg,"QUICK",sizeof("QUICK")))
     205              :                         {
     206            2 :                                 config->db_check_level = QUICK;
     207            0 :                         } else if(0 == strncasecmp(arg,"FULL",sizeof("FULL"))){
     208            0 :                                 config->db_check_level = FULL;
     209              :                         } else {
     210            0 :                                 return(ARGP_ERR_UNKNOWN);
     211              :                         }
     212            2 :                         break;
     213           22 :                 case 's':
     214              :                         // Global variable
     215           22 :                         rational_logger_mode = SILENT;
     216           22 :                         break;
     217            4 :                 case 'v':
     218              :                         // Global variable
     219            4 :                         rational_logger_mode = VERBOSE;
     220            4 :                         config->verbose = true;
     221            4 :                         break;
     222            2 :                 case ARGP_KEY_NO_ARGS:
     223              : #ifdef TESTITALL
     224            1 :                         missing_arguments = true;
     225            1 :                         state->flags |= ARGP_NO_EXIT;
     226            1 :                         argp_usage(state);
     227            1 :                         return(EX_USAGE);
     228              : #else
     229            1 :                         argp_usage(state);
     230              : #endif
     231            0 :                         break;
     232          202 :                 case ARGP_KEY_ARG:
     233          202 :                         config->paths = &state->argv[state->next - 1];
     234          202 :                         state->next = state->argc;
     235          202 :                         break;
     236          202 :                 case ARGP_KEY_END:
     237              : 
     238          202 :                         if(config->compare == true)
     239              :                         {
     240           36 :                                 if(state->arg_num < 2)
     241              :                                 {
     242            0 :                                         argp_failure(state,1,0,"ERROR: Too few arguments\n--compare require two arguments with paths to database files. See --help for more information");
     243           36 :                                 } else if(state->arg_num > 2){
     244            0 :                                         argp_failure(state,1,0,"ERROR: Too many arguments\n--compare require just two arguments with paths to database files. See --help for more information");
     245              :                                 }
     246          166 :                         } else if(state->arg_num > 1){
     247            0 :                                 slog(TRACE,"Caution: multiple PATH arguments received. Multipath mode activated. It’s important to note that when comparison mode is enabled, the ORDER of the paths must be identical for the database comparison to work correctly. Number of paths: %d\n",state->arg_num);
     248              :                         }
     249          202 :                         break;
     250          610 :                 default:
     251          610 :                         return(ARGP_ERR_UNKNOWN);
     252              :         }
     253              : 
     254          848 :         return(0);
     255              : }
     256              : 
     257              : /* Our argp parser. */
     258              : static struct argp argp = {
     259              :         options,parse_opt,args_doc,doc,0,0,0
     260              : };
     261              : 
     262          204 : Return parse_arguments(
     263              :         const int argc,
     264              :         char      *argv[])
     265              : {
     266              :         /// The status that will be passed to return() before exiting.
     267              :         /// By default, the function worked without errors.
     268          204 :         Return status = SUCCESS;
     269              : 
     270              : #ifdef TESTITALL
     271          102 :         missing_arguments = false;
     272              : #endif
     273              : 
     274              :         /* Parse our arguments; every option seen by parse_opt will be
     275              :            reflected in arguments. */
     276          204 :         argp_parse(&argp,argc,argv,
     277              : 
     278              : #ifdef TESTITALL
     279              :         ARGP_NO_EXIT,
     280              : #else
     281              :         0,
     282              : #endif
     283              :         0,0);
     284              : 
     285              : #ifdef TESTITALL
     286          102 :         if(true == missing_arguments)
     287              :         {
     288            1 :                 status = (Return)EX_USAGE;
     289              :         }
     290              : #endif
     291              : 
     292          203 :         if(config->paths != NULL)
     293              :         {
     294          440 :                 for(int i = 0; config->paths[i]; i++)
     295              :                 {
     296              :                         // Remove unnecessary trailing slash at the end of the directory path
     297          238 :                         remove_trailing_slash(config->paths[i]);
     298              :                 }
     299              :         }
     300              : 
     301          203 :         if(config->compare == true)
     302              :         {
     303           36 :                 if(config->paths != NULL)
     304              :                 {
     305              :                         // The array with database names
     306           36 :                         config->db_file_paths = config->paths;
     307              : 
     308          108 :                         for(int i = 0; config->db_file_paths[i] && (SUCCESS == status); i++)
     309              :                         {
     310              :                                 // Create a copy of the path string for basename
     311           72 :                                 char *tmp = strdup(config->db_file_paths[i]);
     312              : 
     313           72 :                                 if(tmp == NULL)
     314              :                                 {
     315            0 :                                         report("Failed to duplicate string: %s",config->db_file_paths[i]);
     316            0 :                                         status = FAILURE;
     317            0 :                                         break;
     318              :                                 }
     319              : 
     320              :                                 // Get basename and handle possible NULL return
     321           72 :                                 const char *db_file_basename = basename(tmp);
     322              : 
     323           72 :                                 if(db_file_basename == NULL)
     324              :                                 {
     325            0 :                                         report("basename failed for path: %s",tmp);
     326            0 :                                         free(tmp);
     327            0 :                                         status = FAILURE;
     328            0 :                                         break;
     329              :                                 }
     330              : 
     331           72 :                                 status = add_string_to_array(&config->db_file_names,db_file_basename);
     332           72 :                                 free(tmp);
     333              : 
     334           72 :                                 if(SUCCESS != status)
     335              :                                 {
     336            0 :                                         break;
     337              :                                 }
     338              :                         }
     339              :                 }
     340              :         }
     341              : 
     342          203 :         if(SUCCESS != status)
     343              :         {
     344            1 :                 provide(status);
     345              :         }
     346              : 
     347              :         /* Testing mode */
     348              :         {
     349          202 :                 slog(TESTING,"rational_logger_mode=%s\n",rational_reconvert(rational_logger_mode));
     350              : 
     351          202 :                 if(config->paths != NULL)
     352              :                 {
     353          202 :                         slog(TESTING,"argument:paths=");
     354              : 
     355          440 :                         for(int i = 0; config->paths[i]; i++)
     356              :                         {
     357          238 :                                 slog(TESTING|UNDECOR,i == 0 ? "%s" : ", %s",config->paths[i]);
     358              :                         }
     359          202 :                         slog(TESTING|UNDECOR,"\n");
     360              :                 }
     361              : 
     362          202 :                 if(config->db_primary_file_path != NULL)
     363              :                 {
     364          148 :                         slog(TESTING,"argument:database=%s\n",config->db_primary_file_path);
     365              :                 }
     366              : 
     367          202 :                 if(config->db_file_name != NULL)
     368              :                 {
     369          148 :                         slog(TESTING,"argument:db_file_name=%s\n",config->db_file_name);
     370              :                 }
     371              : 
     372          202 :                 if(config->db_file_paths != NULL)
     373              :                 {
     374           36 :                         slog(TESTING,"argument:db_file_paths=");
     375              : 
     376          108 :                         for(int i = 0; config->db_file_paths[i]; i++)
     377              :                         {
     378           72 :                                 slog(TESTING|UNDECOR,i == 0 ? "%s" : ", %s",config->db_file_paths[i]);
     379              :                         }
     380           36 :                         slog(TESTING|UNDECOR,"\n");
     381              :                 }
     382              : 
     383          202 :                 if(config->db_file_names != NULL)
     384              :                 {
     385           36 :                         slog(TESTING,"argument:db_file_names=");
     386              : 
     387          108 :                         for(int i = 0; config->db_file_names[i]; i++)
     388              :                         {
     389           72 :                                 slog(TESTING|UNDECOR,i == 0 ? "%s" : ", %s",config->db_file_names[i]);
     390              :                         }
     391           36 :                         slog(TESTING|UNDECOR,"\n");
     392              :                 }
     393              : 
     394          202 :                 if(config->ignore != NULL)
     395              :                 {
     396           18 :                         slog(TESTING,"argument:ignore=");
     397              : 
     398              :                         // Print the contents of the string array
     399           40 :                         for(int i = 0; config->ignore[i] != NULL; ++i)
     400              :                         {
     401           22 :                                 slog(TESTING|UNDECOR,i == 0 ? "%s" : ", %s",config->ignore[i]);
     402              :                         }
     403           18 :                         slog(TESTING|UNDECOR,"\n");
     404              :                 }
     405              : 
     406          202 :                 if(config->include != NULL)
     407              :                 {
     408            2 :                         slog(TESTING,"argument:include=");
     409              : 
     410              :                         // Print the contents of the string array
     411            6 :                         for(int i = 0; config->include[i] != NULL; ++i)
     412              :                         {
     413            4 :                                 slog(TESTING|UNDECOR,i == 0 ? "%s" : ", %s",config->include[i]);
     414              :                         }
     415            2 :                         slog(TESTING|UNDECOR,"\n");
     416              :                 }
     417              : 
     418          202 :                 if(config->lock_checksum != NULL)
     419              :                 {
     420           22 :                         slog(TESTING,"argument:lock-checksum=");
     421              : 
     422              :                         // Print the contents of the string array
     423           50 :                         for(int i = 0; config->lock_checksum[i] != NULL; ++i)
     424              :                         {
     425           28 :                                 slog(TESTING|UNDECOR,i == 0 ? "%s" : ", %s",config->lock_checksum[i]);
     426              :                         }
     427           22 :                         slog(TESTING|UNDECOR,"\n");
     428              :                 }
     429              : 
     430          202 :                 if(config->db_check_level != FULL)
     431              :                 {
     432            2 :                         slog(TESTING,"argument:check-level=%s\n",config->db_check_level == QUICK ? "QUICK" : "FULL");
     433              :                 }
     434              : 
     435          202 :                 if(config->maxdepth > 0)
     436              :                 {
     437            2 :                         slog(TESTING,"argument:maxdepth=%d\n",config->maxdepth);
     438              :                 }
     439              : 
     440          202 :                 if(config->verbose)
     441              :                 {
     442            4 :                         slog(TESTING,"argument:verbose=%s\n",config->verbose ? "yes" : "no");
     443              :                 }
     444              : 
     445          202 :                 if(config->watch_timestamps)
     446              :                 {
     447           16 :                         slog(TESTING,"argument:watch-timestamps=%s\n",config->watch_timestamps ? "yes" : "no");
     448              :                 }
     449              : 
     450          202 :                 if(config->rehash_locked == true)
     451              :                 {
     452            4 :                         slog(TESTING,"argument:rehash-locked=%s\n",config->rehash_locked ? "yes" : "no");
     453              :                 }
     454              : 
     455          202 :                 if(config->force)
     456              :                 {
     457            2 :                         slog(TESTING,"argument:force=%s\n",config->force ? "yes" : "no");
     458              :                 }
     459              : 
     460          202 :                 if(config->update)
     461              :                 {
     462           88 :                         slog(TESTING,"argument:update=%s\n",config->update ? "yes" : "no");
     463              :                 }
     464              : 
     465          202 :                 if(config->progress)
     466              :                 {
     467           40 :                         slog(TESTING,"argument:progress=%s\n",config->progress ? "yes" : "no");
     468              :                 }
     469              : 
     470          202 :                 if(config->compare)
     471              :                 {
     472           36 :                         slog(TESTING,"argument:compare=%s\n",config->compare ? "yes" : "no");
     473              :                 }
     474              : 
     475          202 :                 if(config->db_clean_ignored)
     476              :                 {
     477           12 :                         slog(TESTING,"argument:db-clean-ignored=%s\n",config->db_clean_ignored ? "yes" : "no");
     478              :                 }
     479              : 
     480          202 :                 if(config->dry_run)
     481              :                 {
     482           10 :                         slog(TESTING,"argument:dry-run=%s\n",config->dry_run ? "yes" : "no");
     483              :                 }
     484              : 
     485          202 :                 if(config->start_device_only)
     486              :                 {
     487            2 :                         slog(TESTING,"argument:start-device-only=%s\n",config->start_device_only ? "yes" : "no");
     488              :                 }
     489              : 
     490              :         }
     491              : 
     492              :         /* Verbose mode */
     493              :         {
     494          202 :                 slog(VERBOSE,"Configuration: ");
     495          202 :                 slog(VERBOSE|UNDECOR,"rational_logger_mode=%s\n",rational_reconvert(rational_logger_mode));
     496              : 
     497          202 :                 if(config->paths != NULL)
     498              :                 {
     499          202 :                         slog(VERBOSE|UNDECOR,"paths=");
     500              : 
     501          440 :                         for(int i = 0; config->paths[i]; i++)
     502              :                         {
     503          238 :                                 slog(VERBOSE|UNDECOR,i == 0 ? "%s" : ", %s",config->paths[i]);
     504              :                         }
     505          202 :                         slog(VERBOSE|UNDECOR,"; ");
     506              :                 }
     507              : 
     508          202 :                 if(config->db_primary_file_path != NULL)
     509              :                 {
     510          148 :                         slog(VERBOSE|UNDECOR,"database=%s; ",config->db_primary_file_path);
     511              :                 }
     512              : 
     513          202 :                 if(config->db_file_name != NULL)
     514              :                 {
     515          148 :                         slog(VERBOSE|UNDECOR,"db_file_name=%s; ",config->db_file_name);
     516              :                 }
     517              : 
     518          202 :                 if(config->db_file_paths != NULL)
     519              :                 {
     520           36 :                         slog(VERBOSE|UNDECOR,"db_file_paths=");
     521              : 
     522          108 :                         for(int i = 0; config->db_file_paths[i]; i++)
     523              :                         {
     524           72 :                                 slog(VERBOSE|UNDECOR,i == 0 ? "%s" : ", %s",config->db_file_paths[i]);
     525              :                         }
     526           36 :                         slog(VERBOSE|UNDECOR,"; ");
     527              :                 }
     528              : 
     529          202 :                 if(config->db_file_names != NULL)
     530              :                 {
     531           36 :                         slog(VERBOSE|UNDECOR,"db_file_names=");
     532              : 
     533          108 :                         for(int i = 0; config->db_file_names[i]; i++)
     534              :                         {
     535           72 :                                 slog(VERBOSE|UNDECOR,i == 0 ? "%s" : ", %s",config->db_file_names[i]);
     536              :                         }
     537           36 :                         slog(VERBOSE|UNDECOR,"; ");
     538              :                 }
     539              : 
     540          202 :                 if(config->ignore != NULL)
     541              :                 {
     542           18 :                         slog(VERBOSE|UNDECOR,"ignore=");
     543              : 
     544              :                         // Print the contents of the string array
     545           40 :                         for(int i = 0; config->ignore[i] != NULL; ++i)
     546              :                         {
     547           22 :                                 slog(VERBOSE|UNDECOR,i == 0 ? "%s" : ", %s",config->ignore[i]);
     548              :                         }
     549           18 :                         slog(VERBOSE|UNDECOR,"; ");
     550              :                 }
     551              : 
     552          202 :                 if(config->include != NULL)
     553              :                 {
     554            2 :                         slog(VERBOSE|UNDECOR,"include=");
     555              : 
     556              :                         // Print the contents of the string array
     557            6 :                         for(int i = 0; config->include[i] != NULL; ++i)
     558              :                         {
     559            4 :                                 slog(VERBOSE|UNDECOR,i == 0 ? "%s" : ", %s",config->include[i]);
     560              :                         }
     561            2 :                         slog(VERBOSE|UNDECOR,"; ");
     562              :                 }
     563              : 
     564          202 :                 if(config->lock_checksum != NULL)
     565              :                 {
     566           22 :                         slog(VERBOSE|UNDECOR,"lock-checksum=");
     567              : 
     568              :                         // Print the contents of the string array
     569           50 :                         for(int i = 0; config->lock_checksum[i] != NULL; ++i)
     570              :                         {
     571           28 :                                 slog(VERBOSE|UNDECOR,i == 0 ? "%s" : ", %s",config->lock_checksum[i]);
     572              :                         }
     573           22 :                         slog(VERBOSE|UNDECOR,"; ");
     574              :                 }
     575              : 
     576          202 :                 slog(VERBOSE|UNDECOR,"verbose=%s; maxdepth=%d; silent=no; force=%s; update=%s; watch-timestamps=%s; rehash-locked=%s; progress=%s; compare=%s, db-clean-ignored=%s, dry-run=%s, start-device-only=%s, check-level=%s, rational_logger_mode=%s",
     577              :                         config->verbose ? "yes" : "no",
     578              :                         config->maxdepth,
     579              :                         config->force ? "yes" : "no",
     580              :                         config->update ? "yes" : "no",
     581              :                         config->watch_timestamps ? "yes" : "no",
     582              :                         config->rehash_locked ? "yes" : "no",
     583              :                         config->progress ? "yes" : "no",
     584              :                         config->compare ? "yes" : "no",
     585              :                         config->db_clean_ignored ? "yes" : "no",
     586              :                         config->dry_run ? "yes" : "no",
     587              :                         config->start_device_only ? "yes" : "no",
     588              :                         config->db_check_level == QUICK ? "QUICK" : "FULL",
     589              :                         rational_reconvert(rational_logger_mode));
     590          202 :                 slog(VERBOSE|UNDECOR,"\n");
     591              :         }
     592              : 
     593          202 :         slog(TRACE,"Argument parsing is complete\n");
     594              : 
     595          202 :         provide(status);
     596              : }
        

Generated by: LCOV version 2.0-1