1 /*
2  * xerrorhandler.cpp
3  *
4  * Copyright (C) 2001 J. "MUFTI" Scheurich
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program (see the file "COPYING" for details); if
17  * not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18  * Cambridge, MA 02139, USA.
19  *
20  * Additional License - if you need another License 8-)
21 
22      Permission is hereby granted, free of charge, to any person obtaining a
23      copy of this file, to deal in this file without restriction, including
24      without limitation the rights to use, copy, modify, merge, publish,
25      distribute, and/or sell copies of this file, and to permit persons
26      to whom this file is furnished to do so, provided that the above
27      copyright notice(s) and this permission notice appear in all copies of
28      this file and that both the above copyright notice(s) and this
29      permission notice appear in supporting documentation.
30 
31      THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
32      OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33      MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
34      OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
35      HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
36      INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
37      FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
38      NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
39      WITH THE USE OR PERFORMANCE OF THIS FILE.
40 
41      Except as contained in this notice, the name of a copyright holder
42      shall not be used in advertising or otherwise to promote the sale, use
43      or other dealings in this Software without prior written authorization
44      of the copyright holder.
45  */
46 
47 /*
48  * tries to catch signals and X11 errors and
49  * try to save the content in case of crashes
50  */
51 
52 #include "xerrorhandler.h"
53 #include "stdafx.h"
54 #include "MainWindow.h"
55 #include "DuneApp.h"
56 #include "swt.h"
57 #include "maxpath.h"
58 
coredump(void)59 void coredump(void)
60    {
61    int *nix=NULL;
62    nix[0]=1;
63    }
64 
65 static int normal_exit=0;
66 #ifdef _WIN32
67 extern "C" {
68     int popupConsole();
69 }
70 #endif
71 
setNormalExit(void)72 void setNormalExit(void)
73 {
74     normal_exit=1;
75 }
76 
normalExit(int status)77 void normalExit(int status)
78 {
79     myflushall();
80 #ifdef _WIN32
81     if (popupConsole()) {
82         printf("Press Enter to Exit:");
83         getchar();
84     }
85 #endif
86     setNormalExit();
87     exit(status);
88 }
89 
90 #ifdef EXIT_HANDLER
exit_handler(void)91 void exit_handler(void)
92 {
93 //    if (normal_exit==0)
94 //        TheApp->emergency_rescue();
95 }
96 #endif
97 
98 #ifndef HAVE_WANT_CORE
99 # ifdef HAVE_NEW_NEW_HANDLER
100 #  ifndef HAVE_NEW_HANDLER
101 #   define HAVE_NEW_HANDLER 1
102 #  endif
103 # endif
104 
105 # ifdef HAVE_NEW_HANDLER
106 #  ifdef HAVE_NEW_NEW_HANDLER
107 #   include <new>
108 #  else
109 #   include <new.h>
110 #  endif
111 
dune_new_handler(void)112 static void dune_new_handler(void)
113 {
114     TheApp->emergency_rescue();
115 //    normalExit(1);
116 }
117 # endif
118 #endif
119 
120 /*
121  *  Try to save scenegraphs into files
122  */
123 
124 #ifdef _WIN32
125 #include <process.h>
126 #include "stdafx.h"
127 #include "Windows.h"
128 #   define sleep(x)
129 #   define myMessageBox(x) MessageBox(NULL,x,"White_dune",MB_ICONINFORMATION);
130 #else
131 #   define mywriteerr(x) while(write(2,x,mystrlen(x)) == -1);
132 #endif
133 
134 
135 char* home;
136 
emergency_rescue(int sig)137 int DuneApp::emergency_rescue(int sig)
138 #ifdef  __clang__
139 # if __MAGEIA__
140  __attribute__((noreturn))
141 # endif
142 # if defined __FreeBSD__ || defined __DragonFly__
143  __attribute__((noreturn))
144 # endif
145 # ifdef MACOSX
146  __attribute__((noreturn))
147 # endif
148 #endif
149    {
150    int filenum=0;
151 
152    int console;
153 
154    myflushall();
155    swUploadCleanupPasswd(m_upload);
156 
157 #ifndef _WIN32
158    console=open("/dev/console",O_WRONLY | O_NONBLOCK);
159    if (console==-1)
160       console=2;
161 
162    if ((sig != SIGPIPE) && !isatty(0)) {
163        mywritestr(console,"white_dune: Internal Crash !\nwhite_dune: Try to save Files\n");
164        mywriteerr("Internal Crash !\a\n Try to save Files\n");
165    }
166 #endif
167    for (List<MainWindow *>::Iterator *i=m_windows.first(); i; i=i->next())
168       {
169       char mypath[MY_MAX_PATH+1];
170       char filename[MY_MAX_PATH+1];
171       struct stat fileStat;
172       bool x3d = i->item()->GetScene()->isX3d();
173       const char *ext = "wrl";
174       if (x3d)
175           ext = "x3dv";
176       int flags = TEMP_SAVE | (x3d ? X3DV : 0);
177       int f = -1;
178       do {
179           filenum++;
180           mysnprintf(filename,MY_MAX_PATH,".dune_crash_%d_%d.%s",getpid(),
181                      filenum, ext);
182 #ifdef _WIN32
183           mysnprintf(mypath,MY_MAX_PATH,"%s%s\\%s",getenv("HOMEDRIVE"),
184                                                    getenv("HOMEPATH"),filename);
185 #else
186           mysnprintf(mypath,MY_MAX_PATH,"%s/%s",home,filename);
187 #endif
188           f = open(mypath, O_WRONLY | O_CREAT
189 /* writing with O_SYNC is too slow on most systems... */
190 #     ifdef PARANOIA
191 #       ifdef O_SYNC
192                                               | O_SYNC
193 #       endif
194 #     endif
195 #ifdef _WIN32
196                                               ,_S_IREAD | _S_IWRITE);
197 #else
198                                               ,S_IRUSR | S_IWUSR);
199 #endif
200       } while (f == -1);
201 #ifndef _WIN32
202       mywritef(console, "%s:  %s\n", mypath, strerror(errno));
203       mywritef(console,"white_dune: %s:  %s\n", mypath, strerror(errno));
204 #endif
205       int writeError = false;
206       if (i->item()->GetScene()->write(f, mypath, flags) < 0)
207          writeError = true;
208       if (!writeError && swTruncateClose(f))
209          writeError = true;
210       if (writeError)
211          {
212          mywritef(console, "write %s:  %s\n", mypath, strerror(errno));
213          mywritef(console," error write white_dune: %s:  %s\n", mypath,
214                   strerror(errno));
215          }
216       else
217          {
218          TheApp->setCrashFile(i->item()->GetScene()->getPath());
219          TheApp->AddToRecentFiles(mypath);
220          TheApp->SaveRecentFileList();
221          TheApp->SavePreferences();
222 #ifdef _WIN32
223          char message[1024];
224          mysnprintf(message,1023,"file successfully written to %s",mypath);
225          myMessageBox(message);
226 #else
227          mywritestr(console,"white_dune: write successful to ");
228          mywritestr(console,mypath);
229          mywritestr(console,"\n");
230 #endif
231       }
232       if (TheApp->returnTracker())
233          {
234 #ifndef _WIN32
235          mywritestr(console,"white_dune: tracker stopped successfully\n");
236          mywritestr(2,"tracker stopped successfully\n");
237 #endif
238          }
239       }
240 #ifndef _WIN32
241    if ((filenum==0) && ((sig != SIGPIPE) && !isatty(0)))
242       {
243       mywritestr(console, "white_dune: Nothing to save anymore\n");
244       mywriteerr("Nothing to save anymore\n");
245       }
246 #endif
247    return filenum;
248    }
249 
250 #ifdef _WIN32
251 
init_handlers(void)252     void init_handlers(void)
253        {
254 # ifndef HAVE_WANT_CORE
255 #  ifdef HAVE_NEW_HANDLER
256 #   ifdef HAVE_NEW_NEW_HANDLER
257        std::set_new_handler(dune_new_handler);
258 #   else
259        set_new_handler(dune_new_handler);
260 #   endif
261 #  endif
262 # endif
263        return;
264        }
265 
266 #else
267 
268 /*
269  *  Handler for nofatal X11 Errors: you ignore them
270  */
271 
nofatal_handler(Display * display,XErrorEvent * xerrorevent)272    int nofatal_handler(Display *display, XErrorEvent *xerrorevent)
273       {
274       static int numberX11Errors = 0;
275       int limit = TheApp->GetX11ErrorsLimit();
276       numberX11Errors++;
277       if ((limit == -1) || (numberX11Errors <= limit))
278          {
279          /* so what ?*/
280          char errortext[1025];
281 
282          mywriteerr("nofatal X11 Error ignored\n");
283          XGetErrorText(display,xerrorevent->error_code,errortext,1024);
284          mywriteerr(errortext);
285          mywriteerr("\n");
286          }
287       else if (numberX11Errors == (limit + 1) && limit != 0)
288          mywriteerr("X11ErrorsLimit (see $HOME/.dunerc) exceeded\n");
289       return(1);
290       }
291 
292 /*
293  *  Handler for fatal X11 Errors: try to save files
294  */
295 
fatal_handler(Display * display)296    int fatal_handler(Display *display)
297       {
298       TheApp->emergency_rescue();
299 //      normalExit(2);
300       return(0);
301       }
302 
303 /*
304  *  Handler for fatal Xt Errors: try to save files
305  */
306 
fatal_xthandler(char * message)307    void fatal_xthandler(char* message)
308       {
309       bool exitFlag = true;
310       // the following error is (hopefully) not really fatal for white_dune
311       if (strcmp(message,
312                  "XtPopdown requires a subclass of shellWidgetClass") == 0)
313          exitFlag = false;
314       // no file to save, not really a fatal problem ?
315       if (exitFlag)
316          if (TheApp->emergency_rescue() == 0)
317             exitFlag = false;
318       if (exitFlag)
319          {
320          mywriteerr(message);
321          mywriteerr("\n");
322 //         normalExit(2);
323          }
324       }
325 
326 
327 /*
328  *  Handler for dangerous Unix Signals: try to save files
329  */
330 
331 volatile int fatal_error_in_progress = 0;
332 
333 #ifdef  HAVE_SIGNAL_INT
signal_fatal_handler(int sig)334    void signal_fatal_handler(int sig)
335       {
336 # ifndef HAVE_WANT_CORE
337       signal (sig, SIG_IGN);
338       if (!fatal_error_in_progress)
339          {
340          fatal_error_in_progress = 1;
341          TheApp->emergency_rescue(sig);
342          signal (sig, SIG_DFL);
343          mywritef(2,"killed by signal %d\n",sig);
344          raise (sig);
345          }
346 # endif
347       }
348 # else
signal_fatal_handler()349    void signal_fatal_handler()
350       {
351 # ifndef HAVE_WANT_CORE
352       for (int i=1;i<=64;i++)
353          signal (i, SIG_IGN);
354       if (!fatal_error_in_progress)
355          {
356          fatal_error_in_progress = 1;
357          TheApp->emergency_rescue();
358          signal (SIGTERM, SIG_DFL);
359          raise (SIGTERM);
360          }
361 # endif
362       }
363 #endif
364 
365 /*
366  *  Initalize X11 and Unix Signal Handlers
367  */
368 
369 #   ifndef TRUE
370 #      define TRUE 1
371 #      define FALSE 0
372 #   endif
373 
init_handlers(void)374     void init_handlers(void)
375       {
376       int dangerous_signals[65];
377 
378       /* initialise path to $HOME for usage in handler */
379       home=getenv("HOME");
380 
381 #ifdef EXIT_HANDLER
382       atexit(&exit_handler);
383 #endif
384 # ifdef HAVE_NEW_HANDLER
385   # ifdef HAVE_NEW_NEW_HANDLER
386       std::set_new_handler(dune_new_handler);
387   #else
388       set_new_handler(dune_new_handler);
389   # endif
390 # endif
391       XSetErrorHandler(&nofatal_handler);
392       XSetIOErrorHandler(&fatal_handler);
393 //      XtSetErrorHandler(&fatal_xthandler);
394       for (int i=1;i<=32;i++)
395          dangerous_signals[i]=TRUE;
396 
397       /* list of not dangerous signals */
398       dangerous_signals[SIGCHLD]=FALSE;
399       dangerous_signals[SIGWINCH]=FALSE;
400       dangerous_signals[SIGURG]=FALSE;
401       dangerous_signals[SIGSTOP]=FALSE;
402       dangerous_signals[SIGTSTP]=FALSE;
403       dangerous_signals[SIGCONT]=FALSE;
404       dangerous_signals[SIGTTIN]=FALSE;
405       dangerous_signals[SIGTTOU]=FALSE;
406 # ifdef SIGCKPT
407       dangerous_signals[SIGCKPT]=FALSE;
408 # endif
409 # ifdef SIGRESTART
410       dangerous_signals[SIGRESTART]=FALSE;
411 # endif
412       /*
413       dangerous_signals[SIGPWR]=FALSE;
414       */
415 
416       /* handle "dangerous Signals */
417       for (int i=1;i<=32;i++)
418          if (dangerous_signals[i]==TRUE)
419             signal(i,&signal_fatal_handler);
420 
421       /* ignore CTRL-C interrupts */
422       signal(SIGINT,SIG_IGN);
423 
424       /* handle known interrupts > 32 */
425 # ifdef SIGRTMIN
426       signal(SIGRTMIN,&signal_fatal_handler);
427 # endif
428 # ifdef SIGRTMAX
429 #  ifdef __linux__
430 #   ifdef HAVE_GNUC_ECGS_2_8
431      signal(SIGRTMAX,&signal_fatal_handler);
432 #   endif
433 #  else
434     signal(SIGRTMAX,&signal_fatal_handler);
435 #  endif
436 # endif
437       }
438 #endif
439 
440 #ifdef HAVE_FPU_ENABLE_INTERRUPTS
441 
442 #  ifdef HAVE_FPU_SETCW
443 #     include <fpu_control.h>
444 #   endif
445 
446 #  ifdef HAVE_HANDLE_SIGFPES
447 #     include <sigfpe.h>
448 #  endif
449 
fpu_enable_interrupts(void)450 void fpu_enable_interrupts(void)
451    {
452 
453 #  ifdef HAVE_FPU_SETCW
454    unsigned int mask = _FPU_MASK_IM |
455                        _FPU_MASK_DM |
456                        _FPU_MASK_ZM |
457 _FPU_MASK_PM |
458 _FPU_MASK_UM |
459                        _FPU_MASK_OM ;
460    mask=~mask & _FPU_DEFAULT;
461    _FPU_SETCW(mask);
462 #  endif
463 
464 #  ifdef HAVE_HANDLE_SIGFPES
465    sigfpe_[_UNDERFL].abort   =1;
466    sigfpe_[_OVERFL].abort    =1;
467    sigfpe_[_INVALID].abort   =1;
468    sigfpe_[_INT_OVERFL].abort=1;
469    sigfpe_[_DIVZERO].abort   =1;
470 
471    unsigned int mask = /* _EN_UNDERFL | */
472                        _EN_OVERFL  |
473                        _EN_DIVZERO |
474                        _EN_INVALID |
475                        _EN_INT_OVERFL;
476    handle_sigfpes(_ON,mask,0,0,0);
477 
478    }
479 
480 # endif
481 
482 #endif
483 
484 
485