]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
ptyfwd,run: process remaining outputs in IO event sources
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 25 Dec 2024 08:40:04 +0000 (17:40 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 25 Dec 2024 08:50:15 +0000 (17:50 +0900)
This partially reverts 12807b5a49d1fe60434d473afe11ff81a4c92306.

Otherwise, reading or writing a fd in on_exit_event() handler may return
EBUSY, and the event loop may finish with -ELOOP.

Also, this makes drained() returns true if the PTY forwarder is already
disconnected, for safety. Hence, it is not necessary to re-introduce
pty_forward_is_done().

src/run/run.c
src/shared/ptyfwd.c
src/shared/ptyfwd.h

index 72f8affc2dde29fb486e2682afd14de538e58aee..28953a6514b925b5f25cb1d2a2338f3baa5533b7 100644 (file)
@@ -1557,7 +1557,12 @@ static int run_context_reconnect(RunContext *c) {
 static void run_context_check_done(RunContext *c) {
         assert(c);
 
-        if (STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job)
+        bool done = STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job;
+
+        if (done && c->forward) /* If the service is gone, it's time to drain the output */
+                done = pty_forward_drain(c->forward);
+
+        if (done)
                 (void) sd_event_exit(c->event, EXIT_SUCCESS);
 }
 
index e66c4edf5812cb1dc3c0d42905a42943002e3b89..901a73dafdebb3cf4f2f05c86273145f1325ab81 100644 (file)
@@ -81,6 +81,7 @@ struct PTYForward {
         bool read_from_master:1;
 
         bool done:1;
+        bool drain:1;
 
         bool last_char_set:1;
         char last_char;
@@ -240,6 +241,9 @@ static bool drained(PTYForward *f) {
 
         assert(f);
 
+        if (f->done)
+                return true;
+
         if (f->out_buffer_full > 0)
                 return false;
 
@@ -759,6 +763,11 @@ static int do_shovel(PTYForward *f) {
                         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;
 }
 
@@ -1086,6 +1095,20 @@ void pty_forward_set_handler(PTYForward *f, PTYForwardHandler cb, void *userdata
         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;
 
index 615e1056e883166db10451e36586a724b28fa5be..a6e729d7bc67b34af9525833b29637ad6e21d35e 100644 (file)
@@ -33,6 +33,8 @@ bool pty_forward_get_ignore_vhangup(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);