// @(#)root/unix:$Name: $:$Id: TUnixSystem.cxx,v 1.41 2002/08/20 10:51:50 rdm Exp $ // Author: Fons Rademakers 15/09/95 /************************************************************************* * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ ////////////////////////////////////////////////////////////////////////// // // // TUnixSystem // // // // Class providing an interface to the UNIX Operating System. // // // ////////////////////////////////////////////////////////////////////////// #ifdef HAVE_CONFIG #include "config.h" #endif #include "TUnixSystem.h" #include "TROOT.h" #include "TError.h" #include "TMath.h" #include "TOrdCollection.h" #include "TRegexp.h" #include "TException.h" #include "Demangle.h" #include "TEnv.h" #include "TSocket.h" #include "Getline.h" #include "TInterpreter.h" #include "TApplication.h" //#define G__OLDEXPAND #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #if defined(R__SUN) || defined(R__SGI) || defined(R__HPUX) || \ defined(R__AIX) || defined(R__LINUX) || defined(R__SOLARIS) || \ defined(R__ALPHA) || defined(R__HIUX) || defined(R__FBSD) || \ defined(R__MACOSX) || defined(R__HURD) # include <dirent.h> #else # include <sys/dir.h> #endif #if defined(ULTRIX) || defined(R__SUN) # include <sgtty.h> #endif #if defined(R__AIX) || defined(R__LINUX) || defined(R__ALPHA) || \ defined(R__SGI) || defined(R__HIUX) || defined(R__FBSD) || \ defined(R__LYNXOS) || defined(R__MACOSX) || defined(R__HURD) # include <sys/ioctl.h> #endif #if defined(R__AIX) || defined(R__SOLARIS) # include <sys/select.h> #endif #if (defined(R__LINUX) && !defined(R__MKLINUX)) || defined(R__HURD) # ifndef SIGSYS # define SIGSYS SIGUNUSED // SIGSYS does not exist in linux ?? # endif # include <dlfcn.h> #endif #if defined(R__ALPHA) # include <sys/mount.h> # ifndef R__TRUE64 extern "C" int statfs(const char *file, struct statfs *buffer); # endif #elif defined(R__MACOSX) # include <sys/mount.h> extern "C" int statfs(const char *file, struct statfs *buffer); #elif defined(R__LINUX) || defined(R__HPUX) || defined(R__HURD) # include <sys/vfs.h> #elif defined(R__FBSD) # include <sys/param.h> # include <sys/mount.h> #else # include <sys/statfs.h> #endif #include <utime.h> #include <syslog.h> #include <sys/stat.h> #include <setjmp.h> #include <signal.h> #include <sys/param.h> #include <pwd.h> #include <errno.h> #include <sys/wait.h> #include <time.h> #include <sys/time.h> #include <sys/file.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #if defined(R__AIX) # define _XOPEN_EXTENDED_SOURCE # include <arpa/inet.h> # undef _XOPEN_EXTENDED_SOURCE # if !defined(_AIX41) && !defined(_AIX43) // AIX 3.2 doesn't have it # define HASNOT_INETATON # endif #else # include <arpa/inet.h> #endif #include <sys/un.h> #include <netdb.h> #include <fcntl.h> #if defined(R__SGI) # include <net/soioctl.h> #endif #if defined(R__SOLARIS) # include <sys/systeminfo.h> # include <sys/filio.h> # include <sys/sockio.h> # define HASNOT_INETATON # define INADDR_NONE (UInt_t)-1 #endif #if defined(R__HPUX) # include <symlink.h> # include <dl.h> # if defined(R__GNU) extern "C" { extern shl_t cxxshl_load(const char *path, int flags, long address); extern int cxxshl_unload(shl_t handle); } # elif !defined(__STDCPP__) # include <cxxdl.h> # endif // print stack trace (HP undocumented internal call) extern "C" void U_STACK_TRACE(); # if defined(hpux9) extern "C" { extern void openlog(const char *, int, int); extern void syslog(int, const char *, ...); extern void closelog(void); extern int setlogmask(int); } # define HASNOT_INETATON # endif #endif #if defined(R__ALPHA) && !defined(R__GNU) # define HASNOT_INETATON #endif #if defined(R__HIUX) # define HASNOT_INETATON #endif #if defined(R__SGI) || defined(R__SOLARIS) # define HAVE_UTMPX_H # define UTMP_NO_ADDR #endif #if defined(R__ALPHA) || defined(R__AIX) || defined(R__FBSD) || \ defined(R__LYNXOS) || defined(R__MACOSX) # define UTMP_NO_ADDR #endif #if defined(R__AIX) || (defined(R__FBSD) && !defined(R__ALPHA)) # define USE_SIZE_T #elif defined(R__GLIBC) || (defined(R__FBSD) && defined(R__ALPHA)) # define USE_SOCKLEN_T #endif #if defined(R__LYNXOS) extern "C" { extern int putenv(const char *); extern int inet_aton(const char *, struct in_addr *); }; #endif #ifdef HAVE_UTMPX_H #include <utmpx.h> #define STRUCT_UTMP struct utmpx #else #if defined(R__MKLINUX) && !defined(R__PPCEGCS) extern "C" { #endif #include <utmp.h> #define STRUCT_UTMP struct utmp #endif #if !defined(UTMP_FILE) && defined(_PATH_UTMP) // 4.4BSD #define UTMP_FILE _PATH_UTMP #endif #if defined(UTMPX_FILE) // Solaris, SysVr4 #undef UTMP_FILE #define UTMP_FILE UTMPX_FILE #endif #ifndef UTMP_FILE #define UTMP_FILE "/etc/utmp" #endif static STRUCT_UTMP *gUtmpContents; const char *kServerPath = "/tmp"; const char *kProtocolName = "tcp"; //______________________________________________________________________________ static void SigHandler(ESignals sig) { // Unix signal handler. if (gSystem) ((TUnixSystem*)gSystem)->DispatchSignals(sig); } ClassImp(TUnixSystem) //______________________________________________________________________________ TUnixSystem::TUnixSystem() : TSystem("Unix", "Unix System") { } //______________________________________________________________________________ TUnixSystem::~TUnixSystem() { // Reset to original state. UnixResetSignals(); } //______________________________________________________________________________ Bool_t TUnixSystem::Init() { // Initialize Unix system interface. if (TSystem::Init()) return kTRUE; //--- install default handlers UnixSignal(kSigChild, SigHandler); UnixSignal(kSigBus, SigHandler); UnixSignal(kSigSegmentationViolation, SigHandler); UnixSignal(kSigIllegalInstruction, SigHandler); UnixSignal(kSigSystem, SigHandler); UnixSignal(kSigPipe, SigHandler); UnixSignal(kSigAlarm, SigHandler); UnixSignal(kSigUrgent, SigHandler); UnixSignal(kSigFloatingException, SigHandler); UnixSignal(kSigWindowChanged, SigHandler); #ifndef ROOTPREFIX gRootDir = Getenv("ROOTSYS"); if (gRootDir == 0) gRootDir= "/usr/local/root"; #else gRootDir = ROOTPREFIX; #endif return kFALSE; } //---- Misc -------------------------------------------------------------------- //______________________________________________________________________________ void TUnixSystem::SetProgname(const char *name) { // Set the application name (from command line, argv[0]) and copy it in // gProgName. Copy the application pathname in gProgPath. if (name && strlen(name) > 0) { gProgName = StrDup(BaseName(name)); char *w = Which(Getenv("PATH"), gProgName); gProgPath = StrDup(DirName(w)); delete [] w; } } //______________________________________________________________________________ void TUnixSystem::SetDisplay() { // Set DISPLAY environment variable based on utmp entry. Only for UNIX. if (!Getenv("DISPLAY")) { char *tty = ::ttyname(0); // device user is logged in on if (tty) { tty += 5; // remove "/dev/" STRUCT_UTMP *utmp_entry; utmp_entry = (STRUCT_UTMP *)SearchUtmpEntry(ReadUtmpFile(), tty); if (utmp_entry) { if (utmp_entry->ut_host[0]) if (strchr(utmp_entry->ut_host, ':')) { Setenv("DISPLAY", utmp_entry->ut_host); Warning("SetDisplay", "DISPLAY not set, setting it to %s", utmp_entry->ut_host); } else { char disp[64]; sprintf(disp, "%s:0.0", utmp_entry->ut_host); Setenv("DISPLAY", disp); Warning("SetDisplay", "DISPLAY not set, setting it to %s", disp); } #ifndef UTMP_NO_ADDR else if (utmp_entry->ut_addr) { struct hostent *he; if ((he = gethostbyaddr((const char*)&utmp_entry->ut_addr, sizeof(utmp_entry->ut_addr), AF_INET))) { char disp[64]; sprintf(disp, "%s:0.0", he->h_name); Setenv("DISPLAY", disp); Warning("SetDisplay", "DISPLAY not set, setting it to %s", disp); } } #endif } free(gUtmpContents); } } } //______________________________________________________________________________ const char *TUnixSystem::GetError() { // Return system error string. Int_t err = GetErrno(); #if defined(R__SOLARIS) || defined (R__LINUX) || defined(R__AIX) || \ defined(R__FBSD) || defined(R__HURD) return strerror(err); #else if (err < 0 || err >= sys_nerr) return Form("errno out of range %d", err); return sys_errlist[err]; #endif } //______________________________________________________________________________ const char *TUnixSystem::HostName() { // Return the system's host name. if (fHostname == "") { char hn[64]; #if defined(R__SOLARIS) && !defined(R__KCC) sysinfo(SI_HOSTNAME, hn, sizeof(hn)); #else gethostname(hn, sizeof(hn)); #endif fHostname = hn; } return (const char *)fHostname; } //---- EventLoop --------------------------------------------------------------- //______________________________________________________________________________ void TUnixSystem::AddFileHandler(TFileHandler *h) { // Add a file handler to the list of system file handlers. TSystem::AddFileHandler(h); if (h) { int fd = h->GetFd(); if (h->HasReadInterest()) { fReadmask.Set(fd); fMaxrfd = TMath::Max(fMaxrfd, fd); } if (h->HasWriteInterest()) { fWritemask.Set(fd); fMaxwfd = TMath::Max(fMaxwfd, fd); } } } //______________________________________________________________________________ TFileHandler *TUnixSystem::RemoveFileHandler(TFileHandler *h) { // Remove a file handler from the list of file handlers. TFileHandler *oh = TSystem::RemoveFileHandler(h); if (oh) { // found TFileHandler *th; TIter next(fFileHandler); fMaxrfd = 0; fMaxwfd = 0; fReadmask.Zero(); fWritemask.Zero(); while ((th = (TFileHandler *) next())) { int fd = th->GetFd(); if (th->HasReadInterest()) { fReadmask.Set(fd); fMaxrfd = TMath::Max(fMaxrfd, fd); } if (th->HasWriteInterest()) { fWritemask.Set(fd); fMaxwfd = TMath::Max(fMaxwfd, fd); } } } return oh; } //______________________________________________________________________________ void TUnixSystem::AddSignalHandler(TSignalHandler *h) { // Add a signal handler to list of system signal handlers. TSystem::AddSignalHandler(h); UnixSignal(h->GetSignal(), SigHandler); } //______________________________________________________________________________ TSignalHandler *TUnixSystem::RemoveSignalHandler(TSignalHandler *h) { // Remove a signal handler from list of signal handlers. // if last handler of specific signal need to reset sighandler to default return TSystem::RemoveSignalHandler(h); } //______________________________________________________________________________ void TUnixSystem::ResetSignal(ESignals sig, Bool_t reset) { // If reset is true reset the signal handler for the specified signal // to the default handler, else restore previous behaviour. if (reset) UnixResetSignal(sig); else UnixSignal(sig, SigHandler); } //______________________________________________________________________________ void TUnixSystem::IgnoreSignal(ESignals sig, Bool_t ignore) { // If ignore is true ignore the specified signal, else restore previous // behaviour. UnixIgnoreSignal(sig, ignore); } //______________________________________________________________________________ void TUnixSystem::DispatchOneEvent(Bool_t pendingOnly) { // Dispatch a single event. while (1) { // first handle any X11 events if (gXDisplay && gXDisplay->Notify()) { if (fReadready.IsSet(gXDisplay->GetFd())) { fReadready.Clr(gXDisplay->GetFd()); fNfd--; } if (!pendingOnly) return; } // check for file descriptors ready for reading/writing if (fNfd > 0 && fFileHandler->GetSize() > 0) if (CheckDescriptors()) if (!pendingOnly) return; fNfd = 0; fReadready.Zero(); fWriteready.Zero(); // check synchronous signals if (fSigcnt > 0 && fSignalHandler->GetSize() > 0) if (CheckSignals(kTRUE)) if (!pendingOnly) return; fSigcnt = 0; fSignals.Zero(); // check synchronous timers if (fTimers && fTimers->GetSize() > 0) if (DispatchTimers(kTRUE)) { // prevent timers from blocking file descriptor monitoring Long_t to = NextTimeOut(kTRUE); if (to > kItimerResolution || to == -1) return; } if (pendingOnly) return; // nothing ready, so setup select call fReadready = fReadmask; fWriteready = fWritemask; int mxfd = TMath::Max(fMaxrfd, fMaxwfd) + 1; fNfd = UnixSelect(mxfd, &fReadready, &fWriteready, NextTimeOut(kTRUE)); if (fNfd < 0 && fNfd != -2) { int fd, rc; TFdSet t; for (fd = 0; fd < mxfd; fd++) { t.Set(fd); if (fReadmask.IsSet(fd)) { rc = UnixSelect(fd+1, &t, 0, 0); if (rc < 0 && rc != -2) { SysError("DispatchOneEvent", "select: read error on %dn", fd); fReadmask.Clr(fd); } } if (fWritemask.IsSet(fd)) { rc = UnixSelect(fd+1, 0, &t, 0); if (rc < 0 && rc != -2) { SysError("DispatchOneEvent", "select: write error on %dn", fd); fWritemask.Clr(fd); } } t.Clr(fd); } } } } //______________________________________________________________________________ void TUnixSystem::Sleep(UInt_t milliSec) { // Sleep milliSec milliseconds. struct timeval tv; tv.tv_sec = milliSec / 1000; tv.tv_usec = (milliSec % 1000) * 1000; select(0, 0, 0, 0, &tv); } //---- handling of system events ----------------------------------------------- //______________________________________________________________________________ void TUnixSystem::DispatchSignals(ESignals sig) { // Handle and dispatch signals. switch (sig) { case kSigAlarm: DispatchTimers(kFALSE); break; case kSigChild: CheckChilds(); return; case kSigBus: case kSigSegmentationViolation: case kSigIllegalInstruction: case kSigFloatingException: Printf("n *** Break *** %s", UnixSigname(sig)); StackTrace(); if (TROOT::Initialized()) { if (gException) { if (gApplication && gApplication->InheritsFrom("TRint")) { Getlinem(kCleanUp, 0); Getlinem(kInit, "Root > "); } gInterpreter->RewindDictionary(); gInterpreter->ClearFileBusy(); } Throw(sig); } Abort(-1); break; case kSigSystem: case kSigPipe: Printf("n *** Break *** %s", UnixSigname(sig)); break; case kSigWindowChanged: Gl_windowchanged(); break; default: fSignals.Set(sig); fSigcnt++; break; } // check a-synchronous signals if (fSigcnt > 0 && fSignalHandler->GetSize() > 0) CheckSignals(kFALSE); } //______________________________________________________________________________ Bool_t TUnixSystem::CheckSignals(Bool_t sync) { // Check if some signals were raised and call their Notify() member. TSignalHandler *sh; Int_t sigdone = -1; { TOrdCollectionIter it((TOrdCollection*)fSignalHandler); while ((sh = (TSignalHandler*)it.Next())) { if (sync == sh->IsSync()) { ESignals sig = sh->GetSignal(); if ((fSignals.IsSet(sig) && sigdone == -1) || sigdone == sig) { if (sigdone == -1) { fSignals.Clr(sig); sigdone = sig; fSigcnt--; } sh->Notify(); } } } } if (sigdone != -1) return kTRUE; return kFALSE; } //______________________________________________________________________________ void TUnixSystem::CheckChilds() { // Check if childs have finished. #if 0 //rdm int pid; while ((pid = UnixWaitchild()) > 0) { TIter next(zombieHandler); register UnixPtty *pty; while (pty = (UnixPtty*) next()) if (pty->GetPid() == pid) { zombieHandler->RemovePtr(pty); pty->DiedNotify(); } } #endif } //______________________________________________________________________________ Bool_t TUnixSystem::CheckDescriptors() { // Check if there is activity on some file descriptors and call their // Notify() member. TFileHandler *fh; Int_t fddone = -1; Bool_t read = kFALSE; #if defined(R__LINUX) && defined(__alpha__) // TOrdCollectionIter it(...) causes segv ?!?!? Also TIter fails. Int_t cursor = 0; while (cursor < fFileHandler->GetSize()) { fh = (TFileHandler*) fFileHandler->At(cursor++); #else TOrdCollectionIter it((TOrdCollection*)fFileHandler); while ((fh = (TFileHandler*) it.Next())) { #endif Int_t fd = fh->GetFd(); if ((fd <= fMaxrfd && fReadready.IsSet(fd) && fddone == -1) || (fddone == fd && read)) { if (fddone == -1) { fReadready.Clr(fd); fddone = fd; read = kTRUE; fNfd--; } fh->ReadNotify(); } if ((fd <= fMaxwfd && fWriteready.IsSet(fd) && fddone == -1) || (fddone == fd && !read)) { if (fddone == -1) { fWriteready.Clr(fd); fddone = fd; read = kFALSE; fNfd--; } fh->WriteNotify(); } } if (fddone != -1) return kTRUE; return kFALSE; } //---- Directories ------------------------------------------------------------- //______________________________________________________________________________ int TUnixSystem::MakeDirectory(const char *name) { // Make a Unix file system directory. Returns 0 in case of success and // -1 if the directory could not be created. return UnixMakedir(name); } //______________________________________________________________________________ void *TUnixSystem::OpenDirectory(const char *name) { // Open a Unix file system directory. Returns 0 if directory does not exist. return UnixOpendir(name); } //______________________________________________________________________________ void TUnixSystem::FreeDirectory(void *dirp) { // Close a Unix file system directory. if (dirp) ::closedir((DIR*)dirp); } //______________________________________________________________________________ const char *TUnixSystem::GetDirEntry(void *dirp) { // Get next Unix file system directory entry. Returns 0 if no more entries. if (dirp) return UnixGetdirentry(dirp); return 0; } //______________________________________________________________________________ Bool_t TUnixSystem::ChangeDirectory(const char *path) { // Change directory. Returns kTRUE in case of success, kFALSE otherwise. Bool_t ret = (Bool_t) (::chdir(path) == 0); if (fWdpath != "") fWdpath = ""; // invalidate path cache return ret; } //______________________________________________________________________________ const char *TUnixSystem::WorkingDirectory() { // Return working directory. if (fWdpath != "") return fWdpath.Data(); static char cwd[kMAXPATHLEN]; if (::getcwd(cwd, kMAXPATHLEN) == 0) { fWdpath = "/"; Error("WorkingDirectory", "getcwd() failed"); } fWdpath = cwd; return fWdpath.Data(); } //______________________________________________________________________________ const char *TUnixSystem::HomeDirectory(const Char_t *userName) { // Return the user's home directory. return UnixHomedirectory(userName); } //______________________________________________________________________________ char *TUnixSystem::ConcatFileName(const char *dir, const char *name) { // Concatenate a directory and a file name. Returned string must be // deleted by user. if (name == 0 || strlen(name) <= 0 || strcmp(name, ".") == 0) return StrDup(dir); char buf[kMAXPATHLEN]; if (dir && (strcmp(dir, "/") != 0)) { if (dir[strlen(dir)-1] == '/') sprintf(buf, "%s%s", dir, name); else sprintf(buf, "%s/%s", dir, name); } else sprintf(buf, "/%s", name); return StrDup(buf); } //---- Paths & Files ----------------------------------------------------------- //______________________________________________________________________________ Bool_t TUnixSystem::AccessPathName(const char *path, EAccessMode mode) { // Returns FALSE if one can access a file using the specified access mode. // Mode is the same as for the Unix access(2) function. // Attention, bizarre convention of return value!! if (::access(path, mode) == 0) return kFALSE; fLastErrorString = GetError(); return kTRUE; } //______________________________________________________________________________ void TUnixSystem::Rename(const char *f, const char *t) { // Rename a file. ::rename(f, t); fLastErrorString = GetError(); } //______________________________________________________________________________ int TUnixSystem::GetPathInfo(const char *path, Long_t *id, Long_t *size, Long_t *flags, Long_t *modtime) { // Get info about a file: id, size, flags, modification time. // Id is (statbuf.st_dev << 24) + statbuf.st_ino // Size is the file size // Flags is file type: 0 is regular file, bit 0 set executable, // bit 1 set directory, bit 2 set special file // (socket, fifo, pipe, etc.) // Modtime is modification time. // The function returns 0 in case of success and 1 if the file could // not be stat'ed. return UnixFilestat(path, id, size, flags, modtime); } //______________________________________________________________________________ int TUnixSystem::GetFsInfo(const char *path, Long_t *id, Long_t *bsize, Long_t *blocks, Long_t *bfree) { // Get info about a file system: id, bsize, bfree, blocks. // Id is file system type (machine dependend, see statfs()) // Bsize is block size of file system // Blocks is total number of blocks in file system // Bfree is number of free blocks in file system // The function returns 0 in case of success and 1 if the file system could // not be stat'ed. return UnixFSstat(path, id, bsize, blocks, bfree); } //______________________________________________________________________________ int TUnixSystem::Link(const char *from, const char *to) { // Create a link from file1 to file2. Returns 0 when successful, // -1 in case of failure. return ::link(from, to); } //______________________________________________________________________________ int TUnixSystem::Symlink(const char *from, const char *to) { // Create a symlink from file1 to file2. Returns 0 when succesfull, // -1 in case of failure. #if defined(R__AIX) return ::symlink((char*)from, (char*)to); #else return ::symlink(from, to); #endif } //______________________________________________________________________________ int TUnixSystem::Unlink(const char *name) { // Unlink, i.e. remove, a file or directory. Returns 0 when succesfull, // -1 in case of failure. struct stat finfo; if (stat(name, &finfo) < 0) return -1; if (S_ISDIR(finfo.st_mode)) return ::rmdir(name); else return ::unlink(name); } //---- expand the metacharacters as in the shell ------------------------------- // expand the metacharacters as in the shell static const char #ifdef G__OLDEXPAND shellEscape = '\\', *shellStuff = "(){}<>\"'", #endif *shellMeta = "~*[]{}?$"; #ifndef G__OLDEXPAND //______________________________________________________________________________ Bool_t TUnixSystem::ExpandPathName(TString &path) { // Expand a pathname getting rid of special shell characters like ~.$, etc. // For Unix/Win32 compatibility use $(XXX) instead of $XXX when using // environment variables in a pathname. If compatibility is not an issue // you can use on Unix directly $XXX. const char *p, *patbuf = (const char *)path; // skip leading blanks while (*patbuf == ' ') patbuf++; // any shell meta characters ? for (p = patbuf; *p; p++) if (strchr(shellMeta, *p)) goto expand; return kFALSE; expand: // replace $(XXX) by $XXX path.ReplaceAll("$(","$"); path.ReplaceAll(")",""); path = ExpandFileName(path.Data()); return kFALSE; } #endif #ifdef G__OLDEXPAND //______________________________________________________________________________ Bool_t TUnixSystem::ExpandPathName(TString &patbuf0) { // Expand a pathname getting rid of special shell characters like ~.$, etc. // For Unix/Win32 compatibility use $(XXX) instead of $XXX when using // environment variables in a pathname. If compatibility is not an issue // you can use on Unix directly $XXX. const char *patbuf = (const char *)patbuf0; const char *hd, *p; char cmd[kMAXPATHLEN], stuffedPat[kMAXPATHLEN], name[70]; char *q; FILE *pf; int ch; // skip leading blanks while (*patbuf == ' ') patbuf++; // any shell meta characters ? for (p = patbuf; *p; p++) if (strchr(shellMeta, *p)) goto needshell; return kFALSE; needshell: // replace $(XXX) by $XXX patbuf0.ReplaceAll("$(","$"); patbuf0.ReplaceAll(")",""); // escape shell quote characters EscChar(patbuf, stuffedPat, sizeof(stuffedPat), (char*)shellStuff, shellEscape); #ifdef R__HPUX strcpy(cmd, "/bin/echo "); #else strcpy(cmd, "echo "); #endif // emulate csh -> popen executes sh if (stuffedPat[0] == '~') { if (stuffedPat[1] != '0' && stuffedPat[1] != '/') { // extract user name for (p = &stuffedPat[1], q = name; *p && *p !='/';) *q++ = *p++; *q = '0'; hd = UnixHomedirectory(name); if (hd == 0) strcat(cmd, stuffedPat); else { strcat(cmd, hd); strcat(cmd, p); } } else { hd = UnixHomedirectory(0); if (hd == 0) { fLastErrorString = GetError(); return kTRUE; } strcat(cmd, hd); strcat(cmd, &stuffedPat[1]); } } else strcat(cmd, stuffedPat); if ((pf = ::popen(&cmd[0], "r")) == NULL) { fLastErrorString = GetError(); return kTRUE; } // read first argument patbuf0 = ""; int cnt = 0; #if defined(R__ALPHA) || defined(R__AIX) again: #endif for (ch = fgetc(pf); ch != EOF && ch != ' ' && ch != '\n'; ch = fgetc(pf)) { patbuf0.Append(ch); cnt++; } #if defined(R__ALPHA) || defined(R__AIX) // Work around bug timing problem due to delay in forking a large program if (cnt == 0 && ch == EOF) goto again; #endif // skip rest of pipe while (ch != EOF) { ch = fgetc(pf); if (ch == ' ' || ch == 't') { fLastErrorString = "expression ambigous"; ::pclose(pf); return kTRUE; } } ::pclose(pf); return kFALSE; } #endif //______________________________________________________________________________ char *TUnixSystem::ExpandPathName(const char *path) { // Expand a pathname getting rid of special shell characaters like ~.$, etc. // For Unix/Win32 compatibility use $(XXX) instead of $XXX when using // environment variables in a pathname. If compatibility is not an issue // you can use on Unix directly $XXX. The user must delete returned string. TString patbuf = path; if (ExpandPathName(patbuf)) return 0; return StrDup(patbuf.Data()); } //______________________________________________________________________________ int TUnixSystem::Umask(Int_t mask) { // Set the process file creation mode mask. return ::umask(mask); } //______________________________________________________________________________ int TUnixSystem::Utime(const char *file, Long_t modtime, Long_t actime) { // Set a files modification and access times. If actime = 0 it will be // set to the modtime. Returns 0 on success and -1 in case of error. if (!actime) actime = modtime; struct utimbuf t; t.actime = (time_t)actime; t.modtime = (time_t)modtime; return ::utime(file, &t); } //______________________________________________________________________________ char *TUnixSystem::Which(const char *search, const char *wfil, EAccessMode mode) { // Find location of file "wfil" in a search path. // The search path is specified as a : separated list of directories. // User must delete returned string. Returns 0 in case file is not found. char name[kMAXPATHLEN], file[kMAXPATHLEN]; const char *ptr; char *next, *exname; exname = gSystem->ExpandPathName(wfil); if (exname) strcpy(file, exname); else file[0] = 0; delete [] exname; if (file[0] == '/') { exname = StrDup(file); if (exname && access(exname, mode) == 0) { if (gEnv->GetValue("Root.ShowPath", 0)) Printf("Which: %s = %s", wfil, exname); return exname; } delete [] exname; if (gEnv->GetValue("Root.ShowPath", 0)) Printf("Which: %s = <not found>", wfil); return 0; } if (search == 0) search = "."; for (ptr = search; *ptr;) { for (next = name; *ptr && *ptr != ':'; ) *next++ = *ptr++; *next = '0'; if (name[0] != '/' && name[0] != '$' && name[0] != '~') { char tmp[kMAXPATHLEN]; strcpy(tmp, name); strcpy(name, gSystem->WorkingDirectory()); strcat(name, "/"); strcat(name, tmp); } if (*(name + strlen(name) - 1) != '/') strcat(name, "/"); strcat(name, file); exname = gSystem->ExpandPathName(name); if (exname && access(exname, mode) == 0) { if (gEnv->GetValue("Root.ShowPath", 0)) Printf("Which: %s = %s", wfil, exname); return exname; } delete [] exname; if (*ptr) ptr++; } if (gEnv->GetValue("Root.ShowPath", 0)) Printf("Which: %s = <not found>", wfil); return 0; } //---- environment manipulation ------------------------------------------------ //______________________________________________________________________________ void TUnixSystem::Setenv(const char *name, const char *value) { // Set environment variable. The string passed will be owned by // the environment and can not be reused till a "name" is set // again. The solution below will lose the space for the string // in that case, but if this functions is not called thousands // of times that should not be a problem. char *s = new char [strlen(name)+strlen(value) + 2]; sprintf(s, "%s=%s", name, value); ::putenv(s); } //______________________________________________________________________________ const char *TUnixSystem::Getenv(const char *name) { // Get environment variable. return ::getenv(name); } //---- Processes --------------------------------------------------------------- //______________________________________________________________________________ int TUnixSystem::Exec(const char *shellcmd) { // Execute a command. return ::system(shellcmd); } //______________________________________________________________________________ FILE *TUnixSystem::OpenPipe(const char *command, const char *mode) { // Open a pipe. return ::popen(command, mode); } //______________________________________________________________________________ int TUnixSystem::ClosePipe(FILE *pipe) { // Close the pipe. return ::pclose(pipe); } //______________________________________________________________________________ int TUnixSystem::GetPid() { // Get process id. return ::getpid(); } //______________________________________________________________________________ void TUnixSystem::Exit(int code, Bool_t mode) { // Exit the application. if (mode) ::exit(code); else ::_exit(code); } //______________________________________________________________________________ void TUnixSystem::Abort(int) { // Abort the application. ::abort(); } //______________________________________________________________________________ void TUnixSystem::StackTrace() { // Print a stack trace. #if defined(R__HPUX) && !defined(R__GNU) Printf(""); U_STACK_TRACE(); Printf(""); #endif } //---- System Logging ---------------------------------------------------------- //______________________________________________________________________________