Compare commits

...

17 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek 78af8a798a meson: bump version numbers for v244 2019-11-22 14:41:10 +01:00
Zbigniew Jędrzejewski-Szmek 58c0663b97
Merge pull request #14099 from keszybz/machine-ref-unref-fix
Fix for the issue when machine cannot be started second time, and better nspawn logging
2019-11-22 14:33:27 +01:00
Pascal de Bruijn b4e2236a72 systemd-tmpfiles: don't install timer when service isn't installed either
Fixes: systemd-tmpfiles-clean.timer: Refusing to start, unit
systemd-tmpfiles-clean.service to trigger not loaded.
2019-11-22 14:30:37 +01:00
Zbigniew Jędrzejewski-Szmek 62092b2fae
Merge pull request #14109 from poettering/varlink-tweaks
varlink: fix more/continues method calls, and correctly apply method call timeout
2019-11-22 14:30:16 +01:00
Lennart Poettering f1194f5d59 varlink: fix enablement of varlink timeout event source 2019-11-22 10:54:52 +01:00
Lennart Poettering c4fe0cbc17 varlink: drop too much whitespace 2019-11-22 10:54:52 +01:00
Lennart Poettering 88a36d3690 varlink: port varlink code over to use getdtablesize() for sizing number of concurrent connections
Use the official glibc API for determining this parameter. In most other
cases in our tree it's better to go directly for RLIMIT_NOFILE since
it's semantically what we want, but for this case it appears more
appropriate to use the friendlier, shorter, explicit API.
2019-11-22 10:54:52 +01:00
Lennart Poettering a0c41de277 varlink: move connection fds > fd2
We want to use this code in NSS modules, and we never know the execution
environment we are run in there, hence let's move our fds up to ensure
we won't step into dangerous fd territory.

This is similar to how we already do it in sd-bus for client connection
fds.
2019-11-22 10:54:52 +01:00
Lennart Poettering 45a6c96598 varlink: fix support for more/continues method calls 2019-11-22 10:54:52 +01:00
Zbigniew Jędrzejewski-Szmek 698876640d machine: fold machine_stop_scope() into machine_stop()
No functional change.
2019-11-22 10:24:32 +01:00
Zbigniew Jędrzejewski-Szmek eec12b7756 machined: simplify reference handling for units
Before, we'd unref from machine_stop_unit, still keeping the unit name around,
and only forget the name later, when garbage collecting. If we didn't call
manager_stop_unit(), then we wouldn't do the unref. Let's unref at the same
point where we do garbage collection, so that it is always true that
iff we have the name generated with AddRef=1, then have a reference to the unit,
and as soon as we forget the name, we drop the reference.

This should fix the issue when repeated systemd-nspawn --register=yes fails
with "scope already exists" error.

Incidentally, this fixes an error in the code path where r was used instead of q.
2019-11-22 10:24:32 +01:00
Zbigniew Jędrzejewski-Szmek a01ecfa982 machine: simplify machine_start_scope()
It is called from only one place, and we can make things simpler by calculating the
necessary stuff directly in the function. No functional change.
2019-11-22 10:24:29 +01:00
Zbigniew Jędrzejewski-Szmek af22794712 machine: make machine_start_scope() static
Having this function which is called only from one place in a separate file
makes the code harder to follow. In preparation for subsequent changes, let's
make it static.
2019-11-22 10:23:32 +01:00
Zbigniew Jędrzejewski-Szmek f47bd09749 nspawn: log syscalls we cannot add at debug level
Without out at least a debug log line it is hard to figure out when something
goes wrong.

Reduce scope of a variable while at it.
2019-11-22 10:23:32 +01:00
Zbigniew Jędrzejewski-Szmek ec56251533 man: use <constant> for capability names in nspawn page 2019-11-22 10:23:32 +01:00
Zbigniew Jędrzejewski-Szmek 8a99bd0c46 nspawn: dump capability list with --capabilities=help 2019-11-22 10:15:46 +01:00
Zbigniew Jędrzejewski-Szmek 7f95bb22d3 resolve: rename define fixing a typo 2019-11-21 12:45:25 +01:00
11 changed files with 299 additions and 223 deletions

View File

@ -754,7 +754,7 @@
container, with the exception of the loopback device and those
specified with <option>--network-interface=</option> and
configured with <option>--network-veth</option>. If this
option is specified, the CAP_NET_ADMIN capability will be
option is specified, the <constant>CAP_NET_ADMIN</constant> capability will be
added to the set of capabilities the container retains. The
latter may be disabled by using <option>--drop-capability=</option>.
If this option is not specified (or implied by one of the options
@ -943,17 +943,27 @@
<varlistentry>
<term><option>--capability=</option></term>
<listitem><para>List one or more additional capabilities to grant the container.
Takes a comma-separated list of capability names, see
<citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
<listitem><para>List one or more additional capabilities to grant the container. Takes a
comma-separated list of capability names, see <citerefentry
project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for more information. Note that the following capabilities will be granted in any way:
CAP_AUDIT_CONTROL, CAP_AUDIT_WRITE, CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH,
CAP_FOWNER, CAP_FSETID, CAP_IPC_OWNER, CAP_KILL, CAP_LEASE, CAP_LINUX_IMMUTABLE,
CAP_MKNOD, CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, CAP_NET_RAW, CAP_SETFCAP,
CAP_SETGID, CAP_SETPCAP, CAP_SETUID, CAP_SYS_ADMIN, CAP_SYS_BOOT, CAP_SYS_CHROOT,
CAP_SYS_NICE, CAP_SYS_PTRACE, CAP_SYS_RESOURCE, CAP_SYS_TTY_CONFIG. Also CAP_NET_ADMIN
is retained if <option>--private-network</option> is specified. If the special value
<literal>all</literal> is passed, all capabilities are retained.</para></listitem>
<constant>CAP_AUDIT_CONTROL</constant>, <constant>CAP_AUDIT_WRITE</constant>,
<constant>CAP_CHOWN</constant>, <constant>CAP_DAC_OVERRIDE</constant>,
<constant>CAP_DAC_READ_SEARCH</constant>, <constant>CAP_FOWNER</constant>,
<constant>CAP_FSETID</constant>, <constant>CAP_IPC_OWNER</constant>, <constant>CAP_KILL</constant>,
<constant>CAP_LEASE</constant>, <constant>CAP_LINUX_IMMUTABLE</constant>,
<constant>CAP_MKNOD</constant>, <constant>CAP_NET_BIND_SERVICE</constant>,
<constant>CAP_NET_BROADCAST</constant>, <constant>CAP_NET_RAW</constant>,
<constant>CAP_SETFCAP</constant>, <constant>CAP_SETGID</constant>, <constant>CAP_SETPCAP</constant>,
<constant>CAP_SETUID</constant>, <constant>CAP_SYS_ADMIN</constant>,
<constant>CAP_SYS_BOOT</constant>, <constant>CAP_SYS_CHROOT</constant>,
<constant>CAP_SYS_NICE</constant>, <constant>CAP_SYS_PTRACE</constant>,
<constant>CAP_SYS_RESOURCE</constant>, <constant>CAP_SYS_TTY_CONFIG</constant>. Also
<constant>CAP_NET_ADMIN</constant> is retained if <option>--private-network</option> is specified.
If the special value <literal>all</literal> is passed, all capabilities are retained.</para>
<para>If the special value of <literal>help</literal> is passed, the program will print known
capability names and exit.</para></listitem>
</varlistentry>
<varlistentry>
@ -962,7 +972,10 @@
<listitem><para>Specify one or more additional capabilities to
drop for the container. This allows running the container with
fewer capabilities than the default (see
above).</para></listitem>
above).</para>
<para>If the special value of <literal>help</literal> is passed, the program will print known
capability names and exit.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1+
project('systemd', 'c',
version : '243',
version : '244',
license : 'LGPLv2+',
default_options: [
'c_std=gnu99',
@ -13,8 +13,8 @@ project('systemd', 'c',
meson_version : '>= 0.46',
)
libsystemd_version = '0.27.0'
libudev_version = '1.6.15'
libsystemd_version = '0.27.1'
libudev_version = '1.6.16'
# We need the same data in two different formats, ugh!
# Also, for hysterical reasons, we use different variable

View File

@ -330,36 +330,107 @@ int machine_load(Machine *m) {
return r;
}
static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
static int machine_start_scope(
Machine *machine,
sd_bus_message *more_properties,
sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
_cleanup_free_ char *escaped = NULL, *unit = NULL;
const char *description;
int r;
assert(machine);
assert(machine->leader > 0);
assert(!machine->unit);
escaped = unit_name_escape(machine->name);
if (!escaped)
return log_oom();
unit = strjoin("machine-", escaped, ".scope");
if (!unit)
return log_oom();
r = sd_bus_message_new_method_call(
machine->manager->bus,
&m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StartTransientUnit");
if (r < 0)
return r;
r = sd_bus_message_append(m, "ss", unit, "fail");
if (r < 0)
return r;
r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0)
return r;
r = sd_bus_message_append(m, "(sv)", "Slice", "s", SPECIAL_MACHINE_SLICE);
if (r < 0)
return r;
description = strjoina(machine->class == MACHINE_VM ? "Virtual Machine " : "Container ", machine->name);
r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
if (r < 0)
return r;
r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)(sv)",
"PIDs", "au", 1, machine->leader,
"Delegate", "b", 1,
"CollectMode", "s", "inactive-or-failed",
"AddRef", "b", 1,
"TasksMax", "t", UINT64_C(16384));
if (r < 0)
return r;
if (more_properties) {
r = sd_bus_message_copy(m, more_properties, true);
if (r < 0)
return r;
}
r = sd_bus_message_close_container(m);
if (r < 0)
return r;
r = sd_bus_message_append(m, "a(sa(sv))", 0);
if (r < 0)
return r;
r = sd_bus_call(NULL, m, 0, error, &reply);
if (r < 0)
return r;
machine->unit = TAKE_PTR(unit);
machine->referenced = true;
const char *job;
r = sd_bus_message_read(reply, "o", &job);
if (r < 0)
return r;
return free_and_strdup(&machine->scope_job, job);
}
static int machine_ensure_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
int r;
assert(m);
assert(m->class != MACHINE_HOST);
if (!m->unit) {
_cleanup_free_ char *escaped = NULL, *scope = NULL;
char *description, *job = NULL;
int r;
escaped = unit_name_escape(m->name);
if (!escaped)
return log_oom();
scope = strjoin("machine-", escaped, ".scope");
if (!scope)
return log_oom();
description = strjoina(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
r = machine_start_scope(m, properties, error);
if (r < 0)
return log_error_errno(r, "Failed to start machine scope: %s", bus_error_message(error, r));
m->unit = TAKE_PTR(scope);
m->referenced = true;
free_and_replace(m->scope_job, job);
}
if (m->unit)
hashmap_put(m->manager->machine_units, m->unit, m);
assert(m->unit);
hashmap_put(m->manager->machine_units, m->unit, m);
return 0;
}
@ -380,7 +451,7 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
return r;
/* Create cgroup */
r = machine_start_scope(m, properties, error);
r = machine_ensure_scope(m, properties, error);
if (r < 0)
return r;
@ -404,49 +475,31 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
return 0;
}
static int machine_stop_scope(Machine *m) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char *job = NULL;
int r, q;
assert(m);
assert(m->class != MACHINE_HOST);
if (!m->unit)
return 0;
r = manager_stop_unit(m->manager, m->unit, &error, &job);
if (r < 0) {
log_error_errno(r, "Failed to stop machine scope: %s", bus_error_message(&error, r));
sd_bus_error_free(&error);
} else
free_and_replace(m->scope_job, job);
if (m->referenced) {
q = manager_unref_unit(m->manager, m->unit, &error);
if (q < 0)
log_warning_errno(q, "Failed to drop reference to machine scope, ignoring: %s", bus_error_message(&error, r));
m->referenced = false;
}
return r;
}
int machine_stop(Machine *m) {
int r;
assert(m);
if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
return -EOPNOTSUPP;
r = machine_stop_scope(m);
if (m->unit) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char *job = NULL;
r = manager_stop_unit(m->manager, m->unit, &error, &job);
if (r < 0)
return log_error_errno(r, "Failed to stop machine scope: %s", bus_error_message(&error, r));
free_and_replace(m->scope_job, job);
}
m->stopping = true;
machine_save(m);
(void) manager_enqueue_nscd_cache_flush(m->manager);
return r;
return 0;
}
int machine_finalize(Machine *m) {
@ -583,6 +636,18 @@ void machine_release_unit(Machine *m) {
if (!m->unit)
return;
if (m->referenced) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
r = manager_unref_unit(m->manager, m->unit, &error);
if (r < 0)
log_warning_errno(r, "Failed to drop reference to machine scope, ignoring: %s",
bus_error_message(&error, r));
m->referenced = false;
}
(void) hashmap_remove(m->manager->machine_units, m->unit);
m->unit = mfree(m->unit);
}

View File

@ -1294,98 +1294,6 @@ int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error
return 0;
}
int manager_start_scope(
Manager *manager,
const char *scope,
pid_t pid,
const char *slice,
const char *description,
sd_bus_message *more_properties,
sd_bus_error *error,
char **job) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
int r;
assert(manager);
assert(scope);
assert(pid > 1);
r = sd_bus_message_new_method_call(
manager->bus,
&m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StartTransientUnit");
if (r < 0)
return r;
r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
if (r < 0)
return r;
r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0)
return r;
if (!isempty(slice)) {
r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
if (r < 0)
return r;
}
if (!isempty(description)) {
r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
if (r < 0)
return r;
}
r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)(sv)",
"PIDs", "au", 1, pid,
"Delegate", "b", 1,
"CollectMode", "s", "inactive-or-failed",
"AddRef", "b", 1,
"TasksMax", "t", UINT64_C(16384));
if (r < 0)
return r;
if (more_properties) {
r = sd_bus_message_copy(m, more_properties, true);
if (r < 0)
return r;
}
r = sd_bus_message_close_container(m);
if (r < 0)
return r;
r = sd_bus_message_append(m, "a(sa(sv))", 0);
if (r < 0)
return r;
r = sd_bus_call(manager->bus, m, 0, error, &reply);
if (r < 0)
return r;
if (job) {
const char *j;
char *copy;
r = sd_bus_message_read(reply, "o", &j);
if (r < 0)
return r;
copy = strdup(j);
if (!copy)
return -ENOMEM;
*job = copy;
}
return 1;
}
int manager_unref_unit(
Manager *m,
const char *unit,

View File

@ -49,7 +49,6 @@ int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *er
int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error);
int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error);
int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, sd_bus_message *more_properties, sd_bus_error *error, char **job);
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error);
int manager_unref_unit(Manager *m, const char *unit, sd_bus_error *error);

View File

@ -139,11 +139,10 @@ static int seccomp_add_default_syscall_filter(
*/
};
int r;
size_t i;
char **p;
int r;
for (i = 0; i < ELEMENTSOF(whitelist); i++) {
for (size_t i = 0; i < ELEMENTSOF(whitelist); i++) {
if (whitelist[i].capability != 0 && (cap_list_retain & (1ULL << whitelist[i].capability)) == 0)
continue;
@ -153,7 +152,7 @@ static int seccomp_add_default_syscall_filter(
}
STRV_FOREACH(p, syscall_whitelist) {
r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, false);
r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, true);
if (r < 0)
log_warning_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m",
*p, seccomp_arch_to_string(arch));

View File

@ -492,6 +492,46 @@ static int detect_unified_cgroup_hierarchy_from_image(const char *directory) {
return 0;
}
static int parse_capability_spec(const char *spec, uint64_t *ret_mask) {
uint64_t mask = 0;
int r;
for (;;) {
_cleanup_free_ char *t = NULL;
r = extract_first_word(&spec, &t, ",", 0);
if (r < 0)
return log_error_errno(r, "Failed to parse capability %s.", t);
if (r == 0)
break;
if (streq(t, "help")) {
for (int i = 0; i < capability_list_length(); i++) {
const char *name;
name = capability_to_name(i);
if (name)
puts(name);
}
return 0; /* quit */
}
if (streq(t, "all"))
mask = (uint64_t) -1;
else {
r = capability_from_name(t);
if (r < 0)
return log_error_errno(r, "Failed to parse capability %s.", t);
mask |= 1ULL << r;
}
}
*ret_mask = mask;
return 1; /* continue */
}
static int parse_share_ns_env(const char *name, unsigned long ns_flag) {
int r;
@ -695,7 +735,6 @@ static int parse_argv(int argc, char *argv[]) {
};
int c, r;
const char *p;
uint64_t plus = 0, minus = 0;
bool mask_all_settings = false, mask_no_settings = false;
@ -937,37 +976,18 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_CAPABILITY:
case ARG_DROP_CAPABILITY: {
p = optarg;
for (;;) {
_cleanup_free_ char *t = NULL;
r = extract_first_word(&p, &t, ",", 0);
if (r < 0)
return log_error_errno(r, "Failed to parse capability %s.", t);
if (r == 0)
break;
if (streq(t, "all")) {
if (c == ARG_CAPABILITY)
plus = (uint64_t) -1;
else
minus = (uint64_t) -1;
} else {
r = capability_from_name(t);
if (r < 0)
return log_error_errno(r, "Failed to parse capability %s.", t);
if (c == ARG_CAPABILITY)
plus |= 1ULL << r;
else
minus |= 1ULL << r;
}
}
uint64_t m;
r = parse_capability_spec(optarg, &m);
if (r <= 0)
return r;
if (c == ARG_CAPABILITY)
plus |= m;
else
minus |= m;
arg_settings_mask |= SETTING_CAPABILITY;
break;
}
case ARG_NO_NEW_PRIVILEGES:
r = parse_boolean(optarg);
if (r < 0)

View File

@ -9,7 +9,7 @@
#include "resolved-dns-stream.h"
#include "resolved-dnstls.h"
#define PRIORTY_STRING "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2"
#define TLS_PROTOCOL_PRIORITY "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2"
DEFINE_TRIVIAL_CLEANUP_FUNC(gnutls_session_t, gnutls_deinit);
static ssize_t dnstls_stream_writev(gnutls_transport_ptr_t p, const giovec_t *iov, int iovcnt) {
@ -38,7 +38,7 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
return r;
/* As DNS-over-TLS is a recent protocol, older TLS versions can be disabled */
r = gnutls_priority_set_direct(gs, PRIORTY_STRING, NULL);
r = gnutls_priority_set_direct(gs, TLS_PROTOCOL_PRIORITY, NULL);
if (r < 0)
return r;

View File

@ -29,6 +29,7 @@ typedef enum VarlinkState {
/* Client side states */
VARLINK_IDLE_CLIENT,
VARLINK_AWAITING_REPLY,
VARLINK_AWAITING_REPLY_MORE,
VARLINK_CALLING,
VARLINK_CALLED,
VARLINK_PROCESSING_REPLY,
@ -39,7 +40,6 @@ typedef enum VarlinkState {
VARLINK_PROCESSING_METHOD_MORE,
VARLINK_PROCESSING_METHOD_ONEWAY,
VARLINK_PROCESSED_METHOD,
VARLINK_PROCESSED_METHOD_MORE,
VARLINK_PENDING_METHOD,
VARLINK_PENDING_METHOD_MORE,
@ -63,6 +63,7 @@ typedef enum VarlinkState {
IN_SET(state, \
VARLINK_IDLE_CLIENT, \
VARLINK_AWAITING_REPLY, \
VARLINK_AWAITING_REPLY_MORE, \
VARLINK_CALLING, \
VARLINK_CALLED, \
VARLINK_PROCESSING_REPLY, \
@ -71,7 +72,6 @@ typedef enum VarlinkState {
VARLINK_PROCESSING_METHOD_MORE, \
VARLINK_PROCESSING_METHOD_ONEWAY, \
VARLINK_PROCESSED_METHOD, \
VARLINK_PROCESSED_METHOD_MORE, \
VARLINK_PENDING_METHOD, \
VARLINK_PENDING_METHOD_MORE)
@ -185,6 +185,7 @@ struct VarlinkServer {
static const char* const varlink_state_table[_VARLINK_STATE_MAX] = {
[VARLINK_IDLE_CLIENT] = "idle-client",
[VARLINK_AWAITING_REPLY] = "awaiting-reply",
[VARLINK_AWAITING_REPLY_MORE] = "awaiting-reply-more",
[VARLINK_CALLING] = "calling",
[VARLINK_CALLED] = "called",
[VARLINK_PROCESSING_REPLY] = "processing-reply",
@ -193,7 +194,6 @@ static const char* const varlink_state_table[_VARLINK_STATE_MAX] = {
[VARLINK_PROCESSING_METHOD_MORE] = "processing-method-more",
[VARLINK_PROCESSING_METHOD_ONEWAY] = "processing-method-oneway",
[VARLINK_PROCESSED_METHOD] = "processed-method",
[VARLINK_PROCESSED_METHOD_MORE] = "processed-method-more",
[VARLINK_PENDING_METHOD] = "pending-method",
[VARLINK_PENDING_METHOD_MORE] = "pending-method-more",
[VARLINK_PENDING_DISCONNECT] = "pending-disconnect",
@ -287,6 +287,8 @@ int varlink_connect_address(Varlink **ret, const char *address) {
if (v->fd < 0)
return -errno;
v->fd = fd_move_above_stdio(v->fd);
if (connect(v->fd, &sockaddr.sa, SOCKADDR_UN_LEN(sockaddr.un)) < 0) {
if (!IN_SET(errno, EAGAIN, EINPROGRESS))
return -errno;
@ -341,11 +343,8 @@ static void varlink_detach_event_sources(Varlink *v) {
assert(v);
v->io_event_source = sd_event_source_disable_unref(v->io_event_source);
v->time_event_source = sd_event_source_disable_unref(v->time_event_source);
v->quit_event_source = sd_event_source_disable_unref(v->quit_event_source);
v->defer_event_source = sd_event_source_disable_unref(v->defer_event_source);
}
@ -405,7 +404,7 @@ static int varlink_test_disconnect(Varlink *v) {
goto disconnect;
/* If we are waiting for incoming data but the read side is shut down, disconnect. */
if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING, VARLINK_IDLE_SERVER) && v->read_disconnected)
if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING, VARLINK_IDLE_SERVER) && v->read_disconnected)
goto disconnect;
/* Similar, if are a client that hasn't written anything yet but the write side is dead, also
@ -478,7 +477,7 @@ static int varlink_read(Varlink *v) {
assert(v);
if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING, VARLINK_IDLE_SERVER))
if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING, VARLINK_IDLE_SERVER))
return 0;
if (v->connecting) /* read() on a socket while we are in connect() will fail with EINVAL, hence exit early here */
return 0;
@ -596,7 +595,7 @@ static int varlink_parse_message(Varlink *v) {
static int varlink_test_timeout(Varlink *v) {
assert(v);
if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING))
if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING))
return 0;
if (v->timeout == USEC_INFINITY)
return 0;
@ -673,7 +672,7 @@ static int varlink_dispatch_reply(Varlink *v) {
assert(v);
if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING))
if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING))
return 0;
if (!v->current)
return 0;
@ -715,6 +714,11 @@ static int varlink_dispatch_reply(Varlink *v) {
goto invalid;
}
/* Replies with 'continue' set are only OK if we set 'more' when the method call was initiated */
if (v->state != VARLINK_AWAITING_REPLY_MORE && FLAGS_SET(flags, VARLINK_REPLY_CONTINUES))
goto invalid;
/* An error is final */
if (error && FLAGS_SET(flags, VARLINK_REPLY_CONTINUES))
goto invalid;
@ -722,7 +726,7 @@ static int varlink_dispatch_reply(Varlink *v) {
if (r < 0)
goto invalid;
if (v->state == VARLINK_AWAITING_REPLY) {
if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE)) {
varlink_set_state(v, VARLINK_PROCESSING_REPLY);
if (v->reply_callback) {
@ -734,17 +738,18 @@ static int varlink_dispatch_reply(Varlink *v) {
v->current = json_variant_unref(v->current);
if (v->state == VARLINK_PROCESSING_REPLY) {
assert(v->n_pending > 0);
v->n_pending--;
varlink_set_state(v, v->n_pending == 0 ? VARLINK_IDLE_CLIENT : VARLINK_AWAITING_REPLY);
assert(v->n_pending > 0);
if (!FLAGS_SET(flags, VARLINK_REPLY_CONTINUES))
v->n_pending--;
varlink_set_state(v,
FLAGS_SET(flags, VARLINK_REPLY_CONTINUES) ? VARLINK_AWAITING_REPLY_MORE :
v->n_pending == 0 ? VARLINK_IDLE_CLIENT : VARLINK_AWAITING_REPLY);
}
} else {
assert(v->state == VARLINK_CALLING);
if (FLAGS_SET(flags, VARLINK_REPLY_CONTINUES))
goto invalid;
varlink_set_state(v, VARLINK_CALLED);
}
@ -878,7 +883,6 @@ static int varlink_dispatch_method(Varlink *v) {
varlink_set_state(v, VARLINK_PENDING_METHOD);
break;
case VARLINK_PROCESSED_METHOD_MORE: /* One reply for a "more" message was sent, more to come */
case VARLINK_PROCESSING_METHOD_MORE: /* No reply for a "more" message was sent, more to come */
varlink_set_state(v, VARLINK_PENDING_METHOD_MORE);
break;
@ -1073,7 +1077,7 @@ int varlink_get_events(Varlink *v) {
return EPOLLOUT;
if (!v->read_disconnected &&
IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING, VARLINK_IDLE_SERVER) &&
IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING, VARLINK_IDLE_SERVER) &&
!v->current &&
v->input_buffer_unscanned <= 0)
ret |= EPOLLIN;
@ -1091,7 +1095,7 @@ int varlink_get_timeout(Varlink *v, usec_t *ret) {
if (v->state == VARLINK_DISCONNECTED)
return -ENOTCONN;
if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING) &&
if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING) &&
v->timeout != USEC_INFINITY) {
if (ret)
*ret = usec_add(v->timestamp, v->timeout);
@ -1259,6 +1263,8 @@ int varlink_send(Varlink *v, const char *method, JsonVariant *parameters) {
if (v->state == VARLINK_DISCONNECTED)
return -ENOTCONN;
/* We allow enqueuing multiple method calls at once! */
if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY))
return -EBUSY;
@ -1308,6 +1314,8 @@ int varlink_invoke(Varlink *v, const char *method, JsonVariant *parameters) {
if (v->state == VARLINK_DISCONNECTED)
return -ENOTCONN;
/* We allow enqueing multiple method calls at once! */
if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY))
return -EBUSY;
@ -1349,6 +1357,60 @@ int varlink_invokeb(Varlink *v, const char *method, ...) {
return varlink_invoke(v, method, parameters);
}
int varlink_observe(Varlink *v, const char *method, JsonVariant *parameters) {
_cleanup_(json_variant_unrefp) JsonVariant *m = NULL;
int r;
assert_return(v, -EINVAL);
assert_return(method, -EINVAL);
if (v->state == VARLINK_DISCONNECTED)
return -ENOTCONN;
/* Note that we don't allow enqueuing multiple method calls when we are in more/continues mode! We
* thus insist on an idle client here. */
if (v->state != VARLINK_IDLE_CLIENT)
return -EBUSY;
r = varlink_sanitize_parameters(&parameters);
if (r < 0)
return r;
r = json_build(&m, JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)),
JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)),
JSON_BUILD_PAIR("more", JSON_BUILD_BOOLEAN(true))));
if (r < 0)
return r;
r = varlink_enqueue_json(v, m);
if (r < 0)
return r;
varlink_set_state(v, VARLINK_AWAITING_REPLY_MORE);
v->n_pending++;
v->timestamp = now(CLOCK_MONOTONIC);
return 0;
}
int varlink_observeb(Varlink *v, const char *method, ...) {
_cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL;
va_list ap;
int r;
assert_return(v, -EINVAL);
va_start(ap, method);
r = json_buildv(&parameters, ap);
va_end(ap);
if (r < 0)
return r;
return varlink_observe(v, method, parameters);
}
int varlink_call(
Varlink *v,
const char *method,
@ -1769,6 +1831,7 @@ static int prepare_callback(sd_event_source *s, void *userdata) {
Varlink *v = userdata;
int r, e;
usec_t until;
bool have_timeout;
assert(s);
assert(v);
@ -1784,13 +1847,15 @@ static int prepare_callback(sd_event_source *s, void *userdata) {
r = varlink_get_timeout(v, &until);
if (r < 0)
return r;
if (r > 0) {
have_timeout = r > 0;
if (have_timeout) {
r = sd_event_source_set_time(v->time_event_source, until);
if (r < 0)
return r;
}
r = sd_event_source_set_enabled(v->time_event_source, r > 0 ? SD_EVENT_ON : SD_EVENT_OFF);
r = sd_event_source_set_enabled(v->time_event_source, have_timeout ? SD_EVENT_ON : SD_EVENT_OFF);
if (r < 0)
return r;
@ -2157,6 +2222,8 @@ int varlink_server_listen_address(VarlinkServer *s, const char *address, mode_t
if (fd < 0)
return -errno;
fd = fd_move_above_stdio(fd);
(void) sockaddr_un_unlink(&sockaddr.un);
RUN_WITH_UMASK(~m & 0777)
@ -2339,17 +2406,18 @@ int varlink_server_bind_connect(VarlinkServer *s, VarlinkConnect callback) {
}
unsigned varlink_server_connections_max(VarlinkServer *s) {
struct rlimit rl;
int dts;
/* If a server is specified, return the setting for that server, otherwise the default value */
if (s)
return s->connections_max;
assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
dts = getdtablesize();
assert_se(dts > 0);
/* Make sure we never use up more than ¾th of RLIMIT_NOFILE for IPC */
if (VARLINK_DEFAULT_CONNECTIONS_MAX > rl.rlim_cur / 4 * 3)
return rl.rlim_cur / 4 * 3;
if (VARLINK_DEFAULT_CONNECTIONS_MAX > (unsigned) dts / 4 * 3)
return dts / 4 * 3;
return VARLINK_DEFAULT_CONNECTIONS_MAX;
}

View File

@ -86,6 +86,10 @@ int varlink_callb(Varlink *v, const char *method, JsonVariant **ret_parameters,
int varlink_invoke(Varlink *v, const char *method, JsonVariant *parameters);
int varlink_invokeb(Varlink *v, const char *method, ...);
/* Enqueue method call, expect a reply now, and possibly more later, which are all delivered to the reply callback */
int varlink_observe(Varlink *v, const char *method, JsonVariant *parameters);
int varlink_observeb(Varlink *v, const char *method, ...);
/* Enqueue a final reply */
int varlink_reply(Varlink *v, JsonVariant *parameters);
int varlink_replyb(Varlink *v, ...);

View File

@ -98,7 +98,7 @@ units = [
['systemd-poweroff.service', ''],
['systemd-reboot.service', ''],
['systemd-rfkill.socket', 'ENABLE_RFKILL'],
['systemd-tmpfiles-clean.timer', '',
['systemd-tmpfiles-clean.timer', 'ENABLE_TMPFILES',
'timers.target.wants/'],
['systemd-udevd-control.socket', '',
'sockets.target.wants/'],