From 4bb67bc06f18e4a7e2dad89d8353ecaaf810e8c3 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Wed, 14 Apr 2021 23:41:22 +0200 Subject: [PATCH] Restore @console handling and support for external getty - Drop vhangup(), how did things ever work *with* this in?! - setsid() + TIOCSCTTY are best buds, see notty code - Allow storing any non-NULL string as tty->dev, expand in service_register() - Reorder parse_cmdline_args(), we need to expand @console to current dev - Fix tty arg parser, swapparoo for external getty - Refactor tty_atcon(), iterated over by service_register() - New arg format, need to translate for old run_getty2() Signed-off-by: Joachim Wiberg --- src/exec.c | 9 +++--- src/service.c | 31 ++++++++++++++++---- src/svc.c | 2 ++ src/tty.c | 81 +++++++++++++++++++++++++++++++++++---------------- src/tty.h | 2 +- 5 files changed, 89 insertions(+), 36 deletions(-) diff --git a/src/exec.c b/src/exec.c index 37ea36ec..dc97b34e 100644 --- a/src/exec.c +++ b/src/exec.c @@ -245,10 +245,6 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit char name[80]; int fd; - /* Detach from initial controlling TTY and become session leader */ - vhangup(); - setsid(); - fd = open(tty, O_RDWR); if (fd < 0) { logit(LOG_ERR, "Failed opening %s: %s", tty, strerror(errno)); @@ -260,6 +256,11 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit dup2(fd, STDERR_FILENO); close(fd); + /* + * Become session leader and set controlling TTY + * to enable Ctrl-C and job control in shell. + */ + setsid(); if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0) logit(LOG_WARNING, "Failed TIOCSCTTY on %s: %s", tty, strerror(errno)); diff --git a/src/service.c b/src/service.c index 2c6e28fb..e532557e 100644 --- a/src/service.c +++ b/src/service.c @@ -988,6 +988,10 @@ static void parse_cmdline_args(svc_t *svc, char *cmd) continue; } + /* replace any @console arg with the expanded device name */ + if (svc_is_tty(svc) && tty_isatcon(svc->args[i])) + strlcpy(svc->args[i], svc->dev, sizeof(svc->args[i])); + if (strcmp(svc->args[i], prev)) diff++; @@ -1074,6 +1078,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) char *name = NULL, *halt = NULL, *delay = NULL; char *id = NULL, *env = NULL, *cgroup = NULL; struct tty tty = { 0 }; + char *dev = NULL; int levels = 0; int manual = 0; char *line; @@ -1167,7 +1172,9 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) if (tty_parse_args(cmd, &tty)) return errno; - len += tty.num + 5; + if (tty.cmd) + len += strlen(tty.cmd); + len += tty.num + 2; for (i = 0; i < tty.num; i++) len += strlen(tty.args[i]); @@ -1184,7 +1191,12 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) if (!cmd) return errno; - svc = svc_find_by_tty(tty.dev); + if (tty_isatcon(tty.dev)) + dev = tty_atcon(); + else + dev = tty.dev; + next: + svc = svc_find_by_tty(dev); } else svc = svc_find(cmd, id); @@ -1222,8 +1234,6 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) getcgroup(svc->group, sizeof(svc->group)); } - parse_cmdline_args(svc, cmd); - svc->runlevels = levels; _d("Service %s runlevel 0x%02x", svc->cmd, svc->runlevels); @@ -1232,8 +1242,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) if (type == SVC_TYPE_TTY) { char *ptr; - if (tty.dev) - strlcpy(svc->dev, tty.dev, sizeof(svc->dev)); + if (dev) + strlcpy(svc->dev, dev, sizeof(svc->dev)); if (tty.baud) strlcpy(svc->baud, tty.baud, sizeof(svc->baud)); if (tty.term) @@ -1261,6 +1271,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) } else parse_name(svc, name); + parse_cmdline_args(svc, cmd); + /* * Warn if svc generates same condition (based on name:id) * as an existing service. @@ -1302,6 +1314,13 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) if (!file) svc->protect = 1; + /* continue expanding any 'tty @console ...' */ + if (tty_isatcon(tty.dev)) { + dev = tty_atcon(); + if (dev) + goto next; + } + return 0; } diff --git a/src/svc.c b/src/svc.c index 8f3df45e..93e70727 100644 --- a/src/svc.c +++ b/src/svc.c @@ -192,6 +192,8 @@ void svc_validate(svc_t *svc) for (s = svc_iterator(&iter, 1); s; s = svc_iterator(&iter, 0)) { char c[MAX_COND_LEN]; + if (s->removed) + continue; if (s == svc) continue; diff --git a/src/tty.c b/src/tty.c index e5581e5b..06a7b737 100644 --- a/src/tty.c +++ b/src/tty.c @@ -47,6 +47,8 @@ char *tty_canonicalize(char *dev) if (!dev) return NULL; + if (tty_isatcon(dev)) + return dev; strlcpy(path, dev, sizeof(path)); if (stat(path, &st)) { @@ -76,26 +78,51 @@ int tty_isatcon(char *dev) return dev && !strcmp(dev, "@console"); } -int tty_atcon(char *buf, size_t len) +/* + * Returns console TTYs known by the kernel, from cmdline + */ +char *tty_atcon(void) { - FILE *fp; + static char *buf = NULL; + static char *save; + char *ptr = NULL; + char *dev; - fp = fopen("/sys/class/tty/console/active", "r"); - if (!fp) { - _e("Cannot find system console, is sysfs not mounted?"); - errno = ENOENT; - return -1; - } + if (!buf) { + FILE *fp; - if (!fgets(buf, len, fp)) { + fp = fopen("/sys/class/tty/console/active", "r"); + if (!fp) { + _e("Cannot find system console, is sysfs not mounted?"); + errno = ENOENT; + return NULL; + } + + buf = malloc(512); + if (!buf) { + _pe("Failed allocating memory for @console"); + fclose(fp); + return NULL; + } + + if (!fgets(buf, 512, fp)) { + fclose(fp); + goto done; + } fclose(fp); - return -1; + + ptr = chomp(buf); + _d("consoles: %s", ptr); } - chomp(buf); - fclose(fp); + dev = strtok_r(ptr, " \t", &save); + if (!dev) { + done: + free(buf); + return buf = NULL; + } - return 0; + return dev; } /** @@ -133,6 +160,8 @@ int tty_parse_args(char *cmd, struct tty *tty) tty->nologin = 1; else if (!strcmp(cmd, "notty")) tty->notty = 1; /* for fallback shell */ + else if (!access(cmd, X_OK)) + tty->cmd = cmd; else tty->args[tty->num++] = cmd; @@ -151,15 +180,13 @@ int tty_parse_args(char *cmd, struct tty *tty) * tty [12345] /dev/ttyAMA0 115200 noclear vt220 # built-in * tty [12345] /sbin/getty -L 115200 @console vt100 noclear # external */ - if ((!tty->cmd && !dev) || (tty->cmd && !dev)) { + if (!dev) { if (!strcmp(tty->args[i], "@console")) dev = tty->args[i]; if (!strncmp(tty->args[i], "/dev", 4)) dev = tty->args[i]; if (!strncmp(tty->args[i], "tty", 3) || !strcmp(tty->args[i], "console")) dev = tty->args[i]; - if (!access(tty->args[i], X_OK)) - tty->cmd = tty->args[i]; /* The first arg must be one of the above */ continue; @@ -182,9 +209,7 @@ int tty_parse_args(char *cmd, struct tty *tty) } } - if (!tty_isatcon(dev)) - tty->dev = tty_canonicalize(dev); - + tty->dev = tty_canonicalize(dev); if (!tty->dev) { _e("Incomplete or non-existing TTY device given, cannot register."); return errno = EINVAL; @@ -214,8 +239,9 @@ static int tty_exist(char *dev) int tty_exec(svc_t *tty) { + char *args[MAX_NUM_SVC_ARGS]; char *dev; - int rc; + int i, j; if (tty->notty) { /* @@ -247,12 +273,17 @@ int tty_exec(svc_t *tty) _d("%s: Starting %sgetty ...", dev, !tty->cmd ? "built-in " : ""); if (!strcmp(tty->cmd, "tty")) - rc = run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit); - else -// rc = run_getty2(dev, tty->cmd, tty->args, tty->noclear, tty->nowait, tty->rlimit); - rc = -1; + return run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit); - return rc; + for (i = 1, j = 0; i < MAX_NUM_SVC_ARGS; i++) { + if (!tty->args[i][0]) + break; + + args[j++] = tty->args[i]; + } + args[j++] = NULL; + + return run_getty2(dev, tty->cmd, args, tty->noclear, tty->nowait, tty->rlimit); } /* diff --git a/src/tty.h b/src/tty.h index a8a151c5..8007a344 100644 --- a/src/tty.h +++ b/src/tty.h @@ -45,7 +45,7 @@ struct tty { char *tty_canonicalize (char *dev); int tty_isatcon (char *dev); -int tty_atcon (char *buf, size_t len); +char *tty_atcon (void); int tty_parse_args (char *cmdline, struct tty *tty);