• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

  • tdecore
kcrash.cpp
1 /*
2  * This file is part of the KDE Libraries
3  * Copyright (C) 2000 Timo Hummel <timo.hummel@sap.com>
4  * Tom Braun <braunt@fh-konstanz.de>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB. If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 /*
23  * This file is used to catch signals which would normally
24  * crash the application (like segmentation fault, floating
25  * point exception and such).
26  */
27 
28 #include "config.h"
29 
30 #include <string.h>
31 #include <signal.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <time.h>
36 #include "kcrash.h"
37 
38 #include <sys/types.h>
39 #include <sys/time.h>
40 #include <sys/resource.h>
41 #include <sys/wait.h>
42 #include <sys/un.h>
43 #include <sys/socket.h>
44 #include <errno.h>
45 
46 #include <tqwindowdefs.h>
47 #include <tdeglobal.h>
48 #include <kinstance.h>
49 #include <tdeaboutdata.h>
50 #include <kdebug.h>
51 #include <tdeapplication.h>
52 #include <dcopclient.h>
53 
54 #include <../tdeinit/tdelauncher_cmds.h>
55 
56 #if defined Q_WS_X11
57 #include <X11/Xlib.h>
58 #endif
59 
60 TDECrash::HandlerType TDECrash::_emergencySaveFunction = 0;
61 TDECrash::HandlerType TDECrash::_crashHandler = 0;
62 const char *TDECrash::appName = 0;
63 const char *TDECrash::appPath = 0;
64 bool TDECrash::safer = false;
65 
66 // This function sets the function which should be called when the
67 // application crashes and the
68 // application is asked to try to save its data.
69 void
70 TDECrash::setEmergencySaveFunction (HandlerType saveFunction)
71 {
72  _emergencySaveFunction = saveFunction;
73 
74  /*
75  * We need at least the default crash handler for
76  * emergencySaveFunction to be called
77  */
78  if (_emergencySaveFunction && !_crashHandler)
79  _crashHandler = defaultCrashHandler;
80 }
81 
82 
83 // This function sets the function which should be responsible for
84 // the application crash handling.
85 void
86 TDECrash::setCrashHandler (HandlerType handler)
87 {
88 #ifdef Q_OS_UNIX
89  if (!handler)
90  handler = SIG_DFL;
91 
92  sigset_t mask;
93  sigemptyset(&mask);
94 
95 #ifdef SIGSEGV
96  signal (SIGSEGV, handler);
97  sigaddset(&mask, SIGSEGV);
98 #endif
99 #ifdef SIGFPE
100  signal (SIGFPE, handler);
101  sigaddset(&mask, SIGFPE);
102 #endif
103 #ifdef SIGILL
104  signal (SIGILL, handler);
105  sigaddset(&mask, SIGILL);
106 #endif
107 #ifdef SIGABRT
108  signal (SIGABRT, handler);
109  sigaddset(&mask, SIGABRT);
110 #endif
111 
112  sigprocmask(SIG_UNBLOCK, &mask, 0);
113 #endif //Q_OS_UNIX
114 
115  _crashHandler = handler;
116 }
117 
118 void
119 TDECrash::defaultCrashHandler (int sig)
120 {
121 #ifdef Q_OS_UNIX
122  // WABA: Do NOT use kdDebug() in this function because it is much too risky!
123  // Handle possible recursions
124  static int crashRecursionCounter = 0;
125  crashRecursionCounter++; // Nothing before this, please !
126 
127  signal(SIGALRM, SIG_DFL);
128  alarm(3); // Kill me... (in case we deadlock in malloc)
129 
130  if (crashRecursionCounter < 2) {
131  if (_emergencySaveFunction) {
132  _emergencySaveFunction (sig);
133  }
134  crashRecursionCounter++; //
135  }
136 
137  // Close all remaining file descriptors except for stdin/stdout/stderr
138  struct rlimit rlp;
139  getrlimit(RLIMIT_NOFILE, &rlp);
140  for (int i = 3; i < (int)rlp.rlim_cur; i++)
141  close(i);
142 
143 
144  // this code is leaking, but this should not hurt cause we will do a
145  // exec() afterwards. exec() is supposed to clean up.
146  if (crashRecursionCounter < 3)
147  {
148  if (appName)
149  {
150 #ifndef NDEBUG
151  fprintf(stderr, "[kcrash] TDECrash: crashing... crashRecursionCounter = %d\n", crashRecursionCounter);
152  fprintf(stderr, "[kcrash] TDECrash: Application Name = %s path = %s pid = %d\n", appName ? appName : "<unknown>" , appPath ? appPath : "<unknown>", getpid());
153 #else
154  fprintf(stderr, "[kcrash] TDECrash: Application '%s' crashing...\n", appName ? appName : "<unknown>");
155 #endif
156 
157  const char * argv[24]; // don't forget to update this
158  int i = 0;
159 
160  // argument 0 has to be drkonqi
161  argv[i++] = "drkonqi";
162 
163 #if defined Q_WS_X11
164  // start up on the correct display
165  argv[i++] = "-display";
166  if ( tqt_xdisplay() )
167  argv[i++] = XDisplayString(tqt_xdisplay());
168  else
169  argv[i++] = getenv("DISPLAY");
170 #elif defined(Q_WS_QWS)
171  // start up on the correct display
172  argv[i++] = "-display";
173  argv[i++] = getenv("QWS_DISPLAY");
174 #endif
175 
176  // we have already tested this
177  argv[i++] = "--appname";
178  argv[i++] = appName;
179  if (TDEApplication::loadedByKdeinit)
180  argv[i++] = "--tdeinit";
181 
182  // only add apppath if it's not NULL
183  if (appPath) {
184  argv[i++] = "--apppath";
185  argv[i++] = appPath;
186  }
187 
188  // signal number -- will never be NULL
189  char sigtxt[ 10 ];
190  sprintf( sigtxt, "%d", sig );
191  argv[i++] = "--signal";
192  argv[i++] = sigtxt;
193 
194  char pidtxt[ 10 ];
195  sprintf( pidtxt, "%d", getpid());
196  argv[i++] = "--pid";
197  argv[i++] = pidtxt;
198 
199  const TDEInstance *instance = TDEGlobal::_instance;
200  const TDEAboutData *about = instance ? instance->aboutData() : 0;
201  if (about) {
202  if (about->internalVersion()) {
203  argv[i++] = "--appversion";
204  argv[i++] = about->internalVersion();
205  }
206 
207  if (about->internalProgramName()) {
208  argv[i++] = "--programname";
209  argv[i++] = about->internalProgramName();
210  }
211 
212  if (about->internalBugAddress()) {
213  argv[i++] = "--bugaddress";
214  argv[i++] = about->internalBugAddress();
215  }
216  }
217 
218  if ( kapp && !kapp->startupId().isNull()) {
219  argv[i++] = "--startupid";
220  argv[i++] = kapp->startupId().data();
221  }
222 
223  if ( safer )
224  argv[i++] = "--safer";
225 
226  // NULL terminated list
227  argv[i] = NULL;
228 
229  startDrKonqi( argv, i );
230  _exit(253);
231 
232  }
233  else {
234  fprintf(stderr, "[kcrash] Unknown appname\n");
235  }
236  }
237 
238  if (crashRecursionCounter < 4)
239  {
240  fprintf(stderr, "[kcrash] Unable to start Dr. Konqi\n");
241  }
242 #endif //Q_OS_UNIX
243 
244  _exit(255);
245 }
246 
247 #ifdef Q_OS_UNIX
248 
249 // Since we can't fork() in the crashhandler, we cannot execute any external code
250 // (there can be functions registered to be performed before fork(), for example
251 // handling of malloc locking, which doesn't work when malloc crashes because of heap corruption).
252 
253 static int write_socket(int sock, char *buffer, int len);
254 static int read_socket(int sock, char *buffer, int len);
255 static int openSocket();
256 
257 void TDECrash::startDrKonqi( const char* argv[], int argc )
258 {
259  int socket = openSocket();
260  if( socket < -1 )
261  {
262  startDirectly( argv, argc );
263  return;
264  }
265  tdelauncher_header header;
266  header.cmd = LAUNCHER_EXEC_NEW;
267  const int BUFSIZE = 8192; // make sure this is big enough
268  char buffer[ BUFSIZE + 10 ];
269  int pos = 0;
270  long argcl = argc;
271  memcpy( buffer + pos, &argcl, sizeof( argcl ));
272  pos += sizeof( argcl );
273  for( int i = 0;
274  i < argc;
275  ++i )
276  {
277  int len = strlen( argv[ i ] ) + 1; // include terminating \0
278  if( pos + len > BUFSIZE )
279  {
280  fprintf( stderr, "[kcrash] BUFSIZE in TDECrash not big enough!\n" );
281  startDirectly( argv, argc );
282  return;
283  }
284  memcpy( buffer + pos, argv[ i ], len );
285  pos += len;
286  }
287  long env = 0;
288  memcpy( buffer + pos, &env, sizeof( env ));
289  pos += sizeof( env );
290  long avoid_loops = 0;
291  memcpy( buffer + pos, &avoid_loops, sizeof( avoid_loops ));
292  pos += sizeof( avoid_loops );
293  header.arg_length = pos;
294  write_socket(socket, (char *) &header, sizeof(header));
295  write_socket(socket, buffer, pos);
296  if( read_socket( socket, (char *) &header, sizeof(header)) < 0
297  || header.cmd != LAUNCHER_OK )
298  {
299  startDirectly( argv, argc );
300  return;
301  }
302  long pid;
303  read_socket(socket, buffer, header.arg_length);
304  pid = *((long *) buffer);
305 
306  alarm(0); // Seems we made it....
307 
308  for(;;)
309  {
310  if( kill( pid, 0 ) < 0 )
311  _exit(253);
312  sleep(1);
313  // the debugger should stop this process anyway
314  }
315 }
316 
317 // If we can't reach tdeinit we can still at least try to fork()
318 void TDECrash::startDirectly( const char* argv[], int )
319 {
320  fprintf( stderr, "[kcrash] TDECrash cannot reach tdeinit, launching directly.\n" );
321  pid_t pid = fork();
322  if (pid <= 0)
323  {
324  if(!geteuid() && setgid(getgid()) < 0)
325  _exit(253);
326  if(!geteuid() && setuid(getuid()) < 0)
327  _exit(253);
328  execvp("drkonqi", const_cast< char** >( argv ));
329  _exit(errno);
330  }
331  else
332  {
333  alarm(0); // Seems we made it....
334  // wait for child to exit
335  waitpid(pid, NULL, 0);
336  _exit(253);
337  }
338 }
339 
340 // From now on this code is copy&pasted from tdeinit/wrapper.c :
341 
342 extern char **environ;
343 
344 static char *getDisplay()
345 {
346  const char *display;
347  char *result;
348  char *screen;
349  char *colon;
350  char *i;
351 /*
352  don't test for a value from tqglobal.h but instead distinguish
353  Qt/X11 from Qt/Embedded by the fact that Qt/E apps have -DQWS
354  on the commandline (which in tqglobal.h however triggers Q_WS_QWS,
355  but we don't want to include that here) (Simon)
356 #ifdef Q_WS_X11
357  */
358 #if !defined(QWS)
359  display = getenv("DISPLAY");
360 #else
361  display = getenv("QWS_DISPLAY");
362 #endif
363  if (!display || !*display)
364  {
365  display = ":0";
366  }
367  result = (char*)malloc(strlen(display)+1);
368  if (result == NULL)
369  return NULL;
370 
371  strcpy(result, display);
372  screen = strrchr(result, '.');
373  colon = strrchr(result, ':');
374  if (screen && (screen > colon))
375  *screen = '\0';
376  while((i = strchr(result, ':')))
377  *i = '_';
378  return result;
379 }
380 
381 /*
382  * Write 'len' bytes from 'buffer' into 'sock'.
383  * returns 0 on success, -1 on failure.
384  */
385 static int write_socket(int sock, char *buffer, int len)
386 {
387  ssize_t result;
388  int bytes_left = len;
389  while ( bytes_left > 0)
390  {
391  result = write(sock, buffer, bytes_left);
392  if (result > 0)
393  {
394  buffer += result;
395  bytes_left -= result;
396  }
397  else if (result == 0)
398  return -1;
399  else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
400  return -1;
401  }
402  return 0;
403 }
404 
405 /*
406  * Read 'len' bytes from 'sock' into 'buffer'.
407  * returns 0 on success, -1 on failure.
408  */
409 static int read_socket(int sock, char *buffer, int len)
410 {
411  ssize_t result;
412  int bytes_left = len;
413  while ( bytes_left > 0)
414  {
415  result = read(sock, buffer, bytes_left);
416  if (result > 0)
417  {
418  buffer += result;
419  bytes_left -= result;
420  }
421  else if (result == 0)
422  return -1;
423  else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
424  return -1;
425  }
426  return 0;
427 }
428 
429 static int openSocket()
430 {
431  kde_socklen_t socklen;
432  int s;
433  struct sockaddr_un server;
434 #define MAX_SOCK_FILE 255
435  char sock_file[MAX_SOCK_FILE + 1];
436  const char *home_dir = getenv("HOME");
437  const char *kde_home = getenv("TDEHOME");
438  char *display;
439 
440  sock_file[0] = sock_file[MAX_SOCK_FILE] = 0;
441 
442  if (!kde_home || !kde_home[0])
443  {
444  kde_home = "~/.trinity/";
445  }
446 
447  if (kde_home[0] == '~')
448  {
449  if (!home_dir || !home_dir[0])
450  {
451  fprintf(stderr, "[kcrash] Warning: $HOME not set!\n");
452  return -1;
453  }
454  if (strlen(home_dir) > (MAX_SOCK_FILE-100))
455  {
456  fprintf(stderr, "[kcrash] Warning: Home directory path too long!\n");
457  return -1;
458  }
459  kde_home++;
460  strncpy(sock_file, home_dir, MAX_SOCK_FILE);
461  }
462  strncat(sock_file, kde_home, MAX_SOCK_FILE - strlen(sock_file));
463 
465  if ( sock_file[strlen(sock_file)-1] == '/')
466  sock_file[strlen(sock_file)-1] = 0;
467 
468  strncat(sock_file, "/socket-", MAX_SOCK_FILE - strlen(sock_file));
469  if( getenv("XAUTHLOCALHOSTNAME"))
470  strncat(sock_file, getenv("XAUTHLOCALHOSTNAME"), MAX_SOCK_FILE - strlen(sock_file) - 1);
471  else if (gethostname(sock_file+strlen(sock_file), MAX_SOCK_FILE - strlen(sock_file) - 1) != 0)
472  {
473  perror("[kcrash] Warning: Could not determine hostname: ");
474  return -1;
475  }
476  sock_file[sizeof(sock_file)-1] = '\0';
477 
478  /* append $DISPLAY */
479  display = getDisplay();
480  if (display == NULL)
481  {
482  fprintf(stderr, "[kcrash] Error: Could not determine display.\n");
483  return -1;
484  }
485 
486  if (strlen(sock_file)+strlen(display)+strlen("/tdeinit_")+2 > MAX_SOCK_FILE)
487  {
488  fprintf(stderr, "[kcrash] Warning: Socket name will be too long.\n");
489  free(display);
490  return -1;
491  }
492  strcat(sock_file, "/tdeinit_");
493  strcat(sock_file, display);
494  free(display);
495 
496  if (strlen(sock_file) >= sizeof(server.sun_path))
497  {
498  fprintf(stderr, "[kcrash] Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n");
499  return -1;
500  }
501 
502  /*
503  * create the socket stream
504  */
505  s = socket(PF_UNIX, SOCK_STREAM, 0);
506  if (s < 0)
507  {
508  perror("[kcrash] Warning: socket creation failed: ");
509  return -1;
510  }
511 
512  server.sun_family = AF_UNIX;
513  strcpy(server.sun_path, sock_file);
514  socklen = sizeof(server);
515  if(connect(s, (struct sockaddr *)&server, socklen) == -1)
516  {
517  perror("[kcrash] Warning: socket connection failed: ");
518  close(s);
519  return -1;
520  }
521  return s;
522 }
523 
524 #endif // Q_OS_UNIX
TDECrash::_crashHandler
static HandlerType _crashHandler
Pointer to the crash handler.
Definition: kcrash.h:115
TDECrash::setCrashHandler
static void setCrashHandler(HandlerType handler=defaultCrashHandler)
Install a function to be called in case a SIGSEGV is caught.
Definition: kcrash.cpp:86
TDEAboutData
This class is used to store information about a program.
Definition: tdeaboutdata.h:182
TDEInstance::aboutData
const TDEAboutData * aboutData() const
Returns the about data of this instance Warning, can be 0L.
Definition: kinstance.cpp:314
TDECrash::_emergencySaveFunction
static HandlerType _emergencySaveFunction
Pointer to the emergency save function.
Definition: kcrash.h:119
TDECrash::setEmergencySaveFunction
static void setEmergencySaveFunction(HandlerType saveFunction=(HandlerType) 0)
Installs a function which should try to save the applications data.
Definition: kcrash.cpp:70
TDECrash::HandlerType
void(* HandlerType)(int)
This function type is a pointer to a crash handler function.
Definition: kcrash.h:55
TDECrash::defaultCrashHandler
static void defaultCrashHandler(int signal)
The default crash handler.
Definition: kcrash.cpp:119
KStdAction::close
TDEAction * close(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
TDEInstance
Access to KDE global objects for use in shared libraries.
Definition: kinstance.h:47

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.8.8
This website is maintained by Timothy Pearson.