// // Copyright © 2005-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "CfgParserSource.hh" #include "Util.hh" #include #include #include extern "C" { #include #include } using std::cerr; using std::endl; using std::string; using std::fopen; using std::fclose; using std::exit; unsigned int CfgParserSourceCommand::_sigaction_counter = 0; /** * Open file based configuration source. */ bool CfgParserSourceFile::open(void) throw (std::string&) { if (_file) { throw string("TRYING TO OPEN ALLREADY OPEN SOURCE"); } _file = fopen(_name.c_str(), "r"); if (! _file) { throw string("failed to open file " + _name); } return true; } void CfgParserSourceFile::close(void) throw (std::string&) { if (! _file) { throw string("trying to close already closed source"); } fclose(_file); _file = 0; } /** * Run command and treat output as configuration source. */ 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 (_sigaction_counter++ == 0) { struct sigaction action; action.sa_handler = SIG_DFL; action.sa_mask = sigset_t(); action.sa_flags = 0; sigaction(SIGCHLD, &action, &_sigaction); } _pid = fork(); if (_pid == -1) { // Error return false; } else if (_pid == 0) { // Child dup2(fd[1], STDOUT_FILENO); ::close(fd[0]); ::close(fd[1]); execlp("/bin/sh", "sh", "-c", _name.c_str(), (char *) 0); // PRINT ERROR ::close (STDOUT_FILENO); exit (1); } else { // Parent ::close (fd[1]); _file = ::fdopen(fd[0], "r"); } return true; } /** * Close source, wait for child process to finish. */ void CfgParserSourceCommand::close(void) throw (std::string&) { if (_sigaction_counter < 1) { return; } _sigaction_counter--; // Close source. fclose(_file); // Wait for process. int status; int pid_status; status = waitpid(_pid, &pid_status, 0); // If no other open CfgParserSourceCommand open, restore sigaction. if (_sigaction_counter == 0) { sigaction(SIGCHLD, &_sigaction, 0); } // Wait failed, throw error if (status == -1) { throw string("failed to wait for pid " + Util::to_string(_pid)); } }