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