TUnixSystem.cxx

Go to the documentation of this file.
00001 // @(#)root/unix:$Id: TUnixSystem.cxx 37431 2010-12-09 10:30:44Z rdm $
00002 // Author: Fons Rademakers   15/09/95
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TUnixSystem                                                          //
00015 //                                                                      //
00016 // Class providing an interface to the UNIX Operating System.           //
00017 //                                                                      //
00018 //////////////////////////////////////////////////////////////////////////
00019 
00020 #include "RConfigure.h"
00021 #include "RConfig.h"
00022 #include "TUnixSystem.h"
00023 #include "TROOT.h"
00024 #include "TError.h"
00025 #include "TOrdCollection.h"
00026 #include "TRegexp.h"
00027 #include "TPRegexp.h"
00028 #include "TException.h"
00029 #include "Demangle.h"
00030 #include "TEnv.h"
00031 #include "TSocket.h"
00032 #include "Getline.h"
00033 #include "TInterpreter.h"
00034 #include "TApplication.h"
00035 #include "TObjString.h"
00036 #include "Riostream.h"
00037 #include "TVirtualMutex.h"
00038 #include "TObjArray.h"
00039 #include <map>
00040 
00041 //#define G__OLDEXPAND
00042 
00043 #include <unistd.h>
00044 #include <stdlib.h>
00045 #include <sys/types.h>
00046 #if defined(R__SUN) || defined(R__SGI) || defined(R__HPUX) || \
00047     defined(R__AIX) || defined(R__LINUX) || defined(R__SOLARIS) || \
00048     defined(R__ALPHA) || defined(R__HIUX) || defined(R__FBSD) || \
00049     defined(R__OBSD) || defined(R__MACOSX) || defined(R__HURD)
00050 #define HAS_DIRENT
00051 #endif
00052 #ifdef HAS_DIRENT
00053 #   include <dirent.h>
00054 #else
00055 #   include <sys/dir.h>
00056 #endif
00057 #if defined(ULTRIX) || defined(R__SUN)
00058 #   include <sgtty.h>
00059 #endif
00060 #if defined(R__AIX) || defined(R__LINUX) || defined(R__ALPHA) || \
00061     defined(R__SGI) || defined(R__HIUX) || defined(R__FBSD) || \
00062     defined(R__OBSD) || defined(R__LYNXOS) || defined(R__MACOSX) || \
00063     defined(R__HURD)
00064 #   include <sys/ioctl.h>
00065 #endif
00066 #if defined(R__AIX) || defined(R__SOLARIS)
00067 #   include <sys/select.h>
00068 #endif
00069 #if defined(R__LINUX) || defined(R__HURD)
00070 #   ifndef SIGSYS
00071 #      define SIGSYS  SIGUNUSED       // SIGSYS does not exist in linux ??
00072 #   endif
00073 #endif
00074 #if defined(R__ALPHA)
00075 #   include <sys/mount.h>
00076 #   ifndef R__TRUE64
00077    extern "C" int statfs(const char *file, struct statfs *buffer);
00078 #   endif
00079 #elif defined(R__MACOSX)
00080 #   include <mach-o/dyld.h>
00081 #   include <sys/mount.h>
00082    extern "C" int statfs(const char *file, struct statfs *buffer);
00083 #elif defined(R__LINUX) || defined(R__HPUX) || defined(R__HURD)
00084 #   include <sys/vfs.h>
00085 #elif defined(R__FBSD) || defined(R__OBSD)
00086 #   include <sys/param.h>
00087 #   include <sys/mount.h>
00088 #else
00089 #   include <sys/statfs.h>
00090 #endif
00091 
00092 #include <utime.h>
00093 #include <syslog.h>
00094 #include <sys/stat.h>
00095 #include <setjmp.h>
00096 #include <signal.h>
00097 #include <sys/param.h>
00098 #include <pwd.h>
00099 #include <grp.h>
00100 #include <errno.h>
00101 #include <sys/wait.h>
00102 #include <time.h>
00103 #include <sys/time.h>
00104 #include <sys/file.h>
00105 #include <sys/socket.h>
00106 #include <netinet/in.h>
00107 #include <netinet/tcp.h>
00108 #if defined(R__AIX)
00109 #   define _XOPEN_EXTENDED_SOURCE
00110 #   include <arpa/inet.h>
00111 #   undef _XOPEN_EXTENDED_SOURCE
00112 #   if !defined(_AIX41) && !defined(_AIX43)
00113     // AIX 3.2 doesn't have it
00114 #   define HASNOT_INETATON
00115 #   endif
00116 #else
00117 #   include <arpa/inet.h>
00118 #endif
00119 #include <sys/un.h>
00120 #include <netdb.h>
00121 #include <fcntl.h>
00122 #if defined(R__SGI)
00123 #   include <net/soioctl.h>
00124 #endif
00125 #if defined(R__SOLARIS)
00126 #   include <sys/systeminfo.h>
00127 #   include <sys/filio.h>
00128 #   include <sys/sockio.h>
00129 #   define HASNOT_INETATON
00130 #   ifndef INADDR_NONE
00131 #      define INADDR_NONE (UInt_t)-1
00132 #   endif
00133 #endif
00134 #if defined(R__HPUX)
00135 #   include <symlink.h>
00136 #   include <dl.h>
00137 #   if defined(R__GNU)
00138    extern "C" {
00139       extern shl_t cxxshl_load(const char *path, int flags, long address);
00140       extern int   cxxshl_unload(shl_t handle);
00141    }
00142 #   elif !defined(__STDCPP__)
00143 #      include <cxxdl.h>
00144 #   endif
00145 #   if defined(hpux9)
00146    extern "C" {
00147       extern void openlog(const char *, int, int);
00148       extern void syslog(int, const char *, ...);
00149       extern void closelog(void);
00150       extern int setlogmask(int);
00151    }
00152 #   define HASNOT_INETATON
00153 #   endif
00154 #endif
00155 #if defined(R__ALPHA) && !defined(R__GNU)
00156 #   define HASNOT_INETATON
00157 #endif
00158 #if defined(R__HIUX)
00159 #   define HASNOT_INETATON
00160 #endif
00161 
00162 #if defined(R__SGI) || defined(R__SOLARIS)
00163 #   define HAVE_UTMPX_H
00164 #   define UTMP_NO_ADDR
00165 #endif
00166 
00167 #if defined(MAC_OS_X_VERSION_10_5)
00168 #   define HAVE_UTMPX_H
00169 #   define UTMP_NO_ADDR
00170 #   ifndef ut_user
00171 #      define ut_user ut_name
00172 #   endif
00173 #endif
00174 
00175 #if defined(R__ALPHA) || defined(R__AIX) || defined(R__FBSD) || \
00176     defined(R__OBSD) || defined(R__LYNXOS) || \
00177     (defined(R__MACOSX) && !defined(MAC_OS_X_VERSION_10_5))
00178 #   define UTMP_NO_ADDR
00179 #endif
00180 
00181 #if (defined(R__AIX) && !defined(_AIX43)) || \
00182     (defined(R__SUNGCC3) && !defined(__arch64__))
00183 #   define USE_SIZE_T
00184 #elif defined(R__GLIBC) || defined(R__FBSD) || \
00185       (defined(R__SUNGCC3) && defined(__arch64__)) || \
00186       defined(R__OBSD) || defined(MAC_OS_X_VERSION_10_4) || \
00187       (defined(R__AIX) && defined(_AIX43))
00188 #   define USE_SOCKLEN_T
00189 #endif
00190 
00191 #if defined(R__LYNXOS)
00192 extern "C" {
00193    extern int putenv(const char *);
00194    extern int inet_aton(const char *, struct in_addr *);
00195 };
00196 #endif
00197 
00198 #ifdef HAVE_UTMPX_H
00199 #include <utmpx.h>
00200 #define STRUCT_UTMP struct utmpx
00201 #else
00202 #include <utmp.h>
00203 #define STRUCT_UTMP struct utmp
00204 #endif
00205 #if !defined(UTMP_FILE) && defined(_PATH_UTMP)      // 4.4BSD
00206 #define UTMP_FILE _PATH_UTMP
00207 #endif
00208 #if defined(UTMPX_FILE)                             // Solaris, SysVr4
00209 #undef  UTMP_FILE
00210 #define UTMP_FILE UTMPX_FILE
00211 #endif
00212 #ifndef UTMP_FILE
00213 #define UTMP_FILE "/etc/utmp"
00214 #endif
00215 
00216 // stack trace code
00217 #if defined(R__HPUX) && !defined(R__GNU)
00218 #   define HAVE_U_STACK_TRACE
00219 #endif
00220 #if defined(R__AIX)
00221 // #   define HAVE_XL_TRBK   // does not work as expected
00222 #endif
00223 #if (defined(R__LINUX) || defined(R__HURD)) && !defined(R__WINGCC)
00224 #   if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1
00225 #      define HAVE_BACKTRACE_SYMBOLS_FD
00226 #   endif
00227 #   define HAVE_DLADDR
00228 #endif
00229 #if defined(R__MACOSX)
00230 #   define USE_GDB_STACK_TRACE
00231 #endif
00232 
00233 #ifdef HAVE_U_STACK_TRACE
00234    // HP-UX stack walker (http://devresource.hp.com/STK/partner/unwind.pdf)
00235    extern "C" void U_STACK_TRACE(void);
00236 #endif
00237 #ifdef HAVE_XL_TRBK
00238    // AIX stack walker (from xlf FORTRAN 90 runtime).
00239    extern "C" void xl__trbk(void);
00240 #endif
00241 #ifdef HAVE_BACKTRACE_SYMBOLS_FD
00242 #   include <execinfo.h>
00243 #endif
00244 #ifdef HAVE_DLADDR
00245 #   ifndef __USE_GNU
00246 #      define __USE_GNU
00247 #   endif
00248 #   include <dlfcn.h>
00249 #endif
00250 
00251 #ifdef HAVE_BACKTRACE_SYMBOLS_FD
00252    // The maximum stack trace depth for systems where we request the
00253    // stack depth separately (currently glibc-based systems).
00254    static const int kMAX_BACKTRACE_DEPTH = 128;
00255 #endif
00256 
00257 // FPE handling includes
00258 #if (defined(R__LINUX) && !defined(R__WINGCC))
00259 #include <fpu_control.h>
00260 #include <fenv.h>
00261 #endif
00262 
00263 #if defined(R__MACOSX) && !defined(__xlC__) && !defined(__i386__) && \
00264    !defined(__x86_64__) && !defined(__arm__)
00265 #include <fenv.h>
00266 #include <signal.h>
00267 #include <ucontext.h>
00268 #include <stdlib.h>
00269 #include <stdio.h>
00270 #include <mach/thread_status.h>
00271 
00272 #define fegetenvd(x) asm volatile("mffs %0" : "=f" (x));
00273 #define fesetenvd(x) asm volatile("mtfsf 255,%0" : : "f" (x));
00274 
00275 enum {
00276   FE_ENABLE_INEXACT    = 0x00000008,
00277   FE_ENABLE_DIVBYZERO  = 0x00000010,
00278   FE_ENABLE_UNDERFLOW  = 0x00000020,
00279   FE_ENABLE_OVERFLOW   = 0x00000040,
00280   FE_ENABLE_INVALID    = 0x00000080,
00281   FE_ENABLE_ALL_EXCEPT = 0x000000F8
00282 };
00283 #endif
00284 
00285 #if defined(R__MACOSX) && (defined(__i386__) || defined(__x86_64__) || defined(__arm__))
00286 #include <fenv.h>
00287 #endif
00288 // End FPE handling includes
00289 
00290 
00291 static STRUCT_UTMP *gUtmpContents;
00292 
00293 
00294 const char *kServerPath     = "/tmp";
00295 const char *kProtocolName   = "tcp";
00296 
00297 //------------------- Unix TFdSet ----------------------------------------------
00298 #ifndef HOWMANY
00299 #   define HOWMANY(x, y)   (((x)+((y)-1))/(y))
00300 #endif
00301 
00302 const Int_t kNFDBITS = (sizeof(Long_t) * 8);  // 8 bits per byte
00303 #ifdef FD_SETSIZE
00304 const Int_t kFDSETSIZE = FD_SETSIZE;          // Linux = 1024 file descriptors
00305 #else
00306 const Int_t kFDSETSIZE = 256;                 // upto 256 file descriptors
00307 #endif
00308 
00309 
00310 class TFdSet {
00311 private:
00312    ULong_t fds_bits[HOWMANY(kFDSETSIZE, kNFDBITS)];
00313 public:
00314    TFdSet() { memset(fds_bits, 0, sizeof(fds_bits)); }
00315    TFdSet(const TFdSet &org) { memcpy(fds_bits, org.fds_bits, sizeof(org.fds_bits)); }
00316    TFdSet &operator=(const TFdSet &rhs) { if (this != &rhs) { memcpy(fds_bits, rhs.fds_bits, sizeof(rhs.fds_bits));} return *this; }
00317    void   Zero() { memset(fds_bits, 0, sizeof(fds_bits)); }
00318    void   Set(Int_t n)
00319    {
00320       if (n >= 0 && n < kFDSETSIZE) {
00321          fds_bits[n/kNFDBITS] |= (1UL << (n % kNFDBITS));
00322       } else {
00323          ::Fatal("TFdSet::Set","fd (%d) out of range [0..%d]", n, kFDSETSIZE-1);
00324       }
00325    }
00326    void   Clr(Int_t n)
00327    {
00328       if (n >= 0 && n < kFDSETSIZE) {
00329          fds_bits[n/kNFDBITS] &= ~(1UL << (n % kNFDBITS));
00330       } else {
00331          ::Fatal("TFdSet::Clr","fd (%d) out of range [0..%d]", n, kFDSETSIZE-1);
00332       }
00333    }
00334    Int_t  IsSet(Int_t n)
00335    {
00336       if (n >= 0 && n < kFDSETSIZE) {
00337          return (fds_bits[n/kNFDBITS] & (1UL << (n % kNFDBITS))) != 0;
00338       } else {
00339          ::Fatal("TFdSet::IsSet","fd (%d) out of range [0..%d]", n, kFDSETSIZE-1);
00340          return 0;
00341       }
00342    }
00343    ULong_t *GetBits() { return (ULong_t *)fds_bits; }
00344 };
00345 
00346 //______________________________________________________________________________
00347 static void SigHandler(ESignals sig)
00348 {
00349    // Unix signal handler.
00350 
00351    if (gSystem)
00352       ((TUnixSystem*)gSystem)->DispatchSignals(sig);
00353 }
00354 
00355 //______________________________________________________________________________
00356 static const char *GetExePath()
00357 {
00358    static TString exepath;
00359    if (exepath == "") {
00360 #ifdef __APPLE__
00361       exepath = _dyld_get_image_name(0);
00362 #endif
00363 #ifdef __linux
00364       char linkname[64];      // /proc/<pid>/exe
00365       char buf[kMAXPATHLEN];  // exe path name
00366       pid_t pid;
00367 
00368       // get our pid and build the name of the link in /proc
00369       pid = getpid();
00370       snprintf(linkname,64, "/proc/%i/exe", pid);
00371       int ret = readlink(linkname, buf, kMAXPATHLEN);
00372       if (ret > 0 && ret < kMAXPATHLEN) {
00373          buf[ret] = 0;
00374          exepath = buf;
00375       }
00376 #endif
00377    }
00378    return exepath;
00379 }
00380 
00381 #if defined(HAVE_DLADDR)
00382 //______________________________________________________________________________
00383 static void SetRootSys()
00384 {
00385 #ifndef ROOTPREFIX
00386    void *addr = (void *)SetRootSys;
00387    Dl_info info;
00388    if (dladdr(addr, &info) && info.dli_fname && info.dli_fname[0]) {
00389       char respath[kMAXPATHLEN];
00390       if (!realpath(info.dli_fname, respath)) {
00391          if (!gSystem->Getenv("ROOTSYS"))
00392             ::SysError("TUnixSystem::SetRootSys", "error getting realpath of libCore, please set ROOTSYS in the shell");
00393       } else {
00394          TString rs = gSystem->DirName(respath);
00395          gSystem->Setenv("ROOTSYS", gSystem->DirName(rs));
00396       }
00397    }
00398 #else
00399    return;
00400 #endif
00401 }
00402 #endif
00403 
00404 #if defined(R__MACOSX)
00405 static TString gLinkedDylibs;
00406 
00407 //______________________________________________________________________________
00408 static void DylibAdded(const struct mach_header *mh, intptr_t /* vmaddr_slide */)
00409 {
00410    static int i = 0;
00411    static Bool_t gotFirstSo = kFALSE;
00412    static TString linkedDylibs;
00413 
00414    // to copy the local linkedDylibs to the global gLinkedDylibs call this
00415    // function with mh==0
00416    if (!mh) {
00417       gLinkedDylibs = linkedDylibs;
00418       return;
00419    }
00420 
00421    TString lib = _dyld_get_image_name(i++);
00422 
00423 #ifndef ROOTPREFIX
00424 #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
00425    // first loaded is the app so set ROOTSYS to app bundle
00426    if (i == 1) {
00427       char respath[kMAXPATHLEN];
00428       if (!realpath(lib, respath)) {
00429          if (!gSystem->Getenv("ROOTSYS"))
00430             ::SysError("TUnixSystem::DylibAdded", "error getting realpath of %s", gSystem->BaseName(lib));
00431       } else {
00432          TString rs = gSystem->DirName(respath);
00433          rs.ReplaceAll(" ", "\\ ");
00434          gSystem->Setenv("ROOTSYS", rs);
00435       }
00436    }
00437 #else
00438    if (lib.EndsWith("libCore.dylib") || lib.EndsWith("libCore.so")) {
00439       char respath[kMAXPATHLEN];
00440       if (!realpath(lib, respath)) {
00441          if (!gSystem->Getenv("ROOTSYS"))
00442             ::SysError("TUnixSystem::DylibAdded", "error getting realpath of libCore, please set ROOTSYS in the shell");
00443       } else {
00444          TString rs = gSystem->DirName(respath);
00445          gSystem->Setenv("ROOTSYS", gSystem->DirName(rs));
00446       }
00447    }
00448 #endif
00449 #endif
00450 
00451    // when libSystem.B.dylib is loaded we have finished loading all dylibs
00452    // explicitly linked against the executable. Additional dylibs
00453    // come when they are explicitly linked against loaded so's, currently
00454    // we are not interested in these
00455    if (lib.EndsWith("/libSystem.B.dylib"))
00456       gotFirstSo = kTRUE;
00457 
00458    // add all libs loaded before libSystem.B.dylib
00459    if (!gotFirstSo && (lib.EndsWith(".dylib") || lib.EndsWith(".so"))) {
00460       if (linkedDylibs.Length())
00461          linkedDylibs += " ";
00462       linkedDylibs += lib;
00463    }
00464 }
00465 #endif
00466 
00467 
00468 ClassImp(TUnixSystem)
00469 
00470 //______________________________________________________________________________
00471 TUnixSystem::TUnixSystem() : TSystem("Unix", "Unix System")
00472 { }
00473 
00474 //______________________________________________________________________________
00475 TUnixSystem::~TUnixSystem()
00476 {
00477    // Reset to original state.
00478 
00479    UnixResetSignals();
00480 
00481    delete fReadmask;
00482    delete fWritemask;
00483    delete fReadready;
00484    delete fWriteready;
00485    delete fSignals;
00486 }
00487 
00488 //______________________________________________________________________________
00489 Bool_t TUnixSystem::Init()
00490 {
00491    // Initialize Unix system interface.
00492 
00493    if (TSystem::Init())
00494       return kTRUE;
00495 
00496    fReadmask   = new TFdSet;
00497    fWritemask  = new TFdSet;
00498    fReadready  = new TFdSet;
00499    fWriteready = new TFdSet;
00500    fSignals    = new TFdSet;
00501 
00502    //--- install default handlers
00503    UnixSignal(kSigChild,                 SigHandler);
00504    UnixSignal(kSigBus,                   SigHandler);
00505    UnixSignal(kSigSegmentationViolation, SigHandler);
00506    UnixSignal(kSigIllegalInstruction,    SigHandler);
00507    UnixSignal(kSigSystem,                SigHandler);
00508    UnixSignal(kSigPipe,                  SigHandler);
00509    UnixSignal(kSigAlarm,                 SigHandler);
00510    UnixSignal(kSigUrgent,                SigHandler);
00511    UnixSignal(kSigFloatingException,     SigHandler);
00512    UnixSignal(kSigWindowChanged,         SigHandler);
00513 
00514 #if defined(R__MACOSX)
00515    // trap loading of all dylibs to register dylib name,
00516    // sets also ROOTSYS if built without ROOTPREFIX
00517    _dyld_register_func_for_add_image(DylibAdded);
00518 #elif defined(HAVE_DLADDR)
00519    SetRootSys();
00520 #endif
00521 
00522 #ifndef ROOTPREFIX
00523    gRootDir = Getenv("ROOTSYS");
00524    if (gRootDir == 0)
00525       gRootDir= "/usr/local/root";
00526 #else
00527    gRootDir = ROOTPREFIX;
00528 #endif
00529 
00530    return kFALSE;
00531 }
00532 
00533 //---- Misc --------------------------------------------------------------------
00534 
00535 //______________________________________________________________________________
00536 void TUnixSystem::SetProgname(const char *name)
00537 {
00538    // Set the application name (from command line, argv[0]) and copy it in
00539    // gProgName. Copy the application pathname in gProgPath.
00540    // If name is 0 let the system set the actual executable name and path
00541    // (works on MacOS X and Linux).
00542 
00543    if (gProgName)
00544       delete [] gProgName;
00545    if (gProgPath)
00546       delete [] gProgPath;
00547 
00548    if (!name || !*name) {
00549       name = GetExePath();
00550       gProgName = StrDup(BaseName(name));
00551       gProgPath = StrDup(DirName(name));
00552    } else {
00553       gProgName = StrDup(BaseName(name));
00554       char *w   = Which(Getenv("PATH"), gProgName);
00555       gProgPath = StrDup(DirName(w));
00556       delete [] w;
00557    }
00558 }
00559 
00560 //______________________________________________________________________________
00561 void TUnixSystem::SetDisplay()
00562 {
00563    // Set DISPLAY environment variable based on utmp entry. Only for UNIX.
00564 
00565    if (!Getenv("DISPLAY")) {
00566       char *tty = ::ttyname(0);  // device user is logged in on
00567       if (tty) {
00568          tty += 5;               // remove "/dev/"
00569 
00570          R__LOCKGUARD2(gSystemMutex);
00571 
00572          STRUCT_UTMP *utmp_entry = (STRUCT_UTMP *)SearchUtmpEntry(ReadUtmpFile(), tty);
00573          if (utmp_entry) {
00574             if (utmp_entry->ut_host[0])
00575                if (strchr(utmp_entry->ut_host, ':')) {
00576                   Setenv("DISPLAY", utmp_entry->ut_host);
00577                   Warning("SetDisplay", "DISPLAY not set, setting it to %s",
00578                           utmp_entry->ut_host);
00579                } else {
00580                   char disp[64];
00581                   snprintf(disp, sizeof(disp), "%s:0.0", utmp_entry->ut_host);
00582                   Setenv("DISPLAY", disp);
00583                   Warning("SetDisplay", "DISPLAY not set, setting it to %s",
00584                           disp);
00585                }
00586 #ifndef UTMP_NO_ADDR
00587             else if (utmp_entry->ut_addr) {
00588                struct hostent *he;
00589                if ((he = gethostbyaddr((const char*)&utmp_entry->ut_addr,
00590                                        sizeof(utmp_entry->ut_addr), AF_INET))) {
00591                   char disp[64];
00592                   snprintf(disp, sizeof(disp), "%s:0.0", he->h_name);
00593                   Setenv("DISPLAY", disp);
00594                   Warning("SetDisplay", "DISPLAY not set, setting it to %s",
00595                           disp);
00596                }
00597             }
00598 #endif
00599          }
00600          free(gUtmpContents);
00601       }
00602    }
00603 }
00604 
00605 //______________________________________________________________________________
00606 const char *TUnixSystem::GetError()
00607 {
00608    // Return system error string.
00609 
00610    Int_t err = GetErrno();
00611    if (err == 0 && fLastErrorString != "")
00612       return fLastErrorString;
00613 #if defined(R__SOLARIS) || defined (R__LINUX) || defined(R__AIX) || \
00614     defined(R__FBSD) || defined(R__OBSD) || defined(R__HURD)
00615    return strerror(err);
00616 #else
00617    if (err < 0 || err >= sys_nerr)
00618       return Form("errno out of range %d", err);
00619    return sys_errlist[err];
00620 #endif
00621 }
00622 
00623 //______________________________________________________________________________
00624 const char *TUnixSystem::HostName()
00625 {
00626    // Return the system's host name.
00627 
00628    if (fHostname == "") {
00629       char hn[64];
00630 #if defined(R__SOLARIS)
00631       sysinfo(SI_HOSTNAME, hn, sizeof(hn));
00632 #else
00633       gethostname(hn, sizeof(hn));
00634 #endif
00635       fHostname = hn;
00636    }
00637    return (const char *)fHostname;
00638 }
00639 
00640 //---- EventLoop ---------------------------------------------------------------
00641 
00642 //______________________________________________________________________________
00643 void TUnixSystem::AddFileHandler(TFileHandler *h)
00644 {
00645    // Add a file handler to the list of system file handlers. Only adds
00646    // the handler if it is not already in the list of file handlers.
00647 
00648    R__LOCKGUARD2(gSystemMutex);
00649 
00650    TSystem::AddFileHandler(h);
00651    if (h) {
00652       int fd = h->GetFd();
00653       if (h->HasReadInterest()) {
00654          fReadmask->Set(fd);
00655          fMaxrfd = TMath::Max(fMaxrfd, fd);
00656       }
00657       if (h->HasWriteInterest()) {
00658          fWritemask->Set(fd);
00659          fMaxwfd = TMath::Max(fMaxwfd, fd);
00660       }
00661    }
00662 }
00663 
00664 //______________________________________________________________________________
00665 TFileHandler *TUnixSystem::RemoveFileHandler(TFileHandler *h)
00666 {
00667    // Remove a file handler from the list of file handlers. Returns
00668    // the handler or 0 if the handler was not in the list of file handlers.
00669 
00670    if (!h) return 0;
00671 
00672    R__LOCKGUARD2(gSystemMutex);
00673 
00674    TFileHandler *oh = TSystem::RemoveFileHandler(h);
00675    if (oh) {       // found
00676       TFileHandler *th;
00677       TIter next(fFileHandler);
00678       fMaxrfd = -1;
00679       fMaxwfd = -1;
00680       fReadmask->Zero();
00681       fWritemask->Zero();
00682       while ((th = (TFileHandler *) next())) {
00683          int fd = th->GetFd();
00684          if (th->HasReadInterest()) {
00685             fReadmask->Set(fd);
00686             fMaxrfd = TMath::Max(fMaxrfd, fd);
00687          }
00688          if (th->HasWriteInterest()) {
00689             fWritemask->Set(fd);
00690             fMaxwfd = TMath::Max(fMaxwfd, fd);
00691          }
00692       }
00693    }
00694    return oh;
00695 }
00696 
00697 //______________________________________________________________________________
00698 void TUnixSystem::AddSignalHandler(TSignalHandler *h)
00699 {
00700    // Add a signal handler to list of system signal handlers. Only adds
00701    // the handler if it is not already in the list of signal handlers.
00702 
00703    R__LOCKGUARD2(gSystemMutex);
00704 
00705    TSystem::AddSignalHandler(h);
00706    UnixSignal(h->GetSignal(), SigHandler);
00707 }
00708 
00709 //______________________________________________________________________________
00710 TSignalHandler *TUnixSystem::RemoveSignalHandler(TSignalHandler *h)
00711 {
00712    // Remove a signal handler from list of signal handlers. Returns
00713    // the handler or 0 if the handler was not in the list of signal handlers.
00714 
00715    if (!h) return 0;
00716 
00717    R__LOCKGUARD2(gSystemMutex);
00718 
00719    TSignalHandler *oh = TSystem::RemoveSignalHandler(h);
00720 
00721    Bool_t last = kTRUE;
00722    TSignalHandler *hs;
00723    TIter next(fSignalHandler);
00724 
00725    while ((hs = (TSignalHandler*) next())) {
00726       if (hs->GetSignal() == h->GetSignal())
00727          last = kFALSE;
00728    }
00729    if (last)
00730       ResetSignal(h->GetSignal(), kTRUE);
00731 
00732    return oh;
00733 }
00734 
00735 //______________________________________________________________________________
00736 void TUnixSystem::ResetSignal(ESignals sig, Bool_t reset)
00737 {
00738    // If reset is true reset the signal handler for the specified signal
00739    // to the default handler, else restore previous behaviour.
00740 
00741    if (reset)
00742       UnixResetSignal(sig);
00743    else
00744       UnixSignal(sig, SigHandler);
00745 }
00746 
00747 //______________________________________________________________________________
00748 void TUnixSystem::IgnoreSignal(ESignals sig, Bool_t ignore)
00749 {
00750    // If ignore is true ignore the specified signal, else restore previous
00751    // behaviour.
00752 
00753    UnixIgnoreSignal(sig, ignore);
00754 }
00755 
00756 //______________________________________________________________________________
00757 void TUnixSystem::SigAlarmInterruptsSyscalls(Bool_t set)
00758 {
00759    // When the argument is true the SIGALRM signal handler is set so that
00760    // interrupted syscalls will not be restarted by the kernel. This is
00761    // typically used in case one wants to put a timeout on an I/O operation.
00762    // By default interrupted syscalls will always be restarted (for all
00763    // signals). This can be controlled for each a-synchronous TTimer via
00764    // the method TTimer::SetInterruptSyscalls().
00765 
00766    UnixSigAlarmInterruptsSyscalls(set);
00767 }
00768 
00769 //______________________________________________________________________________
00770 Int_t TUnixSystem::GetFPEMask()
00771 {
00772    // Return the bitmap of conditions that trigger a floating point exception.
00773 
00774    Int_t mask = 0;
00775 
00776 #if defined(R__LINUX) && !defined(__powerpc__)
00777 #if defined(__GLIBC__) && (__GLIBC__>2 || __GLIBC__==2 && __GLIBC_MINOR__>=1)
00778 
00779 #if __GLIBC_MINOR__>=3
00780 
00781    // clear pending exceptions so feenableexcept does not trigger them
00782    feclearexcept(FE_ALL_EXCEPT);
00783    Int_t oldmask = feenableexcept(0);
00784 
00785 #else
00786    fenv_t oldenv;
00787    fegetenv(&oldenv);
00788    fesetenv(&oldenv);
00789 #ifdef __alpha__
00790    ULong_t oldmask = ~oldenv;
00791 #elif __ia64__
00792    Int_t oldmask = ~oldenv;
00793 #else
00794    Int_t oldmask = ~oldenv.__control_word;
00795 #endif
00796 #endif
00797 
00798    if (oldmask & FE_INVALID  )   mask |= kInvalid;
00799    if (oldmask & FE_DIVBYZERO)   mask |= kDivByZero;
00800    if (oldmask & FE_OVERFLOW )   mask |= kOverflow;
00801    if (oldmask & FE_UNDERFLOW)   mask |= kUnderflow;
00802 # ifdef FE_INEXACT
00803    if (oldmask & FE_INEXACT  )   mask |= kInexact;
00804 # endif
00805 #endif
00806 #endif
00807 
00808 #if defined(R__MACOSX) && (defined(__i386__) || defined(__x86_64__) || defined(__arm__))
00809    fenv_t oldenv;
00810    fegetenv(&oldenv);
00811    fesetenv(&oldenv);
00812 #if defined(__arm__)
00813    Int_t oldmask = ~oldenv.__fpscr;
00814 #else
00815    Int_t oldmask = ~oldenv.__control;
00816 #endif
00817 
00818    if (oldmask & FE_INVALID  )   mask |= kInvalid;
00819    if (oldmask & FE_DIVBYZERO)   mask |= kDivByZero;
00820    if (oldmask & FE_OVERFLOW )   mask |= kOverflow;
00821    if (oldmask & FE_UNDERFLOW)   mask |= kUnderflow;
00822 # ifdef FE_INEXACT
00823    if (oldmask & FE_INEXACT  )   mask |= kInexact;
00824 # endif
00825 #endif
00826 
00827 #if defined(R__MACOSX) && !defined(__xlC__) && !defined(__i386__) && \
00828    !defined(__x86_64__) && !defined(__arm__)
00829    Long64_t oldmask;
00830    fegetenvd(oldmask);
00831 
00832    if (oldmask & FE_ENABLE_INVALID  )   mask |= kInvalid;
00833    if (oldmask & FE_ENABLE_DIVBYZERO)   mask |= kDivByZero;
00834    if (oldmask & FE_ENABLE_OVERFLOW )   mask |= kOverflow;
00835    if (oldmask & FE_ENABLE_UNDERFLOW)   mask |= kUnderflow;
00836    if (oldmask & FE_ENABLE_INEXACT  )   mask |= kInexact;
00837 #endif
00838 
00839    return mask;
00840 }
00841 
00842 //______________________________________________________________________________
00843 Int_t TUnixSystem::SetFPEMask(Int_t mask)
00844 {
00845    // Set which conditions trigger a floating point exception.
00846    // Return the previous set of conditions.
00847 
00848    if (mask) { }  // use mask to avoid warning
00849 
00850    Int_t old = GetFPEMask();
00851 
00852 #if defined(R__LINUX) && !defined(__powerpc__)
00853 #if defined(__GLIBC__) && (__GLIBC__>2 || __GLIBC__==2 && __GLIBC_MINOR__>=1)
00854    Int_t newm = 0;
00855    if (mask & kInvalid  )   newm |= FE_INVALID;
00856    if (mask & kDivByZero)   newm |= FE_DIVBYZERO;
00857    if (mask & kOverflow )   newm |= FE_OVERFLOW;
00858    if (mask & kUnderflow)   newm |= FE_UNDERFLOW;
00859 # ifdef FE_INEXACT
00860    if (mask & kInexact  )   newm |= FE_INEXACT;
00861 # endif
00862 
00863 #if __GLIBC_MINOR__>=3
00864 
00865    // clear pending exceptions so feenableexcept does not trigger them
00866    feclearexcept(FE_ALL_EXCEPT);
00867    fedisableexcept(FE_ALL_EXCEPT);
00868    feenableexcept(newm);
00869 
00870 #else
00871 
00872    fenv_t cur;
00873    fegetenv(&cur);
00874 #if defined __ia64__ || defined __alpha__
00875    cur &= ~newm;
00876 #else
00877    cur.__control_word &= ~newm;
00878 #endif
00879    fesetenv(&cur);
00880 
00881 #endif
00882 #endif
00883 #endif
00884 
00885 #if defined(R__MACOSX) && (defined(__i386__) || defined(__x86_64__) || defined(__arm__))
00886    Int_t newm = 0;
00887    if (mask & kInvalid  )   newm |= FE_INVALID;
00888    if (mask & kDivByZero)   newm |= FE_DIVBYZERO;
00889    if (mask & kOverflow )   newm |= FE_OVERFLOW;
00890    if (mask & kUnderflow)   newm |= FE_UNDERFLOW;
00891    if (mask & kInexact  )   newm |= FE_INEXACT;
00892 
00893    fenv_t cur;
00894    fegetenv(&cur);
00895 #if defined(__arm__)
00896    cur.__fpscr &= ~newm;
00897 #else
00898    cur.__control &= ~newm;
00899 #endif
00900    fesetenv(&cur);
00901 #endif
00902 
00903 #if defined(R__MACOSX) && !defined(__xlC__) && !defined(__i386__) && \
00904    !defined(__x86_64__) && !defined(__arm__)
00905    Int_t newm = 0;
00906    if (mask & kInvalid  )   newm |= FE_ENABLE_INVALID;
00907    if (mask & kDivByZero)   newm |= FE_ENABLE_DIVBYZERO;
00908    if (mask & kOverflow )   newm |= FE_ENABLE_OVERFLOW;
00909    if (mask & kUnderflow)   newm |= FE_ENABLE_UNDERFLOW;
00910    if (mask & kInexact  )   newm |= FE_ENABLE_INEXACT;
00911 
00912    Long64_t curmask;
00913    fegetenvd(curmask);
00914    curmask = (curmask & ~FE_ENABLE_ALL_EXCEPT) | newm;
00915    fesetenvd(curmask);
00916 #endif
00917 
00918    return old;
00919 }
00920 
00921 //______________________________________________________________________________
00922 void TUnixSystem::DispatchOneEvent(Bool_t pendingOnly)
00923 {
00924    // Dispatch a single event.
00925 
00926    Bool_t pollOnce = pendingOnly;
00927 
00928    while (1) {
00929       // first handle any X11 events
00930       if (gXDisplay && gXDisplay->Notify()) {
00931          if (fReadready->IsSet(gXDisplay->GetFd())) {
00932             fReadready->Clr(gXDisplay->GetFd());
00933             fNfd--;
00934          }
00935          if (!pendingOnly) return;
00936       }
00937 
00938       // check for file descriptors ready for reading/writing
00939       if (fNfd > 0 && fFileHandler && fFileHandler->GetSize() > 0)
00940          if (CheckDescriptors())
00941             if (!pendingOnly) return;
00942       fNfd = 0;
00943       fReadready->Zero();
00944       fWriteready->Zero();
00945 
00946       if (pendingOnly && !pollOnce)
00947          return;
00948 
00949       // check synchronous signals
00950       if (fSigcnt > 0 && fSignalHandler->GetSize() > 0)
00951          if (CheckSignals(kTRUE))
00952             if (!pendingOnly) return;
00953       fSigcnt = 0;
00954       fSignals->Zero();
00955 
00956       // check synchronous timers
00957       Long_t nextto;
00958       if (fTimers && fTimers->GetSize() > 0)
00959          if (DispatchTimers(kTRUE)) {
00960             // prevent timers from blocking file descriptor monitoring
00961             nextto = NextTimeOut(kTRUE);
00962             if (nextto > kItimerResolution || nextto == -1)
00963                return;
00964          }
00965 
00966       // if in pendingOnly mode poll once file descriptor activity
00967       nextto = NextTimeOut(kTRUE);
00968       if (pendingOnly) {
00969          if (fFileHandler && fFileHandler->GetSize() == 0)
00970             return;
00971          nextto = 0;
00972          pollOnce = kFALSE;
00973       }
00974 
00975       // nothing ready, so setup select call
00976       *fReadready  = *fReadmask;
00977       *fWriteready = *fWritemask;
00978 
00979       int mxfd = TMath::Max(fMaxrfd, fMaxwfd);
00980       mxfd++;
00981 
00982       // if nothing to select (socket or timer) return
00983       if (mxfd == 0 && nextto == -1)
00984          return;
00985 
00986       fNfd = UnixSelect(mxfd, fReadready, fWriteready, nextto);
00987       if (fNfd < 0 && fNfd != -2) {
00988          int fd, rc;
00989          TFdSet t;
00990          for (fd = 0; fd < mxfd; fd++) {
00991             t.Set(fd);
00992             if (fReadmask->IsSet(fd)) {
00993                rc = UnixSelect(fd+1, &t, 0, 0);
00994                if (rc < 0 && rc != -2) {
00995                   SysError("DispatchOneEvent", "select: read error on %d\n", fd);
00996                   fReadmask->Clr(fd);
00997                }
00998             }
00999             if (fWritemask->IsSet(fd)) {
01000                rc = UnixSelect(fd+1, 0, &t, 0);
01001                if (rc < 0 && rc != -2) {
01002                   SysError("DispatchOneEvent", "select: write error on %d\n", fd);
01003                   fWritemask->Clr(fd);
01004                }
01005             }
01006             t.Clr(fd);
01007          }
01008       }
01009    }
01010 }
01011 
01012 //______________________________________________________________________________
01013 void TUnixSystem::Sleep(UInt_t milliSec)
01014 {
01015    // Sleep milliSec milliseconds.
01016 
01017    struct timeval tv;
01018 
01019    tv.tv_sec  = milliSec / 1000;
01020    tv.tv_usec = (milliSec % 1000) * 1000;
01021 
01022    select(0, 0, 0, 0, &tv);
01023 }
01024 
01025 //______________________________________________________________________________
01026 Int_t TUnixSystem::Select(TList *act, Long_t to)
01027 {
01028    // Select on file descriptors. The timeout to is in millisec. Returns
01029    // the number of ready descriptors, or 0 in case of timeout, or < 0 in
01030    // case of an error, with -2 being EINTR and -3 EBADF. In case of EINTR
01031    // the errno has been reset and the method can be called again. Returns
01032    // -4 in case the list did not contain any file handlers or file handlers
01033    // with file descriptor >= 0.
01034 
01035    Int_t rc = -4;
01036 
01037    TFdSet rd, wr;
01038    Int_t mxfd = -1;
01039    TIter next(act);
01040    TFileHandler *h = 0;
01041    while ((h = (TFileHandler *) next())) {
01042       Int_t fd = h->GetFd();
01043       if (fd > -1) {
01044          if (h->HasReadInterest()) {
01045             rd.Set(fd);
01046             mxfd = TMath::Max(mxfd, fd);
01047          }
01048          if (h->HasWriteInterest()) {
01049             wr.Set(fd);
01050             mxfd = TMath::Max(mxfd, fd);
01051          }
01052          h->ResetReadyMask();
01053       }
01054    }
01055    if (mxfd > -1)
01056       rc = UnixSelect(mxfd+1, &rd, &wr, to);
01057 
01058    // Set readiness bits
01059    if (rc > 0) {
01060       next.Reset();
01061       while ((h = (TFileHandler *) next())) {
01062          Int_t fd = h->GetFd();
01063          if (rd.IsSet(fd))
01064             h->SetReadReady();
01065          if (wr.IsSet(fd))
01066             h->SetWriteReady();
01067       }
01068    }
01069 
01070    return rc;
01071 }
01072 
01073 //______________________________________________________________________________
01074 Int_t TUnixSystem::Select(TFileHandler *h, Long_t to)
01075 {
01076    // Select on the file descriptor related to file handler h.
01077    // The timeout to is in millisec. Returns the number of ready descriptors,
01078    // or 0 in case of timeout, or < 0 in case of an error, with -2 being EINTR
01079    // and -3 EBADF. In case of EINTR the errno has been reset and the method
01080    // can be called again. Returns -4 in case the file handler is 0 or does
01081    // not have a file descriptor >= 0.
01082 
01083    Int_t rc = -4;
01084 
01085    TFdSet rd, wr;
01086    Int_t mxfd = -1;
01087    Int_t fd = -1;
01088    if (h) {
01089       fd = h->GetFd();
01090       if (fd > -1) {
01091          if (h->HasReadInterest())
01092             rd.Set(fd);
01093          if (h->HasWriteInterest())
01094             wr.Set(fd);
01095          h->ResetReadyMask();
01096          mxfd = fd;
01097          rc = UnixSelect(mxfd+1, &rd, &wr, to);
01098       }
01099    }
01100 
01101    // Fill output lists, if required
01102    if (rc > 0) {
01103       if (rd.IsSet(fd))
01104          h->SetReadReady();
01105       if (wr.IsSet(fd))
01106          h->SetWriteReady();
01107    }
01108 
01109    return rc;
01110 }
01111 
01112 //---- handling of system events -----------------------------------------------
01113 
01114 //______________________________________________________________________________
01115 void TUnixSystem::DispatchSignals(ESignals sig)
01116 {
01117    // Handle and dispatch signals.
01118 
01119    switch (sig) {
01120    case kSigAlarm:
01121       DispatchTimers(kFALSE);
01122       break;
01123    case kSigChild:
01124       CheckChilds();
01125       break;
01126    case kSigBus:
01127    case kSigSegmentationViolation:
01128    case kSigIllegalInstruction:
01129    case kSigFloatingException:
01130       Break("TUnixSystem::DispatchSignals", "%s", UnixSigname(sig));
01131       StackTrace();
01132       if (gApplication)
01133          gApplication->HandleException(sig);
01134       else
01135          Exit(sig);
01136       break;
01137    case kSigSystem:
01138    case kSigPipe:
01139       Break("TUnixSystem::DispatchSignals", "%s", UnixSigname(sig));
01140       break;
01141    case kSigWindowChanged:
01142       Gl_windowchanged();
01143       break;
01144    default:
01145       fSignals->Set(sig);
01146       fSigcnt++;
01147       break;
01148    }
01149 
01150    // check a-synchronous signals
01151    if (fSigcnt > 0 && fSignalHandler->GetSize() > 0)
01152       CheckSignals(kFALSE);
01153 }
01154 
01155 //______________________________________________________________________________
01156 Bool_t TUnixSystem::CheckSignals(Bool_t sync)
01157 {
01158    // Check if some signals were raised and call their Notify() member.
01159 
01160    TSignalHandler *sh;
01161    Int_t sigdone = -1;
01162    {
01163       TOrdCollectionIter it((TOrdCollection*)fSignalHandler);
01164 
01165       while ((sh = (TSignalHandler*)it.Next())) {
01166          if (sync == sh->IsSync()) {
01167             ESignals sig = sh->GetSignal();
01168             if ((fSignals->IsSet(sig) && sigdone == -1) || sigdone == sig) {
01169                if (sigdone == -1) {
01170                   fSignals->Clr(sig);
01171                   sigdone = sig;
01172                   fSigcnt--;
01173                }
01174                if (sh->IsActive())
01175                   sh->Notify();
01176             }
01177          }
01178       }
01179    }
01180    if (sigdone != -1)
01181       return kTRUE;
01182 
01183    return kFALSE;
01184 }
01185 
01186 //______________________________________________________________________________
01187 void TUnixSystem::CheckChilds()
01188 {
01189    // Check if childs have finished.
01190 
01191 #if 0  //rdm
01192    int pid;
01193    while ((pid = UnixWaitchild()) > 0) {
01194       TIter next(zombieHandler);
01195       register UnixPtty *pty;
01196       while ((pty = (UnixPtty*) next()))
01197          if (pty->GetPid() == pid) {
01198             zombieHandler->RemovePtr(pty);
01199             pty->DiedNotify();
01200          }
01201    }
01202 #endif
01203 }
01204 
01205 //______________________________________________________________________________
01206 Bool_t TUnixSystem::CheckDescriptors()
01207 {
01208    // Check if there is activity on some file descriptors and call their
01209    // Notify() member.
01210 
01211    TFileHandler *fh;
01212    Int_t  fddone = -1;
01213    Bool_t read   = kFALSE;
01214 #if defined(R__LINUX) && defined(__alpha__)
01215    // TOrdCollectionIter it(...) causes segv ?!?!? Also TIter fails.
01216    Int_t cursor = 0;
01217    while (cursor < fFileHandler->GetSize()) {
01218       fh = (TFileHandler*) fFileHandler->At(cursor++);
01219 #else
01220    TOrdCollectionIter it((TOrdCollection*)fFileHandler);
01221    while ((fh = (TFileHandler*) it.Next())) {
01222 #endif
01223       Int_t fd = fh->GetFd();
01224       if ((fd <= fMaxrfd && fReadready->IsSet(fd) && fddone == -1) ||
01225           (fddone == fd && read)) {
01226          if (fddone == -1) {
01227             fReadready->Clr(fd);
01228             fddone = fd;
01229             read = kTRUE;
01230             fNfd--;
01231          }
01232          if (fh->IsActive())
01233             fh->ReadNotify();
01234       }
01235       if ((fd <= fMaxwfd && fWriteready->IsSet(fd) && fddone == -1) ||
01236           (fddone == fd && !read)) {
01237          if (fddone == -1) {
01238             fWriteready->Clr(fd);
01239             fddone = fd;
01240             read = kFALSE;
01241             fNfd--;
01242          }
01243          if (fh->IsActive())
01244             fh->WriteNotify();
01245       }
01246    }
01247    if (fddone != -1)
01248       return kTRUE;
01249 
01250    return kFALSE;
01251 }
01252 
01253 //---- Directories -------------------------------------------------------------
01254 
01255 //______________________________________________________________________________
01256 int TUnixSystem::MakeDirectory(const char *name)
01257 {
01258    // Make a Unix file system directory. Returns 0 in case of success and
01259    // -1 if the directory could not be created.
01260 
01261    TSystem *helper = FindHelper(name);
01262    if (helper)
01263       return helper->MakeDirectory(name);
01264 
01265    return UnixMakedir(name);
01266 }
01267 
01268 //______________________________________________________________________________
01269 void *TUnixSystem::OpenDirectory(const char *name)
01270 {
01271    // Open a Unix file system directory. Returns 0 if directory does not exist.
01272 
01273    TSystem *helper = FindHelper(name);
01274    if (helper)
01275       return helper->OpenDirectory(name);
01276 
01277    return UnixOpendir(name);
01278 }
01279 
01280 //______________________________________________________________________________
01281 void TUnixSystem::FreeDirectory(void *dirp)
01282 {
01283    // Close a Unix file system directory.
01284 
01285    TSystem *helper = FindHelper(0, dirp);
01286    if (helper) {
01287       helper->FreeDirectory(dirp);
01288       return;
01289    }
01290 
01291    if (dirp)
01292       ::closedir((DIR*)dirp);
01293 }
01294 
01295 //______________________________________________________________________________
01296 const char *TUnixSystem::GetDirEntry(void *dirp)
01297 {
01298    // Get next Unix file system directory entry. Returns 0 if no more entries.
01299 
01300    TSystem *helper = FindHelper(0, dirp);
01301    if (helper)
01302       return helper->GetDirEntry(dirp);
01303 
01304    if (dirp)
01305       return UnixGetdirentry(dirp);
01306 
01307    return 0;
01308 }
01309 
01310 //______________________________________________________________________________
01311 Bool_t TUnixSystem::ChangeDirectory(const char *path)
01312 {
01313    // Change directory. Returns kTRUE in case of success, kFALSE otherwise.
01314 
01315    Bool_t ret = (Bool_t) (::chdir(path) == 0);
01316    if (fWdpath != "")
01317       fWdpath = "";   // invalidate path cache
01318    return ret;
01319 }
01320 
01321 //______________________________________________________________________________
01322 const char *TUnixSystem::WorkingDirectory()
01323 {
01324    // Return working directory.
01325 
01326    if (fWdpath != "")
01327       return fWdpath.Data();
01328 
01329    R__LOCKGUARD2(gSystemMutex);
01330 
01331    static char cwd[kMAXPATHLEN];
01332    if (::getcwd(cwd, kMAXPATHLEN) == 0) {
01333       fWdpath = "/";
01334       Error("WorkingDirectory", "getcwd() failed");
01335    }
01336    fWdpath = cwd;
01337    return fWdpath.Data();
01338 }
01339 
01340 //______________________________________________________________________________
01341 const char *TUnixSystem::HomeDirectory(const char *userName)
01342 {
01343    // Return the user's home directory.
01344 
01345    return UnixHomedirectory(userName);
01346 }
01347 
01348 //______________________________________________________________________________
01349 const char *TUnixSystem::TempDirectory() const
01350 {
01351    // Return a user configured or systemwide directory to create
01352    // temporary files in.
01353 
01354    const char *dir =  gSystem->Getenv("TMPDIR");
01355    if (!dir || gSystem->AccessPathName(dir, kWritePermission))
01356       dir = "/tmp";
01357 
01358    return dir;
01359 }
01360 
01361 //______________________________________________________________________________
01362 FILE *TUnixSystem::TempFileName(TString &base, const char *dir)
01363 {
01364    // Create a secure temporary file by appending a unique
01365    // 6 letter string to base. The file will be created in
01366    // a standard (system) directory or in the directory
01367    // provided in dir. The full filename is returned in base
01368    // and a filepointer is returned for safely writing to the file
01369    // (this avoids certain security problems). Returns 0 in case
01370    // of error.
01371 
01372    char *b = ConcatFileName(dir ? dir : TempDirectory(), base);
01373    base = b;
01374    base += "XXXXXX";
01375    delete [] b;
01376 
01377    char *arg = StrDup(base);
01378    int fd = mkstemp(arg);
01379    base = arg;
01380    delete [] arg;
01381 
01382    if (fd == -1) {
01383       SysError("TempFileName", "%s", base.Data());
01384       return 0;
01385    } else {
01386       FILE *fp = fdopen(fd, "w+");
01387       if (fp == 0)
01388          SysError("TempFileName", "converting filedescriptor (%d)", fd);
01389       return fp;
01390    }
01391 }
01392 
01393 //______________________________________________________________________________
01394 const char *TUnixSystem::PrependPathName(const char *dir, TString& name)
01395 {
01396    // Concatenate a directory and a file name.
01397 
01398    if (name.IsNull() || name == ".") {
01399       if (dir) {
01400          name = dir;
01401          if (dir[strlen(dir) - 1] != '/')
01402             name += '/';
01403       } else name = "";
01404       return name.Data();
01405    }
01406 
01407    if (!dir || !dir[0]) dir = "/";
01408    else if (dir[strlen(dir) - 1] != '/')
01409       name.Prepend('/');
01410    name.Prepend(dir);
01411 
01412    return name.Data();
01413 }
01414 
01415 //---- Paths & Files -----------------------------------------------------------
01416 
01417 //______________________________________________________________________________
01418 Bool_t TUnixSystem::AccessPathName(const char *path, EAccessMode mode)
01419 {
01420    // Returns FALSE if one can access a file using the specified access mode.
01421    // Mode is the same as for the Unix access(2) function.
01422    // Attention, bizarre convention of return value!!
01423 
01424    TSystem *helper = FindHelper(path);
01425    if (helper)
01426       return helper->AccessPathName(path, mode);
01427 
01428    if (::access(StripOffProto(path, "file:"), mode) == 0)
01429       return kFALSE;
01430    fLastErrorString = GetError();
01431    return kTRUE;
01432 }
01433 
01434 //______________________________________________________________________________
01435 int TUnixSystem::CopyFile(const char *f, const char *t, Bool_t overwrite)
01436 {
01437    // Copy a file. If overwrite is true and file already exists the
01438    // file will be overwritten. Returns 0 when successful, -1 in case
01439    // of file open failure, -2 in case the file already exists and overwrite
01440    // was false and -3 in case of error during copy.
01441 
01442    if (!AccessPathName(t) && !overwrite)
01443       return -2;
01444 
01445    FILE *from = fopen(f, "r");
01446    if (!from)
01447       return -1;
01448 
01449    FILE *to   = fopen(t, "w");
01450    if (!to) {
01451       fclose(from);
01452       return -1;
01453    }
01454 
01455    const int bufsize = 1024;
01456    char buf[bufsize];
01457    int ret = 0;
01458    while (!ret && !feof(from)) {
01459       size_t numread    = fread (buf, sizeof(char), bufsize, from);
01460       size_t numwritten = fwrite(buf, sizeof(char), numread, to);
01461       if (numread != numwritten)
01462          ret = -3;
01463    }
01464 
01465    fclose(from);
01466    fclose(to);
01467 
01468    return ret;
01469 }
01470 
01471 //______________________________________________________________________________
01472 int TUnixSystem::Rename(const char *f, const char *t)
01473 {
01474    // Rename a file. Returns 0 when successful, -1 in case of failure.
01475 
01476    int ret = ::rename(f, t);
01477    fLastErrorString = GetError();
01478    return ret;
01479 }
01480 
01481 //______________________________________________________________________________
01482 Bool_t TUnixSystem::IsPathLocal(const char *path)
01483 {
01484    // Returns TRUE if the url in 'path' points to the local file system.
01485    // This is used to avoid going through the NIC card for local operations.
01486 
01487    TSystem *helper = FindHelper(path);
01488    if (helper)
01489       return helper->IsPathLocal(path);
01490 
01491    return TSystem::IsPathLocal(path);
01492 }
01493 
01494 //______________________________________________________________________________
01495 int TUnixSystem::GetPathInfo(const char *path, FileStat_t &buf)
01496 {
01497    // Get info about a file. Info is returned in the form of a FileStat_t
01498    // structure (see TSystem.h).
01499    // The function returns 0 in case of success and 1 if the file could
01500    // not be stat'ed.
01501 
01502    TSystem *helper = FindHelper(path);
01503    if (helper)
01504       return helper->GetPathInfo(path, buf);
01505 
01506    return UnixFilestat(path, buf);
01507 }
01508 
01509 //______________________________________________________________________________
01510 int TUnixSystem::GetFsInfo(const char *path, Long_t *id, Long_t *bsize,
01511                            Long_t *blocks, Long_t *bfree)
01512 {
01513    // Get info about a file system: id, bsize, bfree, blocks.
01514    // Id      is file system type (machine dependend, see statfs())
01515    // Bsize   is block size of file system
01516    // Blocks  is total number of blocks in file system
01517    // Bfree   is number of free blocks in file system
01518    // The function returns 0 in case of success and 1 if the file system could
01519    // not be stat'ed.
01520 
01521    return UnixFSstat(path, id, bsize, blocks, bfree);
01522 }
01523 
01524 //______________________________________________________________________________
01525 int TUnixSystem::Link(const char *from, const char *to)
01526 {
01527    // Create a link from file1 to file2. Returns 0 when successful,
01528    // -1 in case of failure.
01529 
01530    return ::link(from, to);
01531 }
01532 
01533 //______________________________________________________________________________
01534 int TUnixSystem::Symlink(const char *from, const char *to)
01535 {
01536    // Create a symlink from file1 to file2. Returns 0 when succesfull,
01537    // -1 in case of failure.
01538 
01539 #if defined(R__AIX)
01540    return ::symlink((char*)from, (char*)to);
01541 #else
01542    return ::symlink(from, to);
01543 #endif
01544 }
01545 
01546 //______________________________________________________________________________
01547 int TUnixSystem::Unlink(const char *name)
01548 {
01549    // Unlink, i.e. remove, a file or directory. Returns 0 when succesfull,
01550    // -1 in case of failure.
01551 
01552    TSystem *helper = FindHelper(name);
01553    if (helper)
01554       return helper->Unlink(name);
01555 
01556 #if defined(R__SEEK64)
01557    struct stat64 finfo;
01558    if (lstat64(name, &finfo) < 0)
01559 #else
01560    struct stat finfo;
01561    if (lstat(name, &finfo) < 0)
01562 #endif
01563       return -1;
01564 
01565    if (S_ISDIR(finfo.st_mode))
01566       return ::rmdir(name);
01567    else
01568       return ::unlink(name);
01569 }
01570 
01571 //---- expand the metacharacters as in the shell -------------------------------
01572 
01573 // expand the metacharacters as in the shell
01574 
01575 const char
01576 #ifdef G__OLDEXPAND
01577    kShellEscape     = '\\',
01578    *kShellStuff     = "(){}<>\"'",
01579 #endif
01580    *kShellMeta      = "~*[]{}?$";
01581 
01582 
01583 #ifndef G__OLDEXPAND
01584 //______________________________________________________________________________
01585 Bool_t TUnixSystem::ExpandPathName(TString &path)
01586 {
01587    // Expand a pathname getting rid of special shell characters like ~.$, etc.
01588    // For Unix/Win32 compatibility use $(XXX) instead of $XXX when using
01589    // environment variables in a pathname. If compatibility is not an issue
01590    // you can use on Unix directly $XXX. Returns kFALSE in case of success
01591    // or kTRUE in case of error.
01592 
01593    const char *p, *patbuf = (const char *)path;
01594 
01595    // skip leading blanks
01596    while (*patbuf == ' ')
01597       patbuf++;
01598 
01599    // any shell meta characters ?
01600    for (p = patbuf; *p; p++)
01601       if (strchr(kShellMeta, *p))
01602          goto expand;
01603 
01604    return kFALSE;
01605 
01606 expand:
01607    // replace $(XXX) by $XXX
01608    path.ReplaceAll("$(","$");
01609    path.ReplaceAll(")","");
01610 
01611    if ((p = ExpandFileName(path))) {
01612       path = p;
01613       return kFALSE;
01614    }
01615    return kTRUE;
01616 }
01617 #endif
01618 
01619 #ifdef G__OLDEXPAND
01620 //______________________________________________________________________________
01621 Bool_t TUnixSystem::ExpandPathName(TString &patbuf0)
01622 {
01623    // Expand a pathname getting rid of special shell characters like ~.$, etc.
01624    // For Unix/Win32 compatibility use $(XXX) instead of $XXX when using
01625    // environment variables in a pathname. If compatibility is not an issue
01626    // you can use on Unix directly $XXX. Returns kFALSE in case of success
01627    // or kTRUE in case of error.
01628 
01629    const char *patbuf = (const char *)patbuf0;
01630    const char *hd, *p;
01631    //   char   cmd[kMAXPATHLEN],
01632    char stuffedPat[kMAXPATHLEN], name[70];
01633    char  *q;
01634    FILE  *pf;
01635    int    ch;
01636 
01637    // skip leading blanks
01638    while (*patbuf == ' ')
01639       patbuf++;
01640 
01641    // any shell meta characters ?
01642    for (p = patbuf; *p; p++)
01643       if (strchr(kShellMeta, *p))
01644          goto needshell;
01645 
01646    return kFALSE;
01647 
01648 needshell:
01649    // replace $(XXX) by $XXX
01650    patbuf0.ReplaceAll("$(","$");
01651    patbuf0.ReplaceAll(")","");
01652 
01653    // escape shell quote characters
01654    EscChar(patbuf, stuffedPat, sizeof(stuffedPat), (char*)kShellStuff, kShellEscape);
01655 
01656 #ifdef R__HPUX
01657    TString cmd("/bin/echo ");
01658 #else
01659    TString cmd("echo ");
01660 #endif
01661 
01662    // emulate csh -> popen executes sh
01663    if (stuffedPat[0] == '~') {
01664       if (stuffedPat[1] != '\0' && stuffedPat[1] != '/') {
01665          // extract user name
01666          for (p = &stuffedPat[1], q = name; *p && *p !='/';)
01667             *q++ = *p++;
01668          *q = '\0';
01669          hd = UnixHomedirectory(name);
01670          if (hd == 0)
01671             cmd += stuffedPat;
01672          else {
01673             cmd += hd;
01674             cmd += p;
01675          }
01676       } else {
01677          hd = UnixHomedirectory(0);
01678          if (hd == 0) {
01679             fLastErrorString = GetError();
01680             return kTRUE;
01681          }
01682          cmd += hd;
01683          cmd += &stuffedPat[1];
01684       }
01685    } else
01686       cmd += stuffedPat;
01687 
01688    if ((pf = ::popen(cmd.Data(), "r")) == 0) {
01689       fLastErrorString = GetError();
01690       return kTRUE;
01691    }
01692 
01693    // read first argument
01694    patbuf0 = "";
01695    int cnt = 0;
01696 #if defined(R__ALPHA) || defined(R__AIX)
01697 again:
01698 #endif
01699    for (ch = fgetc(pf); ch != EOF && ch != ' ' && ch != '\n'; ch = fgetc(pf)) {
01700       patbuf0.Append(ch);
01701       cnt++;
01702    }
01703 #if defined(R__ALPHA) || defined(R__AIX)
01704    // Work around bug timing problem due to delay in forking a large program
01705    if (cnt == 0 && ch == EOF) goto again;
01706 #endif
01707 
01708    // skip rest of pipe
01709    while (ch != EOF) {
01710       ch = fgetc(pf);
01711       if (ch == ' ' || ch == '\t') {
01712          fLastErrorString = "expression ambigous";
01713          ::pclose(pf);
01714          return kTRUE;
01715       }
01716    }
01717 
01718    ::pclose(pf);
01719 
01720    return kFALSE;
01721 }
01722 #endif
01723 
01724 //______________________________________________________________________________
01725 char *TUnixSystem::ExpandPathName(const char *path)
01726 {
01727    // Expand a pathname getting rid of special shell characaters like ~.$, etc.
01728    // For Unix/Win32 compatibility use $(XXX) instead of $XXX when using
01729    // environment variables in a pathname. If compatibility is not an issue
01730    // you can use on Unix directly $XXX. The user must delete returned string.
01731    // Returns the expanded pathname or 0 in case of error.
01732 
01733    TString patbuf = path;
01734    if (ExpandPathName(patbuf))
01735       return 0;
01736    return StrDup(patbuf.Data());
01737 }
01738 
01739 //______________________________________________________________________________
01740 int TUnixSystem::Chmod(const char *file, UInt_t mode)
01741 {
01742    // Set the file permission bits. Returns -1 in case or error, 0 otherwise.
01743 
01744    return ::chmod(file, mode);
01745 }
01746 
01747 //______________________________________________________________________________
01748 int TUnixSystem::Umask(Int_t mask)
01749 {
01750    // Set the process file creation mode mask.
01751 
01752    return ::umask(mask);
01753 }
01754 
01755 //______________________________________________________________________________
01756 int TUnixSystem::Utime(const char *file, Long_t modtime, Long_t actime)
01757 {
01758    // Set a files modification and access times. If actime = 0 it will be
01759    // set to the modtime. Returns 0 on success and -1 in case of error.
01760 
01761    if (!actime)
01762       actime = modtime;
01763 
01764    struct utimbuf t;
01765    t.actime  = (time_t)actime;
01766    t.modtime = (time_t)modtime;
01767    return ::utime(file, &t);
01768 }
01769 
01770 //______________________________________________________________________________
01771 const char *TUnixSystem::FindFile(const char *search, TString& wfil, EAccessMode mode)
01772 {
01773    // Find location of file "wfil" in a search path.
01774    // The search path is specified as a : separated list of directories.
01775    // Return value is pointing to wfile for compatibility with
01776    // Which(const char*,const char*,EAccessMode) version.
01777 
01778    TString show;
01779    if (gEnv->GetValue("Root.ShowPath", 0))
01780       show.Form("Which: %s =", wfil.Data());
01781 
01782    gSystem->ExpandPathName(wfil);
01783 
01784    if (wfil[0] == '/') {
01785 #if defined(R__SEEK64)
01786       struct stat64 finfo;
01787       if (access(wfil.Data(), mode) == 0 &&
01788           stat64(wfil.Data(), &finfo) == 0 && S_ISREG(finfo.st_mode)) {
01789 #else
01790       struct stat finfo;
01791       if (access(wfil.Data(), mode) == 0 &&
01792           stat(wfil.Data(), &finfo) == 0 && S_ISREG(finfo.st_mode)) {
01793 #endif
01794          if (show != "")
01795             Printf("%s %s", show.Data(), wfil.Data());
01796          return wfil.Data();
01797       }
01798       if (show != "")
01799          Printf("%s <not found>", show.Data());
01800       wfil = "";
01801       return 0;
01802    }
01803 
01804    if (search == 0)
01805       search = ".";
01806 
01807    TString apwd(gSystem->WorkingDirectory());
01808    apwd += "/";
01809    for (const char* ptr = search; *ptr;) {
01810       TString name;
01811       if (*ptr != '/' && *ptr !='$' && *ptr != '~')
01812          name = apwd;
01813       const char* posEndOfPart = strchr(ptr, ':');
01814       if (posEndOfPart) {
01815          name.Append(ptr, posEndOfPart - ptr);
01816          ptr = posEndOfPart + 1; // skip ':'
01817       } else {
01818          name.Append(ptr);
01819          ptr += strlen(ptr);
01820       }
01821 
01822       if (!name.EndsWith("/"))
01823          name += '/';
01824       name += wfil;
01825 
01826       gSystem->ExpandPathName(name);
01827 #if defined(R__SEEK64)
01828       struct stat64 finfo;
01829       if (access(name.Data(), mode) == 0 &&
01830           stat64(name.Data(), &finfo) == 0 && S_ISREG(finfo.st_mode)) {
01831 #else
01832       struct stat finfo;
01833       if (access(name.Data(), mode) == 0 &&
01834           stat(name.Data(), &finfo) == 0 && S_ISREG(finfo.st_mode)) {
01835 #endif
01836          if (show != "")
01837             Printf("%s %s", show.Data(), name.Data());
01838          wfil = name;
01839          return wfil.Data();
01840       }
01841    }
01842 
01843    if (show != "")
01844       Printf("%s <not found>", show.Data());
01845    wfil = "";
01846    return 0;
01847 }
01848 
01849 //---- Users & Groups ----------------------------------------------------------
01850 
01851 //______________________________________________________________________________
01852 Int_t TUnixSystem::GetUid(const char *user)
01853 {
01854    // Returns the user's id. If user = 0, returns current user's id.
01855 
01856    if (!user || !user[0])
01857       return getuid();
01858    else {
01859       struct passwd *apwd = getpwnam(user);
01860       if (apwd)
01861          return apwd->pw_uid;
01862    }
01863    return 0;
01864 }
01865 
01866 //______________________________________________________________________________
01867 Int_t TUnixSystem::GetEffectiveUid()
01868 {
01869    // Returns the effective user id. The effective id corresponds to the
01870    // set id bit on the file being executed.
01871 
01872    return geteuid();
01873 }
01874 
01875 //______________________________________________________________________________
01876 Int_t TUnixSystem::GetGid(const char *group)
01877 {
01878    // Returns the group's id. If group = 0, returns current user's group.
01879 
01880    if (!group || !group[0])
01881       return getgid();
01882    else {
01883       struct group *grp = getgrnam(group);
01884       if (grp)
01885          return grp->gr_gid;
01886    }
01887    return 0;
01888 }
01889 
01890 //______________________________________________________________________________
01891 Int_t TUnixSystem::GetEffectiveGid()
01892 {
01893    // Returns the effective group id. The effective group id corresponds
01894    // to the set id bit on the file being executed.
01895 
01896    return getegid();
01897 }
01898 
01899 //______________________________________________________________________________
01900 UserGroup_t *TUnixSystem::GetUserInfo(Int_t uid)
01901 {
01902    // Returns all user info in the UserGroup_t structure. The returned
01903    // structure must be deleted by the user. In case of error 0 is returned.
01904 
01905    typedef std::map<Int_t /*uid*/, UserGroup_t> UserInfoCache_t;
01906    static UserInfoCache_t gUserInfo;
01907 
01908    UserInfoCache_t::const_iterator iUserInfo = gUserInfo.find(uid);
01909    if (iUserInfo != gUserInfo.end())
01910       return new UserGroup_t(iUserInfo->second);
01911 
01912    struct passwd *apwd = getpwuid(uid);
01913    if (apwd) {
01914       UserGroup_t *ug = new UserGroup_t;
01915       ug->fUid      = apwd->pw_uid;
01916       ug->fGid      = apwd->pw_gid;
01917       ug->fUser     = apwd->pw_name;
01918       ug->fPasswd   = apwd->pw_passwd;
01919       ug->fRealName = apwd->pw_gecos;
01920       ug->fShell    = apwd->pw_shell;
01921       UserGroup_t *gr = GetGroupInfo(apwd->pw_gid);
01922       if (gr) ug->fGroup = gr->fGroup;
01923       delete gr;
01924 
01925       gUserInfo[uid] = *ug;
01926       return ug;
01927    }
01928    return 0;
01929 }
01930 
01931 //______________________________________________________________________________
01932 UserGroup_t *TUnixSystem::GetUserInfo(const char *user)
01933 {
01934    // Returns all user info in the UserGroup_t structure. If user = 0, returns
01935    // current user's id info. The returned structure must be deleted by the
01936    // user. In case of error 0 is returned.
01937 
01938    return GetUserInfo(GetUid(user));
01939 }
01940 
01941 //______________________________________________________________________________
01942 UserGroup_t *TUnixSystem::GetGroupInfo(Int_t gid)
01943 {
01944    // Returns all group info in the UserGroup_t structure. The only active
01945    // fields in the UserGroup_t structure for this call are:
01946    //    fGid and fGroup
01947    // The returned structure must be deleted by the user. In case of
01948    // error 0 is returned.
01949 
01950    struct group *grp = getgrgid(gid);
01951    if (grp) {
01952       UserGroup_t *gr = new UserGroup_t;
01953       gr->fUid   = 0;
01954       gr->fGid   = grp->gr_gid;
01955       gr->fGroup = grp->gr_name;
01956       return gr;
01957    }
01958    return 0;
01959 }
01960 
01961 //______________________________________________________________________________
01962 UserGroup_t *TUnixSystem::GetGroupInfo(const char *group)
01963 {
01964    // Returns all group info in the UserGroup_t structure. The only active
01965    // fields in the UserGroup_t structure for this call are:
01966    //    fGid and fGroup
01967    // If group = 0, returns current user's group. The returned structure
01968    // must be deleted by the user. In case of error 0 is returned.
01969 
01970    return GetGroupInfo(GetGid(group));
01971 }
01972 
01973 //---- environment manipulation ------------------------------------------------
01974 
01975 //______________________________________________________________________________
01976 void TUnixSystem::Setenv(const char *name, const char *value)
01977 {
01978    // Set environment variable. The string passed will be owned by
01979    // the environment and can not be reused till a "name" is set
01980    // again. The solution below will lose the space for the string
01981    // in that case, but if this functions is not called thousands
01982    // of times that should not be a problem.
01983 
01984    char *s = new char [strlen(name)+strlen(value) + 2];
01985    sprintf(s, "%s=%s", name, value);
01986 
01987    ::putenv(s);
01988 }
01989 
01990 //______________________________________________________________________________
01991 const char *TUnixSystem::Getenv(const char *name)
01992 {
01993    // Get environment variable.
01994 
01995    return ::getenv(name);
01996 }
01997 
01998 //---- Processes ---------------------------------------------------------------
01999 
02000 //______________________________________________________________________________
02001 int TUnixSystem::Exec(const char *shellcmd)
02002 {
02003    // Execute a command.
02004 
02005    return ::system(shellcmd);
02006 }
02007 
02008 //______________________________________________________________________________
02009 FILE *TUnixSystem::OpenPipe(const char *command, const char *mode)
02010 {
02011    // Open a pipe.
02012 
02013    return ::popen(command, mode);
02014 }
02015 
02016 //______________________________________________________________________________
02017 int TUnixSystem::ClosePipe(FILE *pipe)
02018 {
02019    // Close the pipe.
02020 
02021    return ::pclose(pipe);
02022 }
02023 
02024 //______________________________________________________________________________
02025 int TUnixSystem::GetPid()
02026 {
02027    // Get process id.
02028 
02029    return ::getpid();
02030 }
02031 
02032 //______________________________________________________________________________
02033 void TUnixSystem::Exit(int code, Bool_t mode)
02034 {
02035    // Exit the application.
02036 
02037    // Insures that the files and sockets are closed before any library is unloaded!
02038    if (gROOT) {
02039       if (gROOT->GetListOfFiles()) gROOT->GetListOfFiles()->Delete("slow");
02040       if (gROOT->GetListOfSockets()) gROOT->GetListOfSockets()->Delete();
02041       if (gROOT->GetListOfMappedFiles()) gROOT->GetListOfMappedFiles()->Delete("slow");
02042    }
02043 
02044    if (mode)
02045       ::exit(code);
02046    else
02047       ::_exit(code);
02048 }
02049 
02050 //______________________________________________________________________________
02051 void TUnixSystem::Abort(int)
02052 {
02053    // Abort the application.
02054 
02055    ::abort();
02056 }
02057 
02058 //______________________________________________________________________________
02059 void TUnixSystem::StackTrace()
02060 {
02061    // Print a stack trace.
02062 
02063    if (!gEnv->GetValue("Root.Stacktrace", 1))
02064       return;
02065 
02066 #if defined(R__MACOSX) && (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)
02067    if (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR) {
02068       fprintf(stderr, "Info in <TUnixSystem::StackTrace> function not supported on iOS\n");
02069       return;
02070    }
02071 #endif
02072 
02073    TString gdbscript = gEnv->GetValue("Root.StacktraceScript", "");
02074    gdbscript = gdbscript.Strip();
02075    if (gdbscript != "") {
02076       if (AccessPathName(gdbscript, kReadPermission)) {
02077          fprintf(stderr, "Root.StacktraceScript %s does not exist\n", gdbscript.Data());
02078          gdbscript = "";
02079       } else {
02080          gdbscript += " ";
02081       }
02082    }
02083    if (gdbscript == "") {
02084 #ifdef ROOTETCDIR
02085       gdbscript.Form("%s/gdb-backtrace.sh", ROOTETCDIR);
02086 #else
02087       gdbscript.Form("%s/etc/gdb-backtrace.sh", gSystem->Getenv("ROOTSYS"));
02088 #endif
02089       if (AccessPathName(gdbscript, kReadPermission)) {
02090          fprintf(stderr, "Error in <TUnixSystem::StackTrace> script %s is missing\n", gdbscript.Data());
02091          return;
02092       }
02093       gdbscript += " ";
02094    }
02095 
02096    TString gdbmess = gEnv->GetValue("Root.StacktraceMessage", "");
02097    gdbmess = gdbmess.Strip();
02098 
02099    cout.flush();
02100    fflush(stdout);
02101 
02102    cerr.flush();
02103    fflush(stderr);
02104 
02105    int fd = STDERR_FILENO;
02106 
02107    const char *message = " Generating stack trace...\n";
02108 
02109    if (fd && message) { }  // remove unused warning (remove later)
02110 
02111    if (gApplication && !strcmp(gApplication->GetName(), "TRint"))
02112       Getlinem(kCleanUp, 0);
02113 
02114 #if defined(USE_GDB_STACK_TRACE)
02115    char *gdb = Which(Getenv("PATH"), "gdb", kExecutePermission);
02116    if (!gdb) {
02117       fprintf(stderr, "gdb not found, need it for stack trace\n");
02118       return;
02119    }
02120 
02121    // write custom message file
02122    TString gdbmessf = "gdb-message";
02123    if (gdbmess != "") {
02124       FILE *f = TempFileName(gdbmessf);
02125       fprintf(f, "%s\n", gdbmess.Data());
02126       fclose(f);
02127    }
02128 
02129    // use gdb to get stack trace
02130    gdbscript += GetExePath();
02131    gdbscript += " ";
02132    gdbscript += GetPid();
02133    if (gdbmess != "") {
02134       gdbscript += " ";
02135       gdbscript += gdbmessf;
02136    }
02137    gdbscript += " 1>&2";
02138    Exec(gdbscript);
02139    delete [] gdb;
02140    return;
02141 
02142 #elif defined(HAVE_U_STACK_TRACE) || defined(HAVE_XL_TRBK)   // hp-ux, aix
02143 /*
02144    // FIXME: deal with inability to duplicate the file handle
02145    int stderrfd = dup(STDERR_FILENO);
02146    if (stderrfd == -1)
02147       return;
02148 
02149    int newfd = dup2(fd, STDERR_FILENO);
02150    if (newfd == -1) {
02151       close (stderrfd);
02152       return;
02153    }
02154 */
02155 # if defined(HAVE_U_STACK_TRACE)                      // hp-ux
02156    U_STACK_TRACE();
02157 # elif defined(HAVE_XL_TRBK)                          // aix
02158    xl__trbk();
02159 # endif
02160 /*
02161    fflush(stderr);
02162    dup2(stderrfd, STDERR_FILENO);
02163    close(newfd);
02164 */
02165 #elif defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_DLADDR)  // linux
02166    // we could have used backtrace_symbols_fd, except its output
02167    // format is pretty bad, so recode that here :-(
02168 
02169    // take care of demangling
02170    Bool_t demangle = kTRUE;
02171 
02172    // check for c++filt
02173    const char *cppfilt = "c++filt";
02174    const char *cppfiltarg = "";
02175 #ifdef R__B64
02176    const char *format1 = " 0x%016lx in %.200s %s 0x%lx from %.200s\n";
02177    const char *format2 = " 0x%016lx in %.200s at %.200s from %.200s\n";
02178    const char *format3 = " 0x%016lx in %.200s from %.200s\n";
02179    const char *format4 = " 0x%016lx in <unknown function>\n";
02180 #else
02181    const char *format1 = " 0x%08lx in %.200s %s 0x%lx from %.200s\n";
02182    const char *format2 = " 0x%08lx in %.200s at %.200s from %.200s\n";
02183    const char *format3 = " 0x%08lx in %.200s from %.200s\n";
02184    const char *format4 = " 0x%08lx in <unknown function>\n";
02185 #endif
02186 
02187    char *filter = Which(Getenv("PATH"), cppfilt, kExecutePermission);
02188    if (!filter)
02189       demangle = kFALSE;
02190 
02191 #if (__GNUC__ >= 3)
02192    // try finding supported format option for g++ v3
02193    if (filter) {
02194       FILE *p = OpenPipe(TString::Format("%s --help 2>&1", filter), "r");
02195       TString help;
02196       while (help.Gets(p)) {
02197          if (help.Index("gnu-v3") != kNPOS) {
02198             cppfiltarg = "--format=gnu-v3";
02199             break;
02200          } else if (help.Index("gnu-new-abi") != kNPOS) {
02201             cppfiltarg = "--format=gnu-new-abi";
02202             break;
02203          }
02204       }
02205       ClosePipe(p);
02206    }
02207 #endif
02208    // gdb-backtrace.sh uses gdb to produce a backtrace. See if it is available.
02209    // If it is, use it. If not proceed as before.
02210    char *gdb = Which(Getenv("PATH"), "gdb", kExecutePermission);
02211    if (gdb) {
02212       // write custom message file
02213       TString gdbmessf = "gdb-message";
02214       if (gdbmess != "") {
02215          FILE *f = TempFileName(gdbmessf);
02216          fprintf(f, "%s\n", gdbmess.Data());
02217          fclose(f);
02218       }
02219 
02220       // use gdb to get stack trace
02221       gdbscript += GetPid();
02222       if (gdbmess != "") {
02223          gdbscript += " ";
02224          gdbscript += gdbmessf;
02225       }
02226       gdbscript += " 1>&2";
02227       Exec(gdbscript);
02228       delete [] gdb;
02229    } else {
02230       // addr2line uses debug info to convert addresses into file names
02231       // and line numbers
02232       char *addr2line = Which(Getenv("PATH"), "addr2line", kExecutePermission);
02233       if (addr2line) {
02234          // might take some time so tell what we are doing...
02235          if (write(fd, message, strlen(message)) < 0)
02236             Warning("StackTrace", "problems writing line numbers (errno: %d)", TSystem::GetErrno());
02237       }
02238 
02239       // open tmp file for demangled stack trace
02240       TString tmpf1 = "gdb-backtrace";
02241       ofstream file1;
02242       if (demangle) {
02243          FILE *f = TempFileName(tmpf1);
02244          if (f) fclose(f);
02245          file1.open(tmpf1);
02246          if (!file1) {
02247             Error("StackTrace", "could not open file %s", tmpf1.Data());
02248             Unlink(tmpf1);
02249             demangle = kFALSE;
02250          }
02251       }
02252 
02253       char buffer[4096];
02254       void *trace[kMAX_BACKTRACE_DEPTH];
02255       int  depth = backtrace(trace, kMAX_BACKTRACE_DEPTH);
02256       for (int n = 5; n < depth; n++) {
02257          ULong_t addr = (ULong_t) trace[n];
02258          Dl_info info;
02259 
02260          if (dladdr(trace[n], &info) && info.dli_fname && info.dli_fname[0]) {
02261             const char *libname = info.dli_fname;
02262             const char *symname = (info.dli_sname && info.dli_sname[0]) ?
02263                                    info.dli_sname : "<unknown>";
02264             ULong_t libaddr = (ULong_t) info.dli_fbase;
02265             ULong_t symaddr = (ULong_t) info.dli_saddr;
02266             Bool_t  gte = (addr >= symaddr);
02267             ULong_t diff = (gte) ? addr - symaddr : symaddr - addr;
02268             if (addr2line && symaddr) {
02269                ULong_t offset = (addr >= libaddr) ? addr - libaddr :
02270                                                     libaddr - addr;
02271                TString name   = TString(libname);
02272                Bool_t noPath  = kFALSE;
02273                Bool_t noShare = kTRUE;
02274                if (name[0] != '/') noPath = kTRUE;
02275                if (name.Contains(".so") || name.Contains(".sl")) noShare = kFALSE;
02276                if (noShare) offset = addr;
02277                if (noPath)  name = "`which " + name + "`";
02278                snprintf(buffer, sizeof(buffer), "%s -e %s 0x%016lx", addr2line, name.Data(), offset);
02279                Bool_t nodebug = kTRUE;
02280                if (FILE *pf = ::popen(buffer, "r")) {
02281                   char buf[2048];
02282                   if (fgets(buf, 2048, pf)) {
02283                      buf[strlen(buf)-1] = 0;  // remove trailing \n
02284                      if (strncmp(buf, "??", 2)) {
02285                         snprintf(buffer, sizeof(buffer), format2, addr, symname, buf, libname);
02286                         nodebug = kFALSE;
02287                      }
02288                   }
02289                   ::pclose(pf);
02290                }
02291                if (nodebug)
02292                   snprintf(buffer, sizeof(buffer), format1, addr, symname,
02293                            gte ? "+" : "-", diff, libname);
02294             } else {
02295                if (symaddr)
02296                   snprintf(buffer, sizeof(buffer), format1, addr, symname,
02297                            gte ? "+" : "-", diff, libname);
02298                else
02299                   snprintf(buffer, sizeof(buffer), format3, addr, symname, libname);
02300             }
02301          } else {
02302             snprintf(buffer, sizeof(buffer), format4, addr);
02303          }
02304 
02305          if (demangle)
02306             file1 << buffer;
02307          else
02308             if (write(fd, buffer, ::strlen(buffer)) < 0)
02309                Warning("StackTrace", "problems writing buffer (errno: %d)", TSystem::GetErrno());
02310       }
02311 
02312       if (demangle) {
02313          TString tmpf2 = "gdb-backtrace";
02314          FILE *f = TempFileName(tmpf2);
02315          if (f) fclose(f);
02316          file1.close();
02317          snprintf(buffer, sizeof(buffer), "%s %s < %s > %s", filter, cppfiltarg, tmpf1.Data(), tmpf2.Data());
02318          Exec(buffer);
02319          ifstream file2(tmpf2);
02320          TString line;
02321          while (file2) {
02322             line = "";
02323             line.ReadString(file2);
02324             if (write(fd, line.Data(), line.Length()) < 0)
02325                Warning("StackTrace", "problems writing line (errno: %d)", TSystem::GetErrno());
02326          }
02327          file2.close();
02328          Unlink(tmpf1);
02329          Unlink(tmpf2);
02330       }
02331 
02332       delete [] addr2line;
02333       delete [] filter;
02334    }
02335 #elif defined(PROG_PSTACK)                            // solaris
02336 # ifdef PROG_CXXFILT
02337 #  define CXXFILTER " | " PROG_CXXFILT
02338 # else
02339 #  define CXXFILTER
02340 # endif
02341    // 64 should more than plenty for a space and a pid.
02342    char buffer[sizeof(PROG_PSTACK) + 64 + 3 + sizeof(PROG_CXXFILT) + 64];
02343    sprintf(buffer, "%s %lu%s 1>&%d", PROG_PSTACK, (ULong_t) getpid(),
02344            "" CXXFILTER, fd);
02345    buffer[sizeof (buffer)-1] = 0;
02346    Exec(buffer);
02347 # undef CXXFILTER
02348 
02349 #elif defined(HAVE_EXCPT_H) && defined(HAVE_PDSC_H) && \
02350                                defined(HAVE_RLD_INTERFACE_H) // tru64
02351    // Tru64 stack walk.  Uses the exception handling library and the
02352    // run-time linker's core functions (loader(5)).  FIXME: Tru64
02353    // should have _RLD_DLADDR like IRIX below.  Verify and update.
02354 
02355    char         buffer [128];
02356    sigcontext   context;
02357    int          rc = 0;
02358 
02359    exc_capture_context (&context);
02360    while (!rc && context.sc_pc) {
02361       // FIXME: Elf32?
02362       pdsc_crd *func, *base, *crd
02363          = exc_remote_lookup_function_entry(0, 0, context.sc_pc, 0, &func, &base);
02364       Elf32_Addr addr = PDSC_CRD_BEGIN_ADDRESS(base, func);
02365       // const char *name = _rld_address_to_name(addr);
02366       const char *name = "<unknown function>";
02367       sprintf(buffer, " 0x%012lx %.200s + 0x%lx\n",
02368               context.sc_pc, name, context.sc_pc - addr);
02369       write(fd, buffer, ::strlen(buffer));
02370       rc = exc_virtual_unwind(0, &context);
02371    }
02372 
02373 #elif defined(HAVE_EXCEPTION_H) && defined(__sgi)     // irix
02374    // IRIX stack walk -- like Tru64 but with a little different names.
02375    // NB: The guard above is to protect against unrelated <exception.h>
02376    //   provided by some compilers (e.g. KCC 4.0f).
02377    // NB: libexc.h has trace_back_stack and trace_back_stack_and_print
02378    //   but their output isn't pretty and nowhere as complete as ours.
02379    char       buffer [340];
02380    sigcontext context;
02381 
02382    exc_setjmp(&context);
02383    while (context.sc_pc >= 4) {
02384       // Do two lookups, one using exception handling tables and
02385       // another using _RLD_DLADDR, and use the one with a smaller
02386       // offset.  For signal handlers we seem to get things wrong:
02387       // _sigtramp's exception range is huge while based on Dl_info
02388       // the offset is small -- but both supposedly describe the
02389       // same thing.  Go figure.
02390       char            *name = 0;
02391       const char      *libname = 0;
02392       const char      *symname = 0;
02393       Elf32_Addr      offset = ~0L;
02394 
02395       // Do the exception/dwarf lookup
02396       Elf32_Addr      pc = context.sc_pc;
02397       Dwarf_Fde       fde = find_fde_name(&pc, &name);
02398       Dwarf_Addr      low_pc = context.sc_pc;
02399       Dwarf_Unsigned  udummy;
02400       Dwarf_Signed    sdummy;
02401       Dwarf_Ptr       pdummy;
02402       Dwarf_Off       odummy;
02403       Dwarf_Error     err;
02404 
02405       symname = name;
02406 
02407       // Determine offset using exception descriptor range information.
02408       if (dwarf_get_fde_range(fde, &low_pc, &udummy, &pdummy, &udummy,
02409                               &odummy, &sdummy, &odummy, &err) == DW_DLV_OK)
02410          offset = context.sc_pc - low_pc;
02411 
02412       // Now do a dladdr() lookup.  If the found symbol has the same
02413       // address, trust the more accurate offset from dladdr();
02414       // ignore the looked up mangled symbol name and prefer the
02415       // demangled name produced by find_fde_name().  If we find a
02416       // smaller offset, trust the dynamic symbol as well.  Always
02417       // trust the library name even if we can't match it with an
02418       // exact symbol.
02419       Elf32_Addr      addr = context.sc_pc;
02420       Dl_info         info;
02421 
02422       if (_rld_new_interface (_RLD_DLADDR, addr, &info)) {
02423          if (info.dli_fname && info.dli_fname [0])
02424             libname = info.dli_fname;
02425 
02426          Elf32_Addr symaddr = (Elf32_Addr) info.dli_saddr;
02427          if (symaddr == low_pc)
02428             offset = addr - symaddr;
02429          else if (info.dli_sname
02430                   && info.dli_sname [0]
02431                   && addr - symaddr < offset) {
02432             offset = addr - symaddr;
02433             symname = info.dli_sname;
02434          }
02435       }
02436 
02437       // Print out the result
02438       if (libname && symname)
02439          write(fd, buffer, sprintf
02440                (buffer, " 0x%012lx %.200s + 0x%lx [%.200s]\n",
02441                addr, symname, offset, libname));
02442       else if (symname)
02443          write(fd, buffer, sprintf
02444                (buffer, " 0x%012lx %.200s + 0x%lx\n",
02445                addr, symname, offset));
02446       else
02447          write(fd, buffer, sprintf
02448                (buffer, " 0x%012lx <unknown function>\n", addr));
02449 
02450       // Free name from find_fde_name().
02451       free(name);
02452 
02453       // Check for termination.  exc_unwind() sets context.sc_pc to
02454       // 0 or an error (< 4).  However it seems we can't unwind
02455       // through signal stack frames though this is not mentioned in
02456       // the docs; it seems that for those we need to check for
02457       // changed pc after find_fde_name().  That seems to indicate
02458       // end of the post-signal stack frame.  (FIXME: Figure out how
02459       // to unwind through signal stack frame, e.g. perhaps using
02460       // sigcontext_t's old pc?  Or perhaps we can keep on going
02461       // down without doing the symbol lookup?)
02462       if (pc != context.sc_pc)
02463          break;
02464 
02465       exc_unwind(&context, fde);
02466    }
02467 #endif
02468 }
02469 
02470 //---- System Logging ----------------------------------------------------------
02471 
02472 //______________________________________________________________________________
02473 void TUnixSystem::Openlog(const char *name, Int_t options, ELogFacility facility)
02474 {
02475    // Open connection to system log daemon. For the use of the options and
02476    // facility see the Unix openlog man page.
02477 
02478    int fac = 0;
02479 
02480    switch (facility) {
02481       case kLogLocal0:
02482          fac = LOG_LOCAL0;
02483          break;
02484       case kLogLocal1:
02485          fac = LOG_LOCAL1;
02486          break;
02487       case kLogLocal2:
02488          fac = LOG_LOCAL2;
02489          break;
02490       case kLogLocal3:
02491          fac = LOG_LOCAL3;
02492          break;
02493       case kLogLocal4:
02494          fac = LOG_LOCAL4;
02495          break;
02496       case kLogLocal5:
02497          fac = LOG_LOCAL5;
02498          break;
02499       case kLogLocal6:
02500          fac = LOG_LOCAL6;
02501          break;
02502       case kLogLocal7:
02503          fac = LOG_LOCAL7;
02504          break;
02505    }
02506 
02507    ::openlog(name, options, fac);
02508 }
02509 
02510 //______________________________________________________________________________
02511 void TUnixSystem::Syslog(ELogLevel level, const char *mess)
02512 {
02513    // Send mess to syslog daemon. Level is the logging level and mess the
02514    // message that will be written on the log.
02515 
02516    // ELogLevel matches exactly the Unix values.
02517    ::syslog(level, "%s", mess);
02518 }
02519 
02520 //______________________________________________________________________________
02521 void TUnixSystem::Closelog()
02522 {
02523    // Close connection to system log daemon.
02524 
02525    ::closelog();
02526 }
02527 
02528 //---- Standard output redirection ---------------------------------------------
02529 
02530 //______________________________________________________________________________
02531 Int_t TUnixSystem::RedirectOutput(const char *file, const char *mode,
02532                                   RedirectHandle_t *h)
02533 {
02534    // Redirect standard output (stdout, stderr) to the specified file.
02535    // If the file argument is 0 the output is set again to stderr, stdout.
02536    // The second argument specifies whether the output should be added to the
02537    // file ("a", default) or the file be truncated before ("w").
02538    // This function saves internally the current state into a static structure.
02539    // The call can be made reentrant by specifying the opaque structure pointed
02540    // by 'h', which is filled with the relevant information. The handle 'h'
02541    // obtained on the first call must then be used in any subsequent call,
02542    // included ShowOutput, to display the redirected output.
02543    // Returns 0 on success, -1 in case of error.
02544 
02545    // Instance to be used if the caller does not passes 'h'
02546    static RedirectHandle_t loch;
02547 
02548    Int_t rc = 0;
02549 
02550    // Which handle to use ?
02551    RedirectHandle_t *xh = (h) ? h : &loch;
02552 
02553    if (file) {
02554       // Save the paths
02555       Bool_t outdone = kFALSE;
02556       if (xh->fStdOutTty.IsNull()) {
02557          const char *tty = ttyname(STDOUT_FILENO);
02558          if (tty) {
02559             xh->fStdOutTty = tty;
02560          } else {
02561             if ((xh->fStdOutDup = dup(STDOUT_FILENO)) < 0) {
02562                SysError("RedirectOutput", "could not 'dup' stdout (errno: %d)", TSystem::GetErrno());
02563                return -1;
02564             }
02565             outdone = kTRUE;
02566          }
02567       }
02568       if (xh->fStdErrTty.IsNull()) {
02569          const char *tty = ttyname(STDERR_FILENO);
02570          if (tty) {
02571             xh->fStdErrTty = tty;
02572          } else {
02573             if ((xh->fStdErrDup = dup(STDERR_FILENO)) < 0) {
02574                SysError("RedirectOutput", "could not 'dup' stderr (errno: %d)", TSystem::GetErrno());
02575                if (outdone && dup2(xh->fStdOutDup, STDOUT_FILENO) < 0) {
02576                   Warning("RedirectOutput", "could not restore stdout (back to original redirected"
02577                           " file) (errno: %d)", TSystem::GetErrno());
02578                }
02579                return -1;
02580             }
02581          }
02582       }
02583 
02584       // Make sure mode makes sense; default "a"
02585       const char *m = (mode[0] == 'a' || mode[0] == 'w') ? mode : "a";
02586 
02587       // Current file size
02588       xh->fReadOffSet = 0;
02589       if (m[0] == 'a') {
02590          // If the file exists, save the current size
02591          FileStat_t st;
02592          if (!gSystem->GetPathInfo(file, st))
02593             xh->fReadOffSet = (st.fSize > 0) ? st.fSize : xh->fReadOffSet;
02594       }
02595       xh->fFile = file;
02596 
02597       // Redirect stdout & stderr
02598       if (freopen(file, m, stdout) == 0) {
02599          SysError("RedirectOutput", "could not freopen stdout (errno: %d)", TSystem::GetErrno());
02600          return -1;
02601       }
02602       if (freopen(file, m, stderr) == 0) {
02603          SysError("RedirectOutput", "could not freopen stderr (errno: %d)", TSystem::GetErrno());
02604          if (freopen(xh->fStdOutTty.Data(), "a", stdout) == 0)
02605             SysError("RedirectOutput", "could not restore stdout (errno: %d)", TSystem::GetErrno());
02606          return -1;
02607       }
02608    } else {
02609       // Restore stdout & stderr
02610       fflush(stdout);
02611       if (!(xh->fStdOutTty.IsNull())) {
02612          if (freopen(xh->fStdOutTty.Data(), "a", stdout) == 0) {
02613             SysError("RedirectOutput", "could not restore stdout (errno: %d)", TSystem::GetErrno());
02614             rc = -1;
02615          }
02616          xh->fStdOutTty = "";
02617       } else {
02618          if (dup2(xh->fStdOutDup, STDOUT_FILENO) < 0) {
02619             SysError("RedirectOutput", "could not restore stdout (back to original redirected"
02620                      " file) (errno: %d)", TSystem::GetErrno());
02621             rc = -1;
02622          }
02623       }
02624       fflush(stderr);
02625       if (!(xh->fStdErrTty.IsNull())) {
02626          if (freopen(xh->fStdErrTty.Data(), "a", stderr) == 0) {
02627             SysError("RedirectOutput", "could not restore stderr (errno: %d)", TSystem::GetErrno());
02628             rc = -1;
02629          }
02630          xh->fStdErrTty = "";
02631       } else {
02632          if (dup2(xh->fStdErrDup, STDERR_FILENO) < 0) {
02633             SysError("RedirectOutput", "could not restore stderr (back to original redirected"
02634                      " file) (errno: %d)", TSystem::GetErrno());
02635             rc = -1;
02636          }
02637       }
02638       // Reset the static instance, if using that
02639       if (xh == &loch)
02640          xh->Reset();
02641    }
02642    return rc;
02643 }
02644 
02645 //---- dynamic loading and linking ---------------------------------------------
02646 
02647 //______________________________________________________________________________
02648 Func_t TUnixSystem::DynFindSymbol(const char *module, const char *entry)
02649 {
02650    //dynamic linking of module
02651    #ifdef NOCINT
02652    return UnixDynFindSymbol(module,entry);
02653 #else
02654    if (module) { }   // silence compiler about not using module
02655    return TSystem::DynFindSymbol("*", entry);
02656 #endif
02657 }
02658 
02659 //______________________________________________________________________________
02660 int TUnixSystem::Load(const char *module, const char *entry, Bool_t system)
02661 {
02662    // Load a shared library. Returns 0 on successful loading, 1 in
02663    // case lib was already loaded and -1 in case lib does not exist
02664    // or in case of error.
02665 
02666 #ifdef NOCINT
02667    int i = UnixDynLoad(module);
02668    if (!entry || !strlen(entry)) return i;
02669 
02670    Func_t f = UnixDynFindSymbol(module, entry);
02671    if (f) return 0;
02672    return -1;
02673 #else
02674    return TSystem::Load(module, entry, system);
02675 #endif
02676 }
02677 
02678 //______________________________________________________________________________
02679 void TUnixSystem::Unload(const char *module)
02680 {
02681    // Unload a shared library.
02682 
02683 #ifdef NOCINT
02684    UnixDynUnload(module);
02685 #else
02686    if (module) { TSystem::Unload(module); }
02687 #endif
02688 }
02689 
02690 //______________________________________________________________________________
02691 void TUnixSystem::ListSymbols(const char *module, const char *regexp)
02692 {
02693    // List symbols in a shared library.
02694 
02695    UnixDynListSymbols(module, regexp);
02696 }
02697 
02698 //______________________________________________________________________________
02699 void TUnixSystem::ListLibraries(const char *regexp)
02700 {
02701    // List all loaded shared libraries.
02702 
02703 #ifdef R__HPUX
02704    UnixDynListLibs(regexp);
02705 #else
02706    TSystem::ListLibraries(regexp);
02707 #endif
02708 }
02709 
02710 //______________________________________________________________________________
02711 const char *TUnixSystem::GetLinkedLibraries()
02712 {
02713    // Get list of shared libraries loaded at the start of the executable.
02714    // Returns 0 in case list cannot be obtained or in case of error.
02715 
02716 #if !defined(R__MACOSX)
02717    if (!gApplication) return 0;
02718 #endif
02719 
02720    static Bool_t once = kFALSE;
02721    static TString linkedLibs;
02722 
02723    R__LOCKGUARD2(gSystemMutex);
02724 
02725    if (!linkedLibs.IsNull())
02726       return linkedLibs;
02727 
02728    if (once)
02729       return 0;
02730 
02731 #if !defined(R__MACOSX)
02732    char *exe = gSystem->Which(Getenv("PATH"), gApplication->Argv(0),
02733                               kExecutePermission);
02734    if (!exe) {
02735       once = kTRUE;
02736       return 0;
02737    }
02738 #endif
02739 
02740 #if defined(R__MACOSX)
02741    char *exe = 0;
02742    DylibAdded(0, 0);
02743    linkedLibs = gLinkedDylibs;
02744 #if 0
02745    FILE *p = OpenPipe(TString::Format("otool -L %s", exe), "r");
02746    TString otool;
02747    while (otool.Gets(p)) {
02748       TString delim(" \t");
02749       TObjArray *tok = otool.Tokenize(delim);
02750       TString dylib = ((TObjString*)tok->At(0))->String();
02751       if (dylib.EndsWith(".dylib") && !dylib.Contains("/libSystem.B.dylib")) {
02752          if (!linkedLibs.IsNull())
02753             linkedLibs += " ";
02754          linkedLibs += dylib;
02755       }
02756       delete tok;
02757    }
02758    if (p) {
02759       ClosePipe(p);
02760    }
02761 #endif
02762 #elif defined(R__LINUX) || defined(R__SOLARIS)
02763 #if defined(R__WINGCC )
02764    const char *cLDD="cygcheck";
02765    const char *cSOEXT=".dll";
02766    size_t lenexe = strlen(exe);
02767    if (strcmp(exe + lenexe - 4, ".exe")
02768        && strcmp(exe + lenexe - 4, ".dll")) {
02769       // it's not a dll and exe doesn't end on ".exe";
02770       // need to add it for cygcheck to find it:
02771       char* longerexe = new char[lenexe + 5];
02772       strlcpy(longerexe, exe,lenexe+5);
02773       strlcat(longerexe, ".exe",lenexe+5);
02774       delete [] exe;
02775       exe = longerexe;
02776    }
02777 #else
02778    const char *cLDD="ldd";
02779    const char *cSOEXT=".so";
02780 #endif
02781    FILE *p = OpenPipe(TString::Format("%s %s", cLDD, exe), "r");
02782    TString ldd;
02783    while (ldd.Gets(p)) {
02784       TString delim(" \t");
02785       TObjArray *tok = ldd.Tokenize(delim);
02786 
02787       // expected format:
02788       //    libCore.so => /home/rdm/root/lib/libCore.so (0x40017000)
02789       TObjString *solibName = (TObjString*)tok->At(2);
02790       if (!solibName) {
02791          // case where there is only one name of the list:
02792          //    /usr/platform/SUNW,UltraAX-i2/lib/libc_psr.so.1
02793          solibName = (TObjString*)tok->At(0);
02794       }
02795       if (solibName) {
02796          TString solib = solibName->String();
02797          if (solib.EndsWith(cSOEXT)) {
02798             if (!linkedLibs.IsNull())
02799                linkedLibs += " ";
02800             linkedLibs += solib;
02801          }
02802       }
02803       delete tok;
02804    }
02805    ClosePipe(p);
02806 #endif
02807 
02808    delete [] exe;
02809 
02810    once = kTRUE;
02811 
02812    if (linkedLibs.IsNull())
02813       return 0;
02814 
02815    return linkedLibs;
02816 }
02817 
02818 //---- Time & Date -------------------------------------------------------------
02819 
02820 //______________________________________________________________________________
02821 TTime TUnixSystem::Now()
02822 {
02823    // Get current time in milliseconds since 0:00 Jan 1 1995.
02824 
02825    return UnixNow();
02826 }
02827 
02828 //______________________________________________________________________________
02829 Bool_t TUnixSystem::DispatchTimers(Bool_t mode)
02830 {
02831    // Handle and dispatch timers. If mode = kTRUE dispatch synchronous
02832    // timers else a-synchronous timers.
02833 
02834    if (!fTimers) return kFALSE;
02835 
02836    fInsideNotify = kTRUE;
02837 
02838    TOrdCollectionIter it((TOrdCollection*)fTimers);
02839    TTimer *t;
02840    Bool_t  timedout = kFALSE;
02841 
02842    while ((t = (TTimer *) it.Next())) {
02843       // NB: the timer resolution is added in TTimer::CheckTimer()
02844       Long64_t now = UnixNow();
02845       if (mode && t->IsSync()) {
02846          if (t->CheckTimer(now))
02847             timedout = kTRUE;
02848       } else if (!mode && t->IsAsync()) {
02849          if (t->CheckTimer(now)) {
02850             UnixSetitimer(NextTimeOut(kFALSE));
02851             timedout = kTRUE;
02852          }
02853       }
02854    }
02855    fInsideNotify = kFALSE;
02856    return timedout;
02857 }
02858 
02859 //______________________________________________________________________________
02860 void TUnixSystem::AddTimer(TTimer *ti)
02861 {
02862    // Add timer to list of system timers.
02863 
02864    TSystem::AddTimer(ti);
02865    ResetTimer(ti);
02866 }
02867 
02868 //______________________________________________________________________________
02869 TTimer *TUnixSystem::RemoveTimer(TTimer *ti)
02870 {
02871    // Remove timer from list of system timers.
02872 
02873    if (!ti) return 0;
02874 
02875    R__LOCKGUARD2(gSystemMutex);
02876 
02877    TTimer *t = TSystem::RemoveTimer(ti);
02878    if (ti->IsAsync())
02879       UnixSetitimer(NextTimeOut(kFALSE));
02880    return t;
02881 }
02882 
02883 //______________________________________________________________________________
02884 void TUnixSystem::ResetTimer(TTimer *ti)
02885 {
02886    // Reset a-sync timer.
02887 
02888    if (!fInsideNotify && ti && ti->IsAsync())
02889       UnixSetitimer(NextTimeOut(kFALSE));
02890 }
02891 
02892 //---- RPC ---------------------------------------------------------------------
02893 
02894 //______________________________________________________________________________
02895 TInetAddress TUnixSystem::GetHostByName(const char *hostname)
02896 {
02897    // Get Internet Protocol (IP) address of host. Returns an TInetAddress
02898    // object. To see if the hostname lookup was successfull call
02899    // TInetAddress::IsValid().
02900 
02901    struct hostent *host_ptr;
02902    const char     *host;
02903    int             type;
02904    UInt_t          addr;    // good for 4 byte addresses
02905 
02906 #ifdef HASNOT_INETATON
02907    if ((addr = (UInt_t)inet_addr(hostname)) != INADDR_NONE) {
02908 #else
02909    struct in_addr ad;
02910    if (inet_aton(hostname, &ad)) {
02911       memcpy(&addr, &ad.s_addr, sizeof(ad.s_addr));
02912 #endif
02913       type = AF_INET;
02914       if ((host_ptr = gethostbyaddr((const char *)&addr,
02915                                     sizeof(addr), AF_INET))) {
02916          host = host_ptr->h_name;
02917          TInetAddress a(host, ntohl(addr), type);
02918          UInt_t addr2;
02919          Int_t  i;
02920          for (i = 1; host_ptr->h_addr_list[i]; i++) {
02921             memcpy(&addr2, host_ptr->h_addr_list[i], host_ptr->h_length);
02922             a.AddAddress(ntohl(addr2));
02923          }
02924          for (i = 0; host_ptr->h_aliases[i]; i++)
02925             a.AddAlias(host_ptr->h_aliases[i]);
02926          return a;
02927       } else {
02928          host = "UnNamedHost";
02929       }
02930    } else if ((host_ptr = gethostbyname(hostname))) {
02931       // Check the address type for an internet host
02932       if (host_ptr->h_addrtype != AF_INET) {
02933          Error("GetHostByName", "%s is not an internet host\n", hostname);
02934          return TInetAddress();
02935       }
02936       memcpy(&addr, host_ptr->h_addr, host_ptr->h_length);
02937       host = host_ptr->h_name;
02938       type = host_ptr->h_addrtype;
02939       TInetAddress a(host, ntohl(addr), type);
02940       UInt_t addr2;
02941       Int_t  i;
02942       for (i = 1; host_ptr->h_addr_list[i]; i++) {
02943          memcpy(&addr2, host_ptr->h_addr_list[i], host_ptr->h_length);
02944          a.AddAddress(ntohl(addr2));
02945       }
02946       for (i = 0; host_ptr->h_aliases[i]; i++)
02947          a.AddAlias(host_ptr->h_aliases[i]);
02948       return a;
02949    } else {
02950       if (gDebug > 0) Error("GetHostByName", "unknown host %s", hostname);
02951       return TInetAddress(hostname, 0, -1);
02952    }
02953 
02954    return TInetAddress(host, ntohl(addr), type);
02955 }
02956 
02957 //______________________________________________________________________________
02958 TInetAddress TUnixSystem::GetSockName(int sock)
02959 {
02960    // Get Internet Protocol (IP) address of host and port #.
02961 
02962    struct sockaddr_in addr;
02963 #if defined(USE_SIZE_T)
02964    size_t len = sizeof(addr);
02965 #elif defined(USE_SOCKLEN_T)
02966    socklen_t len = sizeof(addr);
02967 #else
02968    int len = sizeof(addr);
02969 #endif
02970 
02971    if (getsockname(sock, (struct sockaddr *)&addr, &len) == -1) {
02972       SysError("GetSockName", "getsockname");
02973       return TInetAddress();
02974    }
02975 
02976    struct hostent *host_ptr;
02977    const char *hostname;
02978    int         family;
02979    UInt_t      iaddr;
02980 
02981    if ((host_ptr = gethostbyaddr((const char *)&addr.sin_addr,
02982                                  sizeof(addr.sin_addr), AF_INET))) {
02983       memcpy(&iaddr, host_ptr->h_addr, host_ptr->h_length);
02984       hostname = host_ptr->h_name;
02985       family   = host_ptr->h_addrtype;
02986    } else {
02987       memcpy(&iaddr, &addr.sin_addr, sizeof(addr.sin_addr));
02988       hostname = "????";
02989       family   = AF_INET;
02990    }
02991 
02992    return TInetAddress(hostname, ntohl(iaddr), family, ntohs(addr.sin_port));
02993 }
02994 
02995 //______________________________________________________________________________
02996 TInetAddress TUnixSystem::GetPeerName(int sock)
02997 {
02998    // Get Internet Protocol (IP) address of remote host and port #.
02999 
03000    struct sockaddr_in addr;
03001 #if defined(USE_SIZE_T)
03002    size_t len = sizeof(addr);
03003 #elif defined(USE_SOCKLEN_T)
03004    socklen_t len = sizeof(addr);
03005 #else
03006    int len = sizeof(addr);
03007 #endif
03008 
03009    if (getpeername(sock, (struct sockaddr *)&addr, &len) == -1) {
03010       SysError("GetPeerName", "getpeername");
03011       return TInetAddress();
03012    }
03013 
03014    struct hostent *host_ptr;
03015    const char *hostname;
03016    int         family;
03017    UInt_t      iaddr;
03018 
03019    if ((host_ptr = gethostbyaddr((const char *)&addr.sin_addr,
03020                                  sizeof(addr.sin_addr), AF_INET))) {
03021       memcpy(&iaddr, host_ptr->h_addr, host_ptr->h_length);
03022       hostname = host_ptr->h_name;
03023       family   = host_ptr->h_addrtype;
03024    } else {
03025       memcpy(&iaddr, &addr.sin_addr, sizeof(addr.sin_addr));
03026       hostname = "????";
03027       family   = AF_INET;
03028    }
03029 
03030    return TInetAddress(hostname, ntohl(iaddr), family, ntohs(addr.sin_port));
03031 }
03032 
03033 //______________________________________________________________________________
03034 int TUnixSystem::GetServiceByName(const char *servicename)
03035 {
03036    // Get port # of internet service.
03037 
03038    struct servent *sp;
03039 
03040    if ((sp = getservbyname(servicename, kProtocolName)) == 0) {
03041       Error("GetServiceByName", "no service \"%s\" with protocol \"%s\"\n",
03042               servicename, kProtocolName);
03043       return -1;
03044    }
03045    return ntohs(sp->s_port);
03046 }
03047 
03048 //______________________________________________________________________________
03049 char *TUnixSystem::GetServiceByPort(int port)
03050 {
03051    // Get name of internet service.
03052 
03053    struct servent *sp;
03054 
03055    if ((sp = getservbyport(htons(port), kProtocolName)) == 0) {
03056       //::Error("GetServiceByPort", "no service \"%d\" with protocol \"%s\"",
03057       //        port, kProtocolName);
03058       return Form("%d", port);
03059    }
03060    return sp->s_name;
03061 }
03062 
03063 //______________________________________________________________________________
03064 int TUnixSystem::ConnectService(const char *servername, int port,
03065                                 int tcpwindowsize)
03066 {
03067    // Connect to service servicename on server servername.
03068 
03069    if (!strcmp(servername, "unix")) {
03070       return UnixUnixConnect(port);
03071    } else if (!gSystem->AccessPathName(servername) || servername[0] == '/') {
03072       return UnixUnixConnect(servername);
03073    }
03074    return UnixTcpConnect(servername, port, tcpwindowsize);
03075 }
03076 
03077 //______________________________________________________________________________
03078 int TUnixSystem::OpenConnection(const char *server, int port, int tcpwindowsize)
03079 {
03080    // Open a connection to a service on a server. Returns -1 in case
03081    // connection cannot be opened.
03082    // Use tcpwindowsize to specify the size of the receive buffer, it has
03083    // to be specified here to make sure the window scale option is set (for
03084    // tcpwindowsize > 65KB and for platforms supporting window scaling).
03085    // Is called via the TSocket constructor.
03086 
03087    return ConnectService(server, port, tcpwindowsize);
03088 }
03089 
03090 //______________________________________________________________________________
03091 int TUnixSystem::AnnounceTcpService(int port, Bool_t reuse, int backlog,
03092                                     int tcpwindowsize)
03093 {
03094    // Announce TCP/IP service.
03095    // Open a socket, bind to it and start listening for TCP/IP connections
03096    // on the port. If reuse is true reuse the address, backlog specifies
03097    // how many sockets can be waiting to be accepted.
03098    // Use tcpwindowsize to specify the size of the receive buffer, it has
03099    // to be specified here to make sure the window scale option is set (for
03100    // tcpwindowsize > 65KB and for platforms supporting window scaling).
03101    // Returns socket fd or -1 if socket() failed, -2 if bind() failed
03102    // or -3 if listen() failed.
03103 
03104    return UnixTcpService(port, reuse, backlog, tcpwindowsize);
03105 }
03106 
03107 //______________________________________________________________________________
03108 int TUnixSystem::AnnounceUnixService(int port, int backlog)
03109 {
03110    // Announce unix domain service on path "kServerPath/<port>"
03111 
03112    return UnixUnixService(port, backlog);
03113 }
03114 
03115 //______________________________________________________________________________
03116 int TUnixSystem::AnnounceUnixService(const char *sockpath, int backlog)
03117 {
03118    // Announce unix domain service on path 'sockpath'
03119 
03120    return UnixUnixService(sockpath, backlog);
03121 }
03122 
03123 //______________________________________________________________________________
03124 int TUnixSystem::AcceptConnection(int sock)
03125 {
03126    // Accept a connection. In case of an error return -1. In case
03127    // non-blocking I/O is enabled and no connections are available
03128    // return -2.
03129 
03130    int soc = -1;
03131 
03132    while ((soc = ::accept(sock, 0, 0)) == -1 && GetErrno() == EINTR)
03133       ResetErrno();
03134 
03135    if (soc == -1) {
03136       if (GetErrno() == EWOULDBLOCK)
03137          return -2;
03138       else {
03139          SysError("AcceptConnection", "accept");
03140          return -1;
03141       }
03142    }
03143 
03144    return soc;
03145 }
03146 
03147 //______________________________________________________________________________
03148 void TUnixSystem::CloseConnection(int sock, Bool_t force)
03149 {
03150    // Close socket.
03151 
03152    if (sock < 0) return;
03153 
03154 #if !defined(R__AIX) || defined(_AIX41) || defined(_AIX43)
03155    if (force)
03156       ::shutdown(sock, 2);   // will also close connection of parent
03157 #endif
03158 
03159    while (::close(sock) == -1 && GetErrno() == EINTR)
03160       ResetErrno();
03161 }
03162 
03163 //______________________________________________________________________________
03164 int TUnixSystem::RecvBuf(int sock, void *buf, int length)
03165 {
03166    // Receive a buffer headed by a length indicator. Lenght is the size of
03167    // the buffer. Returns the number of bytes received in buf or -1 in
03168    // case of error.
03169 
03170    Int_t header;
03171 
03172    if (UnixRecv(sock, &header, sizeof(header), 0) > 0) {
03173       int count = ntohl(header);
03174 
03175       if (count > length) {
03176          Error("RecvBuf", "record header exceeds buffer size");
03177          return -1;
03178       } else if (count > 0) {
03179          if (UnixRecv(sock, buf, count, 0) < 0) {
03180             Error("RecvBuf", "cannot receive buffer");
03181             return -1;
03182          }
03183       }
03184       return count;
03185    }
03186    return -1;
03187 }
03188 
03189 //______________________________________________________________________________
03190 int TUnixSystem::SendBuf(int sock, const void *buf, int length)
03191 {
03192    // Send a buffer headed by a length indicator. Returns length of sent buffer
03193    // or -1 in case of error.
03194 
03195    Int_t header = htonl(length);
03196 
03197    if (UnixSend(sock, &header, sizeof(header), 0) < 0) {
03198       Error("SendBuf", "cannot send header");
03199       return -1;
03200    }
03201    if (length > 0) {
03202       if (UnixSend(sock, buf, length, 0) < 0) {
03203          Error("SendBuf", "cannot send buffer");
03204          return -1;
03205       }
03206    }
03207    return length;
03208 }
03209 
03210 //______________________________________________________________________________
03211 int TUnixSystem::RecvRaw(int sock, void *buf, int length, int opt)
03212 {
03213    // Receive exactly length bytes into buffer. Use opt to receive out-of-band
03214    // data or to have a peek at what is in the buffer (see TSocket). Buffer
03215    // must be able to store at least length bytes. Returns the number of
03216    // bytes received (can be 0 if other side of connection was closed) or -1
03217    // in case of error, -2 in case of MSG_OOB and errno == EWOULDBLOCK, -3
03218    // in case of MSG_OOB and errno == EINVAL and -4 in case of kNoBlock and
03219    // errno == EWOULDBLOCK. Returns -5 if pipe broken or reset by peer
03220    // (EPIPE || ECONNRESET).
03221 
03222    int flag;
03223 
03224    switch (opt) {
03225    case kDefault:
03226       flag = 0;
03227       break;
03228    case kOob:
03229       flag = MSG_OOB;
03230       break;
03231    case kPeek:
03232       flag = MSG_PEEK;
03233       break;
03234    case kDontBlock:
03235       flag = -1;
03236       break;
03237    default:
03238       flag = 0;
03239       break;
03240    }
03241 
03242    int n;
03243    if ((n = UnixRecv(sock, buf, length, flag)) <= 0) {
03244       if (n == -1 && GetErrno() != EINTR)
03245          Error("RecvRaw", "cannot receive buffer");
03246       return n;
03247    }
03248    return n;
03249 }
03250 
03251 //______________________________________________________________________________
03252 int TUnixSystem::SendRaw(int sock, const void *buf, int length, int opt)
03253 {
03254    // Send exactly length bytes from buffer. Use opt to send out-of-band
03255    // data (see TSocket). Returns the number of bytes sent or -1 in case of
03256    // error. Returns -4 in case of kNoBlock and errno == EWOULDBLOCK.
03257    // Returns -5 if pipe broken or reset by peer (EPIPE || ECONNRESET).
03258 
03259    int flag;
03260 
03261    switch (opt) {
03262    case kDefault:
03263       flag = 0;
03264       break;
03265    case kOob:
03266       flag = MSG_OOB;
03267       break;
03268    case kDontBlock:
03269       flag = -1;
03270       break;
03271    case kPeek:            // receive only option (see RecvRaw)
03272    default:
03273       flag = 0;
03274       break;
03275    }
03276 
03277    int n;
03278    if ((n = UnixSend(sock, buf, length, flag)) <= 0) {
03279       if (n == -1 && GetErrno() != EINTR)
03280          Error("SendRaw", "cannot send buffer");
03281       return n;
03282    }
03283    return n;
03284 }
03285 
03286 //______________________________________________________________________________
03287 int TUnixSystem::SetSockOpt(int sock, int opt, int val)
03288 {
03289    // Set socket option.
03290 
03291    if (sock < 0) return -1;
03292 
03293    switch (opt) {
03294    case kSendBuffer:
03295       if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&val, sizeof(val)) == -1) {
03296          SysError("SetSockOpt", "setsockopt(SO_SNDBUF)");
03297          return -1;
03298       }
03299       break;
03300    case kRecvBuffer:
03301       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&val, sizeof(val)) == -1) {
03302          SysError("SetSockOpt", "setsockopt(SO_RCVBUF)");
03303          return -1;
03304       }
03305       break;
03306    case kOobInline:
03307       if (setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (char*)&val, sizeof(val)) == -1) {
03308          SysError("SetSockOpt", "setsockopt(SO_OOBINLINE)");
03309          return -1;
03310       }
03311       break;
03312    case kKeepAlive:
03313       if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&val, sizeof(val)) == -1) {
03314          SysError("SetSockOpt", "setsockopt(SO_KEEPALIVE)");
03315          return -1;
03316       }
03317       break;
03318    case kReuseAddr:
03319       if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val)) == -1) {
03320          SysError("SetSockOpt", "setsockopt(SO_REUSEADDR)");
03321          return -1;
03322       }
03323       break;
03324    case kNoDelay:
03325       if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&val, sizeof(val)) == -1) {
03326          SysError("SetSockOpt", "setsockopt(TCP_NODELAY)");
03327          return -1;
03328       }
03329       break;
03330    case kNoBlock:
03331       if (ioctl(sock, FIONBIO, (char*)&val) == -1) {
03332          SysError("SetSockOpt", "ioctl(FIONBIO)");
03333          return -1;
03334       }
03335       break;
03336    case kProcessGroup:
03337 #ifndef R__WINGCC
03338       if (ioctl(sock, SIOCSPGRP, (char*)&val) == -1) {
03339          SysError("SetSockOpt", "ioctl(SIOCSPGRP)");
03340          return -1;
03341       }
03342 #else
03343       Error("SetSockOpt", "ioctl(SIOCGPGRP) not supported on cygwin/gcc");
03344       return -1;
03345 #endif
03346       break;
03347    case kAtMark:       // read-only option (see GetSockOpt)
03348    case kBytesToRead:  // read-only option
03349    default:
03350       Error("SetSockOpt", "illegal option (%d)", opt);
03351       return -1;
03352    }
03353    return 0;
03354 }
03355 
03356 //______________________________________________________________________________
03357 int TUnixSystem::GetSockOpt(int sock, int opt, int *val)
03358 {
03359    // Get socket option.
03360 
03361    if (sock < 0) return -1;
03362 
03363 #if defined(USE_SOCKLEN_T) || defined(_AIX43)
03364    socklen_t optlen = sizeof(*val);
03365 #elif defined(USE_SIZE_T)
03366    size_t optlen = sizeof(*val);
03367 #else
03368    int optlen = sizeof(*val);
03369 #endif
03370 
03371    switch (opt) {
03372    case kSendBuffer:
03373       if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)val, &optlen) == -1) {
03374          SysError("GetSockOpt", "getsockopt(SO_SNDBUF)");
03375          return -1;
03376       }
03377       break;
03378    case kRecvBuffer:
03379       if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)val, &optlen) == -1) {
03380          SysError("GetSockOpt", "getsockopt(SO_RCVBUF)");
03381          return -1;
03382       }
03383       break;
03384    case kOobInline:
03385       if (getsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (char*)val, &optlen) == -1) {
03386          SysError("GetSockOpt", "getsockopt(SO_OOBINLINE)");
03387          return -1;
03388       }
03389       break;
03390    case kKeepAlive:
03391       if (getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)val, &optlen) == -1) {
03392          SysError("GetSockOpt", "getsockopt(SO_KEEPALIVE)");
03393          return -1;
03394       }
03395       break;
03396    case kReuseAddr:
03397       if (getsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)val, &optlen) == -1) {
03398          SysError("GetSockOpt", "getsockopt(SO_REUSEADDR)");
03399          return -1;
03400       }
03401       break;
03402    case kNoDelay:
03403       if (getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)val, &optlen) == -1) {
03404          SysError("GetSockOpt", "getsockopt(TCP_NODELAY)");
03405          return -1;
03406       }
03407       break;
03408    case kNoBlock:
03409       int flg;
03410       if ((flg = fcntl(sock, F_GETFL, 0)) == -1) {
03411          SysError("GetSockOpt", "fcntl(F_GETFL)");
03412          return -1;
03413       }
03414       *val = flg & O_NDELAY;
03415       break;
03416    case kProcessGroup:
03417 #if !defined(R__LYNXOS) && !defined(R__WINGCC)
03418       if (ioctl(sock, SIOCGPGRP, (char*)val) == -1) {
03419          SysError("GetSockOpt", "ioctl(SIOCGPGRP)");
03420          return -1;
03421       }
03422 #else
03423       Error("GetSockOpt", "ioctl(SIOCGPGRP) not supported on LynxOS and cygwin/gcc");
03424       return -1;
03425 #endif
03426       break;
03427    case kAtMark:
03428 #if !defined(R__LYNXOS)
03429       if (ioctl(sock, SIOCATMARK, (char*)val) == -1) {
03430          SysError("GetSockOpt", "ioctl(SIOCATMARK)");
03431          return -1;
03432       }
03433 #else
03434       Error("GetSockOpt", "ioctl(SIOCATMARK) not supported on LynxOS");
03435       return -1;
03436 #endif
03437       break;
03438    case kBytesToRead:
03439 #if !defined(R__LYNXOS)
03440       if (ioctl(sock, FIONREAD, (char*)val) == -1) {
03441          SysError("GetSockOpt", "ioctl(FIONREAD)");
03442          return -1;
03443       }
03444 #else
03445       Error("GetSockOpt", "ioctl(FIONREAD) not supported on LynxOS");
03446       return -1;
03447 #endif
03448       break;
03449    default:
03450       Error("GetSockOpt", "illegal option (%d)", opt);
03451       *val = 0;
03452       return -1;
03453    }
03454    return 0;
03455 }
03456 
03457 //////////////////////////////////////////////////////////////////////////
03458 //                                                                      //
03459 // Static Protected Unix Interface functions.                           //
03460 //                                                                      //
03461 //////////////////////////////////////////////////////////////////////////
03462 
03463 //---- signals -----------------------------------------------------------------
03464 
03465 static struct Signalmap_t {
03466    int               fCode;
03467    SigHandler_t      fHandler;
03468    struct sigaction *fOldHandler;
03469    const char       *fSigName;
03470 } gSignalMap[kMAXSIGNALS] = {       // the order of the signals should be identical
03471    { SIGBUS,   0, 0, "bus error" }, // to the one in TSysEvtHandler.h
03472    { SIGSEGV,  0, 0, "segmentation violation" },
03473    { SIGSYS,   0, 0, "bad argument to system call" },
03474    { SIGPIPE,  0, 0, "write on a pipe with no one to read it" },
03475    { SIGILL,   0, 0, "illegal instruction" },
03476    { SIGQUIT,  0, 0, "quit" },
03477    { SIGINT,   0, 0, "interrupt" },
03478    { SIGWINCH, 0, 0, "window size change" },
03479    { SIGALRM,  0, 0, "alarm clock" },
03480    { SIGCHLD,  0, 0, "death of a child" },
03481    { SIGURG,   0, 0, "urgent data arrived on an I/O channel" },
03482    { SIGFPE,   0, 0, "floating point exception" },
03483    { SIGTERM,  0, 0, "termination signal" },
03484    { SIGUSR1,  0, 0, "user-defined signal 1" },
03485    { SIGUSR2,  0, 0, "user-defined signal 2" }
03486 };
03487 
03488 
03489 //______________________________________________________________________________
03490 static void sighandler(int sig)
03491 {
03492    // Call the signal handler associated with the signal.
03493 
03494    for (int i= 0; i < kMAXSIGNALS; i++) {
03495       if (gSignalMap[i].fCode == sig) {
03496          (*gSignalMap[i].fHandler)((ESignals)i);
03497          return;
03498       }
03499    }
03500 }
03501 
03502 //______________________________________________________________________________
03503 void TUnixSystem::UnixSignal(ESignals sig, SigHandler_t handler)
03504 {
03505    // Set a signal handler for a signal.
03506 
03507    if (gSignalMap[sig].fHandler != handler) {
03508       struct sigaction sigact;
03509 
03510       gSignalMap[sig].fHandler    = handler;
03511       gSignalMap[sig].fOldHandler = new struct sigaction();
03512 
03513 #if defined(R__SUN)
03514       sigact.sa_handler = (void (*)())sighandler;
03515 #elif defined(R__SOLARIS)
03516       sigact.sa_handler = sighandler;
03517 #elif defined(R__SGI) || defined(R__LYNXOS)
03518 #  if defined(R__SGI64) || (__GNUG__>=3)
03519       sigact.sa_handler = sighandler;
03520 #  else
03521       sigact.sa_handler = (void (*)(...))sighandler;
03522 #  endif
03523 #else
03524       sigact.sa_handler = sighandler;
03525 #endif
03526       sigemptyset(&sigact.sa_mask);
03527       sigact.sa_flags = 0;
03528 #if defined(SA_RESTART)
03529       sigact.sa_flags |= SA_RESTART;
03530 #endif
03531       if (sigaction(gSignalMap[sig].fCode, &sigact,
03532                     gSignalMap[sig].fOldHandler) < 0)
03533          ::SysError("TUnixSystem::UnixSignal", "sigaction");
03534    }
03535 }
03536 
03537 //______________________________________________________________________________
03538 void TUnixSystem::UnixIgnoreSignal(ESignals sig, Bool_t ignore)
03539 {
03540    // If ignore is true ignore the specified signal, else restore previous
03541    // behaviour.
03542 
03543    static Bool_t ignoreSig[kMAXSIGNALS] = { kFALSE };
03544    static struct sigaction oldsigact[kMAXSIGNALS];
03545 
03546    if (ignore != ignoreSig[sig]) {
03547       ignoreSig[sig] = ignore;
03548       if (ignore) {
03549          struct sigaction sigact;
03550 #if defined(R__SUN)
03551          sigact.sa_handler = (void (*)())SIG_IGN;
03552 #elif defined(R__SOLARIS)
03553          sigact.sa_handler = (void (*)(int))SIG_IGN;
03554 #else
03555          sigact.sa_handler = SIG_IGN;
03556 #endif
03557          sigemptyset(&sigact.sa_mask);
03558          sigact.sa_flags = 0;
03559          if (sigaction(gSignalMap[sig].fCode, &sigact, &oldsigact[sig]) < 0)
03560             ::SysError("TUnixSystem::UnixIgnoreSignal", "sigaction");
03561       } else {
03562          if (sigaction(gSignalMap[sig].fCode, &oldsigact[sig], 0) < 0)
03563             ::SysError("TUnixSystem::UnixIgnoreSignal", "sigaction");
03564       }
03565    }
03566 }
03567 
03568 //______________________________________________________________________________
03569 void TUnixSystem::UnixSigAlarmInterruptsSyscalls(Bool_t set)
03570 {
03571    // When the argument is true the SIGALRM signal handler is set so that
03572    // interrupted syscalls will not be restarted by the kernel. This is
03573    // typically used in case one wants to put a timeout on an I/O operation.
03574    // By default interrupted syscalls will always be restarted (for all
03575    // signals). This can be controlled for each a-synchronous TTimer via
03576    // the method TTimer::SetInterruptSyscalls().
03577 
03578    if (gSignalMap[kSigAlarm].fHandler) {
03579       struct sigaction sigact;
03580 #if defined(R__SUN)
03581       sigact.sa_handler = (void (*)())sighandler;
03582 #elif defined(R__SOLARIS)
03583       sigact.sa_handler = sighandler;
03584 #elif defined(R__SGI) || defined(R__LYNXOS)
03585 #  if defined(R__SGI64) || (__GNUG__>=3)
03586       sigact.sa_handler = sighandler;
03587 #  else
03588       sigact.sa_handler = (void (*)(...))sighandler;
03589 #  endif
03590 #else
03591       sigact.sa_handler = sighandler;
03592 #endif
03593       sigemptyset(&sigact.sa_mask);
03594       sigact.sa_flags = 0;
03595       if (set) {
03596 #if defined(SA_INTERRUPT)       // SunOS
03597          sigact.sa_flags |= SA_INTERRUPT;
03598 #endif
03599       } else {
03600 #if defined(SA_RESTART)
03601          sigact.sa_flags |= SA_RESTART;
03602 #endif
03603       }
03604       if (sigaction(gSignalMap[kSigAlarm].fCode, &sigact, 0) < 0)
03605          ::SysError("TUnixSystem::UnixSigAlarmInterruptsSyscalls", "sigaction");
03606    }
03607 }
03608 
03609 //______________________________________________________________________________
03610 const char *TUnixSystem::UnixSigname(ESignals sig)
03611 {
03612    // Return the signal name associated with a signal.
03613 
03614    return gSignalMap[sig].fSigName;
03615 }
03616 
03617 //______________________________________________________________________________
03618 void TUnixSystem::UnixResetSignal(ESignals sig)
03619 {
03620    // Restore old signal handler for specified signal.
03621 
03622    if (gSignalMap[sig].fOldHandler) {
03623       // restore old signal handler
03624       if (sigaction(gSignalMap[sig].fCode, gSignalMap[sig].fOldHandler, 0) < 0)
03625          ::SysError("TUnixSystem::UnixSignal", "sigaction");
03626       delete gSignalMap[sig].fOldHandler;
03627       gSignalMap[sig].fOldHandler = 0;
03628       gSignalMap[sig].fHandler    = 0;
03629    }
03630 }
03631 
03632 //______________________________________________________________________________
03633 void TUnixSystem::UnixResetSignals()
03634 {
03635    // Restore old signal handlers.
03636 
03637    for (int sig = 0; sig < kMAXSIGNALS; sig++)
03638       UnixResetSignal((ESignals)sig);
03639 }
03640 
03641 //---- time --------------------------------------------------------------------
03642 
03643 //______________________________________________________________________________
03644 Long64_t TUnixSystem::UnixNow()
03645 {
03646    // Get current time in milliseconds since 0:00 Jan 1 1995.
03647 
03648    static time_t jan95 = 0;
03649    if (!jan95) {
03650       struct tm tp;
03651       tp.tm_year  = 95;
03652       tp.tm_mon   = 0;
03653       tp.tm_mday  = 1;
03654       tp.tm_hour  = 0;
03655       tp.tm_min   = 0;
03656       tp.tm_sec   = 0;
03657       tp.tm_isdst = -1;
03658 
03659       jan95 = mktime(&tp);
03660       if ((int)jan95 == -1) {
03661          ::SysError("TUnixSystem::UnixNow", "error converting 950001 0:00 to time_t");
03662          return 0;
03663       }
03664    }
03665 
03666    struct timeval t;
03667    gettimeofday(&t, 0);
03668    return Long64_t(t.tv_sec-(Long_t)jan95)*1000 + t.tv_usec/1000;
03669 }
03670 
03671 //______________________________________________________________________________
03672 int TUnixSystem::UnixSetitimer(Long_t ms)
03673 {
03674    // Set interval timer to time-out in ms milliseconds.
03675 
03676    struct itimerval itv;
03677    itv.it_value.tv_sec     = 0;
03678    itv.it_value.tv_usec    = 0;
03679    itv.it_interval.tv_sec  = 0;
03680    itv.it_interval.tv_usec = 0;
03681    if (ms > 0) {
03682       itv.it_value.tv_sec  = time_t(ms / 1000);
03683       itv.it_value.tv_usec = time_t((ms % 1000) * 1000);
03684    }
03685    int st = setitimer(ITIMER_REAL, &itv, 0);
03686    if (st == -1)
03687       ::SysError("TUnixSystem::UnixSetitimer", "setitimer");
03688    return st;
03689 }
03690 
03691 //---- file descriptors --------------------------------------------------------
03692 
03693 //______________________________________________________________________________
03694 int TUnixSystem::UnixSelect(Int_t nfds, TFdSet *readready, TFdSet *writeready,
03695                             Long_t timeout)
03696 {
03697    // Wait for events on the file descriptors specified in the readready and
03698    // writeready masks or for timeout (in milliseconds) to occur. Returns
03699    // the number of ready descriptors, or 0 in case of timeout, or < 0 in
03700    // case of an error, with -2 being EINTR and -3 EBADF. In case of EINTR
03701    // the errno has been reset and the method can be called again.
03702 
03703    int retcode;
03704 
03705 #if defined(R__HPUX) && defined(R__B64)
03706    fd_set frd;
03707    fd_set fwr;
03708    FD_ZERO(&frd);
03709    FD_ZERO(&fwr);
03710    for (int i = 0; i < nfds; i++) {
03711       if (readready  && readready->IsSet(i))  FD_SET(i, &frd);
03712       if (writeready && writeready->IsSet(i)) FD_SET(i, &fwr);
03713    }
03714    fd_set *rd = (readready)  ? &frd : 0;
03715    fd_set *wr = (writeready) ? &fwr : 0;
03716 #else
03717    fd_set *rd = (readready)  ? (fd_set*)readready->GetBits()  : 0;
03718    fd_set *wr = (writeready) ? (fd_set*)writeready->GetBits() : 0;
03719 #endif
03720 
03721    if (timeout >= 0) {
03722       struct timeval tv;
03723       tv.tv_sec  = Int_t(timeout / 1000);
03724       tv.tv_usec = (timeout % 1000) * 1000;
03725       retcode = select(nfds, rd, wr, 0, &tv);
03726    } else {
03727       retcode = select(nfds, rd, wr, 0, 0);
03728    }
03729    if (retcode == -1) {
03730       if (GetErrno() == EINTR) {
03731          ResetErrno();  // errno is not self reseting
03732          return -2;
03733       }
03734       if (GetErrno() == EBADF)
03735          return -3;
03736       return -1;
03737    }
03738 
03739 #if defined(R__HPUX) && defined(R__B64)
03740    if (rd) readready->Zero();
03741    if (wr) writeready->Zero();
03742    for (int i = 0; i < nfds; i++) {
03743       if (rd && FD_ISSET(i, rd)) readready->Set(i);
03744       if (wr && FD_ISSET(i, wr)) writeready->Set(i);
03745    }
03746 #endif
03747 
03748    return retcode;
03749 }
03750 
03751 //---- directories -------------------------------------------------------------
03752 
03753 //______________________________________________________________________________
03754 const char *TUnixSystem::UnixHomedirectory(const char *name)
03755 {
03756    // Returns the user's home directory.
03757 
03758    static char path[kMAXPATHLEN], mydir[kMAXPATHLEN] = { '\0' };
03759    struct passwd *pw;
03760 
03761    if (name) {
03762       pw = getpwnam(name);
03763       if (pw) {
03764          strncpy(path, pw->pw_dir, kMAXPATHLEN-1);
03765          path[sizeof(path)-1] = '\0';
03766          return path;
03767       }
03768    } else {
03769       if (mydir[0])
03770          return mydir;
03771       pw = getpwuid(getuid());
03772       if (pw) {
03773          strncpy(mydir, pw->pw_dir, kMAXPATHLEN-1);
03774          mydir[sizeof(mydir)-1] = '\0';
03775          return mydir;
03776       }
03777    }
03778    return 0;
03779 }
03780 
03781 //______________________________________________________________________________
03782 int TUnixSystem::UnixMakedir(const char *dir)
03783 {
03784    // Make a Unix file system directory. Returns 0 in case of success and
03785    // -1 if the directory could not be created (either already exists or
03786    // illegal path name).
03787 
03788    return ::mkdir(StripOffProto(dir, "file:"), 0755);
03789 }
03790 
03791 //______________________________________________________________________________
03792 void *TUnixSystem::UnixOpendir(const char *dir)
03793 {
03794    // Open a directory.
03795 
03796    struct stat finfo;
03797 
03798    const char *edir = StripOffProto(dir, "file:");
03799 
03800    if (stat(edir, &finfo) < 0)
03801       return 0;
03802 
03803    if (!S_ISDIR(finfo.st_mode))
03804       return 0;
03805 
03806    return (void*) opendir(edir);
03807 }
03808 
03809 #if defined(_POSIX_SOURCE)
03810 // Posix does not require that the d_ino field be present, and some
03811 // systems do not provide it.
03812 #   define REAL_DIR_ENTRY(dp) 1
03813 #else
03814 #   define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
03815 #endif
03816 
03817 //______________________________________________________________________________
03818 const char *TUnixSystem::UnixGetdirentry(void *dirp1)
03819 {
03820    // Returns the next directory entry.
03821 
03822    DIR *dirp = (DIR*)dirp1;
03823 #ifdef HAS_DIRENT
03824    struct dirent *dp;
03825 #else
03826    struct direct *dp;
03827 #endif
03828 
03829    if (dirp) {
03830       for (;;) {
03831          dp = readdir(dirp);
03832          if (dp == 0)
03833             return 0;
03834          if (REAL_DIR_ENTRY(dp))
03835             return dp->d_name;
03836       }
03837    }
03838    return 0;
03839 }
03840 
03841 //---- files -------------------------------------------------------------------
03842 
03843 //______________________________________________________________________________
03844 int TUnixSystem::UnixFilestat(const char *fpath, FileStat_t &buf)
03845 {
03846    // Get info about a file. Info is returned in the form of a FileStat_t
03847    // structure (see TSystem.h).
03848    // The function returns 0 in case of success and 1 if the file could
03849    // not be stat'ed.
03850 
03851    const char *path = StripOffProto(fpath, "file:");
03852    buf.fIsLink = kFALSE;
03853 
03854 #if defined(R__SEEK64)
03855    struct stat64 sbuf;
03856    if (path && lstat64(path, &sbuf) == 0) {
03857 #else
03858    struct stat sbuf;
03859    if (path && lstat(path, &sbuf) == 0) {
03860 #endif
03861       buf.fIsLink = S_ISLNK(sbuf.st_mode);
03862       if (buf.fIsLink) {
03863 #if defined(R__SEEK64)
03864          if (stat64(path, &sbuf) == -1) {
03865 #else
03866          if (stat(path, &sbuf) == -1) {
03867 #endif
03868             return 1;
03869          }
03870       }
03871       buf.fDev   = sbuf.st_dev;
03872       buf.fIno   = sbuf.st_ino;
03873       buf.fMode  = sbuf.st_mode;
03874       buf.fUid   = sbuf.st_uid;
03875       buf.fGid   = sbuf.st_gid;
03876       buf.fSize  = sbuf.st_size;
03877       buf.fMtime = sbuf.st_mtime;
03878 
03879       return 0;
03880    }
03881    return 1;
03882 }
03883 
03884 //______________________________________________________________________________
03885 int TUnixSystem::UnixFSstat(const char *path, Long_t *id, Long_t *bsize,
03886                             Long_t *blocks, Long_t *bfree)
03887 {
03888    // Get info about a file system: id, bsize, bfree, blocks.
03889    // Id      is file system type (machine dependend, see statfs())
03890    // Bsize   is block size of file system
03891    // Blocks  is total number of blocks in file system
03892    // Bfree   is number of free blocks in file system
03893    // The function returns 0 in case of success and 1 if the file system could
03894    // not be stat'ed.
03895 
03896    struct statfs statfsbuf;
03897 #if defined(R__SGI) || (defined(R__SOLARIS) && !defined(R__LINUX))
03898    if (statfs(path, &statfsbuf, sizeof(struct statfs), 0) == 0) {
03899       *id = statfsbuf.f_fstyp;
03900       *bsize = statfsbuf.f_bsize;
03901       *blocks = statfsbuf.f_blocks;
03902       *bfree = statfsbuf.f_bfree;
03903 #else
03904    if (statfs((char*)path, &statfsbuf) == 0) {
03905 #ifdef R__OBSD
03906       // Convert BSD filesystem names to Linux filesystem type numbers
03907       // where possible.  Linux statfs uses a value of -1 to indicate
03908       // an unsupported field.
03909 
03910       if (!strcmp(statfsbuf.f_fstypename, MOUNT_FFS) ||
03911           !strcmp(statfsbuf.f_fstypename, MOUNT_MFS))
03912          *id = 0x11954;
03913       else if (!strcmp(statfsbuf.f_fstypename, MOUNT_NFS))
03914          *id = 0x6969;
03915       else if (!strcmp(statfsbuf.f_fstypename, MOUNT_MSDOS))
03916          *id = 0x4d44;
03917       else if (!strcmp(statfsbuf.f_fstypename, MOUNT_PROCFS))
03918          *id = 0x9fa0;
03919       else if (!strcmp(statfsbuf.f_fstypename, MOUNT_EXT2FS))
03920          *id = 0xef53;
03921       else if (!strcmp(statfsbuf.f_fstypename, MOUNT_CD9660))
03922          *id = 0x9660;
03923       else if (!strcmp(statfsbuf.f_fstypename, MOUNT_NCPFS))
03924          *id = 0x6969;
03925       else
03926          *id = -1;
03927 #else
03928       *id = statfsbuf.f_type;
03929 #endif
03930       *bsize = statfsbuf.f_bsize;
03931       *blocks = statfsbuf.f_blocks;
03932       *bfree = statfsbuf.f_bavail;
03933 #endif
03934       return 0;
03935    }
03936    return 1;
03937 }
03938 
03939 //______________________________________________________________________________
03940 int TUnixSystem::UnixWaitchild()
03941 {
03942    // Wait till child is finished.
03943 
03944    int status;
03945    return (int) waitpid(0, &status, WNOHANG);
03946 }
03947 
03948 //---- RPC -------------------------------------------------------------------
03949 
03950 //______________________________________________________________________________
03951 int TUnixSystem::UnixTcpConnect(const char *hostname, int port,
03952                                 int tcpwindowsize)
03953 {
03954    // Open a TCP/IP connection to server and connect to a service (i.e. port).
03955    // Use tcpwindowsize to specify the size of the receive buffer, it has
03956    // to be specified here to make sure the window scale option is set (for
03957    // tcpwindowsize > 65KB and for platforms supporting window scaling).
03958    // Is called via the TSocket constructor. Returns -1 in case of error.
03959 
03960    short  sport;
03961    struct servent *sp;
03962 
03963    if ((sp = getservbyport(htons(port), kProtocolName)))
03964       sport = sp->s_port;
03965    else
03966       sport = htons(port);
03967 
03968    TInetAddress addr = gSystem->GetHostByName(hostname);
03969    if (!addr.IsValid()) return -1;
03970    UInt_t adr = htonl(addr.GetAddress());
03971 
03972    struct sockaddr_in server;
03973    memset(&server, 0, sizeof(server));
03974    memcpy(&server.sin_addr, &adr, sizeof(adr));
03975    server.sin_family = addr.GetFamily();
03976    server.sin_port   = sport;
03977 
03978    // Create socket
03979    int sock;
03980    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
03981       ::SysError("TUnixSystem::UnixTcpConnect", "socket (%s:%d)",
03982                  hostname, port);
03983       return -1;
03984    }
03985 
03986    if (tcpwindowsize > 0) {
03987       gSystem->SetSockOpt(sock, kRecvBuffer, tcpwindowsize);
03988       gSystem->SetSockOpt(sock, kSendBuffer, tcpwindowsize);
03989    }
03990 
03991    while (connect(sock, (struct sockaddr*) &server, sizeof(server)) == -1) {
03992       if (GetErrno() == EINTR)
03993          ResetErrno();
03994       else {
03995          ::SysError("TUnixSystem::UnixTcpConnect", "connect (%s:%d)",
03996                     hostname, port);
03997          close(sock);
03998          return -1;
03999       }
04000    }
04001    return sock;
04002 }
04003 
04004 //______________________________________________________________________________
04005 int TUnixSystem::UnixUnixConnect(int port)
04006 {
04007    // Connect to a Unix domain socket.
04008 
04009    return UnixUnixConnect(TString::Format("%s/%d", kServerPath, port));
04010 }
04011 
04012 //______________________________________________________________________________
04013 int TUnixSystem::UnixUnixConnect(const char *sockpath)
04014 {
04015    // Connect to a Unix domain socket. Returns -1 in case of error.
04016 
04017    if (!sockpath || strlen(sockpath) <= 0) {
04018       ::SysError("TUnixSystem::UnixUnixConnect", "socket path undefined");
04019       return -1;
04020    }
04021 
04022    int sock;
04023    struct sockaddr_un unserver;
04024    unserver.sun_family = AF_UNIX;
04025 
04026    if (strlen(sockpath) > sizeof(unserver.sun_path)-1) {
04027       ::Error("TUnixSystem::UnixUnixConnect", "socket path %s, longer than max allowed length (%u)",
04028               sockpath, (UInt_t)sizeof(unserver.sun_path)-1);
04029       return -1;
04030    }
04031    strcpy(unserver.sun_path, sockpath);
04032 
04033    // Open socket
04034    if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
04035       ::SysError("TUnixSystem::UnixUnixConnect", "socket");
04036       return -1;
04037    }
04038 
04039    while (connect(sock, (struct sockaddr*) &unserver, strlen(unserver.sun_path)+2) == -1) {
04040       if (GetErrno() == EINTR)
04041          ResetErrno();
04042       else {
04043          ::SysError("TUnixSystem::UnixUnixConnect", "connect");
04044          close(sock);
04045          return -1;
04046       }
04047    }
04048    return sock;
04049 }
04050 
04051 //______________________________________________________________________________
04052 int TUnixSystem::UnixTcpService(int port, Bool_t reuse, int backlog,
04053                                 int tcpwindowsize)
04054 {
04055    // Open a socket, bind to it and start listening for TCP/IP connections
04056    // on the port. If reuse is true reuse the address, backlog specifies
04057    // how many sockets can be waiting to be accepted. If port is 0 a port
04058    // scan will be done to find a free port. This option is mutual exlusive
04059    // with the reuse option.
04060    // Use tcpwindowsize to specify the size of the receive buffer, it has
04061    // to be specified here to make sure the window scale option is set (for
04062    // tcpwindowsize > 65KB and for platforms supporting window scaling).
04063    // Returns socket fd or -1 if socket() failed, -2 if bind() failed
04064    // or -3 if listen() failed.
04065 
04066    const short kSOCKET_MINPORT = 5000, kSOCKET_MAXPORT = 15000;
04067    short  sport, tryport = kSOCKET_MINPORT;
04068    struct servent *sp;
04069 
04070    if (port == 0 && reuse) {
04071       ::Error("TUnixSystem::UnixTcpService", "cannot do a port scan while reuse is true");
04072       return -1;
04073    }
04074 
04075    if ((sp = getservbyport(htons(port), kProtocolName)))
04076       sport = sp->s_port;
04077    else
04078       sport = htons(port);
04079 
04080    // Create tcp socket
04081    int sock;
04082    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
04083       ::SysError("TUnixSystem::UnixTcpService", "socket");
04084       return -1;
04085    }
04086 
04087    if (reuse)
04088       gSystem->SetSockOpt(sock, kReuseAddr, 1);
04089 
04090    if (tcpwindowsize > 0) {
04091       gSystem->SetSockOpt(sock, kRecvBuffer, tcpwindowsize);
04092       gSystem->SetSockOpt(sock, kSendBuffer, tcpwindowsize);
04093    }
04094 
04095    struct sockaddr_in inserver;
04096    memset(&inserver, 0, sizeof(inserver));
04097    inserver.sin_family = AF_INET;
04098    inserver.sin_addr.s_addr = htonl(INADDR_ANY);
04099    inserver.sin_port = sport;
04100 
04101    // Bind socket
04102    if (port > 0) {
04103       if (bind(sock, (struct sockaddr*) &inserver, sizeof(inserver))) {
04104          ::SysError("TUnixSystem::UnixTcpService", "bind");
04105          return -2;
04106       }
04107    } else {
04108       int bret;
04109       do {
04110          inserver.sin_port = htons(tryport++);
04111          bret = bind(sock, (struct sockaddr*) &inserver, sizeof(inserver));
04112       } while (bret < 0 && GetErrno() == EADDRINUSE && tryport < kSOCKET_MAXPORT);
04113       if (bret < 0) {
04114          ::SysError("TUnixSystem::UnixTcpService", "bind (port scan)");
04115          return -2;
04116       }
04117    }
04118 
04119    // Start accepting connections
04120    if (listen(sock, backlog)) {
04121       ::SysError("TUnixSystem::UnixTcpService", "listen");
04122       return -3;
04123    }
04124 
04125    return sock;
04126 }
04127 
04128 //______________________________________________________________________________
04129 int TUnixSystem::UnixUnixService(int port, int backlog)
04130 {
04131    // Open a socket, bind to it and start listening for Unix domain connections
04132    // to it. Returns socket fd or -1.
04133 
04134    int oldumask;
04135 
04136    // Assure that socket directory exists
04137    oldumask = umask(0);
04138    ::mkdir(kServerPath, 0777);
04139    umask(oldumask);
04140 
04141    // Socket path
04142    TString sockpath;
04143    sockpath.Form("%s/%d", kServerPath, port);
04144 
04145    // Remove old socket
04146    unlink(sockpath.Data());
04147 
04148    return UnixUnixService(sockpath, backlog);
04149 }
04150 
04151 //______________________________________________________________________________
04152 int TUnixSystem::UnixUnixService(const char *sockpath, int backlog)
04153 {
04154    // Open a socket on path 'sockpath', bind to it and start listening for Unix
04155    // domain connections to it. Returns socket fd or -1.
04156 
04157    if (!sockpath || strlen(sockpath) <= 0) {
04158       ::SysError("TUnixSystem::UnixUnixService", "socket path undefined");
04159       return -1;
04160    }
04161 
04162    struct sockaddr_un unserver;
04163    int sock;
04164 
04165    // Prepare structure
04166    memset(&unserver, 0, sizeof(unserver));
04167    unserver.sun_family = AF_UNIX;
04168 
04169    if (strlen(sockpath) > sizeof(unserver.sun_path)-1) {
04170       ::Error("TUnixSystem::UnixUnixService", "socket path %s, longer than max allowed length (%u)",
04171               sockpath, (UInt_t)sizeof(unserver.sun_path)-1);
04172       return -1;
04173    }
04174    strcpy(unserver.sun_path, sockpath);
04175 
04176    // Create socket
04177    if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
04178       ::SysError("TUnixSystem::UnixUnixService", "socket");
04179       return -1;
04180    }
04181 
04182    if (bind(sock, (struct sockaddr*) &unserver, strlen(unserver.sun_path)+2)) {
04183       ::SysError("TUnixSystem::UnixUnixService", "bind");
04184       return -1;
04185    }
04186 
04187    // Start accepting connections
04188    if (listen(sock, backlog)) {
04189       ::SysError("TUnixSystem::UnixUnixService", "listen");
04190       return -1;
04191    }
04192 
04193    return sock;
04194 }
04195 
04196 //______________________________________________________________________________
04197 int TUnixSystem::UnixRecv(int sock, void *buffer, int length, int flag)
04198 {
04199    // Receive exactly length bytes into buffer. Returns number of bytes
04200    // received. Returns -1 in case of error, -2 in case of MSG_OOB
04201    // and errno == EWOULDBLOCK, -3 in case of MSG_OOB and errno == EINVAL
04202    // and -4 in case of kNoBlock and errno == EWOULDBLOCK.
04203    // Returns -5 if pipe broken or reset by peer (EPIPE || ECONNRESET).
04204 
04205    ResetErrno();
04206 
04207    if (sock < 0) return -1;
04208 
04209    int once = 0;
04210    if (flag == -1) {
04211       flag = 0;
04212       once = 1;
04213    }
04214    if (flag == MSG_PEEK)
04215       once = 1;
04216 
04217    int n, nrecv = 0;
04218    char *buf = (char *)buffer;
04219 
04220    for (n = 0; n < length; n += nrecv) {
04221       if ((nrecv = recv(sock, buf+n, length-n, flag)) <= 0) {
04222          if (nrecv == 0)
04223             break;        // EOF
04224          if (flag == MSG_OOB) {
04225             if (GetErrno() == EWOULDBLOCK)
04226                return -2;
04227             else if (GetErrno() == EINVAL)
04228                return -3;
04229          }
04230          if (GetErrno() == EWOULDBLOCK)
04231             return -4;
04232          else {
04233             if (GetErrno() != EINTR)
04234                ::SysError("TUnixSystem::UnixRecv", "recv");
04235             if (GetErrno() == EPIPE || GetErrno() == ECONNRESET)
04236                return -5;
04237             else
04238                return -1;
04239          }
04240       }
04241       if (once)
04242          return nrecv;
04243    }
04244    return n;
04245 }
04246 
04247 //______________________________________________________________________________
04248 int TUnixSystem::UnixSend(int sock, const void *buffer, int length, int flag)
04249 {
04250    // Send exactly length bytes from buffer. Returns -1 in case of error,
04251    // otherwise number of sent bytes. Returns -4 in case of kNoBlock and
04252    // errno == EWOULDBLOCK. Returns -5 if pipe broken or reset by peer
04253    // (EPIPE || ECONNRESET).
04254 
04255    if (sock < 0) return -1;
04256 
04257    int once = 0;
04258    if (flag == -1) {
04259       flag = 0;
04260       once = 1;
04261    }
04262 
04263    int n, nsent = 0;
04264    const char *buf = (const char *)buffer;
04265 
04266    for (n = 0; n < length; n += nsent) {
04267       if ((nsent = send(sock, buf+n, length-n, flag)) <= 0) {
04268          if (nsent == 0)
04269             break;
04270          if (GetErrno() == EWOULDBLOCK)
04271             return -4;
04272          else {
04273             if (GetErrno() != EINTR)
04274                ::SysError("TUnixSystem::UnixSend", "send");
04275             if (GetErrno() == EPIPE || GetErrno() == ECONNRESET)
04276                return -5;
04277             else
04278                return -1;
04279          }
04280       }
04281       if (once)
04282          return nsent;
04283    }
04284    return n;
04285 }
04286 
04287 //---- Dynamic Loading ---------------------------------------------------------
04288 
04289 //______________________________________________________________________________
04290 static const char *DynamicPath(const char *newpath = 0, Bool_t reset = kFALSE)
04291 {
04292    // Get shared library search path. Static utility function.
04293 
04294    static TString dynpath;
04295    static Bool_t initialized = kFALSE;
04296 
04297    if (newpath) {
04298       dynpath = newpath;
04299    } else if (reset || !initialized) {
04300       initialized = kTRUE;
04301       TString rdynpath = gEnv->GetValue("Root.DynamicPath", (char*)0);
04302       rdynpath.ReplaceAll(": ", ":");  // in case DynamicPath was extended
04303       if (rdynpath.IsNull()) {
04304 #ifdef ROOTLIBDIR
04305          rdynpath = ".:"; rdynpath += ROOTLIBDIR;
04306 #else
04307          rdynpath = ".:"; rdynpath += gRootDir; rdynpath += "/lib";
04308 #endif
04309       }
04310       TString ldpath;
04311 #if defined (R__AIX)
04312       ldpath = gSystem->Getenv("LIBPATH");
04313 #elif defined(R__HPUX)
04314       ldpath = gSystem->Getenv("SHLIB_PATH");
04315 #elif defined(R__MACOSX)
04316       ldpath = gSystem->Getenv("DYLD_LIBRARY_PATH");
04317       if (!ldpath.IsNull())
04318          ldpath += ":";
04319       ldpath += gSystem->Getenv("LD_LIBRARY_PATH");
04320 #else
04321       ldpath = gSystem->Getenv("LD_LIBRARY_PATH");
04322 #endif
04323       if (ldpath.IsNull())
04324          dynpath = rdynpath;
04325       else {
04326          dynpath = ldpath; dynpath += ":"; dynpath += rdynpath;
04327       }
04328 
04329 #ifdef ROOTLIBDIR
04330       if (!dynpath.Contains(ROOTLIBDIR)) {
04331          dynpath += ":"; dynpath += ROOTLIBDIR;
04332       }
04333 #else
04334       if (!dynpath.Contains(TString::Format("%s/lib", gRootDir))) {
04335          dynpath += ":"; dynpath += gRootDir; dynpath += "/lib";
04336       }
04337 #endif
04338       dynpath += ":"; dynpath += gInterpreter->GetSTLIncludePath();
04339    }
04340    return dynpath;
04341 }
04342 
04343 //______________________________________________________________________________
04344 void TUnixSystem::AddDynamicPath(const char *path)
04345 {
04346    // Add a new directory to the dynamic path.
04347 
04348    if (path) {
04349       TString oldpath = DynamicPath(0, kFALSE);
04350       oldpath.Append(":");
04351       oldpath.Append(path);
04352       DynamicPath(oldpath);
04353    }
04354 }
04355 
04356 //______________________________________________________________________________
04357 const char *TUnixSystem::GetDynamicPath()
04358 {
04359    // Return the dynamic path (used to find shared libraries).
04360 
04361    return DynamicPath(0, kFALSE);
04362 }
04363 
04364 //______________________________________________________________________________
04365 void TUnixSystem::SetDynamicPath(const char *path)
04366 {
04367    // Set the dynamic path to a new value.
04368    // If the value of 'path' is zero, the dynamic path is reset to its
04369    // default value.
04370 
04371    if (!path)
04372       DynamicPath(0, kTRUE);
04373    else
04374       DynamicPath(path);
04375 }
04376 
04377 //______________________________________________________________________________
04378 char *TUnixSystem::DynamicPathName(const char *lib, Bool_t quiet)
04379 {
04380    // Returns the path of a shared library (searches for library in the
04381    // shared library search path). If no file name extension is provided
04382    // it first tries .so, .sl, .dl and then .a (for AIX). The returned string
04383    // must be deleted.
04384 
04385    char *name;
04386 
04387    int ext = 0, len = strlen(lib);
04388    if (len > 3 && (!strcmp(lib+len-3, ".sl") ||
04389                    !strcmp(lib+len-3, ".dl") ||
04390                    !strcmp(lib+len-4, ".dll")||
04391                    !strcmp(lib+len-4, ".DLL")||
04392                    !strcmp(lib+len-3, ".so") ||
04393                    !strcmp(lib+len-2, ".a"))) {
04394       name = gSystem->Which(GetDynamicPath(), lib, kReadPermission);
04395       ext  = 1;
04396    } else {
04397       TString fname;
04398       fname.Form("%s.so", lib);
04399       name = gSystem->Which(GetDynamicPath(), fname, kReadPermission);
04400       if (!name) {
04401          fname.Form("%s.dll", lib);
04402          name = gSystem->Which(GetDynamicPath(), fname, kReadPermission);
04403          if (!name) {
04404             fname.Form("%s.sl", lib);
04405             name = gSystem->Which(GetDynamicPath(), fname, kReadPermission);
04406             if (!name) {
04407                fname.Form("%s.dl", lib);
04408                name = gSystem->Which(GetDynamicPath(), fname, kReadPermission);
04409                if (!name) {
04410                   fname.Form("%s.a", lib);
04411                   name = gSystem->Which(GetDynamicPath(), fname, kReadPermission);
04412                }
04413             }
04414          }
04415       }
04416    }
04417 
04418    if (!name && !quiet) {
04419       if (ext)
04420          Error("DynamicPathName",
04421                "%s does not exist in %s", lib, GetDynamicPath());
04422       else
04423          Error("DynamicPathName",
04424                "%s[.so | .sl | .dl | .a | .dll] does not exist in %s", lib, GetDynamicPath());
04425    }
04426 
04427    return name;
04428 }
04429 
04430 //______________________________________________________________________________
04431 void *TUnixSystem::FindDynLib(const char *lib)
04432 {
04433    // Returns the handle to a loaded shared library. Returns 0 when library
04434    // not loaded.
04435 
04436 #ifdef R__HPUX
04437    const char *path;
04438 
04439    if ((path = gSystem->DynamicPathName(lib))) {
04440       // find handle of shared library using its name
04441       struct shl_descriptor *desc;
04442       int index = 0;
04443       while (shl_get(index++, &desc) == 0)
04444          if (!strcmp(path, desc->filename))
04445             return desc->handle;
04446    }
04447 #endif
04448 
04449    if (lib) { }  // avoid warning, use lib
04450 
04451    return 0;
04452 }
04453 
04454 //______________________________________________________________________________
04455 int TUnixSystem::UnixDynLoad(const char *lib)
04456 {
04457    // Load a shared library. Returns 0 on successful loading, 1 in
04458    // case lib was already loaded and -1 in case lib does not exist
04459    // or in case of error.
04460 
04461    const char *path;
04462 
04463    if ((path = gSystem->DynamicPathName(lib))) {
04464 #if defined(R__HPUX)
04465 #if !defined(__STDCPP__)
04466       shl_t handle = cxxshl_load(path, BIND_IMMEDIATE | BIND_NONFATAL, 0L);
04467 #else
04468       shl_t handle = shl_load(path, BIND_IMMEDIATE | BIND_NONFATAL, 0L);
04469 #endif
04470       if (handle != 0) return 0;
04471 #else
04472       if (path) { }  // use path remove warning
04473       ::Error("TUnixSystem::UnixDynLoad", "not yet implemented for this platform");
04474       return -1;
04475 #endif
04476    }
04477    return -1;
04478 }
04479 
04480 //______________________________________________________________________________
04481 Func_t TUnixSystem::UnixDynFindSymbol(const char *lib, const char *entry)
04482 {
04483    // Finds and returns a function pointer to a symbol in the shared library.
04484    // Returns 0 when symbol not found.
04485 
04486 #if defined(R__HPUX) && !defined(R__GNU)
04487    shl_t handle;
04488 
04489    if (handle = (shl_t)FindDynLib(lib)) {
04490       Func_t addr = 0;
04491       if (shl_findsym(&handle, entry, TYPE_PROCEDURE, addr) == -1)
04492          ::SysError("TUnixSystem::UnixDynFindSymbol", "shl_findsym");
04493       return addr;
04494    }
04495    return 0;
04496 #else
04497    if (lib || entry) { }
04498 
04499    // Always assume symbol not found
04500    return 0;
04501 #endif
04502 }
04503 
04504 //______________________________________________________________________________
04505 void TUnixSystem::UnixDynListSymbols(const char *lib, const char *regexp)
04506 {
04507    // List symbols in a shared library. One can use wildcards to list only
04508    // the interesting symbols.
04509 
04510 #if defined(R__HPUX) && !defined(R__GNU)
04511    shl_t handle;
04512 
04513    if (handle = (shl_t)FindDynLib(lib)) {
04514       struct shl_symbol *symbols;
04515       int nsym = shl_getsymbols(handle, TYPE_PROCEDURE,
04516                                 EXPORT_SYMBOLS|NO_VALUES, (void *(*)())malloc,
04517                                 &symbols);
04518       if (nsym != -1) {
04519          if (nsym > 0) {
04520             int cnt = 0;
04521             TRegexp *re = 0;
04522             if (regexp && strlen(regexp)) re = new TRegexp(regexp, kTRUE);
04523             Printf("");
04524             Printf("Functions exported by library %s", gSystem->DynamicPathName(lib));
04525             Printf("=========================================================");
04526             for (int i = 0; i < nsym; i++)
04527                if (symbols[i].type == TYPE_PROCEDURE) {
04528                   cnt++;
04529                   char *dsym = cplus_demangle(symbols[i].name,
04530                                               DMGL_PARAMS|DMGL_ANSI|DMGL_ARM);
04531                   if (re) {
04532                      TString s = dsym;
04533                      if (s.Index(*re) != kNPOS) Printf("%s", dsym);
04534                   } else
04535                      Printf("%s", dsym);
04536                   free(dsym);
04537                }
04538             Printf("---------------------------------------------------------");
04539             Printf("%d exported functions", cnt);
04540             Printf("=========================================================");
04541             delete re;
04542          }
04543          free(symbols);
04544       }
04545    }
04546 #endif
04547    if (lib || regexp) { }
04548 }
04549 
04550 //______________________________________________________________________________
04551 void TUnixSystem::UnixDynListLibs(const char *lib)
04552 {
04553    // List all loaded shared libraries.
04554 
04555 #if defined(R__HPUX) && !defined(R__GNU)
04556    TRegexp *re = 0;
04557    if (lib && strlen(lib)) re = new TRegexp(lib, kTRUE);
04558    struct shl_descriptor *desc;
04559    int index = 0;
04560 
04561    Printf("");
04562    Printf("Loaded shared libraries");
04563    Printf("=======================");
04564 
04565    while (shl_get(index++, &desc) == 0)
04566       if (re) {
04567          TString s = desc->filename;
04568          if (s.Index(*re) != kNPOS) Printf("%s", desc->filename);
04569       } else
04570          Printf("%s", desc->filename);
04571    Printf("-----------------------");
04572    Printf("%d libraries loaded", index-1);
04573    Printf("=======================");
04574    delete re;
04575 #else
04576    if (lib) { }
04577 #endif
04578 }
04579 
04580 //______________________________________________________________________________
04581 void TUnixSystem::UnixDynUnload(const char *lib)
04582 {
04583    // Unload a shared library.
04584 
04585 #if defined(R__HPUX)
04586    shl_t handle;
04587 
04588    if (handle = (shl_t)FindDynLib(lib))
04589 #if !defined(__STDCPP__)
04590       if (cxxshl_unload(handle) == -1)
04591 #else
04592       if (shl_unload(handle) == -1)
04593 #endif
04594          ::SysError("TUnixSystem::UnixDynUnload", "could not unload library %s", lib);
04595 #else
04596    if (lib) { }
04597    // should call CINT unload file here, but does not work for sl's yet.
04598    ::Error("TUnixSystem::UnixDynUnload", "not yet implemented for this platform");
04599 #endif
04600 }
04601 
04602 //______________________________________________________________________________
04603 int TUnixSystem::ReadUtmpFile()
04604 {
04605    // Read utmp file. Returns number of entries in utmp file.
04606 
04607    FILE  *utmp;
04608    struct stat file_stats;
04609    size_t n_read, size;
04610 
04611    R__LOCKGUARD2(gSystemMutex);
04612 
04613    gUtmpContents = 0;
04614 
04615    utmp = fopen(UTMP_FILE, "r");
04616    if (!utmp)
04617       return 0;
04618 
04619    fstat(fileno(utmp), &file_stats);
04620    size = file_stats.st_size;
04621    if (size <= 0) {
04622       fclose(utmp);
04623       return 0;
04624    }
04625 
04626    gUtmpContents = (STRUCT_UTMP *) malloc(size);
04627    if (!gUtmpContents) {
04628       fclose(utmp);
04629       return 0;
04630    }
04631 
04632    n_read = fread(gUtmpContents, 1, size, utmp);
04633    if (!ferror(utmp)) {
04634       if (fclose(utmp) != EOF && n_read == size)
04635          return size / sizeof(STRUCT_UTMP);
04636    } else
04637       fclose(utmp);
04638 
04639    free(gUtmpContents);
04640    gUtmpContents = 0;
04641    return 0;
04642 }
04643 
04644 //______________________________________________________________________________
04645 void *TUnixSystem::SearchUtmpEntry(int n, const char *tty)
04646 {
04647    // Look for utmp entry which is connected to terminal tty.
04648 
04649    STRUCT_UTMP *ue = gUtmpContents;
04650 
04651    while (n--) {
04652       if (ue->ut_name[0] && !strncmp(tty, ue->ut_line, sizeof(ue->ut_line)))
04653          return ue;
04654       ue++;
04655    }
04656    return 0;
04657 }
04658 
04659 //---- System, CPU and Memory info ---------------------------------------------
04660 
04661 #if defined(R__MACOSX)
04662 #include <sys/resource.h>
04663 #include <mach/mach.h>
04664 #include <mach/mach_error.h>
04665 
04666 //______________________________________________________________________________
04667 static void GetDarwinSysInfo(SysInfo_t *sysinfo)
04668 {
04669    // Get system info for Mac OS X.
04670 
04671    FILE *p = gSystem->OpenPipe("sysctl -n kern.ostype hw.model hw.ncpu hw.cpufrequency "
04672                                "hw.busfrequency hw.l2cachesize hw.physmem", "r");
04673    TString s;
04674    s.Gets(p);
04675    sysinfo->fOS = s;
04676    s.Gets(p);
04677    sysinfo->fModel = s;
04678    s.Gets(p);
04679    sysinfo->fCpus = s.Atoi();
04680    s.Gets(p);
04681    Long64_t t = s.Atoll();
04682    sysinfo->fCpuSpeed = Int_t(t / 1000000);
04683    s.Gets(p);
04684    t = s.Atoll();
04685    sysinfo->fBusSpeed = Int_t(t / 1000000);
04686    s.Gets(p);
04687    sysinfo->fL2Cache = s.Atoi() / 1024;
04688    s.Gets(p);
04689    t = s.Atoll();
04690    sysinfo->fPhysRam = Int_t(t / 1024 / 1024);
04691    gSystem->ClosePipe(p);
04692    p = gSystem->OpenPipe("hostinfo", "r");
04693    while (s.Gets(p)) {
04694       if (s.BeginsWith("Processor type: ")) {
04695          TPRegexp("Processor type: ([^ ]+).*").Substitute(s, "$1");
04696          sysinfo->fCpuType = s;
04697       }
04698    }
04699    gSystem->ClosePipe(p);
04700 }
04701 
04702 //______________________________________________________________________________
04703 static void ReadDarwinCpu(long *ticks)
04704 {
04705    // Get CPU load on Mac OS X.
04706 
04707    mach_msg_type_number_t count;
04708    kern_return_t kr;
04709    host_cpu_load_info_data_t cpu;
04710 
04711    ticks[0] = ticks[1] = ticks[2] = ticks[3] = 0;
04712 
04713    count = HOST_CPU_LOAD_INFO_COUNT;
04714    kr = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&cpu, &count);
04715    if (kr != KERN_SUCCESS) {
04716       ::Error("TUnixSystem::ReadDarwinCpu", "host_statistics: %s", mach_error_string(kr));
04717    } else {
04718       ticks[0] = cpu.cpu_ticks[CPU_STATE_USER];
04719       ticks[1] = cpu.cpu_ticks[CPU_STATE_SYSTEM];
04720       ticks[2] = cpu.cpu_ticks[CPU_STATE_IDLE];
04721       ticks[3] = cpu.cpu_ticks[CPU_STATE_NICE];
04722    }
04723 }
04724 
04725 //______________________________________________________________________________
04726 static void GetDarwinCpuInfo(CpuInfo_t *cpuinfo, Int_t sampleTime)
04727 {
04728    // Get CPU stat for Mac OS X. Use sampleTime to set the interval over which
04729    // the CPU load will be measured, in ms (default 1000).
04730 
04731    Double_t avg[3];
04732    if (getloadavg(avg, sizeof(avg)) < 0) {
04733       ::Error("TUnixSystem::GetDarwinCpuInfo", "getloadavg failed");
04734    } else {
04735       cpuinfo->fLoad1m  = (Float_t)avg[0];
04736       cpuinfo->fLoad5m  = (Float_t)avg[1];
04737       cpuinfo->fLoad15m = (Float_t)avg[2];
04738    }
04739 
04740    Long_t cpu_ticks1[4], cpu_ticks2[4];
04741    ReadDarwinCpu(cpu_ticks1);
04742    gSystem->Sleep(sampleTime);
04743    ReadDarwinCpu(cpu_ticks2);
04744 
04745    Long_t userticks = (cpu_ticks2[0] + cpu_ticks2[3]) -
04746                       (cpu_ticks1[0] + cpu_ticks1[3]);
04747    Long_t systicks  = cpu_ticks2[1] - cpu_ticks1[1];
04748    Long_t idleticks = cpu_ticks2[2] - cpu_ticks1[2];
04749    if (userticks < 0) userticks = 0;
04750    if (systicks < 0)  systicks = 0;
04751    if (idleticks < 0) idleticks = 0;
04752    Long_t totalticks = userticks + systicks + idleticks;
04753    if (totalticks) {
04754       cpuinfo->fUser  = ((Float_t)(100 * userticks)) / ((Float_t)totalticks);
04755       cpuinfo->fSys   = ((Float_t)(100 * systicks))  / ((Float_t)totalticks);
04756       cpuinfo->fTotal = cpuinfo->fUser + cpuinfo->fSys;
04757       cpuinfo->fIdle  = ((Float_t)(100 * idleticks)) / ((Float_t)totalticks);
04758    }
04759 }
04760 
04761 //______________________________________________________________________________
04762 static void GetDarwinMemInfo(MemInfo_t *meminfo)
04763 {
04764    // Get VM stat for Mac OS X.
04765 
04766    static Int_t pshift = 0;
04767    static DIR *dirp;
04768    vm_statistics_data_t vm_info;
04769    mach_msg_type_number_t count;
04770    kern_return_t kr;
04771    struct dirent *dp;
04772    Long64_t total, used, free, swap_total, swap_used;
04773 
04774    count = HOST_VM_INFO_COUNT;
04775    kr = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_info, &count);
04776    if (kr != KERN_SUCCESS) {
04777       ::Error("TUnixSystem::GetDarwinMemInfo", "host_statistics: %s", mach_error_string(kr));
04778       return;
04779    }
04780    if (pshift == 0) {
04781       for (int psize = getpagesize(); psize > 1; psize >>= 1)
04782          pshift++;
04783    }
04784 
04785    used =  (Long64_t)(vm_info.active_count + vm_info.inactive_count + vm_info.wire_count) << pshift;
04786    free =  (Long64_t)(vm_info.free_count) << pshift;
04787    total = (Long64_t)(vm_info.active_count + vm_info.inactive_count + vm_info.free_count + vm_info.wire_count) << pshift;
04788 
04789    // Swap is available at same time as mem, so grab values here.
04790    swap_used = vm_info.pageouts << pshift;
04791 
04792    // Figure out total swap. This adds up the size of the swapfiles */
04793    dirp = opendir("/private/var/vm");
04794    if (!dirp)
04795        return;
04796 
04797    swap_total = 0;
04798    while ((dp = readdir(dirp)) != 0) {
04799       struct stat sb;
04800       char fname [MAXNAMLEN];
04801       if (strncmp(dp->d_name, "swapfile", 8))
04802          continue;
04803       strlcpy(fname, "/private/var/vm/",MAXNAMLEN);
04804       strlcat (fname, dp->d_name,MAXNAMLEN);
04805       if (stat(fname, &sb) < 0)
04806          continue;
04807       swap_total += sb.st_size;
04808    }
04809    closedir(dirp);
04810 
04811    meminfo->fMemTotal  = (Int_t) (total >> 20);       // divide by 1024 * 1024
04812    meminfo->fMemUsed   = (Int_t) (used >> 20);
04813    meminfo->fMemFree   = (Int_t) (free >> 20);
04814    meminfo->fSwapTotal = (Int_t) (swap_total >> 20);
04815    meminfo->fSwapUsed  = (Int_t) (swap_used >> 20);
04816    meminfo->fSwapFree  = meminfo->fSwapTotal - meminfo->fSwapUsed;
04817 }
04818 
04819 //______________________________________________________________________________
04820 static void GetDarwinProcInfo(ProcInfo_t *procinfo)
04821 {
04822    // Get process info for this process on Mac OS X.
04823 
04824 #ifdef _LP64
04825 #define vm_region vm_region_64
04826 #endif
04827 
04828 // taken from <mach/shared_memory_server.h> which is obsoleted in 10.5
04829 #define GLOBAL_SHARED_TEXT_SEGMENT      0x90000000U
04830 #define GLOBAL_SHARED_DATA_SEGMENT      0xA0000000U
04831 #define SHARED_TEXT_REGION_SIZE         0x10000000
04832 #define SHARED_DATA_REGION_SIZE         0x10000000
04833 
04834    struct rusage ru;
04835    if (getrusage(RUSAGE_SELF, &ru) < 0) {
04836       ::SysError("TUnixSystem::GetDarwinProcInfo", "getrusage failed");
04837    } else {
04838       procinfo->fCpuUser = (Float_t)(ru.ru_utime.tv_sec) +
04839                            ((Float_t)(ru.ru_utime.tv_usec) / 1000000.);
04840       procinfo->fCpuSys  = (Float_t)(ru.ru_stime.tv_sec) +
04841                            ((Float_t)(ru.ru_stime.tv_usec) / 1000000.);
04842    }
04843 
04844    task_basic_info_data_t ti;
04845    mach_msg_type_number_t count;
04846    kern_return_t kr;
04847 
04848    task_t a_task = mach_task_self();
04849 
04850    count = TASK_BASIC_INFO_COUNT;
04851    kr = task_info(a_task, TASK_BASIC_INFO, (task_info_t)&ti, &count);
04852    if (kr != KERN_SUCCESS) {
04853       ::Error("TUnixSystem::GetDarwinProcInfo", "task_info: %s", mach_error_string(kr));
04854    } else {
04855       // resident size does not require any calculation. Virtual size
04856       // needs to be adjusted if traversing memory objects do not include the
04857         // globally shared text and data regions
04858         mach_port_t object_name;
04859         vm_address_t address;
04860         vm_region_top_info_data_t info;
04861         vm_size_t vsize, rsize, size;
04862         rsize = ti.resident_size;
04863         vsize = ti.virtual_size;
04864       for (address = 0; ; address += size) {
04865          // get memory region
04866          count = VM_REGION_TOP_INFO_COUNT;
04867          if (vm_region(a_task, &address, &size,
04868                        VM_REGION_TOP_INFO, (vm_region_info_t)&info, &count,
04869                        &object_name) != KERN_SUCCESS) {
04870             // no more memory regions.
04871             break;
04872          }
04873 
04874          if (address >= GLOBAL_SHARED_TEXT_SEGMENT &&
04875              address < (GLOBAL_SHARED_DATA_SEGMENT + SHARED_DATA_REGION_SIZE)) {
04876             // This region is private shared.
04877             // Check if this process has the globally shared
04878             // text and data regions mapped in. If so, adjust
04879             // virtual memory size and exit loop.
04880             if (info.share_mode == SM_EMPTY) {
04881                vm_region_basic_info_data_64_t b_info;
04882                count = VM_REGION_BASIC_INFO_COUNT_64;
04883                if (vm_region_64(a_task, &address,
04884                                 &size, VM_REGION_BASIC_INFO,
04885                                 (vm_region_info_t)&b_info, &count,
04886                                 &object_name) != KERN_SUCCESS) {
04887                   break;
04888                }
04889 
04890                if (b_info.reserved) {
04891                   vsize -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE);
04892                   break;
04893                }
04894             }
04895          }
04896       }
04897 
04898       procinfo->fMemResident = (Long_t)(rsize / 1024);
04899       procinfo->fMemVirtual  = (Long_t)(vsize / 1024);
04900    }
04901 }
04902 #endif
04903 
04904 #if defined(R__LINUX)
04905 //______________________________________________________________________________
04906 static void GetLinuxSysInfo(SysInfo_t *sysinfo)
04907 {
04908    // Get system info for Linux. Only fBusSpeed is not set.
04909 
04910    TString s;
04911    FILE *f = fopen("/proc/cpuinfo", "r");
04912    while (s.Gets(f)) {
04913       if (s.BeginsWith("model name")) {
04914          TPRegexp("^.+: *(.*$)").Substitute(s, "$1");
04915          sysinfo->fModel = s;
04916       }
04917       if (s.BeginsWith("cpu MHz")) {
04918          TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
04919          sysinfo->fCpuSpeed = s.Atoi();
04920       }
04921       if (s.BeginsWith("cache size")) {
04922          TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
04923          sysinfo->fL2Cache = s.Atoi();
04924       }
04925       if (s.BeginsWith("processor")) {
04926          TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
04927          sysinfo->fCpus = s.Atoi();
04928          sysinfo->fCpus++;
04929       }
04930    }
04931    fclose(f);
04932 
04933    f = fopen("/proc/meminfo", "r");
04934    while (s.Gets(f)) {
04935       if (s.BeginsWith("MemTotal")) {
04936          TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
04937          sysinfo->fPhysRam = (s.Atoi() / 1024);
04938          break;
04939       }
04940    }
04941    fclose(f);
04942 
04943    f = gSystem->OpenPipe("uname -s -p", "r");
04944    s.Gets(f);
04945    Ssiz_t from = 0;
04946    s.Tokenize(sysinfo->fOS, from);
04947    s.Tokenize(sysinfo->fCpuType, from);
04948    gSystem->ClosePipe(f);
04949 }
04950 
04951 //______________________________________________________________________________
04952 static void ReadLinuxCpu(long *ticks)
04953 {
04954    // Get CPU load on Linux.
04955 
04956    ticks[0] = ticks[1] = ticks[2] = ticks[3] = 0;
04957 
04958    TString s;
04959    FILE *f = fopen("/proc/stat", "r");
04960    s.Gets(f);
04961    // user, user nice, sys, idle
04962    sscanf(s.Data(), "%*s %ld %ld %ld %ld", &ticks[0], &ticks[3], &ticks[1], &ticks[2]);
04963    fclose(f);
04964 }
04965 
04966 //______________________________________________________________________________
04967 static void GetLinuxCpuInfo(CpuInfo_t *cpuinfo, Int_t sampleTime)
04968 {
04969    // Get CPU stat for Linux. Use sampleTime to set the interval over which
04970    // the CPU load will be measured, in ms (default 1000).
04971 
04972    Double_t avg[3] = { -1., -1., -1. };
04973 #ifndef R__WINGCC
04974    if (getloadavg(avg, sizeof(avg)) < 0) {
04975       ::Error("TUnixSystem::GetLinuxCpuInfo", "getloadavg failed");
04976    } else
04977 #endif
04978    {
04979       cpuinfo->fLoad1m  = (Float_t)avg[0];
04980       cpuinfo->fLoad5m  = (Float_t)avg[1];
04981       cpuinfo->fLoad15m = (Float_t)avg[2];
04982    }
04983 
04984    Long_t cpu_ticks1[4], cpu_ticks2[4];
04985    ReadLinuxCpu(cpu_ticks1);
04986    gSystem->Sleep(sampleTime);
04987    ReadLinuxCpu(cpu_ticks2);
04988 
04989    Long_t userticks = (cpu_ticks2[0] + cpu_ticks2[3]) -
04990                       (cpu_ticks1[0] + cpu_ticks1[3]);
04991    Long_t systicks  = cpu_ticks2[1] - cpu_ticks1[1];
04992    Long_t idleticks = cpu_ticks2[2] - cpu_ticks1[2];
04993    if (userticks < 0) userticks = 0;
04994    if (systicks < 0)  systicks = 0;
04995    if (idleticks < 0) idleticks = 0;
04996    Long_t totalticks = userticks + systicks + idleticks;
04997    if (totalticks) {
04998       cpuinfo->fUser  = ((Float_t)(100 * userticks)) / ((Float_t)totalticks);
04999       cpuinfo->fSys   = ((Float_t)(100 * systicks))  / ((Float_t)totalticks);
05000       cpuinfo->fTotal = cpuinfo->fUser + cpuinfo->fSys;
05001       cpuinfo->fIdle  = ((Float_t)(100 * idleticks)) / ((Float_t)totalticks);
05002    }
05003 }
05004 
05005 //______________________________________________________________________________
05006 static void GetLinuxMemInfo(MemInfo_t *meminfo)
05007 {
05008    // Get VM stat for Linux.
05009 
05010    TString s;
05011    FILE *f = fopen("/proc/meminfo", "r");
05012    while (s.Gets(f)) {
05013       if (s.BeginsWith("MemTotal")) {
05014          TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
05015          meminfo->fMemTotal = (s.Atoi() / 1024);
05016       }
05017       if (s.BeginsWith("MemFree")) {
05018          TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
05019          meminfo->fMemFree = (s.Atoi() / 1024);
05020       }
05021       if (s.BeginsWith("SwapTotal")) {
05022          TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
05023          meminfo->fSwapTotal = (s.Atoi() / 1024);
05024       }
05025       if (s.BeginsWith("SwapFree")) {
05026          TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
05027          meminfo->fSwapFree = (s.Atoi() / 1024);
05028       }
05029    }
05030    fclose(f);
05031 
05032    meminfo->fMemUsed  = meminfo->fMemTotal - meminfo->fMemFree;
05033    meminfo->fSwapUsed = meminfo->fSwapTotal - meminfo->fSwapFree;
05034 }
05035 
05036 //______________________________________________________________________________
05037 static void GetLinuxProcInfo(ProcInfo_t *procinfo)
05038 {
05039    // Get process info for this process on Linux.
05040 
05041    struct rusage ru;
05042    if (getrusage(RUSAGE_SELF, &ru) < 0) {
05043       ::SysError("TUnixSystem::GetLinuxProcInfo", "getrusage failed");
05044    } else {
05045       procinfo->fCpuUser = (Float_t)(ru.ru_utime.tv_sec) +
05046                            ((Float_t)(ru.ru_utime.tv_usec) / 1000000.);
05047       procinfo->fCpuSys  = (Float_t)(ru.ru_stime.tv_sec) +
05048                            ((Float_t)(ru.ru_stime.tv_usec) / 1000000.);
05049    }
05050 
05051    procinfo->fMemVirtual  = -1;
05052    procinfo->fMemResident = -1;
05053    TString s;
05054    FILE *f = fopen(TString::Format("/proc/%d/statm", gSystem->GetPid()), "r");
05055    if (f) {
05056       s.Gets(f);
05057       fclose(f);
05058       Long_t total, rss;
05059       sscanf(s.Data(), "%ld %ld", &total, &rss);
05060       procinfo->fMemVirtual  = total * (getpagesize() / 1024);
05061       procinfo->fMemResident = rss * (getpagesize() / 1024);
05062    }
05063 }
05064 #endif
05065 
05066 //______________________________________________________________________________
05067 int TUnixSystem::GetSysInfo(SysInfo_t *info) const
05068 {
05069    // Returns static system info, like OS type, CPU type, number of CPUs
05070    // RAM size, etc into the SysInfo_t structure. Returns -1 in case of error,
05071    // 0 otherwise.
05072 
05073    if (!info) return -1;
05074 
05075    static SysInfo_t sysinfo;
05076 
05077    if (!sysinfo.fCpus) {
05078 #if defined(R__MACOSX)
05079       GetDarwinSysInfo(&sysinfo);
05080 #elif defined(R__LINUX)
05081       GetLinuxSysInfo(&sysinfo);
05082 #endif
05083    }
05084 
05085    *info = sysinfo;
05086 
05087    return 0;
05088 }
05089 
05090 //______________________________________________________________________________
05091 int TUnixSystem::GetCpuInfo(CpuInfo_t *info, Int_t sampleTime) const
05092 {
05093    // Returns cpu load average and load info into the CpuInfo_t structure.
05094    // Returns -1 in case of error, 0 otherwise. Use sampleTime to set the
05095    // interval over which the CPU load will be measured, in ms (default 1000).
05096 
05097    if (!info) return -1;
05098 
05099 #if defined(R__MACOSX)
05100    GetDarwinCpuInfo(info, sampleTime);
05101 #elif defined(R__LINUX)
05102    GetLinuxCpuInfo(info, sampleTime);
05103 #endif
05104 
05105    return 0;
05106 }
05107 
05108 //______________________________________________________________________________
05109 int TUnixSystem::GetMemInfo(MemInfo_t *info) const
05110 {
05111    // Returns ram and swap memory usage info into the MemInfo_t structure.
05112    // Returns -1 in case of error, 0 otherwise.
05113 
05114    if (!info) return -1;
05115 
05116 #if defined(R__MACOSX)
05117    GetDarwinMemInfo(info);
05118 #elif defined(R__LINUX)
05119    GetLinuxMemInfo(info);
05120 #endif
05121 
05122    return 0;
05123 }
05124 
05125 //______________________________________________________________________________
05126 int TUnixSystem::GetProcInfo(ProcInfo_t *info) const
05127 {
05128    // Returns cpu and memory used by this process into the ProcInfo_t structure.
05129    // Returns -1 in case of error, 0 otherwise.
05130 
05131    if (!info) return -1;
05132 
05133 #if defined(R__MACOSX)
05134    GetDarwinProcInfo(info);
05135 #elif defined(R__LINUX)
05136    GetLinuxProcInfo(info);
05137 #endif
05138 
05139    return 0;
05140 }

Generated on Tue Jul 5 14:12:03 2011 for ROOT_528-00b_version by  doxygen 1.5.1