diff --git a/CMakeLists.txt b/CMakeLists.txt index 3823291..f99f26b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,12 +69,12 @@ add_subdirectory(libssh EXCLUDE_FROM_ALL) # setup mscp compile options -set(MSCP_COMPILE_OPTS -iquote ${CMAKE_CURRENT_BINARY_DIR}/libssh/include) -set(MSCP_BUILD_INCLUDE_DIRS +list(APPEND MSCP_COMPILE_OPTS -iquote ${CMAKE_CURRENT_BINARY_DIR}/libssh/include) +list(APPEND MSCP_BUILD_INCLUDE_DIRS ${mscp_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/libssh/include) -set(MSCP_LINK_LIBS ssh-static) +list(APPEND MSCP_LINK_LIBS ssh-static) if(BUILD_CONAN) find_package(ZLIB REQUIRED) find_package(OpenSSL REQUIRED) @@ -83,14 +83,20 @@ if(BUILD_CONAN) endif() -# generate version header file +# Symbol check +check_symbol_exists(strlcat string.h HAVE_STRLCAT) + +# generate config.h in build dir configure_file( - ${mscp_SOURCE_DIR}/include/mscp_version.h.in - ${mscp_SOURCE_DIR}/include/mscp_version.h) + ${mscp_SOURCE_DIR}/include/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/include/config.h) +list(APPEND MSCP_BUILD_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/include) + # libmscp.a set(LIBMSCP_SRC - src/mscp.c src/ssh.c src/fileops.c src/path.c src/platform.c src/message.c) + src/mscp.c src/ssh.c src/fileops.c src/path.c src/platform.c src/message.c + src/openbsd-compat/strlcat.c) add_library(mscp-static STATIC ${LIBMSCP_SRC}) target_include_directories(mscp-static PRIVATE ${MSCP_BUILD_INCLUDE_DIRS} ${mscp_SOURCE_DIR}/include) diff --git a/include/config.h.in b/include/config.h.in new file mode 100644 index 0000000..e45dec8 --- /dev/null +++ b/include/config.h.in @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#define MSCP_VERSION "@MSCP_VERSION@" +#define MSCP_BUILD_VERSION "@MSCP_BUILD_VERSION@" + + +/* Define to 1 if you have the strlcat function. */ +#cmakedefine HAVE_STRLCAT 1 + +#endif /* _CONFIG_H_ */ diff --git a/include/mscp.h b/include/mscp.h index b9724f8..8d68032 100644 --- a/include/mscp.h +++ b/include/mscp.h @@ -48,8 +48,6 @@ struct mscp_opts { int interval; /** interval between SSH connection attempts */ int severity; /** messaging severity. set MSCP_SERVERITY_* */ - int msg_fd; /** fd to output message. default STDOUT (0), - * and -1 disables output */ }; #define MSCP_SSH_MAX_LOGIN_NAME 64 diff --git a/include/mscp_version.h.in b/include/mscp_version.h.in deleted file mode 100644 index f442533..0000000 --- a/include/mscp_version.h.in +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-only */ -#ifndef _MSCP_VERSION_H_ -#define _MSCP_VERSION_H_ - -#define MSCP_VERSION "@MSCP_VERSION@" -#define MSCP_BUILD_VERSION "@MSCP_BUILD_VERSION@" - -#endif /* _MSCP_VERSION_H_ */ diff --git a/src/fileops.c b/src/fileops.c index ac85bf8..e4e8088 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -60,7 +60,7 @@ static void sftp_err_to_errno(sftp_session sftp) errno = ENODEV; break; default: - mpr_warn(stderr, "unkown SSH_FX response %d", sftperr); + mpr_warn("unkown SSH_FX response %d", sftperr); } } @@ -184,7 +184,7 @@ static void sftp_attr_to_stat(sftp_attributes attr, struct stat *st) st->st_mode |= S_IFIFO; /* really? */ break; default: - mpr_warn(stderr, "unkown SSH_FILEXFER_TYPE %d", attr->type); + mpr_warn("unkown SSH_FILEXFER_TYPE %d", attr->type); } /* ToDo: convert atime, ctime, and mtime */ diff --git a/src/main.c b/src/main.c index 96bb9f3..0f2aac8 100644 --- a/src/main.c +++ b/src/main.c @@ -12,9 +12,9 @@ #include #include -#include #include +#include "config.h" void usage(bool print_help) { printf("mscp " MSCP_BUILD_VERSION ": copy files over multiple ssh connections\n" @@ -221,12 +221,13 @@ struct target *validate_targets(char **arg, int len) } struct mscp *m = NULL; -int msg_fd = 0; pthread_t tid_stat = 0; void sigint_handler(int sig) { mscp_stop(m); + if (tid_stat > 0) + pthread_cancel(tid_stat); } void *print_stat_thread(void *arg); @@ -396,15 +397,6 @@ int main(int argc, char **argv) MSCP_SSH_MAX_LOGIN_NAME - 1); } - if (!dryrun) { - if (pipe(pipe_fd) < 0) { - fprintf(stderr, "pipe: %s\n", strerror(errno)); - return -1; - } - msg_fd = pipe_fd[0]; - o.msg_fd = pipe_fd[1]; - } - if ((m = mscp_init(remote, direction, &o, &s)) == NULL) { fprintf(stderr, "mscp_init: %s\n", mscp_get_error()); return -1; @@ -619,25 +611,10 @@ struct xfer_stat x; void print_stat(bool final) { - struct pollfd pfd = { .fd = msg_fd, .events = POLLIN }; struct mscp_stats s; char buf[8192]; int timeout; - if (poll(&pfd, 1, !final ? 100 : 0) < 0) { - fprintf(stderr, "poll: %s\n", strerror(errno)); - return; - } - - if (pfd.revents & POLLIN) { - memset(buf, 0, sizeof(buf)); - if (read(msg_fd, buf, sizeof(buf)) < 0) { - fprintf(stderr, "read: %s\n", strerror(errno)); - return; - } - print_cli("\r\033[K" "%s", buf); - } - gettimeofday(&x.after, NULL); if (calculate_timedelta(&x.before, &x.after) > 1 || final) { mscp_get_stats(m, &s); @@ -658,7 +635,6 @@ void print_stat_thread_cleanup(void *arg) void *print_stat_thread(void *arg) { - struct pollfd pfd = { .fd = msg_fd, .events = POLLIN }; struct mscp_stats s; char buf[8192]; @@ -672,6 +648,7 @@ void *print_stat_thread(void *arg) while (true) { print_stat(false); + sleep(1); } pthread_cleanup_pop(1); diff --git a/src/message.h b/src/message.h index 673f45c..a92d760 100644 --- a/src/message.h +++ b/src/message.h @@ -11,24 +11,24 @@ void mprint_set_severity(int severity); int mprint_get_severity(); -#define mprint(fp, severity, fmt, ...) \ - do { \ - if (fp && severity <= mprint_get_severity()) { \ - fprintf(fp, fmt, ##__VA_ARGS__); \ - fflush(fp); \ - } \ +#define mprint(fp, severity, fmt, ...) \ + do { \ + if (severity <= mprint_get_severity()) { \ + fprintf(fp, "\r\033[K" fmt "\n", ##__VA_ARGS__); \ + fflush(fp); \ + } \ } while (0) -#define mpr_err(fp, fmt, ...) \ - mprint(fp, MSCP_SEVERITY_ERR, fmt, ##__VA_ARGS__) -#define mpr_warn(fp, fmt, ...) \ - mprint(fp, MSCP_SEVERITY_WARN, fmt, ##__VA_ARGS__) -#define mpr_notice(fp, fmt, ...) \ - mprint(fp, MSCP_SEVERITY_NOTICE, fmt, ##__VA_ARGS__) -#define mpr_info(fp, fmt, ...) \ - mprint(fp, MSCP_SEVERITY_INFO, fmt, ##__VA_ARGS__) -#define mpr_debug(fp, fmt, ...) \ - mprint(fp, MSCP_SEVERITY_DEBUG, fmt, ##__VA_ARGS__) +#define mpr_err(fmt, ...) \ + mprint(stderr, MSCP_SEVERITY_ERR, fmt, ##__VA_ARGS__) +#define mpr_warn(fmt, ...) \ + mprint(stderr, MSCP_SEVERITY_WARN, fmt, ##__VA_ARGS__) +#define mpr_notice(fmt, ...) \ + mprint(stdout, MSCP_SEVERITY_NOTICE, fmt, ##__VA_ARGS__) +#define mpr_info(fmt, ...) \ + mprint(stdout, MSCP_SEVERITY_INFO, fmt, ##__VA_ARGS__) +#define mpr_debug(fmt, ...) \ + mprint(stdout, MSCP_SEVERITY_DEBUG, fmt, ##__VA_ARGS__) /* errorno wrapper */ diff --git a/src/mscp.c b/src/mscp.c index e0f3dcb..7a6d5d6 100644 --- a/src/mscp.c +++ b/src/mscp.c @@ -16,6 +16,7 @@ #include #include +#include struct mscp { char *remote; /* remote host (and uername) */ @@ -23,8 +24,6 @@ struct mscp { struct mscp_opts *opts; struct mscp_ssh_opts *ssh_opts; - FILE *msg_fp; /* writer fd for message pipe */ - int *cores; /* usable cpu cores by COREMASK */ int nr_cores; /* length of array of cores */ @@ -207,9 +206,6 @@ static int validate_and_set_defaut_params(struct mscp_opts *o) o->max_startups = 1; } - if (o->msg_fd == 0) - o->msg_fd = STDOUT_FILENO; - return 0; } @@ -261,22 +257,17 @@ struct mscp *mscp_init(const char *remote_host, int direction, goto free_out; } m->direction = direction; - if (o->msg_fd > -1) { - m->msg_fp = fdopen(o->msg_fd, "a"); - if (!m->msg_fp) { - mscp_set_error("fdopen failed: %s", strerrno()); - goto free_out; - } - } else - m->msg_fp = NULL; if (strlen(o->coremask) > 0) { if (expand_coremask(o->coremask, &m->cores, &m->nr_cores) < 0) goto free_out; - mpr_notice(m->msg_fp, "usable cpu cores:"); - for (n = 0; n < m->nr_cores; n++) - mpr_notice(m->msg_fp, " %d", m->cores[n]); - mpr_notice(m->msg_fp, "\n"); + char b[512], c[8]; + for (n = 0; n < m->nr_cores; n++) { + memset(c, 0, sizeof(c)); + snprintf(c, sizeof(c) - 1, " %d", m->cores[n]); + strlcat(b, c, sizeof(b)); + } + mpr_notice("usable cpu cores:%s", b); } m->opts = o; @@ -403,7 +394,6 @@ void *mscp_scan_thread(void *arg) /* initialize path_resolve_args */ memset(&a, 0, sizeof(a)); - a.msg_fp = m->msg_fp; a.total_bytes = &m->total_bytes; if (list_count(&m->src_list) > 1) @@ -420,7 +410,7 @@ void *mscp_scan_thread(void *arg) a.max_chunk_sz = m->opts->max_chunk_sz; a.chunk_align = get_page_mask(); - mpr_info(m->msg_fp, "start to walk source path(s)\n"); + mpr_info("start to walk source path(s)"); /* walk a src_path recusively, and resolve path->dst_path for each src */ list_for_each_entry(s, &m->src_list, list) { @@ -453,7 +443,7 @@ void *mscp_scan_thread(void *arg) mscp_globfree(&pglob); } - mpr_info(m->msg_fp, "walk source path(s) done\n"); + mpr_info("walk source path(s) done"); chunk_pool_set_filled(&m->cp); m->ret_scan = 0; return NULL; @@ -536,15 +526,15 @@ int mscp_start(struct mscp *m) int n, ret = 0; if ((n = chunk_pool_size(&m->cp)) < m->opts->nr_threads) { - mpr_notice(m->msg_fp, "we have only %d chunk(s). " - "set number of connections to %d\n", n, n); + mpr_notice("we have only %d chunk(s). " + "set number of connections to %d", n, n); m->opts->nr_threads = n; } for (n = 0; n < m->opts->nr_threads; n++) { t = mscp_copy_thread_spawn(m, n); if (!t) { - mpr_err(m->msg_fp, "failed to spawn copy thread\n"); + mpr_err("failed to spawn copy thread"); break; } RWLOCK_WRITE_ACQUIRE(&m->thread_rwlock); @@ -592,7 +582,7 @@ int mscp_join(struct mscp *m) } } - mpr_notice(m->msg_fp, "%lu/%lu bytes copied for %lu/%lu files\n", + mpr_notice("%lu/%lu bytes copied for %lu/%lu files", done, m->total_bytes, nr_copied, nr_tobe_copied); return ret; @@ -637,31 +627,29 @@ void *mscp_copy_thread(void *arg) } if (sem_wait(m->sem) < 0) { - mscp_set_error("sem_wait: %s", strerrno()); - mpr_err(m->msg_fp, "%s", mscp_get_error()); + mpr_err("sem_wait: %s", strerrno()); goto err_out; } if (!(nomore = chunk_pool_is_empty(&m->cp))) { if (m->opts->interval > 0) wait_for_interval(m->opts->interval); - mpr_notice(m->msg_fp, "thread:%d connecting to %s\n", t->id, m->remote); + mpr_notice("thread:%d connecting to %s", t->id, m->remote); t->sftp = ssh_init_sftp_session(m->remote, m->ssh_opts); } if (sem_post(m->sem) < 0) { - mscp_set_error("sem_post: %s", strerrno()); - mpr_err(m->msg_fp, "%s", mscp_get_error()); + mpr_err("sem_post: %s", strerrno()); goto err_out; } if (nomore) { - mpr_notice(m->msg_fp, "thread:%d no more connections needed\n", t->id); + mpr_notice("thread:%d no more connections needed", t->id); goto out; } if (!t->sftp) { - mpr_err(m->msg_fp, "thread:%d: %s\n", t->id, mscp_get_error()); + mpr_err("thread:%d: %s", t->id, mscp_get_error()); goto err_out; } @@ -688,8 +676,7 @@ void *mscp_copy_thread(void *arg) if (!c) break; /* no more chunks */ - if ((t->ret = copy_chunk(m->msg_fp, - c, src_sftp, dst_sftp, m->opts->nr_ahead, + if ((t->ret = copy_chunk(c, src_sftp, dst_sftp, m->opts->nr_ahead, m->opts->buf_sz, &t->done)) < 0) break; } @@ -697,7 +684,7 @@ void *mscp_copy_thread(void *arg) pthread_cleanup_pop(1); if (t->ret < 0) - mpr_err(m->msg_fp, "thread:%d copy failed: %s 0x%010lx-0x%010lx\n", + mpr_err("thread:%d copy failed: %s 0x%010lx-0x%010lx", t->id, c->p->path, c->off, c->off + c->len); return NULL; diff --git a/src/openbsd-compat/openbsd-compat.h b/src/openbsd-compat/openbsd-compat.h new file mode 100644 index 0000000..33c0288 --- /dev/null +++ b/src/openbsd-compat/openbsd-compat.h @@ -0,0 +1,10 @@ +#ifndef _OPENBSD_COMPAT_H +#define _OPENBSD_COMPAT_H + +#include "config.h" + +#ifndef HAVE_STRLCAT +size_t strlcat(char *dst, const char *src, size_t siz); +#endif + +#endif /* _OPENBSD_COMPAT_H_ */ diff --git a/src/openbsd-compat/strlcat.c b/src/openbsd-compat/strlcat.c new file mode 100644 index 0000000..dc649e4 --- /dev/null +++ b/src/openbsd-compat/strlcat.c @@ -0,0 +1,62 @@ +/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */ + +#include "config.h" +#ifndef HAVE_STRLCAT + +#include +#include + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} + +#endif /* !HAVE_STRLCAT */ diff --git a/src/path.c b/src/path.c index 2d46953..c4e1b94 100644 --- a/src/path.c +++ b/src/path.c @@ -146,11 +146,11 @@ static char *resolve_dst_path(const char *src_file_path, struct path_resolve_arg a->dst_path, src_file_path + strlen(a->src_path) + 1); if (ret >= PATH_MAX) { - mpr_warn(a->msg_fp, "Too long path: %s\n", dst_file_path); + mpr_warn("Too long path: %s", dst_file_path); return NULL; } - mpr_debug(a->msg_fp, "file: %s -> %s\n", src_file_path, dst_file_path); + mpr_debug("file: %s -> %s", src_file_path, dst_file_path); return strndup(dst_file_path, PATH_MAX); } @@ -275,7 +275,7 @@ static int walk_path_recursive(sftp_session sftp, const char *path, int ret; if (mscp_stat(path, &st, sftp) < 0) { - mpr_warn(a->msg_fp, "%s: %s\n", strerrno(), path); + mpr_err("stat: %s: %s", path, strerrno()); return -1; } @@ -289,7 +289,7 @@ static int walk_path_recursive(sftp_session sftp, const char *path, /* ok, this path is a directory. walk through it. */ if (!(d = mscp_opendir(path, sftp))) { - mpr_warn(a->msg_fp, "%s: %s\n", strerrno(), path); + mpr_err("opendir: %s: %s", path, strerrno()); return -1; } @@ -299,7 +299,7 @@ static int walk_path_recursive(sftp_session sftp, const char *path, ret = snprintf(next_path, PATH_MAX, "%s/%s", path, e->d_name); if (ret >= PATH_MAX) { - mpr_warn(a->msg_fp, "Too long path: %s/%s\n", path, e->d_name); + mpr_warn("Too long path: %s/%s", path, e->d_name); continue; } @@ -353,8 +353,10 @@ static int touch_dst_path(struct path *p, sftp_session sftp) if (mscp_stat(path, &st, sftp) == 0) { if (S_ISDIR(st.st_mode)) goto next; /* directory exists. go deeper */ - else + else { + mscp_set_error("mscp_stat %s: not a directory", path); return -1; /* path exists, but not directory. */ + } } if (errno == ENOENT) { @@ -381,7 +383,7 @@ static int touch_dst_path(struct path *p, sftp_session sftp) return 0; } -static int prepare_dst_path(FILE *msg_fp, struct path *p, sftp_session dst_sftp) +static int prepare_dst_path(struct path *p, sftp_session dst_sftp) { int ret = 0; @@ -389,10 +391,11 @@ static int prepare_dst_path(FILE *msg_fp, struct path *p, sftp_session dst_sftp) if (p->state == FILE_STATE_INIT) { if (touch_dst_path(p, dst_sftp) < 0) { ret = -1; + mpr_err("failed to prepare dst path: %s", mscp_get_error()); goto out; } p->state = FILE_STATE_OPENED; - mpr_info(msg_fp, "copy start: %s\n", p->path); + mpr_info("copy start: %s", p->path); } out: @@ -552,8 +555,7 @@ static int _copy_chunk(struct chunk *c, mf *s, mf *d, return -1; /* not reached */ } -int copy_chunk(FILE *msg_fp, struct chunk *c, - sftp_session src_sftp, sftp_session dst_sftp, +int copy_chunk(struct chunk *c, sftp_session src_sftp, sftp_session dst_sftp, int nr_ahead, int buf_sz, size_t *counter) { mode_t mode; @@ -563,7 +565,7 @@ int copy_chunk(FILE *msg_fp, struct chunk *c, assert((src_sftp && !dst_sftp) || (!src_sftp && dst_sftp)); - if (prepare_dst_path(msg_fp, c->p, dst_sftp) < 0) + if (prepare_dst_path(c->p, dst_sftp) < 0) return -1; /* open src */ @@ -593,12 +595,12 @@ int copy_chunk(FILE *msg_fp, struct chunk *c, return -1; } - mpr_debug(msg_fp, "copy chunk start: %s 0x%lx-0x%lx\n", + mpr_debug("copy chunk start: %s 0x%lx-0x%lx", c->p->path, c->off, c->off + c->len); ret = _copy_chunk(c, s, d, nr_ahead, buf_sz, counter); - mpr_debug(msg_fp, "copy chunk done: %s 0x%lx-0x%lx\n", + mpr_debug("copy chunk done: %s 0x%lx-0x%lx", c->p->path, c->off, c->off + c->len); @@ -610,9 +612,9 @@ int copy_chunk(FILE *msg_fp, struct chunk *c, if (refcnt_dec(&c->p->refcnt) == 0) { c->p->state = FILE_STATE_DONE; if (mscp_setstat(c->p->dst_path, c->p->mode, c->p->size, dst_sftp) < 0) - mpr_err(msg_fp, "failed to chmod and truncate %s: %s\n", + mpr_err("failed to chmod and truncate %s: %s", c->p->path, strerrno()); - mpr_info(msg_fp, "copy done: %s\n", c->p->path); + mpr_info("copy done: %s", c->p->path); } return ret; diff --git a/src/path.h b/src/path.h index 072cc79..a46f61a 100644 --- a/src/path.h +++ b/src/path.h @@ -72,7 +72,6 @@ void chunk_pool_release(struct chunk_pool *cp); struct path_resolve_args { - FILE *msg_fp; size_t *total_bytes; /* args to resolve src path to dst path */ @@ -98,8 +97,7 @@ int walk_src_path(sftp_session src_sftp, const char *src_path, void free_path(struct path *p); /* copy a chunk. either src_sftp or dst_sftp is not null, and another is null */ -int copy_chunk(FILE *msg_fp, struct chunk *c, - sftp_session src_sftp, sftp_session dst_sftp, +int copy_chunk(struct chunk *c, sftp_session src_sftp, sftp_session dst_sftp, int nr_ahead, int buf_sz, size_t *counter); /* just print contents. just for debugging */