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