]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/unix/utilsunx.cpp
Correct EnsureVisible() to show last item entirely
[wxWidgets.git] / src / unix / utilsunx.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/unix/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// for compilers that support precompilation, includes "wx.h".
19#include "wx/wxprec.h"
20
21#include "wx/utils.h"
22
23#define USE_PUTENV (!defined(HAVE_SETENV) && defined(HAVE_PUTENV))
24
25#ifndef WX_PRECOMP
26 #include "wx/string.h"
27 #include "wx/intl.h"
28 #include "wx/log.h"
29 #include "wx/app.h"
30 #include "wx/wxcrtvararg.h"
31 #if USE_PUTENV
32 #include "wx/module.h"
33 #include "wx/hashmap.h"
34 #endif
35#endif
36
37#include "wx/apptrait.h"
38
39#include "wx/process.h"
40#include "wx/thread.h"
41
42#include "wx/wfstream.h"
43
44#include "wx/unix/execute.h"
45#include "wx/unix/private.h"
46
47#include <pwd.h>
48#include <sys/wait.h> // waitpid()
49
50#ifdef HAVE_SYS_SELECT_H
51# include <sys/select.h>
52#endif
53
54#define HAS_PIPE_INPUT_STREAM (wxUSE_STREAMS && wxUSE_FILE)
55
56#if HAS_PIPE_INPUT_STREAM
57
58// define this to let wxexec.cpp know that we know what we're doing
59#define _WX_USED_BY_WXEXECUTE_
60#include "../common/execcmn.cpp"
61
62#endif // HAS_PIPE_INPUT_STREAM
63
64#if wxUSE_BASE
65
66#if defined(__MWERKS__) && defined(__MACH__)
67 #ifndef WXWIN_OS_DESCRIPTION
68 #define WXWIN_OS_DESCRIPTION "MacOS X"
69 #endif
70 #ifndef HAVE_NANOSLEEP
71 #define HAVE_NANOSLEEP
72 #endif
73 #ifndef HAVE_UNAME
74 #define HAVE_UNAME
75 #endif
76
77 // our configure test believes we can use sigaction() if the function is
78 // available but Metrowekrs with MSL run-time does have the function but
79 // doesn't have sigaction struct so finally we can't use it...
80 #ifdef __MSL__
81 #undef wxUSE_ON_FATAL_EXCEPTION
82 #define wxUSE_ON_FATAL_EXCEPTION 0
83 #endif
84#endif
85
86// not only the statfs syscall is called differently depending on platform, but
87// one of its incarnations, statvfs(), takes different arguments under
88// different platforms and even different versions of the same system (Solaris
89// 7 and 8): if you want to test for this, don't forget that the problems only
90// appear if the large files support is enabled
91#ifdef HAVE_STATFS
92 #ifdef __BSD__
93 #include <sys/param.h>
94 #include <sys/mount.h>
95 #else // !__BSD__
96 #include <sys/vfs.h>
97 #endif // __BSD__/!__BSD__
98
99 #define wxStatfs statfs
100
101 #ifndef HAVE_STATFS_DECL
102 // some systems lack statfs() prototype in the system headers (AIX 4)
103 extern "C" int statfs(const char *path, struct statfs *buf);
104 #endif
105#endif // HAVE_STATFS
106
107#ifdef HAVE_STATVFS
108 #include <sys/statvfs.h>
109
110 #define wxStatfs statvfs
111#endif // HAVE_STATVFS
112
113#if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
114 // WX_STATFS_T is detected by configure
115 #define wxStatfs_t WX_STATFS_T
116#endif
117
118// SGI signal.h defines signal handler arguments differently depending on
119// whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
120#if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
121 #define _LANGUAGE_C_PLUS_PLUS 1
122#endif // SGI hack
123
124#include <stdarg.h>
125#include <dirent.h>
126#include <string.h>
127#include <sys/stat.h>
128#include <sys/types.h>
129#include <sys/wait.h>
130#include <unistd.h>
131#include <errno.h>
132#include <netdb.h>
133#include <signal.h>
134#include <fcntl.h> // for O_WRONLY and friends
135#include <time.h> // nanosleep() and/or usleep()
136#include <ctype.h> // isspace()
137#include <sys/time.h> // needed for FD_SETSIZE
138
139#ifdef HAVE_UNAME
140 #include <sys/utsname.h> // for uname()
141#endif // HAVE_UNAME
142
143// Used by wxGetFreeMemory().
144#ifdef __SGI__
145 #include <sys/sysmp.h>
146 #include <sys/sysinfo.h> // for SAGET and MINFO structures
147#endif
148
149// ----------------------------------------------------------------------------
150// conditional compilation
151// ----------------------------------------------------------------------------
152
153// many versions of Unices have this function, but it is not defined in system
154// headers - please add your system here if it is the case for your OS.
155// SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
156#if !defined(HAVE_USLEEP) && \
157 ((defined(__SUN__) && !defined(__SunOs_5_6) && \
158 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
159 defined(__osf__) || defined(__EMX__))
160 extern "C"
161 {
162 #ifdef __EMX__
163 /* I copied this from the XFree86 diffs. AV. */
164 #define INCL_DOSPROCESS
165 #include <os2.h>
166 inline void usleep(unsigned long delay)
167 {
168 DosSleep(delay ? (delay/1000l) : 1l);
169 }
170 #else // Unix
171 int usleep(unsigned int usec);
172 #endif // __EMX__/Unix
173 };
174
175 #define HAVE_USLEEP 1
176#endif // Unices without usleep()
177
178// ============================================================================
179// implementation
180// ============================================================================
181
182// ----------------------------------------------------------------------------
183// sleeping
184// ----------------------------------------------------------------------------
185
186void wxSleep(int nSecs)
187{
188 sleep(nSecs);
189}
190
191void wxMicroSleep(unsigned long microseconds)
192{
193#if defined(HAVE_NANOSLEEP)
194 timespec tmReq;
195 tmReq.tv_sec = (time_t)(microseconds / 1000000);
196 tmReq.tv_nsec = (microseconds % 1000000) * 1000;
197
198 // we're not interested in remaining time nor in return value
199 (void)nanosleep(&tmReq, (timespec *)NULL);
200#elif defined(HAVE_USLEEP)
201 // uncomment this if you feel brave or if you are sure that your version
202 // of Solaris has a safe usleep() function but please notice that usleep()
203 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
204 // documented as MT-Safe
205 #if defined(__SUN__) && wxUSE_THREADS
206 #error "usleep() cannot be used in MT programs under Solaris."
207 #endif // Sun
208
209 usleep(microseconds);
210#elif defined(HAVE_SLEEP)
211 // under BeOS sleep() takes seconds (what about other platforms, if any?)
212 sleep(microseconds * 1000000);
213#else // !sleep function
214 #error "usleep() or nanosleep() function required for wxMicroSleep"
215#endif // sleep function
216}
217
218void wxMilliSleep(unsigned long milliseconds)
219{
220 wxMicroSleep(milliseconds*1000);
221}
222
223// ----------------------------------------------------------------------------
224// process management
225// ----------------------------------------------------------------------------
226
227int wxKill(long pid, wxSignal sig, wxKillError *rc, int flags)
228{
229 int err = kill((pid_t) (flags & wxKILL_CHILDREN) ? -pid : pid, (int)sig);
230 if ( rc )
231 {
232 switch ( err ? errno : 0 )
233 {
234 case 0:
235 *rc = wxKILL_OK;
236 break;
237
238 case EINVAL:
239 *rc = wxKILL_BAD_SIGNAL;
240 break;
241
242 case EPERM:
243 *rc = wxKILL_ACCESS_DENIED;
244 break;
245
246 case ESRCH:
247 *rc = wxKILL_NO_PROCESS;
248 break;
249
250 default:
251 // this goes against Unix98 docs so log it
252 wxLogDebug(_T("unexpected kill(2) return value %d"), err);
253
254 // something else...
255 *rc = wxKILL_ERROR;
256 }
257 }
258
259 return err;
260}
261
262#define WXEXECUTE_NARGS 127
263
264#if defined(__DARWIN__)
265long wxMacExecute(wxChar **argv,
266 int flags,
267 wxProcess *process);
268#endif
269
270long wxExecute( const wxString& command, int flags, wxProcess *process )
271{
272 wxCHECK_MSG( !command.empty(), 0, wxT("can't exec empty command") );
273
274 wxLogTrace(wxT("exec"), wxT("Executing \"%s\""), command.c_str());
275
276#if wxUSE_THREADS
277 // fork() doesn't mix well with POSIX threads: on many systems the program
278 // deadlocks or crashes for some reason. Probably our code is buggy and
279 // doesn't do something which must be done to allow this to work, but I
280 // don't know what yet, so for now just warn the user (this is the least we
281 // can do) about it
282 wxASSERT_MSG( wxThread::IsMain(),
283 _T("wxExecute() can be called only from the main thread") );
284#endif // wxUSE_THREADS
285
286 int argc = 0;
287 wxChar *argv[WXEXECUTE_NARGS];
288 wxString argument;
289 const wxChar *cptr = command.c_str();
290 wxChar quotechar = wxT('\0'); // is arg quoted?
291 bool escaped = false;
292
293 // split the command line in arguments
294 do
295 {
296 argument = wxEmptyString;
297 quotechar = wxT('\0');
298
299 // eat leading whitespace:
300 while ( wxIsspace(*cptr) )
301 cptr++;
302
303 if ( *cptr == wxT('\'') || *cptr == wxT('"') )
304 quotechar = *cptr++;
305
306 do
307 {
308 if ( *cptr == wxT('\\') && ! escaped )
309 {
310 escaped = true;
311 cptr++;
312 continue;
313 }
314
315 // all other characters:
316 argument += *cptr++;
317 escaped = false;
318
319 // have we reached the end of the argument?
320 if ( (*cptr == quotechar && ! escaped)
321 || (quotechar == wxT('\0') && wxIsspace(*cptr))
322 || *cptr == wxT('\0') )
323 {
324 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
325 wxT("too many arguments in wxExecute") );
326
327 argv[argc] = new wxChar[argument.length() + 1];
328 wxStrcpy(argv[argc], argument.c_str());
329 argc++;
330
331 // if not at end of buffer, swallow last character:
332 if(*cptr)
333 cptr++;
334
335 break; // done with this one, start over
336 }
337 } while(*cptr);
338 } while(*cptr);
339 argv[argc] = NULL;
340
341 long lRc;
342#if defined(__DARWIN__)
343 // wxMacExecute only executes app bundles.
344 // It returns an error code if the target is not an app bundle, thus falling
345 // through to the regular wxExecute for non app bundles.
346 lRc = wxMacExecute(argv, flags, process);
347 if( lRc != ((flags & wxEXEC_SYNC) ? -1 : 0))
348 return lRc;
349#endif
350
351 // do execute the command
352 lRc = wxExecute(argv, flags, process);
353
354 // clean up
355 argc = 0;
356 while( argv[argc] )
357 delete [] argv[argc++];
358
359 return lRc;
360}
361
362// ----------------------------------------------------------------------------
363// wxShell
364// ----------------------------------------------------------------------------
365
366static wxString wxMakeShellCommand(const wxString& command)
367{
368 wxString cmd;
369 if ( !command )
370 {
371 // just an interactive shell
372 cmd = _T("xterm");
373 }
374 else
375 {
376 // execute command in a shell
377 cmd << _T("/bin/sh -c '") << command << _T('\'');
378 }
379
380 return cmd;
381}
382
383bool wxShell(const wxString& command)
384{
385 return wxExecute(wxMakeShellCommand(command), wxEXEC_SYNC) == 0;
386}
387
388bool wxShell(const wxString& command, wxArrayString& output)
389{
390 wxCHECK_MSG( !command.empty(), false, _T("can't exec shell non interactively") );
391
392 return wxExecute(wxMakeShellCommand(command), output);
393}
394
395// Shutdown or reboot the PC
396bool wxShutdown(wxShutdownFlags wFlags)
397{
398 wxChar level;
399 switch ( wFlags )
400 {
401 case wxSHUTDOWN_POWEROFF:
402 level = _T('0');
403 break;
404
405 case wxSHUTDOWN_REBOOT:
406 level = _T('6');
407 break;
408
409 default:
410 wxFAIL_MSG( _T("unknown wxShutdown() flag") );
411 return false;
412 }
413
414 return system(wxString::Format(_T("init %c"), level).mb_str()) == 0;
415}
416
417// ----------------------------------------------------------------------------
418// wxStream classes to support IO redirection in wxExecute
419// ----------------------------------------------------------------------------
420
421#if HAS_PIPE_INPUT_STREAM
422
423bool wxPipeInputStream::CanRead() const
424{
425 if ( m_lasterror == wxSTREAM_EOF )
426 return false;
427
428 // check if there is any input available
429 struct timeval tv;
430 tv.tv_sec = 0;
431 tv.tv_usec = 0;
432
433 const int fd = m_file->fd();
434
435 fd_set readfds;
436
437 wxFD_ZERO(&readfds);
438 wxFD_SET(fd, &readfds);
439
440 switch ( select(fd + 1, &readfds, NULL, NULL, &tv) )
441 {
442 case -1:
443 wxLogSysError(_("Impossible to get child process input"));
444 // fall through
445
446 case 0:
447 return false;
448
449 default:
450 wxFAIL_MSG(_T("unexpected select() return value"));
451 // still fall through
452
453 case 1:
454 // input available -- or maybe not, as select() returns 1 when a
455 // read() will complete without delay, but it could still not read
456 // anything
457 return !Eof();
458 }
459}
460
461#endif // HAS_PIPE_INPUT_STREAM
462
463// ----------------------------------------------------------------------------
464// wxExecute: the real worker function
465// ----------------------------------------------------------------------------
466
467long wxExecute(wxChar **argv, int flags, wxProcess *process)
468{
469 // for the sync execution, we return -1 to indicate failure, but for async
470 // case we return 0 which is never a valid PID
471 //
472 // we define this as a macro, not a variable, to avoid compiler warnings
473 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
474 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
475
476 wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );
477
478#if wxUSE_UNICODE
479 int mb_argc = 0;
480 char *mb_argv[WXEXECUTE_NARGS];
481
482 while (argv[mb_argc])
483 {
484 wxWX2MBbuf mb_arg = wxSafeConvertWX2MB(argv[mb_argc]);
485 mb_argv[mb_argc] = strdup(mb_arg);
486 mb_argc++;
487 }
488 mb_argv[mb_argc] = (char *) NULL;
489
490 // this macro will free memory we used above
491 #define ARGS_CLEANUP \
492 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
493 free(mb_argv[mb_argc])
494#else // ANSI
495 // no need for cleanup
496 #define ARGS_CLEANUP
497
498 wxChar **mb_argv = argv;
499#endif // Unicode/ANSI
500
501 // we want this function to work even if there is no wxApp so ensure that
502 // we have a valid traits pointer
503 wxConsoleAppTraits traitsConsole;
504 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
505 if ( !traits )
506 traits = &traitsConsole;
507
508 // this struct contains all information which we pass to and from
509 // wxAppTraits methods
510 wxExecuteData execData;
511 execData.flags = flags;
512 execData.process = process;
513
514 // create pipes
515 if ( !traits->CreateEndProcessPipe(execData) )
516 {
517 wxLogError( _("Failed to execute '%s'\n"), *argv );
518
519 ARGS_CLEANUP;
520
521 return ERROR_RETURN_CODE;
522 }
523
524 // pipes for inter process communication
525 wxPipe pipeIn, // stdin
526 pipeOut, // stdout
527 pipeErr; // stderr
528
529 if ( process && process->IsRedirected() )
530 {
531 if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
532 {
533 wxLogError( _("Failed to execute '%s'\n"), *argv );
534
535 ARGS_CLEANUP;
536
537 return ERROR_RETURN_CODE;
538 }
539 }
540
541 // fork the process
542 //
543 // NB: do *not* use vfork() here, it completely breaks this code for some
544 // reason under Solaris (and maybe others, although not under Linux)
545 // But on OpenVMS we do not have fork so we have to use vfork and
546 // cross our fingers that it works.
547#ifdef __VMS
548 pid_t pid = vfork();
549#else
550 pid_t pid = fork();
551#endif
552 if ( pid == -1 ) // error?
553 {
554 wxLogSysError( _("Fork failed") );
555
556 ARGS_CLEANUP;
557
558 return ERROR_RETURN_CODE;
559 }
560 else if ( pid == 0 ) // we're in child
561 {
562 // These lines close the open file descriptors to to avoid any
563 // input/output which might block the process or irritate the user. If
564 // one wants proper IO for the subprocess, the right thing to do is to
565 // start an xterm executing it.
566 if ( !(flags & wxEXEC_SYNC) )
567 {
568 // FD_SETSIZE is unsigned under BSD, signed under other platforms
569 // so we need a cast to avoid warnings on all platforms
570 for ( int fd = 0; fd < (int)FD_SETSIZE; fd++ )
571 {
572 if ( fd == pipeIn[wxPipe::Read]
573 || fd == pipeOut[wxPipe::Write]
574 || fd == pipeErr[wxPipe::Write]
575 || traits->IsWriteFDOfEndProcessPipe(execData, fd) )
576 {
577 // don't close this one, we still need it
578 continue;
579 }
580
581 // leave stderr opened too, it won't do any harm
582 if ( fd != STDERR_FILENO )
583 close(fd);
584 }
585 }
586
587#if !defined(__VMS) && !defined(__EMX__)
588 if ( flags & wxEXEC_MAKE_GROUP_LEADER )
589 {
590 // Set process group to child process' pid. Then killing -pid
591 // of the parent will kill the process and all of its children.
592 setsid();
593 }
594#endif // !__VMS
595
596 // reading side can be safely closed but we should keep the write one
597 // opened
598 traits->DetachWriteFDOfEndProcessPipe(execData);
599
600 // redirect stdin, stdout and stderr
601 if ( pipeIn.IsOk() )
602 {
603 if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 ||
604 dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 ||
605 dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 )
606 {
607 wxLogSysError(_("Failed to redirect child process input/output"));
608 }
609
610 pipeIn.Close();
611 pipeOut.Close();
612 pipeErr.Close();
613 }
614
615 execvp (*mb_argv, mb_argv);
616
617 fprintf(stderr, "execvp(");
618 // CS changed ppc to ppc_ as ppc is not available under mac os CW Mach-O
619 for ( char **ppc_ = mb_argv; *ppc_; ppc_++ )
620 fprintf(stderr, "%s%s", ppc_ == mb_argv ? "" : ", ", *ppc_);
621 fprintf(stderr, ") failed with error %d!\n", errno);
622
623 // there is no return after successful exec()
624 _exit(-1);
625
626 // some compilers complain about missing return - of course, they
627 // should know that exit() doesn't return but what else can we do if
628 // they don't?
629 //
630 // and, sure enough, other compilers complain about unreachable code
631 // after exit() call, so we can just always have return here...
632#if defined(__VMS) || defined(__INTEL_COMPILER)
633 return 0;
634#endif
635 }
636 else // we're in parent
637 {
638 ARGS_CLEANUP;
639
640 // save it for WaitForChild() use
641 execData.pid = pid;
642
643 // prepare for IO redirection
644
645#if HAS_PIPE_INPUT_STREAM
646 // the input buffer bufOut is connected to stdout, this is why it is
647 // called bufOut and not bufIn
648 wxStreamTempInputBuffer bufOut,
649 bufErr;
650#endif // HAS_PIPE_INPUT_STREAM
651
652 if ( process && process->IsRedirected() )
653 {
654#if HAS_PIPE_INPUT_STREAM
655 wxOutputStream *inStream =
656 new wxFileOutputStream(pipeIn.Detach(wxPipe::Write));
657
658 wxPipeInputStream *outStream =
659 new wxPipeInputStream(pipeOut.Detach(wxPipe::Read));
660
661 wxPipeInputStream *errStream =
662 new wxPipeInputStream(pipeErr.Detach(wxPipe::Read));
663
664 process->SetPipeStreams(outStream, inStream, errStream);
665
666 bufOut.Init(outStream);
667 bufErr.Init(errStream);
668
669 execData.bufOut = &bufOut;
670 execData.bufErr = &bufErr;
671#endif // HAS_PIPE_INPUT_STREAM
672 }
673
674 if ( pipeIn.IsOk() )
675 {
676 pipeIn.Close();
677 pipeOut.Close();
678 pipeErr.Close();
679 }
680
681 return traits->WaitForChild(execData);
682 }
683
684#if !defined(__VMS) && !defined(__INTEL_COMPILER)
685 return ERROR_RETURN_CODE;
686#endif
687}
688
689#undef ERROR_RETURN_CODE
690#undef ARGS_CLEANUP
691
692// ----------------------------------------------------------------------------
693// file and directory functions
694// ----------------------------------------------------------------------------
695
696const wxChar* wxGetHomeDir( wxString *home )
697{
698 *home = wxGetUserHome();
699 wxString tmp;
700 if ( home->empty() )
701 *home = wxT("/");
702#ifdef __VMS
703 tmp = *home;
704 if ( tmp.Last() != wxT(']'))
705 if ( tmp.Last() != wxT('/')) *home << wxT('/');
706#endif
707 return home->c_str();
708}
709
710wxString wxGetUserHome( const wxString &user )
711{
712 struct passwd *who = (struct passwd *) NULL;
713
714 if ( !user )
715 {
716 wxChar *ptr;
717
718 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
719 {
720 return ptr;
721 }
722
723 if ((ptr = wxGetenv(wxT("USER"))) != NULL ||
724 (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
725 {
726 who = getpwnam(wxSafeConvertWX2MB(ptr));
727 }
728
729 // make sure the user exists!
730 if ( !who )
731 {
732 who = getpwuid(getuid());
733 }
734 }
735 else
736 {
737 who = getpwnam (user.mb_str());
738 }
739
740 return wxSafeConvertMB2WX(who ? who->pw_dir : 0);
741}
742
743// ----------------------------------------------------------------------------
744// network and user id routines
745// ----------------------------------------------------------------------------
746
747// private utility function which returns output of the given command, removing
748// the trailing newline
749static wxString wxGetCommandOutput(const wxString &cmd)
750{
751 FILE *f = popen(cmd.ToAscii(), "r");
752 if ( !f )
753 {
754 wxLogSysError(_T("Executing \"%s\" failed"), cmd.c_str());
755 return wxEmptyString;
756 }
757
758 wxString s;
759 char buf[256];
760 while ( !feof(f) )
761 {
762 if ( !fgets(buf, sizeof(buf), f) )
763 break;
764
765 s += wxString::FromAscii(buf);
766 }
767
768 pclose(f);
769
770 if ( !s.empty() && s.Last() == _T('\n') )
771 s.RemoveLast();
772
773 return s;
774}
775
776// retrieve either the hostname or FQDN depending on platform (caller must
777// check whether it's one or the other, this is why this function is for
778// private use only)
779static bool wxGetHostNameInternal(wxChar *buf, int sz)
780{
781 wxCHECK_MSG( buf, false, wxT("NULL pointer in wxGetHostNameInternal") );
782
783 *buf = wxT('\0');
784
785 // we're using uname() which is POSIX instead of less standard sysinfo()
786#if defined(HAVE_UNAME)
787 struct utsname uts;
788 bool ok = uname(&uts) != -1;
789 if ( ok )
790 {
791 wxStrncpy(buf, wxSafeConvertMB2WX(uts.nodename), sz - 1);
792 buf[sz] = wxT('\0');
793 }
794#elif defined(HAVE_GETHOSTNAME)
795 char cbuf[sz];
796 bool ok = gethostname(cbuf, sz) != -1;
797 if ( ok )
798 {
799 wxStrncpy(buf, wxSafeConvertMB2WX(cbuf), sz - 1);
800 buf[sz] = wxT('\0');
801 }
802#else // no uname, no gethostname
803 wxFAIL_MSG(wxT("don't know host name for this machine"));
804
805 bool ok = false;
806#endif // uname/gethostname
807
808 if ( !ok )
809 {
810 wxLogSysError(_("Cannot get the hostname"));
811 }
812
813 return ok;
814}
815
816bool wxGetHostName(wxChar *buf, int sz)
817{
818 bool ok = wxGetHostNameInternal(buf, sz);
819
820 if ( ok )
821 {
822 // BSD systems return the FQDN, we only want the hostname, so extract
823 // it (we consider that dots are domain separators)
824 wxChar *dot = wxStrchr(buf, wxT('.'));
825 if ( dot )
826 {
827 // nuke it
828 *dot = wxT('\0');
829 }
830 }
831
832 return ok;
833}
834
835bool wxGetFullHostName(wxChar *buf, int sz)
836{
837 bool ok = wxGetHostNameInternal(buf, sz);
838
839 if ( ok )
840 {
841 if ( !wxStrchr(buf, wxT('.')) )
842 {
843 struct hostent *host = gethostbyname(wxSafeConvertWX2MB(buf));
844 if ( !host )
845 {
846 wxLogSysError(_("Cannot get the official hostname"));
847
848 ok = false;
849 }
850 else
851 {
852 // the canonical name
853 wxStrncpy(buf, wxSafeConvertMB2WX(host->h_name), sz);
854 }
855 }
856 //else: it's already a FQDN (BSD behaves this way)
857 }
858
859 return ok;
860}
861
862bool wxGetUserId(wxChar *buf, int sz)
863{
864 struct passwd *who;
865
866 *buf = wxT('\0');
867 if ((who = getpwuid(getuid ())) != NULL)
868 {
869 wxStrncpy (buf, wxSafeConvertMB2WX(who->pw_name), sz - 1);
870 return true;
871 }
872
873 return false;
874}
875
876bool wxGetUserName(wxChar *buf, int sz)
877{
878#ifdef HAVE_PW_GECOS
879 struct passwd *who;
880
881 *buf = wxT('\0');
882 if ((who = getpwuid (getuid ())) != NULL)
883 {
884 char *comma = strchr(who->pw_gecos, ',');
885 if (comma)
886 *comma = '\0'; // cut off non-name comment fields
887 wxStrncpy (buf, wxSafeConvertMB2WX(who->pw_gecos), sz - 1);
888 return true;
889 }
890
891 return false;
892#else // !HAVE_PW_GECOS
893 return wxGetUserId(buf, sz);
894#endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
895}
896
897bool wxIsPlatform64Bit()
898{
899 const wxString machine = wxGetCommandOutput(wxT("uname -m"));
900
901 // the test for "64" is obviously not 100% reliable but seems to work fine
902 // in practice
903 return machine.Contains(wxT("64")) ||
904 machine.Contains(wxT("alpha"));
905}
906
907// these functions are in mac/utils.cpp for wxMac
908#ifndef __WXMAC__
909
910wxOperatingSystemId wxGetOsVersion(int *verMaj, int *verMin)
911{
912 // get OS version
913 int major, minor;
914 wxString release = wxGetCommandOutput(wxT("uname -r"));
915 if ( release.empty() ||
916 wxSscanf(release.c_str(), wxT("%d.%d"), &major, &minor) != 2 )
917 {
918 // failed to get version string or unrecognized format
919 major =
920 minor = -1;
921 }
922
923 if ( verMaj )
924 *verMaj = major;
925 if ( verMin )
926 *verMin = minor;
927
928 // try to understand which OS are we running
929 wxString kernel = wxGetCommandOutput(wxT("uname -s"));
930 if ( kernel.empty() )
931 kernel = wxGetCommandOutput(wxT("uname -o"));
932
933 if ( kernel.empty() )
934 return wxOS_UNKNOWN;
935
936 return wxPlatformInfo::GetOperatingSystemId(kernel);
937}
938
939wxString wxGetOsDescription()
940{
941 return wxGetCommandOutput(wxT("uname -s -r -m"));
942}
943
944#endif // !__WXMAC__
945
946unsigned long wxGetProcessId()
947{
948 return (unsigned long)getpid();
949}
950
951wxMemorySize wxGetFreeMemory()
952{
953#if defined(__LINUX__)
954 // get it from /proc/meminfo
955 FILE *fp = fopen("/proc/meminfo", "r");
956 if ( fp )
957 {
958 long memFree = -1;
959
960 char buf[1024];
961 if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) )
962 {
963 // /proc/meminfo changed its format in kernel 2.6
964 if ( wxPlatformInfo().CheckOSVersion(2, 6) )
965 {
966 unsigned long cached, buffers;
967 sscanf(buf, "MemFree: %ld", &memFree);
968
969 fgets(buf, WXSIZEOF(buf), fp);
970 sscanf(buf, "Buffers: %lu", &buffers);
971
972 fgets(buf, WXSIZEOF(buf), fp);
973 sscanf(buf, "Cached: %lu", &cached);
974
975 // add to "MemFree" also the "Buffers" and "Cached" values as
976 // free(1) does as otherwise the value never makes sense: for
977 // kernel 2.6 it's always almost 0
978 memFree += buffers + cached;
979
980 // values here are always expressed in kB and we want bytes
981 memFree *= 1024;
982 }
983 else // Linux 2.4 (or < 2.6, anyhow)
984 {
985 long memTotal, memUsed;
986 sscanf(buf, "Mem: %ld %ld %ld", &memTotal, &memUsed, &memFree);
987 }
988 }
989
990 fclose(fp);
991
992 return (wxMemorySize)memFree;
993 }
994#elif defined(__SGI__)
995 struct rminfo realmem;
996 if ( sysmp(MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0 )
997 return ((wxMemorySize)realmem.physmem * sysconf(_SC_PAGESIZE));
998#elif defined(_SC_AVPHYS_PAGES)
999 return ((wxMemorySize)sysconf(_SC_AVPHYS_PAGES))*sysconf(_SC_PAGESIZE);
1000//#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1001#endif
1002
1003 // can't find it out
1004 return -1;
1005}
1006
1007bool wxGetDiskSpace(const wxString& path, wxDiskspaceSize_t *pTotal, wxDiskspaceSize_t *pFree)
1008{
1009#if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
1010 // the case to "char *" is needed for AIX 4.3
1011 wxStatfs_t fs;
1012 if ( wxStatfs((char *)(const char*)path.fn_str(), &fs) != 0 )
1013 {
1014 wxLogSysError( wxT("Failed to get file system statistics") );
1015
1016 return false;
1017 }
1018
1019 // under Solaris we also have to use f_frsize field instead of f_bsize
1020 // which is in general a multiple of f_frsize
1021#ifdef HAVE_STATVFS
1022 wxDiskspaceSize_t blockSize = fs.f_frsize;
1023#else // HAVE_STATFS
1024 wxDiskspaceSize_t blockSize = fs.f_bsize;
1025#endif // HAVE_STATVFS/HAVE_STATFS
1026
1027 if ( pTotal )
1028 {
1029 *pTotal = wxDiskspaceSize_t(fs.f_blocks) * blockSize;
1030 }
1031
1032 if ( pFree )
1033 {
1034 *pFree = wxDiskspaceSize_t(fs.f_bavail) * blockSize;
1035 }
1036
1037 return true;
1038#else // !HAVE_STATFS && !HAVE_STATVFS
1039 return false;
1040#endif // HAVE_STATFS
1041}
1042
1043// ----------------------------------------------------------------------------
1044// env vars
1045// ----------------------------------------------------------------------------
1046
1047#if USE_PUTENV
1048
1049WX_DECLARE_STRING_HASH_MAP(char *, wxEnvVars);
1050
1051static wxEnvVars gs_envVars;
1052
1053class wxSetEnvModule : public wxModule
1054{
1055public:
1056 virtual bool OnInit() { return true; }
1057 virtual void OnExit()
1058 {
1059 for ( wxEnvVars::const_iterator i = gs_envVars.begin();
1060 i != gs_envVars.end();
1061 ++i )
1062 {
1063 free(i->second);
1064 }
1065
1066 gs_envVars.clear();
1067 }
1068
1069 DECLARE_DYNAMIC_CLASS(wxSetEnvModule)
1070};
1071
1072IMPLEMENT_DYNAMIC_CLASS(wxSetEnvModule, wxModule)
1073
1074#endif // USE_PUTENV
1075
1076bool wxGetEnv(const wxString& var, wxString *value)
1077{
1078 // wxGetenv is defined as getenv()
1079 char *p = wxGetenv(var);
1080 if ( !p )
1081 return false;
1082
1083 if ( value )
1084 {
1085 *value = p;
1086 }
1087
1088 return true;
1089}
1090
1091static bool wxDoSetEnv(const wxString& variable, const char *value)
1092{
1093#if defined(HAVE_SETENV)
1094 if ( !value )
1095 {
1096#ifdef HAVE_UNSETENV
1097 // don't test unsetenv() return value: it's void on some systems (at
1098 // least Darwin)
1099 unsetenv(variable.mb_str());
1100 return true;
1101#else
1102 value = ""; // we can't pass NULL to setenv()
1103#endif
1104 }
1105
1106 return setenv(variable.mb_str(), value, 1 /* overwrite */) == 0;
1107#elif defined(HAVE_PUTENV)
1108 wxString s = variable;
1109 if ( value )
1110 s << _T('=') << value;
1111
1112 // transform to ANSI
1113 const wxWX2MBbuf p = s.mb_str();
1114
1115 char *buf = (char *)malloc(strlen(p) + 1);
1116 strcpy(buf, p);
1117
1118 // store the string to free() it later
1119 wxEnvVars::iterator i = gs_envVars.find(variable);
1120 if ( i != gs_envVars.end() )
1121 {
1122 free(i->second);
1123 i->second = buf;
1124 }
1125 else // this variable hadn't been set before
1126 {
1127 gs_envVars[variable] = buf;
1128 }
1129
1130 return putenv(buf) == 0;
1131#else // no way to set an env var
1132 return false;
1133#endif
1134}
1135
1136bool wxSetEnv(const wxString& variable, const wxString& value)
1137{
1138 return wxDoSetEnv(variable, value.mb_str());
1139}
1140
1141bool wxUnsetEnv(const wxString& variable)
1142{
1143 return wxDoSetEnv(variable, NULL);
1144}
1145
1146// ----------------------------------------------------------------------------
1147// signal handling
1148// ----------------------------------------------------------------------------
1149
1150#if wxUSE_ON_FATAL_EXCEPTION
1151
1152#include <signal.h>
1153
1154extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER)
1155{
1156 if ( wxTheApp )
1157 {
1158 // give the user a chance to do something special about this
1159 wxTheApp->OnFatalException();
1160 }
1161
1162 abort();
1163}
1164
1165bool wxHandleFatalExceptions(bool doit)
1166{
1167 // old sig handlers
1168 static bool s_savedHandlers = false;
1169 static struct sigaction s_handlerFPE,
1170 s_handlerILL,
1171 s_handlerBUS,
1172 s_handlerSEGV;
1173
1174 bool ok = true;
1175 if ( doit && !s_savedHandlers )
1176 {
1177 // install the signal handler
1178 struct sigaction act;
1179
1180 // some systems extend it with non std fields, so zero everything
1181 memset(&act, 0, sizeof(act));
1182
1183 act.sa_handler = wxFatalSignalHandler;
1184 sigemptyset(&act.sa_mask);
1185 act.sa_flags = 0;
1186
1187 ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0;
1188 ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0;
1189 ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0;
1190 ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0;
1191 if ( !ok )
1192 {
1193 wxLogDebug(_T("Failed to install our signal handler."));
1194 }
1195
1196 s_savedHandlers = true;
1197 }
1198 else if ( s_savedHandlers )
1199 {
1200 // uninstall the signal handler
1201 ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0;
1202 ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0;
1203 ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0;
1204 ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0;
1205 if ( !ok )
1206 {
1207 wxLogDebug(_T("Failed to uninstall our signal handler."));
1208 }
1209
1210 s_savedHandlers = false;
1211 }
1212 //else: nothing to do
1213
1214 return ok;
1215}
1216
1217#endif // wxUSE_ON_FATAL_EXCEPTION
1218
1219#endif // wxUSE_BASE
1220
1221#if wxUSE_GUI
1222
1223#if __DARWIN__
1224 #include <sys/errno.h>
1225#endif
1226// ----------------------------------------------------------------------------
1227// wxExecute support
1228// ----------------------------------------------------------------------------
1229
1230/*
1231 NOTE: If this proves not to work well for wxMac then move back to the old
1232 behavior. If, however, it proves to work just fine, nuke all of the code
1233 for the old behavior. I strongly suggest backporting this to 2.8 as well.
1234 However, beware that while you can nuke the old code here, you cannot
1235 nuke the wxAddProcessCallbackForPid from the 2.8 branch (found in
1236 utilsexc_cf since it's an exported symbol).
1237 */
1238// #define USE_OLD_DARWIN_END_PROCESS_DETECT (defined(__DARWIN__) && defined(__WXMAC__))
1239#define USE_OLD_DARWIN_END_PROCESS_DETECT 0
1240
1241// wxMac/wxCocoa don't use the same process end detection mechanisms so we don't
1242// need wxExecute-related helpers for them
1243#if !USE_OLD_DARWIN_END_PROCESS_DETECT
1244
1245bool wxGUIAppTraits::CreateEndProcessPipe(wxExecuteData& execData)
1246{
1247 return execData.pipeEndProcDetect.Create();
1248}
1249
1250bool wxGUIAppTraits::IsWriteFDOfEndProcessPipe(wxExecuteData& execData, int fd)
1251{
1252 return fd == (execData.pipeEndProcDetect)[wxPipe::Write];
1253}
1254
1255void wxGUIAppTraits::DetachWriteFDOfEndProcessPipe(wxExecuteData& execData)
1256{
1257 execData.pipeEndProcDetect.Detach(wxPipe::Write);
1258 execData.pipeEndProcDetect.Close();
1259}
1260
1261#else // !Darwin
1262
1263bool wxGUIAppTraits::CreateEndProcessPipe(wxExecuteData& WXUNUSED(execData))
1264{
1265 return true;
1266}
1267
1268bool
1269wxGUIAppTraits::IsWriteFDOfEndProcessPipe(wxExecuteData& WXUNUSED(execData),
1270 int WXUNUSED(fd))
1271{
1272 return false;
1273}
1274
1275void
1276wxGUIAppTraits::DetachWriteFDOfEndProcessPipe(wxExecuteData& WXUNUSED(execData))
1277{
1278 // nothing to do here, we don't use the pipe
1279}
1280
1281#endif // !Darwin/Darwin
1282
1283int wxGUIAppTraits::WaitForChild(wxExecuteData& execData)
1284{
1285 wxEndProcessData *endProcData = new wxEndProcessData;
1286
1287 const int flags = execData.flags;
1288
1289 // wxAddProcessCallback is now (with DARWIN) allowed to call the
1290 // callback function directly if the process terminates before
1291 // the callback can be added to the run loop. Set up the endProcData.
1292 if ( flags & wxEXEC_SYNC )
1293 {
1294 // we may have process for capturing the program output, but it's
1295 // not used in wxEndProcessData in the case of sync execution
1296 endProcData->process = NULL;
1297
1298 // sync execution: indicate it by negating the pid
1299 endProcData->pid = -execData.pid;
1300 }
1301 else
1302 {
1303 // async execution, nothing special to do -- caller will be
1304 // notified about the process termination if process != NULL, endProcData
1305 // will be deleted in GTK_EndProcessDetector
1306 endProcData->process = execData.process;
1307 endProcData->pid = execData.pid;
1308 }
1309
1310
1311 if ( !(flags & wxEXEC_NOEVENTS) )
1312 {
1313#if USE_OLD_DARWIN_END_PROCESS_DETECT
1314 endProcData->tag = wxAddProcessCallbackForPid(endProcData, execData.pid);
1315#else
1316 endProcData->tag = wxAddProcessCallback
1317 (
1318 endProcData,
1319 execData.pipeEndProcDetect.Detach(wxPipe::Read)
1320 );
1321
1322 execData.pipeEndProcDetect.Close();
1323#endif // USE_OLD_DARWIN_END_PROCESS_DETECT
1324 }
1325
1326 if ( flags & wxEXEC_SYNC )
1327 {
1328 wxBusyCursor bc;
1329 int exitcode = 0;
1330
1331 wxWindowDisabler *wd = flags & (wxEXEC_NODISABLE | wxEXEC_NOEVENTS)
1332 ? NULL
1333 : new wxWindowDisabler;
1334
1335 if ( flags & wxEXEC_NOEVENTS )
1336 {
1337 // just block waiting for the child to exit
1338 int status = 0;
1339
1340 int result = waitpid(execData.pid, &status, 0);
1341#ifdef __DARWIN__
1342 /* DE: waitpid manpage states that waitpid can fail with EINTR
1343 if the call is interrupted by a caught signal. I suppose
1344 that means that this ought to be a while loop.
1345
1346 The odd thing is that it seems to fail EVERY time. It fails
1347 with a quickly exiting process (e.g. echo), and fails with a
1348 slowly exiting process (e.g. sleep 2) but clearly after
1349 having waited for the child to exit. Maybe it's a bug in
1350 my particular version.
1351
1352 It works, however, from the CFSocket callback without this
1353 trick but in that case it's used only after CFSocket calls
1354 the callback and with the WNOHANG flag which would seem to
1355 preclude it from being interrupted or at least make it much
1356 less likely since it would not then be waiting.
1357
1358 If Darwin's man page is to be believed then this is definitely
1359 necessary. It's just weird that I've never seen it before
1360 and apparently no one else has either or you'd think they'd
1361 have reported it by now. Perhaps blocking the GUI while
1362 waiting for a child process to exit is simply not that common.
1363 */
1364 if(result == -1 && errno == EINTR)
1365 {
1366 result = waitpid(execData.pid, &status, 0);
1367 }
1368
1369#endif
1370
1371 if ( result == -1 )
1372 {
1373 wxLogLastError(_T("waitpid"));
1374 exitcode = -1;
1375 }
1376 else
1377 {
1378 wxASSERT_MSG( result == execData.pid,
1379 _T("unexpected waitpid() return value") );
1380
1381 if ( WIFEXITED(status) )
1382 {
1383 exitcode = WEXITSTATUS(status);
1384 }
1385 else // abnormal termination?
1386 {
1387 wxASSERT_MSG( WIFSIGNALED(status),
1388 _T("unexpected child wait status") );
1389 exitcode = -1;
1390 }
1391 }
1392 }
1393 else // !wxEXEC_NOEVENTS
1394 {
1395 // endProcData->pid will be set to 0 from GTK_EndProcessDetector when the
1396 // process terminates
1397 while ( endProcData->pid != 0 )
1398 {
1399 bool idle = true;
1400
1401#if HAS_PIPE_INPUT_STREAM
1402 if ( execData.bufOut )
1403 {
1404 execData.bufOut->Update();
1405 idle = false;
1406 }
1407
1408 if ( execData.bufErr )
1409 {
1410 execData.bufErr->Update();
1411 idle = false;
1412 }
1413#endif // HAS_PIPE_INPUT_STREAM
1414
1415 // don't consume 100% of the CPU while we're sitting in this
1416 // loop
1417 if ( idle )
1418 wxMilliSleep(1);
1419
1420 // give GTK+ a chance to call GTK_EndProcessDetector here and
1421 // also repaint the GUI
1422 wxYield();
1423 }
1424
1425 exitcode = endProcData->exitcode;
1426 }
1427
1428 delete wd;
1429 delete endProcData;
1430
1431 return exitcode;
1432 }
1433 else // async execution
1434 {
1435 return execData.pid;
1436 }
1437}
1438
1439#endif // wxUSE_GUI
1440#if wxUSE_BASE
1441
1442void wxHandleProcessTermination(wxEndProcessData *proc_data)
1443{
1444 // notify user about termination if required
1445 if ( proc_data->process )
1446 {
1447 proc_data->process->OnTerminate(proc_data->pid, proc_data->exitcode);
1448 }
1449
1450 // clean up
1451 if ( proc_data->pid > 0 )
1452 {
1453 delete proc_data;
1454 }
1455 else
1456 {
1457 // let wxExecute() know that the process has terminated
1458 proc_data->pid = 0;
1459 }
1460}
1461
1462#endif // wxUSE_BASE