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