From 27977765e8879eb60afe394995a2416bb1ddb201 Mon Sep 17 00:00:00 2001 From: Levi Neely <141506390+lneely@users.noreply.github.com> Date: Sun, 9 Mar 2025 19:18:38 +0100 Subject: [PATCH] non interactive command processing (#123) * support non-interactive command processing - app is now configured in setup_app function - added process_command() to api - support piped input and -c argument - fix memleaks --- control_tools.cpp | 434 ++++++++++++++++++-------------------------- control_tools.h | 8 +- main.cpp | 54 +++--- pclsync/ppath.c | 3 +- pclsync/pshm.c | 1 + pclsync/pssl.c | 16 +- pclsync/rpcclient.c | 106 +++++------ pclsync/rpcclient.h | 2 +- 8 files changed, 269 insertions(+), 355 deletions(-) diff --git a/control_tools.cpp b/control_tools.cpp index 6068f70..0128d60 100644 --- a/control_tools.cpp +++ b/control_tools.cpp @@ -39,8 +39,6 @@ #include #include -#include "control_tools.h" - #include "pclsync_lib.h" #include "pclsync/pshm.h" #include "pclsync/pfoldersync.h" @@ -53,196 +51,6 @@ namespace cc = console_client; namespace control_tools { -static const int STOP = 0; - -int list_sync_folders() { - int ret; - char *errm; - size_t errmsz; - int result; - psync_folder_list_t *flist; - psync_folder_t *folder; - int rval; - - errm = NULL; - errmsz = 0; - rval = 0; - - result = rpc_call(LISTSYNC, "", &ret, &errm, &errmsz); - - if (result != 0) { - std::cout << "List Sync Folders failed. return is " << ret - << " and message is " << (errm ? errm : "no message") - << std::endl; - rval = result; - } - - if(pshm_read((void**)&flist, NULL)) { - const int id_width = 12; - const int path_width = 30; - - if(flist->foldercnt > 0) { - std::cout << std::left << std::setw(id_width) << "Folder ID" - << std::setw(path_width) << "Local Path" - << std::setw(path_width) << "Remote Path" << std::endl; - std::cout << std::string(id_width, '-') - << std::string(path_width - 1, '-') - << std::string(path_width - 1, '-') << std::endl; - for (uint32_t i = 0; i < flist->foldercnt; i++) { - folder = &flist->folders[i]; - std::cout << std::left << std::setw(id_width) << folder->folderid - << std::setw(path_width) << folder->localpath - << std::setw(path_width) << folder->remotepath << std::endl; - } - } else { - std::cout << "No synchronized folders found." << std::endl; - rval = ret; - } - rval = ret; - - free(flist); - } else { - std::cout << "failed to read folder list from shm" << std::endl; - return -1; - } - - if(errm) { - free(errm); - } - - return rval; -} - -int start_crypto(const char *pass) { - int ret; - char *errm; - size_t errm_size; - - int result = rpc_call(STARTCRYPTO, pass, &ret, &errm, &errm_size); - - if (result != 0 || ret != 0) { - std::cout << "Start Crypto failed. return is " << ret << " and message is " - << (errm ? errm : "no message") << std::endl; - } else { - std::cout << "Crypto started. " << std::endl; - } - if (errm) - free(errm); - return ret; -} - -int stop_crypto() { - int ret; - char *errm; - size_t errm_size; - - int result = rpc_call(STOPCRYPTO, "", &ret, &errm, &errm_size); - if (result != 0) { - std::cout << "Stop Crypto failed. return is " << ret << " and message is " - << (errm ? errm : "no message") << std::endl; - } else { - std::cout << "Crypto Stopped. " << std::endl; - } - - if (errm) - free(errm); - return ret; -} - -int remove_sync_folder(const char *folderid) { - int ret; - char *errm; - size_t errmsz; - int result; - int rval; - - errm = NULL; - errmsz = 0; - rval = 0; - - result = rpc_call(STOPSYNC, folderid, &ret, &errm, &errmsz); - if (result != 0) { - std::cout << "Remove Sync Folder failed with unknown error. return is " - << ret << " and message is " << (errm ? errm : "no message") - << std::endl; - rval = result; - } else { - std::cout << "Successfully removed sync folder with folderid " << folderid - << std::endl; - } - - if(errm) { - free(errm); - } - return rval; -} - -// TODO: should add support for specifying sync type. Need a better -// CLI processing solution first. -int add_sync_folder(std::string localpath, std::string remotepath) { - int ret; - char *errm; - size_t errmsz; - int result; - int rval; - - errm = NULL; - errmsz = 0; - rval = 0; - - std::string combinedPaths = localpath + '|' + remotepath; - result = rpc_call(ADDSYNC, combinedPaths.c_str(), &ret, &errm, &errmsz); - - if (result != 0) { - if (result == -1) { - std::cout << "Add Sync Folders failed: remote folder " << remotepath - << " not found." << std::endl; - } else { - std::cout << "Add Sync Folders failed with unknown error. return is " - << ret << " and message is " << (errm ? errm : "no message") - << std::endl; - } - rval = result; - } else { - rval = ret; - } - - if(errm) { - free(errm); - } - - return rval; -} - -int finalize() { - int ret; - char *errm; - size_t errm_size; - - rpc_call(FINALIZE, "", &ret, &errm, &errm_size); - std::cout << "Exiting ..." << std::endl; - - if (errm){ - free(errm); - } - - return ret; -} - -static void help() { - std::cout << "Supported commands are:" << std::endl - << " help(?): Show this help message" << std::endl - << " crypto(c):" << std::endl - << " start : Unlock crypto folder" << std::endl - << " stop: Lock crypto folder" << std::endl - << " sync(s):" << std::endl - << " list(ls): List sync folders" << std::endl - << " add : Add sync folder" << std::endl - << " remove(rm) : Remove sync folder" << std::endl - << " finalize(f): Kill daemon and quit" << std::endl - << " quit(q): Exit this program" << std::endl; -} - static char* command_generator(const char* text, int state) { static int list_index, len; static const char* commands[] = { @@ -255,86 +63,205 @@ static char* command_generator(const char* text, int state) { "quit", "q", nullptr }; - - // If this is a new word to complete, initialize + if (!state) { list_index = 0; len = strlen(text); } - - // Return the next name which partially matches + while (const char* command = commands[list_index++]) { if (strncmp(command, text, len) == 0) { return strdup(command); // Caller frees this with free() } } - return nullptr; // No more matches -} - -static char** command_completion(const char* text, int start, int end) { - // If this is the start of line, complete commands - if (start == 0) { - return rl_completion_matches(text, command_generator); - } - - // Otherwise, don't complete return nullptr; } -void process_commands() { - CLI::App app{"pcloudcc-lneely"}; - app.fallthrough(); - app.footer("Type 'help' or '?' for a list of supported commands."); +static char** command_completion(const char* text, int start, int end) { + if (start == 0) { + return rl_completion_matches(text, command_generator); + } + return nullptr; +} + +void setup_app(CLI::App *app) { + app->fallthrough(); + app->footer("Type 'help' or '?' for a list of supported commands."); // top-level commands - app.add_subcommand("help", "Show help")->alias("?")->callback(help); - auto crypto_cmd = - app.add_subcommand("crypto", "Crypto-related commands")->alias("c"); + app->add_subcommand("help", "Show help")->alias("?")->callback([] { + std::cout << "Supported commands are:" << std::endl + << " help(?): Show this help message" << std::endl + << " crypto(c):" << std::endl + << " start : Unlock crypto folder" << std::endl + << " stop: Lock crypto folder" << std::endl + << " sync(s):" << std::endl + << " list(ls): List sync folders" << std::endl + << " add : Add sync folder" << std::endl + << " remove(rm) : Remove sync folder" << std::endl + << " finalize(f): Kill daemon and quit" << std::endl + << " quit(q): Exit this program" << std::endl; + }); + auto crypto_cmd = app->add_subcommand("crypto", "Crypto-related commands")->alias("c"); crypto_cmd->require_subcommand(); - auto sync_cmd = - app.add_subcommand("sync", "Sync-related commands")->alias("s"); + auto sync_cmd = app->add_subcommand("sync", "Sync-related commands")->alias("s"); sync_cmd->require_subcommand(); - app.add_subcommand("finalize", "Finalize and exit")->alias("f")->callback([] { - finalize(); - exit(0); - }); - app.add_subcommand("quit", "Quit the program")->alias("q")->callback([] { + + // finalize command + app->add_subcommand("finalize", "Finalize and exit")->alias("f")->callback([] { + char *errm = NULL; + size_t errm_size = 0; + rpc_call(FINALIZE, "", &errm, &errm_size); + std::cout << "Exiting ..." << std::endl; + if (errm) { free(errm); } exit(0); }); - // crypto subcommands + app->add_subcommand("quit", "Quit the program")->alias("q")->callback([] { + exit(0); + }); + + // crypto start auto start_crypto_cmd = crypto_cmd->add_subcommand("start", "Start crypto"); - std::string start_crypto_pwd; - start_crypto_cmd->add_option("password", start_crypto_pwd, "Crypto password") - ->required(); - start_crypto_cmd->callback([&] { start_crypto(start_crypto_pwd.c_str()); }); - - crypto_cmd->add_subcommand("stop", "Stop crypto")->callback(stop_crypto); - - // sync subcommands - sync_cmd->add_subcommand("list", "List sync folders") - ->alias("ls") - ->callback(list_sync_folders); - - auto sync_add_cmd = sync_cmd->add_subcommand("add", "Add sync folder"); - std::string syncadd_lpath, syncadd_rpath; - sync_add_cmd->add_option("localpath", syncadd_lpath, "Local Path")->required(); - sync_add_cmd->add_option("remotepath", syncadd_rpath, "Remote Path")->required(); - sync_add_cmd->callback([&] { - add_sync_folder(syncadd_lpath, syncadd_rpath); + static std::string start_crypto_pwd; + start_crypto_cmd->add_option("password", start_crypto_pwd, "Crypto password")->required(); + start_crypto_cmd->callback([] { + char *errm = NULL; + size_t errm_size = 0; + if(int result = rpc_call(STARTCRYPTO, start_crypto_pwd.c_str(), &errm, &errm_size) != 0) { + std::cout << "Start Crypto failed: " << (errm ? errm : "no message") << std::endl; + if (errm) { free(errm); } + return result; + } + std::cout << "Crypto started." << std::endl; + if (errm) { free(errm); } + return 0; }); - auto sync_remove_cmd = - sync_cmd->add_subcommand("remove", "Remove sync folder (use ls to get folder ID)")->alias("rm"); - std::string syncrm_fid; - sync_remove_cmd->add_option("folderid", syncrm_fid, "Folder ID")->required(); - sync_remove_cmd->callback([&] { remove_sync_folder(syncrm_fid.c_str()); }); + // crypto stop + crypto_cmd->add_subcommand("stop", "Stop crypto")->callback([] { + char *errm = NULL; + size_t errm_size = 0; + if(int result = rpc_call(STOPCRYPTO, "", &errm, &errm_size) != 0) { + std::cout << "Stop Crypto failed: "<< (errm ? errm : "no message") << std::endl; + if (errm) { free(errm); } + return result; + } + std::cout << "Crypto Stopped." << std::endl; + if (errm) { free(errm); } + return 0; + }); + + // sync list + sync_cmd->add_subcommand("list", "List sync folders")->alias("ls")->callback([] { + char *errm = NULL; + size_t errmsz = 0; + + if(int result = rpc_call(LISTSYNC, "", &errm, &errmsz) != 0) { + std::cout << "List Sync Folders failed: " << (errm ? errm : "no message") << std::endl; + if (errm) { free(errm); } + return result; + } + + psync_folder_list_t *flist = NULL; + if(pshm_read((void**)&flist, NULL)) { + const int id_width = 12; + const int path_width = 30; + + if(flist->foldercnt > 0) { + std::cout << std::left << std::setw(id_width) << "Folder ID" + << std::setw(path_width) << "Local Path" + << std::setw(path_width) << "Remote Path" << std::endl; + std::cout << std::string(id_width, '-') + << std::string(path_width - 1, '-') + << std::string(path_width - 1, '-') << std::endl; + for (uint32_t i = 0; i < flist->foldercnt; i++) { + psync_folder_t *folder = &flist->folders[i]; + std::cout << std::left << std::setw(id_width) << folder->folderid + << std::setw(path_width) << folder->localpath + << std::setw(path_width) << folder->remotepath << std::endl; + } + } else { + std::cout << "No synchronized folders found." << std::endl; + } + if(flist) { free(flist); } + } else { + std::cout << "failed to read folder list from shm" << std::endl; + if(flist) { free(flist); } + return -1; + } + if(errm) { free(errm); } + return 0; + }); + + // sync add + auto sync_add_cmd = sync_cmd->add_subcommand("add", "Add sync folder"); + static std::string localpath, remotepath; + sync_add_cmd->add_option("localpath", localpath, "Local Path")->required(); + sync_add_cmd->add_option("remotepath", remotepath, "Remote Path")->required(); + sync_add_cmd->callback([] { + char *errm = NULL; + size_t errmsz = 0; + + std::string combinedPaths = localpath + '|' + remotepath; + if(int result = rpc_call(ADDSYNC, combinedPaths.c_str(), &errm, &errmsz) != 0) { + if (result == -1) { + std::cout << "Add Sync Folders failed: remote folder " << remotepath << " not found." << std::endl; + } else { + std::cout << "Add Sync Folders failed:" << (errm ? errm : "no message") << std::endl; + } + if (errm) { free(errm); } + return result; + } + + if(errm) { free(errm); } + return 0; + }); + + // sync remove + auto sync_remove_cmd = sync_cmd->add_subcommand("remove", "Remove sync folder (use ls to get folder ID)")->alias("rm"); + static std::string syncrm_fid; + sync_remove_cmd->add_option("folderid", syncrm_fid, "Folder ID")->required(); + sync_remove_cmd->callback([] { + char *errm = NULL; + size_t errmsz = 0; + const char *folderid = syncrm_fid.c_str(); + + if(int result = rpc_call(STOPSYNC, folderid, &errm, &errmsz) != 0) { + std::cout << "Remove Sync Folder failed: " << (errm ? errm : "no message") << std::endl; + if (errm) { free(errm); } + return result; + } + std::cout << "Successfully removed sync folder with folderid " << folderid << std::endl; + + if(errm) { free(errm); } + return 0; + }); +} + +int process_command(const std::string &command) { + CLI::App app = CLI::App{"pcloudcc-lneely"}; + setup_app(&app); + try { + app.parse(command); + return 0; + } catch (const CLI::ParseError &e) { + std::cerr << "Invalid command: '" << command << "'" << std::endl; + return 1; + } +} + +void process_commands() { + CLI::App app = CLI::App{"pcloudcc-lneely"}; + setup_app(&app); + + // enable command history and auto-completion using_history(); + rl_attempted_completion_function = command_completion; // command loop - rl_attempted_completion_function = command_completion; while (true) { char* line_read = readline("pcloud> "); if (!line_read) break; @@ -350,10 +277,14 @@ void process_commands() { std::vector args; std::istringstream iss(line); std::string arg; + std::ostringstream invs; + while (iss >> arg) { args.push_back(arg); } + invs << "Invalid command: '" << line + << "'. Type 'help' or '?' to get a list of valid commands."; if (!args.empty()) { try { auto *subcom = app.get_subcommand(args[0]); @@ -361,20 +292,13 @@ void process_commands() { std::cout << "Usage for '" << args[0] << "':" << std::endl; std::cout << subcom->help() << std::endl; } else { - std::cout - << "Invalid command: '" << line - << "'. Type 'help' or '?' to get a list of valid commands." - << std::endl; + std::cout << invs.str() << std::endl; } } catch (...) { - std::cout << "Invalid command: '" << line - << "'. Type 'help' or '?' to get a list of valid commands." - << std::endl; + std::cout << invs.str() << std::endl; } } else { - std::cout << "Invalid command: '" << line - << "'. Type 'help' or '?' to get a list of valid commands." - << std::endl; + std::cout << invs.str() << std::endl; } } } diff --git a/control_tools.h b/control_tools.h index 73404c7..62445fb 100644 --- a/control_tools.h +++ b/control_tools.h @@ -29,13 +29,13 @@ #ifndef CONTROL_TOOLS_H #define CONTROL_TOOLS_H +#include + namespace control_tools { -int start_crypto(const char *pass); -int stop_crypto(); -int finalize(); -int daemonize(bool do_commands); void process_commands(); +int daemonize(bool do_commands); +int process_command(const std::string &command); } // namespace control_tools diff --git a/main.cpp b/main.cpp index aab0195..e6be23b 100644 --- a/main.cpp +++ b/main.cpp @@ -58,31 +58,21 @@ int main(int argc, char **argv) { try { po::options_description desc("Allowed options"); - desc.add_options()("help,h", "Show this help message.")( - "username,u", po::value(&username), - "pCloud account name.")( - "password,p", po::bool_switch(&passwordsw), - "Ask for pCloud account password.")( - "tfa_code,t", po::value(&tfa_code), - "pCloud tfa code")( - "trusted_device,r", po::bool_switch(&trusted_device), - "Trust this device.")( - "crypto,c", po::bool_switch(&crypto), - "Ask for crypto password.")( - "passascrypto,y", po::value(), - "User password is the same as crypto password.")( - "daemonize,d", po::bool_switch(&daemon), - "Run the process as a background daemon.")( - "commands ,o", po::bool_switch(&commands), - "Keep parent process alive and process commands. ")( - "mountpoint,m", po::value(), - "Specify where pCloud filesystem is mounted.")( - "commands_only,k", po::bool_switch(&commands_only), - "Open command prompt to interact with running daemon.")( - "newuser,n", po::bool_switch(&newuser), - "Register a new pCloud user account.")( - "savepassword,s", po::bool_switch(&save_pass), - "Save user password in the database."); + desc.add_options() + ("help,h", "Show this help message.") + ("username,u", po::value(&username), "pCloud account name.") + ("password,p", po::bool_switch(&passwordsw), "Ask for pCloud account password.") + ("tfa_code,t", po::value(&tfa_code), "pCloud tfa code") + ("trusted_device,r", po::bool_switch(&trusted_device), "Trust this device.") + ("crypto,c", po::bool_switch(&crypto), "Ask for crypto password.") + ("passascrypto,y", po::value(), "User password is the same as crypto password.") + ("daemonize,d", po::bool_switch(&daemon), "Run the process as a background daemon.") + ("commands ,o", po::bool_switch(&commands), "Keep parent process alive and process commands. ") + ("mountpoint,m", po::value(), "Specify where pCloud filesystem is mounted.") + ("commands_only,k", po::bool_switch(&commands_only), "Open command prompt to interact with running daemon.") + ("command,c", po::value(), "Execute a single command and exit.") + ("newuser,n", po::bool_switch(&newuser), "Register a new pCloud user account.") + ("savepassword,s", po::bool_switch(&save_pass), "Save user password in the database."); po::command_line_parser parser{argc, argv}; po::positional_options_description p; @@ -102,6 +92,20 @@ int main(int argc, char **argv) { exit(0); } + bool has_piped_input = !isatty(STDIN_FILENO); + if (has_piped_input && !vm.count("help")) { + std::string line; + if (std::getline(std::cin, line) && !line.empty()) { + return ct::process_command(line); + } + } + + if (vm.count("command")) { + std::string command = vm["command"].as(); + return ct::process_command(command); + } + + if ((!vm.count("username"))) { std::cout << "Username option is required, specify with " << "-u or --username." << std::endl; diff --git a/pclsync/ppath.c b/pclsync/ppath.c index af33754..a67d028 100644 --- a/pclsync/ppath.c +++ b/pclsync/ppath.c @@ -191,11 +191,12 @@ char *ppath_private(char *name) { if (!path) return NULL; rpath = psync_strcat(path, "/", name, NULL); - free(path); if (stat(rpath, &st) && mkdir(path, PSYNC_DEFAULT_POSIX_FOLDER_MODE)) { psync_free(rpath); + free(path); return NULL; } + free(path); return rpath; } diff --git a/pclsync/pshm.c b/pclsync/pshm.c index 20f42d4..6eeb71f 100644 --- a/pclsync/pshm.c +++ b/pclsync/pshm.c @@ -21,6 +21,7 @@ key_t pshm_get_key() { return (key_t)-1; } snprintf(path, sizeof(path), "%s/.pcloud/data.db", home); + free(home); return ftok(path, 'A'); } diff --git a/pclsync/pssl.c b/pclsync/pssl.c index 4b7de7e..c9fa996 100644 --- a/pclsync/pssl.c +++ b/pclsync/pssl.c @@ -610,9 +610,8 @@ psync_rsa_publickey_t prsa_load_public(const unsigned char *keydata, // function gets the actual key length from the ASN.1 header, trims any bytes // that exceed that length, and writes the trimmed key and length to keydata // and keylen. -static unsigned char* trim_der_key(const unsigned char *keydata, size_t *keylen) { +static void trim_der_key(unsigned char *keydata, size_t *keylen) { size_t len, header_size, correct_len; - unsigned char tag; unsigned char *p = (unsigned char *)keydata; const unsigned char *end; int ret; @@ -621,17 +620,16 @@ static unsigned char* trim_der_key(const unsigned char *keydata, size_t *keylen) end = keydata + *keylen; ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (ret != 0) { - return NULL; + return; } header_size = p - keydata; correct_len = header_size + len; trimmed = malloc(correct_len); - if (!trimmed) return NULL; - + if (!trimmed) return; memcpy(trimmed, keydata, correct_len); + memcpy(keydata, trimmed, correct_len); + free(trimmed); *keylen = correct_len; - - return trimmed; } psync_rsa_privatekey_t prsa_load_private(const unsigned char *keydata, size_t keylen) { @@ -639,8 +637,8 @@ psync_rsa_privatekey_t prsa_load_private(const unsigned char *keydata, size_t ke mbedtls_rsa_context *rsa; int ret; - trim_der_key(keydata, &keylen); - + trim_der_key((unsigned char *)keydata, &keylen); + mbedtls_pk_init(&ctx); ret = mbedtls_pk_parse_key(&ctx, keydata, keylen, NULL, 0, rng_get, &rng); if(unlikely(ret)) { diff --git a/pclsync/rpcclient.c b/pclsync/rpcclient.c index 38ca750..d45f0ee 100644 --- a/pclsync/rpcclient.c +++ b/pclsync/rpcclient.c @@ -77,8 +77,7 @@ // specified sockpath. it may write an error message and error message // size to out and out_size, and a "ret" value to ret (i think this is // redundant maybe...) -static int socket_connect(const char *sockpath, char **out, size_t *out_size, - int *ret) { +static int socket_connect(const char *sockpath, char **out, size_t *out_size) { int fd; struct sockaddr_un addr; const char *error_msg; @@ -87,7 +86,6 @@ static int socket_connect(const char *sockpath, char **out, size_t *out_size, error_msg = "Unable to create unix socket"; *out = strdup(error_msg); *out_size = strlen(error_msg) + 1; - *ret = POVERLAY_SOCKET_CREATE_FAILED; return POVERLAY_SOCKET_CREATE_FAILED; } @@ -98,43 +96,36 @@ static int socket_connect(const char *sockpath, char **out, size_t *out_size, error_msg = "Unable to connect to UNIX socket"; *out = strdup(error_msg); *out_size = strlen(error_msg) + 1; - *ret = POVERLAY_SOCKET_CONNECT_FAILED; return POVERLAY_SOCKET_CONNECT_FAILED; } return fd; } -static int write_request(int fd, int msgtype, const char *value, char **out, - size_t *out_size, int *ret) { +static int write_request(int fd, int msgtype, const char *value, char **out, size_t *out_size) { uint64_t bytes_written; - int rc; - int len; - int size; - char *buf; - const char *err; - rpc_message_t *request; - char *curbuf; + int len = strlen(value); + int size = sizeof(rpc_message_t) + len + 1; + char *buf = (char *)malloc(size); - *ret = 0; // Initialize ret to 0 - - len = strlen(value); - size = sizeof(rpc_message_t) + len + 1; - buf = (char *)malloc(size); - request = (rpc_message_t *)buf; + // prepare the message + rpc_message_t *request = (rpc_message_t *)buf; memset(request, 0, size); request->type = msgtype; strncpy(request->value, value, len + 1); request->length = size; bytes_written = 0; - curbuf = (char *)request; - while (bytes_written < request->length && *ret == 0) { - rc = write(fd, curbuf, (request->length - bytes_written)); + // write to the socket + char *curbuf = (char *)request; + int writeerr = 0; + while (bytes_written < request->length && !writeerr) { + int rc = write(fd, curbuf, (request->length - bytes_written)); if (rc <= 0) { if (errno != EINTR) { - err = "failed to write to socket."; + const char *err = "failed to write to socket."; *out = strdup(err); - *ret = POVERLAY_WRITE_SOCK_ERR; + *out_size = strlen(err) + 1; + writeerr = POVERLAY_WRITE_SOCK_ERR; } } else { bytes_written += rc; @@ -142,91 +133,86 @@ static int write_request(int fd, int msgtype, const char *value, char **out, } } - if (*ret == 0 && bytes_written != request->length) { - err = "Communication error"; + // return error if only partial data written + if (!writeerr && bytes_written != request->length) { + const char *err = "communication error"; *out = strdup(err); *out_size = strlen(err) + 1; - *ret = POVERLAY_WRITE_COMM_ERR; + writeerr = POVERLAY_WRITE_COMM_ERR; } free(buf); - return *ret; + return writeerr; } -static int read_response(int fd, char **out, size_t *out_size, int *ret) { - rpc_message_t *msg; - ssize_t bytes_read; +static int read_response(int fd, char **out, size_t *out_size) { - msg = (rpc_message_t *)malloc(POVERLAY_BUFSIZE); + rpc_message_t *msg = (rpc_message_t *)malloc(POVERLAY_BUFSIZE); if (msg == NULL) { const char *error_msg = "Memory allocation failed"; *out = strdup(error_msg); *out_size = strlen(error_msg) + 1; - *ret = -1; return -1; } - bytes_read = read(fd, msg, POVERLAY_BUFSIZE); + ssize_t bytes_read = read(fd, msg, POVERLAY_BUFSIZE); if (bytes_read <= 0) { const char *error_msg = (bytes_read == 0) ? "Connection closed" : "Read error"; - free(msg); *out = strdup(error_msg); *out_size = strlen(error_msg) + 1; - *ret = -1; + free(msg); return -1; } *out = (char *)malloc(msg->length); memcpy(*out, msg->value, msg->length); *out_size = msg->length; - *ret = msg->type; free(msg); return 0; } int rpc_get_state(pCloud_FileState *state, char *path) { + char *errm = NULL; + size_t errm_size = 0; int rep = 0; - char *errm; - size_t errm_size; - if (!rpc_call(4, path /*IN*/, &rep, &errm, &errm_size)) { + if ((rep = rpc_call(4, path, &errm, &errm_size) == 0)) { debug(D_NOTICE, "rpc_get_state responese rep[%d] path[%s]", rep, path); - if (errm) + if (errm) { debug(D_NOTICE, "The error is %s", errm); - if (rep == 10) + } + if (rep == 10) { *state = FileStateInSync; - else if (rep == 12) + } else if (rep == 12) { *state = FileStateInProgress; - else if (rep == 11) + } else if (rep == 11) { *state = FileStateNoSync; - else + } else { *state = FileStateInvalid; - } else + } + } else { debug(D_ERROR, "rpc_get_state ERROR rep[%d] path[%s]", rep, path); - free(errm); + } + if(errm) { + free(errm); + } return 0; } // path contains the input argument(s). -int rpc_call(int id, const char *path, int *ret, char **errm, size_t *errmsz) { - int result; - int sockfd; +int rpc_call(int id, const char *path, char **errm, size_t *errmsz) { + int result = 0; + int sockfd = -1; - sockfd = -1; - result = 0; - *errm = NULL; - *errmsz = 0; - *ret = 0; - - sockfd = socket_connect(PRPC_SOCK_PATH, errm, errmsz, ret); + sockfd = socket_connect(PRPC_SOCK_PATH, errm, errmsz); if (sockfd >= 0) { - if ((result = write_request(sockfd, id, path, errm, errmsz, ret)) == 0) { - result = read_response(sockfd, errm, errmsz, ret); + if ((result = write_request(sockfd, id, path, errm, errmsz)) == 0) { + result = read_response(sockfd, errm, errmsz); } close(sockfd); } else { result = -1; } - return *ret; // always 0 on success + return result; // always 0 on success } diff --git a/pclsync/rpcclient.h b/pclsync/rpcclient.h index 4516d5b..d33ae92 100644 --- a/pclsync/rpcclient.h +++ b/pclsync/rpcclient.h @@ -49,7 +49,7 @@ typedef enum _pCloud_FileState { } pCloud_FileState; int rpc_get_state(pCloud_FileState *, char *); -int rpc_call(int id, const char *, int *, char **, size_t *); +int rpc_call(int id, const char *path, char **errm, size_t *errmsz); #ifdef __cplusplus }