From b629348973d6780ca2f8acbb0cd6952a30caec5d Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 26 Aug 2017 19:32:09 +0200 Subject: [PATCH 1/8] Refactor TTY exec, prepare for external getty Signed-off-by: Joachim Nilsson --- src/exec.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/exec.c b/src/exec.c index 06a3e2b2..49fb95a1 100644 --- a/src/exec.c +++ b/src/exec.c @@ -212,31 +212,41 @@ int run_interactive(char *cmd, char *fmt, ...) return status; } +static void prepare_tty(char *tty, char *procname, int console) +{ + /* Reset signal handlers that were set by the parent process */ + sig_unblock(); + setsid(); + + /* Set INIT_PROCESS UTMP entry */ + utmp_set_init(tty, 0); + + if (console) + procname = "console"; + prctl(PR_SET_NAME, procname, 0, 0, 0); +} + pid_t run_getty(char *tty, char *speed, char *term, int noclear, int console) { pid_t pid; pid = fork(); if (!pid) { - /* Reset signal handlers that were set by the parent process */ - sig_unblock(); - setsid(); - - /* Set INIT_PROCESS UTMP entry */ - utmp_set_init(tty, 0); - - if (console) - prctl(PR_SET_NAME, "console", 0, 0, 0); - else - prctl(PR_SET_NAME, "finit-getty", 0, 0, 0); - + prepare_tty(tty, "finit-getty", console); _exit(getty(tty, speed, term, noclear, NULL)); } return pid; } + /* Reset signal handlers that were set by the parent process */ + + } + + return pid; +} + int run_parts(char *dir, char *cmd) { struct dirent **e; From 7c50d86a559674e86a659fa03fcf7a2f71f1a1ff Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 27 Aug 2017 15:01:42 +0200 Subject: [PATCH 2/8] Restore pre built-in run_getty() as run_getty2() Signed-off-by: Joachim Nilsson --- src/exec.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/helpers.h | 1 + 2 files changed, 55 insertions(+) diff --git a/src/exec.c b/src/exec.c index 49fb95a1..a0b7ca24 100644 --- a/src/exec.c +++ b/src/exec.c @@ -27,6 +27,7 @@ #include /* isdigit() */ #include #include +#include #include #include #include @@ -238,10 +239,63 @@ pid_t run_getty(char *tty, char *speed, char *term, int noclear, int console) return pid; } + +pid_t run_getty2(char *tty, char *cmd, char *args[], int console) +{ + pid_t pid; + + pid = fork(); + if (!pid) { + int i, fd; + struct sigaction sa; + /* Reset signal handlers that were set by the parent process */ + for (i = 1; i < NSIG; i++) + DFLSIG(sa, i, 0); + /* Detach from initial controlling TTY */ + vhangup(); + close(STDERR_FILENO); + close(STDOUT_FILENO); + close(STDIN_FILENO); + /* Attach TTY to console */ + fd = open(tty, O_RDWR); + if (fd != STDIN_FILENO) + exit(1); + + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + + prepare_tty(tty, "getty", console); + + if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0) + _pe("Failed TIOCSCTTY"); + + while (!fexist(SYNC_SHUTDOWN)) { + char c; + static const char msg[] = "\nPlease press Enter to activate this console."; + + if (fexist(SYNC_STOPPED)) { + sleep(1); + continue; + } + + (void)write(STDERR_FILENO, msg, sizeof(msg)); + while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n') + continue; + + if (fexist(SYNC_STOPPED)) + continue; + + execv(cmd, args); + } + + close(fd); + vhangup(); + exit(0); } return pid; diff --git a/src/helpers.h b/src/helpers.h index 4c762850..cb06d81c 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -64,6 +64,7 @@ int complete (char *cmd, int pid); int run (char *cmd); int run_interactive (char *cmd, char *fmt, ...); pid_t run_getty (char *tty, char *speed, char *term, int noclear, int console); +pid_t run_getty2 (char *tty, char *cmd, char *args[], int console); int run_parts (char *dir, char *cmd); static inline void create(char *path, mode_t mode, uid_t uid, gid_t gid) From 19fcfcfef4854793260029e8af71dd8b7eed6b18 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 27 Aug 2017 15:02:55 +0200 Subject: [PATCH 3/8] Initial support for external getty Signed-off-by: Joachim Nilsson --- src/tty.c | 94 +++++++++++++++++++++++++++++++++++++++++++------------ src/tty.h | 3 ++ 2 files changed, 77 insertions(+), 20 deletions(-) diff --git a/src/tty.c b/src/tty.c index ec63cf5c..beed0c34 100644 --- a/src/tty.c +++ b/src/tty.c @@ -83,12 +83,33 @@ void tty_sweep(void) } } -/* tty [!1-9,S] [BAUD[,BAUD,...]] [TERM] [noclear] */ +/** + * tty_register - Register a getty on a device + * @line: Configuration, text after initial "tty" + * @mtime: Modification time, to propagate to lower layers + * + * A Finit tty line can use the internal getty implementation or an + * external one, like the BusyBox getty for instance. This function + * determines which one to use based on a leading '/dev' prefix. If + * a leading '/dev' is encountered the remaining options must be in + * the following sequence: + * + * tty [!1-9,S] [BAUD[,BAUD,...]] [TERM] [noclear] + * + * Otherwise the leading prefix must be the full path to an existing + * getty implementation, with it's arguments following: + * + * tty [!1-9,S] [ARGS] + * + * Different getty implementations prefer the TTY device argument in + * different order, so take care to investigate this first. + */ int tty_register(char *line, struct timeval *mtime) { tty_node_t *entry; - int insert = 0, noclear = 0; - char *tok, *dev = NULL, *baud = NULL; + int i, num = 0, insert = 0, noclear = 0; + char *tok, *cmd = NULL, *args[10]; + char *dev = NULL, *baud = NULL; char *runlevels = NULL, *term = NULL; if (!line) { @@ -96,24 +117,45 @@ int tty_register(char *line, struct timeval *mtime) return errno = EINVAL; } - tok = strtok(line, " "); - while (tok) { - if (tok[0] == '[') - runlevels = &tok[0]; - else if (tok[0] == '/') - dev = tok; - else if (isdigit(tok[0])) - baud = tok; - else if (!strcmp(tok, "noclear")) - noclear = 1; - else - term = tok; + tok = strchr(line, '/'); + if (tok && strncmp(tok, "/dev", 4)) { + /* External getty */ + cmd = tok; - tok = strtok(NULL, " "); + tok = strtok(line, " "); + while (tok) { + if (tok[0] == '[') { + runlevels = &tok[0]; + } else if (tok[0] == '/' && tok != cmd) { + dev = strdup(tok); + args[num++] = tok; + } else { + args[num++] = tok; + } + + tok = strtok(NULL, " "); + } + } else { + /* Built-in getty */ + tok = strtok(line, " "); + while (tok) { + if (tok[0] == '[') + runlevels = &tok[0]; + else if (tok[0] == '/') + dev = strdup(tok); + else if (isdigit(tok[0])) + baud = tok; + else if (!strcmp(tok, "noclear")) + noclear = 1; + else + term = tok; + + tok = strtok(NULL, " "); + } } if (!dev) { - _e("Incomplete tty, cannot register"); + _e("Incomplete tty, no device given, cannot register."); return errno = EINVAL; } @@ -121,15 +163,24 @@ int tty_register(char *line, struct timeval *mtime) if (!entry) { insert = 1; entry = calloc(1, sizeof(*entry)); - if (!entry) + if (!entry) { + free(dev); return errno = ENOMEM; + } } - entry->data.name = strdup(dev); + entry->data.name = dev; entry->data.baud = baud ? strdup(baud) : NULL; entry->data.term = term ? strdup(term) : NULL; entry->data.noclear = noclear; entry->data.runlevels = conf_parse_runlevels(runlevels); + + /* External getty */ + entry->data.cmd = cmd; + for (i = 0; i < num; i++) + entry->data.args[i] = args[i]; + entry->data.args[++i] = NULL; + _d("Registering tty %s at %s baud with term=%s on runlevels %s", dev, baud ?: "NULL", term ?: "N/A", runlevels ?: "[2-5]"); @@ -275,7 +326,10 @@ void tty_start(finit_tty_t *tty) return; } - tty->pid = run_getty(dev, tty->baud, tty->term, tty->noclear, is_console); + if (!tty->cmd) + tty->pid = run_getty(dev, tty->baud, tty->term, tty->noclear, is_console); + else + tty->pid = run_getty2(dev, tty->cmd, tty->args, is_console); } void tty_stop(finit_tty_t *tty) diff --git a/src/tty.h b/src/tty.h index 9b9ed166..f2091efa 100644 --- a/src/tty.h +++ b/src/tty.h @@ -37,6 +37,9 @@ typedef struct { int noclear; int runlevels; + char *cmd; /* NULL when running built-in getty */ + char *args[10]; + int pid; } finit_tty_t; From 675f82a6b97b88322e542681618ec78a6666f376 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 27 Aug 2017 16:41:58 +0200 Subject: [PATCH 4/8] run_getty2(): Minor fixes only, whitespace + cautionary _exit() Signed-off-by: Joachim Nilsson --- src/exec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/exec.c b/src/exec.c index a0b7ca24..ec3b51c2 100644 --- a/src/exec.c +++ b/src/exec.c @@ -285,12 +285,12 @@ pid_t run_getty2(char *tty, char *cmd, char *args[], int console) (void)write(STDERR_FILENO, msg, sizeof(msg)); while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n') - continue; + continue; if (fexist(SYNC_STOPPED)) continue; - execv(cmd, args); + _exit(execv(cmd, args)); } close(fd); From 74affb32d3448ed59377138bc2e5fb69cf93ca8c Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 27 Aug 2017 16:43:01 +0200 Subject: [PATCH 5/8] tty_register(): Fix parser for external getty Signed-off-by: Joachim Nilsson --- src/tty.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/tty.c b/src/tty.c index beed0c34..e73ffb36 100644 --- a/src/tty.c +++ b/src/tty.c @@ -107,7 +107,7 @@ void tty_sweep(void) int tty_register(char *line, struct timeval *mtime) { tty_node_t *entry; - int i, num = 0, insert = 0, noclear = 0; + int i, num = 1, insert = 0, noclear = 0; char *tok, *cmd = NULL, *args[10]; char *dev = NULL, *baud = NULL; char *runlevels = NULL, *term = NULL; @@ -122,19 +122,30 @@ int tty_register(char *line, struct timeval *mtime) /* External getty */ cmd = tok; - tok = strtok(line, " "); - while (tok) { - if (tok[0] == '[') { - runlevels = &tok[0]; - } else if (tok[0] == '/' && tok != cmd) { - dev = strdup(tok); - args[num++] = tok; - } else { - args[num++] = tok; + for (tok = strtok(line, " "); tok; tok = strtok(NULL, " ")) { + if (cmd == tok) { + cmd = strdup(tok); + continue; } - tok = strtok(NULL, " "); + if (tok[0] == '[') { + runlevels = &tok[0]; + continue; + } + + if (tok[0] == '/' && tok != cmd) + dev = strdup(tok); + + args[num++] = strdup(tok); } + + cmd = strdup(cmd); + tok = strrchr(cmd, '/'); + if (!tok) + tok = cmd; + else + tok++; + args[0] = strdup(tok); } else { /* Built-in getty */ tok = strtok(line, " "); From f7b9b7be960db6e5c05241f69aa5de7073624147 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 27 Aug 2017 16:57:26 +0200 Subject: [PATCH 6/8] tty.c: Free memory for external getty on tty_unregister() Signed-off-by: Joachim Nilsson --- src/tty.c | 15 +++++++++++++-- src/tty.h | 3 ++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/tty.c b/src/tty.c index e73ffb36..37f20596 100644 --- a/src/tty.c +++ b/src/tty.c @@ -108,7 +108,7 @@ int tty_register(char *line, struct timeval *mtime) { tty_node_t *entry; int i, num = 1, insert = 0, noclear = 0; - char *tok, *cmd = NULL, *args[10]; + char *tok, *cmd = NULL, *args[TTY_MAX_ARGS]; char *dev = NULL, *baud = NULL; char *runlevels = NULL, *term = NULL; @@ -137,6 +137,8 @@ int tty_register(char *line, struct timeval *mtime) dev = strdup(tok); args[num++] = strdup(tok); + if (num >= TTY_MAX_ARGS) + break; } cmd = strdup(cmd); @@ -188,7 +190,7 @@ int tty_register(char *line, struct timeval *mtime) /* External getty */ entry->data.cmd = cmd; - for (i = 0; i < num; i++) + for (i = 0; i < num && i < TTY_MAX_ARGS; i++) entry->data.args[i] = args[i]; entry->data.args[++i] = NULL; @@ -217,6 +219,15 @@ int tty_unregister(tty_node_t *tty) free(tty->data.baud); if (tty->data.term) free(tty->data.term); + if (tty->data.cmd) { + int i; + + free(tty->data.cmd); + for (i = 0; tty->data.args[i] && i < TTY_MAX_ARGS; i++) { + free(tty->data.args[i]); + tty->data.args[i] = NULL; + } + } free(tty); return 0; diff --git a/src/tty.h b/src/tty.h index f2091efa..a484aefa 100644 --- a/src/tty.h +++ b/src/tty.h @@ -28,6 +28,7 @@ #include #include /* BSD sys/queue.h API */ +#define TTY_MAX_ARGS 16 #define EVENT_SIZE ((sizeof(struct inotify_event) + NAME_MAX + 1)) typedef struct { @@ -38,7 +39,7 @@ typedef struct { int runlevels; char *cmd; /* NULL when running built-in getty */ - char *args[10]; + char *args[TTY_MAX_ARGS]; int pid; } finit_tty_t; From f9f1846c8b0d849f8fd40e127dc33f3576f3337f Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 27 Aug 2017 17:03:39 +0200 Subject: [PATCH 7/8] Document alternative `tty ...` config option for external getty Signed-off-by: Joachim Nilsson --- doc/config.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/doc/config.md b/doc/config.md index 97485a3d..82b93034 100644 --- a/doc/config.md +++ b/doc/config.md @@ -137,13 +137,24 @@ Syntax: Include another configuration file. Absolute path required. * `tty [LVLS] [BAUD] [TERM] [noclear]` - Start the built-in getty on the given TTY device DEV, in the given - runlevels. Default baud rate is `38400`. + `tty [LVLS] ` + The first variant of this option uses the built-in getty on the given + TTY device DEV, in the given runlevels. Default baud rate is `38400`. + **Example:** ```conf tty [12345] /dev/ttyAMA0 115200 noclear ``` + The second variant is for using an external getty, like agetty or the + BusyBox getty. There are no default settings for this variant, but a + word of caution: *you have give the absolute path to the TTY*. + + **Example:** +```conf + tty [12345] /sbin/getty -L 115200 /dev/ttyAMA0 vt100 +``` + On really bare bones systems Finit offers a fallback shell, but one can also use the `service` stanza to start a stand-alone shell: From 371fb3d0d06e2b5b5d37832970cc92d228b09614 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 27 Aug 2017 17:07:12 +0200 Subject: [PATCH 8/8] Add example for using an external getty Signed-off-by: Joachim Nilsson --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 70371c4f..2cfc8324 100644 --- a/README.md +++ b/README.md @@ -86,9 +86,14 @@ inetd ssh/tcp@*,!eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service # Run start scripts from this directory # runparts /etc/start.d -# Virtual consoles to start built-in getty on -tty [12345] /dev/tty1 115200 linux +# Virtual consoles run BusyBox getty +tty [12345] /sbin/getty -L 115200 /dev/tty1 linux +tty [12345] /sbin/getty -L 115200 /dev/tty2 linux +tty [12345] /sbin/getty -L 115200 /dev/tty3 linux + +# Use built-in getty for serial port and USB serial tty [12345] /dev/ttyAMA0 115200 vt100 +tty [12345] /dev/ttyUSB0 115200 vt100 ``` The `service` stanza, as well as `task`, `run`, `inetd` and others are