Compare commits

..

No commits in common. "78af8a798aa9f1100a1228454ff8ebf98ce1b9e5" and "bdf2357c12e775ca2c9491d4117227dfc992881c" have entirely different histories.

11 changed files with 222 additions and 298 deletions

View File

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

View File

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

View File

@ -330,107 +330,36 @@ int machine_load(Machine *m) {
return r; return r;
} }
static int machine_start_scope( static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
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);
assert(m->class != MACHINE_HOST); assert(m->class != MACHINE_HOST);
if (!m->unit) { if (!m->unit) {
r = machine_start_scope(m, properties, error); _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);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to start machine scope: %s", bus_error_message(error, r)); 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);
} }
assert(m->unit); if (m->unit)
hashmap_put(m->manager->machine_units, m->unit, m); hashmap_put(m->manager->machine_units, m->unit, m);
return 0; return 0;
} }
@ -451,7 +380,7 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
return r; return r;
/* Create cgroup */ /* Create cgroup */
r = machine_ensure_scope(m, properties, error); r = machine_start_scope(m, properties, error);
if (r < 0) if (r < 0)
return r; return r;
@ -475,31 +404,49 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
return 0; 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 machine_stop(Machine *m) {
int r; int r;
assert(m); assert(m);
if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM)) if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (m->unit) { r = machine_stop_scope(m);
_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; m->stopping = true;
machine_save(m); machine_save(m);
(void) manager_enqueue_nscd_cache_flush(m->manager); (void) manager_enqueue_nscd_cache_flush(m->manager);
return 0; return r;
} }
int machine_finalize(Machine *m) { int machine_finalize(Machine *m) {
@ -636,18 +583,6 @@ void machine_release_unit(Machine *m) {
if (!m->unit) if (!m->unit)
return; 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); (void) hashmap_remove(m->manager->machine_units, m->unit);
m->unit = mfree(m->unit); m->unit = mfree(m->unit);
} }

View File

@ -1294,6 +1294,98 @@ int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error
return 0; 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( int manager_unref_unit(
Manager *m, Manager *m,
const char *unit, const char *unit,

View File

@ -49,6 +49,7 @@ 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_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 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_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_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); int manager_unref_unit(Manager *m, const char *unit, sd_bus_error *error);

View File

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

View File

@ -492,46 +492,6 @@ static int detect_unified_cgroup_hierarchy_from_image(const char *directory) {
return 0; 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) { static int parse_share_ns_env(const char *name, unsigned long ns_flag) {
int r; int r;
@ -735,6 +695,7 @@ static int parse_argv(int argc, char *argv[]) {
}; };
int c, r; int c, r;
const char *p;
uint64_t plus = 0, minus = 0; uint64_t plus = 0, minus = 0;
bool mask_all_settings = false, mask_no_settings = false; bool mask_all_settings = false, mask_no_settings = false;
@ -976,18 +937,37 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_CAPABILITY: case ARG_CAPABILITY:
case ARG_DROP_CAPABILITY: { case ARG_DROP_CAPABILITY: {
uint64_t m; p = optarg;
r = parse_capability_spec(optarg, &m); for (;;) {
if (r <= 0) _cleanup_free_ char *t = NULL;
return r;
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;
}
}
if (c == ARG_CAPABILITY)
plus |= m;
else
minus |= m;
arg_settings_mask |= SETTING_CAPABILITY; arg_settings_mask |= SETTING_CAPABILITY;
break; break;
} }
case ARG_NO_NEW_PRIVILEGES: case ARG_NO_NEW_PRIVILEGES:
r = parse_boolean(optarg); r = parse_boolean(optarg);
if (r < 0) if (r < 0)

View File

@ -9,7 +9,7 @@
#include "resolved-dns-stream.h" #include "resolved-dns-stream.h"
#include "resolved-dnstls.h" #include "resolved-dnstls.h"
#define TLS_PROTOCOL_PRIORITY "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2" #define PRIORTY_STRING "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2"
DEFINE_TRIVIAL_CLEANUP_FUNC(gnutls_session_t, gnutls_deinit); 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) { 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; return r;
/* As DNS-over-TLS is a recent protocol, older TLS versions can be disabled */ /* As DNS-over-TLS is a recent protocol, older TLS versions can be disabled */
r = gnutls_priority_set_direct(gs, TLS_PROTOCOL_PRIORITY, NULL); r = gnutls_priority_set_direct(gs, PRIORTY_STRING, NULL);
if (r < 0) if (r < 0)
return r; return r;

View File

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

View File

@ -86,10 +86,6 @@ int varlink_callb(Varlink *v, const char *method, JsonVariant **ret_parameters,
int varlink_invoke(Varlink *v, const char *method, JsonVariant *parameters); int varlink_invoke(Varlink *v, const char *method, JsonVariant *parameters);
int varlink_invokeb(Varlink *v, const char *method, ...); 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 */ /* Enqueue a final reply */
int varlink_reply(Varlink *v, JsonVariant *parameters); int varlink_reply(Varlink *v, JsonVariant *parameters);
int varlink_replyb(Varlink *v, ...); int varlink_replyb(Varlink *v, ...);

View File

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