Files
sashimono/sashi-cli/cli-manager.cpp
2021-07-22 09:51:28 +05:30

143 lines
4.2 KiB
C++

#include "pchheader.hpp"
#include "cli-manager.hpp"
namespace cli
{
constexpr const char *SOCKET_NAME = "sa.sock"; // Name of the sashimono socket.
constexpr const char *DATA_DIR = "/etc/sashimono"; // Sashimono data directory.
constexpr const int BUFFER_SIZE = 1024; // Max read buffer size.
cli_context ctx;
bool init_success = false;
/**
* Initialize the socket and connect.
* @return 0 on success, -1 on error.
*/
int init(std::string_view sashi_dir)
{
ctx.sashi_dir = sashi_dir;
// Get the socket path from available location.
if (get_socket_path(ctx.socket_path) == -1)
return -1;
// Create the seq paket socket.
ctx.socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (ctx.socket_fd == -1)
{
std::cerr << errno << " :Error while creating the sashimono socket.\n";
return -1;
}
struct sockaddr_un addr;
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, ctx.socket_path.data(), sizeof(addr.sun_path) - 1);
if (connect(ctx.socket_fd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1)
{
// If permission denied, show a custom error.
if (errno == EACCES)
std::cerr << "Permission denied: Only root or users in 'sashiadmin' group can access the sashimono socket.\n";
else
std::cerr << errno << " :Error while connecting to the sashimono socket.\n";
close(ctx.socket_fd);
return -1;
}
init_success = true;
return 0;
}
/**
* Locate and return the sashimono agent socket path according predefined rules.
* If sa.sock found on the same path as the cli binary, use that. (to support dev testing)
* Else sa.sock found on /etc/sashimono, use that.
* Else show error.
* @param socket_path Socket path to be populated.
* @return 0 on success, -1 on error.
*/
int get_socket_path(std::string &socket_path)
{
// Check whether socket exists in exec path.
std::string path = ctx.sashi_dir + std::string("/") + SOCKET_NAME;
struct stat st;
if (stat(path.data(), &st) == 0 && S_ISSOCK(st.st_mode))
{
socket_path = path;
return 0;
}
// Otherwise check in the data dir.
path = DATA_DIR + std::string("/") + SOCKET_NAME;
memset(&st, 0, sizeof(struct stat));
if (stat(path.data(), &st) == 0 && S_ISSOCK(st.st_mode))
{
socket_path = path;
return 0;
}
std::cerr << SOCKET_NAME << " is not found.\n";
return -1;
}
/**
* Write a given message into the sashimono socket.
* @param message Message to be write.
* @return 0 on success, -1 on error.
*/
int write_to_socket(std::string_view message)
{
if (!init_success)
{
std::cerr << "Sashimono socket is not initialized.\n";
return -1;
}
if (write(ctx.socket_fd, message.data(), message.size()) == -1)
{
std::cerr << errno << " :Error while wrting to the sashimono socket.\n";
return -1;
}
return 0;
}
/**
* Read message from the sashimono socket.
* @param message Message to be read.
* @return Read message length on success, -1 on error.
*/
int read_from_socket(std::string &message)
{
if (!init_success)
{
std::cerr << "Sashimono socket is not initialized.\n";
return -1;
}
// Resize the message to max length and resize to original read length after reading.
message.resize(BUFFER_SIZE);
const int res = read(ctx.socket_fd, message.data(), message.length());
if (res == -1)
{
std::cerr << errno << " :Error while reading from the sashimono socket.\n";
return -1;
}
message.resize(res);
return res;
}
/**
* Close the socket and deinitialize.
*/
void deinit()
{
if (init_success)
close(ctx.socket_fd);
}
}