Print progress
parent
2881ba7e3a
commit
bbc706a5c7
2
Makefile
2
Makefile
|
@ -1,4 +1,6 @@
|
|||
all: era_copy era_apply
|
||||
install: all
|
||||
cp era_copy era_apply /usr/local/bin
|
||||
era_copy: era_copy.c
|
||||
gcc -o era_copy -Wall era_copy.c
|
||||
era_apply: era_apply.c
|
||||
|
|
38
era_apply.c
38
era_apply.c
|
@ -21,7 +21,7 @@
|
|||
|
||||
static void* copy_buffer = NULL;
|
||||
|
||||
void apply_blocks(int src, int dst, off64_t start, off64_t length)
|
||||
void apply_blocks(int src, int dst, off64_t start, off64_t length, long long *total, long long *prev_total)
|
||||
{
|
||||
off64_t copied = 0;
|
||||
ssize_t fact = 0, written = 0, fact_write = 0;
|
||||
|
@ -59,13 +59,30 @@ void apply_blocks(int src, int dst, off64_t start, off64_t length)
|
|||
written += fact_write;
|
||||
}
|
||||
copied += fact;
|
||||
if (total != NULL)
|
||||
{
|
||||
*total += fact;
|
||||
if (*total > *prev_total + 1048576)
|
||||
{
|
||||
fprintf(stderr, "\r%lld MB...", *total/1048576);
|
||||
*prev_total = *total;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void read_era_copy_and_apply(int src, int dst)
|
||||
void read_era_copy_and_apply(int src, int dst, int print_progress)
|
||||
{
|
||||
long long sign = 0, start = 0, length = 0;
|
||||
long long total = 0, prev_total = 0; // for printing progress
|
||||
long long *ptr_total = NULL, *ptr_prev_total = NULL;
|
||||
int r;
|
||||
if (print_progress)
|
||||
{
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
ptr_total = &total;
|
||||
ptr_prev_total = &prev_total;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
r = read(src, &sign, 8);
|
||||
|
@ -88,11 +105,15 @@ void read_era_copy_and_apply(int src, int dst)
|
|||
fprintf(stderr, "era_copy signature does not match\n");
|
||||
exit(1);
|
||||
}
|
||||
apply_blocks(src, dst, start, length);
|
||||
apply_blocks(src, dst, start, length, ptr_total, ptr_prev_total);
|
||||
}
|
||||
if (print_progress)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void era_apply(char *dst_path)
|
||||
void era_apply(char *dst_path, int print_progress)
|
||||
{
|
||||
struct stat sb;
|
||||
int dst, flags = O_WRONLY | O_LARGEFILE;
|
||||
|
@ -119,7 +140,7 @@ void era_apply(char *dst_path)
|
|||
fprintf(stderr, "Failed to open %s for writing: %s\n", dst_path, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
read_era_copy_and_apply(0, dst);
|
||||
read_era_copy_and_apply(0, dst, print_progress);
|
||||
// fsync and close
|
||||
fsync(dst);
|
||||
close(dst);
|
||||
|
@ -127,16 +148,17 @@ void era_apply(char *dst_path)
|
|||
|
||||
int main(int narg, char *args[])
|
||||
{
|
||||
if (narg < 2)
|
||||
int print_progress = 0;
|
||||
if (narg < 2 || ((print_progress = !strcmp(args[1], "--progress")) && narg < 3))
|
||||
{
|
||||
fprintf(stderr,
|
||||
"era_apply - applies era_copy output to a file or block device\n"
|
||||
"(c) Vitaliy Filippov, 2019+, distributed under the terms of GNU GPLv3.0 or later license\n"
|
||||
"\n"
|
||||
"USAGE:\nera_apply DESTINATION < era_copy_output.bin\n"
|
||||
"USAGE:\nera_apply [--progress] DESTINATION < era_copy_output.bin\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
era_apply(args[1]);
|
||||
era_apply(args[print_progress ? 2 : 1], print_progress);
|
||||
return 0;
|
||||
}
|
||||
|
|
64
era_copy.c
64
era_copy.c
|
@ -39,12 +39,14 @@ void copy_blocks(int src, int dst, off64_t start, off64_t length)
|
|||
}
|
||||
}
|
||||
|
||||
void read_era_invalidate_and_copy(FILE *fp, int src, int era_block_size)
|
||||
void read_era_invalidate_and_copy(FILE *fp, int src, int era_block_size, int print_progress)
|
||||
{
|
||||
// read input XML
|
||||
char buf[XML_BUFSIZE] = { 0 };
|
||||
char c = 0;
|
||||
long long start = 0, length = 0, total = 0;
|
||||
long long *offsets = NULL;
|
||||
int i, offsets_alloc = 0, offsets_len = 0;
|
||||
if (fgets(buf, XML_BUFSIZE, fp) == NULL)
|
||||
{
|
||||
fprintf(stderr, "Input block list is empty\n");
|
||||
|
@ -71,32 +73,51 @@ void read_era_invalidate_and_copy(FILE *fp, int src, int era_block_size)
|
|||
}
|
||||
start = start*era_block_size*512;
|
||||
length = length*era_block_size*512;
|
||||
if (src >= 0)
|
||||
if (offsets_len >= offsets_alloc)
|
||||
{
|
||||
// write a very simple binary format: SIGNATURE, start, length, data, ...
|
||||
write(1, SIGNATURE, 8);
|
||||
write(1, &start, 8);
|
||||
write(1, &length, 8);
|
||||
copy_blocks(src, 1, start, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate diff size
|
||||
total += length;
|
||||
offsets_alloc += 4096/sizeof(long long);
|
||||
offsets = (long long*)realloc(offsets, offsets_alloc*2*sizeof(long long));
|
||||
}
|
||||
offsets[offsets_len++] = start;
|
||||
offsets[offsets_len++] = length;
|
||||
// calculate diff size
|
||||
total += length;
|
||||
}
|
||||
if (sscanf(buf, " </blocks > %c", &c) == 0 || c != 0)
|
||||
{
|
||||
fprintf(stderr, "</blocks> expected, but \"%s\" found\n", buf);
|
||||
exit(1);
|
||||
}
|
||||
if (src < 0)
|
||||
if (src >= 0)
|
||||
{
|
||||
printf("%lld bytes\n", total);
|
||||
long long copied = 0, prev_copied = 0;
|
||||
if (print_progress)
|
||||
{
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
}
|
||||
for (i = 0; i < offsets_len; i += 2)
|
||||
{
|
||||
if (print_progress && (!copied || copied >= prev_copied + 1048576))
|
||||
{
|
||||
fprintf(stderr, "\rDone %lld MB / %lld MB, copying next %lld MB...", copied/1048576, total/1048576, offsets[i+1]/1048576);
|
||||
prev_copied = copied;
|
||||
}
|
||||
// write a very simple binary format: SIGNATURE, start, length, data, ...
|
||||
write(1, SIGNATURE, 8);
|
||||
write(1, offsets+i, 8);
|
||||
write(1, offsets+i+1, 8);
|
||||
copy_blocks(src, 1, offsets[i], offsets[i+1]);
|
||||
copied += offsets[i+1];
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%lld bytes to copy\n", total);
|
||||
}
|
||||
}
|
||||
|
||||
void era_copy(char *src_path, int era_block_size)
|
||||
void era_copy(char *src_path, int era_block_size, int print_progress)
|
||||
{
|
||||
int src = -1;
|
||||
if (src_path != NULL)
|
||||
|
@ -108,7 +129,7 @@ void era_copy(char *src_path, int era_block_size)
|
|||
exit(1);
|
||||
}
|
||||
}
|
||||
read_era_invalidate_and_copy(stdin, src, era_block_size);
|
||||
read_era_invalidate_and_copy(stdin, src, era_block_size, print_progress);
|
||||
if (src_path != NULL)
|
||||
{
|
||||
close(src);
|
||||
|
@ -117,29 +138,30 @@ void era_copy(char *src_path, int era_block_size)
|
|||
|
||||
int main(int narg, char *args[])
|
||||
{
|
||||
if (narg < 2)
|
||||
int print_progress = 0;
|
||||
if (narg < 2 || ((print_progress = !strcmp(args[1], "--progress")) && narg < 3))
|
||||
{
|
||||
fprintf(stderr,
|
||||
"era_copy - parses era_invalidate output and saves changed blocks to a stream\n"
|
||||
"(c) Vitaliy Filippov, 2019+, distributed under the terms of GNU GPLv3.0 or later license\n"
|
||||
"\n"
|
||||
"USAGE:\nera_invalidate --metadata-snapshot --written-since <ERA> <META_DEVICE> |\\\n"
|
||||
" era_copy <ERA_BLOCK_SIZE> [<DATA_DEVICE>] > era_copy.bin\n"
|
||||
" era_copy [--progress] <ERA_BLOCK_SIZE> [<DATA_DEVICE>] > era_copy.bin\n"
|
||||
"\n"
|
||||
"When invoked without <DATA_DEVICE>, era_copy only calculates the future diff size and prints it\n"
|
||||
"\n"
|
||||
"ERA_BLOCK_SIZE is dm-era's granularity in 512-byte sectors you used when creating dm-era device\n"
|
||||
"You can take it from `dmsetup table <DATA_DEVICE>`: it's the last number in DM table\n"
|
||||
"For example, in `0 3625546496 era 259:3 259:2 65536` it's 65536\n"
|
||||
"For example, in `0 3625546496 era 259:3 259:2 1024` it's 1024\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
int bs = atoi(args[1]);
|
||||
int bs = atoi(args[print_progress ? 2 : 1]);
|
||||
if (bs < 1)
|
||||
{
|
||||
fprintf(stderr, "Incorrect era_block_size = %d\n", bs);
|
||||
exit(1);
|
||||
}
|
||||
era_copy(narg == 2 ? NULL : args[2], bs);
|
||||
era_copy(narg == (print_progress ? 3 : 2) ? NULL : args[print_progress ? 3 : 2], bs, print_progress);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue