/* cdrdao - write audio CD-Rs in disc-at-once mode
*
* Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <unistd.h>
#include <stddef.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "ProcessMonitor.h"
#include "xcdrdao.h"
#include "util.h"
Process::Process(int pid, int commFd)
{
pid_ = pid;
commFd_ = commFd;
exited_ = 0;
exitStatus_ = 0;
next_ = NULL;
}
Process::~Process()
{
if (commFd_ >= 0)
close(commFd_);
next_ = NULL;
}
int Process::pid() const
{
return pid_;
}
int Process::commFd() const
{
return commFd_;
}
int Process::exited() const
{
return exited_;
}
int Process::exitStatus() const
{
return exitStatus_;
}
ProcessMonitor::ProcessMonitor()
{
processes_ = NULL;
statusChanged_ = 0;
}
ProcessMonitor::~ProcessMonitor()
{
Process *next;
blockProcessMonitorSignals();
while (processes_ != NULL) {
next = processes_->next_;
delete processes_;
processes_ = next;
}
unblockProcessMonitorSignals();
}
int ProcessMonitor::statusChanged()
{
int s = statusChanged_;
statusChanged_ = 0;
return s;
}
/* Starts a child process 'prg' with arguments 'args'.
* If 'pipeFdArgNum' is > 0 the file descriptor number will be written to
* 'args[pipeFdArgNum]'.
* Return: newly allocated 'Process' object or NULL on error
*/
Process *ProcessMonitor::start(const char *prg, char *args[], int pipeFdArgNum)
{
int pid;
Process *p;
int pipeFds[2];
char buf[20];
if (pipe(pipeFds) != 0) {
message(-2, "Cannot create pipe: %s", strerror(errno));
return NULL;
}
if (pipeFdArgNum > 0) {
sprintf(buf, "%d", pipeFds[1]);
args[pipeFdArgNum] = buf;
}
message(0, "Starting: ");
for (int i = 0; args[i] != NULL; i++)
message(0, "%s ", args[i]);
message(0, "");
blockProcessMonitorSignals();
pid = fork();
if (pid == 0) {
// we are the new process
// detach from controlling terminal
setsid();
// close reading end of pipe
close(pipeFds[0]);
execvp(prg, args);
message(-2, "Cannot execute '%s': %s", prg, strerror(errno));
_exit(255);
}
else if (pid < 0) {
message(-2, "Cannot fork: %s", strerror(errno));
unblockProcessMonitorSignals();
return NULL;
}
// close writing end of pipe
close(pipeFds[1]);
p = new Process(pid, pipeFds[0]);
p->next_ = processes_;
processes_ = p;
unblockProcessMonitorSignals();
return p;
}
Process *ProcessMonitor::find(Process *p, Process **pred)
{
Process *run;
for (*pred = NULL, run = processes_; run != NULL;
*pred = run, run = run->next_) {
if (p == run) {
return run;
}
}
return NULL;
}
Process *ProcessMonitor::find(int pid)
{
Process *run;
for (run = processes_; run != NULL; run = run->next_) {
if (run->pid() == pid) {
return run;
}
}
return NULL;
}
void ProcessMonitor::stop(Process *p)
{
kill(p->pid(), SIGTERM);
}
void ProcessMonitor::remove(Process *p)
{
Process *act, *pred;
blockProcessMonitorSignals();
if ((act = find(p, &pred)) != NULL) {
if (pred == NULL)
processes_ = act->next_;
else
pred->next_ = act->next_;
delete act;
}
unblockProcessMonitorSignals();
}
void ProcessMonitor::handleSigChld()
{
int pid;
Process *p;
int status;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
if ((p = find(pid)) != NULL) {
p->exited_ = 1;
if (WIFEXITED(status)) {
p->exitStatus_ = WEXITSTATUS(status);
}
else if (WIFSIGNALED(status)) {
p->exitStatus_ = 254;
}
else {
p->exitStatus_ = 253;
}
statusChanged_ = 1;
}
else {
message(-3, "Unknown child with pid %d exited.", pid);
}
}
/*
if (pid < 0)
message(-2, "waitpid failed: %s", strerror(errno));
*/
}
syntax highlighted by Code2HTML, v. 0.9.1