From 9d6378f373a3e54862bfcefe820177c0613498c7 Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Fri, 1 Jan 2016 16:32:21 +0000 Subject: [PATCH] Run "run-on-console" services as a new process group/session so that ^C can be used to interrupt it. (Probably will make this optional, later). --- dinit.cc | 7 +++++++ service.cc | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/dinit.cc b/dinit.cc index 317dffa..9b26b3a 100644 --- 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 services_to_start; diff --git a/service.cc b/service.cc index 346c0a8..33dc2ab 100644 --- a/service.cc +++ b/service.cc @@ -3,10 +3,14 @@ #include #include #include + #include #include +#include #include #include +#include + #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 &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 &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(args)); -- 2.25.1