https://github.com/root-project/root
Raw File
Tip revision: 48e34ed3d3d8adccef966f1166cdc27a3491a62b authored by Axel Naumann on 21 March 2023, 10:09:10 UTC
"Update ROOT version files to v6.28/02."
Tip revision: 48e34ed
rootx.cxx
// @(#)root/rootx:$Id$
// Author: Fons Rademakers   19/02/98

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Rootx                                                                //
//                                                                      //
// Rootx is a small front-end program that starts the main ROOT module. //
// This program is called "root" in the $ROOTSYS/bin directory and the  //
// real ROOT executable is now called "root.exe" (formerly "root").     //
// Rootx puts up a splash screen giving some info about the current     //
// version of ROOT and, more importantly, it sets up the required       //
// LD_LIBRARY_PATH, SHLIB_PATH and LIBPATH environment variables        //
// (depending on the platform).                                         //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "RConfigure.h"
#include "Rtypes.h"
#include "strlcpy.h"
#include "snprintf.h"
#include "rootCommandLineOptionsHelp.h"

#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <cerrno>
#include <netdb.h>
#include <sys/socket.h>
#include <string>
#ifdef __APPLE__
#include <AvailabilityMacros.h>
#include <mach-o/dyld.h>
#endif

#ifdef __sun
#   ifndef _REENTRANT
#      if __SUNPRO_CC > 0x420
#         define GLOBAL_ERRNO
#      endif
#   endif
#endif

#if defined(__CYGWIN__) && defined(__GNUC__)
#define ROOTBINARY "root_exe.exe"
#else
#define ROOTBINARY "root.exe"
#endif

extern void PopupLogo(bool);
extern void WaitLogo();
extern void PopdownLogo();
extern void CloseDisplay();


static bool gNoLogo = true;
      //const  int  kMAXPATHLEN = 8192; defined in Rtypes.h


//Part for Cocoa - requires external linkage.
namespace ROOT {
namespace ROOTX {

//This had internal linkage before, now must be accessible from rootx-cocoa.mm.
int gChildpid = -1;

}
}


#ifdef R__HAS_COCOA

using ROOT::ROOTX::gChildpid;

#else


static int gChildpid;
static int GetErrno()
{
#ifdef GLOBAL_ERRNO
   return ::errno;
#else
   return errno;
#endif
}

static void ResetErrno()
{
#ifdef GLOBAL_ERRNO
   ::errno = 0;
#else
   errno = 0;
#endif
}

#endif

static const char *GetExePath()
{
   static std::string exepath;
   if (exepath == "") {
#ifdef __APPLE__
      exepath = _dyld_get_image_name(0);
#endif
#ifdef __linux
      char linkname[64];      // /proc/<pid>/exe
      char buf[kMAXPATHLEN];  // exe path name
      pid_t pid;

      // get our pid and build the name of the link in /proc
      pid = getpid();
      snprintf(linkname,64, "/proc/%i/exe", pid);
      int ret = readlink(linkname, buf, kMAXPATHLEN);
      if (ret > 0 && ret < kMAXPATHLEN) {
         buf[ret] = 0;
         exepath = buf;
      }
#endif
   }
   return exepath.c_str();
}

static void SetRootSys()
{
   const char *exepath = GetExePath();
   if (exepath && *exepath) {
      int l1 = strlen(exepath)+1;
      char *ep = new char[l1];
      strlcpy(ep, exepath, l1);
      char *s;
      if ((s = strrchr(ep, '/'))) {
         *s = 0;
         if ((s = strrchr(ep, '/'))) {
            *s = 0;
            int l2 = strlen(ep) + 10;
            char *env = new char[l2];
            snprintf(env, l2, "ROOTSYS=%s", ep);
            putenv(env); // NOLINT: allocated memory now used by environment variable
         }
      }
      delete [] ep;
   }
}

#ifndef IS_RPATH_BUILD
static void SetLibraryPath()
{
# ifdef ROOTPREFIX
   if (getenv("ROOTIGNOREPREFIX")) {
# endif
   // Set library path for the different platforms.

   char *msg;

# if defined(__hpux)  || defined(_HIUX_SOURCE)
   if (getenv("SHLIB_PATH")) {
      msg = new char [strlen(getenv("ROOTSYS"))+strlen(getenv("SHLIB_PATH"))+100];
      sprintf(msg, "SHLIB_PATH=%s/lib:%s", getenv("ROOTSYS"),
                                           getenv("SHLIB_PATH"));
   } else {
      msg = new char [strlen(getenv("ROOTSYS"))+100];
      sprintf(msg, "SHLIB_PATH=%s/lib", getenv("ROOTSYS"));
   }
# elif defined(_AIX)
   if (getenv("LIBPATH")) {
      msg = new char [strlen(getenv("ROOTSYS"))+strlen(getenv("LIBPATH"))+100];
      sprintf(msg, "LIBPATH=%s/lib:%s", getenv("ROOTSYS"),
                                        getenv("LIBPATH"));
   } else {
      msg = new char [strlen(getenv("ROOTSYS"))+100];
      sprintf(msg, "LIBPATH=%s/lib:/lib:/usr/lib", getenv("ROOTSYS"));
   }
# elif defined(__APPLE__)
   if (getenv("DYLD_LIBRARY_PATH")) {
      msg = new char [strlen(getenv("ROOTSYS"))+strlen(getenv("DYLD_LIBRARY_PATH"))+100];
      sprintf(msg, "DYLD_LIBRARY_PATH=%s/lib:%s", getenv("ROOTSYS"),
                                                  getenv("DYLD_LIBRARY_PATH"));
   } else {
      msg = new char [strlen(getenv("ROOTSYS"))+100];
      sprintf(msg, "DYLD_LIBRARY_PATH=%s/lib", getenv("ROOTSYS"));
   }
# else
   if (getenv("LD_LIBRARY_PATH")) {
      msg = new char [strlen(getenv("ROOTSYS"))+strlen(getenv("LD_LIBRARY_PATH"))+100];
      sprintf(msg, "LD_LIBRARY_PATH=%s/lib:%s", getenv("ROOTSYS"),
                                                getenv("LD_LIBRARY_PATH"));
   } else {
      msg = new char [strlen(getenv("ROOTSYS"))+100];
#  if defined(__sun)
      sprintf(msg, "LD_LIBRARY_PATH=%s/lib:/usr/dt/lib", getenv("ROOTSYS"));
#  else
      sprintf(msg, "LD_LIBRARY_PATH=%s/lib", getenv("ROOTSYS"));
#  endif
   }
# endif
   putenv(msg);
# ifdef ROOTPREFIX
   } else /* if (getenv("ROOTIGNOREPREFIX")) */ {
      std::string ldLibPath = "LD_LIBRARY_PATH=" ROOTLIBDIR;
      if (const char *oldLdLibPath = getenv("LD_LIBRARY_PATH"))
         ldLibPath += std::string(":") + oldLdLibPath;
      char *msg = strdup(ldLibPath.c_str());
      putenv(msg);
   }
# endif
}
#endif

extern "C" {
   static void SigUsr1(int);
   static void SigTerm(int);
}

static void SigUsr1(int)
{
   // When we get SIGUSR1 from child (i.e. ROOT) then pop down logo.

   if (!gNoLogo)
      PopdownLogo();
}

static void SigTerm(int sig)
{
   // When we get terminated, terminate child, too.
   kill(gChildpid, sig);
}

//ifdefs for Cocoa/other *xes.

#ifdef R__HAS_COCOA

namespace ROOT {
namespace ROOTX {

//Before it had internal linkage, now must be external,
//add namespaces!
void WaitChild();

}
}

using ROOT::ROOTX::WaitChild;

#else

static void WaitChild()
{
   // Wait till child (i.e. ROOT) is finished.

   int status;

   do {
      while (waitpid(gChildpid, &status, WUNTRACED) < 0) {
         if (GetErrno() != EINTR)
            break;
         ResetErrno();
      }

      if (WIFEXITED(status))
         exit(WEXITSTATUS(status));

      if (WIFSIGNALED(status))
         exit(WTERMSIG(status));

      if (WIFSTOPPED(status)) {         // child got ctlr-Z
         raise(SIGTSTP);                // stop also parent
         kill(gChildpid, SIGCONT);       // if parent wakes up, wake up child
      }
   } while (WIFSTOPPED(status));

   exit(0);
}

#endif

static void PrintUsage()
{
   fprintf(stderr, kCommandLineOptionsHelp);
}

int main(int argc, char **argv)
{
   char **argvv;
   char  arg0[kMAXPATHLEN];

#ifdef ROOTPREFIX
   if (getenv("ROOTIGNOREPREFIX")) {
#endif
   // Try to set ROOTSYS depending on pathname of the executable
   SetRootSys();

   if (!getenv("ROOTSYS")) {
      fprintf(stderr, "%s: ROOTSYS not set. Set it before trying to run %s.\n",
              argv[0], argv[0]);
      return 1;
   }
#ifdef ROOTPREFIX
   }
#endif

   // In batch mode don't show splash screen, idem for no logo mode,
   // in about mode show always splash screen
   bool batch = false, about = false;
   int i;
   for (i = 1; i < argc; i++) {
      if (!strcmp(argv[i], "-?") || !strncmp(argv[i], "-h", 2) ||
          !strncmp(argv[i], "--help", 6)) {
         PrintUsage();
         return 1;
      }
      if (!strcmp(argv[i], "-b"))         batch    = true;
      if (!strcmp(argv[i], "-l"))         gNoLogo  = true;
      if (!strcmp(argv[i], "-ll"))        gNoLogo  = true;
      if (!strcmp(argv[i], "-a"))         about    = true;
      if (!strcmp(argv[i], "-config"))    gNoLogo  = true;
      if (!strcmp(argv[i], "--version"))  gNoLogo  = true;
   }

#ifndef R__HAS_COCOA
   if (!getenv("DISPLAY")) {
      gNoLogo = true;
   }
#endif
   if (batch)
      gNoLogo = true;
   if (about) {
      batch   = false;
      gNoLogo = false;
   }

   if (!batch) {
      if (about) {
         PopupLogo(true);
         WaitLogo();
         return 0;
      } else if (!gNoLogo)
         PopupLogo(false);
   }

   // Ignore SIGINT and SIGQUIT. Install handler for SIGUSR1.

   struct sigaction ignore, actUsr1, actTerm,
      saveintr, savequit, saveusr1, saveterm;

#if defined(__sun) && !defined(__i386) && !defined(__SVR4)
   ignore.sa_handler = (void (*)())SIG_IGN;
#elif defined(__sun) && defined(__SVR4)
   ignore.sa_handler = (void (*)(int))SIG_IGN;
#else
   ignore.sa_handler = SIG_IGN;
#endif
   sigemptyset(&ignore.sa_mask);
   ignore.sa_flags = 0;

   actUsr1 = ignore;
   actTerm = ignore;
#if defined(__sun) && !defined(__i386) && !defined(__SVR4)
   actUsr1.sa_handler = (void (*)())SigUsr1;
   actTerm.sa_handler = (void (*)())SigTerm;
#elif defined(__sun) && defined(__SVR4)
   actUsr1.sa_handler = SigUsr1;
   actTerm.sa_handler = SigTerm;
#elif (defined(__sgi) && !defined(__KCC)) || defined(__Lynx__)
#   if defined(IRIX64) || (__GNUG__>=3)
   actUsr1.sa_handler = SigUsr1;
   actTerm.sa_handler = SigTerm;
#   else
   actUsr1.sa_handler = (void (*)(...))SigUsr1;
   actTerm.sa_handler = (void (*)(...))SigTerm;
#   endif
#else
   actUsr1.sa_handler = SigUsr1;
   actTerm.sa_handler = SigTerm;
#endif
   sigaction(SIGINT,  &ignore, &saveintr);
   sigaction(SIGQUIT, &ignore, &savequit);
   sigaction(SIGUSR1, &actUsr1, &saveusr1);
   sigaction(SIGTERM, &actTerm, &saveterm);

   // Create child...

   if ((gChildpid = fork()) < 0) {
      fprintf(stderr, "%s: error forking child\n", argv[0]);
      return 1;
   } else if (gChildpid > 0) {
      if (!gNoLogo)
         WaitLogo();
      WaitChild();
   }

   // Continue with child...

   // Restore original signal actions
   sigaction(SIGINT,  &saveintr, 0);
   sigaction(SIGQUIT, &savequit, 0);
   sigaction(SIGUSR1, &saveusr1, 0);
   sigaction(SIGTERM, &saveterm, 0);

   // Close X display connection
   CloseDisplay();

   // Child is going to overlay itself with the actual ROOT module...

   // Build argv vector
   argvv = new char* [argc+2];
#ifdef ROOTBINDIR
   if (getenv("ROOTIGNOREPREFIX"))
#endif
      snprintf(arg0, sizeof(arg0), "%s/bin/%s", getenv("ROOTSYS"), ROOTBINARY);
#ifdef ROOTBINDIR
   else
      snprintf(arg0, sizeof(arg0), "%s/%s", ROOTBINDIR, ROOTBINARY);
#endif
   argvv[0] = arg0;
   argvv[1] = (char *) "-splash";

   for (i = 1; i < argc; i++)
      argvv[1+i] = argv[i];
   argvv[1+i] = 0;

#ifndef IS_RPATH_BUILD
   // Make sure library path is set
   SetLibraryPath();
#endif

   // Execute actual ROOT module
   execv(arg0, argvv);

   // Exec failed
   fprintf(stderr, "%s: can't start ROOT -- check that %s exists!\n",
           argv[0], arg0);

   delete [] argvv;

   return 1;
}
back to top