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