// @(#)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 ----------------------------------------------------------
//______________________________________________________________________________