|
29 | 29 | #include <sched.h> /* sched_yield() */ |
30 | 30 | #include <string.h> |
31 | 31 | #include <sys/reboot.h> |
| 32 | +#include <sys/ioctl.h> |
32 | 33 | #include <sys/prctl.h> |
33 | 34 | #include <sys/resource.h> |
34 | 35 | #include <sys/un.h> |
35 | 36 | #include <sys/wait.h> |
| 37 | +#include <linux/vt.h> |
36 | 38 | #include <net/if.h> |
37 | 39 | #ifdef _LIBITE_LITE |
38 | 40 | # include <libite/lite.h> |
@@ -387,6 +389,43 @@ static int lredirect(svc_t *svc) |
387 | 389 | return close(pipefd[1]); |
388 | 390 | } |
389 | 391 |
|
| 392 | +/* |
| 393 | + * Set up a controlling TTY for run/task/service. |
| 394 | + * Opens the TTY device, dups to 0/1/2, resets termios to |
| 395 | + * sane defaults, sets TERM env, and updates procname. |
| 396 | + */ |
| 397 | +static void svc_prepare_ctty(const char *tty, const char *procname, int log) |
| 398 | +{ |
| 399 | + int fd, dummy; |
| 400 | + |
| 401 | + fd = open(tty, O_RDWR); |
| 402 | + if (fd < 0) { |
| 403 | + logit(LOG_ERR, "Failed opening %s: %s", tty, strerror(errno)); |
| 404 | + _exit(1); |
| 405 | + } |
| 406 | + |
| 407 | + /* Acquire as controlling terminal for the session */ |
| 408 | + ioctl(fd, TIOCSCTTY, 0); |
| 409 | + |
| 410 | + dup2(fd, STDIN_FILENO); |
| 411 | + if (!log) { |
| 412 | + dup2(fd, STDOUT_FILENO); |
| 413 | + dup2(fd, STDERR_FILENO); |
| 414 | + } |
| 415 | + |
| 416 | + /* Set default TERM */ |
| 417 | + if (ioctl(fd, VT_OPENQRY, &dummy) == -1) |
| 418 | + setenv("TERM", "vt102", 1); /* likely a serial line */ |
| 419 | + else |
| 420 | + setenv("TERM", "linux", 1); |
| 421 | + |
| 422 | + /* Reset to sane defaults */ |
| 423 | + stty(fd, B0); |
| 424 | + close(fd); |
| 425 | + |
| 426 | + prctl(PR_SET_NAME, procname, 0, 0, 0); |
| 427 | +} |
| 428 | + |
390 | 429 | /* |
391 | 430 | * Handle redirection of process output, if enabled |
392 | 431 | */ |
@@ -946,6 +985,14 @@ static int service_start(svc_t *svc) |
946 | 985 |
|
947 | 986 | sig_unblock(); |
948 | 987 |
|
| 988 | + /* |
| 989 | + * If the stanza declared tty:<dev>, set up a controlling |
| 990 | + * terminal on that device now that we're a session leader. |
| 991 | + * Must run after setsid() to acquire the controlling TTY. |
| 992 | + */ |
| 993 | + if (!svc_is_tty(svc) && svc_has_ctty(svc)) |
| 994 | + svc_prepare_ctty(svc->log.ctty, svc->cmd, !!svc->log.enabled); |
| 995 | + |
949 | 996 | if (svc_is_runtask(svc)) |
950 | 997 | status = exec_runtask(args[0], &args[1]); |
951 | 998 | else if (svc_is_tty(svc)) |
@@ -1795,6 +1842,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) |
1795 | 1842 | char ident[MAX_IDENT_LEN]; |
1796 | 1843 | char *ifstmt = NULL; |
1797 | 1844 | char *notify = NULL; |
| 1845 | + char *ctty = NULL; |
1798 | 1846 | struct tty tty = { 0 }; |
1799 | 1847 | char *dev = NULL; |
1800 | 1848 | int respawn = 0; |
@@ -1911,6 +1959,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) |
1911 | 1959 | env = arg; |
1912 | 1960 | else if (MATCH_CMD(cmd, "caps:", arg)) |
1913 | 1961 | caps = arg; |
| 1962 | + else if (MATCH_CMD(cmd, "tty:", arg)) |
| 1963 | + ctty = arg; |
1914 | 1964 | /* catch both cgroup: and cgroup. handled in parse_cgroup() */ |
1915 | 1965 | else if (MATCH_CMD(cmd, "cgroup", arg)) |
1916 | 1966 | cgroup = arg; |
@@ -2160,6 +2210,22 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) |
2160 | 2210 | parse_caps(svc, caps); |
2161 | 2211 | else |
2162 | 2212 | memset(svc->capabilities, 0, sizeof(svc->capabilities)); |
| 2213 | + |
| 2214 | + if (!svc_is_tty(svc) && ctty) { |
| 2215 | + char *dev = ctty; |
| 2216 | + |
| 2217 | + /* NOTE: @console expands only to first console, not all */ |
| 2218 | + if (tty_isatcon(ctty)) |
| 2219 | + dev = tty_atcon(); |
| 2220 | + dev = tty_canonicalize(dev); |
| 2221 | + if (dev) |
| 2222 | + strlcpy(svc->log.ctty, dev, sizeof(svc->log.ctty)); |
| 2223 | + else |
| 2224 | + logit(LOG_WARNING, "%s: tty: %s not found, skipping ctty", svc_ident(svc, NULL, 0), ctty); |
| 2225 | + } else if (!svc_is_tty(svc)) { |
| 2226 | + memset(svc->log.ctty, 0, sizeof(svc->log.ctty)); |
| 2227 | + } |
| 2228 | + |
2163 | 2229 | if (file) |
2164 | 2230 | strlcpy(svc->file, file, sizeof(svc->file)); |
2165 | 2231 | else |
|
0 commit comments