summaryrefslogtreecommitdiffstats
path: root/x11vnc/cleanup.c
diff options
context:
space:
mode:
authorrunge <runge>2006-01-09 01:54:38 +0000
committerrunge <runge>2006-01-09 01:54:38 +0000
commit71f2ec79180185a6c3db0c87f9d53c491dc31e76 (patch)
tree67c341571cbeb1bd9a0744cc8eb03b30ef04f381 /x11vnc/cleanup.c
parentdef301266373e462f4a5e90eab443087ccfc7ccc (diff)
downloadlibtdevnc-71f2ec79180185a6c3db0c87f9d53c491dc31e76.tar.gz
libtdevnc-71f2ec79180185a6c3db0c87f9d53c491dc31e76.zip
x11vnc: the big split.
Diffstat (limited to 'x11vnc/cleanup.c')
-rw-r--r--x11vnc/cleanup.c427
1 files changed, 427 insertions, 0 deletions
diff --git a/x11vnc/cleanup.c b/x11vnc/cleanup.c
new file mode 100644
index 0000000..f8c4ae4
--- /dev/null
+++ b/x11vnc/cleanup.c
@@ -0,0 +1,427 @@
+/* -- cleanup.c -- */
+
+#include "x11vnc.h"
+#include "xwrappers.h"
+#include "xdamage.h"
+#include "remote.h"
+#include "keyboard.h"
+#include "scan.h"
+#include "gui.h"
+#include "solid.h"
+
+/*
+ * Exiting and error handling routines
+ */
+
+int trapped_xerror = 0;
+int trapped_xioerror = 0;
+int trapped_getimage_xerror = 0;
+int trapped_record_xerror = 0;
+XErrorEvent *trapped_xerror_event;
+
+/* XXX CHECK BEFORE RELEASE */
+int crash_debug = 0;
+
+void clean_shm(int quick);
+void clean_up_exit (int ret);
+int trap_xerror(Display *d, XErrorEvent *error);
+int trap_xioerror(Display *d);
+int trap_getimage_xerror(Display *d, XErrorEvent *error);
+char *xerror_string(XErrorEvent *error);
+void initialize_crash_handler(void);
+void initialize_signals(void);
+int known_sigpipe_mode(char *s);
+
+
+static int exit_flag = 0;
+static int exit_sig = 0;
+
+static void clean_icon_mode(void);
+static int Xerror(Display *d, XErrorEvent *error);
+static int XIOerr(Display *d);
+static void crash_shell_help(void);
+static void crash_shell(void);
+static void interrupted (int sig);
+
+
+void clean_shm(int quick) {
+ int i, cnt = 0;
+
+ if (raw_fb) quick = 1; /* raw_fb hack */
+
+ /*
+ * to avoid deadlock, etc, under quick=1 we just delete the shm
+ * areas and leave the X stuff hanging.
+ */
+ if (quick) {
+ shm_delete(&scanline_shm);
+ shm_delete(&fullscreen_shm);
+ shm_delete(&snaprect_shm);
+ } else {
+ shm_clean(&scanline_shm, scanline);
+ shm_clean(&fullscreen_shm, fullscreen);
+ shm_clean(&snaprect_shm, snaprect);
+ }
+
+ /*
+ * Here we have to clean up quite a few shm areas for all
+ * the possible tile row runs (40 for 1280), not as robust
+ * as one might like... sometimes need to run ipcrm(1).
+ */
+ for(i=1; i<=ntiles_x; i++) {
+ if (i > tile_shm_count) {
+ break;
+ }
+ if (quick) {
+ shm_delete(&tile_row_shm[i]);
+ } else {
+ shm_clean(&tile_row_shm[i], tile_row[i]);
+ }
+ cnt++;
+ if (single_copytile_count && i >= single_copytile_count) {
+ break;
+ }
+ }
+ if (!quiet) {
+ rfbLog("deleted %d tile_row polling images.\n", cnt);
+ }
+}
+
+static void clean_icon_mode(void) {
+ if (icon_mode && icon_mode_fh) {
+ fprintf(icon_mode_fh, "quit\n");
+ fflush(icon_mode_fh);
+ fclose(icon_mode_fh);
+ icon_mode_fh = NULL;
+ if (icon_mode_file) {
+ unlink(icon_mode_file);
+ icon_mode_file = NULL;
+ }
+ }
+}
+
+/*
+ * Normal exiting
+ */
+void clean_up_exit (int ret) {
+ exit_flag = 1;
+
+ if (icon_mode) {
+ clean_icon_mode();
+ }
+
+ /* remove the shm areas: */
+ clean_shm(0);
+
+ if (! dpy) exit(ret); /* raw_rb hack */
+
+ /* X keyboard cleanups */
+ delete_added_keycodes(0);
+
+ if (clear_mods == 1) {
+ clear_modifiers(0);
+ } else if (clear_mods == 2) {
+ clear_keys();
+ }
+
+ if (no_autorepeat) {
+ autorepeat(1, 0);
+ }
+ if (use_solid_bg) {
+ solid_bg(1);
+ }
+ X_LOCK;
+ XTestDiscard_wr(dpy);
+#if LIBVNCSERVER_HAVE_LIBXDAMAGE
+ if (xdamage) {
+ XDamageDestroy(dpy, xdamage);
+ }
+#endif
+#if LIBVNCSERVER_HAVE_LIBXTRAP
+ if (trap_ctx) {
+ XEFreeTC(trap_ctx);
+ }
+#endif
+ /* XXX rdpy_ctrl, etc. cannot close w/o blocking */
+ XCloseDisplay(dpy);
+ X_UNLOCK;
+
+ fflush(stderr);
+ exit(ret);
+}
+
+/* X11 error handlers */
+
+static XErrorHandler Xerror_def;
+static XIOErrorHandler XIOerr_def;
+
+int trap_xerror(Display *d, XErrorEvent *error) {
+ trapped_xerror = 1;
+ trapped_xerror_event = error;
+
+ if (d) {} /* unused vars warning: */
+
+ return 0;
+}
+
+int trap_xioerror(Display *d) {
+ trapped_xioerror = 1;
+
+ if (d) {} /* unused vars warning: */
+
+ return 0;
+}
+
+int trap_getimage_xerror(Display *d, XErrorEvent *error) {
+ trapped_getimage_xerror = 1;
+ trapped_xerror_event = error;
+
+ if (d) {} /* unused vars warning: */
+
+ return 0;
+}
+
+static int Xerror(Display *d, XErrorEvent *error) {
+ X_UNLOCK;
+ interrupted(0);
+
+ if (d) {} /* unused vars warning: */
+
+ return (*Xerror_def)(d, error);
+}
+
+static int XIOerr(Display *d) {
+ X_UNLOCK;
+ interrupted(-1);
+
+ if (d) {} /* unused vars warning: */
+
+ return (*XIOerr_def)(d);
+}
+
+static char *xerrors[] = {
+ "Success",
+ "BadRequest",
+ "BadValue",
+ "BadWindow",
+ "BadPixmap",
+ "BadAtom",
+ "BadCursor",
+ "BadFont",
+ "BadMatch",
+ "BadDrawable",
+ "BadAccess",
+ "BadAlloc",
+ "BadColor",
+ "BadGC",
+ "BadIDChoice",
+ "BadName",
+ "BadLength",
+ "BadImplementation",
+ "unknown"
+};
+static int xerrors_max = BadImplementation;
+
+char *xerror_string(XErrorEvent *error) {
+ int index = -1;
+ if (error) {
+ index = (int) error->error_code;
+ }
+ if (0 <= index && index <= xerrors_max) {
+ return xerrors[index];
+ } else {
+ return xerrors[xerrors_max+1];
+ }
+}
+
+static char *crash_stack_command1 = NULL;
+static char *crash_stack_command2 = NULL;
+static char *crash_debug_command = NULL;
+
+void initialize_crash_handler(void) {
+ int pid = program_pid;
+ crash_stack_command1 = (char *) malloc(1000);
+ crash_stack_command2 = (char *) malloc(1000);
+ crash_debug_command = (char *) malloc(1000);
+
+ snprintf(crash_stack_command1, 500, "echo where > /tmp/gdb.%d;"
+ " env PATH=$PATH:/usr/local/bin:/usr/sfw/bin:/usr/bin"
+ " gdb -x /tmp/gdb.%d -batch -n %s %d;"
+ " rm -f /tmp/gdb.%d", pid, pid, program_name, pid, pid);
+ snprintf(crash_stack_command2, 500, "pstack %d", program_pid);
+
+ snprintf(crash_debug_command, 500, "gdb %s %d", program_name, pid);
+}
+
+static void crash_shell_help(void) {
+ int pid = program_pid;
+ fprintf(stderr, "\n");
+ fprintf(stderr, " *** Welcome to the x11vnc crash shell! ***\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "PROGRAM: %s PID: %d\n", program_name, pid);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "POSSIBLE DEBUGGER COMMAND:\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " %s\n", crash_debug_command);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Press \"q\" to quit.\n");
+ fprintf(stderr, "Press \"h\" or \"?\" for this help.\n");
+ fprintf(stderr, "Press \"s\" to try to run some commands to"
+ " show a stack trace (gdb/pstack).\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Anything else is passed to -Q query function.\n");
+ fprintf(stderr, "\n");
+}
+
+static void crash_shell(void) {
+ char qry[1000], cmd[1000], line[1000];
+ char *str, *p;
+
+ crash_shell_help();
+ fprintf(stderr, "\ncrash> ");
+ while (fgets(line, 1000, stdin) != NULL) {
+ str = lblanks(line);
+
+ p = str;
+ while(*p) {
+ if (*p == '\n') {
+ *p = '\0';
+ }
+ p++;
+ }
+
+ if (*str == 'q' && *(str+1) == '\0') {
+ fprintf(stderr, "quiting.\n");
+ return;
+ } else if (*str == 'h' && *(str+1) == '\0') {
+ crash_shell_help();
+ } else if (*str == '?' && *(str+1) == '\0') {
+ crash_shell_help();
+ } else if (*str == 's' && *(str+1) == '\0') {
+ sprintf(cmd, "sh -c '(%s) &'", crash_stack_command1);
+ fprintf(stderr, "\nrunning:\n\t%s\n\n",
+ crash_stack_command1);
+ system(cmd);
+ usleep(1000*1000);
+
+ sprintf(cmd, "sh -c '(%s) &'", crash_stack_command2);
+ fprintf(stderr, "\nrunning:\n\t%s\n\n",
+ crash_stack_command2);
+ system(cmd);
+ usleep(1000*1000);
+ } else {
+ snprintf(qry, 1000, "qry=%s", str);
+ p = process_remote_cmd(qry, 1);
+ fprintf(stderr, "\n\nresult:\n%s\n", p);
+ free(p);
+ }
+
+ fprintf(stderr, "crash> ");
+ }
+}
+
+/*
+ * General problem handler
+ */
+static void interrupted (int sig) {
+ exit_sig = sig;
+ if (exit_flag) {
+ exit_flag++;
+ if (use_threads) {
+ usleep2(250 * 1000);
+ } else if (exit_flag <= 2) {
+ return;
+ }
+ exit(4);
+ }
+ exit_flag++;
+ if (sig == 0) {
+ fprintf(stderr, "caught X11 error:\n");
+ } else if (sig == -1) {
+ fprintf(stderr, "caught XIO error:\n");
+ } else {
+ fprintf(stderr, "caught signal: %d\n", sig);
+ }
+ if (sig == SIGINT) {
+ shut_down = 1;
+ return;
+ }
+
+ X_UNLOCK;
+
+ if (icon_mode) {
+ clean_icon_mode();
+ }
+ /* remove the shm areas with quick=1: */
+ clean_shm(1);
+
+ if (sig == -1) {
+ /* not worth trying any more cleanup, X server probably gone */
+ exit(3);
+ }
+
+ /* X keyboard cleanups */
+ delete_added_keycodes(0);
+
+ if (clear_mods == 1) {
+ clear_modifiers(0);
+ } else if (clear_mods == 2) {
+ clear_keys();
+ }
+ if (no_autorepeat) {
+ autorepeat(1, 0);
+ }
+ if (use_solid_bg) {
+ solid_bg(1);
+ }
+
+ if (crash_debug) {
+ crash_shell();
+ }
+
+ if (sig) {
+ exit(2);
+ }
+}
+
+/* signal handlers */
+void initialize_signals(void) {
+ signal(SIGHUP, interrupted);
+ signal(SIGINT, interrupted);
+ signal(SIGQUIT, interrupted);
+ signal(SIGABRT, interrupted);
+ signal(SIGTERM, interrupted);
+ signal(SIGBUS, interrupted);
+ signal(SIGSEGV, interrupted);
+ signal(SIGFPE, interrupted);
+
+ if (!sigpipe || *sigpipe == '\0' || !strcmp(sigpipe, "skip")) {
+ ;
+ } else if (!strcmp(sigpipe, "ignore")) {
+#ifdef SIG_IGN
+ signal(SIGPIPE, SIG_IGN);
+#endif
+ } else if (!strcmp(sigpipe, "exit")) {
+ rfbLog("initialize_signals: will exit on SIGPIPE\n");
+ signal(SIGPIPE, interrupted);
+ }
+
+ X_LOCK;
+ Xerror_def = XSetErrorHandler(Xerror);
+ XIOerr_def = XSetIOErrorHandler(XIOerr);
+ X_UNLOCK;
+}
+
+int known_sigpipe_mode(char *s) {
+/*
+ * skip, ignore, exit
+ */
+ if (strcmp(s, "skip") && strcmp(s, "ignore") &&
+ strcmp(s, "exit")) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+