Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TUnixSystem.cxx
Go to the documentation of this file.
1 // @(#)root/unix:$Id: 887c618d89c4ed436e4034fc133f468fecad651b $
2 // Author: Fons Rademakers 15/09/95
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //////////////////////////////////////////////////////////////////////////
13 // //
14 // TUnixSystem //
15 // //
16 // Class providing an interface to the UNIX Operating System. //
17 // //
18 //////////////////////////////////////////////////////////////////////////
19 
20 #include "RConfigure.h"
21 #include <ROOT/RConfig.hxx>
22 #include <ROOT/FoundationUtils.hxx>
23 #include "TUnixSystem.h"
24 #include "TROOT.h"
25 #include "TError.h"
26 #include "TOrdCollection.h"
27 #include "TRegexp.h"
28 #include "TPRegexp.h"
29 #include "TException.h"
30 #include "Demangle.h"
31 #include "TEnv.h"
32 #include "Getline.h"
33 #include "TInterpreter.h"
34 #include "TApplication.h"
35 #include "TObjString.h"
36 #include "Riostream.h"
37 #include "TVirtualMutex.h"
38 #include "TObjArray.h"
39 #include <map>
40 #include <algorithm>
41 #include <atomic>
42 
43 //#define G__OLDEXPAND
44 
45 #include <unistd.h>
46 #include <stdlib.h>
47 #include <sys/types.h>
48 #if defined(R__SUN) || defined(R__AIX) || \
49  defined(R__LINUX) || defined(R__SOLARIS) || \
50  defined(R__FBSD) || defined(R__OBSD) || \
51  defined(R__MACOSX) || defined(R__HURD)
52 #define HAS_DIRENT
53 #endif
54 #ifdef HAS_DIRENT
55 # include <dirent.h>
56 #else
57 # include <sys/dir.h>
58 #endif
59 #if defined(ULTRIX) || defined(R__SUN)
60 # include <sgtty.h>
61 #endif
62 #if defined(R__AIX) || defined(R__LINUX) || \
63  defined(R__FBSD) || defined(R__OBSD) || \
64  defined(R__LYNXOS) || defined(R__MACOSX) || defined(R__HURD)
65 # include <sys/ioctl.h>
66 #endif
67 #if defined(R__AIX) || defined(R__SOLARIS)
68 # include <sys/select.h>
69 #endif
70 #if defined(R__MACOSX)
71 # include <mach-o/dyld.h>
72 # include <sys/mount.h>
73  extern "C" int statfs(const char *file, struct statfs *buffer);
74 #elif defined(R__LINUX) || defined(R__HURD)
75 # include <sys/vfs.h>
76 #elif defined(R__FBSD) || defined(R__OBSD)
77 # include <sys/param.h>
78 # include <sys/mount.h>
79 #else
80 # include <sys/statfs.h>
81 #endif
82 
83 #include <utime.h>
84 #include <syslog.h>
85 #include <sys/stat.h>
86 #include <setjmp.h>
87 #include <signal.h>
88 #include <sys/param.h>
89 #include <pwd.h>
90 #include <grp.h>
91 #include <errno.h>
92 #include <sys/resource.h>
93 #include <sys/wait.h>
94 #include <time.h>
95 #include <sys/time.h>
96 #include <sys/file.h>
97 #include <sys/socket.h>
98 #include <netinet/in.h>
99 #include <netinet/tcp.h>
100 #if defined(R__AIX)
101 # define _XOPEN_EXTENDED_SOURCE
102 # include <arpa/inet.h>
103 # undef _XOPEN_EXTENDED_SOURCE
104 # if !defined(_AIX41) && !defined(_AIX43)
105  // AIX 3.2 doesn't have it
106 # define HASNOT_INETATON
107 # endif
108 #else
109 # include <arpa/inet.h>
110 #endif
111 #include <sys/un.h>
112 #include <netdb.h>
113 #include <fcntl.h>
114 #if defined(R__SOLARIS)
115 # include <sys/systeminfo.h>
116 # include <sys/filio.h>
117 # include <sys/sockio.h>
118 # define HASNOT_INETATON
119 # ifndef INADDR_NONE
120 # define INADDR_NONE (UInt_t)-1
121 # endif
122 #endif
123 
124 #if defined(R__SOLARIS)
125 # define HAVE_UTMPX_H
126 # define UTMP_NO_ADDR
127 #endif
128 
129 #if defined(MAC_OS_X_VERSION_10_5)
130 # define HAVE_UTMPX_H
131 # define UTMP_NO_ADDR
132 #endif
133 
134 #if defined(R__FBSD)
135 # include <sys/param.h>
136 # if __FreeBSD_version >= 900007
137 # define HAVE_UTMPX_H
138 # endif
139 #endif
140 
141 #if defined(R__AIX) || defined(R__FBSD) || \
142  defined(R__OBSD) || defined(R__LYNXOS) || \
143  (defined(R__MACOSX) && !defined(MAC_OS_X_VERSION_10_5))
144 # define UTMP_NO_ADDR
145 #endif
146 
147 #if (defined(R__AIX) && !defined(_AIX43)) || \
148  (defined(R__SUNGCC3) && !defined(__arch64__))
149 # define USE_SIZE_T
150 #elif defined(R__GLIBC) || defined(R__FBSD) || \
151  (defined(R__SUNGCC3) && defined(__arch64__)) || \
152  defined(R__OBSD) || defined(MAC_OS_X_VERSION_10_4) || \
153  (defined(R__AIX) && defined(_AIX43)) || \
154  (defined(R__SOLARIS) && defined(_SOCKLEN_T))
155 # define USE_SOCKLEN_T
156 #endif
157 
158 #if defined(R__LYNXOS)
159 extern "C" {
160  extern int putenv(const char *);
161  extern int inet_aton(const char *, struct in_addr *);
162 };
163 #endif
164 
165 #ifdef HAVE_UTMPX_H
166 #include <utmpx.h>
167 #define STRUCT_UTMP struct utmpx
168 #else
169 #include <utmp.h>
170 #define STRUCT_UTMP struct utmp
171 #endif
172 #if !defined(UTMP_FILE) && defined(_PATH_UTMP) // 4.4BSD
173 #define UTMP_FILE _PATH_UTMP
174 #endif
175 #if defined(UTMPX_FILE) // Solaris, SysVr4
176 #undef UTMP_FILE
177 #define UTMP_FILE UTMPX_FILE
178 #endif
179 #ifndef UTMP_FILE
180 #define UTMP_FILE "/etc/utmp"
181 #endif
182 
183 // stack trace code
184 #if (defined(R__LINUX) || defined(R__HURD)) && !defined(R__WINGCC)
185 # if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1
186 # define HAVE_BACKTRACE_SYMBOLS_FD
187 # endif
188 # define HAVE_DLADDR
189 #endif
190 #if defined(R__MACOSX)
191 # define HAVE_BACKTRACE_SYMBOLS_FD
192 # define HAVE_DLADDR
193 #endif
194 
195 #ifdef HAVE_BACKTRACE_SYMBOLS_FD
196 # include <execinfo.h>
197 #endif
198 #ifdef HAVE_DLADDR
199 # ifndef __USE_GNU
200 # define __USE_GNU
201 # endif
202 # include <dlfcn.h>
203 #endif
204 
205 #ifdef HAVE_BACKTRACE_SYMBOLS_FD
206  // The maximum stack trace depth for systems where we request the
207  // stack depth separately (currently glibc-based systems).
208  static const int kMAX_BACKTRACE_DEPTH = 128;
209 #endif
210 
211 // FPE handling includes
212 #if (defined(R__LINUX) && !defined(R__WINGCC))
213 #include <fpu_control.h>
214 #include <fenv.h>
215 #include <sys/prctl.h> // for prctl() function used in StackTrace()
216 #endif
217 
218 #if defined(R__MACOSX) && defined(__SSE2__)
219 #include <xmmintrin.h>
220 #endif
221 
222 #if defined(R__MACOSX) && !defined(__SSE2__) && !defined(__xlC__) && \
223  !defined(__i386__) && !defined(__x86_64__) && !defined(__arm__) && \
224  !defined(__arm64__)
225 #include <fenv.h>
226 #include <signal.h>
227 #include <ucontext.h>
228 #include <stdlib.h>
229 #include <stdio.h>
230 #include <mach/thread_status.h>
231 
232 #define fegetenvd(x) asm volatile("mffs %0" : "=f" (x));
233 #define fesetenvd(x) asm volatile("mtfsf 255,%0" : : "f" (x));
234 
235 enum {
236  FE_ENABLE_INEXACT = 0x00000008,
237  FE_ENABLE_DIVBYZERO = 0x00000010,
238  FE_ENABLE_UNDERFLOW = 0x00000020,
239  FE_ENABLE_OVERFLOW = 0x00000040,
240  FE_ENABLE_INVALID = 0x00000080,
241  FE_ENABLE_ALL_EXCEPT = 0x000000F8
242 };
243 #endif
244 
245 #if defined(R__MACOSX) && !defined(__SSE2__) && \
246  (defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__))
247 #include <fenv.h>
248 #endif
249 // End FPE handling includes
250 
251 namespace {
252  // Depending on the platform the struct utmp (or utmpx) has either ut_name or ut_user
253  // which are semantically equivalent. Instead of using preprocessor magic,
254  // which is bothersome for cxx modules use SFINAE.
255 
256  template<typename T>
257  struct ut_name {
258  template<typename U = T, typename std::enable_if<std::is_member_pointer<decltype(&U::ut_name)>::value, int>::type = 0>
259  static char getValue(U* ue, int) {
260  return ue->ut_name[0];
261  }
262 
263  template<typename U = T, typename std::enable_if<std::is_member_pointer<decltype(&U::ut_user)>::value, int>::type = 0>
264  static char getValue(U* ue, long) {
265  return ue->ut_user[0];
266  }
267  };
268 
269  static char get_ut_name(STRUCT_UTMP *ue) {
270  // 0 is an integer literal forcing an overload pickup in case both ut_name and ut_user are present.
271  return ut_name<STRUCT_UTMP>::getValue(ue, 0);
272  }
273 }
274 
275 struct TUtmpContent {
276  STRUCT_UTMP *fUtmpContents;
277  UInt_t fEntries; // Number of entries in utmp file.
278 
279  TUtmpContent() : fUtmpContents(0), fEntries(0) {}
280  ~TUtmpContent() { free(fUtmpContents); }
281 
282  STRUCT_UTMP *SearchUtmpEntry(const char *tty)
283  {
284  // Look for utmp entry which is connected to terminal tty.
285 
286  STRUCT_UTMP *ue = fUtmpContents;
287 
288  UInt_t n = fEntries;
289  while (n--) {
290  if (get_ut_name(ue) && !strncmp(tty, ue->ut_line, sizeof(ue->ut_line)))
291  return ue;
292  ue++;
293  }
294  return 0;
295  }
296 
297  int ReadUtmpFile()
298  {
299  // Read utmp file. Returns number of entries in utmp file.
300 
301  FILE *utmp;
302  struct stat file_stats;
303  size_t n_read, size;
304 
305  fEntries = 0;
306 
307  R__LOCKGUARD2(gSystemMutex);
308 
309  utmp = fopen(UTMP_FILE, "r");
310  if (!utmp)
311  return 0;
312 
313  if (fstat(fileno(utmp), &file_stats) == -1) {
314  fclose(utmp);
315  return 0;
316  }
317  size = file_stats.st_size;
318  if (size <= 0) {
319  fclose(utmp);
320  return 0;
321  }
322 
323  fUtmpContents = (STRUCT_UTMP *) malloc(size);
324  if (!fUtmpContents) {
325  fclose(utmp);
326  return 0;
327  }
328 
329  n_read = fread(fUtmpContents, 1, size, utmp);
330  if (!ferror(utmp)) {
331  if (fclose(utmp) != EOF && n_read == size) {
332  fEntries = size / sizeof(STRUCT_UTMP);
333  return fEntries;
334  }
335  } else
336  fclose(utmp);
337 
338  free(fUtmpContents);
339  fUtmpContents = 0;
340  return 0;
341  }
342 
343 };
344 
345 const char *kServerPath = "/tmp";
346 const char *kProtocolName = "tcp";
347 
348 //------------------- Unix TFdSet ----------------------------------------------
349 #ifndef HOWMANY
350 # define HOWMANY(x, y) (((x)+((y)-1))/(y))
351 #endif
352 
353 const Int_t kNFDBITS = (sizeof(Long_t) * 8); // 8 bits per byte
354 #ifdef FD_SETSIZE
355 const Int_t kFDSETSIZE = FD_SETSIZE; // Linux = 1024 file descriptors
356 #else
357 const Int_t kFDSETSIZE = 256; // upto 256 file descriptors
358 #endif
359 
360 
361 class TFdSet {
362 private:
363  ULong_t fds_bits[HOWMANY(kFDSETSIZE, kNFDBITS)];
364 public:
365  TFdSet() { memset(fds_bits, 0, sizeof(fds_bits)); }
366  TFdSet(const TFdSet &org) { memcpy(fds_bits, org.fds_bits, sizeof(org.fds_bits)); }
367  TFdSet &operator=(const TFdSet &rhs) { if (this != &rhs) { memcpy(fds_bits, rhs.fds_bits, sizeof(rhs.fds_bits));} return *this; }
368  void Zero() { memset(fds_bits, 0, sizeof(fds_bits)); }
369  void Set(Int_t n)
370  {
371  if (n >= 0 && n < kFDSETSIZE) {
372  fds_bits[n/kNFDBITS] |= (1UL << (n % kNFDBITS));
373  } else {
374  ::Fatal("TFdSet::Set","fd (%d) out of range [0..%d]", n, kFDSETSIZE-1);
375  }
376  }
377  void Clr(Int_t n)
378  {
379  if (n >= 0 && n < kFDSETSIZE) {
380  fds_bits[n/kNFDBITS] &= ~(1UL << (n % kNFDBITS));
381  } else {
382  ::Fatal("TFdSet::Clr","fd (%d) out of range [0..%d]", n, kFDSETSIZE-1);
383  }
384  }
385  Int_t IsSet(Int_t n)
386  {
387  if (n >= 0 && n < kFDSETSIZE) {
388  return (fds_bits[n/kNFDBITS] & (1UL << (n % kNFDBITS))) != 0;
389  } else {
390  ::Fatal("TFdSet::IsSet","fd (%d) out of range [0..%d]", n, kFDSETSIZE-1);
391  return 0;
392  }
393  }
394  ULong_t *GetBits() { return (ULong_t *)fds_bits; }
395 };
396 
397 ////////////////////////////////////////////////////////////////////////////////
398 /// Unix signal handler.
399 
400 static void SigHandler(ESignals sig)
401 {
402  if (gSystem)
403  ((TUnixSystem*)gSystem)->DispatchSignals(sig);
404 }
405 
406 ////////////////////////////////////////////////////////////////////////////////
407 
408 static const char *GetExePath()
409 {
410  TTHREAD_TLS_DECL(TString,exepath);
411  if (exepath == "") {
412 #if defined(R__MACOSX)
413  exepath = _dyld_get_image_name(0);
414 #elif defined(R__LINUX) || defined(R__SOLARIS) || defined(R__FBSD)
415  char buf[kMAXPATHLEN]; // exe path name
416 
417  // get the name from the link in /proc
418 #if defined(R__LINUX)
419  int ret = readlink("/proc/self/exe", buf, kMAXPATHLEN);
420 #elif defined(R__SOLARIS)
421  int ret = readlink("/proc/self/path/a.out", buf, kMAXPATHLEN);
422 #elif defined(R__FBSD)
423  int ret = readlink("/proc/curproc/file", buf, kMAXPATHLEN);
424 #endif
425  if (ret > 0 && ret < kMAXPATHLEN) {
426  buf[ret] = 0;
427  exepath = buf;
428  }
429 #else
430  if (!gApplication)
431  return exepath;
432  TString p = gApplication->Argv(0);
433  if (p.BeginsWith("/"))
434  exepath = p;
435  else if (p.Contains("/")) {
436  exepath = gSystem->WorkingDirectory();
437  exepath += "/";
438  exepath += p;
439  } else {
440  char *exe = gSystem->Which(gSystem->Getenv("PATH"), p, kExecutePermission);
441  if (exe) {
442  exepath = exe;
443  delete [] exe;
444  }
445  }
446 #endif
447  }
448  return exepath;
449 }
450 
451 #if defined(HAVE_DLADDR) && !defined(R__MACOSX)
452 ////////////////////////////////////////////////////////////////////////////////
453 
454 static void SetRootSys()
455 {
456 #ifdef ROOTPREFIX
457  if (gSystem->Getenv("ROOTIGNOREPREFIX")) {
458 #endif
459  void *addr = (void *)SetRootSys;
460  Dl_info info;
461  if (dladdr(addr, &info) && info.dli_fname && info.dli_fname[0]) {
462  char respath[kMAXPATHLEN];
463  if (!realpath(info.dli_fname, respath)) {
464  if (!gSystem->Getenv("ROOTSYS"))
465  ::SysError("TUnixSystem::SetRootSys", "error getting realpath of libCore, please set ROOTSYS in the shell");
466  } else {
467  TString rs = gSystem->DirName(respath);
468  gSystem->Setenv("ROOTSYS", gSystem->DirName(rs));
469  }
470  }
471 #ifdef ROOTPREFIX
472  }
473 #endif
474 }
475 #endif
476 
477 #if defined(R__MACOSX)
478 static TString gLinkedDylibs;
479 
480 ////////////////////////////////////////////////////////////////////////////////
481 
482 static void DylibAdded(const struct mach_header *mh, intptr_t /* vmaddr_slide */)
483 {
484  static int i = 0;
485  static Bool_t gotFirstSo = kFALSE;
486  static TString linkedDylibs;
487 
488  // to copy the local linkedDylibs to the global gLinkedDylibs call this
489  // function with mh==0
490  if (!mh) {
491  gLinkedDylibs = linkedDylibs;
492  return;
493  }
494 
495  TString lib = _dyld_get_image_name(i++);
496 
497  TRegexp sovers = "libCore\\.[0-9]+\\.*[0-9]*\\.*[0-9]*\\.so";
498  TRegexp dyvers = "libCore\\.[0-9]+\\.*[0-9]*\\.*[0-9]*\\.dylib";
499 
500 #ifdef ROOTPREFIX
501  if (gSystem->Getenv("ROOTIGNOREPREFIX")) {
502 #endif
503  if (lib.EndsWith("libCore.dylib") || lib.EndsWith("libCore.so") ||
504  lib.Index(sovers) != kNPOS || lib.Index(dyvers) != kNPOS) {
505  char respath[kMAXPATHLEN];
506  if (!realpath(lib, respath)) {
507  if (!gSystem->Getenv("ROOTSYS"))
508  ::SysError("TUnixSystem::DylibAdded", "error getting realpath of libCore, please set ROOTSYS in the shell");
509  } else {
510  TString rs = gSystem->DirName(respath);
511  gSystem->Setenv("ROOTSYS", gSystem->DirName(rs));
512  }
513  }
514 #ifdef ROOTPREFIX
515  }
516 #endif
517 
518  // when libSystem.B.dylib is loaded we have finished loading all dylibs
519  // explicitly linked against the executable. Additional dylibs
520  // come when they are explicitly linked against loaded so's, currently
521  // we are not interested in these
522  if (lib.EndsWith("/libSystem.B.dylib"))
523  gotFirstSo = kTRUE;
524 
525  // add all libs loaded before libSystem.B.dylib
526  if (!gotFirstSo && (lib.EndsWith(".dylib") || lib.EndsWith(".so"))) {
527  sovers = "\\.[0-9]+\\.*[0-9]*\\.so";
528  Ssiz_t idx = lib.Index(sovers);
529  if (idx != kNPOS) {
530  lib.Remove(idx);
531  lib += ".so";
532  }
533  dyvers = "\\.[0-9]+\\.*[0-9]*\\.dylib";
534  idx = lib.Index(dyvers);
535  if (idx != kNPOS) {
536  lib.Remove(idx);
537  lib += ".dylib";
538  }
539  if (!gSystem->AccessPathName(lib, kReadPermission)) {
540  if (linkedDylibs.Length())
541  linkedDylibs += " ";
542  linkedDylibs += lib;
543  }
544  }
545 }
546 #endif
547 
548 ClassImp(TUnixSystem);
549 
550 ////////////////////////////////////////////////////////////////////////////////
551 
552 TUnixSystem::TUnixSystem() : TSystem("Unix", "Unix System")
553 { }
554 
555 ////////////////////////////////////////////////////////////////////////////////
556 /// Reset to original state.
557 
558 TUnixSystem::~TUnixSystem()
559 {
560  UnixResetSignals();
561 
562  delete fReadmask;
563  delete fWritemask;
564  delete fReadready;
565  delete fWriteready;
566  delete fSignals;
567 }
568 
569 ////////////////////////////////////////////////////////////////////////////////
570 /// Initialize Unix system interface.
571 
572 Bool_t TUnixSystem::Init()
573 {
574  if (TSystem::Init())
575  return kTRUE;
576 
577  fReadmask = new TFdSet;
578  fWritemask = new TFdSet;
579  fReadready = new TFdSet;
580  fWriteready = new TFdSet;
581  fSignals = new TFdSet;
582 
583  //--- install default handlers
584  UnixSignal(kSigChild, SigHandler);
585  UnixSignal(kSigBus, SigHandler);
586  UnixSignal(kSigSegmentationViolation, SigHandler);
587  UnixSignal(kSigIllegalInstruction, SigHandler);
588  UnixSignal(kSigSystem, SigHandler);
589  UnixSignal(kSigAlarm, SigHandler);
590  UnixSignal(kSigUrgent, SigHandler);
591  UnixSignal(kSigFloatingException, SigHandler);
592  UnixSignal(kSigWindowChanged, SigHandler);
593  UnixSignal(kSigUser2, SigHandler);
594 
595 #if defined(R__MACOSX)
596  // trap loading of all dylibs to register dylib name,
597  // sets also ROOTSYS if built without ROOTPREFIX
598  _dyld_register_func_for_add_image(DylibAdded);
599 #elif defined(HAVE_DLADDR)
600  SetRootSys();
601 #endif
602 
603  // This is a fallback in case TROOT::GetRootSys() can't determine ROOTSYS
604  gRootDir = ROOT::FoundationUtils::GetFallbackRootSys().c_str();
605 
606  return kFALSE;
607 }
608 
609 //---- Misc --------------------------------------------------------------------
610 
611 ////////////////////////////////////////////////////////////////////////////////
612 /// Set the application name (from command line, argv[0]) and copy it in
613 /// gProgName. Copy the application pathname in gProgPath.
614 /// If name is 0 let the system set the actual executable name and path
615 /// (works on MacOS X and Linux).
616 
617 void TUnixSystem::SetProgname(const char *name)
618 {
619  if (gProgName)
620  delete [] gProgName;
621  if (gProgPath)
622  delete [] gProgPath;
623 
624  if (!name || !*name) {
625  name = GetExePath();
626  gProgName = StrDup(BaseName(name));
627  gProgPath = StrDup(DirName(name));
628  } else {
629  gProgName = StrDup(BaseName(name));
630  char *w = Which(Getenv("PATH"), gProgName);
631  gProgPath = StrDup(DirName(w));
632  delete [] w;
633  }
634 }
635 
636 ////////////////////////////////////////////////////////////////////////////////
637 /// Set DISPLAY environment variable based on utmp entry. Only for UNIX.
638 
639 void TUnixSystem::SetDisplay()
640 {
641  if (!Getenv("DISPLAY")) {
642  char *tty = ::ttyname(0); // device user is logged in on
643  if (tty) {
644  tty += 5; // remove "/dev/"
645 
646  TUtmpContent utmp;
647  utmp.ReadUtmpFile();
648 
649  STRUCT_UTMP *utmp_entry = utmp.SearchUtmpEntry(tty);
650  if (utmp_entry) {
651  if (utmp_entry->ut_host[0]) {
652  if (strchr(utmp_entry->ut_host, ':')) {
653  Setenv("DISPLAY", utmp_entry->ut_host);
654  Warning("SetDisplay", "DISPLAY not set, setting it to %s",
655  utmp_entry->ut_host);
656  } else {
657  char disp[260];
658  snprintf(disp, sizeof(disp), "%s:0.0", utmp_entry->ut_host);
659  Setenv("DISPLAY", disp);
660  Warning("SetDisplay", "DISPLAY not set, setting it to %s",
661  disp);
662  }
663  }
664 #ifndef UTMP_NO_ADDR
665  else if (utmp_entry->ut_addr) {
666 
667  struct sockaddr_in addr;
668  addr.sin_family = AF_INET;
669  addr.sin_port = 0;
670  memcpy(&addr.sin_addr, &utmp_entry->ut_addr, sizeof(addr.sin_addr));
671  memset(&addr.sin_zero[0], 0, sizeof(addr.sin_zero));
672  struct sockaddr *sa = (struct sockaddr *) &addr; // input
673 
674  char hbuf[NI_MAXHOST + 4];
675  if (getnameinfo(sa, sizeof(struct sockaddr), hbuf, sizeof(hbuf), nullptr, 0, NI_NAMEREQD) == 0) {
676  assert( strlen(hbuf) < NI_MAXHOST );
677  strcat(hbuf, ":0.0");
678  Setenv("DISPLAY", hbuf);
679  Warning("SetDisplay", "DISPLAY not set, setting it to %s",
680  hbuf);
681  }
682  }
683 #endif
684  }
685  }
686 #ifndef R__HAS_COCOA
687  if (!gROOT->IsBatch() && !getenv("DISPLAY")) {
688  Error("SetDisplay", "Can't figure out DISPLAY, set it manually\n"
689  "In case you run a remote ssh session, restart your ssh session with:\n"
690  "=========> ssh -Y");
691  }
692 #endif
693  }
694 }
695 
696 ////////////////////////////////////////////////////////////////////////////////
697 /// Return system error string.
698 
699 const char *TUnixSystem::GetError()
700 {
701  Int_t err = GetErrno();
702  if (err == 0 && GetLastErrorString() != "")
703  return GetLastErrorString();
704 
705 #if defined(R__SOLARIS) || defined (R__LINUX) || defined(R__AIX) || \
706  defined(R__FBSD) || defined(R__OBSD) || defined(R__HURD)
707  return strerror(err);
708 #else
709  if (err < 0 || err >= sys_nerr)
710  return Form("errno out of range %d", err);
711  return sys_errlist[err];
712 #endif
713 }
714 
715 ////////////////////////////////////////////////////////////////////////////////
716 /// Return the system's host name.
717 
718 const char *TUnixSystem::HostName()
719 {
720  if (fHostname == "") {
721  char hn[64];
722 #if defined(R__SOLARIS)
723  sysinfo(SI_HOSTNAME, hn, sizeof(hn));
724 #else
725  gethostname(hn, sizeof(hn));
726 #endif
727  fHostname = hn;
728  }
729  return (const char *)fHostname;
730 }
731 
732 //---- EventLoop ---------------------------------------------------------------
733 
734 ////////////////////////////////////////////////////////////////////////////////
735 /// Add a file handler to the list of system file handlers. Only adds
736 /// the handler if it is not already in the list of file handlers.
737 
738 void TUnixSystem::AddFileHandler(TFileHandler *h)
739 {
740  R__LOCKGUARD2(gSystemMutex);
741 
742  TSystem::AddFileHandler(h);
743  if (h) {
744  int fd = h->GetFd();
745  if (h->HasReadInterest()) {
746  fReadmask->Set(fd);
747  fMaxrfd = TMath::Max(fMaxrfd, fd);
748  }
749  if (h->HasWriteInterest()) {
750  fWritemask->Set(fd);
751  fMaxwfd = TMath::Max(fMaxwfd, fd);
752  }
753  }
754 }
755 
756 ////////////////////////////////////////////////////////////////////////////////
757 /// Remove a file handler from the list of file handlers. Returns
758 /// the handler or 0 if the handler was not in the list of file handlers.
759 
760 TFileHandler *TUnixSystem::RemoveFileHandler(TFileHandler *h)
761 {
762  if (!h) return 0;
763 
764  R__LOCKGUARD2(gSystemMutex);
765 
766  TFileHandler *oh = TSystem::RemoveFileHandler(h);
767  if (oh) { // found
768  TFileHandler *th;
769  TIter next(fFileHandler);
770  fMaxrfd = -1;
771  fMaxwfd = -1;
772  fReadmask->Zero();
773  fWritemask->Zero();
774  while ((th = (TFileHandler *) next())) {
775  int fd = th->GetFd();
776  if (th->HasReadInterest()) {
777  fReadmask->Set(fd);
778  fMaxrfd = TMath::Max(fMaxrfd, fd);
779  }
780  if (th->HasWriteInterest()) {
781  fWritemask->Set(fd);
782  fMaxwfd = TMath::Max(fMaxwfd, fd);
783  }
784  }
785  }
786  return oh;
787 }
788 
789 ////////////////////////////////////////////////////////////////////////////////
790 /// Add a signal handler to list of system signal handlers. Only adds
791 /// the handler if it is not already in the list of signal handlers.
792 
793 void TUnixSystem::AddSignalHandler(TSignalHandler *h)
794 {
795  R__LOCKGUARD2(gSystemMutex);
796 
797  TSystem::AddSignalHandler(h);
798  UnixSignal(h->GetSignal(), SigHandler);
799 }
800 
801 ////////////////////////////////////////////////////////////////////////////////
802 /// Remove a signal handler from list of signal handlers. Returns
803 /// the handler or 0 if the handler was not in the list of signal handlers.
804 
805 TSignalHandler *TUnixSystem::RemoveSignalHandler(TSignalHandler *h)
806 {
807  if (!h) return 0;
808 
809  R__LOCKGUARD2(gSystemMutex);
810 
811  TSignalHandler *oh = TSystem::RemoveSignalHandler(h);
812 
813  Bool_t last = kTRUE;
814  TSignalHandler *hs;
815  TIter next(fSignalHandler);
816 
817  while ((hs = (TSignalHandler*) next())) {
818  if (hs->GetSignal() == h->GetSignal())
819  last = kFALSE;
820  }
821  if (last)
822  ResetSignal(h->GetSignal(), kTRUE);
823 
824  return oh;
825 }
826 
827 ////////////////////////////////////////////////////////////////////////////////
828 /// If reset is true reset the signal handler for the specified signal
829 /// to the default handler, else restore previous behaviour.
830 
831 void TUnixSystem::ResetSignal(ESignals sig, Bool_t reset)
832 {
833  if (reset)
834  UnixResetSignal(sig);
835  else
836  UnixSignal(sig, SigHandler);
837 }
838 
839 ////////////////////////////////////////////////////////////////////////////////
840 /// Reset signals handlers to previous behaviour.
841 
842 void TUnixSystem::ResetSignals()
843 {
844  UnixResetSignals();
845 }
846 
847 ////////////////////////////////////////////////////////////////////////////////
848 /// If ignore is true ignore the specified signal, else restore previous
849 /// behaviour.
850 
851 void TUnixSystem::IgnoreSignal(ESignals sig, Bool_t ignore)
852 {
853  UnixIgnoreSignal(sig, ignore);
854 }
855 
856 ////////////////////////////////////////////////////////////////////////////////
857 /// When the argument is true the SIGALRM signal handler is set so that
858 /// interrupted syscalls will not be restarted by the kernel. This is
859 /// typically used in case one wants to put a timeout on an I/O operation.
860 /// By default interrupted syscalls will always be restarted (for all
861 /// signals). This can be controlled for each a-synchronous TTimer via
862 /// the method TTimer::SetInterruptSyscalls().
863 
864 void TUnixSystem::SigAlarmInterruptsSyscalls(Bool_t set)
865 {
866  UnixSigAlarmInterruptsSyscalls(set);
867 }
868 
869 ////////////////////////////////////////////////////////////////////////////////
870 /// Return the bitmap of conditions that trigger a floating point exception.
871 
872 Int_t TUnixSystem::GetFPEMask()
873 {
874  Int_t mask = 0;
875 
876 #if defined(R__LINUX) && !defined(__powerpc__)
877 #if defined(__GLIBC__) && (__GLIBC__>2 || __GLIBC__==2 && __GLIBC_MINOR__>=1)
878 
879 #if __GLIBC_MINOR__>=3
880 
881  Int_t oldmask = fegetexcept();
882 
883 #else
884  fenv_t oldenv;
885  fegetenv(&oldenv);
886  fesetenv(&oldenv);
887 #if __ia64__
888  Int_t oldmask = ~oldenv;
889 #else
890  Int_t oldmask = ~oldenv.__control_word;
891 #endif
892 #endif
893 
894  if (oldmask & FE_INVALID ) mask |= kInvalid;
895  if (oldmask & FE_DIVBYZERO) mask |= kDivByZero;
896  if (oldmask & FE_OVERFLOW ) mask |= kOverflow;
897  if (oldmask & FE_UNDERFLOW) mask |= kUnderflow;
898 # ifdef FE_INEXACT
899  if (oldmask & FE_INEXACT ) mask |= kInexact;
900 # endif
901 #endif
902 #endif
903 
904 #if defined(R__MACOSX) && defined(__SSE2__)
905  // OS X uses the SSE unit for all FP math by default, not the x87 FP unit
906  Int_t oldmask = ~_MM_GET_EXCEPTION_MASK();
907 
908  if (oldmask & _MM_MASK_INVALID ) mask |= kInvalid;
909  if (oldmask & _MM_MASK_DIV_ZERO ) mask |= kDivByZero;
910  if (oldmask & _MM_MASK_OVERFLOW ) mask |= kOverflow;
911  if (oldmask & _MM_MASK_UNDERFLOW) mask |= kUnderflow;
912  if (oldmask & _MM_MASK_INEXACT ) mask |= kInexact;
913 #endif
914 
915 #if defined(R__MACOSX) && !defined(__SSE2__) && \
916  (defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__))
917  fenv_t oldenv;
918  fegetenv(&oldenv);
919  fesetenv(&oldenv);
920 #if defined(__arm__)
921  Int_t oldmask = ~oldenv.__fpscr;
922 #elif defined(__arm64__)
923  Int_t oldmask = ~oldenv.__fpcr;
924 #else
925  Int_t oldmask = ~oldenv.__control;
926 #endif
927 
928  if (oldmask & FE_INVALID ) mask |= kInvalid;
929  if (oldmask & FE_DIVBYZERO) mask |= kDivByZero;
930  if (oldmask & FE_OVERFLOW ) mask |= kOverflow;
931  if (oldmask & FE_UNDERFLOW) mask |= kUnderflow;
932  if (oldmask & FE_INEXACT ) mask |= kInexact;
933 #endif
934 
935 #if defined(R__MACOSX) && !defined(__SSE2__) && !defined(__xlC__) && \
936  !defined(__i386__) && !defined(__x86_64__) && !defined(__arm__) && \
937  !defined(__arm64__)
938  Long64_t oldmask;
939  fegetenvd(oldmask);
940 
941  if (oldmask & FE_ENABLE_INVALID ) mask |= kInvalid;
942  if (oldmask & FE_ENABLE_DIVBYZERO) mask |= kDivByZero;
943  if (oldmask & FE_ENABLE_OVERFLOW ) mask |= kOverflow;
944  if (oldmask & FE_ENABLE_UNDERFLOW) mask |= kUnderflow;
945  if (oldmask & FE_ENABLE_INEXACT ) mask |= kInexact;
946 #endif
947 
948  return mask;
949 }
950 
951 ////////////////////////////////////////////////////////////////////////////////
952 /// Set which conditions trigger a floating point exception.
953 /// Return the previous set of conditions.
954 
955 Int_t TUnixSystem::SetFPEMask(Int_t mask)
956 {
957  if (mask) { } // use mask to avoid warning
958 
959  Int_t old = GetFPEMask();
960 
961 #if defined(R__LINUX) && !defined(__powerpc__)
962 #if defined(__GLIBC__) && (__GLIBC__>2 || __GLIBC__==2 && __GLIBC_MINOR__>=1)
963  Int_t newm = 0;
964  if (mask & kInvalid ) newm |= FE_INVALID;
965  if (mask & kDivByZero) newm |= FE_DIVBYZERO;
966  if (mask & kOverflow ) newm |= FE_OVERFLOW;
967  if (mask & kUnderflow) newm |= FE_UNDERFLOW;
968 # ifdef FE_INEXACT
969  if (mask & kInexact ) newm |= FE_INEXACT;
970 # endif
971 
972 #if __GLIBC_MINOR__>=3
973 
974  // clear pending exceptions so feenableexcept does not trigger them
975  feclearexcept(FE_ALL_EXCEPT);
976  fedisableexcept(FE_ALL_EXCEPT);
977  feenableexcept(newm);
978 
979 #else
980 
981  fenv_t cur;
982  fegetenv(&cur);
983 #if defined __ia64__
984  cur &= ~newm;
985 #else
986  cur.__control_word &= ~newm;
987 #endif
988  fesetenv(&cur);
989 
990 #endif
991 #endif
992 #endif
993 
994 #if defined(R__MACOSX) && defined(__SSE2__)
995  // OS X uses the SSE unit for all FP math by default, not the x87 FP unit
996  Int_t newm = 0;
997  if (mask & kInvalid ) newm |= _MM_MASK_INVALID;
998  if (mask & kDivByZero) newm |= _MM_MASK_DIV_ZERO;
999  if (mask & kOverflow ) newm |= _MM_MASK_OVERFLOW;
1000  if (mask & kUnderflow) newm |= _MM_MASK_UNDERFLOW;
1001  if (mask & kInexact ) newm |= _MM_MASK_INEXACT;
1002 
1003  _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~newm);
1004 #endif
1005 
1006 #if defined(R__MACOSX) && !defined(__SSE2__) && \
1007  (defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__))
1008  Int_t newm = 0;
1009  if (mask & kInvalid ) newm |= FE_INVALID;
1010  if (mask & kDivByZero) newm |= FE_DIVBYZERO;
1011  if (mask & kOverflow ) newm |= FE_OVERFLOW;
1012  if (mask & kUnderflow) newm |= FE_UNDERFLOW;
1013  if (mask & kInexact ) newm |= FE_INEXACT;
1014 
1015  fenv_t cur;
1016  fegetenv(&cur);
1017 #if defined(__arm__)
1018  cur.__fpscr &= ~newm;
1019 #elif defined(__arm64__)
1020  cur.__fpcr &= ~newm;
1021 #else
1022  cur.__control &= ~newm;
1023 #endif
1024  fesetenv(&cur);
1025 #endif
1026 
1027 #if defined(R__MACOSX) && !defined(__SSE2__) && !defined(__xlC__) && \
1028  !defined(__i386__) && !defined(__x86_64__) && !defined(__arm__) && \
1029  !defined(__arm64__)
1030  Int_t newm = 0;
1031  if (mask & kInvalid ) newm |= FE_ENABLE_INVALID;
1032  if (mask & kDivByZero) newm |= FE_ENABLE_DIVBYZERO;
1033  if (mask & kOverflow ) newm |= FE_ENABLE_OVERFLOW;
1034  if (mask & kUnderflow) newm |= FE_ENABLE_UNDERFLOW;
1035  if (mask & kInexact ) newm |= FE_ENABLE_INEXACT;
1036 
1037  Long64_t curmask;
1038  fegetenvd(curmask);
1039  curmask = (curmask & ~FE_ENABLE_ALL_EXCEPT) | newm;
1040  fesetenvd(curmask);
1041 #endif
1042 
1043  return old;
1044 }
1045 
1046 ////////////////////////////////////////////////////////////////////////////////
1047 /// Dispatch a single event.
1048 
1049 void TUnixSystem::DispatchOneEvent(Bool_t pendingOnly)
1050 {
1051  Bool_t pollOnce = pendingOnly;
1052 
1053  while (1) {
1054  // first handle any X11 events
1055  if (gXDisplay && gXDisplay->Notify()) {
1056  if (fReadready->IsSet(gXDisplay->GetFd())) {
1057  fReadready->Clr(gXDisplay->GetFd());
1058  fNfd--;
1059  }
1060  if (!pendingOnly) return;
1061  }
1062 
1063  // check for file descriptors ready for reading/writing
1064  if (fNfd > 0 && fFileHandler && fFileHandler->GetSize() > 0)
1065  if (CheckDescriptors())
1066  if (!pendingOnly) return;
1067  fNfd = 0;
1068  fReadready->Zero();
1069  fWriteready->Zero();
1070 
1071  if (pendingOnly && !pollOnce)
1072  return;
1073 
1074  // check synchronous signals
1075  if (fSigcnt > 0 && fSignalHandler->GetSize() > 0)
1076  if (CheckSignals(kTRUE))
1077  if (!pendingOnly) return;
1078  fSigcnt = 0;
1079  fSignals->Zero();
1080 
1081  // check synchronous timers
1082  Long_t nextto;
1083  if (fTimers && fTimers->GetSize() > 0)
1084  if (DispatchTimers(kTRUE)) {
1085  // prevent timers from blocking file descriptor monitoring
1086  nextto = NextTimeOut(kTRUE);
1087  if (nextto > kItimerResolution || nextto == -1)
1088  return;
1089  }
1090 
1091  // if in pendingOnly mode poll once file descriptor activity
1092  nextto = NextTimeOut(kTRUE);
1093  if (pendingOnly) {
1094  if (fFileHandler && fFileHandler->GetSize() == 0)
1095  return;
1096  nextto = 0;
1097  pollOnce = kFALSE;
1098  }
1099 
1100  // nothing ready, so setup select call
1101  *fReadready = *fReadmask;
1102  *fWriteready = *fWritemask;
1103 
1104  int mxfd = TMath::Max(fMaxrfd, fMaxwfd);
1105  mxfd++;
1106 
1107  // if nothing to select (socket or timer) return
1108  if (mxfd == 0 && nextto == -1)
1109  return;
1110 
1111  fNfd = UnixSelect(mxfd, fReadready, fWriteready, nextto);
1112  if (fNfd < 0 && fNfd != -2) {
1113  int fd, rc;
1114  TFdSet t;
1115  for (fd = 0; fd < mxfd; fd++) {
1116  t.Set(fd);
1117  if (fReadmask->IsSet(fd)) {
1118  rc = UnixSelect(fd+1, &t, 0, 0);
1119  if (rc < 0 && rc != -2) {
1120  SysError("DispatchOneEvent", "select: read error on %d", fd);
1121  fReadmask->Clr(fd);
1122  }
1123  }
1124  if (fWritemask->IsSet(fd)) {
1125  rc = UnixSelect(fd+1, 0, &t, 0);
1126  if (rc < 0 && rc != -2) {
1127  SysError("DispatchOneEvent", "select: write error on %d", fd);
1128  fWritemask->Clr(fd);
1129  }
1130  }
1131  t.Clr(fd);
1132  }
1133  }
1134  }
1135 }
1136 
1137 ////////////////////////////////////////////////////////////////////////////////
1138 /// Sleep milliSec milliseconds.
1139 
1140 void TUnixSystem::Sleep(UInt_t milliSec)
1141 {
1142  struct timeval tv;
1143 
1144  tv.tv_sec = milliSec / 1000;
1145  tv.tv_usec = (milliSec % 1000) * 1000;
1146 
1147  select(0, 0, 0, 0, &tv);
1148 }
1149 
1150 ////////////////////////////////////////////////////////////////////////////////
1151 /// Select on file descriptors. The timeout to is in millisec. Returns
1152 /// the number of ready descriptors, or 0 in case of timeout, or < 0 in
1153 /// case of an error, with -2 being EINTR and -3 EBADF. In case of EINTR
1154 /// the errno has been reset and the method can be called again. Returns
1155 /// -4 in case the list did not contain any file handlers or file handlers
1156 /// with file descriptor >= 0.
1157 
1158 Int_t TUnixSystem::Select(TList *act, Long_t to)
1159 {
1160  Int_t rc = -4;
1161 
1162  TFdSet rd, wr;
1163  Int_t mxfd = -1;
1164  TIter next(act);
1165  TFileHandler *h = 0;
1166  while ((h = (TFileHandler *) next())) {
1167  Int_t fd = h->GetFd();
1168  if (fd > -1) {
1169  if (h->HasReadInterest()) {
1170  rd.Set(fd);
1171  mxfd = TMath::Max(mxfd, fd);
1172  }
1173  if (h->HasWriteInterest()) {
1174  wr.Set(fd);
1175  mxfd = TMath::Max(mxfd, fd);
1176  }
1177  h->ResetReadyMask();
1178  }
1179  }
1180  if (mxfd > -1)
1181  rc = UnixSelect(mxfd+1, &rd, &wr, to);
1182 
1183  // Set readiness bits
1184  if (rc > 0) {
1185  next.Reset();
1186  while ((h = (TFileHandler *) next())) {
1187  Int_t fd = h->GetFd();
1188  if (rd.IsSet(fd))
1189  h->SetReadReady();
1190  if (wr.IsSet(fd))
1191  h->SetWriteReady();
1192  }
1193  }
1194 
1195  return rc;
1196 }
1197 
1198 ////////////////////////////////////////////////////////////////////////////////
1199 /// Select on the file descriptor related to file handler h.
1200 /// The timeout to is in millisec. Returns the number of ready descriptors,
1201 /// or 0 in case of timeout, or < 0 in case of an error, with -2 being EINTR
1202 /// and -3 EBADF. In case of EINTR the errno has been reset and the method
1203 /// can be called again. Returns -4 in case the file handler is 0 or does
1204 /// not have a file descriptor >= 0.
1205 
1206 Int_t TUnixSystem::Select(TFileHandler *h, Long_t to)
1207 {
1208  Int_t rc = -4;
1209 
1210  TFdSet rd, wr;
1211  Int_t mxfd = -1;
1212  Int_t fd = -1;
1213  if (h) {
1214  fd = h->GetFd();
1215  if (fd > -1) {
1216  if (h->HasReadInterest())
1217  rd.Set(fd);
1218  if (h->HasWriteInterest())
1219  wr.Set(fd);
1220  h->ResetReadyMask();
1221  mxfd = fd;
1222  rc = UnixSelect(mxfd+1, &rd, &wr, to);
1223  }
1224  }
1225 
1226  // Fill output lists, if required
1227  if (rc > 0) {
1228  if (rd.IsSet(fd))
1229  h->SetReadReady();
1230  if (wr.IsSet(fd))
1231  h->SetWriteReady();
1232  }
1233 
1234  return rc;
1235 }
1236 
1237 //---- handling of system events -----------------------------------------------
1238 
1239 ////////////////////////////////////////////////////////////////////////////////
1240 /// Check if some signals were raised and call their Notify() member.
1241 
1242 Bool_t TUnixSystem::CheckSignals(Bool_t sync)
1243 {
1244  TSignalHandler *sh;
1245  Int_t sigdone = -1;
1246  {
1247  TOrdCollectionIter it((TOrdCollection*)fSignalHandler);
1248 
1249  while ((sh = (TSignalHandler*)it.Next())) {
1250  if (sync == sh->IsSync()) {
1251  ESignals sig = sh->GetSignal();
1252  if ((fSignals->IsSet(sig) && sigdone == -1) || sigdone == sig) {
1253  if (sigdone == -1) {
1254  fSignals->Clr(sig);
1255  sigdone = sig;
1256  fSigcnt--;
1257  }
1258  if (sh->IsActive())
1259  sh->Notify();
1260  }
1261  }
1262  }
1263  }
1264  if (sigdone != -1)
1265  return kTRUE;
1266 
1267  return kFALSE;
1268 }
1269 
1270 ////////////////////////////////////////////////////////////////////////////////
1271 /// Check if children have finished.
1272 
1273 void TUnixSystem::CheckChilds()
1274 {
1275 #if 0 //rdm
1276  int pid;
1277  while ((pid = UnixWaitchild()) > 0) {
1278  TIter next(zombieHandler);
1279  register UnixPtty *pty;
1280  while ((pty = (UnixPtty*) next()))
1281  if (pty->GetPid() == pid) {
1282  zombieHandler->RemovePtr(pty);
1283  pty->DiedNotify();
1284  }
1285  }
1286 #endif
1287 }
1288 
1289 ////////////////////////////////////////////////////////////////////////////////
1290 /// Check if there is activity on some file descriptors and call their
1291 /// Notify() member.
1292 
1293 Bool_t TUnixSystem::CheckDescriptors()
1294 {
1295  TFileHandler *fh;
1296  Int_t fddone = -1;
1297  Bool_t read = kFALSE;
1298  TOrdCollectionIter it((TOrdCollection*)fFileHandler);
1299  while ((fh = (TFileHandler*) it.Next())) {
1300  Int_t fd = fh->GetFd();
1301  if ((fd <= fMaxrfd && fReadready->IsSet(fd) && fddone == -1) ||
1302  (fddone == fd && read)) {
1303  if (fddone == -1) {
1304  fReadready->Clr(fd);
1305  fddone = fd;
1306  read = kTRUE;
1307  fNfd--;
1308  }
1309  if (fh->IsActive())
1310  fh->ReadNotify();
1311  }
1312  if ((fd <= fMaxwfd && fWriteready->IsSet(fd) && fddone == -1) ||
1313  (fddone == fd && !read)) {
1314  if (fddone == -1) {
1315  fWriteready->Clr(fd);
1316  fddone = fd;
1317  read = kFALSE;
1318  fNfd--;
1319  }
1320  if (fh->IsActive())
1321  fh->WriteNotify();
1322  }
1323  }
1324  if (fddone != -1)
1325  return kTRUE;
1326 
1327  return kFALSE;
1328 }
1329 
1330 //---- Directories -------------------------------------------------------------
1331 
1332 ////////////////////////////////////////////////////////////////////////////////
1333 /// Make a Unix file system directory. Returns 0 in case of success and
1334 /// -1 if the directory could not be created.
1335 
1336 int TUnixSystem::MakeDirectory(const char *name)
1337 {
1338  TSystem *helper = FindHelper(name);
1339  if (helper)
1340  return helper->MakeDirectory(name);
1341 
1342  return UnixMakedir(name);
1343 }
1344 
1345 ////////////////////////////////////////////////////////////////////////////////
1346 /// Open a Unix file system directory. Returns 0 if directory does not exist.
1347 
1348 void *TUnixSystem::OpenDirectory(const char *name)
1349 {
1350  TSystem *helper = FindHelper(name);
1351  if (helper)
1352  return helper->OpenDirectory(name);
1353 
1354  return UnixOpendir(name);
1355 }
1356 
1357 ////////////////////////////////////////////////////////////////////////////////
1358 /// Close a Unix file system directory.
1359 
1360 void TUnixSystem::FreeDirectory(void *dirp)
1361 {
1362  TSystem *helper = FindHelper(0, dirp);
1363  if (helper) {
1364  helper->FreeDirectory(dirp);
1365  return;
1366  }
1367 
1368  if (dirp)
1369  ::closedir((DIR*)dirp);
1370 }
1371 
1372 ////////////////////////////////////////////////////////////////////////////////
1373 /// Get next Unix file system directory entry. Returns 0 if no more entries.
1374 
1375 const char *TUnixSystem::GetDirEntry(void *dirp)
1376 {
1377  TSystem *helper = FindHelper(0, dirp);
1378  if (helper)
1379  return helper->GetDirEntry(dirp);
1380 
1381  if (dirp)
1382  return UnixGetdirentry(dirp);
1383 
1384  return 0;
1385 }
1386 
1387 ////////////////////////////////////////////////////////////////////////////////
1388 /// Change directory. Returns kTRUE in case of success, kFALSE otherwise.
1389 
1390 Bool_t TUnixSystem::ChangeDirectory(const char *path)
1391 {
1392  Bool_t ret = (Bool_t) (::chdir(path) == 0);
1393  if (fWdpath != "")
1394  fWdpath = ""; // invalidate path cache
1395  return ret;
1396 }
1397 
1398 ////////////////////////////////////////////////////////////////////////////////
1399 /// Return working directory.
1400 
1401 const char *TUnixSystem::WorkingDirectory()
1402 {
1403  // don't use cache as user can call chdir() directly somewhere else
1404  //if (fWdpath != "")
1405  // return fWdpath.Data();
1406 
1407  R__LOCKGUARD2(gSystemMutex);
1408 
1409  static char cwd[kMAXPATHLEN];
1410  FillWithCwd(cwd);
1411  fWdpath = cwd;
1412 
1413  return fWdpath.Data();
1414 }
1415 
1416 //////////////////////////////////////////////////////////////////////////////
1417 /// Return working directory.
1418 
1419 std::string TUnixSystem::GetWorkingDirectory() const
1420 {
1421  char cwd[kMAXPATHLEN];
1422  FillWithCwd(cwd);
1423  return std::string(cwd);
1424 }
1425 
1426 //////////////////////////////////////////////////////////////////////////////
1427 /// Fill buffer with current working directory.
1428 
1429 void TUnixSystem::FillWithCwd(char *cwd) const
1430 {
1431  if (::getcwd(cwd, kMAXPATHLEN) == 0) {
1432  Error("WorkingDirectory", "getcwd() failed");
1433  }
1434 }
1435 
1436 ////////////////////////////////////////////////////////////////////////////////
1437 /// Return the user's home directory.
1438 
1439 const char *TUnixSystem::HomeDirectory(const char *userName)
1440 {
1441  return UnixHomedirectory(userName);
1442 }
1443 
1444 //////////////////////////////////////////////////////////////////////////////
1445 /// Return the user's home directory.
1446 
1447 std::string TUnixSystem::GetHomeDirectory(const char *userName) const
1448 {
1449  char path[kMAXPATHLEN], mydir[kMAXPATHLEN] = { '\0' };
1450  auto res = UnixHomedirectory(userName, path, mydir);
1451  if (res) return std::string(res);
1452  else return std::string();
1453 }
1454 
1455 ////////////////////////////////////////////////////////////////////////////////
1456 /// Return a user configured or systemwide directory to create
1457 /// temporary files in.
1458 
1459 const char *TUnixSystem::TempDirectory() const
1460 {
1461  const char *dir = gSystem->Getenv("TMPDIR");
1462  if (!dir || gSystem->AccessPathName(dir, kWritePermission))
1463  dir = "/tmp";
1464 
1465  return dir;
1466 }
1467 
1468 ////////////////////////////////////////////////////////////////////////////////
1469 /// Create a secure temporary file by appending a unique
1470 /// 6 letter string to base. The file will be created in
1471 /// a standard (system) directory or in the directory
1472 /// provided in dir. The full filename is returned in base
1473 /// and a filepointer is returned for safely writing to the file
1474 /// (this avoids certain security problems). Returns 0 in case
1475 /// of error.
1476 
1477 FILE *TUnixSystem::TempFileName(TString &base, const char *dir)
1478 {
1479  char *b = ConcatFileName(dir ? dir : TempDirectory(), base);
1480  base = b;
1481  base += "XXXXXX";
1482  delete [] b;
1483 
1484  char *arg = StrDup(base);
1485  int fd = mkstemp(arg);
1486  base = arg;
1487  delete [] arg;
1488 
1489  if (fd == -1) {
1490  SysError("TempFileName", "%s", base.Data());
1491  return 0;
1492  } else {
1493  FILE *fp = fdopen(fd, "w+");
1494  if (fp == 0)
1495  SysError("TempFileName", "converting filedescriptor (%d)", fd);
1496  return fp;
1497  }
1498 }
1499 
1500 ////////////////////////////////////////////////////////////////////////////////
1501 /// Concatenate a directory and a file name.
1502 
1503 const char *TUnixSystem::PrependPathName(const char *dir, TString& name)
1504 {
1505  if (name.IsNull() || name == ".") {
1506  if (dir) {
1507  name = dir;
1508  if (dir[strlen(dir) - 1] != '/')
1509  name += '/';
1510  } else name = "";
1511  return name.Data();
1512  }
1513 
1514  if (!dir || !dir[0]) dir = "/";
1515  else if (dir[strlen(dir) - 1] != '/')
1516  name.Prepend('/');
1517  name.Prepend(dir);
1518 
1519  return name.Data();
1520 }
1521 
1522 //---- Paths & Files -----------------------------------------------------------
1523 
1524 ////////////////////////////////////////////////////////////////////////////////
1525 /// Returns FALSE if one can access a file using the specified access mode.
1526 /// Mode is the same as for the Unix access(2) function.
1527 /// Attention, bizarre convention of return value!!
1528 
1529 Bool_t TUnixSystem::AccessPathName(const char *path, EAccessMode mode)
1530 {
1531  TSystem *helper = FindHelper(path);
1532  if (helper)
1533  return helper->AccessPathName(path, mode);
1534 
1535  if (::access(StripOffProto(path, "file:"), mode) == 0)
1536  return kFALSE;
1537  GetLastErrorString() = GetError();
1538 
1539  return kTRUE;
1540 }
1541 
1542 ////////////////////////////////////////////////////////////////////////////////
1543 /// Copy a file. If overwrite is true and file already exists the
1544 /// file will be overwritten. Returns 0 when successful, -1 in case
1545 /// of file open failure, -2 in case the file already exists and overwrite
1546 /// was false and -3 in case of error during copy.
1547 
1548 int TUnixSystem::CopyFile(const char *f, const char *t, Bool_t overwrite)
1549 {
1550  if (!AccessPathName(t) && !overwrite)
1551  return -2;
1552 
1553  FILE *from = fopen(f, "r");
1554  if (!from)
1555  return -1;
1556 
1557  FILE *to = fopen(t, "w");
1558  if (!to) {
1559  fclose(from);
1560  return -1;
1561  }
1562 
1563  const int bufsize = 1024;
1564  char buf[bufsize];
1565  int ret = 0;
1566  while (!ret && !feof(from)) {
1567  size_t numread = fread (buf, sizeof(char), bufsize, from);
1568  size_t numwritten = fwrite(buf, sizeof(char), numread, to);
1569  if (numread != numwritten)
1570  ret = -3;
1571  }
1572 
1573  fclose(from);
1574  fclose(to);
1575 
1576  return ret;
1577 }
1578 
1579 ////////////////////////////////////////////////////////////////////////////////
1580 /// Rename a file. Returns 0 when successful, -1 in case of failure.
1581 
1582 int TUnixSystem::Rename(const char *f, const char *t)
1583 {
1584  int ret = ::rename(f, t);
1585  GetLastErrorString() = GetError();
1586  return ret;
1587 }
1588 
1589 ////////////////////////////////////////////////////////////////////////////////
1590 /// Returns TRUE if the url in 'path' points to the local file system.
1591 /// This is used to avoid going through the NIC card for local operations.
1592 
1593 Bool_t TUnixSystem::IsPathLocal(const char *path)
1594 {
1595  TSystem *helper = FindHelper(path);
1596  if (helper)
1597  return helper->IsPathLocal(path);
1598 
1599  return TSystem::IsPathLocal(path);
1600 }
1601 
1602 ////////////////////////////////////////////////////////////////////////////////
1603 /// Get info about a file. Info is returned in the form of a FileStat_t
1604 /// structure (see TSystem.h).
1605 /// The function returns 0 in case of success and 1 if the file could
1606 /// not be stat'ed.
1607 
1608 int TUnixSystem::GetPathInfo(const char *path, FileStat_t &buf)
1609 {
1610  TSystem *helper = FindHelper(path);
1611  if (helper)
1612  return helper->GetPathInfo(path, buf);
1613 
1614  return UnixFilestat(path, buf);
1615 }
1616 
1617 ////////////////////////////////////////////////////////////////////////////////
1618 /// Get info about a file system: id, bsize, bfree, blocks.
1619 /// Id is file system type (machine dependend, see statfs())
1620 /// Bsize is block size of file system
1621 /// Blocks is total number of blocks in file system
1622 /// Bfree is number of free blocks in file system
1623 /// The function returns 0 in case of success and 1 if the file system could
1624 /// not be stat'ed.
1625 
1626 int TUnixSystem::GetFsInfo(const char *path, Long_t *id, Long_t *bsize,
1627  Long_t *blocks, Long_t *bfree)
1628 {
1629  return UnixFSstat(path, id, bsize, blocks, bfree);
1630 }
1631 
1632 ////////////////////////////////////////////////////////////////////////////////
1633 /// Create a link from file1 to file2. Returns 0 when successful,
1634 /// -1 in case of failure.
1635 
1636 int TUnixSystem::Link(const char *from, const char *to)
1637 {
1638  return ::link(from, to);
1639 }
1640 
1641 ////////////////////////////////////////////////////////////////////////////////
1642 /// Create a symlink from file1 to file2. Returns 0 when successful,
1643 /// -1 in case of failure.
1644 
1645 int TUnixSystem::Symlink(const char *from, const char *to)
1646 {
1647 #if defined(R__AIX)
1648  return ::symlink((char*)from, (char*)to);
1649 #else
1650  return ::symlink(from, to);
1651 #endif
1652 }
1653 
1654 ////////////////////////////////////////////////////////////////////////////////
1655 /// Unlink, i.e. remove, a file or directory. Returns 0 when successful,
1656 /// -1 in case of failure.
1657 
1658 int TUnixSystem::Unlink(const char *name)
1659 {
1660  TSystem *helper = FindHelper(name);
1661  if (helper)
1662  return helper->Unlink(name);
1663 
1664 #if defined(R__SEEK64)
1665  struct stat64 finfo;
1666  if (lstat64(name, &finfo) < 0)
1667 #else
1668  struct stat finfo;
1669  if (lstat(name, &finfo) < 0)
1670 #endif
1671  return -1;
1672 
1673  if (S_ISDIR(finfo.st_mode))
1674  return ::rmdir(name);
1675  else
1676  return ::unlink(name);
1677 }
1678 
1679 //---- expand the metacharacters as in the shell -------------------------------
1680 
1681 // expand the metacharacters as in the shell
1682 
1683 const char
1684 #ifdef G__OLDEXPAND
1685  kShellEscape = '\\',
1686  *kShellStuff = "(){}<>\"'",
1687 #endif
1688  *kShellMeta = "~*[]{}?$";
1689 
1690 
1691 #ifndef G__OLDEXPAND
1692 ////////////////////////////////////////////////////////////////////////////////
1693 /// Expand a pathname getting rid of special shell characters like ~.$, etc.
1694 /// For Unix/Win32 compatibility use $(XXX) instead of $XXX when using
1695 /// environment variables in a pathname. If compatibility is not an issue
1696 /// you can use on Unix directly $XXX. Returns kFALSE in case of success
1697 /// or kTRUE in case of error.
1698 
1699 Bool_t TUnixSystem::ExpandPathName(TString &path)
1700 {
1701  const char *p, *patbuf = (const char *)path;
1702 
1703  // skip leading blanks
1704  while (*patbuf == ' ')
1705  patbuf++;
1706 
1707  // any shell meta characters ?
1708  for (p = patbuf; *p; p++)
1709  if (strchr(kShellMeta, *p))
1710  goto expand;
1711 
1712  return kFALSE;
1713 
1714 expand:
1715  // replace $(XXX) by $XXX
1716  path.ReplaceAll("$(","$");
1717  path.ReplaceAll(")","");
1718 
1719  return ExpandFileName(path);
1720 }
1721 #endif
1722 
1723 #ifdef G__OLDEXPAND
1724 ////////////////////////////////////////////////////////////////////////////////
1725 /// Expand a pathname getting rid of special shell characters like ~.$, etc.
1726 /// For Unix/Win32 compatibility use $(XXX) instead of $XXX when using
1727 /// environment variables in a pathname. If compatibility is not an issue
1728 /// you can use on Unix directly $XXX. Returns kFALSE in case of success
1729 /// or kTRUE in case of error.
1730 
1731 Bool_t TUnixSystem::ExpandPathName(TString &patbuf0)
1732 {
1733  const char *patbuf = (const char *)patbuf0;
1734  const char *hd, *p;
1735  // char cmd[kMAXPATHLEN],
1736  char stuffedPat[kMAXPATHLEN], name[70];
1737  char *q;
1738  FILE *pf;
1739  int ch;
1740 
1741  // skip leading blanks
1742  while (*patbuf == ' ')
1743  patbuf++;
1744 
1745  // any shell meta characters ?
1746  for (p = patbuf; *p; p++)
1747  if (strchr(kShellMeta, *p))
1748  goto needshell;
1749 
1750  return kFALSE;
1751 
1752 needshell:
1753  // replace $(XXX) by $XXX
1754  patbuf0.ReplaceAll("$(","$");
1755  patbuf0.ReplaceAll(")","");
1756 
1757  // escape shell quote characters
1758  EscChar(patbuf, stuffedPat, sizeof(stuffedPat), (char*)kShellStuff, kShellEscape);
1759 
1760  TString cmd("echo ");
1761 
1762  // emulate csh -> popen executes sh
1763  if (stuffedPat[0] == '~') {
1764  if (stuffedPat[1] != '\0' && stuffedPat[1] != '/') {
1765  // extract user name
1766  for (p = &stuffedPat[1], q = name; *p && *p !='/';)
1767  *q++ = *p++;
1768  *q = '\0';
1769  hd = UnixHomedirectory(name);
1770  if (hd == 0)
1771  cmd += stuffedPat;
1772  else {
1773  cmd += hd;
1774  cmd += p;
1775  }
1776  } else {
1777  hd = UnixHomedirectory(0);
1778  if (hd == 0) {
1779  GetLastErrorString() = GetError();
1780  return kTRUE;
1781  }
1782  cmd += hd;
1783  cmd += &stuffedPat[1];
1784  }
1785  } else
1786  cmd += stuffedPat;
1787 
1788  if ((pf = ::popen(cmd.Data(), "r")) == 0) {
1789  GetLastErrorString() = GetError();
1790  return kTRUE;
1791  }
1792 
1793  // read first argument
1794  patbuf0 = "";
1795  int cnt = 0;
1796 #if defined(R__AIX)
1797 again:
1798 #endif
1799  for (ch = fgetc(pf); ch != EOF && ch != ' ' && ch != '\n'; ch = fgetc(pf)) {
1800  patbuf0.Append(ch);
1801  cnt++;
1802  }
1803 #if defined(R__AIX)
1804  // Work around bug timing problem due to delay in forking a large program
1805  if (cnt == 0 && ch == EOF) goto again;
1806 #endif
1807 
1808  // skip rest of pipe
1809  while (ch != EOF) {
1810  ch = fgetc(pf);
1811  if (ch == ' ' || ch == '\t') {
1812  GetLastErrorString() = "expression ambigous";
1813  ::pclose(pf);
1814  return kTRUE;
1815  }
1816  }
1817 
1818  ::pclose(pf);
1819 
1820  return kFALSE;
1821 }
1822 #endif
1823 
1824 ////////////////////////////////////////////////////////////////////////////////
1825 /// Expand a pathname getting rid of special shell characaters like ~.$, etc.
1826 /// For Unix/Win32 compatibility use $(XXX) instead of $XXX when using
1827 /// environment variables in a pathname. If compatibility is not an issue
1828 /// you can use on Unix directly $XXX. The user must delete returned string.
1829 /// Returns the expanded pathname or 0 in case of error.
1830 /// The user must delete returned string (delete []).
1831 
1832 char *TUnixSystem::ExpandPathName(const char *path)
1833 {
1834  TString patbuf = path;
1835  if (ExpandPathName(patbuf))
1836  return 0;
1837  return StrDup(patbuf.Data());
1838 }
1839 
1840 ////////////////////////////////////////////////////////////////////////////////
1841 /// Set the file permission bits. Returns -1 in case or error, 0 otherwise.
1842 
1843 int TUnixSystem::Chmod(const char *file, UInt_t mode)
1844 {
1845  return ::chmod(file, mode);
1846 }
1847 
1848 ////////////////////////////////////////////////////////////////////////////////
1849 /// Set the process file creation mode mask.
1850 
1851 int TUnixSystem::Umask(Int_t mask)
1852 {
1853  return ::umask(mask);
1854 }
1855 
1856 ////////////////////////////////////////////////////////////////////////////////
1857 /// Set a files modification and access times. If actime = 0 it will be
1858 /// set to the modtime. Returns 0 on success and -1 in case of error.
1859 
1860 int TUnixSystem::Utime(const char *file, Long_t modtime, Long_t actime)
1861 {
1862  if (!actime)
1863  actime = modtime;
1864 
1865  struct utimbuf t;
1866  t.actime = (time_t)actime;
1867  t.modtime = (time_t)modtime;
1868  return ::utime(file, &t);
1869 }
1870 
1871 ////////////////////////////////////////////////////////////////////////////////
1872 /// Find location of file "wfil" in a search path.
1873 /// The search path is specified as a : separated list of directories.
1874 /// Return value is pointing to wfile for compatibility with
1875 /// Which(const char*,const char*,EAccessMode) version.
1876 
1877 const char *TUnixSystem::FindFile(const char *search, TString& wfil, EAccessMode mode)
1878 {
1879  TString show;
1880  if (gEnv->GetValue("Root.ShowPath", 0))
1881  show.Form("Which: %s =", wfil.Data());
1882 
1883  gSystem->ExpandPathName(wfil);
1884 
1885  if (wfil[0] == '/') {
1886 #if defined(R__SEEK64)
1887  struct stat64 finfo;
1888  if (access(wfil.Data(), mode) == 0 &&
1889  stat64(wfil.Data(), &finfo) == 0 && S_ISREG(finfo.st_mode)) {
1890 #else
1891  struct stat finfo;
1892  if (access(wfil.Data(), mode) == 0 &&
1893  stat(wfil.Data(), &finfo) == 0 && S_ISREG(finfo.st_mode)) {
1894 #endif
1895  if (show != "")
1896  Printf("%s %s", show.Data(), wfil.Data());
1897  return wfil.Data();
1898  }
1899  if (show != "")
1900  Printf("%s <not found>", show.Data());
1901  wfil = "";
1902  return 0;
1903  }
1904 
1905  if (search == 0)
1906  search = ".";
1907 
1908  TString apwd(gSystem->WorkingDirectory());
1909  apwd += "/";
1910  for (const char* ptr = search; *ptr;) {
1911  TString name;
1912  if (*ptr != '/' && *ptr !='$' && *ptr != '~')
1913  name = apwd;
1914  const char* posEndOfPart = strchr(ptr, ':');
1915  if (posEndOfPart) {
1916  name.Append(ptr, posEndOfPart - ptr);
1917  ptr = posEndOfPart + 1; // skip ':'
1918  } else {
1919  name.Append(ptr);
1920  ptr += strlen(ptr);
1921  }
1922 
1923  if (!name.EndsWith("/"))
1924  name += '/';
1925  name += wfil;
1926 
1927  gSystem->ExpandPathName(name);
1928 #if defined(R__SEEK64)
1929  struct stat64 finfo;
1930  if (access(name.Data(), mode) == 0 &&
1931  stat64(name.Data(), &finfo) == 0 && S_ISREG(finfo.st_mode)) {
1932 #else
1933  struct stat finfo;
1934  if (access(name.Data(), mode) == 0 &&
1935  stat(name.Data(), &finfo) == 0 && S_ISREG(finfo.st_mode)) {
1936 #endif
1937  if (show != "")
1938  Printf("%s %s", show.Data(), name.Data());
1939  wfil = name;
1940  return wfil.Data();
1941  }
1942  }
1943 
1944  if (show != "")
1945  Printf("%s <not found>", show.Data());
1946  wfil = "";
1947  return 0;
1948 }
1949 
1950 //---- Users & Groups ----------------------------------------------------------
1951 
1952 ////////////////////////////////////////////////////////////////////////////////
1953 /// Returns the user's id. If user = 0, returns current user's id.
1954 
1955 Int_t TUnixSystem::GetUid(const char *user)
1956 {
1957  if (!user || !user[0])
1958  return getuid();
1959  else {
1960  struct passwd *apwd = getpwnam(user);
1961  if (apwd)
1962  return apwd->pw_uid;
1963  }
1964  return 0;
1965 }
1966 
1967 ////////////////////////////////////////////////////////////////////////////////
1968 /// Returns the effective user id. The effective id corresponds to the
1969 /// set id bit on the file being executed.
1970 
1971 Int_t TUnixSystem::GetEffectiveUid()
1972 {
1973  return geteuid();
1974 }
1975 
1976 ////////////////////////////////////////////////////////////////////////////////
1977 /// Returns the group's id. If group = 0, returns current user's group.
1978 
1979 Int_t TUnixSystem::GetGid(const char *group)
1980 {
1981  if (!group || !group[0])
1982  return getgid();
1983  else {
1984  struct group *grp = getgrnam(group);
1985  if (grp)
1986  return grp->gr_gid;
1987  }
1988  return 0;
1989 }
1990 
1991 ////////////////////////////////////////////////////////////////////////////////
1992 /// Returns the effective group id. The effective group id corresponds
1993 /// to the set id bit on the file being executed.
1994 
1995 Int_t TUnixSystem::GetEffectiveGid()
1996 {
1997  return getegid();
1998 }
1999 
2000 ////////////////////////////////////////////////////////////////////////////////
2001 /// Returns all user info in the UserGroup_t structure. The returned
2002 /// structure must be deleted by the user. In case of error 0 is returned.
2003 
2004 UserGroup_t *TUnixSystem::GetUserInfo(Int_t uid)
2005 {
2006  typedef std::map<Int_t /*uid*/, UserGroup_t> UserInfoCache_t;
2007  static UserInfoCache_t gUserInfo;
2008 
2009  UserInfoCache_t::const_iterator iUserInfo = gUserInfo.find(uid);
2010  if (iUserInfo != gUserInfo.end())
2011  return new UserGroup_t(iUserInfo->second);
2012 
2013  struct passwd *apwd = getpwuid(uid);
2014  if (apwd) {
2015  UserGroup_t *ug = new UserGroup_t;
2016  ug->fUid = apwd->pw_uid;
2017  ug->fGid = apwd->pw_gid;
2018  ug->fUser = apwd->pw_name;
2019  ug->fPasswd = apwd->pw_passwd;
2020  ug->fRealName = apwd->pw_gecos;
2021  ug->fShell = apwd->pw_shell;
2022  UserGroup_t *gr = GetGroupInfo(apwd->pw_gid);
2023  if (gr) ug->fGroup = gr->fGroup;
2024  delete gr;
2025 
2026  gUserInfo[uid] = *ug;
2027  return ug;
2028  }
2029  return 0;
2030 }
2031 
2032 ////////////////////////////////////////////////////////////////////////////////
2033 /// Returns all user info in the UserGroup_t structure. If user = 0, returns
2034 /// current user's id info. The returned structure must be deleted by the
2035 /// user. In case of error 0 is returned.
2036 
2037 UserGroup_t *TUnixSystem::GetUserInfo(const char *user)
2038 {
2039  return GetUserInfo(GetUid(user));
2040 }
2041 
2042 ////////////////////////////////////////////////////////////////////////////////
2043 /// Returns all group info in the UserGroup_t structure. The only active
2044 /// fields in the UserGroup_t structure for this call are:
2045 /// fGid and fGroup
2046 /// The returned structure must be deleted by the user. In case of
2047 /// error 0 is returned.
2048 
2049 UserGroup_t *TUnixSystem::GetGroupInfo(Int_t gid)
2050 {
2051  struct group *grp = getgrgid(gid);
2052  if (grp) {
2053  UserGroup_t *gr = new UserGroup_t;
2054  gr->fUid = 0;
2055  gr->fGid = grp->gr_gid;
2056  gr->fGroup = grp->gr_name;
2057  return gr;
2058  }
2059  return 0;
2060 }
2061 
2062 ////////////////////////////////////////////////////////////////////////////////
2063 /// Returns all group info in the UserGroup_t structure. The only active
2064 /// fields in the UserGroup_t structure for this call are:
2065 /// fGid and fGroup
2066 /// If group = 0, returns current user's group. The returned structure
2067 /// must be deleted by the user. In case of error 0 is returned.
2068 
2069 UserGroup_t *TUnixSystem::GetGroupInfo(const char *group)
2070 {
2071  return GetGroupInfo(GetGid(group));
2072 }
2073 
2074 //---- environment manipulation ------------------------------------------------
2075 
2076 ////////////////////////////////////////////////////////////////////////////////
2077 /// Set environment variable.
2078 
2079 void TUnixSystem::Setenv(const char *name, const char *value)
2080 {
2081  ::setenv(name, value, 1);
2082 }
2083 
2084 ////////////////////////////////////////////////////////////////////////////////
2085 /// Get environment variable.
2086 
2087 const char *TUnixSystem::Getenv(const char *name)
2088 {
2089  return ::getenv(name);
2090 }
2091 
2092 ////////////////////////////////////////////////////////////////////////////////
2093 /// Unset environment variable.
2094 
2095 void TUnixSystem::Unsetenv(const char *name)
2096 {
2097  ::unsetenv(name);
2098 }
2099 
2100 //---- Processes ---------------------------------------------------------------
2101 
2102 ////////////////////////////////////////////////////////////////////////////////
2103 /// Execute a command.
2104 
2105 int TUnixSystem::Exec(const char *shellcmd)
2106 {
2107  return ::system(shellcmd);
2108 }
2109 
2110 ////////////////////////////////////////////////////////////////////////////////
2111 /// Open a pipe.
2112 
2113 FILE *TUnixSystem::OpenPipe(const char *command, const char *mode)
2114 {
2115  return ::popen(command, mode);
2116 }
2117 
2118 ////////////////////////////////////////////////////////////////////////////////
2119 /// Close the pipe.
2120 
2121 int TUnixSystem::ClosePipe(FILE *pipe)
2122 {
2123  return ::pclose(pipe);
2124 }
2125 
2126 ////////////////////////////////////////////////////////////////////////////////
2127 /// Get process id.
2128 
2129 int TUnixSystem::GetPid()
2130 {
2131  return ::getpid();
2132 }
2133 
2134 ////////////////////////////////////////////////////////////////////////////////
2135 /// Exit the application.
2136 
2137 void TUnixSystem::Exit(int code, Bool_t mode)
2138 {
2139  // Insures that the files and sockets are closed before any library is unloaded
2140  // and before emptying CINT.
2141  TROOT::ShutDown();
2142 
2143  if (mode)
2144  ::exit(code);
2145  else
2146  ::_exit(code);
2147 }
2148 
2149 ////////////////////////////////////////////////////////////////////////////////
2150 /// Abort the application.
2151 
2152 void TUnixSystem::Abort(int)
2153 {
2154  ::abort();
2155 }
2156 
2157 
2158 #ifdef R__MACOSX
2159 /// Use CoreSymbolication to retrieve the stacktrace.
2160 #include <mach/mach.h>
2161 extern "C" {
2162  // Adapted from https://github.com/mountainstorm/CoreSymbolication
2163  // Under the hood the framework basically just calls through to a set of C++ libraries
2164  typedef struct {
2165  void* csCppData;
2166  void* csCppObj;
2167  } CSTypeRef;
2168  typedef CSTypeRef CSSymbolicatorRef;
2169  typedef CSTypeRef CSSourceInfoRef;
2170  typedef CSTypeRef CSSymbolOwnerRef;
2171  typedef CSTypeRef CSSymbolRef;
2172 
2173  CSSymbolicatorRef CSSymbolicatorCreateWithPid(pid_t pid);
2174  CSSymbolRef CSSymbolicatorGetSymbolWithAddressAtTime(CSSymbolicatorRef cs, vm_address_t addr, uint64_t time);
2175  CSSourceInfoRef CSSymbolicatorGetSourceInfoWithAddressAtTime(CSSymbolicatorRef cs, vm_address_t addr, uint64_t time);
2176  const char* CSSymbolGetName(CSSymbolRef sym);
2177  CSSymbolOwnerRef CSSymbolGetSymbolOwner(CSSymbolRef sym);
2178  const char* CSSymbolOwnerGetPath(CSSymbolOwnerRef symbol);
2179  const char* CSSourceInfoGetPath(CSSourceInfoRef info);
2180  int CSSourceInfoGetLineNumber(CSSourceInfoRef info);
2181 }
2182 
2183 bool CSTypeRefIdValid(CSTypeRef ref) {
2184  return ref.csCppData || ref.csCppObj;
2185 }
2186 
2187 void macosx_backtrace() {
2188 void* addrlist[kMAX_BACKTRACE_DEPTH];
2189  // retrieve current stack addresses
2190  int numstacks = backtrace( addrlist, sizeof( addrlist ) / sizeof( void* ));
2191 
2192  CSSymbolicatorRef symbolicator = CSSymbolicatorCreateWithPid(getpid());
2193 
2194  // skip TUnixSystem::Backtrace(), macosx_backtrace()
2195  static const int skipFrames = 2;
2196  for (int i = skipFrames; i < numstacks; ++i) {
2197  // No debug info, try to get at least the symbol name.
2198  CSSymbolRef sym = CSSymbolicatorGetSymbolWithAddressAtTime(symbolicator,
2199  (vm_address_t)addrlist[i],
2200  0x80000000u);
2201  CSSymbolOwnerRef symOwner = CSSymbolGetSymbolOwner(sym);
2202 
2203  if (const char* libPath = CSSymbolOwnerGetPath(symOwner)) {
2204  printf("[%s]", libPath);
2205  } else {
2206  printf("[<unknown binary>]");
2207  }
2208 
2209  if (const char* symname = CSSymbolGetName(sym)) {
2210  printf(" %s", symname);
2211  }
2212 
2213  CSSourceInfoRef sourceInfo
2214  = CSSymbolicatorGetSourceInfoWithAddressAtTime(symbolicator,
2215  (vm_address_t)addrlist[i],
2216  0x80000000u /*"now"*/);
2217  if (const char* sourcePath = CSSourceInfoGetPath(sourceInfo)) {
2218  printf(" %s:%d", sourcePath, (int)CSSourceInfoGetLineNumber(sourceInfo));
2219  } else {
2220  printf(" (no debug info)");
2221  }
2222  printf("\n");
2223  }
2224 }
2225 #endif // R__MACOSX
2226 
2227 ////////////////////////////////////////////////////////////////////////////////
2228 /// Print a stack trace.
2229 
2230 void TUnixSystem::StackTrace()
2231 {
2232  if (!gEnv->GetValue("Root.Stacktrace", 1))
2233  return;
2234 
2235 #ifndef R__MACOSX
2236  TString gdbscript = gEnv->GetValue("Root.StacktraceScript", "");
2237  gdbscript = gdbscript.Strip();
2238  if (gdbscript != "") {
2239  if (AccessPathName(gdbscript, kReadPermission)) {
2240  fprintf(stderr, "Root.StacktraceScript %s does not exist\n", gdbscript.Data());
2241  gdbscript = "";
2242  }
2243  }
2244  if (gdbscript == "") {
2245  gdbscript = "gdb-backtrace.sh";
2246  gSystem->PrependPathName(TROOT::GetEtcDir(), gdbscript);
2247  if (AccessPathName(gdbscript, kReadPermission)) {
2248  fprintf(stderr, "Error in <TUnixSystem::StackTrace> script %s is missing\n", gdbscript.Data());
2249  return;
2250  }
2251  }
2252  gdbscript += " ";
2253 
2254  TString gdbmess = gEnv->GetValue("Root.StacktraceMessage", "");
2255  gdbmess = gdbmess.Strip();
2256 
2257  std::cout.flush();
2258  fflush(stdout);
2259 
2260  std::cerr.flush();
2261  fflush(stderr);
2262 
2263  int fd = STDERR_FILENO;
2264 
2265  const char *message = " Generating stack trace...\n";
2266 
2267  if (fd && message) { } // remove unused warning (remove later)
2268 
2269  if (gApplication && !strcmp(gApplication->GetName(), "TRint"))
2270  Getlinem(kCleanUp, 0);
2271 
2272 #if defined(USE_GDB_STACK_TRACE)
2273  char *gdb = Which(Getenv("PATH"), "gdb", kExecutePermission);
2274  if (!gdb) {
2275  fprintf(stderr, "gdb not found, need it for stack trace\n");
2276  return;
2277  }
2278 
2279  // write custom message file
2280  TString gdbmessf = "gdb-message";
2281  if (gdbmess != "") {
2282  FILE *f = TempFileName(gdbmessf);
2283  fprintf(f, "%s\n", gdbmess.Data());
2284  fclose(f);
2285  }
2286 
2287  // use gdb to get stack trace
2288  gdbscript += GetExePath();
2289  gdbscript += " ";
2290  gdbscript += GetPid();
2291  if (gdbmess != "") {
2292  gdbscript += " ";
2293  gdbscript += gdbmessf;
2294  }
2295  gdbscript += " 1>&2";
2296  Exec(gdbscript);
2297  delete [] gdb;
2298  return;
2299 
2300 #elif defined(R__AIX)
2301  TString script = "procstack ";
2302  script += GetPid();
2303  Exec(script);
2304  return;
2305 #elif defined(R__SOLARIS)
2306  char *cppfilt = Which(Getenv("PATH"), "c++filt", kExecutePermission);
2307  TString script = "pstack ";
2308  script += GetPid();
2309  if (cppfilt) {
2310  script += " | ";
2311  script += cppfilt;
2312  delete [] cppfilt;
2313  }
2314  Exec(script);
2315  return;
2316 #elif defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_DLADDR) // linux + MacOS X >= 10.5
2317  // we could have used backtrace_symbols_fd, except its output
2318  // format is pretty bad, so recode that here :-(
2319 
2320  // take care of demangling
2321  Bool_t demangle = kTRUE;
2322 
2323  // check for c++filt
2324  const char *cppfilt = "c++filt";
2325  const char *cppfiltarg = "";
2326 #ifdef R__B64
2327  const char *format1 = " 0x%016lx in %.200s %s 0x%lx from %.200s\n";
2328 #ifdef R__MACOSX
2329  const char *format2 = " 0x%016lx in %.200s\n";
2330 #else
2331  const char *format2 = " 0x%016lx in %.200s at %.200s from %.200s\n";
2332 #endif
2333  const char *format3 = " 0x%016lx in %.200s from %.200s\n";
2334  const char *format4 = " 0x%016lx in <unknown function>\n";
2335 #else
2336  const char *format1 = " 0x%08lx in %.200s %s 0x%lx from %.200s\n";
2337 #ifdef R__MACOSX
2338  const char *format2 = " 0x%08lx in %.200s\n";
2339 #else
2340  const char *format2 = " 0x%08lx in %.200s at %.200s from %.200s\n";
2341 #endif
2342  const char *format3 = " 0x%08lx in %.200s from %.200s\n";
2343  const char *format4 = " 0x%08lx in <unknown function>\n";
2344 #endif
2345 
2346  char *filter = Which(Getenv("PATH"), cppfilt, kExecutePermission);
2347  if (!filter)
2348  demangle = kFALSE;
2349 
2350 #if (__GNUC__ >= 3)
2351  // try finding supported format option for g++ v3
2352  if (filter) {
2353  FILE *p = OpenPipe(TString::Format("%s --help 2>&1", filter), "r");
2354  TString help;
2355  while (help.Gets(p)) {
2356  if (help.Index("gnu-v3") != kNPOS) {
2357  cppfiltarg = "--format=gnu-v3";
2358  break;
2359  } else if (help.Index("gnu-new-abi") != kNPOS) {
2360  cppfiltarg = "--format=gnu-new-abi";
2361  break;
2362  }
2363  }
2364  ClosePipe(p);
2365  }
2366 #endif
2367  // gdb-backtrace.sh uses gdb to produce a backtrace. See if it is available.
2368  // If it is, use it. If not proceed as before.
2369 #if (defined(R__LINUX) && !defined(R__WINGCC))
2370  // Declare the process that will be generating the stacktrace
2371  // For more see: http://askubuntu.com/questions/41629/after-upgrade-gdb-wont-attach-to-process
2372 #ifdef PR_SET_PTRACER
2373  prctl(PR_SET_PTRACER, getpid(), 0, 0, 0);
2374 #endif
2375 #endif
2376  char *gdb = Which(Getenv("PATH"), "gdb", kExecutePermission);
2377  if (gdb) {
2378  // write custom message file
2379  TString gdbmessf = "gdb-message";
2380  if (gdbmess != "") {
2381  FILE *f = TempFileName(gdbmessf);
2382  fprintf(f, "%s\n", gdbmess.Data());
2383  fclose(f);
2384  }
2385 
2386  // use gdb to get stack trace
2387 #ifdef R__MACOSX
2388  gdbscript += GetExePath();
2389  gdbscript += " ";
2390 #endif
2391  gdbscript += GetPid();
2392  if (gdbmess != "") {
2393  gdbscript += " ";
2394  gdbscript += gdbmessf;
2395  }
2396  gdbscript += " 1>&2";
2397  Exec(gdbscript);
2398  delete [] gdb;
2399  } else {
2400  // addr2line uses debug info to convert addresses into file names
2401  // and line numbers
2402 #ifdef R__MACOSX
2403  char *addr2line = Which(Getenv("PATH"), "atos", kExecutePermission);
2404 #else
2405  char *addr2line = Which(Getenv("PATH"), "addr2line", kExecutePermission);
2406 #endif
2407  if (addr2line) {
2408  // might take some time so tell what we are doing...
2409  if (write(fd, message, strlen(message)) < 0)
2410  Warning("StackTrace", "problems writing line numbers (errno: %d)", TSystem::GetErrno());
2411  }
2412 
2413  // open tmp file for demangled stack trace
2414  TString tmpf1 = "gdb-backtrace";
2415  std::ofstream file1;
2416  if (demangle) {
2417  FILE *f = TempFileName(tmpf1);
2418  if (f) fclose(f);
2419  file1.open(tmpf1);
2420  if (!file1) {
2421  Error("StackTrace", "could not open file %s", tmpf1.Data());
2422  Unlink(tmpf1);
2423  demangle = kFALSE;
2424  }
2425  }
2426 
2427 #ifdef R__MACOSX
2428  if (addr2line)
2429  demangle = kFALSE; // atos always demangles
2430 #endif
2431 
2432  char buffer[4096];
2433  void *trace[kMAX_BACKTRACE_DEPTH];
2434  int depth = backtrace(trace, kMAX_BACKTRACE_DEPTH);
2435  for (int n = 5; n < depth; n++) {
2436  ULong_t addr = (ULong_t) trace[n];
2437  Dl_info info;
2438 
2439  if (dladdr(trace[n], &info) && info.dli_fname && info.dli_fname[0]) {
2440  const char *libname = info.dli_fname;
2441  const char *symname = (info.dli_sname && info.dli_sname[0]) ?
2442  info.dli_sname : "<unknown>";
2443  ULong_t libaddr = (ULong_t) info.dli_fbase;
2444  ULong_t symaddr = (ULong_t) info.dli_saddr;
2445  Bool_t gte = (addr >= symaddr);
2446  ULong_t diff = (gte) ? addr - symaddr : symaddr - addr;
2447  if (addr2line && symaddr) {
2448  Bool_t nodebug = kTRUE;
2449 #ifdef R__MACOSX
2450  if (libaddr) { } // use libaddr
2451 #if defined(MAC_OS_X_VERSION_10_10)
2452  snprintf(buffer, sizeof(buffer), "%s -p %d 0x%016lx", addr2line, GetPid(), addr);
2453 #elif defined(MAC_OS_X_VERSION_10_9)
2454  // suppress deprecation warning with opti
2455  snprintf(buffer, sizeof(buffer), "%s -d -p %d 0x%016lx", addr2line, GetPid(), addr);
2456 #else
2457  snprintf(buffer, sizeof(buffer), "%s -p %d 0x%016lx", addr2line, GetPid(), addr);
2458 #endif
2459 #else
2460  ULong_t offset = (addr >= libaddr) ? addr - libaddr :
2461  libaddr - addr;
2462  TString name = TString(libname);
2463  Bool_t noPath = kFALSE;
2464  Bool_t noShare = kTRUE;
2465  if (name[0] != '/') noPath = kTRUE;
2466  if (name.Contains(".so") || name.Contains(".sl")) noShare = kFALSE;
2467  if (noShare) offset = addr;
2468  if (noPath) name = "`which " + name + "`";
2469  snprintf(buffer, sizeof(buffer), "%s -e %s 0x%016lx", addr2line, name.Data(), offset);
2470 #endif
2471  if (FILE *pf = ::popen(buffer, "r")) {
2472  char buf[2048];
2473  if (fgets(buf, 2048, pf)) {
2474  buf[strlen(buf)-1] = 0; // remove trailing \n
2475  if (strncmp(buf, "??", 2)) {
2476 #ifdef R__MACOSX
2477  snprintf(buffer, sizeof(buffer), format2, addr, buf);
2478 #else
2479  snprintf(buffer, sizeof(buffer), format2, addr, symname, buf, libname);
2480 #endif
2481  nodebug = kFALSE;
2482  }
2483  }
2484  ::pclose(pf);
2485  }
2486  if (nodebug)
2487  snprintf(buffer, sizeof(buffer), format1, addr, symname,
2488  gte ? "+" : "-", diff, libname);
2489  } else {
2490  if (symaddr)
2491  snprintf(buffer, sizeof(buffer), format1, addr, symname,
2492  gte ? "+" : "-", diff, libname);
2493  else
2494  snprintf(buffer, sizeof(buffer), format3, addr, symname, libname);
2495  }
2496  } else {
2497  snprintf(buffer, sizeof(buffer), format4, addr);
2498  }
2499 
2500  if (demangle)
2501  file1 << buffer;
2502  else
2503  if (write(fd, buffer, ::strlen(buffer)) < 0)
2504  Warning("StackTrace", "problems writing buffer (errno: %d)", TSystem::GetErrno());
2505  }
2506 
2507  if (demangle) {
2508  TString tmpf2 = "gdb-backtrace";
2509  FILE *f = TempFileName(tmpf2);
2510  if (f) fclose(f);
2511  file1.close();
2512  snprintf(buffer, sizeof(buffer), "%s %s < %s > %s", filter, cppfiltarg, tmpf1.Data(), tmpf2.Data());
2513  Exec(buffer);
2514  std::ifstream file2(tmpf2);
2515  TString line;
2516  while (file2) {
2517  line = "";
2518  line.ReadString(file2);
2519  if (write(fd, line.Data(), line.Length()) < 0)
2520  Warning("StackTrace", "problems writing line (errno: %d)", TSystem::GetErrno());
2521  }
2522  file2.close();
2523  Unlink(tmpf1);
2524  Unlink(tmpf2);
2525  }
2526 
2527  delete [] addr2line;
2528  }
2529  delete [] filter;
2530 #elif defined(HAVE_EXCPT_H) && defined(HAVE_PDSC_H) && \
2531  defined(HAVE_RLD_INTERFACE_H) // tru64
2532  // Tru64 stack walk. Uses the exception handling library and the
2533  // run-time linker's core functions (loader(5)). FIXME: Tru64
2534  // should have _RLD_DLADDR like IRIX below. Verify and update.
2535 
2536  char buffer [128];
2537  sigcontext context;
2538  int rc = 0;
2539 
2540  exc_capture_context (&context);
2541  while (!rc && context.sc_pc) {
2542  // FIXME: Elf32?
2543  pdsc_crd *func, *base, *crd
2544  = exc_remote_lookup_function_entry(0, 0, context.sc_pc, 0, &func, &base);
2545  Elf32_Addr addr = PDSC_CRD_BEGIN_ADDRESS(base, func);
2546  // const char *name = _rld_address_to_name(addr);
2547  const char *name = "<unknown function>";
2548  sprintf(buffer, " 0x%012lx %.200s + 0x%lx\n",
2549  context.sc_pc, name, context.sc_pc - addr);
2550  write(fd, buffer, ::strlen(buffer));
2551  rc = exc_virtual_unwind(0, &context);
2552  }
2553 #endif
2554 #else //R__MACOSX
2555  macosx_backtrace();
2556 #endif //R__MACOSX
2557 }
2558 
2559 //---- System Logging ----------------------------------------------------------
2560 
2561 ////////////////////////////////////////////////////////////////////////////////
2562 /// Open connection to system log daemon. For the use of the options and
2563 /// facility see the Unix openlog man page.
2564 
2565 void TUnixSystem::Openlog(const char *name, Int_t options, ELogFacility facility)
2566 {
2567  int fac = 0;
2568 
2569  switch (facility) {
2570  case kLogLocal0:
2571  fac = LOG_LOCAL0;
2572  break;
2573  case kLogLocal1:
2574  fac = LOG_LOCAL1;
2575  break;
2576  case kLogLocal2:
2577  fac = LOG_LOCAL2;
2578  break;
2579  case kLogLocal3:
2580  fac = LOG_LOCAL3;
2581  break;
2582  case kLogLocal4:
2583  fac = LOG_LOCAL4;
2584  break;
2585  case kLogLocal5:
2586  fac = LOG_LOCAL5;
2587  break;
2588  case kLogLocal6:
2589  fac = LOG_LOCAL6;
2590  break;
2591  case kLogLocal7:
2592  fac = LOG_LOCAL7;
2593  break;
2594  }
2595 
2596  ::openlog(name, options, fac);
2597 }
2598 
2599 ////////////////////////////////////////////////////////////////////////////////
2600 /// Send mess to syslog daemon. Level is the logging level and mess the
2601 /// message that will be written on the log.
2602 
2603 void TUnixSystem::Syslog(ELogLevel level, const char *mess)
2604 {
2605  // ELogLevel matches exactly the Unix values.
2606  ::syslog(level, "%s", mess);
2607 }
2608 
2609 ////////////////////////////////////////////////////////////////////////////////
2610 /// Close connection to system log daemon.
2611 
2612 void TUnixSystem::Closelog()
2613 {
2614  ::closelog();
2615 }
2616 
2617 //---- Standard output redirection ---------------------------------------------
2618 
2619 ////////////////////////////////////////////////////////////////////////////////
2620 /// Redirect standard output (stdout, stderr) to the specified file.
2621 /// If the file argument is 0 the output is set again to stderr, stdout.
2622 /// The second argument specifies whether the output should be added to the
2623 /// file ("a", default) or the file be truncated before ("w").
2624 /// This function saves internally the current state into a static structure.
2625 /// The call can be made reentrant by specifying the opaque structure pointed
2626 /// by 'h', which is filled with the relevant information. The handle 'h'
2627 /// obtained on the first call must then be used in any subsequent call,
2628 /// included ShowOutput, to display the redirected output.
2629 /// Returns 0 on success, -1 in case of error.
2630 
2631 Int_t TUnixSystem::RedirectOutput(const char *file, const char *mode,
2632  RedirectHandle_t *h)
2633 {
2634  // Instance to be used if the caller does not passes 'h'
2635  static RedirectHandle_t loch;
2636 
2637  Int_t rc = 0;
2638 
2639  // Which handle to use ?
2640  RedirectHandle_t *xh = (h) ? h : &loch;
2641 
2642  if (file) {
2643  // Save the paths
2644  Bool_t outdone = kFALSE;
2645  if (xh->fStdOutTty.IsNull()) {
2646  const char *tty = ttyname(STDOUT_FILENO);
2647  if (tty) {
2648  xh->fStdOutTty = tty;
2649  } else {
2650  if ((xh->fStdOutDup = dup(STDOUT_FILENO)) < 0) {
2651  SysError("RedirectOutput", "could not 'dup' stdout (errno: %d)", TSystem::GetErrno());
2652  return -1;
2653  }
2654  outdone = kTRUE;
2655  }
2656  }
2657  if (xh->fStdErrTty.IsNull()) {
2658  const char *tty = ttyname(STDERR_FILENO);
2659  if (tty) {
2660  xh->fStdErrTty = tty;
2661  } else {
2662  if ((xh->fStdErrDup = dup(STDERR_FILENO)) < 0) {
2663  SysError("RedirectOutput", "could not 'dup' stderr (errno: %d)", TSystem::GetErrno());
2664  if (outdone && dup2(xh->fStdOutDup, STDOUT_FILENO) < 0) {
2665  Warning("RedirectOutput", "could not restore stdout (back to original redirected"
2666  " file) (errno: %d)", TSystem::GetErrno());
2667  }
2668  return -1;
2669  }
2670  }
2671  }
2672 
2673  // Make sure mode makes sense; default "a"
2674  const char *m = (mode[0] == 'a' || mode[0] == 'w') ? mode : "a";
2675 
2676  // Current file size
2677  xh->fReadOffSet = 0;
2678  if (m[0] == 'a') {
2679  // If the file exists, save the current size
2680  FileStat_t st;
2681  if (!gSystem->GetPathInfo(file, st))
2682  xh->fReadOffSet = (st.fSize > 0) ? st.fSize : xh->fReadOffSet;
2683  }
2684  xh->fFile = file;
2685 
2686  // Redirect stdout & stderr
2687  if (freopen(file, m, stdout) == 0) {
2688  SysError("RedirectOutput", "could not freopen stdout (errno: %d)", TSystem::GetErrno());
2689  return -1;
2690  }
2691  if (freopen(file, m, stderr) == 0) {
2692  SysError("RedirectOutput", "could not freopen stderr (errno: %d)", TSystem::GetErrno());
2693  if (freopen(xh->fStdOutTty.Data(), "a", stdout) == 0)
2694  SysError("RedirectOutput", "could not restore stdout (errno: %d)", TSystem::GetErrno());
2695  return -1;
2696  }
2697  } else {
2698  // Restore stdout & stderr
2699  fflush(stdout);
2700  if (!(xh->fStdOutTty.IsNull())) {
2701  if (freopen(xh->fStdOutTty.Data(), "a", stdout) == 0) {
2702  SysError("RedirectOutput", "could not restore stdout (errno: %d)", TSystem::GetErrno());
2703  rc = -1;
2704  }
2705  xh->fStdOutTty = "";
2706  } else {
2707  if (close(STDOUT_FILENO) != 0) {
2708  SysError("RedirectOutput",
2709  "problems closing STDOUT_FILENO (%d) before 'dup2' (errno: %d)",
2710  STDOUT_FILENO, TSystem::GetErrno());
2711  rc = -1;
2712  }
2713  if (dup2(xh->fStdOutDup, STDOUT_FILENO) < 0) {
2714  SysError("RedirectOutput", "could not restore stdout (back to original redirected"
2715  " file) (errno: %d)", TSystem::GetErrno());
2716  rc = -1;
2717  }
2718  if (close(xh->fStdOutDup) != 0) {
2719  SysError("RedirectOutput",
2720  "problems closing temporary 'out' descriptor %d (errno: %d)",
2721  TSystem::GetErrno(), xh->fStdOutDup);
2722  rc = -1;
2723  }
2724  }
2725  fflush(stderr);
2726  if (!(xh->fStdErrTty.IsNull())) {
2727  if (freopen(xh->fStdErrTty.Data(), "a", stderr) == 0) {
2728  SysError("RedirectOutput", "could not restore stderr (errno: %d)", TSystem::GetErrno());
2729  rc = -1;
2730  }
2731  xh->fStdErrTty = "";
2732  } else {
2733  if (close(STDERR_FILENO) != 0) {
2734  SysError("RedirectOutput",
2735  "problems closing STDERR_FILENO (%d) before 'dup2' (errno: %d)",
2736  STDERR_FILENO, TSystem::GetErrno());
2737  rc = -1;
2738  }
2739  if (dup2(xh->fStdErrDup, STDERR_FILENO) < 0) {
2740  SysError("RedirectOutput", "could not restore stderr (back to original redirected"
2741  " file) (errno: %d)", TSystem::GetErrno());
2742  rc = -1;
2743  }
2744  if (close(xh->fStdErrDup) != 0) {
2745  SysError("RedirectOutput",
2746  "problems closing temporary 'err' descriptor %d (errno: %d)",
2747  TSystem::GetErrno(), xh->fStdErrDup);
2748  rc = -1;
2749  }
2750  }
2751  // Reset the static instance, if using that
2752  if (xh == &loch)
2753  xh->Reset();
2754  }
2755  return rc;
2756 }
2757 
2758 //---- dynamic loading and linking ---------------------------------------------
2759 
2760 ////////////////////////////////////////////////////////////////////////////////
2761 ///dynamic linking of module
2762 
2763 Func_t TUnixSystem::DynFindSymbol(const char * /*module*/, const char *entry)
2764 {
2765  return TSystem::DynFindSymbol("*", entry);
2766 }
2767 
2768 ////////////////////////////////////////////////////////////////////////////////
2769 /// Load a shared library. Returns 0 on successful loading, 1 in
2770 /// case lib was already loaded and -1 in case lib does not exist
2771 /// or in case of error.
2772 
2773 int TUnixSystem::Load(const char *module, const char *entry, Bool_t system)
2774 {
2775  return TSystem::Load(module, entry, system);
2776 }
2777 
2778 ////////////////////////////////////////////////////////////////////////////////
2779 /// Unload a shared library.
2780 
2781 void TUnixSystem::Unload(const char *module)
2782 {
2783  if (module) { TSystem::Unload(module); }
2784 }
2785 
2786 ////////////////////////////////////////////////////////////////////////////////
2787 /// List symbols in a shared library.
2788 
2789 void TUnixSystem::ListSymbols(const char * /*module*/, const char * /*regexp*/)
2790 {
2791  Error("ListSymbols", "not yet implemented");
2792 }
2793 
2794 ////////////////////////////////////////////////////////////////////////////////
2795 /// List all loaded shared libraries.
2796 
2797 void TUnixSystem::ListLibraries(const char *regexp)
2798 {
2799  TSystem::ListLibraries(regexp);
2800 }
2801 
2802 ////////////////////////////////////////////////////////////////////////////////
2803 /// Get list of shared libraries loaded at the start of the executable.
2804 /// Returns 0 in case list cannot be obtained or in case of error.
2805 
2806 const char *TUnixSystem::GetLinkedLibraries()
2807 {
2808  static TString linkedLibs;
2809  static Bool_t once = kFALSE;
2810 
2811  R__LOCKGUARD2(gSystemMutex);
2812 
2813  if (!linkedLibs.IsNull())
2814  return linkedLibs;
2815 
2816  if (once)
2817  return 0;
2818 
2819 #if !defined(R__MACOSX)
2820  const char *exe = GetExePath();
2821  if (!exe || !*exe)
2822  return 0;
2823 #endif
2824 
2825 #if defined(R__MACOSX)
2826  DylibAdded(0, 0);
2827  linkedLibs = gLinkedDylibs;
2828 #if 0
2829  FILE *p = OpenPipe(TString::Format("otool -L %s", exe), "r");
2830  TString otool;
2831  while (otool.Gets(p)) {
2832  TString delim(" \t");
2833  TObjArray *tok = otool.Tokenize(delim);
2834  TString dylib = ((TObjString*)tok->At(0))->String();
2835  if (dylib.EndsWith(".dylib") && !dylib.Contains("/libSystem.B.dylib")) {
2836  if (!linkedLibs.IsNull())
2837  linkedLibs += " ";
2838  linkedLibs += dylib;
2839  }
2840  delete tok;
2841  }
2842  if (p) {
2843  ClosePipe(p);
2844  }
2845 #endif
2846 #elif defined(R__LINUX) || defined(R__SOLARIS) || defined(R__AIX)
2847 #if defined(R__WINGCC )
2848  const char *cLDD="cygcheck";
2849  const char *cSOEXT=".dll";
2850  size_t lenexe = strlen(exe);
2851  if (strcmp(exe + lenexe - 4, ".exe")
2852  && strcmp(exe + lenexe - 4, ".dll")) {
2853  // it's not a dll and exe doesn't end on ".exe";
2854  // need to add it for cygcheck to find it:
2855  char* longerexe = new char[lenexe + 5];
2856  strlcpy(longerexe, exe,lenexe+5);
2857  strlcat(longerexe, ".exe",lenexe+5);
2858  delete [] exe;
2859  exe = longerexe;
2860  }
2861  TRegexp sovers = "\\.so\\.[0-9]+";
2862 #else
2863  const char *cLDD="ldd";
2864 #if defined(R__AIX)
2865  const char *cSOEXT=".a";
2866  TRegexp sovers = "\\.a\\.[0-9]+";
2867 #else
2868  const char *cSOEXT=".so";
2869  TRegexp sovers = "\\.so\\.[0-9]+";
2870 #endif
2871 #endif
2872  FILE *p = OpenPipe(TString::Format("%s '%s'", cLDD, exe), "r");
2873  if (p) {
2874  TString ldd;
2875  while (ldd.Gets(p)) {
2876  TString delim(" \t");
2877  TObjArray *tok = ldd.Tokenize(delim);
2878 
2879  // expected format:
2880  // libCore.so => /home/rdm/root/lib/libCore.so (0x40017000)
2881  TObjString *solibName = (TObjString*)tok->At(2);
2882  if (!solibName) {
2883  // case where there is only one name of the list:
2884  // /usr/platform/SUNW,UltraAX-i2/lib/libc_psr.so.1
2885  solibName = (TObjString*)tok->At(0);
2886  }
2887  if (solibName) {
2888  TString solib = solibName->String();
2889  Ssiz_t idx = solib.Index(sovers);
2890  if (solib.EndsWith(cSOEXT) || idx != kNPOS) {
2891  if (idx != kNPOS)
2892  solib.Remove(idx+3);
2893  if (!AccessPathName(solib, kReadPermission)) {
2894  if (!linkedLibs.IsNull())
2895  linkedLibs += " ";
2896  linkedLibs += solib;
2897  }
2898  }
2899  }
2900  delete tok;
2901  }
2902  ClosePipe(p);
2903  }
2904 #endif
2905 
2906  once = kTRUE;
2907 
2908  if (linkedLibs.IsNull())
2909  return 0;
2910 
2911  return linkedLibs;
2912 }
2913 
2914 //---- Time & Date -------------------------------------------------------------
2915 
2916 ////////////////////////////////////////////////////////////////////////////////
2917 /// Get current time in milliseconds since 0:00 Jan 1 1995.
2918 
2919 TTime TUnixSystem::Now()
2920 {
2921  return UnixNow();
2922 }
2923 
2924 ////////////////////////////////////////////////////////////////////////////////
2925 /// Handle and dispatch timers. If mode = kTRUE dispatch synchronous
2926 /// timers else a-synchronous timers.
2927 
2928 Bool_t TUnixSystem::DispatchTimers(Bool_t mode)
2929 {
2930  if (!fTimers) return kFALSE;
2931 
2932  fInsideNotify = kTRUE;
2933 
2934  TOrdCollectionIter it((TOrdCollection*)fTimers);
2935  TTimer *t;
2936  Bool_t timedout = kFALSE;
2937 
2938  while ((t = (TTimer *) it.Next())) {
2939  // NB: the timer resolution is added in TTimer::CheckTimer()
2940  Long64_t now = UnixNow();
2941  if (mode && t->IsSync()) {
2942  if (t->CheckTimer(now))
2943  timedout = kTRUE;
2944  } else if (!mode && t->IsAsync()) {
2945  if (t->CheckTimer(now)) {
2946  UnixSetitimer(NextTimeOut(kFALSE));
2947  timedout = kTRUE;
2948  }
2949  }
2950  }
2951  fInsideNotify = kFALSE;
2952  return timedout;
2953 }
2954 
2955 ////////////////////////////////////////////////////////////////////////////////
2956 /// Add timer to list of system timers.
2957 
2958 void TUnixSystem::AddTimer(TTimer *ti)
2959 {
2960  TSystem::AddTimer(ti);
2961  ResetTimer(ti);
2962 }
2963 
2964 ////////////////////////////////////////////////////////////////////////////////
2965 /// Remove timer from list of system timers.
2966 
2967 TTimer *TUnixSystem::RemoveTimer(TTimer *ti)
2968 {
2969  if (!ti) return 0;
2970 
2971  R__LOCKGUARD2(gSystemMutex);
2972 
2973  TTimer *t = TSystem::RemoveTimer(ti);
2974  if (ti->IsAsync())
2975  UnixSetitimer(NextTimeOut(kFALSE));
2976  return t;
2977 }
2978 
2979 ////////////////////////////////////////////////////////////////////////////////
2980 /// Reset a-sync timer.
2981 
2982 void TUnixSystem::ResetTimer(TTimer *ti)
2983 {
2984  if (!fInsideNotify && ti && ti->IsAsync())
2985  UnixSetitimer(NextTimeOut(kFALSE));
2986 }
2987 
2988 //---- RPC ---------------------------------------------------------------------
2989 
2990 ////////////////////////////////////////////////////////////////////////////////
2991 /// Get Internet Protocol (IP) address of host. Returns an TInetAddress
2992 /// object. To see if the hostname lookup was successfull call
2993 /// TInetAddress::IsValid().
2994 
2995 TInetAddress TUnixSystem::GetHostByName(const char *hostname)
2996 {
2997  TInetAddress ia;
2998  struct addrinfo hints;
2999  struct addrinfo *result, *rp;
3000  memset(&hints, 0, sizeof(struct addrinfo));
3001  hints.ai_family = AF_INET; // only IPv4
3002  hints.ai_socktype = 0; // any socket type
3003  hints.ai_protocol = 0; // any protocol
3004  hints.ai_flags = AI_CANONNAME; // get canonical name
3005 #ifdef R__MACOSX
3006  // Anything ending on ".local" causes a 5 second delay in getaddrinfo().
3007  // See e.g. https://apple.stackexchange.com/questions/175320/why-is-my-hostname-resolution-taking-so-long
3008  // Only reasonable solution: remove the "domain" part if it's ".local".
3009  size_t lenHostname = strlen(hostname);
3010  std::string hostnameWithoutLocal{hostname};
3011  if (lenHostname > 6 && !strcmp(hostname + lenHostname - 6, ".local")) {
3012  hostnameWithoutLocal.erase(lenHostname - 6);
3013  hostname = hostnameWithoutLocal.c_str();
3014  }
3015 #endif
3016 
3017  // obsolete gethostbyname() replaced by getaddrinfo()
3018  int rc = getaddrinfo(hostname, nullptr, &hints, &result);
3019  if (rc != 0) {
3020  if (rc == EAI_NONAME) {
3021  if (gDebug > 0) Error("GetHostByName", "unknown host '%s'", hostname);
3022  ia.fHostname = "UnNamedHost";
3023  } else {
3024  Error("GetHostByName", "getaddrinfo failed for '%s': %s", hostname, gai_strerror(rc));
3025  ia.fHostname = "UnknownHost";
3026  }
3027  return ia;
3028  }
3029 
3030  std::string hostcanon(result->ai_canonname ? result->ai_canonname : hostname);
3031  ia.fHostname = hostcanon.data();
3032  ia.fFamily = result->ai_family;
3033  ia.fAddresses[0] = ntohl(((struct sockaddr_in *)(result->ai_addr))->sin_addr.s_addr);
3034  // with getaddrinfo() no way to get list of aliases for a hostname
3035  if (hostcanon.compare(hostname) != 0) ia.AddAlias(hostname);
3036 
3037  // check on numeric hostname
3038  char tmp[sizeof(struct in_addr)];
3039  if (inet_pton(AF_INET, hostcanon.data(), tmp) == 1) {
3040  char hbuf[NI_MAXHOST];
3041  if (getnameinfo(result->ai_addr, result->ai_addrlen, hbuf, sizeof(hbuf), nullptr, 0, 0) == 0)
3042  ia.fHostname = hbuf;
3043  }
3044 
3045  // check other addresses (if exist)
3046  rp = result->ai_next;
3047  for (; rp != nullptr; rp = rp->ai_next) {
3048  UInt_t arp = ntohl(((struct sockaddr_in *)(rp->ai_addr))->sin_addr.s_addr);
3049  if ( !(std::find(ia.fAddresses.begin(), ia.fAddresses.end(), arp) != ia.fAddresses.end()) )
3050  ia.AddAddress(arp);
3051  }
3052 
3053  freeaddrinfo(result);
3054  return ia;
3055 }
3056 
3057 ////////////////////////////////////////////////////////////////////////////////
3058 /// Get Internet Protocol (IP) address of host and port #.
3059 
3060 TInetAddress TUnixSystem::GetSockName(int sock)
3061 {
3062  struct sockaddr addr;
3063 #if defined(USE_SIZE_T)
3064  size_t len = sizeof(addr);
3065 #elif defined(USE_SOCKLEN_T)
3066  socklen_t len = sizeof(addr);
3067 #else
3068  int len = sizeof(addr);
3069 #endif
3070 
3071  TInetAddress ia;
3072  if (getsockname(sock, &addr, &len) == -1) {
3073  SysError("GetSockName", "getsockname failed");
3074  return ia;
3075  }
3076 
3077  if (addr.sa_family != AF_INET) return ia; // only IPv4
3078  ia.fFamily = addr.sa_family;
3079  struct sockaddr_in *addrin = (struct sockaddr_in *)&addr;
3080  ia.fPort = ntohs(addrin->sin_port);
3081  ia.fAddresses[0] = ntohl(addrin->sin_addr.s_addr);
3082 
3083  char hbuf[NI_MAXHOST];
3084  if (getnameinfo(&addr, sizeof(struct sockaddr), hbuf, sizeof(hbuf), nullptr, 0, 0) != 0) {
3085  Error("GetSockName", "getnameinfo failed");
3086  ia.fHostname = "????";
3087  } else
3088  ia.fHostname = hbuf;
3089 
3090  return ia;
3091 }
3092 
3093 ////////////////////////////////////////////////////////////////////////////////
3094 /// Get Internet Protocol (IP) address of remote host and port #.
3095 
3096 TInetAddress TUnixSystem::GetPeerName(int sock)
3097 {
3098  struct sockaddr addr;
3099 #if defined(USE_SIZE_T)
3100  size_t len = sizeof(addr);
3101 #elif defined(USE_SOCKLEN_T)
3102  socklen_t len = sizeof(addr);
3103 #else
3104  int len = sizeof(addr);
3105 #endif
3106 
3107  TInetAddress ia;
3108  if (getpeername(sock, &addr, &len) == -1) {
3109  SysError("GetPeerName", "getpeername failed");
3110  return ia;
3111  }
3112 
3113  if (addr.sa_family != AF_INET) return ia; // only IPv4
3114  ia.fFamily = addr.sa_family;
3115  struct sockaddr_in *addrin = (struct sockaddr_in *)&addr;
3116  ia.fPort = ntohs(addrin->sin_port);
3117  ia.fAddresses[0] = ntohl(addrin->sin_addr.s_addr);
3118 
3119  char hbuf[NI_MAXHOST];
3120  if (getnameinfo(&addr, sizeof(struct sockaddr), hbuf, sizeof(hbuf), nullptr, 0, 0) != 0) {
3121  Error("GetPeerName", "getnameinfo failed");
3122  ia.fHostname = "????";
3123  } else
3124  ia.fHostname = hbuf;
3125 
3126  return ia;
3127 }
3128 
3129 ////////////////////////////////////////////////////////////////////////////////
3130 /// Get port # of internet service.
3131 
3132 int TUnixSystem::GetServiceByName(const char *servicename)
3133 {
3134  struct servent *sp;
3135 
3136  if ((sp = getservbyname(servicename, kProtocolName)) == 0) {
3137  Error("GetServiceByName", "no service \"%s\" with protocol \"%s\"\n",
3138  servicename, kProtocolName);
3139  return -1;
3140  }
3141  return ntohs(sp->s_port);
3142 }
3143 
3144 ////////////////////////////////////////////////////////////////////////////////
3145 /// Get name of internet service.
3146 
3147 char *TUnixSystem::GetServiceByPort(int port)
3148 {
3149  struct servent *sp;
3150 
3151  if ((sp = getservbyport(htons(port), kProtocolName)) == 0) {
3152  //::Error("GetServiceByPort", "no service \"%d\" with protocol \"%s\"",
3153  // port, kProtocolName);
3154  return Form("%d", port);
3155  }
3156  return sp->s_name;
3157 }
3158 
3159 ////////////////////////////////////////////////////////////////////////////////
3160 /// Connect to service servicename on server servername.
3161 
3162 int TUnixSystem::ConnectService(const char *servername, int port,
3163  int tcpwindowsize, const char *protocol)
3164 {
3165  if (!strcmp(servername, "unix")) {
3166  return UnixUnixConnect(port);
3167  } else if (!gSystem->AccessPathName(servername) || servername[0] == '/') {
3168  return UnixUnixConnect(servername);
3169  }
3170 
3171  if (!strcmp(protocol, "udp")){
3172  return UnixUdpConnect(servername, port);
3173  }
3174 
3175  return UnixTcpConnect(servername, port, tcpwindowsize);
3176 }
3177 
3178 ////////////////////////////////////////////////////////////////////////////////
3179 /// Open a connection to a service on a server. Returns -1 in case
3180 /// connection cannot be opened.
3181 /// Use tcpwindowsize to specify the size of the receive buffer, it has
3182 /// to be specified here to make sure the window scale option is set (for
3183 /// tcpwindowsize > 65KB and for platforms supporting window scaling).
3184 /// Is called via the TSocket constructor.
3185 
3186 int TUnixSystem::OpenConnection(const char *server, int port, int tcpwindowsize, const char *protocol)
3187 {
3188  return ConnectService(server, port, tcpwindowsize, protocol);
3189 }
3190 
3191 ////////////////////////////////////////////////////////////////////////////////
3192 /// Announce TCP/IP service.
3193 /// Open a socket, bind to it and start listening for TCP/IP connections
3194 /// on the port. If reuse is true reuse the address, backlog specifies
3195 /// how many sockets can be waiting to be accepted.
3196 /// Use tcpwindowsize to specify the size of the receive buffer, it has
3197 /// to be specified here to make sure the window scale option is set (for
3198 /// tcpwindowsize > 65KB and for platforms supporting window scaling).
3199 /// Returns socket fd or -1 if socket() failed, -2 if bind() failed
3200 /// or -3 if listen() failed.
3201 
3202 int TUnixSystem::AnnounceTcpService(int port, Bool_t reuse, int backlog,
3203  int tcpwindowsize)
3204 {
3205  return UnixTcpService(port, reuse, backlog, tcpwindowsize);
3206 }
3207 
3208 ////////////////////////////////////////////////////////////////////////////////
3209 /// Announce UDP service.
3210 
3211 int TUnixSystem::AnnounceUdpService(int port, int backlog)
3212 {
3213  return UnixUdpService(port, backlog);
3214 }
3215 
3216 ////////////////////////////////////////////////////////////////////////////////
3217 /// Announce unix domain service on path "kServerPath/<port>"
3218 
3219 int TUnixSystem::AnnounceUnixService(int port, int backlog)
3220 {
3221  return UnixUnixService(port, backlog);
3222 }
3223 
3224 ////////////////////////////////////////////////////////////////////////////////
3225 /// Announce unix domain service on path 'sockpath'
3226 
3227 int TUnixSystem::AnnounceUnixService(const char *sockpath, int backlog)
3228 {
3229  return UnixUnixService(sockpath, backlog);
3230 }
3231 
3232 ////////////////////////////////////////////////////////////////////////////////
3233 /// Accept a connection. In case of an error return -1. In case
3234 /// non-blocking I/O is enabled and no connections are available
3235 /// return -2.
3236 
3237 int TUnixSystem::AcceptConnection(int sock)
3238 {
3239  int soc = -1;
3240 
3241  while ((soc = ::accept(sock, 0, 0)) == -1 && GetErrno() == EINTR)
3242  ResetErrno();
3243 
3244  if (soc == -1) {
3245  if (GetErrno() == EWOULDBLOCK)
3246  return -2;
3247  else {
3248  SysError("AcceptConnection", "accept");
3249  return -1;
3250  }
3251  }
3252 
3253  return soc;
3254 }
3255 
3256 ////////////////////////////////////////////////////////////////////////////////
3257 /// Close socket.
3258 
3259 void TUnixSystem::CloseConnection(int sock, Bool_t force)
3260 {
3261  if (sock < 0) return;
3262 
3263 #if !defined(R__AIX) || defined(_AIX41) || defined(_AIX43)
3264  if (force)
3265  ::shutdown(sock, 2); // will also close connection of parent
3266 #endif
3267 
3268  while (::close(sock) == -1 && GetErrno() == EINTR)
3269  ResetErrno();
3270 }
3271 
3272 ////////////////////////////////////////////////////////////////////////////////
3273 /// Receive a buffer headed by a length indicator. Length is the size of
3274 /// the buffer. Returns the number of bytes received in buf or -1 in
3275 /// case of error.
3276 
3277 int TUnixSystem::RecvBuf(int sock, void *buf, int length)
3278 {
3279  Int_t header;
3280 
3281  if (UnixRecv(sock, &header, sizeof(header), 0) > 0) {
3282  int count = ntohl(header);
3283 
3284  if (count > length) {
3285  Error("RecvBuf", "record header exceeds buffer size");
3286  return -1;
3287  } else if (count > 0) {
3288  if (UnixRecv(sock, buf, count, 0) < 0) {
3289  Error("RecvBuf", "cannot receive buffer");
3290  return -1;
3291  }
3292  }
3293  return count;
3294  }
3295  return -1;
3296 }
3297 
3298 ////////////////////////////////////////////////////////////////////////////////
3299 /// Send a buffer headed by a length indicator. Returns length of sent buffer
3300 /// or -1 in case of error.
3301 
3302 int TUnixSystem::SendBuf(int sock, const void *buf, int length)
3303 {
3304  Int_t header = htonl(length);
3305 
3306  if (UnixSend(sock, &header, sizeof(header), 0) < 0) {
3307  Error("SendBuf", "cannot send header");
3308  return -1;
3309  }
3310  if (length > 0) {
3311  if (UnixSend(sock, buf, length, 0) < 0) {
3312  Error("SendBuf", "cannot send buffer");
3313  return -1;
3314  }
3315  }
3316  return length;
3317 }
3318 
3319 ////////////////////////////////////////////////////////////////////////////////
3320 /// Receive exactly length bytes into buffer. Use opt to receive out-of-band
3321 /// data or to have a peek at what is in the buffer (see TSocket). Buffer
3322 /// must be able to store at least length bytes. Returns the number of
3323 /// bytes received (can be 0 if other side of connection was closed) or -1
3324 /// in case of error, -2 in case of MSG_OOB and errno == EWOULDBLOCK, -3
3325 /// in case of MSG_OOB and errno == EINVAL and -4 in case of kNoBlock and
3326 /// errno == EWOULDBLOCK. Returns -5 if pipe broken or reset by peer
3327 /// (EPIPE || ECONNRESET).
3328 
3329 int TUnixSystem::RecvRaw(int sock, void *buf, int length, int opt)
3330 {
3331  int flag;
3332 
3333  switch (opt) {
3334  case kDefault:
3335  flag = 0;
3336  break;
3337  case kOob:
3338  flag = MSG_OOB;
3339  break;
3340  case kPeek:
3341  flag = MSG_PEEK;
3342  break;
3343  case kDontBlock:
3344  flag = -1;
3345  break;
3346  default:
3347  flag = 0;
3348  break;
3349  }
3350 
3351  int n;
3352  if ((n = UnixRecv(sock, buf, length, flag)) <= 0) {
3353  if (n == -1 && GetErrno() != EINTR)
3354  Error("RecvRaw", "cannot receive buffer");
3355  return n;
3356  }
3357  return n;
3358 }
3359 
3360 ////////////////////////////////////////////////////////////////////////////////
3361 /// Send exactly length bytes from buffer. Use opt to send out-of-band
3362 /// data (see TSocket). Returns the number of bytes sent or -1 in case of
3363 /// error. Returns -4 in case of kNoBlock and errno == EWOULDBLOCK.
3364 /// Returns -5 if pipe broken or reset by peer (EPIPE || ECONNRESET).
3365 
3366 int TUnixSystem::SendRaw(int sock, const void *buf, int length, int opt)
3367 {
3368  int flag;
3369 
3370  switch (opt) {
3371  case kDefault:
3372  flag = 0;
3373  break;
3374  case kOob:
3375  flag = MSG_OOB;
3376  break;
3377  case kDontBlock:
3378  flag = -1;
3379  break;
3380  case kPeek: // receive only option (see RecvRaw)
3381  default:
3382  flag = 0;
3383  break;
3384  }
3385 
3386  int n;
3387  if ((n = UnixSend(sock, buf, length, flag)) <= 0) {
3388  if (n == -1 && GetErrno() != EINTR)
3389  Error("SendRaw", "cannot send buffer");
3390  return n;
3391  }
3392  return n;
3393 }
3394 
3395 ////////////////////////////////////////////////////////////////////////////////
3396 /// Set socket option.
3397 
3398 int TUnixSystem::SetSockOpt(int sock, int opt, int val)
3399 {
3400  if (sock < 0) return -1;
3401 
3402  switch (opt) {
3403  case kSendBuffer:
3404  if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&val, sizeof(val)) == -1) {
3405  SysError("SetSockOpt", "setsockopt(SO_SNDBUF)");
3406  return -1;
3407  }
3408  break;
3409  case kRecvBuffer:
3410  if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&val, sizeof(val)) == -1) {
3411  SysError("SetSockOpt", "setsockopt(SO_RCVBUF)");
3412  return -1;
3413  }
3414  break;
3415  case kOobInline:
3416  if (setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (char*)&val, sizeof(val)) == -1) {
3417  SysError("SetSockOpt", "setsockopt(SO_OOBINLINE)");
3418  return -1;
3419  }
3420  break;
3421  case kKeepAlive:
3422  if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&val, sizeof(val)) == -1) {
3423  SysError("SetSockOpt", "setsockopt(SO_KEEPALIVE)");
3424  return -1;
3425  }
3426  break;
3427  case kReuseAddr:
3428  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val)) == -1) {
3429  SysError("SetSockOpt", "setsockopt(SO_REUSEADDR)");
3430  return -1;
3431  }
3432  break;
3433  case kNoDelay:
3434  if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&val, sizeof(val)) == -1) {
3435  SysError("SetSockOpt", "setsockopt(TCP_NODELAY)");
3436  return -1;
3437  }
3438  break;
3439  case kNoBlock:
3440  if (ioctl(sock, FIONBIO, (char*)&val) == -1) {
3441  SysError("SetSockOpt", "ioctl(FIONBIO)");
3442  return -1;
3443  }
3444  break;
3445  case kProcessGroup:
3446 #ifndef R__WINGCC
3447  if (ioctl(sock, SIOCSPGRP, (char*)&val) == -1) {
3448  SysError("SetSockOpt", "ioctl(SIOCSPGRP)");
3449  return -1;
3450  }
3451 #else
3452  Error("SetSockOpt", "ioctl(SIOCGPGRP) not supported on cygwin/gcc");
3453  return -1;
3454 #endif
3455  break;
3456  case kAtMark: // read-only option (see GetSockOpt)
3457  case kBytesToRead: // read-only option
3458  default:
3459  Error("SetSockOpt", "illegal option (%d)", opt);
3460  return -1;
3461  }
3462  return 0;
3463 }
3464 
3465 ////////////////////////////////////////////////////////////////////////////////
3466 /// Get socket option.
3467 
3468 int TUnixSystem::GetSockOpt(int sock, int opt, int *val)
3469 {
3470  if (sock < 0) return -1;
3471 
3472 #if defined(USE_SOCKLEN_T) || defined(_AIX43)
3473  socklen_t optlen = sizeof(*val);
3474 #elif defined(USE_SIZE_T)
3475  size_t optlen = sizeof(*val);
3476 #else
3477  int optlen = sizeof(*val);
3478 #endif
3479 
3480  switch (opt) {
3481  case kSendBuffer:
3482  if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)val, &optlen) == -1) {
3483  SysError("GetSockOpt", "getsockopt(SO_SNDBUF)");
3484  return -1;
3485  }
3486  break;
3487  case kRecvBuffer:
3488  if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)val, &optlen) == -1) {
3489  SysError("GetSockOpt", "getsockopt(SO_RCVBUF)");
3490  return -1;
3491  }
3492  break;
3493  case kOobInline:
3494  if (getsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (char*)val, &optlen) == -1) {
3495  SysError("GetSockOpt", "getsockopt(SO_OOBINLINE)");
3496  return -1;
3497  }
3498  break;
3499  case kKeepAlive:
3500  if (getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)val, &optlen) == -1) {
3501  SysError("GetSockOpt", "getsockopt(SO_KEEPALIVE)");
3502  return -1;
3503  }
3504  break;
3505  case kReuseAddr:
3506  if (getsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)val, &optlen) == -1) {
3507  SysError("GetSockOpt", "getsockopt(SO_REUSEADDR)");
3508  return -1;
3509  }
3510  break;
3511  case kNoDelay:
3512  if (getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)val, &optlen) == -1) {
3513  SysError("GetSockOpt", "getsockopt(TCP_NODELAY)");
3514  return -1;
3515  }
3516  break;
3517  case kNoBlock:
3518  int flg;
3519  if ((flg = fcntl(sock, F_GETFL, 0)) == -1) {
3520  SysError("GetSockOpt", "fcntl(F_GETFL)");
3521  return -1;
3522  }
3523  *val = flg & O_NDELAY;
3524  break;
3525  case kProcessGroup:
3526 #if !defined(R__LYNXOS) && !defined(R__WINGCC)
3527  if (ioctl(sock, SIOCGPGRP, (char*)val) == -1) {
3528  SysError("GetSockOpt", "ioctl(SIOCGPGRP)");
3529  return -1;
3530  }
3531 #else
3532  Error("GetSockOpt", "ioctl(SIOCGPGRP) not supported on LynxOS and cygwin/gcc");
3533  return -1;
3534 #endif
3535  break;
3536  case kAtMark:
3537 #if !defined(R__LYNXOS)
3538  if (ioctl(sock, SIOCATMARK, (char*)val) == -1) {
3539  SysError("GetSockOpt", "ioctl(SIOCATMARK)");
3540  return -1;
3541  }
3542 #else
3543  Error("GetSockOpt", "ioctl(SIOCATMARK) not supported on LynxOS");
3544  return -1;
3545 #endif
3546  break;
3547  case kBytesToRead:
3548 #if !defined(R__LYNXOS)
3549  if (ioctl(sock, FIONREAD, (char*)val) == -1) {
3550  SysError("GetSockOpt", "ioctl(FIONREAD)");
3551  return -1;
3552  }
3553 #else
3554  Error("GetSockOpt", "ioctl(FIONREAD) not supported on LynxOS");
3555  return -1;
3556 #endif
3557  break;
3558  default:
3559  Error("GetSockOpt", "illegal option (%d)", opt);
3560  *val = 0;
3561  return -1;
3562  }
3563  return 0;
3564 }
3565 
3566 //////////////////////////////////////////////////////////////////////////
3567 // //
3568 // Static Protected Unix Interface functions. //
3569 // //
3570 //////////////////////////////////////////////////////////////////////////
3571 
3572 //---- signals -----------------------------------------------------------------
3573 
3574 static struct Signalmap_t {
3575  int fCode;
3576  SigHandler_t fHandler;
3577  struct sigaction *fOldHandler;
3578  const char *fSigName;
3579 } gSignalMap[kMAXSIGNALS] = { // the order of the signals should be identical
3580  { SIGBUS, 0, 0, "bus error" }, // to the one in TSysEvtHandler.h
3581  { SIGSEGV, 0, 0, "segmentation violation" },
3582  { SIGSYS, 0, 0, "bad argument to system call" },
3583  { SIGPIPE, 0, 0, "write on a pipe with no one to read it" },
3584  { SIGILL, 0, 0, "illegal instruction" },
3585  { SIGQUIT, 0, 0, "quit" },
3586  { SIGINT, 0, 0, "interrupt" },
3587  { SIGWINCH, 0, 0, "window size change" },
3588  { SIGALRM, 0, 0, "alarm clock" },
3589  { SIGCHLD, 0, 0, "death of a child" },
3590  { SIGURG, 0, 0, "urgent data arrived on an I/O channel" },
3591  { SIGFPE, 0, 0, "floating point exception" },
3592  { SIGTERM, 0, 0, "termination signal" },
3593  { SIGUSR1, 0, 0, "user-defined signal 1" },
3594  { SIGUSR2, 0, 0, "user-defined signal 2" }
3595 };
3596 
3597 
3598 ////////////////////////////////////////////////////////////////////////////////
3599 /// Call the signal handler associated with the signal.
3600 
3601 static void sighandler(int sig)
3602 {
3603  for (int i= 0; i < kMAXSIGNALS; i++) {
3604  if (gSignalMap[i].fCode == sig) {
3605  (*gSignalMap[i].fHandler)((ESignals)i);
3606  return;
3607  }
3608  }
3609 }
3610 
3611 ////////////////////////////////////////////////////////////////////////////////
3612 /// Handle and dispatch signals.
3613 
3614 void TUnixSystem::DispatchSignals(ESignals sig)
3615 {
3616  switch (sig) {
3617  case kSigAlarm:
3618  DispatchTimers(kFALSE);
3619  break;
3620  case kSigChild:
3621  CheckChilds();
3622  break;
3623  case kSigBus:
3624  case kSigSegmentationViolation:
3625  case kSigIllegalInstruction:
3626  case kSigFloatingException:
3627  Break("TUnixSystem::DispatchSignals", "%s", UnixSigname(sig));
3628  StackTrace();
3629  if (gApplication)
3630  //sig is ESignal, should it be mapped to the correct signal number?
3631  gApplication->HandleException(sig);
3632  else
3633  //map to the real signal code + set the
3634  //high order bit to indicate a signal (?)
3635  Exit(gSignalMap[sig].fCode + 0x80);
3636  break;
3637  case kSigSystem:
3638  case kSigPipe:
3639  Break("TUnixSystem::DispatchSignals", "%s", UnixSigname(sig));
3640  break;
3641  case kSigWindowChanged:
3642  Gl_windowchanged();
3643  break;
3644  case kSigUser2:
3645  Break("TUnixSystem::DispatchSignals", "%s: printing stacktrace", UnixSigname(sig));
3646  StackTrace();
3647  // Intentional fall-through; pass the signal to handlers (or terminate):
3648  default:
3649  fSignals->Set(sig);
3650  fSigcnt++;
3651  break;
3652  }
3653 
3654  // check a-synchronous signals
3655  if (fSigcnt > 0 && fSignalHandler->GetSize() > 0)
3656  CheckSignals(kFALSE);
3657 }
3658 
3659 ////////////////////////////////////////////////////////////////////////////////
3660 /// Set a signal handler for a signal.
3661 
3662 void TUnixSystem::UnixSignal(ESignals sig, SigHandler_t handler)
3663 {
3664  if (gEnv && !gEnv->GetValue("Root.ErrorHandlers", 1))
3665  return;
3666 
3667  if (gSignalMap[sig].fHandler != handler) {
3668  struct sigaction sigact;
3669 
3670  gSignalMap[sig].fHandler = handler;
3671  gSignalMap[sig].fOldHandler = new struct sigaction();
3672 
3673 #if defined(R__SUN)
3674  sigact.sa_handler = (void (*)())sighandler;
3675 #elif defined(R__SOLARIS)
3676  sigact.sa_handler = sighandler;
3677 #elif defined(R__LYNXOS)
3678 # if (__GNUG__>=3)
3679  sigact.sa_handler = sighandler;
3680 # else
3681  sigact.sa_handler = (void (*)(...))sighandler;
3682 # endif
3683 #else
3684  sigact.sa_handler = sighandler;
3685 #endif
3686  sigemptyset(&sigact.sa_mask);
3687  sigact.sa_flags = 0;
3688 #if defined(SA_RESTART)
3689  sigact.sa_flags |= SA_RESTART;
3690 #endif
3691  if (sigaction(gSignalMap[sig].fCode, &sigact,
3692  gSignalMap[sig].fOldHandler) < 0)
3693  ::SysError("TUnixSystem::UnixSignal", "sigaction");
3694  }
3695 }
3696 
3697 ////////////////////////////////////////////////////////////////////////////////
3698 /// If ignore is true ignore the specified signal, else restore previous
3699 /// behaviour.
3700 
3701 void TUnixSystem::UnixIgnoreSignal(ESignals sig, Bool_t ignore)
3702 {
3703  TTHREAD_TLS(Bool_t) ignoreSig[kMAXSIGNALS] = { kFALSE };
3704  TTHREAD_TLS_ARRAY(struct sigaction,kMAXSIGNALS,oldsigact);
3705 
3706  if (ignore != ignoreSig[sig]) {
3707  ignoreSig[sig] = ignore;
3708  if (ignore) {
3709  struct sigaction sigact;
3710 #if defined(R__SUN)
3711  sigact.sa_handler = (void (*)())SIG_IGN;
3712 #elif defined(R__SOLARIS)
3713  sigact.sa_handler = (void (*)(int))SIG_IGN;
3714 #else
3715  sigact.sa_handler = SIG_IGN;
3716 #endif
3717  sigemptyset(&sigact.sa_mask);
3718  sigact.sa_flags = 0;
3719  if (sigaction(gSignalMap[sig].fCode, &sigact, &oldsigact[sig]) < 0)
3720  ::SysError("TUnixSystem::UnixIgnoreSignal", "sigaction");
3721  } else {
3722  if (sigaction(gSignalMap[sig].fCode, &oldsigact[sig], 0) < 0)
3723  ::SysError("TUnixSystem::UnixIgnoreSignal", "sigaction");
3724  }
3725  }
3726 }
3727 
3728 ////////////////////////////////////////////////////////////////////////////////
3729 /// When the argument is true the SIGALRM signal handler is set so that
3730 /// interrupted syscalls will not be restarted by the kernel. This is
3731 /// typically used in case one wants to put a timeout on an I/O operation.
3732 /// By default interrupted syscalls will always be restarted (for all
3733 /// signals). This can be controlled for each a-synchronous TTimer via
3734 /// the method TTimer::SetInterruptSyscalls().
3735 
3736 void TUnixSystem::UnixSigAlarmInterruptsSyscalls(Bool_t set)
3737 {
3738  if (gSignalMap[kSigAlarm].fHandler) {
3739  struct sigaction sigact;
3740 #if defined(R__SUN)
3741  sigact.sa_handler = (void (*)())sighandler;
3742 #elif defined(R__SOLARIS)
3743  sigact.sa_handler = sighandler;
3744 #elif defined(R__LYNXOS)
3745 # if (__GNUG__>=3)
3746  sigact.sa_handler = sighandler;
3747 # else
3748  sigact.sa_handler = (void (*)(...))sighandler;
3749 # endif
3750 #else
3751  sigact.sa_handler = sighandler;
3752 #endif
3753  sigemptyset(&sigact.sa_mask);
3754  sigact.sa_flags = 0;
3755  if (set) {
3756 #if defined(SA_INTERRUPT) // SunOS
3757  sigact.sa_flags |= SA_INTERRUPT;
3758 #endif
3759  } else {
3760 #if defined(SA_RESTART)
3761  sigact.sa_flags |= SA_RESTART;
3762 #endif
3763  }
3764  if (sigaction(gSignalMap[kSigAlarm].fCode, &sigact, 0) < 0)
3765  ::SysError("TUnixSystem::UnixSigAlarmInterruptsSyscalls", "sigaction");
3766  }
3767 }
3768 
3769 ////////////////////////////////////////////////////////////////////////////////
3770 /// Return the signal name associated with a signal.
3771 
3772 const char *TUnixSystem::UnixSigname(ESignals sig)
3773 {
3774  return gSignalMap[sig].fSigName;
3775 }
3776 
3777 ////////////////////////////////////////////////////////////////////////////////
3778 /// Restore old signal handler for specified signal.
3779 
3780 void TUnixSystem::UnixResetSignal(ESignals sig)
3781 {
3782  if (gSignalMap[sig].fOldHandler) {
3783  // restore old signal handler
3784  if (sigaction(gSignalMap[sig].fCode, gSignalMap[sig].fOldHandler, 0) < 0)
3785  ::SysError("TUnixSystem::UnixSignal", "sigaction");
3786  delete gSignalMap[sig].fOldHandler;
3787  gSignalMap[sig].fOldHandler = 0;
3788  gSignalMap[sig].fHandler = 0;
3789  }
3790 }
3791 
3792 ////////////////////////////////////////////////////////////////////////////////
3793 /// Restore old signal handlers.
3794 
3795 void TUnixSystem::UnixResetSignals()
3796 {
3797  for (int sig = 0; sig < kMAXSIGNALS; sig++)
3798  UnixResetSignal((ESignals)sig);
3799 }
3800 
3801 //---- time --------------------------------------------------------------------
3802 
3803 ////////////////////////////////////////////////////////////////////////////////
3804 /// Get current time in milliseconds since 0:00 Jan 1 1995.
3805 
3806 Long64_t TUnixSystem::UnixNow()
3807 {
3808  static std::atomic<time_t> jan95{0};
3809  if (!jan95) {
3810  struct tm tp;
3811  tp.tm_year = 95;
3812  tp.tm_mon = 0;
3813  tp.tm_mday = 1;
3814  tp.tm_hour = 0;
3815  tp.tm_min = 0;
3816  tp.tm_sec = 0;
3817  tp.tm_isdst = -1;
3818 
3819  jan95 = mktime(&tp);
3820  if ((int)jan95 == -1) {
3821  ::SysError("TUnixSystem::UnixNow", "error converting 950001 0:00 to time_t");
3822  return 0;
3823  }
3824  }
3825 
3826  struct timeval t;
3827  gettimeofday(&t, 0);
3828  return Long64_t(t.tv_sec-(Long_t)jan95)*1000 + t.tv_usec/1000;
3829 }
3830 
3831 ////////////////////////////////////////////////////////////////////////////////
3832 /// Set interval timer to time-out in ms milliseconds.
3833 
3834 int TUnixSystem::UnixSetitimer(Long_t ms)
3835 {
3836  struct itimerval itv;
3837  itv.it_value.tv_sec = 0;
3838  itv.it_value.tv_usec = 0;
3839  itv.it_interval.tv_sec = 0;
3840  itv.it_interval.tv_usec = 0;
3841  if (ms > 0) {
3842  itv.it_value.tv_sec = time_t(ms / 1000);
3843  itv.it_value.tv_usec = time_t((ms % 1000) * 1000);
3844  }
3845  int st = setitimer(ITIMER_REAL, &itv, 0);
3846  if (st == -1)
3847  ::SysError("TUnixSystem::UnixSetitimer", "setitimer");
3848  return st;
3849 }
3850 
3851 //---- file descriptors --------------------------------------------------------
3852 
3853 ////////////////////////////////////////////////////////////////////////////////
3854 /// Wait for events on the file descriptors specified in the readready and
3855 /// writeready masks or for timeout (in milliseconds) to occur. Returns
3856 /// the number of ready descriptors, or 0 in case of timeout, or < 0 in
3857 /// case of an error, with -2 being EINTR and -3 EBADF. In case of EINTR
3858 /// the errno has been reset and the method can be called again.
3859 
3860 int TUnixSystem::UnixSelect(Int_t nfds, TFdSet *readready, TFdSet *writeready,
3861  Long_t timeout)
3862 {
3863  int retcode;
3864 
3865  fd_set *rd = (readready) ? (fd_set*)readready->GetBits() : 0;
3866  fd_set *wr = (writeready) ? (fd_set*)writeready->GetBits() : 0;
3867 
3868  if (timeout >= 0) {
3869  struct timeval tv;
3870  tv.tv_sec = Int_t(timeout / 1000);
3871  tv.tv_usec = (timeout % 1000) * 1000;
3872  retcode = select(nfds, rd, wr, 0, &tv);
3873  } else {
3874  retcode = select(nfds, rd, wr, 0, 0);
3875  }
3876  if (retcode == -1) {
3877  if (GetErrno() == EINTR) {
3878  ResetErrno(); // errno is not self reseting
3879  return -2;
3880  }
3881  if (GetErrno() == EBADF)
3882  return -3;
3883  return -1;
3884  }
3885 
3886  return retcode;
3887 }
3888 
3889 //---- directories -------------------------------------------------------------
3890 
3891 ////////////////////////////////////////////////////////////////////////////////
3892 /// Returns the user's home directory.
3893 
3894 const char *TUnixSystem::UnixHomedirectory(const char *name)
3895 {
3896  static char path[kMAXPATHLEN], mydir[kMAXPATHLEN] = { '\0' };
3897  return UnixHomedirectory(name, path, mydir);
3898 }
3899 
3900 ////////////////////////////////////////////////////////////////////////////
3901 /// Returns the user's home directory.
3902 
3903 const char *TUnixSystem::UnixHomedirectory(const char *name, char *path, char *mydir)
3904 {
3905  struct passwd *pw;
3906  if (name) {
3907  pw = getpwnam(name);
3908  if (pw) {
3909  strncpy(path, pw->pw_dir, kMAXPATHLEN-1);
3910  path[kMAXPATHLEN-1] = '\0';
3911  return path;
3912  }
3913  } else {
3914  if (mydir[0])
3915  return mydir;
3916  pw = getpwuid(getuid());
3917  if (pw && pw->pw_dir) {
3918  strncpy(mydir, pw->pw_dir, kMAXPATHLEN-1);
3919  mydir[kMAXPATHLEN-1] = '\0';
3920  return mydir;
3921  } else if (gSystem->Getenv("HOME")) {
3922  strncpy(mydir, gSystem->Getenv("HOME"), kMAXPATHLEN-1);
3923  mydir[kMAXPATHLEN-1] = '\0';
3924  return mydir;
3925  }
3926  }
3927  return 0;
3928 }
3929 
3930 ////////////////////////////////////////////////////////////////////////////////
3931 /// Make a Unix file system directory. Returns 0 in case of success and
3932 /// -1 if the directory could not be created (either already exists or
3933 /// illegal path name).
3934 
3935 int TUnixSystem::UnixMakedir(const char *dir)
3936 {
3937  return ::mkdir(StripOffProto(dir, "file:"), 0755);
3938 }
3939 
3940 ////////////////////////////////////////////////////////////////////////////////
3941 /// Open a directory.
3942 
3943 void *TUnixSystem::UnixOpendir(const char *dir)
3944 {
3945  struct stat finfo;
3946 
3947  const char *edir = StripOffProto(dir, "file:");
3948 
3949  if (stat(edir, &finfo) < 0)
3950  return 0;
3951 
3952  if (!S_ISDIR(finfo.st_mode))
3953  return 0;
3954 
3955  return (void*) opendir(edir);
3956 }
3957 
3958 #if defined(_POSIX_SOURCE)
3959 // Posix does not require that the d_ino field be present, and some
3960 // systems do not provide it.
3961 # define REAL_DIR_ENTRY(dp) 1
3962 #else
3963 # define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
3964 #endif
3965 
3966 ////////////////////////////////////////////////////////////////////////////////
3967 /// Returns the next directory entry.
3968 
3969 const char *TUnixSystem::UnixGetdirentry(void *dirp1)
3970 {
3971  DIR *dirp = (DIR*)dirp1;
3972 #ifdef HAS_DIRENT
3973  struct dirent *dp;
3974 #else
3975  struct direct *dp;
3976 #endif
3977 
3978  if (dirp) {
3979  for (;;) {
3980  dp = readdir(dirp);
3981  if (dp == 0)
3982  return 0;
3983  if (REAL_DIR_ENTRY(dp))
3984  return dp->d_name;
3985  }
3986  }
3987  return 0;
3988 }
3989 
3990 //---- files -------------------------------------------------------------------
3991 
3992 ////////////////////////////////////////////////////////////////////////////////
3993 /// Get info about a file. Info is returned in the form of a FileStat_t
3994 /// structure (see TSystem.h).
3995 /// The function returns 0 in case of success and 1 if the file could
3996 /// not be stat'ed.
3997 
3998 int TUnixSystem::UnixFilestat(const char *fpath, FileStat_t &buf)
3999 {
4000  const char *path = StripOffProto(fpath, "file:");
4001  buf.fIsLink = kFALSE;
4002 
4003 #if defined(R__SEEK64)
4004  struct stat64 sbuf;
4005  if (path && lstat64(path, &sbuf) == 0) {
4006 #else
4007  struct stat sbuf;
4008  if (path && lstat(path, &sbuf) == 0) {
4009 #endif
4010  buf.fIsLink = S_ISLNK(sbuf.st_mode);
4011  if (buf.fIsLink) {
4012 #if defined(R__SEEK64)
4013  if (stat64(path, &sbuf) == -1) {
4014 #else
4015  if (stat(path, &sbuf) == -1) {
4016 #endif
4017  return 1;
4018  }
4019  }
4020  buf.fDev = sbuf.st_dev;
4021  buf.fIno = sbuf.st_ino;
4022  buf.fMode = sbuf.st_mode;
4023  buf.fUid = sbuf.st_uid;
4024  buf.fGid = sbuf.st_gid;
4025  buf.fSize = sbuf.st_size;
4026  buf.fMtime = sbuf.st_mtime;
4027 
4028  return 0;
4029  }
4030  return 1;
4031 }
4032 
4033 ////////////////////////////////////////////////////////////////////////////////
4034 /// Get info about a file system: id, bsize, bfree, blocks.
4035 /// Id is file system type (machine dependend, see statfs())
4036 /// Bsize is block size of file system
4037 /// Blocks is total number of blocks in file system
4038 /// Bfree is number of free blocks in file system
4039 /// The function returns 0 in case of success and 1 if the file system could
4040 /// not be stat'ed.
4041 
4042 int TUnixSystem::UnixFSstat(const char *path, Long_t *id, Long_t *bsize,
4043  Long_t *blocks, Long_t *bfree)
4044 {
4045  struct statfs statfsbuf;
4046 #if (defined(R__SOLARIS) && !defined(R__LINUX))
4047  if (statfs(path, &statfsbuf, sizeof(struct statfs), 0) == 0) {
4048  *id = statfsbuf.f_fstyp;
4049  *bsize = statfsbuf.f_bsize;
4050  *blocks = statfsbuf.f_blocks;
4051  *bfree = statfsbuf.f_bfree;
4052 #else
4053  if (statfs((char*)path, &statfsbuf) == 0) {
4054 #ifdef R__OBSD
4055  // Convert BSD filesystem names to Linux filesystem type numbers
4056  // where possible. Linux statfs uses a value of -1 to indicate
4057  // an unsupported field.
4058 
4059  if (!strcmp(statfsbuf.f_fstypename, MOUNT_FFS) ||
4060  !strcmp(statfsbuf.f_fstypename, MOUNT_MFS))
4061  *id = 0x11954;
4062  else if (!strcmp(statfsbuf.f_fstypename, MOUNT_NFS))
4063  *id = 0x6969;
4064  else if (!strcmp(statfsbuf.f_fstypename, MOUNT_MSDOS))
4065  *id = 0x4d44;
4066  else if (!strcmp(statfsbuf.f_fstypename, MOUNT_EXT2FS))
4067  *id = 0xef53;
4068  else if (!strcmp(statfsbuf.f_fstypename, MOUNT_CD9660))
4069  *id = 0x9660;
4070  else if (!strcmp(statfsbuf.f_fstypename, MOUNT_NCPFS))
4071  *id = 0x6969;
4072  else
4073  *id = -1;
4074 #else
4075  *id = statfsbuf.f_type;
4076 #endif
4077  *bsize = statfsbuf.f_bsize;
4078  *blocks = statfsbuf.f_blocks;
4079  *bfree = statfsbuf.f_bavail;
4080 #endif
4081  return 0;
4082  }
4083  return 1;
4084 }
4085 
4086 ////////////////////////////////////////////////////////////////////////////////
4087 /// Wait till child is finished.
4088 
4089 int TUnixSystem::UnixWaitchild()
4090 {
4091  int status;
4092  return (int) waitpid(0, &status, WNOHANG);
4093 }
4094 
4095 //---- RPC -------------------------------------------------------------------
4096 
4097 ////////////////////////////////////////////////////////////////////////////////
4098 /// Open a TCP/IP connection to server and connect to a service (i.e. port).
4099 /// Use tcpwindowsize to specify the size of the receive buffer, it has
4100 /// to be specified here to make sure the window scale option is set (for
4101 /// tcpwindowsize > 65KB and for platforms supporting window scaling).
4102 /// Is called via the TSocket constructor. Returns -1 in case of error.
4103 
4104 int TUnixSystem::UnixTcpConnect(const char *hostname, int port,
4105  int tcpwindowsize)
4106 {
4107  short sport;
4108  struct servent *sp;
4109 
4110  if ((sp = getservbyport(htons(port), kProtocolName)))
4111  sport = sp->s_port;
4112  else
4113  sport = htons(port);
4114 
4115  TInetAddress addr = gSystem->GetHostByName(hostname);
4116  if (!addr.IsValid()) return -1;
4117  UInt_t adr = htonl(addr.GetAddress());
4118 
4119  struct sockaddr_in server;
4120  memset(&server, 0, sizeof(server));
4121  memcpy(&server.sin_addr, &adr, sizeof(adr));
4122  server.sin_family = addr.GetFamily();
4123  server.sin_port = sport;
4124 
4125  // Create socket
4126  int sock;
4127  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
4128  ::SysError("TUnixSystem::UnixTcpConnect", "socket (%s:%d)",
4129  hostname, port);
4130  return -1;
4131  }
4132 
4133  if (tcpwindowsize > 0) {
4134  gSystem->SetSockOpt(sock, kRecvBuffer, tcpwindowsize);
4135  gSystem->SetSockOpt(sock, kSendBuffer, tcpwindowsize);
4136  }
4137 
4138  while (connect(sock, (struct sockaddr*) &server, sizeof(server)) == -1) {
4139  if (GetErrno() == EINTR)
4140  ResetErrno();
4141  else {
4142  ::SysError("TUnixSystem::UnixTcpConnect", "connect (%s:%d)",
4143  hostname, port);
4144  close(sock);
4145  return -1;
4146  }
4147  }
4148  return sock;
4149 }
4150 
4151 
4152 ////////////////////////////////////////////////////////////////////////////////
4153 /// Creates a UDP socket connection
4154 /// Is called via the TSocket constructor. Returns -1 in case of error.
4155 
4156 int TUnixSystem::UnixUdpConnect(const char *hostname, int port)
4157 {
4158  short sport;
4159  struct servent *sp;
4160 
4161  if ((sp = getservbyport(htons(port), kProtocolName)))
4162  sport = sp->s_port;
4163  else
4164  sport = htons(port);
4165 
4166  TInetAddress addr = gSystem->GetHostByName(hostname);
4167  if (!addr.IsValid()) return -1;
4168  UInt_t adr = htonl(addr.GetAddress());
4169 
4170  struct sockaddr_in server;
4171  memset(&server, 0, sizeof(server));
4172  memcpy(&server.sin_addr, &adr, sizeof(adr));
4173  server.sin_family = addr.GetFamily();
4174  server.sin_port = sport;
4175 
4176  // Create socket
4177  int sock;
4178  if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
4179  ::SysError("TUnixSystem::UnixUdpConnect", "socket (%s:%d)",
4180  hostname, port);
4181  return -1;
4182  }
4183 
4184  while (connect(sock, (struct sockaddr*) &server, sizeof(server)) == -1) {
4185  if (GetErrno() == EINTR)
4186  ResetErrno();
4187  else {
4188  ::SysError("TUnixSystem::UnixUdpConnect", "connect (%s:%d)",
4189  hostname, port);
4190  close(sock);
4191  return -1;
4192  }
4193  }
4194  return sock;
4195 }
4196 
4197 ////////////////////////////////////////////////////////////////////////////////
4198 /// Connect to a Unix domain socket.
4199 
4200 int TUnixSystem::UnixUnixConnect(int port)
4201 {
4202  return UnixUnixConnect(TString::Format("%s/%d", kServerPath, port));
4203 }
4204 
4205 ////////////////////////////////////////////////////////////////////////////////
4206 /// Connect to a Unix domain socket. Returns -1 in case of error.
4207 
4208 int TUnixSystem::UnixUnixConnect(const char *sockpath)
4209 {
4210  if (!sockpath || strlen(sockpath) <= 0) {
4211  ::SysError("TUnixSystem::UnixUnixConnect", "socket path undefined");
4212  return -1;
4213  }
4214 
4215  int sock;
4216  struct sockaddr_un unserver;
4217  unserver.sun_family = AF_UNIX;
4218 
4219  if (strlen(sockpath) > sizeof(unserver.sun_path)-1) {
4220  ::Error("TUnixSystem::UnixUnixConnect", "socket path %s, longer than max allowed length (%u)",
4221  sockpath, (UInt_t)sizeof(unserver.sun_path)-1);
4222  return -1;
4223  }
4224  strcpy(unserver.sun_path, sockpath);
4225 
4226  // Open socket
4227  if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
4228  ::SysError("TUnixSystem::UnixUnixConnect", "socket");
4229  return -1;
4230  }
4231 
4232  while (connect(sock, (struct sockaddr*) &unserver, strlen(unserver.sun_path)+2) == -1) {
4233  if (GetErrno() == EINTR)
4234  ResetErrno();
4235  else {
4236  ::SysError("TUnixSystem::UnixUnixConnect", "connect");
4237  close(sock);
4238  return -1;
4239  }
4240  }
4241  return sock;
4242 }
4243 
4244 ////////////////////////////////////////////////////////////////////////////////
4245 /// Open a socket, bind to it and start listening for TCP/IP connections
4246 /// on the port. If reuse is true reuse the address, backlog specifies
4247 /// how many sockets can be waiting to be accepted. If port is 0 a port
4248 /// scan will be done to find a free port. This option is mutual exlusive
4249 /// with the reuse option.
4250 /// Use tcpwindowsize to specify the size of the receive buffer, it has
4251 /// to be specified here to make sure the window scale option is set (for
4252 /// tcpwindowsize > 65KB and for platforms supporting window scaling).
4253 /// Returns socket fd or -1 if socket() failed, -2 if bind() failed
4254 /// or -3 if listen() failed.
4255 
4256 int TUnixSystem::UnixTcpService(int port, Bool_t reuse, int backlog,
4257  int tcpwindowsize)
4258 {
4259  const short kSOCKET_MINPORT = 5000, kSOCKET_MAXPORT = 15000;
4260  short sport, tryport = kSOCKET_MINPORT;
4261  struct servent *sp;
4262 
4263  if (port == 0 && reuse) {
4264  ::Error("TUnixSystem::UnixTcpService", "cannot do a port scan while reuse is true");
4265  return -1;
4266  }
4267 
4268  if ((sp = getservbyport(htons(port), kProtocolName)))
4269  sport = sp->s_port;
4270  else
4271  sport = htons(port);
4272 
4273  // Create tcp socket
4274  int sock;
4275  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
4276  ::SysError("TUnixSystem::UnixTcpService", "socket");
4277  return -1;
4278  }
4279 
4280  if (reuse)
4281  gSystem->SetSockOpt(sock, kReuseAddr, 1);
4282 
4283  if (tcpwindowsize > 0) {
4284  gSystem->SetSockOpt(sock, kRecvBuffer, tcpwindowsize);
4285  gSystem->SetSockOpt(sock, kSendBuffer, tcpwindowsize);
4286  }
4287 
4288  struct sockaddr_in inserver;
4289  memset(&inserver, 0, sizeof(inserver));
4290  inserver.sin_family = AF_INET;
4291  inserver.sin_addr.s_addr = htonl(INADDR_ANY);
4292  inserver.sin_port = sport;
4293 
4294  // Bind socket
4295  if (port > 0) {
4296  if (::bind(sock, (struct sockaddr*) &inserver, sizeof(inserver))) {
4297  ::SysError("TUnixSystem::UnixTcpService", "bind");
4298  close(sock);
4299  return -2;
4300  }
4301  } else {
4302  int bret;
4303  do {
4304  inserver.sin_port = htons(tryport);
4305  bret = ::bind(sock, (struct sockaddr*) &inserver, sizeof(inserver));
4306  tryport++;
4307  } while (bret < 0 && GetErrno() == EADDRINUSE && tryport < kSOCKET_MAXPORT);
4308  if (bret < 0) {
4309  ::SysError("TUnixSystem::UnixTcpService", "bind (port scan)");
4310  close(sock);
4311  return -2;
4312  }
4313  }
4314 
4315  // Start accepting connections
4316  if (::listen(sock, backlog)) {
4317  ::SysError("TUnixSystem::UnixTcpService", "listen");
4318  close(sock);
4319  return -3;
4320  }
4321 
4322  return sock;
4323 }
4324 
4325 ////////////////////////////////////////////////////////////////////////////////
4326 /// Open a socket, bind to it and start listening for UDP connections
4327 /// on the port. If reuse is true reuse the address, backlog specifies
4328 /// how many sockets can be waiting to be accepted. If port is 0 a port
4329 /// scan will be done to find a free port. This option is mutual exlusive
4330 /// with the reuse option.
4331 
4332 int TUnixSystem::UnixUdpService(int port, int backlog)
4333 {
4334  const short kSOCKET_MINPORT = 5000, kSOCKET_MAXPORT = 15000;
4335  short sport, tryport = kSOCKET_MINPORT;
4336  struct servent *sp;
4337 
4338  if ((sp = getservbyport(htons(port), kProtocolName)))
4339  sport = sp->s_port;
4340  else
4341  sport = htons(port);
4342 
4343  // Create udp socket
4344  int sock;
4345  if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
4346  ::SysError("TUnixSystem::UnixUdpService", "socket");
4347  return -1;
4348  }
4349 
4350  struct sockaddr_in inserver;
4351  memset(&inserver, 0, sizeof(inserver));
4352  inserver.sin_family = AF_INET;
4353  inserver.sin_addr.s_addr = htonl(INADDR_ANY);
4354  inserver.sin_port = sport;
4355 
4356  // Bind socket
4357  if (port > 0) {
4358  if (::bind(sock, (struct sockaddr*) &inserver, sizeof(inserver))) {
4359  ::SysError("TUnixSystem::UnixUdpService", "bind");
4360  close(sock);
4361  return -2;
4362  }
4363  } else {
4364  int bret;
4365  do {
4366  inserver.sin_port = htons(tryport);
4367  bret = ::bind(sock, (struct sockaddr*) &inserver, sizeof(inserver));
4368  tryport++;
4369  } while (bret < 0 && GetErrno() == EADDRINUSE && tryport < kSOCKET_MAXPORT);
4370  if (bret < 0) {
4371  ::SysError("TUnixSystem::UnixUdpService", "bind (port scan)");
4372  close(sock);
4373  return -2;
4374  }
4375  }
4376 
4377  // Start accepting connections
4378  if (::listen(sock, backlog)) {
4379  ::SysError("TUnixSystem::UnixUdpService", "listen");
4380  close(sock);
4381  return -3;
4382  }
4383 
4384  return sock;
4385 }
4386 
4387 ////////////////////////////////////////////////////////////////////////////////
4388 /// Open a socket, bind to it and start listening for Unix domain connections
4389 /// to it. Returns socket fd or -1.
4390 
4391 int TUnixSystem::UnixUnixService(int port, int backlog)
4392 {
4393  int oldumask;
4394 
4395  // Assure that socket directory exists
4396  oldumask = umask(0);
4397  int res = ::mkdir(kServerPath, 0777);
4398  umask(oldumask);
4399 
4400  if (res == -1)
4401  return -1;
4402 
4403  // Socket path
4404  TString sockpath;
4405  sockpath.Form("%s/%d", kServerPath, port);
4406 
4407  // Remove old socket
4408  unlink(sockpath.Data());
4409 
4410  return UnixUnixService(sockpath, backlog);
4411 }
4412 
4413 ////////////////////////////////////////////////////////////////////////////////
4414 /// Open a socket on path 'sockpath', bind to it and start listening for Unix
4415 /// domain connections to it. Returns socket fd or -1.
4416 
4417 int TUnixSystem::UnixUnixService(const char *sockpath, int backlog)
4418 {
4419  if (!sockpath || strlen(sockpath) <= 0) {
4420  ::SysError("TUnixSystem::UnixUnixService", "socket path undefined");
4421  return -1;
4422  }
4423 
4424  struct sockaddr_un unserver;
4425  int sock;
4426 
4427  // Prepare structure
4428  memset(&unserver, 0, sizeof(unserver));
4429  unserver.sun_family = AF_UNIX;
4430 
4431  if (strlen(sockpath) > sizeof(unserver.sun_path)-1) {
4432  ::Error("TUnixSystem::UnixUnixService", "socket path %s, longer than max allowed length (%u)",
4433  sockpath, (UInt_t)sizeof(unserver.sun_path)-1);
4434  return -1;
4435  }
4436  strcpy(unserver.sun_path, sockpath);
4437 
4438  // Create socket
4439  if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
4440  ::SysError("TUnixSystem::UnixUnixService", "socket");
4441  return -1;
4442  }
4443 
4444  if (::bind(sock, (struct sockaddr*) &unserver, strlen(unserver.sun_path)+2)) {
4445  ::SysError("TUnixSystem::UnixUnixService", "bind");
4446  close(sock);
4447  return -1;
4448  }
4449 
4450  // Start accepting connections
4451  if (::listen(sock, backlog)) {
4452  ::SysError("TUnixSystem::UnixUnixService", "listen");
4453  close(sock);
4454  return -1;
4455  }
4456 
4457  return sock;
4458 }
4459 
4460 ////////////////////////////////////////////////////////////////////////////////
4461 /// Receive exactly length bytes into buffer. Returns number of bytes
4462 /// received. Returns -1 in case of error, -2 in case of MSG_OOB
4463 /// and errno == EWOULDBLOCK, -3 in case of MSG_OOB and errno == EINVAL
4464 /// and -4 in case of kNoBlock and errno == EWOULDBLOCK.
4465 /// Returns -5 if pipe broken or reset by peer (EPIPE || ECONNRESET).
4466 
4467 int TUnixSystem::UnixRecv(int sock, void *buffer, int length, int flag)
4468 {
4469  ResetErrno();
4470 
4471  if (sock < 0) return -1;
4472 
4473  int once = 0;
4474  if (flag == -1) {
4475  flag = 0;
4476  once = 1;
4477  }
4478  if (flag == MSG_PEEK)
4479  once = 1;
4480 
4481  int n, nrecv = 0;
4482  char *buf = (char *)buffer;
4483 
4484  for (n = 0; n < length; n += nrecv) {
4485  if ((nrecv = recv(sock, buf+n, length-n, flag)) <= 0) {
4486  if (nrecv == 0)
4487  break; // EOF
4488  if (flag == MSG_OOB) {
4489  if (GetErrno() == EWOULDBLOCK)
4490  return -2;
4491  else if (GetErrno() == EINVAL)
4492  return -3;
4493  }
4494  if (GetErrno() == EWOULDBLOCK)
4495  return -4;
4496  else {
4497  if (GetErrno() != EINTR)
4498  ::SysError("TUnixSystem::UnixRecv", "recv");
4499  if (GetErrno() == EPIPE || GetErrno() == ECONNRESET)
4500  return -5;
4501  else
4502  return -1;
4503  }
4504  }
4505  if (once)
4506  return nrecv;
4507  }
4508  return n;
4509 }
4510 
4511 ////////////////////////////////////////////////////////////////////////////////
4512 /// Send exactly length bytes from buffer. Returns -1 in case of error,
4513 /// otherwise number of sent bytes. Returns -4 in case of kNoBlock and
4514 /// errno == EWOULDBLOCK. Returns -5 if pipe broken or reset by peer
4515 /// (EPIPE || ECONNRESET).
4516 
4517 int TUnixSystem::UnixSend(int sock, const void *buffer, int length, int flag)
4518 {
4519  if (sock < 0) return -1;
4520 
4521  int once = 0;
4522  if (flag == -1) {
4523  flag = 0;
4524  once = 1;
4525  }
4526 
4527  int n, nsent = 0;
4528  const char *buf = (const char *)buffer;
4529 
4530  for (n = 0; n < length; n += nsent) {
4531  if ((nsent = send(sock, buf+n, length-n, flag)) <= 0) {
4532  if (nsent == 0)
4533  break;
4534  if (GetErrno() == EWOULDBLOCK)
4535  return -4;
4536  else {
4537  if (GetErrno() != EINTR)
4538  ::SysError("TUnixSystem::UnixSend", "send");
4539  if (GetErrno() == EPIPE || GetErrno() == ECONNRESET)
4540  return -5;
4541  else
4542  return -1;
4543  }
4544  }
4545  if (once)
4546  return nsent;
4547  }
4548  return n;
4549 }
4550 
4551 //---- Dynamic Loading ---------------------------------------------------------
4552 
4553 ////////////////////////////////////////////////////////////////////////////////
4554 /// Get shared library search path. Static utility function.
4555 
4556 static const char *DynamicPath(const char *newpath = 0, Bool_t reset = kFALSE)
4557 {
4558  static TString dynpath;
4559  static Bool_t initialized = kFALSE;
4560  if (!initialized) {
4561  // force one time initialization of gROOT before we start
4562  // (otherwise it might be done as a side effect of gEnv->GetValue and
4563  // TROOT's initialization will call this routine).
4564  gROOT;
4565  }
4566 
4567  if (newpath) {
4568  dynpath = newpath;
4569  } else if (reset || !initialized) {
4570  initialized = kTRUE;
4571  TString rdynpath = gEnv->GetValue("Root.DynamicPath", (char*)0);
4572  rdynpath.ReplaceAll(": ", ":"); // in case DynamicPath was extended
4573  if (rdynpath.IsNull()) {
4574  rdynpath = ".:"; rdynpath += TROOT::GetLibDir();
4575  }
4576  TString ldpath;
4577 #if defined (R__AIX)
4578  ldpath = gSystem->Getenv("LIBPATH");
4579 #elif defined(R__MACOSX)
4580  ldpath = gSystem->Getenv("DYLD_LIBRARY_PATH");
4581  if (!ldpath.IsNull())
4582  ldpath += ":";
4583  ldpath += gSystem->Getenv("LD_LIBRARY_PATH");
4584  if (!ldpath.IsNull())
4585  ldpath += ":";
4586  ldpath += gSystem->Getenv("DYLD_FALLBACK_LIBRARY_PATH");
4587 #else
4588  ldpath = gSystem->Getenv("LD_LIBRARY_PATH");
4589 #endif
4590  if (ldpath.IsNull())
4591  dynpath = rdynpath;
4592  else {
4593  dynpath = ldpath; dynpath += ":"; dynpath += rdynpath;
4594  }
4595  if (!dynpath.Contains(TROOT::GetLibDir())) {
4596  dynpath += ":"; dynpath += TROOT::GetLibDir();
4597  }
4598  if (gCling) {
4599  dynpath += ":"; dynpath += gCling->GetSTLIncludePath();
4600  } else
4601  initialized = kFALSE;
4602 
4603 #if defined(R__WINGCC) || defined(R__MACOSX)
4604  if (!dynpath.EndsWith(":")) dynpath += ":";
4605  dynpath += "/usr/local/lib:/usr/X11R6/lib:/usr/lib:/lib:";
4606  dynpath += "/lib/x86_64-linux-gnu:/usr/local/lib64:/usr/lib64:/lib64:";
4607 #else
4608  // trick to get the system search path
4609  std::string cmd("LD_DEBUG=libs LD_PRELOAD=DOESNOTEXIST ls 2>&1");
4610  FILE *pf = popen(cmd.c_str (), "r");
4611  std::string result = "";
4612  char buffer[128];
4613  while (!feof(pf)) {
4614  if (fgets(buffer, 128, pf) != NULL)
4615  result += buffer;
4616  }
4617  pclose(pf);
4618  std::size_t from = result.find("search path=", result.find("(LD_LIBRARY_PATH)"));
4619  std::size_t to = result.find("(system search path)");
4620  if (from != std::string::npos && to != std::string::npos) {
4621  from += 12;
4622  std::string sys_path = result.substr(from, to-from);
4623  sys_path.erase(std::remove_if(sys_path.begin(), sys_path.end(), isspace), sys_path.end());
4624  if (!dynpath.EndsWith(":")) dynpath += ":";
4625  dynpath += sys_path.c_str();
4626  }
4627  dynpath.ReplaceAll("::", ":");
4628 #endif
4629  if (gDebug > 0) std::cout << "dynpath = " << dynpath.Data() << std::endl;
4630  }
4631  return dynpath;
4632 }
4633 
4634 ////////////////////////////////////////////////////////////////////////////////
4635 /// Add a new directory to the dynamic path.
4636 
4637 void TUnixSystem::AddDynamicPath(const char *path)
4638 {
4639  if (path) {
4640  TString oldpath = DynamicPath(0, kFALSE);
4641  oldpath.Append(":");
4642  oldpath.Append(path);
4643  DynamicPath(oldpath);
4644  }
4645 }
4646 
4647 ////////////////////////////////////////////////////////////////////////////////
4648 /// Return the dynamic path (used to find shared libraries).
4649 
4650 const char *TUnixSystem::GetDynamicPath()
4651 {
4652  return DynamicPath(0, kFALSE);
4653 }
4654 
4655 ////////////////////////////////////////////////////////////////////////////////
4656 /// Set the dynamic path to a new value.
4657 /// If the value of 'path' is zero, the dynamic path is reset to its
4658 /// default value.
4659 
4660 void TUnixSystem::SetDynamicPath(const char *path)
4661 {
4662  if (!path)
4663  DynamicPath(0, kTRUE);
4664  else
4665  DynamicPath(path);
4666 }
4667 
4668 ////////////////////////////////////////////////////////////////////////////////
4669 /// Returns the path of a shared library (searches for library in the
4670 /// shared library search path). If no file name extension is provided
4671 /// it first tries .so, .sl, .dl and then .a (for AIX).
4672 
4673 const char *TUnixSystem::FindDynamicLibrary(TString& sLib, Bool_t quiet)
4674 {
4675  char buf[PATH_MAX + 1];
4676  char *res = realpath(sLib.Data(), buf);
4677  if (res) sLib = buf;
4678  TString searchFor = sLib;
4679  if (gSystem->FindFile(GetDynamicPath(), sLib, kReadPermission)) {
4680  return sLib;
4681  }
4682  sLib = searchFor;
4683  const char* lib = sLib.Data();
4684  int len = sLib.Length();
4685  if (len > 3 && (!strcmp(lib+len-3, ".so") ||
4686  !strcmp(lib+len-3, ".dl") ||
4687  !strcmp(lib+len-4, ".dll") ||
4688  !strcmp(lib+len-4, ".DLL") ||
4689  !strcmp(lib+len-6, ".dylib") ||
4690  !strcmp(lib+len-3, ".sl") ||
4691  !strcmp(lib+len-2, ".a"))) {
4692  if (gSystem->FindFile(GetDynamicPath(), sLib, kReadPermission)) {
4693  return sLib;
4694  }
4695  if (!quiet)
4696  Error("FindDynamicLibrary",
4697  "%s does not exist in %s", searchFor.Data(), GetDynamicPath());
4698  return 0;
4699  }
4700  static const char* exts[] = {
4701  ".so", ".dll", ".dylib", ".sl", ".dl", ".a", 0 };
4702  const char** ext = exts;
4703  while (*ext) {
4704  TString fname(sLib);
4705  fname += *ext;
4706  ++ext;
4707  if (gSystem->FindFile(GetDynamicPath(), fname, kReadPermission)) {
4708  sLib.Swap(fname);
4709  return sLib;
4710  }
4711  }
4712 
4713  if (!quiet)
4714  Error("FindDynamicLibrary",
4715  "%s[.so | .dll | .dylib | .sl | .dl | .a] does not exist in %s",
4716  searchFor.Data(), GetDynamicPath());
4717 
4718  return 0;
4719 }
4720 
4721 //---- System, CPU and Memory info ---------------------------------------------
4722 
4723 #if defined(R__MACOSX)
4724 #include <sys/resource.h>
4725 #include <mach/mach.h>
4726 #include <mach/mach_error.h>
4727 
4728 ////////////////////////////////////////////////////////////////////////////////
4729 /// Get system info for Mac OS X.
4730 
4731 static void GetDarwinSysInfo(SysInfo_t *sysinfo)
4732 {
4733  FILE *p = gSystem->OpenPipe("sysctl -n kern.ostype hw.model hw.ncpu hw.cpufrequency "
4734  "hw.busfrequency hw.l2cachesize hw.memsize", "r");
4735  TString s;
4736  s.Gets(p);
4737  sysinfo->fOS = s;
4738  s.Gets(p);
4739  sysinfo->fModel = s;
4740  s.Gets(p);
4741  sysinfo->fCpus = s.Atoi();
4742  s.Gets(p);
4743  Long64_t t = s.Atoll();
4744  sysinfo->fCpuSpeed = Int_t(t / 1000000);
4745  s.Gets(p);
4746  t = s.Atoll();
4747  sysinfo->fBusSpeed = Int_t(t / 1000000);
4748  s.Gets(p);
4749  sysinfo->fL2Cache = s.Atoi() / 1024;
4750  s.Gets(p);
4751  t = s.Atoll();
4752  sysinfo->fPhysRam = Int_t(t / 1024 / 1024);
4753  gSystem->ClosePipe(p);
4754  p = gSystem->OpenPipe("hostinfo", "r");
4755  while (s.Gets(p)) {
4756  if (s.BeginsWith("Processor type: ")) {
4757  TPRegexp("Processor type: ([^ ]+).*").Substitute(s, "$1");
4758  sysinfo->fCpuType = s;
4759  }
4760  }
4761  gSystem->ClosePipe(p);
4762 }
4763 
4764 ////////////////////////////////////////////////////////////////////////////////
4765 /// Get CPU load on Mac OS X.
4766 
4767 static void ReadDarwinCpu(long *ticks)
4768 {
4769  mach_msg_type_number_t count;
4770  kern_return_t kr;
4771  host_cpu_load_info_data_t cpu;
4772 
4773  ticks[0] = ticks[1] = ticks[2] = ticks[3] = 0;
4774 
4775  count = HOST_CPU_LOAD_INFO_COUNT;
4776  kr = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&cpu, &count);
4777  if (kr != KERN_SUCCESS) {
4778  ::Error("TUnixSystem::ReadDarwinCpu", "host_statistics: %s", mach_error_string(kr));
4779  } else {
4780  ticks[0] = cpu.cpu_ticks[CPU_STATE_USER];
4781  ticks[1] = cpu.cpu_ticks[CPU_STATE_SYSTEM];
4782  ticks[2] = cpu.cpu_ticks[CPU_STATE_IDLE];
4783  ticks[3] = cpu.cpu_ticks[CPU_STATE_NICE];
4784  }
4785 }
4786 
4787 ////////////////////////////////////////////////////////////////////////////////
4788 /// Get CPU stat for Mac OS X. Use sampleTime to set the interval over which
4789 /// the CPU load will be measured, in ms (default 1000).
4790 
4791 static void GetDarwinCpuInfo(CpuInfo_t *cpuinfo, Int_t sampleTime)
4792 {
4793  Double_t avg[3];
4794  if (getloadavg(avg, sizeof(avg)) < 0) {
4795  ::Error("TUnixSystem::GetDarwinCpuInfo", "getloadavg failed");
4796  } else {
4797  cpuinfo->fLoad1m = (Float_t)avg[0];
4798  cpuinfo->fLoad5m = (Float_t)avg[1];
4799  cpuinfo->fLoad15m = (Float_t)avg[2];
4800  }
4801 
4802  Long_t cpu_ticks1[4], cpu_ticks2[4];
4803  ReadDarwinCpu(cpu_ticks1);
4804  gSystem->Sleep(sampleTime);
4805  ReadDarwinCpu(cpu_ticks2);
4806 
4807  Long_t userticks = (cpu_ticks2[0] + cpu_ticks2[3]) -
4808  (cpu_ticks1[0] + cpu_ticks1[3]);
4809  Long_t systicks = cpu_ticks2[1] - cpu_ticks1[1];
4810  Long_t idleticks = cpu_ticks2[2] - cpu_ticks1[2];
4811  if (userticks < 0) userticks = 0;
4812  if (systicks < 0) systicks = 0;
4813  if (idleticks < 0) idleticks = 0;
4814  Long_t totalticks = userticks + systicks + idleticks;
4815  if (totalticks) {
4816  cpuinfo->fUser = ((Float_t)(100 * userticks)) / ((Float_t)totalticks);
4817  cpuinfo->fSys = ((Float_t)(100 * systicks)) / ((Float_t)totalticks);
4818  cpuinfo->fTotal = cpuinfo->fUser + cpuinfo->fSys;
4819  cpuinfo->fIdle = ((Float_t)(100 * idleticks)) / ((Float_t)totalticks);
4820  }
4821 }
4822 
4823 ////////////////////////////////////////////////////////////////////////////////
4824 /// Get VM stat for Mac OS X.
4825 
4826 static void GetDarwinMemInfo(MemInfo_t *meminfo)
4827 {
4828  static Int_t pshift = 0;
4829  static DIR *dirp;
4830  vm_statistics_data_t vm_info;
4831  mach_msg_type_number_t count;
4832  kern_return_t kr;
4833  struct dirent *dp;
4834  Long64_t total, used, free, swap_total, swap_used;
4835 
4836  count = HOST_VM_INFO_COUNT;
4837  kr = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_info, &count);
4838  if (kr != KERN_SUCCESS) {
4839  ::Error("TUnixSystem::GetDarwinMemInfo", "host_statistics: %s", mach_error_string(kr));
4840  return;
4841  }
4842  if (pshift == 0) {
4843  for (int psize = getpagesize(); psize > 1; psize >>= 1)
4844  pshift++;
4845  }
4846 
4847  used = (Long64_t)(vm_info.active_count + vm_info.inactive_count + vm_info.wire_count) << pshift;
4848  free = (Long64_t)(vm_info.free_count) << pshift;
4849  total = (Long64_t)(vm_info.active_count + vm_info.inactive_count + vm_info.free_count + vm_info.wire_count) << pshift;
4850 
4851  // Swap is available at same time as mem, so grab values here.
4852  swap_used = vm_info.pageouts << pshift;
4853 
4854  // Figure out total swap. This adds up the size of the swapfiles */
4855  dirp = opendir("/private/var/vm");
4856  if (!dirp)
4857  return;
4858 
4859  swap_total = 0;
4860  while ((dp = readdir(dirp)) != 0) {
4861  struct stat sb;
4862  char fname [MAXNAMLEN];
4863  if (strncmp(dp->d_name, "swapfile", 8))
4864  continue;
4865  strlcpy(fname, "/private/var/vm/",MAXNAMLEN);
4866  strlcat (fname, dp->d_name,MAXNAMLEN);
4867  if (stat(fname, &sb) < 0)
4868  continue;
4869  swap_total += sb.st_size;
4870  }
4871  closedir(dirp);
4872 
4873  meminfo->fMemTotal = (Int_t) (total >> 20); // divide by 1024 * 1024
4874  meminfo->fMemUsed = (Int_t) (used >> 20);
4875  meminfo->fMemFree = (Int_t) (free >> 20);
4876  meminfo->fSwapTotal = (Int_t) (swap_total >> 20);
4877  meminfo->fSwapUsed = (Int_t) (swap_used >> 20);
4878  meminfo->fSwapFree = meminfo->fSwapTotal - meminfo->fSwapUsed;
4879 }
4880 
4881 ////////////////////////////////////////////////////////////////////////////////
4882 /// Get process info for this process on Mac OS X.
4883 /// Code largely taken from:
4884 /// http://www.opensource.apple.com/source/top/top-15/libtop.c
4885 /// The virtual memory usage is slightly over estimated as we don't
4886 /// subtract shared regions, but the value makes more sense
4887 /// then pure vsize, which is useless on 64-bit machines.
4888 
4889 static void GetDarwinProcInfo(ProcInfo_t *procinfo)
4890 {
4891 #ifdef _LP64
4892 #define vm_region vm_region_64
4893 #endif
4894 
4895 // taken from <mach/shared_memory_server.h> which is obsoleted in 10.5
4896 #define GLOBAL_SHARED_TEXT_SEGMENT 0x90000000U
4897 #define GLOBAL_SHARED_DATA_SEGMENT 0xA0000000U
4898 #define SHARED_TEXT_REGION_SIZE 0x10000000
4899 #define SHARED_DATA_REGION_SIZE 0x10000000
4900 
4901  struct rusage ru;
4902  if (getrusage(RUSAGE_SELF, &ru) < 0) {
4903  ::SysError("TUnixSystem::GetDarwinProcInfo", "getrusage failed");
4904  } else {
4905  procinfo->fCpuUser = (Float_t)(ru.ru_utime.tv_sec) +
4906  ((Float_t)(ru.ru_utime.tv_usec) / 1000000.);
4907  procinfo->fCpuSys = (Float_t)(ru.ru_stime.tv_sec) +
4908  ((Float_t)(ru.ru_stime.tv_usec) / 1000000.);
4909  }
4910 
4911  task_basic_info_data_t ti;
4912  mach_msg_type_number_t count;
4913  kern_return_t kr;
4914 
4915  task_t a_task = mach_task_self();
4916 
4917  count = TASK_BASIC_INFO_COUNT;
4918  kr = task_info(a_task, TASK_BASIC_INFO, (task_info_t)&ti, &count);
4919  if (kr != KERN_SUCCESS) {
4920  ::Error("TUnixSystem::GetDarwinProcInfo", "task_info: %s", mach_error_string(kr));
4921  } else {
4922  // resident size does not require any calculation. Virtual size
4923  // needs to be adjusted if traversing memory objects do not include the
4924  // globally shared text and data regions
4925  mach_port_t object_name;
4926  vm_address_t address;
4927  vm_region_top_info_data_t info;
4928  vm_size_t vsize, vprvt, rsize, size;
4929  rsize = ti.resident_size;
4930  vsize = ti.virtual_size;
4931  vprvt = 0;
4932  for (address = 0; ; address += size) {
4933  // get memory region
4934  count = VM_REGION_TOP_INFO_COUNT;
4935  if (vm_region(a_task, &address, &size,
4936  VM_REGION_TOP_INFO, (vm_region_info_t)&info, &count,
4937  &object_name) != KERN_SUCCESS) {
4938  // no more memory regions.
4939  break;
4940  }
4941 
4942  if (address >= GLOBAL_SHARED_TEXT_SEGMENT &&
4943  address < (GLOBAL_SHARED_DATA_SEGMENT + SHARED_DATA_REGION_SIZE)) {
4944  // This region is private shared.
4945  // Check if this process has the globally shared
4946  // text and data regions mapped in. If so, adjust
4947  // virtual memory size and exit loop.
4948  if (info.share_mode == SM_EMPTY) {
4949  vm_region_basic_info_data_64_t b_info;
4950  count = VM_REGION_BASIC_INFO_COUNT_64;
4951  if (vm_region_64(a_task, &address,
4952  &size, VM_REGION_BASIC_INFO,
4953  (vm_region_info_t)&b_info, &count,
4954  &object_name) != KERN_SUCCESS) {
4955  break;
4956  }
4957 
4958  if (b_info.reserved) {
4959  vsize -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE);
4960  //break; // only for vsize
4961  }
4962  }
4963  // Short circuit the loop if this isn't a shared
4964  // private region, since that's the only region
4965  // type we care about within the current address range.
4966  if (info.share_mode != SM_PRIVATE) {
4967  continue;
4968  }
4969  }
4970  switch (info.share_mode) {
4971  case SM_COW: {
4972  if (info.ref_count == 1) {
4973  vprvt += size;
4974  } else {
4975  vprvt += info.private_pages_resident * getpagesize();
4976  }
4977  break;
4978  }
4979  case SM_PRIVATE: {
4980  vprvt += size;
4981  break;
4982  }
4983  default:
4984  break;
4985  }
4986  }
4987 
4988  procinfo->fMemResident = (Long_t)(rsize / 1024);
4989  //procinfo->fMemVirtual = (Long_t)(vsize / 1024);
4990  procinfo->fMemVirtual = (Long_t)(vprvt / 1024);
4991  }
4992 }
4993 #endif
4994 
4995 #if defined(R__LINUX)
4996 ////////////////////////////////////////////////////////////////////////////////
4997 /// Get system info for Linux. Only fBusSpeed is not set.
4998 
4999 static void GetLinuxSysInfo(SysInfo_t *sysinfo)
5000 {
5001  TString s;
5002  FILE *f = fopen("/proc/cpuinfo", "r");
5003  if (f) {
5004  while (s.Gets(f)) {
5005  if (s.BeginsWith("model name")) {
5006  TPRegexp("^.+: *(.*$)").Substitute(s, "$1");
5007  sysinfo->fModel = s;
5008  }
5009  if (s.BeginsWith("cpu MHz")) {
5010  TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
5011  sysinfo->fCpuSpeed = s.Atoi();
5012  }
5013  if (s.BeginsWith("cache size")) {
5014  TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
5015  sysinfo->fL2Cache = s.Atoi();
5016  }
5017  if (s.BeginsWith("processor")) {
5018  TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
5019  sysinfo->fCpus = s.Atoi();
5020  sysinfo->fCpus++;
5021  }
5022  }
5023  fclose(f);
5024  }
5025 
5026  f = fopen("/proc/meminfo", "r");
5027  if (f) {
5028  while (s.Gets(f)) {
5029  if (s.BeginsWith("MemTotal")) {
5030  TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
5031  sysinfo->fPhysRam = (s.Atoi() / 1024);
5032  break;
5033  }
5034  }
5035  fclose(f);
5036  }
5037 
5038  f = gSystem->OpenPipe("uname -s -p", "r");
5039  if (f) {
5040  s.Gets(f);
5041  Ssiz_t from = 0;
5042  s.Tokenize(sysinfo->fOS, from);
5043  s.Tokenize(sysinfo->fCpuType, from);
5044  gSystem->ClosePipe(f);
5045  }
5046 }
5047 
5048 ////////////////////////////////////////////////////////////////////////////////
5049 /// Get CPU load on Linux.
5050 
5051 static void ReadLinuxCpu(long *ticks)
5052 {
5053  ticks[0] = ticks[1] = ticks[2] = ticks[3] = 0;
5054 
5055  TString s;
5056  FILE *f = fopen("/proc/stat", "r");
5057  if (!f) return;
5058  s.Gets(f);
5059  // user, user nice, sys, idle
5060  sscanf(s.Data(), "%*s %ld %ld %ld %ld", &ticks[0], &ticks[3], &ticks[1], &ticks[2]);
5061  fclose(f);
5062 }
5063 
5064 ////////////////////////////////////////////////////////////////////////////////
5065 /// Get CPU stat for Linux. Use sampleTime to set the interval over which
5066 /// the CPU load will be measured, in ms (default 1000).
5067 
5068 static void GetLinuxCpuInfo(CpuInfo_t *cpuinfo, Int_t sampleTime)
5069 {
5070  Double_t avg[3] = { -1., -1., -1. };
5071 #ifndef R__WINGCC
5072  if (getloadavg(avg, sizeof(avg)) < 0) {
5073  ::Error("TUnixSystem::GetLinuxCpuInfo", "getloadavg failed");
5074  } else
5075 #endif
5076  {
5077  cpuinfo->fLoad1m = (Float_t)avg[0];
5078  cpuinfo->fLoad5m = (Float_t)avg[1];
5079  cpuinfo->fLoad15m = (Float_t)avg[2];
5080  }
5081 
5082  Long_t cpu_ticks1[4], cpu_ticks2[4];
5083  ReadLinuxCpu(cpu_ticks1);
5084  gSystem->Sleep(sampleTime);
5085  ReadLinuxCpu(cpu_ticks2);
5086 
5087  Long_t userticks = (cpu_ticks2[0] + cpu_ticks2[3]) -
5088  (cpu_ticks1[0] + cpu_ticks1[3]);
5089  Long_t systicks = cpu_ticks2[1] - cpu_ticks1[1];
5090  Long_t idleticks = cpu_ticks2[2] - cpu_ticks1[2];
5091  if (userticks < 0) userticks = 0;
5092  if (systicks < 0) systicks = 0;
5093  if (idleticks < 0) idleticks = 0;
5094  Long_t totalticks = userticks + systicks + idleticks;
5095  if (totalticks) {
5096  cpuinfo->fUser = ((Float_t)(100 * userticks)) / ((Float_t)totalticks);
5097  cpuinfo->fSys = ((Float_t)(100 * systicks)) / ((Float_t)totalticks);
5098  cpuinfo->fTotal = cpuinfo->fUser + cpuinfo->fSys;
5099  cpuinfo->fIdle = ((Float_t)(100 * idleticks)) / ((Float_t)totalticks);
5100  }
5101 }
5102 
5103 ////////////////////////////////////////////////////////////////////////////////
5104 /// Get VM stat for Linux.
5105 
5106 static void GetLinuxMemInfo(MemInfo_t *meminfo)
5107 {
5108  TString s;
5109  FILE *f = fopen("/proc/meminfo", "r");
5110  if (!f) return;
5111  while (s.Gets(f)) {
5112  if (s.BeginsWith("MemTotal")) {
5113  TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
5114  meminfo->fMemTotal = (s.Atoi() / 1024);
5115  }
5116  if (s.BeginsWith("MemFree")) {
5117  TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
5118  meminfo->fMemFree = (s.Atoi() / 1024);
5119  }
5120  if (s.BeginsWith("SwapTotal")) {
5121  TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
5122  meminfo->fSwapTotal = (s.Atoi() / 1024);
5123  }
5124  if (s.BeginsWith("SwapFree")) {
5125  TPRegexp("^.+: *([^ ]+).*").Substitute(s, "$1");
5126  meminfo->fSwapFree = (s.Atoi() / 1024);
5127  }
5128  }
5129  fclose(f);
5130 
5131  meminfo->fMemUsed = meminfo->fMemTotal - meminfo->fMemFree;
5132  meminfo->fSwapUsed = meminfo->fSwapTotal - meminfo->fSwapFree;
5133 }
5134 
5135 ////////////////////////////////////////////////////////////////////////////////
5136 /// Get process info for this process on Linux.
5137 
5138 static void GetLinuxProcInfo(ProcInfo_t *procinfo)
5139 {
5140  struct rusage ru;
5141  if (getrusage(RUSAGE_SELF, &ru) < 0) {
5142  ::SysError("TUnixSystem::GetLinuxProcInfo", "getrusage failed");
5143  } else {
5144  procinfo->fCpuUser = (Float_t)(ru.ru_utime.tv_sec) +
5145  ((Float_t)(ru.ru_utime.tv_usec) / 1000000.);
5146  procinfo->fCpuSys = (Float_t)(ru.ru_stime.tv_sec) +
5147  ((Float_t)(ru.ru_stime.tv_usec) / 1000000.);
5148  }
5149 
5150  procinfo->fMemVirtual = -1;
5151  procinfo->fMemResident = -1;
5152  TString s;
5153  FILE *f = fopen(TString::Format("/proc/%d/statm", gSystem->GetPid()), "r");
5154  if (f) {
5155  s.Gets(f);
5156  fclose(f);
5157  Long_t total, rss;
5158  sscanf(s.Data(), "%ld %ld", &total, &rss);
5159  procinfo->fMemVirtual = total * (getpagesize() / 1024);
5160  procinfo->fMemResident = rss * (getpagesize() / 1024);
5161  }
5162 }
5163 #endif
5164 
5165 ////////////////////////////////////////////////////////////////////////////////
5166 /// Returns static system info, like OS type, CPU type, number of CPUs
5167 /// RAM size, etc into the SysInfo_t structure. Returns -1 in case of error,
5168 /// 0 otherwise.
5169 
5170 int TUnixSystem::GetSysInfo(SysInfo_t *info) const
5171 {
5172  if (!info) return -1;
5173 
5174  static SysInfo_t sysinfo;
5175 
5176  if (!sysinfo.fCpus) {
5177 #if defined(R__MACOSX)
5178  GetDarwinSysInfo(&sysinfo);
5179 #elif defined(R__LINUX)
5180  GetLinuxSysInfo(&sysinfo);
5181 #endif
5182  }
5183 
5184  *info = sysinfo;
5185 
5186  return 0;
5187 }
5188 
5189 ////////////////////////////////////////////////////////////////////////////////
5190 /// Returns cpu load average and load info into the CpuInfo_t structure.
5191 /// Returns -1 in case of error, 0 otherwise. Use sampleTime to set the
5192 /// interval over which the CPU load will be measured, in ms (default 1000).
5193 
5194 int TUnixSystem::GetCpuInfo(CpuInfo_t *info, Int_t sampleTime) const
5195 {
5196  if (!info) return -1;
5197 
5198 #if defined(R__MACOSX)
5199  GetDarwinCpuInfo(info, sampleTime);
5200 #elif defined(R__LINUX)
5201  GetLinuxCpuInfo(info, sampleTime);
5202 #endif
5203 
5204  return 0;
5205 }
5206 
5207 ////////////////////////////////////////////////////////////////////////////////
5208 /// Returns ram and swap memory usage info into the MemInfo_t structure.
5209 /// Returns -1 in case of error, 0 otherwise.
5210 
5211 int TUnixSystem::GetMemInfo(MemInfo_t *info) const
5212 {
5213  if (!info) return -1;
5214 
5215 #if defined(R__MACOSX)
5216  GetDarwinMemInfo(info);
5217 #elif defined(R__LINUX)
5218  GetLinuxMemInfo(info);
5219 #endif
5220 
5221  return 0;
5222 }
5223 
5224 ////////////////////////////////////////////////////////////////////////////////
5225 /// Returns cpu and memory used by this process into the ProcInfo_t structure.
5226 /// Returns -1 in case of error, 0 otherwise.
5227 
5228 int TUnixSystem::GetProcInfo(ProcInfo_t *info) const
5229 {
5230  if (!info) return -1;
5231 
5232 #if defined(R__MACOSX)
5233  GetDarwinProcInfo(info);
5234 #elif defined(R__LINUX)
5235  GetLinuxProcInfo(info);
5236 #endif
5237 
5238  return 0;
5239 }