mirror of
https://github.com/edeproject/ede.git
synced 2023-08-10 21:13:03 +03:00
149 lines
2.7 KiB
C++
149 lines
2.7 KiB
C++
|
//
|
||
|
// Copyright © 2005-2009 Claes Nästén <me@pekdon.net>
|
||
|
//
|
||
|
// 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 <iostream>
|
||
|
#include <cstdio>
|
||
|
#include <cstdlib>
|
||
|
|
||
|
extern "C" {
|
||
|
#include <stdio.h>
|
||
|
#include <unistd.h>
|
||
|
}
|
||
|
|
||
|
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<int>(_pid));
|
||
|
}
|
||
|
}
|