summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
authorRyo Nakamura <upa@haeena.net>2022-10-15 21:59:25 +0900
committerRyo Nakamura <upa@haeena.net>2022-10-15 21:59:25 +0900
commit303a9eb974f884b5f9f7e14fdd83a821f21e32e6 (patch)
tree91c535639e39e7f204db7a194854f4865dfff184 /src/main.c
initial commit
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..bec9a00
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,135 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include <util.h>
+#include <ssh.h>
+#include <file.h>
+#include <platform.h>
+
+
+#define DEFAULT_MIN_CHUNK_SZ (2 << 20) /* 2MB */
+
+void usage(bool print_help) {
+ printf("sscp: super scp, copy files over multiple ssh connections\n"
+ "\n"
+ "Usage: sscp [rvC] [-n max_conns] [-s min_chunk_sz] [-S max_chunk_sz]\n"
+ " [-l login_name] [-p port] [-i identity_file]\n"
+ " [-c cipher_spec] source ... target\n"
+ "\n");
+
+ if (!print_help)
+ return;
+
+ printf(" -r copy directory recusrively\n"
+ " -n NR_CONNECTIONS max number of connections (default: # of cpu cores)\n"
+ " -s CHUNKSIZE min chunk size (default: 2MB)\n"
+ " -S CHUNKSIZE max chunk size (default: filesize / nr_conn)\n"
+ "\n"
+ " -l LOGIN_NAME login name\n"
+ " -p PORT port number\n"
+ " -i IDENTITY identity to be used for ssh\n"
+ " -c CIPHER cipher spec, see `ssh -Q cipher`\n"
+ " -C enable compression on libssh\n"
+ " -v increment output level\n"
+ " -h print this help\n"
+ "\n");
+}
+
+int main(int argc, char **argv)
+{
+ 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;
+ char ch;
+
+ memset(&opts, 0, sizeof(opts));
+
+ while ((ch = getopt(argc, argv, "r: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) {
+ 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 'l':
+ opts.login_name = optarg;
+ break;
+ case 'p':
+ opts.port = optarg;
+ break;
+ case 'i':
+ opts.identity = optarg;
+ break;
+ case 'c':
+ opts.cipher = optarg;
+ break;
+ case 'C':
+ opts.compress++;
+ break;
+ case 'v':
+ opts.debuglevel++;
+ break;
+ case 'h':
+ usage(true);
+ return 1;
+ default:
+ usage(false);
+ return 1;
+ }
+ }
+
+ 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;
+ }
+
+ printf("opts.port %s\n", opts.port);
+
+ int n;
+ for (n = 0; n < argc; n++) {
+ printf("%d %s\n", n, argv[n]);
+ }
+ printf("optind %d", optind);
+
+ return 0;
+}