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