s6

Mirror/fork of https://skarnet.org/software/s6/
git clone https://ccx.te2000.cz/git/s6
Log | Files | Refs | README | LICENSE

commit 19590f4157aefc706db79356e3134a34d6e2c8b0
parent bcb2bb4b6ee85f19c80472df9b44eff0c4016e7b
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date:   Wed,  4 Mar 2015 12:57:14 +0000

 Add process group management functionality to s6-setsid

Diffstat:
Mdoc/s6-setsid.html | 49+++++++++++++++++++++++++++++++++++++++----------
Msrc/daemontools-extras/s6-setsid.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++--------------
2 files changed, 89 insertions(+), 24 deletions(-)

diff --git a/doc/s6-setsid.html b/doc/s6-setsid.html @@ -18,29 +18,58 @@ <h1> The s6-setsid program </h1> <p> -s6-setsid runs a program as session leader. + s6-setsid runs a program as a new session leader, or in a new +foreground or background process group. </p> <h2> Interface </h2> <pre> - s6-setsid [ -I | -i ] <em>prog...</em> + s6-setsid [ -s | -b | -f | -g ] [ -i | -I | -q ] [ -d ctty ] <em>prog...</em> </pre> <ul> - <li> s6-setsid creates a new session if it is not a session leader, and becomes -session leader of this new session. </li> - <li> It then executes into <em>prog...</em>. </li> + <li> s6-setsid creates a new session, or a new process group, +and may make that process group the foreground process group, +depending on the options it has been given. </li> + <li> As session leader or process group leader, s6-setsid then +executes into <em>prog...</em>. </li> </ul> <h2> Options </h2> <ul> - <li> <tt>-i</tt>&nbsp;: strict. If s6-setsid is already a session leader, it will -exit 111 with an error message. </li> - <li> <tt>-I</tt>&nbsp;: loose. If s6-setsid is already a session leader, it will -print a warning message, but exec into <em>prog</em> nonetheless. This is the -default. </li> + <li> <tt>-s</tt>&nbsp;: session. s6-setsid will try and execute +<em>prog</em> as a session leader. This is the default. </li> + <li> <tt>-b</tt>&nbsp;: background process group. s6-setsid will +not create a new session, but will create a new process group, and +try and execute <em>prog</em> as the new process group leader. </li> + <li> <tt>-f</tt>&nbsp;: foreground process group. s6-setsid will +not create a new session, but will create a new process group and +attach its session's controlling terminal to the new process group +before executing <em>prog</em>. However, the new process group +will likely be stopped, waiting for the former foreground process +group to relinquish the controlling terminal, and will need to be +sent a SIGCONT to resume. To avoid that, use the next option. </li> + <li> <tt>-g</tt>&nbsp;: grab terminal. s6-setsid will +not create a new session, but will create a new process group and +attach its session's controlling terminal to the new process group +before executing <em>prog</em>. It will forcefully grab the controlling +terminal from the former foreground process group, which means that +a process belonging to the former foreground process group attempting +to read from or write to that terminal will be stopped. </li> + <li> <tt>-i</tt>&nbsp;: strict. If s6-setsid cannot perform the +operations it needs, it will exit 111 with an error message. </li> + <li> <tt>-I</tt>&nbsp;: loose. If s6-setsid cannot perform the operations, +it will print a warning message, but exec into <em>prog</em> nonetheless. +This is the default. </li> + <li> <tt>-q</tt>&nbsp;: silent. s6-setsid will not print any warning +message; it will exec into <em>prog</em> even if it cannot perform the +operations. </li> + <li> <tt>-d&nbsp;<em>ctty</em></tt>&nbsp;: assume <em>ctty</em> is +the controlling terminal for the current session. Default is 0. +This is only useful when used with the <tt>-f</tt> or +<tt>-g</tt> options. </li> </ul> </body> diff --git a/src/daemontools-extras/s6-setsid.c b/src/daemontools-extras/s6-setsid.c @@ -1,35 +1,71 @@ /* ISC license. */ #include <unistd.h> +#include <signal.h> +#include <skalibs/uint.h> #include <skalibs/sgetopt.h> #include <skalibs/strerr2.h> +#include <skalibs/sig.h> #include <skalibs/djbunix.h> -#define USAGE "s6-setsid [ -i | -I ] prog..." +#define USAGE "s6-setsid [ -s | -b | -f | -g ] [ -i | -I | -q ] [ -d ctty ] prog..." +#define dieusage() strerr_dieusage(100, USAGE) int main (int argc, char const *const *argv, char const *const *envp) { - int insist = 0 ; + unsigned int ctty = 0, what = 0, insist = 1 ; PROG = "s6-setsid" ; - for (;;) { - register int opt = subgetopt(argc, argv, "iI") ; - if (opt == -1) break ; - switch (opt) + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) { - case 'i' : insist = 1 ; break ; - case 'I' : insist = 0 ; break ; - default : strerr_dieusage(100, USAGE) ; + register int opt = subgetopt_r(argc, argv, "sbfgiIqt:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 's' : what = 0 ; break ; + case 'b' : what = 1 ; break ; + case 'f' : what = 2 ; break ; + case 'g' : what = 3 ; break ; + case 'i' : insist = 2 ; break ; + case 'I' : insist = 1 ; break ; + case 'q' : insist = 0 ; break ; + case 't' : if (!uint0_scan(l.arg, &ctty)) dieusage() ; break ; + default : dieusage() ; + } } + argc -= l.ind ; argv += l.ind ; } - argc -= subgetopt_here.ind ; argv += subgetopt_here.ind ; - if (!argc) strerr_dieusage(100, USAGE) ; + if (!argc) dieusage() ; - if (setsid() < 0) + if (what) { - if (insist) strerr_diefu1sys(111, "setsid") ; - else strerr_warnwu1sys("setsid") ; + if (setpgid(0, 0) < 0) switch (insist) + { + case 2 : strerr_diefu1sys(111, "setpgid") ; + case 1 : strerr_warnwu1sys("setpgid") ; break ; + default : break ; + } + + if (what >= 2) + { + if (what == 3) sig_ignore(SIGTTOU) ; + if (tcsetpgrp(ctty, getpid()) < 0) switch (insist) + { + case 2 : strerr_diefu1sys(111, "tcsetpgrp") ; + case 1 : strerr_warnwu1sys("tcsetpgrp") ; break ; + default : break ; + } + if (what == 3) sig_restore(SIGTTOU) ; + } + } + else if (setsid() < 0) switch (insist) + { + case 2 : strerr_diefu1sys(111, "setsid") ; + case 1 : strerr_warnwu1sys("setsid") ; break ; + default : break ; } + pathexec_run(argv[0], argv, envp) ; strerr_dieexec(111, argv[0]) ; }