Commit e174cb05 authored by Seblu's avatar Seblu
Browse files

Ajout des fonctions reseaux

parent be270a29
Loading
Loading
Loading
Loading

src/sld/README

0 → 100644
+1 −0
Original line number Diff line number Diff line
Max command line size = 512

src/sld/TODO

0 → 100644
+9 −0
Original line number Diff line number Diff line
Improvments
Commande exec avec execution en //
command clean
command status
command reload
command update

BUG:
la commande file est buggé suremetn dans le MD5
+332 −134
Original line number Diff line number Diff line
@@ -3,9 +3,11 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -13,9 +15,12 @@
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>
#include <openssl/md5.h>

#include "sld.hh"

SLDaemon::SLDaemon() : socket_fs_(NULL) {}

SLDaemon::options::options() {
  this->port = 0;
  this->verbose = 3;
@@ -24,14 +29,14 @@ SLDaemon::options::options() {
void SLDaemon::usage(const char *argv0) const {
  std::cerr << "usage: " 
	    << argv0
	    << " [-f conffile] [-d scriptdir] [-h] [-v] [-u user]"
	    << " [-f conffile] [-d scriptdir] [-h] [-v] [-l login]"
	    << "[-p pass] [-H host] [-P port] [-V]"
	    << std::endl
	    << "  -f conffile  : read and load conf file." << std::endl
	    << "  -d scriptdir : Scripts directory." << std::endl
	    << "  -h           : Print this usage." << std::endl
	    << "  -v           : Verbose mode." << std::endl
	    << "  -u name      : Set user to name." << std::endl
	    << "  -l name      : Set login to name." << std::endl
	    << "  -p secret    : Set pass to secret." << std::endl
	    << "  -H name      : Set server host to name." << std::endl
	    << "  -P number    : Set server port to number." << std::endl
@@ -44,56 +49,56 @@ SLDaemon::options *SLDaemon::getoptions(int argc, char *argv[]) const {

  if (argc == 1) {
    usage(*argv);
    throw Error(EXIT_USAGE);
    throw Error(ERR_USAGE);
  }

  for (int i = 1; i < argc; ++i) {
    if (!strcmp(argv[i], "-h")) {
      usage(*argv);
      throw Error(EXIT_USAGE);
      throw Error(ERR_USAGE);
    }
    else if (!strcmp(argv[i], "-v")) {
      opt.verbose = 1;
    }
    else if (!strcmp(argv[i], "-V")) {
      std::cout << "sl daemon version : " << VERSION << std::endl;
      exit(EXIT_OK);
      exit(ERR_OK);
    }
    else if (!strcmp(argv[i], "-H")) {
      if (++i >= argc)
	throw Error(EXIT_USAGE, "No enough argument for option -h.");
      opt.host = string(argv[i]);
	throw Error(ERR_USAGE, "No enough argument for option -h.");
      opt.server = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-P")) {
      if (++i >= argc)
	throw Error(EXIT_USAGE, "No enough argument for option -p.");
	throw Error(ERR_USAGE, "No enough argument for option -p.");
      char *endptr;
      opt.port = strtol(argv[i], &endptr, 10);
      if (!(*argv[i] != '\0' && *endptr == '\0'))
	throw Error(EXIT_USAGE, "Unable to convert port to a number.");
	throw Error(ERR_USAGE, "Unable to convert port to a number.");
    }
    else if (!strcmp(argv[i], "-f")) {
      if (++i >= argc)
	throw Error(EXIT_USAGE, "No enough argument for option -f.");
	throw Error(ERR_USAGE, "No enough argument for option -f.");
      opt.conffile = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-d")) {
      if (++i >= argc)
	throw Error(EXIT_USAGE, "No enough argument for option -d.");
	throw Error(ERR_USAGE, "No enough argument for option -d.");
      opt.scriptdir = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-u")) {
    else if (!strcmp(argv[i], "-l")) {
      if (++i >= argc)
	throw Error(EXIT_USAGE, "No enough argument for option -u.");
      opt.user = string(argv[i]);
	throw Error(ERR_USAGE, "No enough argument for option -l.");
      opt.login = string(argv[i]);
    }
    else if (!strcmp(argv[i], "-p")) {
      if (++i >= argc)
	throw Error(EXIT_USAGE, "No enough argument for option -s.");
	throw Error(ERR_USAGE, "No enough argument for option -p.");
      opt.pass = string(argv[i]);
    }
    else {
      Error *err = new Error(EXIT_USAGE);
      Error *err = new Error(ERR_USAGE);
      *err << "Invalid options : " << string(argv[i]) << ".";
      throw *err;
    }
@@ -105,16 +110,16 @@ SLDaemon::options *SLDaemon::getoptions(int argc, char *argv[]) const {

SLDaemon::options *SLDaemon::getoptions(const string file) const {
  if (file == "")
    throw Error(EXIT_BADPARAM, "Conf file not implemented");
  throw Error(EXIT_BADPARAM, "Conf file not implemented");
    throw Error(ERR_BADPARAM, "Conf file not implemented");
  throw Error(ERR_BADPARAM, "Conf file not implemented");
  return NULL;
}

void SLDaemon::applyoptions(const options *opt) {
  assert(opt);
  if (opt->host != "") options_.host = opt->host;
  if (opt->server != "") options_.server = opt->server;
  if (opt->port != 0) options_.port = opt->port;
  if (opt->user != "") options_.user = opt->user;
  if (opt->login != "") options_.login = opt->login;
  if (opt->pass != "") options_.pass = opt->pass;
  if (opt->verbose != 3) options_.verbose = opt->verbose;
  if (opt->conffile != "") options_.conffile = opt->conffile;
@@ -124,115 +129,166 @@ void SLDaemon::applyoptions(const options *opt) {
void SLDaemon::check_options() const {
  // print info in verbose mode
  if (verbose()) {
    std::cout << "Server host is : " << options_.host << "." << std::endl;
    std::cout << "Server host is : " << options_.server << "." << std::endl;
    std::cout << "Server port is : " << options_.port << "." << std::endl;
    std::cout << "Daemon user is : " << options_.user << "." << std::endl;
    std::cout << "Daemon login is : " << options_.login << "." << std::endl;
    std::cout << "Daemon pass is : " << options_.pass << "." << std::endl;
    std::cout << "Daemon scripts directory is : " << options_.scriptdir << "." << std::endl;
    std::cout << "Verbose mode : " << verbose() << "." << std::endl;
  }

  // Check validy of arguement
  if (options_.host == "")
    throw Error(EXIT_BADPARAM, "No server address specified.");
  if (options_.server == "")
    throw Error(ERR_BADPARAM, "No server address specified.");
  if (options_.port == 0)
    throw Error(EXIT_BADPARAM, "No server port specified.");
    throw Error(ERR_BADPARAM, "No server port specified.");
  if (options_.port < 1 || options_.port > 65535)
    throw Error(EXIT_BADPARAM, "Bad server port number (1 - 65535).");
  if (options_.user == "")
    throw Error(EXIT_BADPARAM, "No user specified.");
    throw Error(ERR_BADPARAM, "Bad server port number (1 - 65535).");
  if (options_.login == "")
    throw Error(ERR_BADPARAM, "No login specified.");
  if (options_.pass == "")
    throw Error(EXIT_BADPARAM, "No pass specified.");
    throw Error(ERR_BADPARAM, "No pass specified.");
  if (options_.scriptdir == "")
    throw Error(EXIT_BADPARAM, "No scripts directory specified.");
    throw Error(ERR_BADPARAM, "No scripts directory specified.");

  // Empty scripts dir
  // TODO
}
void SLDaemon::run() {
  char *line;

  check_options();
  connect();
  auth();
  while (1) {
    line = recvln();
    // call right handler
    try {
      if (!strcmp(line, "EXIT\n"))
	cmd_exit();
      else if (!strcmp(line, "RELOAD\n"))
	cmd_reload();
      else if (!strcmp(line, "VERSION\n"))
	cmd_version();
      else if (!strcmp(line, "CLEAN\n"))
	cmd_clean();
      else if (!strcmp(line, "LIST\n"))
	cmd_list();
      else if (!strncmp(line, "EXEC ", 5))
	cmd_exec(line);
      else if (!strncmp(line, "FILE ", 5))
	cmd_file(line);
      else if (!strncmp(line, "UPDATE ", 6))
	cmd_update(line);
      else
	proto_violation();
    }
    catch (const Error &e) {
      e.print();
      send("!! ");
      send(e.message());
    }
    delete line;
  }
}

//******************************************************************************
// network functions
//******************************************************************************

void SLDaemon::connect() {
  struct sockaddr_in daddr;
  struct hostent *h;

  h = gethostbyname(options_.host.c_str());
  // close existing connexion
  if (socket_fs_ == NULL)
    disconnect();

  // retrieve remote host info
  h = gethostbyname(options_.server.c_str());
  if (h == NULL)
    throw Error(EXIT_NET, hstrerror(h_errno));
    throw Error(ERR_NET, hstrerror(h_errno));

  socket_ = socket(PF_INET, SOCK_STREAM, 0);
  if (socket_ == -1)
    throw Error(EXIT_NET, strerror(errno));
  // create socket
  socket_fd_ = socket(PF_INET, SOCK_STREAM, 0);
  if (socket_fd_ == -1)
    throw Error(ERR_NET, strerror(errno));

  daddr.sin_family = AF_INET;
  daddr.sin_port = htons(options_.port);
  daddr.sin_addr = *((struct in_addr *) h->h_addr);
  memset(daddr.sin_zero, '\0', sizeof daddr.sin_zero);

  if (::connect(socket_, (struct sockaddr *) &daddr, sizeof daddr) == -1)
    throw Error(EXIT_NET, strerror(errno));
  // connect
  if (::connect(socket_fd_, (struct sockaddr *) &daddr, sizeof daddr) == -1)
    throw Error(ERR_NET, strerror(errno));

  recv_offset_ = 0;
  recv_size_ = 0;
  // initialize socket stream
  if ((socket_fs_ = fdopen(socket_fd_, "r+")) == NULL)
    throw Error(ERR_NET, strerror(errno));
}

void SLDaemon::send(const string str) {
  if (str.length() == 0)
void SLDaemon::disconnect() {
  if (socket_fs_ == NULL)
    return;
  if (write(socket_, str.c_str(), str.length()) <= 0)
    throw Error(EXIT_NET, strerror(errno));
  if (fclose(socket_fs_))
    throw Error(ERR_NET, strerror(errno));
  socket_fs_ = NULL;
}

void SLDaemon::send(const string str, bool buf) {
  send(str.c_str(), str.length(), buf);
}

void SLDaemon::send(const char *data, size_t len) {
void SLDaemon::send(const char *data, size_t len, bool buf) {
  if (len == 0)
    return;
  if (write(socket_, data, len) <= 0)
    throw Error(EXIT_NET, strerror(errno));
  if (fwrite(data, 1, len, socket_fs_) != len)
    throw Error(ERR_NET, strerror(errno));
  if (!buf && fflush(socket_fs_))
    throw Error(ERR_NET, strerror(errno));
}

char *SLDaemon::recv() {
  char *stringbuffer = NULL;
  ssize_t ret;
char *SLDaemon::recv(size_t size) {
  char *data = new char[size];

  do {
    for (size_t i = recv_offset_; i < recv_size_; ++i) {
      if (recv_buf_[i] == '\n') {
	bufferize(&stringbuffer, (const char*) recv_buf_ + recv_offset_, i - recv_offset_);
	recv_offset_ = i + 1;
	return stringbuffer;
  if (fread(data, 1, size, socket_fs_) != size) {
    delete data;
    throw Error(ERR_NET, strerror(errno));
  }
  return data;
}
    if (recv_size_ > recv_offset_)
      bufferize(&stringbuffer, (const char*) recv_buf_ + recv_offset_, recv_size_ - recv_offset_);
    recv_offset_ = 0;
    ret = read(socket_, recv_buf_, RECV_BUF_SIZE);
    if (ret == 0)
      throw Error(EXIT_NET, "Connexion closed.");
    if (ret < 0)
      throw Error(EXIT_NET, (string) "SLDaemon::recv: " + strerror(errno));
    recv_size_ = ret;
  }
  while (recv_size_ > 0);
  return stringbuffer;

void SLDaemon::recv(size_t size, const string filename) {
  char *data = recv(size);
  FILE *fs = fopen(filename.c_str(), "w");
  if (fs == NULL)
    throw Error(ERR_FILE, strerror(errno));
  if (fwrite(data, 1, size, fs) != size)
    throw Error(ERR_FILE, strerror(errno));
  if (fclose(fs))
    throw Error(ERR_FILE, strerror(errno));
}

void	SLDaemon::bufferize(char **str, const char *append, size_t n)
{
  size_t	ln;
  size_t	i;
  size_t	j;
char *SLDaemon::recvln() {
  char *line = new char[MAX_LINE_SIZE];

  ln = (*str == NULL) ? 0 : strlen(*str);
  if ((*str = (char *) realloc(*str, (ln + n + 1) * sizeof (char))) == NULL)
    throw Error(EXIT_NOMEM, strerror(errno));
  for (i = ln, j = 0; i < ln + n; i++, j++)
    (*str)[i] = append[j];
  (*str)[ln + n] = 0;
  if (fgets(line, MAX_LINE_SIZE, socket_fs_) == NULL) {
    delete line;
    throw Error(ERR_FILE, strerror(errno));
  }
  return line;
}

void SLDaemon::protocol_violation() {
  std::cerr << "Protocol Violation." << std::endl;
  send("Protocol Violation.\n");  
void SLDaemon::flush() {
  if (fflush(socket_fs_))
    throw Error(ERR_NET, strerror(errno));
}

//******************************************************************************
// protocol functions
//******************************************************************************

void SLDaemon::auth() {
  unsigned char md[SHA_DIGEST_LENGTH];
  BIO *bmem, *b64;
@@ -247,71 +303,78 @@ void SLDaemon::auth() {
  BIO_flush(b64);
  BIO_get_mem_ptr(b64, &bptr);

  char *buff = (char *) malloc(bptr->length);
  char *buff = new char[bptr->length];
  memcpy(buff, bptr->data, bptr->length-1);
  buff[bptr->length-1] = 0;

  BIO_free_all(b64);

  send(options_.user);
  send(":");
  send("USER ");
  send(options_.login);
  send("\n");

  send("PASS ");
  send(buff);
  send("\n");

  free(buff);
  flush();

  delete buff;

  char *line = recvln();
  if (strcmp(line, "OK\n")) {
    delete line;
    throw Error(ERR_AUTH, "Authentification failed !");
  }
  delete line;
  return;
}

void SLDaemon::run() {
  char *line;

  check_options();
  connect();
  auth();
  while (1) {
    line = recv();
    // call right handler
    try {
      if (!strncmp(line, "EXIT", 4))
	cmd_exit();
      else if (!strncmp(line, "VERSION", 7))
	cmd_version();
      else if (!strncmp(line, "EXEC ", 5))
	cmd_exec(line);
      else if (!strncmp(line, "FILE ", 5))
	cmd_file(line);
      else if (!strncmp(line, "UPDATE", 6))
	cmd_update();
      else
	protocol_violation();
void SLDaemon::tee(const string msg) {
  if (verbose())
    std::cout << msg << std::endl;
  send(msg);
  send("\n");
}
    catch (const Error &e) {
      e.print();
      send("!! ");
      send(e.message());

void SLDaemon::proto_ok() {
  send("OK\n");
}

void SLDaemon::proto_ko() {
  send("KO\n");
}

void SLDaemon::proto_violation() {
  std::cerr << "Protocol Violation." << std::endl;
  send((string) "Protocol Violation.\n", false);  
}

void SLDaemon::cmd_version() {


//******************************************************************************
// command functions
//******************************************************************************

void SLDaemon::cmd_exit() {
  if (verbose())
    std::cout << ">> Version requested." << std::endl;
  send(VERSION);
    std::cout << "EXIT requested." << std::endl;
  send("Bye.\n");
  exit(ERR_OK);
}

void SLDaemon::cmd_exit() {
void SLDaemon::cmd_version() {
  if (verbose())
    std::cout << ">> Exit requested." << std::endl;
  send("Bye", 3);
  exit(0);
    std::cout << "VERSION requested." << std::endl;
  send(VERSION);
  send("\n");
}

void SLDaemon::cmd_exec(const char *line) {
  assert(line);
  char *p = strchr(line, ' ');
  if (p == NULL) {
    protocol_violation();
    proto_violation();
    return;
  }
  string path = options_.scriptdir + "/" +  string(p + 1);
@@ -322,7 +385,7 @@ void SLDaemon::cmd_exec(const char *line) {
  // fork
  pid_t pid = fork();
  if (pid == -1)
    throw Error(EXIT_NET, "Unable to fork");
    throw Error(ERR_NET, "Unable to fork");

  if (pid > 0) {
    int status;
@@ -333,27 +396,162 @@ void SLDaemon::cmd_exec(const char *line) {
    send((string) ">> EXEC return " + buf + "\n");
  }
  else if (pid == 0) {
    if (dup2(socket_, STDOUT_FILENO) == -1) {
    if (dup2(socket_fd_, STDOUT_FILENO) == -1) {
      perror(">> dup2");
      exit(EXIT_UNKNOWN);
      exit(ERR_UNKNOWN);
    }
    if (dup2(socket_, STDERR_FILENO) == -1) {
    if (dup2(socket_fd_, STDERR_FILENO) == -1) {
      perror(">> dup2");
      exit(EXIT_UNKNOWN);
      exit(ERR_UNKNOWN);
    }
    if (execl(path.c_str(), path.c_str(), NULL) == -1) {
      perror(">> execl");
      exit(EXIT_UNKNOWN);
      exit(ERR_UNKNOWN);
    }
  }
}

void SLDaemon::cmd_file(const char *line) {
  char *buf;
  int ret;

  assert(line);

  // get filename
  char filename[512]; //FIXME: bad magic size
  if (sscanf(line, "FILE %512s\n", filename) != 1) {
    proto_violation();
    return;
  }
  string target = options_.scriptdir + "/" + filename;

  //get size
  int size;  
  buf = recvln();
  ret = sscanf(buf, "SIZE %i\n", &size);
  delete buf;
  if (ret != 1) {
    tee("Invalid size parameter."); 
    return;
  }
  
  //get md5
  char *md5;  
  buf = recvln();
  ret = sscanf(buf, "MD5 %s\n", md5);
  delete buf;
  if (ret != 1) {
    tee("Invalid md5 parameter.");
    return;
  }

  // show verbose
  if (verbose())
    std::cout << "FILE transfer requested: "
	      << "to=" << target
	      << ", size=" << size
	      << ", md5=" << md5 << "."
	      << std::endl;

  //get data
  try {
    recv(size, target);
  }
  catch (const Error &err) {
    if (err.code() == ERR_FILE) {
      tee("Data transfer error.");
      return;
    }
    throw;
  }

  // check MD5
  std::cout << SLDaemon::md5(target) <<std::endl;;
  if (SLDaemon::md5(target) != string(md5)) {
    tee("Transfer of " + target + ": FAILED.");
    unlink(target.c_str());
    return;
  }

  // proceed chown
  if (chown(target.c_str(), getuid(), getgid())) {
    tee("chown of " + target + ": FAILED.");
    unlink(target.c_str());
    return;
  }

  // proceed chmod
  if (chmod(target.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) {
    tee("chmod of " + target + ": FAILED.");
    unlink(target.c_str());
    return;
  }

  tee("Transfer of " + target + ": OK."); 
}
 
void SLDaemon::cmd_update(const char *line) {
  assert(line);
  if (verbose())
    std::cout << "FILE transfer : " << std::endl;
    std::cout << "UPDATE requested." << std::endl;
}

void SLDaemon::cmd_list() {
  if (verbose())
    std::cout << "LIST requested." << std::endl;
  FILE *fls = popen(string("ls -1A " + options_.scriptdir).c_str(), "r");
  if (fls == NULL) {
    tee("Unable to list " + options_.scriptdir + ".");
    return;
  }

void SLDaemon::cmd_update() {
  std::cout << "UPDATE detected" << std::endl;
  char buf[255];
  size_t len;
  try {
    while ((len = fread(buf, 1, 255, fls)) > 0)
      send(buf, len);
    flush();
  }
  catch (...) {
    pclose(fls);
    throw;
  }
}

void SLDaemon::cmd_clean() {
  if (verbose())
    std::cout << "CLEAN requested." << std::endl;
}

void SLDaemon::cmd_reload() {
  if (verbose())
    std::cout << "RELOAD requested." << std::endl;
}

//******************************************************************************
// others functions
//******************************************************************************

string SLDaemon::md5(const string file) const {
  MD5_CTX ctx;
  FILE *fs;
  size_t len;
  char buf[512];
  char md[MD5_DIGEST_LENGTH];
  char digest[MD5_DIGEST_LENGTH * 2 + 1];

  if (!MD5_Init(&ctx))
    return "";
  if ((fs = fopen(file.c_str(), "r")) == NULL)
    return "";
  while ((len = fread(buf, 1, 512, fs)) > 0)
    if (!MD5_Update(&ctx, buf, len))
      break;
  if (!MD5_Final((unsigned char*)md, &ctx))
    return "";
  for(len = 0; len < MD5_DIGEST_LENGTH; ++len) {
    sprintf(digest + (len * 2), "%02x", (unsigned char) md[len]);
  }
  digest[MD5_DIGEST_LENGTH * 2] = 0;
  return string(digest);
}
+1 −1
Original line number Diff line number Diff line
@@ -45,5 +45,5 @@ int main(int argc, char *argv[])
    std::cerr <<"sld: error: " << e.message() << std::endl;
    return e.code();
  }
  return EXIT_UNKNOWN;
  return ERR_UNKNOWN;
}
+45 −29
Original line number Diff line number Diff line
@@ -17,14 +17,16 @@ typedef std::ostream ostream;
typedef std::ifstream ifstream;

enum {
  EXIT_OK = 0,
  EXIT_USAGE = 1,
  EXIT_BADPARAM = 2,
  EXIT_FILE = 3,
  EXIT_NET = 4,
  EXIT_PROTO = 5,
  EXIT_NOMEM = 41,
  EXIT_UNKNOWN = 42
  ERR_OK = 0,
  ERR_USAGE = 1,
  ERR_BADPARAM = 2,
  ERR_FILE = 3,
  ERR_NET = 4,
  ERR_PROTO = 5,
  ERR_AUTH = 6,
  ERR_NOMEM = 41,
  ERR_UNKNOWN = 42
  
};

// -----------------------------------------------------------------------------
@@ -32,7 +34,7 @@ enum {
// -----------------------------------------------------------------------------

const string VERSION = "1";
const int RECV_BUF_SIZE = 512;
const int MAX_LINE_SIZE = 512;

// -----------------------------------------------------------------------------
// SLDAEMON CLASS
@@ -44,17 +46,21 @@ public:

  static const string version;
  
  SLDaemon();

  struct options {
    options();
    string host;
    string server;
    int port;
    string user;
    string login;
    string pass;
    int verbose; //0=false, 1=true, 3=undef
    string scriptdir;
    string conffile;
  };

  inline bool verbose() const { return options_.verbose == 1; }

  options *getoptions(int argc, char *argv[]) const;
  options *getoptions(const string file) const;
  void applyoptions(const options *opt);
@@ -64,32 +70,42 @@ protected:
  options options_;

  // current socket
  int socket_;

  // receive buffer
  int recv_buf_[RECV_BUF_SIZE];
  char *recv_line_;
  size_t recv_offset_;
  size_t recv_size_;
  int socket_fd_;
  FILE* socket_fs_;

  // functions
  // Options functions
  void usage(const char *argv0) const;
  void check_options() const;

  // network functions
  void connect();
  void send(const char *data, size_t len);
  void send(const string str);
  char *recv();
  void bufferize(char **str, const char *append, size_t n);
  void protocol_violation();
  void disconnect();  
  void send(const char *data, size_t len, bool buf = true);
  void send(const string str, bool buf = true);
  char *recv(size_t size);
  void recv(size_t size, const string filename);
  char *recvln();
  void flush();
  
  // protocol functions
  void auth();
  void tee(const string msg);
  void proto_ok();
  void proto_ko();
  void proto_violation();
  
  inline bool verbose() const { return options_.verbose == 1; }

  void cmd_version();
  // commmand functions
  void cmd_exit();
  void cmd_update();
  void cmd_version();
  void cmd_clean();
  void cmd_list();
  void cmd_reload();
  void cmd_update(const char *line);
  void cmd_exec(const char *line);
  void cmd_file(const char *line);

  // others functions
  string md5(const string file) const;
};

#endif