core: add proper escaping to writing of drop-ins/transient unit files
authorLennart Poettering <lennart@poettering.net>
Wed, 22 Nov 2017 14:03:51 +0000 (15:03 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 29 Nov 2017 11:34:12 +0000 (12:34 +0100)
This majorly refactors the transient unit file and drop-in writing
logic, so that we properly C-escape and specifier-escape (% → %%)
everything we write out, so that when we read it back again, specifiers
are parsed that aren't supposed to be parsed.

This renames unit_write_drop_in() and friends by unit_write_setting().
The name change is supposed to clarify that the functions are not only
used to write drop-in files, but also transient unit files.

The previous "mode" parameter to this function is replaced by a more
generic "flags", which knows additional flags for implicit C-style and
specifier escaping before writing things out. This can cover most
properties where either form of escaping is defined. For the cases where
this isn't sufficient, we add helpers unit_escape_setting() and
unit_concat_strv() for escaping individual strings or strvs properly.

While we are at it, we also prettify generation of transient unit files:
we try to reduce the number of section headers written out: previously
we'd write the right section header our for each setting. With this
change we do so only if the setting lives in a different section than
the one before.

(This should also be considered preparation for when we add proper APIs
to systemd to write normal, persistant unit files through the bus API)

26 files changed:
src/core/dbus-automount.c
src/core/dbus-automount.h
src/core/dbus-cgroup.c
src/core/dbus-cgroup.h
src/core/dbus-execute.c
src/core/dbus-execute.h
src/core/dbus-kill.c
src/core/dbus-kill.h
src/core/dbus-mount.c
src/core/dbus-mount.h
src/core/dbus-scope.c
src/core/dbus-scope.h
src/core/dbus-service.c
src/core/dbus-service.h
src/core/dbus-slice.c
src/core/dbus-slice.h
src/core/dbus-socket.c
src/core/dbus-socket.h
src/core/dbus-swap.c
src/core/dbus-swap.h
src/core/dbus-timer.c
src/core/dbus-timer.h
src/core/dbus-unit.c
src/core/dbus-unit.h
src/core/unit.c
src/core/unit.h

index 3c165c4..4b1b86f 100644 (file)
@@ -38,7 +38,7 @@ static int bus_automount_set_transient_property(
                 Automount *a,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         int r;
@@ -47,18 +47,21 @@ static int bus_automount_set_transient_property(
         assert(name);
         assert(message);
 
+        flags |= UNIT_PRIVATE;
+
         if (streq(name, "TimeoutIdleUSec")) {
                 usec_t timeout_idle_usec;
+
                 r = sd_bus_message_read(message, "t", &timeout_idle_usec);
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         char time[FORMAT_TIMESPAN_MAX];
 
                         a->timeout_idle_usec = timeout_idle_usec;
-                        unit_write_drop_in_format(UNIT(a), mode, name, "[Automount]\nTimeoutIdleSec=%s\n",
-                                format_timespan(time, sizeof(time), timeout_idle_usec, USEC_PER_MSEC));
+                        unit_write_settingf(UNIT(a), flags, name, "TimeoutIdleSec=%s\n",
+                                            format_timespan(time, sizeof(time), timeout_idle_usec, USEC_PER_MSEC));
                 }
         } else
                 return 0;
@@ -70,20 +73,17 @@ int bus_automount_set_property(
                 Unit *u,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         Automount *a = AUTOMOUNT(u);
-        int r = 0;
 
         assert(a);
         assert(name);
         assert(message);
 
-        if (u->transient && u->load_state == UNIT_STUB)
-                /* This is a transient unit, let's load a little more */
-
-                r = bus_automount_set_transient_property(a, name, message, mode, error);
+        if (u->transient && u->load_state == UNIT_STUB) /* This is a transient unit? let's load a little more */
+                return bus_automount_set_transient_property(a, name, message, flags, error);
 
-        return r;
+        return 0;
 }
index dc56de9..3781194 100644 (file)
@@ -23,4 +23,4 @@
 
 extern const sd_bus_vtable bus_automount_vtable[];
 
-int bus_automount_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
+int bus_automount_set_property(Unit *u, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
index f09d9fe..0343aae 100644 (file)
@@ -334,7 +334,7 @@ static int bus_cgroup_set_transient_property(
                 CGroupContext *c,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         int r;
@@ -344,6 +344,8 @@ static int bus_cgroup_set_transient_property(
         assert(name);
         assert(message);
 
+        flags |= UNIT_PRIVATE;
+
         if (streq(name, "Delegate")) {
                 int b;
 
@@ -351,11 +353,11 @@ static int bus_cgroup_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->delegate = b;
                         c->delegate_controllers = b ? _CGROUP_MASK_ALL : 0;
 
-                        unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no");
+                        unit_write_settingf(u, flags, name, "Delegate=%s", yes_no(b));
                 }
 
                 return 1;
@@ -388,7 +390,7 @@ static int bus_cgroup_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *t = NULL;
 
                         r = cg_mask_to_string(mask, &t);
@@ -401,7 +403,7 @@ static int bus_cgroup_set_transient_property(
                         else
                                 c->delegate_controllers |= mask;
 
-                        unit_write_drop_in_private_format(u, mode, name, "Delegate=%s", strempty(t));
+                        unit_write_settingf(u, flags, name, "Delegate=%s", strempty(t));
                 }
 
                 return 1;
@@ -415,7 +417,7 @@ int bus_cgroup_set_property(
                 CGroupContext *c,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         CGroupIOLimitType iol_type;
@@ -426,6 +428,8 @@ int bus_cgroup_set_property(
         assert(name);
         assert(message);
 
+        flags |= UNIT_PRIVATE;
+
         if (streq(name, "CPUAccounting")) {
                 int b;
 
@@ -433,10 +437,10 @@ int bus_cgroup_set_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->cpu_accounting = b;
                         unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU);
-                        unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
+                        unit_write_settingf(u, flags, name, "CPUAccounting=%s", yes_no(b));
                 }
 
                 return 1;
@@ -449,16 +453,16 @@ int bus_cgroup_set_property(
                         return r;
 
                 if (!CGROUP_WEIGHT_IS_OK(weight))
-                        return sd_bus_error_set_errnof(error, EINVAL, "CPUWeight value out of range");
+                        return sd_bus_error_set_errnof(error, EINVAL, "CPUWeight= value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->cpu_weight = weight;
                         unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
 
                         if (weight == CGROUP_WEIGHT_INVALID)
-                                unit_write_drop_in_private(u, mode, name, "CPUWeight=");
+                                unit_write_setting(u, flags, name, "CPUWeight=");
                         else
-                                unit_write_drop_in_private_format(u, mode, name, "CPUWeight=%" PRIu64, weight);
+                                unit_write_settingf(u, flags, name, "CPUWeight=%" PRIu64, weight);
                 }
 
                 return 1;
@@ -471,16 +475,16 @@ int bus_cgroup_set_property(
                         return r;
 
                 if (!CGROUP_WEIGHT_IS_OK(weight))
-                        return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUWeight value out of range");
+                        return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUWeight= value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->startup_cpu_weight = weight;
                         unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
 
                         if (weight == CGROUP_CPU_SHARES_INVALID)
-                                unit_write_drop_in_private(u, mode, name, "StartupCPUWeight=");
+                                unit_write_setting(u, flags, name, "StartupCPUWeight=");
                         else
-                                unit_write_drop_in_private_format(u, mode, name, "StartupCPUWeight=%" PRIu64, weight);
+                                unit_write_settingf(u, flags, name, "StartupCPUWeight=%" PRIu64, weight);
                 }
 
                 return 1;
@@ -493,16 +497,16 @@ int bus_cgroup_set_property(
                         return r;
 
                 if (!CGROUP_CPU_SHARES_IS_OK(shares))
-                        return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
+                        return sd_bus_error_set_errnof(error, EINVAL, "CPUShares= value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->cpu_shares = shares;
                         unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
 
                         if (shares == CGROUP_CPU_SHARES_INVALID)
-                                unit_write_drop_in_private(u, mode, name, "CPUShares=");
+                                unit_write_setting(u, flags, name, "CPUShares=");
                         else
-                                unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64, shares);
+                                unit_write_settingf(u, flags, name, "CPUShares=%" PRIu64, shares);
                 }
 
                 return 1;
@@ -515,16 +519,16 @@ int bus_cgroup_set_property(
                         return r;
 
                 if (!CGROUP_CPU_SHARES_IS_OK(shares))
-                        return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range");
+                        return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares= value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->startup_cpu_shares = shares;
                         unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
 
                         if (shares == CGROUP_CPU_SHARES_INVALID)
-                                unit_write_drop_in_private(u, mode, name, "StartupCPUShares=");
+                                unit_write_setting(u, flags, name, "StartupCPUShares=");
                         else
-                                unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64, shares);
+                                unit_write_settingf(u, flags, name, "StartupCPUShares=%" PRIu64, shares);
                 }
 
                 return 1;
@@ -537,20 +541,20 @@ int bus_cgroup_set_property(
                         return r;
 
                 if (u64 <= 0)
-                        return sd_bus_error_set_errnof(error, EINVAL, "CPUQuotaPerSecUSec value out of range");
+                        return sd_bus_error_set_errnof(error, EINVAL, "CPUQuotaPerSecUSec= value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->cpu_quota_per_sec_usec = u64;
                         unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
+
                         if (c->cpu_quota_per_sec_usec == USEC_INFINITY)
-                                unit_write_drop_in_private_format(u, mode, "CPUQuota",
-                                                                  "CPUQuota=");
+                                unit_write_setting(u, flags, "CPUQuota", "CPUQuota=");
                         else
-                                /* config_parse_cpu_quota() requires an integer, so
-                                 * truncating division is used on purpose here. */
-                                unit_write_drop_in_private_format(u, mode, "CPUQuota",
-                                                                  "CPUQuota=%0.f%%",
-                                                                  (double) (c->cpu_quota_per_sec_usec / 10000));
+                                /* config_parse_cpu_quota() requires an integer, so truncating division is used on
+                                 * purpose here. */
+                                unit_write_settingf(u, flags, "CPUQuota",
+                                                    "CPUQuota=%0.f%%",
+                                                    (double) (c->cpu_quota_per_sec_usec / 10000));
                 }
 
                 return 1;
@@ -562,10 +566,10 @@ int bus_cgroup_set_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->io_accounting = b;
                         unit_invalidate_cgroup(u, CGROUP_MASK_IO);
-                        unit_write_drop_in_private(u, mode, name, b ? "IOAccounting=yes" : "IOAccounting=no");
+                        unit_write_settingf(u, flags, name, "IOAccounting=%s", yes_no(b));
                 }
 
                 return 1;
@@ -578,16 +582,16 @@ int bus_cgroup_set_property(
                         return r;
 
                 if (!CGROUP_WEIGHT_IS_OK(weight))
-                        return sd_bus_error_set_errnof(error, EINVAL, "IOWeight value out of range");
+                        return sd_bus_error_set_errnof(error, EINVAL, "IOWeight= value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->io_weight = weight;
                         unit_invalidate_cgroup(u, CGROUP_MASK_IO);
 
                         if (weight == CGROUP_WEIGHT_INVALID)
-                                unit_write_drop_in_private(u, mode, name, "IOWeight=");
+                                unit_write_setting(u, flags, name, "IOWeight=");
                         else
-                                unit_write_drop_in_private_format(u, mode, name, "IOWeight=%" PRIu64, weight);
+                                unit_write_settingf(u, flags, name, "IOWeight=%" PRIu64, weight);
                 }
 
                 return 1;
@@ -600,16 +604,16 @@ int bus_cgroup_set_property(
                         return r;
 
                 if (CGROUP_WEIGHT_IS_OK(weight))
-                        return sd_bus_error_set_errnof(error, EINVAL, "StartupIOWeight value out of range");
+                        return sd_bus_error_set_errnof(error, EINVAL, "StartupIOWeight= value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->startup_io_weight = weight;
                         unit_invalidate_cgroup(u, CGROUP_MASK_IO);
 
                         if (weight == CGROUP_WEIGHT_INVALID)
-                                unit_write_drop_in_private(u, mode, name, "StartupIOWeight=");
+                                unit_write_setting(u, flags, name, "StartupIOWeight=");
                         else
-                                unit_write_drop_in_private_format(u, mode, name, "StartupIOWeight=%" PRIu64, weight);
+                                unit_write_settingf(u, flags, name, "StartupIOWeight=%" PRIu64, weight);
                 }
 
                 return 1;
@@ -625,7 +629,7 @@ int bus_cgroup_set_property(
 
                 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 CGroupIODeviceLimit *a = NULL, *b;
 
                                 LIST_FOREACH(device_limits, b, c->io_device_limits) {
@@ -666,7 +670,7 @@ int bus_cgroup_set_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         CGroupIODeviceLimit *a;
                         _cleanup_free_ char *buf = NULL;
                         _cleanup_fclose_ FILE *f = NULL;
@@ -691,7 +695,7 @@ int bus_cgroup_set_property(
                         r = fflush_and_check(f);
                         if (r < 0)
                                 return r;
-                        unit_write_drop_in_private(u, mode, name, buf);
+                        unit_write_setting(u, flags, name, buf);
                 }
 
                 return 1;
@@ -708,9 +712,9 @@ int bus_cgroup_set_property(
                 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
 
                         if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
-                                return sd_bus_error_set_errnof(error, EINVAL, "IODeviceWeight out of range");
+                                return sd_bus_error_set_errnof(error, EINVAL, "IODeviceWeight= value out of range");
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 CGroupIODeviceWeight *a = NULL, *b;
 
                                 LIST_FOREACH(device_weights, b, c->io_device_weights) {
@@ -743,7 +747,7 @@ int bus_cgroup_set_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *buf = NULL;
                         _cleanup_fclose_ FILE *f = NULL;
                         CGroupIODeviceWeight *a;
@@ -767,7 +771,7 @@ int bus_cgroup_set_property(
                         r = fflush_and_check(f);
                         if (r < 0)
                                 return r;
-                        unit_write_drop_in_private(u, mode, name, buf);
+                        unit_write_setting(u, flags, name, buf);
                 }
 
                 return 1;
@@ -779,10 +783,10 @@ int bus_cgroup_set_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->blockio_accounting = b;
                         unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
-                        unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
+                        unit_write_settingf(u, flags, name, "BlockIOAccounting=%s", yes_no(b));
                 }
 
                 return 1;
@@ -795,16 +799,16 @@ int bus_cgroup_set_property(
                         return r;
 
                 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
-                        return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
+                        return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight= value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->blockio_weight = weight;
                         unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
 
                         if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
-                                unit_write_drop_in_private(u, mode, name, "BlockIOWeight=");
+                                unit_write_setting(u, flags, name, "BlockIOWeight=");
                         else
-                                unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64, weight);
+                                unit_write_settingf(u, flags, name, "BlockIOWeight=%" PRIu64, weight);
                 }
 
                 return 1;
@@ -817,16 +821,16 @@ int bus_cgroup_set_property(
                         return r;
 
                 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
-                        return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
+                        return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight= value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->startup_blockio_weight = weight;
                         unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
 
                         if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
-                                unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight=");
+                                unit_write_setting(u, flags, name, "StartupBlockIOWeight=");
                         else
-                                unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64, weight);
+                                unit_write_settingf(u, flags, name, "StartupBlockIOWeight=%" PRIu64, weight);
                 }
 
                 return 1;
@@ -846,7 +850,7 @@ int bus_cgroup_set_property(
 
                 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 CGroupBlockIODeviceBandwidth *a = NULL, *b;
 
                                 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
@@ -887,7 +891,7 @@ int bus_cgroup_set_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         CGroupBlockIODeviceBandwidth *a;
                         _cleanup_free_ char *buf = NULL;
                         _cleanup_fclose_ FILE *f = NULL;
@@ -923,7 +927,8 @@ int bus_cgroup_set_property(
                         r = fflush_and_check(f);
                         if (r < 0)
                                 return r;
-                        unit_write_drop_in_private(u, mode, name, buf);
+
+                        unit_write_setting(u, flags, name, buf);
                 }
 
                 return 1;
@@ -940,9 +945,9 @@ int bus_cgroup_set_property(
                 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
 
                         if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
-                                return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
+                                return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight= out of range");
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 CGroupBlockIODeviceWeight *a = NULL, *b;
 
                                 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
@@ -975,7 +980,7 @@ int bus_cgroup_set_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *buf = NULL;
                         _cleanup_fclose_ FILE *f = NULL;
                         CGroupBlockIODeviceWeight *a;
@@ -999,7 +1004,8 @@ int bus_cgroup_set_property(
                         r = fflush_and_check(f);
                         if (r < 0)
                                 return r;
-                        unit_write_drop_in_private(u, mode, name, buf);
+
+                        unit_write_setting(u, flags, name, buf);
                 }
 
                 return 1;
@@ -1011,10 +1017,10 @@ int bus_cgroup_set_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->memory_accounting = b;
                         unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
-                        unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
+                        unit_write_settingf(u, flags, name, "MemoryAccounting=%s", yes_no(b));
                 }
 
                 return 1;
@@ -1028,7 +1034,7 @@ int bus_cgroup_set_property(
                 if (v <= 0)
                         return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (streq(name, "MemoryLow"))
                                 c->memory_low = v;
                         else if (streq(name, "MemoryHigh"))
@@ -1041,9 +1047,9 @@ int bus_cgroup_set_property(
                         unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
 
                         if (v == CGROUP_LIMIT_MAX)
-                                unit_write_drop_in_private_format(u, mode, name, "%s=infinity", name);
+                                unit_write_settingf(u, flags, name, "%s=infinity", name);
                         else
-                                unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, v);
+                                unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, v);
                 }
 
                 return 1;
@@ -1060,7 +1066,7 @@ int bus_cgroup_set_property(
                 if (v <= 0 || v == UINT64_MAX)
                         return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         const char *e;
 
                         /* Chop off suffix */
@@ -1075,8 +1081,8 @@ int bus_cgroup_set_property(
                                 c->memory_max = v;
 
                         unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu32 "%%", name,
-                                                          (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
+                        unit_write_settingf(u, flags, name, "%s=%" PRIu32 "%%", name,
+                                            (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
                 }
 
                 return 1;
@@ -1090,14 +1096,14 @@ int bus_cgroup_set_property(
                 if (limit <= 0)
                         return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->memory_limit = limit;
                         unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
 
                         if (limit == (uint64_t) -1)
-                                unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity");
+                                unit_write_setting(u, flags, name, "MemoryLimit=infinity");
                         else
-                                unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit);
+                                unit_write_settingf(u, flags, name, "MemoryLimit=%" PRIu64, limit);
                 }
 
                 return 1;
@@ -1114,10 +1120,10 @@ int bus_cgroup_set_property(
                 if (limit <= 0 || limit == UINT64_MAX)
                         return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->memory_limit = limit;
                         unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
-                        unit_write_drop_in_private_format(u, mode, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%",
+                        unit_write_settingf(u, flags, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%",
                                                           (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
                 }
 
@@ -1135,10 +1141,10 @@ int bus_cgroup_set_property(
                 if (p < 0)
                         return -EINVAL;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->device_policy = p;
                         unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
-                        unit_write_drop_in_private_format(u, mode, name, "DevicePolicy=%s", policy);
+                        unit_write_settingf(u, flags, name, "DevicePolicy=%s", policy);
                 }
 
                 return 1;
@@ -1166,7 +1172,7 @@ int bus_cgroup_set_property(
                         if (!in_charset(rwm, "rwm"))
                                 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 CGroupDeviceAllow *a = NULL, *b;
 
                                 LIST_FOREACH(device_allow, b, c->device_allow) {
@@ -1204,7 +1210,7 @@ int bus_cgroup_set_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *buf = NULL;
                         _cleanup_fclose_ FILE *f = NULL;
                         CGroupDeviceAllow *a;
@@ -1228,7 +1234,7 @@ int bus_cgroup_set_property(
                         r = fflush_and_check(f);
                         if (r < 0)
                                 return r;
-                        unit_write_drop_in_private(u, mode, name, buf);
+                        unit_write_setting(u, flags, name, buf);
                 }
 
                 return 1;
@@ -1240,10 +1246,10 @@ int bus_cgroup_set_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->tasks_accounting = b;
                         unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
-                        unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no");
+                        unit_write_settingf(u, flags, name, "TasksAccounting=%s", yes_no(b));
                 }
 
                 return 1;
@@ -1257,14 +1263,14 @@ int bus_cgroup_set_property(
                 if (limit <= 0)
                         return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->tasks_max = limit;
                         unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
 
                         if (limit == (uint64_t) -1)
-                                unit_write_drop_in_private(u, mode, name, "TasksMax=infinity");
+                                unit_write_setting(u, flags, name, "TasksMax=infinity");
                         else
-                                unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit);
+                                unit_write_settingf(u, flags, name, "TasksMax=%" PRIu64, limit);
                 }
 
                 return 1;
@@ -1281,11 +1287,11 @@ int bus_cgroup_set_property(
                 if (limit <= 0 || limit >= UINT64_MAX)
                         return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->tasks_max = limit;
                         unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
-                        unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu32 "%%",
-                                                          (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
+                        unit_write_settingf(u, flags, name, "TasksMax=%" PRIu32 "%%",
+                                            (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
                 }
 
                 return 1;
@@ -1297,11 +1303,11 @@ int bus_cgroup_set_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->ip_accounting = b;
 
                         unit_invalidate_cgroup_bpf(u);
-                        unit_write_drop_in_private(u, mode, name, b ? "IPAccounting=yes" : "IPAccounting=no");
+                        unit_write_settingf(u, flags, name, "IPAccounting=%s", yes_no(b));
                 }
 
                 return 1;
@@ -1350,7 +1356,7 @@ int bus_cgroup_set_property(
                         if (prefixlen > FAMILY_ADDRESS_SIZE(family)*8)
                                 return sd_bus_error_set_errnof(error, EINVAL, "Prefix length %" PRIu32 " too large for address family %s.", prefixlen, af_to_name(family));
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 IPAddressAccessItem *item;
 
                                 item = new0(IPAddressAccessItem, 1);
@@ -1377,7 +1383,7 @@ int bus_cgroup_set_property(
 
                 *list = ip_address_access_reduce(*list);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *buf = NULL;
                         _cleanup_fclose_ FILE *f = NULL;
                         IPAddressAccessItem *item;
@@ -1407,7 +1413,8 @@ int bus_cgroup_set_property(
                         r = fflush_and_check(f);
                         if (r < 0)
                                 return r;
-                        unit_write_drop_in_private(u, mode, name, buf);
+
+                        unit_write_setting(u, flags, name, buf);
 
                         if (*list) {
                                 r = bpf_firewall_supported();
@@ -1429,7 +1436,7 @@ int bus_cgroup_set_property(
         }
 
         if (u->transient && u->load_state == UNIT_STUB) {
-                r = bus_cgroup_set_transient_property(u, c, name, message, mode, error);
+                r = bus_cgroup_set_transient_property(u, c, name, message, flags, error);
                 if (r != 0)
                         return r;
 
index 0e3b903..0588370 100644 (file)
@@ -26,4 +26,4 @@
 
 extern const sd_bus_vtable bus_cgroup_vtable[];
 
-int bus_cgroup_set_property(Unit *u, CGroupContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
+int bus_cgroup_set_property(Unit *u, CGroupContext *c, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
index 57ccdcb..412be2a 100644 (file)
@@ -32,6 +32,7 @@
 #include "dbus-execute.h"
 #include "env-util.h"
 #include "errno-list.h"
+#include "escape.h"
 #include "execute.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -50,6 +51,7 @@
 #include "seccomp-util.h"
 #endif
 #include "securebits-util.h"
+#include "specifier.h"
 #include "strv.h"
 #include "syslog-util.h"
 #include "unit-printf.h"
@@ -1037,7 +1039,7 @@ int bus_exec_context_set_transient_property(
                 ExecContext *c,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         const char *soft = NULL;
@@ -1048,6 +1050,8 @@ int bus_exec_context_set_transient_property(
         assert(name);
         assert(message);
 
+        flags |= UNIT_PRIVATE;
+
         if (streq(name, "User")) {
                 const char *uu;
 
@@ -1058,14 +1062,13 @@ int bus_exec_context_set_transient_property(
                 if (!isempty(uu) && !valid_user_group_name_or_id(uu))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user name: %s", uu);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
 
-                        if (isempty(uu))
-                                c->user = mfree(c->user);
-                        else if (free_and_strdup(&c->user, uu) < 0)
-                                return -ENOMEM;
+                        r = free_and_strdup(&c->user, empty_to_null(uu));
+                        if (r < 0)
+                                return r;
 
-                        unit_write_drop_in_private_format(u, mode, name, "User=%s", uu);
+                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "User=%s", uu);
                 }
 
                 return 1;
@@ -1080,14 +1083,13 @@ int bus_exec_context_set_transient_property(
                 if (!isempty(gg) && !valid_user_group_name_or_id(gg))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group name: %s", gg);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
 
-                        if (isempty(gg))
-                                c->group = mfree(c->group);
-                        else if (free_and_strdup(&c->group, gg) < 0)
-                                return -ENOMEM;
+                        r = free_and_strdup(&c->group, empty_to_null(gg));
+                        if (r < 0)
+                                return r;
 
-                        unit_write_drop_in_private_format(u, mode, name, "Group=%s", gg);
+                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "Group=%s", gg);
                 }
 
                 return 1;
@@ -1105,10 +1107,10 @@ int bus_exec_context_set_transient_property(
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid supplementary group names");
                 }
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (strv_length(l) == 0) {
                                 c->supplementary_groups = strv_free(c->supplementary_groups);
-                                unit_write_drop_in_private_format(u, mode, name, "%s=", name);
+                                unit_write_settingf(u, flags, name, "%s=", name);
                         } else {
                                 _cleanup_free_ char *joined = NULL;
 
@@ -1120,7 +1122,7 @@ int bus_exec_context_set_transient_property(
                                 if (!joined)
                                         return -ENOMEM;
 
-                                unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, joined);
+                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, joined);
                         }
                 }
 
@@ -1133,14 +1135,14 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
 
                         if (isempty(id))
                                 c->syslog_identifier = mfree(c->syslog_identifier);
                         else if (free_and_strdup(&c->syslog_identifier, id) < 0)
                                 return -ENOMEM;
 
-                        unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s", id);
+                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "SyslogIdentifier=%s", id);
                 }
 
                 return 1;
@@ -1154,9 +1156,9 @@ int bus_exec_context_set_transient_property(
                 if (!log_level_is_valid(level))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level;
-                        unit_write_drop_in_private_format(u, mode, name, "SyslogLevel=%i", level);
+                        unit_write_settingf(u, flags, name, "SyslogLevel=%i", level);
                 }
 
                 return 1;
@@ -1170,9 +1172,9 @@ int bus_exec_context_set_transient_property(
                 if (!log_facility_unshifted_is_valid(facility))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority);
-                        unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i", facility);
+                        unit_write_settingf(u, flags, name, "SyslogFacility=%i", facility);
                 }
 
                 return 1;
@@ -1187,9 +1189,9 @@ int bus_exec_context_set_transient_property(
                 if (!log_level_is_valid(level))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Maximum log level value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->log_level_max = level;
-                        unit_write_drop_in_private_format(u, mode, name, "LogLevelMax=%i", level);
+                        unit_write_settingf(u, flags, name, "LogLevelMax=%i", level);
                 }
 
                 return 1;
@@ -1230,7 +1232,7 @@ int bus_exec_context_set_transient_property(
                         if (!journal_field_valid(p, eq - (const char*) p, false))
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field invalid");
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 t = realloc_multiply(c->log_extra_fields, sizeof(struct iovec), c->n_log_extra_fields+1);
                                 if (!t)
                                         return -ENOMEM;
@@ -1247,9 +1249,9 @@ int bus_exec_context_set_transient_property(
                         if (!utf8_is_valid(copy))
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field is not valid UTF-8");
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 c->log_extra_fields[c->n_log_extra_fields++] = IOVEC_MAKE(copy, sz);
-                                unit_write_drop_in_private_format(u, mode, name, "LogExtraFields=%s", (char*) copy);
+                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_C, name, "LogExtraFields=%s", (char*) copy);
 
                                 copy = NULL;
                         }
@@ -1261,9 +1263,9 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK && n == 0) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags) && n == 0) {
                         exec_context_free_log_extra_fields(c);
-                        unit_write_drop_in_private(u, mode, name, "LogExtraFields=");
+                        unit_write_setting(u, flags, name, "LogExtraFields=");
                 }
 
                 return 1;
@@ -1278,7 +1280,7 @@ int bus_exec_context_set_transient_property(
                 if (!secure_bits_is_valid(n))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid secure bits");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *str = NULL;
 
                         c->secure_bits = n;
@@ -1286,7 +1288,7 @@ int bus_exec_context_set_transient_property(
                         if (r < 0)
                                 return r;
 
-                        unit_write_drop_in_private_format(u, mode, name, "SecureBits=%s", str);
+                        unit_write_settingf(u, flags, name, "SecureBits=%s", str);
                 }
 
                 return 1;
@@ -1297,7 +1299,7 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *str = NULL;
 
                         if (streq(name, "CapabilityBoundingSet"))
@@ -1309,7 +1311,7 @@ int bus_exec_context_set_transient_property(
                         if (r < 0)
                                 return r;
 
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, str);
+                        unit_write_settingf(u, flags, name, "%s=%s", name, str);
                 }
 
                 return 1;
@@ -1326,9 +1328,9 @@ int bus_exec_context_set_transient_property(
                 if (p == PERSONALITY_INVALID)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid personality");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->personality = p;
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s);
+                        unit_write_settingf(u, flags, name, "%s=%s", name, s);
                 }
 
                 return 1;
@@ -1355,7 +1357,7 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *joined = NULL;
 
                         if (strv_length(l) == 0) {
@@ -1416,7 +1418,7 @@ int bus_exec_context_set_transient_property(
                         if (!joined)
                                 return -ENOMEM;
 
-                        unit_write_drop_in_private_format(u, mode, name, "SystemCallFilter=%s%s", whitelist ? "" : "~", joined);
+                        unit_write_settingf(u, flags, name, "SystemCallFilter=%s%s", whitelist ? "" : "~", joined);
                 }
 
                 return 1;
@@ -1428,7 +1430,7 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *joined = NULL;
 
                         if (strv_length(l) == 0)
@@ -1458,7 +1460,7 @@ int bus_exec_context_set_transient_property(
                         if (!joined)
                                 return -ENOMEM;
 
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, joined);
+                        unit_write_settingf(u, flags, name, "%s=%s", name, joined);
                 }
 
                 return 1;
@@ -1473,10 +1475,10 @@ int bus_exec_context_set_transient_property(
                 if (n <= 0 || n > ERRNO_MAX)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SystemCallErrorNumber");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->syscall_errno = n;
 
-                        unit_write_drop_in_private_format(u, mode, name, "SystemCallErrorNumber=%d", n);
+                        unit_write_settingf(u, flags, name, "SystemCallErrorNumber=%d", n);
                 }
 
                 return 1;
@@ -1501,7 +1503,7 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *joined = NULL;
 
                         if (strv_length(l) == 0) {
@@ -1533,7 +1535,7 @@ int bus_exec_context_set_transient_property(
                         if (!joined)
                                 return -ENOMEM;
 
-                        unit_write_drop_in_private_format(u, mode, name, "RestrictAddressFamilies=%s%s", whitelist ? "" : "~", joined);
+                        unit_write_settingf(u, flags, name, "RestrictAddressFamilies=%s%s", whitelist ? "" : "~", joined);
                 }
 
                 return 1;
@@ -1549,7 +1551,7 @@ int bus_exec_context_set_transient_property(
                 if (!sched_policy_is_valid(n))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling policy");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *str = NULL;
 
                         c->cpu_sched_policy = n;
@@ -1557,7 +1559,7 @@ int bus_exec_context_set_transient_property(
                         if (r < 0)
                                 return r;
 
-                        unit_write_drop_in_private_format(u, mode, name, "CPUSchedulingPolicy=%s", str);
+                        unit_write_settingf(u, flags, name, "CPUSchedulingPolicy=%s", str);
                 }
 
                 return 1;
@@ -1572,9 +1574,9 @@ int bus_exec_context_set_transient_property(
                 if (!ioprio_priority_is_valid(n))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling priority");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->cpu_sched_priority = n;
-                        unit_write_drop_in_private_format(u, mode, name, "CPUSchedulingPriority=%i", n);
+                        unit_write_settingf(u, flags, name, "CPUSchedulingPriority=%i", n);
                 }
 
                 return 1;
@@ -1587,10 +1589,10 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (n == 0) {
                                 c->cpuset = mfree(c->cpuset);
-                                unit_write_drop_in_private_format(u, mode, name, "%s=", name);
+                                unit_write_settingf(u, flags, name, "%s=", name);
                         } else {
                                 _cleanup_free_ char *str = NULL;
                                 uint8_t *l;
@@ -1621,7 +1623,7 @@ int bus_exec_context_set_transient_property(
                                 if (len != 0)
                                         str[len - 1] = '\0';
 
-                                unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, str);
+                                unit_write_settingf(u, flags, name, "%s=%s", name, str);
                         }
                 }
 
@@ -1636,9 +1638,9 @@ int bus_exec_context_set_transient_property(
                 if (!nice_is_valid(n))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Nice value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->nice = n;
-                        unit_write_drop_in_private_format(u, mode, name, "Nice=%i", n);
+                        unit_write_settingf(u, flags, name, "Nice=%i", n);
                 }
 
                 return 1;
@@ -1653,7 +1655,7 @@ int bus_exec_context_set_transient_property(
                 if (!ioprio_class_is_valid(q))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid IO scheduling class: %i", q);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *s = NULL;
 
                         r = ioprio_class_to_string_alloc(q, &s);
@@ -1663,7 +1665,7 @@ int bus_exec_context_set_transient_property(
                         c->ioprio = IOPRIO_PRIO_VALUE(q, IOPRIO_PRIO_DATA(c->ioprio));
                         c->ioprio_set = true;
 
-                        unit_write_drop_in_private_format(u, mode, name, "IOSchedulingClass=%s", s);
+                        unit_write_settingf(u, flags, name, "IOSchedulingClass=%s", s);
                 }
 
                 return 1;
@@ -1678,11 +1680,11 @@ int bus_exec_context_set_transient_property(
                 if (!ioprio_priority_is_valid(p))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid IO scheduling priority: %i", p);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), p);
                         c->ioprio_set = true;
 
-                        unit_write_drop_in_private_format(u, mode, name, "IOSchedulingPriority=%i", p);
+                        unit_write_settingf(u, flags, name, "IOSchedulingPriority=%i", p);
                 }
 
                 return 1;
@@ -1697,7 +1699,7 @@ int bus_exec_context_set_transient_property(
                 if (!path_is_absolute(s))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s takes an absolute path", name);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (streq(name, "TTYPath"))
                                 r = free_and_strdup(&c->tty_path, s);
                         else if (streq(name, "RootImage"))
@@ -1709,7 +1711,7 @@ int bus_exec_context_set_transient_property(
                         if (r < 0)
                                 return r;
 
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s);
+                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, s);
                 }
 
                 return 1;
@@ -1731,7 +1733,7 @@ int bus_exec_context_set_transient_property(
                 if (!streq(s, "~") && !path_is_absolute(s))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (streq(s, "~")) {
                                 c->working_directory = mfree(c->working_directory);
                                 c->working_directory_home = true;
@@ -1744,7 +1746,7 @@ int bus_exec_context_set_transient_property(
                         }
 
                         c->working_directory_missing_ok = missing_ok;
-                        unit_write_drop_in_private_format(u, mode, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s);
+                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s);
                 }
 
                 return 1;
@@ -1761,10 +1763,10 @@ int bus_exec_context_set_transient_property(
                 if (p < 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard input name");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->std_input = p;
 
-                        unit_write_drop_in_private_format(u, mode, name, "StandardInput=%s", exec_input_to_string(p));
+                        unit_write_settingf(u, flags, name, "StandardInput=%s", exec_input_to_string(p));
                 }
 
                 return 1;
@@ -1781,10 +1783,10 @@ int bus_exec_context_set_transient_property(
                 if (p < 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard output name");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->std_output = p;
 
-                        unit_write_drop_in_private_format(u, mode, name, "StandardOutput=%s", exec_output_to_string(p));
+                        unit_write_settingf(u, flags, name, "StandardOutput=%s", exec_output_to_string(p));
                 }
 
                 return 1;
@@ -1801,10 +1803,10 @@ int bus_exec_context_set_transient_property(
                 if (p < 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard error name");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->std_error = p;
 
-                        unit_write_drop_in_private_format(u, mode, name, "StandardError=%s", exec_output_to_string(p));
+                        unit_write_settingf(u, flags, name, "StandardError=%s", exec_output_to_string(p));
                 }
 
                 return 1;
@@ -1822,7 +1824,7 @@ int bus_exec_context_set_transient_property(
                 else if (!fdname_is_valid(s))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid file descriptor name");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
 
                         if (streq(name, "StandardInputFileDescriptorName")) {
                                 r = free_and_strdup(c->stdio_fdname + STDIN_FILENO, s);
@@ -1830,7 +1832,7 @@ int bus_exec_context_set_transient_property(
                                         return r;
 
                                 c->std_input = EXEC_INPUT_NAMED_FD;
-                                unit_write_drop_in_private_format(u, mode, name, "StandardInput=fd:%s", exec_context_fdname(c, STDIN_FILENO));
+                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=fd:%s", exec_context_fdname(c, STDIN_FILENO));
 
                         } else if (streq(name, "StandardOutputFileDescriptorName")) {
                                 r = free_and_strdup(c->stdio_fdname + STDOUT_FILENO, s);
@@ -1838,7 +1840,7 @@ int bus_exec_context_set_transient_property(
                                         return r;
 
                                 c->std_output = EXEC_OUTPUT_NAMED_FD;
-                                unit_write_drop_in_private_format(u, mode, name, "StandardOutput=fd:%s", exec_context_fdname(c, STDOUT_FILENO));
+                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=fd:%s", exec_context_fdname(c, STDOUT_FILENO));
 
                         } else {
                                 assert(streq(name, "StandardErrorFileDescriptorName"));
@@ -1848,7 +1850,7 @@ int bus_exec_context_set_transient_property(
                                         return r;
 
                                 c->std_error = EXEC_OUTPUT_NAMED_FD;
-                                unit_write_drop_in_private_format(u, mode, name, "StandardError=fd:%s", exec_context_fdname(c, STDERR_FILENO));
+                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=fd:%s", exec_context_fdname(c, STDERR_FILENO));
                         }
                 }
 
@@ -1866,7 +1868,7 @@ int bus_exec_context_set_transient_property(
                 if (!path_is_normalized(s))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not normalized", s);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
 
                         if (streq(name, "StandardInputFile")) {
                                 r = free_and_strdup(&c->stdio_file[STDIN_FILENO], s);
@@ -1874,7 +1876,7 @@ int bus_exec_context_set_transient_property(
                                         return r;
 
                                 c->std_input = EXEC_INPUT_FILE;
-                                unit_write_drop_in_private_format(u, mode, name, "StandardInput=file:%s", s);
+                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=file:%s", s);
 
                         } else if (streq(name, "StandardOutputFile")) {
                                 r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], s);
@@ -1882,7 +1884,7 @@ int bus_exec_context_set_transient_property(
                                         return r;
 
                                 c->std_output = EXEC_OUTPUT_FILE;
-                                unit_write_drop_in_private_format(u, mode, name, "StandardOutput=file:%s", s);
+                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s);
 
                         } else {
                                 assert(streq(name, "StandardErrorFile"));
@@ -1892,7 +1894,7 @@ int bus_exec_context_set_transient_property(
                                         return r;
 
                                 c->std_error = EXEC_OUTPUT_FILE;
-                                unit_write_drop_in_private_format(u, mode, name, "StandardError=file:%s", s);
+                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=file:%s", s);
                         }
                 }
 
@@ -1906,14 +1908,14 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *encoded = NULL;
 
                         if (sz == 0) {
                                 c->stdin_data = mfree(c->stdin_data);
                                 c->stdin_data_size = 0;
 
-                                unit_write_drop_in_private(u, mode, name, "StandardInputData=");
+                                unit_write_settingf(u, flags, name, "StandardInputData=");
                         } else {
                                 void *q;
                                 ssize_t n;
@@ -1935,7 +1937,7 @@ int bus_exec_context_set_transient_property(
                                 c->stdin_data = q;
                                 c->stdin_data_size += sz;
 
-                                unit_write_drop_in_private_format(u, mode, name, "StandardInputData=%s", encoded);
+                                unit_write_settingf(u, flags, name, "StandardInputData=%s", encoded);
                         }
                 }
 
@@ -1954,7 +1956,7 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (streq(name, "IgnoreSIGPIPE"))
                                 c->ignore_sigpipe = b;
                         else if (streq(name, "TTYVHangup"))
@@ -1998,7 +2000,7 @@ int bus_exec_context_set_transient_property(
                         else if (streq(name, "LockPersonality"))
                                 c->lock_personality = b;
 
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, yes_no(b));
+                        unit_write_settingf(u, flags, name, "%s=%s", name, yes_no(b));
                 }
 
                 return 1;
@@ -2010,13 +2012,13 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
-                        if (isempty(id))
-                                c->utmp_id = mfree(c->utmp_id);
-                        else if (free_and_strdup(&c->utmp_id, id) < 0)
-                                return -ENOMEM;
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+
+                        r = free_and_strdup(&c->utmp_id, empty_to_null(id));
+                        if (r < 0)
+                                return r;
 
-                        unit_write_drop_in_private_format(u, mode, name, "UtmpIdentifier=%s", strempty(id));
+                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "UtmpIdentifier=%s", strempty(id));
                 }
 
                 return 1;
@@ -2033,10 +2035,10 @@ int bus_exec_context_set_transient_property(
                 if (m < 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid utmp mode");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->utmp_mode = m;
 
-                        unit_write_drop_in_private_format(u, mode, name, "UtmpMode=%s", exec_utmp_mode_to_string(m));
+                        unit_write_settingf(u, flags, name, "UtmpMode=%s", exec_utmp_mode_to_string(m));
                 }
 
                 return 1;
@@ -2048,13 +2050,13 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
-                        if (isempty(n))
-                                c->pam_name = mfree(c->pam_name);
-                        else if (free_and_strdup(&c->pam_name, n) < 0)
-                                return -ENOMEM;
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
 
-                        unit_write_drop_in_private_format(u, mode, name, "PAMName=%s", strempty(n));
+                        r = free_and_strdup(&c->pam_name, empty_to_null(n));
+                        if (r < 0)
+                                return r;
+
+                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "PAMName=%s", strempty(n));
                 }
 
                 return 1;
@@ -2070,14 +2072,18 @@ int bus_exec_context_set_transient_property(
                 if (!strv_env_is_valid(l))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (strv_length(l) == 0) {
                                 c->environment = strv_free(c->environment);
-                                unit_write_drop_in_private_format(u, mode, name, "Environment=");
+                                unit_write_setting(u, flags, name, "Environment=");
                         } else {
                                 _cleanup_free_ char *joined = NULL;
                                 char **e;
 
+                                joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_C);
+                                if (!joined)
+                                        return -ENOMEM;
+
                                 e = strv_env_merge(2, c->environment, l);
                                 if (!e)
                                         return -ENOMEM;
@@ -2085,11 +2091,7 @@ int bus_exec_context_set_transient_property(
                                 strv_free(c->environment);
                                 c->environment = e;
 
-                                joined = strv_join_quoted(l);
-                                if (!joined)
-                                        return -ENOMEM;
-
-                                unit_write_drop_in_private_format(u, mode, name, "Environment=%s", joined);
+                                unit_write_settingf(u, flags, name, "Environment=%s", joined);
                         }
                 }
 
@@ -2106,14 +2108,18 @@ int bus_exec_context_set_transient_property(
                 if (!strv_env_name_or_assignment_is_valid(l))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UnsetEnvironment= list.");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (strv_length(l) == 0) {
                                 c->unset_environment = strv_free(c->unset_environment);
-                                unit_write_drop_in_private_format(u, mode, name, "UnsetEnvironment=");
+                                unit_write_setting(u, flags, name, "UnsetEnvironment=");
                         } else {
                                 _cleanup_free_ char *joined = NULL;
                                 char **e;
 
+                                joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_C);
+                                if (!joined)
+                                        return -ENOMEM;
+
                                 e = strv_env_merge(2, c->unset_environment, l);
                                 if (!e)
                                         return -ENOMEM;
@@ -2121,12 +2127,7 @@ int bus_exec_context_set_transient_property(
                                 strv_free(c->unset_environment);
                                 c->unset_environment = e;
 
-                                /* We write just the new settings out to file, with unresolved specifiers */
-                                joined = strv_join_quoted(l);
-                                if (!joined)
-                                        return -ENOMEM;
-
-                                unit_write_drop_in_private_format(u, mode, name, "UnsetEnvironment=%s", joined);
+                                unit_write_settingf(u, flags, name, "UnsetEnvironment=%s", joined);
                         }
                 }
 
@@ -2140,9 +2141,9 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->timer_slack_nsec = n;
-                        unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT, n);
+                        unit_write_settingf(u, flags, name, "TimerSlackNSec=" NSEC_FMT, n);
                 }
 
                 return 1;
@@ -2157,10 +2158,10 @@ int bus_exec_context_set_transient_property(
                 if (!oom_score_adjust_is_valid(oa))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "OOM score adjust value out of range");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->oom_score_adjust = oa;
                         c->oom_score_adjust_set = true;
-                        unit_write_drop_in_private_format(u, mode, name, "OOMScoreAdjust=%i", oa);
+                        unit_write_settingf(u, flags, name, "OOMScoreAdjust=%i", oa);
                 }
 
                 return 1;
@@ -2181,8 +2182,17 @@ int bus_exec_context_set_transient_property(
                 if (!f)
                         return -ENOMEM;
 
-                STRV_FOREACH(i, c->environment_files)
-                        fprintf(f, "EnvironmentFile=%s", *i);
+                fputs("EnvironmentFile=\n", f);
+
+                STRV_FOREACH(i, c->environment_files) {
+                        _cleanup_free_ char *q = NULL;
+
+                        q = specifier_escape(*i);
+                        if (!q)
+                                return -ENOMEM;
+
+                        fprintf(f, "EnvironmentFile=%s\n", q);
+                }
 
                 while ((r = sd_bus_message_enter_container(message, 'r', "sb")) > 0) {
                         const char *path;
@@ -2199,14 +2209,21 @@ int bus_exec_context_set_transient_property(
                         if (!path_is_absolute(path))
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                                _cleanup_free_ char *q = NULL;
                                 char *buf;
 
                                 buf = strjoin(b ? "-" : "", path);
                                 if (!buf)
                                         return -ENOMEM;
 
-                                fprintf(f, "EnvironmentFile=%s", buf);
+                                q = specifier_escape(buf);
+                                if (!q) {
+                                        free(buf);
+                                        return -ENOMEM;
+                                }
+
+                                fprintf(f, "EnvironmentFile=%s\n", q);
 
                                 r = strv_consume(&l, buf);
                                 if (r < 0)
@@ -2224,16 +2241,16 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (strv_isempty(l)) {
                                 c->environment_files = strv_free(c->environment_files);
-                                unit_write_drop_in_private(u, mode, name, "EnvironmentFile=");
+                                unit_write_setting(u, flags, name, "EnvironmentFile=");
                         } else {
                                 r = strv_extend_strv(&c->environment_files, l, true);
                                 if (r < 0)
                                         return r;
 
-                                unit_write_drop_in_private(u, mode, name, joined);
+                                unit_write_setting(u, flags, name, joined);
                         }
                 }
 
@@ -2250,19 +2267,19 @@ int bus_exec_context_set_transient_property(
                 if (!strv_env_name_is_valid(l))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment= block.");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (strv_isempty(l)) {
                                 c->pass_environment = strv_free(c->pass_environment);
-                                unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=");
+                                unit_write_setting(u, flags, name, "PassEnvironment=");
                         } else {
                                 _cleanup_free_ char *joined = NULL;
 
                                 /* We write just the new settings out to file, with unresolved specifiers. */
-                                joined = strv_join_quoted(l);
+                                joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS);
                                 if (!joined)
                                         return -ENOMEM;
 
-                                unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=%s", joined);
+                                unit_write_settingf(u, flags, name, "PassEnvironment=%s", joined);
                         }
                 }
 
@@ -2291,9 +2308,7 @@ int bus_exec_context_set_transient_property(
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
                 }
 
-                if (mode != UNIT_CHECK) {
-                        _cleanup_free_ char *joined = NULL;
-
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (STR_IN_SET(name, "ReadWriteDirectories", "ReadWritePaths"))
                                 dirs = &c->read_write_paths;
                         else if (STR_IN_SET(name, "ReadOnlyDirectories", "ReadOnlyPaths"))
@@ -2303,19 +2318,20 @@ int bus_exec_context_set_transient_property(
 
                         if (strv_length(l) == 0) {
                                 *dirs = strv_free(*dirs);
-                                unit_write_drop_in_private_format(u, mode, name, "%s=", name);
+                                unit_write_settingf(u, flags, name, "%s=", name);
                         } else {
-                                r = strv_extend_strv(dirs, l, true);
-                                if (r < 0)
-                                        return -ENOMEM;
+                                _cleanup_free_ char *joined = NULL;
 
-                                joined = strv_join_quoted(*dirs);
+                                joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS);
                                 if (!joined)
                                         return -ENOMEM;
 
-                                unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, joined);
-                        }
+                                r = strv_extend_strv(dirs, l, true);
+                                if (r < 0)
+                                        return -ENOMEM;
 
+                                unit_write_settingf(u, flags, name, "%s=%s", name, joined);
+                        }
                 }
 
                 return 1;
@@ -2339,9 +2355,9 @@ int bus_exec_context_set_transient_property(
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect system value");
                 }
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->protect_system = ps;
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s);
+                        unit_write_settingf(u, flags, name, "%s=%s", name, s);
                 }
 
                 return 1;
@@ -2365,9 +2381,9 @@ int bus_exec_context_set_transient_property(
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect home value");
                 }
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->protect_home = ph;
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s);
+                        unit_write_settingf(u, flags, name, "%s=%s", name, s);
                 }
 
                 return 1;
@@ -2385,10 +2401,10 @@ int bus_exec_context_set_transient_property(
                 if (m < 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid keyring mode");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->keyring_mode = m;
 
-                        unit_write_drop_in_private_format(u, mode, name, "KeyringMode=%s", exec_keyring_mode_to_string(m));
+                        unit_write_settingf(u, flags, name, "KeyringMode=%s", exec_keyring_mode_to_string(m));
                 }
 
                 return 1;
@@ -2405,10 +2421,10 @@ int bus_exec_context_set_transient_property(
                 if (m < 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid preserve mode");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->runtime_directory_preserve_mode = m;
 
-                        unit_write_drop_in_private_format(u, mode, name, "RuntimeDirectoryPreserve=%s", exec_preserve_mode_to_string(m));
+                        unit_write_settingf(u, flags, name, "RuntimeDirectoryPreserve=%s", exec_preserve_mode_to_string(m));
                 }
 
                 return 1;
@@ -2420,7 +2436,7 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         ExecDirectoryType i;
 
                         if (streq(name, "UMask"))
@@ -2432,7 +2448,7 @@ int bus_exec_context_set_transient_property(
                                                 break;
                                         }
 
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%040o", name, m);
+                        unit_write_settingf(u, flags, name, "%s=%040o", name, m);
                 }
 
                 return 1;
@@ -2450,8 +2466,7 @@ int bus_exec_context_set_transient_property(
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path is not valid: %s", name, *p);
                 }
 
-                if (mode != UNIT_CHECK) {
-                        _cleanup_free_ char *joined = NULL;
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         char ***dirs = NULL;
                         ExecDirectoryType i;
 
@@ -2465,17 +2480,19 @@ int bus_exec_context_set_transient_property(
 
                         if (strv_isempty(l)) {
                                 *dirs = strv_free(*dirs);
-                                unit_write_drop_in_private_format(u, mode, name, "%s=", name);
+                                unit_write_settingf(u, flags, name, "%s=", name);
                         } else {
+                                _cleanup_free_ char *joined = NULL;
+
                                 r = strv_extend_strv(dirs, l, true);
                                 if (r < 0)
                                         return -ENOMEM;
 
-                                joined = strv_join_quoted(*dirs);
+                                joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS);
                                 if (!joined)
                                         return -ENOMEM;
 
-                                unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, joined);
+                                unit_write_settingf(u, flags, name, "%s=%s", name, joined);
                         }
                 }
 
@@ -2487,13 +2504,13 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (isempty(s))
                                 c->selinux_context = mfree(c->selinux_context);
                         else if (free_and_strdup(&c->selinux_context, s) < 0)
                                 return -ENOMEM;
 
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, strempty(s));
+                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(s));
                 }
 
                 return 1;
@@ -2510,7 +2527,7 @@ int bus_exec_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         char **p;
                         bool *b;
 
@@ -2531,45 +2548,45 @@ int bus_exec_context_set_transient_property(
                                 *b = ignore;
                         }
 
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%s%s", name, ignore ? "-" : "", strempty(s));
+                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s%s", name, ignore ? "-" : "", strempty(s));
                 }
 
                 return 1;
 
         } else if (streq(name, "RestrictNamespaces")) {
-                uint64_t flags;
+                uint64_t rf;
 
-                r = sd_bus_message_read(message, "t", &flags);
+                r = sd_bus_message_read(message, "t", &rf);
                 if (r < 0)
                         return r;
-                if ((flags & NAMESPACE_FLAGS_ALL) != flags)
+                if ((rf & NAMESPACE_FLAGS_ALL) != rf)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown namespace types");
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *s = NULL;
 
-                        r = namespace_flag_to_string_many(flags, &s);
+                        r = namespace_flag_to_string_many(rf, &s);
                         if (r < 0)
                                 return r;
 
-                        c->restrict_namespaces = flags;
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s);
+                        c->restrict_namespaces = rf;
+                        unit_write_settingf(u, flags, name, "%s=%s", name, s);
                 }
 
                 return 1;
         } else if (streq(name, "MountFlags")) {
-                uint64_t flags;
+                uint64_t fl;
 
-                r = sd_bus_message_read(message, "t", &flags);
+                r = sd_bus_message_read(message, "t", &fl);
                 if (r < 0)
                         return r;
-                if (!IN_SET(flags, 0, MS_SHARED, MS_PRIVATE, MS_SLAVE))
+                if (!IN_SET(fl, 0, MS_SHARED, MS_PRIVATE, MS_SLAVE))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mount propagation flags");
 
-                if (mode != UNIT_CHECK) {
-                        c->mount_flags = flags;
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        c->mount_flags = fl;
 
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, mount_propagation_flags_to_string(flags));
+                        unit_write_settingf(u, flags, name, "%s=%s", name, mount_propagation_flags_to_string(fl));
                 }
 
                 return 1;
@@ -2600,7 +2617,7 @@ int bus_exec_context_set_transient_property(
                         if (!IN_SET(mount_flags, 0, MS_REC))
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mount flags.");
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
                                                    &(BindMount) {
                                                            .source = strdup(source),
@@ -2612,8 +2629,8 @@ int bus_exec_context_set_transient_property(
                                 if (r < 0)
                                         return r;
 
-                                unit_write_drop_in_private_format(
-                                                u, mode, name,
+                                unit_write_settingf(
+                                                u, flags|UNIT_ESCAPE_SPECIFIERS, name,
                                                 "%s=%s%s:%s:%s",
                                                 name,
                                                 ignore_enoent ? "-" : "",
@@ -2635,6 +2652,8 @@ int bus_exec_context_set_transient_property(
                         bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
                         c->bind_mounts = NULL;
                         c->n_bind_mounts = 0;
+
+                        unit_write_settingf(u, flags, name, "%s=", name);
                 }
 
                 return 1;
@@ -2671,7 +2690,7 @@ int bus_exec_context_set_transient_property(
                                 return -ERANGE;
                 }
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *f = NULL;
                         struct rlimit nl;
 
@@ -2701,7 +2720,7 @@ int bus_exec_context_set_transient_property(
                                         return -ENOMEM;
                         }
 
-                        unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, f);
+                        unit_write_settingf(u, flags, name, "%s=%s", name, f);
                 }
 
                 return 1;
index 631edcc..f30f077 100644 (file)
@@ -43,4 +43,4 @@ int bus_property_get_exec_output(sd_bus *bus, const char *path, const char *inte
 int bus_property_get_exec_command(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
 int bus_property_get_exec_command_list(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
 
-int bus_exec_context_set_transient_property(Unit *u, ExecContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
+int bus_exec_context_set_transient_property(Unit *u, ExecContext *c, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
index 4ac9f36..bf3bbb2 100644 (file)
@@ -39,7 +39,7 @@ int bus_kill_context_set_transient_property(
                 KillContext *c,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         int r;
@@ -49,6 +49,8 @@ int bus_kill_context_set_transient_property(
         assert(name);
         assert(message);
 
+        flags |= UNIT_PRIVATE;
+
         if (streq(name, "KillMode")) {
                 const char *m;
                 KillMode k;
@@ -61,10 +63,10 @@ int bus_kill_context_set_transient_property(
                 if (k < 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Kill mode '%s' not known.", m);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->kill_mode = k;
 
-                        unit_write_drop_in_private_format(u, mode, name, "KillMode=%s", kill_mode_to_string(k));
+                        unit_write_settingf(u, flags, name, "KillMode=%s", kill_mode_to_string(k));
                 }
 
                 return 1;
@@ -79,10 +81,10 @@ int bus_kill_context_set_transient_property(
                 if (!SIGNAL_VALID(sig))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal %i out of range", sig);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->kill_signal = sig;
 
-                        unit_write_drop_in_private_format(u, mode, name, "KillSignal=%s", signal_to_string(sig));
+                        unit_write_settingf(u, flags, name, "KillSignal=%s", signal_to_string(sig));
                 }
 
                 return 1;
@@ -94,10 +96,10 @@ int bus_kill_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->send_sighup = b;
 
-                        unit_write_drop_in_private_format(u, mode, name, "SendSIGHUP=%s", yes_no(b));
+                        unit_write_settingf(u, flags, name, "SendSIGHUP=%s", yes_no(b));
                 }
 
                 return 1;
@@ -109,10 +111,10 @@ int bus_kill_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->send_sigkill = b;
 
-                        unit_write_drop_in_private_format(u, mode, name, "SendSIGKILL=%s", yes_no(b));
+                        unit_write_settingf(u, flags, name, "SendSIGKILL=%s", yes_no(b));
                 }
 
                 return 1;
index 44fb9f9..1df3b37 100644 (file)
@@ -27,4 +27,4 @@
 
 extern const sd_bus_vtable bus_kill_vtable[];
 
-int bus_kill_context_set_transient_property(Unit *u, KillContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
+int bus_kill_context_set_transient_property(Unit *u, KillContext *c, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
index 794b292..628bce0 100644 (file)
@@ -126,18 +126,19 @@ static int bus_mount_set_transient_property(
                 Mount *m,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         const char *new_property;
         char **property;
-        char *p;
         int r;
 
         assert(m);
         assert(name);
         assert(message);
 
+        flags |= UNIT_PRIVATE;
+
         if (streq(name, "What"))
                 property = &m->parameters_fragment.what;
         else if (streq(name, "Options"))
@@ -151,16 +152,13 @@ static int bus_mount_set_transient_property(
         if (r < 0)
                 return r;
 
-        if (mode != UNIT_CHECK) {
-                p = strdup(new_property);
-                if (!p)
-                        return -ENOMEM;
+        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
 
-                unit_write_drop_in_format(UNIT(m), mode, name, "[Mount]\n%s=%s\n",
-                        name, new_property);
+                r = free_and_strdup(property, new_property);
+                if (r < 0)
+                        return r;
 
-                free(*property);
-                *property = p;
+                unit_write_settingf(UNIT(m), flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, new_property);
         }
 
         return 1;
@@ -170,7 +168,7 @@ int bus_mount_set_property(
                 Unit *u,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         Mount *m = MOUNT(u);
@@ -180,22 +178,22 @@ int bus_mount_set_property(
         assert(name);
         assert(message);
 
-        r = bus_cgroup_set_property(u, &m->cgroup_context, name, message, mode, error);
+        r = bus_cgroup_set_property(u, &m->cgroup_context, name, message, flags, error);
         if (r != 0)
                 return r;
 
         if (u->transient && u->load_state == UNIT_STUB) {
                 /* This is a transient unit, let's load a little more */
 
-                r = bus_mount_set_transient_property(m, name, message, mode, error);
+                r = bus_mount_set_transient_property(m, name, message, flags, error);
                 if (r != 0)
                         return r;
 
-                r = bus_exec_context_set_transient_property(u, &m->exec_context, name, message, mode, error);
+                r = bus_exec_context_set_transient_property(u, &m->exec_context, name, message, flags, error);
                 if (r != 0)
                         return r;
 
-                r = bus_kill_context_set_transient_property(u, &m->kill_context, name, message, mode, error);
+                r = bus_kill_context_set_transient_property(u, &m->kill_context, name, message, flags, error);
                 if (r != 0)
                         return r;
         }
index f0a7637..5d5e1f6 100644 (file)
@@ -26,5 +26,5 @@
 
 extern const sd_bus_vtable bus_mount_vtable[];
 
-int bus_mount_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
+int bus_mount_set_property(Unit *u, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 int bus_mount_commit_properties(Unit *u);
index 4737c6d..9195ad3 100644 (file)
@@ -73,7 +73,7 @@ static int bus_scope_set_transient_property(
                 Scope *s,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         int r;
@@ -82,6 +82,8 @@ static int bus_scope_set_transient_property(
         assert(name);
         assert(message);
 
+        flags |= UNIT_PRIVATE;
+
         if (streq(name, "PIDs")) {
                 unsigned n = 0;
                 uint32_t pid;
@@ -95,7 +97,7 @@ static int bus_scope_set_transient_property(
                         if (pid <= 1)
                                 return -EINVAL;
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 r = unit_watch_pid(UNIT(s), pid);
                                 if (r < 0 && r != -EEXIST)
                                         return r;
@@ -117,7 +119,6 @@ static int bus_scope_set_transient_property(
 
         } else if (streq(name, "Controller")) {
                 const char *controller;
-                char *c;
 
                 /* We can't support direct connections with this, as direct connections know no service or unique name
                  * concept, but the Controller field stores exactly that. */
@@ -131,33 +132,25 @@ static int bus_scope_set_transient_property(
                 if (!isempty(controller) && !service_name_is_valid(controller))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Controller '%s' is not a valid bus name.", controller);
 
-                if (mode != UNIT_CHECK) {
-                        if (isempty(controller))
-                                c = NULL;
-                        else {
-                                c = strdup(controller);
-                                if (!c)
-                                        return -ENOMEM;
-                        }
-
-                        free(s->controller);
-                        s->controller = c;
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        r = free_and_strdup(&s->controller, empty_to_null(controller));
+                        if (r < 0)
+                                return r;
                 }
 
                 return 1;
 
         } else if (streq(name, "TimeoutStopUSec")) {
+                uint64_t t;
 
-                if (mode != UNIT_CHECK) {
-                        r = sd_bus_message_read(message, "t", &s->timeout_stop_usec);
-                        if (r < 0)
-                                return r;
+                r = sd_bus_message_read(message, "t", &t);
+                if (r < 0)
+                        return r;
 
-                        unit_write_drop_in_private_format(UNIT(s), mode, name, "TimeoutStopSec="USEC_FMT"us", s->timeout_stop_usec);
-                } else {
-                        r = sd_bus_message_skip(message, "t");
-                        if (r < 0)
-                                return r;
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        s->timeout_stop_usec = t;
+
+                        unit_write_settingf(UNIT(s), flags, name, "TimeoutStopSec=" USEC_FMT "us", t);
                 }
 
                 return 1;
@@ -170,7 +163,7 @@ int bus_scope_set_property(
                 Unit *u,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         Scope *s = SCOPE(u);
@@ -180,18 +173,18 @@ int bus_scope_set_property(
         assert(name);
         assert(message);
 
-        r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
+        r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
         if (r != 0)
                 return r;
 
         if (u->load_state == UNIT_STUB) {
                 /* While we are created we still accept PIDs */
 
-                r = bus_scope_set_transient_property(s, name, message, mode, error);
+                r = bus_scope_set_transient_property(s, name, message, flags, error);
                 if (r != 0)
                         return r;
 
-                r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error);
+                r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, flags, error);
                 if (r != 0)
                         return r;
         }
index c80317c..aa60489 100644 (file)
@@ -26,7 +26,7 @@
 
 extern const sd_bus_vtable bus_scope_vtable[];
 
-int bus_scope_set_property(Unit *u, const char *name, sd_bus_message *i, UnitSetPropertiesMode mode, sd_bus_error *error);
+int bus_scope_set_property(Unit *u, const char *name, sd_bus_message *i, UnitWriteFlags flags, sd_bus_error *error);
 int bus_scope_commit_properties(Unit *u);
 
 int bus_scope_send_request_stop(Scope *s);
index 7b6cb39..593094e 100644 (file)
@@ -90,7 +90,7 @@ static int bus_service_set_transient_property(
                 Service *s,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         int r;
@@ -99,6 +99,8 @@ static int bus_service_set_transient_property(
         assert(name);
         assert(message);
 
+        flags |= UNIT_PRIVATE;
+
         if (streq(name, "RemainAfterExit")) {
                 int b;
 
@@ -106,9 +108,9 @@ static int bus_service_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         s->remain_after_exit = b;
-                        unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s", yes_no(b));
+                        unit_write_settingf(UNIT(s), flags, name, "RemainAfterExit=%s", yes_no(b));
                 }
 
                 return 1;
@@ -125,9 +127,9 @@ static int bus_service_set_transient_property(
                 if (k < 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service type %s", t);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         s->type = k;
-                        unit_write_drop_in_private_format(UNIT(s), mode, name, "Type=%s", service_type_to_string(s->type));
+                        unit_write_settingf(UNIT(s), flags, name, "Type=%s", service_type_to_string(s->type));
                 }
 
                 return 1;
@@ -138,9 +140,9 @@ static int bus_service_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         s->runtime_max_usec = u;
-                        unit_write_drop_in_private_format(UNIT(s), mode, name, "RuntimeMaxSec=" USEC_FMT "us", u);
+                        unit_write_settingf(UNIT(s), flags, name, "RuntimeMaxSec=" USEC_FMT "us", u);
                 }
 
                 return 1;
@@ -161,9 +163,9 @@ static int bus_service_set_transient_property(
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid restart setting: %s", v);
                 }
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         s->restart = sr;
-                        unit_write_drop_in_private_format(UNIT(s), mode, name, "Restart=%s", service_restart_to_string(sr));
+                        unit_write_settingf(UNIT(s), flags, name, "Restart=%s", service_restart_to_string(sr));
                 }
 
                 return 1;
@@ -178,7 +180,7 @@ static int bus_service_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         int copy;
 
                         copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
@@ -208,9 +210,9 @@ static int bus_service_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         s->n_fd_store_max = (unsigned) u;
-                        unit_write_drop_in_private_format(UNIT(s), mode, name, "FileDescriptorStoreMax=%" PRIu32, u);
+                        unit_write_settingf(UNIT(s), flags, name, "FileDescriptorStoreMax=%" PRIu32, u);
                 }
 
                 return 1;
@@ -227,9 +229,9 @@ static int bus_service_set_transient_property(
                 if (k < 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid notify access setting %s", t);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         s->notify_access = k;
-                        unit_write_drop_in_private_format(UNIT(s), mode, name, "NotifyAccess=%s", notify_access_to_string(s->notify_access));
+                        unit_write_settingf(UNIT(s), flags, name, "NotifyAccess=%s", notify_access_to_string(s->notify_access));
                 }
 
                 return 1;
@@ -265,7 +267,7 @@ static int bus_service_set_transient_property(
                         if (r < 0)
                                 return r;
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 ExecCommand *c;
 
                                 c = new0(ExecCommand, 1);
@@ -297,7 +299,7 @@ static int bus_service_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *buf = NULL;
                         _cleanup_fclose_ FILE *f = NULL;
                         ExecCommand *c;
@@ -313,22 +315,28 @@ static int bus_service_set_transient_property(
                         fputs_unlocked("ExecStart=\n", f);
 
                         LIST_FOREACH(command, c, s->exec_command[SERVICE_EXEC_START]) {
-                                _cleanup_free_ char *a;
+                                _cleanup_free_ char *a = NULL, *t = NULL;
+                                const char *p;
+
+                                p = unit_escape_setting(c->path, UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS, &t);
+                                if (!p)
+                                        return -ENOMEM;
 
-                                a = strv_join_quoted(c->argv);
+                                a = unit_concat_strv(c->argv, UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS);
                                 if (!a)
                                         return -ENOMEM;
 
                                 fprintf(f, "ExecStart=%s@%s %s\n",
                                         c->flags & EXEC_COMMAND_IGNORE_FAILURE ? "-" : "",
-                                        c->path,
+                                        p,
                                         a);
                         }
 
                         r = fflush_and_check(f);
                         if (r < 0)
                                 return r;
-                        unit_write_drop_in_private(UNIT(s), mode, name, buf);
+
+                        unit_write_setting(UNIT(s), flags, name, buf);
                 }
 
                 return 1;
@@ -341,7 +349,7 @@ int bus_service_set_property(
                 Unit *u,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         Service *s = SERVICE(u);
@@ -351,22 +359,22 @@ int bus_service_set_property(
         assert(name);
         assert(message);
 
-        r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
+        r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
         if (r != 0)
                 return r;
 
         if (u->transient && u->load_state == UNIT_STUB) {
                 /* This is a transient unit, let's load a little more */
 
-                r = bus_service_set_transient_property(s, name, message, mode, error);
+                r = bus_service_set_transient_property(s, name, message, flags, error);
                 if (r != 0)
                         return r;
 
-                r = bus_exec_context_set_transient_property(u, &s->exec_context, name, message, mode, error);
+                r = bus_exec_context_set_transient_property(u, &s->exec_context, name, message, flags, error);
                 if (r != 0)
                         return r;
 
-                r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error);
+                r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, flags, error);
                 if (r != 0)
                         return r;
         }
index a0f89fa..2da29ec 100644 (file)
@@ -26,5 +26,5 @@
 
 extern const sd_bus_vtable bus_service_vtable[];
 
-int bus_service_set_property(Unit *u, const char *name, sd_bus_message *i, UnitSetPropertiesMode mode, sd_bus_error *error);
+int bus_service_set_property(Unit *u, const char *name, sd_bus_message *i, UnitWriteFlags flags, sd_bus_error *error);
 int bus_service_commit_properties(Unit *u);
index d269cb2..fa2ff72 100644 (file)
@@ -32,7 +32,7 @@ int bus_slice_set_property(
                 Unit *u,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         Slice *s = SLICE(u);
@@ -40,7 +40,7 @@ int bus_slice_set_property(
         assert(name);
         assert(u);
 
-        return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
+        return bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
 }
 
 int bus_slice_commit_properties(Unit *u) {
index 5855332..0c21919 100644 (file)
@@ -26,5 +26,5 @@
 
 extern const sd_bus_vtable bus_slice_vtable[];
 
-int bus_slice_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
+int bus_slice_set_property(Unit *u, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 int bus_slice_commit_properties(Unit *u);
index 3c7d99c..930b7fa 100644 (file)
@@ -166,7 +166,7 @@ int bus_socket_set_property(
                 Unit *u,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         Socket *s = SOCKET(u);
@@ -175,7 +175,7 @@ int bus_socket_set_property(
         assert(name);
         assert(message);
 
-        return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
+        return bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
 }
 
 int bus_socket_commit_properties(Unit *u) {
index ee9663f..e6db2d0 100644 (file)
@@ -26,5 +26,5 @@
 
 extern const sd_bus_vtable bus_socket_vtable[];
 
-int bus_socket_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
+int bus_socket_set_property(Unit *u, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 int bus_socket_commit_properties(Unit *u);
index ae67f3e..795aaa9 100644 (file)
@@ -96,7 +96,7 @@ int bus_swap_set_property(
                 Unit *u,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         Swap *s = SWAP(u);
@@ -105,7 +105,7 @@ int bus_swap_set_property(
         assert(name);
         assert(message);
 
-        return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
+        return bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
 }
 
 int bus_swap_commit_properties(Unit *u) {
index 7df5cc7..6cca748 100644 (file)
@@ -27,5 +27,5 @@
 
 extern const sd_bus_vtable bus_swap_vtable[];
 
-int bus_swap_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
+int bus_swap_set_property(Unit *u, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 int bus_swap_commit_properties(Unit *u);
index 282d7f6..e440320 100644 (file)
@@ -176,7 +176,7 @@ static int bus_timer_set_transient_property(
                 Timer *t,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         int r;
@@ -185,6 +185,8 @@ static int bus_timer_set_transient_property(
         assert(name);
         assert(message);
 
+        flags |= UNIT_PRIVATE;
+
         if (STR_IN_SET(name,
                        "OnActiveSec",
                        "OnBootSec",
@@ -204,10 +206,10 @@ static int bus_timer_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         char time[FORMAT_TIMESPAN_MAX];
 
-                        unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
+                        unit_write_settingf(UNIT(t), flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
 
                         v = new0(TimerValue, 1);
                         if (!v)
@@ -231,12 +233,12 @@ static int bus_timer_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         r = calendar_spec_from_string(str, &c);
                         if (r < 0)
                                 return r;
 
-                        unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s", name, str);
+                        unit_write_settingf(UNIT(t), flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, str);
 
                         v = new0(TimerValue, 1);
                         if (!v) {
@@ -262,9 +264,9 @@ static int bus_timer_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         t->accuracy_usec = u;
-                        unit_write_drop_in_private_format(UNIT(t), mode, name, "AccuracySec=" USEC_FMT "us", u);
+                        unit_write_settingf(UNIT(t), flags, name, "AccuracySec=" USEC_FMT "us", u);
                 }
 
                 return 1;
@@ -276,9 +278,9 @@ static int bus_timer_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         t->random_usec = u;
-                        unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=" USEC_FMT "us", u);
+                        unit_write_settingf(UNIT(t), flags, name, "RandomizedDelaySec=" USEC_FMT "us", u);
                 }
 
                 return 1;
@@ -290,9 +292,9 @@ static int bus_timer_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         t->wake_system = b;
-                        unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s", name, yes_no(b));
+                        unit_write_settingf(UNIT(t), flags, name, "%s=%s", name, yes_no(b));
                 }
 
                 return 1;
@@ -304,9 +306,9 @@ static int bus_timer_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         t->remain_after_elapse = b;
-                        unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s", name, yes_no(b));
+                        unit_write_settingf(UNIT(t), flags, name, "%s=%s", name, yes_no(b));
                 }
 
                 return 1;
@@ -319,21 +321,17 @@ int bus_timer_set_property(
                 Unit *u,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags mode,
                 sd_bus_error *error) {
 
         Timer *t = TIMER(u);
-        int r;
 
         assert(t);
         assert(name);
         assert(message);
 
-        if (u->transient && u->load_state == UNIT_STUB) {
-                r = bus_timer_set_transient_property(t, name, message, mode, error);
-                if (r != 0)
-                        return r;
-        }
+        if (u->transient && u->load_state == UNIT_STUB)
+                return bus_timer_set_transient_property(t, name, message, mode, error);
 
         return 0;
 }
index e71f6cf..d810b04 100644 (file)
@@ -26,4 +26,4 @@
 
 extern const sd_bus_vtable bus_timer_vtable[];
 
-int bus_timer_set_property(Unit *u, const char *name, sd_bus_message *i, UnitSetPropertiesMode mode, sd_bus_error *error);
+int bus_timer_set_property(Unit *u, const char *name, sd_bus_message *i, UnitWriteFlags flags, sd_bus_error *error);
index d4bdf17..5d4bc28 100644 (file)
@@ -1319,7 +1319,7 @@ static int bus_unit_set_transient_property(
                 Unit *u,
                 const char *name,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 sd_bus_error *error) {
 
         int r;
@@ -1335,12 +1335,12 @@ static int bus_unit_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         r = unit_set_description(u, d);
                         if (r < 0)
                                 return r;
 
-                        unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s", d);
+                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "Description=%s", d);
                 }
 
                 return 1;
@@ -1352,9 +1352,9 @@ static int bus_unit_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         u->default_dependencies = b;
-                        unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s", yes_no(b));
+                        unit_write_settingf(u, flags, name, "DefaultDependencies=%s", yes_no(b));
                 }
 
                 return 1;
@@ -1371,9 +1371,9 @@ static int bus_unit_set_transient_property(
                 if (m < 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown garbage collection mode: %s", s);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         u->collect_mode = m;
-                        unit_write_drop_in_format(u, mode, name, "[Unit]\nCollectMode=%s", collect_mode_to_string(m));
+                        unit_write_settingf(u, flags, name, "CollectMode=%s", collect_mode_to_string(m));
                 }
 
                 return 1;
@@ -1406,12 +1406,12 @@ static int bus_unit_set_transient_property(
                 if (slice->type != UNIT_SLICE)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         r = unit_set_slice(u, slice);
                         if (r < 0)
                                 return r;
 
-                        unit_write_drop_in_private_format(u, mode, name, "Slice=%s", s);
+                        unit_write_settingf(u, flags|UNIT_PRIVATE, name, "Slice=%s", s);
                 }
 
                 return 1;
@@ -1448,7 +1448,7 @@ static int bus_unit_set_transient_property(
                         if (!unit_name_is_valid(other, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
 
-                        if (mode != UNIT_CHECK) {
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 _cleanup_free_ char *label = NULL;
 
                                 r = unit_add_dependency_by_name(u, d, other, NULL, true, UNIT_DEPENDENCY_FILE);
@@ -1459,7 +1459,7 @@ static int bus_unit_set_transient_property(
                                 if (!label)
                                         return -ENOMEM;
 
-                                unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s", name, other);
+                                unit_write_settingf(u, flags, label, "%s=%s", name, other);
                         }
 
                 }
@@ -1484,14 +1484,14 @@ static int bus_unit_set_transient_property(
                 if (action < 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid emergency action: %s", s);
 
-                if (mode != UNIT_CHECK) {
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
 
                         if (streq(name, "FailureAction"))
                                 u->failure_action = action;
                         else
                                 u->success_action = action;
 
-                        unit_write_drop_in_format(u, mode, name, "%s=%s", name, emergency_action_to_string(action));
+                        unit_write_settingf(u, flags, name, "%s=%s", name, emergency_action_to_string(action));
                 }
 
                 return 1;
@@ -1514,7 +1514,7 @@ static int bus_unit_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (mode != UNIT_CHECK)
+                if (!UNIT_WRITE_FLAGS_NOOP(flags))
                         u->bus_track_add = b;
 
                 return 1;
@@ -1526,7 +1526,7 @@ static int bus_unit_set_transient_property(
 int bus_unit_set_properties(
                 Unit *u,
                 sd_bus_message *message,
-                UnitSetPropertiesMode mode,
+                UnitWriteFlags flags,
                 bool commit,
                 sd_bus_error *error) {
 
@@ -1548,12 +1548,13 @@ int bus_unit_set_properties(
 
         for (;;) {
                 const char *name;
+                UnitWriteFlags f;
 
                 r = sd_bus_message_enter_container(message, 'r', "sv");
                 if (r < 0)
                         return r;
                 if (r == 0) {
-                        if (for_real || mode == UNIT_CHECK)
+                        if (for_real || UNIT_WRITE_FLAGS_NOOP(flags))
                                 break;
 
                         /* Reached EOF. Let's try again, and this time for realz... */
@@ -1576,9 +1577,12 @@ int bus_unit_set_properties(
                 if (r < 0)
                         return r;
 
-                r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
+                /* If not for real, then mask out the two target flags */
+                f = for_real ? flags : (flags & ~(UNIT_RUNTIME|UNIT_PERSISTENT));
+
+                r = UNIT_VTABLE(u)->bus_set_property(u, name, message, f, error);
                 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
-                        r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
+                        r = bus_unit_set_transient_property(u, name, message, f, error);
                 if (r < 0)
                         return r;
                 if (r == 0)
index b723453..d7066ee 100644 (file)
@@ -34,7 +34,7 @@ int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_
 int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error);
 
-int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error);
+int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitWriteFlags flags, bool commit, sd_bus_error *error);
 int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error);
index 8569398..90a09ce 100644 (file)
@@ -55,6 +55,7 @@
 #include "signal-util.h"
 #include "sparse-endian.h"
 #include "special.h"
+#include "specifier.h"
 #include "stat-util.h"
 #include "stdio-util.h"
 #include "string-table.h"
@@ -117,6 +118,8 @@ Unit *unit_new(Manager *m, size_t size) {
         u->ipv4_deny_map_fd = -1;
         u->ipv6_deny_map_fd = -1;
 
+        u->last_section_private = -1;
+
         RATELIMIT_INIT(u->start_limit, m->default_start_limit_interval, m->default_start_limit_burst);
         RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16);
 
@@ -4120,43 +4123,156 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) {
         return *(ExecRuntime**) ((uint8_t*) u + offset);
 }
 
-static const char* unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode) {
+static const char* unit_drop_in_dir(Unit *u, UnitWriteFlags flags) {
         assert(u);
 
-        if (!IN_SET(mode, UNIT_RUNTIME, UNIT_PERSISTENT))
+        if (UNIT_WRITE_FLAGS_NOOP(flags))
                 return NULL;
 
         if (u->transient) /* Redirect drop-ins for transient units always into the transient directory. */
                 return u->manager->lookup_paths.transient;
 
-        if (mode == UNIT_RUNTIME)
-                return u->manager->lookup_paths.runtime_control;
-
-        if (mode == UNIT_PERSISTENT)
+        if (flags & UNIT_PERSISTENT)
                 return u->manager->lookup_paths.persistent_control;
 
+        if (flags & UNIT_RUNTIME)
+                return u->manager->lookup_paths.runtime_control;
+
         return NULL;
 }
 
-int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
-        _cleanup_free_ char *p = NULL, *q = NULL;
+char* unit_escape_setting(const char *s, UnitWriteFlags flags, char **buf) {
+        char *ret = NULL;
+
+        if (!s)
+                return NULL;
+
+        /* Escapes the input string as requested. Returns the escaped string. If 'buf' is specified then the allocated
+         * return buffer pointer is also written to *buf, except if no escaping was necessary, in which case *buf is
+         * set to NULL, and the input pointer is returned as-is. This means the return value always contains a properly
+         * escaped version, but *buf when passed only contains a pointer if an allocation was necessary. If *buf is
+         * not specified, then the return value always needs to be freed. Callers can use this to optimize memory
+         * allocations. */
+
+        if (flags & UNIT_ESCAPE_SPECIFIERS) {
+                ret = specifier_escape(s);
+                if (!ret)
+                        return NULL;
+
+                s = ret;
+        }
+
+        if (flags & UNIT_ESCAPE_C) {
+                char *a;
+
+                a = cescape(s);
+                free(ret);
+                if (!a)
+                        return NULL;
+
+                ret = a;
+        }
+
+        if (buf) {
+                *buf = ret;
+                return ret ?: (char*) s;
+        }
+
+        return ret ?: strdup(s);
+}
+
+char* unit_concat_strv(char **l, UnitWriteFlags flags) {
+        _cleanup_free_ char *result = NULL;
+        size_t n = 0, allocated = 0;
+        char **i, *ret;
+
+        /* Takes a list of strings, escapes them, and concatenates them. This may be used to format command lines in a
+         * way suitable for ExecStart= stanzas */
+
+        STRV_FOREACH(i, l) {
+                _cleanup_free_ char *buf = NULL;
+                const char *p;
+                size_t a;
+                char *q;
+
+                p = unit_escape_setting(*i, flags, &buf);
+                if (!p)
+                        return NULL;
+
+                a = (n > 0) + 1 + strlen(p) + 1; /* separating space + " + entry + " */
+                if (!GREEDY_REALLOC(result, allocated, n + a + 1))
+                        return NULL;
+
+                q = result + n;
+                if (n > 0)
+                        *(q++) = ' ';
+
+                *(q++) = '"';
+                q = stpcpy(q, p);
+                *(q++) = '"';
+
+                n += a;
+        }
+
+        if (!GREEDY_REALLOC(result, allocated, n + 1))
+                return NULL;
+
+        result[n] = 0;
+
+        ret = result;
+        result = NULL;
+
+        return ret;
+}
+
+int unit_write_setting(Unit *u, UnitWriteFlags flags, const char *name, const char *data) {
+        _cleanup_free_ char *p = NULL, *q = NULL, *escaped = NULL;
         const char *dir, *wrapped;
         int r;
 
         assert(u);
+        assert(name);
+        assert(data);
+
+        if (UNIT_WRITE_FLAGS_NOOP(flags))
+                return 0;
+
+        data = unit_escape_setting(data, flags, &escaped);
+        if (!data)
+                return -ENOMEM;
+
+        /* Prefix the section header. If we are writing this out as transient file, then let's suppress this if the
+         * previous section header is the same */
+
+        if (flags & UNIT_PRIVATE) {
+                if (!UNIT_VTABLE(u)->private_section)
+                        return -EINVAL;
+
+                if (!u->transient_file || u->last_section_private < 0)
+                        data = strjoina("[", UNIT_VTABLE(u)->private_section, "]\n", data);
+                else if (u->last_section_private == 0)
+                        data = strjoina("\n[", UNIT_VTABLE(u)->private_section, "]\n", data);
+        } else {
+                if (!u->transient_file || u->last_section_private < 0)
+                        data = strjoina("[Unit]\n", data);
+                else if (u->last_section_private > 0)
+                        data = strjoina("\n[Unit]\n", data);
+        }
 
         if (u->transient_file) {
                 /* When this is a transient unit file in creation, then let's not create a new drop-in but instead
                  * write to the transient unit file. */
                 fputs(data, u->transient_file);
-                fputc('\n', u->transient_file);
-                return 0;
-        }
 
-        if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
+                if (!endswith(data, "\n"))
+                        fputc('\n', u->transient_file);
+
+                /* Remember which section we wrote this entry to */
+                u->last_section_private = !!(flags & UNIT_PRIVATE);
                 return 0;
+        }
 
-        dir = unit_drop_in_dir(u, mode);
+        dir = unit_drop_in_dir(u, flags);
         if (!dir)
                 return -EINVAL;
 
@@ -4186,47 +4302,7 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co
         return 0;
 }
 
-int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) {
-        _cleanup_free_ char *p = NULL;
-        va_list ap;
-        int r;
-
-        assert(u);
-        assert(name);
-        assert(format);
-
-        if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
-                return 0;
-
-        va_start(ap, format);
-        r = vasprintf(&p, format, ap);
-        va_end(ap);
-
-        if (r < 0)
-                return -ENOMEM;
-
-        return unit_write_drop_in(u, mode, name, p);
-}
-
-int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
-        const char *ndata;
-
-        assert(u);
-        assert(name);
-        assert(data);
-
-        if (!UNIT_VTABLE(u)->private_section)
-                return -EINVAL;
-
-        if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
-                return 0;
-
-        ndata = strjoina("[", UNIT_VTABLE(u)->private_section, "]\n", data);
-
-        return unit_write_drop_in(u, mode, name, ndata);
-}
-
-int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) {
+int unit_write_settingf(Unit *u, UnitWriteFlags flags, const char *name, const char *format, ...) {
         _cleanup_free_ char *p = NULL;
         va_list ap;
         int r;
@@ -4235,7 +4311,7 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const
         assert(name);
         assert(format);
 
-        if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
+        if (UNIT_WRITE_FLAGS_NOOP(flags))
                 return 0;
 
         va_start(ap, format);
@@ -4245,7 +4321,7 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const
         if (r < 0)
                 return -ENOMEM;
 
-        return unit_write_drop_in_private(u, mode, name, p);
+        return unit_write_setting(u, flags, name, p);
 }
 
 int unit_make_transient(Unit *u) {
index cd7c08a..92bb477 100644 (file)
@@ -360,6 +360,10 @@ struct Unit {
         bool exported_invocation_id:1;
         bool exported_log_level_max:1;
         bool exported_log_extra_fields:1;
+
+        /* When writing transient unit files, stores which section we stored last. If < 0, we didn't write any yet. If
+         * == 0 we are in the [Unit] section, if > 0 we are in the unit type-specific section. */
+        int last_section_private:2;
 };
 
 struct UnitStatusMessageFormats {
@@ -368,11 +372,26 @@ struct UnitStatusMessageFormats {
         const char *finished_stop_job[_JOB_RESULT_MAX];
 };
 
-typedef enum UnitSetPropertiesMode {
-        UNIT_CHECK = 0,
-        UNIT_RUNTIME = 1,
-        UNIT_PERSISTENT = 2,
-} UnitSetPropertiesMode;
+/* Flags used when writing drop-in files or transient unit files */
+typedef enum UnitWriteFlags {
+        /* Write a runtime unit file or drop-in (i.e. one below /run) */
+        UNIT_RUNTIME           = 1 << 0,
+
+        /* Write a persistent drop-in (i.e. one below /etc) */
+        UNIT_PERSISTENT        = 1 << 1,
+
+        /* Place this item in the per-unit-type private section, instead of [Unit] */
+        UNIT_PRIVATE           = 1 << 2,
+
+        /* Apply specifier escaping before writing */
+        UNIT_ESCAPE_SPECIFIERS = 1 << 3,
+
+        /* Apply C escaping before writing */
+        UNIT_ESCAPE_C          = 1 << 4,
+} UnitWriteFlags;
+
+/* Returns true if neither persistent, nor runtime storage is requested, i.e. this is a check invocation only */
+#define UNIT_WRITE_FLAGS_NOOP(flags) (((flags) & (UNIT_RUNTIME|UNIT_PERSISTENT)) == 0)
 
 #include "automount.h"
 #include "device.h"
@@ -490,7 +509,7 @@ struct UnitVTable {
         void (*bus_name_owner_change)(Unit *u, const char *name, const char *old_owner, const char *new_owner);
 
         /* Called for each property that is being set */
-        int (*bus_set_property)(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
+        int (*bus_set_property)(Unit *u, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 
         /* Called after at least one property got changed to apply the necessary change */
         int (*bus_commit_properties)(Unit *u);
@@ -713,11 +732,11 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) _pure_;
 int unit_setup_exec_runtime(Unit *u);
 int unit_setup_dynamic_creds(Unit *u);
 
-int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data);
-int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5);
+char* unit_escape_setting(const char *s, UnitWriteFlags flags, char **buf);
+char* unit_concat_strv(char **l, UnitWriteFlags flags);
 
-int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data);
-int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5);
+int unit_write_setting(Unit *u, UnitWriteFlags flags, const char *name, const char *data);
+int unit_write_settingf(Unit *u, UnitWriteFlags mode, const char *name, const char *format, ...) _printf_(4,5);
 
 int unit_kill_context(Unit *u, KillContext *c, KillOperation k, pid_t main_pid, pid_t control_pid, bool main_pid_alien);