LCOV - code coverage report
Current view: top level - cmdline - status.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 271 283 95.8 %
Date: 2017-11-06 22:14:04 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2013 Andrea Mazzoleni
       3             :  *
       4             :  * This program is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 3 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * This program is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "portable.h"
      19             : 
      20             : #include "support.h"
      21             : #include "elem.h"
      22             : #include "state.h"
      23             : #include "parity.h"
      24             : #include "handle.h"
      25             : #include "raid/raid.h"
      26             : 
      27             : /****************************************************************************/
      28             : /* status */
      29             : 
      30          27 : unsigned day_ago(time_t ref, time_t now)
      31             : {
      32          27 :         return (now - ref) / (24 * 3600);
      33             : }
      34             : 
      35             : #define GRAPH_COLUMN 70
      36             : #define GRAPH_ROW 15
      37             : 
      38          68 : static unsigned perc(uint64_t part, uint64_t total)
      39             : {
      40          68 :         if (!total)
      41           6 :                 return 0;
      42             : 
      43          62 :         return (unsigned)(part * 100 / total);
      44             : }
      45             : 
      46             : /**
      47             :  * Bit used to mark unscrubbed time info.
      48             :  */
      49             : #define TIME_NEW 1
      50             : 
      51          15 : int state_status(struct snapraid_state* state)
      52             : {
      53             :         block_off_t blockmax;
      54             :         block_off_t i;
      55             :         time_t* timemap;
      56             :         time_t now;
      57             :         block_off_t bad;
      58             :         block_off_t bad_first;
      59             :         block_off_t bad_last;
      60             :         block_off_t rehash;
      61             :         block_off_t count;
      62             :         unsigned l;
      63             :         unsigned dayoldest, daymedian, daynewest;
      64             :         unsigned bar_scrubbed[GRAPH_COLUMN];
      65             :         unsigned bar_new[GRAPH_COLUMN];
      66             :         unsigned barpos;
      67             :         unsigned barmax;
      68             :         time_t oldest, newest, median;
      69             :         unsigned x, y;
      70             :         tommy_node* node_disk;
      71             :         unsigned file_count;
      72             :         unsigned file_fragmented;
      73             :         unsigned extra_fragment;
      74             :         unsigned file_zerosubsecond;
      75             :         uint64_t file_size;
      76             :         uint64_t file_block_count;
      77             :         uint64_t file_block_free;
      78             :         block_off_t parity_block_free;
      79             :         unsigned unsynced_blocks;
      80             :         unsigned unscrubbed_blocks;
      81             :         uint64_t all_wasted;
      82             :         int free_not_zero;
      83             : 
      84             :         /* get the present time */
      85          15 :         now = time(0);
      86             : 
      87             :         /* keep track if at least a free info is available */
      88          15 :         free_not_zero = 0;
      89             : 
      90          15 :         blockmax = parity_allocated_size(state);
      91             : 
      92          15 :         log_tag("summary:block_size:%u\n", state->block_size);
      93          15 :         log_tag("summary:parity_block_count:%u\n", blockmax);
      94             : 
      95             :         /* get the minimum parity free space */
      96          15 :         parity_block_free = state->parity[0].free_blocks;
      97         105 :         for (l = 0; l < state->level; ++l) {
      98          90 :                 log_tag("summary:parity_block_total:%s:%u\n", lev_config_name(l), state->parity[l].total_blocks);
      99          90 :                 log_tag("summary:parity_block_free:%s:%u\n", lev_config_name(l), state->parity[l].free_blocks);
     100          90 :                 if (state->parity[l].free_blocks < parity_block_free)
     101           1 :                         parity_block_free = state->parity[l].free_blocks;
     102          90 :                 if (state->parity[l].free_blocks != 0)
     103          79 :                         free_not_zero = 1;
     104             :         }
     105          15 :         log_tag("summary:parity_block_free_min:%u\n", parity_block_free);
     106             : 
     107          15 :         printf("SnapRAID status report:\n");
     108          15 :         printf("\n");
     109          15 :         printf("   Files Fragmented Excess  Wasted  Used    Free  Use Name\n");
     110          15 :         printf("            Files  Fragments  GB      GB      GB\n");
     111             : 
     112             :         /* count fragments */
     113          15 :         file_count = 0;
     114          15 :         file_size = 0;
     115          15 :         file_block_count = 0;
     116          15 :         file_block_free = 0;
     117          15 :         file_fragmented = 0;
     118          15 :         extra_fragment = 0;
     119          15 :         file_zerosubsecond = 0;
     120          15 :         all_wasted = 0;
     121         105 :         for (node_disk = state->disklist; node_disk != 0; node_disk = node_disk->next) {
     122          90 :                 struct snapraid_disk* disk = node_disk->data;
     123             :                 tommy_node* node;
     124             :                 block_off_t j;
     125          90 :                 unsigned disk_file_count = 0;
     126          90 :                 unsigned disk_file_fragmented = 0;
     127          90 :                 unsigned disk_extra_fragment = 0;
     128          90 :                 unsigned disk_file_zerosubsecond = 0;
     129          90 :                 block_off_t disk_block_count = 0;
     130          90 :                 uint64_t disk_file_size = 0;
     131          90 :                 block_off_t disk_block_latest_used = 0;
     132             :                 block_off_t disk_block_max_by_space;
     133             :                 block_off_t disk_block_max_by_parity;
     134             :                 block_off_t disk_block_max;
     135             :                 int64_t wasted;
     136             : 
     137             :                 /* for each file in the disk */
     138          90 :                 node = disk->filelist;
     139       95714 :                 while (node) {
     140             :                         struct snapraid_file* file;
     141             : 
     142       95534 :                         file = node->data;
     143       95534 :                         node = node->next; /* next node */
     144             : 
     145       95534 :                         if (file->mtime_nsec == STAT_NSEC_INVALID
     146       95534 :                                 || file->mtime_nsec == 0
     147             :                         ) {
     148           0 :                                 ++file_zerosubsecond;
     149           0 :                                 ++disk_file_zerosubsecond;
     150           0 :                                 if (disk_file_zerosubsecond < 50)
     151           0 :                                         log_tag("zerosubsecond:%s:%s: \n", disk->name, file->sub);
     152           0 :                                 if (disk_file_zerosubsecond == 50)
     153           0 :                                         log_tag("zerosubsecond:%s:%s: (more follow)\n", disk->name, file->sub);
     154             :                         }
     155             : 
     156             :                         /* check fragmentation */
     157       95534 :                         if (file->blockmax != 0) {
     158             :                                 block_off_t prev_pos;
     159             :                                 block_off_t last_pos;
     160             :                                 int fragmented;
     161             : 
     162       95396 :                                 fragmented = 0;
     163       95396 :                                 prev_pos = fs_file2par_get(disk, file, 0);
     164      235735 :                                 for (j = 1; j < file->blockmax; ++j) {
     165      140339 :                                         block_off_t parity_pos = fs_file2par_get(disk, file, j);
     166      140339 :                                         if (prev_pos + 1 != parity_pos) {
     167         698 :                                                 fragmented = 1;
     168         698 :                                                 ++extra_fragment;
     169         698 :                                                 ++disk_extra_fragment;
     170             :                                         }
     171      140339 :                                         prev_pos = parity_pos;
     172             :                                 }
     173             : 
     174             :                                 /* keep track of latest block used */
     175       95396 :                                 last_pos = fs_file2par_get(disk, file, file->blockmax - 1);
     176       95396 :                                 if (last_pos > disk_block_latest_used) {
     177       92537 :                                         disk_block_latest_used = last_pos;
     178             :                                 }
     179             : 
     180       95396 :                                 if (fragmented) {
     181         582 :                                         ++file_fragmented;
     182         582 :                                         ++disk_file_fragmented;
     183             :                                 }
     184             : 
     185       95396 :                                 disk_block_count += file->blockmax;
     186             :                         }
     187             : 
     188             :                         /* count files */
     189       95534 :                         ++file_count;
     190       95534 :                         ++disk_file_count;
     191       95534 :                         file_size += file->size;
     192       95534 :                         file_block_count += file->blockmax;
     193       95534 :                         disk_file_size += file->size;
     194             :                 }
     195             : 
     196          90 :                 if (disk->free_blocks != 0)
     197          53 :                         free_not_zero = 1;
     198             : 
     199             :                 /* get the free block info */
     200          90 :                 disk_block_max_by_space = disk_block_count + disk->free_blocks;
     201          90 :                 disk_block_max_by_parity = blockmax + parity_block_free;
     202             : 
     203             :                 /* the maximum usable space in a disk is limited by the smallest */
     204             :                 /* of the disk size and the parity size */
     205             :                 /* the wasted space is the space that we have to leave */
     206             :                 /* free on the data disk, when the parity is filled up */
     207          90 :                 if (disk_block_max_by_space < disk_block_max_by_parity) {
     208          78 :                         disk_block_max = disk_block_max_by_space;
     209             :                 } else {
     210          12 :                         disk_block_max = disk_block_max_by_parity;
     211             :                 }
     212             : 
     213             :                 /* wasted space is the difference of the two maximum size */
     214             :                 /* if negative, it's extra space available in parity */
     215          90 :                 wasted = (int64_t)disk_block_max_by_space - (int64_t)disk_block_max_by_parity;
     216          90 :                 wasted *= state->block_size;
     217             : 
     218          90 :                 if (wasted > 0)
     219           6 :                         all_wasted += wasted;
     220          90 :                 file_block_free += disk_block_max - disk_block_count;
     221             : 
     222          90 :                 printf("%8u", disk_file_count);
     223          90 :                 printf("%8u", disk_file_fragmented);
     224          90 :                 printf("%8u", disk_extra_fragment);
     225          90 :                 if (wasted < -100LL * GIGA) {
     226          78 :                         printf("       -");
     227             :                 } else {
     228          12 :                         printf("%8.1f", (double)wasted / GIGA);
     229             :                 }
     230          90 :                 printf("%8" PRIu64, disk_file_size / GIGA);
     231             : 
     232          90 :                 if (disk_block_max == 0 && disk_block_count == 0) {
     233             :                         /* if the disk is empty and we don't have the free space info */
     234          37 :                         printf("       -");
     235          37 :                         printf("   - ");
     236             :                 } else {
     237          53 :                         printf("%8" PRIu64, (disk_block_max - disk_block_count) * (uint64_t)state->block_size / GIGA);
     238          53 :                         printf(" %3u%%", perc(disk_block_count, disk_block_max));
     239             :                 }
     240          90 :                 printf(" %s\n", disk->name);
     241             : 
     242          90 :                 log_tag("summary:disk_file_count:%s:%u\n", disk->name, disk_file_count);
     243          90 :                 log_tag("summary:disk_block_count:%s:%u\n", disk->name, disk_block_count);
     244          90 :                 log_tag("summary:disk_fragmented_file_count:%s:%u\n", disk->name, disk_file_fragmented);
     245          90 :                 log_tag("summary:disk_excess_fragment_count:%s:%u\n", disk->name, disk_extra_fragment);
     246          90 :                 log_tag("summary:disk_zerosubsecond_file_count:%s:%u\n", disk->name, disk_file_zerosubsecond);
     247          90 :                 log_tag("summary:disk_file_size:%s:%" PRIu64 "\n", disk->name, disk_file_size);
     248          90 :                 log_tag("summary:disk_block_allocated:%s:%u\n", disk->name, disk_block_latest_used + 1);
     249          90 :                 log_tag("summary:disk_block_total:%s:%u\n", disk->name, disk->total_blocks);
     250          90 :                 log_tag("summary:disk_block_free:%s:%u\n", disk->name, disk->free_blocks);
     251          90 :                 log_tag("summary:disk_block_max_by_space:%s:%u\n", disk->name, disk_block_max_by_space);
     252          90 :                 log_tag("summary:disk_block_max_by_parity:%s:%u\n", disk->name, disk_block_max_by_parity);
     253          90 :                 log_tag("summary:disk_block_max:%s:%u\n", disk->name, disk_block_max);
     254          90 :                 log_tag("summary:disk_space_wasted:%s:%" PRId64 "\n", disk->name, wasted);
     255             :         }
     256             : 
     257             :         /* totals */
     258          15 :         printf(" --------------------------------------------------------------------------\n");
     259          15 :         printf("%8u", file_count);
     260          15 :         printf("%8u", file_fragmented);
     261          15 :         printf("%8u", extra_fragment);
     262          15 :         printf("%8.1f", (double)all_wasted / GIGA);
     263          15 :         printf("%8" PRIu64, file_size / GIGA);
     264          15 :         printf("%8" PRIu64, file_block_free * state->block_size / GIGA);
     265          15 :         printf(" %3u%%", perc(file_block_count, file_block_count + file_block_free));
     266          15 :         printf("\n");
     267             : 
     268             :         /* warn about invalid data free info */
     269          15 :         if (!free_not_zero)
     270           1 :                 printf("\nWARNING! Free space info will be valid after the first sync.\n");
     271             : 
     272          15 :         log_tag("summary:file_count:%u\n", file_count);
     273          15 :         log_tag("summary:file_block_count:%" PRIu64 "\n", file_block_count);
     274          15 :         log_tag("summary:fragmented_file_count:%u\n", file_fragmented);
     275          15 :         log_tag("summary:excess_fragment_count:%u\n", extra_fragment);
     276          15 :         log_tag("summary:zerosubsecond_file_count:%u\n", file_zerosubsecond);
     277          15 :         log_tag("summary:file_size:%" PRIu64 "\n", file_size);
     278          15 :         log_tag("summary:parity_size:%" PRIu64 "\n", blockmax * (uint64_t)state->block_size);
     279          15 :         log_tag("summary:parity_size_max:%" PRIu64 "\n", (blockmax + parity_block_free) * (uint64_t)state->block_size);
     280          15 :         log_tag("summary:hash:%s\n", hash_config_name(state->hash));
     281          15 :         log_tag("summary:prev_hash:%s\n", hash_config_name(state->prevhash));
     282          15 :         log_tag("summary:best_hash:%s\n", hash_config_name(state->besthash));
     283          15 :         log_flush();
     284             : 
     285             :         /* copy the info a temp vector, and count bad/rehash/unsynced blocks */
     286          15 :         timemap = malloc_nofail(blockmax * sizeof(time_t));
     287          15 :         bad = 0;
     288          15 :         bad_first = 0;
     289          15 :         bad_last = 0;
     290          15 :         count = 0;
     291          15 :         rehash = 0;
     292          15 :         unsynced_blocks = 0;
     293          15 :         unscrubbed_blocks = 0;
     294          15 :         log_tag("block_count:%u\n", blockmax);
     295       39823 :         for (i = 0; i < blockmax; ++i) {
     296             :                 int one_invalid;
     297             :                 int one_valid;
     298             : 
     299       39808 :                 snapraid_info info = info_get(&state->infoarr, i);
     300             : 
     301             :                 /* for each disk */
     302       39808 :                 one_invalid = 0;
     303       39808 :                 one_valid = 0;
     304      278656 :                 for (node_disk = state->disklist; node_disk != 0; node_disk = node_disk->next) {
     305      238848 :                         struct snapraid_disk* disk = node_disk->data;
     306      238848 :                         struct snapraid_block* block = fs_par2block_find(disk, i);
     307             : 
     308      238848 :                         if (block_has_file(block))
     309      235735 :                                 one_valid = 1;
     310      238848 :                         if (block_has_invalid_parity(block))
     311          56 :                                 one_invalid = 1;
     312             :                 }
     313             : 
     314             :                 /* if both valid and invalid, we need to update */
     315       39808 :                 if (one_invalid && one_valid) {
     316          40 :                         ++unsynced_blocks;
     317             :                 }
     318             : 
     319             :                 /* skip unused blocks */
     320       39808 :                 if (info != 0) {
     321             :                         time_t scrub_time;
     322             : 
     323       39808 :                         if (info_get_bad(info)) {
     324        1773 :                                 if (bad == 0)
     325           2 :                                         bad_first = i;
     326        1773 :                                 bad_last = i;
     327        1773 :                                 ++bad;
     328             :                         }
     329             : 
     330       39808 :                         if (info_get_rehash(info))
     331        4607 :                                 ++rehash;
     332             : 
     333       39808 :                         scrub_time = info_get_time(info);
     334             : 
     335       39808 :                         if (info_get_justsynced(info)) {
     336       20494 :                                 ++unscrubbed_blocks;
     337             : 
     338             :                                 /* mark the time as not scrubbed */
     339       20494 :                                 scrub_time |= TIME_NEW;
     340             :                         }
     341             : 
     342       39808 :                         timemap[count++] = scrub_time;
     343             :                 }
     344             : 
     345       39808 :                 if (state->opt.gui) {
     346           0 :                         if (info != 0)
     347           0 :                                 log_tag("block:%u:%" PRIu64 ":%s:%s:%s:%s\n", i, (uint64_t)info_get_time(info), one_valid ? "used" : "", one_invalid ? "unsynced" : "", info_get_bad(info) ? "bad" : "", info_get_rehash(info) ? "rehash" : "");
     348             :                         else
     349           0 :                                 log_tag("block_noinfo:%u:%s:%s\n", i, one_valid ? "used" : "", one_invalid ? "unsynced" : "");
     350             :                 }
     351             :         }
     352             : 
     353          15 :         log_tag("summary:has_unsynced:%u\n", unsynced_blocks);
     354          15 :         log_tag("summary:has_unscrubbed:%u\n", unscrubbed_blocks);
     355          15 :         log_tag("summary:has_rehash:%u\n", rehash);
     356          15 :         log_tag("summary:has_bad:%u:%u:%u\n", bad, bad_first, bad_last);
     357          15 :         log_flush();
     358             : 
     359          15 :         if (!count) {
     360           6 :                 log_fatal("The array is empty.\n");
     361           6 :                 free(timemap);
     362           6 :                 return 0;
     363             :         }
     364             : 
     365             :         /* sort the info to get the time info */
     366           9 :         qsort(timemap, count, sizeof(time_t), time_compare);
     367             : 
     368             :         /* output the info map */
     369           9 :         i = 0;
     370           9 :         log_tag("info_count:%u\n", count);
     371          35 :         while (i < count) {
     372          17 :                 unsigned j = i + 1;
     373       39825 :                 while (j < count && timemap[i] == timemap[j])
     374       39791 :                         ++j;
     375          17 :                 if ((timemap[i] & TIME_NEW) == 0) {
     376           6 :                         log_tag("info_time:%" PRIu64 ":%u:scrubbed\n", (uint64_t)timemap[i], j - i);
     377             :                 } else {
     378          11 :                         log_tag("info_time:%" PRIu64 ":%u:new\n", (uint64_t)(timemap[i] & ~TIME_NEW), j - i);
     379             :                 }
     380          17 :                 i = j;
     381             :         }
     382             : 
     383           9 :         oldest = timemap[0];
     384           9 :         median = timemap[count / 2];
     385           9 :         newest = timemap[count - 1];
     386           9 :         dayoldest = day_ago(oldest, now);
     387           9 :         daymedian = day_ago(median, now);
     388           9 :         daynewest = day_ago(newest, now);
     389             : 
     390             :         /* compute graph limits */
     391           9 :         barpos = 0;
     392           9 :         barmax = 0;
     393         639 :         for (i = 0; i < GRAPH_COLUMN; ++i) {
     394             :                 time_t limit;
     395             :                 unsigned step_scrubbed, step_new;
     396             : 
     397         630 :                 limit = oldest + (newest - oldest) * (i + 1) / GRAPH_COLUMN;
     398             : 
     399         630 :                 step_scrubbed = 0;
     400         630 :                 step_new = 0;
     401       41068 :                 while (barpos < count && timemap[barpos] <= limit) {
     402       39808 :                         if ((timemap[barpos] & TIME_NEW) != 0)
     403       20494 :                                 ++step_new;
     404             :                         else
     405       19314 :                                 ++step_scrubbed;
     406       39808 :                         ++barpos;
     407             :                 }
     408             : 
     409         630 :                 if (step_new + step_scrubbed > barmax)
     410          11 :                         barmax = step_new + step_scrubbed;
     411             : 
     412         630 :                 bar_scrubbed[i] = step_scrubbed;
     413         630 :                 bar_new[i] = step_new;
     414             :         }
     415             : 
     416           9 :         printf("\n\n");
     417             : 
     418             :         /* print the graph */
     419         144 :         for (y = 0; y < GRAPH_ROW; ++y) {
     420         135 :                 if (y == 0)
     421           9 :                         printf("%3u%%|", barmax * 100 / count);
     422         126 :                 else if (y == GRAPH_ROW - 1)
     423           9 :                         printf("  0%%|");
     424         117 :                 else if (y == GRAPH_ROW / 2)
     425           9 :                         printf("%3u%%|", barmax * 50 / count);
     426             :                 else
     427         108 :                         printf("    |");
     428        9585 :                 for (x = 0; x < GRAPH_COLUMN; ++x) {
     429        9450 :                         unsigned pivot_upper = barmax * (GRAPH_ROW - y) / GRAPH_ROW;
     430        9450 :                         unsigned pivot_lower = barmax * (GRAPH_ROW - 1 - y) / GRAPH_ROW;
     431        9450 :                         unsigned both = bar_scrubbed[x] + bar_new[x];
     432        9450 :                         unsigned scrubbed = bar_scrubbed[x];
     433             : 
     434        9450 :                         if (both > pivot_upper) {
     435         155 :                                 if (scrubbed > pivot_lower)
     436          60 :                                         printf("*");
     437             :                                 else
     438          95 :                                         printf("o");
     439        9295 :                         } else if (both > pivot_lower) {
     440          17 :                                 if (scrubbed == both)
     441           6 :                                         printf("*");
     442             :                                 else
     443          11 :                                         printf("o");
     444             :                         } else {
     445        9278 :                                 if (y == GRAPH_ROW - 1)
     446         613 :                                         printf("_");
     447             :                                 else
     448        8665 :                                         printf(" ");
     449             :                         }
     450             :                 }
     451         135 :                 printf("\n");
     452             :         }
     453           9 :         printf("   %3u                    days ago of the last scrub/sync               %3u\n", dayoldest, daynewest);
     454             : 
     455           9 :         printf("\n");
     456             : 
     457           9 :         printf("The oldest block was scrubbed %u days ago, the median %u, the newest %u.\n", dayoldest, daymedian, daynewest);
     458             : 
     459           9 :         printf("\n");
     460             : 
     461           9 :         if (unsynced_blocks) {
     462           1 :                 printf("WARNING! The array is NOT fully synced.\n");
     463           1 :                 printf("You have a sync in progress at %u%%.\n", (blockmax - unsynced_blocks) * 100 / blockmax);
     464             :         } else {
     465           8 :                 printf("No sync is in progress.\n");
     466             :         }
     467             : 
     468           9 :         if (unscrubbed_blocks) {
     469           7 :                 printf("The %u%% of the array is not scrubbed.\n", (unscrubbed_blocks * 100 + blockmax - 1) / blockmax);
     470             :         } else {
     471           2 :                 printf("The full array was scrubbed at least one time.\n");
     472             :         }
     473             : 
     474           9 :         if (file_zerosubsecond) {
     475           0 :                 printf("You have %u files with zero sub-second timestamp.\n", file_zerosubsecond);
     476           0 :                 printf("Run the 'touch' command to set it to a not zero value.\n");
     477             :         } else {
     478           9 :                 printf("No file has a zero sub-second timestamp.\n");
     479             :         }
     480             : 
     481           9 :         if (rehash) {
     482           1 :                 printf("You have a rehash in progress at %u%%.\n", (count - rehash) * 100 / count);
     483             :         } else {
     484           8 :                 if (state->besthash != state->hash) {
     485           7 :                         printf("No rehash is in progress, but for optimal performance one is recommended.\n");
     486             :                 } else {
     487           1 :                         printf("No rehash is in progress or needed.\n");
     488             :                 }
     489             :         }
     490             : 
     491           9 :         if (bad) {
     492             :                 block_off_t bad_print;
     493             : 
     494           2 :                 printf("DANGER! In the array there are %u errors!\n\n", bad);
     495             : 
     496           2 :                 printf("They are from block %u to %u, specifically at blocks:", bad_first, bad_last);
     497             : 
     498             :                 /* print some of the errors */
     499           2 :                 bad_print = 0;
     500         715 :                 for (i = 0; i < blockmax; ++i) {
     501         715 :                         snapraid_info info = info_get(&state->infoarr, i);
     502             : 
     503             :                         /* skip unused blocks */
     504         715 :                         if (info == 0)
     505           0 :                                 continue;
     506             : 
     507         715 :                         if (info_get_bad(info)) {
     508         202 :                                 printf(" %u", i);
     509         202 :                                 ++bad_print;
     510             :                         }
     511             : 
     512         715 :                         if (bad_print > 100) {
     513           2 :                                 printf(" and %u more...", bad - bad_print);
     514           2 :                                 break;
     515             :                         }
     516             :                 }
     517             : 
     518           2 :                 printf("\n\n");
     519             : 
     520           2 :                 printf("To fix them use the command 'snapraid -e fix'.\n");
     521           2 :                 printf("The errors will disappear from the 'status' at the next 'scrub' command.\n");
     522             :         } else {
     523           7 :                 printf("No error detected.\n");
     524             :         }
     525             : 
     526             :         /* free the temp vector */
     527           9 :         free(timemap);
     528             : 
     529           9 :         return 0;
     530             : }
     531             : 

Generated by: LCOV version 1.13