]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/unix/utilsunx.cpp
added wx/defs.h include to correct compilation issues under Mac OS X
[wxWidgets.git] / src / unix / utilsunx.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: utilsunx.cpp
3// Purpose: generic Unix implementation of many wx functions
4// Author: Vadim Zeitlin
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
18#include "wx/defs.h"
19#include "wx/string.h"
20
21#include "wx/intl.h"
22#include "wx/log.h"
23#include "wx/app.h"
24
25#include "wx/utils.h"
26#include "wx/process.h"
27#include "wx/thread.h"
28
29#include "wx/stream.h"
30
31#ifdef HAVE_STATFS
32# ifdef __DARWIN__
33# include <sys/param.h>
34# include <sys/mount.h>
35# else
36# include <sys/vfs.h>
37# endif
38#endif // HAVE_STATFS
39
40#if wxUSE_GUI
41 #include "wx/unix/execute.h"
42#endif
43
44// SGI signal.h defines signal handler arguments differently depending on
45// whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
46#if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
47 #define _LANGUAGE_C_PLUS_PLUS 1
48#endif // SGI hack
49
50#include <stdarg.h>
51#include <dirent.h>
52#include <string.h>
53#include <sys/stat.h>
54#include <sys/types.h>
55#include <unistd.h>
56#include <sys/wait.h>
57#include <pwd.h>
58#include <errno.h>
59#include <netdb.h>
60#include <signal.h>
61#include <fcntl.h> // for O_WRONLY and friends
62#include <time.h> // nanosleep() and/or usleep()
63#include <ctype.h> // isspace()
64#include <sys/time.h> // needed for FD_SETSIZE
65
66#ifdef HAVE_UNAME
67 #include <sys/utsname.h> // for uname()
68#endif // HAVE_UNAME
69
70// ----------------------------------------------------------------------------
71// conditional compilation
72// ----------------------------------------------------------------------------
73
74// many versions of Unices have this function, but it is not defined in system
75// headers - please add your system here if it is the case for your OS.
76// SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
77#if !defined(HAVE_USLEEP) && \
78 (defined(__SUN__) && !defined(__SunOs_5_6) && \
79 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
80 defined(__osf__) || defined(__EMX__)
81 extern "C"
82 {
83 #ifdef __SUN__
84 int usleep(unsigned int usec);
85 #else // !Sun
86 #ifdef __EMX__
87 /* I copied this from the XFree86 diffs. AV. */
88 #define INCL_DOSPROCESS
89 #include <os2.h>
90 inline void usleep(unsigned long delay)
91 {
92 DosSleep(delay ? (delay/1000l) : 1l);
93 }
94 #else // !Sun && !EMX
95 void usleep(unsigned long usec);
96 #endif
97 #endif // Sun/EMX/Something else
98 };
99
100 #define HAVE_USLEEP 1
101#endif // Unices without usleep()
102
103// ============================================================================
104// implementation
105// ============================================================================
106
107// ----------------------------------------------------------------------------
108// sleeping
109// ----------------------------------------------------------------------------
110
111void wxSleep(int nSecs)
112{
113 sleep(nSecs);
114}
115
116void wxUsleep(unsigned long milliseconds)
117{
118#if defined(HAVE_NANOSLEEP)
119 timespec tmReq;
120 tmReq.tv_sec = (time_t)(milliseconds / 1000);
121 tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
122
123 // we're not interested in remaining time nor in return value
124 (void)nanosleep(&tmReq, (timespec *)NULL);
125#elif defined(HAVE_USLEEP)
126 // uncomment this if you feel brave or if you are sure that your version
127 // of Solaris has a safe usleep() function but please notice that usleep()
128 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
129 // documented as MT-Safe
130 #if defined(__SUN__) && wxUSE_THREADS
131 #error "usleep() cannot be used in MT programs under Solaris."
132 #endif // Sun
133
134 usleep(milliseconds * 1000); // usleep(3) wants microseconds
135#elif defined(HAVE_SLEEP)
136 // under BeOS sleep() takes seconds (what about other platforms, if any?)
137 sleep(milliseconds * 1000);
138#else // !sleep function
139 #error "usleep() or nanosleep() function required for wxUsleep"
140#endif // sleep function
141}
142
143// ----------------------------------------------------------------------------
144// process management
145// ----------------------------------------------------------------------------
146
147int wxKill(long pid, wxSignal sig, wxKillError *rc)
148{
149 int err = kill((pid_t)pid, (int)sig);
150 if ( rc )
151 {
152 switch ( err )
153 {
154 case 0:
155 *rc = wxKILL_OK;
156 break;
157
158 case EINVAL:
159 *rc = wxKILL_BAD_SIGNAL;
160 break;
161
162 case EPERM:
163 *rc = wxKILL_ACCESS_DENIED;
164 break;
165
166 case ESRCH:
167 *rc = wxKILL_NO_PROCESS;
168 break;
169
170 default:
171 // this goes against Unix98 docs so log it
172 wxLogDebug(_T("unexpected kill(2) return value %d"), err);
173
174 // something else...
175 *rc = wxKILL_ERROR;
176 }
177 }
178
179 return err;
180}
181
182#define WXEXECUTE_NARGS 127
183
184long wxExecute( const wxString& command, bool sync, wxProcess *process )
185{
186 wxCHECK_MSG( !command.IsEmpty(), 0, wxT("can't exec empty command") );
187
188 int argc = 0;
189 wxChar *argv[WXEXECUTE_NARGS];
190 wxString argument;
191 const wxChar *cptr = command.c_str();
192 wxChar quotechar = wxT('\0'); // is arg quoted?
193 bool escaped = FALSE;
194
195 // split the command line in arguments
196 do
197 {
198 argument=wxT("");
199 quotechar = wxT('\0');
200
201 // eat leading whitespace:
202 while ( wxIsspace(*cptr) )
203 cptr++;
204
205 if ( *cptr == wxT('\'') || *cptr == wxT('"') )
206 quotechar = *cptr++;
207
208 do
209 {
210 if ( *cptr == wxT('\\') && ! escaped )
211 {
212 escaped = TRUE;
213 cptr++;
214 continue;
215 }
216
217 // all other characters:
218 argument += *cptr++;
219 escaped = FALSE;
220
221 // have we reached the end of the argument?
222 if ( (*cptr == quotechar && ! escaped)
223 || (quotechar == wxT('\0') && wxIsspace(*cptr))
224 || *cptr == wxT('\0') )
225 {
226 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
227 wxT("too many arguments in wxExecute") );
228
229 argv[argc] = new wxChar[argument.length() + 1];
230 wxStrcpy(argv[argc], argument.c_str());
231 argc++;
232
233 // if not at end of buffer, swallow last character:
234 if(*cptr)
235 cptr++;
236
237 break; // done with this one, start over
238 }
239 } while(*cptr);
240 } while(*cptr);
241 argv[argc] = NULL;
242
243 // do execute the command
244 long lRc = wxExecute(argv, sync, process);
245
246 // clean up
247 argc = 0;
248 while( argv[argc] )
249 delete [] argv[argc++];
250
251 return lRc;
252}
253
254// ----------------------------------------------------------------------------
255// wxShell
256// ----------------------------------------------------------------------------
257
258static wxString wxMakeShellCommand(const wxString& command)
259{
260 wxString cmd;
261 if ( !command )
262 {
263 // just an interactive shell
264 cmd = _T("xterm");
265 }
266 else
267 {
268 // execute command in a shell
269 cmd << _T("/bin/sh -c '") << command << _T('\'');
270 }
271
272 return cmd;
273}
274
275bool wxShell(const wxString& command)
276{
277 return wxExecute(wxMakeShellCommand(command), TRUE /* sync */) == 0;
278}
279
280bool wxShell(const wxString& command, wxArrayString& output)
281{
282 wxCHECK_MSG( !!command, FALSE, _T("can't exec shell non interactively") );
283
284 return wxExecute(wxMakeShellCommand(command), output);
285}
286
287#if wxUSE_GUI
288
289void wxHandleProcessTermination(wxEndProcessData *proc_data)
290{
291 // notify user about termination if required
292 if ( proc_data->process )
293 {
294 proc_data->process->OnTerminate(proc_data->pid, proc_data->exitcode);
295 }
296
297 // clean up
298 if ( proc_data->pid > 0 )
299 {
300 delete proc_data;
301 }
302 else
303 {
304 // let wxExecute() know that the process has terminated
305 proc_data->pid = 0;
306 }
307}
308
309#endif // wxUSE_GUI
310
311// ----------------------------------------------------------------------------
312// wxStream classes to support IO redirection in wxExecute
313// ----------------------------------------------------------------------------
314
315#if wxUSE_STREAMS
316
317class wxProcessFileInputStream : public wxInputStream
318{
319public:
320 wxProcessFileInputStream(int fd) { m_fd = fd; }
321 ~wxProcessFileInputStream() { close(m_fd); }
322
323 virtual bool Eof() const;
324
325protected:
326 size_t OnSysRead(void *buffer, size_t bufsize);
327
328protected:
329 int m_fd;
330};
331
332class wxProcessFileOutputStream : public wxOutputStream
333{
334public:
335 wxProcessFileOutputStream(int fd) { m_fd = fd; }
336 ~wxProcessFileOutputStream() { close(m_fd); }
337
338protected:
339 size_t OnSysWrite(const void *buffer, size_t bufsize);
340
341protected:
342 int m_fd;
343};
344
345bool wxProcessFileInputStream::Eof() const
346{
347 if ( m_lasterror == wxSTREAM_EOF )
348 return TRUE;
349
350 // check if there is any input available
351 struct timeval tv;
352 tv.tv_sec = 0;
353 tv.tv_usec = 0;
354
355 fd_set readfds;
356 FD_ZERO(&readfds);
357 FD_SET(m_fd, &readfds);
358 switch ( select(m_fd + 1, &readfds, NULL, NULL, &tv) )
359 {
360 case -1:
361 wxLogSysError(_("Impossible to get child process input"));
362 // fall through
363
364 case 0:
365 return TRUE;
366
367 default:
368 wxFAIL_MSG(_T("unexpected select() return value"));
369 // still fall through
370
371 case 1:
372 // input available: check if there is any
373 return wxInputStream::Eof();
374 }
375}
376
377size_t wxProcessFileInputStream::OnSysRead(void *buffer, size_t bufsize)
378{
379 int ret = read(m_fd, buffer, bufsize);
380 if ( ret == 0 )
381 {
382 m_lasterror = wxSTREAM_EOF;
383 }
384 else if ( ret == -1 )
385 {
386 m_lasterror = wxSTREAM_READ_ERROR;
387 ret = 0;
388 }
389 else
390 {
391 m_lasterror = wxSTREAM_NOERROR;
392 }
393
394 return ret;
395}
396
397size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
398{
399 int ret = write(m_fd, buffer, bufsize);
400 if ( ret == -1 )
401 {
402 m_lasterror = wxSTREAM_WRITE_ERROR;
403 ret = 0;
404 }
405 else
406 {
407 m_lasterror = wxSTREAM_NOERROR;
408 }
409
410 return ret;
411}
412
413// ----------------------------------------------------------------------------
414// wxStreamTempBuffer
415// ----------------------------------------------------------------------------
416
417/*
418 Extract of a mail to wx-users to give the context of the problem we are
419 trying to solve here:
420
421 MC> If I run the command:
422 MC> find . -name "*.h" -exec grep linux {} \;
423 MC> in the exec sample synchronously from the 'Capture command output'
424 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
425 MC> else encountered this?
426
427 Yes, I can reproduce it too.
428
429 I even think I understand why it happens: before launching the external
430 command we set up a pipe with a valid file descriptor on the reading side
431 when the output is redirected. So the subprocess happily writes to it ...
432 until the pipe buffer (which is usually quite big on Unix, I think the
433 default is 4Mb) is full. Then the writing process stops and waits until we
434 read some data from the pipe to be able to continue writing to it but we
435 never do it because we wait until it terminates to start reading and so we
436 have a classical deadlock.
437
438 Here is the fix: we now read the output as soon as it appears into a temp
439 buffer (wxStreamTempBuffer object) and later just stuff it back into the
440 stream when the process terminates. See supporting code in wxExecute()
441 itself as well.
442*/
443
444class wxStreamTempBuffer
445{
446public:
447 wxStreamTempBuffer();
448
449 // call to associate a stream with this buffer, otherwise nothing happens
450 // at all
451 void Init(wxInputStream *stream);
452
453 // check for input on our stream and cache it in our buffer if any
454 void Update();
455
456 ~wxStreamTempBuffer();
457
458private:
459 // the stream we're buffering, if NULL we don't do anything at all
460 wxInputStream *m_stream;
461
462 // the buffer of size m_size (NULL if m_size == 0)
463 void *m_buffer;
464
465 // the size of the buffer
466 size_t m_size;
467};
468
469wxStreamTempBuffer::wxStreamTempBuffer()
470{
471 m_stream = NULL;
472 m_buffer = NULL;
473 m_size = 0;
474}
475
476void wxStreamTempBuffer::Init(wxInputStream *stream)
477{
478 m_stream = stream;
479}
480
481void wxStreamTempBuffer::Update()
482{
483 if ( m_stream && !m_stream->Eof() )
484 {
485 // realloc in blocks of 1Kb - surely not the best strategy but which
486 // one is?
487 static const size_t incSize = 1024;
488
489 void *buf = realloc(m_buffer, m_size + incSize);
490 if ( !buf )
491 {
492 // don't read any more, we don't have enough memory to do it
493 m_stream = NULL;
494 }
495 else // got memory for the buffer
496 {
497 m_buffer = buf;
498 m_stream->Read((char *)m_buffer + m_size, incSize);
499 m_size += incSize;
500 }
501 }
502}
503
504wxStreamTempBuffer::~wxStreamTempBuffer()
505{
506 if ( m_buffer )
507 {
508 m_stream->Ungetch(m_buffer, m_size);
509 free(m_buffer);
510 }
511}
512
513#endif // wxUSE_STREAMS
514
515long wxExecute(wxChar **argv,
516 bool sync,
517 wxProcess *process)
518{
519 // for the sync execution, we return -1 to indicate failure, but for async
520 // case we return 0 which is never a valid PID
521 //
522 // we define this as a macro, not a variable, to avoid compiler warnings
523 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
524 #define ERROR_RETURN_CODE ((sync) ? -1 : 0)
525
526 wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );
527
528#if wxUSE_UNICODE
529 int mb_argc = 0;
530 char *mb_argv[WXEXECUTE_NARGS];
531
532 while (argv[mb_argc])
533 {
534 wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
535 mb_argv[mb_argc] = strdup(mb_arg);
536 mb_argc++;
537 }
538 mb_argv[mb_argc] = (char *) NULL;
539
540 // this macro will free memory we used above
541 #define ARGS_CLEANUP \
542 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
543 free(mb_argv[mb_argc])
544#else // ANSI
545 // no need for cleanup
546 #define ARGS_CLEANUP
547
548 wxChar **mb_argv = argv;
549#endif // Unicode/ANSI
550
551#if wxUSE_GUI
552 // create pipes
553 int end_proc_detect[2];
554 if ( pipe(end_proc_detect) == -1 )
555 {
556 wxLogSysError( _("Pipe creation failed") );
557 wxLogError( _("Failed to execute '%s'\n"), *argv );
558
559 ARGS_CLEANUP;
560
561 return ERROR_RETURN_CODE;
562 }
563#endif // wxUSE_GUI
564
565 // pipes for inter process communication
566 int pipeIn[2], // stdin
567 pipeOut[2], // stdout
568 pipeErr[2]; // stderr
569
570 pipeIn[0] = pipeIn[1] =
571 pipeOut[0] = pipeOut[1] =
572 pipeErr[0] = pipeErr[1] = -1;
573
574 if ( process && process->IsRedirected() )
575 {
576 if ( pipe(pipeIn) == -1 || pipe(pipeOut) == -1 || pipe(pipeErr) == -1 )
577 {
578#if wxUSE_GUI
579 // free previously allocated resources
580 close(end_proc_detect[0]);
581 close(end_proc_detect[1]);
582#endif // wxUSE_GUI
583
584 wxLogSysError( _("Pipe creation failed") );
585 wxLogError( _("Failed to execute '%s'\n"), *argv );
586
587 ARGS_CLEANUP;
588
589 return ERROR_RETURN_CODE;
590 }
591 }
592
593 // fork the process
594#ifdef HAVE_VFORK
595 pid_t pid = vfork();
596#else
597 pid_t pid = fork();
598#endif
599
600 if ( pid == -1 ) // error?
601 {
602#if wxUSE_GUI
603 close(end_proc_detect[0]);
604 close(end_proc_detect[1]);
605 close(pipeIn[0]);
606 close(pipeIn[1]);
607 close(pipeOut[0]);
608 close(pipeOut[1]);
609 close(pipeErr[0]);
610 close(pipeErr[1]);
611#endif // wxUSE_GUI
612
613 wxLogSysError( _("Fork failed") );
614
615 ARGS_CLEANUP;
616
617 return ERROR_RETURN_CODE;
618 }
619 else if ( pid == 0 ) // we're in child
620 {
621#if wxUSE_GUI
622 close(end_proc_detect[0]); // close reading side
623#endif // wxUSE_GUI
624
625 // These lines close the open file descriptors to to avoid any
626 // input/output which might block the process or irritate the user. If
627 // one wants proper IO for the subprocess, the right thing to do is to
628 // start an xterm executing it.
629 if ( !sync )
630 {
631 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
632 {
633 if ( fd == pipeIn[0] || fd == pipeOut[1] || fd == pipeErr[1]
634#if wxUSE_GUI
635 || fd == end_proc_detect[1]
636#endif // wxUSE_GUI
637 )
638 {
639 // don't close this one, we still need it
640 continue;
641 }
642
643 // leave stderr opened too, it won't do any hurm
644 if ( fd != STDERR_FILENO )
645 close(fd);
646 }
647 }
648
649 // redirect stdio, stdout and stderr
650 if ( pipeIn[0] != -1 )
651 {
652 if ( dup2(pipeIn[0], STDIN_FILENO) == -1 ||
653 dup2(pipeOut[1], STDOUT_FILENO) == -1 ||
654 dup2(pipeErr[1], STDERR_FILENO) == -1 )
655 {
656 wxLogSysError(_("Failed to redirect child process input/output"));
657 }
658
659 close(pipeIn[0]);
660 close(pipeOut[1]);
661 close(pipeErr[1]);
662 }
663
664 execvp (*mb_argv, mb_argv);
665
666 // there is no return after successful exec()
667 _exit(-1);
668
669 // some compilers complain about missing return - of course, they
670 // should know that exit() doesn't return but what else can we do if
671 // they don't?
672#if defined(__VMS) || defined(__INTEL_COMPILER)
673 return 0;
674#endif
675 }
676 else // we're in parent
677 {
678 ARGS_CLEANUP;
679
680 // pipe initialization: construction of the wxStreams
681#if wxUSE_STREAMS
682 wxStreamTempBuffer bufIn, bufErr;
683#endif // wxUSE_STREAMS
684
685 if ( process && process->IsRedirected() )
686 {
687#if wxUSE_STREAMS
688 // in/out for subprocess correspond to our out/in
689 wxOutputStream *outStream = new wxProcessFileOutputStream(pipeIn[1]);
690 wxInputStream *inStream = new wxProcessFileInputStream(pipeOut[0]);
691 wxInputStream *errStream = new wxProcessFileInputStream(pipeErr[0]);
692
693 process->SetPipeStreams(inStream, outStream, errStream);
694
695 bufIn.Init(inStream);
696 bufErr.Init(inStream);
697#endif // wxUSE_STREAMS
698
699 close(pipeIn[0]); // close reading side
700 close(pipeOut[1]); // close writing side
701 close(pipeErr[1]); // close writing side
702 }
703
704#if wxUSE_GUI && !defined(__WXMICROWIN__)
705 wxEndProcessData *data = new wxEndProcessData;
706
707 if ( sync )
708 {
709 // we may have process for capturing the program output, but it's
710 // not used in wxEndProcessData in the case of sync execution
711 data->process = NULL;
712
713 // sync execution: indicate it by negating the pid
714 data->pid = -pid;
715 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
716
717 close(end_proc_detect[1]); // close writing side
718
719 wxBusyCursor bc;
720 wxWindowDisabler wd;
721
722 // data->pid will be set to 0 from GTK_EndProcessDetector when the
723 // process terminates
724 while ( data->pid != 0 )
725 {
726#if wxUSE_STREAMS
727 bufIn.Update();
728 bufErr.Update();
729#endif // wxUSE_STREAMS
730
731 // give GTK+ a chance to call GTK_EndProcessDetector here and
732 // also repaint the GUI
733 wxYield();
734 }
735
736 int exitcode = data->exitcode;
737
738 delete data;
739
740 return exitcode;
741 }
742 else // async execution
743 {
744 // async execution, nothing special to do - caller will be
745 // notified about the process termination if process != NULL, data
746 // will be deleted in GTK_EndProcessDetector
747 data->process = process;
748 data->pid = pid;
749 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
750
751 close(end_proc_detect[1]); // close writing side
752
753 return pid;
754 }
755#else // !wxUSE_GUI
756 wxASSERT_MSG( sync, wxT("async execution not supported yet") );
757
758 int exitcode = 0;
759 if ( waitpid(pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) )
760 {
761 wxLogSysError(_("Waiting for subprocess termination failed"));
762 }
763
764 return exitcode;
765#endif // wxUSE_GUI
766 }
767}
768
769#undef ERROR_RETURN_CODE
770#undef ARGS_CLEANUP
771
772// ----------------------------------------------------------------------------
773// file and directory functions
774// ----------------------------------------------------------------------------
775
776const wxChar* wxGetHomeDir( wxString *home )
777{
778 *home = wxGetUserHome( wxString() );
779 wxString tmp;
780 if ( home->IsEmpty() )
781 *home = wxT("/");
782#ifdef __VMS
783 tmp = *home;
784 if ( tmp.Last() != wxT(']'))
785 if ( tmp.Last() != wxT('/')) *home << wxT('/');
786#endif
787 return home->c_str();
788}
789
790#if wxUSE_UNICODE
791const wxMB2WXbuf wxGetUserHome( const wxString &user )
792#else // just for binary compatibility -- there is no 'const' here
793char *wxGetUserHome( const wxString &user )
794#endif
795{
796 struct passwd *who = (struct passwd *) NULL;
797
798 if ( !user )
799 {
800 wxChar *ptr;
801
802 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
803 {
804 return ptr;
805 }
806 if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
807 {
808 who = getpwnam(wxConvertWX2MB(ptr));
809 }
810
811 // We now make sure the the user exists!
812 if (who == NULL)
813 {
814 who = getpwuid(getuid());
815 }
816 }
817 else
818 {
819 who = getpwnam (user.mb_str());
820 }
821
822 return wxConvertMB2WX(who ? who->pw_dir : 0);
823}
824
825// ----------------------------------------------------------------------------
826// network and user id routines
827// ----------------------------------------------------------------------------
828
829// retrieve either the hostname or FQDN depending on platform (caller must
830// check whether it's one or the other, this is why this function is for
831// private use only)
832static bool wxGetHostNameInternal(wxChar *buf, int sz)
833{
834 wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") );
835
836 *buf = wxT('\0');
837
838 // we're using uname() which is POSIX instead of less standard sysinfo()
839#if defined(HAVE_UNAME)
840 struct utsname uts;
841 bool ok = uname(&uts) != -1;
842 if ( ok )
843 {
844 wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
845 buf[sz] = wxT('\0');
846 }
847#elif defined(HAVE_GETHOSTNAME)
848 bool ok = gethostname(buf, sz) != -1;
849#else // no uname, no gethostname
850 wxFAIL_MSG(wxT("don't know host name for this machine"));
851
852 bool ok = FALSE;
853#endif // uname/gethostname
854
855 if ( !ok )
856 {
857 wxLogSysError(_("Cannot get the hostname"));
858 }
859
860 return ok;
861}
862
863bool wxGetHostName(wxChar *buf, int sz)
864{
865 bool ok = wxGetHostNameInternal(buf, sz);
866
867 if ( ok )
868 {
869 // BSD systems return the FQDN, we only want the hostname, so extract
870 // it (we consider that dots are domain separators)
871 wxChar *dot = wxStrchr(buf, wxT('.'));
872 if ( dot )
873 {
874 // nuke it
875 *dot = wxT('\0');
876 }
877 }
878
879 return ok;
880}
881
882bool wxGetFullHostName(wxChar *buf, int sz)
883{
884 bool ok = wxGetHostNameInternal(buf, sz);
885
886 if ( ok )
887 {
888 if ( !wxStrchr(buf, wxT('.')) )
889 {
890 struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
891 if ( !host )
892 {
893 wxLogSysError(_("Cannot get the official hostname"));
894
895 ok = FALSE;
896 }
897 else
898 {
899 // the canonical name
900 wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
901 }
902 }
903 //else: it's already a FQDN (BSD behaves this way)
904 }
905
906 return ok;
907}
908
909bool wxGetUserId(wxChar *buf, int sz)
910{
911 struct passwd *who;
912
913 *buf = wxT('\0');
914 if ((who = getpwuid(getuid ())) != NULL)
915 {
916 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
917 return TRUE;
918 }
919
920 return FALSE;
921}
922
923bool wxGetUserName(wxChar *buf, int sz)
924{
925 struct passwd *who;
926
927 *buf = wxT('\0');
928 if ((who = getpwuid (getuid ())) != NULL)
929 {
930 // pw_gecos field in struct passwd is not standard
931#ifdef HAVE_PW_GECOS
932 char *comma = strchr(who->pw_gecos, ',');
933 if (comma)
934 *comma = '\0'; // cut off non-name comment fields
935 wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
936#else // !HAVE_PW_GECOS
937 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
938#endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
939 return TRUE;
940 }
941
942 return FALSE;
943}
944
945wxString wxGetOsDescription()
946{
947#ifndef WXWIN_OS_DESCRIPTION
948 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
949#else
950 return WXWIN_OS_DESCRIPTION;
951#endif
952}
953
954// this function returns the GUI toolkit version in GUI programs, but OS
955// version in non-GUI ones
956#if !wxUSE_GUI
957
958int wxGetOsVersion(int *majorVsn, int *minorVsn)
959{
960 int major, minor;
961 char name[256];
962
963 if ( sscanf(WXWIN_OS_DESCRIPTION, "%s %d.%d", name, &major, &minor) != 3 )
964 {
965 // unreckognized uname string format
966 major = minor = -1;
967 }
968
969 if ( majorVsn )
970 *majorVsn = major;
971 if ( minorVsn )
972 *minorVsn = minor;
973
974 return wxUNIX;
975}
976
977#endif // !wxUSE_GUI
978
979long wxGetFreeMemory()
980{
981#if defined(__LINUX__)
982 // get it from /proc/meminfo
983 FILE *fp = fopen("/proc/meminfo", "r");
984 if ( fp )
985 {
986 long memFree = -1;
987
988 char buf[1024];
989 if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) )
990 {
991 long memTotal, memUsed;
992 sscanf(buf, "Mem: %ld %ld %ld", &memTotal, &memUsed, &memFree);
993 }
994
995 fclose(fp);
996
997 return memFree;
998 }
999#elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1000 return sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE);
1001//#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1002#endif
1003
1004 // can't find it out
1005 return -1;
1006}
1007
1008bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
1009{
1010#ifdef HAVE_STATFS
1011
1012 struct statfs fs;
1013 if ( statfs(path, &fs) != 0 )
1014 {
1015 wxLogSysError("Failed to get file system statistics");
1016
1017 return FALSE;
1018 }
1019
1020 if ( pTotal )
1021 {
1022 *pTotal = wxLongLong(fs.f_blocks) * fs.f_bsize;
1023 }
1024
1025 if ( pFree )
1026 {
1027 *pFree = wxLongLong(fs.f_bavail) * fs.f_bsize;
1028 }
1029
1030 return TRUE;
1031#endif // HAVE_STATFS
1032
1033 return FALSE;
1034}
1035
1036// ----------------------------------------------------------------------------
1037// env vars
1038// ----------------------------------------------------------------------------
1039
1040bool wxGetEnv(const wxString& var, wxString *value)
1041{
1042 // wxGetenv is defined as getenv()
1043 wxChar *p = wxGetenv(var);
1044 if ( !p )
1045 return FALSE;
1046
1047 if ( value )
1048 {
1049 *value = p;
1050 }
1051
1052 return TRUE;
1053}
1054
1055bool wxSetEnv(const wxString& variable, const wxChar *value)
1056{
1057#if defined(HAVE_SETENV)
1058 return setenv(variable.mb_str(), value ? wxString(value).mb_str().data()
1059 : NULL, 1 /* overwrite */) == 0;
1060#elif defined(HAVE_PUTENV)
1061 wxString s = variable;
1062 if ( value )
1063 s << _T('=') << value;
1064
1065 // transform to ANSI
1066 const char *p = s.mb_str();
1067
1068 // the string will be free()d by libc
1069 char *buf = (char *)malloc(strlen(p) + 1);
1070 strcpy(buf, p);
1071
1072 return putenv(buf) == 0;
1073#else // no way to set an env var
1074 return FALSE;
1075#endif
1076}
1077
1078// ----------------------------------------------------------------------------
1079// signal handling
1080// ----------------------------------------------------------------------------
1081
1082#if wxUSE_ON_FATAL_EXCEPTION
1083
1084#include <signal.h>
1085
1086static void wxFatalSignalHandler(wxTYPE_SA_HANDLER)
1087{
1088 if ( wxTheApp )
1089 {
1090 // give the user a chance to do something special about this
1091 wxTheApp->OnFatalException();
1092 }
1093
1094 abort();
1095}
1096
1097bool wxHandleFatalExceptions(bool doit)
1098{
1099 // old sig handlers
1100 static bool s_savedHandlers = FALSE;
1101 static struct sigaction s_handlerFPE,
1102 s_handlerILL,
1103 s_handlerBUS,
1104 s_handlerSEGV;
1105
1106 bool ok = TRUE;
1107 if ( doit && !s_savedHandlers )
1108 {
1109 // install the signal handler
1110 struct sigaction act;
1111
1112 // some systems extend it with non std fields, so zero everything
1113 memset(&act, 0, sizeof(act));
1114
1115 act.sa_handler = wxFatalSignalHandler;
1116 sigemptyset(&act.sa_mask);
1117 act.sa_flags = 0;
1118
1119 ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0;
1120 ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0;
1121 ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0;
1122 ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0;
1123 if ( !ok )
1124 {
1125 wxLogDebug(_T("Failed to install our signal handler."));
1126 }
1127
1128 s_savedHandlers = TRUE;
1129 }
1130 else if ( s_savedHandlers )
1131 {
1132 // uninstall the signal handler
1133 ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0;
1134 ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0;
1135 ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0;
1136 ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0;
1137 if ( !ok )
1138 {
1139 wxLogDebug(_T("Failed to uninstall our signal handler."));
1140 }
1141
1142 s_savedHandlers = FALSE;
1143 }
1144 //else: nothing to do
1145
1146 return ok;
1147}
1148
1149#endif // wxUSE_ON_FATAL_EXCEPTION
1150
1151// ----------------------------------------------------------------------------
1152// error and debug output routines (deprecated, use wxLog)
1153// ----------------------------------------------------------------------------
1154
1155void wxDebugMsg( const char *format, ... )
1156{
1157 va_list ap;
1158 va_start( ap, format );
1159 vfprintf( stderr, format, ap );
1160 fflush( stderr );
1161 va_end(ap);
1162}
1163
1164void wxError( const wxString &msg, const wxString &title )
1165{
1166 wxFprintf( stderr, _("Error ") );
1167 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
1168 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
1169 wxFprintf( stderr, wxT(".\n") );
1170}
1171
1172void wxFatalError( const wxString &msg, const wxString &title )
1173{
1174 wxFprintf( stderr, _("Error ") );
1175 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
1176 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
1177 wxFprintf( stderr, wxT(".\n") );
1178 exit(3); // the same exit code as for abort()
1179}
1180