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"
47 #ifdef wxHAS_GENERIC_PROCESS_CALLBACK
48 #include "wx/private/fdiodispatcher.h"
52 #include <sys/wait.h> // waitpid()
54 #ifdef HAVE_SYS_SELECT_H
55 # include <sys/select.h>
58 #define HAS_PIPE_INPUT_STREAM (wxUSE_STREAMS && wxUSE_FILE)
60 #if HAS_PIPE_INPUT_STREAM
62 // define this to let wxexec.cpp know that we know what we're doing
63 #define _WX_USED_BY_WXEXECUTE_
64 #include "../common/execcmn.cpp"
66 #endif // HAS_PIPE_INPUT_STREAM
70 #if defined(__MWERKS__) && defined(__MACH__)
71 #ifndef WXWIN_OS_DESCRIPTION
72 #define WXWIN_OS_DESCRIPTION "MacOS X"
74 #ifndef HAVE_NANOSLEEP
75 #define HAVE_NANOSLEEP
81 // our configure test believes we can use sigaction() if the function is
82 // available but Metrowekrs with MSL run-time does have the function but
83 // doesn't have sigaction struct so finally we can't use it...
85 #undef wxUSE_ON_FATAL_EXCEPTION
86 #define wxUSE_ON_FATAL_EXCEPTION 0
90 // not only the statfs syscall is called differently depending on platform, but
91 // one of its incarnations, statvfs(), takes different arguments under
92 // different platforms and even different versions of the same system (Solaris
93 // 7 and 8): if you want to test for this, don't forget that the problems only
94 // appear if the large files support is enabled
97 #include <sys/param.h>
98 #include <sys/mount.h>
101 #endif // __BSD__/!__BSD__
103 #define wxStatfs statfs
105 #ifndef HAVE_STATFS_DECL
106 // some systems lack statfs() prototype in the system headers (AIX 4)
107 extern "C" int statfs(const char *path
, struct statfs
*buf
);
109 #endif // HAVE_STATFS
112 #include <sys/statvfs.h>
114 #define wxStatfs statvfs
115 #endif // HAVE_STATVFS
117 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
118 // WX_STATFS_T is detected by configure
119 #define wxStatfs_t WX_STATFS_T
122 // SGI signal.h defines signal handler arguments differently depending on
123 // whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
124 #if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
125 #define _LANGUAGE_C_PLUS_PLUS 1
131 #include <sys/stat.h>
132 #include <sys/types.h>
133 #include <sys/wait.h>
138 #include <fcntl.h> // for O_WRONLY and friends
139 #include <time.h> // nanosleep() and/or usleep()
140 #include <ctype.h> // isspace()
141 #include <sys/time.h> // needed for FD_SETSIZE
144 #include <sys/utsname.h> // for uname()
147 // Used by wxGetFreeMemory().
149 #include <sys/sysmp.h>
150 #include <sys/sysinfo.h> // for SAGET and MINFO structures
153 // ----------------------------------------------------------------------------
154 // conditional compilation
155 // ----------------------------------------------------------------------------
157 // many versions of Unices have this function, but it is not defined in system
158 // headers - please add your system here if it is the case for your OS.
159 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
160 #if !defined(HAVE_USLEEP) && \
161 ((defined(__SUN__) && !defined(__SunOs_5_6) && \
162 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
163 defined(__osf__) || defined(__EMX__))
167 /* I copied this from the XFree86 diffs. AV. */
168 #define INCL_DOSPROCESS
170 inline void usleep(unsigned long delay
)
172 DosSleep(delay
? (delay
/1000l) : 1l);
175 int usleep(unsigned int usec
);
176 #endif // __EMX__/Unix
179 #define HAVE_USLEEP 1
180 #endif // Unices without usleep()
182 // ============================================================================
184 // ============================================================================
186 // ----------------------------------------------------------------------------
188 // ----------------------------------------------------------------------------
190 void wxSleep(int nSecs
)
195 void wxMicroSleep(unsigned long microseconds
)
197 #if defined(HAVE_NANOSLEEP)
199 tmReq
.tv_sec
= (time_t)(microseconds
/ 1000000);
200 tmReq
.tv_nsec
= (microseconds
% 1000000) * 1000;
202 // we're not interested in remaining time nor in return value
203 (void)nanosleep(&tmReq
, (timespec
*)NULL
);
204 #elif defined(HAVE_USLEEP)
205 // uncomment this if you feel brave or if you are sure that your version
206 // of Solaris has a safe usleep() function but please notice that usleep()
207 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
208 // documented as MT-Safe
209 #if defined(__SUN__) && wxUSE_THREADS
210 #error "usleep() cannot be used in MT programs under Solaris."
213 usleep(microseconds
);
214 #elif defined(HAVE_SLEEP)
215 // under BeOS sleep() takes seconds (what about other platforms, if any?)
216 sleep(microseconds
* 1000000);
217 #else // !sleep function
218 #error "usleep() or nanosleep() function required for wxMicroSleep"
219 #endif // sleep function
222 void wxMilliSleep(unsigned long milliseconds
)
224 wxMicroSleep(milliseconds
*1000);
227 // ----------------------------------------------------------------------------
228 // process management
229 // ----------------------------------------------------------------------------
231 int wxKill(long pid
, wxSignal sig
, wxKillError
*rc
, int flags
)
233 int err
= kill((pid_t
) (flags
& wxKILL_CHILDREN
) ? -pid
: pid
, (int)sig
);
236 switch ( err
? errno
: 0 )
243 *rc
= wxKILL_BAD_SIGNAL
;
247 *rc
= wxKILL_ACCESS_DENIED
;
251 *rc
= wxKILL_NO_PROCESS
;
255 // this goes against Unix98 docs so log it
256 wxLogDebug(_T("unexpected kill(2) return value %d"), err
);
266 #define WXEXECUTE_NARGS 127
268 #if defined(__DARWIN__)
269 long wxMacExecute(wxChar
**argv
,
274 long wxExecute( const wxString
& command
, int flags
, wxProcess
*process
)
276 wxCHECK_MSG( !command
.empty(), 0, wxT("can't exec empty command") );
278 wxLogTrace(wxT("exec"), wxT("Executing \"%s\""), command
.c_str());
281 // fork() doesn't mix well with POSIX threads: on many systems the program
282 // deadlocks or crashes for some reason. Probably our code is buggy and
283 // doesn't do something which must be done to allow this to work, but I
284 // don't know what yet, so for now just warn the user (this is the least we
286 wxASSERT_MSG( wxThread::IsMain(),
287 _T("wxExecute() can be called only from the main thread") );
288 #endif // wxUSE_THREADS
291 wxChar
*argv
[WXEXECUTE_NARGS
];
293 const wxChar
*cptr
= command
.c_str();
294 wxChar quotechar
= wxT('\0'); // is arg quoted?
295 bool escaped
= false;
297 // split the command line in arguments
300 argument
= wxEmptyString
;
301 quotechar
= wxT('\0');
303 // eat leading whitespace:
304 while ( wxIsspace(*cptr
) )
307 if ( *cptr
== wxT('\'') || *cptr
== wxT('"') )
312 if ( *cptr
== wxT('\\') && ! escaped
)
319 // all other characters:
323 // have we reached the end of the argument?
324 if ( (*cptr
== quotechar
&& ! escaped
)
325 || (quotechar
== wxT('\0') && wxIsspace(*cptr
))
326 || *cptr
== wxT('\0') )
328 wxASSERT_MSG( argc
< WXEXECUTE_NARGS
,
329 wxT("too many arguments in wxExecute") );
331 argv
[argc
] = new wxChar
[argument
.length() + 1];
332 wxStrcpy(argv
[argc
], argument
.c_str());
335 // if not at end of buffer, swallow last character:
339 break; // done with this one, start over
346 #if defined(__DARWIN__)
347 // wxMacExecute only executes app bundles.
348 // It returns an error code if the target is not an app bundle, thus falling
349 // through to the regular wxExecute for non app bundles.
350 lRc
= wxMacExecute(argv
, flags
, process
);
351 if( lRc
!= ((flags
& wxEXEC_SYNC
) ? -1 : 0))
355 // do execute the command
356 lRc
= wxExecute(argv
, flags
, process
);
361 delete [] argv
[argc
++];
366 // ----------------------------------------------------------------------------
368 // ----------------------------------------------------------------------------
370 static wxString
wxMakeShellCommand(const wxString
& command
)
375 // just an interactive shell
380 // execute command in a shell
381 cmd
<< _T("/bin/sh -c '") << command
<< _T('\'');
387 bool wxShell(const wxString
& command
)
389 return wxExecute(wxMakeShellCommand(command
), wxEXEC_SYNC
) == 0;
392 bool wxShell(const wxString
& command
, wxArrayString
& output
)
394 wxCHECK_MSG( !command
.empty(), false, _T("can't exec shell non interactively") );
396 return wxExecute(wxMakeShellCommand(command
), output
);
399 // Shutdown or reboot the PC
400 bool wxShutdown(wxShutdownFlags wFlags
)
405 case wxSHUTDOWN_POWEROFF
:
409 case wxSHUTDOWN_REBOOT
:
414 wxFAIL_MSG( _T("unknown wxShutdown() flag") );
418 return system(wxString::Format(_T("init %c"), level
).mb_str()) == 0;
421 // ----------------------------------------------------------------------------
422 // wxStream classes to support IO redirection in wxExecute
423 // ----------------------------------------------------------------------------
425 #if HAS_PIPE_INPUT_STREAM
427 bool wxPipeInputStream::CanRead() const
429 if ( m_lasterror
== wxSTREAM_EOF
)
432 // check if there is any input available
437 const int fd
= m_file
->fd();
442 wxFD_SET(fd
, &readfds
);
444 switch ( select(fd
+ 1, &readfds
, NULL
, NULL
, &tv
) )
447 wxLogSysError(_("Impossible to get child process input"));
454 wxFAIL_MSG(_T("unexpected select() return value"));
455 // still fall through
458 // input available -- or maybe not, as select() returns 1 when a
459 // read() will complete without delay, but it could still not read
465 #endif // HAS_PIPE_INPUT_STREAM
467 // ----------------------------------------------------------------------------
468 // wxExecute: the real worker function
469 // ----------------------------------------------------------------------------
471 long wxExecute(wxChar
**argv
, int flags
, wxProcess
*process
)
473 // for the sync execution, we return -1 to indicate failure, but for async
474 // case we return 0 which is never a valid PID
476 // we define this as a macro, not a variable, to avoid compiler warnings
477 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
478 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
480 wxCHECK_MSG( *argv
, ERROR_RETURN_CODE
, wxT("can't exec empty command") );
484 char *mb_argv
[WXEXECUTE_NARGS
];
486 while (argv
[mb_argc
])
488 wxWX2MBbuf mb_arg
= wxSafeConvertWX2MB(argv
[mb_argc
]);
489 mb_argv
[mb_argc
] = strdup(mb_arg
);
492 mb_argv
[mb_argc
] = (char *) NULL
;
494 // this macro will free memory we used above
495 #define ARGS_CLEANUP \
496 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
497 free(mb_argv[mb_argc])
499 // no need for cleanup
502 wxChar
**mb_argv
= argv
;
503 #endif // Unicode/ANSI
505 // we want this function to work even if there is no wxApp so ensure that
506 // we have a valid traits pointer
507 wxConsoleAppTraits traitsConsole
;
508 wxAppTraits
*traits
= wxTheApp
? wxTheApp
->GetTraits() : NULL
;
510 traits
= &traitsConsole
;
512 // this struct contains all information which we pass to and from
513 // wxAppTraits methods
514 wxExecuteData execData
;
515 execData
.flags
= flags
;
516 execData
.process
= process
;
519 if ( !traits
->CreateEndProcessPipe(execData
) )
521 wxLogError( _("Failed to execute '%s'\n"), *argv
);
525 return ERROR_RETURN_CODE
;
528 // pipes for inter process communication
529 wxPipe pipeIn
, // stdin
533 if ( process
&& process
->IsRedirected() )
535 if ( !pipeIn
.Create() || !pipeOut
.Create() || !pipeErr
.Create() )
537 wxLogError( _("Failed to execute '%s'\n"), *argv
);
541 return ERROR_RETURN_CODE
;
547 // NB: do *not* use vfork() here, it completely breaks this code for some
548 // reason under Solaris (and maybe others, although not under Linux)
549 // But on OpenVMS we do not have fork so we have to use vfork and
550 // cross our fingers that it works.
556 if ( pid
== -1 ) // error?
558 wxLogSysError( _("Fork failed") );
562 return ERROR_RETURN_CODE
;
564 else if ( pid
== 0 ) // we're in child
566 // These lines close the open file descriptors to to avoid any
567 // input/output which might block the process or irritate the user. If
568 // one wants proper IO for the subprocess, the right thing to do is to
569 // start an xterm executing it.
570 if ( !(flags
& wxEXEC_SYNC
) )
572 // FD_SETSIZE is unsigned under BSD, signed under other platforms
573 // so we need a cast to avoid warnings on all platforms
574 for ( int fd
= 0; fd
< (int)FD_SETSIZE
; fd
++ )
576 if ( fd
== pipeIn
[wxPipe::Read
]
577 || fd
== pipeOut
[wxPipe::Write
]
578 || fd
== pipeErr
[wxPipe::Write
]
579 || traits
->IsWriteFDOfEndProcessPipe(execData
, fd
) )
581 // don't close this one, we still need it
585 // leave stderr opened too, it won't do any harm
586 if ( fd
!= STDERR_FILENO
)
591 #if !defined(__VMS) && !defined(__EMX__)
592 if ( flags
& wxEXEC_MAKE_GROUP_LEADER
)
594 // Set process group to child process' pid. Then killing -pid
595 // of the parent will kill the process and all of its children.
600 // reading side can be safely closed but we should keep the write one
602 traits
->DetachWriteFDOfEndProcessPipe(execData
);
604 // redirect stdin, stdout and stderr
607 if ( dup2(pipeIn
[wxPipe::Read
], STDIN_FILENO
) == -1 ||
608 dup2(pipeOut
[wxPipe::Write
], STDOUT_FILENO
) == -1 ||
609 dup2(pipeErr
[wxPipe::Write
], STDERR_FILENO
) == -1 )
611 wxLogSysError(_("Failed to redirect child process input/output"));
619 execvp (*mb_argv
, mb_argv
);
621 fprintf(stderr
, "execvp(");
622 // CS changed ppc to ppc_ as ppc is not available under mac os CW Mach-O
623 for ( char **ppc_
= mb_argv
; *ppc_
; ppc_
++ )
624 fprintf(stderr
, "%s%s", ppc_
== mb_argv
? "" : ", ", *ppc_
);
625 fprintf(stderr
, ") failed with error %d!\n", errno
);
627 // there is no return after successful exec()
630 // some compilers complain about missing return - of course, they
631 // should know that exit() doesn't return but what else can we do if
634 // and, sure enough, other compilers complain about unreachable code
635 // after exit() call, so we can just always have return here...
636 #if defined(__VMS) || defined(__INTEL_COMPILER)
640 else // we're in parent
644 // save it for WaitForChild() use
647 // prepare for IO redirection
649 #if HAS_PIPE_INPUT_STREAM
650 // the input buffer bufOut is connected to stdout, this is why it is
651 // called bufOut and not bufIn
652 wxStreamTempInputBuffer bufOut
,
654 #endif // HAS_PIPE_INPUT_STREAM
656 if ( process
&& process
->IsRedirected() )
658 #if HAS_PIPE_INPUT_STREAM
659 wxOutputStream
*inStream
=
660 new wxFileOutputStream(pipeIn
.Detach(wxPipe::Write
));
662 wxPipeInputStream
*outStream
=
663 new wxPipeInputStream(pipeOut
.Detach(wxPipe::Read
));
665 wxPipeInputStream
*errStream
=
666 new wxPipeInputStream(pipeErr
.Detach(wxPipe::Read
));
668 process
->SetPipeStreams(outStream
, inStream
, errStream
);
670 bufOut
.Init(outStream
);
671 bufErr
.Init(errStream
);
673 execData
.bufOut
= &bufOut
;
674 execData
.bufErr
= &bufErr
;
675 #endif // HAS_PIPE_INPUT_STREAM
685 return traits
->WaitForChild(execData
);
688 #if !defined(__VMS) && !defined(__INTEL_COMPILER)
689 return ERROR_RETURN_CODE
;
693 #undef ERROR_RETURN_CODE
696 // ----------------------------------------------------------------------------
697 // file and directory functions
698 // ----------------------------------------------------------------------------
700 const wxChar
* wxGetHomeDir( wxString
*home
)
702 *home
= wxGetUserHome();
708 if ( tmp
.Last() != wxT(']'))
709 if ( tmp
.Last() != wxT('/')) *home
<< wxT('/');
711 return home
->c_str();
714 wxString
wxGetUserHome( const wxString
&user
)
716 struct passwd
*who
= (struct passwd
*) NULL
;
722 if ((ptr
= wxGetenv(wxT("HOME"))) != NULL
)
727 if ((ptr
= wxGetenv(wxT("USER"))) != NULL
||
728 (ptr
= wxGetenv(wxT("LOGNAME"))) != NULL
)
730 who
= getpwnam(wxSafeConvertWX2MB(ptr
));
733 // make sure the user exists!
736 who
= getpwuid(getuid());
741 who
= getpwnam (user
.mb_str());
744 return wxSafeConvertMB2WX(who
? who
->pw_dir
: 0);
747 // ----------------------------------------------------------------------------
748 // network and user id routines
749 // ----------------------------------------------------------------------------
751 // private utility function which returns output of the given command, removing
752 // the trailing newline
753 static wxString
wxGetCommandOutput(const wxString
&cmd
)
755 FILE *f
= popen(cmd
.ToAscii(), "r");
758 wxLogSysError(_T("Executing \"%s\" failed"), cmd
.c_str());
759 return wxEmptyString
;
766 if ( !fgets(buf
, sizeof(buf
), f
) )
769 s
+= wxString::FromAscii(buf
);
774 if ( !s
.empty() && s
.Last() == _T('\n') )
780 // retrieve either the hostname or FQDN depending on platform (caller must
781 // check whether it's one or the other, this is why this function is for
783 static bool wxGetHostNameInternal(wxChar
*buf
, int sz
)
785 wxCHECK_MSG( buf
, false, wxT("NULL pointer in wxGetHostNameInternal") );
789 // we're using uname() which is POSIX instead of less standard sysinfo()
790 #if defined(HAVE_UNAME)
792 bool ok
= uname(&uts
) != -1;
795 wxStrncpy(buf
, wxSafeConvertMB2WX(uts
.nodename
), sz
- 1);
798 #elif defined(HAVE_GETHOSTNAME)
800 bool ok
= gethostname(cbuf
, sz
) != -1;
803 wxStrncpy(buf
, wxSafeConvertMB2WX(cbuf
), sz
- 1);
806 #else // no uname, no gethostname
807 wxFAIL_MSG(wxT("don't know host name for this machine"));
810 #endif // uname/gethostname
814 wxLogSysError(_("Cannot get the hostname"));
820 bool wxGetHostName(wxChar
*buf
, int sz
)
822 bool ok
= wxGetHostNameInternal(buf
, sz
);
826 // BSD systems return the FQDN, we only want the hostname, so extract
827 // it (we consider that dots are domain separators)
828 wxChar
*dot
= wxStrchr(buf
, wxT('.'));
839 bool wxGetFullHostName(wxChar
*buf
, int sz
)
841 bool ok
= wxGetHostNameInternal(buf
, sz
);
845 if ( !wxStrchr(buf
, wxT('.')) )
847 struct hostent
*host
= gethostbyname(wxSafeConvertWX2MB(buf
));
850 wxLogSysError(_("Cannot get the official hostname"));
856 // the canonical name
857 wxStrncpy(buf
, wxSafeConvertMB2WX(host
->h_name
), sz
);
860 //else: it's already a FQDN (BSD behaves this way)
866 bool wxGetUserId(wxChar
*buf
, int sz
)
871 if ((who
= getpwuid(getuid ())) != NULL
)
873 wxStrncpy (buf
, wxSafeConvertMB2WX(who
->pw_name
), sz
- 1);
880 bool wxGetUserName(wxChar
*buf
, int sz
)
886 if ((who
= getpwuid (getuid ())) != NULL
)
888 char *comma
= strchr(who
->pw_gecos
, ',');
890 *comma
= '\0'; // cut off non-name comment fields
891 wxStrncpy (buf
, wxSafeConvertMB2WX(who
->pw_gecos
), sz
- 1);
896 #else // !HAVE_PW_GECOS
897 return wxGetUserId(buf
, sz
);
898 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
901 bool wxIsPlatform64Bit()
903 const wxString machine
= wxGetCommandOutput(wxT("uname -m"));
905 // the test for "64" is obviously not 100% reliable but seems to work fine
907 return machine
.Contains(wxT("64")) ||
908 machine
.Contains(wxT("alpha"));
911 // these functions are in mac/utils.cpp for wxMac
914 wxOperatingSystemId
wxGetOsVersion(int *verMaj
, int *verMin
)
918 wxString release
= wxGetCommandOutput(wxT("uname -r"));
919 if ( release
.empty() ||
920 wxSscanf(release
.c_str(), wxT("%d.%d"), &major
, &minor
) != 2 )
922 // failed to get version string or unrecognized format
932 // try to understand which OS are we running
933 wxString kernel
= wxGetCommandOutput(wxT("uname -s"));
934 if ( kernel
.empty() )
935 kernel
= wxGetCommandOutput(wxT("uname -o"));
937 if ( kernel
.empty() )
940 return wxPlatformInfo::GetOperatingSystemId(kernel
);
943 wxString
wxGetOsDescription()
945 return wxGetCommandOutput(wxT("uname -s -r -m"));
950 unsigned long wxGetProcessId()
952 return (unsigned long)getpid();
955 wxMemorySize
wxGetFreeMemory()
957 #if defined(__LINUX__)
958 // get it from /proc/meminfo
959 FILE *fp
= fopen("/proc/meminfo", "r");
965 if ( fgets(buf
, WXSIZEOF(buf
), fp
) && fgets(buf
, WXSIZEOF(buf
), fp
) )
967 // /proc/meminfo changed its format in kernel 2.6
968 if ( wxPlatformInfo().CheckOSVersion(2, 6) )
970 unsigned long cached
, buffers
;
971 sscanf(buf
, "MemFree: %ld", &memFree
);
973 fgets(buf
, WXSIZEOF(buf
), fp
);
974 sscanf(buf
, "Buffers: %lu", &buffers
);
976 fgets(buf
, WXSIZEOF(buf
), fp
);
977 sscanf(buf
, "Cached: %lu", &cached
);
979 // add to "MemFree" also the "Buffers" and "Cached" values as
980 // free(1) does as otherwise the value never makes sense: for
981 // kernel 2.6 it's always almost 0
982 memFree
+= buffers
+ cached
;
984 // values here are always expressed in kB and we want bytes
987 else // Linux 2.4 (or < 2.6, anyhow)
989 long memTotal
, memUsed
;
990 sscanf(buf
, "Mem: %ld %ld %ld", &memTotal
, &memUsed
, &memFree
);
996 return (wxMemorySize
)memFree
;
998 #elif defined(__SGI__)
999 struct rminfo realmem
;
1000 if ( sysmp(MP_SAGET
, MPSA_RMINFO
, &realmem
, sizeof realmem
) == 0 )
1001 return ((wxMemorySize
)realmem
.physmem
* sysconf(_SC_PAGESIZE
));
1002 #elif defined(_SC_AVPHYS_PAGES)
1003 return ((wxMemorySize
)sysconf(_SC_AVPHYS_PAGES
))*sysconf(_SC_PAGESIZE
);
1004 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1007 // can't find it out
1011 bool wxGetDiskSpace(const wxString
& path
, wxDiskspaceSize_t
*pTotal
, wxDiskspaceSize_t
*pFree
)
1013 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
1014 // the case to "char *" is needed for AIX 4.3
1016 if ( wxStatfs((char *)(const char*)path
.fn_str(), &fs
) != 0 )
1018 wxLogSysError( wxT("Failed to get file system statistics") );
1023 // under Solaris we also have to use f_frsize field instead of f_bsize
1024 // which is in general a multiple of f_frsize
1026 wxDiskspaceSize_t blockSize
= fs
.f_frsize
;
1027 #else // HAVE_STATFS
1028 wxDiskspaceSize_t blockSize
= fs
.f_bsize
;
1029 #endif // HAVE_STATVFS/HAVE_STATFS
1033 *pTotal
= wxDiskspaceSize_t(fs
.f_blocks
) * blockSize
;
1038 *pFree
= wxDiskspaceSize_t(fs
.f_bavail
) * blockSize
;
1042 #else // !HAVE_STATFS && !HAVE_STATVFS
1044 #endif // HAVE_STATFS
1047 // ----------------------------------------------------------------------------
1049 // ----------------------------------------------------------------------------
1053 WX_DECLARE_STRING_HASH_MAP(char *, wxEnvVars
);
1055 static wxEnvVars gs_envVars
;
1057 class wxSetEnvModule
: public wxModule
1060 virtual bool OnInit() { return true; }
1061 virtual void OnExit()
1063 for ( wxEnvVars::const_iterator i
= gs_envVars
.begin();
1064 i
!= gs_envVars
.end();
1073 DECLARE_DYNAMIC_CLASS(wxSetEnvModule
)
1076 IMPLEMENT_DYNAMIC_CLASS(wxSetEnvModule
, wxModule
)
1078 #endif // USE_PUTENV
1080 bool wxGetEnv(const wxString
& var
, wxString
*value
)
1082 // wxGetenv is defined as getenv()
1083 char *p
= wxGetenv(var
);
1095 static bool wxDoSetEnv(const wxString
& variable
, const char *value
)
1097 #if defined(HAVE_SETENV)
1100 #ifdef HAVE_UNSETENV
1101 // don't test unsetenv() return value: it's void on some systems (at
1103 unsetenv(variable
.mb_str());
1106 value
= ""; // we can't pass NULL to setenv()
1110 return setenv(variable
.mb_str(), value
, 1 /* overwrite */) == 0;
1111 #elif defined(HAVE_PUTENV)
1112 wxString s
= variable
;
1114 s
<< _T('=') << value
;
1116 // transform to ANSI
1117 const wxWX2MBbuf p
= s
.mb_str();
1119 char *buf
= (char *)malloc(strlen(p
) + 1);
1122 // store the string to free() it later
1123 wxEnvVars::iterator i
= gs_envVars
.find(variable
);
1124 if ( i
!= gs_envVars
.end() )
1129 else // this variable hadn't been set before
1131 gs_envVars
[variable
] = buf
;
1134 return putenv(buf
) == 0;
1135 #else // no way to set an env var
1140 bool wxSetEnv(const wxString
& variable
, const wxString
& value
)
1142 return wxDoSetEnv(variable
, value
.mb_str());
1145 bool wxUnsetEnv(const wxString
& variable
)
1147 return wxDoSetEnv(variable
, NULL
);
1150 // ----------------------------------------------------------------------------
1152 // ----------------------------------------------------------------------------
1154 #if wxUSE_ON_FATAL_EXCEPTION
1158 extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER
)
1162 // give the user a chance to do something special about this
1163 wxTheApp
->OnFatalException();
1169 bool wxHandleFatalExceptions(bool doit
)
1172 static bool s_savedHandlers
= false;
1173 static struct sigaction s_handlerFPE
,
1179 if ( doit
&& !s_savedHandlers
)
1181 // install the signal handler
1182 struct sigaction act
;
1184 // some systems extend it with non std fields, so zero everything
1185 memset(&act
, 0, sizeof(act
));
1187 act
.sa_handler
= wxFatalSignalHandler
;
1188 sigemptyset(&act
.sa_mask
);
1191 ok
&= sigaction(SIGFPE
, &act
, &s_handlerFPE
) == 0;
1192 ok
&= sigaction(SIGILL
, &act
, &s_handlerILL
) == 0;
1193 ok
&= sigaction(SIGBUS
, &act
, &s_handlerBUS
) == 0;
1194 ok
&= sigaction(SIGSEGV
, &act
, &s_handlerSEGV
) == 0;
1197 wxLogDebug(_T("Failed to install our signal handler."));
1200 s_savedHandlers
= true;
1202 else if ( s_savedHandlers
)
1204 // uninstall the signal handler
1205 ok
&= sigaction(SIGFPE
, &s_handlerFPE
, NULL
) == 0;
1206 ok
&= sigaction(SIGILL
, &s_handlerILL
, NULL
) == 0;
1207 ok
&= sigaction(SIGBUS
, &s_handlerBUS
, NULL
) == 0;
1208 ok
&= sigaction(SIGSEGV
, &s_handlerSEGV
, NULL
) == 0;
1211 wxLogDebug(_T("Failed to uninstall our signal handler."));
1214 s_savedHandlers
= false;
1216 //else: nothing to do
1221 #endif // wxUSE_ON_FATAL_EXCEPTION
1223 #endif // wxUSE_BASE
1228 #include <sys/errno.h>
1230 // ----------------------------------------------------------------------------
1231 // wxExecute support
1232 // ----------------------------------------------------------------------------
1235 NOTE: If this proves not to work well for wxMac then move back to the old
1236 behavior. If, however, it proves to work just fine, nuke all of the code
1237 for the old behavior. I strongly suggest backporting this to 2.8 as well.
1238 However, beware that while you can nuke the old code here, you cannot
1239 nuke the wxAddProcessCallbackForPid from the 2.8 branch (found in
1240 utilsexc_cf since it's an exported symbol).
1242 // #define USE_OLD_DARWIN_END_PROCESS_DETECT (defined(__DARWIN__) && defined(__WXMAC__))
1243 #define USE_OLD_DARWIN_END_PROCESS_DETECT 0
1245 // wxMac/wxCocoa don't use the same process end detection mechanisms so we don't
1246 // need wxExecute-related helpers for them
1247 #if !USE_OLD_DARWIN_END_PROCESS_DETECT
1249 bool wxGUIAppTraits::CreateEndProcessPipe(wxExecuteData
& execData
)
1251 return execData
.pipeEndProcDetect
.Create();
1254 bool wxGUIAppTraits::IsWriteFDOfEndProcessPipe(wxExecuteData
& execData
, int fd
)
1256 return fd
== (execData
.pipeEndProcDetect
)[wxPipe::Write
];
1259 void wxGUIAppTraits::DetachWriteFDOfEndProcessPipe(wxExecuteData
& execData
)
1261 execData
.pipeEndProcDetect
.Detach(wxPipe::Write
);
1262 execData
.pipeEndProcDetect
.Close();
1267 bool wxGUIAppTraits::CreateEndProcessPipe(wxExecuteData
& WXUNUSED(execData
))
1273 wxGUIAppTraits::IsWriteFDOfEndProcessPipe(wxExecuteData
& WXUNUSED(execData
),
1280 wxGUIAppTraits::DetachWriteFDOfEndProcessPipe(wxExecuteData
& WXUNUSED(execData
))
1282 // nothing to do here, we don't use the pipe
1285 #endif // !Darwin/Darwin
1287 int wxGUIAppTraits::WaitForChild(wxExecuteData
& execData
)
1289 wxEndProcessData
*endProcData
= new wxEndProcessData
;
1291 const int flags
= execData
.flags
;
1293 // wxAddProcessCallback is now (with DARWIN) allowed to call the
1294 // callback function directly if the process terminates before
1295 // the callback can be added to the run loop. Set up the endProcData.
1296 if ( flags
& wxEXEC_SYNC
)
1298 // we may have process for capturing the program output, but it's
1299 // not used in wxEndProcessData in the case of sync execution
1300 endProcData
->process
= NULL
;
1302 // sync execution: indicate it by negating the pid
1303 endProcData
->pid
= -execData
.pid
;
1307 // async execution, nothing special to do -- caller will be
1308 // notified about the process termination if process != NULL, endProcData
1309 // will be deleted in GTK_EndProcessDetector
1310 endProcData
->process
= execData
.process
;
1311 endProcData
->pid
= execData
.pid
;
1315 if ( !(flags
& wxEXEC_NOEVENTS
) )
1317 #if USE_OLD_DARWIN_END_PROCESS_DETECT
1318 endProcData
->tag
= wxAddProcessCallbackForPid(endProcData
, execData
.pid
);
1320 endProcData
->tag
= wxAddProcessCallback
1323 execData
.pipeEndProcDetect
.Detach(wxPipe::Read
)
1326 execData
.pipeEndProcDetect
.Close();
1327 #endif // USE_OLD_DARWIN_END_PROCESS_DETECT
1330 if ( flags
& wxEXEC_SYNC
)
1335 wxWindowDisabler
*wd
= flags
& (wxEXEC_NODISABLE
| wxEXEC_NOEVENTS
)
1337 : new wxWindowDisabler
;
1339 if ( flags
& wxEXEC_NOEVENTS
)
1341 // just block waiting for the child to exit
1344 int result
= waitpid(execData
.pid
, &status
, 0);
1346 /* DE: waitpid manpage states that waitpid can fail with EINTR
1347 if the call is interrupted by a caught signal. I suppose
1348 that means that this ought to be a while loop.
1350 The odd thing is that it seems to fail EVERY time. It fails
1351 with a quickly exiting process (e.g. echo), and fails with a
1352 slowly exiting process (e.g. sleep 2) but clearly after
1353 having waited for the child to exit. Maybe it's a bug in
1354 my particular version.
1356 It works, however, from the CFSocket callback without this
1357 trick but in that case it's used only after CFSocket calls
1358 the callback and with the WNOHANG flag which would seem to
1359 preclude it from being interrupted or at least make it much
1360 less likely since it would not then be waiting.
1362 If Darwin's man page is to be believed then this is definitely
1363 necessary. It's just weird that I've never seen it before
1364 and apparently no one else has either or you'd think they'd
1365 have reported it by now. Perhaps blocking the GUI while
1366 waiting for a child process to exit is simply not that common.
1368 if(result
== -1 && errno
== EINTR
)
1370 result
= waitpid(execData
.pid
, &status
, 0);
1377 wxLogLastError(_T("waitpid"));
1382 wxASSERT_MSG( result
== execData
.pid
,
1383 _T("unexpected waitpid() return value") );
1385 if ( WIFEXITED(status
) )
1387 exitcode
= WEXITSTATUS(status
);
1389 else // abnormal termination?
1391 wxASSERT_MSG( WIFSIGNALED(status
),
1392 _T("unexpected child wait status") );
1397 else // !wxEXEC_NOEVENTS
1399 // endProcData->pid will be set to 0 from
1400 // wxHandleProcessTermination when the process terminates
1401 while ( endProcData
->pid
!= 0 )
1405 #if HAS_PIPE_INPUT_STREAM
1406 if ( execData
.bufOut
)
1408 execData
.bufOut
->Update();
1412 if ( execData
.bufErr
)
1414 execData
.bufErr
->Update();
1417 #endif // HAS_PIPE_INPUT_STREAM
1419 // don't consume 100% of the CPU while we're sitting in this
1424 // give GTK+ a chance to call GTK_EndProcessDetector here and
1425 // also repaint the GUI
1429 exitcode
= endProcData
->exitcode
;
1437 else // async execution
1439 return execData
.pid
;
1443 #if wxHAS_GENERIC_PROCESS_CALLBACK
1444 struct wxEndProcessFDIOHandler
: public wxFDIOHandler
1446 wxEndProcessFDIOHandler(wxEndProcessData
*data
, int fd
)
1447 : m_data(data
), m_fd(fd
)
1450 virtual void OnReadWaiting()
1451 { wxFAIL_MSG("this isn't supposed to happen"); }
1452 virtual void OnWriteWaiting()
1453 { wxFAIL_MSG("this isn't supposed to happen"); }
1455 virtual void OnExceptionWaiting()
1457 int pid
= (m_data
->pid
> 0) ? m_data
->pid
: -(m_data
->pid
);
1460 // has the process really terminated?
1461 int rc
= waitpid(pid
, &status
, WNOHANG
);
1464 // This can only happen if the child application closes our dummy
1465 // pipe that is used to monitor its lifetime; in that case, our
1466 // best bet is to pretend the process did terminate, because
1467 // otherwise wxExecute() would hang indefinitely
1468 // (OnExceptionWaiting() won't be called again, the descriptor
1470 wxLogDebug("Child process (PID %i) still alive, even though notification was received that it terminated.", pid
);
1472 else if ( rc
== -1 )
1474 // As above, if waitpid() fails, the best we can do is to log the
1475 // error and pretend the child terminated:
1476 wxLogSysError(_("Failed to check child process' status"));
1479 // set exit code to -1 if something bad happened
1480 m_data
->exitcode
= (rc
> 0 && WIFEXITED(status
))
1481 ? WEXITSTATUS(status
)
1485 "Child process (PID %i) terminated with exit code %i",
1486 pid
, m_data
->exitcode
);
1488 // child exited, end waiting
1489 wxFDIODispatcher::Get()->UnregisterFD(m_fd
);
1492 m_data
->fdioHandler
= NULL
;
1493 wxHandleProcessTermination(m_data
);
1498 wxEndProcessData
*m_data
;
1502 int wxAddProcessCallback(wxEndProcessData
*proc_data
, int fd
)
1504 proc_data
->fdioHandler
= new wxEndProcessFDIOHandler(proc_data
, fd
);
1505 wxFDIODispatcher::Get()->RegisterFD
1508 proc_data
->fdioHandler
,
1511 return fd
; // unused, but return something unique for the tag
1513 #endif // wxHAS_GENERIC_PROCESS_CALLBACK
1518 void wxHandleProcessTermination(wxEndProcessData
*proc_data
)
1520 // notify user about termination if required
1521 if ( proc_data
->process
)
1523 proc_data
->process
->OnTerminate(proc_data
->pid
, proc_data
->exitcode
);
1527 if ( proc_data
->pid
> 0 )
1533 // let wxExecute() know that the process has terminated
1538 #endif // wxUSE_BASE