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