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