1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/unix/utilsunx.cpp 
   3 // Purpose:     generic Unix implementation of many wx functions 
   4 // Author:      Vadim Zeitlin 
   6 // Copyright:   (c) 1998 Robert Roebling, Vadim Zeitlin 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // ============================================================================ 
  12 // ============================================================================ 
  14 // ---------------------------------------------------------------------------- 
  16 // ---------------------------------------------------------------------------- 
  18 // for compilers that support precompilation, includes "wx.h". 
  19 #include "wx/wxprec.h" 
  23 #define USE_PUTENV (!defined(HAVE_SETENV) && defined(HAVE_PUTENV)) 
  26     #include "wx/string.h" 
  30     #include "wx/wxcrtvararg.h" 
  32         #include "wx/module.h" 
  33         #include "wx/hashmap.h" 
  37 #include "wx/apptrait.h" 
  39 #include "wx/process.h" 
  40 #include "wx/thread.h" 
  42 #include "wx/wfstream.h" 
  44 #include "wx/unix/execute.h" 
  45 #include "wx/unix/private.h" 
  48 #include <sys/wait.h>       // waitpid() 
  50 #ifdef HAVE_SYS_SELECT_H 
  51 #   include <sys/select.h> 
  54 #define HAS_PIPE_INPUT_STREAM (wxUSE_STREAMS && wxUSE_FILE) 
  56 #if HAS_PIPE_INPUT_STREAM 
  58 // define this to let wxexec.cpp know that we know what we're doing 
  59 #define _WX_USED_BY_WXEXECUTE_ 
  60 #include "../common/execcmn.cpp" 
  62 #endif // HAS_PIPE_INPUT_STREAM 
  66 #if defined(__MWERKS__) && defined(__MACH__) 
  67     #ifndef WXWIN_OS_DESCRIPTION 
  68         #define WXWIN_OS_DESCRIPTION "MacOS X" 
  70     #ifndef HAVE_NANOSLEEP 
  71         #define HAVE_NANOSLEEP 
  77     // our configure test believes we can use sigaction() if the function is 
  78     // available but Metrowekrs with MSL run-time does have the function but 
  79     // doesn't have sigaction struct so finally we can't use it... 
  81         #undef wxUSE_ON_FATAL_EXCEPTION 
  82         #define wxUSE_ON_FATAL_EXCEPTION 0 
  86 // not only the statfs syscall is called differently depending on platform, but 
  87 // one of its incarnations, statvfs(), takes different arguments under 
  88 // different platforms and even different versions of the same system (Solaris 
  89 // 7 and 8): if you want to test for this, don't forget that the problems only 
  90 // appear if the large files support is enabled 
  93         #include <sys/param.h> 
  94         #include <sys/mount.h> 
  97     #endif // __BSD__/!__BSD__ 
  99     #define wxStatfs statfs 
 101     #ifndef HAVE_STATFS_DECL 
 102         // some systems lack statfs() prototype in the system headers (AIX 4) 
 103         extern "C" int statfs(const char *path
, struct statfs 
*buf
); 
 105 #endif // HAVE_STATFS 
 108     #include <sys/statvfs.h> 
 110     #define wxStatfs statvfs 
 111 #endif // HAVE_STATVFS 
 113 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS) 
 114     // WX_STATFS_T is detected by configure 
 115     #define wxStatfs_t WX_STATFS_T 
 118 // SGI signal.h defines signal handler arguments differently depending on 
 119 // whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it 
 120 #if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS) 
 121     #define _LANGUAGE_C_PLUS_PLUS 1 
 127 #include <sys/stat.h> 
 128 #include <sys/types.h> 
 129 #include <sys/wait.h> 
 134 #include <fcntl.h>          // for O_WRONLY and friends 
 135 #include <time.h>           // nanosleep() and/or usleep() 
 136 #include <ctype.h>          // isspace() 
 137 #include <sys/time.h>       // needed for FD_SETSIZE 
 140     #include <sys/utsname.h> // for uname() 
 143 // Used by wxGetFreeMemory(). 
 145     #include <sys/sysmp.h> 
 146     #include <sys/sysinfo.h>   // for SAGET and MINFO structures 
 149 // ---------------------------------------------------------------------------- 
 150 // conditional compilation 
 151 // ---------------------------------------------------------------------------- 
 153 // many versions of Unices have this function, but it is not defined in system 
 154 // headers - please add your system here if it is the case for your OS. 
 155 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this. 
 156 #if !defined(HAVE_USLEEP) && \ 
 157     ((defined(__SUN__) && !defined(__SunOs_5_6) && \ 
 158                          !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \ 
 159      defined(__osf__) || defined(__EMX__)) 
 163             /* I copied this from the XFree86 diffs. AV. */ 
 164             #define INCL_DOSPROCESS 
 166             inline void usleep(unsigned long delay
) 
 168                 DosSleep(delay 
? (delay
/1000l) : 1l); 
 171             int usleep(unsigned int usec
); 
 172         #endif // __EMX__/Unix 
 175     #define HAVE_USLEEP 1 
 176 #endif // Unices without usleep() 
 178 // ============================================================================ 
 180 // ============================================================================ 
 182 // ---------------------------------------------------------------------------- 
 184 // ---------------------------------------------------------------------------- 
 186 void wxSleep(int nSecs
) 
 191 void wxMicroSleep(unsigned long microseconds
) 
 193 #if defined(HAVE_NANOSLEEP) 
 195     tmReq
.tv_sec 
= (time_t)(microseconds 
/ 1000000); 
 196     tmReq
.tv_nsec 
= (microseconds 
% 1000000) * 1000; 
 198     // we're not interested in remaining time nor in return value 
 199     (void)nanosleep(&tmReq
, (timespec 
*)NULL
); 
 200 #elif defined(HAVE_USLEEP) 
 201     // uncomment this if you feel brave or if you are sure that your version 
 202     // of Solaris has a safe usleep() function but please notice that usleep() 
 203     // is known to lead to crashes in MT programs in Solaris 2.[67] and is not 
 204     // documented as MT-Safe 
 205     #if defined(__SUN__) && wxUSE_THREADS 
 206         #error "usleep() cannot be used in MT programs under Solaris." 
 209     usleep(microseconds
); 
 210 #elif defined(HAVE_SLEEP) 
 211     // under BeOS sleep() takes seconds (what about other platforms, if any?) 
 212     sleep(microseconds 
* 1000000); 
 213 #else // !sleep function 
 214     #error "usleep() or nanosleep() function required for wxMicroSleep" 
 215 #endif // sleep function 
 218 void wxMilliSleep(unsigned long milliseconds
) 
 220     wxMicroSleep(milliseconds
*1000); 
 223 // ---------------------------------------------------------------------------- 
 224 // process management 
 225 // ---------------------------------------------------------------------------- 
 227 int wxKill(long pid
, wxSignal sig
, wxKillError 
*rc
, int flags
) 
 229     int err 
= kill((pid_t
) (flags 
& wxKILL_CHILDREN
) ? -pid 
: pid
, (int)sig
); 
 232         switch ( err 
? errno 
: 0 ) 
 239                 *rc 
= wxKILL_BAD_SIGNAL
; 
 243                 *rc 
= wxKILL_ACCESS_DENIED
; 
 247                 *rc 
= wxKILL_NO_PROCESS
; 
 251                 // this goes against Unix98 docs so log it 
 252                 wxLogDebug(_T("unexpected kill(2) return value %d"), err
); 
 262 #define WXEXECUTE_NARGS   127 
 264 #if defined(__DARWIN__) 
 265 long wxMacExecute(wxChar 
**argv
, 
 270 long wxExecute( const wxString
& command
, int flags
, wxProcess 
*process 
) 
 272     wxCHECK_MSG( !command
.empty(), 0, wxT("can't exec empty command") ); 
 274     wxLogTrace(wxT("exec"), wxT("Executing \"%s\""), command
.c_str()); 
 277     // fork() doesn't mix well with POSIX threads: on many systems the program 
 278     // deadlocks or crashes for some reason. Probably our code is buggy and 
 279     // doesn't do something which must be done to allow this to work, but I 
 280     // don't know what yet, so for now just warn the user (this is the least we 
 282     wxASSERT_MSG( wxThread::IsMain(), 
 283                     _T("wxExecute() can be called only from the main thread") ); 
 284 #endif // wxUSE_THREADS 
 287     wxChar 
*argv
[WXEXECUTE_NARGS
]; 
 289     const wxChar 
*cptr 
= command
.c_str(); 
 290     wxChar quotechar 
= wxT('\0'); // is arg quoted? 
 291     bool escaped 
= false; 
 293     // split the command line in arguments 
 296         argument 
= wxEmptyString
; 
 297         quotechar 
= wxT('\0'); 
 299         // eat leading whitespace: 
 300         while ( wxIsspace(*cptr
) ) 
 303         if ( *cptr 
== wxT('\'') || *cptr 
== wxT('"') ) 
 308             if ( *cptr 
== wxT('\\') && ! escaped 
) 
 315             // all other characters: 
 319             // have we reached the end of the argument? 
 320             if ( (*cptr 
== quotechar 
&& ! escaped
) 
 321                  || (quotechar 
== wxT('\0') && wxIsspace(*cptr
)) 
 322                  || *cptr 
== wxT('\0') ) 
 324                 wxASSERT_MSG( argc 
< WXEXECUTE_NARGS
, 
 325                               wxT("too many arguments in wxExecute") ); 
 327                 argv
[argc
] = new wxChar
[argument
.length() + 1]; 
 328                 wxStrcpy(argv
[argc
], argument
.c_str()); 
 331                 // if not at end of buffer, swallow last character: 
 335                 break; // done with this one, start over 
 342 #if defined(__DARWIN__) 
 343     // wxMacExecute only executes app bundles. 
 344     // It returns an error code if the target is not an app bundle, thus falling 
 345     // through to the regular wxExecute for non app bundles. 
 346     lRc 
= wxMacExecute(argv
, flags
, process
); 
 347     if( lRc 
!= ((flags 
& wxEXEC_SYNC
) ? -1 : 0)) 
 351     // do execute the command 
 352     lRc 
= wxExecute(argv
, flags
, process
); 
 357         delete [] argv
[argc
++]; 
 362 // ---------------------------------------------------------------------------- 
 364 // ---------------------------------------------------------------------------- 
 366 static wxString 
wxMakeShellCommand(const wxString
& command
) 
 371         // just an interactive shell 
 376         // execute command in a shell 
 377         cmd 
<< _T("/bin/sh -c '") << command 
<< _T('\''); 
 383 bool wxShell(const wxString
& command
) 
 385     return wxExecute(wxMakeShellCommand(command
), wxEXEC_SYNC
) == 0; 
 388 bool wxShell(const wxString
& command
, wxArrayString
& output
) 
 390     wxCHECK_MSG( !command
.empty(), false, _T("can't exec shell non interactively") ); 
 392     return wxExecute(wxMakeShellCommand(command
), output
); 
 395 // Shutdown or reboot the PC 
 396 bool wxShutdown(wxShutdownFlags wFlags
) 
 401         case wxSHUTDOWN_POWEROFF
: 
 405         case wxSHUTDOWN_REBOOT
: 
 410             wxFAIL_MSG( _T("unknown wxShutdown() flag") ); 
 414     return system(wxString::Format(_T("init %c"), level
).mb_str()) == 0; 
 417 // ---------------------------------------------------------------------------- 
 418 // wxStream classes to support IO redirection in wxExecute 
 419 // ---------------------------------------------------------------------------- 
 421 #if HAS_PIPE_INPUT_STREAM 
 423 bool wxPipeInputStream::CanRead() const 
 425     if ( m_lasterror 
== wxSTREAM_EOF 
) 
 428     // check if there is any input available 
 433     const int fd 
= m_file
->fd(); 
 438     wxFD_SET(fd
, &readfds
); 
 440     switch ( select(fd 
+ 1, &readfds
, NULL
, NULL
, &tv
) ) 
 443             wxLogSysError(_("Impossible to get child process input")); 
 450             wxFAIL_MSG(_T("unexpected select() return value")); 
 451             // still fall through 
 454             // input available -- or maybe not, as select() returns 1 when a 
 455             // read() will complete without delay, but it could still not read 
 461 #endif // HAS_PIPE_INPUT_STREAM 
 463 // ---------------------------------------------------------------------------- 
 464 // wxExecute: the real worker function 
 465 // ---------------------------------------------------------------------------- 
 467 long wxExecute(wxChar 
**argv
, int flags
, wxProcess 
*process
) 
 469     // for the sync execution, we return -1 to indicate failure, but for async 
 470     // case we return 0 which is never a valid PID 
 472     // we define this as a macro, not a variable, to avoid compiler warnings 
 473     // about "ERROR_RETURN_CODE value may be clobbered by fork()" 
 474     #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0) 
 476     wxCHECK_MSG( *argv
, ERROR_RETURN_CODE
, wxT("can't exec empty command") ); 
 480     char *mb_argv
[WXEXECUTE_NARGS
]; 
 482     while (argv
[mb_argc
]) 
 484         wxWX2MBbuf mb_arg 
= wxSafeConvertWX2MB(argv
[mb_argc
]); 
 485         mb_argv
[mb_argc
] = strdup(mb_arg
); 
 488     mb_argv
[mb_argc
] = (char *) NULL
; 
 490     // this macro will free memory we used above 
 491     #define ARGS_CLEANUP                                 \ 
 492         for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \ 
 493             free(mb_argv[mb_argc]) 
 495     // no need for cleanup 
 498     wxChar 
**mb_argv 
= argv
; 
 499 #endif // Unicode/ANSI 
 501     // we want this function to work even if there is no wxApp so ensure that 
 502     // we have a valid traits pointer 
 503     wxConsoleAppTraits traitsConsole
; 
 504     wxAppTraits 
*traits 
= wxTheApp 
? wxTheApp
->GetTraits() : NULL
; 
 506         traits 
= &traitsConsole
; 
 508     // this struct contains all information which we pass to and from 
 509     // wxAppTraits methods 
 510     wxExecuteData execData
; 
 511     execData
.flags 
= flags
; 
 512     execData
.process 
= process
; 
 515     if ( !traits
->CreateEndProcessPipe(execData
) ) 
 517         wxLogError( _("Failed to execute '%s'\n"), *argv 
); 
 521         return ERROR_RETURN_CODE
; 
 524     // pipes for inter process communication 
 525     wxPipe pipeIn
,      // stdin 
 529     if ( process 
&& process
->IsRedirected() ) 
 531         if ( !pipeIn
.Create() || !pipeOut
.Create() || !pipeErr
.Create() ) 
 533             wxLogError( _("Failed to execute '%s'\n"), *argv 
); 
 537             return ERROR_RETURN_CODE
; 
 543     // NB: do *not* use vfork() here, it completely breaks this code for some 
 544     //     reason under Solaris (and maybe others, although not under Linux) 
 545     //     But on OpenVMS we do not have fork so we have to use vfork and 
 546     //     cross our fingers that it works. 
 552    if ( pid 
== -1 )     // error? 
 554         wxLogSysError( _("Fork failed") ); 
 558         return ERROR_RETURN_CODE
; 
 560     else if ( pid 
== 0 )  // we're in child 
 562         // These lines close the open file descriptors to to avoid any 
 563         // input/output which might block the process or irritate the user. If 
 564         // one wants proper IO for the subprocess, the right thing to do is to 
 565         // start an xterm executing it. 
 566         if ( !(flags 
& wxEXEC_SYNC
) ) 
 568             // FD_SETSIZE is unsigned under BSD, signed under other platforms 
 569             // so we need a cast to avoid warnings on all platforms 
 570             for ( int fd 
= 0; fd 
< (int)FD_SETSIZE
; fd
++ ) 
 572                 if ( fd 
== pipeIn
[wxPipe::Read
] 
 573                         || fd 
== pipeOut
[wxPipe::Write
] 
 574                         || fd 
== pipeErr
[wxPipe::Write
] 
 575                         || traits
->IsWriteFDOfEndProcessPipe(execData
, fd
) ) 
 577                     // don't close this one, we still need it 
 581                 // leave stderr opened too, it won't do any harm 
 582                 if ( fd 
!= STDERR_FILENO 
) 
 587 #if !defined(__VMS) && !defined(__EMX__) 
 588         if ( flags 
& wxEXEC_MAKE_GROUP_LEADER 
) 
 590             // Set process group to child process' pid.  Then killing -pid 
 591             // of the parent will kill the process and all of its children. 
 596         // reading side can be safely closed but we should keep the write one 
 598         traits
->DetachWriteFDOfEndProcessPipe(execData
); 
 600         // redirect stdin, stdout and stderr 
 603             if ( dup2(pipeIn
[wxPipe::Read
], STDIN_FILENO
) == -1 || 
 604                  dup2(pipeOut
[wxPipe::Write
], STDOUT_FILENO
) == -1 || 
 605                  dup2(pipeErr
[wxPipe::Write
], STDERR_FILENO
) == -1 ) 
 607                 wxLogSysError(_("Failed to redirect child process input/output")); 
 615         execvp (*mb_argv
, mb_argv
); 
 617         fprintf(stderr
, "execvp("); 
 618         // CS changed ppc to ppc_ as ppc is not available under mac os CW Mach-O 
 619         for ( char **ppc_ 
= mb_argv
; *ppc_
; ppc_
++ ) 
 620             fprintf(stderr
, "%s%s", ppc_ 
== mb_argv 
? "" : ", ", *ppc_
); 
 621         fprintf(stderr
, ") failed with error %d!\n", errno
); 
 623         // there is no return after successful exec() 
 626         // some compilers complain about missing return - of course, they 
 627         // should know that exit() doesn't return but what else can we do if 
 630         // and, sure enough, other compilers complain about unreachable code 
 631         // after exit() call, so we can just always have return here... 
 632 #if defined(__VMS) || defined(__INTEL_COMPILER) 
 636     else // we're in parent 
 640         // save it for WaitForChild() use 
 643         // prepare for IO redirection 
 645 #if HAS_PIPE_INPUT_STREAM 
 646         // the input buffer bufOut is connected to stdout, this is why it is 
 647         // called bufOut and not bufIn 
 648         wxStreamTempInputBuffer bufOut
, 
 650 #endif // HAS_PIPE_INPUT_STREAM 
 652         if ( process 
&& process
->IsRedirected() ) 
 654 #if HAS_PIPE_INPUT_STREAM 
 655             wxOutputStream 
*inStream 
= 
 656                 new wxFileOutputStream(pipeIn
.Detach(wxPipe::Write
)); 
 658             wxPipeInputStream 
*outStream 
= 
 659                 new wxPipeInputStream(pipeOut
.Detach(wxPipe::Read
)); 
 661             wxPipeInputStream 
*errStream 
= 
 662                 new wxPipeInputStream(pipeErr
.Detach(wxPipe::Read
)); 
 664             process
->SetPipeStreams(outStream
, inStream
, errStream
); 
 666             bufOut
.Init(outStream
); 
 667             bufErr
.Init(errStream
); 
 669             execData
.bufOut 
= &bufOut
; 
 670             execData
.bufErr 
= &bufErr
; 
 671 #endif // HAS_PIPE_INPUT_STREAM 
 681         return traits
->WaitForChild(execData
); 
 684 #if !defined(__VMS) && !defined(__INTEL_COMPILER) 
 685     return ERROR_RETURN_CODE
; 
 689 #undef ERROR_RETURN_CODE 
 692 // ---------------------------------------------------------------------------- 
 693 // file and directory functions 
 694 // ---------------------------------------------------------------------------- 
 696 const wxChar
* wxGetHomeDir( wxString 
*home  
) 
 698     *home 
= wxGetUserHome(); 
 704     if ( tmp
.Last() != wxT(']')) 
 705         if ( tmp
.Last() != wxT('/')) *home 
<< wxT('/'); 
 707     return home
->c_str(); 
 710 wxString 
wxGetUserHome( const wxString 
&user 
) 
 712     struct passwd 
*who 
= (struct passwd 
*) NULL
; 
 718         if ((ptr 
= wxGetenv(wxT("HOME"))) != NULL
) 
 723         if ((ptr 
= wxGetenv(wxT("USER"))) != NULL 
|| 
 724              (ptr 
= wxGetenv(wxT("LOGNAME"))) != NULL
) 
 726             who 
= getpwnam(wxSafeConvertWX2MB(ptr
)); 
 729         // make sure the user exists! 
 732             who 
= getpwuid(getuid()); 
 737       who 
= getpwnam (user
.mb_str()); 
 740     return wxSafeConvertMB2WX(who 
? who
->pw_dir 
: 0); 
 743 // ---------------------------------------------------------------------------- 
 744 // network and user id routines 
 745 // ---------------------------------------------------------------------------- 
 747 // private utility function which returns output of the given command, removing 
 748 // the trailing newline 
 749 static wxString 
wxGetCommandOutput(const wxString 
&cmd
) 
 751     FILE *f 
= popen(cmd
.ToAscii(), "r"); 
 754         wxLogSysError(_T("Executing \"%s\" failed"), cmd
.c_str()); 
 755         return wxEmptyString
; 
 762         if ( !fgets(buf
, sizeof(buf
), f
) ) 
 765         s 
+= wxString::FromAscii(buf
); 
 770     if ( !s
.empty() && s
.Last() == _T('\n') ) 
 776 // retrieve either the hostname or FQDN depending on platform (caller must 
 777 // check whether it's one or the other, this is why this function is for 
 779 static bool wxGetHostNameInternal(wxChar 
*buf
, int sz
) 
 781     wxCHECK_MSG( buf
, false, wxT("NULL pointer in wxGetHostNameInternal") ); 
 785     // we're using uname() which is POSIX instead of less standard sysinfo() 
 786 #if defined(HAVE_UNAME) 
 788     bool ok 
= uname(&uts
) != -1; 
 791         wxStrncpy(buf
, wxSafeConvertMB2WX(uts
.nodename
), sz 
- 1); 
 794 #elif defined(HAVE_GETHOSTNAME) 
 796     bool ok 
= gethostname(cbuf
, sz
) != -1; 
 799         wxStrncpy(buf
, wxSafeConvertMB2WX(cbuf
), sz 
- 1); 
 802 #else // no uname, no gethostname 
 803     wxFAIL_MSG(wxT("don't know host name for this machine")); 
 806 #endif // uname/gethostname 
 810         wxLogSysError(_("Cannot get the hostname")); 
 816 bool wxGetHostName(wxChar 
*buf
, int sz
) 
 818     bool ok 
= wxGetHostNameInternal(buf
, sz
); 
 822         // BSD systems return the FQDN, we only want the hostname, so extract 
 823         // it (we consider that dots are domain separators) 
 824         wxChar 
*dot 
= wxStrchr(buf
, wxT('.')); 
 835 bool wxGetFullHostName(wxChar 
*buf
, int sz
) 
 837     bool ok 
= wxGetHostNameInternal(buf
, sz
); 
 841         if ( !wxStrchr(buf
, wxT('.')) ) 
 843             struct hostent 
*host 
= gethostbyname(wxSafeConvertWX2MB(buf
)); 
 846                 wxLogSysError(_("Cannot get the official hostname")); 
 852                 // the canonical name 
 853                 wxStrncpy(buf
, wxSafeConvertMB2WX(host
->h_name
), sz
); 
 856         //else: it's already a FQDN (BSD behaves this way) 
 862 bool wxGetUserId(wxChar 
*buf
, int sz
) 
 867     if ((who 
= getpwuid(getuid ())) != NULL
) 
 869         wxStrncpy (buf
, wxSafeConvertMB2WX(who
->pw_name
), sz 
- 1); 
 876 bool wxGetUserName(wxChar 
*buf
, int sz
) 
 882     if ((who 
= getpwuid (getuid ())) != NULL
) 
 884        char *comma 
= strchr(who
->pw_gecos
, ','); 
 886            *comma 
= '\0'; // cut off non-name comment fields 
 887        wxStrncpy (buf
, wxSafeConvertMB2WX(who
->pw_gecos
), sz 
- 1); 
 892 #else // !HAVE_PW_GECOS 
 893     return wxGetUserId(buf
, sz
); 
 894 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS 
 897 bool wxIsPlatform64Bit() 
 899     const wxString machine 
= wxGetCommandOutput(wxT("uname -m")); 
 901     // the test for "64" is obviously not 100% reliable but seems to work fine 
 903     return machine
.Contains(wxT("64")) || 
 904                 machine
.Contains(wxT("alpha")); 
 907 // these functions are in mac/utils.cpp for wxMac 
 910 wxOperatingSystemId 
wxGetOsVersion(int *verMaj
, int *verMin
) 
 914     wxString release 
= wxGetCommandOutput(wxT("uname -r")); 
 915     if ( release
.empty() || 
 916          wxSscanf(release
.c_str(), wxT("%d.%d"), &major
, &minor
) != 2 ) 
 918         // failed to get version string or unrecognized format 
 928     // try to understand which OS are we running 
 929     wxString kernel 
= wxGetCommandOutput(wxT("uname -s")); 
 930     if ( kernel
.empty() ) 
 931         kernel 
= wxGetCommandOutput(wxT("uname -o")); 
 933     if ( kernel
.empty() ) 
 936     return wxPlatformInfo::GetOperatingSystemId(kernel
); 
 939 wxString 
wxGetOsDescription() 
 941     return wxGetCommandOutput(wxT("uname -s -r -m")); 
 946 unsigned long wxGetProcessId() 
 948     return (unsigned long)getpid(); 
 951 wxMemorySize 
wxGetFreeMemory() 
 953 #if defined(__LINUX__) 
 954     // get it from /proc/meminfo 
 955     FILE *fp 
= fopen("/proc/meminfo", "r"); 
 961         if ( fgets(buf
, WXSIZEOF(buf
), fp
) && fgets(buf
, WXSIZEOF(buf
), fp
) ) 
 963             // /proc/meminfo changed its format in kernel 2.6 
 964             if ( wxPlatformInfo().CheckOSVersion(2, 6) ) 
 966                 unsigned long cached
, buffers
; 
 967                 sscanf(buf
, "MemFree: %ld", &memFree
); 
 969                 fgets(buf
, WXSIZEOF(buf
), fp
); 
 970                 sscanf(buf
, "Buffers: %lu", &buffers
); 
 972                 fgets(buf
, WXSIZEOF(buf
), fp
); 
 973                 sscanf(buf
, "Cached: %lu", &cached
); 
 975                 // add to "MemFree" also the "Buffers" and "Cached" values as 
 976                 // free(1) does as otherwise the value never makes sense: for 
 977                 // kernel 2.6 it's always almost 0 
 978                 memFree 
+= buffers 
+ cached
; 
 980                 // values here are always expressed in kB and we want bytes 
 983             else // Linux 2.4 (or < 2.6, anyhow) 
 985                 long memTotal
, memUsed
; 
 986                 sscanf(buf
, "Mem: %ld %ld %ld", &memTotal
, &memUsed
, &memFree
); 
 992         return (wxMemorySize
)memFree
; 
 994 #elif defined(__SGI__) 
 995     struct rminfo realmem
; 
 996     if ( sysmp(MP_SAGET
, MPSA_RMINFO
, &realmem
, sizeof realmem
) == 0 ) 
 997         return ((wxMemorySize
)realmem
.physmem 
* sysconf(_SC_PAGESIZE
)); 
 998 #elif defined(_SC_AVPHYS_PAGES) 
 999     return ((wxMemorySize
)sysconf(_SC_AVPHYS_PAGES
))*sysconf(_SC_PAGESIZE
); 
1000 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably 
1003     // can't find it out 
1007 bool wxGetDiskSpace(const wxString
& path
, wxDiskspaceSize_t 
*pTotal
, wxDiskspaceSize_t 
*pFree
) 
1009 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS) 
1010     // the case to "char *" is needed for AIX 4.3 
1012     if ( wxStatfs((char *)(const char*)path
.fn_str(), &fs
) != 0 ) 
1014         wxLogSysError( wxT("Failed to get file system statistics") ); 
1019     // under Solaris we also have to use f_frsize field instead of f_bsize 
1020     // which is in general a multiple of f_frsize 
1022     wxDiskspaceSize_t blockSize 
= fs
.f_frsize
; 
1023 #else // HAVE_STATFS 
1024     wxDiskspaceSize_t blockSize 
= fs
.f_bsize
; 
1025 #endif // HAVE_STATVFS/HAVE_STATFS 
1029         *pTotal 
= wxDiskspaceSize_t(fs
.f_blocks
) * blockSize
; 
1034         *pFree 
= wxDiskspaceSize_t(fs
.f_bavail
) * blockSize
; 
1038 #else // !HAVE_STATFS && !HAVE_STATVFS 
1040 #endif // HAVE_STATFS 
1043 // ---------------------------------------------------------------------------- 
1045 // ---------------------------------------------------------------------------- 
1049 WX_DECLARE_STRING_HASH_MAP(char *, wxEnvVars
); 
1051 static wxEnvVars gs_envVars
; 
1053 class wxSetEnvModule 
: public wxModule
 
1056     virtual bool OnInit() { return true; } 
1057     virtual void OnExit() 
1059         for ( wxEnvVars::const_iterator i 
= gs_envVars
.begin(); 
1060               i 
!= gs_envVars
.end(); 
1069     DECLARE_DYNAMIC_CLASS(wxSetEnvModule
) 
1072 IMPLEMENT_DYNAMIC_CLASS(wxSetEnvModule
, wxModule
) 
1074 #endif // USE_PUTENV 
1076 bool wxGetEnv(const wxString
& var
, wxString 
*value
) 
1078     // wxGetenv is defined as getenv() 
1079     char *p 
= wxGetenv(var
); 
1091 static bool wxDoSetEnv(const wxString
& variable
, const char *value
) 
1093 #if defined(HAVE_SETENV) 
1096 #ifdef HAVE_UNSETENV 
1097         // don't test unsetenv() return value: it's void on some systems (at 
1099         unsetenv(variable
.mb_str()); 
1102         value 
= ""; // we can't pass NULL to setenv() 
1106     return setenv(variable
.mb_str(), value
, 1 /* overwrite */) == 0; 
1107 #elif defined(HAVE_PUTENV) 
1108     wxString s 
= variable
; 
1110         s 
<< _T('=') << value
; 
1112     // transform to ANSI 
1113     const wxWX2MBbuf p 
= s
.mb_str(); 
1115     char *buf 
= (char *)malloc(strlen(p
) + 1); 
1118     // store the string to free() it later 
1119     wxEnvVars::iterator i 
= gs_envVars
.find(variable
); 
1120     if ( i 
!= gs_envVars
.end() ) 
1125     else // this variable hadn't been set before 
1127         gs_envVars
[variable
] = buf
; 
1130     return putenv(buf
) == 0; 
1131 #else // no way to set an env var 
1136 bool wxSetEnv(const wxString
& variable
, const wxString
& value
) 
1138     return wxDoSetEnv(variable
, value
.mb_str()); 
1141 bool wxUnsetEnv(const wxString
& variable
) 
1143     return wxDoSetEnv(variable
, NULL
); 
1146 // ---------------------------------------------------------------------------- 
1148 // ---------------------------------------------------------------------------- 
1150 #if wxUSE_ON_FATAL_EXCEPTION 
1154 extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER
) 
1158         // give the user a chance to do something special about this 
1159         wxTheApp
->OnFatalException(); 
1165 bool wxHandleFatalExceptions(bool doit
) 
1168     static bool s_savedHandlers 
= false; 
1169     static struct sigaction s_handlerFPE
, 
1175     if ( doit 
&& !s_savedHandlers 
) 
1177         // install the signal handler 
1178         struct sigaction act
; 
1180         // some systems extend it with non std fields, so zero everything 
1181         memset(&act
, 0, sizeof(act
)); 
1183         act
.sa_handler 
= wxFatalSignalHandler
; 
1184         sigemptyset(&act
.sa_mask
); 
1187         ok 
&= sigaction(SIGFPE
, &act
, &s_handlerFPE
) == 0; 
1188         ok 
&= sigaction(SIGILL
, &act
, &s_handlerILL
) == 0; 
1189         ok 
&= sigaction(SIGBUS
, &act
, &s_handlerBUS
) == 0; 
1190         ok 
&= sigaction(SIGSEGV
, &act
, &s_handlerSEGV
) == 0; 
1193             wxLogDebug(_T("Failed to install our signal handler.")); 
1196         s_savedHandlers 
= true; 
1198     else if ( s_savedHandlers 
) 
1200         // uninstall the signal handler 
1201         ok 
&= sigaction(SIGFPE
, &s_handlerFPE
, NULL
) == 0; 
1202         ok 
&= sigaction(SIGILL
, &s_handlerILL
, NULL
) == 0; 
1203         ok 
&= sigaction(SIGBUS
, &s_handlerBUS
, NULL
) == 0; 
1204         ok 
&= sigaction(SIGSEGV
, &s_handlerSEGV
, NULL
) == 0; 
1207             wxLogDebug(_T("Failed to uninstall our signal handler.")); 
1210         s_savedHandlers 
= false; 
1212     //else: nothing to do 
1217 #endif // wxUSE_ON_FATAL_EXCEPTION 
1219 #endif // wxUSE_BASE 
1224     #include <sys/errno.h> 
1226 // ---------------------------------------------------------------------------- 
1227 // wxExecute support 
1228 // ---------------------------------------------------------------------------- 
1231     NOTE: If this proves not to work well for wxMac then move back to the old 
1232     behavior.  If, however, it proves to work just fine, nuke all of the code 
1233     for the old behavior.  I strongly suggest backporting this to 2.8 as well. 
1234     However, beware that while you can nuke the old code here, you cannot 
1235     nuke the wxAddProcessCallbackForPid from the 2.8 branch (found in 
1236     utilsexc_cf since it's an exported symbol). 
1238 // #define USE_OLD_DARWIN_END_PROCESS_DETECT (defined(__DARWIN__) && defined(__WXMAC__)) 
1239 #define USE_OLD_DARWIN_END_PROCESS_DETECT 0 
1241 // wxMac/wxCocoa don't use the same process end detection mechanisms so we don't 
1242 // need wxExecute-related helpers for them 
1243 #if !USE_OLD_DARWIN_END_PROCESS_DETECT 
1245 bool wxGUIAppTraits::CreateEndProcessPipe(wxExecuteData
& execData
) 
1247     return execData
.pipeEndProcDetect
.Create(); 
1250 bool wxGUIAppTraits::IsWriteFDOfEndProcessPipe(wxExecuteData
& execData
, int fd
) 
1252     return fd 
== (execData
.pipeEndProcDetect
)[wxPipe::Write
]; 
1255 void wxGUIAppTraits::DetachWriteFDOfEndProcessPipe(wxExecuteData
& execData
) 
1257     execData
.pipeEndProcDetect
.Detach(wxPipe::Write
); 
1258     execData
.pipeEndProcDetect
.Close(); 
1263 bool wxGUIAppTraits::CreateEndProcessPipe(wxExecuteData
& WXUNUSED(execData
)) 
1269 wxGUIAppTraits::IsWriteFDOfEndProcessPipe(wxExecuteData
& WXUNUSED(execData
), 
1276 wxGUIAppTraits::DetachWriteFDOfEndProcessPipe(wxExecuteData
& WXUNUSED(execData
)) 
1278     // nothing to do here, we don't use the pipe 
1281 #endif // !Darwin/Darwin 
1283 int wxGUIAppTraits::WaitForChild(wxExecuteData
& execData
) 
1285     wxEndProcessData 
*endProcData 
= new wxEndProcessData
; 
1287     const int flags 
= execData
.flags
; 
1289     // wxAddProcessCallback is now (with DARWIN) allowed to call the 
1290     // callback function directly if the process terminates before 
1291     // the callback can be added to the run loop. Set up the endProcData. 
1292     if ( flags 
& wxEXEC_SYNC 
) 
1294         // we may have process for capturing the program output, but it's 
1295         // not used in wxEndProcessData in the case of sync execution 
1296         endProcData
->process 
= NULL
; 
1298         // sync execution: indicate it by negating the pid 
1299         endProcData
->pid 
= -execData
.pid
; 
1303         // async execution, nothing special to do -- caller will be 
1304         // notified about the process termination if process != NULL, endProcData 
1305         // will be deleted in GTK_EndProcessDetector 
1306         endProcData
->process  
= execData
.process
; 
1307         endProcData
->pid      
= execData
.pid
; 
1311     if ( !(flags 
& wxEXEC_NOEVENTS
) ) 
1313 #if USE_OLD_DARWIN_END_PROCESS_DETECT 
1314         endProcData
->tag 
= wxAddProcessCallbackForPid(endProcData
, execData
.pid
); 
1316         endProcData
->tag 
= wxAddProcessCallback
 
1319                              execData
.pipeEndProcDetect
.Detach(wxPipe::Read
) 
1322         execData
.pipeEndProcDetect
.Close(); 
1323 #endif // USE_OLD_DARWIN_END_PROCESS_DETECT 
1326     if ( flags 
& wxEXEC_SYNC 
) 
1331         wxWindowDisabler 
*wd 
= flags 
& (wxEXEC_NODISABLE 
| wxEXEC_NOEVENTS
) 
1333                                     : new wxWindowDisabler
; 
1335         if ( flags 
& wxEXEC_NOEVENTS 
) 
1337             // just block waiting for the child to exit 
1340             int result 
= waitpid(execData
.pid
, &status
, 0); 
1342             /*  DE: waitpid manpage states that waitpid can fail with EINTR 
1343                 if the call is interrupted by a caught signal.  I suppose 
1344                 that means that this ought to be a while loop. 
1346                 The odd thing is that it seems to fail EVERY time.  It fails 
1347                 with a quickly exiting process (e.g. echo), and fails with a 
1348                 slowly exiting process (e.g. sleep 2) but clearly after 
1349                 having waited for the child to exit. Maybe it's a bug in 
1350                 my particular version. 
1352                 It works, however, from the CFSocket callback without this 
1353                 trick but in that case it's used only after CFSocket calls 
1354                 the callback and with the WNOHANG flag which would seem to 
1355                 preclude it from being interrupted or at least make it much 
1356                 less likely since it would not then be waiting. 
1358                 If Darwin's man page is to be believed then this is definitely 
1359                 necessary.  It's just weird that I've never seen it before 
1360                 and apparently no one else has either or you'd think they'd 
1361                 have reported it by now.  Perhaps blocking the GUI while 
1362                 waiting for a child process to exit is simply not that common. 
1364             if(result 
== -1 && errno 
== EINTR
) 
1366                 result 
= waitpid(execData
.pid
, &status
, 0); 
1373                 wxLogLastError(_T("waitpid")); 
1378                 wxASSERT_MSG( result 
== execData
.pid
, 
1379                               _T("unexpected waitpid() return value") ); 
1381                 if ( WIFEXITED(status
) ) 
1383                     exitcode 
= WEXITSTATUS(status
); 
1385                 else // abnormal termination? 
1387                     wxASSERT_MSG( WIFSIGNALED(status
), 
1388                                   _T("unexpected child wait status") ); 
1393         else // !wxEXEC_NOEVENTS 
1395             // endProcData->pid will be set to 0 from GTK_EndProcessDetector when the 
1396             // process terminates 
1397             while ( endProcData
->pid 
!= 0 ) 
1401 #if HAS_PIPE_INPUT_STREAM 
1402                 if ( execData
.bufOut 
) 
1404                     execData
.bufOut
->Update(); 
1408                 if ( execData
.bufErr 
) 
1410                     execData
.bufErr
->Update(); 
1413 #endif // HAS_PIPE_INPUT_STREAM 
1415                 // don't consume 100% of the CPU while we're sitting in this 
1420                 // give GTK+ a chance to call GTK_EndProcessDetector here and 
1421                 // also repaint the GUI 
1425             exitcode 
= endProcData
->exitcode
; 
1433     else // async execution 
1435         return execData
.pid
; 
1442 void wxHandleProcessTermination(wxEndProcessData 
*proc_data
) 
1444     // notify user about termination if required 
1445     if ( proc_data
->process 
) 
1447         proc_data
->process
->OnTerminate(proc_data
->pid
, proc_data
->exitcode
); 
1451     if ( proc_data
->pid 
> 0 ) 
1457        // let wxExecute() know that the process has terminated 
1462 #endif // wxUSE_BASE