Run "run-on-console" services as a new process group/session so
authorDavin McCall <davmac@davmac.org>
Fri, 1 Jan 2016 16:32:21 +0000 (16:32 +0000)
committerDavin McCall <davmac@davmac.org>
Fri, 1 Jan 2016 16:32:21 +0000 (16:32 +0000)
that ^C can be used to interrupt it.

(Probably will make this optional, later).

dinit.cc
service.cc

index 317dffa9522928aabb94977c107bef100822f4e7..9b26b3a1c277c1e3de3f24c1bcc71e1a86117f7e 100644 (file)
--- a/dinit.cc
+++ b/dinit.cc
@@ -105,6 +105,13 @@ int main(int argc, char **argv)
     /* sigaddset(&sigwait_set, SIGTERM); */
     /* sigprocmask(SIG_BLOCK, &sigwait_set, NULL); */
     
+    // Terminal access control signals - we block these so that dinit can't be
+    // suspended if it writes to the terminal after some other process has claimed
+    // ownership of it.
+    signal(SIGTSTP, SIG_IGN);
+    signal(SIGTTIN, SIG_IGN);
+    signal(SIGTTOU, SIG_IGN);
+    
     /* list of services to start */
     list<const char *> services_to_start;
     
index 346c0a843ff36d81506054cfcb058f6f16d5e66f..33dc2ab3fa2d19660b5eb9f088bf1efc1668171e 100644 (file)
@@ -3,10 +3,14 @@
 #include <sstream>
 #include <iterator>
 #include <memory>
+
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/ioctl.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <termios.h>
+
 #include "service.h"
 #include "dinit-log.h"
 
@@ -53,6 +57,7 @@ void ServiceSet::stopService(const std::string & name) noexcept
 void ServiceRecord::stopped() noexcept
 {
     if (service_type != ServiceType::SCRIPTED && onstart_flags.runs_on_console) {
+        tcsetpgrp(0, getpgrp());
         releaseConsole();
     }
 
@@ -258,6 +263,7 @@ void ServiceRecord::acquiredConsole() noexcept
 void ServiceRecord::started()
 {
     if (onstart_flags.runs_on_console && service_type == ServiceType::SCRIPTED) {
+        tcsetpgrp(0, getpgrp());
         releaseConsole();
     }
 
@@ -295,6 +301,7 @@ void ServiceRecord::started()
 void ServiceRecord::failed_to_start()
 {
     if (onstart_flags.runs_on_console) {
+        tcsetpgrp(0, getpgrp());
         releaseConsole();
     }
     
@@ -370,6 +377,11 @@ bool ServiceRecord::start_ps_process(const std::vector<const char *> &cmd, bool
         return false;
     }
 
+    // If the console already has a session leader, presumably it is us. On the other hand
+    // if it has no session leader, and we don't create one, then control inputs such as
+    // ^C will have no effect.
+    bool do_set_ctty = (tcgetsid(0) == -1);
+
     if (forkpid == 0) {
         // Child process. Must not allocate memory (or otherwise risk throwing any exception)
         // from here until exit().
@@ -387,6 +399,18 @@ bool ServiceRecord::start_ps_process(const std::vector<const char *> &cmd, bool
               dup2(1, 2);
             }
         }
+        else {
+            // "run on console" - run as a foreground job on the terminal/console device
+            if (do_set_ctty) {
+                setsid();
+                ioctl(0, TIOCSCTTY, 0);
+            }
+            setpgid(0,0);
+            tcsetpgrp(0, getpgrp());
+            
+            // TODO disable suspend (^Z)? (via tcsetattr)
+            //      (should be done before TIOCSCTTY)
+        }
 
         execvp(exec_arg_parts[0], const_cast<char **>(args));