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