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

tdecore

  • tdecore
tdecrash.cpp
1/*
2 * This file is part of the TDE 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 "tdecrash.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 TQ_WS_X11
57#include <X11/Xlib.h>
58#endif
59
60TDECrash::HandlerType TDECrash::_emergencySaveFunction = 0;
61TDECrash::HandlerType TDECrash::_crashHandler = 0;
62const char *TDECrash::appName = 0;
63const char *TDECrash::appPath = 0;
64bool 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.
69void
70TDECrash::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.
85void
86TDECrash::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
118void
119TDECrash::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, "[tdecrash] TDECrash: crashing... crashRecursionCounter = %d\n", crashRecursionCounter);
152 fprintf(stderr, "[tdecrash] TDECrash: Application Name = %s path = %s pid = %d\n", appName ? appName : "<unknown>" , appPath ? appPath : "<unknown>", getpid());
153#else
154 fprintf(stderr, "[tdecrash] 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 TQ_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(TQ_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 ( tdeApp && !tdeApp->startupId().isNull()) {
219 argv[i++] = "--startupid";
220 argv[i++] = tdeApp->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, "[tdecrash] Unknown appname\n");
235 }
236 }
237
238 if (crashRecursionCounter < 4)
239 {
240 fprintf(stderr, "[tdecrash] 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
253static int write_socket(int sock, char *buffer, int len);
254static int read_socket(int sock, char *buffer, int len);
255static int openSocket();
256
257void 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, "[tdecrash] 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()
318void TDECrash::startDirectly( const char* argv[], int )
319{
320 fprintf( stderr, "[tdecrash] 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
342extern char **environ;
343
344static 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 TQ_WS_QWS,
355 but we don't want to include that here) (Simon)
356#ifdef TQ_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 */
385static 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 */
409static 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
429static 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, "[tdecrash] Warning: $HOME not set!\n");
452 return -1;
453 }
454 if (strlen(home_dir) > (MAX_SOCK_FILE-100))
455 {
456 fprintf(stderr, "[tdecrash] 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("[tdecrash] 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, "[tdecrash] 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, "[tdecrash] 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, "[tdecrash] 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("[tdecrash] 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("[tdecrash] Warning: socket connection failed: ");
518 close(s);
519 return -1;
520 }
521 return s;
522}
523
524#endif // Q_OS_UNIX
TDEAboutData
This class is used to store information about a program.
Definition: tdeaboutdata.h:183
TDECrash::_crashHandler
static HandlerType _crashHandler
Pointer to the crash handler.
Definition: tdecrash.h:115
TDECrash::HandlerType
void(* HandlerType)(int)
This function type is a pointer to a crash handler function.
Definition: tdecrash.h:55
TDECrash::setEmergencySaveFunction
static void setEmergencySaveFunction(HandlerType saveFunction=(HandlerType) 0)
Installs a function which should try to save the applications data.
Definition: tdecrash.cpp:70
TDECrash::defaultCrashHandler
static void defaultCrashHandler(int signal)
The default crash handler.
Definition: tdecrash.cpp:119
TDECrash::_emergencySaveFunction
static HandlerType _emergencySaveFunction
Pointer to the emergency save function.
Definition: tdecrash.h:119
TDECrash::setCrashHandler
static void setCrashHandler(HandlerType handler=defaultCrashHandler)
Install a function to be called in case a SIGSEGV is caught.
Definition: tdecrash.cpp:86
TDEInstance
Access to KDE global objects for use in shared libraries.
Definition: kinstance.h:48
TDEInstance::aboutData
const TDEAboutData * aboutData() const
Returns the about data of this instance Warning, can be 0L.
Definition: kinstance.cpp:336
KStdAction::close
TDEAction * close(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)

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
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.9.4
This website is maintained by Timothy Pearson.