diff options
author | Ryo Nakamura <upa@haeena.net> | 2022-10-29 23:48:50 +0900 |
---|---|---|
committer | Ryo Nakamura <upa@haeena.net> | 2022-10-29 23:48:50 +0900 |
commit | c76fa3141dd648b145dde2534a1ca3824ff81466 (patch) | |
tree | 6be1bc1f5ce8c0a200b65cba34987b1df2844239 /src | |
parent | ff697aa514b13cbb8105f2f3c04c1889820796d9 (diff) |
change indent from space to tab
Diffstat (limited to 'src')
-rw-r--r-- | src/atomic.h | 50 | ||||
-rw-r--r-- | src/file.c | 1220 | ||||
-rw-r--r-- | src/file.h | 34 | ||||
-rw-r--r-- | src/main.c | 832 | ||||
-rw-r--r-- | src/platform.c | 22 | ||||
-rw-r--r-- | src/pprint.c | 20 | ||||
-rw-r--r-- | src/ssh.c | 440 | ||||
-rw-r--r-- | src/ssh.h | 16 | ||||
-rw-r--r-- | src/util.h | 6 |
9 files changed, 1320 insertions, 1320 deletions
diff --git a/src/atomic.h b/src/atomic.h index 4f643e9..e0e735d 100644 --- a/src/atomic.h +++ b/src/atomic.h @@ -9,12 +9,12 @@ typedef int refcnt; static inline void refcnt_inc(refcnt *cnt) { - __sync_add_and_fetch(cnt, 1); + __sync_add_and_fetch(cnt, 1); } static inline refcnt refcnt_dec(refcnt *cnt) { - return __sync_sub_and_fetch(cnt, 1); + return __sync_sub_and_fetch(cnt, 1); } @@ -22,37 +22,37 @@ typedef pthread_mutex_t lock; static inline void lock_init(lock *l) { - pthread_mutex_init(l, NULL); + pthread_mutex_init(l, NULL); } static inline void lock_acquire(lock *l) { - int ret = pthread_mutex_lock(l); - if (ret < 0) { - switch (ret) { - case EINVAL: - pr_err("invalid mutex\n"); - exit(1); - case EDEADLK: - pr_err("a deadlock would occur\n"); - exit(1); - } - } + int ret = pthread_mutex_lock(l); + if (ret < 0) { + switch (ret) { + case EINVAL: + pr_err("invalid mutex\n"); + exit(1); + case EDEADLK: + pr_err("a deadlock would occur\n"); + exit(1); + } + } } static inline void lock_release(lock *l) { - int ret = pthread_mutex_unlock(l); - if (ret < 0) { - switch (ret) { - case EINVAL: - pr_err("invalid mutex\n"); - exit(1); - case EPERM: - pr_err("this thread does not hold this mutex\n"); - exit(1); - } - } + int ret = pthread_mutex_unlock(l); + if (ret < 0) { + switch (ret) { + case EINVAL: + pr_err("invalid mutex\n"); + exit(1); + case EPERM: + pr_err("this thread does not hold this mutex\n"); + exit(1); + } + } } #endif /* _ATOMIC_H_ */ @@ -13,758 +13,758 @@ bool file_has_hostname(char *path) { - char *p; + char *p; - p = strchr(path, ':'); - if (p) { - if (p == path || ((p > path) && *(p - 1) == '\\')) - return false; /* first byte is colon or escaped colon, skip */ - else - return true; - } + p = strchr(path, ':'); + if (p) { + if (p == path || ((p > path) && *(p - 1) == '\\')) + return false; /* first byte is colon or escaped colon, skip */ + else + return true; + } - return false; + return false; } char *file_find_hostname(char *path) { - char *dup, *p; - - dup = strdup(path); - if (!dup) { - pr_err("%s", strerrno()); - return NULL; - } - - p = strchr(dup, ':'); - if (p) { - if (p == dup || ((p > dup) && *(p - 1) == '\\')) { - /* first byte is colon or escaped colon, skip */ - free(dup); - } else { - /* handle this as remote hostname (with username) */ - *p = '\0'; - return dup; - } - } - - return NULL; + char *dup, *p; + + dup = strdup(path); + if (!dup) { + pr_err("%s", strerrno()); + return NULL; + } + + p = strchr(dup, ':'); + if (p) { + if (p == dup || ((p > dup) && *(p - 1) == '\\')) { + /* first byte is colon or escaped colon, skip */ + free(dup); + } else { + /* handle this as remote hostname (with username) */ + *p = '\0'; + return dup; + } + } + + return NULL; } static char *file_find_path(char *path) { - char *p; - - p = strchr(path, ':'); - if (p) { - if (p == path || ((p > path) && *(p - 1) == '\\')) { - /* first byte is colon or escaped colon, skip */ - return path; - } else { - return p + 1; - } - } - - return path; + char *p; + + p = strchr(path, ':'); + if (p) { + if (p == path || ((p > path) && *(p - 1) == '\\')) { + /* first byte is colon or escaped colon, skip */ + return path; + } else { + return p + 1; + } + } + + return path; } /* return 1 when path is directory, 0 is not directory, and -1 on error */ static int file_is_directory(char *path, sftp_session sftp, bool print_error) { - int ret = 0; - - if (sftp) { - char *remote_path = file_find_path(path); - sftp_attributes attr; - - char *p = *remote_path == '\0' ? "." : remote_path; - attr = sftp_stat(sftp, p); - if (!attr) { - if (print_error) - pr_err("sftp_stat %s: %s\n", - path, sftp_get_ssh_error(sftp)); - ret = -1; - } else if (attr->type == SSH_FILEXFER_TYPE_DIRECTORY) - ret = 1; - sftp_attributes_free(attr); - } else { - struct stat statbuf; - if (stat(path, &statbuf) < 0) { - if (print_error) - pr_err("stat %s: %s\n", path, strerrno()); - ret = -1; - } else if (S_ISDIR(statbuf.st_mode)) - ret = 1; - } - - return ret; + int ret = 0; + + if (sftp) { + char *remote_path = file_find_path(path); + sftp_attributes attr; + + char *p = *remote_path == '\0' ? "." : remote_path; + attr = sftp_stat(sftp, p); + if (!attr) { + if (print_error) + pr_err("sftp_stat %s: %s\n", + path, sftp_get_ssh_error(sftp)); + ret = -1; + } else if (attr->type == SSH_FILEXFER_TYPE_DIRECTORY) + ret = 1; + sftp_attributes_free(attr); + } else { + struct stat statbuf; + if (stat(path, &statbuf) < 0) { + if (print_error) + pr_err("stat %s: %s\n", path, strerrno()); + ret = -1; + } else if (S_ISDIR(statbuf.st_mode)) + ret = 1; + } + + return ret; } /* return 1 when directory exists, 0 not exists, and -1 on error */ int file_directory_exists(char *path, sftp_session sftp) { - int ret = 0; - - if (sftp) { - sftp_attributes attr; - attr = sftp_stat(sftp, path); - if (!attr) { - if (sftp_get_error(sftp) == SSH_FX_NO_SUCH_PATH || - sftp_get_error(sftp) == SSH_FX_NO_SUCH_FILE) - ret = 0; - else { - pr_err("%s: %s\n", path, ssh_get_error(sftp_ssh(sftp))); - ret = -1; - } - } else if (attr->type == SSH_FILEXFER_TYPE_DIRECTORY) - ret = 1; - sftp_attributes_free(attr); - } else { - struct stat statbuf; - if (stat(path, &statbuf) < 0) { - if (errno == ENOENT) - ret = 0; - else { - pr_err("%s: %s\n", path, strerrno()); - ret = -1; - } - } else if ((statbuf.st_mode & S_IFMT) == S_IFDIR) - ret = 1; - } - - return ret; + int ret = 0; + + if (sftp) { + sftp_attributes attr; + attr = sftp_stat(sftp, path); + if (!attr) { + if (sftp_get_error(sftp) == SSH_FX_NO_SUCH_PATH || + sftp_get_error(sftp) == SSH_FX_NO_SUCH_FILE) + ret = 0; + else { + pr_err("%s: %s\n", path, ssh_get_error(sftp_ssh(sftp))); + ret = -1; + } + } else if (attr->type == SSH_FILEXFER_TYPE_DIRECTORY) + ret = 1; + sftp_attributes_free(attr); + } else { + struct stat statbuf; + if (stat(path, &statbuf) < 0) { + if (errno == ENOENT) + ret = 0; + else { + pr_err("%s: %s\n", path, strerrno()); + ret = -1; + } + } else if ((statbuf.st_mode & S_IFMT) == S_IFDIR) + ret = 1; + } + + return ret; } static struct file *file_alloc(char *path, size_t size, bool remote) { - struct file *f; - - f = malloc(sizeof(*f)); - if (!f) { - pr_err("%s\n", strerrno()); - return NULL; - } - memset(f, 0, sizeof(*f)); - - strncpy(f->path, path, PATH_MAX - 1); - f->size = size; - f->remote = remote; - f->dst_remote = !remote; - lock_init(&f->lock); - - return f; + struct file *f; + + f = malloc(sizeof(*f)); + if (!f) { + pr_err("%s\n", strerrno()); + return NULL; + } + memset(f, 0, sizeof(*f)); + + strncpy(f->path, path, PATH_MAX - 1); + f->size = size; + f->remote = remote; + f->dst_remote = !remote; + lock_init(&f->lock); + + return f; } static bool file_should_skip(char *path) { - int len = strlen(path); - if ((len == 1 && strncmp(path, ".", 1) == 0) || - (len == 2 && strncmp(path, "..", 2) == 0)) { - return true; - } - return false; + int len = strlen(path); + if ((len == 1 && strncmp(path, ".", 1) == 0) || + (len == 2 && strncmp(path, "..", 2) == 0)) { + return true; + } + return false; } /* return -1 when error, 0 when should skip, and 1 when should be copied */ static int check_file_tobe_copied(char *path, sftp_session sftp, size_t *size) { - struct stat statbuf; - sftp_attributes attr; - int ret = 0; - - if (!sftp) { - /* local */ - if (stat(path, &statbuf) < 0) { - pr_err("failed to get stat for %s: %s\n", path, strerrno()); - return -1; - } - if (S_ISREG(statbuf.st_mode)) { - *size = statbuf.st_size; - return 1; - } - return 0; - } - - /* remote */ - attr = sftp_stat(sftp, path); - if (!attr) { - pr_err("failed to get stat for %s: %s\n", - path, ssh_get_error(sftp_ssh(sftp))); - return -1; - } - if (attr->type == SSH_FILEXFER_TYPE_REGULAR || - attr->type == SSH_FILEXFER_TYPE_SYMLINK) { - *size = attr->size; - ret = 1; - } - - sftp_attributes_free(attr); - - return ret; + struct stat statbuf; + sftp_attributes attr; + int ret = 0; + + if (!sftp) { + /* local */ + if (stat(path, &statbuf) < 0) { + pr_err("failed to get stat for %s: %s\n", path, strerrno()); + return -1; + } + if (S_ISREG(statbuf.st_mode)) { + *size = statbuf.st_size; + return 1; + } + return 0; + } + + /* remote */ + attr = sftp_stat(sftp, path); + if (!attr) { + pr_err("failed to get stat for %s: %s\n", + path, ssh_get_error(sftp_ssh(sftp))); + return -1; + } + if (attr->type == SSH_FILEXFER_TYPE_REGULAR || + attr->type == SSH_FILEXFER_TYPE_SYMLINK) { + *size = attr->size; + ret = 1; + } + + sftp_attributes_free(attr); + + return ret; } static int file_fill_recursive(struct list_head *file_list, - bool dst_is_remote, sftp_session sftp, char *src_path, - char *rel_path, char *dst_path, bool dst_should_dir) + bool dst_is_remote, sftp_session sftp, char *src_path, + char *rel_path, char *dst_path, bool dst_should_dir) { - char next_src_path[PATH_MAX], next_rel_path[PATH_MAX]; - struct file *f; - size_t size; - int ret; - - ret = file_is_directory(src_path, dst_is_remote ? NULL : sftp, true); - if (ret < 0) - return -1; - - if (ret == 0) { - /* src_path is file */ - ret = check_file_tobe_copied(src_path, dst_is_remote ? NULL : sftp, - &size); - if (ret <= 0) - return ret; /* error or skip */ - - if ((f = file_alloc(src_path, size, !dst_is_remote)) == NULL) { - pr_err("%s\n", strerrno()); - return -1; - } - - if (dst_should_dir) - snprintf(f->dst_path, PATH_MAX, "%s/%s%s", - dst_path, rel_path, basename(src_path)); - else - snprintf(f->dst_path, PATH_MAX, "%s%s", rel_path, dst_path); - - list_add_tail(&f->list, file_list); - pprint2("file %s %s -> %s %s\n", - f->path, dst_is_remote ? "(local)" : "(remote)", - f->dst_path, dst_is_remote ? "(remote)" : "(local)"); - - return 0; - } - - /* src_path is directory */ - if (dst_is_remote) { - /* src_path is local directory */ - struct dirent *de; - DIR *dir; - if ((dir = opendir(src_path)) == NULL) { - pr_err("opendir '%s': %s\n", src_path, strerrno()); - return -1; - } - while ((de = readdir(dir)) != NULL) { - if (file_should_skip(de->d_name)) - continue; - snprintf(next_src_path, sizeof(next_src_path), - "%s/%s", src_path, de->d_name); - snprintf(next_rel_path, sizeof(next_rel_path), - "%s%s/", rel_path, basename(src_path)); - ret = file_fill_recursive(file_list, dst_is_remote, sftp, - next_src_path, next_rel_path, - dst_path, dst_should_dir); - if (ret < 0) - return ret; - } - } else { - /* src_path is remote directory */ - sftp_attributes attr; - sftp_dir dir; - if ((dir = sftp_opendir(sftp, src_path)) == NULL) { - pr_err("sftp_opendir: '%s': %s\n", src_path, - sftp_get_ssh_error(sftp)); - return -1; - } - while ((attr = sftp_readdir(sftp, dir)) != NULL) { - if (file_should_skip(attr->name)) - continue; - snprintf(next_src_path, sizeof(next_src_path), - "%s/%s", src_path, attr->name); - snprintf(next_rel_path, sizeof(next_rel_path), - "%s%s/", rel_path, basename(src_path)); - ret = file_fill_recursive(file_list, dst_is_remote, sftp, - next_src_path, next_rel_path, - dst_path, dst_should_dir); - if (ret < 0) - return ret; - } - } - - return 0; + char next_src_path[PATH_MAX], next_rel_path[PATH_MAX]; + struct file *f; + size_t size; + int ret; + + ret = file_is_directory(src_path, dst_is_remote ? NULL : sftp, true); + if (ret < 0) + return -1; + + if (ret == 0) { + /* src_path is file */ + ret = check_file_tobe_copied(src_path, dst_is_remote ? NULL : sftp, + &size); + if (ret <= 0) + return ret; /* error or skip */ + + if ((f = file_alloc(src_path, size, !dst_is_remote)) == NULL) { + pr_err("%s\n", strerrno()); + return -1; + } + + if (dst_should_dir) + snprintf(f->dst_path, PATH_MAX, "%s/%s%s", + dst_path, rel_path, basename(src_path)); + else + snprintf(f->dst_path, PATH_MAX, "%s%s", rel_path, dst_path); + + list_add_tail(&f->list, file_list); + pprint2("file %s %s -> %s %s\n", + f->path, dst_is_remote ? "(local)" : "(remote)", + f->dst_path, dst_is_remote ? "(remote)" : "(local)"); + + return 0; + } + + /* src_path is directory */ + if (dst_is_remote) { + /* src_path is local directory */ + struct dirent *de; + DIR *dir; + if ((dir = opendir(src_path)) == NULL) { + pr_err("opendir '%s': %s\n", src_path, strerrno()); + return -1; + } + while ((de = readdir(dir)) != NULL) { + if (file_should_skip(de->d_name)) + continue; + snprintf(next_src_path, sizeof(next_src_path), + "%s/%s", src_path, de->d_name); + snprintf(next_rel_path, sizeof(next_rel_path), + "%s%s/", rel_path, basename(src_path)); + ret = file_fill_recursive(file_list, dst_is_remote, sftp, + next_src_path, next_rel_path, + dst_path, dst_should_dir); + if (ret < 0) + return ret; + } + } else { + /* src_path is remote directory */ + sftp_attributes attr; + sftp_dir dir; + if ((dir = sftp_opendir(sftp, src_path)) == NULL) { + pr_err("sftp_opendir: '%s': %s\n", src_path, + sftp_get_ssh_error(sftp)); + return -1; + } + while ((attr = sftp_readdir(sftp, dir)) != NULL) { + if (file_should_skip(attr->name)) + continue; + snprintf(next_src_path, sizeof(next_src_path), + "%s/%s", src_path, attr->name); + snprintf(next_rel_path, sizeof(next_rel_path), + "%s%s/", rel_path, basename(src_path)); + ret = file_fill_recursive(file_list, dst_is_remote, sftp, + next_src_path, next_rel_path, + dst_path, dst_should_dir); + if (ret < 0) + return ret; + } + } + + return 0; } int file_fill(sftp_session sftp, struct list_head *file_list, char **src_array, int cnt, - char *dst) + char *dst) { - bool dst_is_remote, dst_is_dir, dst_should_dir; - char *dst_path, *src_path; - int n, ret; - - dst_path = file_find_path(dst); - dst_path = *dst_path == '\0' ? "." : dst_path; - dst_is_remote = file_find_hostname(dst) ? true : false; - - if (file_is_directory(dst_path, dst_is_remote ? sftp : NULL, false) > 0) - dst_is_dir = true; - else - dst_is_dir = false; - - for (n = 0; n < cnt; n++) { - src_path = file_find_path(src_array[n]); - - if (file_is_directory(src_path, dst_is_remote ? NULL : sftp, false) > 0) - dst_should_dir = true; - else - dst_should_dir = false; - ret = file_fill_recursive(file_list, dst_is_remote, sftp, - src_path, "", - dst_path, dst_is_dir | dst_should_dir); - if (ret < 0) - return ret; - } - - return 0; + bool dst_is_remote, dst_is_dir, dst_should_dir; + char *dst_path, *src_path; + int n, ret; + + dst_path = file_find_path(dst); + dst_path = *dst_path == '\0' ? "." : dst_path; + dst_is_remote = file_find_hostname(dst) ? true : false; + + if (file_is_directory(dst_path, dst_is_remote ? sftp : NULL, false) > 0) + dst_is_dir = true; + else + dst_is_dir = false; + + for (n = 0; n < cnt; n++) { + src_path = file_find_path(src_array[n]); + + if (file_is_directory(src_path, dst_is_remote ? NULL : sftp, false) > 0) + dst_should_dir = true; + else + dst_should_dir = false; + ret = file_fill_recursive(file_list, dst_is_remote, sftp, + src_path, "", + dst_path, dst_is_dir | dst_should_dir); + if (ret < 0) + return ret; + } + + return 0; } /* based on * https://stackoverflow.com/questions/2336242/recursive-mkdir-system-call-on-unix */ static int file_dst_prepare(struct file *f, sftp_session sftp) { - /* XXX: should reflect the permission of the original directory? */ - mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; - char path[PATH_MAX]; - char *p; - int ret; - - strncpy(path, f->dst_path, sizeof(path)); - - pr_debug("prepare for %s\n", path); - - for (p = strchr(path + 1, '/'); p; p = strchr(p + 1, '/')) { - *p = '\0'; - - ret = file_directory_exists(path, sftp); - pr_debug("check %s ret=%d\n", path, ret); - if (ret < -1) - return -1; - if (ret == 1) - goto next; - - pr_debug("mkdir %s\n", path); - - if (sftp) { - ret = sftp_mkdir(sftp, path, mode); - if (ret < 0 && - sftp_get_error(sftp) != SSH_FX_FILE_ALREADY_EXISTS) { - pr_err("failed to create %s: %s\n", - path, ssh_get_error(sftp_ssh(sftp))); - return -1; - } - } else { - if (mkdir(path, mode) == -1 && errno != EEXIST) { - pr_err("failed to create %s: %s\n", - path, strerrno()); - return -1; - } - } - next: - *p = '/'; - } - - return 0; + /* XXX: should reflect the permission of the original directory? */ + mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; + char path[PATH_MAX]; + char *p; + int ret; + + strncpy(path, f->dst_path, sizeof(path)); + + pr_debug("prepare for %s\n", path); + + for (p = strchr(path + 1, '/'); p; p = strchr(p + 1, '/')) { + *p = '\0'; + + ret = file_directory_exists(path, sftp); + pr_debug("check %s ret=%d\n", path, ret); + if (ret < -1) + return -1; + if (ret == 1) + goto next; + + pr_debug("mkdir %s\n", path); + + if (sftp) { + ret = sftp_mkdir(sftp, path, mode); + if (ret < 0 && + sftp_get_error(sftp) != SSH_FX_FILE_ALREADY_EXISTS) { + pr_err("failed to create %s: %s\n", + path, ssh_get_error(sftp_ssh(sftp))); + return -1; + } + } else { + if (mkdir(path, mode) == -1 && errno != EEXIST) { + pr_err("failed to create %s: %s\n", + path, strerrno()); + return -1; + } + } + next: + *p = '/'; + } + + return 0; } #ifdef DEBUG void file_dump(struct list_head *file_list) { - struct file *f; - - list_for_each_entry(f, file_list, list) { - pr_debug("%s %s -> %s %s %lu-byte\n", - f->path, f->remote ? "(remote)" : "(local)", - f->dst_path, f->dst_remote ? "(remote)" : "(local)", - f->size); - } + struct file *f; + + list_for_each_entry(f, file_list, list) { + pr_debug("%s %s -> %s %s %lu-byte\n", + f->path, f->remote ? "(remote)" : "(local)", + f->dst_path, f->dst_remote ? "(remote)" : "(local)", + f->size); + } } #endif static void *chunk_alloc(struct file *f) { - struct chunk *c; - - c = malloc(sizeof(*c)); - if (!c) { - pr_err("%s\n", strerrno()); - return NULL; - } - memset(c, 0, sizeof(*c)); - - c->f = f; - c->off = 0; - c->len = 0; - refcnt_inc(&f->refcnt); - return c; + struct chunk *c; + + c = malloc(sizeof(*c)); + if (!c) { + pr_err("%s\n", strerrno()); + return NULL; + } + memset(c, 0, sizeof(*c)); + + c->f = f; + c->off = 0; + c->len = 0; + refcnt_inc(&f->refcnt); + return c; } static int get_page_mask(void) { - int n; - long page_sz = sysconf(_SC_PAGESIZE); - size_t page_mask = 0; + int n; + long page_sz = sysconf(_SC_PAGESIZE); + size_t page_mask = 0; - for (n = 0; page_sz > 0; page_sz >>= 1, n++) { - page_mask <<= 1; - page_mask |= 1; - } + for (n = 0; page_sz > 0; page_sz >>= 1, n++) { + page_mask <<= 1; + page_mask |= 1; + } - return page_mask >> 1; + return page_mask >> 1; } int chunk_fill(struct list_head *file_list, struct list_head *chunk_list, - int nr_conn, int min_chunk_sz, int max_chunk_sz) + int nr_conn, int min_chunk_sz, int max_chunk_sz) { - struct chunk *c; - struct file *f; - size_t page_mask; - size_t chunk_sz; - size_t size; - - page_mask = get_page_mask(); - - list_for_each_entry(f, file_list, list) { - if (f->size <= min_chunk_sz) - chunk_sz = f->size; - else if (max_chunk_sz) - chunk_sz = max_chunk_sz; - else { - chunk_sz = (f->size - (f->size % nr_conn)) / nr_conn; - chunk_sz &= ~page_mask; /* align in page_sz */ - if (chunk_sz <= min_chunk_sz) - chunk_sz = min_chunk_sz; - } - - pr_debug("%s chunk_sz %lu-byte\n", f->path, chunk_sz); - - for (size = f->size; size > 0;) { - c = chunk_alloc(f); - if (!c) - return -1; - c->off = f->size - size; - 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); - } - } - - return 0; + struct chunk *c; + struct file *f; + size_t page_mask; + size_t chunk_sz; + size_t size; + + page_mask = get_page_mask(); + + list_for_each_entry(f, file_list, list) { + if (f->size <= min_chunk_sz) + chunk_sz = f->size; + else if (max_chunk_sz) + chunk_sz = max_chunk_sz; + else { + chunk_sz = (f->size - (f->size % nr_conn)) / nr_conn; + chunk_sz &= ~page_mask; /* align in page_sz */ + if (chunk_sz <= min_chunk_sz) + chunk_sz = min_chunk_sz; + } + + pr_debug("%s chunk_sz %lu-byte\n", f->path, chunk_sz); + + for (size = f->size; size > 0;) { + c = chunk_alloc(f); + if (!c) + return -1; + c->off = f->size - size; + 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); + } + } + + return 0; } #ifdef DEBUG void chunk_dump(struct list_head *chunk_list) { - struct chunk *c; + struct chunk *c; - list_for_each_entry(c, chunk_list, list) { - pr_debug("%s %s 0x%010lx-0x%010lx %lu-byte\n", - c->f->path, c->f->remote ? "(remote)" : "(local)", - c->off, c->off + c->len, c->len); - } + list_for_each_entry(c, chunk_list, list) { + pr_debug("%s %s 0x%010lx-0x%010lx %lu-byte\n", + c->f->path, c->f->remote ? "(remote)" : "(local)", + c->off, c->off + c->len, c->len); + } } #endif struct chunk *chunk_acquire(struct list_head *chunk_list) { - /* under the lock for chunk_list */ + /* under the lock for chunk_list */ - struct list_head *first = chunk_list->next; - struct chunk *c = NULL; + struct list_head *first = chunk_list->next; + struct chunk *c = NULL; - if (list_empty(chunk_list)) - return NULL; /* list is empty */ + if (list_empty(chunk_list)) + return NULL; /* list is empty */ - c = list_entry(first, struct chunk, list); - list_del(first); - return c; + c = list_entry(first, struct chunk, list); + list_del(first); + return c; } int chunk_prepare(struct chunk *c, sftp_session sftp) { - struct file *f = c->f; - int ret = 0; - - lock_acquire(&f->lock); /* XXX: is always acquiring lock per-chunk heavy? */ - if (f->state == FILE_STATE_INIT) { - if (file_dst_prepare(f, f->dst_remote ? sftp : NULL) < 0) { - ret = -1; - goto out; - } - f->state = FILE_STATE_OPENED; - pprint2("copy start: %s\n", f->path); - } + struct file *f = c->f; + int ret = 0; + + lock_acquire(&f->lock); /* XXX: is always acquiring lock per-chunk heavy? */ + if (f->state == FILE_STATE_INIT) { + if (file_dst_prepare(f, f->dst_remote ? sftp : NULL) < 0) { + ret = -1; + goto out; + } + f->state = FILE_STATE_OPENED; + pprint2("copy start: %s\n", f->path); + } out: - lock_release(&f->lock); - return ret; + lock_release(&f->lock); + return ret; } static mode_t chunk_get_mode(const char *path, sftp_session sftp) { - mode_t mode; - - if (sftp) { - sftp_attributes attr = sftp_stat(sftp, path); - if (!attr) { - pr_err("failed to get stat for %s: %s\n", - path, ssh_get_error(sftp_ssh(sftp))); - return -1; - } - mode = attr->permissions; - sftp_attributes_free(attr); - } else { - struct stat statbuf; - if (stat(path, &statbuf) < 0) { - pr_err("failed to get stat for %s: %s\n", - path, strerrno()); - return -1; - } - mode = statbuf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO); - } - return mode; + mode_t mode; + + if (sftp) { + sftp_attributes attr = sftp_stat(sftp, path); + if (!attr) { + pr_err("failed to get stat for %s: %s\n", + path, ssh_get_error(sftp_ssh(sftp))); + return -1; + } + mode = attr->permissions; + sftp_attributes_free(attr); + } else { + struct stat statbuf; + if (stat(path, &statbuf) < 0) { + pr_err("failed to get stat for %s: %s\n", + path, strerrno()); + return -1; + } + mode = statbuf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO); + } + return mode; } static int chunk_set_mode(const char *path, mode_t mode, sftp_session sftp) { - if (sftp) { - if (sftp_chmod(sftp, path, mode) < 0) { - pr_err("failed to chmod %s: %s\n", - path, ssh_get_error(sftp_ssh(sftp))); - return -1; - } - } else { - if (chmod(path, mode) < 0) { - pr_err("failed to chmod %s: %s\n", - path, strerrno()); - return -1; - } - } - - return 0; + if (sftp) { + if (sftp_chmod(sftp, path, mode) < 0) { + pr_err("failed to chmod %s: %s\n", + path, ssh_get_error(sftp_ssh(sftp))); + return -1; + } + } else { + if (chmod(path, mode) < 0) { + pr_err("failed to chmod %s: %s\n", + path, strerrno()); + return -1; + } + } + + return 0; } static int chunk_open_local(const char *path, int flags, mode_t mode, size_t off) { - int fd; - - fd = open(path, flags, mode); - if (fd < 0) { - pr_err("open failed for %s: %s\n", path, strerrno()); - return -1; - } - if (lseek(fd, off, SEEK_SET) < 0) { - pr_err("seek error for %s: %s\n", path, strerrno()); - close(fd); - return -1; - } - - return fd; + int fd; + + fd = open(path, flags, mode); + if (fd < 0) { + pr_err("open failed for %s: %s\n", path, strerrno()); + return -1; + } + if (lseek(fd, off, SEEK_SET) < 0) { + pr_err("seek error for %s: %s\n", path, strerrno()); + close(fd); + return -1; + } + + return fd; } static sftp_file chunk_open_remote(const char *path, int flags, mode_t mode, size_t off, - sftp_session sftp) + sftp_session sftp) { - sftp_file sf; + sftp_file sf; - sf = sftp_open(sftp, path, flags, mode); + sf = sftp_open(sftp, path, flags, mode); - if (!sf) { - pr_err("open failed for remote %s: %s\n", - path, ssh_get_error(sftp_ssh(sftp))); - return NULL; - } + if (!sf) { + pr_err("open failed for remote %s: %s\n", + path, ssh_get_error(sftp_ssh(sftp))); + return NULL; + } - if (sftp_seek64(sf, off) < 0) { - pr_err("seek error for %s: %s\n", path, ssh_get_error(sftp_ssh(sftp))); - return NULL; - } + if (sftp_seek64(sf, off) < 0) { + pr_err("seek error for %s: %s\n", path, ssh_get_error(sftp_ssh(sftp))); + return NULL; + } - return sf; + return sf; } static int chunk_copy_internal(struct chunk *c, int fd, sftp_file sf, - size_t sftp_buf_sz, size_t io_buf_sz, - bool reverse, size_t *counter) + size_t sftp_buf_sz, size_t io_buf_sz, + bool reverse, size_t *counter) { - int remaind, read_bytes, write_bytes; - char buf[io_buf_sz]; - - /* if reverse is false, copy fd->sf (local to remote). - * if reverse is true, copy sf->fd (remote to local) - */ - - for (remaind = c->len; remaind > 0;) { - - if (!reverse) - read_bytes = read(fd, buf, min(remaind, io_buf_sz)); - else - read_bytes = sftp_read2(sf, buf, min(remaind, io_buf_sz), - sftp_buf_sz); - - if (read_bytes < 0) { - pr_err("failed to read %s: %s\n", c->f->dst_path, - !reverse ? - strerrno() : ssh_get_error(sftp_ssh(sf->sftp))); - return -1; - } - - if (!reverse) - write_bytes = sftp_write2(sf, buf, read_bytes, sftp_buf_sz); - else - write_bytes = write(fd, buf, read_bytes); - - if (write_bytes < 0) { - pr_err("failed to write %s: %s\n", c->f->dst_path, - !reverse ? - strerrno() : ssh_get_error(sftp_ssh(sf->sftp))); - return -1; - } - - if (write_bytes < read_bytes) { - pr_err("failed to write full bytes to %s\n", c->f->dst_path); - return -1; - } - - *counter += write_bytes; - remaind -= write_bytes; - } - - return 0; + int remaind, read_bytes, write_bytes; + char buf[io_buf_sz]; + + /* if reverse is false, copy fd->sf (local to remote). + * if reverse is true, copy sf->fd (remote to local) + */ + + for (remaind = c->len; remaind > 0;) { + + if (!reverse) + read_bytes = read(fd, buf, min(remaind, io_buf_sz)); + else + read_bytes = sftp_read2(sf, buf, min(remaind, io_buf_sz), + sftp_buf_sz); + + if (read_bytes < 0) { + pr_err("failed to read %s: %s\n", c->f->dst_path, + !reverse ? + strerrno() : ssh_get_error(sftp_ssh(sf->sftp))); + return -1; + } + + if (!reverse) + write_bytes = sftp_write2(sf, buf, read_bytes, sftp_buf_sz); + else + write_bytes = write(fd, buf, read_bytes); + + if (write_bytes < 0) { + pr_err("failed to write %s: %s\n", c->f->dst_path, + !reverse ? + strerrno() : ssh_get_error(sftp_ssh(sf->sftp))); + return -1; + } + + if (write_bytes < read_bytes) { + pr_err("failed to write full bytes to %s\n", c->f->dst_path); + return -1; + } + + *counter += write_bytes; + remaind -= write_bytes; + } + + return 0; } static int chunk_copy_local_to_remote(struct chunk *c, sftp_session sftp, - size_t sftp_buf_sz, size_t io_buf_sz, - size_t *counter) + size_t sftp_buf_sz, size_t io_buf_sz, + size_t *counter) { - struct file *f = c->f; - sftp_file sf = NULL; - mode_t mode; - int ret = 0; - int fd = 0; - int flags; - - flags = O_RDONLY; - mode = S_IRUSR; - if ((fd = chunk_open_local(f->path, flags, mode, c->off)) < 0) { - ret = -1; - goto out; - } - - flags = O_WRONLY|O_CREAT; - mode = S_IRUSR|S_IWUSR; - if (!(sf = chunk_open_remote(f->dst_path, flags, mode, c->off, sftp))) { - ret = -1; - goto out; - } - - ret = chunk_copy_internal(c, fd, sf, sftp_buf_sz, io_buf_sz, false, counter); - if (ret< 0) - goto out; - - if ((mode = chunk_get_mode(f->path, NULL)) < 0) { - ret = -1; - goto out; - } - if (chunk_set_mode(f->dst_path, mode, sftp) < 0) { - ret = -1; - } + struct file *f = c->f; + sftp_file sf = NULL; + mode_t mode; + int ret = 0; + int fd = 0; + int flags; + + flags = O_RDONLY; + mode = S_IRUSR; + if ((fd = chunk_open_local(f->path, flags, mode, c->off)) < 0) { + ret = -1; + goto out; + } + + flags = O_WRONLY|O_CREAT; + mode = S_IRUSR|S_IWUSR; + if (!(sf = chunk_open_remote(f->dst_path, flags, mode, c->off, sftp))) { + ret = -1; + goto out; + } + + ret = chunk_copy_internal(c, fd, sf, sftp_buf_sz, io_buf_sz, false, counter); + if (ret< 0) + goto out; + + if ((mode = chunk_get_mode(f->path, NULL)) < 0) { + ret = -1; + goto out; + } + if (chunk_set_mode(f->dst_path, mode, sftp) < 0) { + ret = -1; + } out: - if (fd > 0) - close(fd); - if (sf) - sftp_close(sf); - return ret; + if (fd > 0) + close(fd); + if (sf) + sftp_close(sf); + return ret; } static int chunk_copy_remote_to_local(struct chunk *c, sftp_session sftp, - size_t sftp_buf_sz, size_t io_buf_sz, - size_t *counter) + size_t sftp_buf_sz, size_t io_buf_sz, + size_t *counter) { - struct file *f = c->f; - sftp_file sf = NULL; - mode_t mode; - int flags; - int fd = 0; - int ret = 0; - - flags = O_WRONLY|O_CREAT; - mode = S_IRUSR|S_IWUSR; - if ((fd = chunk_open_local(f->dst_path, flags, mode, c->off)) < 0) { - ret = -1; - goto out; - } - - flags = O_RDONLY; - mode = S_IRUSR; - if (!(sf = chunk_open_remote(f->path, flags, mode, c->off, sftp))) { - ret = -1; - goto out; - } - - ret = chunk_copy_internal(c, fd, sf, sftp_buf_sz, io_buf_sz, true, counter); - if (ret< 0) - goto out; + struct file *f = c->f; + sftp_file sf = NULL; + mode_t mode; + int flags; + int fd = 0; + int ret = 0; + + flags = O_WRONLY|O_CREAT; + mode = S_IRUSR|S_IWUSR; + if ((fd = chunk_open_local(f->dst_path, flags, mode, c->off)) < 0) { + ret = -1; + goto out; + } + + flags = O_RDONLY; + mode = S_IRUSR; + if (!(sf = chunk_open_remote(f->path, flags, mode, c->off, sftp))) { + ret = -1; + goto out; + } + + ret = chunk_copy_internal(c, fd, sf, sftp_buf_sz, io_buf_sz, true, counter); + if (ret< 0) + goto out; out: - if (fd > 0) - close(fd); - if (sf) - sftp_close(sf); + if (fd > 0) + close(fd); + if (sf) + sftp_close(sf); - return ret; + return ret; } int chunk_copy(struct chunk *c, sftp_session sftp, size_t sftp_buf_sz, size_t io_buf_sz, - size_t *counter) + size_t *counter) { - struct file *f = c->f; - int ret = 0; + struct file *f = c->f; + int ret = 0; - 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); + 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); + 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); - else - ret = chunk_copy_remote_to_local(c, sftp, - sftp_buf_sz, io_buf_sz, counter); + if (f->dst_remote) + ret = chunk_copy_local_to_remote(c, sftp, + sftp_buf_sz, io_buf_sz, counter); + else + ret = chunk_copy_remote_to_local(c, sftp, + sftp_buf_sz, io_buf_sz, counter); - if (ret < 0) - return ret; + if (ret < 0) + return ret; - pr_debug("done %s %s -> %s %s off=0x%010lx\n", - f->path, f->remote ? "(remote)" : "(local)", - f->dst_path, f->dst_remote ? "(remote)" : "(local)", c->off); + pr_debug("done %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 done: chunk %s 0x%010lx-0x%010lx %luB\n", - c->f->path, c->off, c->off + c->len, c->len); + 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) { - f->state = FILE_STATE_DONE; - pprint2("copy done: %s\n", f->path); - } + if (refcnt_dec(&f->refcnt) == 0) { + f->state = FILE_STATE_DONE; + pprint2("copy done: %s\n", f->path); + } - return ret; + return ret; } @@ -10,18 +10,18 @@ #include <atomic.h> struct file { - struct list_head list; /* sscp->file_list */ + struct list_head list; /* sscp->file_list */ - char path[PATH_MAX]; /* copy source path */ - bool remote; /* source is remote */ - size_t size; /* size of this file */ + char path[PATH_MAX]; /* copy source path */ + bool remote; /* source is remote */ + size_t size; /* size of this file */ - char dst_path[PATH_MAX]; /* copy destination path */ - bool dst_remote; /* destination is remote */ + char dst_path[PATH_MAX]; /* copy destination path */ + bool dst_remote; /* destination is remote */ - int state; /* destination file state */ - lock lock; /* mutex to protect state */ - refcnt refcnt; /* chunks referencing this file */ + int state; /* destination file state */ + lock lock; /* mutex to protect state */ + refcnt refcnt; /* chunks referencing this file */ }; #define FILE_STATE_INIT 0 #define FILE_STATE_OPENED 1 @@ -51,26 +51,26 @@ struct file { */ struct chunk { - struct list_head list; /* sscp->chunk_list */ - struct file *f; - size_t off; /* offset of this chunk on the file f */ - size_t len; /* length of this chunk */ - size_t done; /* copied bytes for this chunk by a thread */ + struct list_head list; /* sscp->chunk_list */ + struct file *f; + size_t off; /* offset of this chunk on the file f */ + size_t len; /* length of this chunk */ + size_t done; /* copied bytes for this chunk by a thread */ }; char *file_find_hostname(char *path); bool file_has_hostname(char *path); int file_fill(sftp_session sftp, struct list_head *file_list, char **src_array, int cnt, - char *dst); + char *dst); int chunk_fill(struct list_head *file_list, struct list_head *chunk_list, - int nr_conn, int min_chunk_sz, int max_chunk_sz); + int nr_conn, int min_chunk_sz, int max_chunk_sz); struct chunk *chunk_acquire(struct list_head *chunk_list); int chunk_prepare(struct chunk *c, sftp_session sftp); int chunk_copy(struct chunk *c, sftp_session sftp, - size_t sftp_buf_sz, size_t io_buf_sz, size_t *counter); + size_t sftp_buf_sz, size_t io_buf_sz, size_t *counter); #ifdef DEBUG void file_dump(struct list_head *file_list); @@ -22,28 +22,28 @@ /* XXX: need to investigate max buf size for sftp_read/sftp_write */ struct sscp { - char *host; /* remote host (and username) */ - struct ssh_opts *opts; /* ssh parameters */ - sftp_session ctrl; /* control sftp session */ + char *host; /* remote host (and username) */ + struct ssh_opts *opts; /* ssh parameters */ + sftp_session ctrl; /* control sftp session */ - struct list_head file_list; - struct list_head chunk_list; /* stack of chunks */ - lock chunk_lock; /* lock for chunk list */ + struct list_head file_list; + struct list_head chunk_list; /* stack of chunks */ + lock chunk_lock; /* lock for chunk list */ - char *target; + char *target; - int sftp_buf_sz, io_buf_sz; + int sftp_buf_sz, io_buf_sz; - struct timeval start; /* timestamp of starting copy */ + struct timeval start; /* timestamp of starting copy */ }; struct sscp_thread { - struct sscp *sscp; - sftp_session sftp; + struct sscp *sscp; + sftp_session sftp; - pthread_t tid; - size_t done; /* copied bytes */ - bool finished; + pthread_t tid; + size_t done; /* copied bytes */ + bool finished; }; void *sscp_copy_thread(void *arg); @@ -55,175 +55,175 @@ int nr_threads; void stop_copy_threads(int sig) { - int n; + int n; - pr("stopping...\n"); - for (n = 0; n < nr_threads; n++) { - pthread_cancel(threads[n].tid); - } + pr("stopping...\n"); + for (n = 0; n < nr_threads; n++) { + pthread_cancel(threads[n].tid); + } } void usage(bool print_help) { - printf("sscp: super scp, copy files over multiple ssh connections\n" - "\n" - "Usage: sscp [CvqDdh] [-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\n" - "\n"); - - if (!print_help) - return; - - 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" - " -D dry run\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" - " -d increment ssh debug output level\n" - " -h print this help\n" - "\n"); + printf("sscp: super scp, copy files over multiple ssh connections\n" + "\n" + "Usage: sscp [CvqDdh] [-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\n" + "\n"); + + if (!print_help) + return; + + 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" + " -D dry run\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" + " -d increment ssh debug output level\n" + " -h print this help\n" + "\n"); } char *find_hostname(int ind, int argc, char **argv) { - char *h, *hostnames[argc]; - int n, cnt = 0; - - for (n = ind; n < argc; n++) { - h = file_find_hostname(argv[n]); - if (h) - hostnames[cnt++] = h; - } - - if (cnt == 0) - return NULL; - - /* check all hostnames are identical */ - for (n = 1; n < cnt; n++) { - int s1 = strlen(hostnames[n - 1]); - int s2 = strlen(hostnames[n]); - if (s1 != s2) { - pr_err("different hostnames: %s and %s\n", - hostnames[n - 1], hostnames[n]); - goto err_out; - } - if (strncmp(hostnames[n - 1], hostnames[n], s1) != 0) { - pr_err("different hostnames: %s and %s\n", - hostnames[n - 1], hostnames[n]); - goto err_out; - } - } - - for (n = 1; n < cnt; n++) { - free(hostnames[n]); - } - - return hostnames[0]; + char *h, *hostnames[argc]; + int n, cnt = 0; + + for (n = ind; n < argc; n++) { + h = file_find_hostname(argv[n]); + if (h) + hostnames[cnt++] = h; + } + + if (cnt == 0) + return NULL; + + /* check all hostnames are identical */ + for (n = 1; n < cnt; n++) { + int s1 = strlen(hostnames[n - 1]); + int s2 = strlen(hostnames[n]); + if (s1 != s2) { + pr_err("different hostnames: %s and %s\n", + hostnames[n - 1], hostnames[n]); + goto err_out; + } + if (strncmp(hostnames[n - 1], hostnames[n], s1) != 0) { + pr_err("different hostnames: %s and %s\n", + hostnames[n - 1], hostnames[n]); + goto err_out; + } + } + + for (n = 1; n < cnt; n++) { + free(hostnames[n]); + } + + return hostnames[0]; err_out: - for (n = 0; n < cnt; n++) { - free(hostnames[n]); - } - return NULL; + for (n = 0; n < cnt; n++) { + free(hostnames[n]); + } + return NULL; } int main(int argc, char **argv) { - struct sscp sscp; + struct sscp sscp; struct ssh_opts opts; - int min_chunk_sz = DEFAULT_MIN_CHUNK_SZ; - int max_chunk_sz = 0; - int verbose = 1; - bool dryrun = false; - int ret = 0, n; - char ch; - - memset(&opts, 0, sizeof(opts)); - memset(&sscp, 0, sizeof(sscp)); - INIT_LIST_HEAD(&sscp.file_list); - INIT_LIST_HEAD(&sscp.chunk_list); - lock_init(&sscp.chunk_lock); - sscp.sftp_buf_sz = DEFAULT_SFTP_BUF_SZ; - sscp.io_buf_sz = DEFAULT_IO_BUF_SZ; - - nr_threads = (int)(nr_cpus() / 2); - nr_threads = nr_threads == 0 ? 1 : nr_threads; + int min_chunk_sz = DEFAULT_MIN_CHUNK_SZ; + int max_chunk_sz = 0; + int verbose = 1; + bool dryrun = false; + int ret = 0, n; + char ch; + + memset(&opts, 0, sizeof(opts)); + memset(&sscp, 0, sizeof(sscp)); + INIT_LIST_HEAD(&sscp.file_list); + INIT_LIST_HEAD(&sscp.chunk_list); + lock_init(&sscp.chunk_lock); + sscp.sftp_buf_sz = DEFAULT_SFTP_BUF_SZ; + sscp.io_buf_sz = DEFAULT_IO_BUF_SZ; + + nr_threads = (int)(nr_cpus() / 2); + nr_threads = nr_threads == 0 ? 1 : nr_threads; while ((ch = getopt(argc, argv, "n:s:S:b:B:vqDl:p:i:c:Cdh")) != -1) { switch (ch) { - case 'n': - nr_threads = atoi(optarg); - if (nr_threads < 1) { - pr_err("invalid number of connections: %s\n", optarg); - return 1; - } - break; - case 's': - min_chunk_sz = atoi(optarg); - if (min_chunk_sz < getpagesize()) { - pr_err("min chunk size must be " - "larger than or equal to %d: %s\n", - getpagesize(), optarg); - return 1; - } - if (min_chunk_sz % getpagesize() != 0) { - pr_err("min chunk size must be " - "multiple of page size %d: %s\n", - getpagesize(), optarg); - return -1; - } - break; - case 'S': - max_chunk_sz = atoi(optarg); - if (max_chunk_sz < getpagesize()) { - pr_err("max chunk size must be " - "larger than or equal to %d: %s\n", - getpagesize(), optarg); - return 1; - } - if (max_chunk_sz % getpagesize() != 0) { - pr_err("max chunk size must be " - "multiple of page size %d: %s\n", - getpagesize(), optarg); - return -1; - } - break; - case 'b': - sscp.sftp_buf_sz = atoi(optarg); - if (sscp.sftp_buf_sz < 1) { - pr_err("invalid buffer size: %s\n", optarg); - return -1; - } - break; - case 'B': - sscp.io_buf_sz = atoi(optarg); - if (sscp.io_buf_sz < 1) { - pr_err("invalid buffer size: %s\n", optarg); - return -1; - } - break; - case 'v': - verbose++; - break; - case 'q': - verbose = -1; - break; - case 'D': - dryrun = true; - break; + case 'n': + nr_threads = atoi(optarg); + if (nr_threads < 1) { + pr_err("invalid number of connections: %s\n", optarg); + return 1; + } + break; + case 's': + min_chunk_sz = atoi(optarg); + if (min_chunk_sz < getpagesize()) { + pr_err("min chunk size must be " + "larger than or equal to %d: %s\n", + getpagesize(), optarg); + return 1; + } + if (min_chunk_sz % getpagesize() != 0) { + pr_err("min chunk size must be " + "multiple of page size %d: %s\n", + getpagesize(), optarg); + return -1; + } + break; + case 'S': + max_chunk_sz = atoi(optarg); + if (max_chunk_sz < getpagesize()) { + pr_err("max chunk size must be " + "larger than or equal to %d: %s\n", + getpagesize(), optarg); + return 1; + } + if (max_chunk_sz % getpagesize() != 0) { + pr_err("max chunk size must be " + "multiple of page size %d: %s\n", + getpagesize(), optarg); + return -1; + } + break; + case 'b': + sscp.sftp_buf_sz = atoi(optarg); + if (sscp.sftp_buf_sz < 1) { + pr_err("invalid buffer size: %s\n", optarg); + return -1; + } + break; + case 'B': + sscp.io_buf_sz = atoi(optarg); + if (sscp.io_buf_sz < 1) { + pr_err("invalid buffer size: %s\n", optarg); + return -1; + } + break; + case 'v': + verbose++; + break; + case 'q': + verbose = -1; + break; + case 'D': + dryrun = true; + break; case 'l': opts.login_name = optarg; break; @@ -242,322 +242,322 @@ int main(int argc, char **argv) case 'd': opts.debuglevel++; break; - case 'h': - usage(true); - return 1; - default: - usage(false); - return 1; + case 'h': + usage(true); + return 1; + default: + usage(false); + return 1; } - } - - 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); - return 1; - } - - if (argc - optind < 2) { - /* sscp needs at lease 2 (src and target) argument */ - usage(false); - return 1; - } - - sscp.target = argv[argc - 1]; - - /* create control session */ - sscp.host = find_hostname(optind, argc, argv); - if (!sscp.host) { - 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; - sscp.opts = &opts; /* save ssh-able ssh_opts */ - - - /* fill file list */ - ret = file_fill(sscp.ctrl, &sscp.file_list, &argv[optind], argc - optind - 1, - sscp.target); - if (ret < 0) - goto out; + } + + 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); + return 1; + } + + if (argc - optind < 2) { + /* sscp needs at lease 2 (src and target) argument */ + usage(false); + return 1; + } + + sscp.target = argv[argc - 1]; + + /* create control session */ + sscp.host = find_hostname(optind, argc, argv); + if (!sscp.host) { + 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; + sscp.opts = &opts; /* save ssh-able ssh_opts */ + + + /* fill file list */ + ret = file_fill(sscp.ctrl, &sscp.file_list, &argv[optind], argc - optind - 1, + sscp.target); + if (ret < 0) + goto out; #ifdef DEBUG - file_dump(&sscp.file_list); + file_dump(&sscp.file_list); #endif - /* fill chunk list */ - ret = chunk_fill(&sscp.file_list, &sscp.chunk_list, - nr_threads, min_chunk_sz, max_chunk_sz); - if (ret < 0) - goto out; + /* fill chunk list */ + ret = chunk_fill(&sscp.file_list, &sscp.chunk_list, + nr_threads, min_chunk_sz, max_chunk_sz); + if (ret < 0) + goto out; #ifdef DEBUG - chunk_dump(&sscp.chunk_list); + chunk_dump(&sscp.chunk_list); #endif - if (dryrun) - return 0; - - /* register SIGINT to stop thrads */ - if (signal(SIGINT, stop_copy_threads) == SIG_ERR) { - pr_err("cannot set signal: %s\n", strerrno()); - ret = 1; - goto out; - } - - /* prepare thread instances */ - threads = calloc(nr_threads, sizeof(struct sscp_thread)); - memset(threads, 0, nr_threads * sizeof(struct sscp_thread)); - for (n = 0; n < nr_threads; n++) { - 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; - } - - /* spawn count thread */ - ret = pthread_create(&mtid, NULL, sscp_monitor_thread, &sscp); - if (ret < 0) { - pr_err("pthread_create error: %d\n", ret); - stop_copy_threads(0); - goto join_out; - } - - /* save start time */ - gettimeofday(&sscp.start, NULL); - - /* spawn threads */ - for (n = 0; n < nr_threads; n++) { - struct sscp_thread *t = &threads[n]; - ret = pthread_create(&t->tid, NULL, sscp_copy_thread, t); - if (ret < 0) { - pr_err("pthread_create error: %d\n", ret); - stop_copy_threads(0); - goto join_out; - } - } + if (dryrun) + return 0; + + /* register SIGINT to stop thrads */ + if (signal(SIGINT, stop_copy_threads) == SIG_ERR) { + pr_err("cannot set signal: %s\n", strerrno()); + ret = 1; + goto out; + } + + /* prepare thread instances */ + threads = calloc(nr_threads, sizeof(struct sscp_thread)); + memset(threads, 0, nr_threads * sizeof(struct sscp_thread)); + for (n = 0; n < nr_threads; n++) { + 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; + } + + /* spawn count thread */ + ret = pthread_create(&mtid, NULL, sscp_monitor_thread, &sscp); + if (ret < 0) { + pr_err("pthread_create error: %d\n", ret); + stop_copy_threads(0); + goto join_out; + } + + /* save start time */ + gettimeofday(&sscp.start, NULL); + + /* spawn threads */ + for (n = 0; n < nr_threads; n++) { + struct sscp_thread *t = &threads[n]; + ret = pthread_create(&t->tid, NULL, sscp_copy_thread, t); + if (ret < 0) { + pr_err("pthread_create error: %d\n", ret); + stop_copy_threads(0); + goto join_out; + } + } join_out: - /* waiting for threads join... */ - for (n = 0; n < nr_threads; n++) - if (threads[n].tid) - pthread_join(threads[n].tid, NULL); + /* waiting for threads join... */ + for (n = 0; n < nr_threads; n++) + if (threads[n].tid) + pthread_join(threads[n].tid, NULL); - if (mtid != 0) { - pthread_cancel(mtid); - pthread_join(mtid, NULL); - } + if (mtid != 0) { + pthread_cancel(mtid); + pthread_join(mtid, NULL); + } out: - if (sscp.ctrl) - ssh_sftp_close(sscp.ctrl); + if (sscp.ctrl) + ssh_sftp_close(sscp.ctrl); return ret; } void sscp_copy_thread_cleanup(void *arg) { - struct sscp_thread *t = arg; - if (t->sftp) - ssh_sftp_close(t->sftp); - t->finished = true; + struct sscp_thread *t = arg; + if (t->sftp) + ssh_sftp_close(t->sftp); + t->finished = true; } void *sscp_copy_thread(void *arg) { - struct sscp_thread *t = arg; - struct sscp *sscp = t->sscp; - sftp_session sftp = t->sftp; - struct chunk *c; + struct sscp_thread *t = arg; + struct sscp *sscp = t->sscp; + sftp_session sftp = t->sftp; + struct chunk *c; - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); - pthread_cleanup_push(sscp_copy_thread_cleanup, t); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); + pthread_cleanup_push(sscp_copy_thread_cleanup, t); - while (1) { - lock_acquire(&sscp->chunk_lock); - c = chunk_acquire(&sscp->chunk_list); - lock_release(&sscp->chunk_lock); + while (1) { + lock_acquire(&sscp->chunk_lock); + c = chunk_acquire(&sscp->chunk_list); + lock_release(&sscp->chunk_lock); - if (!c) - break; /* no more chunks */ + if (!c) + break; /* no more chunks */ - if (chunk_prepare(c, sftp) < 0) - break; + if (chunk_prepare(c, sftp) < 0) + break; - if (chunk_copy(c, sftp, - sscp->sftp_buf_sz, sscp->io_buf_sz, &t->done) < 0) - break; - } + if (chunk_copy(c, sftp, + sscp->sftp_buf_sz, sscp->io_buf_sz, &t->done) < 0) + break; + } - pthread_cleanup_pop(1); + pthread_cleanup_pop(1); - return NULL; + return NULL; } static double calculate_bps(size_t diff, struct timeval *b, struct timeval *a) { - double sec, usec; + double sec, usec; - if (a->tv_usec < b->tv_usec) { - a->tv_usec += 1000000; - a->tv_sec--; - } + if (a->tv_usec < b->tv_usec) { + a->tv_usec += 1000000; + a->tv_sec--; + } - sec = a->tv_sec - b->tv_sec; - usec = a->tv_usec - b->tv_usec; - sec += usec / 1000000; + sec = a->tv_sec - b->tv_sec; + usec = a->tv_usec - b->tv_usec; + sec += usec / 1000000; - return (double)diff / sec; + return (double)diff / sec; } static void print_progress_bar(double percent, char *suffix) { - int n, thresh, bar_width; - struct winsize ws; - char buf[128]; - - /* - * [=======> ] XX.X% SUFFIX - */ - - buf[0] = '\0'; - - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0) - return; /* XXX */ - bar_width = min(sizeof(buf), ws.ws_col) - strlen(suffix) - 8; - - if (bar_width > 8) { - memset(buf, 0, sizeof(buf)); - thresh = floor(bar_width * (percent / 100)) - 1; - - for (n = 1; n < bar_width - 1; n++) { - if (n <= thresh) - buf[n] = '='; - else - buf[n] = ' '; - } - buf[thresh] = '>'; - buf[0] = '['; - buf[bar_width - 1] = ']'; - snprintf(buf + bar_width, sizeof(buf) - bar_width, - " %3d%% ", (int)floor(percent)); - } - - pprint1("%s%s", buf, suffix); + int n, thresh, bar_width; + struct winsize ws; + char buf[128]; + +/* + * [=======> ] XX.X% SUFFIX + */ + + buf[0] = '\0'; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0) + return; /* XXX */ + bar_width = min(sizeof(buf), ws.ws_col) - strlen(suffix) - 8; + + if (bar_width > 8) { + memset(buf, 0, sizeof(buf)); + thresh = floor(bar_width * (percent / 100)) - 1; + + for (n = 1; n < bar_width - 1; n++) { + if (n <= thresh) + buf[n] = '='; + else + buf[n] = ' '; + } + buf[thresh] = '>'; + buf[0] = '['; + buf[bar_width - 1] = ']'; + snprintf(buf + bar_width, sizeof(buf) - bar_width, + " %3d%% ", (int)floor(percent)); + } + + pprint1("%s%s", buf, suffix); } static void print_progress(struct timeval *start, struct timeval *end, - size_t total, size_t last, size_t done) + size_t total, size_t last, size_t done) { - char *bps_units[] = { "B/s", "KB/s", "MB/s", "GB/s" }; - char *byte_units[] = { "B", "KB", "MB", "GB", "TB", "PB" }; - char suffix[128]; - int bps_u, byte_tu, byte_du; - size_t total_round; - int percent; - double bps; + char *bps_units[] = { "B/s", "KB/s", "MB/s", "GB/s" }; + char *byte_units[] = { "B", "KB", "MB", "GB", "TB", "PB" }; + char suffix[128]; + int bps_u, byte_tu, byte_du; + size_t total_round; + int percent; + double bps; #define array_size(a) (sizeof(a) / sizeof(a[0])) - total_round = total; - for (byte_tu = 0; total_round > 1000 && byte_tu < array_size(byte_units) - 1; - byte_tu++) - total_round /= 1024; + total_round = total; + for (byte_tu = 0; total_round > 1000 && byte_tu < array_size(byte_units) - 1; + byte_tu++) + total_round /= 1024; - bps = calculate_bps(done - last, start, end); - for (bps_u = 0; bps > 1000 && bps_u < array_size(bps_units); bps_u++) - bps /= 1000; + bps = calculate_bps(done - last, start, end); + for (bps_u = 0; bps > 1000 && bps_u < array_size(bps_units); bps_u++) + bps /= 1000; - percent = floor(((double)(done) / (double)total) * 100); - for (byte_du = 0; done > 1000 && byte_du < array_size(byte_units) - 1; byte_du++) - done /= 1024; + percent = floor(((double)(done) / (double)total) * 100); + for (byte_du = 0; done > 1000 && byte_du < array_size(byte_units) - 1; byte_du++) + done /= 1024; - snprintf(suffix, sizeof(suffix), "%lu%s/%lu%s %.2f%s ", - done, byte_units[byte_du], total_round, byte_units[byte_tu], - bps, bps_units[bps_u]); + snprintf(suffix, sizeof(suffix), "%lu%s/%lu%s %.2f%s ", + done, byte_units[byte_du], total_round, byte_units[byte_tu], + bps, bps_units[bps_u]); - print_progress_bar(percent, suffix); + print_progress_bar(percent, suffix); } void sscp_monitor_thread_cleanup(void *arg) { - struct sscp *sscp = arg; - struct timeval end; - struct file *f; - size_t total, done; - int n; + struct sscp *sscp = arg; + struct timeval end; + struct file *f; + size_t total, done; + int n; - total = done = 0; + total = done = 0; - gettimeofday(&end, NULL); + gettimeofday(&end, NULL); - /* get total byte to be transferred */ - list_for_each_entry(f, &sscp->file_list, list) { - total += f->size; - } + /* get total byte to be transferred */ + list_for_each_entry(f, &sscp->file_list, list) { + total += f->size; + } - /* get total byte transferred */ - for (n = 0; n < nr_threads; n++) { - done += threads[n].done; - } + /* get total byte transferred */ + for (n = 0; n < nr_threads; n++) { + done += threads[n].done; + } - print_progress(&sscp->start, &end, total, 0, done); - fputs("\n", stdout); /* the final ouput. we need \n */ + print_progress(&sscp->start, &end, total, 0, done); + fputs("\n", stdout); /* the final ouput. we need \n */ } void *sscp_monitor_thread(void *arg) { - struct sscp *sscp = arg; - struct timeval a, b; - struct file *f; - bool all_done; - size_t total, done, last; - int n; - - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); - pthread_cleanup_push(sscp_monitor_thread_cleanup, sscp); - - /* get total byte to be transferred */ - total = 0; - list_for_each_entry(f, &sscp->file_list, list) { - total += f->size; - } - - while (1) { - all_done = true; - last = done = 0; - - for (n = 0; n < nr_threads; n++) { - last += threads[n].done; - } - gettimeofday(&b, NULL); - - usleep(500000); - - for (n = 0; n < nr_threads; n++) { - done += threads[n].done;; - if (!threads[n].finished) - all_done = false; - } - gettimeofday(&a, NULL); - - print_progress(&b, &a, total, last, done); - - if (all_done || total == done) - break; - } - - pthread_cleanup_pop(1); - - return NULL; + struct sscp *sscp = arg; + struct timeval a, b; + struct file *f; + bool all_done; + size_t total, done, last; + int n; + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); + pthread_cleanup_push(sscp_monitor_thread_cleanup, sscp); + + /* get total byte to be transferred */ + total = 0; + list_for_each_entry(f, &sscp->file_list, list) { + total += f->size; + } + + while (1) { + all_done = true; + last = done = 0; + + for (n = 0; n < nr_threads; n++) { + last += threads[n].done; + } + gettimeofday(&b, NULL); + + usleep(500000); + + for (n = 0; n < nr_threads; n++) { + done += threads[n].done;; + if (!threads[n].finished) + all_done = false; + } + gettimeofday(&a, NULL); + + print_progress(&b, &a, total, last, done); + + if (all_done || total == done) + break; + } + + pthread_cleanup_pop(1); + + return NULL; } diff --git a/src/platform.c b/src/platform.c index 1a87cd3..ea6b8ad 100644 --- a/src/platform.c +++ b/src/platform.c @@ -14,25 +14,25 @@ #ifdef __APPLE__ int nr_cpus() { - int n; - size_t size = sizeof(n); + int n; + size_t size = sizeof(n); - if (sysctlbyname("machdep.cpu.core_count", &n, &size, NULL, 0) != 0) { - pr_err("failed to get number of cpu cores: %s\n", strerrno()); - return -1; - } + if (sysctlbyname("machdep.cpu.core_count", &n, &size, NULL, 0) != 0) { + pr_err("failed to get number of cpu cores: %s\n", strerrno()); + return -1; + } - return n; + return n; } #endif #ifdef linux int nr_cpus() { - cpu_set_t cpu_set; - if (sched_getaffinity(0, sizeof(cpu_set_t), &cpu_set) == 0) - return CPU_COUNT(&cpu_set); - return -1; + cpu_set_t cpu_set; + if (sched_getaffinity(0, sizeof(cpu_set_t), &cpu_set) == 0) + return CPU_COUNT(&cpu_set); + return -1; } #endif diff --git a/src/pprint.c b/src/pprint.c index 51eb4ad..64f8a21 100644 --- a/src/pprint.c +++ b/src/pprint.c @@ -13,20 +13,20 @@ static pthread_mutex_t pprint_lock = PTHREAD_MUTEX_INITIALIZER; void pprint_set_level(int level) { - pprint_level = level; + pprint_level = level; } void pprint(int level, const char *fmt, ...) { - va_list va; + 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); - } + 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); + } } @@ -10,265 +10,265 @@ static int ssh_verify_known_hosts(ssh_session session); static int ssh_set_opts(ssh_session ssh, struct ssh_opts *opts) { - ssh_set_log_level(opts->debuglevel); - - if (opts->login_name && - ssh_options_set(ssh, SSH_OPTIONS_USER, opts->login_name) < 0) { - pr_err("failed to set login name\n"); - return -1; - } - - if (opts->port && - ssh_options_set(ssh, SSH_OPTIONS_PORT_STR, opts->port) < 0) { - pr_err("failed to set port number\n"); - return -1; - } - - if (opts->identity && - ssh_options_set(ssh, SSH_OPTIONS_IDENTITY, opts->identity) < 0) { - pr_err("failed to set identity\n"); - return -1; - } - - if (opts->cipher) { - if (ssh_options_set(ssh, SSH_OPTIONS_CIPHERS_C_S, opts->cipher) < 0) { - pr_err("failed to set cipher client to server\n"); - return -1; - } - if (ssh_options_set(ssh, SSH_OPTIONS_CIPHERS_S_C, opts->cipher) < 0) { - pr_err("failed to set cipher client to server\n"); - return -1; - } - } - - if (opts->compress && - ssh_options_set(ssh, SSH_OPTIONS_COMPRESSION, "yes") < 0) { - pr_err("failed to enable ssh compression\n"); - return -1; - } - - return 0; + ssh_set_log_level(opts->debuglevel); + + if (opts->login_name && + ssh_options_set(ssh, SSH_OPTIONS_USER, opts->login_name) < 0) { + pr_err("failed to set login name\n"); + return -1; + } + + if (opts->port && + ssh_options_set(ssh, SSH_OPTIONS_PORT_STR, opts->port) < 0) { + pr_err("failed to set port number\n"); + return -1; + } + + if (opts->identity && + ssh_options_set(ssh, SSH_OPTIONS_IDENTITY, opts->identity) < 0) { + pr_err("failed to set identity\n"); + return -1; + } + + if (opts->cipher) { + if (ssh_options_set(ssh, SSH_OPTIONS_CIPHERS_C_S, opts->cipher) < 0) { + pr_err("failed to set cipher client to server\n"); + return -1; + } + if (ssh_options_set(ssh, SSH_OPTIONS_CIPHERS_S_C, opts->cipher) < 0) { + pr_err("failed to set cipher client to server\n"); + return -1; + } + } + + if (opts->compress && + ssh_options_set(ssh, SSH_OPTIONS_COMPRESSION, "yes") < 0) { + pr_err("failed to enable ssh compression\n"); + return -1; + } + + return 0; } static int ssh_authenticate(ssh_session ssh, struct ssh_opts *opts) { - int auth_bit_mask; - int ret; - - /* none method */ - ret = ssh_userauth_none(ssh, NULL); - if (ret == SSH_AUTH_SUCCESS) - return 0; - - auth_bit_mask = ssh_userauth_list(ssh, NULL); - - if (auth_bit_mask & SSH_AUTH_METHOD_NONE && - ssh_userauth_none(ssh, NULL) == SSH_AUTH_SUCCESS) { - return 0; - } - - if (auth_bit_mask & SSH_AUTH_METHOD_PUBLICKEY && - ssh_userauth_publickey_auto(ssh, NULL, NULL) == SSH_AUTH_SUCCESS) { - return 0; - } - - if (auth_bit_mask & SSH_AUTH_METHOD_PASSWORD) { - if (!opts->password) { - opts->password = getpass("Password: "); - } - if (ssh_userauth_password(ssh, NULL, opts->password) == SSH_AUTH_SUCCESS) - return 0; - } - - pr_err("authentication failure: %s\n", ssh_get_error(ssh)); - return -1; + int auth_bit_mask; + int ret; + +/* none method */ + ret = ssh_userauth_none(ssh, NULL); + if (ret == SSH_AUTH_SUCCESS) + return 0; + + auth_bit_mask = ssh_userauth_list(ssh, NULL); + + if (auth_bit_mask & SSH_AUTH_METHOD_NONE && + ssh_userauth_none(ssh, NULL) == SSH_AUTH_SUCCESS) { + return 0; + } + + if (auth_bit_mask & SSH_AUTH_METHOD_PUBLICKEY && + ssh_userauth_publickey_auto(ssh, NULL, NULL) == SSH_AUTH_SUCCESS) { + return 0; + } + + if (auth_bit_mask & SSH_AUTH_METHOD_PASSWORD) { + if (!opts->password) { + opts->password = getpass("Password: "); + } + if (ssh_userauth_password(ssh, NULL, opts->password) == SSH_AUTH_SUCCESS) + return 0; + } + + pr_err("authentication failure: %s\n", ssh_get_error(ssh)); + return -1; } static ssh_session ssh_make_ssh_session(char *sshdst, struct ssh_opts *opts) { - ssh_session ssh = ssh_new(); + ssh_session ssh = ssh_new(); - if (ssh_set_opts(ssh, opts) != 0) - goto free_out; + if (ssh_set_opts(ssh, opts) != 0) + goto free_out; - if (ssh_options_set(ssh, SSH_OPTIONS_HOST, sshdst) != SSH_OK) { - pr_err("failed to set destination host\n"); - goto free_out; - } + if (ssh_options_set(ssh, SSH_OPTIONS_HOST, sshdst) != SSH_OK) { + pr_err("failed to set destination host\n"); + goto free_out; + } - if (ssh_connect(ssh) != SSH_OK) { - pr_err("failed to connect ssh server: %s\n", ssh_get_error(ssh)); - goto free_out; - } + if (ssh_connect(ssh) != SSH_OK) { + pr_err("failed to connect ssh server: %s\n", ssh_get_error(ssh)); + goto free_out; + } - if (ssh_authenticate(ssh, opts) != 0) { - pr_err("authentication failed: %s\n", ssh_get_error(ssh)); - goto disconnect_out; - } + if (ssh_authenticate(ssh, opts) != 0) { + pr_err("authentication failed: %s\n", ssh_get_error(ssh)); + goto disconnect_out; + } - if (ssh_verify_known_hosts(ssh) != 0) { - goto disconnect_out; - } + if (ssh_verify_known_hosts(ssh) != 0) { + goto disconnect_out; + } - return ssh; + return ssh; disconnect_out: - ssh_disconnect(ssh); + ssh_disconnect(ssh); free_out: - ssh_free(ssh); - return NULL; + ssh_free(ssh); + return NULL; } sftp_session ssh_make_sftp_session(char *sshdst, struct ssh_opts *opts) { - sftp_session sftp; - ssh_session ssh = ssh_make_ssh_session(sshdst, opts); - - if (!ssh) { - return NULL; - } - - sftp = sftp_new(ssh); - if (!sftp) { - pr_err("failed to allocate sftp session: %s\n", ssh_get_error(ssh)); - goto err_out; - } - - if (sftp_init(sftp) != SSH_OK) { - pr_err("failed to initialize sftp session: err code %d\n", - sftp_get_error(sftp)); - goto err_out; - } - - return sftp; + sftp_session sftp; + ssh_session ssh = ssh_make_ssh_session(sshdst, opts); + + if (!ssh) { + return NULL; + } + + sftp = sftp_new(ssh); + if (!sftp) { + pr_err("failed to allocate sftp session: %s\n", ssh_get_error(ssh)); + goto err_out; + } + + if (sftp_init(sftp) != SSH_OK) { + pr_err("failed to initialize sftp session: err code %d\n", + sftp_get_error(sftp)); + goto err_out; + } + + return sftp; err_out: - ssh_disconnect(ssh); - ssh_free(ssh); - return NULL; + ssh_disconnect(ssh); + ssh_free(ssh); + return NULL; } /* copied from https://api.libssh.org/stable/libssh_tutor_guided_tour.html*/ static int ssh_verify_known_hosts(ssh_session session) { - enum ssh_known_hosts_e state; - unsigned char *hash = NULL; - ssh_key srv_pubkey = NULL; - size_t hlen; - char buf[10]; - char *hexa; - char *p; - int cmp; - int rc; - - rc = ssh_get_server_publickey(session, &srv_pubkey); - if (rc < 0) { - return -1; - } - - rc = ssh_get_publickey_hash(srv_pubkey, - SSH_PUBLICKEY_HASH_SHA1, - &hash, - &hlen); - ssh_key_free(srv_pubkey); - if (rc < 0) { - return -1; - } - - state = ssh_session_is_known_server(session); - switch (state) { - case SSH_KNOWN_HOSTS_OK: - /* OK */ - - break; - case SSH_KNOWN_HOSTS_CHANGED: - fprintf(stderr, "Host key for server changed: it is now:\n"); - //ssh_print_hexa("Public key hash", hash, hlen); - fprintf(stderr, "For security reasons, connection will be stopped\n"); - ssh_clean_pubkey_hash(&hash); - - return -1; - case SSH_KNOWN_HOSTS_OTHER: - fprintf(stderr, "The host key for this server was not found but an other" - "type of key exists.\n"); - fprintf(stderr, "An attacker might change the default server key to" - "confuse your client into thinking the key does not exist\n"); - ssh_clean_pubkey_hash(&hash); - - return -1; - case SSH_KNOWN_HOSTS_NOT_FOUND: - fprintf(stderr, "Could not find known host file.\n"); - fprintf(stderr, "If you accept the host key here, the file will be" - "automatically created.\n"); - - /* FALL THROUGH to SSH_SERVER_NOT_KNOWN behavior */ - - case SSH_KNOWN_HOSTS_UNKNOWN: - hexa = ssh_get_hexa(hash, hlen); - fprintf(stderr,"The server is unknown. Do you trust the host key?\n"); - fprintf(stderr, "Public key hash: %s\n", hexa); - ssh_string_free_char(hexa); - ssh_clean_pubkey_hash(&hash); - p = fgets(buf, sizeof(buf), stdin); - if (p == NULL) { - return -1; - } - - cmp = strncasecmp(buf, "yes", 3); - if (cmp != 0) { - return -1; - } - - rc = ssh_session_update_known_hosts(session); - if (rc < 0) { - fprintf(stderr, "Error %s\n", strerror(errno)); - return -1; - } - - break; - case SSH_KNOWN_HOSTS_ERROR: - fprintf(stderr, "Error %s", ssh_get_error(session)); - ssh_clean_pubkey_hash(&hash); - return -1; - } - - ssh_clean_pubkey_hash(&hash); - return 0; + enum ssh_known_hosts_e state; + unsigned char *hash = NULL; + ssh_key srv_pubkey = NULL; + size_t hlen; + char buf[10]; + char *hexa; + char *p; + int cmp; + int rc; + + rc = ssh_get_server_publickey(session, &srv_pubkey); + if (rc < 0) { + return -1; + } + + rc = ssh_get_publickey_hash(srv_pubkey, + SSH_PUBLICKEY_HASH_SHA1, + &hash, + &hlen); + ssh_key_free(srv_pubkey); + if (rc < 0) { + return -1; + } + + state = ssh_session_is_known_server(session); + switch (state) { + case SSH_KNOWN_HOSTS_OK: +/* OK */ + + break; + case SSH_KNOWN_HOSTS_CHANGED: + fprintf(stderr, "Host key for server changed: it is now:\n"); +//ssh_print_hexa("Public key hash", hash, hlen); + fprintf(stderr, "For security reasons, connection will be stopped\n"); + ssh_clean_pubkey_hash(&hash); + + return -1; + case SSH_KNOWN_HOSTS_OTHER: + fprintf(stderr, "The host key for this server was not found but an other" + "type of key exists.\n"); + fprintf(stderr, "An attacker might change the default server key to" + "confuse your client into thinking the key does not exist\n"); + ssh_clean_pubkey_hash(&hash); + + return -1; + case SSH_KNOWN_HOSTS_NOT_FOUND: + fprintf(stderr, "Could not find known host file.\n"); + fprintf(stderr, "If you accept the host key here, the file will be" + "automatically created.\n"); + +/* FALL THROUGH to SSH_SERVER_NOT_KNOWN behavior */ + + case SSH_KNOWN_HOSTS_UNKNOWN: + hexa = ssh_get_hexa(hash, hlen); + fprintf(stderr,"The server is unknown. Do you trust the host key?\n"); + fprintf(stderr, "Public key hash: %s\n", hexa); + ssh_string_free_char(hexa); + ssh_clean_pubkey_hash(&hash); + p = fgets(buf, sizeof(buf), stdin); + if (p == NULL) { + return -1; + } + + cmp = strncasecmp(buf, "yes", 3); + if (cmp != 0) { + return -1; + } + + rc = ssh_session_update_known_hosts(session); + if (rc < 0) { + fprintf(stderr, "Error %s\n", strerror(errno)); + return -1; + } + + break; + case SSH_KNOWN_HOSTS_ERROR: + fprintf(stderr, "Error %s", ssh_get_error(session)); + ssh_clean_pubkey_hash(&hash); + return -1; + } + + ssh_clean_pubkey_hash(&hash); + return 0; } void ssh_sftp_close(sftp_session sftp) { - ssh_session ssh = sftp_ssh(sftp); - sftp_free(sftp); - ssh_disconnect(ssh); - ssh_free(ssh); + ssh_session ssh = sftp_ssh(sftp); + sftp_free(sftp); + ssh_disconnect(ssh); + ssh_free(ssh); } int sftp_write2(sftp_file sf, const void *buf, size_t len, size_t sftp_buf_sz) { - int ret, nbytes; - - for (nbytes = 0; nbytes < len;) { - ret = sftp_write(sf, buf + nbytes, - min(len - nbytes, sftp_buf_sz)); - if (ret < 0) - return ret; - nbytes += ret; - } - return nbytes; + int ret, nbytes; + + for (nbytes = 0; nbytes < len;) { + ret = sftp_write(sf, buf + nbytes, + min(len - nbytes, sftp_buf_sz)); + if (ret < 0) + return ret; + nbytes += ret; + } + return nbytes; } int sftp_read2(sftp_file sf, void *buf, size_t len, size_t sftp_buf_sz) { - int ret, nbytes; - - for (nbytes = 0; nbytes < len;) { - ret = sftp_read(sf, buf + nbytes, - min(len - nbytes, sftp_buf_sz)); - if (ret < 0) - return ret; - nbytes += ret; - } - return nbytes; + int ret, nbytes; + + for (nbytes = 0; nbytes < len;) { + ret = sftp_read(sf, buf + nbytes, + min(len - nbytes, sftp_buf_sz)); + if (ret < 0) + return ret; + nbytes += ret; + } + return nbytes; } @@ -6,14 +6,14 @@ struct ssh_opts { - char *login_name; /* -l */ - char *port; /* -p */ - char *identity; /* -i */ - char *cipher; /* -c */ - int compress; /* -C */ - int debuglevel; /* -v */ - - char *password; /* filled at the first connecting phase */ + char *login_name; /* -l */ + char *port; /* -p */ + char *identity; /* -i */ + char *cipher; /* -c */ + int compress; /* -C */ + int debuglevel; /* -v */ + + char *password; /* filled at the first connecting phase */ }; /* ssh_make_sftp_session() creates sftp_session. sshdst accpets @@ -12,7 +12,7 @@ #define pr(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) #define pr_info(fmt, ...) fprintf(stderr, "INFO:%s(): " fmt, \ - __func__, ##__VA_ARGS__) + __func__, ##__VA_ARGS__) #define pr_warn(fmt, ...) fprintf(stderr, "\x1b[1m\x1b[33m" \ "WARN:%s():\x1b[0m " fmt, \ @@ -24,8 +24,8 @@ #ifdef DEBUG #define pr_debug(fmt, ...) fprintf(stderr, "\x1b[1m\x1b[33m" \ - "DEBUG:%s():\x1b[0m " fmt, \ - __func__, ##__VA_ARGS__); + "DEBUG:%s():\x1b[0m " fmt, \ + __func__, ##__VA_ARGS__); #else #define pr_debug(fmt, ...) #endif |