mirror of
https://github.com/troglobit/finit.git
synced 2026-10-11 17:02:42 +07:00
Refactor tty handling to use service backend enabling conditions etc.
Initial refactor of the tty implementation to use the service/run/task general backend. This enables all the features of services also for ttys, except logging because it makes no sense. Work in progress: - plugins/tty.c does not work anymore, could possibly be removed in favor of usinga (a new) condition instead (if-tty-exists) - fallback tty does not work anymore, should we remove it, or can we handle it as an optional built-in with (a new) condition? - @console does not work anymore, needs to generate N cloned services Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
+2
-3
@@ -592,7 +592,7 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
||||
|
||||
/* Regular or serial TTYs to run getty */
|
||||
if (MATCH_CMD(line, "tty ", x)) {
|
||||
tty_register(strip_line(x), rlimit, file);
|
||||
service_register(SVC_TYPE_TTY, strip_line(x), rlimit, file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -664,7 +664,6 @@ int conf_reload(void)
|
||||
/* Mark and sweep */
|
||||
cgroup_mark_all();
|
||||
svc_mark_dynamic();
|
||||
tty_mark();
|
||||
|
||||
/*
|
||||
* Reset global rlimit to bootstrap values from conf_init().
|
||||
@@ -678,7 +677,7 @@ int conf_reload(void)
|
||||
/* If rescue.conf is missing, fall back to a root shell */
|
||||
rc = parse_conf(RESCUE_CONF, 0);
|
||||
if (rc)
|
||||
tty_register(line, global_rlimit, NULL);
|
||||
service_register(SVC_TYPE_TTY, line, global_rlimit, NULL);
|
||||
|
||||
print(rc, "Entering rescue mode");
|
||||
goto done;
|
||||
|
||||
+24
-51
@@ -382,74 +382,47 @@ static int activate_console(int noclear, int nowait)
|
||||
*/
|
||||
pid_t run_getty(char *tty, char *baud, char *term, int noclear, int nowait, struct rlimit rlimit[])
|
||||
{
|
||||
pid_t pid;
|
||||
speed_t speed;
|
||||
int rc = 1;
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
speed_t speed;
|
||||
int rc = 1;
|
||||
|
||||
sched_yield();
|
||||
|
||||
speed = stty_parse_speed(baud);
|
||||
prepare_tty(tty, speed, "tty", rlimit);
|
||||
if (activate_console(noclear, nowait)) {
|
||||
logit(LOG_INFO, "Starting built-in getty on %s, speed %u", tty, speed);
|
||||
rc = getty(tty, speed, term, NULL);
|
||||
}
|
||||
|
||||
_exit(rc);
|
||||
speed = stty_parse_speed(baud);
|
||||
prepare_tty(tty, speed, "tty", rlimit);
|
||||
if (activate_console(noclear, nowait)) {
|
||||
logit(LOG_INFO, "Starting built-in getty on %s, speed %u", tty, speed);
|
||||
rc = getty(tty, speed, term, NULL);
|
||||
}
|
||||
|
||||
cgroup_user("getty", pid);
|
||||
|
||||
return pid;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start external getty as defined by user in .conf file
|
||||
*/
|
||||
pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[])
|
||||
{
|
||||
pid_t pid;
|
||||
int rc = 1;
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
int rc = 1;
|
||||
|
||||
sched_yield();
|
||||
|
||||
/* Dunno speed, tell stty() to not mess with it */
|
||||
prepare_tty(tty, B0, "getty", rlimit);
|
||||
if (activate_console(noclear, nowait)) {
|
||||
logit(LOG_INFO, "Starting external getty on %s, speed %u", tty, B0);
|
||||
rc = execv(cmd, args);
|
||||
}
|
||||
|
||||
vhangup();
|
||||
_exit(rc);
|
||||
/* Dunno speed, tell stty() to not mess with it */
|
||||
prepare_tty(tty, B0, "getty", rlimit);
|
||||
if (activate_console(noclear, nowait)) {
|
||||
logit(LOG_INFO, "Starting external getty on %s, speed %u", tty, B0);
|
||||
rc = execv(cmd, args);
|
||||
}
|
||||
|
||||
cgroup_user("getty", pid);
|
||||
vhangup();
|
||||
|
||||
return pid;
|
||||
return rc;
|
||||
}
|
||||
|
||||
pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
|
||||
{
|
||||
pid_t pid;
|
||||
int rc = 1;
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
int rc = 1;
|
||||
prepare_tty(tty, B0, "finit-sh", rlimit);
|
||||
if (activate_console(noclear, nowait))
|
||||
rc = sh(tty);
|
||||
|
||||
prepare_tty(tty, B0, "finit-sh", rlimit);
|
||||
if (activate_console(noclear, nowait))
|
||||
rc = sh(tty);
|
||||
|
||||
_exit(rc);
|
||||
}
|
||||
|
||||
cgroup_user("root", pid);
|
||||
|
||||
return pid;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int run_parts(char *dir, char *cmd)
|
||||
|
||||
+4
-3
@@ -59,6 +59,7 @@ int prevlevel = -1;
|
||||
int debug = 0; /* debug mode from kernel cmdline */
|
||||
int rescue = 0; /* rescue mode from kernel cmdline */
|
||||
int single = 0; /* single user mode from kernel cmdline */
|
||||
int bootstrap = 1; /* set while bootrapping (for TTYs) */
|
||||
char *sdown = NULL;
|
||||
char *network = NULL;
|
||||
char *hostname = NULL;
|
||||
@@ -310,9 +311,9 @@ static void finalize(void *unused)
|
||||
/* Disable progress output at normal runtime */
|
||||
enable_progress(0);
|
||||
|
||||
/* Delayed start of TTYs at bootstrap */
|
||||
_d("Launching all getty services ...");
|
||||
tty_runlevel();
|
||||
/* System bootrapped, launch TTYs et al */
|
||||
bootstrap = 0;
|
||||
service_step_all(SVC_TYPE_RESPAWN);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sysexits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
@@ -105,6 +106,7 @@ extern int prevlevel;
|
||||
extern int debug;
|
||||
extern int rescue;
|
||||
extern int single;
|
||||
extern int bootstrap;
|
||||
extern char *rcsd;
|
||||
extern char *sdown;
|
||||
extern char *network;
|
||||
|
||||
+1
-1
@@ -626,7 +626,7 @@ static char *status(svc_t *svc, int full)
|
||||
{
|
||||
static char buf[64];
|
||||
const char *color;
|
||||
char ok[64] = {0};
|
||||
char ok[32] = {0};
|
||||
char *s;
|
||||
|
||||
s = svc_status(svc);
|
||||
|
||||
+90
-21
@@ -538,7 +538,8 @@ static int service_start(svc_t *svc)
|
||||
}
|
||||
args[i] = NULL;
|
||||
|
||||
redirect(svc);
|
||||
if (!svc_is_tty(svc))
|
||||
redirect(svc);
|
||||
sig_unblock();
|
||||
|
||||
/*
|
||||
@@ -556,6 +557,8 @@ static int service_start(svc_t *svc)
|
||||
|
||||
if (svc_is_runtask(svc))
|
||||
status = exec_runtask(args[0], &args[1]);
|
||||
else if (svc_is_tty(svc))
|
||||
status = tty_exec(svc);
|
||||
else
|
||||
status = execvp(args[0], &args[1]);
|
||||
|
||||
@@ -573,7 +576,10 @@ static int service_start(svc_t *svc)
|
||||
_d("Starting %s %s", svc->cmd, buf);
|
||||
}
|
||||
|
||||
cgroup_service(group_name(svc, grnam, sizeof(grnam)), pid, &svc->cgroup);
|
||||
if (svc_is_tty(svc))
|
||||
cgroup_user("getty", pid);
|
||||
else
|
||||
cgroup_service(group_name(svc, grnam, sizeof(grnam)), pid, &svc->cgroup);
|
||||
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Starting %s[%d]", svc_ident(svc, NULL, 0), pid);
|
||||
|
||||
@@ -649,6 +655,9 @@ static void service_cleanup(svc_t *svc)
|
||||
basename(svc->cmd), fn);
|
||||
|
||||
/* No longer running, update books. */
|
||||
if (svc_is_tty(svc) && svc->pid > 1)
|
||||
utmp_set_dead(svc->pid); /* Set DEAD_PROCESS UTMP entry */
|
||||
|
||||
svc->oldpid = svc->pid;
|
||||
svc->start_time = svc->pid = 0;
|
||||
}
|
||||
@@ -925,13 +934,10 @@ static void parse_name(svc_t *svc, char *arg)
|
||||
}
|
||||
|
||||
strlcpy(svc->name, name, sizeof(svc->name));
|
||||
|
||||
/* Warn if svc generates same condition as an existing service */
|
||||
svc_validate(svc);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_cmdline_args - Update the command line args in the svc struct
|
||||
/*
|
||||
* Update the command line args in the svc struct
|
||||
*
|
||||
* strtok internal pointer must be positioned at first command line arg
|
||||
* when this function is called.
|
||||
@@ -1071,6 +1077,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
char *username = NULL, *log = NULL, *pid = NULL;
|
||||
char *name = NULL, *halt = NULL, *delay = NULL;
|
||||
char *id = NULL, *env = NULL, *cgroup = NULL;
|
||||
struct tty tty = { 0 };
|
||||
int levels = 0;
|
||||
int manual = 0;
|
||||
char *line;
|
||||
@@ -1103,7 +1110,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
}
|
||||
}
|
||||
|
||||
cmd = strtok(line, " ");
|
||||
cmd = strtok(line, " \t");
|
||||
if (!cmd) {
|
||||
incomplete:
|
||||
_e("Incomplete service '%s', cannot register", cfg);
|
||||
@@ -1111,6 +1118,9 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
}
|
||||
|
||||
while (cmd) {
|
||||
if (type == SVC_TYPE_TTY && cmd[0] == '@')
|
||||
break; /* @console */
|
||||
|
||||
if (cmd[0] == '@') /* @username[:group] */
|
||||
username = &cmd[1];
|
||||
else if (cmd[0] == '[') /* [runlevels] */
|
||||
@@ -1155,7 +1165,33 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
if (!id)
|
||||
id = "";
|
||||
|
||||
svc = svc_find(cmd, id);
|
||||
if (type == SVC_TYPE_TTY) {
|
||||
size_t i, len = 0;
|
||||
|
||||
if (tty_parse_args(cmd, &tty))
|
||||
return errno;
|
||||
|
||||
len += tty.num + 5;
|
||||
for (i = 0; i < tty.num; i++)
|
||||
len += strlen(tty.args[i]);
|
||||
|
||||
line = alloca(len);
|
||||
if (!line)
|
||||
return errno;
|
||||
|
||||
snprintf(line, len, "%s ", tty.cmd ?: "tty");
|
||||
for (i = 0; i < tty.num; i++) {
|
||||
strlcat(line, tty.args[i], len);
|
||||
strlcat(line, " ", len);
|
||||
}
|
||||
cmd = strtok(line, " \t");
|
||||
if (!cmd)
|
||||
return errno;
|
||||
|
||||
svc = svc_find_by_tty(tty.dev);
|
||||
} else
|
||||
svc = svc_find(cmd, id);
|
||||
|
||||
if (!svc) {
|
||||
_d("Creating new svc for %s id #%s type %d", cmd, id, type);
|
||||
svc = svc_new(cmd, id, type);
|
||||
@@ -1197,7 +1233,43 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
|
||||
conf_parse_cond(svc, cond);
|
||||
|
||||
parse_name(svc, name);
|
||||
if (type == SVC_TYPE_TTY) {
|
||||
char *ptr;
|
||||
|
||||
if (tty.dev)
|
||||
strlcpy(svc->dev, tty.dev, sizeof(svc->dev));
|
||||
if (tty.baud)
|
||||
strlcpy(svc->baud, tty.baud, sizeof(svc->baud));
|
||||
if (tty.term)
|
||||
strlcpy(svc->term, tty.term, sizeof(svc->term));
|
||||
svc->noclear = tty.noclear;
|
||||
svc->nowait = tty.nowait;
|
||||
svc->nologin = tty.nologin;
|
||||
|
||||
/* TTYs cannot be redirected */
|
||||
log = NULL;
|
||||
|
||||
/* Create name:id tuple for identiy, e.g., tty:S0 */
|
||||
ptr = strrchr(svc->dev, '/');
|
||||
if (ptr) {
|
||||
ptr++;
|
||||
if (!strncmp(ptr, "tty", 3))
|
||||
ptr += 3;
|
||||
} else
|
||||
ptr = svc->dev;
|
||||
if (!id || id[0] == 0)
|
||||
id = ptr;
|
||||
strlcpy(svc->name, "tty", sizeof(svc->name));
|
||||
strlcpy(svc->id, id, sizeof(svc->id));
|
||||
} else
|
||||
parse_name(svc, name);
|
||||
|
||||
/*
|
||||
* Warn if svc generates same condition (based on name:id)
|
||||
* as an existing service.
|
||||
*/
|
||||
svc_validate(svc);
|
||||
|
||||
if (halt)
|
||||
parse_sighalt(svc, halt);
|
||||
if (delay)
|
||||
@@ -1206,6 +1278,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
parse_log(svc, log);
|
||||
if (desc)
|
||||
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
||||
else if (type == SVC_TYPE_TTY)
|
||||
snprintf(svc->desc, sizeof(svc->desc), "Getty on %s", svc->dev);
|
||||
if (env)
|
||||
parse_env(svc, env);
|
||||
if (file)
|
||||
@@ -1258,9 +1332,6 @@ void service_monitor(pid_t lost, int status)
|
||||
if (fexist(SYNC_SHUTDOWN) || lost <= 1)
|
||||
return;
|
||||
|
||||
if (tty_respawn(lost))
|
||||
return;
|
||||
|
||||
svc = svc_find_by_pid(lost);
|
||||
if (!svc) {
|
||||
_d("collected unknown PID %d", lost);
|
||||
@@ -1276,7 +1347,7 @@ void service_monitor(pid_t lost, int status)
|
||||
return;
|
||||
|
||||
/* Try removing PID file (in case service does not clean up after itself) */
|
||||
if (svc_is_daemon(svc)) {
|
||||
if (svc_is_daemon(svc) || svc_is_tty(svc)) {
|
||||
service_cleanup(svc);
|
||||
} else if (svc_is_runtask(svc)) {
|
||||
/* run/task should run at least once per runlevel */
|
||||
@@ -1376,7 +1447,7 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
|
||||
*state = new;
|
||||
|
||||
/* if PID isn't collected within SVC_TERM_TIMEOUT msec, kill it! */
|
||||
if ((*state == SVC_STOPPING_STATE)) {
|
||||
if (*state == SVC_STOPPING_STATE) {
|
||||
_d("%s is stopping, wait %d sec before sending SIGKILL ...",
|
||||
svc->cmd, svc->killdelay / 1000);
|
||||
service_timeout_cancel(svc);
|
||||
@@ -1421,15 +1492,13 @@ restart:
|
||||
if (!svc->pid) {
|
||||
char cond[MAX_COND_LEN];
|
||||
|
||||
/* PID was collected normally, no need to kill it */
|
||||
_d("%s: stopped normally, no need to send SIGKILL :)", svc->cmd);
|
||||
_d("%s: stopped, cleaning up timers and conditions ...", svc->cmd);
|
||||
service_timeout_cancel(svc);
|
||||
|
||||
_d("%s: clearing pid condition ...", svc->name);
|
||||
cond_clear(mkcond(svc, cond, sizeof(cond)));
|
||||
|
||||
switch (svc->type) {
|
||||
case SVC_TYPE_SERVICE:
|
||||
case SVC_TYPE_TTY:
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
break;
|
||||
|
||||
@@ -1477,7 +1546,7 @@ restart:
|
||||
}
|
||||
|
||||
if (!svc->pid) {
|
||||
if (svc_is_daemon(svc)) {
|
||||
if (svc_is_daemon(svc) || svc_is_tty(svc)) {
|
||||
svc_restarting(svc);
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
|
||||
@@ -1596,7 +1665,7 @@ void service_step_all(int types)
|
||||
|
||||
void service_worker(void *unused)
|
||||
{
|
||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK);
|
||||
service_step_all(SVC_TYPE_RESPAWN | SVC_TYPE_RUNTASK);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -206,10 +206,6 @@ restart:
|
||||
break;
|
||||
}
|
||||
|
||||
/* No TTYs run at bootstrap, they have a delayed start. */
|
||||
if (prevlevel > 0)
|
||||
tty_runlevel();
|
||||
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
|
||||
@@ -224,8 +220,7 @@ restart:
|
||||
_d("Stopping services not allowed after reconf ...");
|
||||
sm->in_teardown = 1;
|
||||
cond_reload();
|
||||
service_step_all(SVC_TYPE_SERVICE);
|
||||
tty_reload(NULL);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
sm->state = SM_RELOAD_WAIT_STATE;
|
||||
break;
|
||||
@@ -242,16 +237,17 @@ restart:
|
||||
}
|
||||
|
||||
sm->in_teardown = 0;
|
||||
/* Cleanup stale services */
|
||||
svc_clean_dynamic(service_unregister);
|
||||
|
||||
_d("Starting services after reconf ...");
|
||||
service_step_all(SVC_TYPE_SERVICE);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
/* Cleanup stale services */
|
||||
svc_clean_dynamic(service_unregister);
|
||||
|
||||
_d("Calling reconf hooks ...");
|
||||
plugin_run_hooks(HOOK_SVC_RECONF);
|
||||
|
||||
service_step_all(SVC_TYPE_SERVICE);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
_d("Reconfiguration done");
|
||||
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
|
||||
@@ -114,7 +114,7 @@ svc_t *svc_new(char *cmd, char *id, int type)
|
||||
|
||||
/* Find first job n:o if registering multiple instances */
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (!strcmp(svc->cmd, cmd)) {
|
||||
if (cmd && !strcmp(svc->cmd, cmd)) {
|
||||
job = svc->job;
|
||||
break;
|
||||
}
|
||||
@@ -130,13 +130,17 @@ svc_t *svc_new(char *cmd, char *id, int type)
|
||||
svc->job = job;
|
||||
if (id && id[0])
|
||||
strlcpy(svc->id, id, sizeof(svc->id));
|
||||
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
||||
if (cmd)
|
||||
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
||||
|
||||
/* Default description, if missing */
|
||||
strlcpy(svc->desc, svc->name, sizeof(svc->desc));
|
||||
|
||||
/* Default HALT signal to send */
|
||||
svc->sighalt = SIGTERM;
|
||||
if (svc_is_tty(svc))
|
||||
svc->sighalt = SIGHUP;
|
||||
else
|
||||
svc->sighalt = SIGTERM;
|
||||
|
||||
/* Default delay between SIGTERM and SIGKILL */
|
||||
svc->killdelay = SVC_TERM_TIMEOUT;
|
||||
@@ -327,7 +331,7 @@ svc_t *svc_stop_completed(void)
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (svc->state == SVC_STOPPING_STATE)
|
||||
if (svc->state == SVC_STOPPING_STATE && svc->pid > 1)
|
||||
return svc;
|
||||
}
|
||||
|
||||
@@ -422,6 +426,22 @@ svc_t *svc_find_by_nameid(char *name, char *id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
svc_t *svc_find_by_tty(char *dev)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (!svc_is_tty(svc))
|
||||
continue;
|
||||
|
||||
if (!strcmp(dev, svc->name))
|
||||
return svc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_find_by_plidfile - Find a service by its PID file
|
||||
* @fn: PID file, can be absolute path or relative to /run
|
||||
@@ -581,6 +601,9 @@ int svc_enabled(svc_t *svc)
|
||||
if (svc_is_missing(svc))
|
||||
return 0;
|
||||
|
||||
if (svc_is_tty(svc) && bootstrap)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,10 +42,12 @@ typedef enum {
|
||||
SVC_TYPE_SERVICE = 1, /* Monitored, will be respawned */
|
||||
SVC_TYPE_TASK = 2, /* One-shot, runs in parallell */
|
||||
SVC_TYPE_RUN = 4, /* Like task, but wait for completion */
|
||||
SVC_TYPE_TTY = 8, /* Like service, but dedicated to TTYs */
|
||||
SVC_TYPE_SYSV = 32, /* SysV style init.d script w/ start/stop */
|
||||
} svc_type_t;
|
||||
|
||||
#define SVC_TYPE_ANY (-1)
|
||||
#define SVC_TYPE_RESPAWN (SVC_TYPE_SERVICE | SVC_TYPE_TTY)
|
||||
#define SVC_TYPE_RUNTASK (SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SYSV)
|
||||
|
||||
typedef enum {
|
||||
@@ -125,15 +127,27 @@ typedef struct svc {
|
||||
char once; /* run/task, (at least) once per runlevel */
|
||||
const char restart_cnt; /* Incremented for each restart by service monitor. */
|
||||
|
||||
/* Set for services we need to redirect stdout/stderr to syslog */
|
||||
struct {
|
||||
char enabled;
|
||||
char null;
|
||||
char console;
|
||||
char file[64];
|
||||
char prio[20];
|
||||
char ident[20];
|
||||
} log;
|
||||
union {
|
||||
/* services we redirect stdout/stderr to syslog (not TTYs!) */
|
||||
struct {
|
||||
char enabled;
|
||||
char null;
|
||||
char console;
|
||||
char file[64];
|
||||
char prio[20];
|
||||
char ident[20];
|
||||
} log;
|
||||
|
||||
/* Only for TTY type services */
|
||||
struct {
|
||||
char dev[32];
|
||||
char baud[10];
|
||||
char term[10];
|
||||
int noclear;
|
||||
int nowait;
|
||||
int nologin;
|
||||
};
|
||||
};
|
||||
|
||||
/* Identity */
|
||||
char username[MAX_USER_LEN];
|
||||
@@ -165,6 +179,7 @@ svc_t *svc_find (char *cmd, char *id);
|
||||
svc_t *svc_find_by_pid (pid_t pid);
|
||||
svc_t *svc_find_by_jobid (int job, char *id);
|
||||
svc_t *svc_find_by_nameid (char *name, char *id);
|
||||
svc_t *svc_find_by_tty (char *dev);
|
||||
svc_t *svc_find_by_pidfile (char *fn);
|
||||
|
||||
svc_t *svc_iterator (svc_t **iter, int first);
|
||||
@@ -189,9 +204,10 @@ int svc_is_unique (svc_t *svc);
|
||||
|
||||
int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *));
|
||||
|
||||
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
|
||||
static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == svc->type; }
|
||||
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type); }
|
||||
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
|
||||
static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == svc->type; }
|
||||
static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY == svc->type; }
|
||||
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type);}
|
||||
static inline int svc_is_forking (svc_t *svc) { return (svc_is_daemon(svc) || svc_is_sysv(svc)) && svc->pidfile[0] == '!'; }
|
||||
|
||||
static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
|
||||
@@ -229,6 +245,7 @@ static inline int svc_has_cond(svc_t *svc)
|
||||
case SVC_TYPE_SERVICE:
|
||||
case SVC_TYPE_TASK:
|
||||
case SVC_TYPE_RUN:
|
||||
case SVC_TYPE_TTY:
|
||||
case SVC_TYPE_SYSV:
|
||||
return 1;
|
||||
|
||||
|
||||
@@ -42,17 +42,16 @@
|
||||
#ifdef FALLBACK_SHELL
|
||||
static pid_t fallback = 0;
|
||||
#endif
|
||||
static LIST_HEAD(, tty) tty_list = LIST_HEAD_INITIALIZER();
|
||||
|
||||
static char *canonicalize(char *tty)
|
||||
char *tty_canonicalize(char *dev)
|
||||
{
|
||||
struct stat st;
|
||||
static char path[80];
|
||||
struct stat st;
|
||||
|
||||
if (!tty)
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
strlcpy(path, tty, sizeof(path));
|
||||
strlcpy(path, dev, sizeof(path));
|
||||
if (stat(path, &st)) {
|
||||
if (!strncmp(path, _PATH_DEV, strlen(_PATH_DEV))) {
|
||||
unavailable:
|
||||
@@ -60,7 +59,7 @@ static char *canonicalize(char *tty)
|
||||
return path;
|
||||
}
|
||||
|
||||
snprintf(path, sizeof(path), "%s%s", _PATH_DEV, tty);
|
||||
snprintf(path, sizeof(path), "%s%s", _PATH_DEV, dev);
|
||||
if (stat(path, &st))
|
||||
goto unavailable;
|
||||
}
|
||||
@@ -71,37 +70,40 @@ static char *canonicalize(char *tty)
|
||||
return path;
|
||||
}
|
||||
|
||||
void tty_mark(void)
|
||||
/*
|
||||
* The @console syntax is a wildcard to match the system console(s) given
|
||||
* on the kernel cmdline. As such it can match multiple, or even none.
|
||||
*/
|
||||
int tty_isatcon(char *dev)
|
||||
{
|
||||
struct tty *tty;
|
||||
|
||||
LIST_FOREACH(tty, &tty_list, link)
|
||||
tty->dirty = -1;
|
||||
return dev && !strcmp(dev, "@console");
|
||||
}
|
||||
|
||||
void tty_sweep(void)
|
||||
int tty_atcon(char *buf, size_t len)
|
||||
{
|
||||
struct tty *tty, *tmp;
|
||||
FILE *fp;
|
||||
|
||||
LIST_FOREACH_SAFE(tty, &tty_list, link, tmp) {
|
||||
if (!tty->dirty)
|
||||
continue;
|
||||
|
||||
_d("TTY %s dirty, stopping ...", tty->name);
|
||||
tty_stop(tty);
|
||||
|
||||
if (tty->dirty == -1) {
|
||||
_d("TTY %s removed, cleaning up.", tty->name);
|
||||
tty_unregister(tty);
|
||||
}
|
||||
fp = fopen("/sys/class/tty/console/active", "r");
|
||||
if (!fp) {
|
||||
_e("Cannot find system console, is sysfs not mounted?");
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!fgets(buf, len, fp)) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
chomp(buf);
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_register - Register a getty on a device
|
||||
* @line: Configuration, text after initial "tty"
|
||||
* @rlimit: Limits for this service/run/task, may be global limits
|
||||
* @file: The file name TTY was loaded from
|
||||
* tty_parse_args - Parse cmdline args for a tty
|
||||
* @cmd: command or tty
|
||||
*
|
||||
* A Finit tty line can use the internal getty implementation or an
|
||||
* external one, like the BusyBox getty for instance. This function
|
||||
@@ -119,66 +121,52 @@ void tty_sweep(void)
|
||||
* Different getty implementations prefer the TTY device argument in
|
||||
* different order, so take care to investigate this first.
|
||||
*/
|
||||
int tty_register(char *line, struct rlimit rlimit[], char *file)
|
||||
int tty_parse_args(char *cmd, struct tty *tty)
|
||||
{
|
||||
struct tty *entry;
|
||||
size_t i, num = 0;
|
||||
char *tok, *cmd = NULL, *args[TTY_MAX_ARGS], buf[256];
|
||||
char *dev = NULL, *baud = NULL;
|
||||
char *runlevels = NULL, *term = NULL;
|
||||
int insert = 0, noclear = 0, nowait = 0, nologin = 0, atcon = 0;
|
||||
char *dev = NULL;
|
||||
size_t i;
|
||||
|
||||
if (!line) {
|
||||
_e("Missing argument");
|
||||
return errno = EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Split line in separate arguments. For an external getty
|
||||
* this is used with execv(), for the built-in it simplifies
|
||||
* further translation.
|
||||
*/
|
||||
tok = strtok(line, " \t");
|
||||
while (tok && num < NELEMS(args)) {
|
||||
if (!strcmp(tok, "noclear"))
|
||||
noclear = 1;
|
||||
else if (!strcmp(tok, "nowait"))
|
||||
nowait = 1;
|
||||
else if (!strcmp(tok, "nologin"))
|
||||
nologin = 1;
|
||||
do {
|
||||
_d("token %s", cmd);
|
||||
if (!strcmp(cmd, "noclear"))
|
||||
tty->noclear = 1;
|
||||
else if (!strcmp(cmd, "nowait"))
|
||||
tty->nowait = 1;
|
||||
else if (!strcmp(cmd, "nologin"))
|
||||
tty->nologin = 1;
|
||||
else
|
||||
args[num++] = tok;
|
||||
tty->args[tty->num++] = cmd;
|
||||
|
||||
tok = strtok(NULL, " \t");
|
||||
}
|
||||
cmd = strtok(NULL, " \t");
|
||||
} while (cmd && tty->num < NELEMS(tty->args));
|
||||
|
||||
/* Iterate over all args */
|
||||
for (i = 0; i < num; i++) {
|
||||
for (i = 0; i < tty->num; i++) {
|
||||
_d("Checking arg %s for dev and cmd ...", tty->args[i]);
|
||||
/*
|
||||
* First, figure out if built-in or external getty
|
||||
* tty [12345] /dev/ttyAMA0 115200 noclear vt220 # built-in
|
||||
* tty [12345] /sbin/getty -L 115200 @console vt100 noclear # external
|
||||
*/
|
||||
if ((!cmd && !dev) || (cmd && !dev)) {
|
||||
if (args[i][0] == '[')
|
||||
runlevels = line;
|
||||
if (!strcmp(args[i], "@console"))
|
||||
dev = args[i];
|
||||
if (!strncmp(args[i], "/dev", 4))
|
||||
dev = args[i];
|
||||
if (!strncmp(args[i], "tty", 3) || !strcmp(args[i], "console"))
|
||||
dev = args[i];
|
||||
if (!access(args[i], X_OK))
|
||||
cmd = args[i];
|
||||
if ((!tty->cmd && !dev) || (tty->cmd && !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;
|
||||
}
|
||||
|
||||
/* Built-in getty args */
|
||||
if (!cmd && dev) {
|
||||
if (isdigit(args[i][0])) {
|
||||
baud = args[i];
|
||||
if (!tty->cmd && dev) {
|
||||
_d("Found dev %s for built-in getty", dev);
|
||||
if (isdigit(tty->args[i][0])) {
|
||||
tty->baud = tty->args[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -186,189 +174,25 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
||||
* Last arg, if not anything else, is the value
|
||||
* to be used for the TERM environment variable.
|
||||
*/
|
||||
if (i + 1 == num)
|
||||
term = args[i];
|
||||
if (i + 1 == tty->num)
|
||||
tty->term = tty->args[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev) {
|
||||
error:
|
||||
if (!tty_isatcon(dev))
|
||||
tty->dev = tty_canonicalize(dev);
|
||||
|
||||
if (!tty->dev) {
|
||||
_e("Incomplete or non-existing TTY device given, cannot register.");
|
||||
return errno = EINVAL;
|
||||
}
|
||||
|
||||
/* Auto-detect serial console, for embedded devices mostly */
|
||||
if (!strcmp(dev, "@console")) {
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen("/sys/class/tty/console/active", "r");
|
||||
if (!fp) {
|
||||
_e("Cannot find system console, is sysfs not mounted?");
|
||||
return errno = ENOENT;
|
||||
}
|
||||
|
||||
atcon = 1;
|
||||
if (fgets(buf, sizeof(buf), fp))
|
||||
dev = strtok(chomp(buf), " \t");
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
again:
|
||||
/* Ensure all getty (built-in + external) are registered with absolute path */
|
||||
dev = canonicalize(dev);
|
||||
if (!dev)
|
||||
goto error;
|
||||
|
||||
entry = tty_find(dev);
|
||||
if (!entry) {
|
||||
entry = calloc(1, sizeof(*entry));
|
||||
if (!entry)
|
||||
return errno = ENOMEM;
|
||||
insert = 1;
|
||||
} else {
|
||||
if (entry->cmd) {
|
||||
free(entry->cmd);
|
||||
entry->cmd = NULL;
|
||||
for (i = 0; i < TTY_MAX_ARGS; i++) {
|
||||
if (entry->args[i])
|
||||
free(entry->args[i]);
|
||||
entry->args[i] = NULL;
|
||||
}
|
||||
}
|
||||
insert = 0;
|
||||
}
|
||||
|
||||
strlcpy(entry->name, dev, sizeof(entry->name));
|
||||
strlcpy(entry->baud, baud ? baud : "", sizeof(entry->baud));
|
||||
strlcpy(entry->term, term ? term : "", sizeof(entry->term));
|
||||
entry->noclear = noclear;
|
||||
entry->nowait = nowait;
|
||||
entry->nologin = nologin;
|
||||
entry->runlevels = conf_parse_runlevels(runlevels);
|
||||
|
||||
/* External getty */
|
||||
if (cmd) {
|
||||
int j = 0;
|
||||
|
||||
tok = strrchr(cmd, '/');
|
||||
if (!tok)
|
||||
tok = cmd;
|
||||
else
|
||||
tok++;
|
||||
entry->cmd = strdup(cmd);
|
||||
args[1] = strdup(tok);
|
||||
|
||||
for (i = 1; i < num; i++) {
|
||||
char *arg = args[i];
|
||||
|
||||
/* Replace @console with actual device */
|
||||
if (arg && !strcmp(arg, "@console"))
|
||||
arg = dev;
|
||||
if (arg)
|
||||
entry->args[j++] = strdup(arg);
|
||||
}
|
||||
entry->args[++j] = NULL;
|
||||
}
|
||||
|
||||
_d("Registering %s getty on TTY %s at %s baud with term %s on runlevels %s",
|
||||
cmd ? "external" : "built-in", dev, baud ?: "NULL", term ?: "N/A", runlevels ?: "[2-5]");
|
||||
|
||||
if (insert)
|
||||
LIST_INSERT_HEAD(&tty_list, entry, link);
|
||||
|
||||
/* Register configured limits */
|
||||
memcpy(entry->rlimit, rlimit, sizeof(entry->rlimit));
|
||||
|
||||
if (file && conf_changed(file))
|
||||
entry->dirty = 1; /* Modified, restart */
|
||||
else
|
||||
entry->dirty = 0; /* Not modified */
|
||||
_d("TTY %s is %sdirty", dev, entry->dirty ? "" : "NOT ");
|
||||
|
||||
if (atcon) {
|
||||
dev = strtok(NULL, " \t");
|
||||
if (dev) {
|
||||
_d("Found another @console: %s", dev);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
_d("Registering %s getty on TTY %s at %s baud with term %s", tty->cmd ? "external" : "built-in",
|
||||
tty->dev, tty->baud ?: "NULL", tty->term ?: "N/A");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tty_unregister(struct tty *tty)
|
||||
{
|
||||
if (!tty) {
|
||||
_e("Missing argument");
|
||||
return errno = EINVAL;
|
||||
}
|
||||
|
||||
LIST_REMOVE(tty, link);
|
||||
|
||||
if (tty->cmd) {
|
||||
int i;
|
||||
|
||||
free(tty->cmd);
|
||||
for (i = 0; i < TTY_MAX_ARGS; i++) {
|
||||
if (tty->args[i])
|
||||
free(tty->args[i]);
|
||||
tty->args[i] = NULL;
|
||||
}
|
||||
}
|
||||
free(tty);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tty *tty_find(char *dev)
|
||||
{
|
||||
struct tty *entry;
|
||||
|
||||
LIST_FOREACH(entry, &tty_list, link) {
|
||||
if (!strcmp(dev, entry->name))
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t tty_num(void)
|
||||
{
|
||||
size_t num = 0;
|
||||
struct tty *entry;
|
||||
|
||||
LIST_FOREACH(entry, &tty_list, link)
|
||||
num++;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
size_t tty_num_active(void)
|
||||
{
|
||||
size_t num = 0;
|
||||
struct tty *entry;
|
||||
|
||||
LIST_FOREACH(entry, &tty_list, link) {
|
||||
if (entry->pid)
|
||||
num++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
struct tty *tty_find_by_pid(pid_t pid)
|
||||
{
|
||||
struct tty *entry;
|
||||
|
||||
LIST_FOREACH(entry, &tty_list, link) {
|
||||
if (entry->pid == pid)
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int tty_exist(char *dev)
|
||||
{
|
||||
int fd, result;
|
||||
@@ -385,65 +209,35 @@ static int tty_exist(char *dev)
|
||||
return result;
|
||||
}
|
||||
|
||||
void tty_start(struct tty *tty)
|
||||
int tty_exec(svc_t *tty)
|
||||
{
|
||||
char *dev;
|
||||
int rc;
|
||||
|
||||
if (tty->pid) {
|
||||
_d("%s: TTY already active", tty->name);
|
||||
return;
|
||||
}
|
||||
|
||||
dev = canonicalize(tty->name);
|
||||
dev = tty_canonicalize(tty->dev);
|
||||
if (!dev) {
|
||||
_d("%s: Cannot find TTY device: %s", tty->name, strerror(errno));
|
||||
return;
|
||||
_d("%s: Cannot find TTY device: %s", tty->dev, strerror(errno));
|
||||
return EX_CONFIG;
|
||||
}
|
||||
|
||||
if (tty_exist(dev)) {
|
||||
_d("%s: Not a valid TTY: %s", dev, strerror(errno));
|
||||
return;
|
||||
return EX_OSFILE;
|
||||
}
|
||||
|
||||
if (tty->nologin) {
|
||||
_d("%s: Starting /bin/sh ...", dev);
|
||||
tty->pid = run_sh(dev, tty->noclear, tty->nowait, tty->rlimit);
|
||||
return;
|
||||
return run_sh(dev, tty->noclear, tty->nowait, tty->rlimit);
|
||||
}
|
||||
|
||||
_d("%s: Starting %sgetty ...", dev, !tty->cmd ? "built-in " : "");
|
||||
if (!tty->cmd)
|
||||
tty->pid = run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit);
|
||||
if (!strcmp(tty->cmd, "tty"))
|
||||
rc = run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit);
|
||||
else
|
||||
tty->pid = run_getty2(dev, tty->cmd, tty->args, tty->noclear, tty->nowait, tty->rlimit);
|
||||
}
|
||||
// rc = run_getty2(dev, tty->cmd, tty->args, tty->noclear, tty->nowait, tty->rlimit);
|
||||
rc = -1;
|
||||
|
||||
void tty_stop(struct tty *tty)
|
||||
{
|
||||
if (!tty->pid)
|
||||
return;
|
||||
|
||||
/*
|
||||
* XXX: TTY handling should be refactored to regular services,
|
||||
* XXX: that way we could rely on the state machine to properly
|
||||
* XXX: send SIGTERM, wait for max 2 sec to collect PID before
|
||||
* XXX: sending SIGKILL.
|
||||
*/
|
||||
_d("Stopping TTY %s", tty->name);
|
||||
kill(tty->pid, SIGKILL);
|
||||
waitpid(tty->pid, NULL, 0);
|
||||
tty->pid = 0;
|
||||
}
|
||||
|
||||
int tty_enabled(struct tty *tty)
|
||||
{
|
||||
if (!tty)
|
||||
return 0;
|
||||
|
||||
if (ISSET(tty->runlevels, runlevel))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -484,73 +278,6 @@ int tty_fallback(pid_t lost)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tty_action(struct tty *tty)
|
||||
{
|
||||
if (!tty_enabled(tty))
|
||||
tty_stop(tty);
|
||||
else
|
||||
tty_start(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
* TTY monitor, called by service_monitor()
|
||||
*/
|
||||
int tty_respawn(pid_t pid)
|
||||
{
|
||||
struct tty *tty = tty_find_by_pid(pid);
|
||||
|
||||
if (!tty)
|
||||
return tty_fallback(pid);
|
||||
|
||||
/* Set DEAD_PROCESS UTMP entry */
|
||||
utmp_set_dead(pid);
|
||||
|
||||
/* Clear PID to be able to respawn it. */
|
||||
tty->pid = 0;
|
||||
tty_action(tty);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called after reload of /etc/finit.d/, stop/start TTYs
|
||||
*/
|
||||
void tty_reload(char *dev)
|
||||
{
|
||||
struct tty *tty;
|
||||
|
||||
if (dev) {
|
||||
tty = tty_find(dev);
|
||||
if (!tty) {
|
||||
logit(LOG_WARNING, "No TTY registered for %s", dev);
|
||||
return;
|
||||
}
|
||||
|
||||
tty_action(tty);
|
||||
tty->dirty = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
tty_sweep();
|
||||
|
||||
LIST_FOREACH(tty, &tty_list, link) {
|
||||
tty_action(tty);
|
||||
tty->dirty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start all TTYs that exist in the system and are allowed at this runlevel */
|
||||
void tty_runlevel(void)
|
||||
{
|
||||
struct tty *tty;
|
||||
|
||||
LIST_FOREACH(tty, &tty_list, link)
|
||||
tty_action(tty);
|
||||
|
||||
/* Start fallback shell if enabled && no TTYs */
|
||||
tty_fallback(tty_num_active() > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
|
||||
@@ -25,51 +25,30 @@
|
||||
#ifndef FINIT_TTY_H_
|
||||
#define FINIT_TTY_H_
|
||||
|
||||
#include <limits.h>
|
||||
#include <sys/resource.h>
|
||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
|
||||
#define TTY_MAX_ARGS 16
|
||||
#include <stdio.h>
|
||||
#include "svc.h"
|
||||
|
||||
struct tty {
|
||||
LIST_ENTRY(tty) link;
|
||||
char *cmd;
|
||||
char *args[MAX_NUM_SVC_ARGS];
|
||||
size_t num;
|
||||
|
||||
char name[42];
|
||||
char baud[10];
|
||||
char term[10];
|
||||
int noclear;
|
||||
int nowait;
|
||||
int nologin;
|
||||
int runlevels;
|
||||
|
||||
char *cmd; /* NULL when running built-in getty */
|
||||
char *args[TTY_MAX_ARGS];
|
||||
|
||||
int pid;
|
||||
|
||||
/* Limits and scoping */
|
||||
struct rlimit rlimit[RLIMIT_NLIMITS];
|
||||
|
||||
/* Set if modified => reloaded, or -1 when marked for removal */
|
||||
int dirty;
|
||||
char *dev;
|
||||
char *baud;
|
||||
char *term;
|
||||
int noclear;
|
||||
int nowait;
|
||||
int nologin;
|
||||
};
|
||||
|
||||
void tty_mark (void);
|
||||
void tty_sweep (void);
|
||||
char *tty_canonicalize (char *dev);
|
||||
|
||||
int tty_register (char *line, struct rlimit rlimit[], char *file);
|
||||
int tty_unregister (struct tty *tty);
|
||||
int tty_isatcon (char *dev);
|
||||
int tty_atcon (char *buf, size_t len);
|
||||
|
||||
struct tty *tty_find (char *dev);
|
||||
size_t tty_num (void);
|
||||
size_t tty_num_active (void);
|
||||
struct tty *tty_find_by_pid (pid_t pid);
|
||||
void tty_start (struct tty *tty);
|
||||
void tty_stop (struct tty *tty);
|
||||
int tty_enabled (struct tty *tty);
|
||||
int tty_respawn (pid_t pid);
|
||||
void tty_reload (char *dev);
|
||||
void tty_runlevel (void);
|
||||
int tty_parse_args (char *cmdline, struct tty *tty);
|
||||
|
||||
int tty_exec (svc_t *tty);
|
||||
|
||||
#endif /* FINIT_TTY_H_ */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user