//! @file
//! @author Claes Nasten <pekdon{@}pekdon{.}net
//! @date 2005-06-15
//! @brief Configuration parser source handler.

//
// Copyright (C) 2005 Claes Nasten <pekdon{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//

#include "CfgParserSource.hh"
#include "Util.hh"

#include <iostream>

extern "C" {
#include <unistd.h>
}

using std::cerr;
using std::endl;
using std::string;

unsigned int CfgParserSourceCommand::m_sigaction_counter = 0;

//! @brief
//! @return
bool
CfgParserSourceFile::open (void)
  throw (std::string&)
{
  if (m_op_file) {
    throw string ("TRYING TO OPEN ALLREADY OPEN SOURCE");
  }

  m_op_file = fopen (m_or_name.c_str (), "r");
  if (!m_op_file)  {
    throw string("FAILED TO OPEN " + m_or_name);
  }

  return true;
}

//! @brief
void
CfgParserSourceFile::close (void)
  throw (std::string&)
{
  if (!m_op_file) {
    throw string("TRYING TO CLOSE ALLREADY CLOSED SOURCE");
  }

  fclose (m_op_file);
  m_op_file = NULL;
}

//! @brief
//! @param
//! @return
bool
CfgParserSourceCommand::open (void)
  throw (std::string&)
{
  int fd[2];
  int status;

  status = pipe(fd);
  if (status == -1) {
    return false;
  }

  // Remove signal handler while parsing as otherwise reading from the
  // pipe will break sometimes.
  if (m_sigaction_counter++ == 0) {
    struct sigaction action;

    action.sa_handler = SIG_DFL;
    action.sa_mask = sigset_t();
    action.sa_flags = 0;

    sigaction(SIGCHLD, &action, &m_sigaction);
  }

  m_o_pid = fork ();
  if (m_o_pid == -1) { // Error
    return false;

  } else if (m_o_pid == 0) { // Child
    dup2 (fd[1], STDOUT_FILENO);

    ::close (fd[0]);
    ::close (fd[1]);

    execlp ("/bin/sh", "sh", "-c", m_or_name.c_str(), (char *) NULL);

    // PRINT ERROR

    ::close (STDOUT_FILENO);

    exit (1);

  } else { // Parent

    ::close (fd[1]);

    m_op_file = fdopen (fd[0], "r");
  }
  return true;
}

//! @brief
void
CfgParserSourceCommand::close (void)
  throw (std::string&)
{
  if (m_sigaction_counter < 1) {
    return;
  }
  m_sigaction_counter--;

  // Close source.
  fclose (m_op_file);

  // Wait for process.
  int status;
  int pid_status;

  status = waitpid(m_o_pid, &pid_status, 0);

  // If no other open CfgParserSourceCommand open, restore sigaction.
  if (m_sigaction_counter == 0) {
    sigaction(SIGCHLD, &m_sigaction, NULL);
  }

  // Wait failed, throw error
  if (status == -1) {
    throw string("FAILED TO WAIT FOR PID " + Util::to_string<int> (m_o_pid));
  }
}


syntax highlighted by Code2HTML, v. 0.9.1