summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c109
1 files changed, 97 insertions, 12 deletions
diff --git a/src/main.c b/src/main.c
index 317722f..0771bbd 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3,14 +3,25 @@
#include <stdbool.h>
#include <unistd.h>
+#include <list.h>
#include <util.h>
#include <ssh.h>
#include <file.h>
#include <platform.h>
+int verbose = 0; /* util.h */
#define DEFAULT_MIN_CHUNK_SZ (64 << 20) /* 64MB */
+struct sscp {
+ char *host; /* remote host (and username) */
+ sftp_session ctrl; /* control sftp session */
+
+ struct list_head file_list;
+ char *target;
+ bool target_is_remote;
+};
+
void usage(bool print_help) {
printf("sscp: super scp, copy files over multiple ssh connections\n"
"\n"
@@ -22,8 +33,7 @@ void usage(bool print_help) {
if (!print_help)
return;
- printf(" -r expand directory recusrively\n"
- " -n NR_CONNECTIONS max number of connections (default: # of cpu cores)\n"
+ printf(" -n NR_CONNECTIONS max number of connections (default: # of cpu cores)\n"
" -s MIN_CHUNKSIZE min chunk size (default: 64MB)\n"
" -S MAX_CHUNKSIZE max chunk size (default: filesize / nr_conn)\n"
"\n"
@@ -43,22 +53,65 @@ void usage(bool print_help) {
"\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];
+
+err_out:
+ for (n = 0; n < cnt; n++) {
+ free(hostnames[n]);
+ }
+ return NULL;
+}
+
int main(int argc, char **argv)
{
+ struct sscp sscp;
struct ssh_opts opts;
int nr_conn = nr_cpus();
- bool recursive = false;
int min_chunk_sz = DEFAULT_MIN_CHUNK_SZ;
int max_chunk_sz = 0;
+ int ret = 0;
char ch;
memset(&opts, 0, sizeof(opts));
+ memset(&sscp, 0, sizeof(sscp));
+ INIT_LIST_HEAD(&sscp.file_list);
- while ((ch = getopt(argc, argv, "r:n:s:S:l:p:i:c:Cvh")) != -1) {
+ while ((ch = getopt(argc, argv, "n:s:S:l:p:i:c:Cvh")) != -1) {
switch (ch) {
- case 'r':
- recursive = true;
- break;
case 'n':
nr_conn = atoi(optarg);
if (nr_conn < 1) {
@@ -113,6 +166,7 @@ int main(int argc, char **argv)
break;
case 'v':
opts.debuglevel++;
+ verbose++;
break;
case 'h':
usage(true);
@@ -129,13 +183,44 @@ int main(int argc, char **argv)
return 1;
}
- printf("opts.port %s\n", opts.port);
+ if (argc - optind < 2) {
+ /* sscp needs at lease 2 (src and target) argument */
+ usage(false);
+ return 1;
+ }
+
+ sscp.target = argv[argc - 1];
+ sscp.target_is_remote = file_has_hostname(sscp.target);
+
+ /* create control session */
+ sscp.host = find_hostname(optind, argc, argv);
+ if (!sscp.host) {
+ pr_err("no remote host given\n");
+ return 1;
+ }
+ sscp.ctrl = ssh_make_sftp_session(sscp.host, &opts);
+ if (!sscp.ctrl)
+ return 1;
+
+ /* check target is directory */
+ ret = file_is_directory(sscp.target, sscp.target_is_remote ? sscp.ctrl : NULL);
+ if (ret < 0)
+ return 1;
+ if (ret == 0) {
+ pr_err("target must be directory\n");
+ return 1;
+ }
- int n;
- for (n = 0; n < argc; n++) {
- printf("%d %s\n", n, argv[n]);
+ ret = file_fill(sscp.ctrl, &sscp.file_list, &argv[optind], argc - optind - 1);
+ if (ret < 0) {
+ ssh_sftp_close(sscp.ctrl);
+ return 1;
}
- printf("optind %d", optind);
+#ifdef DEBUG
+ file_dump(&sscp.file_list);
+#endif
+
+ ssh_sftp_close(sscp.ctrl);
return 0;
}