///////////////////////////////////////////////////////////////////////////// // Name: src/unix/utilsunx.cpp // Purpose: generic Unix implementation of many wx functions // Author: Vadim Zeitlin // Id: $Id: utilsunx.cpp 49239 2007-10-19 03:10:31Z DE $ // Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // ============================================================================ // declarations // ============================================================================ // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- // for compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #include "wx/utils.h" #ifndef WX_PRECOMP #include "wx/string.h" #include "wx/intl.h" #include "wx/log.h" #include "wx/app.h" #endif #include "wx/apptrait.h" #include "wx/process.h" #include "wx/thread.h" #include "wx/wfstream.h" #include "wx/unix/execute.h" #include "wx/unix/private.h" #include #ifdef HAVE_SYS_SELECT_H # include #endif #define HAS_PIPE_INPUT_STREAM (wxUSE_STREAMS && wxUSE_FILE) #if HAS_PIPE_INPUT_STREAM // define this to let wxexec.cpp know that we know what we're doing #define _WX_USED_BY_WXEXECUTE_ #include "../common/execcmn.cpp" #endif // HAS_PIPE_INPUT_STREAM #if wxUSE_BASE #if defined(__MWERKS__) && defined(__MACH__) #ifndef WXWIN_OS_DESCRIPTION #define WXWIN_OS_DESCRIPTION "MacOS X" #endif #ifndef HAVE_NANOSLEEP #define HAVE_NANOSLEEP #endif #ifndef HAVE_UNAME #define HAVE_UNAME #endif // our configure test believes we can use sigaction() if the function is // available but Metrowekrs with MSL run-time does have the function but // doesn't have sigaction struct so finally we can't use it... #ifdef __MSL__ #undef wxUSE_ON_FATAL_EXCEPTION #define wxUSE_ON_FATAL_EXCEPTION 0 #endif #endif // not only the statfs syscall is called differently depending on platform, but // one of its incarnations, statvfs(), takes different arguments under // different platforms and even different versions of the same system (Solaris // 7 and 8): if you want to test for this, don't forget that the problems only // appear if the large files support is enabled #ifdef HAVE_STATFS #ifdef __BSD__ #include #include #else // !__BSD__ #include #endif // __BSD__/!__BSD__ #define wxStatfs statfs #ifndef HAVE_STATFS_DECL // some systems lack statfs() prototype in the system headers (AIX 4) extern "C" int statfs(const char *path, struct statfs *buf); #endif #endif // HAVE_STATFS #ifdef HAVE_STATVFS #include #define wxStatfs statvfs #endif // HAVE_STATVFS #if defined(HAVE_STATFS) || defined(HAVE_STATVFS) // WX_STATFS_T is detected by configure #define wxStatfs_t WX_STATFS_T #endif // SGI signal.h defines signal handler arguments differently depending on // whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it #if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS) #define _LANGUAGE_C_PLUS_PLUS 1 #endif // SGI hack #include #include #include #include #include #include #include #include #include #include #include // for O_WRONLY and friends #include // nanosleep() and/or usleep() #include // isspace() #include // needed for FD_SETSIZE #ifdef HAVE_UNAME #include // for uname() #endif // HAVE_UNAME // Used by wxGetFreeMemory(). #ifdef __SGI__ #include #include // for SAGET and MINFO structures #endif // ---------------------------------------------------------------------------- // conditional compilation // ---------------------------------------------------------------------------- // many versions of Unices have this function, but it is not defined in system // headers - please add your system here if it is the case for your OS. // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this. #if !defined(HAVE_USLEEP) && \ ((defined(__SUN__) && !defined(__SunOs_5_6) && \ !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \ defined(__osf__) || defined(__EMX__)) extern "C" { #ifdef __EMX__ /* I copied this from the XFree86 diffs. AV. */ #define INCL_DOSPROCESS #include inline void usleep(unsigned long delay) { DosSleep(delay ? (delay/1000l) : 1l); } #else // Unix int usleep(unsigned int usec); #endif // __EMX__/Unix }; #define HAVE_USLEEP 1 #endif // Unices without usleep() // ============================================================================ // implementation // ============================================================================ // ---------------------------------------------------------------------------- // sleeping // ---------------------------------------------------------------------------- void wxSleep(int nSecs) { sleep(nSecs); } void wxMicroSleep(unsigned long microseconds) { #if defined(HAVE_NANOSLEEP) timespec tmReq; tmReq.tv_sec = (time_t)(microseconds / 1000000); tmReq.tv_nsec = (microseconds % 1000000) * 1000; // we're not interested in remaining time nor in return value (void)nanosleep(&tmReq, (timespec *)NULL); #elif defined(HAVE_USLEEP) // uncomment this if you feel brave or if you are sure that your version // of Solaris has a safe usleep() function but please notice that usleep() // is known to lead to crashes in MT programs in Solaris 2.[67] and is not // documented as MT-Safe #if defined(__SUN__) && wxUSE_THREADS #error "usleep() cannot be used in MT programs under Solaris." #endif // Sun usleep(microseconds); #elif defined(HAVE_SLEEP) // under BeOS sleep() takes seconds (what about other platforms, if any?) sleep(microseconds * 1000000); #else // !sleep function #error "usleep() or nanosleep() function required for wxMicroSleep" #endif // sleep function } void wxMilliSleep(unsigned long milliseconds) { wxMicroSleep(milliseconds*1000); } // ---------------------------------------------------------------------------- // process management // ---------------------------------------------------------------------------- int wxKill(long pid, wxSignal sig, wxKillError *rc, int flags) { int err = kill((pid_t) (flags & wxKILL_CHILDREN) ? -pid : pid, (int)sig); if ( rc ) { switch ( err ? errno : 0 ) { case 0: *rc = wxKILL_OK; break; case EINVAL: *rc = wxKILL_BAD_SIGNAL; break; case EPERM: *rc = wxKILL_ACCESS_DENIED; break; case ESRCH: *rc = wxKILL_NO_PROCESS; break; default: // this goes against Unix98 docs so log it wxLogDebug(_T("unexpected kill(2) return value %d"), err); // something else... *rc = wxKILL_ERROR; } } return err; } #define WXEXECUTE_NARGS 127 #if defined(__DARWIN__) long wxMacExecute(wxChar **argv, int flags, wxProcess *process); #endif long wxExecute( const wxString& command, int flags, wxProcess *process ) { wxCHECK_MSG( !command.empty(), 0, wxT("can't exec empty command") ); wxLogTrace(wxT("exec"), wxT("Executing \"%s\""), command.c_str()); #if wxUSE_THREADS // fork() doesn't mix well with POSIX threads: on many systems the program // deadlocks or crashes for some reason. Probably our code is buggy and // doesn't do something which must be done to allow this to work, but I // don't know what yet, so for now just warn the user (this is the least we // can do) about it wxASSERT_MSG( wxThread::IsMain(), _T("wxExecute() can be called only from the main thread") ); #endif // wxUSE_THREADS int argc = 0; wxChar *argv[WXEXECUTE_NARGS]; wxString argument; const wxChar *cptr = command.c_str(); wxChar quotechar = wxT('\0'); // is arg quoted? bool escaped = false; // split the command line in arguments do { argument = wxEmptyString; quotechar = wxT('\0'); // eat leading whitespace: while ( wxIsspace(*cptr) ) cptr++; if ( *cptr == wxT('\'') || *cptr == wxT('"') ) quotechar = *cptr++; do { if ( *cptr == wxT('\\') && ! escaped ) { escaped = true; cptr++; continue; } // all other characters: argument += *cptr++; escaped = false; // have we reached the end of the argument? if ( (*cptr == quotechar && ! escaped) || (quotechar == wxT('\0') && wxIsspace(*cptr)) || *cptr == wxT('\0') ) { wxASSERT_MSG( argc < WXEXECUTE_NARGS, wxT("too many arguments in wxExecute") ); argv[argc] = new wxChar[argument.length() + 1]; wxStrcpy(argv[argc], argument.c_str()); argc++; // if not at end of buffer, swallow last character: if(*cptr) cptr++; break; // done with this one, start over } } while(*cptr); } while(*cptr); argv[argc] = NULL; long lRc; #if defined(__DARWIN__) // wxMacExecute only executes app bundles. // It returns an error code if the target is not an app bundle, thus falling // through to the regular wxExecute for non app bundles. lRc = wxMacExecute(argv, flags, process); if( lRc != ((flags & wxEXEC_SYNC) ? -1 : 0)) return lRc; #endif // do execute the command lRc = wxExecute(argv, flags, process); // clean up argc = 0; while( argv[argc] ) delete [] argv[argc++]; return lRc; } // ---------------------------------------------------------------------------- // wxShell // ---------------------------------------------------------------------------- static wxString wxMakeShellCommand(const wxString& command) { wxString cmd; if ( !command ) { // just an interactive shell cmd = _T("xterm"); } else { // execute command in a shell cmd << _T("/bin/sh -c '") << command << _T('\''); } return cmd; } bool wxShell(const wxString& command) { return wxExecute(wxMakeShellCommand(command), wxEXEC_SYNC) == 0; } bool wxShell(const wxString& command, wxArrayString& output) { wxCHECK_MSG( !command.empty(), false, _T("can't exec shell non interactively") ); return wxExecute(wxMakeShellCommand(command), output); } // Shutdown or reboot the PC bool wxShutdown(wxShutdownFlags wFlags) { wxChar level; switch ( wFlags ) { case wxSHUTDOWN_POWEROFF: level = _T('0'); break; case wxSHUTDOWN_REBOOT: level = _T('6'); break; default: wxFAIL_MSG( _T("unknown wxShutdown() flag") ); return false; } return system(wxString::Format(_T("init %c"), level).mb_str()) == 0; } // ---------------------------------------------------------------------------- // wxStream classes to support IO redirection in wxExecute // ---------------------------------------------------------------------------- #if HAS_PIPE_INPUT_STREAM bool wxPipeInputStream::CanRead() const { if ( m_lasterror == wxSTREAM_EOF ) return false; // check if there is any input available struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; const int fd = m_file->fd(); fd_set readfds; wxFD_ZERO(&readfds); wxFD_SET(fd, &readfds); switch ( select(fd + 1, &readfds, NULL, NULL, &tv) ) { case -1: wxLogSysError(_("Impossible to get child process input")); // fall through case 0: return false; default: wxFAIL_MSG(_T("unexpected select() return value")); // still fall through case 1: // input available -- or maybe not, as select() returns 1 when a // read() will complete without delay, but it could still not read // anything return !Eof(); } } #endif // HAS_PIPE_INPUT_STREAM // ---------------------------------------------------------------------------- // wxExecute: the real worker function // ---------------------------------------------------------------------------- long wxExecute(wxChar **argv, int flags, wxProcess *process) { // for the sync execution, we return -1 to indicate failure, but for async // case we return 0 which is never a valid PID // // we define this as a macro, not a variable, to avoid compiler warnings // about "ERROR_RETURN_CODE value may be clobbered by fork()" #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0) wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") ); #if wxUSE_UNICODE int mb_argc = 0; char *mb_argv[WXEXECUTE_NARGS]; while (argv[mb_argc]) { wxWX2MBbuf mb_arg = wxSafeConvertWX2MB(argv[mb_argc]); mb_argv[mb_argc] = strdup(mb_arg); mb_argc++; } mb_argv[mb_argc] = (char *) NULL; // this macro will free memory we used above #define ARGS_CLEANUP \ for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \ free(mb_argv[mb_argc]) #else // ANSI // no need for cleanup #define ARGS_CLEANUP wxChar **mb_argv = argv; #endif // Unicode/ANSI // we want this function to work even if there is no wxApp so ensure that // we have a valid traits pointer wxConsoleAppTraits traitsConsole; wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; if ( !traits ) traits = &traitsConsole; // this struct contains all information which we pass to and from // wxAppTraits methods wxExecuteData execData; execData.flags = flags; execData.process = process; // create pipes if ( !traits->CreateEndProcessPipe(execData) ) { wxLogError( _("Failed to execute '%s'\n"), *argv ); ARGS_CLEANUP; return ERROR_RETURN_CODE; } // pipes for inter process communication wxPipe pipeIn, // stdin pipeOut, // stdout pipeErr; // stderr if ( process && process->IsRedirected() ) { if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() ) { wxLogError( _("Failed to execute '%s'\n"), *argv ); ARGS_CLEANUP; return ERROR_RETURN_CODE; } } // fork the process // // NB: do *not* use vfork() here, it completely breaks this code for some // reason under Solaris (and maybe others, although not under Linux) // But on OpenVMS we do not have fork so we have to use vfork and // cross our fingers that it works. #ifdef __VMS pid_t pid = vfork(); #else pid_t pid = fork(); #endif if ( pid == -1 ) // error? { wxLogSysError( _("Fork failed") ); ARGS_CLEANUP; return ERROR_RETURN_CODE; } else if ( pid == 0 ) // we're in child { // These lines close the open file descriptors to to avoid any // input/output which might block the process or irritate the user. If // one wants proper IO for the subprocess, the right thing to do is to // start an xterm executing it. if ( !(flags & wxEXEC_SYNC) ) { // FD_SETSIZE is unsigned under BSD, signed under other platforms // so we need a cast to avoid warnings on all platforms for ( int fd = 0; fd < (int)FD_SETSIZE; fd++ ) { if ( fd == pipeIn[wxPipe::Read] || fd == pipeOut[wxPipe::Write] || fd == pipeErr[wxPipe::Write] || traits->IsWriteFDOfEndProcessPipe(execData, fd) ) { // don't close this one, we still need it continue; } // leave stderr opened too, it won't do any harm if ( fd != STDERR_FILENO ) close(fd); } } #if !defined(__VMS) && !defined(__EMX__) if ( flags & wxEXEC_MAKE_GROUP_LEADER ) { // Set process group to child process' pid. Then killing -pid // of the parent will kill the process and all of its children. setsid(); } #endif // !__VMS // reading side can be safely closed but we should keep the write one // opened traits->DetachWriteFDOfEndProcessPipe(execData); // redirect stdin, stdout and stderr if ( pipeIn.IsOk() ) { if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 || dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 || dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 ) { wxLogSysError(_("Failed to redirect child process input/output")); } pipeIn.Close(); pipeOut.Close(); pipeErr.Close(); } execvp (*mb_argv, mb_argv); fprintf(stderr, "execvp("); // CS changed ppc to ppc_ as ppc is not available under mac os CW Mach-O for ( char **ppc_ = mb_argv; *ppc_; ppc_++ ) fprintf(stderr, "%s%s", ppc_ == mb_argv ? "" : ", ", *ppc_); fprintf(stderr, ") failed with error %d!\n", errno); // there is no return after successful exec() _exit(-1); // some compilers complain about missing return - of course, they // should know that exit() doesn't return but what else can we do if // they don't? // // and, sure enough, other compilers complain about unreachable code // after exit() call, so we can just always have return here... #if defined(__VMS) || defined(__INTEL_COMPILER) return 0; #endif } else // we're in parent { ARGS_CLEANUP; // save it for WaitForChild() use execData.pid = pid; // prepare for IO redirection #if HAS_PIPE_INPUT_STREAM // the input buffer bufOut is connected to stdout, this is why it is // called bufOut and not bufIn wxStreamTempInputBuffer bufOut, bufErr; #endif // HAS_PIPE_INPUT_STREAM if ( process && process->IsRedirected() ) { #if HAS_PIPE_INPUT_STREAM wxOutputStream *inStream = new wxFileOutputStream(pipeIn.Detach(wxPipe::Write)); wxPipeInputStream *outStream = new wxPipeInputStream(pipeOut.Detach(wxPipe::Read)); wxPipeInputStream *errStream = new wxPipeInputStream(pipeErr.Detach(wxPipe::Read)); process->SetPipeStreams(outStream, inStream, errStream); bufOut.Init(outStream); bufErr.Init(errStream); execData.bufOut = &bufOut; execData.bufErr = &bufErr; #endif // HAS_PIPE_INPUT_STREAM } if ( pipeIn.IsOk() ) { pipeIn.Close(); pipeOut.Close(); pipeErr.Close(); } return traits->WaitForChild(execData); } #if !defined(__VMS) && !defined(__INTEL_COMPILER) return ERROR_RETURN_CODE; #endif } #undef ERROR_RETURN_CODE #undef ARGS_CLEANUP // ---------------------------------------------------------------------------- // file and directory functions // ---------------------------------------------------------------------------- const wxChar* wxGetHomeDir( wxString *home ) { *home = wxGetUserHome( wxEmptyString ); wxString tmp; if ( home->empty() ) *home = wxT("/"); #ifdef __VMS tmp = *home; if ( tmp.Last() != wxT(']')) if ( tmp.Last() != wxT('/')) *home << wxT('/'); #endif return home->c_str(); } #if wxUSE_UNICODE const wxMB2WXbuf wxGetUserHome( const wxString &user ) #else // just for binary compatibility -- there is no 'const' here char *wxGetUserHome( const wxString &user ) #endif { struct passwd *who = (struct passwd *) NULL; if ( !user ) { wxChar *ptr; if ((ptr = wxGetenv(wxT("HOME"))) != NULL) { #if wxUSE_UNICODE wxWCharBuffer buffer( ptr ); return buffer; #else return ptr; #endif } if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL) { who = getpwnam(wxSafeConvertWX2MB(ptr)); } // We now make sure the the user exists! if (who == NULL) { who = getpwuid(getuid()); } } else { who = getpwnam (user.mb_str()); } return wxSafeConvertMB2WX(who ? who->pw_dir : 0); } // ---------------------------------------------------------------------------- // network and user id routines // ---------------------------------------------------------------------------- // private utility function which returns output of the given command, removing // the trailing newline static wxString wxGetCommandOutput(const wxString &cmd) { FILE *f = popen(cmd.ToAscii(), "r"); if ( !f ) { wxLogSysError(_T("Executing \"%s\" failed"), cmd.c_str()); return wxEmptyString; } wxString s; char buf[256]; while ( !feof(f) ) { if ( !fgets(buf, sizeof(buf), f) ) break; s += wxString::FromAscii(buf); } pclose(f); if ( !s.empty() && s.Last() == _T('\n') ) s.RemoveLast(); return s; } // retrieve either the hostname or FQDN depending on platform (caller must // check whether it's one or the other, this is why this function is for // private use only) static bool wxGetHostNameInternal(wxChar *buf, int sz) { wxCHECK_MSG( buf, false, wxT("NULL pointer in wxGetHostNameInternal") ); *buf = wxT('\0'); // we're using uname() which is POSIX instead of less standard sysinfo() #if defined(HAVE_UNAME) struct utsname uts; bool ok = uname(&uts) != -1; if ( ok ) { wxStrncpy(buf, wxSafeConvertMB2WX(uts.nodename), sz - 1); buf[sz] = wxT('\0'); } #elif defined(HAVE_GETHOSTNAME) char cbuf[sz]; bool ok = gethostname(cbuf, sz) != -1; if ( ok ) { wxStrncpy(buf, wxSafeConvertMB2WX(cbuf), sz - 1); buf[sz] = wxT('\0'); } #else // no uname, no gethostname wxFAIL_MSG(wxT("don't know host name for this machine")); bool ok = false; #endif // uname/gethostname if ( !ok ) { wxLogSysError(_("Cannot get the hostname")); } return ok; } bool wxGetHostName(wxChar *buf, int sz) { bool ok = wxGetHostNameInternal(buf, sz); if ( ok ) { // BSD systems return the FQDN, we only want the hostname, so extract // it (we consider that dots are domain separators) wxChar *dot = wxStrchr(buf, wxT('.')); if ( dot ) { // nuke it *dot = wxT('\0'); } } return ok; } bool wxGetFullHostName(wxChar *buf, int sz) { bool ok = wxGetHostNameInternal(buf, sz); if ( ok ) { if ( !wxStrchr(buf, wxT('.')) ) { struct hostent *host = gethostbyname(wxSafeConvertWX2MB(buf)); if ( !host ) { wxLogSysError(_("Cannot get the official hostname")); ok = false; } else { // the canonical name wxStrncpy(buf, wxSafeConvertMB2WX(host->h_name), sz); } } //else: it's already a FQDN (BSD behaves this way) } return ok; } bool wxGetUserId(wxChar *buf, int sz) { struct passwd *who; *buf = wxT('\0'); if ((who = getpwuid(getuid ())) != NULL) { wxStrncpy (buf, wxSafeConvertMB2WX(who->pw_name), sz - 1); return true; } return false; } bool wxGetUserName(wxChar *buf, int sz) { #ifdef HAVE_PW_GECOS struct passwd *who; *buf = wxT('\0'); if ((who = getpwuid (getuid ())) != NULL) { char *comma = strchr(who->pw_gecos, ','); if (comma) *comma = '\0'; // cut off non-name comment fields wxStrncpy (buf, wxSafeConvertMB2WX(who->pw_gecos), sz - 1); return true; } return false; #else // !HAVE_PW_GECOS return wxGetUserId(buf, sz); #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS } bool wxIsPlatform64Bit() { const wxString machine = wxGetCommandOutput(wxT("uname -m")); // the test for "64" is obviously not 100% reliable but seems to work fine // in practice return machine.Contains(wxT("64")) || machine.Contains(wxT("alpha")); } // these functions are in mac/utils.cpp for wxMac #ifndef __WXMAC__ wxOperatingSystemId wxGetOsVersion(int *verMaj, int *verMin) { // get OS version int major, minor; wxString release = wxGetCommandOutput(wxT("uname -r")); if ( !release.empty() && wxSscanf(release, wxT("%d.%d"), &major, &minor) != 2 ) { // unrecognized uname string format major = minor = -1; } if ( verMaj ) *verMaj = major; if ( verMin ) *verMin = minor; // try to understand which OS are we running wxString kernel = wxGetCommandOutput(wxT("uname -s")); if ( kernel.empty() ) kernel = wxGetCommandOutput(wxT("uname -o")); if ( kernel.empty() ) return wxOS_UNKNOWN; return wxPlatformInfo::GetOperatingSystemId(kernel); } wxString wxGetOsDescription() { return wxGetCommandOutput(wxT("uname -s -r -m")); } #endif // !__WXMAC__ unsigned long wxGetProcessId() { return (unsigned long)getpid(); } wxMemorySize wxGetFreeMemory() { #if defined(__LINUX__) // get it from /proc/meminfo FILE *fp = fopen("/proc/meminfo", "r"); if ( fp ) { long memFree = -1; char buf[1024]; if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) ) { // /proc/meminfo changed its format in kernel 2.6 if ( wxPlatformInfo().CheckOSVersion(2, 6) ) { unsigned long cached, buffers; sscanf(buf, "MemFree: %ld", &memFree); fgets(buf, WXSIZEOF(buf), fp); sscanf(buf, "Buffers: %lu", &buffers); fgets(buf, WXSIZEOF(buf), fp); sscanf(buf, "Cached: %lu", &cached); // add to "MemFree" also the "Buffers" and "Cached" values as // free(1) does as otherwise the value never makes sense: for // kernel 2.6 it's always almost 0 memFree += buffers + cached; // values here are always expressed in kB and we want bytes memFree *= 1024; } else // Linux 2.4 (or < 2.6, anyhow) { long memTotal, memUsed; sscanf(buf, "Mem: %ld %ld %ld", &memTotal, &memUsed, &memFree); } } fclose(fp); return (wxMemorySize)memFree; } #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES) return (wxMemorySize)(sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE)); #elif defined(__SGI__) struct rminfo realmem; if ( sysmp(MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0 ) return ((wxMemorySize)realmem.physmem * sysconf(_SC_PAGESIZE)); //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably #endif // can't find it out return -1; } bool wxGetDiskSpace(const wxString& path, wxDiskspaceSize_t *pTotal, wxDiskspaceSize_t *pFree) { #if defined(HAVE_STATFS) || defined(HAVE_STATVFS) // the case to "char *" is needed for AIX 4.3 wxStatfs_t fs; if ( wxStatfs((char *)(const char*)path.fn_str(), &fs) != 0 ) { wxLogSysError( wxT("Failed to get file system statistics") ); return false; } // under Solaris we also have to use f_frsize field instead of f_bsize // which is in general a multiple of f_frsize #ifdef HAVE_STATVFS wxDiskspaceSize_t blockSize = fs.f_frsize; #else // HAVE_STATFS wxDiskspaceSize_t blockSize = fs.f_bsize; #endif // HAVE_STATVFS/HAVE_STATFS if ( pTotal ) { *pTotal = wxDiskspaceSize_t(fs.f_blocks) * blockSize; } if ( pFree ) { *pFree = wxDiskspaceSize_t(fs.f_bavail) * blockSize; } return true; #else // !HAVE_STATFS && !HAVE_STATVFS return false; #endif // HAVE_STATFS } // ---------------------------------------------------------------------------- // env vars // ---------------------------------------------------------------------------- bool wxGetEnv(const wxString& var, wxString *value) { // wxGetenv is defined as getenv() wxChar *p = wxGetenv(var); if ( !p ) return false; if ( value ) { *value = p; } return true; } bool wxSetEnv(const wxString& variable, const wxChar *value) { #if defined(HAVE_SETENV) if ( !value ) { #ifdef HAVE_UNSETENV // don't test unsetenv() return value: it's void on some systems (at // least Darwin) unsetenv(variable.mb_str()); return true; #else value = _T(""); // we can't pass NULL to setenv() #endif } return setenv(variable.mb_str(), wxString(value).mb_str(), 1 /* overwrite */) == 0; #elif defined(HAVE_PUTENV) wxString s = variable; if ( value ) s << _T('=') << value; // transform to ANSI const wxWX2MBbuf p = s.mb_str(); // the string will be free()d by libc char *buf = (char *)malloc(strlen(p) + 1); strcpy(buf, p); return putenv(buf) == 0; #else // no way to set an env var return false; #endif } // ---------------------------------------------------------------------------- // signal handling // ---------------------------------------------------------------------------- #if wxUSE_ON_FATAL_EXCEPTION #include extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER) { if ( wxTheApp ) { // give the user a chance to do something special about this wxTheApp->OnFatalException(); } abort(); } bool wxHandleFatalExceptions(bool doit) { // old sig handlers static bool s_savedHandlers = false; static struct sigaction s_handlerFPE, s_handlerILL, s_handlerBUS, s_handlerSEGV; bool ok = true; if ( doit && !s_savedHandlers ) { // install the signal handler struct sigaction act; // some systems extend it with non std fields, so zero everything memset(&act, 0, sizeof(act)); act.sa_handler = wxFatalSignalHandler; sigemptyset(&act.sa_mask); act.sa_flags = 0; ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0; ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0; ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0; ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0; if ( !ok ) { wxLogDebug(_T("Failed to install our signal handler.")); } s_savedHandlers = true; } else if ( s_savedHandlers ) { // uninstall the signal handler ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0; ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0; ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0; ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0; if ( !ok ) { wxLogDebug(_T("Failed to uninstall our signal handler.")); } s_savedHandlers = false; } //else: nothing to do return ok; } #endif // wxUSE_ON_FATAL_EXCEPTION #endif // wxUSE_BASE #if wxUSE_GUI #ifdef __DARWIN__ #include #endif // ---------------------------------------------------------------------------- // wxExecute support // ---------------------------------------------------------------------------- /* NOTE: The original code shipped in 2.8 used __DARWIN__ && __WXMAC__ to wrap the wxGUIAppTraits differences but __DARWIN__ && (__WXMAC__ || __WXCOCOA__) to decide whether to call wxAddProcessCallbackForPid instead of wxAddProcessCallback. This define normalizes things so the two match. Since wxCocoa was already creating the pipes in its wxGUIAppTraits I decided to leave that as is and implement wxAddProcessCallback in the utilsexec_cf.cpp file. I didn't see a reason to wrap that in a __WXCOCOA__ check since it's valid for both wxMac and wxCocoa. Since the existing code is working for wxMac I've left it as is although do note that the old task_for_pid method still used on PPC machines is expected to fail in Leopard PPC and theoretically already fails if you run your PPC app under Rosetta. You thus have two choices if you find end process detect broken: 1) Change the define below such that the new code is used for wxMac. This is theoretically ABI compatible since the old code still remains in utilsexec_cf.cpp it's just no longer used by this code. 2) Change the USE_POLLING define in utilsexc_cf.cpp to 1 unconditionally This is theoretically not compatible since it removes the wxMAC_MachPortEndProcessDetect helper function. Though in practice this shouldn't be a problem since it wasn't prototyped anywhere. */ #define USE_OLD_DARWIN_END_PROCESS_DETECT (defined(__DARWIN__) && defined(__WXMAC__)) // #define USE_OLD_DARWIN_END_PROCESS_DETECT 0 // wxMac doesn't use the same process end detection mechanisms so we don't // need wxExecute-related helpers for it. #if !USE_OLD_DARWIN_END_PROCESS_DETECT bool wxGUIAppTraits::CreateEndProcessPipe(wxExecuteData& execData) { return execData.pipeEndProcDetect.Create(); } bool wxGUIAppTraits::IsWriteFDOfEndProcessPipe(wxExecuteData& execData, int fd) { return fd == (execData.pipeEndProcDetect)[wxPipe::Write]; } void wxGUIAppTraits::DetachWriteFDOfEndProcessPipe(wxExecuteData& execData) { execData.pipeEndProcDetect.Detach(wxPipe::Write); execData.pipeEndProcDetect.Close(); } #else // !Darwin bool wxGUIAppTraits::CreateEndProcessPipe(wxExecuteData& WXUNUSED(execData)) { return true; } bool wxGUIAppTraits::IsWriteFDOfEndProcessPipe(wxExecuteData& WXUNUSED(execData), int WXUNUSED(fd)) { return false; } void wxGUIAppTraits::DetachWriteFDOfEndProcessPipe(wxExecuteData& WXUNUSED(execData)) { // nothing to do here, we don't use the pipe } #endif // !Darwin/Darwin int wxGUIAppTraits::WaitForChild(wxExecuteData& execData) { wxEndProcessData *endProcData = new wxEndProcessData; const int flags = execData.flags; // wxAddProcessCallback is now (with DARWIN) allowed to call the // callback function directly if the process terminates before // the callback can be added to the run loop. Set up the endProcData. if ( flags & wxEXEC_SYNC ) { // we may have process for capturing the program output, but it's // not used in wxEndProcessData in the case of sync execution endProcData->process = NULL; // sync execution: indicate it by negating the pid endProcData->pid = -execData.pid; } else { // async execution, nothing special to do -- caller will be // notified about the process termination if process != NULL, endProcData // will be deleted in GTK_EndProcessDetector endProcData->process = execData.process; endProcData->pid = execData.pid; } #if USE_OLD_DARWIN_END_PROCESS_DETECT endProcData->tag = wxAddProcessCallbackForPid(endProcData, execData.pid); #else endProcData->tag = wxAddProcessCallback ( endProcData, execData.pipeEndProcDetect.Detach(wxPipe::Read) ); execData.pipeEndProcDetect.Close(); #endif // USE_OLD_DARWIN_END_PROCESS_DETECT if ( flags & wxEXEC_SYNC ) { wxBusyCursor bc; wxWindowDisabler *wd = flags & wxEXEC_NODISABLE ? NULL : new wxWindowDisabler; // endProcData->pid will be set to 0 from GTK_EndProcessDetector when the // process terminates while ( endProcData->pid != 0 ) { bool idle = true; #if HAS_PIPE_INPUT_STREAM if ( execData.bufOut ) { execData.bufOut->Update(); idle = false; } if ( execData.bufErr ) { execData.bufErr->Update(); idle = false; } #endif // HAS_PIPE_INPUT_STREAM // don't consume 100% of the CPU while we're sitting in this // loop if ( idle ) wxMilliSleep(1); // give GTK+ a chance to call GTK_EndProcessDetector here and // also repaint the GUI wxYield(); } int exitcode = endProcData->exitcode; delete wd; delete endProcData; return exitcode; } else // async execution { return execData.pid; } } #endif // wxUSE_GUI #if wxUSE_BASE void wxHandleProcessTermination(wxEndProcessData *proc_data) { // notify user about termination if required if ( proc_data->process ) { proc_data->process->OnTerminate(proc_data->pid, proc_data->exitcode); } // clean up if ( proc_data->pid > 0 ) { delete proc_data; } else { // let wxExecute() know that the process has terminated proc_data->pid = 0; } } #endif // wxUSE_BASE