1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-10 05:18:17 +03:00

exec: hangup/reset/deallocate VTs in gettys

Explicitly disconnect all clients from a VT when a getty starts/finishes
(requires TIOCVHANGUP, available in 2.6.29).

Explicitly deallocate getty VTs in order to flush scrollback buffer.

Explicitly reset terminals to a defined state before spawning getty.
This commit is contained in:
Lennart Poettering 2011-05-18 01:07:31 +02:00
parent 9131f660ee
commit 6ea832a207
16 changed files with 275 additions and 31 deletions

12
TODO
View File

@ -22,7 +22,7 @@ Features:
* Make it possible to set the keymap independently from the font on * Make it possible to set the keymap independently from the font on
the kernel cmdline. Right now setting one resets also the other. the kernel cmdline. Right now setting one resets also the other.
* add dbus call to convert snapshot ino target * add dbus call to convert snapshot into target
* move nss-myhostname into systemd * move nss-myhostname into systemd
@ -30,11 +30,6 @@ Features:
* add dbus call to convert snapshot into target * add dbus call to convert snapshot into target
* make use of TIOCVHANGUP to revoke access to tty before we spawn a getty on it
* release VT before we spawn a getty on it to entirely clear scrollback buffer
https://bugzilla.redhat.com/show_bug.cgi?id=701704
* move /selinux to /sys/fs/selinux * move /selinux to /sys/fs/selinux
* unset cgroup agents on shutdown * unset cgroup agents on shutdown
@ -45,14 +40,12 @@ Features:
* add inode stat() check to readahead to suppress preloading changed files * add inode stat() check to readahead to suppress preloading changed files
* allow list of pathes in config_parse_condition_path() * allow list of paths in config_parse_condition_path()
* introduce dbus calls for enabling/disabling a service * introduce dbus calls for enabling/disabling a service
* support notifications for services being enabled/disabled * support notifications for services being enabled/disabled
* Maybe merge nss-myhostname into systemd?
* GC unreferenced jobs (such as .device jobs) * GC unreferenced jobs (such as .device jobs)
* support wildcard expansion in ListenStream= and friends * support wildcard expansion in ListenStream= and friends
@ -68,7 +61,6 @@ Features:
* write blog stories about: * write blog stories about:
- enabling dbus services - enabling dbus services
- status update - status update
- you are a distro: why switch?
- /etc/sysconfig and /etc/default - /etc/sysconfig and /etc/default
- how to write socket activated services - how to write socket activated services

View File

@ -421,6 +421,36 @@
TTY (see above). Defaults to TTY (see above). Defaults to
<filename>/dev/console</filename>.</para></listitem> <filename>/dev/console</filename>.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>TTYReset=</varname></term>
<listitem><para>Reset the terminal
device specified with
<varname>TTYPath=</varname> before and
after execution. Defaults to
<literal>no</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>TTYVHangup=</varname></term>
<listitem><para>Disconnect all clients
which have opened the terminal device
specified with
<varname>TTYPath=</varname>
before and after execution. Defaults
to
<literal>no</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>TTYVTDisallocate=</varname></term>
<listitem><para>If the the terminal
device specified with
<varname>TTYPath=</varname> is a
virtual console terminal try to
deallocate the TTY before and after
execution. This ensures that the
screen and scrollback buffer is
cleared. Defaults to
<literal>no</literal>.</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>SyslogIdentifier=</varname></term> <term><varname>SyslogIdentifier=</varname></term>
<listitem><para>Sets the process name <listitem><para>Sets the process name

View File

@ -128,6 +128,9 @@
{ interface, "StandardOutput", bus_execute_append_output, "s", &(context).std_output }, \ { interface, "StandardOutput", bus_execute_append_output, "s", &(context).std_output }, \
{ interface, "StandardError", bus_execute_append_output, "s", &(context).std_error }, \ { interface, "StandardError", bus_execute_append_output, "s", &(context).std_error }, \
{ interface, "TTYPath", bus_property_append_string, "s", (context).tty_path }, \ { interface, "TTYPath", bus_property_append_string, "s", (context).tty_path }, \
{ interface, "TTYReset", bus_property_append_bool, "b", &(context).tty_reset }, \
{ interface, "TTYVHangup", bus_property_append_bool, "b", &(context).tty_vhangup }, \
{ interface, "TTYVTDisallocate", bus_property_append_bool, "b", &(context).tty_vt_disallocate }, \
{ interface, "SyslogPriority", bus_property_append_int, "i", &(context).syslog_priority }, \ { interface, "SyslogPriority", bus_property_append_int, "i", &(context).syslog_priority }, \
{ interface, "SyslogIdentifier", bus_property_append_string, "s", (context).syslog_identifier }, \ { interface, "SyslogIdentifier", bus_property_append_string, "s", (context).syslog_identifier }, \
{ interface, "SyslogLevelPrefix", bus_property_append_bool, "b", &(context).syslog_level_prefix }, \ { interface, "SyslogLevelPrefix", bus_property_append_bool, "b", &(context).syslog_level_prefix }, \

View File

@ -140,6 +140,19 @@ static const char *tty_path(const ExecContext *context) {
return "/dev/console"; return "/dev/console";
} }
void exec_context_tty_reset(const ExecContext *context) {
assert(context);
if (context->tty_vhangup)
terminal_vhangup(tty_path(context));
if (context->tty_reset)
reset_terminal(tty_path(context));
if (context->tty_vt_disallocate && context->tty_path)
vt_disallocate(context->tty_path);
}
static int open_null_as(int flags, int nfd) { static int open_null_as(int flags, int nfd) {
int fd, r; int fd, r;
@ -1089,6 +1102,8 @@ int exec_spawn(ExecCommand *command,
} }
} }
exec_context_tty_reset(context);
/* We skip the confirmation step if we shall not apply the TTY */ /* We skip the confirmation step if we shall not apply the TTY */
if (confirm_spawn && if (confirm_spawn &&
(!is_terminal_input(context->std_input) || apply_tty_stdin)) { (!is_terminal_input(context->std_input) || apply_tty_stdin)) {
@ -1700,8 +1715,14 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
if (c->tty_path) if (c->tty_path)
fprintf(f, fprintf(f,
"%sTTYPath: %s\n", "%sTTYPath: %s\n"
prefix, c->tty_path); "%sTTYReset: %s\n"
"%sTTYVHangup: %s\n"
"%sTTYVTDisallocate: %s\n",
prefix, c->tty_path,
prefix, yes_no(c->tty_reset),
prefix, yes_no(c->tty_vhangup),
prefix, yes_no(c->tty_vt_disallocate));
if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KMSG || if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KMSG ||
c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
@ -1802,7 +1823,7 @@ void exec_status_start(ExecStatus *s, pid_t pid) {
dual_timestamp_get(&s->start_timestamp); dual_timestamp_get(&s->start_timestamp);
} }
void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status, const char *utmp_id) { void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status) {
assert(s); assert(s);
if ((s->pid && s->pid != pid) || if ((s->pid && s->pid != pid) ||
@ -1815,8 +1836,12 @@ void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status, const char
s->code = code; s->code = code;
s->status = status; s->status = status;
if (utmp_id) if (context) {
utmp_put_dead_process(utmp_id, pid, code, status); if (context->utmp_id)
utmp_put_dead_process(context->utmp_id, pid, code, status);
exec_context_tty_reset(context);
}
} }
void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) { void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {

View File

@ -123,6 +123,10 @@ struct ExecContext {
char *tty_path; char *tty_path;
bool tty_reset;
bool tty_vhangup;
bool tty_vt_disallocate;
/* Since resolving these names might might involve socket /* Since resolving these names might might involve socket
* connections and we don't want to deadlock ourselves these * connections and we don't want to deadlock ourselves these
* names are resolved on execution only and in the child * names are resolved on execution only and in the child
@ -198,11 +202,12 @@ int exec_command_set(ExecCommand *c, const char *path, ...);
void exec_context_init(ExecContext *c); void exec_context_init(ExecContext *c);
void exec_context_done(ExecContext *c); void exec_context_done(ExecContext *c);
void exec_context_dump(ExecContext *c, FILE* f, const char *prefix); void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
void exec_context_tty_reset(const ExecContext *context);
int exec_context_load_environment(const ExecContext *c, char ***l); int exec_context_load_environment(const ExecContext *c, char ***l);
void exec_status_start(ExecStatus *s, pid_t pid); void exec_status_start(ExecStatus *s, pid_t pid);
void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status, const char *utmp_id); void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status);
void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix); void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);
const char* exec_output_to_string(ExecOutput i); const char* exec_output_to_string(ExecOutput i);

View File

@ -188,6 +188,43 @@ static int config_parse_string_printf(
return 0; return 0;
} }
static int config_parse_path_printf(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Unit *u = userdata;
char **s = data;
char *k;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(s);
assert(u);
if (!(k = unit_full_printf(u, rvalue)))
return -ENOMEM;
if (!path_is_absolute(k)) {
log_error("[%s:%u] Not an absolute path: %s", filename, line, k);
free(k);
return -EINVAL;
}
path_kill_slashes(k);
free(*s);
*s = k;
return 0;
}
static int config_parse_listen( static int config_parse_listen(
const char *filename, const char *filename,
unsigned line, unsigned line,
@ -1719,6 +1756,7 @@ static void dump_items(FILE *f, const ConfigItem *items) {
{ config_parse_bool, "BOOLEAN" }, { config_parse_bool, "BOOLEAN" },
{ config_parse_string, "STRING" }, { config_parse_string, "STRING" },
{ config_parse_path, "PATH" }, { config_parse_path, "PATH" },
{ config_parse_path_printf, "PATH" },
{ config_parse_strv, "STRING [...]" }, { config_parse_strv, "STRING [...]" },
{ config_parse_nice, "NICE" }, { config_parse_nice, "NICE" },
{ config_parse_oom_score_adjust, "OOMSCOREADJUST" }, { config_parse_oom_score_adjust, "OOMSCOREADJUST" },
@ -1812,8 +1850,8 @@ static int load_from_path(Unit *u, const char *path) {
}; };
#define EXEC_CONTEXT_CONFIG_ITEMS(context, section) \ #define EXEC_CONTEXT_CONFIG_ITEMS(context, section) \
{ "WorkingDirectory", config_parse_path, 0, &(context).working_directory, section }, \ { "WorkingDirectory", config_parse_path_printf, 0, &(context).working_directory, section }, \
{ "RootDirectory", config_parse_path, 0, &(context).root_directory, section }, \ { "RootDirectory", config_parse_path_printf, 0, &(context).root_directory, section }, \
{ "User", config_parse_string_printf, 0, &(context).user, section }, \ { "User", config_parse_string_printf, 0, &(context).user, section }, \
{ "Group", config_parse_string_printf, 0, &(context).group, section }, \ { "Group", config_parse_string_printf, 0, &(context).group, section }, \
{ "SupplementaryGroups", config_parse_strv, 0, &(context).supplementary_groups, section }, \ { "SupplementaryGroups", config_parse_strv, 0, &(context).supplementary_groups, section }, \
@ -1831,7 +1869,10 @@ static int load_from_path(Unit *u, const char *path) {
{ "StandardInput", config_parse_input, 0, &(context).std_input, section }, \ { "StandardInput", config_parse_input, 0, &(context).std_input, section }, \
{ "StandardOutput", config_parse_output, 0, &(context).std_output, section }, \ { "StandardOutput", config_parse_output, 0, &(context).std_output, section }, \
{ "StandardError", config_parse_output, 0, &(context).std_error, section }, \ { "StandardError", config_parse_output, 0, &(context).std_error, section }, \
{ "TTYPath", config_parse_path, 0, &(context).tty_path, section }, \ { "TTYPath", config_parse_path_printf, 0, &(context).tty_path, section }, \
{ "TTYReset", config_parse_bool, 0, &(context).tty_reset, section }, \
{ "TTYVHangup", config_parse_bool, 0, &(context).tty_vhangup, section }, \
{ "TTYVTDisallocate", config_parse_bool, 0, &(context).tty_vt_disallocate, section }, \
{ "SyslogIdentifier", config_parse_string_printf, 0, &(context).syslog_identifier, section }, \ { "SyslogIdentifier", config_parse_string_printf, 0, &(context).syslog_identifier, section }, \
{ "SyslogFacility", config_parse_facility, 0, &(context).syslog_priority, section }, \ { "SyslogFacility", config_parse_facility, 0, &(context).syslog_priority, section }, \
{ "SyslogLevel", config_parse_level, 0, &(context).syslog_priority, section }, \ { "SyslogLevel", config_parse_level, 0, &(context).syslog_priority, section }, \
@ -1899,7 +1940,7 @@ static int load_from_path(Unit *u, const char *path) {
{ "ConditionSecurity", config_parse_condition_string, CONDITION_SECURITY, u, "Unit" }, { "ConditionSecurity", config_parse_condition_string, CONDITION_SECURITY, u, "Unit" },
{ "ConditionNull", config_parse_condition_null, 0, u, "Unit" }, { "ConditionNull", config_parse_condition_null, 0, u, "Unit" },
{ "PIDFile", config_parse_path, 0, &u->service.pid_file, "Service" }, { "PIDFile", config_parse_path_printf, 0, &u->service.pid_file, "Service" },
{ "ExecStartPre", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_START_PRE, "Service" }, { "ExecStartPre", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_START_PRE, "Service" },
{ "ExecStart", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_START, "Service" }, { "ExecStart", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_START, "Service" },
{ "ExecStartPost", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_START_POST, "Service" }, { "ExecStartPost", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_START_POST, "Service" },

View File

@ -203,7 +203,7 @@ static int console_setup(bool do_reset) {
return -tty_fd; return -tty_fd;
} }
if ((r = reset_terminal(tty_fd)) < 0) if ((r = reset_terminal_fd(tty_fd)) < 0)
log_error("Failed to reset /dev/console: %s", strerror(-r)); log_error("Failed to reset /dev/console: %s", strerror(-r));
close_nointr_nofail(tty_fd); close_nointr_nofail(tty_fd);

View File

@ -76,6 +76,10 @@
#define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */ #define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */
#endif #endif
#ifndef TIOCVHANGUP
#define TIOCVHANGUP 0x5437
#endif
static inline int pivot_root(const char *new_root, const char *put_old) { static inline int pivot_root(const char *new_root, const char *put_old) {
return syscall(SYS_pivot_root, new_root, put_old); return syscall(SYS_pivot_root, new_root, put_old);
} }

View File

@ -1212,7 +1212,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
m->failure = m->failure || !success; m->failure = m->failure || !success;
if (m->control_command) { if (m->control_command) {
exec_status_exit(&m->control_command->exec_status, pid, code, status, m->exec_context.utmp_id); exec_status_exit(&m->control_command->exec_status, &m->exec_context, pid, code, status);
m->control_command = NULL; m->control_command = NULL;
m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
} }

View File

@ -2571,7 +2571,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
if (s->main_pid == pid) { if (s->main_pid == pid) {
s->main_pid = 0; s->main_pid = 0;
exec_status_exit(&s->main_exec_status, pid, code, status, s->exec_context.utmp_id); exec_status_exit(&s->main_exec_status, &s->exec_context, pid, code, status);
/* If this is not a forking service than the main /* If this is not a forking service than the main
* process got started and hence we copy the exit * process got started and hence we copy the exit
@ -2650,7 +2650,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->control_pid = 0; s->control_pid = 0;
if (s->control_command) { if (s->control_command) {
exec_status_exit(&s->control_command->exec_status, pid, code, status, s->exec_context.utmp_id); exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
if (s->control_command->ignore) if (s->control_command->ignore)
success = true; success = true;

View File

@ -1808,7 +1808,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
success = is_clean_exit(code, status); success = is_clean_exit(code, status);
if (s->control_command) { if (s->control_command) {
exec_status_exit(&s->control_command->exec_status, pid, code, status, s->exec_context.utmp_id); exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
if (s->control_command->ignore) if (s->control_command->ignore)
success = true; success = true;

View File

@ -940,7 +940,7 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->failure = s->failure || !success; s->failure = s->failure || !success;
if (s->control_command) { if (s->control_command) {
exec_status_exit(&s->control_command->exec_status, pid, code, status, s->exec_context.utmp_id); exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
s->control_command = NULL; s->control_command = NULL;
s->control_command_id = _SWAP_EXEC_COMMAND_INVALID; s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
} }

View File

@ -2261,7 +2261,7 @@ int ask(char *ret, const char *replies, const char *text, ...) {
} }
} }
int reset_terminal(int fd) { int reset_terminal_fd(int fd) {
struct termios termios; struct termios termios;
int r = 0; int r = 0;
long arg; long arg;
@ -2323,6 +2323,19 @@ finish:
return r; return r;
} }
int reset_terminal(const char *name) {
int fd, r;
fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return fd;
r = reset_terminal_fd(fd);
close_nointr_nofail(fd);
return r;
}
int open_terminal(const char *name, int mode) { int open_terminal(const char *name, int mode) {
int fd, r; int fd, r;
unsigned c = 0; unsigned c = 0;
@ -2443,8 +2456,8 @@ int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocst
/* We pass here O_NOCTTY only so that we can check the return /* We pass here O_NOCTTY only so that we can check the return
* value TIOCSCTTY and have a reliable way to figure out if we * value TIOCSCTTY and have a reliable way to figure out if we
* successfully became the controlling process of the tty */ * successfully became the controlling process of the tty */
if ((fd = open_terminal(name, O_RDWR|O_NOCTTY)) < 0) if ((fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0)
return -errno; return fd;
/* First, try to get the tty */ /* First, try to get the tty */
r = ioctl(fd, TIOCSCTTY, force); r = ioctl(fd, TIOCSCTTY, force);
@ -2511,7 +2524,7 @@ int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocst
if (notify >= 0) if (notify >= 0)
close_nointr_nofail(notify); close_nointr_nofail(notify);
if ((r = reset_terminal(fd)) < 0) if ((r = reset_terminal_fd(fd)) < 0)
log_warning("Failed to reset terminal: %s", strerror(-r)); log_warning("Failed to reset terminal: %s", strerror(-r));
return fd; return fd;
@ -4413,6 +4426,123 @@ char* hostname_cleanup(char *s) {
return s; return s;
} }
int terminal_vhangup_fd(int fd) {
if (ioctl(fd, TIOCVHANGUP) < 0)
return -errno;
return 0;
}
int terminal_vhangup(const char *name) {
int fd, r;
fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return fd;
r = terminal_vhangup_fd(fd);
close_nointr_nofail(fd);
return r;
}
int vt_disallocate(const char *name) {
int fd, r;
unsigned u;
int temporary_vt, temporary_fd;
char tpath[64];
struct vt_stat vt_stat;
/* Deallocate the VT if possible. If not possible
* (i.e. because it is the active one), at least clear it
* entirely (including the scrollback buffer) */
if (!tty_is_vc(name))
return -EIO;
if (!startswith(name, "/dev/tty"))
return -EINVAL;
r = safe_atou(name+8, &u);
if (r < 0)
return r;
if (u <= 0)
return -EIO;
fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return fd;
r = ioctl(fd, VT_DISALLOCATE, u);
if (r >= 0) {
close_nointr_nofail(fd);
return 0;
}
if (errno != EBUSY) {
close_nointr_nofail(fd);
return -errno;
}
if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0) {
close_nointr_nofail(fd);
return -errno;
}
if (u != vt_stat.v_active) {
close_nointr_nofail(fd);
return -EBUSY;
}
if (ioctl(fd, VT_OPENQRY, &temporary_vt) < 0) {
close_nointr_nofail(fd);
return -errno;
}
if (temporary_vt <= 0) {
close_nointr_nofail(fd);
return -EIO;
}
/* Switch to temporary VT */
snprintf(tpath, sizeof(tpath), "/dev/tty%i", temporary_vt);
char_array_0(tpath);
temporary_fd = open_terminal(tpath, O_RDWR|O_NOCTTY|O_CLOEXEC);
ioctl(fd, VT_ACTIVATE, temporary_vt);
if (temporary_fd >= 0)
close_nointr_nofail(temporary_fd);
/* Reopen /dev/tty0 */
close_nointr_nofail(fd);
fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
r = -errno;
else {
/* Disallocate the real VT */
if (ioctl(fd, VT_DISALLOCATE, u) < 0)
r = -errno;
else
r = 0;
}
/* Recreate original VT */
temporary_fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (temporary_fd >= 0) {
loop_write(temporary_fd, "\033[H\033[2J", 7, false); /* clear screen explicitly */
close_nointr_nofail(temporary_fd);
}
/* Switch back to original VT */
if (fd >= 0) {
ioctl(fd, VT_ACTIVATE, vt_stat.v_active);
close_nointr_nofail(fd);
}
return r;
}
static const char *const ioprio_class_table[] = { static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime", [IOPRIO_CLASS_RT] = "realtime",

View File

@ -315,7 +315,9 @@ int chvt(int vt);
int read_one_char(FILE *f, char *ret, bool *need_nl); int read_one_char(FILE *f, char *ret, bool *need_nl);
int ask(char *ret, const char *replies, const char *text, ...); int ask(char *ret, const char *replies, const char *text, ...);
int reset_terminal(int fd); int reset_terminal_fd(int fd);
int reset_terminal(const char *name);
int open_terminal(const char *name, int mode); int open_terminal(const char *name, int mode);
int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm); int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm);
int release_terminal(void); int release_terminal(void);
@ -411,6 +413,11 @@ char* hostname_cleanup(char *s);
char* strshorten(char *s, size_t l); char* strshorten(char *s, size_t l);
int terminal_vhangup_fd(int fd);
int terminal_vhangup(const char *name);
int vt_disallocate(const char *name);
#define NULSTR_FOREACH(i, l) \ #define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)

View File

@ -36,6 +36,10 @@ ExecStart=-/sbin/agetty %I 38400
Restart=always Restart=always
RestartSec=0 RestartSec=0
UtmpIdentifier=%I UtmpIdentifier=%I
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
KillMode=process KillMode=process
# Unset locale for the console getty since the console has problems # Unset locale for the console getty since the console has problems

View File

@ -36,6 +36,9 @@ ExecStart=-/sbin/agetty -s %I 115200,38400,9600
Restart=always Restart=always
RestartSec=0 RestartSec=0
UtmpIdentifier=%I UtmpIdentifier=%I
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
KillMode=process KillMode=process
# Some login implementations ignore SIGTERM, so we send SIGHUP # Some login implementations ignore SIGTERM, so we send SIGHUP