mirror of
https://github.com/upa/mscp.git
synced 2026-02-04 11:34:44 +08:00
wrap print progress in pprint
This commit is contained in:
@@ -6,7 +6,7 @@ set(CMAKE_C_FLAGS "-Wall -g")
|
||||
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")
|
||||
|
||||
add_executable(sscp src/main.c src/platform.c src/ssh.c src/file.c)
|
||||
add_executable(sscp src/main.c src/platform.c src/ssh.c src/file.c src/pprint.c)
|
||||
target_include_directories(sscp PUBLIC ./src /usr/local/include)
|
||||
target_link_directories(sscp PUBLIC /usr/local/lib)
|
||||
target_link_libraries(sscp ssh pthread m)
|
||||
|
||||
21
src/file.c
21
src/file.c
@@ -7,6 +7,7 @@
|
||||
#include <ssh.h>
|
||||
#include <util.h>
|
||||
#include <file.h>
|
||||
#include <pprint.h>
|
||||
#include <platform.h>
|
||||
|
||||
bool file_has_hostname(char *path)
|
||||
@@ -450,6 +451,8 @@ int chunk_fill(struct list_head *file_list, struct list_head *chunk_list,
|
||||
c->len = size < chunk_sz ? size : chunk_sz;
|
||||
size -= c->len;
|
||||
list_add_tail(&c->list, chunk_list);
|
||||
pprint4("chunk %s 0x%010lx-0x%010lx %luB\n",
|
||||
c->f->path, c->off, c->off + c->len, c->len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,7 +490,6 @@ struct chunk *chunk_acquire(struct list_head *chunk_list)
|
||||
|
||||
int chunk_prepare(struct chunk *c, sftp_session sftp)
|
||||
{
|
||||
char output[PATH_MAX + 32];
|
||||
struct file *f = c->f;
|
||||
int ret = 0;
|
||||
|
||||
@@ -497,10 +499,8 @@ int chunk_prepare(struct chunk *c, sftp_session sftp)
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
snprintf(output, sizeof(output), "\r\033[Kcopy start: %s\n", f->path);
|
||||
fputs(output, stderr);
|
||||
fflush(stderr);
|
||||
f->state = FILE_STATE_OPENED;
|
||||
pprint2("copy start: %s\n", f->path);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -731,12 +731,15 @@ int chunk_copy(struct chunk *c, sftp_session sftp, size_t sftp_buf_sz, size_t io
|
||||
{
|
||||
struct file *f = c->f;
|
||||
int ret = 0;
|
||||
char output[PATH_MAX + 16];
|
||||
|
||||
pr_debug("copy %s %s -> %s %s off=0x%010lx\n",
|
||||
f->path, f->remote ? "(remote)" : "(local)",
|
||||
f->dst_path, f->dst_remote ? "(remote)" : "(local)", c->off);
|
||||
|
||||
pprint4("copy start: chunk %s 0x%010lx-0x%010lx %luB\n",
|
||||
c->f->path, c->off, c->off + c->len, c->len);
|
||||
|
||||
|
||||
if (f->dst_remote)
|
||||
ret = chunk_copy_local_to_remote(c, sftp,
|
||||
sftp_buf_sz, io_buf_sz, counter);
|
||||
@@ -751,12 +754,14 @@ int chunk_copy(struct chunk *c, sftp_session sftp, size_t sftp_buf_sz, size_t io
|
||||
f->path, f->remote ? "(remote)" : "(local)",
|
||||
f->dst_path, f->dst_remote ? "(remote)" : "(local)", c->off);
|
||||
|
||||
pprint4("copy done: chunk %s 0x%010lx-0x%010lx %luB\n",
|
||||
c->f->path, c->off, c->off + c->len, c->len);
|
||||
|
||||
if (refcnt_dec(&f->refcnt) == 0) {
|
||||
snprintf(output, sizeof(output), "\r\033[Kcopy done: %s\n", f->path);
|
||||
fputs(output, stderr);
|
||||
fflush(stderr);
|
||||
f->state = FILE_STATE_DONE;
|
||||
pprint2("copy done: %s\n", f->path);
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
41
src/main.c
41
src/main.c
@@ -12,12 +12,10 @@
|
||||
#include <util.h>
|
||||
#include <ssh.h>
|
||||
#include <file.h>
|
||||
#include <pprint.h>
|
||||
#include <atomic.h>
|
||||
#include <platform.h>
|
||||
|
||||
int verbose = 0; /* util.h */
|
||||
|
||||
|
||||
#define DEFAULT_MIN_CHUNK_SZ (64 << 20) /* 64MB */
|
||||
#define DEFAULT_SFTP_BUF_SZ 131072 /* derived from qemu/block/ssh.c */
|
||||
#define DEFAULT_IO_BUF_SZ DEFAULT_SFTP_BUF_SZ
|
||||
@@ -69,29 +67,31 @@ void stop_copy_threads(int sig)
|
||||
void usage(bool print_help) {
|
||||
printf("sscp: super scp, copy files over multiple ssh connections\n"
|
||||
"\n"
|
||||
"Usage: sscp [Cvh] [-n max_conns] [-s min_chunk_sz] [-S max_chunk_sz]\n"
|
||||
"Usage: sscp [Cvqdh] [-n nr_conns] [-s min_chunk_sz] [-S max_chunk_sz]\n"
|
||||
" [-b sftp_buf_sz] [-B io_buf_sz]\n"
|
||||
" [-l login_name] [-p port] [-i identity_file]\n"
|
||||
" [-c cipher_spec] source ... target_directory\n"
|
||||
" [-c cipher_spec] []source ... target_directory\n"
|
||||
"\n");
|
||||
|
||||
if (!print_help)
|
||||
return;
|
||||
|
||||
printf(" -n NR_CONNECTIONS max number of connections (default: # of cpu cores)\n"
|
||||
printf(" -n NR_CONNECTIONS number of connections (default: half of # of cpu cores)\n"
|
||||
" -s MIN_CHUNK_SIZE min chunk size (default: 64MB)\n"
|
||||
" -S MAX_CHUNK_SIZE max chunk size (default: filesize / nr_conn)\n"
|
||||
" -b SFTP_BUF_SIZE buf size for sftp_read/write (default 131072B)\n"
|
||||
" -B IO_BUF_SIZE buf size for read/write (default 131072B)\n"
|
||||
" Note that this value is derived from\n"
|
||||
" qemu/block/ssh.c. need investigation...\n"
|
||||
" -v increment verbose output level\n"
|
||||
" -q disable output\n"
|
||||
"\n"
|
||||
" -l LOGIN_NAME login name\n"
|
||||
" -p PORT port number\n"
|
||||
" -i IDENTITY identity file for publickey authentication\n"
|
||||
" -c CIPHER cipher spec, see `ssh -Q cipher`\n"
|
||||
" -C enable compression on libssh\n"
|
||||
" -v increment output level\n"
|
||||
" -d increment ssh debug output level\n"
|
||||
" -h print this help\n"
|
||||
"\n");
|
||||
|
||||
@@ -151,6 +151,7 @@ int main(int argc, char **argv)
|
||||
struct ssh_opts opts;
|
||||
int min_chunk_sz = DEFAULT_MIN_CHUNK_SZ;
|
||||
int max_chunk_sz = 0;
|
||||
int verbose = 1;
|
||||
int ret = 0, n;
|
||||
char ch;
|
||||
|
||||
@@ -162,9 +163,10 @@ int main(int argc, char **argv)
|
||||
sscp.sftp_buf_sz = DEFAULT_SFTP_BUF_SZ;
|
||||
sscp.io_buf_sz = DEFAULT_IO_BUF_SZ;
|
||||
|
||||
nr_threads = nr_cpus();
|
||||
nr_threads = (int)(nr_cpus() / 2);
|
||||
nr_threads = nr_threads == 0 ? 1 : nr_threads;
|
||||
|
||||
while ((ch = getopt(argc, argv, "n:s:S:b:B:l:p:i:c:Cvh")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "n:s:S:b:B:vql:p:i:c:Cdh")) != -1) {
|
||||
switch (ch) {
|
||||
case 'n':
|
||||
nr_threads = atoi(optarg);
|
||||
@@ -217,6 +219,12 @@ int main(int argc, char **argv)
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'q':
|
||||
verbose = -1;
|
||||
break;
|
||||
case 'l':
|
||||
opts.login_name = optarg;
|
||||
break;
|
||||
@@ -232,9 +240,8 @@ int main(int argc, char **argv)
|
||||
case 'C':
|
||||
opts.compress++;
|
||||
break;
|
||||
case 'v':
|
||||
case 'd':
|
||||
opts.debuglevel++;
|
||||
verbose++;
|
||||
break;
|
||||
case 'h':
|
||||
usage(true);
|
||||
@@ -245,6 +252,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
pprint_set_level(verbose);
|
||||
|
||||
if (max_chunk_sz > 0 && min_chunk_sz > max_chunk_sz) {
|
||||
pr_err("smaller max chunk size than min chunk size: %d < %d\n",
|
||||
max_chunk_sz, min_chunk_sz);
|
||||
@@ -265,6 +274,7 @@ int main(int argc, char **argv)
|
||||
pr_err("no remote host given\n");
|
||||
return 1;
|
||||
}
|
||||
pprint3("connecting to %s for checking destinations...\n", sscp.host);
|
||||
sscp.ctrl = ssh_make_sftp_session(sscp.host, &opts);
|
||||
if (!sscp.ctrl)
|
||||
return 1;
|
||||
@@ -317,6 +327,7 @@ int main(int argc, char **argv)
|
||||
struct sscp_thread *t = &threads[n];
|
||||
t->sscp = &sscp;
|
||||
t->finished = false;
|
||||
pprint3("connecting to %s for a copy thread...\n", sscp.host);
|
||||
t->sftp = ssh_make_sftp_session(sscp.host, sscp.opts);
|
||||
if (!t->sftp)
|
||||
goto join_out;
|
||||
@@ -451,10 +462,7 @@ static void print_progress_bar(double percent, char *suffix)
|
||||
" %3d%% ", (int)floor(percent));
|
||||
}
|
||||
|
||||
fputs("\r\033[K", stderr);
|
||||
fputs(buf, stderr);
|
||||
fputs(suffix, stderr);
|
||||
fflush(stderr);
|
||||
pprint1("%s%s", buf, suffix);
|
||||
}
|
||||
|
||||
static void print_progress(struct timeval *start, struct timeval *end,
|
||||
@@ -513,6 +521,7 @@ void sscp_monitor_thread_cleanup(void *arg)
|
||||
}
|
||||
|
||||
print_progress(&sscp->start, &end, total, 0, done);
|
||||
fputs("\n", stdout); /* the final ouput. we need \n */
|
||||
}
|
||||
|
||||
void *sscp_monitor_thread(void *arg)
|
||||
@@ -560,7 +569,5 @@ void *sscp_monitor_thread(void *arg)
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
fputs("\n", stderr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
32
src/pprint.c
Normal file
32
src/pprint.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static int pprint_level = 1;
|
||||
/* level 1: print progress bar only.
|
||||
* level 2: print copy start/done messages.
|
||||
* level 3: print ssh connection establishment/disconnection.
|
||||
* level 4: print chunk information.
|
||||
*/
|
||||
|
||||
static pthread_mutex_t pprint_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void pprint_set_level(int level)
|
||||
{
|
||||
pprint_level = level;
|
||||
}
|
||||
|
||||
void pprint(int level, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
if (level <= pprint_level) {
|
||||
pthread_mutex_lock(&pprint_lock);
|
||||
va_start(va, fmt);
|
||||
vfprintf(stdout, fmt, va);
|
||||
fflush(stdout);
|
||||
va_end(va);
|
||||
pthread_mutex_unlock(&pprint_lock);
|
||||
}
|
||||
}
|
||||
|
||||
14
src/pprint.h
Normal file
14
src/pprint.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef _PPRINT_H_
|
||||
#define _PPRINT_H_
|
||||
|
||||
/* progress print functions */
|
||||
|
||||
void pprint_set_level(int level);
|
||||
void pprint(int level, const char *fmt, ...);
|
||||
|
||||
#define pprint1(fmt, ...) pprint(1, "\r\033[K" fmt, ##__VA_ARGS__)
|
||||
#define pprint2(fmt, ...) pprint(2, "\r\033[K" fmt, ##__VA_ARGS__)
|
||||
#define pprint3(fmt, ...) pprint(3, "\r\033[K" fmt, ##__VA_ARGS__)
|
||||
#define pprint4(fmt, ...) pprint(4, "\r\033[K" fmt, ##__VA_ARGS__)
|
||||
|
||||
#endif /* _PPRRINT_H_ */
|
||||
14
src/util.h
14
src/util.h
@@ -8,20 +8,6 @@
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
extern int verbose;
|
||||
|
||||
#define pr_v(level, fmt, ...) do { \
|
||||
if (verbose >= level) { \
|
||||
fprintf(stdout, "\x1b[1m\x1b[34m" \
|
||||
"%s(): \x1b[0m" fmt, \
|
||||
__func__, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define pr_v1(fmt, ...) pr_v(1, fmt, ##__VA_ARGS__)
|
||||
#define pr_v2(fmt, ...) pr_v(2, fmt, ##__VA_ARGS__)
|
||||
#define pr_v3(fmt, ...) pr_v(3, fmt, ##__VA_ARGS__)
|
||||
|
||||
|
||||
#define pr(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user