}
static void run_context_check_done(RunContext *c) {
- bool done;
-
assert(c);
- done = STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job;
-
- if (c->forward && !pty_forward_is_done(c->forward) && done) /* If the service is gone, it's time to drain the output */
- done = pty_forward_drain(c->forward);
-
- if (done)
+ if (STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job)
(void) sd_event_exit(c->event, EXIT_SUCCESS);
}
if (arg_wait && !arg_quiet) {
- /* Explicitly destroy the PTY forwarder, so that the PTY device is usable again, with its
- * original settings (i.e. proper line breaks), so that we can show the summary in a pretty
- * way. */
- c.forward = pty_forward_free(c.forward);
-
if (!isempty(c.result))
log_info("Finished with result: %s", strna(c.result));
sd_event_source *stdin_event_source;
sd_event_source *stdout_event_source;
sd_event_source *master_event_source;
-
sd_event_source *sigwinch_event_source;
+ sd_event_source *exit_event_source;
struct termios saved_stdin_attr;
struct termios saved_stdout_attr;
bool read_from_master:1;
bool done:1;
- bool drain:1;
bool last_char_set:1;
char last_char;
f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
f->stdout_event_source = sd_event_source_unref(f->stdout_event_source);
-
f->master_event_source = sd_event_source_unref(f->master_event_source);
f->sigwinch_event_source = sd_event_source_unref(f->sigwinch_event_source);
+ f->exit_event_source = sd_event_source_unref(f->exit_event_source);
f->event = sd_event_unref(f->event);
if (f->output_fd >= 0) {
return pty_forward_done(f, 0);
}
- /* If we were asked to drain, and there's nothing more to handle from the master, then call the callback
- * too. */
- if (f->drain && drained(f))
- return pty_forward_done(f, 0);
-
return 0;
}
return 0;
}
+static int on_exit_event(sd_event_source *e, void *userdata) {
+ PTYForward *f = ASSERT_PTR(userdata);
+ int r;
+
+ assert(e);
+ assert(e == f->exit_event_source);
+
+ /* Drain the buffer on exit. */
+
+ if (f->done)
+ return 0;
+
+ for (unsigned trial = 0; trial < 1000; trial++) {
+ if (drained(f))
+ return pty_forward_done(f, 0);
+
+ r = shovel(f);
+ if (r < 0)
+ return r;
+ if (f->done)
+ return 0;
+ }
+
+ /* If we could not drain, then propagate recognizable error code. */
+ return pty_forward_done(f, -ELOOP);
+}
+
int pty_forward_new(
sd_event *event,
int master,
(void) sd_event_source_set_description(f->sigwinch_event_source, "ptyfwd-sigwinch");
+ r = sd_event_add_exit(f->event, &f->exit_event_source, on_exit_event, f);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(f->exit_event_source, "ptyfwd-exit");
+
*ret = TAKE_PTR(f);
return 0;
return FLAGS_SET(f->flags, PTY_FORWARD_IGNORE_VHANGUP);
}
-bool pty_forward_is_done(PTYForward *f) {
- assert(f);
-
- return f->done;
-}
-
void pty_forward_set_handler(PTYForward *f, PTYForwardHandler cb, void *userdata) {
assert(f);
f->userdata = userdata;
}
-bool pty_forward_drain(PTYForward *f) {
- assert(f);
-
- /* Starts draining the forwarder. Specifically:
- *
- * - Returns true if there are no unprocessed bytes from the pty, false otherwise
- *
- * - Makes sure the handler function is called the next time the number of unprocessed bytes hits zero
- */
-
- f->drain = true;
- return drained(f);
-}
-
int pty_forward_set_priority(PTYForward *f, int64_t priority) {
int r;
int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup);
bool pty_forward_get_ignore_vhangup(PTYForward *f);
-bool pty_forward_is_done(PTYForward *f);
-
void pty_forward_set_handler(PTYForward *f, PTYForwardHandler handler, void *userdata);
-bool pty_forward_drain(PTYForward *f);
-
int pty_forward_set_priority(PTYForward *f, int64_t priority);
int pty_forward_set_width_height(PTYForward *f, unsigned width, unsigned height);