diff --git a/control_tools.cpp b/control_tools.cpp index 6068f70..f39de89 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,30 +63,25 @@ 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 + return nullptr; } 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; } @@ -288,53 +91,160 @@ void process_commands() { 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(); + + // finalize command app.add_subcommand("finalize", "Finalize and exit")->alias("f")->callback([] { - finalize(); + 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); }); + app.add_subcommand("quit", "Quit the program")->alias("q")->callback([] { exit(0); }); - // crypto subcommands + // 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); + 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"); + // 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; + } + free(flist); + } else { + std::cout << "failed to read folder list from shm" << std::endl; + return -1; + } + if(errm) { free(errm); } + return 0; + }); + + // sync add + auto sync_add_cmd = sync_cmd->add_subcommand("add", "Add sync folder"); + 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"); 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()); }); + 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; + }); + + // 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 +260,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 +275,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..69fef4e 100644 --- a/control_tools.h +++ b/control_tools.h @@ -31,11 +31,8 @@ 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); } // namespace control_tools 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 }