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/private/fdiodispatcher.h"
45 #include "wx/unix/execute.h"
46 #include "wx/unix/private.h"
48 #ifdef wxHAS_GENERIC_PROCESS_CALLBACK
49 #include "wx/private/fdiodispatcher.h"
53 #include <sys/wait.h> // waitpid()
55 #ifdef HAVE_SYS_SELECT_H
56 # include <sys/select.h>
59 #define HAS_PIPE_INPUT_STREAM (wxUSE_STREAMS && wxUSE_FILE)
61 #if HAS_PIPE_INPUT_STREAM
63 // define this to let wxexec.cpp know that we know what we're doing
64 #define _WX_USED_BY_WXEXECUTE_
65 #include "../common/execcmn.cpp"
67 #endif // HAS_PIPE_INPUT_STREAM
69 #if defined(__MWERKS__) && defined(__MACH__)
70 #ifndef WXWIN_OS_DESCRIPTION
71 #define WXWIN_OS_DESCRIPTION "MacOS X"
73 #ifndef HAVE_NANOSLEEP
74 #define HAVE_NANOSLEEP
80 // our configure test believes we can use sigaction() if the function is
81 // available but Metrowekrs with MSL run-time does have the function but
82 // doesn't have sigaction struct so finally we can't use it...
84 #undef wxUSE_ON_FATAL_EXCEPTION
85 #define wxUSE_ON_FATAL_EXCEPTION 0
89 // not only the statfs syscall is called differently depending on platform, but
90 // one of its incarnations, statvfs(), takes different arguments under
91 // different platforms and even different versions of the same system (Solaris
92 // 7 and 8): if you want to test for this, don't forget that the problems only
93 // appear if the large files support is enabled
96 #include <sys/param.h>
97 #include <sys/mount.h>
100 #endif // __BSD__/!__BSD__
102 #define wxStatfs statfs
104 #ifndef HAVE_STATFS_DECL
105 // some systems lack statfs() prototype in the system headers (AIX 4)
106 extern "C" int statfs(const char *path
, struct statfs
*buf
);
108 #endif // HAVE_STATFS
111 #include <sys/statvfs.h>
113 #define wxStatfs statvfs
114 #endif // HAVE_STATVFS
116 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
117 // WX_STATFS_T is detected by configure
118 #define wxStatfs_t WX_STATFS_T
121 // SGI signal.h defines signal handler arguments differently depending on
122 // whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
123 #if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
124 #define _LANGUAGE_C_PLUS_PLUS 1
130 #include <sys/stat.h>
131 #include <sys/types.h>
132 #include <sys/wait.h>
137 #include <fcntl.h> // for O_WRONLY and friends
138 #include <time.h> // nanosleep() and/or usleep()
139 #include <ctype.h> // isspace()
140 #include <sys/time.h> // needed for FD_SETSIZE
143 #include <sys/utsname.h> // for uname()
146 // Used by wxGetFreeMemory().
148 #include <sys/sysmp.h>
149 #include <sys/sysinfo.h> // for SAGET and MINFO structures
152 // ----------------------------------------------------------------------------
153 // conditional compilation
154 // ----------------------------------------------------------------------------
156 // many versions of Unices have this function, but it is not defined in system
157 // headers - please add your system here if it is the case for your OS.
158 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
159 #if !defined(HAVE_USLEEP) && \
160 ((defined(__SUN__) && !defined(__SunOs_5_6) && \
161 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
162 defined(__osf__) || defined(__EMX__))
166 /* I copied this from the XFree86 diffs. AV. */
167 #define INCL_DOSPROCESS
169 inline void usleep(unsigned long delay
)
171 DosSleep(delay
? (delay
/1000l) : 1l);
174 int usleep(unsigned int usec
);
175 #endif // __EMX__/Unix
178 #define HAVE_USLEEP 1
179 #endif // Unices without usleep()
181 // ============================================================================
183 // ============================================================================
185 // ----------------------------------------------------------------------------
187 // ----------------------------------------------------------------------------
189 void wxSleep(int nSecs
)
194 void wxMicroSleep(unsigned long microseconds
)
196 #if defined(HAVE_NANOSLEEP)
198 tmReq
.tv_sec
= (time_t)(microseconds
/ 1000000);
199 tmReq
.tv_nsec
= (microseconds
% 1000000) * 1000;
201 // we're not interested in remaining time nor in return value
202 (void)nanosleep(&tmReq
, (timespec
*)NULL
);
203 #elif defined(HAVE_USLEEP)
204 // uncomment this if you feel brave or if you are sure that your version
205 // of Solaris has a safe usleep() function but please notice that usleep()
206 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
207 // documented as MT-Safe
208 #if defined(__SUN__) && wxUSE_THREADS
209 #error "usleep() cannot be used in MT programs under Solaris."
212 usleep(microseconds
);
213 #elif defined(HAVE_SLEEP)
214 // under BeOS sleep() takes seconds (what about other platforms, if any?)
215 sleep(microseconds
* 1000000);
216 #else // !sleep function
217 #error "usleep() or nanosleep() function required for wxMicroSleep"
218 #endif // sleep function
221 void wxMilliSleep(unsigned long milliseconds
)
223 wxMicroSleep(milliseconds
*1000);
226 // ----------------------------------------------------------------------------
227 // process management
228 // ----------------------------------------------------------------------------
230 int wxKill(long pid
, wxSignal sig
, wxKillError
*rc
, int flags
)
232 int err
= kill((pid_t
) (flags
& wxKILL_CHILDREN
) ? -pid
: pid
, (int)sig
);
235 switch ( err
? errno
: 0 )
242 *rc
= wxKILL_BAD_SIGNAL
;
246 *rc
= wxKILL_ACCESS_DENIED
;
250 *rc
= wxKILL_NO_PROCESS
;
254 // this goes against Unix98 docs so log it
255 wxLogDebug(_T("unexpected kill(2) return value %d"), err
);
265 #define WXEXECUTE_NARGS 127
267 #if defined(__DARWIN__)
268 long wxMacExecute(wxChar
**argv
,
273 long wxExecute( const wxString
& command
, int flags
, wxProcess
*process
)
275 wxCHECK_MSG( !command
.empty(), 0, wxT("can't exec empty command") );
277 wxLogTrace(wxT("exec"), wxT("Executing \"%s\""), command
.c_str());
280 // fork() doesn't mix well with POSIX threads: on many systems the program
281 // deadlocks or crashes for some reason. Probably our code is buggy and
282 // doesn't do something which must be done to allow this to work, but I
283 // don't know what yet, so for now just warn the user (this is the least we
285 wxASSERT_MSG( wxThread::IsMain(),
286 _T("wxExecute() can be called only from the main thread") );
287 #endif // wxUSE_THREADS
290 wxChar
*argv
[WXEXECUTE_NARGS
];
292 const wxChar
*cptr
= command
.c_str();
293 wxChar quotechar
= wxT('\0'); // is arg quoted?
294 bool escaped
= false;
296 // split the command line in arguments
299 argument
= wxEmptyString
;
300 quotechar
= wxT('\0');
302 // eat leading whitespace:
303 while ( wxIsspace(*cptr
) )
306 if ( *cptr
== wxT('\'') || *cptr
== wxT('"') )
311 if ( *cptr
== wxT('\\') && ! escaped
)
318 // all other characters:
322 // have we reached the end of the argument?
323 if ( (*cptr
== quotechar
&& ! escaped
)
324 || (quotechar
== wxT('\0') && wxIsspace(*cptr
))
325 || *cptr
== wxT('\0') )
327 wxASSERT_MSG( argc
< WXEXECUTE_NARGS
,
328 wxT("too many arguments in wxExecute") );
330 argv
[argc
] = new wxChar
[argument
.length() + 1];
331 wxStrcpy(argv
[argc
], argument
.c_str());
334 // if not at end of buffer, swallow last character:
338 break; // done with this one, start over
345 #if defined(__DARWIN__)
346 // wxMacExecute only executes app bundles.
347 // It returns an error code if the target is not an app bundle, thus falling
348 // through to the regular wxExecute for non app bundles.
349 lRc
= wxMacExecute(argv
, flags
, process
);
350 if( lRc
!= ((flags
& wxEXEC_SYNC
) ? -1 : 0))
354 // do execute the command
355 lRc
= wxExecute(argv
, flags
, process
);
360 delete [] argv
[argc
++];
365 // ----------------------------------------------------------------------------
367 // ----------------------------------------------------------------------------
369 static wxString
wxMakeShellCommand(const wxString
& command
)
374 // just an interactive shell
379 // execute command in a shell
380 cmd
<< _T("/bin/sh -c '") << command
<< _T('\'');
386 bool wxShell(const wxString
& command
)
388 return wxExecute(wxMakeShellCommand(command
), wxEXEC_SYNC
) == 0;
391 bool wxShell(const wxString
& command
, wxArrayString
& output
)
393 wxCHECK_MSG( !command
.empty(), false, _T("can't exec shell non interactively") );
395 return wxExecute(wxMakeShellCommand(command
), output
);
398 // Shutdown or reboot the PC
399 bool wxShutdown(wxShutdownFlags wFlags
)
404 case wxSHUTDOWN_POWEROFF
:
408 case wxSHUTDOWN_REBOOT
:
413 wxFAIL_MSG( _T("unknown wxShutdown() flag") );
417 return system(wxString::Format(_T("init %c"), level
).mb_str()) == 0;
420 // ----------------------------------------------------------------------------
421 // wxStream classes to support IO redirection in wxExecute
422 // ----------------------------------------------------------------------------
424 #if HAS_PIPE_INPUT_STREAM
426 bool wxPipeInputStream::CanRead() const
428 if ( m_lasterror
== wxSTREAM_EOF
)
431 // check if there is any input available
436 const int fd
= m_file
->fd();
441 wxFD_SET(fd
, &readfds
);
443 switch ( select(fd
+ 1, &readfds
, NULL
, NULL
, &tv
) )
446 wxLogSysError(_("Impossible to get child process input"));
453 wxFAIL_MSG(_T("unexpected select() return value"));
454 // still fall through
457 // input available -- or maybe not, as select() returns 1 when a
458 // read() will complete without delay, but it could still not read
464 #endif // HAS_PIPE_INPUT_STREAM
466 // ----------------------------------------------------------------------------
467 // wxExecute: the real worker function
468 // ----------------------------------------------------------------------------
470 long wxExecute(wxChar
**argv
, int flags
, wxProcess
*process
)
472 // for the sync execution, we return -1 to indicate failure, but for async
473 // case we return 0 which is never a valid PID
475 // we define this as a macro, not a variable, to avoid compiler warnings
476 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
477 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
479 wxCHECK_MSG( *argv
, ERROR_RETURN_CODE
, wxT("can't exec empty command") );
483 char *mb_argv
[WXEXECUTE_NARGS
];
485 while (argv
[mb_argc
])
487 wxWX2MBbuf mb_arg
= wxSafeConvertWX2MB(argv
[mb_argc
]);
488 mb_argv
[mb_argc
] = strdup(mb_arg
);
491 mb_argv
[mb_argc
] = (char *) NULL
;
493 // this macro will free memory we used above
494 #define ARGS_CLEANUP \
495 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
496 free(mb_argv[mb_argc])
498 // no need for cleanup
501 wxChar
**mb_argv
= argv
;
502 #endif // Unicode/ANSI
504 // we want this function to work even if there is no wxApp so ensure that
505 // we have a valid traits pointer
506 wxConsoleAppTraits traitsConsole
;
507 wxAppTraits
*traits
= wxTheApp
? wxTheApp
->GetTraits() : NULL
;
509 traits
= &traitsConsole
;
511 // this struct contains all information which we pass to and from
512 // wxAppTraits methods
513 wxExecuteData execData
;
514 execData
.flags
= flags
;
515 execData
.process
= process
;
518 if ( !traits
->CreateEndProcessPipe(execData
) )
520 wxLogError( _("Failed to execute '%s'\n"), *argv
);
524 return ERROR_RETURN_CODE
;
527 // pipes for inter process communication
528 wxPipe pipeIn
, // stdin
532 if ( process
&& process
->IsRedirected() )
534 if ( !pipeIn
.Create() || !pipeOut
.Create() || !pipeErr
.Create() )
536 wxLogError( _("Failed to execute '%s'\n"), *argv
);
540 return ERROR_RETURN_CODE
;
546 // NB: do *not* use vfork() here, it completely breaks this code for some
547 // reason under Solaris (and maybe others, although not under Linux)
548 // But on OpenVMS we do not have fork so we have to use vfork and
549 // cross our fingers that it works.
555 if ( pid
== -1 ) // error?
557 wxLogSysError( _("Fork failed") );
561 return ERROR_RETURN_CODE
;
563 else if ( pid
== 0 ) // we're in child
565 // These lines close the open file descriptors to to avoid any
566 // input/output which might block the process or irritate the user. If
567 // one wants proper IO for the subprocess, the right thing to do is to
568 // start an xterm executing it.
569 if ( !(flags
& wxEXEC_SYNC
) )
571 // FD_SETSIZE is unsigned under BSD, signed under other platforms
572 // so we need a cast to avoid warnings on all platforms
573 for ( int fd
= 0; fd
< (int)FD_SETSIZE
; fd
++ )
575 if ( fd
== pipeIn
[wxPipe::Read
]
576 || fd
== pipeOut
[wxPipe::Write
]
577 || fd
== pipeErr
[wxPipe::Write
]
578 || traits
->IsWriteFDOfEndProcessPipe(execData
, fd
) )
580 // don't close this one, we still need it
584 // leave stderr opened too, it won't do any harm
585 if ( fd
!= STDERR_FILENO
)
590 #if !defined(__VMS) && !defined(__EMX__)
591 if ( flags
& wxEXEC_MAKE_GROUP_LEADER
)
593 // Set process group to child process' pid. Then killing -pid
594 // of the parent will kill the process and all of its children.
599 // reading side can be safely closed but we should keep the write one
601 traits
->DetachWriteFDOfEndProcessPipe(execData
);
603 // redirect stdin, stdout and stderr
606 if ( dup2(pipeIn
[wxPipe::Read
], STDIN_FILENO
) == -1 ||
607 dup2(pipeOut
[wxPipe::Write
], STDOUT_FILENO
) == -1 ||
608 dup2(pipeErr
[wxPipe::Write
], STDERR_FILENO
) == -1 )
610 wxLogSysError(_("Failed to redirect child process input/output"));
618 execvp (*mb_argv
, mb_argv
);
620 fprintf(stderr
, "execvp(");
621 // CS changed ppc to ppc_ as ppc is not available under mac os CW Mach-O
622 for ( char **ppc_
= mb_argv
; *ppc_
; ppc_
++ )
623 fprintf(stderr
, "%s%s", ppc_
== mb_argv
? "" : ", ", *ppc_
);
624 fprintf(stderr
, ") failed with error %d!\n", errno
);
626 // there is no return after successful exec()
629 // some compilers complain about missing return - of course, they
630 // should know that exit() doesn't return but what else can we do if
633 // and, sure enough, other compilers complain about unreachable code
634 // after exit() call, so we can just always have return here...
635 #if defined(__VMS) || defined(__INTEL_COMPILER)
639 else // we're in parent
643 // save it for WaitForChild() use
646 // prepare for IO redirection
648 #if HAS_PIPE_INPUT_STREAM
649 // the input buffer bufOut is connected to stdout, this is why it is
650 // called bufOut and not bufIn
651 wxStreamTempInputBuffer bufOut
,
653 #endif // HAS_PIPE_INPUT_STREAM
655 if ( process
&& process
->IsRedirected() )
657 #if HAS_PIPE_INPUT_STREAM
658 wxOutputStream
*inStream
=
659 new wxFileOutputStream(pipeIn
.Detach(wxPipe::Write
));
661 wxPipeInputStream
*outStream
=
662 new wxPipeInputStream(pipeOut
.Detach(wxPipe::Read
));
664 wxPipeInputStream
*errStream
=
665 new wxPipeInputStream(pipeErr
.Detach(wxPipe::Read
));
667 process
->SetPipeStreams(outStream
, inStream
, errStream
);
669 bufOut
.Init(outStream
);
670 bufErr
.Init(errStream
);
672 execData
.bufOut
= &bufOut
;
673 execData
.bufErr
= &bufErr
;
674 #endif // HAS_PIPE_INPUT_STREAM
684 return traits
->WaitForChild(execData
);
687 #if !defined(__VMS) && !defined(__INTEL_COMPILER)
688 return ERROR_RETURN_CODE
;
692 #undef ERROR_RETURN_CODE
695 // ----------------------------------------------------------------------------
696 // file and directory functions
697 // ----------------------------------------------------------------------------
699 const wxChar
* wxGetHomeDir( wxString
*home
)
701 *home
= wxGetUserHome();
707 if ( tmp
.Last() != wxT(']'))
708 if ( tmp
.Last() != wxT('/')) *home
<< wxT('/');
710 return home
->c_str();
713 wxString
wxGetUserHome( const wxString
&user
)
715 struct passwd
*who
= (struct passwd
*) NULL
;
721 if ((ptr
= wxGetenv(wxT("HOME"))) != NULL
)
726 if ((ptr
= wxGetenv(wxT("USER"))) != NULL
||
727 (ptr
= wxGetenv(wxT("LOGNAME"))) != NULL
)
729 who
= getpwnam(wxSafeConvertWX2MB(ptr
));
732 // make sure the user exists!
735 who
= getpwuid(getuid());
740 who
= getpwnam (user
.mb_str());
743 return wxSafeConvertMB2WX(who
? who
->pw_dir
: 0);
746 // ----------------------------------------------------------------------------
747 // network and user id routines
748 // ----------------------------------------------------------------------------
750 // private utility function which returns output of the given command, removing
751 // the trailing newline
752 static wxString
wxGetCommandOutput(const wxString
&cmd
)
754 FILE *f
= popen(cmd
.ToAscii(), "r");
757 wxLogSysError(_T("Executing \"%s\" failed"), cmd
.c_str());
758 return wxEmptyString
;
765 if ( !fgets(buf
, sizeof(buf
), f
) )
768 s
+= wxString::FromAscii(buf
);
773 if ( !s
.empty() && s
.Last() == _T('\n') )
779 // retrieve either the hostname or FQDN depending on platform (caller must
780 // check whether it's one or the other, this is why this function is for
782 static bool wxGetHostNameInternal(wxChar
*buf
, int sz
)
784 wxCHECK_MSG( buf
, false, wxT("NULL pointer in wxGetHostNameInternal") );
788 // we're using uname() which is POSIX instead of less standard sysinfo()
789 #if defined(HAVE_UNAME)
791 bool ok
= uname(&uts
) != -1;
794 wxStrncpy(buf
, wxSafeConvertMB2WX(uts
.nodename
), sz
- 1);
797 #elif defined(HAVE_GETHOSTNAME)
799 bool ok
= gethostname(cbuf
, sz
) != -1;
802 wxStrncpy(buf
, wxSafeConvertMB2WX(cbuf
), sz
- 1);
805 #else // no uname, no gethostname
806 wxFAIL_MSG(wxT("don't know host name for this machine"));
809 #endif // uname/gethostname
813 wxLogSysError(_("Cannot get the hostname"));
819 bool wxGetHostName(wxChar
*buf
, int sz
)
821 bool ok
= wxGetHostNameInternal(buf
, sz
);
825 // BSD systems return the FQDN, we only want the hostname, so extract
826 // it (we consider that dots are domain separators)
827 wxChar
*dot
= wxStrchr(buf
, wxT('.'));
838 bool wxGetFullHostName(wxChar
*buf
, int sz
)
840 bool ok
= wxGetHostNameInternal(buf
, sz
);
844 if ( !wxStrchr(buf
, wxT('.')) )
846 struct hostent
*host
= gethostbyname(wxSafeConvertWX2MB(buf
));
849 wxLogSysError(_("Cannot get the official hostname"));
855 // the canonical name
856 wxStrncpy(buf
, wxSafeConvertMB2WX(host
->h_name
), sz
);
859 //else: it's already a FQDN (BSD behaves this way)
865 bool wxGetUserId(wxChar
*buf
, int sz
)
870 if ((who
= getpwuid(getuid ())) != NULL
)
872 wxStrncpy (buf
, wxSafeConvertMB2WX(who
->pw_name
), sz
- 1);
879 bool wxGetUserName(wxChar
*buf
, int sz
)
885 if ((who
= getpwuid (getuid ())) != NULL
)
887 char *comma
= strchr(who
->pw_gecos
, ',');
889 *comma
= '\0'; // cut off non-name comment fields
890 wxStrncpy (buf
, wxSafeConvertMB2WX(who
->pw_gecos
), sz
- 1);
895 #else // !HAVE_PW_GECOS
896 return wxGetUserId(buf
, sz
);
897 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
900 bool wxIsPlatform64Bit()
902 const wxString machine
= wxGetCommandOutput(wxT("uname -m"));
904 // the test for "64" is obviously not 100% reliable but seems to work fine
906 return machine
.Contains(wxT("64")) ||
907 machine
.Contains(wxT("alpha"));
910 // these functions are in mac/utils.cpp for wxMac
913 wxOperatingSystemId
wxGetOsVersion(int *verMaj
, int *verMin
)
917 wxString release
= wxGetCommandOutput(wxT("uname -r"));
918 if ( release
.empty() ||
919 wxSscanf(release
.c_str(), wxT("%d.%d"), &major
, &minor
) != 2 )
921 // failed to get version string or unrecognized format
931 // try to understand which OS are we running
932 wxString kernel
= wxGetCommandOutput(wxT("uname -s"));
933 if ( kernel
.empty() )
934 kernel
= wxGetCommandOutput(wxT("uname -o"));
936 if ( kernel
.empty() )
939 return wxPlatformInfo::GetOperatingSystemId(kernel
);
942 wxString
wxGetOsDescription()
944 return wxGetCommandOutput(wxT("uname -s -r -m"));
949 unsigned long wxGetProcessId()
951 return (unsigned long)getpid();
954 wxMemorySize
wxGetFreeMemory()
956 #if defined(__LINUX__)
957 // get it from /proc/meminfo
958 FILE *fp
= fopen("/proc/meminfo", "r");
964 if ( fgets(buf
, WXSIZEOF(buf
), fp
) && fgets(buf
, WXSIZEOF(buf
), fp
) )
966 // /proc/meminfo changed its format in kernel 2.6
967 if ( wxPlatformInfo().CheckOSVersion(2, 6) )
969 unsigned long cached
, buffers
;
970 sscanf(buf
, "MemFree: %ld", &memFree
);
972 fgets(buf
, WXSIZEOF(buf
), fp
);
973 sscanf(buf
, "Buffers: %lu", &buffers
);
975 fgets(buf
, WXSIZEOF(buf
), fp
);
976 sscanf(buf
, "Cached: %lu", &cached
);
978 // add to "MemFree" also the "Buffers" and "Cached" values as
979 // free(1) does as otherwise the value never makes sense: for
980 // kernel 2.6 it's always almost 0
981 memFree
+= buffers
+ cached
;
983 // values here are always expressed in kB and we want bytes
986 else // Linux 2.4 (or < 2.6, anyhow)
988 long memTotal
, memUsed
;
989 sscanf(buf
, "Mem: %ld %ld %ld", &memTotal
, &memUsed
, &memFree
);
995 return (wxMemorySize
)memFree
;
997 #elif defined(__SGI__)
998 struct rminfo realmem
;
999 if ( sysmp(MP_SAGET
, MPSA_RMINFO
, &realmem
, sizeof realmem
) == 0 )
1000 return ((wxMemorySize
)realmem
.physmem
* sysconf(_SC_PAGESIZE
));
1001 #elif defined(_SC_AVPHYS_PAGES)
1002 return ((wxMemorySize
)sysconf(_SC_AVPHYS_PAGES
))*sysconf(_SC_PAGESIZE
);
1003 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1006 // can't find it out
1010 bool wxGetDiskSpace(const wxString
& path
, wxDiskspaceSize_t
*pTotal
, wxDiskspaceSize_t
*pFree
)
1012 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
1013 // the case to "char *" is needed for AIX 4.3
1015 if ( wxStatfs((char *)(const char*)path
.fn_str(), &fs
) != 0 )
1017 wxLogSysError( wxT("Failed to get file system statistics") );
1022 // under Solaris we also have to use f_frsize field instead of f_bsize
1023 // which is in general a multiple of f_frsize
1025 wxDiskspaceSize_t blockSize
= fs
.f_frsize
;
1026 #else // HAVE_STATFS
1027 wxDiskspaceSize_t blockSize
= fs
.f_bsize
;
1028 #endif // HAVE_STATVFS/HAVE_STATFS
1032 *pTotal
= wxDiskspaceSize_t(fs
.f_blocks
) * blockSize
;
1037 *pFree
= wxDiskspaceSize_t(fs
.f_bavail
) * blockSize
;
1041 #else // !HAVE_STATFS && !HAVE_STATVFS
1043 #endif // HAVE_STATFS
1046 // ----------------------------------------------------------------------------
1048 // ----------------------------------------------------------------------------
1052 WX_DECLARE_STRING_HASH_MAP(char *, wxEnvVars
);
1054 static wxEnvVars gs_envVars
;
1056 class wxSetEnvModule
: public wxModule
1059 virtual bool OnInit() { return true; }
1060 virtual void OnExit()
1062 for ( wxEnvVars::const_iterator i
= gs_envVars
.begin();
1063 i
!= gs_envVars
.end();
1072 DECLARE_DYNAMIC_CLASS(wxSetEnvModule
)
1075 IMPLEMENT_DYNAMIC_CLASS(wxSetEnvModule
, wxModule
)
1077 #endif // USE_PUTENV
1079 bool wxGetEnv(const wxString
& var
, wxString
*value
)
1081 // wxGetenv is defined as getenv()
1082 char *p
= wxGetenv(var
);
1094 static bool wxDoSetEnv(const wxString
& variable
, const char *value
)
1096 #if defined(HAVE_SETENV)
1099 #ifdef HAVE_UNSETENV
1100 // don't test unsetenv() return value: it's void on some systems (at
1102 unsetenv(variable
.mb_str());
1105 value
= ""; // we can't pass NULL to setenv()
1109 return setenv(variable
.mb_str(), value
, 1 /* overwrite */) == 0;
1110 #elif defined(HAVE_PUTENV)
1111 wxString s
= variable
;
1113 s
<< _T('=') << value
;
1115 // transform to ANSI
1116 const wxWX2MBbuf p
= s
.mb_str();
1118 char *buf
= (char *)malloc(strlen(p
) + 1);
1121 // store the string to free() it later
1122 wxEnvVars::iterator i
= gs_envVars
.find(variable
);
1123 if ( i
!= gs_envVars
.end() )
1128 else // this variable hadn't been set before
1130 gs_envVars
[variable
] = buf
;
1133 return putenv(buf
) == 0;
1134 #else // no way to set an env var
1139 bool wxSetEnv(const wxString
& variable
, const wxString
& value
)
1141 return wxDoSetEnv(variable
, value
.mb_str());
1144 bool wxUnsetEnv(const wxString
& variable
)
1146 return wxDoSetEnv(variable
, NULL
);
1149 // ----------------------------------------------------------------------------
1151 // ----------------------------------------------------------------------------
1153 #if wxUSE_ON_FATAL_EXCEPTION
1157 extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER
)
1161 // give the user a chance to do something special about this
1162 wxTheApp
->OnFatalException();
1168 bool wxHandleFatalExceptions(bool doit
)
1171 static bool s_savedHandlers
= false;
1172 static struct sigaction s_handlerFPE
,
1178 if ( doit
&& !s_savedHandlers
)
1180 // install the signal handler
1181 struct sigaction act
;
1183 // some systems extend it with non std fields, so zero everything
1184 memset(&act
, 0, sizeof(act
));
1186 act
.sa_handler
= wxFatalSignalHandler
;
1187 sigemptyset(&act
.sa_mask
);
1190 ok
&= sigaction(SIGFPE
, &act
, &s_handlerFPE
) == 0;
1191 ok
&= sigaction(SIGILL
, &act
, &s_handlerILL
) == 0;
1192 ok
&= sigaction(SIGBUS
, &act
, &s_handlerBUS
) == 0;
1193 ok
&= sigaction(SIGSEGV
, &act
, &s_handlerSEGV
) == 0;
1196 wxLogDebug(_T("Failed to install our signal handler."));
1199 s_savedHandlers
= true;
1201 else if ( s_savedHandlers
)
1203 // uninstall the signal handler
1204 ok
&= sigaction(SIGFPE
, &s_handlerFPE
, NULL
) == 0;
1205 ok
&= sigaction(SIGILL
, &s_handlerILL
, NULL
) == 0;
1206 ok
&= sigaction(SIGBUS
, &s_handlerBUS
, NULL
) == 0;
1207 ok
&= sigaction(SIGSEGV
, &s_handlerSEGV
, NULL
) == 0;
1210 wxLogDebug(_T("Failed to uninstall our signal handler."));
1213 s_savedHandlers
= false;
1215 //else: nothing to do
1220 #endif // wxUSE_ON_FATAL_EXCEPTION
1222 // ----------------------------------------------------------------------------
1223 // wxExecute support
1224 // ----------------------------------------------------------------------------
1226 bool wxAppTraits::CreateEndProcessPipe(wxExecuteData
& execData
)
1228 return execData
.pipeEndProcDetect
.Create();
1231 bool wxAppTraits::IsWriteFDOfEndProcessPipe(wxExecuteData
& execData
, int fd
)
1233 return fd
== (execData
.pipeEndProcDetect
)[wxPipe::Write
];
1236 void wxAppTraits::DetachWriteFDOfEndProcessPipe(wxExecuteData
& execData
)
1238 execData
.pipeEndProcDetect
.Detach(wxPipe::Write
);
1239 execData
.pipeEndProcDetect
.Close();
1242 int wxAppTraits::AddProcessCallback(wxEndProcessData
*data
, int fd
)
1244 // define a custom handler processing only the closure of the descriptor
1245 struct wxEndProcessFDIOHandler
: public wxFDIOHandler
1247 wxEndProcessFDIOHandler(wxEndProcessData
*data
, int fd
)
1248 : m_data(data
), m_fd(fd
)
1251 virtual void OnReadWaiting()
1252 { wxFAIL_MSG("this isn't supposed to happen"); }
1253 virtual void OnWriteWaiting()
1254 { wxFAIL_MSG("this isn't supposed to happen"); }
1256 virtual void OnExceptionWaiting()
1258 const int pid
= m_data
->pid
> 0 ? m_data
->pid
: -(m_data
->pid
);
1261 // has the process really terminated?
1262 int rc
= waitpid(pid
, &status
, WNOHANG
);
1265 // This can only happen if the child application closes our
1266 // dummy pipe that is used to monitor its lifetime; in that
1267 // case, our best bet is to pretend the process did terminate,
1268 // because otherwise wxExecute() would hang indefinitely
1269 // (OnExceptionWaiting() won't be called again, the descriptor
1271 wxLogDebug("Child process (PID %d) still alive, "
1272 "even though pipe was closed.", pid
);
1274 else if ( rc
== -1 )
1276 // As above, if waitpid() fails, the best we can do is to log the
1277 // error and pretend the child terminated:
1278 wxLogSysError(_("Failed to check child process' status"));
1281 // set exit code to -1 if something bad happened
1282 m_data
->exitcode
= rc
> 0 && WIFEXITED(status
) ? WEXITSTATUS(status
)
1286 "Child process (PID %d) terminated with exit code %d",
1287 pid
, m_data
->exitcode
);
1289 // child exited, end waiting
1290 wxFDIODispatcher::Get()->UnregisterFD(m_fd
);
1293 wxHandleProcessTermination(m_data
);
1298 wxEndProcessData
* const m_data
;
1302 wxFDIODispatcher::Get()->RegisterFD
1305 new wxEndProcessFDIOHandler(data
, fd
),
1308 return fd
; // unused, but return something unique for the tag
1311 bool wxAppTraits::CheckForRedirectedIO(wxExecuteData
& execData
)
1313 #if HAS_PIPE_INPUT_STREAM
1316 if ( execData
.bufOut
&& execData
.bufOut
->Update() )
1319 if ( execData
.bufErr
&& execData
.bufErr
->Update() )
1323 #else // !HAS_PIPE_INPUT_STREAM
1325 #endif // HAS_PIPE_INPUT_STREAM/!HAS_PIPE_INPUT_STREAM
1328 int wxAppTraits::WaitForChild(wxExecuteData
& execData
)
1330 if ( execData
.flags
& wxEXEC_SYNC
)
1332 // just block waiting for the child to exit
1335 int result
= waitpid(execData
.pid
, &status
, 0);
1337 /* DE: waitpid manpage states that waitpid can fail with EINTR
1338 if the call is interrupted by a caught signal. I suppose
1339 that means that this ought to be a while loop.
1341 The odd thing is that it seems to fail EVERY time. It fails
1342 with a quickly exiting process (e.g. echo), and fails with a
1343 slowly exiting process (e.g. sleep 2) but clearly after
1344 having waited for the child to exit. Maybe it's a bug in
1345 my particular version.
1347 It works, however, from the CFSocket callback without this
1348 trick but in that case it's used only after CFSocket calls
1349 the callback and with the WNOHANG flag which would seem to
1350 preclude it from being interrupted or at least make it much
1351 less likely since it would not then be waiting.
1353 If Darwin's man page is to be believed then this is definitely
1354 necessary. It's just weird that I've never seen it before
1355 and apparently no one else has either or you'd think they'd
1356 have reported it by now. Perhaps blocking the GUI while
1357 waiting for a child process to exit is simply not that common.
1359 if ( result
== -1 && errno
== EINTR
)
1361 result
= waitpid(execData
.pid
, &status
, 0);
1363 #endif // __DARWIN__
1367 wxLogLastError("waitpid");
1369 else // child terminated
1371 wxASSERT_MSG( result
== execData
.pid
,
1372 "unexpected waitpid() return value" );
1374 if ( WIFEXITED(status
) )
1376 return WEXITSTATUS(status
);
1378 else // abnormal termination?
1380 wxASSERT_MSG( WIFSIGNALED(status
),
1381 "unexpected child wait status" );
1385 wxLogSysError(_("Waiting for subprocess termination failed"));
1389 else // asynchronous execution
1391 wxEndProcessData
*endProcData
= new wxEndProcessData
;
1392 endProcData
->process
= execData
.process
;
1393 endProcData
->pid
= execData
.pid
;
1394 endProcData
->tag
= AddProcessCallback
1397 execData
.pipeEndProcDetect
.Detach(wxPipe::Read
)
1400 execData
.pipeEndProcDetect
.Close();
1401 return execData
.pid
;
1406 void wxHandleProcessTermination(wxEndProcessData
*proc_data
)
1408 // notify user about termination if required
1409 if ( proc_data
->process
)
1411 proc_data
->process
->OnTerminate(proc_data
->pid
, proc_data
->exitcode
);
1415 if ( proc_data
->pid
> 0 )
1420 else // sync execution
1422 // let wxExecute() know that the process has terminated