Home | History | Annotate | Download | only in x11vnc
      1 /*
      2    Copyright (C) 2002-2010 Karl J. Runge <runge (at) karlrunge.com>
      3    All rights reserved.
      4 
      5 This file is part of x11vnc.
      6 
      7 x11vnc is free software; you can redistribute it and/or modify
      8 it under the terms of the GNU General Public License as published by
      9 the Free Software Foundation; either version 2 of the License, or (at
     10 your option) any later version.
     11 
     12 x11vnc is distributed in the hope that it will be useful,
     13 but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with x11vnc; if not, write to the Free Software
     19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
     20 or see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, as a special exception, Karl J. Runge
     23 gives permission to link the code of its release of x11vnc with the
     24 OpenSSL project's "OpenSSL" library (or with modified versions of it
     25 that use the same license as the "OpenSSL" library), and distribute
     26 the linked executables.  You must obey the GNU General Public License
     27 in all respects for all of the code used other than "OpenSSL".  If you
     28 modify this file, you may extend this exception to your version of the
     29 file, but you are not obligated to do so.  If you do not wish to do
     30 so, delete this exception statement from your version.
     31 */
     32 
     33 /* -- cleanup.c -- */
     34 
     35 #include "x11vnc.h"
     36 #include "xwrappers.h"
     37 #include "xdamage.h"
     38 #include "remote.h"
     39 #include "keyboard.h"
     40 #include "scan.h"
     41 #include "gui.h"
     42 #include "solid.h"
     43 #include "unixpw.h"
     44 #include "sslcmds.h"
     45 #include "sslhelper.h"
     46 #include "connections.h"
     47 #include "macosx.h"
     48 #include "macosxCG.h"
     49 #include "avahi.h"
     50 #include "screen.h"
     51 #include "xrecord.h"
     52 #include "xevents.h"
     53 #include "uinput.h"
     54 
     55 /*
     56  * Exiting and error handling routines
     57  */
     58 
     59 int trapped_xerror = 0;
     60 int trapped_xioerror = 0;
     61 int trapped_getimage_xerror = 0;
     62 int trapped_record_xerror = 0;
     63 XErrorEvent *trapped_xerror_event;
     64 
     65 /* XXX CHECK BEFORE RELEASE */
     66 int crash_debug = 0;
     67 
     68 void clean_shm(int quick);
     69 void clean_up_exit(int ret);
     70 int trap_xerror(Display *d, XErrorEvent *error);
     71 int trap_xioerror(Display *d);
     72 int trap_getimage_xerror(Display *d, XErrorEvent *error);
     73 char *xerror_string(XErrorEvent *error);
     74 void initialize_crash_handler(void);
     75 void initialize_signals(void);
     76 void unset_signals(void);
     77 void close_exec_fds(void);
     78 int known_sigpipe_mode(char *s);
     79 
     80 
     81 static int exit_flag = 0;
     82 static int exit_sig = 0;
     83 
     84 static void clean_icon_mode(void);
     85 static int Xerror(Display *d, XErrorEvent *error);
     86 static int XIOerr(Display *d);
     87 static void crash_shell_help(void);
     88 static void crash_shell(void);
     89 static void interrupted (int sig);
     90 
     91 
     92 void clean_shm(int quick) {
     93 	int i, cnt = 0;
     94 
     95 	/*
     96 	 * to avoid deadlock, etc, under quick=1 we just delete the shm
     97 	 * areas and leave the X stuff hanging.
     98 	 */
     99 	if (quick) {
    100 		shm_delete(&scanline_shm);
    101 		shm_delete(&fullscreen_shm);
    102 		shm_delete(&snaprect_shm);
    103 	} else {
    104 		shm_clean(&scanline_shm, scanline);
    105 		shm_clean(&fullscreen_shm, fullscreen);
    106 		shm_clean(&snaprect_shm, snaprect);
    107 	}
    108 
    109 	/*
    110 	 * Here we have to clean up quite a few shm areas for all
    111 	 * the possible tile row runs (40 for 1280), not as robust
    112 	 * as one might like... sometimes need to run ipcrm(1).
    113 	 */
    114 	for(i=1; i<=ntiles_x; i++) {
    115 		if (i > tile_shm_count) {
    116 			break;
    117 		}
    118 		if (quick) {
    119 			shm_delete(&tile_row_shm[i]);
    120 		} else {
    121 			shm_clean(&tile_row_shm[i], tile_row[i]);
    122 		}
    123 		cnt++;
    124 		if (single_copytile_count && i >= single_copytile_count) {
    125 			break;
    126 		}
    127 	}
    128 	if (!quiet && cnt > 0) {
    129 		rfbLog("deleted %d tile_row polling images.\n", cnt);
    130 	}
    131 }
    132 
    133 static void clean_icon_mode(void) {
    134 	if (icon_mode && icon_mode_fh) {
    135 		fprintf(icon_mode_fh, "quit\n");
    136 		fflush(icon_mode_fh);
    137 		fclose(icon_mode_fh);
    138 		icon_mode_fh = NULL;
    139 		if (icon_mode_file) {
    140 			unlink(icon_mode_file);
    141 			icon_mode_file = NULL;
    142 		}
    143 	}
    144 }
    145 
    146 /*
    147  * Normal exiting
    148  */
    149 void clean_up_exit(int ret) {
    150 	static int depth = 0;
    151 	exit_flag = 1;
    152 
    153 	if (depth++ > 2) {
    154 		exit(ret);
    155 	}
    156 
    157 	if (icon_mode) {
    158 		clean_icon_mode();
    159 	}
    160 
    161 	/* remove the shm areas: */
    162 	clean_shm(0);
    163 
    164 	stop_stunnel();
    165 	if (use_openssl) {
    166 		ssl_helper_pid(0, 0);	/* killall */
    167 	}
    168 
    169 	if (ssh_pid > 0) {
    170 		kill(ssh_pid, SIGTERM);
    171 		ssh_pid = 0;
    172 	}
    173 
    174 #ifdef MACOSX
    175 	if (client_connect_file) {
    176 		if (strstr(client_connect_file, "/tmp/x11vnc-macosx-remote")
    177 		    == client_connect_file) {
    178 			unlink(client_connect_file);
    179 		}
    180 	}
    181 	if (macosx_console) {
    182 		macosxCG_fini();
    183 	}
    184 #endif
    185 
    186 	if (pipeinput_fh != NULL) {
    187 		pclose(pipeinput_fh);
    188 		pipeinput_fh = NULL;
    189 	}
    190 
    191 	shutdown_uinput();
    192 
    193 	if (unix_sock) {
    194 		if (unix_sock_fd >= 0) {
    195 			rfbLog("deleting unix sock: %s\n", unix_sock);
    196 			close(unix_sock_fd);
    197 			unix_sock_fd = -1;
    198 			unlink(unix_sock);
    199 		}
    200 	}
    201 
    202 	if (! dpy) {	/* raw_rb hack */
    203 		if (rm_flagfile) {
    204 			unlink(rm_flagfile);
    205 			rm_flagfile = NULL;
    206 		}
    207 		exit(ret);
    208 	}
    209 
    210 	/* X keyboard cleanups */
    211 	delete_added_keycodes(0);
    212 
    213 	if (clear_mods == 1) {
    214 		clear_modifiers(0);
    215 	} else if (clear_mods == 2) {
    216 		clear_keys();
    217 	} else if (clear_mods == 3) {
    218 		clear_keys();
    219 		clear_locks();
    220 	}
    221 
    222 	if (no_autorepeat) {
    223 		autorepeat(1, 0);
    224 	}
    225 	if (use_solid_bg) {
    226 		solid_bg(1);
    227 	}
    228 	if (ncache || ncache0) {
    229 		kde_no_animate(1);
    230 	}
    231 	X_LOCK;
    232 	XTestDiscard_wr(dpy);
    233 #if LIBVNCSERVER_HAVE_LIBXDAMAGE
    234 	if (xdamage) {
    235 		XDamageDestroy(dpy, xdamage);
    236 	}
    237 #endif
    238 #if LIBVNCSERVER_HAVE_LIBXTRAP
    239 	if (trap_ctx) {
    240 		XEFreeTC(trap_ctx);
    241 	}
    242 #endif
    243 	/* XXX rdpy_ctrl, etc. cannot close w/o blocking */
    244 	XCloseDisplay_wr(dpy);
    245 	X_UNLOCK;
    246 
    247 	fflush(stderr);
    248 
    249 	if (rm_flagfile) {
    250 		unlink(rm_flagfile);
    251 		rm_flagfile = NULL;
    252 	}
    253 
    254 	if (avahi) {
    255 		avahi_cleanup();
    256 		fflush(stderr);
    257 	}
    258 
    259 	exit(ret);
    260 }
    261 
    262 /* X11 error handlers */
    263 
    264 static XErrorHandler   Xerror_def;
    265 static XIOErrorHandler XIOerr_def;
    266 
    267 int trap_xerror(Display *d, XErrorEvent *error) {
    268 	trapped_xerror = 1;
    269 	trapped_xerror_event = error;
    270 
    271 	if (d) {} /* unused vars warning: */
    272 
    273 	return 0;
    274 }
    275 
    276 int trap_xioerror(Display *d) {
    277 	trapped_xioerror = 1;
    278 
    279 	if (d) {} /* unused vars warning: */
    280 
    281 	return 0;
    282 }
    283 
    284 int trap_getimage_xerror(Display *d, XErrorEvent *error) {
    285 	trapped_getimage_xerror = 1;
    286 	trapped_xerror_event = error;
    287 
    288 	if (d) {} /* unused vars warning: */
    289 
    290 	return 0;
    291 }
    292 
    293 /* Are silly Xorg people removing X_ShmAttach from XShm.h? */
    294 /* INDEED!  What stupid, myopic morons...  */
    295 /* Maintenance Monkeys busy typing at their keyboards... */
    296 #ifndef X_ShmAttach
    297 #define X_ShmAttach 1
    298 #endif
    299 
    300 static int Xerror(Display *d, XErrorEvent *error) {
    301 	X_UNLOCK;
    302 
    303 	if (getenv("X11VNC_PRINT_XERROR")) {
    304 		fprintf(stderr, "Xerror: major_opcode: %d minor_opcode: %d error_code: %d\n",
    305 		    error->request_code, error->minor_code, error->error_code);
    306 	}
    307 
    308 	if (xshm_opcode > 0 && error->request_code == xshm_opcode) {
    309 		if (error->minor_code == X_ShmAttach) {
    310 			char *dstr = DisplayString(dpy);
    311 			fprintf(stderr, "\nX11 MIT Shared Memory Attach failed:\n");
    312 			fprintf(stderr, "  Is your DISPLAY=%s on a remote machine?\n", dstr);
    313 			if (strstr(dstr, "localhost:")) {
    314 				fprintf(stderr, "  Note:   DISPLAY=localhost:N suggests a SSH X11 redir to a remote machine.\n");
    315 			} else if (dstr[0] != ':') {
    316 				fprintf(stderr, "  Note:   DISPLAY=hostname:N suggests a remote display.\n");
    317 			}
    318 			fprintf(stderr, "  Suggestion, use: x11vnc -display :0 ... for local display :0\n\n");
    319 		}
    320 	}
    321 
    322 	interrupted(0);
    323 
    324 	if (d) {} /* unused vars warning: */
    325 
    326 	return (*Xerror_def)(d, error);
    327 }
    328 
    329 void watch_loop(void);
    330 
    331 static int XIOerr(Display *d) {
    332 	static int reopen = 0, rmax = 1;
    333 	X_UNLOCK;
    334 
    335 	if (getenv("X11VNC_REOPEN_DISPLAY")) {
    336 		rmax = atoi(getenv("X11VNC_REOPEN_DISPLAY"));
    337 	}
    338 
    339 #if !NO_X11
    340 	if (reopen < rmax && getenv("X11VNC_REOPEN_DISPLAY")) {
    341 		int db = getenv("X11VNC_REOPEN_DEBUG") ? 1 : 0;
    342 		int sleepmax = 10, i;
    343 		Display *save_dpy = dpy;
    344 		char *dstr = strdup(DisplayString(save_dpy));
    345 		reopen++;
    346 		if (getenv("X11VNC_REOPEN_SLEEP_MAX")) {
    347 			sleepmax = atoi(getenv("X11VNC_REOPEN_SLEEP_MAX"));
    348 		}
    349 		rfbLog("*** XIO error: Trying to reopen[%d/%d] display '%s'\n", reopen, rmax, dstr);
    350 		rfbLog("*** XIO error: Note the reopened state may be unstable.\n");
    351 		for (i=0; i < sleepmax; i++) {
    352 			usleep (1000 * 1000);
    353 			dpy = XOpenDisplay_wr(dstr);
    354 			rfbLog("dpy[%d/%d]: %p\n", i+1, sleepmax, dpy);
    355 			if (dpy) {
    356 				break;
    357 			}
    358 		}
    359 		last_open_xdisplay = time(NULL);
    360 		if (dpy) {
    361 			rfbLog("*** XIO error: Reopened display '%s' successfully.\n", dstr);
    362 			if (db) rfbLog("*** XIO error: '%s' 0x%x\n", dstr, dpy);
    363 			scr = DefaultScreen(dpy);
    364 			rootwin = RootWindow(dpy, scr);
    365 			if (db) rfbLog("*** XIO error: disable_grabserver\n");
    366 			disable_grabserver(dpy, 0);
    367 			if (db) rfbLog("*** XIO error: xrecord\n");
    368 			zerodisp_xrecord();
    369 			initialize_xrecord();
    370 			if (db) rfbLog("*** XIO error: xdamage\n");
    371 			create_xdamage_if_needed(1);
    372 			if (db) rfbLog("*** XIO error: do_new_fb\n");
    373 			if (using_shm) {
    374 				if (db) rfbLog("*** XIO error: clean_shm\n");
    375 				clean_shm(1);
    376 			}
    377 			do_new_fb(1);
    378 			if (db) rfbLog("*** XIO error: check_xevents\n");
    379 			check_xevents(1);
    380 
    381 			/* sadly, we can never return... */
    382 			if (db) rfbLog("*** XIO error: watch_loop\n");
    383 			watch_loop();
    384 			clean_up_exit(1);
    385 		}
    386 	}
    387 #endif
    388 
    389 	interrupted(-1);
    390 
    391 	if (d) {} /* unused vars warning: */
    392 
    393 	return (*XIOerr_def)(d);
    394 }
    395 
    396 static char *xerrors[] = {
    397 	"Success",
    398 	"BadRequest",
    399 	"BadValue",
    400 	"BadWindow",
    401 	"BadPixmap",
    402 	"BadAtom",
    403 	"BadCursor",
    404 	"BadFont",
    405 	"BadMatch",
    406 	"BadDrawable",
    407 	"BadAccess",
    408 	"BadAlloc",
    409 	"BadColor",
    410 	"BadGC",
    411 	"BadIDChoice",
    412 	"BadName",
    413 	"BadLength",
    414 	"BadImplementation",
    415 	"unknown"
    416 };
    417 static int xerrors_max = BadImplementation;
    418 
    419 char *xerror_string(XErrorEvent *error) {
    420 	int index = -1;
    421 	if (error) {
    422 		index = (int) error->error_code;
    423 	}
    424 	if (0 <= index && index <= xerrors_max) {
    425 		return xerrors[index];
    426 	} else {
    427 		return xerrors[xerrors_max+1];
    428 	}
    429 }
    430 
    431 static char *crash_stack_command1 = NULL;
    432 static char *crash_stack_command2 = NULL;
    433 static char *crash_debug_command = NULL;
    434 
    435 void initialize_crash_handler(void) {
    436 	int pid = program_pid;
    437 	crash_stack_command1 = (char *) malloc(1000);
    438 	crash_stack_command2 = (char *) malloc(1000);
    439 	crash_debug_command =  (char *) malloc(1000);
    440 
    441 	snprintf(crash_stack_command1, 500, "echo where > /tmp/gdb.%d;"
    442 	    " env PATH=$PATH:/usr/local/bin:/usr/sfw/bin:/usr/bin"
    443 	    " gdb -x /tmp/gdb.%d -batch -n %s %d;"
    444 	    " rm -f /tmp/gdb.%d", pid, pid, program_name, pid, pid);
    445 	snprintf(crash_stack_command2, 500, "pstack %d", program_pid);
    446 
    447 	snprintf(crash_debug_command, 500, "gdb %s %d", program_name, pid);
    448 }
    449 
    450 static void crash_shell_help(void) {
    451 	int pid = program_pid;
    452 	fprintf(stderr, "\n");
    453 	fprintf(stderr, "   *** Welcome to the x11vnc crash shell! ***\n");
    454 	fprintf(stderr, "\n");
    455 	fprintf(stderr, "PROGRAM: %s  PID: %d\n", program_name, pid);
    456 	fprintf(stderr, "\n");
    457 	fprintf(stderr, "POSSIBLE DEBUGGER COMMAND:\n");
    458 	fprintf(stderr, "\n");
    459 	fprintf(stderr, "  %s\n", crash_debug_command);
    460 	fprintf(stderr, "\n");
    461 	fprintf(stderr, "Press \"q\" to quit.\n");
    462 	fprintf(stderr, "Press \"h\" or \"?\" for this help.\n");
    463 	fprintf(stderr, "Press \"s\" to try to run some commands to"
    464 	    " show a stack trace (gdb/pstack).\n");
    465 	fprintf(stderr, "\n");
    466 	fprintf(stderr, "Anything else is passed to -Q query function.\n");
    467 	fprintf(stderr, "\n");
    468 }
    469 
    470 static void crash_shell(void) {
    471 	char qry[1000], cmd[1000], line[1000];
    472 	char *str, *p;
    473 
    474 	crash_shell_help();
    475 	fprintf(stderr, "\ncrash> ");
    476 	while (fgets(line, 1000, stdin) != NULL) {
    477 		str = lblanks(line);
    478 
    479 		p = str;
    480 		while(*p) {
    481 			if (*p == '\n') {
    482 				*p = '\0';
    483 			}
    484 			p++;
    485 		}
    486 
    487 		if (*str == 'q' && *(str+1) == '\0') {
    488 			fprintf(stderr, "quiting.\n");
    489 			return;
    490 		} else if (*str == 'h' && *(str+1) == '\0') {
    491 			crash_shell_help();
    492 		} else if (*str == '?' && *(str+1) == '\0') {
    493 			crash_shell_help();
    494 		} else if (*str == 's' && *(str+1) == '\0') {
    495 			sprintf(cmd, "sh -c '(%s) &'", crash_stack_command1);
    496 			/* crash */
    497 			if (no_external_cmds || !cmd_ok("crash")) {
    498 				fprintf(stderr, "\nno_external_cmds=%d\n",
    499 				    no_external_cmds);
    500 				goto crash_prompt;
    501 			}
    502 			fprintf(stderr, "\nrunning:\n\t%s\n\n",
    503 			    crash_stack_command1);
    504 			system(cmd);
    505 			usleep(1000*1000);
    506 
    507 			sprintf(cmd, "sh -c '(%s) &'", crash_stack_command2);
    508 			fprintf(stderr, "\nrunning:\n\t%s\n\n",
    509 			    crash_stack_command2);
    510 			system(cmd);
    511 			usleep(1000*1000);
    512 		} else {
    513 			snprintf(qry, 1000, "qry=%s", str);
    514 			p = process_remote_cmd(qry, 1);
    515 			fprintf(stderr, "\n\nresult:\n%s\n", p);
    516 			free(p);
    517 		}
    518 
    519 crash_prompt:
    520 		fprintf(stderr, "crash> ");
    521 	}
    522 }
    523 
    524 /*
    525  * General problem handler
    526  */
    527 static void interrupted (int sig) {
    528 	exit_sig = sig;
    529 	if (exit_flag) {
    530 		fprintf(stderr, "extra[%d] signal: %d\n", exit_flag, sig);
    531 		exit_flag++;
    532 		if (use_threads) {
    533 			usleep2(250 * 1000);
    534 		} else if (exit_flag <= 2) {
    535 			return;
    536 		}
    537 		if (rm_flagfile) {
    538 			unlink(rm_flagfile);
    539 			rm_flagfile = NULL;
    540 		}
    541 		exit(4);
    542 	}
    543 	exit_flag++;
    544 	if (sig == 0) {
    545 		fprintf(stderr, "caught X11 error:\n");
    546 		if (crash_debug) { crash_shell(); }
    547 	} else if (sig == -1) {
    548 		fprintf(stderr, "caught XIO error:\n");
    549 	} else {
    550 		fprintf(stderr, "caught signal: %d\n", sig);
    551 	}
    552 	if (sig == SIGINT) {
    553 		shut_down = 1;
    554 		return;
    555 	}
    556 
    557 	if (crash_debug) {
    558 		crash_shell();
    559 	}
    560 
    561 	X_UNLOCK;
    562 
    563 	if (icon_mode) {
    564 		clean_icon_mode();
    565 	}
    566 	/* remove the shm areas with quick=1: */
    567 	clean_shm(1);
    568 
    569 	if (sig == -1) {
    570 		/* not worth trying any more cleanup, X server probably gone */
    571 		if (rm_flagfile) {
    572 			unlink(rm_flagfile);
    573 			rm_flagfile = NULL;
    574 		}
    575 		exit(3);
    576 	}
    577 
    578 	/* X keyboard cleanups */
    579 	delete_added_keycodes(0);
    580 
    581 	if (clear_mods == 1) {
    582 		clear_modifiers(0);
    583 	} else if (clear_mods == 2) {
    584 		clear_keys();
    585 	} else if (clear_mods == 3) {
    586 		clear_keys();
    587 		clear_locks();
    588 	}
    589 	if (no_autorepeat) {
    590 		autorepeat(1, 0);
    591 	}
    592 	if (use_solid_bg) {
    593 		solid_bg(1);
    594 	}
    595 	if (ncache || ncache0) {
    596 		kde_no_animate(1);
    597 	}
    598 	stop_stunnel();
    599 
    600 	if (crash_debug) {
    601 		crash_shell();
    602 	}
    603 
    604 	if (sig) {
    605 		if (rm_flagfile) {
    606 			unlink(rm_flagfile);
    607 			rm_flagfile = NULL;
    608 		}
    609 		exit(2);
    610 	}
    611 }
    612 
    613 static void ignore_sigs(char *list) {
    614 	char *str, *p;
    615 	int ignore = 1;
    616 	if (list == NULL || *list == '\0') {
    617 		return;
    618 	}
    619 	str = strdup(list);
    620 	p = strtok(str, ":,");
    621 
    622 #define SETSIG(x, y) \
    623 	if (strstr(p, x)) { \
    624 		if (ignore) { \
    625 			signal(y, SIG_IGN); \
    626 		} else { \
    627 			signal(y, interrupted); \
    628 		} \
    629 	}
    630 
    631 #ifdef SIG_IGN
    632 	while (p) {
    633 		if (!strcmp(p, "ignore")) {
    634 			ignore = 1;
    635 		} else if (!strcmp(p, "exit")) {
    636 			ignore = 0;
    637 		}
    638 		/* Take off every 'sig' ;-) */
    639 #ifdef SIGHUP
    640 		SETSIG("HUP", SIGHUP);
    641 #endif
    642 #ifdef SIGINT
    643 		SETSIG("INT", SIGINT);
    644 #endif
    645 #ifdef SIGQUIT
    646 		SETSIG("QUIT", SIGQUIT);
    647 #endif
    648 #ifdef SIGTRAP
    649 		SETSIG("TRAP", SIGTRAP);
    650 #endif
    651 #ifdef SIGABRT
    652 		SETSIG("ABRT", SIGABRT);
    653 #endif
    654 #ifdef SIGBUS
    655 		SETSIG("BUS", SIGBUS);
    656 #endif
    657 #ifdef SIGFPE
    658 		SETSIG("FPE", SIGFPE);
    659 #endif
    660 #ifdef SIGSEGV
    661 		SETSIG("SEGV", SIGSEGV);
    662 #endif
    663 #ifdef SIGPIPE
    664 		SETSIG("PIPE", SIGPIPE);
    665 #endif
    666 #ifdef SIGTERM
    667 		SETSIG("TERM", SIGTERM);
    668 #endif
    669 #ifdef SIGUSR1
    670 		SETSIG("USR1", SIGUSR1);
    671 #endif
    672 #ifdef SIGUSR2
    673 		SETSIG("USR2", SIGUSR2);
    674 #endif
    675 #ifdef SIGCONT
    676 		SETSIG("CONT", SIGCONT);
    677 #endif
    678 #ifdef SIGSTOP
    679 		SETSIG("STOP", SIGSTOP);
    680 #endif
    681 #ifdef SIGTSTP
    682 		SETSIG("TSTP", SIGTSTP);
    683 #endif
    684 		p = strtok(NULL, ":,");
    685 	}
    686 #endif	/* SIG_IGN */
    687 	free(str);
    688 }
    689 
    690 /* signal handlers */
    691 void initialize_signals(void) {
    692 	signal(SIGHUP,  interrupted);
    693 	signal(SIGINT,  interrupted);
    694 	signal(SIGQUIT, interrupted);
    695 	signal(SIGABRT, interrupted);
    696 	signal(SIGTERM, interrupted);
    697 	signal(SIGBUS,  interrupted);
    698 	signal(SIGSEGV, interrupted);
    699 	signal(SIGFPE,  interrupted);
    700 
    701 	if (!sigpipe || *sigpipe == '\0' || !strcmp(sigpipe, "skip")) {
    702 		;
    703 	} else if (strstr(sigpipe, "ignore:") == sigpipe) {
    704 		ignore_sigs(sigpipe);
    705 	} else if (strstr(sigpipe, "exit:") == sigpipe) {
    706 		ignore_sigs(sigpipe);
    707 	} else if (!strcmp(sigpipe, "ignore")) {
    708 #ifdef SIG_IGN
    709 		signal(SIGPIPE, SIG_IGN);
    710 #endif
    711 	} else if (!strcmp(sigpipe, "exit")) {
    712 		rfbLog("initialize_signals: will exit on SIGPIPE\n");
    713 		signal(SIGPIPE, interrupted);
    714 	}
    715 
    716 #if NO_X11
    717 	return;
    718 #else
    719 	X_LOCK;
    720 	Xerror_def = XSetErrorHandler(Xerror);
    721 	XIOerr_def = XSetIOErrorHandler(XIOerr);
    722 	X_UNLOCK;
    723 #endif	/* NO_X11 */
    724 }
    725 
    726 void unset_signals(void) {
    727 	signal(SIGHUP,  SIG_DFL);
    728 	signal(SIGINT,  SIG_DFL);
    729 	signal(SIGQUIT, SIG_DFL);
    730 	signal(SIGABRT, SIG_DFL);
    731 	signal(SIGTERM, SIG_DFL);
    732 	signal(SIGBUS,  SIG_DFL);
    733 	signal(SIGSEGV, SIG_DFL);
    734 	signal(SIGFPE,  SIG_DFL);
    735 	signal(SIGPIPE, SIG_DFL);
    736 }
    737 
    738 void close_exec_fds(void) {
    739 	int fd;
    740 #ifdef FD_CLOEXEC
    741 	for (fd = 3; fd < 64; fd++) {
    742 		int flags = fcntl(fd, F_GETFD);
    743 		if (flags != -1) {
    744 			flags |= FD_CLOEXEC;
    745 			fcntl(fd, F_SETFD, flags);
    746 		}
    747 	}
    748 #endif
    749 }
    750 
    751 int known_sigpipe_mode(char *s) {
    752 /*
    753  * skip, ignore, exit
    754  */
    755 	if (strstr(s, "ignore:") == s) {
    756 		return 1;
    757 	}
    758 	if (strstr(s, "exit:") == s) {
    759 		return 1;
    760 	}
    761 	if (strcmp(s, "skip") && strcmp(s, "ignore") &&
    762 	    strcmp(s, "exit")) {
    763 		return 0;
    764 	} else {
    765 		return 1;
    766 	}
    767 }
    768 
    769 
    770