1 /////////////////////////////////////////////////////////////////////////////
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 // ----------------------------------------------------------------------------
19 #include "wx/string.h"
26 #include "wx/process.h"
27 #include "wx/thread.h"
29 #include "wx/wfstream.h"
33 # include <sys/param.h>
34 # include <sys/mount.h>
40 // not only the statfs syscall is called differently depending on platform, but
41 // we also can't use "struct statvfs" under Solaris because it breaks down if
42 // HAVE_LARGEFILE_SUPPORT == 1 and we must use statvfs_t instead
44 #include <sys/statvfs.h>
46 #define statfs statvfs
47 #define wxStatFs statvfs_t
49 #define wxStatFs struct statfs
50 #endif // HAVE_STAT[V]FS
53 #include "wx/unix/execute.h"
56 // SGI signal.h defines signal handler arguments differently depending on
57 // whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
58 #if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
59 #define _LANGUAGE_C_PLUS_PLUS 1
66 #include <sys/types.h>
73 #include <fcntl.h> // for O_WRONLY and friends
74 #include <time.h> // nanosleep() and/or usleep()
75 #include <ctype.h> // isspace()
76 #include <sys/time.h> // needed for FD_SETSIZE
79 #include <sys/utsname.h> // for uname()
82 // ----------------------------------------------------------------------------
83 // conditional compilation
84 // ----------------------------------------------------------------------------
86 // many versions of Unices have this function, but it is not defined in system
87 // headers - please add your system here if it is the case for your OS.
88 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
89 #if !defined(HAVE_USLEEP) && \
90 (defined(__SUN__) && !defined(__SunOs_5_6) && \
91 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
92 defined(__osf__) || defined(__EMX__)
96 int usleep(unsigned int usec
);
99 /* I copied this from the XFree86 diffs. AV. */
100 #define INCL_DOSPROCESS
102 inline void usleep(unsigned long delay
)
104 DosSleep(delay
? (delay
/1000l) : 1l);
106 #else // !Sun && !EMX
107 void usleep(unsigned long usec
);
109 #endif // Sun/EMX/Something else
112 #define HAVE_USLEEP 1
113 #endif // Unices without usleep()
115 // ============================================================================
117 // ============================================================================
119 // ----------------------------------------------------------------------------
121 // ----------------------------------------------------------------------------
123 void wxSleep(int nSecs
)
128 void wxUsleep(unsigned long milliseconds
)
130 #if defined(HAVE_NANOSLEEP)
132 tmReq
.tv_sec
= (time_t)(milliseconds
/ 1000);
133 tmReq
.tv_nsec
= (milliseconds
% 1000) * 1000 * 1000;
135 // we're not interested in remaining time nor in return value
136 (void)nanosleep(&tmReq
, (timespec
*)NULL
);
137 #elif defined(HAVE_USLEEP)
138 // uncomment this if you feel brave or if you are sure that your version
139 // of Solaris has a safe usleep() function but please notice that usleep()
140 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
141 // documented as MT-Safe
142 #if defined(__SUN__) && wxUSE_THREADS
143 #error "usleep() cannot be used in MT programs under Solaris."
146 usleep(milliseconds
* 1000); // usleep(3) wants microseconds
147 #elif defined(HAVE_SLEEP)
148 // under BeOS sleep() takes seconds (what about other platforms, if any?)
149 sleep(milliseconds
* 1000);
150 #else // !sleep function
151 #error "usleep() or nanosleep() function required for wxUsleep"
152 #endif // sleep function
155 // ----------------------------------------------------------------------------
156 // process management
157 // ----------------------------------------------------------------------------
159 int wxKill(long pid
, wxSignal sig
, wxKillError
*rc
)
161 int err
= kill((pid_t
)pid
, (int)sig
);
171 *rc
= wxKILL_BAD_SIGNAL
;
175 *rc
= wxKILL_ACCESS_DENIED
;
179 *rc
= wxKILL_NO_PROCESS
;
183 // this goes against Unix98 docs so log it
184 wxLogDebug(_T("unexpected kill(2) return value %d"), err
);
194 #define WXEXECUTE_NARGS 127
196 long wxExecute( const wxString
& command
, int flags
, wxProcess
*process
)
198 wxCHECK_MSG( !command
.IsEmpty(), 0, wxT("can't exec empty command") );
201 wxChar
*argv
[WXEXECUTE_NARGS
];
203 const wxChar
*cptr
= command
.c_str();
204 wxChar quotechar
= wxT('\0'); // is arg quoted?
205 bool escaped
= FALSE
;
207 // split the command line in arguments
211 quotechar
= wxT('\0');
213 // eat leading whitespace:
214 while ( wxIsspace(*cptr
) )
217 if ( *cptr
== wxT('\'') || *cptr
== wxT('"') )
222 if ( *cptr
== wxT('\\') && ! escaped
)
229 // all other characters:
233 // have we reached the end of the argument?
234 if ( (*cptr
== quotechar
&& ! escaped
)
235 || (quotechar
== wxT('\0') && wxIsspace(*cptr
))
236 || *cptr
== wxT('\0') )
238 wxASSERT_MSG( argc
< WXEXECUTE_NARGS
,
239 wxT("too many arguments in wxExecute") );
241 argv
[argc
] = new wxChar
[argument
.length() + 1];
242 wxStrcpy(argv
[argc
], argument
.c_str());
245 // if not at end of buffer, swallow last character:
249 break; // done with this one, start over
255 // do execute the command
256 long lRc
= wxExecute(argv
, flags
, process
);
261 delete [] argv
[argc
++];
266 // ----------------------------------------------------------------------------
268 // ----------------------------------------------------------------------------
270 static wxString
wxMakeShellCommand(const wxString
& command
)
275 // just an interactive shell
280 // execute command in a shell
281 cmd
<< _T("/bin/sh -c '") << command
<< _T('\'');
287 bool wxShell(const wxString
& command
)
289 return wxExecute(wxMakeShellCommand(command
), wxEXEC_SYNC
) == 0;
292 bool wxShell(const wxString
& command
, wxArrayString
& output
)
294 wxCHECK_MSG( !!command
, FALSE
, _T("can't exec shell non interactively") );
296 return wxExecute(wxMakeShellCommand(command
), output
);
299 // Shutdown or reboot the PC
300 bool wxShutdown(wxShutdownFlags wFlags
)
305 case wxSHUTDOWN_POWEROFF
:
309 case wxSHUTDOWN_REBOOT
:
314 wxFAIL_MSG( _T("unknown wxShutdown() flag") );
318 return system(wxString::Format(_T("init %c"), level
).mb_str()) == 0;
324 void wxHandleProcessTermination(wxEndProcessData
*proc_data
)
326 // notify user about termination if required
327 if ( proc_data
->process
)
329 proc_data
->process
->OnTerminate(proc_data
->pid
, proc_data
->exitcode
);
333 if ( proc_data
->pid
> 0 )
339 // let wxExecute() know that the process has terminated
346 // ----------------------------------------------------------------------------
347 // wxStream classes to support IO redirection in wxExecute
348 // ----------------------------------------------------------------------------
352 // ----------------------------------------------------------------------------
353 // wxProcessFileInputStream: stream for reading from a pipe
354 // ----------------------------------------------------------------------------
356 class wxProcessFileInputStream
: public wxFileInputStream
359 wxProcessFileInputStream(int fd
) : wxFileInputStream(fd
) { }
361 // return TRUE if we have anything to read, don't block
362 bool IsAvailable() const;
365 bool wxProcessFileInputStream::IsAvailable() const
367 if ( m_lasterror
== wxSTREAM_EOF
)
370 // check if there is any input available
375 const int fd
= m_file
->fd();
379 FD_SET(fd
, &readfds
);
380 switch ( select(fd
+ 1, &readfds
, NULL
, NULL
, &tv
) )
383 wxLogSysError(_("Impossible to get child process input"));
390 wxFAIL_MSG(_T("unexpected select() return value"));
391 // still fall through
399 // ----------------------------------------------------------------------------
400 // wxStreamTempInputBuffer
401 // ----------------------------------------------------------------------------
404 Extract of a mail to wx-users to give the context of the problem we are
405 trying to solve here:
407 MC> If I run the command:
408 MC> find . -name "*.h" -exec grep linux {} \;
409 MC> in the exec sample synchronously from the 'Capture command output'
410 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
411 MC> else encountered this?
413 Yes, I can reproduce it too.
415 I even think I understand why it happens: before launching the external
416 command we set up a pipe with a valid file descriptor on the reading side
417 when the output is redirected. So the subprocess happily writes to it ...
418 until the pipe buffer (which is usually quite big on Unix, I think the
419 default is 4Kb) is full. Then the writing process stops and waits until we
420 read some data from the pipe to be able to continue writing to it but we
421 never do it because we wait until it terminates to start reading and so we
422 have a classical deadlock.
424 Here is the fix: we now read the output as soon as it appears into a temp
425 buffer (wxStreamTempInputBuffer object) and later just stuff it back into the
426 stream when the process terminates. See supporting code in wxExecute()
429 Note that this is horribly inefficient for large amounts of output (count
430 the number of times we copy the data around) and so a better API is badly
434 class wxStreamTempInputBuffer
437 wxStreamTempInputBuffer();
439 // call to associate a stream with this buffer, otherwise nothing happens
441 void Init(wxProcessFileInputStream
*stream
);
443 // check for input on our stream and cache it in our buffer if any
446 ~wxStreamTempInputBuffer();
449 // the stream we're buffering, if NULL we don't do anything at all
450 wxProcessFileInputStream
*m_stream
;
452 // the buffer of size m_size (NULL if m_size == 0)
455 // the size of the buffer
459 wxStreamTempInputBuffer::wxStreamTempInputBuffer()
466 void wxStreamTempInputBuffer::Init(wxProcessFileInputStream
*stream
)
471 void wxStreamTempInputBuffer::Update()
473 if ( m_stream
&& m_stream
->IsAvailable() )
475 // realloc in blocks of 4Kb: this is the default (and minimal) buffer
476 // size of the Unix pipes so it should be the optimal step
477 static const size_t incSize
= 4096;
479 void *buf
= realloc(m_buffer
, m_size
+ incSize
);
482 // don't read any more, we don't have enough memory to do it
485 else // got memory for the buffer
488 m_stream
->Read((char *)m_buffer
+ m_size
, incSize
);
489 m_size
+= m_stream
->LastRead();
494 wxStreamTempInputBuffer::~wxStreamTempInputBuffer()
498 m_stream
->Ungetch(m_buffer
, m_size
);
503 #endif // wxUSE_STREAMS
505 // ----------------------------------------------------------------------------
506 // wxPipe: this encapsulates pipe() system call
507 // ----------------------------------------------------------------------------
512 // the symbolic names for the pipe ends
524 // default ctor doesn't do anything
525 wxPipe() { m_fds
[Read
] = m_fds
[Write
] = INVALID_FD
; }
527 // create the pipe, return TRUE if ok, FALSE on error
530 if ( pipe(m_fds
) == -1 )
532 wxLogSysError(_("Pipe creation failed"));
540 // return TRUE if we were created successfully
541 bool IsOk() const { return m_fds
[Read
] != INVALID_FD
; }
543 // return the descriptor for one of the pipe ends
544 int operator[](Direction which
) const
546 wxASSERT_MSG( which
>= 0 && (size_t)which
< WXSIZEOF(m_fds
),
547 _T("invalid pipe index") );
552 // detach a descriptor, meaning that the pipe dtor won't close it, and
554 int Detach(Direction which
)
556 wxASSERT_MSG( which
>= 0 && (size_t)which
< WXSIZEOF(m_fds
),
557 _T("invalid pipe index") );
559 int fd
= m_fds
[which
];
560 m_fds
[which
] = INVALID_FD
;
565 // close the pipe descriptors
568 for ( size_t n
= 0; n
< WXSIZEOF(m_fds
); n
++ )
570 if ( m_fds
[n
] != INVALID_FD
)
575 // dtor closes the pipe descriptors
576 ~wxPipe() { Close(); }
582 // ----------------------------------------------------------------------------
583 // wxExecute: the real worker function
584 // ----------------------------------------------------------------------------
586 #pragma message disable codeunreachable
589 long wxExecute(wxChar
**argv
,
593 // for the sync execution, we return -1 to indicate failure, but for async
594 // case we return 0 which is never a valid PID
596 // we define this as a macro, not a variable, to avoid compiler warnings
597 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
598 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
600 wxCHECK_MSG( *argv
, ERROR_RETURN_CODE
, wxT("can't exec empty command") );
604 char *mb_argv
[WXEXECUTE_NARGS
];
606 while (argv
[mb_argc
])
608 wxWX2MBbuf mb_arg
= wxConvertWX2MB(argv
[mb_argc
]);
609 mb_argv
[mb_argc
] = strdup(mb_arg
);
612 mb_argv
[mb_argc
] = (char *) NULL
;
614 // this macro will free memory we used above
615 #define ARGS_CLEANUP \
616 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
617 free(mb_argv[mb_argc])
619 // no need for cleanup
622 wxChar
**mb_argv
= argv
;
623 #endif // Unicode/ANSI
627 wxPipe pipeEndProcDetect
;
628 if ( !pipeEndProcDetect
.Create() )
630 wxLogError( _("Failed to execute '%s'\n"), *argv
);
634 return ERROR_RETURN_CODE
;
638 // pipes for inter process communication
639 wxPipe pipeIn
, // stdin
643 if ( process
&& process
->IsRedirected() )
645 if ( !pipeIn
.Create() || !pipeOut
.Create() || !pipeErr
.Create() )
647 wxLogError( _("Failed to execute '%s'\n"), *argv
);
651 return ERROR_RETURN_CODE
;
662 if ( pid
== -1 ) // error?
664 wxLogSysError( _("Fork failed") );
668 return ERROR_RETURN_CODE
;
670 else if ( pid
== 0 ) // we're in child
672 // These lines close the open file descriptors to to avoid any
673 // input/output which might block the process or irritate the user. If
674 // one wants proper IO for the subprocess, the right thing to do is to
675 // start an xterm executing it.
676 if ( !(flags
& wxEXEC_SYNC
) )
678 for ( int fd
= 0; fd
< FD_SETSIZE
; fd
++ )
680 if ( fd
== pipeIn
[wxPipe::Read
]
681 || fd
== pipeOut
[wxPipe::Write
]
682 || fd
== pipeErr
[wxPipe::Write
]
684 || fd
== pipeEndProcDetect
[wxPipe::Write
]
688 // don't close this one, we still need it
692 // leave stderr opened too, it won't do any harm
693 if ( fd
!= STDERR_FILENO
)
699 if ( flags
& wxEXEC_MAKE_GROUP_LEADER
)
701 // Set process group to child process' pid. Then killing -pid
702 // of the parent will kill the process and all of its children.
708 // reading side can be safely closed but we should keep the write one
710 pipeEndProcDetect
.Detach(wxPipe::Write
);
711 pipeEndProcDetect
.Close();
714 // redirect stdin, stdout and stderr
717 if ( dup2(pipeIn
[wxPipe::Read
], STDIN_FILENO
) == -1 ||
718 dup2(pipeOut
[wxPipe::Write
], STDOUT_FILENO
) == -1 ||
719 dup2(pipeErr
[wxPipe::Write
], STDERR_FILENO
) == -1 )
721 wxLogSysError(_("Failed to redirect child process input/output"));
729 execvp (*mb_argv
, mb_argv
);
731 // there is no return after successful exec()
734 // some compilers complain about missing return - of course, they
735 // should know that exit() doesn't return but what else can we do if
738 // and, sure enough, other compilers complain about unreachable code
739 // after exit() call, so we can just always have return here...
740 #if defined(__VMS) || defined(__INTEL_COMPILER)
744 else // we're in parent
748 // prepare for IO redirection
751 // the input buffer bufOut is connected to stdout, this is why it is
752 // called bufOut and not bufIn
753 wxStreamTempInputBuffer bufOut
,
755 #endif // wxUSE_STREAMS
757 if ( process
&& process
->IsRedirected() )
760 wxOutputStream
*inStream
=
761 new wxFileOutputStream(pipeIn
.Detach(wxPipe::Write
));
763 wxProcessFileInputStream
*outStream
=
764 new wxProcessFileInputStream(pipeOut
.Detach(wxPipe::Read
));
766 wxProcessFileInputStream
*errStream
=
767 new wxProcessFileInputStream(pipeErr
.Detach(wxPipe::Read
));
769 process
->SetPipeStreams(outStream
, inStream
, errStream
);
771 bufOut
.Init(outStream
);
772 bufErr
.Init(errStream
);
773 #endif // wxUSE_STREAMS
783 #if wxUSE_GUI && !defined(__WXMICROWIN__)
784 wxEndProcessData
*data
= new wxEndProcessData
;
786 data
->tag
= wxAddProcessCallback
789 pipeEndProcDetect
.Detach(wxPipe::Read
)
792 pipeEndProcDetect
.Close();
794 if ( flags
& wxEXEC_SYNC
)
796 // we may have process for capturing the program output, but it's
797 // not used in wxEndProcessData in the case of sync execution
798 data
->process
= NULL
;
800 // sync execution: indicate it by negating the pid
806 // data->pid will be set to 0 from GTK_EndProcessDetector when the
807 // process terminates
808 while ( data
->pid
!= 0 )
813 #endif // wxUSE_STREAMS
815 // give GTK+ a chance to call GTK_EndProcessDetector here and
816 // also repaint the GUI
820 int exitcode
= data
->exitcode
;
826 else // async execution
828 // async execution, nothing special to do - caller will be
829 // notified about the process termination if process != NULL, data
830 // will be deleted in GTK_EndProcessDetector
831 data
->process
= process
;
838 wxASSERT_MSG( flags
& wxEXEC_SYNC
,
839 wxT("async execution not supported yet") );
842 if ( waitpid(pid
, &exitcode
, 0) == -1 || !WIFEXITED(exitcode
) )
844 wxLogSysError(_("Waiting for subprocess termination failed"));
851 return ERROR_RETURN_CODE
;
854 #pragma message enable codeunreachable
857 #undef ERROR_RETURN_CODE
860 // ----------------------------------------------------------------------------
861 // file and directory functions
862 // ----------------------------------------------------------------------------
864 const wxChar
* wxGetHomeDir( wxString
*home
)
866 *home
= wxGetUserHome( wxString() );
868 if ( home
->IsEmpty() )
872 if ( tmp
.Last() != wxT(']'))
873 if ( tmp
.Last() != wxT('/')) *home
<< wxT('/');
875 return home
->c_str();
879 const wxMB2WXbuf
wxGetUserHome( const wxString
&user
)
880 #else // just for binary compatibility -- there is no 'const' here
881 char *wxGetUserHome( const wxString
&user
)
884 struct passwd
*who
= (struct passwd
*) NULL
;
890 if ((ptr
= wxGetenv(wxT("HOME"))) != NULL
)
894 if ((ptr
= wxGetenv(wxT("USER"))) != NULL
|| (ptr
= wxGetenv(wxT("LOGNAME"))) != NULL
)
896 who
= getpwnam(wxConvertWX2MB(ptr
));
899 // We now make sure the the user exists!
902 who
= getpwuid(getuid());
907 who
= getpwnam (user
.mb_str());
910 return wxConvertMB2WX(who
? who
->pw_dir
: 0);
913 // ----------------------------------------------------------------------------
914 // network and user id routines
915 // ----------------------------------------------------------------------------
917 // retrieve either the hostname or FQDN depending on platform (caller must
918 // check whether it's one or the other, this is why this function is for
920 static bool wxGetHostNameInternal(wxChar
*buf
, int sz
)
922 wxCHECK_MSG( buf
, FALSE
, wxT("NULL pointer in wxGetHostNameInternal") );
926 // we're using uname() which is POSIX instead of less standard sysinfo()
927 #if defined(HAVE_UNAME)
929 bool ok
= uname(&uts
) != -1;
932 wxStrncpy(buf
, wxConvertMB2WX(uts
.nodename
), sz
- 1);
935 #elif defined(HAVE_GETHOSTNAME)
936 bool ok
= gethostname(buf
, sz
) != -1;
937 #else // no uname, no gethostname
938 wxFAIL_MSG(wxT("don't know host name for this machine"));
941 #endif // uname/gethostname
945 wxLogSysError(_("Cannot get the hostname"));
951 bool wxGetHostName(wxChar
*buf
, int sz
)
953 bool ok
= wxGetHostNameInternal(buf
, sz
);
957 // BSD systems return the FQDN, we only want the hostname, so extract
958 // it (we consider that dots are domain separators)
959 wxChar
*dot
= wxStrchr(buf
, wxT('.'));
970 bool wxGetFullHostName(wxChar
*buf
, int sz
)
972 bool ok
= wxGetHostNameInternal(buf
, sz
);
976 if ( !wxStrchr(buf
, wxT('.')) )
978 struct hostent
*host
= gethostbyname(wxConvertWX2MB(buf
));
981 wxLogSysError(_("Cannot get the official hostname"));
987 // the canonical name
988 wxStrncpy(buf
, wxConvertMB2WX(host
->h_name
), sz
);
991 //else: it's already a FQDN (BSD behaves this way)
997 bool wxGetUserId(wxChar
*buf
, int sz
)
1002 if ((who
= getpwuid(getuid ())) != NULL
)
1004 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
1011 bool wxGetUserName(wxChar
*buf
, int sz
)
1016 if ((who
= getpwuid (getuid ())) != NULL
)
1018 // pw_gecos field in struct passwd is not standard
1019 #ifdef HAVE_PW_GECOS
1020 char *comma
= strchr(who
->pw_gecos
, ',');
1022 *comma
= '\0'; // cut off non-name comment fields
1023 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_gecos
), sz
- 1);
1024 #else // !HAVE_PW_GECOS
1025 wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz
- 1);
1026 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
1034 wxString
wxGetOsDescription()
1036 #ifndef WXWIN_OS_DESCRIPTION
1037 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
1039 return WXWIN_OS_DESCRIPTION
;
1044 // this function returns the GUI toolkit version in GUI programs, but OS
1045 // version in non-GUI ones
1048 int wxGetOsVersion(int *majorVsn
, int *minorVsn
)
1053 if ( sscanf(WXWIN_OS_DESCRIPTION
, "%s %d.%d", name
, &major
, &minor
) != 3 )
1055 // unreckognized uname string format
1067 #endif // !wxUSE_GUI
1069 unsigned long wxGetProcessId()
1071 return (unsigned long)getpid();
1074 long wxGetFreeMemory()
1076 #if defined(__LINUX__)
1077 // get it from /proc/meminfo
1078 FILE *fp
= fopen("/proc/meminfo", "r");
1084 if ( fgets(buf
, WXSIZEOF(buf
), fp
) && fgets(buf
, WXSIZEOF(buf
), fp
) )
1086 long memTotal
, memUsed
;
1087 sscanf(buf
, "Mem: %ld %ld %ld", &memTotal
, &memUsed
, &memFree
);
1094 #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1095 return sysconf(_SC_AVPHYS_PAGES
)*sysconf(_SC_PAGESIZE
);
1096 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1099 // can't find it out
1103 bool wxGetDiskSpace(const wxString
& path
, wxLongLong
*pTotal
, wxLongLong
*pFree
)
1105 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
1106 // the case to "char *" is needed for AIX 4.3
1108 if ( statfs((char *)path
.fn_str(), &fs
) != 0 )
1110 wxLogSysError("Failed to get file system statistics");
1115 // under Solaris we also have to use f_frsize field instead of f_bsize
1116 // which is in general a multiple of f_frsize
1118 wxLongLong blockSize
= fs
.f_frsize
;
1119 #else // HAVE_STATFS
1120 wxLongLong blockSize
= fs
.f_bsize
;
1121 #endif // HAVE_STATVFS/HAVE_STATFS
1125 *pTotal
= wxLongLong(fs
.f_blocks
) * blockSize
;
1130 *pFree
= wxLongLong(fs
.f_bavail
) * blockSize
;
1134 #else // !HAVE_STATFS && !HAVE_STATVFS
1136 #endif // HAVE_STATFS
1139 // ----------------------------------------------------------------------------
1141 // ----------------------------------------------------------------------------
1143 bool wxGetEnv(const wxString
& var
, wxString
*value
)
1145 // wxGetenv is defined as getenv()
1146 wxChar
*p
= wxGetenv(var
);
1158 bool wxSetEnv(const wxString
& variable
, const wxChar
*value
)
1160 #if defined(HAVE_SETENV)
1161 return setenv(variable
.mb_str(),
1162 value
? (const char *)wxString(value
).mb_str()
1164 1 /* overwrite */) == 0;
1165 #elif defined(HAVE_PUTENV)
1166 wxString s
= variable
;
1168 s
<< _T('=') << value
;
1170 // transform to ANSI
1171 const char *p
= s
.mb_str();
1173 // the string will be free()d by libc
1174 char *buf
= (char *)malloc(strlen(p
) + 1);
1177 return putenv(buf
) == 0;
1178 #else // no way to set an env var
1183 // ----------------------------------------------------------------------------
1185 // ----------------------------------------------------------------------------
1187 #if wxUSE_ON_FATAL_EXCEPTION
1191 extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER
)
1195 // give the user a chance to do something special about this
1196 wxTheApp
->OnFatalException();
1202 bool wxHandleFatalExceptions(bool doit
)
1205 static bool s_savedHandlers
= FALSE
;
1206 static struct sigaction s_handlerFPE
,
1212 if ( doit
&& !s_savedHandlers
)
1214 // install the signal handler
1215 struct sigaction act
;
1217 // some systems extend it with non std fields, so zero everything
1218 memset(&act
, 0, sizeof(act
));
1220 act
.sa_handler
= wxFatalSignalHandler
;
1221 sigemptyset(&act
.sa_mask
);
1224 ok
&= sigaction(SIGFPE
, &act
, &s_handlerFPE
) == 0;
1225 ok
&= sigaction(SIGILL
, &act
, &s_handlerILL
) == 0;
1226 ok
&= sigaction(SIGBUS
, &act
, &s_handlerBUS
) == 0;
1227 ok
&= sigaction(SIGSEGV
, &act
, &s_handlerSEGV
) == 0;
1230 wxLogDebug(_T("Failed to install our signal handler."));
1233 s_savedHandlers
= TRUE
;
1235 else if ( s_savedHandlers
)
1237 // uninstall the signal handler
1238 ok
&= sigaction(SIGFPE
, &s_handlerFPE
, NULL
) == 0;
1239 ok
&= sigaction(SIGILL
, &s_handlerILL
, NULL
) == 0;
1240 ok
&= sigaction(SIGBUS
, &s_handlerBUS
, NULL
) == 0;
1241 ok
&= sigaction(SIGSEGV
, &s_handlerSEGV
, NULL
) == 0;
1244 wxLogDebug(_T("Failed to uninstall our signal handler."));
1247 s_savedHandlers
= FALSE
;
1249 //else: nothing to do
1254 #endif // wxUSE_ON_FATAL_EXCEPTION
1256 // ----------------------------------------------------------------------------
1257 // error and debug output routines (deprecated, use wxLog)
1258 // ----------------------------------------------------------------------------
1260 #if WXWIN_COMPATIBILITY_2_2
1262 void wxDebugMsg( const char *format
, ... )
1265 va_start( ap
, format
);
1266 vfprintf( stderr
, format
, ap
);
1271 void wxError( const wxString
&msg
, const wxString
&title
)
1273 wxFprintf( stderr
, _("Error ") );
1274 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1275 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1276 wxFprintf( stderr
, wxT(".\n") );
1279 void wxFatalError( const wxString
&msg
, const wxString
&title
)
1281 wxFprintf( stderr
, _("Error ") );
1282 if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) );
1283 if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) );
1284 wxFprintf( stderr
, wxT(".\n") );
1285 exit(3); // the same exit code as for abort()
1288 #endif // WXWIN_COMPATIBILITY_2_2