mirror of
https://github.com/troglobit/finit.git
synced 2026-10-17 10:49:34 +00:00
Merge pull request #488 from Ollie-Gutierrez/ctty-support
service: add optional controlling TTY via tty: stanza
This commit is contained in:
6 files changed
+130
-2
No files matched your search
@@ -46,6 +46,7 @@ Other run/task/service options are:
|
||||
* `cgroup.NAME[,opts]` or `cgroup:opts` -- see the [Cgroups](cgroups.md) section
|
||||
* `env:[-]/path/to/env` -- see the [Service Environment](service-env.md) section
|
||||
* `log:...` -- see [Redirecting Output](logging.md#redirecting-output)
|
||||
* `tty:<dev>` -- see [Controlling TTY](tty.md#controlling-tty)
|
||||
* `nowarn` -- see [Conditional Loading](services.md#conditional-loading)
|
||||
* `notify:...` -- see [Service Synchronization](service-sync.md)
|
||||
* `if:...` -- see [Conditional Execution](services.md#conditional-execution)
|
||||
|
||||
+28
-1
@@ -83,4 +83,31 @@ board bringup and system debugging it can come in handy.
|
||||
|
||||
One can also use the `service` stanza to start a stand-alone shell:
|
||||
|
||||
service [12345] /bin/sh -l
|
||||
service [12345] /bin/sh -l
|
||||
|
||||
Controlling TTY for Services
|
||||
----------------------------
|
||||
|
||||
The `tty:<dev>` option gives a `run`, `task`, or `service` a controlling
|
||||
terminal on the given device. The device is opened, set as the
|
||||
controlling terminal for the session (after `setsid()`), and connected to
|
||||
the process's stdin, stdout, and stderr. A default `TERM` environment
|
||||
variable is set based on the device type: `vt102` for serial lines and
|
||||
`linux` for virtual terminals.
|
||||
|
||||
`<dev>` may be a device node like `/dev/ttyS0`, or the special keyword
|
||||
`@console` (see above). Note that `@console` expands only to the
|
||||
first console, not all.
|
||||
|
||||
When `tty:` is combined with `log:`, stdout and stderr are redirected
|
||||
to the log sink instead of the TTY, but stdin remains connected to the
|
||||
TTY device.
|
||||
|
||||
> The `tty:<dev>` option is for `run`, `task`, and `service` stanzas only.
|
||||
> The `tty` directive itself (for getty/login) has its own syntax, see
|
||||
> above.
|
||||
|
||||
**Example:**
|
||||
|
||||
service [2345] tty:/dev/ttyS0 /usr/sbin/foo -- Foo on serial console
|
||||
task [S] tty:@console my-setup-script -- Board bringup on console
|
||||
+2
-1
@@ -61,7 +61,8 @@ For more complex setups (LUKS, LVM, etc.):
|
||||
|
||||
```
|
||||
# Unlock LUKS volume
|
||||
run [S] name:cryptsetup /sbin/cryptsetup open /dev/sda2 cryptroot -- Unlocking encrypted root
|
||||
# The tty:@console stanza is required so cryptsetup can prompt for a passphrase
|
||||
run [S] name:cryptsetup tty:@console /sbin/cryptsetup open /dev/sda2 cryptroot -- Unlocking encrypted root
|
||||
|
||||
# Activate LVM
|
||||
run [S] name:lvm /sbin/lvm vgchange -ay -- Activating LVM volumes
|
||||
|
||||
@@ -744,6 +744,37 @@ is
|
||||
and the default
|
||||
.Cm tag
|
||||
identity is the basename of the service or run/task command.
|
||||
.It Cm tty:\&<dev>
|
||||
Give the
|
||||
.Cm run , task ,
|
||||
or
|
||||
.Cm service
|
||||
a controlling terminal on
|
||||
.Cm <dev> .
|
||||
The device is opened, set as the controlling terminal for the session
|
||||
(after
|
||||
.Fn setsid ) ,
|
||||
and connected to stdin, stdout, and stderr.
|
||||
A default
|
||||
.Ev TERM
|
||||
variable is set based on the device type:
|
||||
.Cm vt102
|
||||
for serial lines and
|
||||
.Cm linux
|
||||
for virtual terminals.
|
||||
.Cm <dev>
|
||||
may be a device node like
|
||||
.Pa /dev/ttyS0 ,
|
||||
or the special keyword
|
||||
.Cm @console
|
||||
(see TTYs and Consoles above).
|
||||
When combined with
|
||||
.Cm log: ,
|
||||
stdout and stderr are redirected to the log sink instead, but stdin
|
||||
remains connected to the TTY device.
|
||||
.Bd -unfilled -offset indent
|
||||
service [2345] tty:/dev/ttyS0 /usr/sbin/foo -- Foo on serial console
|
||||
.Ed
|
||||
.El
|
||||
.Sh RESCUE MODE
|
||||
Finit supports a rescue mode which is activated by the
|
||||
|
||||
@@ -29,10 +29,12 @@
|
||||
#include <sched.h> /* sched_yield() */
|
||||
#include <string.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <linux/vt.h>
|
||||
#include <net/if.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
@@ -387,6 +389,43 @@ static int lredirect(svc_t *svc)
|
||||
return close(pipefd[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a controlling TTY for run/task/service.
|
||||
* Opens the TTY device, dups to 0/1/2, resets termios to
|
||||
* sane defaults, sets TERM env, and updates procname.
|
||||
*/
|
||||
static void svc_prepare_ctty(const char *tty, const char *procname, int log)
|
||||
{
|
||||
int fd, dummy;
|
||||
|
||||
fd = open(tty, O_RDWR);
|
||||
if (fd < 0) {
|
||||
logit(LOG_ERR, "Failed opening %s: %s", tty, strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* Acquire as controlling terminal for the session */
|
||||
ioctl(fd, TIOCSCTTY, 0);
|
||||
|
||||
dup2(fd, STDIN_FILENO);
|
||||
if (!log) {
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
}
|
||||
|
||||
/* Set default TERM */
|
||||
if (ioctl(fd, VT_OPENQRY, &dummy) == -1)
|
||||
setenv("TERM", "vt102", 1); /* likely a serial line */
|
||||
else
|
||||
setenv("TERM", "linux", 1);
|
||||
|
||||
/* Reset to sane defaults */
|
||||
stty(fd, B0);
|
||||
close(fd);
|
||||
|
||||
prctl(PR_SET_NAME, procname, 0, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle redirection of process output, if enabled
|
||||
*/
|
||||
@@ -946,6 +985,14 @@ static int service_start(svc_t *svc)
|
||||
|
||||
sig_unblock();
|
||||
|
||||
/*
|
||||
* If the stanza declared tty:<dev>, set up a controlling
|
||||
* terminal on that device now that we're a session leader.
|
||||
* Must run after setsid() to acquire the controlling TTY.
|
||||
*/
|
||||
if (!svc_is_tty(svc) && svc_has_ctty(svc))
|
||||
svc_prepare_ctty(svc->log.ctty, svc->cmd, !!svc->log.enabled);
|
||||
|
||||
if (svc_is_runtask(svc))
|
||||
status = exec_runtask(args[0], &args[1]);
|
||||
else if (svc_is_tty(svc))
|
||||
@@ -1795,6 +1842,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
char ident[MAX_IDENT_LEN];
|
||||
char *ifstmt = NULL;
|
||||
char *notify = NULL;
|
||||
char *ctty = NULL;
|
||||
struct tty tty = { 0 };
|
||||
char *dev = NULL;
|
||||
int respawn = 0;
|
||||
@@ -1911,6 +1959,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
env = arg;
|
||||
else if (MATCH_CMD(cmd, "caps:", arg))
|
||||
caps = arg;
|
||||
else if (MATCH_CMD(cmd, "tty:", arg))
|
||||
ctty = arg;
|
||||
/* catch both cgroup: and cgroup. handled in parse_cgroup() */
|
||||
else if (MATCH_CMD(cmd, "cgroup", arg))
|
||||
cgroup = arg;
|
||||
@@ -2160,6 +2210,22 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
parse_caps(svc, caps);
|
||||
else
|
||||
memset(svc->capabilities, 0, sizeof(svc->capabilities));
|
||||
|
||||
if (!svc_is_tty(svc) && ctty) {
|
||||
char *dev = ctty;
|
||||
|
||||
/* NOTE: @console expands only to first console, not all */
|
||||
if (tty_isatcon(ctty))
|
||||
dev = tty_atcon();
|
||||
dev = tty_canonicalize(dev);
|
||||
if (dev)
|
||||
strlcpy(svc->log.ctty, dev, sizeof(svc->log.ctty));
|
||||
else
|
||||
logit(LOG_WARNING, "%s: tty: %s not found, skipping ctty", svc_ident(svc, NULL, 0), ctty);
|
||||
} else if (!svc_is_tty(svc)) {
|
||||
memset(svc->log.ctty, 0, sizeof(svc->log.ctty));
|
||||
}
|
||||
|
||||
if (file)
|
||||
strlcpy(svc->file, file, sizeof(svc->file));
|
||||
else
|
||||
|
||||
@@ -176,6 +176,7 @@ typedef struct svc {
|
||||
char file[64];
|
||||
char prio[20];
|
||||
char ident[20];
|
||||
char ctty[32];
|
||||
} log;
|
||||
|
||||
/* Only for TTY type services */
|
||||
@@ -291,6 +292,7 @@ static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && IS
|
||||
static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && svc->pidfile[0] != 0 && svc->pidfile[0] != '!'; }
|
||||
static inline int svc_has_pre (svc_t *svc) { return svc->pre_script[0]; }
|
||||
static inline int svc_has_post (svc_t *svc) { return svc->post_script[0]; }
|
||||
static inline int svc_has_ctty (svc_t *svc) { return svc && svc->log.ctty[0]; }
|
||||
static inline int svc_has_ready (svc_t *svc) { return svc->ready_script[0];}
|
||||
static inline int svc_has_cleanup (svc_t *svc) { return svc->cleanup_script[0]; }
|
||||
|
||||
|
||||
Reference in new issue
Block a user