/* monitor.c - monitors the wmaker process * * Window Maker window manager * * Copyright (c) 1997-2004 Alfredo K. Kojima * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "wconfig.h" #include #include #include #include #include #ifdef __FreeBSD__ #include #endif #include #include #include #include "WindowMaker.h" #include "screen.h" #include "window.h" #include "dialog.h" #include "main.h" #include "funcs.h" /****** Global Variables ******/ extern WPreferences wPreferences; static int showCrashDialog(int sig) { int crashAction; dpy = XOpenDisplay(NULL); if (dpy) { /* XXX TODO make sure that window states are saved and restored via netwm */ XGrabServer(dpy); crashAction = wShowCrashingDialogPanel(sig); XCloseDisplay(dpy); dpy = NULL; } else { werror(_("cannot open connection for crashing dialog panel. Aborting.")); crashAction = WMAbort; } if (crashAction == WMStartAlternate) { int i; wmessage(_("trying to start alternate window manager...")); for (i = 0; i < WMGetArrayItemCount(wPreferences.fallbackWMs); i++) { Restart(WMGetFromArray(wPreferences.fallbackWMs, i), False); } wfatal(_("failed to start alternate window manager. Aborting.")); return 0; } else if (crashAction == WMAbort) return 0; else return 1; } int MonitorLoop(int argc, char **argv) { pid_t pid, exited; char **child_argv = wmalloc(sizeof(char *) * (argc + 2)); int i, status; time_t last_start; Bool error = False; for (i = 0; i < argc; i++) child_argv[i] = argv[i]; child_argv[i++] = "--for-real"; child_argv[i] = NULL; for (;;) { last_start = time(NULL); /* Start Window Maker */ pid = fork(); if (pid == 0) { execvp(child_argv[0], child_argv); werror(_("Error respawning Window Maker")); exit(1); } else if (pid < 0) { werror(_("Error respawning Window Maker")); exit(1); } do { if ((exited = waitpid(-1, &status, 0)) < 0) { werror(_("Error during monitoring of Window Maker process.")); error = True; break; } } while (exited != pid); if (error) break; child_argv[argc] = "--for-real-"; /* Check if the wmaker process exited due to a crash */ if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGSEGV || WTERMSIG(status) == SIGBUS || WTERMSIG(status) == SIGILL || WTERMSIG(status) == SIGABRT || WTERMSIG(status) == SIGFPE)) { /* If so, we check when was the last restart. * If it was less than 3s ago, it's a bad sign, so we show * the crash panel and ask the user what to do */ if (time(NULL) - last_start < 3) { if (showCrashDialog(WTERMSIG(status)) == 0) { return 1; } } wwarning(_("Window Maker exited due to a crash (signal %i) and will be restarted."), WTERMSIG(status)); } else break; } return 0; }