degesch: add backlog/scrollback functionality
Finally! I went with possibly the simplest solution, which is to run less, instead of badly reimplementing its functionality.
This commit is contained in:
		
							
								
								
									
										221
									
								
								degesch.c
									
									
									
									
									
								
							
							
						
						
									
										221
									
								
								degesch.c
									
									
									
									
									
								
							@@ -1364,6 +1364,8 @@ struct app_context
 | 
				
			|||||||
	bool awaiting_mirc_escape;          ///< Awaiting a mIRC attribute escape
 | 
						bool awaiting_mirc_escape;          ///< Awaiting a mIRC attribute escape
 | 
				
			||||||
	char char_buf[MB_LEN_MAX + 1];      ///< Buffered multibyte char
 | 
						char char_buf[MB_LEN_MAX + 1];      ///< Buffered multibyte char
 | 
				
			||||||
	size_t char_buf_len;                ///< How much of an MB char is buffered
 | 
						size_t char_buf_len;                ///< How much of an MB char is buffered
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool running_backlog_helper;        ///< Running a backlog helper
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
*g_ctx;
 | 
					*g_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1640,6 +1642,10 @@ static struct config_schema g_config_behaviour[] =
 | 
				
			|||||||
	  .type      = CONFIG_ITEM_BOOLEAN,
 | 
						  .type      = CONFIG_ITEM_BOOLEAN,
 | 
				
			||||||
	  .default_  = "off",
 | 
						  .default_  = "off",
 | 
				
			||||||
	  .on_change = on_config_logging_change },
 | 
						  .on_change = on_config_logging_change },
 | 
				
			||||||
 | 
						{ .name      = "backlog_helper",
 | 
				
			||||||
 | 
						  .comment   = "Shell command to display a buffer's history",
 | 
				
			||||||
 | 
						  .type      = CONFIG_ITEM_STRING,
 | 
				
			||||||
 | 
						  .default_  = "\"LESSSECURE=1 less -M -R +G\"" },
 | 
				
			||||||
	{ .name      = "save_on_quit",
 | 
						{ .name      = "save_on_quit",
 | 
				
			||||||
	  .comment   = "Save configuration before quitting",
 | 
						  .comment   = "Save configuration before quitting",
 | 
				
			||||||
	  .type      = CONFIG_ITEM_BOOLEAN,
 | 
						  .type      = CONFIG_ITEM_BOOLEAN,
 | 
				
			||||||
@@ -2839,11 +2845,18 @@ log_formatter (struct app_context *ctx,
 | 
				
			|||||||
		&& buffer == ctx->current_buffer->server->buffer))
 | 
							&& buffer == ctx->current_buffer->server->buffer))
 | 
				
			||||||
		can_leak = true;
 | 
							can_leak = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (buffer == ctx->current_buffer)
 | 
						bool displayed = true;
 | 
				
			||||||
 | 
						if (ctx->running_backlog_helper)
 | 
				
			||||||
 | 
							// Another process is using the terminal
 | 
				
			||||||
 | 
							displayed = false;
 | 
				
			||||||
 | 
						else if (buffer == ctx->current_buffer)
 | 
				
			||||||
		buffer_line_display (ctx, line, false);
 | 
							buffer_line_display (ctx, line, false);
 | 
				
			||||||
	else if (!ctx->isolate_buffers && can_leak)
 | 
						else if (!ctx->isolate_buffers && can_leak)
 | 
				
			||||||
		buffer_line_display (ctx, line, true);
 | 
							buffer_line_display (ctx, line, true);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
 | 
							displayed = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!displayed)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		buffer->unseen_messages_count++;
 | 
							buffer->unseen_messages_count++;
 | 
				
			||||||
		if (flags & BUFFER_LINE_HIGHLIGHT)
 | 
							if (flags & BUFFER_LINE_HIGHLIGHT)
 | 
				
			||||||
@@ -2957,6 +2970,8 @@ buffer_open_log_file (struct app_context *ctx, struct buffer *buffer)
 | 
				
			|||||||
	if (!(buffer->log_file = fopen (path.str, "ab")))
 | 
						if (!(buffer->log_file = fopen (path.str, "ab")))
 | 
				
			||||||
		log_global_error (ctx, "Couldn't open log file `#s': #s",
 | 
							log_global_error (ctx, "Couldn't open log file `#s': #s",
 | 
				
			||||||
			path.str, strerror (errno));
 | 
								path.str, strerror (errno));
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							set_cloexec (fileno (buffer->log_file));
 | 
				
			||||||
	str_free (&path);
 | 
						str_free (&path);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -8807,6 +8822,38 @@ make_completions (struct app_context *ctx, char *line, int start, int end)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// --- Common code for user actions --------------------------------------------
 | 
					// --- Common code for user actions --------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					suspend_terminal (struct app_context *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef HAVE_READLINE
 | 
				
			||||||
 | 
						rl_deprep_terminal ();
 | 
				
			||||||
 | 
					#elif defined (HAVE_EDITLINE)
 | 
				
			||||||
 | 
						el_set (ctx->input.editline, EL_PREP_TERM, 0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_hide (&ctx->input);
 | 
				
			||||||
 | 
						poller_fd_reset (&ctx->tty_event);
 | 
				
			||||||
 | 
						// TODO: also disable the date change timer
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					resume_terminal (struct app_context *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef HAVE_READLINE
 | 
				
			||||||
 | 
						rl_prep_terminal (true);
 | 
				
			||||||
 | 
					#elif defined (HAVE_EDITLINE)
 | 
				
			||||||
 | 
						el_set (ctx->input.editline, EL_PREP_TERM, 1);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// In theory we could just print all unseen messages but this is safer
 | 
				
			||||||
 | 
						buffer_print_backlog (ctx, ctx->current_buffer);
 | 
				
			||||||
 | 
						// Now it's safe to process any user input
 | 
				
			||||||
 | 
						poller_fd_set (&ctx->tty_event, POLLIN);
 | 
				
			||||||
 | 
						input_show (&ctx->input);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
redraw_screen (struct app_context *ctx)
 | 
					redraw_screen (struct app_context *ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -8849,6 +8896,59 @@ await_mirc_escape (struct app_context *ctx)
 | 
				
			|||||||
	ctx->char_buf_len = 0;
 | 
						ctx->char_buf_len = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					exec_backlog_helper (const char *command, FILE *backlog)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						dup2 (fileno (backlog), STDIN_FILENO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Put the child into a new foreground process group
 | 
				
			||||||
 | 
						hard_assert (setpgid (0, 0)!= -1);
 | 
				
			||||||
 | 
						hard_assert (tcsetpgrp (STDOUT_FILENO, getpgid (0)) != -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						execl ("/bin/sh", "/bin/sh", "-c", command, NULL);
 | 
				
			||||||
 | 
						print_error ("%s: %s", "Failed to launch backlog helper", strerror (errno));
 | 
				
			||||||
 | 
						_exit (EXIT_FAILURE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					display_backlog (struct app_context *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						hard_assert (!ctx->running_backlog_helper);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FILE *backlog = tmpfile ();
 | 
				
			||||||
 | 
						set_cloexec (fileno (backlog));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: retrieve the lines with formatting
 | 
				
			||||||
 | 
						for (struct buffer_line *line = ctx->current_buffer->lines;
 | 
				
			||||||
 | 
							line; line = line->next)
 | 
				
			||||||
 | 
							buffer_line_write_to_log (ctx, line, backlog);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rewind (backlog);
 | 
				
			||||||
 | 
						suspend_terminal (ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pid_t child = fork ();
 | 
				
			||||||
 | 
						if (child == 0)
 | 
				
			||||||
 | 
							exec_backlog_helper (get_config_string
 | 
				
			||||||
 | 
								(ctx->config.root, "behaviour.backlog_helper"), backlog);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (child == -1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int saved_errno = errno;
 | 
				
			||||||
 | 
							resume_terminal (ctx);
 | 
				
			||||||
 | 
							log_global_error (ctx, "#s: #s",
 | 
				
			||||||
 | 
								"Failed to launch backlog helper", strerror (saved_errno));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// Make sure the child has its own process group
 | 
				
			||||||
 | 
							(void) setpgid (child, child);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ctx->running_backlog_helper = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fclose (backlog);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
bind_common_keys (struct app_context *ctx)
 | 
					bind_common_keys (struct app_context *ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -8866,6 +8966,8 @@ bind_common_keys (struct app_context *ctx)
 | 
				
			|||||||
		input_bind (self, key_f5, "previous-buffer");
 | 
							input_bind (self, key_f5, "previous-buffer");
 | 
				
			||||||
	if (key_f6)
 | 
						if (key_f6)
 | 
				
			||||||
		input_bind (self, key_f6, "next-buffer");
 | 
							input_bind (self, key_f6, "next-buffer");
 | 
				
			||||||
 | 
						if (key_ppage)
 | 
				
			||||||
 | 
							input_bind (self, key_ppage, "display-backlog");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (clear_screen)
 | 
						if (clear_screen)
 | 
				
			||||||
		input_bind_control (self, 'l', "redraw-screen");
 | 
							input_bind_control (self, 'l', "redraw-screen");
 | 
				
			||||||
@@ -8906,6 +9008,17 @@ on_readline_next_buffer (int count, int key)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					on_readline_display_backlog (int count, int key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						(void) count;
 | 
				
			||||||
 | 
						(void) key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct app_context *ctx = g_ctx;
 | 
				
			||||||
 | 
						display_backlog (ctx);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
on_readline_redraw_screen (int count, int key)
 | 
					on_readline_redraw_screen (int count, int key)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -8998,6 +9111,7 @@ app_readline_init (void)
 | 
				
			|||||||
	rl_add_defun ("previous-buffer",  on_readline_previous_buffer,  -1);
 | 
						rl_add_defun ("previous-buffer",  on_readline_previous_buffer,  -1);
 | 
				
			||||||
	rl_add_defun ("next-buffer",      on_readline_next_buffer,      -1);
 | 
						rl_add_defun ("next-buffer",      on_readline_next_buffer,      -1);
 | 
				
			||||||
	rl_add_defun ("goto-buffer",      on_readline_goto_buffer,      -1);
 | 
						rl_add_defun ("goto-buffer",      on_readline_goto_buffer,      -1);
 | 
				
			||||||
 | 
						rl_add_defun ("display-backlog",  on_readline_display_backlog,  -1);
 | 
				
			||||||
	rl_add_defun ("redraw-screen",    on_readline_redraw_screen,    -1);
 | 
						rl_add_defun ("redraw-screen",    on_readline_redraw_screen,    -1);
 | 
				
			||||||
	rl_add_defun ("insert-attribute", on_readline_insert_attribute, -1);
 | 
						rl_add_defun ("insert-attribute", on_readline_insert_attribute, -1);
 | 
				
			||||||
	rl_add_defun ("send-line",        on_readline_return,           -1);
 | 
						rl_add_defun ("send-line",        on_readline_return,           -1);
 | 
				
			||||||
@@ -9057,6 +9171,15 @@ on_editline_next_buffer (EditLine *editline, int key)
 | 
				
			|||||||
	return CC_NORM;
 | 
						return CC_NORM;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned char
 | 
				
			||||||
 | 
					on_editline_display_backlog (EditLine *editline, int key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						(void) editline;
 | 
				
			||||||
 | 
						(void) key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						display_backlog (g_ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned char
 | 
					static unsigned char
 | 
				
			||||||
on_editline_redraw_screen (EditLine *editline, int key)
 | 
					on_editline_redraw_screen (EditLine *editline, int key)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -9173,6 +9296,7 @@ app_editline_init (struct input *self)
 | 
				
			|||||||
		{ "goto-buffer",      "Go to buffer",    on_editline_goto_buffer      },
 | 
							{ "goto-buffer",      "Go to buffer",    on_editline_goto_buffer      },
 | 
				
			||||||
		{ "previous-buffer",  "Previous buffer", on_editline_previous_buffer  },
 | 
							{ "previous-buffer",  "Previous buffer", on_editline_previous_buffer  },
 | 
				
			||||||
		{ "next-buffer",      "Next buffer",     on_editline_next_buffer      },
 | 
							{ "next-buffer",      "Next buffer",     on_editline_next_buffer      },
 | 
				
			||||||
 | 
							{ "display-backlog",  "Display backlog", on_editline_display_backlog  },
 | 
				
			||||||
		{ "redraw-screen",    "Redraw screen",   on_editline_redraw_screen    },
 | 
							{ "redraw-screen",    "Redraw screen",   on_editline_redraw_screen    },
 | 
				
			||||||
		{ "insert-attribute", "mIRC formatting", on_editline_insert_attribute },
 | 
							{ "insert-attribute", "mIRC formatting", on_editline_insert_attribute },
 | 
				
			||||||
		{ "send-line",        "Send line",       on_editline_return           },
 | 
							{ "send-line",        "Send line",       on_editline_return           },
 | 
				
			||||||
@@ -9376,29 +9500,34 @@ static volatile sig_atomic_t g_termination_requested;
 | 
				
			|||||||
static volatile sig_atomic_t g_winch_received;
 | 
					static volatile sig_atomic_t g_winch_received;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
sigterm_handler (int signum)
 | 
					postpone_signal_handling (char id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	(void) signum;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	g_termination_requested = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int original_errno = errno;
 | 
						int original_errno = errno;
 | 
				
			||||||
	if (write (g_signal_pipe[1], "t", 1) == -1)
 | 
						if (write (g_signal_pipe[1], &id, 1) == -1)
 | 
				
			||||||
		soft_assert (errno == EAGAIN);
 | 
							soft_assert (errno == EAGAIN);
 | 
				
			||||||
	errno = original_errno;
 | 
						errno = original_errno;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
sigwinch_handler (int signum)
 | 
					signal_superhandler (int signum)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	(void) signum;
 | 
						switch (signum)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						case SIGWINCH:
 | 
				
			||||||
		g_winch_received = true;
 | 
							g_winch_received = true;
 | 
				
			||||||
 | 
							postpone_signal_handling ('w');
 | 
				
			||||||
	int original_errno = errno;
 | 
							break;
 | 
				
			||||||
	if (write (g_signal_pipe[1], "w", 1) == -1)
 | 
						case SIGINT:
 | 
				
			||||||
		soft_assert (errno == EAGAIN);
 | 
						case SIGTERM:
 | 
				
			||||||
	errno = original_errno;
 | 
							g_termination_requested = true;
 | 
				
			||||||
 | 
							postpone_signal_handling ('t');
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SIGCHLD:
 | 
				
			||||||
 | 
							postpone_signal_handling ('c');
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							hard_assert (!"unhandled signal");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@@ -9418,28 +9547,76 @@ setup_signal_handlers (void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	signal (SIGPIPE, SIG_IGN);
 | 
						signal (SIGPIPE, SIG_IGN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// So that we can write to the terminal while we're running a backlog
 | 
				
			||||||
 | 
						// helper.  This is also inherited by the child so that it doesn't stop
 | 
				
			||||||
 | 
						// when it calls tcsetpgrp().
 | 
				
			||||||
 | 
						signal (SIGTTOU, SIG_IGN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sigaction sa;
 | 
						struct sigaction sa;
 | 
				
			||||||
	sa.sa_flags = SA_RESTART;
 | 
						sa.sa_flags = SA_RESTART;
 | 
				
			||||||
	sa.sa_handler = sigwinch_handler;
 | 
						sa.sa_handler = signal_superhandler;
 | 
				
			||||||
	sigemptyset (&sa.sa_mask);
 | 
						sigemptyset (&sa.sa_mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sigaction (SIGWINCH, &sa, NULL) == -1)
 | 
						if (sigaction (SIGWINCH, &sa, NULL) == -1
 | 
				
			||||||
		exit_fatal ("sigaction: %s", strerror (errno));
 | 
						 || sigaction (SIGINT,   &sa, NULL) == -1
 | 
				
			||||||
 | 
						 || sigaction (SIGTERM,  &sa, NULL) == -1
 | 
				
			||||||
	sa.sa_handler = sigterm_handler;
 | 
						 || sigaction (SIGCHLD,  &sa, NULL) == -1)
 | 
				
			||||||
	if (sigaction (SIGINT, &sa, NULL) == -1
 | 
					 | 
				
			||||||
	 || sigaction (SIGTERM, &sa, NULL) == -1)
 | 
					 | 
				
			||||||
		exit_fatal ("sigaction: %s", strerror (errno));
 | 
							exit_fatal ("sigaction: %s", strerror (errno));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// --- I/O event handlers ------------------------------------------------------
 | 
					// --- I/O event handlers ------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					try_reap_child (struct app_context *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
 | 
						pid_t zombie = waitpid (-1, &status, WNOHANG | WUNTRACED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (zombie == -1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (errno == ECHILD)  return false;
 | 
				
			||||||
 | 
							if (errno == EINTR)   return true;
 | 
				
			||||||
 | 
							exit_fatal ("%s: %s", "waitpid", strerror (errno));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!zombie)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ctx->running_backlog_helper)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							print_debug ("an unknown child has died");
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (WIFSTOPPED (status))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// We could also send SIGCONT but what's the point
 | 
				
			||||||
 | 
							kill (-zombie, SIGKILL);
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx->running_backlog_helper = false;
 | 
				
			||||||
 | 
						hard_assert (tcsetpgrp (STDOUT_FILENO, getpgid (0)) != -1);
 | 
				
			||||||
 | 
						resume_terminal (ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WIFSIGNALED (status))
 | 
				
			||||||
 | 
							log_global_error (ctx,
 | 
				
			||||||
 | 
								"Child died from signal #d", WTERMSIG (status));
 | 
				
			||||||
 | 
						else if (WIFEXITED (status) && WEXITSTATUS (status) != 0)
 | 
				
			||||||
 | 
							log_global_error (ctx,
 | 
				
			||||||
 | 
								"Child returned status #d", WEXITSTATUS (status));
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
on_signal_pipe_readable (const struct pollfd *fd, struct app_context *ctx)
 | 
					on_signal_pipe_readable (const struct pollfd *fd, struct app_context *ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char dummy;
 | 
						char dummy;
 | 
				
			||||||
	(void) read (fd->fd, &dummy, 1);
 | 
						(void) read (fd->fd, &dummy, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Reap all dead children (since the signal pipe may overflow etc. we run
 | 
				
			||||||
 | 
						// waitpid() in a loop to return all the zombies it knows about).
 | 
				
			||||||
 | 
						while (try_reap_child (ctx))
 | 
				
			||||||
 | 
							;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g_termination_requested && !ctx->quitting)
 | 
						if (g_termination_requested && !ctx->quitting)
 | 
				
			||||||
		// TODO: this way we don't send a QUIT message but just close the
 | 
							// TODO: this way we don't send a QUIT message but just close the
 | 
				
			||||||
		//   connection from our side and wait for a full close.
 | 
							//   connection from our side and wait for a full close.
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user