]> git.saurik.com Git - wxWidgets.git/blame - src/unix/utilsunx.cpp
tell that there was an error...
[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
80d6dc0a 29#include "wx/wfstream.h"
8b33ae2d 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
401eb3de
RR
256#if wxUSE_UNICODE
257 long lRc = -1;
258#else
fbf456aa 259 long lRc = wxExecute(argv, flags, process);
401eb3de 260#endif
518b5d2f 261
0ed9a934 262 // clean up
fad866f4 263 argc = 0;
0ed9a934 264 while( argv[argc] )
fad866f4 265 delete [] argv[argc++];
518b5d2f
VZ
266
267 return lRc;
268}
269
2c8e4738
VZ
270// ----------------------------------------------------------------------------
271// wxShell
272// ----------------------------------------------------------------------------
273
274static wxString wxMakeShellCommand(const wxString& command)
518b5d2f
VZ
275{
276 wxString cmd;
cd6ce4a9 277 if ( !command )
2c8e4738
VZ
278 {
279 // just an interactive shell
cd6ce4a9 280 cmd = _T("xterm");
2c8e4738 281 }
518b5d2f 282 else
2c8e4738
VZ
283 {
284 // execute command in a shell
285 cmd << _T("/bin/sh -c '") << command << _T('\'');
286 }
287
288 return cmd;
289}
290
291bool wxShell(const wxString& command)
292{
fbf456aa 293 return wxExecute(wxMakeShellCommand(command), wxEXEC_SYNC) == 0;
2c8e4738
VZ
294}
295
296bool wxShell(const wxString& command, wxArrayString& output)
297{
298 wxCHECK_MSG( !!command, FALSE, _T("can't exec shell non interactively") );
518b5d2f 299
2c8e4738 300 return wxExecute(wxMakeShellCommand(command), output);
518b5d2f
VZ
301}
302
f6ba47d9
VZ
303// Shutdown or reboot the PC
304bool wxShutdown(wxShutdownFlags wFlags)
305{
306 wxChar level;
307 switch ( wFlags )
308 {
309 case wxSHUTDOWN_POWEROFF:
310 level = _T('0');
311 break;
312
313 case wxSHUTDOWN_REBOOT:
314 level = _T('6');
315 break;
316
317 default:
318 wxFAIL_MSG( _T("unknown wxShutdown() flag") );
319 return FALSE;
320 }
321
322 return system(wxString::Format(_T("init %c"), level).mb_str()) == 0;
323}
324
325
6dc6fda6
VZ
326#if wxUSE_GUI
327
518b5d2f
VZ
328void wxHandleProcessTermination(wxEndProcessData *proc_data)
329{
018e2f13
VZ
330 // notify user about termination if required
331 if ( proc_data->process )
c556f198 332 {
447f908a 333 proc_data->process->OnTerminate(proc_data->pid, proc_data->exitcode);
c556f198 334 }
447f908a 335
018e2f13
VZ
336 // clean up
337 if ( proc_data->pid > 0 )
c556f198 338 {
018e2f13 339 delete proc_data;
0ed9a934 340 }
018e2f13 341 else
0ed9a934 342 {
447f908a 343 // let wxExecute() know that the process has terminated
018e2f13 344 proc_data->pid = 0;
518b5d2f
VZ
345 }
346}
347
6dc6fda6
VZ
348#endif // wxUSE_GUI
349
cd6ce4a9
VZ
350// ----------------------------------------------------------------------------
351// wxStream classes to support IO redirection in wxExecute
352// ----------------------------------------------------------------------------
6dc6fda6 353
1e6feb95
VZ
354#if wxUSE_STREAMS
355
80d6dc0a
VZ
356// ----------------------------------------------------------------------------
357// wxProcessFileInputStream: stream for reading from a pipe
358// ----------------------------------------------------------------------------
8b33ae2d 359
80d6dc0a 360class wxProcessFileInputStream : public wxFileInputStream
cd6ce4a9
VZ
361{
362public:
80d6dc0a 363 wxProcessFileInputStream(int fd) : wxFileInputStream(fd) { }
8b33ae2d 364
80d6dc0a
VZ
365 // return TRUE if we have anything to read, don't block
366 bool IsAvailable() const;
8b33ae2d
GL
367};
368
80d6dc0a 369bool wxProcessFileInputStream::IsAvailable() const
8b33ae2d 370{
cd6ce4a9
VZ
371 if ( m_lasterror == wxSTREAM_EOF )
372 return TRUE;
373
374 // check if there is any input available
375 struct timeval tv;
376 tv.tv_sec = 0;
377 tv.tv_usec = 0;
378
80d6dc0a
VZ
379 const int fd = m_file->fd();
380
cd6ce4a9
VZ
381 fd_set readfds;
382 FD_ZERO(&readfds);
80d6dc0a
VZ
383 FD_SET(fd, &readfds);
384 switch ( select(fd + 1, &readfds, NULL, NULL, &tv) )
cd6ce4a9
VZ
385 {
386 case -1:
387 wxLogSysError(_("Impossible to get child process input"));
388 // fall through
8b33ae2d 389
cd6ce4a9
VZ
390 case 0:
391 return TRUE;
8b33ae2d 392
cd6ce4a9
VZ
393 default:
394 wxFAIL_MSG(_T("unexpected select() return value"));
395 // still fall through
396
397 case 1:
80d6dc0a
VZ
398 // input available
399 return TRUE;
cd6ce4a9 400 }
8b33ae2d
GL
401}
402
0e300ddd 403// ----------------------------------------------------------------------------
80d6dc0a 404// wxStreamTempInputBuffer
0e300ddd
VZ
405// ----------------------------------------------------------------------------
406
407/*
408 Extract of a mail to wx-users to give the context of the problem we are
409 trying to solve here:
410
411 MC> If I run the command:
412 MC> find . -name "*.h" -exec grep linux {} \;
413 MC> in the exec sample synchronously from the 'Capture command output'
414 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
415 MC> else encountered this?
416
417 Yes, I can reproduce it too.
418
419 I even think I understand why it happens: before launching the external
420 command we set up a pipe with a valid file descriptor on the reading side
421 when the output is redirected. So the subprocess happily writes to it ...
422 until the pipe buffer (which is usually quite big on Unix, I think the
b477f956 423 default is 4Kb) is full. Then the writing process stops and waits until we
0e300ddd
VZ
424 read some data from the pipe to be able to continue writing to it but we
425 never do it because we wait until it terminates to start reading and so we
426 have a classical deadlock.
427
428 Here is the fix: we now read the output as soon as it appears into a temp
80d6dc0a 429 buffer (wxStreamTempInputBuffer object) and later just stuff it back into the
0e300ddd 430 stream when the process terminates. See supporting code in wxExecute()
b477f956
VZ
431 itself as well.
432
433 Note that this is horribly inefficient for large amounts of output (count
434 the number of times we copy the data around) and so a better API is badly
435 needed!
0e300ddd
VZ
436*/
437
80d6dc0a 438class wxStreamTempInputBuffer
0e300ddd
VZ
439{
440public:
80d6dc0a 441 wxStreamTempInputBuffer();
0e300ddd
VZ
442
443 // call to associate a stream with this buffer, otherwise nothing happens
444 // at all
80d6dc0a 445 void Init(wxProcessFileInputStream *stream);
0e300ddd
VZ
446
447 // check for input on our stream and cache it in our buffer if any
448 void Update();
449
80d6dc0a 450 ~wxStreamTempInputBuffer();
0e300ddd
VZ
451
452private:
453 // the stream we're buffering, if NULL we don't do anything at all
80d6dc0a 454 wxProcessFileInputStream *m_stream;
0e300ddd
VZ
455
456 // the buffer of size m_size (NULL if m_size == 0)
457 void *m_buffer;
458
459 // the size of the buffer
460 size_t m_size;
461};
462
80d6dc0a 463wxStreamTempInputBuffer::wxStreamTempInputBuffer()
0e300ddd 464{
b477f956 465 m_stream = NULL;
0e300ddd
VZ
466 m_buffer = NULL;
467 m_size = 0;
468}
469
80d6dc0a 470void wxStreamTempInputBuffer::Init(wxProcessFileInputStream *stream)
0e300ddd
VZ
471{
472 m_stream = stream;
473}
474
80d6dc0a 475void wxStreamTempInputBuffer::Update()
0e300ddd 476{
80d6dc0a 477 if ( m_stream && m_stream->IsAvailable() )
0e300ddd 478 {
b477f956
VZ
479 // realloc in blocks of 4Kb: this is the default (and minimal) buffer
480 // size of the Unix pipes so it should be the optimal step
481 static const size_t incSize = 4096;
0e300ddd
VZ
482
483 void *buf = realloc(m_buffer, m_size + incSize);
484 if ( !buf )
485 {
486 // don't read any more, we don't have enough memory to do it
487 m_stream = NULL;
488 }
489 else // got memory for the buffer
490 {
491 m_buffer = buf;
492 m_stream->Read((char *)m_buffer + m_size, incSize);
b477f956 493 m_size += m_stream->LastRead();
0e300ddd
VZ
494 }
495 }
496}
497
80d6dc0a 498wxStreamTempInputBuffer::~wxStreamTempInputBuffer()
0e300ddd
VZ
499{
500 if ( m_buffer )
501 {
502 m_stream->Ungetch(m_buffer, m_size);
503 free(m_buffer);
504 }
505}
506
1e6feb95
VZ
507#endif // wxUSE_STREAMS
508
b477f956 509// ----------------------------------------------------------------------------
80d6dc0a 510// wxPipe: this encapsulates pipe() system call
b477f956
VZ
511// ----------------------------------------------------------------------------
512
513class wxPipe
514{
515public:
516 // the symbolic names for the pipe ends
517 enum Direction
518 {
519 Read,
520 Write
521 };
522
523 enum
524 {
525 INVALID_FD = -1
526 };
527
528 // default ctor doesn't do anything
529 wxPipe() { m_fds[Read] = m_fds[Write] = INVALID_FD; }
530
531 // create the pipe, return TRUE if ok, FALSE on error
532 bool Create()
533 {
534 if ( pipe(m_fds) == -1 )
535 {
536 wxLogSysError(_("Pipe creation failed"));
537
538 return FALSE;
539 }
540
541 return TRUE;
542 }
543
544 // return TRUE if we were created successfully
545 bool IsOk() const { return m_fds[Read] != INVALID_FD; }
546
547 // return the descriptor for one of the pipe ends
548 int operator[](Direction which) const
549 {
550 wxASSERT_MSG( which >= 0 && (size_t)which < WXSIZEOF(m_fds),
551 _T("invalid pipe index") );
552
553 return m_fds[which];
554 }
555
556 // detach a descriptor, meaning that the pipe dtor won't close it, and
557 // return it
558 int Detach(Direction which)
559 {
560 wxASSERT_MSG( which >= 0 && (size_t)which < WXSIZEOF(m_fds),
561 _T("invalid pipe index") );
562
563 int fd = m_fds[which];
564 m_fds[which] = INVALID_FD;
565
566 return fd;
567 }
568
569 // close the pipe descriptors
570 void Close()
571 {
572 for ( size_t n = 0; n < WXSIZEOF(m_fds); n++ )
573 {
574 if ( m_fds[n] != INVALID_FD )
575 close(m_fds[n]);
576 }
577 }
578
579 // dtor closes the pipe descriptors
580 ~wxPipe() { Close(); }
581
582private:
583 int m_fds[2];
584};
585
586// ----------------------------------------------------------------------------
587// wxExecute: the real worker function
588// ----------------------------------------------------------------------------
ef0ed19e
JJ
589#ifdef __VMS
590#pragma message disable codeunreachable
591#endif
b477f956 592
6dc6fda6 593long wxExecute(wxChar **argv,
fbf456aa 594 int flags,
cd6ce4a9 595 wxProcess *process)
518b5d2f 596{
f6bcfd97 597 // for the sync execution, we return -1 to indicate failure, but for async
accb3257
VZ
598 // case we return 0 which is never a valid PID
599 //
600 // we define this as a macro, not a variable, to avoid compiler warnings
601 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
fbf456aa 602 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
f6bcfd97 603
accb3257 604 wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );
518b5d2f 605
05079acc
OK
606#if wxUSE_UNICODE
607 int mb_argc = 0;
608 char *mb_argv[WXEXECUTE_NARGS];
609
e90c1d2a
VZ
610 while (argv[mb_argc])
611 {
cd6ce4a9
VZ
612 wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
613 mb_argv[mb_argc] = strdup(mb_arg);
614 mb_argc++;
05079acc
OK
615 }
616 mb_argv[mb_argc] = (char *) NULL;
e90c1d2a
VZ
617
618 // this macro will free memory we used above
619 #define ARGS_CLEANUP \
345b0247 620 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
e90c1d2a
VZ
621 free(mb_argv[mb_argc])
622#else // ANSI
623 // no need for cleanup
624 #define ARGS_CLEANUP
625
05079acc 626 wxChar **mb_argv = argv;
e90c1d2a 627#endif // Unicode/ANSI
518b5d2f 628
e90c1d2a 629#if wxUSE_GUI
518b5d2f 630 // create pipes
b477f956
VZ
631 wxPipe pipeEndProcDetect;
632 if ( !pipeEndProcDetect.Create() )
518b5d2f 633 {
cd6ce4a9 634 wxLogError( _("Failed to execute '%s'\n"), *argv );
e90c1d2a
VZ
635
636 ARGS_CLEANUP;
637
accb3257 638 return ERROR_RETURN_CODE;
518b5d2f 639 }
e90c1d2a 640#endif // wxUSE_GUI
518b5d2f 641
f6bcfd97 642 // pipes for inter process communication
b477f956
VZ
643 wxPipe pipeIn, // stdin
644 pipeOut, // stdout
645 pipeErr; // stderr
cd6ce4a9
VZ
646
647 if ( process && process->IsRedirected() )
8b33ae2d 648 {
b477f956 649 if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
8b33ae2d 650 {
cd6ce4a9 651 wxLogError( _("Failed to execute '%s'\n"), *argv );
8b33ae2d
GL
652
653 ARGS_CLEANUP;
654
accb3257 655 return ERROR_RETURN_CODE;
8b33ae2d
GL
656 }
657 }
8b33ae2d 658
518b5d2f 659 // fork the process
0fcdf6dc 660#ifdef HAVE_VFORK
518b5d2f
VZ
661 pid_t pid = vfork();
662#else
663 pid_t pid = fork();
664#endif
cd6ce4a9
VZ
665
666 if ( pid == -1 ) // error?
518b5d2f
VZ
667 {
668 wxLogSysError( _("Fork failed") );
e90c1d2a
VZ
669
670 ARGS_CLEANUP;
671
accb3257 672 return ERROR_RETURN_CODE;
518b5d2f 673 }
cd6ce4a9 674 else if ( pid == 0 ) // we're in child
518b5d2f 675 {
cd6ce4a9 676 // These lines close the open file descriptors to to avoid any
518b5d2f 677 // input/output which might block the process or irritate the user. If
cd6ce4a9
VZ
678 // one wants proper IO for the subprocess, the right thing to do is to
679 // start an xterm executing it.
fbf456aa 680 if ( !(flags & wxEXEC_SYNC) )
518b5d2f 681 {
518b5d2f
VZ
682 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
683 {
b477f956
VZ
684 if ( fd == pipeIn[wxPipe::Read]
685 || fd == pipeOut[wxPipe::Write]
686 || fd == pipeErr[wxPipe::Write]
e90c1d2a 687#if wxUSE_GUI
b477f956 688 || fd == pipeEndProcDetect[wxPipe::Write]
e90c1d2a 689#endif // wxUSE_GUI
cd6ce4a9
VZ
690 )
691 {
692 // don't close this one, we still need it
693 continue;
694 }
e90c1d2a 695
b477f956 696 // leave stderr opened too, it won't do any harm
e90c1d2a 697 if ( fd != STDERR_FILENO )
518b5d2f
VZ
698 close(fd);
699 }
0c9c4401 700 }
e1082c9f 701
2e99f815 702#ifndef __VMS
0c9c4401
VZ
703 if ( flags & wxEXEC_MAKE_GROUP_LEADER )
704 {
705 // Set process group to child process' pid. Then killing -pid
706 // of the parent will kill the process and all of its children.
707 setsid();
518b5d2f 708 }
0c9c4401
VZ
709#endif // !__VMS
710
711#if wxUSE_GUI
712 // reading side can be safely closed but we should keep the write one
713 // opened
714 pipeEndProcDetect.Detach(wxPipe::Write);
715 pipeEndProcDetect.Close();
716#endif // wxUSE_GUI
518b5d2f 717
80d6dc0a 718 // redirect stdin, stdout and stderr
b477f956 719 if ( pipeIn.IsOk() )
cd6ce4a9 720 {
b477f956
VZ
721 if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 ||
722 dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 ||
723 dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 )
cd6ce4a9 724 {
f6bcfd97 725 wxLogSysError(_("Failed to redirect child process input/output"));
cd6ce4a9 726 }
518b5d2f 727
b477f956
VZ
728 pipeIn.Close();
729 pipeOut.Close();
730 pipeErr.Close();
cd6ce4a9 731 }
518b5d2f 732
05079acc 733 execvp (*mb_argv, mb_argv);
518b5d2f
VZ
734
735 // there is no return after successful exec()
518b5d2f 736 _exit(-1);
1d8dd65e
VZ
737
738 // some compilers complain about missing return - of course, they
739 // should know that exit() doesn't return but what else can we do if
740 // they don't?
b477f956
VZ
741 //
742 // and, sure enough, other compilers complain about unreachable code
743 // after exit() call, so we can just always have return here...
1d8dd65e
VZ
744#if defined(__VMS) || defined(__INTEL_COMPILER)
745 return 0;
746#endif
518b5d2f 747 }
cd6ce4a9 748 else // we're in parent
518b5d2f 749 {
cd6ce4a9
VZ
750 ARGS_CLEANUP;
751
80d6dc0a
VZ
752 // prepare for IO redirection
753
0e300ddd 754#if wxUSE_STREAMS
80d6dc0a
VZ
755 // the input buffer bufOut is connected to stdout, this is why it is
756 // called bufOut and not bufIn
757 wxStreamTempInputBuffer bufOut,
758 bufErr;
0e300ddd
VZ
759#endif // wxUSE_STREAMS
760
cd6ce4a9
VZ
761 if ( process && process->IsRedirected() )
762 {
1e6feb95 763#if wxUSE_STREAMS
80d6dc0a
VZ
764 wxOutputStream *inStream =
765 new wxFileOutputStream(pipeIn.Detach(wxPipe::Write));
b477f956 766
80d6dc0a 767 wxProcessFileInputStream *outStream =
b477f956
VZ
768 new wxProcessFileInputStream(pipeOut.Detach(wxPipe::Read));
769
80d6dc0a 770 wxProcessFileInputStream *errStream =
b477f956 771 new wxProcessFileInputStream(pipeErr.Detach(wxPipe::Read));
f6bcfd97 772
80d6dc0a 773 process->SetPipeStreams(outStream, inStream, errStream);
0e300ddd 774
80d6dc0a 775 bufOut.Init(outStream);
b477f956 776 bufErr.Init(errStream);
1e6feb95 777#endif // wxUSE_STREAMS
b477f956 778 }
1e6feb95 779
b477f956
VZ
780 if ( pipeIn.IsOk() )
781 {
782 pipeIn.Close();
783 pipeOut.Close();
784 pipeErr.Close();
cd6ce4a9
VZ
785 }
786
fac3b423 787#if wxUSE_GUI && !defined(__WXMICROWIN__)
518b5d2f 788 wxEndProcessData *data = new wxEndProcessData;
ab857a4e 789
b477f956
VZ
790 data->tag = wxAddProcessCallback
791 (
792 data,
793 pipeEndProcDetect.Detach(wxPipe::Read)
794 );
795
796 pipeEndProcDetect.Close();
797
fbf456aa 798 if ( flags & wxEXEC_SYNC )
518b5d2f 799 {
cd6ce4a9
VZ
800 // we may have process for capturing the program output, but it's
801 // not used in wxEndProcessData in the case of sync execution
518b5d2f
VZ
802 data->process = NULL;
803
804 // sync execution: indicate it by negating the pid
cd6ce4a9 805 data->pid = -pid;
518b5d2f 806
cd6ce4a9
VZ
807 wxBusyCursor bc;
808 wxWindowDisabler wd;
809
0e300ddd
VZ
810 // data->pid will be set to 0 from GTK_EndProcessDetector when the
811 // process terminates
812 while ( data->pid != 0 )
813 {
814#if wxUSE_STREAMS
80d6dc0a 815 bufOut.Update();
0e300ddd
VZ
816 bufErr.Update();
817#endif // wxUSE_STREAMS
818
819 // give GTK+ a chance to call GTK_EndProcessDetector here and
820 // also repaint the GUI
518b5d2f 821 wxYield();
0e300ddd 822 }
518b5d2f
VZ
823
824 int exitcode = data->exitcode;
825
826 delete data;
827
828 return exitcode;
829 }
cd6ce4a9 830 else // async execution
518b5d2f
VZ
831 {
832 // async execution, nothing special to do - caller will be
ab857a4e 833 // notified about the process termination if process != NULL, data
518b5d2f 834 // will be deleted in GTK_EndProcessDetector
8b33ae2d
GL
835 data->process = process;
836 data->pid = pid;
518b5d2f
VZ
837
838 return pid;
839 }
e90c1d2a 840#else // !wxUSE_GUI
fbf456aa
VZ
841
842 wxASSERT_MSG( flags & wxEXEC_SYNC,
843 wxT("async execution not supported yet") );
e90c1d2a
VZ
844
845 int exitcode = 0;
846 if ( waitpid(pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) )
847 {
848 wxLogSysError(_("Waiting for subprocess termination failed"));
849 }
850
851 return exitcode;
852#endif // wxUSE_GUI
518b5d2f 853 }
79656e30
GD
854
855 return ERROR_RETURN_CODE;
518b5d2f 856}
ef0ed19e
JJ
857#ifdef __VMS
858#pragma message enable codeunreachable
859#endif
518b5d2f 860
accb3257 861#undef ERROR_RETURN_CODE
f6bcfd97
BP
862#undef ARGS_CLEANUP
863
518b5d2f
VZ
864// ----------------------------------------------------------------------------
865// file and directory functions
866// ----------------------------------------------------------------------------
867
05079acc 868const wxChar* wxGetHomeDir( wxString *home )
518b5d2f
VZ
869{
870 *home = wxGetUserHome( wxString() );
181cbcf4 871 wxString tmp;
518b5d2f 872 if ( home->IsEmpty() )
223d09f6 873 *home = wxT("/");
181cbcf4
JJ
874#ifdef __VMS
875 tmp = *home;
876 if ( tmp.Last() != wxT(']'))
877 if ( tmp.Last() != wxT('/')) *home << wxT('/');
878#endif
518b5d2f
VZ
879 return home->c_str();
880}
881
05079acc
OK
882#if wxUSE_UNICODE
883const wxMB2WXbuf wxGetUserHome( const wxString &user )
e90c1d2a 884#else // just for binary compatibility -- there is no 'const' here
518b5d2f 885char *wxGetUserHome( const wxString &user )
05079acc 886#endif
518b5d2f
VZ
887{
888 struct passwd *who = (struct passwd *) NULL;
889
0fb67cd1 890 if ( !user )
518b5d2f 891 {
e90c1d2a 892 wxChar *ptr;
518b5d2f 893
223d09f6 894 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
518b5d2f
VZ
895 {
896 return ptr;
897 }
223d09f6 898 if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
518b5d2f 899 {
e90c1d2a 900 who = getpwnam(wxConvertWX2MB(ptr));
518b5d2f
VZ
901 }
902
903 // We now make sure the the user exists!
904 if (who == NULL)
905 {
906 who = getpwuid(getuid());
907 }
908 }
909 else
910 {
05079acc 911 who = getpwnam (user.mb_str());
518b5d2f
VZ
912 }
913
af111fc3 914 return wxConvertMB2WX(who ? who->pw_dir : 0);
518b5d2f
VZ
915}
916
917// ----------------------------------------------------------------------------
0fb67cd1 918// network and user id routines
518b5d2f
VZ
919// ----------------------------------------------------------------------------
920
0fb67cd1
VZ
921// retrieve either the hostname or FQDN depending on platform (caller must
922// check whether it's one or the other, this is why this function is for
923// private use only)
05079acc 924static bool wxGetHostNameInternal(wxChar *buf, int sz)
518b5d2f 925{
223d09f6 926 wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") );
518b5d2f 927
223d09f6 928 *buf = wxT('\0');
518b5d2f
VZ
929
930 // we're using uname() which is POSIX instead of less standard sysinfo()
931#if defined(HAVE_UNAME)
cc743a6f 932 struct utsname uts;
518b5d2f
VZ
933 bool ok = uname(&uts) != -1;
934 if ( ok )
935 {
e90c1d2a 936 wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
223d09f6 937 buf[sz] = wxT('\0');
518b5d2f
VZ
938 }
939#elif defined(HAVE_GETHOSTNAME)
940 bool ok = gethostname(buf, sz) != -1;
0fb67cd1 941#else // no uname, no gethostname
223d09f6 942 wxFAIL_MSG(wxT("don't know host name for this machine"));
518b5d2f
VZ
943
944 bool ok = FALSE;
0fb67cd1 945#endif // uname/gethostname
518b5d2f
VZ
946
947 if ( !ok )
948 {
949 wxLogSysError(_("Cannot get the hostname"));
950 }
951
952 return ok;
953}
954
05079acc 955bool wxGetHostName(wxChar *buf, int sz)
0fb67cd1
VZ
956{
957 bool ok = wxGetHostNameInternal(buf, sz);
958
959 if ( ok )
960 {
961 // BSD systems return the FQDN, we only want the hostname, so extract
962 // it (we consider that dots are domain separators)
223d09f6 963 wxChar *dot = wxStrchr(buf, wxT('.'));
0fb67cd1
VZ
964 if ( dot )
965 {
966 // nuke it
223d09f6 967 *dot = wxT('\0');
0fb67cd1
VZ
968 }
969 }
970
971 return ok;
972}
973
05079acc 974bool wxGetFullHostName(wxChar *buf, int sz)
0fb67cd1
VZ
975{
976 bool ok = wxGetHostNameInternal(buf, sz);
977
978 if ( ok )
979 {
223d09f6 980 if ( !wxStrchr(buf, wxT('.')) )
0fb67cd1 981 {
e90c1d2a 982 struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
0fb67cd1
VZ
983 if ( !host )
984 {
985 wxLogSysError(_("Cannot get the official hostname"));
986
987 ok = FALSE;
988 }
989 else
990 {
991 // the canonical name
e90c1d2a 992 wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
0fb67cd1
VZ
993 }
994 }
995 //else: it's already a FQDN (BSD behaves this way)
996 }
997
998 return ok;
999}
1000
05079acc 1001bool wxGetUserId(wxChar *buf, int sz)
518b5d2f
VZ
1002{
1003 struct passwd *who;
1004
223d09f6 1005 *buf = wxT('\0');
518b5d2f
VZ
1006 if ((who = getpwuid(getuid ())) != NULL)
1007 {
e90c1d2a 1008 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
518b5d2f
VZ
1009 return TRUE;
1010 }
1011
1012 return FALSE;
1013}
1014
05079acc 1015bool wxGetUserName(wxChar *buf, int sz)
518b5d2f
VZ
1016{
1017 struct passwd *who;
518b5d2f 1018
223d09f6 1019 *buf = wxT('\0');
b12915c1
VZ
1020 if ((who = getpwuid (getuid ())) != NULL)
1021 {
1022 // pw_gecos field in struct passwd is not standard
bd3277fe 1023#ifdef HAVE_PW_GECOS
b12915c1 1024 char *comma = strchr(who->pw_gecos, ',');
518b5d2f
VZ
1025 if (comma)
1026 *comma = '\0'; // cut off non-name comment fields
e90c1d2a 1027 wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
b12915c1 1028#else // !HAVE_PW_GECOS
0fcdf6dc 1029 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
b12915c1 1030#endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
518b5d2f
VZ
1031 return TRUE;
1032 }
1033
1034 return FALSE;
1035}
1036
6e73695c 1037#ifndef __WXMAC__
bdc72a22
VZ
1038wxString wxGetOsDescription()
1039{
1040#ifndef WXWIN_OS_DESCRIPTION
1041 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
1042#else
1043 return WXWIN_OS_DESCRIPTION;
1044#endif
1045}
6e73695c 1046#endif
bdc72a22 1047
bd3277fe
VZ
1048// this function returns the GUI toolkit version in GUI programs, but OS
1049// version in non-GUI ones
1050#if !wxUSE_GUI
1051
1052int wxGetOsVersion(int *majorVsn, int *minorVsn)
1053{
1054 int major, minor;
1055 char name[256];
1056
1057 if ( sscanf(WXWIN_OS_DESCRIPTION, "%s %d.%d", name, &major, &minor) != 3 )
1058 {
1059 // unreckognized uname string format
1060 major = minor = -1;
1061 }
1062
1063 if ( majorVsn )
1064 *majorVsn = major;
1065 if ( minorVsn )
1066 *minorVsn = minor;
1067
1068 return wxUNIX;
1069}
1070
1071#endif // !wxUSE_GUI
1072
c1cb4153
VZ
1073unsigned long wxGetProcessId()
1074{
1075 return (unsigned long)getpid();
1076}
1077
bd3277fe
VZ
1078long wxGetFreeMemory()
1079{
1080#if defined(__LINUX__)
1081 // get it from /proc/meminfo
1082 FILE *fp = fopen("/proc/meminfo", "r");
1083 if ( fp )
1084 {
1085 long memFree = -1;
1086
1087 char buf[1024];
1088 if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) )
1089 {
1090 long memTotal, memUsed;
1091 sscanf(buf, "Mem: %ld %ld %ld", &memTotal, &memUsed, &memFree);
1092 }
1093
1094 fclose(fp);
1095
1096 return memFree;
1097 }
1098#elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1099 return sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE);
1100//#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1101#endif
1102
1103 // can't find it out
1104 return -1;
1105}
1106
eadd7bd2
VZ
1107bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
1108{
9952adac 1109#if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
fbfb3fb3 1110 // the case to "char *" is needed for AIX 4.3
125cb99b 1111 wxStatFs fs;
401eb3de 1112 if ( statfs((char *)(const char*)path.fn_str(), &fs) != 0 )
eadd7bd2 1113 {
401eb3de 1114 wxLogSysError( wxT("Failed to get file system statistics") );
eadd7bd2
VZ
1115
1116 return FALSE;
1117 }
1118
125cb99b
VZ
1119 // under Solaris we also have to use f_frsize field instead of f_bsize
1120 // which is in general a multiple of f_frsize
1121#ifdef HAVE_STATVFS
1122 wxLongLong blockSize = fs.f_frsize;
1123#else // HAVE_STATFS
1124 wxLongLong blockSize = fs.f_bsize;
1125#endif // HAVE_STATVFS/HAVE_STATFS
9952adac 1126
eadd7bd2
VZ
1127 if ( pTotal )
1128 {
125cb99b 1129 *pTotal = wxLongLong(fs.f_blocks) * blockSize;
eadd7bd2
VZ
1130 }
1131
1132 if ( pFree )
1133 {
125cb99b 1134 *pFree = wxLongLong(fs.f_bavail) * blockSize;
eadd7bd2
VZ
1135 }
1136
1137 return TRUE;
125cb99b 1138#else // !HAVE_STATFS && !HAVE_STATVFS
eadd7bd2 1139 return FALSE;
125cb99b 1140#endif // HAVE_STATFS
eadd7bd2
VZ
1141}
1142
8fd0d89b
VZ
1143// ----------------------------------------------------------------------------
1144// env vars
1145// ----------------------------------------------------------------------------
1146
97b305b7 1147bool wxGetEnv(const wxString& var, wxString *value)
308978f6
VZ
1148{
1149 // wxGetenv is defined as getenv()
1150 wxChar *p = wxGetenv(var);
1151 if ( !p )
1152 return FALSE;
1153
1154 if ( value )
1155 {
1156 *value = p;
1157 }
1158
1159 return TRUE;
1160}
1161
8fd0d89b
VZ
1162bool wxSetEnv(const wxString& variable, const wxChar *value)
1163{
1164#if defined(HAVE_SETENV)
d90b2df8
VZ
1165 return setenv(variable.mb_str(),
1166 value ? (const char *)wxString(value).mb_str()
1167 : NULL,
1168 1 /* overwrite */) == 0;
8fd0d89b
VZ
1169#elif defined(HAVE_PUTENV)
1170 wxString s = variable;
1171 if ( value )
1172 s << _T('=') << value;
1173
1174 // transform to ANSI
1175 const char *p = s.mb_str();
1176
1177 // the string will be free()d by libc
1178 char *buf = (char *)malloc(strlen(p) + 1);
1179 strcpy(buf, p);
1180
1181 return putenv(buf) == 0;
1182#else // no way to set an env var
1183 return FALSE;
1184#endif
1185}
1186
a37a5a73
VZ
1187// ----------------------------------------------------------------------------
1188// signal handling
1189// ----------------------------------------------------------------------------
1190
1191#if wxUSE_ON_FATAL_EXCEPTION
1192
1193#include <signal.h>
1194
90350682 1195extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER)
a37a5a73
VZ
1196{
1197 if ( wxTheApp )
1198 {
1199 // give the user a chance to do something special about this
1200 wxTheApp->OnFatalException();
1201 }
1202
1203 abort();
1204}
1205
1206bool wxHandleFatalExceptions(bool doit)
1207{
1208 // old sig handlers
1209 static bool s_savedHandlers = FALSE;
1210 static struct sigaction s_handlerFPE,
1211 s_handlerILL,
1212 s_handlerBUS,
1213 s_handlerSEGV;
1214
1215 bool ok = TRUE;
1216 if ( doit && !s_savedHandlers )
1217 {
1218 // install the signal handler
1219 struct sigaction act;
1220
1221 // some systems extend it with non std fields, so zero everything
1222 memset(&act, 0, sizeof(act));
1223
1224 act.sa_handler = wxFatalSignalHandler;
1225 sigemptyset(&act.sa_mask);
1226 act.sa_flags = 0;
1227
1228 ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0;
1229 ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0;
1230 ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0;
1231 ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0;
1232 if ( !ok )
1233 {
1234 wxLogDebug(_T("Failed to install our signal handler."));
1235 }
1236
1237 s_savedHandlers = TRUE;
1238 }
1239 else if ( s_savedHandlers )
1240 {
1241 // uninstall the signal handler
1242 ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0;
1243 ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0;
1244 ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0;
1245 ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0;
1246 if ( !ok )
1247 {
1248 wxLogDebug(_T("Failed to uninstall our signal handler."));
1249 }
1250
1251 s_savedHandlers = FALSE;
1252 }
1253 //else: nothing to do
1254
1255 return ok;
1256}
1257
1258#endif // wxUSE_ON_FATAL_EXCEPTION
1259
518b5d2f
VZ
1260// ----------------------------------------------------------------------------
1261// error and debug output routines (deprecated, use wxLog)
1262// ----------------------------------------------------------------------------
1263
73deed44
VZ
1264#if WXWIN_COMPATIBILITY_2_2
1265
518b5d2f
VZ
1266void wxDebugMsg( const char *format, ... )
1267{
1268 va_list ap;
1269 va_start( ap, format );
1270 vfprintf( stderr, format, ap );
1271 fflush( stderr );
1272 va_end(ap);
1273}
1274
1275void wxError( const wxString &msg, const wxString &title )
1276{
05079acc 1277 wxFprintf( stderr, _("Error ") );
223d09f6
KB
1278 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
1279 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
1280 wxFprintf( stderr, wxT(".\n") );
518b5d2f
VZ
1281}
1282
1283void wxFatalError( const wxString &msg, const wxString &title )
1284{
05079acc 1285 wxFprintf( stderr, _("Error ") );
223d09f6
KB
1286 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
1287 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
1288 wxFprintf( stderr, wxT(".\n") );
518b5d2f
VZ
1289 exit(3); // the same exit code as for abort()
1290}
93ccaed8 1291
73deed44
VZ
1292#endif // WXWIN_COMPATIBILITY_2_2
1293