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:
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
|
* 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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 }, \
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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" },
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
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;
|
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",
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user