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