mirror of
https://github.com/troglobit/finit.git
synced 2026-11-12 16:51:25 +00:00
Merge branch 'external-getty-support'
This commit is contained in:
commit
513f03b897
6 files changed
+197
-36
No files matched your search
@@ -86,9 +86,14 @@ inetd ssh/tcp@*,!eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service
|
|||||||
# Run start scripts from this directory
|
# Run start scripts from this directory
|
||||||
# runparts /etc/start.d
|
# runparts /etc/start.d
|
||||||
|
|
||||||
# Virtual consoles to start built-in getty on
|
# Virtual consoles run BusyBox getty
|
||||||
tty [12345] /dev/tty1 115200 linux
|
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/ttyAMA0 115200 vt100
|
||||||
|
tty [12345] /dev/ttyUSB0 115200 vt100
|
||||||
```
|
```
|
||||||
|
|
||||||
The `service` stanza, as well as `task`, `run`, `inetd` and others are
|
The `service` stanza, as well as `task`, `run`, `inetd` and others are
|
||||||
|
|||||||
+13
-2
@@ -137,13 +137,24 @@ Syntax:
|
|||||||
Include another configuration file. Absolute path required.
|
Include another configuration file. Absolute path required.
|
||||||
|
|
||||||
* `tty [LVLS] <DEV> [BAUD] [TERM] [noclear]`
|
* `tty [LVLS] <DEV> [BAUD] [TERM] [noclear]`
|
||||||
Start the built-in getty on the given TTY device DEV, in the given
|
`tty [LVLS] <CMD> <ARGS>`
|
||||||
runlevels. Default baud rate is `38400`.
|
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
|
```conf
|
||||||
tty [12345] /dev/ttyAMA0 115200 noclear
|
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
|
On really bare bones systems Finit offers a fallback shell, but one
|
||||||
can also use the `service` stanza to start a stand-alone shell:
|
can also use the `service` stanza to start a stand-alone shell:
|
||||||
|
|
||||||
|
|||||||
+76
-12
@@ -27,6 +27,7 @@
|
|||||||
#include <ctype.h> /* isdigit() */
|
#include <ctype.h> /* isdigit() */
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
@@ -212,30 +213,93 @@ int run_interactive(char *cmd, char *fmt, ...)
|
|||||||
return status;
|
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 run_getty(char *tty, char *speed, char *term, int noclear, int console)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
/* Reset signal handlers that were set by the parent process */
|
prepare_tty(tty, "finit-getty", console);
|
||||||
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);
|
|
||||||
|
|
||||||
_exit(getty(tty, speed, term, noclear, NULL));
|
_exit(getty(tty, speed, term, noclear, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
return pid;
|
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)
|
int run_parts(char *dir, char *cmd)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ int complete (char *cmd, int pid);
|
|||||||
int run (char *cmd);
|
int run (char *cmd);
|
||||||
int run_interactive (char *cmd, char *fmt, ...);
|
int run_interactive (char *cmd, char *fmt, ...);
|
||||||
pid_t run_getty (char *tty, char *speed, char *term, int noclear, int console);
|
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);
|
int run_parts (char *dir, char *cmd);
|
||||||
|
|
||||||
static inline void create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
static inline void create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
|||||||
@@ -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)
|
int tty_register(char *line, struct timeval *mtime)
|
||||||
{
|
{
|
||||||
tty_node_t *entry;
|
tty_node_t *entry;
|
||||||
int insert = 0, noclear = 0;
|
int i, num = 1, insert = 0, noclear = 0;
|
||||||
char *tok, *dev = NULL, *baud = NULL;
|
char *tok, *cmd = NULL, *args[TTY_MAX_ARGS];
|
||||||
|
char *dev = NULL, *baud = NULL;
|
||||||
char *runlevels = NULL, *term = NULL;
|
char *runlevels = NULL, *term = NULL;
|
||||||
|
|
||||||
if (!line) {
|
if (!line) {
|
||||||
@@ -96,24 +117,58 @@ int tty_register(char *line, struct timeval *mtime)
|
|||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tok = strtok(line, " ");
|
tok = strchr(line, '/');
|
||||||
while (tok) {
|
if (tok && strncmp(tok, "/dev", 4)) {
|
||||||
if (tok[0] == '[')
|
/* External getty */
|
||||||
runlevels = &tok[0];
|
cmd = tok;
|
||||||
else if (tok[0] == '/')
|
|
||||||
dev = tok;
|
|
||||||
else if (isdigit(tok[0]))
|
|
||||||
baud = tok;
|
|
||||||
else if (!strcmp(tok, "noclear"))
|
|
||||||
noclear = 1;
|
|
||||||
else
|
|
||||||
term = 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) {
|
if (!dev) {
|
||||||
_e("Incomplete tty, cannot register");
|
_e("Incomplete tty, no device given, cannot register.");
|
||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,15 +176,24 @@ int tty_register(char *line, struct timeval *mtime)
|
|||||||
if (!entry) {
|
if (!entry) {
|
||||||
insert = 1;
|
insert = 1;
|
||||||
entry = calloc(1, sizeof(*entry));
|
entry = calloc(1, sizeof(*entry));
|
||||||
if (!entry)
|
if (!entry) {
|
||||||
|
free(dev);
|
||||||
return errno = ENOMEM;
|
return errno = ENOMEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->data.name = strdup(dev);
|
entry->data.name = dev;
|
||||||
entry->data.baud = baud ? strdup(baud) : NULL;
|
entry->data.baud = baud ? strdup(baud) : NULL;
|
||||||
entry->data.term = term ? strdup(term) : NULL;
|
entry->data.term = term ? strdup(term) : NULL;
|
||||||
entry->data.noclear = noclear;
|
entry->data.noclear = noclear;
|
||||||
entry->data.runlevels = conf_parse_runlevels(runlevels);
|
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",
|
_d("Registering tty %s at %s baud with term=%s on runlevels %s",
|
||||||
dev, baud ?: "NULL", term ?: "N/A", runlevels ?: "[2-5]");
|
dev, baud ?: "NULL", term ?: "N/A", runlevels ?: "[2-5]");
|
||||||
|
|
||||||
@@ -155,6 +219,15 @@ int tty_unregister(tty_node_t *tty)
|
|||||||
free(tty->data.baud);
|
free(tty->data.baud);
|
||||||
if (tty->data.term)
|
if (tty->data.term)
|
||||||
free(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);
|
free(tty);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -275,7 +348,10 @@ void tty_start(finit_tty_t *tty)
|
|||||||
return;
|
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)
|
void tty_stop(finit_tty_t *tty)
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
|
||||||
|
#define TTY_MAX_ARGS 16
|
||||||
#define EVENT_SIZE ((sizeof(struct inotify_event) + NAME_MAX + 1))
|
#define EVENT_SIZE ((sizeof(struct inotify_event) + NAME_MAX + 1))
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -37,6 +38,9 @@ typedef struct {
|
|||||||
int noclear;
|
int noclear;
|
||||||
int runlevels;
|
int runlevels;
|
||||||
|
|
||||||
|
char *cmd; /* NULL when running built-in getty */
|
||||||
|
char *args[TTY_MAX_ARGS];
|
||||||
|
|
||||||
int pid;
|
int pid;
|
||||||
} finit_tty_t;
|
} finit_tty_t;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user