// $Header: /cvs/gled-1.2/GledCore/Gled/Gled.cxx,v 1.14 2005/06/08 11:21:35 matevz Exp $

// Copyright (C) 1999-2005, Matevz Tadel. All rights reserved.
// This file is part of GLED, released under GNU General Public License version 2.
// For the licensing terms see $GLEDSYS/LICENSE or http://www.gnu.org/.

#include "Gled.h"
#include <Gled/GledNS.h>
#include <Gled/GMutex.h>
#include <Gled/GCondition.h>
#include <Gled/GThread.h>
#include <Gled/GKeyRSA.h>
#include <Ephra/Saturn.h>
#include <Glasses/ZQueen.h>
#include <Glasses/SaturnInfo.h>
#include <Glasses/ShellInfo.h>

#include <TSystem.h>
#include <TROOT.h>
#include <TRint.h>
#include <TSocket.h>
#include <TObjectTable.h>
#include <TSystemDirectory.h>

extern void *GledCore_GLED_init;

ClassImp(Gled)

/**************************************************************************/

Gled* Gled::theOne = 0;
Gled* gGled        = 0;

/**************************************************************************/

 void Gled::next_arg_or_die(list<char*>& args, list<char*>::iterator& i)
{
  list<char*>::iterator j = i;
  if(++j == args.end()) {
    cerr <<"Option "<< *i <<" requires an argument\n";
    exit(1);
  }
  i = j;
}

/**************************************************************************/

 Gled::Gled() : mSaturn(0), bIsSun(false),
	       bQuit(false),
	       bShowSplash(true),
	       bPreExec(false),
	       bAutoSpawn(false),
	       bAllowMoons(false),
	       bRunRint(true),
	       bRintRunning(false),
	       mLoggingMutex(GMutex::recursive)
{
  if(theOne) {
    cerr <<"Gled::Gled trying to instantiate another object ...\n";
    exit(1);
  }
  gGled = theOne = this;
  GThread::init_tsd();

  // Set-up SaturnInfo, set defaults

  mSaturnInfo = new SaturnInfo;
  mSaturnInfo->SetHostName(gSystem->HostName());

  FILE* p = gSystem->OpenPipe("GledNodeReport.pl cpuinfo meminfo", "r");
  if(p != 0) {
    char buf[80]; UShort_t frq, num, mem, swp;
    fgets(buf, 80, p); char* nl = rindex(buf, 10); if(nl) *nl = 0;
    fscanf(p, "%hu %hu %hu %hu", &frq, &num, &mem, &swp);
    mSaturnInfo->SetCPU_Model(buf);
    mSaturnInfo->SetCPU_Freq(frq);
    mSaturnInfo->SetCPU_Num(num);
    mSaturnInfo->SetMemory(mem);
    mSaturnInfo->SetSwap(swp);
    gSystem->ClosePipe(p);
  }

  mLogFileName = "<stdout>"; mLogFile = 0;
  mOutFileName = "<stdout>"; mOutFile = 0;

  mAuthDir = GForm("%s/.gled/auth", gSystem->Getenv("HOME"));
  mDefEyeIdentity = "guest";
}

 void Gled::ParseArguments(list<char*>& args)
{
  // Parse command-line arguments.

  list<char*>::iterator i = args.begin();
  while(i != args.end()) {
    list<char*>::iterator start = i;

    if(strcmp(*i, "-h")==0 || strcmp(*i, "-help")==0 ||
       strcmp(*i, "--help")==0 || strcmp(*i, "-?")==0)
      {
	printf(
	  "Arguments: [options] [dir] [file(s)]n"
	  "                     dir   ~ cd to dir prior to exec of filesn"
	  "                     files ~ ROOT macro scripts to processn"
	  "Gled options:n"
	  "-------------n"
	  "  -preexec <m1:m2..> pre-exec specified macrosn"
	  "  -r[un]             spawn Saturn/Sun immediately (before processing files)n"
	  "                     Saturn if -master is specified, Sun otherwisen"
	  "  -allowmoons        accept moon connectionsn"
	  "  -s[ssize]  <num>   specify size of sun-space (can be eg. 2e20)n"
	  "  -p[ort]    <num>   specify server port (def: 9061)n"
	  "  -portscan  <num>   if server port can not be opened, try <num> higher portsn"
	  "  -m[aster] <host>[:<port>] master Saturn address (def port: 9061)n"
	  "  -n[ame]    <str>   name of Saturnn"
	  "  -t[itle]   <str>   title of Saturnn"
	  "  -l                 no splash infon"
	  "  -norint            do not run TRint (useful for batch saturns)n"
	  "n"
	  "Logging options:n"
	  "  -log[file] <file>  specify log file name (saturn:'<stdout>', gled:'<null>')n" 
	  "  -out[file] <file>  specify output file name (def: '<stdout>')n"
	  "                     <file> shorthands: '-' => '<null>', '+' => '<stdout>'n"
	  "n"
	  "Authentication options:n"
	  "  -auth              use authenticationn"
	  "  -authdir   <str>   directory containing auth data (def: ~/.gled/auth)n"
	  "  -saturnid  <str>   identity of the Saturn (def: 'sun.absolute' or 'saturn')n"
	  "  -eyeid     <str>   default identity of Eyes (def: 'guest')n"
	  );
	bQuit = true;
	return;
      }

    else if(strcmp(*i, "-preexec")==0) {
      next_arg_or_die(args, i);
      bPreExec = true;
      mPreExecString   = *i;
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-r")==0 || strcmp(*i, "-run")==0) {
      bAutoSpawn = true;
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-allowmoons")==0) {
      bAllowMoons = true;
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-s")==0 || strcmp(*i, "-sssize")==0) {
      next_arg_or_die(args, i);
      if(index(*i, 'e')) {
	int m, e, num = sscanf(*i, "%de%d", &m, &e);
	if(num != 2) { cerr <<"-sssize poor exp format: "<< *i <<endl; exit(1); }
	mSaturnInfo->SetSunSpaceSize( ID_t(pow(double(m),e)) );
      } else {
	mSaturnInfo->SetSunSpaceSize( ID_t(atoll(*i)) );
      }
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-p")==0 || strcmp(*i, "-port")==0) {
      next_arg_or_die(args, i);
      mSaturnInfo->SetServerPort( atoi(*i) );
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-portscan")==0) {
      next_arg_or_die(args, i);
      mSaturnInfo->SetServPortScan( atoi(*i) );
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-m")==0 || strcmp(*i, "-master")==0) {
      next_arg_or_die(args, i);
      char* col = index(*i, ':');
      if(col) {
	*(col++) = 0;
	UShort_t p = UShort_t(atoi(col));
	mSaturnInfo->SetMasterPort(p);
      }
      mSaturnInfo->SetMasterName(*i);
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-n")==0 || strcmp(*i, "-name")==0) {
      next_arg_or_die(args, i);
      mSaturnInfo->SetName(*i);
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-t")==0 || strcmp(*i, "-title")==0) {
      next_arg_or_die(args, i);
      mSaturnInfo->SetTitle(*i);
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-l")==0) {
      bShowSplash = false;
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-norint")==0) {
      bRunRint = false;
      args.erase(start, ++i);
    }

    // Logging options

    else if(strcmp(*i, "-log")==0 || strcmp(*i, "-logfile")==0) {
      next_arg_or_die(args, i);
      if(strcmp(*i, "-")==0 || strcmp(*i, "<null>")==0) {
	mLogFileName = "<null>";
      } else if(strcmp(*i, "+")==0 || strcmp(*i, "<stdout>")==0) {
	mLogFileName = "<stdout>";
      } else {
	mLogFileName = *i;
      }
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-out")==0 || strcmp(*i, "-outfile")==0) {
      next_arg_or_die(args, i);
      if(strcmp(*i, "-")==0 || strcmp(*i, "<null>")==0) {
	mOutFileName = "<null>";
      } else if(strcmp(*i, "+")==0 || strcmp(*i, "<stdout>")==0) {
	mOutFileName = "<stdout>";
      } else {
	mOutFileName = *i;
      }
      args.erase(start, ++i);
    }

    // Authentication options

    else if(strcmp(*i, "-auth")==0) {
      mSaturnInfo->SetUseAuth(true);
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-authdir")==0) {
      next_arg_or_die(args, i);
      mAuthDir = *i;
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-saturnid")==0) {
      next_arg_or_die(args, i);
      mSaturnInfo->SetLogin(*i);;
      args.erase(start, ++i);
    }

    else if(strcmp(*i, "-eyeid")==0) {
      next_arg_or_die(args, i);
      mDefEyeIdentity = *i;
      args.erase(start, ++i);
    }

    else {
      ++i;
    }

  }

}

 void Gled::InitLogging()
{
  if(mLogFileName.CompareTo("<null>") == 0)
    mLogFile = 0;
  else if(mLogFileName.CompareTo("<stdout>") == 0)
    mLogFile = stdout;
  else {
    mLogFile = fopen(mLogFileName.Data(), "w");
    if(mLogFile == 0) {
      perror("Gled::InitLogging opening of log file failed");
      exit(1);
    }
  }

  if(mOutFileName.CompareTo("<null>") == 0)
    mOutFile = 0;
  else if (mOutFileName.CompareTo("<stdout>") == 0)
    mOutFile = stdout;
  else if(mOutFileName.CompareTo(mLogFileName) == 0)
    mOutFile = mLogFile;
  else {
    mOutFile = fopen(mOutFileName.Data(), "w");
    if(mLogFile == 0) {
      perror("Gled::InitLogging opening of output file failed");
      exit(1);
    }
  }
}

 void Gled::InitGledCore()
{
  if(bShowSplash) {
    int len = strlen(GLED_VERSION_STRING) + strlen(GLED_BUILD_DATE_STRING) + 4;
    GMutexHolder mh(mLoggingMutex);
    message("+----------------------------------------------------------+");
    message(GForm("| This is Gled, version %s, %s %*s |",
		  GLED_VERSION_STRING, GLED_BUILD_DATE_STRING, 35 - len, "" ));
    message("| Gled is free software, released under GNU GPL version 2. |");
    message("| For further information visit http://www.gled.org/       |");
    message("+----------------------------------------------------------+");
    message("Gled now bootstraping.");
  }

  ((void(*)())GledCore_GLED_init)();
}

 void Gled::StopLogging()
{
  message("Logging stopped.");

  GMutexHolder mh(mLoggingMutex);

  if (mOutFile && mOutFile != stdin) {
    fclose(mOutFile);
  }
  if (mLogFile && mLogFile != stdin && mLogFile != mOutFile) {
    fclose(mLogFile);
  }
  mOutFile = mLogFile = 0;
}

 Gled::~Gled() {
  delete mSaturn;
}

/**************************************************************************/

 void Gled::PreExec()
{
  lStr_t l;
  GledNS::split_string(string(mPreExecString.Data()), l, ':');
  for(lStr_i i=l.begin(); i!=l.end(); ++i)
    gROOT->Macro(i->c_str());
}

/**************************************************************************/

 void Gled::SpawnSunOrSaturn() {
  if(strcmp(mSaturnInfo->GetMasterName(), "") == 0) {
    SpawnSun();
  } else {
    SpawnSaturn();
  }
}

 void Gled::SpawnSun()
{
  static string _eh("Gled::SpawnSun ");

  if(mSaturn) return;
  mSaturnInfo->SetMasterPort(0);

  if(strcmp(mSaturnInfo->GetName(), "SaturnInfo") == 0)
    mSaturnInfo->SetName(GForm("Sun at %s", gSystem->HostName()));
  if(strcmp(mSaturnInfo->GetLogin(), "") == 0)
    mSaturnInfo->SetLogin("sun.absolute");

  CheckAuthDir();

  if(mSaturnInfo->GetUseAuth()) {
    GKeyRSA::init_ssl();
    if(GetPrivKeyFile(mSaturnInfo->mLogin) == 0) {
      cerr << _eh << "can not open server private keyn";
      exit(1);
    }
  }

  mSaturn = new Saturn;
  mSaturn->Create(mSaturnInfo);
  bIsSun = true;
}

 void Gled::SpawnSaturn()
{
  static string _eh("Gled::SpawnSaturn ");

  if(mSaturn) return;
  if(strcmp(mSaturnInfo->GetName(), "SaturnInfo") == 0)
    mSaturnInfo->SetName(GForm("Saturn at %s", gSystem->HostName()));
  if(strcmp(mSaturnInfo->GetLogin(), "") == 0)
    mSaturnInfo->SetLogin("saturn");

  CheckAuthDir();

  // Initialize authentication
  GKeyRSA::init_ssl();
  // Warn for missing RSA-key files
  if(GetPrivKeyFile(mSaturnInfo->mLogin, false) == 0)
    ISwarn(_eh + "private key for Saturn identity not found");
  if(GetPrivKeyFile(mDefEyeIdentity, false) == 0)
    ISwarn(_eh + "private key for default Eye identity not found");

  mSaturn = new Saturn;
  try {
    SaturnInfo* si = mSaturn->Connect(mSaturnInfo);
    if(si) {
      delete mSaturnInfo;
      mSaturnInfo = si;
    } else {
      cerr << _eh <<"failed ... dyingn";
      exit(1);
    }
    WaitUntillQueensLoaded();
  }
  catch(string exc) {
    cerr << _eh <<" failed ... dying at:n  "<< exc <<endl;
    exit(1);
  }
}

/**************************************************************************/

 void Gled::CheckAuthDir() {
  if(gSystem->AccessPathName(mAuthDir.Data(), kReadPermission)) {
    printf(GForm("Gled::SpawnSaturn: auth dir '%s' not accessiblen", mAuthDir.Data()));
    printf("Gled::SpawnSaturn: use gled-auth-init command to create onen");
  }
}

 const char* Gled::PubKeyFile(TString& id)
{
  return GForm("%s/public_keys/%s", mAuthDir.Data(), id.Data());
}

 const char* Gled::PrivKeyFile(TString& id)
{
  return GForm("%s/private_keys/%s", mAuthDir.Data(), id.Data());
}

 const char* Gled::GetPubKeyFile(TString& id, Bool_t use_exc)
{
  const char* ret = PubKeyFile(id);
  if(gSystem->AccessPathName(ret, kReadPermission)) {
    if(use_exc)
      throw(string("Gled::GetPubKeyFile can not access file:") + ret);
    else
      ret = 0;
  }
  return ret;
}

 const char* Gled::GetPrivKeyFile(TString& id, Bool_t use_exc)
{
  const char* ret = PrivKeyFile(id);
  if(gSystem->AccessPathName(ret, kReadPermission)) {
    if(use_exc)
      throw(string("Gled::GetPrivKeyFile can not access file:") + ret);
    else
      ret = 0;
  }
  return ret;
}

/**************************************************************************/

 Bool_t Gled::IsIdentityInGroup(const char* id, const char* group)
{
  //printf("Gled::IsIdentityInGroup checking if %s in group %sn", id, group);
  return (gSystem->Exec(GForm("grep -q %s %s/groups/%s",
			      id, mAuthDir.Data(), group)) == 0) ? true : false;;
}

/**************************************************************************/

 void Gled::WaitUntillQueensLoaded()
{
  // Wait until number of arriving queens is zero.

  mSaturn->RefQueenLoadCnd().Lock();
  while(1) {
    int n = mSaturn->GetQueenLoadNum();
    ISmess(GForm("Gled::WaitUntillQueensLoaded() #queens=%d", n));
    if(n==0) {
      mSaturn->RefQueenLoadCnd().Unlock();
      break;
    }
    mSaturn->RefQueenLoadCnd().Wait();
  }
}

 void Gled::AllowMoonConnections()
{
  // Signal Saturn to allow connections by Moons.

  if(mSaturn) mSaturn->AllowMoons();
}

/**************************************************************************/
// Gled stuff
/**************************************************************************/

 void Gled::Exit()
{
  if(mSaturn) mSaturn->Shutdown();
  bQuit = true;
  if(mExitCondVar) {
    mExitCondVar->Lock();
    mExitCondVar->Signal();
    mExitCondVar->Unlock();
  }
}

/**************************************************************************/

 Int_t Gled::LoadLibSet(const Text_t* lib_set)
{
  return GledNS::LoadSoSet(lib_set);
}

 Int_t Gled::LoadLibSet(LID_t lid)
{
  if(GledNS::IsLoaded(lid)) {
    return 0;
  } else {
    Text_t buf[80];
    FILE* f = fopen(GForm("%s/lib/.%u", gSystem->Getenv("GLEDSYS"), lid), "r");
    if(f == 0) {
      ISerr(GForm("Gled::LoadLibSet lid %u can not be demangled", lid));
      return -1;
    }
    fgets(buf, 80, f);
    fclose(f);
    int i = 0; while(i<79 && (isalnum(buf[i]) || buf[i]=='_')) {++i;} buf[i]=0;
    return LoadLibSet(buf);
  }
}

/**************************************************************************/

 void Gled::SetDebugLevel(Int_t d) {
  if(d<0) d=0;
  G_DEBUG = d;
}

/**************************************************************************/
// Info Stream methods
/**************************************************************************/

 void Gled::output(const char* s) {
  if(mOutFile) {
    GThreadKeepAlive tka;
    GMutexHolder     mh(mLoggingMutex);
    if(mOutFile == mLogFile)
      fputs("OUT: ", mOutFile);
    fputs(s, mOutFile);
    putc(10, mOutFile);
  }
}

 void Gled::message(const char* s) {
  GThread::SetCancelState(GThread::CS_Disable);
  if(mLogFile) {
    GThreadKeepAlive tka;
    GMutexHolder     mh(mLoggingMutex);
    fputs("MSG: ", mLogFile);
    fputs(s, mLogFile);
    putc(10, mLogFile);
  }
  GThread::SetCancelState(GThread::CS_Enable);
}

 void Gled::warning(const char* s) {
  if(mLogFile) {
    GThreadKeepAlive tka;
    GMutexHolder     mh(mLoggingMutex);
    fputs("WRN: ", mLogFile);
    fputs(s, mLogFile);
    putc(10, mLogFile);
  }
}

 void Gled::error(const char* s) {
  if(mLogFile) {
    GThreadKeepAlive tka;
    GMutexHolder     mh(mLoggingMutex);
    fputs("ERR: ", mLogFile);
    fputs(s, mLogFile);
    putc(10, mLogFile);
  }
}

/**************************************************************************/

 EyeInfo* Gled::SpawnEye(const char* libset, const char* eyector)
{
  if(mSaturn == 0) {
    ISerr("Gled::SpawnEye Saturn has not been spawned");
    return 0;
  }

  return SpawnEye(0, 0, libset, eyector);
}

/**************************************************************************/

 void Gled::AssertLibSet(const Text_t* lib_set)
{
  // Makes sure libset 'lib_set' is loaded.

  if(GledNS::IsLoaded(lib_set) == false)
    theOne->LoadLibSet(lib_set);
}

namespace {
  void chomp_tail(string& s, char c='.') {
    size_t p = s.rfind(c);
    if(p != string::npos)
      s.erase(p, string::npos);
  }
}

 void Gled::AssertMacro(const Text_t* mac)
{
  // Load and execute macro 'mac' if it has not been loaded yet.

  string foo(mac); chomp_tail(foo);
  if(gROOT->GetGlobalFunction(foo.c_str(), 0, true) == 0) {
    gROOT->Macro(mac);
  }
}

 void Gled::Macro(const Text_t* mac)
{
  // Execute macro 'mac'. Do not reload the macro.

  string foo(mac); chomp_tail(foo);
  if(gROOT->GetGlobalFunction(foo.c_str(), 0, true) == 0)
    gROOT->LoadMacro(mac);

  foo += "()";
  gROOT->ProcessLine(foo.c_str());
}

 void Gled::LoadMacro(const Text_t* mac)
{
  // Makes sure that macro 'mac' is loaded, but do not reload it.

  string foo(mac); chomp_tail(foo);
  if(gROOT->GetGlobalFunction(foo.c_str(), 0, true) == 0)
    gROOT->LoadMacro(mac);
}

/**************************************************************************/
// Thread foos
/**************************************************************************/

 void* Gled::TRint_runner_tl(TRint* gint)
{
  // Runs the ROOT application. Ownership set to mSaturnInfo.

  GThread::setup_tsd(Gled::theOne->mSaturnInfo);

  Gled::theOne->bRintRunning = true;
  while(Gled::theOne->bRintRunning) {
    // !!! Attempt to catch exceptions from root.
    // !!! Does not work.
    try {
      gint->TApplication::Run(true);
      Gled::theOne->bRintRunning = false;
      cout << "Gint terminated ...n";
    }
    catch(string exc) {
      cout <<"TRint runner caught exception: "<< exc << endl;
      cout <<"TRint runner reentering event loop ...n";
    }
  }

  if(Gled::theOne->GetQuit()==false) Gled::theOne->Exit();
  GThread::Exit();
  return 0;
}

 void* Gled::Gled_runner_tl(Gled* gled)
{
  // Runs Gled UI. Only spawned from gled.cxx.

  GThread::setup_tsd(Gled::theOne->mSaturnInfo);

  gled->Run();
  GThread::Exit();
  return 0;
}

/**************************************************************************/
/**************************************************************************/
// Info stream functions
/**************************************************************************/
/**************************************************************************/

void InfoStream(InfoStream_e type, const char* s)
{
  switch (type) {
  case ISoutput:  Gled::theOne->output(s);  break;
  case ISmessage: Gled::theOne->message(s); break;
  case ISwarning: Gled::theOne->warning(s); break;
  case ISerror:   Gled::theOne->error(s);   break;
  }
}

void InfoStream(InfoStream_e type, const string& s)
{
  InfoStream(type, s.c_str());
}

/**************************************************************************/
/**************************************************************************/


ROOT page - Home page - Class index - Class Hierarchy - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.