mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +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:
parent
9131f660ee
commit
6ea832a207
12
TODO
12
TODO
@ -22,7 +22,7 @@ Features:
|
||||
* Make it possible to set the keymap independently from the font on
|
||||
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
|
||||
|
||||
@ -30,11 +30,6 @@ Features:
|
||||
|
||||
* 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
|
||||
|
||||
* unset cgroup agents on shutdown
|
||||
@ -45,14 +40,12 @@ Features:
|
||||
|
||||
* 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
|
||||
|
||||
* support notifications for services being enabled/disabled
|
||||
|
||||
* Maybe merge nss-myhostname into systemd?
|
||||
|
||||
* GC unreferenced jobs (such as .device jobs)
|
||||
|
||||
* support wildcard expansion in ListenStream= and friends
|
||||
@ -68,7 +61,6 @@ Features:
|
||||
* write blog stories about:
|
||||
- enabling dbus services
|
||||
- status update
|
||||
- you are a distro: why switch?
|
||||
- /etc/sysconfig and /etc/default
|
||||
- how to write socket activated services
|
||||
|
||||
|
@ -421,6 +421,36 @@
|
||||
TTY (see above). Defaults to
|
||||
<filename>/dev/console</filename>.</para></listitem>
|
||||
</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>
|
||||
<term><varname>SyslogIdentifier=</varname></term>
|
||||
<listitem><para>Sets the process name
|
||||
|
@ -128,6 +128,9 @@
|
||||
{ interface, "StandardOutput", bus_execute_append_output, "s", &(context).std_output }, \
|
||||
{ interface, "StandardError", bus_execute_append_output, "s", &(context).std_error }, \
|
||||
{ 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, "SyslogIdentifier", bus_property_append_string, "s", (context).syslog_identifier }, \
|
||||
{ interface, "SyslogLevelPrefix", bus_property_append_bool, "b", &(context).syslog_level_prefix }, \
|
||||
|
@ -140,6 +140,19 @@ static const char *tty_path(const ExecContext *context) {
|
||||
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) {
|
||||
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 */
|
||||
if (confirm_spawn &&
|
||||
(!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)
|
||||
fprintf(f,
|
||||
"%sTTYPath: %s\n",
|
||||
prefix, c->tty_path);
|
||||
"%sTTYPath: %s\n"
|
||||
"%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 ||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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->status = status;
|
||||
|
||||
if (utmp_id)
|
||||
utmp_put_dead_process(utmp_id, pid, code, status);
|
||||
if (context) {
|
||||
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) {
|
||||
|
@ -123,6 +123,10 @@ struct ExecContext {
|
||||
|
||||
char *tty_path;
|
||||
|
||||
bool tty_reset;
|
||||
bool tty_vhangup;
|
||||
bool tty_vt_disallocate;
|
||||
|
||||
/* Since resolving these names might might involve socket
|
||||
* connections and we don't want to deadlock ourselves these
|
||||
* 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_done(ExecContext *c);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
const char* exec_output_to_string(ExecOutput i);
|
||||
|
@ -188,6 +188,43 @@ static int config_parse_string_printf(
|
||||
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(
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
@ -1719,6 +1756,7 @@ static void dump_items(FILE *f, const ConfigItem *items) {
|
||||
{ config_parse_bool, "BOOLEAN" },
|
||||
{ config_parse_string, "STRING" },
|
||||
{ config_parse_path, "PATH" },
|
||||
{ config_parse_path_printf, "PATH" },
|
||||
{ config_parse_strv, "STRING [...]" },
|
||||
{ config_parse_nice, "NICE" },
|
||||
{ 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) \
|
||||
{ "WorkingDirectory", config_parse_path, 0, &(context).working_directory, section }, \
|
||||
{ "RootDirectory", config_parse_path, 0, &(context).root_directory, section }, \
|
||||
{ "WorkingDirectory", config_parse_path_printf, 0, &(context).working_directory, section }, \
|
||||
{ "RootDirectory", config_parse_path_printf, 0, &(context).root_directory, section }, \
|
||||
{ "User", config_parse_string_printf, 0, &(context).user, section }, \
|
||||
{ "Group", config_parse_string_printf, 0, &(context).group, 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 }, \
|
||||
{ "StandardOutput", config_parse_output, 0, &(context).std_output, 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 }, \
|
||||
{ "SyslogFacility", config_parse_facility, 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" },
|
||||
{ "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" },
|
||||
{ "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" },
|
||||
|
@ -203,7 +203,7 @@ static int console_setup(bool do_reset) {
|
||||
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));
|
||||
|
||||
close_nointr_nofail(tty_fd);
|
||||
|
@ -76,6 +76,10 @@
|
||||
#define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */
|
||||
#endif
|
||||
|
||||
#ifndef TIOCVHANGUP
|
||||
#define TIOCVHANGUP 0x5437
|
||||
#endif
|
||||
|
||||
static inline int pivot_root(const char *new_root, const char *put_old) {
|
||||
return syscall(SYS_pivot_root, new_root, put_old);
|
||||
}
|
||||
|
@ -1212,7 +1212,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
m->failure = m->failure || !success;
|
||||
|
||||
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_id = _MOUNT_EXEC_COMMAND_INVALID;
|
||||
}
|
||||
|
@ -2571,7 +2571,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
if (s->main_pid == pid) {
|
||||
|
||||
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
|
||||
* 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;
|
||||
|
||||
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)
|
||||
success = true;
|
||||
|
@ -1808,7 +1808,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
success = is_clean_exit(code, status);
|
||||
|
||||
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)
|
||||
success = true;
|
||||
|
@ -940,7 +940,7 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
s->failure = s->failure || !success;
|
||||
|
||||
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_id = _SWAP_EXEC_COMMAND_INVALID;
|
||||
}
|
||||
|
138
src/util.c
138
src/util.c
@ -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;
|
||||
int r = 0;
|
||||
long arg;
|
||||
@ -2323,6 +2323,19 @@ finish:
|
||||
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 fd, r;
|
||||
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
|
||||
* value TIOCSCTTY and have a reliable way to figure out if we
|
||||
* successfully became the controlling process of the tty */
|
||||
if ((fd = open_terminal(name, O_RDWR|O_NOCTTY)) < 0)
|
||||
return -errno;
|
||||
if ((fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0)
|
||||
return fd;
|
||||
|
||||
/* First, try to get the tty */
|
||||
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)
|
||||
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));
|
||||
|
||||
return fd;
|
||||
@ -4413,6 +4426,123 @@ char* hostname_cleanup(char *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[] = {
|
||||
[IOPRIO_CLASS_NONE] = "none",
|
||||
[IOPRIO_CLASS_RT] = "realtime",
|
||||
|
@ -315,7 +315,9 @@ int chvt(int vt);
|
||||
int read_one_char(FILE *f, char *ret, bool *need_nl);
|
||||
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 acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm);
|
||||
int release_terminal(void);
|
||||
@ -411,6 +413,11 @@ char* hostname_cleanup(char *s);
|
||||
|
||||
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) \
|
||||
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
|
||||
|
||||
|
@ -36,6 +36,10 @@ ExecStart=-/sbin/agetty %I 38400
|
||||
Restart=always
|
||||
RestartSec=0
|
||||
UtmpIdentifier=%I
|
||||
TTYPath=/dev/%I
|
||||
TTYReset=yes
|
||||
TTYVHangup=yes
|
||||
TTYVTDisallocate=yes
|
||||
KillMode=process
|
||||
|
||||
# Unset locale for the console getty since the console has problems
|
||||
|
@ -36,6 +36,9 @@ ExecStart=-/sbin/agetty -s %I 115200,38400,9600
|
||||
Restart=always
|
||||
RestartSec=0
|
||||
UtmpIdentifier=%I
|
||||
TTYPath=/dev/%I
|
||||
TTYReset=yes
|
||||
TTYVHangup=yes
|
||||
KillMode=process
|
||||
|
||||
# Some login implementations ignore SIGTERM, so we send SIGHUP
|
||||
|
Loading…
Reference in New Issue
Block a user