Merge branch 'external-getty-support'

This commit is contained in:
Joachim Nilsson
2017-08-27 17:08:21 +02:00
6 changed files with 197 additions and 36 deletions
+7 -2
View File
@@ -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
+13 -2
View File
@@ -137,13 +137,24 @@ Syntax:
Include another configuration file. Absolute path required.
* `tty [LVLS] <DEV> [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] <CMD> <ARGS>`
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:
+76 -12
View File
@@ -27,6 +27,7 @@
#include <ctype.h> /* isdigit() */
#include <dirent.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <lite/lite.h>
@@ -212,30 +213,93 @@ 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;
}
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;
_exit(execv(cmd, args));
}
close(fd);
vhangup();
exit(0);
}
return pid;
}
int run_parts(char *dir, char *cmd)
{
+1
View File
@@ -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)
+96 -20
View File
@@ -83,12 +83,33 @@ void tty_sweep(void)
}
}
/* tty [!1-9,S] <DEV> [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] <DEV> [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] </path/to/getty> [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 = 1, insert = 0, noclear = 0;
char *tok, *cmd = NULL, *args[TTY_MAX_ARGS];
char *dev = NULL, *baud = NULL;
char *runlevels = NULL, *term = NULL;
if (!line) {
@@ -96,24 +117,58 @@ 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, " ");
for (tok = strtok(line, " "); tok; tok = strtok(NULL, " ")) {
if (cmd == tok) {
cmd = strdup(tok);
continue;
}
if (tok[0] == '[') {
runlevels = &tok[0];
continue;
}
if (tok[0] == '/' && tok != cmd)
dev = strdup(tok);
args[num++] = strdup(tok);
if (num >= TTY_MAX_ARGS)
break;
}
cmd = strdup(cmd);
tok = strrchr(cmd, '/');
if (!tok)
tok = cmd;
else
tok++;
args[0] = strdup(tok);
} 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 +176,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 < TTY_MAX_ARGS; 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]");
@@ -155,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;
@@ -275,7 +348,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)
+4
View File
@@ -28,6 +28,7 @@
#include <limits.h>
#include <lite/queue.h> /* BSD sys/queue.h API */
#define TTY_MAX_ARGS 16
#define EVENT_SIZE ((sizeof(struct inotify_event) + NAME_MAX + 1))
typedef struct {
@@ -37,6 +38,9 @@ typedef struct {
int noclear;
int runlevels;
char *cmd; /* NULL when running built-in getty */
char *args[TTY_MAX_ARGS];
int pid;
} finit_tty_t;