Skip to content
daemon.cc 17.4 KiB
Newer Older
Seblu's avatar
Seblu committed
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
Seblu's avatar
Seblu committed
#include <stdio.h>
Seblu's avatar
Seblu committed
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
Seblu's avatar
Seblu committed
#include <sys/stat.h>
Seblu's avatar
Seblu committed
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/sha.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>
Seblu's avatar
Seblu committed
#include <openssl/md5.h>
Seblu's avatar
Seblu committed

#include "sld.hh"

Seblu's avatar
Seblu committed
const string VERSION = "1";
const int MAX_LINE_SIZE = 512;
const char *RCV_DATA = "<< ";
const char *SND_DATA = ">> ";

SLDaemon *SLDaemon::instance_ = 0;

SLDaemon::SLDaemon() : socket_fs_(0) {}

SLDaemon &SLDaemon::Instance() {
  if (instance_ == 0)
    instance_ = new SLDaemon();
  return *instance_;
}
Seblu's avatar
Seblu committed

SLDaemon::Options::Options() {
Seblu's avatar
Seblu committed
  this->port = 0;
  this->verbose = 3;
}

void SLDaemon::usage(const char *argv0) const {
  std::cerr << "usage: " 
	    << argv0
Seblu's avatar
Seblu committed
	    << " [-f conffile] [-d scriptdir] [-h] [-v] [-l login]"
Seblu's avatar
Seblu committed
	    << "[-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
Seblu's avatar
Seblu committed
	    << "  -l name      : Set login to name." << std::endl
Seblu's avatar
Seblu committed
	    << "  -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
	    << "  -V           : Print version and exit." << std::endl;

}

SLDaemon::Options *SLDaemon::getoptions(int argc, char *argv[]) const {
  Options opt, *mopt;
Seblu's avatar
Seblu committed

  if (argc == 1) {
    usage(*argv);
Seblu's avatar
Seblu committed
    throw Error(ERR_USAGE);
Seblu's avatar
Seblu committed
  }

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

SLDaemon::Options *SLDaemon::getoptions(const string file) const {
Seblu's avatar
Seblu committed
  if (file == "")
Seblu's avatar
Seblu committed
    throw Error(ERR_BADPARAM, "Conf file not implemented");
  throw Error(ERR_BADPARAM, "Conf file not implemented");
  return 0;
Seblu's avatar
Seblu committed
}

void SLDaemon::applyoptions(const Options *opt) {
Seblu's avatar
Seblu committed
  assert(opt);
Seblu's avatar
Seblu committed
  if (opt->server != "") options_.server = opt->server;
Seblu's avatar
Seblu committed
  if (opt->port != 0) options_.port = opt->port;
Seblu's avatar
Seblu committed
  if (opt->login != "") options_.login = opt->login;
Seblu's avatar
Seblu committed
  if (opt->pass != "") options_.pass = opt->pass;
  if (opt->verbose != 3) options_.verbose = opt->verbose;
  if (opt->conffile != "") options_.conffile = opt->conffile;
  if (opt->scriptdir != "") options_.scriptdir = opt->scriptdir;
}

void SLDaemon::check_options() const {
  // print info in verbose mode
  if (verbose()) {
Seblu's avatar
Seblu committed
    std::cout << "Server host is : " << options_.server << "." << std::endl;
Seblu's avatar
Seblu committed
    std::cout << "Server port is : " << options_.port << "." << std::endl;
Seblu's avatar
Seblu committed
    std::cout << "Daemon login is : " << options_.login << "." << std::endl;
Seblu's avatar
Seblu committed
    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
Seblu's avatar
Seblu committed
  if (options_.server == "")
    throw Error(ERR_BADPARAM, "No server address specified.");
Seblu's avatar
Seblu committed
  if (options_.port == 0)
Seblu's avatar
Seblu committed
    throw Error(ERR_BADPARAM, "No server port specified.");
Seblu's avatar
Seblu committed
  if (options_.port < 1 || options_.port > 65535)
Seblu's avatar
Seblu committed
    throw Error(ERR_BADPARAM, "Bad server port number (1 - 65535).");
  if (options_.login == "")
    throw Error(ERR_BADPARAM, "No login specified.");
Seblu's avatar
Seblu committed
  if (options_.pass == "")
Seblu's avatar
Seblu committed
    throw Error(ERR_BADPARAM, "No pass specified.");
Seblu's avatar
Seblu committed
  if (options_.scriptdir == "")
Seblu's avatar
Seblu committed
    throw Error(ERR_BADPARAM, "No scripts directory specified.");
Seblu's avatar
Seblu committed

  // Empty scripts dir
  // TODO
}
Seblu's avatar
Seblu committed
void SLDaemon::run() {
  char *line;

  check_options();
  connect();
  auth();
  while (1) {
    line = recvln();
Seblu's avatar
Seblu committed
    tee(line, RCV_DATA);
Seblu's avatar
Seblu committed
    // 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, "STATUS\n"))
	cmd_status();
Seblu's avatar
Seblu committed
      else if (!strcmp(line, "LIST\n"))
	cmd_list();
      else if (!strcmp(line, "KILLALL\n"))
	cmd_killall();
      else if (!strcmp(line, "KILL\n"))
	cmd_kill(line);
      else if (!strncmp(line, "JOB ", 5))
	cmd_job(line);
Seblu's avatar
Seblu committed
      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
//******************************************************************************
Seblu's avatar
Seblu committed

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

Seblu's avatar
Seblu committed
  // close existing connexion
  if (socket_fs_ == 0)
Seblu's avatar
Seblu committed
    disconnect();

  // retrieve remote host info
  h = gethostbyname(options_.server.c_str());
  if (h == 0)
Seblu's avatar
Seblu committed
    throw Error(ERR_NET, hstrerror(h_errno));
Seblu's avatar
Seblu committed

Seblu's avatar
Seblu committed
  // create socket
  socket_fd_ = socket(PF_INET, SOCK_STREAM, 0);
  if (socket_fd_ == -1)
    throw Error(ERR_NET, strerror(errno));
Seblu's avatar
Seblu committed

  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);

Seblu's avatar
Seblu committed
  // connect
  if (::connect(socket_fd_, (struct sockaddr *) &daddr, sizeof daddr) == -1)
    throw Error(ERR_NET, strerror(errno));
Seblu's avatar
Seblu committed

Seblu's avatar
Seblu committed
  // initialize socket stream
  if ((socket_fs_ = fdopen(socket_fd_, "r+")) == 0)
Seblu's avatar
Seblu committed
    throw Error(ERR_NET, strerror(errno));
Seblu's avatar
Seblu committed
}

Seblu's avatar
Seblu committed
void SLDaemon::disconnect() {
  if (socket_fs_ == 0)
Seblu's avatar
Seblu committed
    return;
Seblu's avatar
Seblu committed
  if (fclose(socket_fs_))
    throw Error(ERR_NET, strerror(errno));
  socket_fs_ = 0;
}

void SLDaemon::send(long int i) {
  fprintf(socket_fs_, "%li", i);
Seblu's avatar
Seblu committed
}

Seblu's avatar
Seblu committed
void SLDaemon::send(const string str, bool buf) {
  send(str.c_str(), str.length(), buf);
}

void SLDaemon::send(const char *data, size_t len, bool buf) {
Seblu's avatar
Seblu committed
  if (len == 0)
    return;
Seblu's avatar
Seblu committed
  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));
Seblu's avatar
Seblu committed
}

Seblu's avatar
Seblu committed
char *SLDaemon::recv(size_t size) {
  char *data = new char[size];

  if (fread(data, 1, size, socket_fs_) != size) {
    delete data;
    throw Error(ERR_NET, strerror(errno));
Seblu's avatar
Seblu committed
  }
Seblu's avatar
Seblu committed
  return data;
Seblu's avatar
Seblu committed
}

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

Seblu's avatar
Seblu committed
char *SLDaemon::recvln() {
  char *line = new char[MAX_LINE_SIZE];

  if (fgets(line, MAX_LINE_SIZE, socket_fs_) == 0) {
Seblu's avatar
Seblu committed
    delete line;
    throw Error(ERR_FILE, (string) "recvln: " + strerror(errno));
Seblu's avatar
Seblu committed
  }
  return line;
}

void SLDaemon::flush() {
  if (fflush(socket_fs_))
    throw Error(ERR_NET, strerror(errno));
Seblu's avatar
Seblu committed
}

Seblu's avatar
Seblu committed
//******************************************************************************
// protocol functions
//******************************************************************************

Seblu's avatar
Seblu committed
void SLDaemon::auth() {
  unsigned char md[SHA_DIGEST_LENGTH];
  BIO *bmem, *b64;
  BUF_MEM *bptr;

  SHA1((const unsigned char *) options_.pass.c_str(), options_.pass.length(), md);

  b64 = BIO_new(BIO_f_base64());
  bmem = BIO_new(BIO_s_mem());
  b64 = BIO_push(b64, bmem);
  BIO_write(b64, md, SHA_DIGEST_LENGTH);
  BIO_flush(b64);
  BIO_get_mem_ptr(b64, &bptr);

Seblu's avatar
Seblu committed
  char *buff = new char[bptr->length];
Seblu's avatar
Seblu committed
  memcpy(buff, bptr->data, bptr->length-1);
  buff[bptr->length-1] = 0;

  BIO_free_all(b64);

  send("HOST ");
Seblu's avatar
Seblu committed
  send(options_.login);
  send("\n");

  send("PASS ");
Seblu's avatar
Seblu committed
  send(buff);
  send("\n");

Seblu's avatar
Seblu committed
  flush();
Seblu's avatar
Seblu committed

Seblu's avatar
Seblu committed
  delete buff;

Seblu's avatar
Seblu committed
  return;
}

Seblu's avatar
Seblu committed
void SLDaemon::tee(const string &msg, const string &local_prefix) {
  if (verbose())
    std::cout << local_prefix << msg;
Seblu's avatar
Seblu committed
  send(msg);
Seblu's avatar
Seblu committed
}

void SLDaemon::tee(long int i) {
  if (verbose()) std::cout << i;
  send(i);
Seblu's avatar
Seblu committed
}

Seblu's avatar
Seblu committed
void SLDaemon::proto_violation() {
  tee("sld: Protocol violation.\n");
Seblu's avatar
Seblu committed
}



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

Seblu's avatar
Seblu committed
void SLDaemon::cmd_exit() {
  if (verbose())
Seblu's avatar
Seblu committed
    std::cout << "EXIT requested." << std::endl;
  send("Bye.\n");
  exit(ERR_OK);
}

void SLDaemon::cmd_version() {
  if (verbose())
    std::cout << "VERSION requested." << std::endl;
  send(VERSION);
  send("\n");
Seblu's avatar
Seblu committed
}

void SLDaemon::cmd_job(const char *line) {
Seblu's avatar
Seblu committed
  assert(line);

  // build path
  //FIXME: Bad static magic number
  char filename[512];
  sscanf(line, "JOB %s\n", filename);
  string path = options_.scriptdir + "/" +  filename;

Seblu's avatar
Seblu committed
  // Check if file exist
  struct stat st;
  int ret = lstat(path.c_str(), &st);
  if (ret == ENOENT || errno == EACCES) {
Seblu's avatar
Seblu committed
    tee(strerror(errno), SND_DATA);
    return;
  }
  // check for exec flag
  if (st.st_mode | S_IXUSR != S_IXUSR) {
    tee("JOB: no exec flag.\n", SND_DATA);
    return;
  }
  // check file owner
  if (st.st_uid != getuid()) {
    tee("JOB: Bad file owner.\n", SND_DATA);
Seblu's avatar
Seblu committed
    return;
  }

  // Create new process
  flush();
Seblu's avatar
Seblu committed
  pid_t pid = fork();
  if (pid == -1)
Seblu's avatar
Seblu committed
    throw Error(ERR_NET, "Unable to fork");
Seblu's avatar
Seblu committed

  // Father job
Seblu's avatar
Seblu committed
  if (pid > 0) {
    // reg job
    SLDaemon::Job j(pid, filename, time(0));
    jobs_.insert(j);
    
    // show job info
Seblu's avatar
Seblu committed
    tee((string) "JOB: " + filename + ", pid: ", SND_DATA);
    tee(pid);
    tee(", start at: ");
    tee(j.start_time);
    tee("\n");
Seblu's avatar
Seblu committed
  }
  // Son job
Seblu's avatar
Seblu committed
  else if (pid == 0) {
Seblu's avatar
Seblu committed
    if (dup2(socket_fd_, STDOUT_FILENO) == -1) {
Seblu's avatar
Seblu committed
      perror(">> dup2");
Seblu's avatar
Seblu committed
      exit(ERR_UNKNOWN);
Seblu's avatar
Seblu committed
    }
Seblu's avatar
Seblu committed
    if (dup2(socket_fd_, STDERR_FILENO) == -1) {
Seblu's avatar
Seblu committed
      perror(">> dup2");
Seblu's avatar
Seblu committed
      exit(ERR_UNKNOWN);
Seblu's avatar
Seblu committed
    }
    execl(path.c_str(), basename(path.c_str()), 0);
    printf("\"%s\"\n", path.c_str());
    perror("sld: execl");
    exit(ERR_UNKNOWN);
Seblu's avatar
Seblu committed
  }
}

void SLDaemon::cmd_file(const char *line) {
Seblu's avatar
Seblu committed
  char *buf;
  int ret;

Seblu's avatar
Seblu committed
  assert(line);
Seblu's avatar
Seblu committed

  // 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
Seblu's avatar
Seblu committed
  char md5[512]; //FIXME: bad magic size
Seblu's avatar
Seblu committed
  buf = recvln();
Seblu's avatar
Seblu committed
  ret = sscanf(buf, "MD5 %512s\n", md5);
Seblu's avatar
Seblu committed
  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
  if (SLDaemon::md5(target) != string(md5)) {
Seblu's avatar
Seblu committed
    tee("Transfer of " + target + ": Invalid MD5.");
Seblu's avatar
Seblu committed
    unlink(target.c_str());
    return;
Seblu's avatar
Seblu committed
 }
Seblu's avatar
Seblu committed

  // proceed chown
  if (chown(target.c_str(), getuid(), getgid())) {
Seblu's avatar
Seblu committed
    tee("chown of " + target + ": Unable to chown.");
Seblu's avatar
Seblu committed
    unlink(target.c_str());
    return;
  }

  // proceed chmod
  if (chmod(target.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) {
Seblu's avatar
Seblu committed
    tee("chmod of " + target + ": Unable to chmod.");
Seblu's avatar
Seblu committed
    unlink(target.c_str());
    return;
  }

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

Seblu's avatar
Seblu committed
void SLDaemon::cmd_list() {
  FILE *fls = popen(string("ls -1A " + options_.scriptdir).c_str(), "r");
  if (fls == 0) {
Seblu's avatar
Seblu committed
    tee("LIST: Unable to list " + options_.scriptdir + ".\n", SND_DATA);
Seblu's avatar
Seblu committed
    return;
  }

  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_status() {
  t_job::iterator i;
  time_t t = time(0);
Seblu's avatar
Seblu committed

  tee("STATUS of \n", SND_DATA);
  for (i = jobs_.begin(); i != jobs_.end(); ++i) {
Seblu's avatar
Seblu committed
    tee("job: ", SND_DATA);
    tee(i->name);
    tee(", pid: ");
    tee(i->pid);
    tee(", start at: ");
    tee(i->start_time);
    tee(", since: ");
    tee(t - i->start_time);
    tee(" seconds.\n");
Seblu's avatar
Seblu committed
  flush();
}

void SLDaemon::cmd_kill(const char *line) {
  t_job::iterator i;

  // retrieve pid
  int pid;
  if (sscanf(line, "KILL %i\n", &pid) != 1) {
    proto_violation();
    return;
  }

  for (i = jobs_.begin(); i != jobs_.end(); ++i)
    if (pid == i->pid) {
      int ret = kill(i->pid, SIGKILL);
      send("kill -SIGKILL ");
      send(i->pid);
      send(" (");
      send(i->name);
      send(") => ");
      if (ret == -1)
	send(strerror(errno));
      else
	send("0");
      send("\n");
    }
  flush();
}

void SLDaemon::cmd_killall() {
  t_job::iterator i;

  for (i = jobs_.begin(); i != jobs_.end(); ++i) {
    int ret = kill(i->pid, SIGKILL);
    send("kill -SIGKILL ");
    send(i->pid);
    send(" (");
    send(i->name);
    send(") => ");
    if (ret == -1)
      send(strerror(errno));
    else
      send("0");
    send("\n");
  }
  flush();
Seblu's avatar
Seblu committed
}

void SLDaemon::cmd_reload() {
Seblu's avatar
Seblu committed
  const char *path = binpath();

  if (path == NULL) {
    tee("RELOAD: Unable to locate sld binary.\n", SND_DATA);
    return;
  }
  
  // Get bin info
  struct stat st;
  if (lstat(path, &st)) {
    tee((string)"RELOAD: lstat: " + strerror(errno) + "\n", SND_DATA);
    return;
  }
  
  // FIXME: check re run right (exec + file owner)
  
  int pid = fork();
  if (pid == -1) {
    tee((string)"RELOAD: " + strerror(errno) + "\n", SND_DATA);
    return;
  }
  // father process
  if (pid) {
    disconnect();
    exit(0);
  }
  // son process
  else {
    execl(path, basename(path));
    tee((string) "RELOAD: " + strerror(errno) + "\n", SND_DATA);
    flush();
    exit(ERR_UNKNOWN);
  }
Seblu's avatar
Seblu committed
}

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

Seblu's avatar
Seblu committed
string SLDaemon::md5(const string &file) const {
Seblu's avatar
Seblu committed
  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")) == 0)
Seblu's avatar
Seblu committed
    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);
Seblu's avatar
Seblu committed
}
Seblu's avatar
Seblu committed
//******************************************************************************
// Class Job functions
//******************************************************************************

SLDaemon::Job::Job(int p, string s, time_t t) : pid(p), name(s), start_time(t) {}

bool SLDaemon::Job::operator()(const SLDaemon::Job &a, const SLDaemon::Job &b) {
  return a.pid < b.pid;
}

//******************************************************************************
// Friends Class functions
//******************************************************************************

void sigchild(int) {
  int status;
  SLDaemon &d = SLDaemon::Instance();
  typedef SLDaemon::t_job t_job;
  t_job::iterator i;
  t_job &jobs_ = d.jobs_;
  pid_t pid;
  
  // Retrieve a pid
  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
    time_t t = time(0);
    for (i = jobs_.begin(); i != jobs_.end(); ++i) {
      if (i->pid == pid) {
	char buf[MAX_LINE_SIZE];
    
	snprintf(buf, MAX_LINE_SIZE,
		 "JOB: %s, pid: %d, end at: %ld, since: %ld, return: %d\n",
		 i->name.c_str(), i->pid,  t, t - i->start_time,
		 WEXITSTATUS(status));
	write(d.socket_fd_, buf, strlen(buf));
	jobs_.erase(i);
	break;
      }
    }
  }
}