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