]> git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
detect EOF properly in wxFileInputStream
[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 4Kb) 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 Note that this is horribly inefficient for large amounts of output (count
479 the number of times we copy the data around) and so a better API is badly
480 needed!
481 */
482
483 class wxStreamTempBuffer
484 {
485 public:
486 wxStreamTempBuffer();
487
488 // call to associate a stream with this buffer, otherwise nothing happens
489 // at all
490 void Init(wxInputStream *stream);
491
492 // check for input on our stream and cache it in our buffer if any
493 void Update();
494
495 ~wxStreamTempBuffer();
496
497 private:
498 // the stream we're buffering, if NULL we don't do anything at all
499 wxInputStream *m_stream;
500
501 // the buffer of size m_size (NULL if m_size == 0)
502 void *m_buffer;
503
504 // the size of the buffer
505 size_t m_size;
506 };
507
508 wxStreamTempBuffer::wxStreamTempBuffer()
509 {
510 m_stream = NULL;
511 m_buffer = NULL;
512 m_size = 0;
513 }
514
515 void wxStreamTempBuffer::Init(wxInputStream *stream)
516 {
517 m_stream = stream;
518 }
519
520 void wxStreamTempBuffer::Update()
521 {
522 if ( m_stream && !m_stream->Eof() )
523 {
524 // realloc in blocks of 4Kb: this is the default (and minimal) buffer
525 // size of the Unix pipes so it should be the optimal step
526 static const size_t incSize = 4096;
527
528 void *buf = realloc(m_buffer, m_size + incSize);
529 if ( !buf )
530 {
531 // don't read any more, we don't have enough memory to do it
532 m_stream = NULL;
533 }
534 else // got memory for the buffer
535 {
536 m_buffer = buf;
537 m_stream->Read((char *)m_buffer + m_size, incSize);
538 m_size += m_stream->LastRead();
539 }
540 }
541 }
542
543 wxStreamTempBuffer::~wxStreamTempBuffer()
544 {
545 if ( m_buffer )
546 {
547 m_stream->Ungetch(m_buffer, m_size);
548 free(m_buffer);
549 }
550 }
551
552 #endif // wxUSE_STREAMS
553
554 // ----------------------------------------------------------------------------
555 // wxPipe: this encpasulates pipe() system call
556 // ----------------------------------------------------------------------------
557
558 class wxPipe
559 {
560 public:
561 // the symbolic names for the pipe ends
562 enum Direction
563 {
564 Read,
565 Write
566 };
567
568 enum
569 {
570 INVALID_FD = -1
571 };
572
573 // default ctor doesn't do anything
574 wxPipe() { m_fds[Read] = m_fds[Write] = INVALID_FD; }
575
576 // create the pipe, return TRUE if ok, FALSE on error
577 bool Create()
578 {
579 if ( pipe(m_fds) == -1 )
580 {
581 wxLogSysError(_("Pipe creation failed"));
582
583 return FALSE;
584 }
585
586 return TRUE;
587 }
588
589 // return TRUE if we were created successfully
590 bool IsOk() const { return m_fds[Read] != INVALID_FD; }
591
592 // return the descriptor for one of the pipe ends
593 int operator[](Direction which) const
594 {
595 wxASSERT_MSG( which >= 0 && (size_t)which < WXSIZEOF(m_fds),
596 _T("invalid pipe index") );
597
598 return m_fds[which];
599 }
600
601 // detach a descriptor, meaning that the pipe dtor won't close it, and
602 // return it
603 int Detach(Direction which)
604 {
605 wxASSERT_MSG( which >= 0 && (size_t)which < WXSIZEOF(m_fds),
606 _T("invalid pipe index") );
607
608 int fd = m_fds[which];
609 m_fds[which] = INVALID_FD;
610
611 return fd;
612 }
613
614 // close the pipe descriptors
615 void Close()
616 {
617 for ( size_t n = 0; n < WXSIZEOF(m_fds); n++ )
618 {
619 if ( m_fds[n] != INVALID_FD )
620 close(m_fds[n]);
621 }
622 }
623
624 // dtor closes the pipe descriptors
625 ~wxPipe() { Close(); }
626
627 private:
628 int m_fds[2];
629 };
630
631 // ----------------------------------------------------------------------------
632 // wxExecute: the real worker function
633 // ----------------------------------------------------------------------------
634
635 long wxExecute(wxChar **argv,
636 int flags,
637 wxProcess *process)
638 {
639 // for the sync execution, we return -1 to indicate failure, but for async
640 // case we return 0 which is never a valid PID
641 //
642 // we define this as a macro, not a variable, to avoid compiler warnings
643 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
644 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
645
646 wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );
647
648 #if wxUSE_UNICODE
649 int mb_argc = 0;
650 char *mb_argv[WXEXECUTE_NARGS];
651
652 while (argv[mb_argc])
653 {
654 wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
655 mb_argv[mb_argc] = strdup(mb_arg);
656 mb_argc++;
657 }
658 mb_argv[mb_argc] = (char *) NULL;
659
660 // this macro will free memory we used above
661 #define ARGS_CLEANUP \
662 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
663 free(mb_argv[mb_argc])
664 #else // ANSI
665 // no need for cleanup
666 #define ARGS_CLEANUP
667
668 wxChar **mb_argv = argv;
669 #endif // Unicode/ANSI
670
671 #if wxUSE_GUI
672 // create pipes
673 wxPipe pipeEndProcDetect;
674 if ( !pipeEndProcDetect.Create() )
675 {
676 wxLogError( _("Failed to execute '%s'\n"), *argv );
677
678 ARGS_CLEANUP;
679
680 return ERROR_RETURN_CODE;
681 }
682 #endif // wxUSE_GUI
683
684 // pipes for inter process communication
685 wxPipe pipeIn, // stdin
686 pipeOut, // stdout
687 pipeErr; // stderr
688
689 if ( process && process->IsRedirected() )
690 {
691 if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
692 {
693 wxLogError( _("Failed to execute '%s'\n"), *argv );
694
695 ARGS_CLEANUP;
696
697 return ERROR_RETURN_CODE;
698 }
699 }
700
701 // fork the process
702 #ifdef HAVE_VFORK
703 pid_t pid = vfork();
704 #else
705 pid_t pid = fork();
706 #endif
707
708 if ( pid == -1 ) // error?
709 {
710 wxLogSysError( _("Fork failed") );
711
712 ARGS_CLEANUP;
713
714 return ERROR_RETURN_CODE;
715 }
716 else if ( pid == 0 ) // we're in child
717 {
718 #if wxUSE_GUI
719 // reading side can be safely closed but we should keep the write one
720 // opened
721 pipeEndProcDetect.Detach(wxPipe::Write);
722 #endif // wxUSE_GUI
723
724 // These lines close the open file descriptors to to avoid any
725 // input/output which might block the process or irritate the user. If
726 // one wants proper IO for the subprocess, the right thing to do is to
727 // start an xterm executing it.
728 if ( !(flags & wxEXEC_SYNC) )
729 {
730 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
731 {
732 if ( fd == pipeIn[wxPipe::Read]
733 || fd == pipeOut[wxPipe::Write]
734 || fd == pipeErr[wxPipe::Write]
735 #if wxUSE_GUI
736 || fd == pipeEndProcDetect[wxPipe::Write]
737 #endif // wxUSE_GUI
738 )
739 {
740 // don't close this one, we still need it
741 continue;
742 }
743
744 // leave stderr opened too, it won't do any harm
745 if ( fd != STDERR_FILENO )
746 close(fd);
747 }
748
749 #ifndef __VMS
750 if ( flags & wxEXEC_MAKE_GROUP_LEADER )
751 {
752 // Set process group to child process' pid. Then killing -pid
753 // of the parent will kill the process and all of its children.
754 setsid();
755 }
756 #endif // !__VMS
757 }
758
759 // redirect stdio, stdout and stderr
760 if ( pipeIn.IsOk() )
761 {
762 if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 ||
763 dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 ||
764 dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 )
765 {
766 wxLogSysError(_("Failed to redirect child process input/output"));
767 }
768
769 pipeIn.Close();
770 pipeOut.Close();
771 pipeErr.Close();
772 }
773
774 execvp (*mb_argv, mb_argv);
775
776 // there is no return after successful exec()
777 _exit(-1);
778
779 // some compilers complain about missing return - of course, they
780 // should know that exit() doesn't return but what else can we do if
781 // they don't?
782 //
783 // and, sure enough, other compilers complain about unreachable code
784 // after exit() call, so we can just always have return here...
785 #if defined(__VMS) || defined(__INTEL_COMPILER)
786 return 0;
787 #endif
788 }
789 else // we're in parent
790 {
791 ARGS_CLEANUP;
792
793 // pipe initialization: construction of the wxStreams
794 #if wxUSE_STREAMS
795 wxStreamTempBuffer bufIn, bufErr;
796 #endif // wxUSE_STREAMS
797
798 if ( process && process->IsRedirected() )
799 {
800 #if wxUSE_STREAMS
801 // in/out for subprocess correspond to our out/in
802 wxOutputStream *outStream =
803 new wxProcessFileOutputStream(pipeIn.Detach(wxPipe::Write));
804
805 wxInputStream *inStream =
806 new wxProcessFileInputStream(pipeOut.Detach(wxPipe::Read));
807
808 wxInputStream *errStream =
809 new wxProcessFileInputStream(pipeErr.Detach(wxPipe::Read));
810
811 process->SetPipeStreams(inStream, outStream, errStream);
812
813 bufIn.Init(inStream);
814 bufErr.Init(errStream);
815 #endif // wxUSE_STREAMS
816 }
817
818 if ( pipeIn.IsOk() )
819 {
820 pipeIn.Close();
821 pipeOut.Close();
822 pipeErr.Close();
823 }
824
825 #if wxUSE_GUI && !defined(__WXMICROWIN__)
826 wxEndProcessData *data = new wxEndProcessData;
827
828 data->tag = wxAddProcessCallback
829 (
830 data,
831 pipeEndProcDetect.Detach(wxPipe::Read)
832 );
833
834 pipeEndProcDetect.Close();
835
836 if ( flags & wxEXEC_SYNC )
837 {
838 // we may have process for capturing the program output, but it's
839 // not used in wxEndProcessData in the case of sync execution
840 data->process = NULL;
841
842 // sync execution: indicate it by negating the pid
843 data->pid = -pid;
844
845 wxBusyCursor bc;
846 wxWindowDisabler wd;
847
848 // data->pid will be set to 0 from GTK_EndProcessDetector when the
849 // process terminates
850 while ( data->pid != 0 )
851 {
852 #if wxUSE_STREAMS
853 bufIn.Update();
854 bufErr.Update();
855 #endif // wxUSE_STREAMS
856
857 // give GTK+ a chance to call GTK_EndProcessDetector here and
858 // also repaint the GUI
859 wxYield();
860 }
861
862 int exitcode = data->exitcode;
863
864 delete data;
865
866 return exitcode;
867 }
868 else // async execution
869 {
870 // async execution, nothing special to do - caller will be
871 // notified about the process termination if process != NULL, data
872 // will be deleted in GTK_EndProcessDetector
873 data->process = process;
874 data->pid = pid;
875
876 return pid;
877 }
878 #else // !wxUSE_GUI
879
880 wxASSERT_MSG( flags & wxEXEC_SYNC,
881 wxT("async execution not supported yet") );
882
883 int exitcode = 0;
884 if ( waitpid(pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) )
885 {
886 wxLogSysError(_("Waiting for subprocess termination failed"));
887 }
888
889 return exitcode;
890 #endif // wxUSE_GUI
891 }
892 }
893
894 #undef ERROR_RETURN_CODE
895 #undef ARGS_CLEANUP
896
897 // ----------------------------------------------------------------------------
898 // file and directory functions
899 // ----------------------------------------------------------------------------
900
901 const wxChar* wxGetHomeDir( wxString *home )
902 {
903 *home = wxGetUserHome( wxString() );
904 wxString tmp;
905 if ( home->IsEmpty() )
906 *home = wxT("/");
907 #ifdef __VMS
908 tmp = *home;
909 if ( tmp.Last() != wxT(']'))
910 if ( tmp.Last() != wxT('/')) *home << wxT('/');
911 #endif
912 return home->c_str();
913 }
914
915 #if wxUSE_UNICODE
916 const wxMB2WXbuf wxGetUserHome( const wxString &user )
917 #else // just for binary compatibility -- there is no 'const' here
918 char *wxGetUserHome( const wxString &user )
919 #endif
920 {
921 struct passwd *who = (struct passwd *) NULL;
922
923 if ( !user )
924 {
925 wxChar *ptr;
926
927 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
928 {
929 return ptr;
930 }
931 if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
932 {
933 who = getpwnam(wxConvertWX2MB(ptr));
934 }
935
936 // We now make sure the the user exists!
937 if (who == NULL)
938 {
939 who = getpwuid(getuid());
940 }
941 }
942 else
943 {
944 who = getpwnam (user.mb_str());
945 }
946
947 return wxConvertMB2WX(who ? who->pw_dir : 0);
948 }
949
950 // ----------------------------------------------------------------------------
951 // network and user id routines
952 // ----------------------------------------------------------------------------
953
954 // retrieve either the hostname or FQDN depending on platform (caller must
955 // check whether it's one or the other, this is why this function is for
956 // private use only)
957 static bool wxGetHostNameInternal(wxChar *buf, int sz)
958 {
959 wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") );
960
961 *buf = wxT('\0');
962
963 // we're using uname() which is POSIX instead of less standard sysinfo()
964 #if defined(HAVE_UNAME)
965 struct utsname uts;
966 bool ok = uname(&uts) != -1;
967 if ( ok )
968 {
969 wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
970 buf[sz] = wxT('\0');
971 }
972 #elif defined(HAVE_GETHOSTNAME)
973 bool ok = gethostname(buf, sz) != -1;
974 #else // no uname, no gethostname
975 wxFAIL_MSG(wxT("don't know host name for this machine"));
976
977 bool ok = FALSE;
978 #endif // uname/gethostname
979
980 if ( !ok )
981 {
982 wxLogSysError(_("Cannot get the hostname"));
983 }
984
985 return ok;
986 }
987
988 bool wxGetHostName(wxChar *buf, int sz)
989 {
990 bool ok = wxGetHostNameInternal(buf, sz);
991
992 if ( ok )
993 {
994 // BSD systems return the FQDN, we only want the hostname, so extract
995 // it (we consider that dots are domain separators)
996 wxChar *dot = wxStrchr(buf, wxT('.'));
997 if ( dot )
998 {
999 // nuke it
1000 *dot = wxT('\0');
1001 }
1002 }
1003
1004 return ok;
1005 }
1006
1007 bool wxGetFullHostName(wxChar *buf, int sz)
1008 {
1009 bool ok = wxGetHostNameInternal(buf, sz);
1010
1011 if ( ok )
1012 {
1013 if ( !wxStrchr(buf, wxT('.')) )
1014 {
1015 struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
1016 if ( !host )
1017 {
1018 wxLogSysError(_("Cannot get the official hostname"));
1019
1020 ok = FALSE;
1021 }
1022 else
1023 {
1024 // the canonical name
1025 wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
1026 }
1027 }
1028 //else: it's already a FQDN (BSD behaves this way)
1029 }
1030
1031 return ok;
1032 }
1033
1034 bool wxGetUserId(wxChar *buf, int sz)
1035 {
1036 struct passwd *who;
1037
1038 *buf = wxT('\0');
1039 if ((who = getpwuid(getuid ())) != NULL)
1040 {
1041 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
1042 return TRUE;
1043 }
1044
1045 return FALSE;
1046 }
1047
1048 bool wxGetUserName(wxChar *buf, int sz)
1049 {
1050 struct passwd *who;
1051
1052 *buf = wxT('\0');
1053 if ((who = getpwuid (getuid ())) != NULL)
1054 {
1055 // pw_gecos field in struct passwd is not standard
1056 #ifdef HAVE_PW_GECOS
1057 char *comma = strchr(who->pw_gecos, ',');
1058 if (comma)
1059 *comma = '\0'; // cut off non-name comment fields
1060 wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
1061 #else // !HAVE_PW_GECOS
1062 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
1063 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
1064 return TRUE;
1065 }
1066
1067 return FALSE;
1068 }
1069
1070 #ifndef __WXMAC__
1071 wxString wxGetOsDescription()
1072 {
1073 #ifndef WXWIN_OS_DESCRIPTION
1074 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
1075 #else
1076 return WXWIN_OS_DESCRIPTION;
1077 #endif
1078 }
1079 #endif
1080
1081 // this function returns the GUI toolkit version in GUI programs, but OS
1082 // version in non-GUI ones
1083 #if !wxUSE_GUI
1084
1085 int wxGetOsVersion(int *majorVsn, int *minorVsn)
1086 {
1087 int major, minor;
1088 char name[256];
1089
1090 if ( sscanf(WXWIN_OS_DESCRIPTION, "%s %d.%d", name, &major, &minor) != 3 )
1091 {
1092 // unreckognized uname string format
1093 major = minor = -1;
1094 }
1095
1096 if ( majorVsn )
1097 *majorVsn = major;
1098 if ( minorVsn )
1099 *minorVsn = minor;
1100
1101 return wxUNIX;
1102 }
1103
1104 #endif // !wxUSE_GUI
1105
1106 unsigned long wxGetProcessId()
1107 {
1108 return (unsigned long)getpid();
1109 }
1110
1111 long wxGetFreeMemory()
1112 {
1113 #if defined(__LINUX__)
1114 // get it from /proc/meminfo
1115 FILE *fp = fopen("/proc/meminfo", "r");
1116 if ( fp )
1117 {
1118 long memFree = -1;
1119
1120 char buf[1024];
1121 if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) )
1122 {
1123 long memTotal, memUsed;
1124 sscanf(buf, "Mem: %ld %ld %ld", &memTotal, &memUsed, &memFree);
1125 }
1126
1127 fclose(fp);
1128
1129 return memFree;
1130 }
1131 #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1132 return sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE);
1133 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1134 #endif
1135
1136 // can't find it out
1137 return -1;
1138 }
1139
1140 bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
1141 {
1142 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
1143 // the case to "char *" is needed for AIX 4.3
1144 wxStatFs fs;
1145 if ( statfs((char *)path.fn_str(), &fs) != 0 )
1146 {
1147 wxLogSysError("Failed to get file system statistics");
1148
1149 return FALSE;
1150 }
1151
1152 // under Solaris we also have to use f_frsize field instead of f_bsize
1153 // which is in general a multiple of f_frsize
1154 #ifdef HAVE_STATVFS
1155 wxLongLong blockSize = fs.f_frsize;
1156 #else // HAVE_STATFS
1157 wxLongLong blockSize = fs.f_bsize;
1158 #endif // HAVE_STATVFS/HAVE_STATFS
1159
1160 if ( pTotal )
1161 {
1162 *pTotal = wxLongLong(fs.f_blocks) * blockSize;
1163 }
1164
1165 if ( pFree )
1166 {
1167 *pFree = wxLongLong(fs.f_bavail) * blockSize;
1168 }
1169
1170 return TRUE;
1171 #else // !HAVE_STATFS && !HAVE_STATVFS
1172 return FALSE;
1173 #endif // HAVE_STATFS
1174 }
1175
1176 // ----------------------------------------------------------------------------
1177 // env vars
1178 // ----------------------------------------------------------------------------
1179
1180 bool wxGetEnv(const wxString& var, wxString *value)
1181 {
1182 // wxGetenv is defined as getenv()
1183 wxChar *p = wxGetenv(var);
1184 if ( !p )
1185 return FALSE;
1186
1187 if ( value )
1188 {
1189 *value = p;
1190 }
1191
1192 return TRUE;
1193 }
1194
1195 bool wxSetEnv(const wxString& variable, const wxChar *value)
1196 {
1197 #if defined(HAVE_SETENV)
1198 return setenv(variable.mb_str(),
1199 value ? (const char *)wxString(value).mb_str()
1200 : NULL,
1201 1 /* overwrite */) == 0;
1202 #elif defined(HAVE_PUTENV)
1203 wxString s = variable;
1204 if ( value )
1205 s << _T('=') << value;
1206
1207 // transform to ANSI
1208 const char *p = s.mb_str();
1209
1210 // the string will be free()d by libc
1211 char *buf = (char *)malloc(strlen(p) + 1);
1212 strcpy(buf, p);
1213
1214 return putenv(buf) == 0;
1215 #else // no way to set an env var
1216 return FALSE;
1217 #endif
1218 }
1219
1220 // ----------------------------------------------------------------------------
1221 // signal handling
1222 // ----------------------------------------------------------------------------
1223
1224 #if wxUSE_ON_FATAL_EXCEPTION
1225
1226 #include <signal.h>
1227
1228 extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER)
1229 {
1230 if ( wxTheApp )
1231 {
1232 // give the user a chance to do something special about this
1233 wxTheApp->OnFatalException();
1234 }
1235
1236 abort();
1237 }
1238
1239 bool wxHandleFatalExceptions(bool doit)
1240 {
1241 // old sig handlers
1242 static bool s_savedHandlers = FALSE;
1243 static struct sigaction s_handlerFPE,
1244 s_handlerILL,
1245 s_handlerBUS,
1246 s_handlerSEGV;
1247
1248 bool ok = TRUE;
1249 if ( doit && !s_savedHandlers )
1250 {
1251 // install the signal handler
1252 struct sigaction act;
1253
1254 // some systems extend it with non std fields, so zero everything
1255 memset(&act, 0, sizeof(act));
1256
1257 act.sa_handler = wxFatalSignalHandler;
1258 sigemptyset(&act.sa_mask);
1259 act.sa_flags = 0;
1260
1261 ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0;
1262 ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0;
1263 ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0;
1264 ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0;
1265 if ( !ok )
1266 {
1267 wxLogDebug(_T("Failed to install our signal handler."));
1268 }
1269
1270 s_savedHandlers = TRUE;
1271 }
1272 else if ( s_savedHandlers )
1273 {
1274 // uninstall the signal handler
1275 ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0;
1276 ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0;
1277 ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0;
1278 ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0;
1279 if ( !ok )
1280 {
1281 wxLogDebug(_T("Failed to uninstall our signal handler."));
1282 }
1283
1284 s_savedHandlers = FALSE;
1285 }
1286 //else: nothing to do
1287
1288 return ok;
1289 }
1290
1291 #endif // wxUSE_ON_FATAL_EXCEPTION
1292
1293 // ----------------------------------------------------------------------------
1294 // error and debug output routines (deprecated, use wxLog)
1295 // ----------------------------------------------------------------------------
1296
1297 #if WXWIN_COMPATIBILITY_2_2
1298
1299 void wxDebugMsg( const char *format, ... )
1300 {
1301 va_list ap;
1302 va_start( ap, format );
1303 vfprintf( stderr, format, ap );
1304 fflush( stderr );
1305 va_end(ap);
1306 }
1307
1308 void wxError( const wxString &msg, const wxString &title )
1309 {
1310 wxFprintf( stderr, _("Error ") );
1311 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
1312 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
1313 wxFprintf( stderr, wxT(".\n") );
1314 }
1315
1316 void wxFatalError( const wxString &msg, const wxString &title )
1317 {
1318 wxFprintf( stderr, _("Error ") );
1319 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
1320 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
1321 wxFprintf( stderr, wxT(".\n") );
1322 exit(3); // the same exit code as for abort()
1323 }
1324
1325 #endif // WXWIN_COMPATIBILITY_2_2
1326