mirror of
https://github.com/systemd/systemd.git
synced 2025-01-23 08:53:39 +08:00
service: optionally, create INIT_PROCESS/DEAD_PROCESS entries for a service
This should fix accounting for pam_limits and suchlike. https://bugzilla.redhat.com/show_bug.cgi?id=636036
This commit is contained in:
parent
926e430133
commit
169c1bda80
@ -374,6 +374,7 @@ libsystemd_core_la_SOURCES = \
|
||||
src/path.c \
|
||||
src/load-dropin.c \
|
||||
src/execute.c \
|
||||
src/utmp-wtmp.c \
|
||||
src/exit-status.c \
|
||||
src/dbus.c \
|
||||
src/dbus-manager.c \
|
||||
@ -440,7 +441,6 @@ EXTRA_DIST += \
|
||||
src/dbus-common.h \
|
||||
src/bus-errors.h \
|
||||
src/cgroup-show.h \
|
||||
src/utmp-wtmp.h \
|
||||
src/build.h \
|
||||
src/shutdownd.h \
|
||||
src/readahead-common.h
|
||||
|
2
TODO
2
TODO
@ -24,8 +24,6 @@
|
||||
- bluetoothd (/var/run/sdp! @/org/bluez/audio!)
|
||||
- distccd
|
||||
|
||||
* write utmp record a la upstart for processes
|
||||
|
||||
* selinux policy loading
|
||||
|
||||
* fingerprint.target, wireless.target, gps.target
|
||||
|
@ -728,6 +728,27 @@
|
||||
it.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>UtmpIdentifier=</varname></term>
|
||||
|
||||
<listitem><para>Takes a a four
|
||||
character identifier string for an
|
||||
utmp/wtmp entry for this service. This
|
||||
should only be set for services such
|
||||
as <command>getty</command>
|
||||
implementations where utmp/wtmp
|
||||
entries must be created and cleared
|
||||
before and after execution. If the
|
||||
configured string is longer than four
|
||||
characters it is truncated and the
|
||||
terminal four characters are
|
||||
used. This setting interprets %I style
|
||||
string replacements. This setting is
|
||||
unset by default, i.e. no utmp/wtmp
|
||||
entries are created or cleaned up for
|
||||
this service.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -84,8 +84,9 @@
|
||||
" <property name=\"MountFlags\" type=\"t\" access=\"read\"/>\n" \
|
||||
" <property name=\"PrivateTmp\" type=\"b\" access=\"read\"/>\n" \
|
||||
" <property name=\"SameProcessGroup\" type=\"b\" access=\"read\"/>\n" \
|
||||
" <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n"
|
||||
" <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n" \
|
||||
" <property name=\"UtmpIdentifier\" type=\"s\" access=\"read\"/>\n"
|
||||
|
||||
#define BUS_EXEC_COMMAND_INTERFACE(name) \
|
||||
" <property name=\"" name "\" type=\"a(sasbttuii)\" access=\"read\"/>\n"
|
||||
@ -142,7 +143,8 @@
|
||||
{ interface, "PrivateTmp", bus_property_append_bool, "b", &(context).private_tmp }, \
|
||||
{ interface, "SameProcessGroup", bus_property_append_bool, "b", &(context).same_pgrp }, \
|
||||
{ interface, "KillMode", bus_execute_append_kill_mode, "s", &(context).kill_mode }, \
|
||||
{ interface, "KillSignal", bus_property_append_int, "i", &(context).kill_signal }
|
||||
{ interface, "KillSignal", bus_property_append_int, "i", &(context).kill_signal }, \
|
||||
{ interface, "UtmpIdentifier", bus_property_append_string, "s", &(context).utmp_id }
|
||||
|
||||
#define BUS_EXEC_STATUS_PROPERTIES(interface, estatus, prefix) \
|
||||
{ interface, prefix "StartTimestamp", bus_property_append_usec, "t", &(estatus).start_timestamp.realtime }, \
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include "tcpwrap.h"
|
||||
#include "exit-status.h"
|
||||
#include "missing.h"
|
||||
#include "utmp-wtmp.h"
|
||||
|
||||
/* This assumes there is a 'tty' group */
|
||||
#define TTY_MODE 0620
|
||||
@ -1129,6 +1130,9 @@ int exec_spawn(ExecCommand *command,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (context->utmp_id)
|
||||
utmp_put_init_process(0, context->utmp_id, getpid(), getsid(0), context->tty_path);
|
||||
|
||||
if (context->user) {
|
||||
username = context->user;
|
||||
if (get_user_creds(&username, &uid, &gid, &home) < 0) {
|
||||
@ -1604,6 +1608,12 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
|
||||
"%sKillSignal: SIG%s\n",
|
||||
prefix, kill_mode_to_string(c->kill_mode),
|
||||
prefix, signal_to_string(c->kill_signal));
|
||||
|
||||
if (c->utmp_id)
|
||||
fprintf(f,
|
||||
"%sUtmpIdentifier: %s\n",
|
||||
prefix, c->utmp_id);
|
||||
|
||||
}
|
||||
|
||||
void exec_status_start(ExecStatus *s, pid_t pid) {
|
||||
@ -1614,7 +1624,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) {
|
||||
void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status, const char *utmp_id) {
|
||||
assert(s);
|
||||
|
||||
if ((s->pid && s->pid != pid) ||
|
||||
@ -1626,6 +1636,9 @@ void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status) {
|
||||
|
||||
s->code = code;
|
||||
s->status = status;
|
||||
|
||||
if (utmp_id)
|
||||
utmp_put_dead_process(utmp_id, pid, code, status);
|
||||
}
|
||||
|
||||
void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
|
||||
|
@ -127,6 +127,8 @@ struct ExecContext {
|
||||
|
||||
char *pam_name;
|
||||
|
||||
char *utmp_id;
|
||||
|
||||
char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
|
||||
unsigned long mount_flags;
|
||||
|
||||
@ -191,7 +193,7 @@ void exec_context_done(ExecContext *c);
|
||||
void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
|
||||
|
||||
void exec_status_start(ExecStatus *s, pid_t pid);
|
||||
void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status);
|
||||
void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status, const char *utmp_id);
|
||||
void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);
|
||||
|
||||
const char* exec_output_to_string(ExecOutput i);
|
||||
|
@ -1669,7 +1669,8 @@ static int load_from_path(Unit *u, const char *path) {
|
||||
{ "TCPWrapName", config_parse_string_printf, &(context).tcpwrap_name, section }, \
|
||||
{ "PAMName", config_parse_string_printf, &(context).pam_name, section }, \
|
||||
{ "KillMode", config_parse_kill_mode, &(context).kill_mode, section }, \
|
||||
{ "KillSignal", config_parse_kill_signal, &(context).kill_signal, section }
|
||||
{ "KillSignal", config_parse_kill_signal, &(context).kill_signal, section }, \
|
||||
{ "UtmpIdentifier", config_parse_string_printf, &(context).utmp_id, section }
|
||||
|
||||
const ConfigItem items[] = {
|
||||
{ "Names", config_parse_names, u, "Unit" },
|
||||
|
@ -1057,7 +1057,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);
|
||||
exec_status_exit(&m->control_command->exec_status, pid, code, status, m->exec_context.utmp_id);
|
||||
m->control_command = NULL;
|
||||
m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
|
||||
}
|
||||
|
@ -2406,7 +2406,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);
|
||||
exec_status_exit(&s->main_exec_status, pid, code, status, s->exec_context.utmp_id);
|
||||
|
||||
if (s->type != SERVICE_FORKING && s->control_command) {
|
||||
s->control_command->exec_status = s->main_exec_status;
|
||||
@ -2483,7 +2483,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);
|
||||
exec_status_exit(&s->control_command->exec_status, pid, code, status, s->exec_context.utmp_id);
|
||||
|
||||
if (s->control_command->ignore)
|
||||
success = true;
|
||||
|
@ -1601,7 +1601,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);
|
||||
exec_status_exit(&s->control_command->exec_status, pid, code, status, s->exec_context.utmp_id);
|
||||
|
||||
if (s->control_command->ignore)
|
||||
success = true;
|
||||
|
@ -92,19 +92,26 @@ int utmp_get_runlevel(int *runlevel, int *previous) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static void init_entry(struct utmpx *store, usec_t t) {
|
||||
struct utsname uts;
|
||||
|
||||
static void init_timestamp(struct utmpx *store, usec_t t) {
|
||||
assert(store);
|
||||
|
||||
zero(*store);
|
||||
zero(uts);
|
||||
|
||||
if (t <= 0)
|
||||
t = now(CLOCK_REALTIME);
|
||||
|
||||
store->ut_tv.tv_sec = t / USEC_PER_SEC;
|
||||
store->ut_tv.tv_usec = t % USEC_PER_SEC;
|
||||
}
|
||||
|
||||
static void init_entry(struct utmpx *store, usec_t t) {
|
||||
struct utsname uts;
|
||||
|
||||
assert(store);
|
||||
|
||||
init_timestamp(store, t);
|
||||
|
||||
zero(uts);
|
||||
|
||||
if (uname(&uts) >= 0)
|
||||
strncpy(store->ut_host, uts.release, sizeof(store->ut_host));
|
||||
@ -187,6 +194,69 @@ int utmp_put_reboot(usec_t t) {
|
||||
return write_entry_both(&store);
|
||||
}
|
||||
|
||||
static const char *sanitize_id(const char *id) {
|
||||
size_t l;
|
||||
|
||||
assert(id);
|
||||
l = strlen(id);
|
||||
|
||||
if (l <= sizeof(((struct utmpx*) NULL)->ut_id))
|
||||
return id;
|
||||
|
||||
return id + l - sizeof(((struct utmpx*) NULL)->ut_id);
|
||||
}
|
||||
|
||||
int utmp_put_init_process(usec_t t, const char *id, pid_t pid, pid_t sid, const char *line) {
|
||||
struct utmpx store;
|
||||
|
||||
assert(id);
|
||||
|
||||
init_timestamp(&store, t);
|
||||
|
||||
store.ut_type = INIT_PROCESS;
|
||||
store.ut_pid = pid;
|
||||
store.ut_session = sid;
|
||||
|
||||
strncpy(store.ut_id, sanitize_id(id), sizeof(store.ut_id));
|
||||
|
||||
if (line)
|
||||
strncpy(store.ut_line, file_name_from_path(line), sizeof(store.ut_line));
|
||||
|
||||
return write_entry_both(&store);
|
||||
}
|
||||
|
||||
int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
|
||||
struct utmpx lookup, store, *found;
|
||||
|
||||
assert(id);
|
||||
|
||||
setutxent();
|
||||
|
||||
zero(lookup);
|
||||
lookup.ut_type = INIT_PROCESS; /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */
|
||||
strncpy(lookup.ut_id, sanitize_id(id), sizeof(lookup.ut_id));
|
||||
|
||||
if (!(found = getutxid(&lookup)))
|
||||
return 0;
|
||||
|
||||
if (found->ut_pid != pid)
|
||||
return 0;
|
||||
|
||||
zero(store);
|
||||
|
||||
memcpy(&store, &lookup, sizeof(store));
|
||||
store.ut_type = DEAD_PROCESS;
|
||||
store.ut_exit.e_termination = code;
|
||||
store.ut_exit.e_exit = status;
|
||||
|
||||
zero(store.ut_user);
|
||||
zero(store.ut_host);
|
||||
zero(store.ut_tv);
|
||||
|
||||
return write_entry_both(&store);
|
||||
}
|
||||
|
||||
|
||||
int utmp_put_runlevel(usec_t t, int runlevel, int previous) {
|
||||
struct utmpx store;
|
||||
int r;
|
||||
|
@ -30,6 +30,9 @@ int utmp_put_shutdown(usec_t timestamp);
|
||||
int utmp_put_reboot(usec_t timestamp);
|
||||
int utmp_put_runlevel(usec_t timestamp, int runlevel, int previous);
|
||||
|
||||
int utmp_put_dead_process(const char *id, pid_t pid, int code, int status);
|
||||
int utmp_put_init_process(usec_t timestamp, const char *id, pid_t pid, pid_t sid, const char *line);
|
||||
|
||||
int utmp_wall(const char *message);
|
||||
|
||||
#endif
|
||||
|
@ -33,6 +33,7 @@ Environment=TERM=linux
|
||||
ExecStart=-GETTY %I
|
||||
Restart=always
|
||||
RestartSec=0
|
||||
UtmpIdentifier=%I
|
||||
KillMode=process-group
|
||||
|
||||
# Some login implementations ignore SIGTERM, so we send SIGHUP
|
||||
|
Loading…
Reference in New Issue
Block a user