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