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