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