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
This commit is contained in:
Levi Neely 2025-03-09 19:18:38 +01:00 committed by GitHub
parent f437fe840e
commit 27977765e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 269 additions and 355 deletions

View File

@ -39,8 +39,6 @@
#include <readline/readline.h>
#include <readline/history.h>
#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 <crypto pass>: Unlock crypto folder" << std::endl
<< " stop: Lock crypto folder" << std::endl
<< " sync(s):" << std::endl
<< " list(ls): List sync folders" << std::endl
<< " add <localpath> <remotepath>: Add sync folder" << std::endl
<< " remove(rm) <folderid>: 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[] = {
@ -256,85 +64,204 @@ static char* command_generator(const char* text, int state) {
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 <crypto pass>: Unlock crypto folder" << std::endl
<< " stop: Lock crypto folder" << std::endl
<< " sync(s):" << std::endl
<< " list(ls): List sync folders" << std::endl
<< " add <localpath> <remotepath>: Add sync folder" << std::endl
<< " remove(rm) <folderid>: 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<std::string> 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;
}
}
}

View File

@ -29,13 +29,13 @@
#ifndef CONTROL_TOOLS_H
#define CONTROL_TOOLS_H
#include <string>
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

View File

@ -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<std::string>(&username),
"pCloud account name.")(
"password,p", po::bool_switch(&passwordsw),
"Ask for pCloud account password.")(
"tfa_code,t", po::value<std::string>(&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<std::string>(),
"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<std::string>(),
"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<std::string>(&username), "pCloud account name.")
("password,p", po::bool_switch(&passwordsw), "Ask for pCloud account password.")
("tfa_code,t", po::value<std::string>(&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<std::string>(), "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<std::string>(), "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<std::string>(), "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<std::string>();
return ct::process_command(command);
}
if ((!vm.count("username"))) {
std::cout << "Username option is required, specify with "
<< "-u or --username." << std::endl;

View File

@ -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;
}

View File

@ -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');
}

View File

@ -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,7 +637,7 @@ 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);

View File

@ -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
}

View File

@ -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
}