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