/*
 * See the files COPYING and README for copyright information and how to reach 
 * the author.
 *
 *  $Id: pipe.c,v 1.2 2006/01/20 19:41:12 lordjaxom Exp $
 */

#include "pipe.h"
#include "environment.h"
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>

// --- cBurnPipe --------------------------------------------------------------

cBurnPipe::cBurnPipe(void):
		mEnvironment(),
		mWorkDir(NULL),
		mPid(-1),
		mPipe(-1),
		mRunning(false)
{
}

cBurnPipe::~cBurnPipe() 
{
	if (mRunning)
		Exit(false);
}

bool cBurnPipe::Launch(FILE *LogFile) 
{
	int piped[2];

	if (pipe(piped) == -1) {
		esyslog("ERROR[burn]: couldn't start subprocesses: %m");
		return false;
	}

	if ((mPid = fork()) == -1) {
		esyslog("ERROR[burn]: couldn't start subprocesses: %m");
		close(piped[0]); close(piped[1]);
		return false;
	}

	if (mPid == 0) {
		// child process
		if (mWorkDir != NULL)
			chdir(mWorkDir);
		close(STDOUT_FILENO); dup(piped[1]);
		close(STDERR_FILENO); dup(piped[1]);
		close(STDIN_FILENO); close(piped[0]);

		// set environment
		mEnvironment.Set();

		// code stolen from VDRs thread.c
		// TODO: use vdr's cPipe
        int MaxPossibleFileDescriptors = getdtablesize();
        for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
            close(i); //close all dup'ed filedescriptors

		// create a process group so we can kill all subprocesses later on
		setpgrp();

		_exit(Action());
	}

	close(piped[1]);
	mPipe = piped[0];

// XXX
#if 0
	if (LogFile) {
		if (mProc == DefaultProc) {
			fprintf(LogFile, "++ starting /bin/sh -c '%s'\n", (char*)mData);
			dsyslog("burn: starting /bin/sh -c '%s'", (char*)mData);
		} else {
			fprintf(LogFile, "++ starting internal procedure\n");
			dsyslog("burn: starting internal procedure");
		}
		fflush(LogFile);
	}
#endif

	return mRunning = true;
}

bool cBurnPipe::Exit(bool Wait) 
{
	int res, status;
	mRunning = false;
	close(mPipe);
	if ((res = waitpid(mPid, &status, Wait ? 0 : WNOHANG)) == 0) {
		kill(-mPid, SIGTERM);
		cCondWait::SleepMs(50);
		res = waitpid(mPid, &status, WNOHANG);

		if (res == 0) {
			isyslog("burn: process %d not ending, killing it...", mPid);
			kill(-mPid, SIGKILL);
			waitpid(mPid, &status, 0); // reap
			//mStatus = rsError;
			return false;
		}
	} 
	
	if (res == -1) {
		esyslog("ERROR[burn]: subprocess lost: %m (this shouldn't happen!)");
		//mStatus = rsError;
		return false;
	}

	if (WIFSIGNALED(status)) {
		esyslog("ERROR[burn]: process %d crashed (signal %d)", mPid,
				WTERMSIG(status));
		return false;
	}

	dsyslog("burn: process %d exited gracefully (exit code %d)", mPid,
			WEXITSTATUS(status));
	return WEXITSTATUS(status) == 0;
}
