#include "exec-util.h"
#include "exit-status.h"
#include "fileio.h"
+#include "firewall-util.h"
#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
#include "percent-util.h"
#include "process-util.h"
#include "rlimit-util.h"
-#if HAVE_SECCOMP
#include "seccomp-util.h"
-#endif
#include "securebits-util.h"
#include "signal-util.h"
#include "socket-util.h"
return sd_bus_message_close_container(m);
}
+static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ assert(m);
+ assert(field);
+ assert(eq);
+
+ if (isempty(eq)) {
+ r = sd_bus_message_append(m, "(sv)", field, "a(iiss)", 0);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+ }
+
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "a(iiss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "(iiss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (const char *p = eq;;) {
+ _cleanup_free_ char *tuple = NULL, *source_str = NULL, *nfproto_str = NULL, *table = NULL, *set = NULL;
+ const char *q = NULL;
+ int source, nfproto;
+
+ r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s: %m", field);
+ if (r == 0)
+ break;
+ if (isempty(tuple))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s", field);
+
+ q = tuple;
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE, &source_str, &nfproto_str, &table, &set);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r != 4 || !isempty(q))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s", field);
+
+ assert(source_str);
+ assert(nfproto_str);
+ assert(table);
+ assert(set);
+
+ source = nft_set_source_from_string(source_str);
+ if (!IN_SET(source, NFT_SET_SOURCE_CGROUP, NFT_SET_SOURCE_USER, NFT_SET_SOURCE_GROUP))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s", field);
+
+ nfproto = nfproto_from_string(nfproto_str);
+ if (nfproto < 0 || !nft_identifier_valid(table) || !nft_identifier_valid(set))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s", field);
+
+ r = sd_bus_message_append(m, "(iiss)", source, nfproto, table, set);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
int r;
if (STR_IN_SET(field, "CPUAccounting",
"MemoryAccounting",
+ "MemoryZSwapWriteback",
"IOAccounting",
"BlockIOAccounting",
"TasksAccounting",
- "IPAccounting"))
+ "IPAccounting",
+ "CoredumpReceive"))
return bus_append_parse_boolean(m, field, eq);
if (STR_IN_SET(field, "CPUWeight",
if (streq(field, "MemoryPressureThresholdSec"))
return bus_append_parse_sec_rename(m, field, eq);
+ if (streq(field, "NFTSet"))
+ return bus_append_nft_set(m, field, eq);
+
return 0;
}
"ProtectHostname",
"MemoryKSM",
"RestrictSUIDSGID",
- "RootEphemeral"))
+ "RootEphemeral",
+ "SetLoginEnvironment"))
return bus_append_parse_boolean(m, field, eq);
if (STR_IN_SET(field, "ReadWriteDirectories",
_cleanup_free_ void *decoded = NULL;
size_t decoded_size;
- r = unbase64mem(p, SIZE_MAX, &decoded, &decoded_size);
+ r = unbase64mem(p, &decoded, &decoded_size);
if (r < 0)
return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
_cleanup_free_ void *decoded = NULL;
size_t sz;
- r = unbase64mem(eq, SIZE_MAX, &decoded, &sz);
+ r = unbase64mem(eq, &decoded, &sz);
if (r < 0)
return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
if (r < 0)
return log_error_errno(r, "Failed to parse resource limit: %s", eq);
- r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
+ r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
if (r < 0)
return bus_log_create_error(r);
sn = strjoina(field, "Soft");
- r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
+ r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
if (r < 0)
return bus_log_create_error(r);
return bus_append_string(m, "RootHashPath", eq);
/* We have a roothash to decode, eg: RootHash=012345789abcdef */
- r = unhexmem(eq, strlen(eq), &roothash_decoded, &roothash_decoded_size);
+ r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
if (r < 0)
return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
if (roothash_decoded_size < sizeof(sd_id128_t))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq);
/* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
- r = unbase64mem(value, strlen(value), &roothash_sig_decoded, &roothash_sig_decoded_size);
+ r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
if (r < 0)
return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
break;
q = tuple;
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second, NULL);
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
if (r < 0)
return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
if (r == 0)
for (;;) {
_cleanup_free_ char *partition = NULL, *mount_options = NULL;
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
if (r < 0)
return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
if (r == 0)
for (;;) {
_cleanup_free_ char *partition = NULL, *mount_options = NULL;
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
if (r < 0)
return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
if (r == 0)
break;
const char *t = tuple;
- r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, NULL);
+ r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination);
if (r <= 0)
return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
return bus_log_create_error(r);
STRV_FOREACH_PAIR(source, destination, symlinks) {
- r = sd_bus_message_append(m, "(sst)", *source, *destination, 0);
+ r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
if (r < 0)
return bus_log_create_error(r);
}
return 1;
}
- if (streq(field, "TriggerLimitBurst"))
+ if (STR_IN_SET(field, "TriggerLimitBurst", "PollLimitBurst"))
return bus_append_safe_atou(m, field, eq);
- if (streq(field, "TriggerLimitIntervalSec"))
+ if (STR_IN_SET(field, "TriggerLimitIntervalSec", "PollLimitIntervalSec"))
return bus_append_parse_sec_rename(m, field, eq);
return 0;
"MaxConnections",
"MaxConnectionsPerSource",
"KeepAliveProbes",
- "TriggerLimitBurst"))
+ "TriggerLimitBurst",
+ "PollLimitBurst"))
return bus_append_safe_atou(m, field, eq);
if (STR_IN_SET(field, "SocketMode",
"KeepAliveTimeSec",
"KeepAliveIntervalSec",
"DeferAcceptSec",
- "TriggerLimitIntervalSec"))
+ "TriggerLimitIntervalSec",
+ "PollLimitIntervalSec"))
return bus_append_parse_sec_rename(m, field, eq);
if (STR_IN_SET(field, "ReceiveBuffer",
"RefuseManualStop",
"AllowIsolate",
"IgnoreOnIsolate",
+ "SurviveFinalKillSignal",
"DefaultDependencies"))
return bus_append_parse_boolean(m, field, eq);
if (unit_dependency_from_string(field) >= 0 ||
STR_IN_SET(field, "Documentation",
"RequiresMountsFor",
+ "WantsMountsFor",
"Markers"))
return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
return 0;
}
+int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
+ assert(m);
+
+ if (!pidref_is_set(pidref))
+ return -ESRCH;
+
+ if (pidref->fd >= 0 && allow_pidfd)
+ return sd_bus_message_append(
+ m, "(sv)",
+ "PIDFDs", "ah", 1, pidref->fd);
+
+ return sd_bus_message_append(
+ m, "(sv)",
+ "PIDs", "au", 1, pidref->pid);
+}
+
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
const char *type, *path, *source;
InstallChange *changes = NULL;
return 0;
}
+
+/* Wait for 1.5 seconds at maximum for freeze operation */
+#define FREEZE_BUS_CALL_TIMEOUT (1500 * USEC_PER_MSEC)
+
+int unit_freezer_new(const char *name, UnitFreezer *ret) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ _cleanup_free_ char *namedup = NULL;
+ int r;
+
+ assert(name);
+ assert(ret);
+
+ namedup = strdup(name);
+ if (!namedup)
+ return log_oom_debug();
+
+ r = bus_connect_system_systemd(&bus);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to open connection to systemd: %m");
+
+ (void) sd_bus_set_method_call_timeout(bus, FREEZE_BUS_CALL_TIMEOUT);
+
+ *ret = (UnitFreezer) {
+ .name = TAKE_PTR(namedup),
+ .bus = TAKE_PTR(bus),
+ };
+ return 0;
+}
+
+void unit_freezer_done(UnitFreezer *f) {
+ assert(f);
+
+ f->name = mfree(f->name);
+ f->bus = sd_bus_flush_close_unref(f->bus);
+}
+
+static int unit_freezer_action(UnitFreezer *f, bool freeze) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+
+ assert(f);
+ assert(f->name);
+ assert(f->bus);
+
+ r = bus_call_method(f->bus, bus_systemd_mgr,
+ freeze ? "FreezeUnit" : "ThawUnit",
+ &error,
+ /* reply = */ NULL,
+ "s",
+ f->name);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to %s unit %s: %s",
+ freeze ? "freeze" : "thaw", f->name, bus_error_message(&error, r));
+
+ return 0;
+}
+
+int unit_freezer_freeze(UnitFreezer *f) {
+ return unit_freezer_action(f, true);
+}
+
+int unit_freezer_thaw(UnitFreezer *f) {
+ return unit_freezer_action(f, false);
+}
+
+int unit_freezer_new_freeze(const char *name, UnitFreezer *ret) {
+ _cleanup_(unit_freezer_done) UnitFreezer f = {};
+ int r;
+
+ assert(name);
+ assert(ret);
+
+ r = unit_freezer_new(name, &f);
+ if (r < 0)
+ return r;
+
+ r = unit_freezer_freeze(&f);
+ if (r < 0)
+ return r;
+
+ *ret = TAKE_STRUCT(f);
+ return 0;
+}
+
+void unit_freezer_done_thaw(UnitFreezer *f) {
+ assert(f);
+
+ if (!f->name)
+ return;
+
+ (void) unit_freezer_thaw(f);
+ unit_freezer_done(f);
+}