]> git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
fb2854f847177fa5fdd13cfd8c9969f68255b271
[wxWidgets.git] / src / unix / utilsunx.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/utilsunx.cpp
3 // Purpose: generic Unix implementation of many wx functions (for wxBase)
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 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21 #include "wx/utils.h"
22
23 #define USE_PUTENV (!defined(HAVE_SETENV) && defined(HAVE_PUTENV))
24
25 #ifndef WX_PRECOMP
26 #include "wx/string.h"
27 #include "wx/intl.h"
28 #include "wx/log.h"
29 #include "wx/app.h"
30 #include "wx/wxcrtvararg.h"
31 #if USE_PUTENV
32 #include "wx/module.h"
33 #include "wx/hashmap.h"
34 #endif
35 #endif
36
37 #include "wx/apptrait.h"
38
39 #include "wx/process.h"
40 #include "wx/thread.h"
41
42 #include "wx/cmdline.h"
43
44 #include "wx/wfstream.h"
45
46 #include "wx/private/selectdispatcher.h"
47 #include "wx/private/fdiodispatcher.h"
48 #include "wx/unix/execute.h"
49 #include "wx/unix/private.h"
50
51 #ifdef wxHAS_GENERIC_PROCESS_CALLBACK
52 #include "wx/private/fdiodispatcher.h"
53 #endif
54
55 #include <pwd.h>
56 #include <sys/wait.h> // waitpid()
57
58 #ifdef HAVE_SYS_SELECT_H
59 # include <sys/select.h>
60 #endif
61
62 #define HAS_PIPE_STREAMS (wxUSE_STREAMS && wxUSE_FILE)
63
64 #if HAS_PIPE_STREAMS
65
66 #include "wx/private/pipestream.h"
67
68 // define this to let wxexec.cpp know that we know what we're doing
69 #define _WX_USED_BY_WXEXECUTE_
70 #include "../common/execcmn.cpp"
71
72 #endif // HAS_PIPE_STREAMS
73
74 // not only the statfs syscall is called differently depending on platform, but
75 // one of its incarnations, statvfs(), takes different arguments under
76 // different platforms and even different versions of the same system (Solaris
77 // 7 and 8): if you want to test for this, don't forget that the problems only
78 // appear if the large files support is enabled
79 #ifdef HAVE_STATFS
80 #ifdef __BSD__
81 #include <sys/param.h>
82 #include <sys/mount.h>
83 #else // !__BSD__
84 #include <sys/vfs.h>
85 #endif // __BSD__/!__BSD__
86
87 #define wxStatfs statfs
88
89 #ifndef HAVE_STATFS_DECL
90 // some systems lack statfs() prototype in the system headers (AIX 4)
91 extern "C" int statfs(const char *path, struct statfs *buf);
92 #endif
93 #endif // HAVE_STATFS
94
95 #ifdef HAVE_STATVFS
96 #include <sys/statvfs.h>
97
98 #define wxStatfs statvfs
99 #endif // HAVE_STATVFS
100
101 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
102 // WX_STATFS_T is detected by configure
103 #define wxStatfs_t WX_STATFS_T
104 #endif
105
106 // SGI signal.h defines signal handler arguments differently depending on
107 // whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
108 #if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
109 #define _LANGUAGE_C_PLUS_PLUS 1
110 #endif // SGI hack
111
112 #include <stdarg.h>
113 #include <dirent.h>
114 #include <string.h>
115 #include <sys/stat.h>
116 #include <sys/types.h>
117 #include <sys/wait.h>
118 #include <unistd.h>
119 #include <errno.h>
120 #include <netdb.h>
121 #include <signal.h>
122 #include <fcntl.h> // for O_WRONLY and friends
123 #include <time.h> // nanosleep() and/or usleep()
124 #include <ctype.h> // isspace()
125 #include <sys/time.h> // needed for FD_SETSIZE
126
127 #ifdef HAVE_UNAME
128 #include <sys/utsname.h> // for uname()
129 #endif // HAVE_UNAME
130
131 // Used by wxGetFreeMemory().
132 #ifdef __SGI__
133 #include <sys/sysmp.h>
134 #include <sys/sysinfo.h> // for SAGET and MINFO structures
135 #endif
136
137 #ifdef HAVE_SETPRIORITY
138 #include <sys/resource.h> // for setpriority()
139 #endif
140
141 // ----------------------------------------------------------------------------
142 // conditional compilation
143 // ----------------------------------------------------------------------------
144
145 // many versions of Unices have this function, but it is not defined in system
146 // headers - please add your system here if it is the case for your OS.
147 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
148 #if !defined(HAVE_USLEEP) && \
149 ((defined(__SUN__) && !defined(__SunOs_5_6) && \
150 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
151 defined(__osf__) || defined(__EMX__))
152 extern "C"
153 {
154 #ifdef __EMX__
155 /* I copied this from the XFree86 diffs. AV. */
156 #define INCL_DOSPROCESS
157 #include <os2.h>
158 inline void usleep(unsigned long delay)
159 {
160 DosSleep(delay ? (delay/1000l) : 1l);
161 }
162 #else // Unix
163 int usleep(unsigned int usec);
164 #endif // __EMX__/Unix
165 };
166
167 #define HAVE_USLEEP 1
168 #endif // Unices without usleep()
169
170 // ============================================================================
171 // implementation
172 // ============================================================================
173
174 // ----------------------------------------------------------------------------
175 // sleeping
176 // ----------------------------------------------------------------------------
177
178 void wxSleep(int nSecs)
179 {
180 sleep(nSecs);
181 }
182
183 void wxMicroSleep(unsigned long microseconds)
184 {
185 #if defined(HAVE_NANOSLEEP)
186 timespec tmReq;
187 tmReq.tv_sec = (time_t)(microseconds / 1000000);
188 tmReq.tv_nsec = (microseconds % 1000000) * 1000;
189
190 // we're not interested in remaining time nor in return value
191 (void)nanosleep(&tmReq, NULL);
192 #elif defined(HAVE_USLEEP)
193 // uncomment this if you feel brave or if you are sure that your version
194 // of Solaris has a safe usleep() function but please notice that usleep()
195 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
196 // documented as MT-Safe
197 #if defined(__SUN__) && wxUSE_THREADS
198 #error "usleep() cannot be used in MT programs under Solaris."
199 #endif // Sun
200
201 usleep(microseconds);
202 #elif defined(HAVE_SLEEP)
203 // under BeOS sleep() takes seconds (what about other platforms, if any?)
204 sleep(microseconds * 1000000);
205 #else // !sleep function
206 #error "usleep() or nanosleep() function required for wxMicroSleep"
207 #endif // sleep function
208 }
209
210 void wxMilliSleep(unsigned long milliseconds)
211 {
212 wxMicroSleep(milliseconds*1000);
213 }
214
215 // ----------------------------------------------------------------------------
216 // process management
217 // ----------------------------------------------------------------------------
218
219 int wxKill(long pid, wxSignal sig, wxKillError *rc, int flags)
220 {
221 int err = kill((pid_t) (flags & wxKILL_CHILDREN) ? -pid : pid, (int)sig);
222 if ( rc )
223 {
224 switch ( err ? errno : 0 )
225 {
226 case 0:
227 *rc = wxKILL_OK;
228 break;
229
230 case EINVAL:
231 *rc = wxKILL_BAD_SIGNAL;
232 break;
233
234 case EPERM:
235 *rc = wxKILL_ACCESS_DENIED;
236 break;
237
238 case ESRCH:
239 *rc = wxKILL_NO_PROCESS;
240 break;
241
242 default:
243 // this goes against Unix98 docs so log it
244 wxLogDebug(wxT("unexpected kill(2) return value %d"), err);
245
246 // something else...
247 *rc = wxKILL_ERROR;
248 }
249 }
250
251 return err;
252 }
253
254 // Shutdown or reboot the PC
255 bool wxShutdown(int flags)
256 {
257 flags &= ~wxSHUTDOWN_FORCE;
258
259 wxChar level;
260 switch ( flags )
261 {
262 case wxSHUTDOWN_POWEROFF:
263 level = wxT('0');
264 break;
265
266 case wxSHUTDOWN_REBOOT:
267 level = wxT('6');
268 break;
269
270 case wxSHUTDOWN_LOGOFF:
271 // TODO: use dcop to log off?
272 return false;
273
274 default:
275 wxFAIL_MSG( wxT("unknown wxShutdown() flag") );
276 return false;
277 }
278
279 return system(wxString::Format("init %c", level).mb_str()) == 0;
280 }
281
282 // ----------------------------------------------------------------------------
283 // wxStream classes to support IO redirection in wxExecute
284 // ----------------------------------------------------------------------------
285
286 #if HAS_PIPE_STREAMS
287
288 bool wxPipeInputStream::CanRead() const
289 {
290 if ( m_lasterror == wxSTREAM_EOF )
291 return false;
292
293 // check if there is any input available
294 struct timeval tv;
295 tv.tv_sec = 0;
296 tv.tv_usec = 0;
297
298 const int fd = m_file->fd();
299
300 fd_set readfds;
301
302 wxFD_ZERO(&readfds);
303 wxFD_SET(fd, &readfds);
304
305 switch ( select(fd + 1, &readfds, NULL, NULL, &tv) )
306 {
307 case -1:
308 wxLogSysError(_("Impossible to get child process input"));
309 // fall through
310
311 case 0:
312 return false;
313
314 default:
315 wxFAIL_MSG(wxT("unexpected select() return value"));
316 // still fall through
317
318 case 1:
319 // input available -- or maybe not, as select() returns 1 when a
320 // read() will complete without delay, but it could still not read
321 // anything
322 return !Eof();
323 }
324 }
325
326 size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t size)
327 {
328 // We need to suppress error logging here, because on writing to a pipe
329 // which is full, wxFile::Write reports a system error. However, this is
330 // not an extraordinary situation, and it should not be reported to the
331 // user (but if really needed, the program can recognize it by checking
332 // whether LastRead() == 0.) Other errors will be reported below.
333 size_t ret;
334 {
335 wxLogNull logNo;
336 ret = m_file->Write(buffer, size);
337 }
338
339 switch ( m_file->GetLastError() )
340 {
341 // pipe is full
342 #ifdef EAGAIN
343 case EAGAIN:
344 #endif
345 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
346 case EWOULDBLOCK:
347 #endif
348 // do not treat it as an error
349 m_file->ClearLastError();
350 // fall through
351
352 // no error
353 case 0:
354 break;
355
356 // some real error
357 default:
358 wxLogSysError(_("Can't write to child process's stdin"));
359 m_lasterror = wxSTREAM_WRITE_ERROR;
360 }
361
362 return ret;
363 }
364
365 #endif // HAS_PIPE_STREAMS
366
367 // ----------------------------------------------------------------------------
368 // wxShell
369 // ----------------------------------------------------------------------------
370
371 static wxString wxMakeShellCommand(const wxString& command)
372 {
373 wxString cmd;
374 if ( !command )
375 {
376 // just an interactive shell
377 cmd = wxT("xterm");
378 }
379 else
380 {
381 // execute command in a shell
382 cmd << wxT("/bin/sh -c '") << command << wxT('\'');
383 }
384
385 return cmd;
386 }
387
388 bool wxShell(const wxString& command)
389 {
390 return wxExecute(wxMakeShellCommand(command), wxEXEC_SYNC) == 0;
391 }
392
393 bool wxShell(const wxString& command, wxArrayString& output)
394 {
395 wxCHECK_MSG( !command.empty(), false, wxT("can't exec shell non interactively") );
396
397 return wxExecute(wxMakeShellCommand(command), output);
398 }
399
400 namespace
401 {
402
403 // helper class for storing arguments as char** array suitable for passing to
404 // execvp(), whatever form they were passed to us
405 class ArgsArray
406 {
407 public:
408 ArgsArray(const wxArrayString& args)
409 {
410 Init(args.size());
411
412 for ( int i = 0; i < m_argc; i++ )
413 {
414 m_argv[i] = wxStrdup(args[i]);
415 }
416 }
417
418 #if wxUSE_UNICODE
419 ArgsArray(wchar_t **wargv)
420 {
421 int argc = 0;
422 while ( wargv[argc] )
423 argc++;
424
425 Init(argc);
426
427 for ( int i = 0; i < m_argc; i++ )
428 {
429 m_argv[i] = wxSafeConvertWX2MB(wargv[i]).release();
430 }
431 }
432 #endif // wxUSE_UNICODE
433
434 ~ArgsArray()
435 {
436 for ( int i = 0; i < m_argc; i++ )
437 {
438 free(m_argv[i]);
439 }
440
441 delete [] m_argv;
442 }
443
444 operator char**() const { return m_argv; }
445
446 private:
447 void Init(int argc)
448 {
449 m_argc = argc;
450 m_argv = new char *[m_argc + 1];
451 m_argv[m_argc] = NULL;
452 }
453
454 int m_argc;
455 char **m_argv;
456
457 wxDECLARE_NO_COPY_CLASS(ArgsArray);
458 };
459
460 } // anonymous namespace
461
462 // ----------------------------------------------------------------------------
463 // wxExecute implementations
464 // ----------------------------------------------------------------------------
465
466 #if defined(__DARWIN__)
467 bool wxMacLaunch(char **argv);
468 #endif
469
470 long wxExecute(const wxString& command, int flags, wxProcess *process,
471 const wxExecuteEnv *env)
472 {
473 ArgsArray argv(wxCmdLineParser::ConvertStringToArgs(command,
474 wxCMD_LINE_SPLIT_UNIX));
475
476 return wxExecute(argv, flags, process, env);
477 }
478
479 #if wxUSE_UNICODE
480
481 long wxExecute(wchar_t **wargv, int flags, wxProcess *process,
482 const wxExecuteEnv *env)
483 {
484 ArgsArray argv(wargv);
485
486 return wxExecute(argv, flags, process, env);
487 }
488
489 #endif // wxUSE_UNICODE
490
491 // wxExecute: the real worker function
492 long wxExecute(char **argv, int flags, wxProcess *process,
493 const wxExecuteEnv *env)
494 {
495 // for the sync execution, we return -1 to indicate failure, but for async
496 // case we return 0 which is never a valid PID
497 //
498 // we define this as a macro, not a variable, to avoid compiler warnings
499 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
500 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
501
502 wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );
503
504 #if wxUSE_THREADS
505 // fork() doesn't mix well with POSIX threads: on many systems the program
506 // deadlocks or crashes for some reason. Probably our code is buggy and
507 // doesn't do something which must be done to allow this to work, but I
508 // don't know what yet, so for now just warn the user (this is the least we
509 // can do) about it
510 wxASSERT_MSG( wxThread::IsMain(),
511 wxT("wxExecute() can be called only from the main thread") );
512 #endif // wxUSE_THREADS
513
514 #if defined(__WXCOCOA__) || ( defined(__WXOSX_MAC__) && wxOSX_USE_COCOA_OR_CARBON )
515 // wxMacLaunch() only executes app bundles and only does it asynchronously.
516 // It returns false if the target is not an app bundle, thus falling
517 // through to the regular code for non app bundles.
518 if ( !(flags & wxEXEC_SYNC) && wxMacLaunch(argv) )
519 {
520 // we don't have any PID to return so just make up something non null
521 return -1;
522 }
523 #endif // __DARWIN__
524
525
526 // this struct contains all information which we use for housekeeping
527 wxExecuteData execData;
528 execData.flags = flags;
529 execData.process = process;
530
531 // create pipes
532 if ( !execData.pipeEndProcDetect.Create() )
533 {
534 wxLogError( _("Failed to execute '%s'\n"), *argv );
535
536 return ERROR_RETURN_CODE;
537 }
538
539 // pipes for inter process communication
540 wxPipe pipeIn, // stdin
541 pipeOut, // stdout
542 pipeErr; // stderr
543
544 if ( process && process->IsRedirected() )
545 {
546 if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
547 {
548 wxLogError( _("Failed to execute '%s'\n"), *argv );
549
550 return ERROR_RETURN_CODE;
551 }
552 }
553
554 // priority: we need to map wxWidgets priority which is in the range 0..100
555 // to Unix nice value which is in the range -20..19. As there is an odd
556 // number of elements in our range and an even number in the Unix one, we
557 // have to do it in this rather ugly way to guarantee that:
558 // 1. wxPRIORITY_{MIN,DEFAULT,MAX} map to -20, 0 and 19 respectively.
559 // 2. The mapping is monotonously increasing.
560 // 3. The mapping is onto the target range.
561 int prio = process ? process->GetPriority() : 0;
562 if ( prio <= 50 )
563 prio = (2*prio)/5 - 20;
564 else if ( prio < 55 )
565 prio = 1;
566 else
567 prio = (2*prio)/5 - 21;
568
569 // fork the process
570 //
571 // NB: do *not* use vfork() here, it completely breaks this code for some
572 // reason under Solaris (and maybe others, although not under Linux)
573 // But on OpenVMS we do not have fork so we have to use vfork and
574 // cross our fingers that it works.
575 #ifdef __VMS
576 pid_t pid = vfork();
577 #else
578 pid_t pid = fork();
579 #endif
580 if ( pid == -1 ) // error?
581 {
582 wxLogSysError( _("Fork failed") );
583
584 return ERROR_RETURN_CODE;
585 }
586 else if ( pid == 0 ) // we're in child
587 {
588 // NB: we used to close all the unused descriptors of the child here
589 // but this broke some programs which relied on e.g. FD 1 being
590 // always opened so don't do it any more, after all there doesn't
591 // seem to be any real problem with keeping them opened
592
593 #if !defined(__VMS) && !defined(__EMX__)
594 if ( flags & wxEXEC_MAKE_GROUP_LEADER )
595 {
596 // Set process group to child process' pid. Then killing -pid
597 // of the parent will kill the process and all of its children.
598 setsid();
599 }
600 #endif // !__VMS
601
602 #if defined(HAVE_SETPRIORITY)
603 if ( prio && setpriority(PRIO_PROCESS, 0, prio) != 0 )
604 {
605 wxLogSysError(_("Failed to set process priority"));
606 }
607 #endif // HAVE_SETPRIORITY
608
609 // redirect stdin, stdout and stderr
610 if ( pipeIn.IsOk() )
611 {
612 if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 ||
613 dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 ||
614 dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 )
615 {
616 wxLogSysError(_("Failed to redirect child process input/output"));
617 }
618
619 pipeIn.Close();
620 pipeOut.Close();
621 pipeErr.Close();
622 }
623
624 // Close all (presumably accidentally) inherited file descriptors to
625 // avoid descriptor leaks. This means that we don't allow inheriting
626 // them purposefully but this seems like a lesser evil in wx code.
627 // Ideally we'd provide some flag to indicate that none (or some?) of
628 // the descriptors do not need to be closed but for now this is better
629 // than never closing them at all as wx code never used FD_CLOEXEC.
630
631 // Note that while the reading side of the end process detection pipe
632 // can be safely closed, we should keep the write one opened, it will
633 // be only closed when the process terminates resulting in a read
634 // notification to the parent
635 const int fdEndProc = execData.pipeEndProcDetect.Detach(wxPipe::Write);
636 execData.pipeEndProcDetect.Close();
637
638 // TODO: Iterating up to FD_SETSIZE is both inefficient (because it may
639 // be quite big) and incorrect (because in principle we could
640 // have more opened descriptions than this number). Unfortunately
641 // there is no good portable solution for closing all descriptors
642 // above a certain threshold but non-portable solutions exist for
643 // most platforms, see [http://stackoverflow.com/questions/899038/
644 // getting-the-highest-allocated-file-descriptor]
645 for ( int fd = 0; fd < (int)FD_SETSIZE; ++fd )
646 {
647 if ( fd != STDIN_FILENO &&
648 fd != STDOUT_FILENO &&
649 fd != STDERR_FILENO &&
650 fd != fdEndProc )
651 {
652 close(fd);
653 }
654 }
655
656
657 // Process additional options if we have any
658 if ( env )
659 {
660 // Change working directory if it is specified
661 if ( !env->cwd.empty() )
662 wxSetWorkingDirectory(env->cwd);
663
664 // Change environment if needed.
665 //
666 // NB: We can't use execve() currently because we allow using
667 // non full paths to wxExecute(), i.e. we want to search for
668 // the program in PATH. However it just might be simpler/better
669 // to do the search manually and use execve() envp parameter to
670 // set up the environment of the child process explicitly
671 // instead of doing what we do below.
672 if ( !env->env.empty() )
673 {
674 wxEnvVariableHashMap oldenv;
675 wxGetEnvMap(&oldenv);
676
677 // Remove unwanted variables
678 wxEnvVariableHashMap::const_iterator it;
679 for ( it = oldenv.begin(); it != oldenv.end(); ++it )
680 {
681 if ( env->env.find(it->first) == env->env.end() )
682 wxUnsetEnv(it->first);
683 }
684
685 // And add the new ones (possibly replacing the old values)
686 for ( it = env->env.begin(); it != env->env.end(); ++it )
687 wxSetEnv(it->first, it->second);
688 }
689 }
690
691 execvp(*argv, argv);
692
693 fprintf(stderr, "execvp(");
694 for ( char **a = argv; *a; a++ )
695 fprintf(stderr, "%s%s", a == argv ? "" : ", ", *a);
696 fprintf(stderr, ") failed with error %d!\n", errno);
697
698 // there is no return after successful exec()
699 _exit(-1);
700
701 // some compilers complain about missing return - of course, they
702 // should know that exit() doesn't return but what else can we do if
703 // they don't?
704 //
705 // and, sure enough, other compilers complain about unreachable code
706 // after exit() call, so we can just always have return here...
707 #if defined(__VMS) || defined(__INTEL_COMPILER)
708 return 0;
709 #endif
710 }
711 else // we're in parent
712 {
713 // save it for WaitForChild() use
714 execData.pid = pid;
715 if (execData.process)
716 execData.process->SetPid(pid); // and also in the wxProcess
717
718 // prepare for IO redirection
719
720 #if HAS_PIPE_STREAMS
721 // the input buffer bufOut is connected to stdout, this is why it is
722 // called bufOut and not bufIn
723 wxStreamTempInputBuffer bufOut,
724 bufErr;
725
726 if ( process && process->IsRedirected() )
727 {
728 // Avoid deadlocks which could result from trying to write to the
729 // child input pipe end while the child itself is writing to its
730 // output end and waiting for us to read from it.
731 if ( !pipeIn.MakeNonBlocking(wxPipe::Write) )
732 {
733 // This message is not terrible useful for the user but what
734 // else can we do? Also, should we fail here or take the risk
735 // to continue and deadlock? Currently we choose the latter but
736 // it might not be the best idea.
737 wxLogSysError(_("Failed to set up non-blocking pipe, "
738 "the program might hang."));
739 #if wxUSE_LOG
740 wxLog::FlushActive();
741 #endif
742 }
743
744 wxOutputStream *inStream =
745 new wxPipeOutputStream(pipeIn.Detach(wxPipe::Write));
746
747 const int fdOut = pipeOut.Detach(wxPipe::Read);
748 wxPipeInputStream *outStream = new wxPipeInputStream(fdOut);
749
750 const int fdErr = pipeErr.Detach(wxPipe::Read);
751 wxPipeInputStream *errStream = new wxPipeInputStream(fdErr);
752
753 process->SetPipeStreams(outStream, inStream, errStream);
754
755 bufOut.Init(outStream);
756 bufErr.Init(errStream);
757
758 execData.bufOut = &bufOut;
759 execData.bufErr = &bufErr;
760
761 execData.fdOut = fdOut;
762 execData.fdErr = fdErr;
763 }
764 #endif // HAS_PIPE_STREAMS
765
766 if ( pipeIn.IsOk() )
767 {
768 pipeIn.Close();
769 pipeOut.Close();
770 pipeErr.Close();
771 }
772
773 // we want this function to work even if there is no wxApp so ensure
774 // that we have a valid traits pointer
775 wxConsoleAppTraits traitsConsole;
776 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
777 if ( !traits )
778 traits = &traitsConsole;
779
780 return traits->WaitForChild(execData);
781 }
782
783 #if !defined(__VMS) && !defined(__INTEL_COMPILER)
784 return ERROR_RETURN_CODE;
785 #endif
786 }
787
788 #undef ERROR_RETURN_CODE
789
790 // ----------------------------------------------------------------------------
791 // file and directory functions
792 // ----------------------------------------------------------------------------
793
794 const wxChar* wxGetHomeDir( wxString *home )
795 {
796 *home = wxGetUserHome();
797 wxString tmp;
798 if ( home->empty() )
799 *home = wxT("/");
800 #ifdef __VMS
801 tmp = *home;
802 if ( tmp.Last() != wxT(']'))
803 if ( tmp.Last() != wxT('/')) *home << wxT('/');
804 #endif
805 return home->c_str();
806 }
807
808 wxString wxGetUserHome( const wxString &user )
809 {
810 struct passwd *who = (struct passwd *) NULL;
811
812 if ( !user )
813 {
814 wxChar *ptr;
815
816 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
817 {
818 return ptr;
819 }
820
821 if ((ptr = wxGetenv(wxT("USER"))) != NULL ||
822 (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
823 {
824 who = getpwnam(wxSafeConvertWX2MB(ptr));
825 }
826
827 // make sure the user exists!
828 if ( !who )
829 {
830 who = getpwuid(getuid());
831 }
832 }
833 else
834 {
835 who = getpwnam (user.mb_str());
836 }
837
838 return wxSafeConvertMB2WX(who ? who->pw_dir : 0);
839 }
840
841 // ----------------------------------------------------------------------------
842 // network and user id routines
843 // ----------------------------------------------------------------------------
844
845 // private utility function which returns output of the given command, removing
846 // the trailing newline
847 static wxString wxGetCommandOutput(const wxString &cmd)
848 {
849 // Suppress stderr from the shell to avoid outputting errors if the command
850 // doesn't exist.
851 FILE *f = popen((cmd + " 2>/dev/null").ToAscii(), "r");
852 if ( !f )
853 {
854 // Notice that this doesn't happen simply if the command doesn't exist,
855 // but only in case of some really catastrophic failure inside popen()
856 // so we should really notify the user about this as this is not normal.
857 wxLogSysError(wxT("Executing \"%s\" failed"), cmd);
858 return wxString();
859 }
860
861 wxString s;
862 char buf[256];
863 while ( !feof(f) )
864 {
865 if ( !fgets(buf, sizeof(buf), f) )
866 break;
867
868 s += wxString::FromAscii(buf);
869 }
870
871 pclose(f);
872
873 if ( !s.empty() && s.Last() == wxT('\n') )
874 s.RemoveLast();
875
876 return s;
877 }
878
879 // retrieve either the hostname or FQDN depending on platform (caller must
880 // check whether it's one or the other, this is why this function is for
881 // private use only)
882 static bool wxGetHostNameInternal(wxChar *buf, int sz)
883 {
884 wxCHECK_MSG( buf, false, wxT("NULL pointer in wxGetHostNameInternal") );
885
886 *buf = wxT('\0');
887
888 // we're using uname() which is POSIX instead of less standard sysinfo()
889 #if defined(HAVE_UNAME)
890 struct utsname uts;
891 bool ok = uname(&uts) != -1;
892 if ( ok )
893 {
894 wxStrlcpy(buf, wxSafeConvertMB2WX(uts.nodename), sz);
895 }
896 #elif defined(HAVE_GETHOSTNAME)
897 char cbuf[sz];
898 bool ok = gethostname(cbuf, sz) != -1;
899 if ( ok )
900 {
901 wxStrlcpy(buf, wxSafeConvertMB2WX(cbuf), sz);
902 }
903 #else // no uname, no gethostname
904 wxFAIL_MSG(wxT("don't know host name for this machine"));
905
906 bool ok = false;
907 #endif // uname/gethostname
908
909 if ( !ok )
910 {
911 wxLogSysError(_("Cannot get the hostname"));
912 }
913
914 return ok;
915 }
916
917 bool wxGetHostName(wxChar *buf, int sz)
918 {
919 bool ok = wxGetHostNameInternal(buf, sz);
920
921 if ( ok )
922 {
923 // BSD systems return the FQDN, we only want the hostname, so extract
924 // it (we consider that dots are domain separators)
925 wxChar *dot = wxStrchr(buf, wxT('.'));
926 if ( dot )
927 {
928 // nuke it
929 *dot = wxT('\0');
930 }
931 }
932
933 return ok;
934 }
935
936 bool wxGetFullHostName(wxChar *buf, int sz)
937 {
938 bool ok = wxGetHostNameInternal(buf, sz);
939
940 if ( ok )
941 {
942 if ( !wxStrchr(buf, wxT('.')) )
943 {
944 struct hostent *host = gethostbyname(wxSafeConvertWX2MB(buf));
945 if ( !host )
946 {
947 wxLogSysError(_("Cannot get the official hostname"));
948
949 ok = false;
950 }
951 else
952 {
953 // the canonical name
954 wxStrlcpy(buf, wxSafeConvertMB2WX(host->h_name), sz);
955 }
956 }
957 //else: it's already a FQDN (BSD behaves this way)
958 }
959
960 return ok;
961 }
962
963 bool wxGetUserId(wxChar *buf, int sz)
964 {
965 struct passwd *who;
966
967 *buf = wxT('\0');
968 if ((who = getpwuid(getuid ())) != NULL)
969 {
970 wxStrlcpy (buf, wxSafeConvertMB2WX(who->pw_name), sz);
971 return true;
972 }
973
974 return false;
975 }
976
977 bool wxGetUserName(wxChar *buf, int sz)
978 {
979 #ifdef HAVE_PW_GECOS
980 struct passwd *who;
981
982 *buf = wxT('\0');
983 if ((who = getpwuid (getuid ())) != NULL)
984 {
985 char *comma = strchr(who->pw_gecos, ',');
986 if (comma)
987 *comma = '\0'; // cut off non-name comment fields
988 wxStrlcpy(buf, wxSafeConvertMB2WX(who->pw_gecos), sz);
989 return true;
990 }
991
992 return false;
993 #else // !HAVE_PW_GECOS
994 return wxGetUserId(buf, sz);
995 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
996 }
997
998 bool wxIsPlatform64Bit()
999 {
1000 const wxString machine = wxGetCommandOutput(wxT("uname -m"));
1001
1002 // the test for "64" is obviously not 100% reliable but seems to work fine
1003 // in practice
1004 return machine.Contains(wxT("64")) ||
1005 machine.Contains(wxT("alpha"));
1006 }
1007
1008 #ifdef __LINUX__
1009 wxLinuxDistributionInfo wxGetLinuxDistributionInfo()
1010 {
1011 const wxString id = wxGetCommandOutput(wxT("lsb_release --id"));
1012 const wxString desc = wxGetCommandOutput(wxT("lsb_release --description"));
1013 const wxString rel = wxGetCommandOutput(wxT("lsb_release --release"));
1014 const wxString codename = wxGetCommandOutput(wxT("lsb_release --codename"));
1015
1016 wxLinuxDistributionInfo ret;
1017
1018 id.StartsWith("Distributor ID:\t", &ret.Id);
1019 desc.StartsWith("Description:\t", &ret.Description);
1020 rel.StartsWith("Release:\t", &ret.Release);
1021 codename.StartsWith("Codename:\t", &ret.CodeName);
1022
1023 return ret;
1024 }
1025 #endif
1026
1027 // these functions are in src/osx/utilsexc_base.cpp for wxMac
1028 #ifndef __DARWIN__
1029
1030 wxOperatingSystemId wxGetOsVersion(int *verMaj, int *verMin)
1031 {
1032 // get OS version
1033 int major, minor;
1034 wxString release = wxGetCommandOutput(wxT("uname -r"));
1035 if ( release.empty() ||
1036 wxSscanf(release.c_str(), wxT("%d.%d"), &major, &minor) != 2 )
1037 {
1038 // failed to get version string or unrecognized format
1039 major =
1040 minor = -1;
1041 }
1042
1043 if ( verMaj )
1044 *verMaj = major;
1045 if ( verMin )
1046 *verMin = minor;
1047
1048 // try to understand which OS are we running
1049 wxString kernel = wxGetCommandOutput(wxT("uname -s"));
1050 if ( kernel.empty() )
1051 kernel = wxGetCommandOutput(wxT("uname -o"));
1052
1053 if ( kernel.empty() )
1054 return wxOS_UNKNOWN;
1055
1056 return wxPlatformInfo::GetOperatingSystemId(kernel);
1057 }
1058
1059 wxString wxGetOsDescription()
1060 {
1061 return wxGetCommandOutput(wxT("uname -s -r -m"));
1062 }
1063
1064 #endif // !__DARWIN__
1065
1066 unsigned long wxGetProcessId()
1067 {
1068 return (unsigned long)getpid();
1069 }
1070
1071 wxMemorySize wxGetFreeMemory()
1072 {
1073 #if defined(__LINUX__)
1074 // get it from /proc/meminfo
1075 FILE *fp = fopen("/proc/meminfo", "r");
1076 if ( fp )
1077 {
1078 long memFree = -1;
1079
1080 char buf[1024];
1081 if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) )
1082 {
1083 // /proc/meminfo changed its format in kernel 2.6
1084 if ( wxPlatformInfo().CheckOSVersion(2, 6) )
1085 {
1086 unsigned long cached, buffers;
1087 sscanf(buf, "MemFree: %ld", &memFree);
1088
1089 fgets(buf, WXSIZEOF(buf), fp);
1090 sscanf(buf, "Buffers: %lu", &buffers);
1091
1092 fgets(buf, WXSIZEOF(buf), fp);
1093 sscanf(buf, "Cached: %lu", &cached);
1094
1095 // add to "MemFree" also the "Buffers" and "Cached" values as
1096 // free(1) does as otherwise the value never makes sense: for
1097 // kernel 2.6 it's always almost 0
1098 memFree += buffers + cached;
1099
1100 // values here are always expressed in kB and we want bytes
1101 memFree *= 1024;
1102 }
1103 else // Linux 2.4 (or < 2.6, anyhow)
1104 {
1105 long memTotal, memUsed;
1106 sscanf(buf, "Mem: %ld %ld %ld", &memTotal, &memUsed, &memFree);
1107 }
1108 }
1109
1110 fclose(fp);
1111
1112 return (wxMemorySize)memFree;
1113 }
1114 #elif defined(__SGI__)
1115 struct rminfo realmem;
1116 if ( sysmp(MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0 )
1117 return ((wxMemorySize)realmem.physmem * sysconf(_SC_PAGESIZE));
1118 #elif defined(_SC_AVPHYS_PAGES)
1119 return ((wxMemorySize)sysconf(_SC_AVPHYS_PAGES))*sysconf(_SC_PAGESIZE);
1120 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1121 #endif
1122
1123 // can't find it out
1124 return -1;
1125 }
1126
1127 bool wxGetDiskSpace(const wxString& path, wxDiskspaceSize_t *pTotal, wxDiskspaceSize_t *pFree)
1128 {
1129 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
1130 // the case to "char *" is needed for AIX 4.3
1131 wxStatfs_t fs;
1132 if ( wxStatfs((char *)(const char*)path.fn_str(), &fs) != 0 )
1133 {
1134 wxLogSysError( wxT("Failed to get file system statistics") );
1135
1136 return false;
1137 }
1138
1139 // under Solaris we also have to use f_frsize field instead of f_bsize
1140 // which is in general a multiple of f_frsize
1141 #ifdef HAVE_STATVFS
1142 wxDiskspaceSize_t blockSize = fs.f_frsize;
1143 #else // HAVE_STATFS
1144 wxDiskspaceSize_t blockSize = fs.f_bsize;
1145 #endif // HAVE_STATVFS/HAVE_STATFS
1146
1147 if ( pTotal )
1148 {
1149 *pTotal = wxDiskspaceSize_t(fs.f_blocks) * blockSize;
1150 }
1151
1152 if ( pFree )
1153 {
1154 *pFree = wxDiskspaceSize_t(fs.f_bavail) * blockSize;
1155 }
1156
1157 return true;
1158 #else // !HAVE_STATFS && !HAVE_STATVFS
1159 return false;
1160 #endif // HAVE_STATFS
1161 }
1162
1163 // ----------------------------------------------------------------------------
1164 // env vars
1165 // ----------------------------------------------------------------------------
1166
1167 #if USE_PUTENV
1168
1169 WX_DECLARE_STRING_HASH_MAP(char *, wxEnvVars);
1170
1171 static wxEnvVars gs_envVars;
1172
1173 class wxSetEnvModule : public wxModule
1174 {
1175 public:
1176 virtual bool OnInit() { return true; }
1177 virtual void OnExit()
1178 {
1179 for ( wxEnvVars::const_iterator i = gs_envVars.begin();
1180 i != gs_envVars.end();
1181 ++i )
1182 {
1183 free(i->second);
1184 }
1185
1186 gs_envVars.clear();
1187 }
1188
1189 DECLARE_DYNAMIC_CLASS(wxSetEnvModule)
1190 };
1191
1192 IMPLEMENT_DYNAMIC_CLASS(wxSetEnvModule, wxModule)
1193
1194 #endif // USE_PUTENV
1195
1196 bool wxGetEnv(const wxString& var, wxString *value)
1197 {
1198 // wxGetenv is defined as getenv()
1199 char *p = wxGetenv(var);
1200 if ( !p )
1201 return false;
1202
1203 if ( value )
1204 {
1205 *value = p;
1206 }
1207
1208 return true;
1209 }
1210
1211 static bool wxDoSetEnv(const wxString& variable, const char *value)
1212 {
1213 #if defined(HAVE_SETENV)
1214 if ( !value )
1215 {
1216 #ifdef HAVE_UNSETENV
1217 // don't test unsetenv() return value: it's void on some systems (at
1218 // least Darwin)
1219 unsetenv(variable.mb_str());
1220 return true;
1221 #else
1222 value = ""; // we can't pass NULL to setenv()
1223 #endif
1224 }
1225
1226 return setenv(variable.mb_str(), value, 1 /* overwrite */) == 0;
1227 #elif defined(HAVE_PUTENV)
1228 wxString s = variable;
1229 if ( value )
1230 s << wxT('=') << value;
1231
1232 // transform to ANSI
1233 const wxWX2MBbuf p = s.mb_str();
1234
1235 char *buf = (char *)malloc(strlen(p) + 1);
1236 strcpy(buf, p);
1237
1238 // store the string to free() it later
1239 wxEnvVars::iterator i = gs_envVars.find(variable);
1240 if ( i != gs_envVars.end() )
1241 {
1242 free(i->second);
1243 i->second = buf;
1244 }
1245 else // this variable hadn't been set before
1246 {
1247 gs_envVars[variable] = buf;
1248 }
1249
1250 return putenv(buf) == 0;
1251 #else // no way to set an env var
1252 return false;
1253 #endif
1254 }
1255
1256 bool wxSetEnv(const wxString& variable, const wxString& value)
1257 {
1258 return wxDoSetEnv(variable, value.mb_str());
1259 }
1260
1261 bool wxUnsetEnv(const wxString& variable)
1262 {
1263 return wxDoSetEnv(variable, NULL);
1264 }
1265
1266 // ----------------------------------------------------------------------------
1267 // signal handling
1268 // ----------------------------------------------------------------------------
1269
1270 #if wxUSE_ON_FATAL_EXCEPTION
1271
1272 #include <signal.h>
1273
1274 extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER)
1275 {
1276 if ( wxTheApp )
1277 {
1278 // give the user a chance to do something special about this
1279 wxTheApp->OnFatalException();
1280 }
1281
1282 abort();
1283 }
1284
1285 bool wxHandleFatalExceptions(bool doit)
1286 {
1287 // old sig handlers
1288 static bool s_savedHandlers = false;
1289 static struct sigaction s_handlerFPE,
1290 s_handlerILL,
1291 s_handlerBUS,
1292 s_handlerSEGV;
1293
1294 bool ok = true;
1295 if ( doit && !s_savedHandlers )
1296 {
1297 // install the signal handler
1298 struct sigaction act;
1299
1300 // some systems extend it with non std fields, so zero everything
1301 memset(&act, 0, sizeof(act));
1302
1303 act.sa_handler = wxFatalSignalHandler;
1304 sigemptyset(&act.sa_mask);
1305 act.sa_flags = 0;
1306
1307 ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0;
1308 ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0;
1309 ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0;
1310 ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0;
1311 if ( !ok )
1312 {
1313 wxLogDebug(wxT("Failed to install our signal handler."));
1314 }
1315
1316 s_savedHandlers = true;
1317 }
1318 else if ( s_savedHandlers )
1319 {
1320 // uninstall the signal handler
1321 ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0;
1322 ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0;
1323 ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0;
1324 ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0;
1325 if ( !ok )
1326 {
1327 wxLogDebug(wxT("Failed to uninstall our signal handler."));
1328 }
1329
1330 s_savedHandlers = false;
1331 }
1332 //else: nothing to do
1333
1334 return ok;
1335 }
1336
1337 #endif // wxUSE_ON_FATAL_EXCEPTION
1338
1339 // ----------------------------------------------------------------------------
1340 // wxExecute support
1341 // ----------------------------------------------------------------------------
1342
1343 int wxAppTraits::AddProcessCallback(wxEndProcessData *data, int fd)
1344 {
1345 // define a custom handler processing only the closure of the descriptor
1346 struct wxEndProcessFDIOHandler : public wxFDIOHandler
1347 {
1348 wxEndProcessFDIOHandler(wxEndProcessData *data, int fd)
1349 : m_data(data), m_fd(fd)
1350 {
1351 }
1352
1353 virtual void OnReadWaiting()
1354 {
1355 wxFDIODispatcher::Get()->UnregisterFD(m_fd);
1356 close(m_fd);
1357
1358 wxHandleProcessTermination(m_data);
1359
1360 delete this;
1361 }
1362
1363 virtual void OnWriteWaiting() { wxFAIL_MSG("unreachable"); }
1364 virtual void OnExceptionWaiting() { wxFAIL_MSG("unreachable"); }
1365
1366 wxEndProcessData * const m_data;
1367 const int m_fd;
1368 };
1369
1370 wxFDIODispatcher::Get()->RegisterFD
1371 (
1372 fd,
1373 new wxEndProcessFDIOHandler(data, fd),
1374 wxFDIO_INPUT
1375 );
1376 return fd; // unused, but return something unique for the tag
1377 }
1378
1379 bool wxAppTraits::CheckForRedirectedIO(wxExecuteData& execData)
1380 {
1381 #if HAS_PIPE_STREAMS
1382 bool hasIO = false;
1383
1384 if ( execData.bufOut && execData.bufOut->Update() )
1385 hasIO = true;
1386
1387 if ( execData.bufErr && execData.bufErr->Update() )
1388 hasIO = true;
1389
1390 return hasIO;
1391 #else // !HAS_PIPE_STREAMS
1392 wxUnusedVar(execData);
1393
1394 return false;
1395 #endif // HAS_PIPE_STREAMS/!HAS_PIPE_STREAMS
1396 }
1397
1398 // helper classes/functions used by WaitForChild()
1399 namespace
1400 {
1401
1402 // convenient base class for IO handlers which are registered for read
1403 // notifications only and which also stores the FD we're reading from
1404 //
1405 // the derived classes still have to implement OnReadWaiting()
1406 class wxReadFDIOHandler : public wxFDIOHandler
1407 {
1408 public:
1409 wxReadFDIOHandler(wxFDIODispatcher& disp, int fd) : m_fd(fd)
1410 {
1411 if ( fd )
1412 disp.RegisterFD(fd, this, wxFDIO_INPUT);
1413 }
1414
1415 virtual void OnWriteWaiting() { wxFAIL_MSG("unreachable"); }
1416 virtual void OnExceptionWaiting() { wxFAIL_MSG("unreachable"); }
1417
1418 protected:
1419 const int m_fd;
1420
1421 wxDECLARE_NO_COPY_CLASS(wxReadFDIOHandler);
1422 };
1423
1424 // class for monitoring our end of the process detection pipe, simply sets a
1425 // flag when input on the pipe (which must be due to EOF) is detected
1426 class wxEndHandler : public wxReadFDIOHandler
1427 {
1428 public:
1429 wxEndHandler(wxFDIODispatcher& disp, int fd)
1430 : wxReadFDIOHandler(disp, fd)
1431 {
1432 m_terminated = false;
1433 }
1434
1435 bool Terminated() const { return m_terminated; }
1436
1437 virtual void OnReadWaiting() { m_terminated = true; }
1438
1439 private:
1440 bool m_terminated;
1441
1442 wxDECLARE_NO_COPY_CLASS(wxEndHandler);
1443 };
1444
1445 #if HAS_PIPE_STREAMS
1446
1447 // class for monitoring our ends of child stdout/err, should be constructed
1448 // with the FD and stream from wxExecuteData and will do nothing if they're
1449 // invalid
1450 //
1451 // unlike wxEndHandler this class registers itself with the provided dispatcher
1452 class wxRedirectedIOHandler : public wxReadFDIOHandler
1453 {
1454 public:
1455 wxRedirectedIOHandler(wxFDIODispatcher& disp,
1456 int fd,
1457 wxStreamTempInputBuffer *buf)
1458 : wxReadFDIOHandler(disp, fd),
1459 m_buf(buf)
1460 {
1461 }
1462
1463 virtual void OnReadWaiting()
1464 {
1465 m_buf->Update();
1466 }
1467
1468 private:
1469 wxStreamTempInputBuffer * const m_buf;
1470
1471 wxDECLARE_NO_COPY_CLASS(wxRedirectedIOHandler);
1472 };
1473
1474 #endif // HAS_PIPE_STREAMS
1475
1476 // helper function which calls waitpid() and analyzes the result
1477 int DoWaitForChild(int pid, int flags = 0)
1478 {
1479 wxASSERT_MSG( pid > 0, "invalid PID" );
1480
1481 int status, rc;
1482
1483 // loop while we're getting EINTR
1484 for ( ;; )
1485 {
1486 rc = waitpid(pid, &status, flags);
1487
1488 if ( rc != -1 || errno != EINTR )
1489 break;
1490 }
1491
1492 if ( rc == 0 )
1493 {
1494 // This can only happen if the child application closes our dummy pipe
1495 // that is used to monitor its lifetime; in that case, our best bet is
1496 // to pretend the process did terminate, because otherwise wxExecute()
1497 // would hang indefinitely (OnReadWaiting() won't be called again, the
1498 // descriptor is closed now).
1499 wxLogDebug("Child process (PID %d) still alive but pipe closed so "
1500 "generating a close notification", pid);
1501 }
1502 else if ( rc == -1 )
1503 {
1504 wxLogLastError(wxString::Format("waitpid(%d)", pid));
1505 }
1506 else // child did terminate
1507 {
1508 wxASSERT_MSG( rc == pid, "unexpected waitpid() return value" );
1509
1510 // notice that the caller expects the exit code to be signed, e.g. -1
1511 // instead of 255 so don't assign WEXITSTATUS() to an int
1512 signed char exitcode;
1513 if ( WIFEXITED(status) )
1514 exitcode = WEXITSTATUS(status);
1515 else if ( WIFSIGNALED(status) )
1516 exitcode = -WTERMSIG(status);
1517 else
1518 {
1519 wxLogError("Child process (PID %d) exited for unknown reason, "
1520 "status = %d", pid, status);
1521 exitcode = -1;
1522 }
1523
1524 return exitcode;
1525 }
1526
1527 return -1;
1528 }
1529
1530 } // anonymous namespace
1531
1532 int wxAppTraits::WaitForChild(wxExecuteData& execData)
1533 {
1534 if ( !(execData.flags & wxEXEC_SYNC) )
1535 {
1536 // asynchronous execution: just launch the process and return,
1537 // endProcData will be destroyed when it terminates (currently we leak
1538 // it if the process doesn't terminate before we do and this should be
1539 // fixed but it's not a real leak so it's not really very high
1540 // priority)
1541 wxEndProcessData *endProcData = new wxEndProcessData;
1542 endProcData->process = execData.process;
1543 endProcData->pid = execData.pid;
1544 endProcData->tag = AddProcessCallback
1545 (
1546 endProcData,
1547 execData.GetEndProcReadFD()
1548 );
1549 endProcData->async = true;
1550
1551 return execData.pid;
1552 }
1553 //else: synchronous execution case
1554
1555 #if HAS_PIPE_STREAMS && wxUSE_SOCKETS
1556 wxProcess * const process = execData.process;
1557 if ( process && process->IsRedirected() )
1558 {
1559 // we can't simply block waiting for the child to terminate as we would
1560 // dead lock if it writes more than the pipe buffer size (typically
1561 // 4KB) bytes of output -- it would then block waiting for us to read
1562 // the data while we'd block waiting for it to terminate
1563 //
1564 // so multiplex here waiting for any input from the child or closure of
1565 // the pipe used to indicate its termination
1566 wxSelectDispatcher disp;
1567
1568 wxEndHandler endHandler(disp, execData.GetEndProcReadFD());
1569
1570 wxRedirectedIOHandler outHandler(disp, execData.fdOut, execData.bufOut),
1571 errHandler(disp, execData.fdErr, execData.bufErr);
1572
1573 while ( !endHandler.Terminated() )
1574 {
1575 disp.Dispatch();
1576 }
1577 }
1578 //else: no IO redirection, just block waiting for the child to exit
1579 #endif // HAS_PIPE_STREAMS
1580
1581 return DoWaitForChild(execData.pid);
1582 }
1583
1584 void wxHandleProcessTermination(wxEndProcessData *data)
1585 {
1586 data->exitcode = DoWaitForChild(data->pid, WNOHANG);
1587
1588 // notify user about termination if required
1589 if ( data->process )
1590 {
1591 data->process->OnTerminate(data->pid, data->exitcode);
1592 }
1593
1594 if ( data->async )
1595 {
1596 // in case of asynchronous execution we don't need this data any more
1597 // after the child terminates
1598 delete data;
1599 }
1600 else // sync execution
1601 {
1602 // let wxExecute() know that the process has terminated
1603 data->pid = 0;
1604 }
1605 }
1606