/* Parse a single option. */ static error_t parse_opt (int key, char *arg, struct argp_state *state) { struct arguments *p = state->input; switch (key) { case ARGP_KEY_ARG: switch (state->arg_num) { case 0: p->input_file = arg; break; case 1: p->output_file = arg; break; default: argp_usage(state); } break; case ARGP_KEY_END: if (!valid_arguments(p)) argp_usage (state); break; default: return ARGP_ERR_UNKNOWN; } return 0; }
static gint scp_file(const wshc_scp_file_args* args) { GError *err = NULL; wsh_ssh_session_t session = { .session = NULL, .channel = NULL, .hostname = args->host, .username = args->user, .password = args->pass, .scp = NULL, .port = args->port, }; if (session.password == NULL) session.auth_type = WSH_SSH_AUTH_PUBKEY; else session.auth_type = WSH_SSH_AUTH_PASSWORD; if (wsh_ssh_host(&session, &err)) { g_printerr("%s\n", err->message); g_error_free(err); return EXIT_FAILURE; } if (wsh_verify_host_key(&session, FALSE, FALSE, &err)) { g_printerr("%s\n", err->message); g_error_free(err); return EXIT_FAILURE; } if (wsh_ssh_authenticate(&session, &err)) { g_printerr("%s\n", err->message); g_error_free(err); return EXIT_FAILURE; } if (wsh_ssh_scp_init(&session, args->location)) { g_printerr("Error initializing scp"); return EXIT_FAILURE; } for (gint i = 0; i < args->num_files; i++) { if (wsh_ssh_scp_file(&session, args->files[i], FALSE, &err)) { g_printerr("%s\n", err->message); g_error_free(err); err = NULL; } } wsh_ssh_scp_cleanup(&session); wsh_ssh_disconnect(&session); return EXIT_SUCCESS; } gint main(gint argc, gchar** argv) { GError* err = NULL; GOptionContext* context; gint ret = EXIT_SUCCESS; gchar** hosts = NULL; gsize num_hosts = 0; gchar* password = NULL; wsh_init_logger(WSH_LOGGER_CLIENT); wsh_ssh_init(); if (wsh_client_init(&err)) { g_printerr("%s", err->message); g_error_free(err); return EXIT_FAILURE; } context = g_option_context_new("[FILENAMES...] - scp file to multiple machines at once"); g_option_context_add_main_entries(context, entries, NULL); if (! g_option_context_parse(context, &argc, &argv, &err)) { g_printerr("Option parsing failed: %s\n", err->message); g_error_free(err); return EXIT_FAILURE; } if (argc == 1) { g_printerr("ERROR: Must provide a host and a file\n\n"); g_printerr("%s", g_option_context_get_help(context, FALSE, NULL)); g_option_context_free(context); return EXIT_FAILURE; } gchar* msg = NULL; if (! valid_arguments(&msg)) { g_printerr("%s\n", msg); g_free(msg); g_printerr("%s", g_option_context_get_help(context, FALSE, NULL)); g_option_context_free(context); return EXIT_FAILURE; } g_option_context_free(context); // We're done with option validation if (username == NULL) username = g_strdup(g_get_user_name()); if (ask_password) { if ((ret = wsh_client_lock_password_pages(&passwd_mem))) { g_printerr("%s\n", strerror(ret)); return ret; } password = ((gchar*)passwd_mem) + (WSH_MAX_PASSWORD_LEN * 0); if ((ret = wsh_client_getpass(password, WSH_MAX_PASSWORD_LEN, "SSH password: "******"%s\n", strerror(ret)); return ret; } if (! password) return EXIT_FAILURE; } if (!location) location = g_strdup("~"); if (file_arg) { if (wsh_exp_filename(&hosts, &num_hosts, file_arg, &err)) { g_printerr("%s\n", err->message); g_error_free(err); return EXIT_FAILURE; } } if (hosts_arg) { hosts = g_strsplit(hosts_arg, ",", 0); num_hosts = g_strv_length(hosts); } #ifdef WITH_RANGE if (range) { if (wsh_exp_range(&hosts, &num_hosts, range, &err)) { g_printerr("%s\n", err->message); g_error_free(err); return EXIT_FAILURE; } } #endif argv++; argc--; for (gint i = 1; i < argc; i++) { // scp will catch this, but I'd like to catch it before // we start even trying to scp files if (!g_file_test(argv[i], G_FILE_TEST_EXISTS)) { g_printerr("ERROR: %s doesn't exist\n", argv[i]); ret = EXIT_FAILURE; goto bad; } } if (threads <= 0) { wshc_scp_file_args args; args.port = port; args.user = username; args.pass = password; args.files = argv; args.num_files = argc; args.location = location; for (gsize i = 0; i < num_hosts; i++) { args.host = hosts[i]; scp_file(&args); } } else { GThreadPool* gtp; if ((gtp = g_thread_pool_new((GFunc)scp_file, NULL, threads, TRUE, &err)) == NULL) { g_printerr("%s\n", err->message); g_error_free(err); return EXIT_FAILURE; } wshc_scp_file_args args[num_hosts]; for (gsize i = 0; i < num_hosts; i++) { args[i].host = hosts[i]; args[i].port = port; args[i].user = username; args[i].pass = password; args[i].files = argv; args[i].num_files = argc; args[i].location = location; g_thread_pool_push(gtp, &args[i], NULL); } g_thread_pool_free(gtp, FALSE, TRUE); } if (password) { memset_s(password, WSH_MAX_PASSWORD_LEN, 0, strlen(password)); wsh_client_unlock_password_pages(passwd_mem); } bad: wsh_ssh_cleanup(); wsh_exit_logger(); if (password) g_free(password); password = NULL; if (range) g_free(range); range = NULL; if (hosts_arg) g_free(hosts_arg); g_free(username); username = NULL; return ret; }