////////////////////////////////////////////////////////////////////////////
// CProcStart クラスのインプリメンテーション
//
////////////////////////////////////////////////////////////////////////////

#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <alloca.h>
#include <sys/wait.h>

#include "ProcStart.h"

////////////////////////////////////////////////////////////////////////////
// 構築/破棄
////////////////////////////////////////////////////////////////////////////

CProcStart::CProcStart() 
{

}

CProcStart::~CProcStart()
{

}

////////////////////////////////////////////////////////////////////////////
// メソッド
////////////////////////////////////////////////////////////////////////////

// 起動するコマンドを指定
void CProcStart::SpecifyCommand( const string& rCmd )
{
	cmd = rCmd;
	listArg.push_back( rCmd );
}

// 引数を追加
void CProcStart::AddArg( const string& rArg )
{
	listArg.push_back( rArg );
}

// プロセスを起動
// 起動したプロセスのpidを返す
// 失敗した場合は-1を返す
int CProcStart::Start() const
{
	int r;
	int status;
	int i;
	list< string >::const_iterator itr;
	char **vArg;

	// 引数を用意する
	vArg = (char**)calloc( sizeof( char * ), listArg.size() + 1 );

	itr = listArg.begin();
	for ( i = 0; i < listArg.size(); i++ ) {
		vArg[i] = (char*)malloc( sizeof( char ) * ( itr->length() + 1 ) );
		if ( !vArg[i] ) goto ERR_EXIT;
		strncpy( vArg[i], itr->c_str(), itr->length() + 1 );
		itr++;
	}

	r = fork();
	if ( r < 0 ) return -1;

	// 親プロセスはこれ以上する事はない。
	if ( r > 0 ) {
		for ( i = 0; i < listArg.size(); i++ )
			free( vArg[i] );
		free( vArg );
		waitpid( r, &status, 0 );
		if ( !WIFEXITED( status ) )
			return -1;

		// 子プロセスは、処理に成功した場合は孫プロセスのpidを返し、
		// 失敗した場合は0を返す
		if ( WEXITSTATUS( status ) == 0 )
			return -1;
		return WEXITSTATUS( status );
	}

	r = fork();
	if ( r < 0 ) {
		// エラー
		_exit( 0 );
	}

	// 子プロセスはここで終了する
	if ( r > 0 ) {
		// 終了ステータスとして、孫プロセスのpidを返す
		_exit( r );
	}

	// 孫プロセスはexecする。
	execv( cmd.c_str(), vArg );

	// 失敗した場合はどうしようもないので、標準エラー出力にメッセージだけ出しておく
	fprintf( stderr, "It Failed to exec. command = \"%s\".", cmd.c_str() );
	_exit( 1 );

ERR_EXIT:
	for ( i = 0; i < listArg.size(); i++ )
		free( vArg[i] );
	free( vArg );

	return -1;
}

