Merge pull request #4067 from poettering/invocation-id

Add an "invocation ID" concept to the service manager
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2016-10-11 13:40:50 -04:00
committed by GitHub
46 changed files with 587 additions and 103 deletions

View File

@@ -239,6 +239,7 @@ MANPAGES_ALIAS += \
man/SD_ID128_FORMAT_STR.3 \
man/SD_ID128_FORMAT_VAL.3 \
man/SD_ID128_MAKE.3 \
man/SD_ID128_NULL.3 \
man/SD_INFO.3 \
man/SD_JOURNAL_APPEND.3 \
man/SD_JOURNAL_CURRENT_USER.3 \
@@ -395,6 +396,8 @@ MANPAGES_ALIAS += \
man/sd_id128_equal.3 \
man/sd_id128_from_string.3 \
man/sd_id128_get_boot.3 \
man/sd_id128_get_invocation.3 \
man/sd_id128_is_null.3 \
man/sd_id128_t.3 \
man/sd_is_mq.3 \
man/sd_is_socket.3 \
@@ -589,6 +592,7 @@ man/SD_ID128_CONST_STR.3: man/sd-id128.3
man/SD_ID128_FORMAT_STR.3: man/sd-id128.3
man/SD_ID128_FORMAT_VAL.3: man/sd-id128.3
man/SD_ID128_MAKE.3: man/sd-id128.3
man/SD_ID128_NULL.3: man/sd-id128.3
man/SD_INFO.3: man/sd-daemon.3
man/SD_JOURNAL_APPEND.3: man/sd_journal_get_fd.3
man/SD_JOURNAL_CURRENT_USER.3: man/sd_journal_open.3
@@ -745,6 +749,8 @@ man/sd_event_unrefp.3: man/sd_event_new.3
man/sd_id128_equal.3: man/sd-id128.3
man/sd_id128_from_string.3: man/sd_id128_to_string.3
man/sd_id128_get_boot.3: man/sd_id128_get_machine.3
man/sd_id128_get_invocation.3: man/sd_id128_get_machine.3
man/sd_id128_is_null.3: man/sd-id128.3
man/sd_id128_t.3: man/sd-id128.3
man/sd_is_mq.3: man/sd_is_fifo.3
man/sd_is_socket.3: man/sd_is_fifo.3
@@ -1051,6 +1057,9 @@ man/SD_ID128_FORMAT_VAL.html: man/sd-id128.html
man/SD_ID128_MAKE.html: man/sd-id128.html
$(html-alias)
man/SD_ID128_NULL.html: man/sd-id128.html
$(html-alias)
man/SD_INFO.html: man/sd-daemon.html
$(html-alias)
@@ -1519,6 +1528,12 @@ man/sd_id128_from_string.html: man/sd_id128_to_string.html
man/sd_id128_get_boot.html: man/sd_id128_get_machine.html
$(html-alias)
man/sd_id128_get_invocation.html: man/sd_id128_get_machine.html
$(html-alias)
man/sd_id128_is_null.html: man/sd-id128.html
$(html-alias)
man/sd_id128_t.html: man/sd-id128.html
$(html-alias)

6
TODO
View File

@@ -74,6 +74,12 @@ Features:
* RemoveKeyRing= to remove all keyring entries of the specified user
* ProtectReboot= that masks reboot() and kexec_load() syscalls, prohibits kill
on PID 1 with the relevant signals, and makes relevant files in /sys and
/proc (such as the sysrq stuff) unavailable
* DeviceAllow= should also generate seccomp filters for mknod()
* Add DataDirectory=, CacheDirectory= and LogDirectory= to match
RuntimeDirectory=, and create it as necessary when starting a service, owned by the right user.

View File

@@ -47,10 +47,12 @@
<refname>sd-id128</refname>
<refname>sd_id128_t</refname>
<refname>SD_ID128_MAKE</refname>
<refname>SD_ID128_NULL</refname>
<refname>SD_ID128_CONST_STR</refname>
<refname>SD_ID128_FORMAT_STR</refname>
<refname>SD_ID128_FORMAT_VAL</refname>
<refname>sd_id128_equal</refname>
<refname>sd_id128_is_null</refname>
<refpurpose>APIs for processing 128-bit IDs</refpurpose>
</refnamediv>
@@ -88,8 +90,8 @@
union type:</para>
<programlisting>typedef union sd_id128 {
uint8_t bytes[16];
uint64_t qwords[2];
uint8_t bytes[16];
uint64_t qwords[2];
} sd_id128_t;</programlisting>
<para>This union type allows accessing the 128-bit ID as 16
@@ -108,37 +110,46 @@
<programlisting>#define SD_MESSAGE_COREDUMP SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)</programlisting>
<para><function>SD_ID128_NULL</function> may be used to refer to the 128bit ID consisting of only NUL
bytes.</para>
<para><function>SD_ID128_CONST_STR()</function> may be used to
convert constant 128-bit IDs into constant strings for output. The
following example code will output the string
"fc2e22bc6ee647b6b90729ab34a250b1":</para>
<programlisting>int main(int argc, char *argv[]) {
puts(SD_ID128_CONST_STR(SD_MESSAGE_COREDUMP));
puts(SD_ID128_CONST_STR(SD_MESSAGE_COREDUMP));
}</programlisting>
<para><function>SD_ID128_FORMAT_STR</function> and
<para><function>SD_ID128_FORMAT_STR()</function> and
<function>SD_ID128_FORMAT_VAL()</function> may be used to format a
128-bit ID in a
<citerefentry project='man-pages'><refentrytitle>printf</refentrytitle><manvolnum>3</manvolnum></citerefentry>
format string, as shown in the following example:</para>
<programlisting>int main(int argc, char *argv[]) {
sd_id128_t id;
id = SD_ID128_MAKE(ee,89,be,71,bd,6e,43,d6,91,e6,c5,5d,eb,03,02,07);
printf("The ID encoded in this C file is " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(id));
return 0;
sd_id128_t id;
id = SD_ID128_MAKE(ee,89,be,71,bd,6e,43,d6,91,e6,c5,5d,eb,03,02,07);
printf("The ID encoded in this C file is " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(id));
return 0;
}</programlisting>
<para>Use <function>sd_id128_equal()</function> to compare two 128-bit IDs:</para>
<programlisting>int main(int argc, char *argv[]) {
sd_id128_t a, b, c;
a = SD_ID128_MAKE(ee,89,be,71,bd,6e,43,d6,91,e6,c5,5d,eb,03,02,07);
b = SD_ID128_MAKE(f2,28,88,9c,5f,09,44,15,9d,d7,04,77,58,cb,e7,3e);
c = a;
assert(sd_id128_equal(a, c));
assert(!sd_id128_equal(a, b));
return 0;
sd_id128_t a, b, c;
a = SD_ID128_MAKE(ee,89,be,71,bd,6e,43,d6,91,e6,c5,5d,eb,03,02,07);
b = SD_ID128_MAKE(f2,28,88,9c,5f,09,44,15,9d,d7,04,77,58,cb,e7,3e);
c = a;
assert(sd_id128_equal(a, c));
assert(!sd_id128_equal(a, b));
return 0;
}</programlisting>
<para>Use <function>sd_id128_is_null()</function> to check if an 128bit ID consists of only NUL bytes:</para>
<programlisting>int main(int argc, char *argv[]) {
assert(sd_id128_is_null(SD_ID128_NULL));
}</programlisting>
<para>Note that new, randomized IDs may be generated with

View File

@@ -45,6 +45,7 @@
<refnamediv>
<refname>sd_id128_get_machine</refname>
<refname>sd_id128_get_boot</refname>
<refname>sd_id128_get_invocation</refname>
<refpurpose>Retrieve 128-bit IDs</refpurpose>
</refnamediv>
@@ -62,6 +63,11 @@
<paramdef>sd_id128_t *<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_id128_get_invocation</function></funcdef>
<paramdef>sd_id128_t *<parameter>ret</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
@@ -83,11 +89,15 @@
for more information. This function also internally caches the
returned ID to make this call a cheap operation.</para>
<para>Note that <function>sd_id128_get_boot()</function> always
returns a UUID v4 compatible ID.
<function>sd_id128_get_machine()</function> will also return a
UUID v4-compatible ID on new installations but might not on older.
It is possible to convert the machine ID into a UUID v4-compatible
<para><function>sd_id128_get_invocation()</function> returns the invocation ID of the currently executed
service. In its current implementation, this reads and parses the <varname>$INVOCATION_ID</varname> environment
variable that the service manager sets when activating a service, see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details. The
ID is cached internally. In future a different mechanism to determine the invocation ID may be added.</para>
<para>Note that <function>sd_id128_get_boot()</function> and <function>sd_id128_get_invocation()</function> always
return UUID v4 compatible IDs. <function>sd_id128_get_machine()</function> will also return a UUID v4-compatible
ID on new installations but might not on older. It is possible to convert the machine ID into a UUID v4-compatible
one. For more information, see
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
@@ -107,11 +117,10 @@
<refsect1>
<title>Notes</title>
<para>The <function>sd_id128_get_machine()</function> and
<function>sd_id128_get_boot()</function> interfaces are available
as a shared library, which can be compiled and linked to with the
<literal>libsystemd</literal> <citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
file.</para>
<para>The <function>sd_id128_get_machine()</function>, <function>sd_id128_get_boot()</function> and
<function>sd_id128_get_invocation()</function> interfaces are available as a shared library, which can be compiled
and linked to with the <literal>libsystemd</literal> <citerefentry
project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> file.</para>
</refsect1>
<refsect1>
@@ -121,8 +130,9 @@
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-id128</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_id128_randomize</refentrytitle><manvolnum>3</manvolnum></citerefentry>
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_id128_randomize</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry>
</para>
</refsect1>

View File

@@ -1513,6 +1513,16 @@
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>$INVOCATION_ID</varname></term>
<listitem><para>Contains a randomized, unique 128bit ID identifying each runtime cycle of the unit, formatted
as 32 character hexadecimal string. A new ID is assigned each time the unit changes from an inactive state into
an activating or active state, and may be used to identify this specific runtime cycle, in particular in data
stored offline, such as the journal. The same ID is passed to all processes run as part of the
unit.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>$XDG_RUNTIME_DIR</varname></term>

View File

@@ -28,6 +28,7 @@
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/types.h>
#include <sys/xattr.h>
#include <unistd.h>
#include "alloc-util.h"
@@ -883,6 +884,43 @@ int cg_set_task_access(
return 0;
}
int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags) {
_cleanup_free_ char *fs = NULL;
int r;
assert(path);
assert(name);
assert(value || size <= 0);
r = cg_get_path(controller, path, NULL, &fs);
if (r < 0)
return r;
if (setxattr(fs, name, value, size, flags) < 0)
return -errno;
return 0;
}
int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size) {
_cleanup_free_ char *fs = NULL;
ssize_t n;
int r;
assert(path);
assert(name);
r = cg_get_path(controller, path, NULL, &fs);
if (r < 0)
return r;
n = getxattr(fs, name, value, size);
if (n < 0)
return -errno;
return (int) n;
}
int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
_cleanup_fclose_ FILE *f = NULL;
char line[LINE_MAX];
@@ -1666,7 +1704,7 @@ int cg_path_get_slice(const char *p, char **slice) {
if (!e) {
char *s;
s = strdup("-.slice");
s = strdup(SPECIAL_ROOT_SLICE);
if (!s)
return -ENOMEM;
@@ -1821,7 +1859,7 @@ int cg_slice_to_path(const char *unit, char **ret) {
assert(unit);
assert(ret);
if (streq(unit, "-.slice")) {
if (streq(unit, SPECIAL_ROOT_SLICE)) {
char *x;
x = strdup("");

View File

@@ -185,6 +185,9 @@ int cg_get_keyed_attribute(const char *controller, const char *path, const char
int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid);
int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid);
int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags);
int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size);
int cg_install_release_agent(const char *controller, const char *agent);
int cg_uninstall_release_agent(const char *controller);

View File

@@ -133,7 +133,7 @@ static int create_log_socket(int type) {
if (fd < 0)
return -errno;
fd_inc_sndbuf(fd, SNDBUF_SIZE);
(void) fd_inc_sndbuf(fd, SNDBUF_SIZE);
/* We need a blocking fd here since we'd otherwise lose
messages way too early. However, let's not hang forever in the
@@ -330,8 +330,6 @@ static int write_to_console(
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
const char *buffer) {
char location[256], prefix[1 + DECIMAL_STR_MAX(int) + 2];
@@ -343,7 +341,7 @@ static int write_to_console(
return 0;
if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
sprintf(prefix, "<%i>", level);
xsprintf(prefix, "<%i>", level);
IOVEC_SET_STRING(iovec[n++], prefix);
}
@@ -390,8 +388,6 @@ static int write_to_syslog(
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
const char *buffer) {
char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
@@ -453,8 +449,6 @@ static int write_to_kmsg(
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
const char *buffer) {
char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
@@ -485,7 +479,8 @@ static int log_do_header(
int level,
int error,
const char *file, int line, const char *func,
const char *object_field, const char *object) {
const char *object_field, const char *object,
const char *extra_field, const char *extra) {
snprintf(header, size,
"PRIORITY=%i\n"
@@ -495,6 +490,7 @@ static int log_do_header(
"%s%s%s"
"%s%.*i%s"
"%s%s%s"
"%s%s%s"
"SYSLOG_IDENTIFIER=%s\n",
LOG_PRI(level),
LOG_FAC(level),
@@ -513,6 +509,9 @@ static int log_do_header(
isempty(object) ? "" : object_field,
isempty(object) ? "" : object,
isempty(object) ? "" : "\n",
isempty(extra) ? "" : extra_field,
isempty(extra) ? "" : extra,
isempty(extra) ? "" : "\n",
program_invocation_short_name);
return 0;
@@ -526,6 +525,8 @@ static int write_to_journal(
const char *func,
const char *object_field,
const char *object,
const char *extra_field,
const char *extra,
const char *buffer) {
char header[LINE_MAX];
@@ -535,7 +536,7 @@ static int write_to_journal(
if (journal_fd < 0)
return 0;
log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object);
log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
IOVEC_SET_STRING(iovec[0], header);
IOVEC_SET_STRING(iovec[1], "MESSAGE=");
@@ -559,10 +560,15 @@ static int log_dispatch(
const char *func,
const char *object_field,
const char *object,
const char *extra,
const char *extra_field,
char *buffer) {
assert(buffer);
if (error < 0)
error = -error;
if (log_target == LOG_TARGET_NULL)
return -error;
@@ -570,9 +576,6 @@ static int log_dispatch(
if ((level & LOG_FACMASK) == 0)
level = log_facility | LOG_PRI(level);
if (error < 0)
error = -error;
do {
char *e;
int k = 0;
@@ -589,7 +592,7 @@ static int log_dispatch(
log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
log_target == LOG_TARGET_JOURNAL) {
k = write_to_journal(level, error, file, line, func, object_field, object, buffer);
k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
if (k < 0) {
if (k != -EAGAIN)
log_close_journal();
@@ -600,7 +603,7 @@ static int log_dispatch(
if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
log_target == LOG_TARGET_SYSLOG) {
k = write_to_syslog(level, error, file, line, func, object_field, object, buffer);
k = write_to_syslog(level, error, file, line, func, buffer);
if (k < 0) {
if (k != -EAGAIN)
log_close_syslog();
@@ -615,7 +618,7 @@ static int log_dispatch(
log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
log_target == LOG_TARGET_KMSG)) {
k = write_to_kmsg(level, error, file, line, func, object_field, object, buffer);
k = write_to_kmsg(level, error, file, line, func, buffer);
if (k < 0) {
log_close_kmsg();
log_open_console();
@@ -623,7 +626,7 @@ static int log_dispatch(
}
if (k <= 0)
(void) write_to_console(level, error, file, line, func, object_field, object, buffer);
(void) write_to_console(level, error, file, line, func, buffer);
buffer = e;
} while (buffer);
@@ -649,7 +652,7 @@ int log_dump_internal(
if (_likely_(LOG_PRI(level) > log_max_level))
return -error;
return log_dispatch(level, error, file, line, func, NULL, NULL, buffer);
return log_dispatch(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
}
int log_internalv(
@@ -676,7 +679,7 @@ int log_internalv(
vsnprintf(buffer, sizeof(buffer), format, ap);
return log_dispatch(level, error, file, line, func, NULL, NULL, buffer);
return log_dispatch(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
}
int log_internal(
@@ -705,6 +708,8 @@ int log_object_internalv(
const char *func,
const char *object_field,
const char *object,
const char *extra_field,
const char *extra,
const char *format,
va_list ap) {
@@ -738,7 +743,7 @@ int log_object_internalv(
vsnprintf(b, l, format, ap);
return log_dispatch(level, error, file, line, func, object_field, object, buffer);
return log_dispatch(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
}
int log_object_internal(
@@ -749,13 +754,15 @@ int log_object_internal(
const char *func,
const char *object_field,
const char *object,
const char *extra_field,
const char *extra,
const char *format, ...) {
va_list ap;
int r;
va_start(ap, format);
r = log_object_internalv(level, error, file, line, func, object_field, object, format, ap);
r = log_object_internalv(level, error, file, line, func, object_field, object, extra_field, extra, format, ap);
va_end(ap);
return r;
@@ -780,7 +787,7 @@ static void log_assert(
log_abort_msg = buffer;
log_dispatch(level, 0, file, line, func, NULL, NULL, buffer);
log_dispatch(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer);
}
noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) {
@@ -888,7 +895,7 @@ int log_struct_internal(
bool fallback = false;
/* If the journal is available do structured logging */
log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL);
log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
IOVEC_SET_STRING(iovec[n++], header);
va_start(ap, format);
@@ -935,7 +942,7 @@ int log_struct_internal(
if (!found)
return -error;
return log_dispatch(level, error, file, line, func, NULL, NULL, buf + 8);
return log_dispatch(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
}
int log_set_target_from_string(const char *e) {

View File

@@ -100,18 +100,22 @@ int log_object_internal(
const char *func,
const char *object_field,
const char *object,
const char *format, ...) _printf_(8,9);
const char *extra_field,
const char *extra,
const char *format, ...) _printf_(10,11);
int log_object_internalv(
int level,
int error,
const char*file,
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
const char *extra_field,
const char *extra,
const char *format,
va_list ap) _printf_(8,0);
va_list ap) _printf_(9,0);
int log_struct_internal(
int level,

View File

@@ -96,10 +96,13 @@ bool strv_overlap(char **a, char **b) _pure_;
#define STRV_FOREACH(s, l) \
for ((s) = (l); (s) && *(s); (s)++)
#define STRV_FOREACH_BACKWARDS(s, l) \
STRV_FOREACH(s, l) \
; \
for ((s)--; (l) && ((s) >= (l)); (s)--)
#define STRV_FOREACH_BACKWARDS(s, l) \
for (s = ({ \
char **_l = l; \
_l ? _l + strv_length(_l) - 1U : NULL; \
}); \
(l) && ((s) >= (l)); \
(s)--)
#define STRV_FOREACH_PAIR(x, y, l) \
for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))

View File

@@ -800,6 +800,10 @@ static int automount_start(Unit *u) {
return r;
}
r = unit_acquire_invocation_id(u);
if (r < 0)
return r;
a->result = AUTOMOUNT_SUCCESS;
automount_enter_waiting(a);
return 1;

View File

@@ -639,6 +639,10 @@ static int busname_start(Unit *u) {
return r;
}
r = unit_acquire_invocation_id(u);
if (r < 0)
return r;
n->result = BUSNAME_SUCCESS;
busname_enter_making(n);

View File

@@ -1361,6 +1361,26 @@ int unit_attach_pids_to_cgroup(Unit *u) {
return 0;
}
static void cgroup_xattr_apply(Unit *u) {
char ids[SD_ID128_STRING_MAX];
int r;
assert(u);
if (!MANAGER_IS_SYSTEM(u->manager))
return;
if (sd_id128_is_null(u->invocation_id))
return;
r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path,
"trusted.invocation_id",
sd_id128_to_string(u->invocation_id, ids), 32,
0);
if (r < 0)
log_unit_warning_errno(u, r, "Failed to set invocation ID on control group %s, ignoring: %m", u->cgroup_path);
}
static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask, CGroupMask enable_mask) {
assert(u);
@@ -1404,6 +1424,7 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
/* Finally, apply the necessary attributes. */
cgroup_context_apply(u, target_mask, state);
cgroup_xattr_apply(u);
return 0;
}

View File

@@ -464,6 +464,64 @@ static int method_get_unit_by_pid(sd_bus_message *message, void *userdata, sd_bu
return sd_bus_reply_method_return(message, "o", path);
}
static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *path = NULL;
Manager *m = userdata;
sd_id128_t id;
const void *a;
Unit *u;
size_t sz;
int r;
assert(message);
assert(m);
/* Anyone can call this method */
r = sd_bus_message_read_array(message, 'y', &a, &sz);
if (r < 0)
return r;
if (sz == 0)
id = SD_ID128_NULL;
else if (sz == 16)
memcpy(&id, a, sz);
else
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid invocation ID");
if (sd_id128_is_null(id)) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
pid_t pid;
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
if (r < 0)
return r;
r = sd_bus_creds_get_pid(creds, &pid);
if (r < 0)
return r;
u = manager_get_unit_by_pid(m, pid);
if (!u)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Client " PID_FMT " not member of any unit.", pid);
} else {
u = hashmap_get(m->units_by_invocation_id, &id);
if (!u)
return sd_bus_error_setf(error, BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID, "No unit with the specified invocation ID " SD_ID128_FORMAT_STR " known.", SD_ID128_FORMAT_VAL(id));
}
r = mac_selinux_unit_access_check(u, message, "status", error);
if (r < 0)
return r;
/* So here's a special trick: the bus path we return actually references the unit by its invocation ID instead
* of the unit name. This means it stays valid only as long as the invocation ID stays the same. */
path = unit_dbus_path_invocation_id(u);
if (!path)
return -ENOMEM;
return sd_bus_reply_method_return(message, "o", path);
}
static int method_load_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *path = NULL;
Manager *m = userdata;
@@ -2254,6 +2312,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitByInvocationID", "ay", "o", method_get_unit_by_invocation_id, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("LoadUnit", "s", "o", method_load_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("StartUnit", "ss", "o", method_start_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("StartUnitReplace", "sss", "o", method_start_unit_replace, SD_BUS_VTABLE_UNPRIVILEGED),

View File

@@ -764,6 +764,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128, offsetof(Unit, invocation_id), 0),
SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),

View File

@@ -464,6 +464,10 @@ static void device_update_found_one(Device *d, bool add, DeviceFound found, bool
if (!now)
return;
/* Didn't exist before, but does now? if so, generate a new invocation ID for it */
if (previous == DEVICE_NOT_FOUND && d->found != DEVICE_NOT_FOUND)
(void) unit_acquire_invocation_id(UNIT(d));
if (d->found & DEVICE_FOUND_UDEV)
/* When the device is known to udev we consider it
* plugged. */

View File

@@ -1553,10 +1553,11 @@ static int build_environment(
unsigned n_env = 0;
char *x;
assert(u);
assert(c);
assert(ret);
our_env = new0(char*, 13);
our_env = new0(char*, 14);
if (!our_env)
return -ENOMEM;
@@ -1627,6 +1628,13 @@ static int build_environment(
our_env[n_env++] = x;
}
if (!sd_id128_is_null(u->invocation_id)) {
if (asprintf(&x, "INVOCATION_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id)) < 0)
return -ENOMEM;
our_env[n_env++] = x;
}
if (exec_context_needs_term(c)) {
const char *tty_path, *term = NULL;

View File

@@ -522,6 +522,7 @@ static void manager_clean_environment(Manager *m) {
"LISTEN_FDNAMES",
"WATCHDOG_PID",
"WATCHDOG_USEC",
"INVOCATION_ID",
NULL);
}
@@ -582,9 +583,15 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
if (MANAGER_IS_SYSTEM(m)) {
m->unit_log_field = "UNIT=";
m->unit_log_format_string = "UNIT=%s";
m->invocation_log_field = "INVOCATION_ID=";
m->invocation_log_format_string = "INVOCATION_ID=" SD_ID128_FORMAT_STR;
} else {
m->unit_log_field = "USER_UNIT=";
m->unit_log_format_string = "USER_UNIT=%s";
m->invocation_log_field = "USER_INVOCATION_ID=";
m->invocation_log_format_string = "USER_INVOCATION_ID=" SD_ID128_FORMAT_STR;
}
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
@@ -1062,6 +1069,7 @@ Manager* manager_free(Manager *m) {
hashmap_free(m->dynamic_users);
hashmap_free(m->units);
hashmap_free(m->units_by_invocation_id);
hashmap_free(m->jobs);
hashmap_free(m->watch_pids1);
hashmap_free(m->watch_pids2);
@@ -2268,6 +2276,7 @@ int manager_loop(Manager *m) {
int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u) {
_cleanup_free_ char *n = NULL;
sd_id128_t invocation_id;
Unit *u;
int r;
@@ -2279,12 +2288,25 @@ int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e,
if (r < 0)
return r;
/* Permit addressing units by invocation ID: if the passed bus path is suffixed by a 128bit ID then we use it
* as invocation ID. */
r = sd_id128_from_string(n, &invocation_id);
if (r >= 0) {
u = hashmap_get(m->units_by_invocation_id, &invocation_id);
if (u) {
*_u = u;
return 0;
}
return sd_bus_error_setf(e, BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID, "No unit with the specified invocation ID " SD_ID128_FORMAT_STR " known.", SD_ID128_FORMAT_VAL(invocation_id));
}
/* If this didn't work, we use the suffix as unit name. */
r = manager_load_unit(m, n, NULL, e, &u);
if (r < 0)
return r;
*_u = u;
return 0;
}

View File

@@ -89,6 +89,7 @@ struct Manager {
/* Active jobs and units */
Hashmap *units; /* name string => Unit object n:1 */
Hashmap *units_by_invocation_id;
Hashmap *jobs; /* job id => Job object 1:1 */
/* To make it easy to iterate through the units of a specific
@@ -319,6 +320,9 @@ struct Manager {
const char *unit_log_field;
const char *unit_log_format_string;
const char *invocation_log_field;
const char *invocation_log_format_string;
int first_boot; /* tri-state */
};

View File

@@ -1006,6 +1006,10 @@ static int mount_start(Unit *u) {
return r;
}
r = unit_acquire_invocation_id(u);
if (r < 0)
return r;
m->result = MOUNT_SUCCESS;
m->reload_result = MOUNT_SUCCESS;
m->reset_cpu_usage = true;
@@ -1746,9 +1750,10 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
case MOUNT_DEAD:
case MOUNT_FAILED:
/* This has just been mounted by
* somebody else, follow the state
* change. */
/* This has just been mounted by somebody else, follow the state change, but let's
* generate a new invocation ID for this implicitly and automatically. */
(void) unit_acquire_invocation_id(UNIT(mount));
mount_enter_mounted(mount, MOUNT_SUCCESS);
break;

Some files were not shown because too many files have changed in this diff Show More