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