]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #18481 from keszybz/rpm-restart-post-trans
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 16 Feb 2021 07:25:49 +0000 (08:25 +0100)
committerGitHub <noreply@github.com>
Tue, 16 Feb 2021 07:25:49 +0000 (08:25 +0100)
Restart units after the rpm transaction

41 files changed:
man/org.freedesktop.systemd1.xml
man/sd_bus_message_read_strv.xml
man/systemctl.xml
meson.build
src/analyze/analyze-verify.c
src/analyze/analyze.c
src/basic/unit-def.c
src/basic/unit-def.h
src/busctl/busctl.c
src/core/dbus-manager.c
src/core/dbus-unit.c
src/core/dbus-unit.h
src/core/execute.c
src/core/fuzz-unit-file.c
src/core/manager.c
src/core/meson.build
src/core/unit-serialize.c [new file with mode: 0644]
src/core/unit-serialize.h [new file with mode: 0644]
src/core/unit.c
src/core/unit.h
src/libsystemd/sd-bus/bus-message.c
src/libsystemd/sd-bus/test-bus-objects.c
src/rpm/macros.systemd.in [moved from src/core/macros.systemd.in with 97% similarity]
src/rpm/meson.build [new file with mode: 0644]
src/rpm/triggers.systemd.in [moved from src/core/triggers.systemd.in with 73% similarity]
src/rpm/triggers.systemd.sh.in [new file with mode: 0644]
src/shared/bus-unit-util.c
src/systemctl/systemctl-is-active.c
src/systemctl/systemctl-is-enabled.c
src/systemctl/systemctl-list-dependencies.c
src/systemctl/systemctl-list-jobs.c
src/systemctl/systemctl-list-machines.c
src/systemctl/systemctl-list-unit-files.c
src/systemctl/systemctl-list-units.c
src/systemctl/systemctl-show.c
src/systemctl/systemctl-start-unit.c
src/systemctl/systemctl-util.c
src/systemctl/systemctl.c
src/systemctl/systemctl.h
src/test/test-bpf-firewall.c
src/udev/test-udev-builtin.c

index 1d419ac495e19f51b556c71b4ecf17a38ddaa638..2da0ff0579d529e723fe2ae5dadc20903b7bceec 100644 (file)
@@ -176,6 +176,7 @@ node /org/freedesktop/systemd1 {
       UnsetEnvironment(in  as names);
       UnsetAndSetEnvironment(in  as names,
                              in  as assignments);
+      EnqueueMarkedJobs(out ao jobs);
       ListUnitFiles(out a(ss) unit_files);
       ListUnitFilesByPatterns(in  as states,
                               in  as patterns,
@@ -848,6 +849,8 @@ node /org/freedesktop/systemd1 {
 
     <variablelist class="dbus-method" generated="True" extra-ref="UnsetAndSetEnvironment()"/>
 
+    <variablelist class="dbus-method" generated="True" extra-ref="EnqueueMarkedJobs()"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="ListUnitFiles()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="ListUnitFilesByPatterns()"/>
@@ -1171,6 +1174,11 @@ node /org/freedesktop/systemd1 {
       the "Try" flavor is used in which case a service that isn't running is not affected by the restart. The
       "ReloadOrRestart" flavors attempt a reload if the unit supports it and use a restart otherwise.</para>
 
+      <para><function>EnqueueMarkedJobs()</function> creates reload/restart jobs for units which have been
+      appropriately marked, see <varname>Marks</varname> property above. This is equivalent to calling
+      <function>TryRestartUnit()</function> or <function>ReloadOrTryRestartUnit()</function> for the marked
+      units.</para>
+
       <para><function>BindMountUnit()</function> can be used to bind mount new files or directories into
       a running service mount namespace.</para>
 
@@ -1685,6 +1693,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       readonly b IgnoreOnIsolate = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly b NeedDaemonReload = ...;
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly as Markers = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly t JobTimeoutUSec = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -1969,6 +1979,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="NeedDaemonReload"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="Markers"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="JobTimeoutUSec"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="JobRunningTimeoutUSec"/>
@@ -2160,8 +2172,16 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
       <para><varname>NeedDaemonReload</varname> is a boolean that indicates whether the configuration file
       this unit is loaded from (i.e. <varname>FragmentPath</varname> or <varname>SourcePath</varname>) has
-      changed since the configuration was read and hence whether a configuration reload is
-      recommended.</para>
+      changed since the configuration was read and hence whether a configuration reload is recommended.
+      </para>
+
+      <para><varname>Markers</varname> is an array of string flags that can be set using
+      <function>SetUnitProperties()</function> to indicate that the service should be reloaded or
+      restarted. Currently known values are <literal>needs-restart</literal> and
+      <literal>needs-reload</literal>. Package scripts may use the first to mark units for later restart when
+      a new version of the package is installed. Configuration management scripts may use the second to mark
+      units for a later reload when the configuration is adjusted. Those flags are not set by the manager,
+      except to unset as appropriate when when the unit is stopped, restarted, or reloaded.</para>
 
       <para><varname>JobTimeoutUSec</varname> maps directly to the corresponding configuration setting in the
       unit file.</para>
index a90ae84098395122209936ea8094155bf02cac1a..50580d86bcc5cd27bb6c7c68ebc202ef6d3e410f 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <para><function>sd_bus_message_read_strv()</function> gives access to an array of strings in message
-    <parameter>m</parameter>. The "read pointer" in the message must be right before an array of strings. On
-    success, a pointer to the <constant>NULL</constant>-terminated array of strings is returned in the output
-    parameter <parameter>l</parameter>. Note that ownership of this array is transferred to the caller.
-    Hence, the caller is responsible for freeing this array and its contents.</para>
+    <para><function>sd_bus_message_read_strv()</function> gives access to an array of string-like items in
+    message <parameter>m</parameter>. The "read pointer" in the message must be right before an array of
+    strings (D-Bus type <literal>as</literal>), object paths (D-Bus type <literal>ao</literal>), or
+    signatures (D-Bus type <literal>ag</literal>). On success, a pointer to a
+    <constant>NULL</constant>-terminated array of strings is returned in the output parameter
+    <parameter>l</parameter>. Note that ownership of this array is transferred to the caller. Hence, the
+    caller is responsible for freeing this array and its contents.</para>
   </refsect1>
 
   <refsect1>
 
           <listitem><para>The message cannot be parsed.</para></listitem>
         </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
+
+          <listitem><para>The message "read pointer" is not right before an array of the appropriate type.
+          </para></listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
   </refsect1>
index 2ed58eb33be95a3d64d14efdc8cb4589dceabc19..be414ebb1e47d80aa6cdad38729fcbff8b4f3c8c 100644 (file)
@@ -2304,6 +2304,18 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
         a directory, but a regular file, device node, socket or FIFO.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--marked</option></term>
+
+        <listitem><para>Only allowed with <command>reload-or-restart</command>. Enqueues restart jobs for all
+        units that have the <literal>needs-restart</literal> mark, and reload jobs for units that have the
+        <literal>needs-reload</literal> mark. When a unit marked for reload does not support reload, restart
+        will be queued. Those properties can be set using <command>set-property Marks</command>.</para>
+
+        <para>Unless <option>--no-block</option> is used, <command>systemctl</command> will wait for the
+        queued jobs to finish.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--read-only</option></term>
 
index 09d8122091dc55cafda6060257227d4ee89510cb..226dc90f9e7290a8059b34af7f3cb21dc4d7c9b2 100644 (file)
@@ -1746,6 +1746,7 @@ subdir('src/partition')
 subdir('src/portable')
 subdir('src/pstore')
 subdir('src/resolve')
+subdir('src/rpm')
 subdir('src/shutdown')
 subdir('src/sysext')
 subdir('src/systemctl')
index bf28624d41f6d0fe7bd136c33319dd2b07e56e09..1b06e0701932b88e23c6d44fb2124cd68d24e36e 100644 (file)
@@ -13,6 +13,7 @@
 #include "path-util.h"
 #include "strv.h"
 #include "unit-name.h"
+#include "unit-serialize.h"
 
 static int prepare_filename(const char *filename, char **ret) {
         int r;
index c25d11e0de356824cd2cb47f42d9e3dff7d3c5d2..72ebd25525cfba65785eb311ee1deee727d669da 100644 (file)
@@ -1277,7 +1277,7 @@ static int dot(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, "");
+        r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, NULL);
         if (r < 0)
                 log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
 
index bb4fa1ec6bf31daf0368475e12579309c0f3fe82..6fbb947f096dab7146b7517cd2cb9f43c0f8529b 100644 (file)
@@ -117,6 +117,13 @@ static const char* const freezer_state_table[_FREEZER_STATE_MAX] = {
 
 DEFINE_STRING_TABLE_LOOKUP(freezer_state, FreezerState);
 
+static const char* const unit_marker_table[_UNIT_MARKER_MAX] = {
+        [UNIT_MARKER_NEEDS_RELOAD]  = "needs-reload",
+        [UNIT_MARKER_NEEDS_RESTART] = "needs-restart",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_marker, UnitMarker);
+
 static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
         [AUTOMOUNT_DEAD] = "dead",
         [AUTOMOUNT_WAITING] = "waiting",
index ff05799c1d54bc788dc7daa722f12b88ffcd0ab0..7742c5c078593e2ce4c8c264944b8378b51e2f14 100644 (file)
@@ -58,6 +58,13 @@ typedef enum FreezerState {
         _FREEZER_STATE_INVALID = -EINVAL,
 } FreezerState;
 
+typedef enum UnitMarker {
+        UNIT_MARKER_NEEDS_RELOAD,
+        UNIT_MARKER_NEEDS_RESTART,
+        _UNIT_MARKER_MAX,
+        _UNIT_MARKER_INVALID = -1
+} UnitMarker;
+
 typedef enum AutomountState {
         AUTOMOUNT_DEAD,
         AUTOMOUNT_WAITING,
@@ -267,6 +274,9 @@ UnitActiveState unit_active_state_from_string(const char *s) _pure_;
 const char *freezer_state_to_string(FreezerState i) _const_;
 FreezerState freezer_state_from_string(const char *s) _pure_;
 
+const char *unit_marker_to_string(UnitMarker m) _const_;
+UnitMarker unit_marker_from_string(const char *s) _pure_;
+
 const char* automount_state_to_string(AutomountState i) _const_;
 AutomountState automount_state_from_string(const char *s) _pure_;
 
index 6a492ebd02f4175d6fc08a085ce6e32cf32c2644..142aba0b92828ee800fa4b92faeb87fb124075b6 100644 (file)
@@ -443,7 +443,7 @@ static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *p
 
         r = sd_bus_call_method(bus, service, path,
                                "org.freedesktop.DBus.Introspectable", "Introspect",
-                               &error, &reply, "");
+                               &error, &reply, NULL);
         if (r < 0) {
                 printf("%sFailed to introspect object %s of service %s: %s%s\n",
                        ansi_highlight_red(),
@@ -982,7 +982,7 @@ static int introspect(int argc, char **argv, void *userdata) {
 
         r = sd_bus_call_method(bus, argv[1], argv[2],
                                "org.freedesktop.DBus.Introspectable", "Introspect",
-                               &error, &reply_xml, "");
+                               &error, &reply_xml, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to introspect object %s of service %s: %s",
                                        argv[2], argv[1], bus_error_message(&error, r));
index 9053d48149598dbffaf9f97cd6c4704a51f1af7f..86d0b3744d07c13d26e22b305b31824b366e273f 100644 (file)
@@ -38,8 +38,8 @@
 #include "virt.h"
 #include "watchdog.h"
 
-/* Require 16MiB free in /run/systemd for reloading/reexecing. After all we need to serialize our state there, and if
- * we can't we'll fail badly. */
+/* Require 16MiB free in /run/systemd for reloading/reexecing. After all we need to serialize our state
+ * there, and if we can't we'll fail badly. */
 #define RELOAD_DISK_SPACE_MIN (UINT64_C(16) * UINT64_C(1024) * UINT64_C(1024))
 
 static UnitFileFlags unit_file_bools_to_flags(bool runtime, bool force) {
@@ -363,8 +363,8 @@ static int bus_get_unit_by_name(Manager *m, sd_bus_message *message, const char
         assert(message);
         assert(ret_unit);
 
-        /* More or less a wrapper around manager_get_unit() that generates nice errors and has one trick up its sleeve:
-         * if the name is specified empty we use the client's unit. */
+        /* More or less a wrapper around manager_get_unit() that generates nice errors and has one trick up
+         * its sleeve: if the name is specified empty we use the client's unit. */
 
         if (isempty(name)) {
                 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
@@ -520,7 +520,8 @@ static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userd
 
                 u = manager_get_unit_by_pid(m, pid);
                 if (!u)
-                        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Client " PID_FMT " not member of any unit.", pid);
+                        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT,
+                                                 "Client " PID_FMT " not member of any unit.", pid);
         } else {
                 u = hashmap_get(m->units_by_invocation_id, &id);
                 if (!u)
@@ -531,8 +532,9 @@ static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userd
         if (r < 0)
                 return r;
 
-        /* So here's a special trick: the bus path we return actually references the unit by its invocation ID instead
-         * of the unit name. This means it stays valid only as long as the invocation ID stays the same. */
+        /* So here's a special trick: the bus path we return actually references the unit by its invocation
+         * ID instead of the unit name. This means it stays valid only as long as the invocation ID stays the
+         * same. */
         path = unit_dbus_path_invocation_id(u);
         if (!path)
                 return -ENOMEM;
@@ -552,7 +554,9 @@ static int method_get_unit_by_control_group(sd_bus_message *message, void *userd
 
         u = manager_get_unit_by_cgroup(m, cgroup);
         if (!u)
-                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Control group '%s' is not valid or not managed by this instance", cgroup);
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT,
+                                         "Control group '%s' is not valid or not managed by this instance",
+                                         cgroup);
 
         return reply_unit_path(u, message, error);
 }
@@ -851,17 +855,21 @@ static int transient_unit_from_message(
 
         t = unit_name_to_type(name);
         if (t < 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name or type.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Invalid unit name or type.");
 
         if (!unit_vtable[t]->can_transient)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Unit type %s does not support transient units.",
+                                         unit_type_to_string(t));
 
         r = manager_load_unit(m, name, NULL, error, &u);
         if (r < 0)
                 return r;
 
         if (!unit_is_pristine(u))
-                return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
+                return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS,
+                                         "Unit %s already exists.", name);
 
         /* OK, the unit failed to load and is unreferenced, now let's
          * fill in the transient data instead */
@@ -1435,7 +1443,8 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
                 return r;
 
         if (!MANAGER_IS_SYSTEM(m))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
+                                         "Reboot is only supported for system managers.");
 
         m->objective = MANAGER_REBOOT;
 
@@ -1454,7 +1463,8 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error
                 return r;
 
         if (!MANAGER_IS_SYSTEM(m))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
+                                         "Powering off is only supported for system managers.");
 
         m->objective = MANAGER_POWEROFF;
 
@@ -1473,7 +1483,8 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er
                 return r;
 
         if (!MANAGER_IS_SYSTEM(m))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
+                                         "Halt is only supported for system managers.");
 
         m->objective = MANAGER_HALT;
 
@@ -1492,7 +1503,8 @@ static int method_kexec(sd_bus_message *message, void *userdata, sd_bus_error *e
                 return r;
 
         if (!MANAGER_IS_SYSTEM(m))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
+                                         "KExec is only supported for system managers.");
 
         m->objective = MANAGER_KEXEC;
 
@@ -1517,7 +1529,7 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
 
         if (available < RELOAD_DISK_SPACE_MIN) {
                 char fb_available[FORMAT_BYTES_MAX], fb_need[FORMAT_BYTES_MAX];
-                log_warning("Dangerously low amount of free space on /run/systemd, root switching operation might not complete successfully. "
+                log_warning("Dangerously low amount of free space on /run/systemd, root switching might fail.\n"
                             "Currently, %s are free, but %s are suggested. Proceeding anyway.",
                             format_bytes(fb_available, sizeof(fb_available), available),
                             format_bytes(fb_need, sizeof(fb_need), RELOAD_DISK_SPACE_MIN));
@@ -1528,41 +1540,53 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
                 return r;
 
         if (!MANAGER_IS_SYSTEM(m))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Root switching is only supported by system manager.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
+                                         "Root switching is only supported by system manager.");
 
         r = sd_bus_message_read(message, "ss", &root, &init);
         if (r < 0)
                 return r;
 
         if (isempty(root))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New root directory may not be the empty string.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "New root directory may not be the empty string.");
         if (!path_is_absolute(root))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New root path '%s' is not absolute.", root);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "New root path '%s' is not absolute.", root);
         if (path_equal(root, "/"))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New root directory cannot be the old root directory.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "New root directory cannot be the old root directory.");
 
         /* Safety check */
         if (isempty(init)) {
                 r = path_is_os_tree(root);
                 if (r < 0)
-                        return sd_bus_error_set_errnof(error, r, "Failed to determine whether root path '%s' contains an OS tree: %m", root);
+                        return sd_bus_error_set_errnof(error, r,
+                                                       "Failed to determine whether root path '%s' contains an OS tree: %m",
+                                                       root);
                 if (r == 0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified switch root path '%s' does not seem to be an OS tree. os-release file is missing.", root);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Specified switch root path '%s' does not seem to be an OS tree. os-release file is missing.",
+                                                 root);
         } else {
                 _cleanup_free_ char *chased = NULL;
 
                 if (!path_is_absolute(init))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path to init binary '%s' not absolute.", init);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Path to init binary '%s' not absolute.", init);
 
                 r = chase_symlinks(init, root, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &chased, NULL);
                 if (r < 0)
-                        return sd_bus_error_set_errnof(error, r, "Could not resolve init executable %s: %m", init);
+                        return sd_bus_error_set_errnof(error, r,
+                                                       "Could not resolve init executable %s: %m", init);
 
                 if (laccess(chased, X_OK) < 0) {
                         if (errno == EACCES)
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Init binary %s is not executable.", init);
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                         "Init binary %s is not executable.", init);
 
-                        return sd_bus_error_set_errnof(error, r, "Could not check whether init binary %s is executable: %m", init);
+                        return sd_bus_error_set_errnof(error, r,
+                                                       "Could not check whether init binary %s is executable: %m", init);
                 }
         }
 
@@ -1632,7 +1656,8 @@ static int method_unset_environment(sd_bus_message *message, void *userdata, sd_
                 return r;
 
         if (!strv_env_name_or_assignment_is_valid(minus))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Invalid environment variable names or assignments");
 
         r = bus_verify_set_environment_async(m, message, error);
         if (r < 0)
@@ -1668,9 +1693,11 @@ static int method_unset_and_set_environment(sd_bus_message *message, void *userd
                 return r;
 
         if (!strv_env_name_or_assignment_is_valid(minus))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Invalid environment variable names or assignments");
         if (!strv_env_is_valid(plus))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Invalid environment assignments");
 
         r = bus_verify_set_environment_async(m, message, error);
         if (r < 0)
@@ -1723,13 +1750,16 @@ static int method_lookup_dynamic_user_by_name(sd_bus_message *message, void *use
                 return r;
 
         if (!MANAGER_IS_SYSTEM(m))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
+                                         "Dynamic users are only supported in the system instance.");
         if (!valid_user_group_name(name, VALID_USER_RELAX))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name invalid: %s", name);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "User name invalid: %s", name);
 
         r = dynamic_user_lookup_name(m, name, &uid);
         if (r == -ESRCH)
-                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DYNAMIC_USER, "Dynamic user %s does not exist.", name);
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DYNAMIC_USER,
+                                         "Dynamic user %s does not exist.", name);
         if (r < 0)
                 return r;
 
@@ -1751,13 +1781,16 @@ static int method_lookup_dynamic_user_by_uid(sd_bus_message *message, void *user
                 return r;
 
         if (!MANAGER_IS_SYSTEM(m))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
+                                         "Dynamic users are only supported in the system instance.");
         if (!uid_is_valid(uid))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User ID invalid: " UID_FMT, uid);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "User ID invalid: " UID_FMT, uid);
 
         r = dynamic_user_lookup_uid(m, uid, &name);
         if (r == -ESRCH)
-                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DYNAMIC_USER, "Dynamic user ID " UID_FMT " does not exist.", uid);
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DYNAMIC_USER,
+                                         "Dynamic user ID " UID_FMT " does not exist.", uid);
         if (r < 0)
                 return r;
 
@@ -1776,7 +1809,8 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_
         assert_cc(sizeof(uid_t) == sizeof(uint32_t));
 
         if (!MANAGER_IS_SYSTEM(m))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
+                                         "Dynamic users are only supported in the system instance.");
 
         r = sd_bus_message_new_method_return(message, &reply);
         if (r < 0)
@@ -1793,7 +1827,8 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_
                 if (r == -EAGAIN) /* not realized yet? */
                         continue;
                 if (r < 0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Failed to look up a dynamic user.");
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED,
+                                                 "Failed to look up a dynamic user.");
 
                 r = sd_bus_message_append(reply, "(us)", uid, d->name);
                 if (r < 0)
@@ -1807,6 +1842,75 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_
         return sd_bus_send(NULL, reply, NULL);
 }
 
+static int method_enqueue_marked_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Manager *m = userdata;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = mac_selinux_access_check(message, "start", error);
+        if (r < 0)
+                return r;
+
+        r = bus_verify_manage_units_async(m, message, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+        log_info("Queuing reload/restart jobs for marked units…");
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        r = sd_bus_message_new_method_return(message, &reply);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(reply, 'a', "o");
+        if (r < 0)
+                return r;
+
+        Unit *u;
+        char *k;
+        int ret = 0;
+        HASHMAP_FOREACH_KEY(u, k, m->units) {
+                /* ignore aliases */
+                if (u->id != k)
+                        continue;
+
+                BusUnitQueueFlags flags;
+                if (FLAGS_SET(u->markers, 1u << UNIT_MARKER_NEEDS_RESTART))
+                        flags = 0;
+                else if (FLAGS_SET(u->markers, 1u << UNIT_MARKER_NEEDS_RELOAD))
+                        flags = BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
+                else
+                        continue;
+
+                r = mac_selinux_unit_access_check(u, message, "start", error);
+                if (r >= 0)
+                        r = bus_unit_queue_job_one(message, u,
+                                                   JOB_TRY_RESTART, JOB_FAIL, flags,
+                                                   reply, error);
+                if (r < 0) {
+                        if (ERRNO_IS_RESOURCE(r))
+                                return r;
+                        if (ret >= 0)
+                                ret = r;
+                        sd_bus_error_free(error);
+                }
+        }
+
+        if (ret < 0)
+                return sd_bus_error_set_errnof(error, ret,
+                                               "Failed to enqueue some jobs, see logs for details: %m");
+
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send(NULL, reply, NULL);
+}
+
 static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states, char **patterns) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         Manager *m = userdata;
@@ -1932,7 +2036,10 @@ static int send_unit_files_changed(sd_bus *bus, void *userdata) {
 
         assert(bus);
 
-        r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
+        r = sd_bus_message_new_signal(bus, &message,
+                                      "/org/freedesktop/systemd1",
+                                      "org.freedesktop.systemd1.Manager",
+                                      "UnitFilesChanged");
         if (r < 0)
                 return r;
 
@@ -2060,8 +2167,8 @@ static int reply_unit_file_changes_and_free(
                 good = true;
         }
 
-        /* If there was a failed change, and no successful change, then return the first failure as proper method call
-         * error. */
+        /* If there was a failed change, and no successful change, then return the first failure as proper
+         * method call error. */
         if (bad && !good)
                 return install_error(error, 0, changes, n_changes);
 
@@ -2486,7 +2593,8 @@ static int method_abandon_scope(sd_bus_message *message, void *userdata, sd_bus_
                 return r;
 
         if (u->type != UNIT_SCOPE)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit '%s' is not a scope unit, refusing.", name);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Unit '%s' is not a scope unit, refusing.", name);
 
         return bus_scope_method_abandon(message, u, error);
 }
@@ -2507,7 +2615,8 @@ static int method_set_show_status(sd_bus_message *message, void *userdata, sd_bu
         if (!isempty(t)) {
                 mode = show_status_from_string(t);
                 if (mode < 0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid show status '%s'", t);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Invalid show status '%s'", t);
         }
 
         manager_override_show_status(m, mode, "bus");
@@ -3007,6 +3116,12 @@ const sd_bus_vtable bus_manager_vtable[] = {
                                  NULL,,
                                  method_unset_and_set_environment,
                                  SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("EnqueueMarkedJobs",
+                                 NULL,,
+                                 "ao",
+                                 SD_BUS_PARAM(jobs),
+                                 method_enqueue_marked_jobs,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD_WITH_NAMES("ListUnitFiles",
                                  NULL,,
                                  "a(ss)",
@@ -3260,7 +3375,11 @@ static int send_finished(sd_bus *bus, void *userdata) {
         assert(bus);
         assert(times);
 
-        r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
+        r = sd_bus_message_new_signal(bus,
+                                      &message,
+                                      "/org/freedesktop/systemd1",
+                                      "org.freedesktop.systemd1.Manager",
+                                      "StartupFinished");
         if (r < 0)
                 return r;
 
index 8d92a4e763f58522833e5a8bf6d2f1cc17d9cf10..859e35eee4244516aaf6a165d78587dd956a8ff6 100644 (file)
@@ -323,6 +323,39 @@ static int property_get_load_error(
         return sd_bus_message_append(reply, "(ss)", NULL, NULL);
 }
 
+static int property_get_markers(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        unsigned *markers = userdata;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(markers);
+
+        r = sd_bus_message_open_container(reply, 'a', "s");
+        if (r < 0)
+                return r;
+
+        /* Make sure out values fit in the bitfield. */
+        assert_cc(_UNIT_MARKER_MAX <= sizeof(((Unit){}).markers) * 8);
+
+        for (UnitMarker m = 0; m < _UNIT_MARKER_MAX; m++)
+                if (FLAGS_SET(*markers, 1u << m)) {
+                        r = sd_bus_message_append(reply, "s", unit_marker_to_string(m));
+                        if (r < 0)
+                                return r;
+                }
+
+        return sd_bus_message_close_container(reply);
+}
+
 static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
         [JOB_START]       = N_("Authentication is required to start '$(unit)'."),
         [JOB_STOP]        = N_("Authentication is required to stop '$(unit)'."),
@@ -778,7 +811,6 @@ static int property_get_refs(
                 sd_bus_error *error) {
 
         Unit *u = userdata;
-        const char *i;
         int r;
 
         assert(bus);
@@ -788,15 +820,15 @@ static int property_get_refs(
         if (r < 0)
                 return r;
 
-        for (i = sd_bus_track_first(u->bus_track); i; i = sd_bus_track_next(u->bus_track)) {
-                int c, k;
+        for (const char *i = sd_bus_track_first(u->bus_track); i; i = sd_bus_track_next(u->bus_track)) {
+                int c;
 
                 c = sd_bus_track_count_name(u->bus_track, i);
                 if (c < 0)
                         return c;
 
                 /* Add the item multiple times if the ref count for each is above 1 */
-                for (k = 0; k < c; k++) {
+                for (int k = 0; k < c; k++) {
                         r = sd_bus_message_append(reply, "s", i);
                         if (r < 0)
                                 return r;
@@ -864,6 +896,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Markers", "as", property_get_markers, offsetof(Unit, markers), 0),
         SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("JobRunningTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_running_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_emergency_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1683,50 +1716,20 @@ void bus_unit_send_removed_signal(Unit *u) {
                 log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id);
 }
 
-int bus_unit_queue_job(
+int bus_unit_queue_job_one(
                 sd_bus_message *message,
                 Unit *u,
                 JobType type,
                 JobMode mode,
                 BusUnitQueueFlags flags,
+                sd_bus_message *reply,
                 sd_bus_error *error) {
 
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        _cleanup_free_ char *job_path = NULL, *unit_path = NULL;
         _cleanup_set_free_ Set *affected = NULL;
+        _cleanup_free_ char *job_path = NULL, *unit_path = NULL;
         Job *j, *a;
         int r;
 
-        assert(message);
-        assert(u);
-        assert(type >= 0 && type < _JOB_TYPE_MAX);
-        assert(mode >= 0 && mode < _JOB_MODE_MAX);
-
-        r = mac_selinux_unit_access_check(
-                        u, message,
-                        job_type_to_access_method(type),
-                        error);
-        if (r < 0)
-                return r;
-
-        if (FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE) && unit_can_reload(u)) {
-                if (type == JOB_RESTART)
-                        type = JOB_RELOAD_OR_START;
-                else if (type == JOB_TRY_RESTART)
-                        type = JOB_TRY_RELOAD;
-        }
-
-        if (type == JOB_STOP &&
-            IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR, UNIT_BAD_SETTING) &&
-            unit_active_state(u) == UNIT_INACTIVE)
-                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
-
-        if ((type == JOB_START && u->refuse_manual_start) ||
-            (type == JOB_STOP && u->refuse_manual_stop) ||
-            (IN_SET(type, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
-            (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
-                return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
-
         if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) {
                 affected = set_new(NULL);
                 if (!affected)
@@ -1750,12 +1753,9 @@ int bus_unit_queue_job(
 
         /* The classic response is just a job object path */
         if (!FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY))
-                return sd_bus_reply_method_return(message, "o", job_path);
+                return sd_bus_message_append(reply, "o", job_path);
 
         /* In verbose mode respond with the anchor job plus everything that has been affected */
-        r = sd_bus_message_new_method_return(message, &reply);
-        if (r < 0)
-                return r;
 
         unit_path = unit_dbus_path(j->unit);
         if (!unit_path)
@@ -1773,7 +1773,6 @@ int bus_unit_queue_job(
                 return r;
 
         SET_FOREACH(a, affected) {
-
                 if (a->id == j->id)
                         continue;
 
@@ -1797,7 +1796,55 @@ int bus_unit_queue_job(
                         return r;
         }
 
-        r = sd_bus_message_close_container(reply);
+        return sd_bus_message_close_container(reply);
+}
+
+int bus_unit_queue_job(
+                sd_bus_message *message,
+                Unit *u,
+                JobType type,
+                JobMode mode,
+                BusUnitQueueFlags flags,
+                sd_bus_error *error) {
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        int r;
+
+        assert(message);
+        assert(u);
+        assert(type >= 0 && type < _JOB_TYPE_MAX);
+        assert(mode >= 0 && mode < _JOB_MODE_MAX);
+
+        r = mac_selinux_unit_access_check(
+                        u, message,
+                        job_type_to_access_method(type),
+                        error);
+        if (r < 0)
+                return r;
+
+        if (FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE) && unit_can_reload(u)) {
+                if (type == JOB_RESTART)
+                        type = JOB_RELOAD_OR_START;
+                else if (type == JOB_TRY_RESTART)
+                        type = JOB_TRY_RELOAD;
+        }
+
+        if (type == JOB_STOP &&
+            IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR, UNIT_BAD_SETTING) &&
+            unit_active_state(u) == UNIT_INACTIVE)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
+
+        if ((type == JOB_START && u->refuse_manual_start) ||
+            (type == JOB_STOP && u->refuse_manual_stop) ||
+            (IN_SET(type, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
+            (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
+                return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
+
+        r = sd_bus_message_new_method_return(message, &reply);
+        if (r < 0)
+                return r;
+
+        r = bus_unit_queue_job_one(message, u, type, mode, flags, reply, error);
         if (r < 0)
                 return r;
 
@@ -1817,8 +1864,8 @@ static int bus_unit_set_live_property(
         assert(name);
         assert(message);
 
-        /* Handles setting properties both "live" (i.e. at any time during runtime), and during creation (for transient
-         * units that are being created). */
+        /* Handles setting properties both "live" (i.e. at any time during runtime), and during creation (for
+         * transient units that are being created). */
 
         if (streq(name, "Description")) {
                 const char *d;
@@ -1838,6 +1885,63 @@ static int bus_unit_set_live_property(
                 return 1;
         }
 
+        /* A setting that only applies to active units. We don't actually write this to /run, this state is
+         * managed internally. "+foo" sets flag foo, "-foo" unsets flag foo, just "foo" resets flags to
+         * foo. The last type cannot be mixed with "+" or "-". */
+
+        if (streq(name, "Markers")) {
+                unsigned settings = 0, mask = 0;
+                bool some_plus_minus = false, some_absolute = false;
+
+                r = sd_bus_message_enter_container(message, 'a', "s");
+                if (r < 0)
+                        return r;
+
+                for (;;) {
+                        const char *word;
+                        bool b;
+
+                        r = sd_bus_message_read(message, "s", &word);
+                        if (r < 0)
+                                return r;
+                        if (r == 0)
+                                break;
+
+                        if (IN_SET(word[0], '+', '-')) {
+                                b = word[0] == '+';
+                                word++;
+                                some_plus_minus = true;
+                        } else {
+                                b = true;
+                                some_absolute = true;
+                        }
+
+                        UnitMarker m = unit_marker_from_string(word);
+                        if (m < 0)
+                                return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING,
+                                                         "Unknown marker \"%s\".", word);
+
+                        SET_FLAG(settings, 1u << m, b);
+                        SET_FLAG(mask, 1u << m, true);
+                }
+
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
+
+                if (some_plus_minus && some_absolute)
+                        return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING, "Bad marker syntax.");
+
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        if (some_absolute)
+                                u->markers = settings;
+                        else
+                                u->markers = settings | (u->markers & ~mask);
+                }
+
+                return 1;
+        }
+
         return 0;
 }
 
@@ -1989,8 +2093,8 @@ static int bus_unit_set_transient_property(
         assert(name);
         assert(message);
 
-        /* Handles settings when transient units are created. This settings cannot be altered anymore after the unit
-         * has been created. */
+        /* Handles settings when transient units are created. This settings cannot be altered anymore after
+         * the unit has been created. */
 
         if (streq(name, "SourcePath"))
                 return bus_set_transient_path(u, name, &u->source_path, message, flags, error);
@@ -2298,7 +2402,8 @@ int bus_unit_set_properties(
                         return r;
 
                 if (!UNIT_VTABLE(u)->bus_set_property)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY,
+                                                 "Objects of this type do not support setting properties.");
 
                 r = sd_bus_message_enter_container(message, 'v', NULL);
                 if (r < 0)
@@ -2316,7 +2421,8 @@ int bus_unit_set_properties(
                         return r;
 
                 if (r == 0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY,
+                                                 "Cannot set property %s, or unknown property.", name);
 
                 r = sd_bus_message_exit_container(message);
                 if (r < 0)
@@ -2435,8 +2541,8 @@ int bus_unit_track_add_sender(Unit *u, sd_bus_message *m) {
 int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m) {
         assert(u);
 
-        /* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet, return an
-         * error */
+        /* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet,
+         * return an error */
         if (!u->bus_track)
                 return -EUNATCH;
 
index 1da3cfeb96b41d264b1dcb3412f441219b5b827f..a3ac320496906c7cd90d62dd8a729b5687c826c1 100644 (file)
@@ -33,7 +33,21 @@ typedef enum BusUnitQueueFlags {
         BUS_UNIT_QUEUE_VERBOSE_REPLY      = 1 << 1,
 } BusUnitQueueFlags;
 
-int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, BusUnitQueueFlags flags, sd_bus_error *error);
+int bus_unit_queue_job_one(
+                sd_bus_message *message,
+                Unit *u,
+                JobType type,
+                JobMode mode,
+                BusUnitQueueFlags flags,
+                sd_bus_message *reply,
+                sd_bus_error *error);
+int bus_unit_queue_job(
+                sd_bus_message *message,
+                Unit *u,
+                JobType type,
+                JobMode mode,
+                BusUnitQueueFlags flags,
+                sd_bus_error *error);
 int bus_unit_validate_load_state(Unit *u, sd_bus_error *error);
 
 int bus_unit_track_add_name(Unit *u, const char *name);
index 2c35a917f88d0c79fc198c19105588dc60f29e07..d14aec47d0e606dccb63198978c69834c518a200 100644 (file)
@@ -93,7 +93,7 @@
 #include "terminal-util.h"
 #include "tmpfile-util.h"
 #include "umask-util.h"
-#include "unit.h"
+#include "unit-serialize.h"
 #include "user-util.h"
 #include "utmp-wtmp.h"
 
index e67f6e9199d4011e2dc963c0d2390a18fbdccb70..311ffcecc1c1694b5cfdc9245bb5b10b4ff1311a 100644 (file)
@@ -7,7 +7,7 @@
 #include "install.h"
 #include "load-fragment.h"
 #include "string-util.h"
-#include "unit.h"
+#include "unit-serialize.h"
 #include "utf8.h"
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
index 0a7a4518356b266741c3956adb2fe4b3eb7bc1f1..82ca4c2482662b85ccecdaba42160fb547346123 100644 (file)
@@ -80,6 +80,7 @@
 #include "transaction.h"
 #include "umask-util.h"
 #include "unit-name.h"
+#include "unit-serialize.h"
 #include "user-util.h"
 #include "virt.h"
 #include "watchdog.h"
@@ -1187,18 +1188,15 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
                         is_bad = false;
         }
 
-        if (u->refs_by_target) {
-                const UnitRef *ref;
+        const UnitRef *ref;
+        LIST_FOREACH(refs_by_target, ref, u->refs_by_target) {
+                unit_gc_sweep(ref->source, gc_marker);
 
-                LIST_FOREACH(refs_by_target, ref, u->refs_by_target) {
-                        unit_gc_sweep(ref->source, gc_marker);
-
-                        if (ref->source->gc_marker == gc_marker + GC_OFFSET_GOOD)
-                                goto good;
+                if (ref->source->gc_marker == gc_marker + GC_OFFSET_GOOD)
+                        goto good;
 
-                        if (ref->source->gc_marker != gc_marker + GC_OFFSET_BAD)
-                                is_bad = false;
-                }
+                if (ref->source->gc_marker != gc_marker + GC_OFFSET_BAD)
+                        is_bad = false;
         }
 
         if (is_bad)
index edfc73e6277d6a4b919941fbcc73721275f0dcac..a389c906b368609084a171fd8cd9235a56ef8110 100644 (file)
@@ -115,6 +115,8 @@ libcore_sources = '''
         transaction.h
         unit-printf.c
         unit-printf.h
+        unit-serialize.c
+        unit-serialize.h
         unit.c
         unit.h
 '''.split()
@@ -162,11 +164,9 @@ core_includes = [includes, include_directories('.')]
 
 systemd_sources = files('main.c')
 
-in_files = [['macros.systemd',   rpmmacrosdir],
-            ['system.conf',      pkgsysconfdir],
+in_files = [['system.conf',      pkgsysconfdir],
             ['user.conf',        pkgsysconfdir],
-            ['systemd.pc',       pkgconfigdatadir],
-            ['triggers.systemd', '']]
+            ['systemd.pc',       pkgconfigdatadir]]
 
 foreach item : in_files
         file = item[0]
diff --git a/src/core/unit-serialize.c b/src/core/unit-serialize.c
new file mode 100644 (file)
index 0000000..3f09924
--- /dev/null
@@ -0,0 +1,780 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "bus-util.h"
+#include "dbus.h"
+#include "fileio-label.h"
+#include "fileio.h"
+#include "format-util.h"
+#include "parse-util.h"
+#include "serialize.h"
+#include "string-table.h"
+#include "unit-serialize.h"
+#include "user-util.h"
+
+static int serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) {
+        _cleanup_free_ char *s = NULL;
+        int r;
+
+        assert(f);
+        assert(key);
+
+        if (mask == 0)
+                return 0;
+
+        r = cg_mask_to_string(mask, &s);
+        if (r < 0)
+                return log_error_errno(r, "Failed to format cgroup mask: %m");
+
+        return serialize_item(f, key, s);
+}
+
+/* Make sure out values fit in the bitfield. */
+assert_cc(_UNIT_MARKER_MAX <= sizeof(((Unit){}).markers) * 8);
+
+static int serialize_markers(FILE *f, unsigned markers) {
+        assert(f);
+
+        if (markers == 0)
+                return 0;
+
+        fputs("markers=", f);
+        for (UnitMarker m = 0; m < _UNIT_MARKER_MAX; m++)
+                if (FLAGS_SET(markers, 1u << m))
+                        fputs(unit_marker_to_string(m), f);
+        fputc('\n', f);
+        return 0;
+}
+
+static int deserialize_markers(Unit *u, const char *value) {
+        assert(u);
+        assert(value);
+        int r;
+
+        for (const char *p = value;;) {
+                _cleanup_free_ char *word = NULL;
+
+                r = extract_first_word(&p, &word, NULL, 0);
+                if (r <= 0)
+                        return r;
+
+                UnitMarker m = unit_marker_from_string(word);
+                if (m < 0) {
+                        log_unit_debug_errno(u, m, "Unknown unit marker \"%s\", ignoring.", word);
+                        continue;
+                }
+
+                u->markers |= 1u << m;
+        }
+}
+
+static const char *const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
+        [CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes",
+        [CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets",
+        [CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes",
+        [CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets",
+};
+
+static const char *const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
+        [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base",
+        [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base",
+        [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base",
+        [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-base",
+};
+
+static const char *const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
+        [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last",
+        [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last",
+        [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last",
+        [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last",
+};
+
+int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
+        int r;
+
+        assert(u);
+        assert(f);
+        assert(fds);
+
+        if (unit_can_serialize(u)) {
+                r = UNIT_VTABLE(u)->serialize(u, f, fds);
+                if (r < 0)
+                        return r;
+        }
+
+        (void) serialize_dual_timestamp(f, "state-change-timestamp", &u->state_change_timestamp);
+
+        (void) serialize_dual_timestamp(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
+        (void) serialize_dual_timestamp(f, "active-enter-timestamp", &u->active_enter_timestamp);
+        (void) serialize_dual_timestamp(f, "active-exit-timestamp", &u->active_exit_timestamp);
+        (void) serialize_dual_timestamp(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
+
+        (void) serialize_dual_timestamp(f, "condition-timestamp", &u->condition_timestamp);
+        (void) serialize_dual_timestamp(f, "assert-timestamp", &u->assert_timestamp);
+
+        if (dual_timestamp_is_set(&u->condition_timestamp))
+                (void) serialize_bool(f, "condition-result", u->condition_result);
+
+        if (dual_timestamp_is_set(&u->assert_timestamp))
+                (void) serialize_bool(f, "assert-result", u->assert_result);
+
+        (void) serialize_bool(f, "transient", u->transient);
+        (void) serialize_bool(f, "in-audit", u->in_audit);
+
+        (void) serialize_bool(f, "exported-invocation-id", u->exported_invocation_id);
+        (void) serialize_bool(f, "exported-log-level-max", u->exported_log_level_max);
+        (void) serialize_bool(f, "exported-log-extra-fields", u->exported_log_extra_fields);
+        (void) serialize_bool(f, "exported-log-rate-limit-interval", u->exported_log_ratelimit_interval);
+        (void) serialize_bool(f, "exported-log-rate-limit-burst", u->exported_log_ratelimit_burst);
+
+        (void) serialize_item_format(f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base);
+        if (u->cpu_usage_last != NSEC_INFINITY)
+                (void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last);
+
+        if (u->managed_oom_kill_last > 0)
+                (void) serialize_item_format(f, "managed-oom-kill-last", "%" PRIu64, u->managed_oom_kill_last);
+
+        if (u->oom_kill_last > 0)
+                (void) serialize_item_format(f, "oom-kill-last", "%" PRIu64, u->oom_kill_last);
+
+        for (CGroupIOAccountingMetric im = 0; im < _CGROUP_IO_ACCOUNTING_METRIC_MAX; im++) {
+                (void) serialize_item_format(f, io_accounting_metric_field_base[im], "%" PRIu64, u->io_accounting_base[im]);
+
+                if (u->io_accounting_last[im] != UINT64_MAX)
+                        (void) serialize_item_format(f, io_accounting_metric_field_last[im], "%" PRIu64, u->io_accounting_last[im]);
+        }
+
+        if (u->cgroup_path)
+                (void) serialize_item(f, "cgroup", u->cgroup_path);
+
+        (void) serialize_bool(f, "cgroup-realized", u->cgroup_realized);
+        (void) serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask);
+        (void) serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask);
+        (void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", u->cgroup_invalidated_mask);
+
+        if (uid_is_valid(u->ref_uid))
+                (void) serialize_item_format(f, "ref-uid", UID_FMT, u->ref_uid);
+        if (gid_is_valid(u->ref_gid))
+                (void) serialize_item_format(f, "ref-gid", GID_FMT, u->ref_gid);
+
+        if (!sd_id128_is_null(u->invocation_id))
+                (void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id));
+
+        (void) serialize_item_format(f, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u)));
+        (void) serialize_markers(f, u->markers);
+
+        bus_track_serialize(u->bus_track, f, "ref");
+
+        for (CGroupIPAccountingMetric m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
+                uint64_t v;
+
+                r = unit_get_ip_accounting(u, m, &v);
+                if (r >= 0)
+                        (void) serialize_item_format(f, ip_accounting_metric_field[m], "%" PRIu64, v);
+        }
+
+        if (serialize_jobs) {
+                if (u->job) {
+                        fputs("job\n", f);
+                        job_serialize(u->job, f);
+                }
+
+                if (u->nop_job) {
+                        fputs("job\n", f);
+                        job_serialize(u->nop_job, f);
+                }
+        }
+
+        /* End marker */
+        fputc('\n', f);
+        return 0;
+}
+
+static int unit_deserialize_job(Unit *u, FILE *f) {
+        _cleanup_(job_freep) Job *j = NULL;
+        int r;
+
+        assert(u);
+        assert(f);
+
+        j = job_new_raw(u);
+        if (!j)
+                return log_oom();
+
+        r = job_deserialize(j, f);
+        if (r < 0)
+                return r;
+
+        r = job_install_deserialized(j);
+        if (r < 0)
+                return r;
+
+        TAKE_PTR(j);
+        return 0;
+}
+
+#define MATCH_DESERIALIZE(key, l, v, parse_func, target)                \
+        ({                                                              \
+                bool _deserialize_matched = streq(l, key);              \
+                if (_deserialize_matched) {                             \
+                        int _deserialize_r = parse_func(v);             \
+                        if (_deserialize_r < 0)                         \
+                                log_unit_debug_errno(u, _deserialize_r, \
+                                                     "Failed to parse \"%s=%s\", ignoring.", l, v); \
+                        else                                            \
+                                target = _deserialize_r;                \
+                };                                                      \
+                _deserialize_matched;                                   \
+        })
+
+#define MATCH_DESERIALIZE_IMMEDIATE(key, l, v, parse_func, target)      \
+        ({                                                              \
+                bool _deserialize_matched = streq(l, key);              \
+                if (_deserialize_matched) {                             \
+                        int _deserialize_r = parse_func(v, &target);    \
+                        if (_deserialize_r < 0)                         \
+                                log_unit_debug_errno(u, _deserialize_r, \
+                                                     "Failed to parse \"%s=%s\", ignoring", l, v); \
+                };                                                      \
+                _deserialize_matched;                                   \
+        })
+
+int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
+        int r;
+
+        assert(u);
+        assert(f);
+        assert(fds);
+
+        for (;;) {
+                _cleanup_free_ char *line = NULL;
+                char *l, *v;
+                ssize_t m;
+                size_t k;
+
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to read serialization line: %m");
+                if (r == 0) /* eof */
+                        break;
+
+                l = strstrip(line);
+                if (isempty(l)) /* End marker */
+                        break;
+
+                k = strcspn(l, "=");
+
+                if (l[k] == '=') {
+                        l[k] = 0;
+                        v = l+k+1;
+                } else
+                        v = l+k;
+
+                if (streq(l, "job")) {
+                        if (v[0] == '\0') {
+                                /* New-style serialized job */
+                                r = unit_deserialize_job(u, f);
+                                if (r < 0)
+                                        return r;
+                        } else  /* Legacy for pre-44 */
+                                log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v);
+                        continue;
+                } else if (streq(l, "state-change-timestamp")) {
+                        (void) deserialize_dual_timestamp(v, &u->state_change_timestamp);
+                        continue;
+                } else if (streq(l, "inactive-exit-timestamp")) {
+                        (void) deserialize_dual_timestamp(v, &u->inactive_exit_timestamp);
+                        continue;
+                } else if (streq(l, "active-enter-timestamp")) {
+                        (void) deserialize_dual_timestamp(v, &u->active_enter_timestamp);
+                        continue;
+                } else if (streq(l, "active-exit-timestamp")) {
+                        (void) deserialize_dual_timestamp(v, &u->active_exit_timestamp);
+                        continue;
+                } else if (streq(l, "inactive-enter-timestamp")) {
+                        (void) deserialize_dual_timestamp(v, &u->inactive_enter_timestamp);
+                        continue;
+                } else if (streq(l, "condition-timestamp")) {
+                        (void) deserialize_dual_timestamp(v, &u->condition_timestamp);
+                        continue;
+                } else if (streq(l, "assert-timestamp")) {
+                        (void) deserialize_dual_timestamp(v, &u->assert_timestamp);
+                        continue;
+
+                } else if (MATCH_DESERIALIZE("condition-result", l, v, parse_boolean, u->condition_result))
+                        continue;
+
+                else if (MATCH_DESERIALIZE("assert-result", l, v, parse_boolean, u->assert_result))
+                        continue;
+
+                else if (MATCH_DESERIALIZE("transient", l, v, parse_boolean, u->transient))
+                        continue;
+
+                else if (MATCH_DESERIALIZE("in-audit", l, v, parse_boolean, u->in_audit))
+                        continue;
+
+                else if (MATCH_DESERIALIZE("exported-invocation-id", l, v, parse_boolean, u->exported_invocation_id))
+                        continue;
+
+                else if (MATCH_DESERIALIZE("exported-log-level-max", l, v, parse_boolean, u->exported_log_level_max))
+                        continue;
+
+                else if (MATCH_DESERIALIZE("exported-log-extra-fields", l, v, parse_boolean, u->exported_log_extra_fields))
+                        continue;
+
+                else if (MATCH_DESERIALIZE("exported-log-rate-limit-interval", l, v, parse_boolean, u->exported_log_ratelimit_interval))
+                        continue;
+
+                else if (MATCH_DESERIALIZE("exported-log-rate-limit-burst", l, v, parse_boolean, u->exported_log_ratelimit_burst))
+                        continue;
+
+                else if (MATCH_DESERIALIZE_IMMEDIATE("cpu-usage-base", l, v, safe_atou64, u->cpu_usage_base) ||
+                         MATCH_DESERIALIZE_IMMEDIATE("cpuacct-usage-base", l, v, safe_atou64, u->cpu_usage_base))
+                        continue;
+
+                else if (MATCH_DESERIALIZE_IMMEDIATE("cpu-usage-last", l, v, safe_atou64, u->cpu_usage_last))
+                        continue;
+
+                else if (MATCH_DESERIALIZE_IMMEDIATE("managed-oom-kill-last", l, v, safe_atou64, u->managed_oom_kill_last))
+                        continue;
+
+                else if (MATCH_DESERIALIZE_IMMEDIATE("oom-kill-last", l, v, safe_atou64, u->oom_kill_last))
+                        continue;
+
+                else if (streq(l, "cgroup")) {
+                        r = unit_set_cgroup_path(u, v);
+                        if (r < 0)
+                                log_unit_debug_errno(u, r, "Failed to set cgroup path %s, ignoring: %m", v);
+
+                        (void) unit_watch_cgroup(u);
+                        (void) unit_watch_cgroup_memory(u);
+
+                        continue;
+
+                } else if (MATCH_DESERIALIZE("cgroup-realized", l, v, parse_boolean, u->cgroup_realized))
+                        continue;
+
+                else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-realized-mask", l, v, cg_mask_from_string, u->cgroup_realized_mask))
+                        continue;
+
+                else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-enabled-mask", l, v, cg_mask_from_string, u->cgroup_enabled_mask))
+                        continue;
+
+                else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-invalidated-mask", l, v, cg_mask_from_string, u->cgroup_invalidated_mask))
+                        continue;
+
+                else if (streq(l, "ref-uid")) {
+                        uid_t uid;
+
+                        r = parse_uid(v, &uid);
+                        if (r < 0)
+                                log_unit_debug(u, "Failed to parse \"%s=%s\", ignoring.", l, v);
+                        else
+                                unit_ref_uid_gid(u, uid, GID_INVALID);
+                        continue;
+
+                } else if (streq(l, "ref-gid")) {
+                        gid_t gid;
+
+                        r = parse_gid(v, &gid);
+                        if (r < 0)
+                                log_unit_debug(u, "Failed to parse \"%s=%s\", ignoring.", l, v);
+                        else
+                                unit_ref_uid_gid(u, UID_INVALID, gid);
+                        continue;
+
+                } else if (streq(l, "ref")) {
+                        r = strv_extend(&u->deserialized_refs, v);
+                        if (r < 0)
+                                return log_oom();
+                        continue;
+
+                } else if (streq(l, "invocation-id")) {
+                        sd_id128_t id;
+
+                        r = sd_id128_from_string(v, &id);
+                        if (r < 0)
+                                log_unit_debug(u, "Failed to parse \"%s=%s\", ignoring.", l, v);
+                        else {
+                                r = unit_set_invocation_id(u, id);
+                                if (r < 0)
+                                        log_unit_warning_errno(u, r, "Failed to set invocation ID for unit: %m");
+                        }
+
+                        continue;
+
+                } else if (MATCH_DESERIALIZE("freezer-state", l, v, freezer_state_from_string, u->freezer_state))
+                        continue;
+
+                else if (streq(l, "markers")) {
+                        r = deserialize_markers(u, v);
+                        if (r < 0)
+                                log_unit_debug_errno(u, r, "Failed to deserialize \"%s=%s\", ignoring: %m", l, v);
+                        continue;
+                }
+
+                /* Check if this is an IP accounting metric serialization field */
+                m = string_table_lookup(ip_accounting_metric_field, ELEMENTSOF(ip_accounting_metric_field), l);
+                if (m >= 0) {
+                        uint64_t c;
+
+                        r = safe_atou64(v, &c);
+                        if (r < 0)
+                                log_unit_debug(u, "Failed to parse IP accounting value %s, ignoring.", v);
+                        else
+                                u->ip_accounting_extra[m] = c;
+                        continue;
+                }
+
+                m = string_table_lookup(io_accounting_metric_field_base, ELEMENTSOF(io_accounting_metric_field_base), l);
+                if (m >= 0) {
+                        uint64_t c;
+
+                        r = safe_atou64(v, &c);
+                        if (r < 0)
+                                log_unit_debug(u, "Failed to parse IO accounting base value %s, ignoring.", v);
+                        else
+                                u->io_accounting_base[m] = c;
+                        continue;
+                }
+
+                m = string_table_lookup(io_accounting_metric_field_last, ELEMENTSOF(io_accounting_metric_field_last), l);
+                if (m >= 0) {
+                        uint64_t c;
+
+                        r = safe_atou64(v, &c);
+                        if (r < 0)
+                                log_unit_debug(u, "Failed to parse IO accounting last value %s, ignoring.", v);
+                        else
+                                u->io_accounting_last[m] = c;
+                        continue;
+                }
+
+                if (unit_can_serialize(u)) {
+                        r = exec_runtime_deserialize_compat(u, l, v, fds);
+                        if (r < 0) {
+                                log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
+                                continue;
+                        }
+
+                        /* Returns positive if key was handled by the call */
+                        if (r > 0)
+                                continue;
+
+                        r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
+                        if (r < 0)
+                                log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
+                }
+        }
+
+        /* Versions before 228 did not carry a state change timestamp. In this case, take the current
+         * time. This is useful, so that timeouts based on this timestamp don't trigger too early, and is
+         * in-line with the logic from before 228 where the base for timeouts was not persistent across
+         * reboots. */
+
+        if (!dual_timestamp_is_set(&u->state_change_timestamp))
+                dual_timestamp_get(&u->state_change_timestamp);
+
+        /* Let's make sure that everything that is deserialized also gets any potential new cgroup settings
+         * applied after we are done. For that we invalidate anything already realized, so that we can
+         * realize it again. */
+        unit_invalidate_cgroup(u, _CGROUP_MASK_ALL);
+        unit_invalidate_cgroup_bpf(u);
+
+        return 0;
+}
+
+int unit_deserialize_skip(FILE *f) {
+        int r;
+        assert(f);
+
+        /* Skip serialized data for this unit. We don't know what it is. */
+
+        for (;;) {
+                _cleanup_free_ char *line = NULL;
+                char *l;
+
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to read serialization line: %m");
+                if (r == 0)
+                        return 0;
+
+                l = strstrip(line);
+
+                /* End marker */
+                if (isempty(l))
+                        return 1;
+        }
+}
+
+static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependencyMask mask, bool *space) {
+        const struct {
+                UnitDependencyMask mask;
+                const char *name;
+        } table[] = {
+                { UNIT_DEPENDENCY_FILE,               "file"               },
+                { UNIT_DEPENDENCY_IMPLICIT,           "implicit"           },
+                { UNIT_DEPENDENCY_DEFAULT,            "default"            },
+                { UNIT_DEPENDENCY_UDEV,               "udev"               },
+                { UNIT_DEPENDENCY_PATH,               "path"               },
+                { UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" },
+                { UNIT_DEPENDENCY_MOUNTINFO_DEFAULT,  "mountinfo-default"  },
+                { UNIT_DEPENDENCY_PROC_SWAP,          "proc-swap"          },
+        };
+
+        assert(f);
+        assert(kind);
+        assert(space);
+
+        for (size_t i = 0; i < ELEMENTSOF(table); i++) {
+
+                if (mask == 0)
+                        break;
+
+                if (FLAGS_SET(mask, table[i].mask)) {
+                        if (*space)
+                                fputc(' ', f);
+                        else
+                                *space = true;
+
+                        fputs(kind, f);
+                        fputs("-", f);
+                        fputs(table[i].name, f);
+
+                        mask &= ~table[i].mask;
+                }
+        }
+
+        assert(mask == 0);
+}
+
+void unit_dump(Unit *u, FILE *f, const char *prefix) {
+        char *t, **j;
+        const char *prefix2;
+        char timestamp[5][FORMAT_TIMESTAMP_MAX], timespan[FORMAT_TIMESPAN_MAX];
+        Unit *following;
+        _cleanup_set_free_ Set *following_set = NULL;
+        CGroupMask m;
+        int r;
+
+        assert(u);
+        assert(u->type >= 0);
+
+        prefix = strempty(prefix);
+        prefix2 = strjoina(prefix, "\t");
+
+        fprintf(f,
+                "%s-> Unit %s:\n",
+                prefix, u->id);
+
+        SET_FOREACH(t, u->aliases)
+                fprintf(f, "%s\tAlias: %s\n", prefix, t);
+
+        fprintf(f,
+                "%s\tDescription: %s\n"
+                "%s\tInstance: %s\n"
+                "%s\tUnit Load State: %s\n"
+                "%s\tUnit Active State: %s\n"
+                "%s\tState Change Timestamp: %s\n"
+                "%s\tInactive Exit Timestamp: %s\n"
+                "%s\tActive Enter Timestamp: %s\n"
+                "%s\tActive Exit Timestamp: %s\n"
+                "%s\tInactive Enter Timestamp: %s\n"
+                "%s\tMay GC: %s\n"
+                "%s\tNeed Daemon Reload: %s\n"
+                "%s\tTransient: %s\n"
+                "%s\tPerpetual: %s\n"
+                "%s\tGarbage Collection Mode: %s\n"
+                "%s\tSlice: %s\n"
+                "%s\tCGroup: %s\n"
+                "%s\tCGroup realized: %s\n",
+                prefix, unit_description(u),
+                prefix, strna(u->instance),
+                prefix, unit_load_state_to_string(u->load_state),
+                prefix, unit_active_state_to_string(unit_active_state(u)),
+                prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->state_change_timestamp.realtime)),
+                prefix, strna(format_timestamp(timestamp[1], sizeof(timestamp[1]), u->inactive_exit_timestamp.realtime)),
+                prefix, strna(format_timestamp(timestamp[2], sizeof(timestamp[2]), u->active_enter_timestamp.realtime)),
+                prefix, strna(format_timestamp(timestamp[3], sizeof(timestamp[3]), u->active_exit_timestamp.realtime)),
+                prefix, strna(format_timestamp(timestamp[4], sizeof(timestamp[4]), u->inactive_enter_timestamp.realtime)),
+                prefix, yes_no(unit_may_gc(u)),
+                prefix, yes_no(unit_need_daemon_reload(u)),
+                prefix, yes_no(u->transient),
+                prefix, yes_no(u->perpetual),
+                prefix, collect_mode_to_string(u->collect_mode),
+                prefix, strna(unit_slice_name(u)),
+                prefix, strna(u->cgroup_path),
+                prefix, yes_no(u->cgroup_realized));
+
+        if (u->markers != 0) {
+                fprintf(f, "%s\tMarkers:", prefix);
+
+                for (UnitMarker marker = 0; marker < _UNIT_MARKER_MAX; marker++)
+                        if (FLAGS_SET(u->markers, 1u << marker))
+                                fprintf(f, " %s", unit_marker_to_string(marker));
+                fputs("\n", f);
+        }
+
+        if (u->cgroup_realized_mask != 0) {
+                _cleanup_free_ char *s = NULL;
+                (void) cg_mask_to_string(u->cgroup_realized_mask, &s);
+                fprintf(f, "%s\tCGroup realized mask: %s\n", prefix, strnull(s));
+        }
+
+        if (u->cgroup_enabled_mask != 0) {
+                _cleanup_free_ char *s = NULL;
+                (void) cg_mask_to_string(u->cgroup_enabled_mask, &s);
+                fprintf(f, "%s\tCGroup enabled mask: %s\n", prefix, strnull(s));
+        }
+
+        m = unit_get_own_mask(u);
+        if (m != 0) {
+                _cleanup_free_ char *s = NULL;
+                (void) cg_mask_to_string(m, &s);
+                fprintf(f, "%s\tCGroup own mask: %s\n", prefix, strnull(s));
+        }
+
+        m = unit_get_members_mask(u);
+        if (m != 0) {
+                _cleanup_free_ char *s = NULL;
+                (void) cg_mask_to_string(m, &s);
+                fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s));
+        }
+
+        m = unit_get_delegate_mask(u);
+        if (m != 0) {
+                _cleanup_free_ char *s = NULL;
+                (void) cg_mask_to_string(m, &s);
+                fprintf(f, "%s\tCGroup delegate mask: %s\n", prefix, strnull(s));
+        }
+
+        if (!sd_id128_is_null(u->invocation_id))
+                fprintf(f, "%s\tInvocation ID: " SD_ID128_FORMAT_STR "\n",
+                        prefix, SD_ID128_FORMAT_VAL(u->invocation_id));
+
+        STRV_FOREACH(j, u->documentation)
+                fprintf(f, "%s\tDocumentation: %s\n", prefix, *j);
+
+        following = unit_following(u);
+        if (following)
+                fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
+
+        r = unit_following_set(u, &following_set);
+        if (r >= 0) {
+                Unit *other;
+
+                SET_FOREACH(other, following_set)
+                        fprintf(f, "%s\tFollowing Set Member: %s\n", prefix, other->id);
+        }
+
+        if (u->fragment_path)
+                fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
+
+        if (u->source_path)
+                fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path);
+
+        STRV_FOREACH(j, u->dropin_paths)
+                fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j);
+
+        if (u->failure_action != EMERGENCY_ACTION_NONE)
+                fprintf(f, "%s\tFailure Action: %s\n", prefix, emergency_action_to_string(u->failure_action));
+        if (u->failure_action_exit_status >= 0)
+                fprintf(f, "%s\tFailure Action Exit Status: %i\n", prefix, u->failure_action_exit_status);
+        if (u->success_action != EMERGENCY_ACTION_NONE)
+                fprintf(f, "%s\tSuccess Action: %s\n", prefix, emergency_action_to_string(u->success_action));
+        if (u->success_action_exit_status >= 0)
+                fprintf(f, "%s\tSuccess Action Exit Status: %i\n", prefix, u->success_action_exit_status);
+
+        if (u->job_timeout != USEC_INFINITY)
+                fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
+
+        if (u->job_timeout_action != EMERGENCY_ACTION_NONE)
+                fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action));
+
+        if (u->job_timeout_reboot_arg)
+                fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg);
+
+        condition_dump_list(u->conditions, f, prefix, condition_type_to_string);
+        condition_dump_list(u->asserts, f, prefix, assert_type_to_string);
+
+        if (dual_timestamp_is_set(&u->condition_timestamp))
+                fprintf(f,
+                        "%s\tCondition Timestamp: %s\n"
+                        "%s\tCondition Result: %s\n",
+                        prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->condition_timestamp.realtime)),
+                        prefix, yes_no(u->condition_result));
+
+        if (dual_timestamp_is_set(&u->assert_timestamp))
+                fprintf(f,
+                        "%s\tAssert Timestamp: %s\n"
+                        "%s\tAssert Result: %s\n",
+                        prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->assert_timestamp.realtime)),
+                        prefix, yes_no(u->assert_result));
+
+        for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
+                UnitDependencyInfo di;
+                Unit *other;
+
+                HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d]) {
+                        bool space = false;
+
+                        fprintf(f, "%s\t%s: %s (", prefix, unit_dependency_to_string(d), other->id);
+
+                        print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
+                        print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
+
+                        fputs(")\n", f);
+                }
+        }
+
+        if (!hashmap_isempty(u->requires_mounts_for)) {
+                UnitDependencyInfo di;
+                const char *path;
+
+                HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) {
+                        bool space = false;
+
+                        fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path);
+
+                        print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
+                        print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
+
+                        fputs(")\n", f);
+                }
+        }
+
+        if (u->load_state == UNIT_LOADED) {
+
+                fprintf(f,
+                        "%s\tStopWhenUnneeded: %s\n"
+                        "%s\tRefuseManualStart: %s\n"
+                        "%s\tRefuseManualStop: %s\n"
+                        "%s\tDefaultDependencies: %s\n"
+                        "%s\tOnFailureJobMode: %s\n"
+                        "%s\tIgnoreOnIsolate: %s\n",
+                        prefix, yes_no(u->stop_when_unneeded),
+                        prefix, yes_no(u->refuse_manual_start),
+                        prefix, yes_no(u->refuse_manual_stop),
+                        prefix, yes_no(u->default_dependencies),
+                        prefix, job_mode_to_string(u->on_failure_job_mode),
+                        prefix, yes_no(u->ignore_on_isolate));
+
+                if (UNIT_VTABLE(u)->dump)
+                        UNIT_VTABLE(u)->dump(u, f, prefix2);
+
+        } else if (u->load_state == UNIT_MERGED)
+                fprintf(f,
+                        "%s\tMerged into: %s\n",
+                        prefix, u->merged_into->id);
+        else if (u->load_state == UNIT_ERROR)
+                fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror_safe(u->load_error));
+
+        for (const char *n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track))
+                fprintf(f, "%s\tBus Ref: %s\n", prefix, n);
+
+        if (u->job)
+                job_dump(u->job, f, prefix2);
+
+        if (u->nop_job)
+                job_dump(u->nop_job, f, prefix2);
+}
diff --git a/src/core/unit-serialize.h b/src/core/unit-serialize.h
new file mode 100644 (file)
index 0000000..599d883
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdio.h>
+
+#include "unit.h"
+#include "fdset.h"
+
+int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
+int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
+int unit_deserialize_skip(FILE *f);
+
+void unit_dump(Unit *u, FILE *f, const char *prefix);
index e6d55db88b61ea06f7b49564e52ab0130c4d0aed..345271259074cc3476fa4a2f5d97dab4a98178fd 100644 (file)
@@ -26,8 +26,8 @@
 #include "fileio.h"
 #include "format-util.h"
 #include "id128-util.h"
-#include "io-util.h"
 #include "install.h"
+#include "io-util.h"
 #include "label.h"
 #include "load-dropin.h"
 #include "load-fragment.h"
 #include "macro.h"
 #include "missing_audit.h"
 #include "mkdir.h"
-#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "rm-rf.h"
-#include "serialize.h"
 #include "set.h"
 #include "signal-util.h"
 #include "sparse-endian.h"
@@ -1166,269 +1164,6 @@ const char *unit_status_string(Unit *u) {
         return unit_description(u);
 }
 
-static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependencyMask mask, bool *space) {
-        const struct {
-                UnitDependencyMask mask;
-                const char *name;
-        } table[] = {
-                { UNIT_DEPENDENCY_FILE,               "file"               },
-                { UNIT_DEPENDENCY_IMPLICIT,           "implicit"           },
-                { UNIT_DEPENDENCY_DEFAULT,            "default"            },
-                { UNIT_DEPENDENCY_UDEV,               "udev"               },
-                { UNIT_DEPENDENCY_PATH,               "path"               },
-                { UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" },
-                { UNIT_DEPENDENCY_MOUNTINFO_DEFAULT,  "mountinfo-default"  },
-                { UNIT_DEPENDENCY_PROC_SWAP,          "proc-swap"          },
-        };
-
-        assert(f);
-        assert(kind);
-        assert(space);
-
-        for (size_t i = 0; i < ELEMENTSOF(table); i++) {
-
-                if (mask == 0)
-                        break;
-
-                if (FLAGS_SET(mask, table[i].mask)) {
-                        if (*space)
-                                fputc(' ', f);
-                        else
-                                *space = true;
-
-                        fputs(kind, f);
-                        fputs("-", f);
-                        fputs(table[i].name, f);
-
-                        mask &= ~table[i].mask;
-                }
-        }
-
-        assert(mask == 0);
-}
-
-void unit_dump(Unit *u, FILE *f, const char *prefix) {
-        char *t, **j;
-        const char *prefix2;
-        char timestamp[5][FORMAT_TIMESTAMP_MAX], timespan[FORMAT_TIMESPAN_MAX];
-        Unit *following;
-        _cleanup_set_free_ Set *following_set = NULL;
-        CGroupMask m;
-        int r;
-
-        assert(u);
-        assert(u->type >= 0);
-
-        prefix = strempty(prefix);
-        prefix2 = strjoina(prefix, "\t");
-
-        fprintf(f,
-                "%s-> Unit %s:\n",
-                prefix, u->id);
-
-        SET_FOREACH(t, u->aliases)
-                fprintf(f, "%s\tAlias: %s\n", prefix, t);
-
-        fprintf(f,
-                "%s\tDescription: %s\n"
-                "%s\tInstance: %s\n"
-                "%s\tUnit Load State: %s\n"
-                "%s\tUnit Active State: %s\n"
-                "%s\tState Change Timestamp: %s\n"
-                "%s\tInactive Exit Timestamp: %s\n"
-                "%s\tActive Enter Timestamp: %s\n"
-                "%s\tActive Exit Timestamp: %s\n"
-                "%s\tInactive Enter Timestamp: %s\n"
-                "%s\tMay GC: %s\n"
-                "%s\tNeed Daemon Reload: %s\n"
-                "%s\tTransient: %s\n"
-                "%s\tPerpetual: %s\n"
-                "%s\tGarbage Collection Mode: %s\n"
-                "%s\tSlice: %s\n"
-                "%s\tCGroup: %s\n"
-                "%s\tCGroup realized: %s\n",
-                prefix, unit_description(u),
-                prefix, strna(u->instance),
-                prefix, unit_load_state_to_string(u->load_state),
-                prefix, unit_active_state_to_string(unit_active_state(u)),
-                prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->state_change_timestamp.realtime)),
-                prefix, strna(format_timestamp(timestamp[1], sizeof(timestamp[1]), u->inactive_exit_timestamp.realtime)),
-                prefix, strna(format_timestamp(timestamp[2], sizeof(timestamp[2]), u->active_enter_timestamp.realtime)),
-                prefix, strna(format_timestamp(timestamp[3], sizeof(timestamp[3]), u->active_exit_timestamp.realtime)),
-                prefix, strna(format_timestamp(timestamp[4], sizeof(timestamp[4]), u->inactive_enter_timestamp.realtime)),
-                prefix, yes_no(unit_may_gc(u)),
-                prefix, yes_no(unit_need_daemon_reload(u)),
-                prefix, yes_no(u->transient),
-                prefix, yes_no(u->perpetual),
-                prefix, collect_mode_to_string(u->collect_mode),
-                prefix, strna(unit_slice_name(u)),
-                prefix, strna(u->cgroup_path),
-                prefix, yes_no(u->cgroup_realized));
-
-        if (u->cgroup_realized_mask != 0) {
-                _cleanup_free_ char *s = NULL;
-                (void) cg_mask_to_string(u->cgroup_realized_mask, &s);
-                fprintf(f, "%s\tCGroup realized mask: %s\n", prefix, strnull(s));
-        }
-
-        if (u->cgroup_enabled_mask != 0) {
-                _cleanup_free_ char *s = NULL;
-                (void) cg_mask_to_string(u->cgroup_enabled_mask, &s);
-                fprintf(f, "%s\tCGroup enabled mask: %s\n", prefix, strnull(s));
-        }
-
-        m = unit_get_own_mask(u);
-        if (m != 0) {
-                _cleanup_free_ char *s = NULL;
-                (void) cg_mask_to_string(m, &s);
-                fprintf(f, "%s\tCGroup own mask: %s\n", prefix, strnull(s));
-        }
-
-        m = unit_get_members_mask(u);
-        if (m != 0) {
-                _cleanup_free_ char *s = NULL;
-                (void) cg_mask_to_string(m, &s);
-                fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s));
-        }
-
-        m = unit_get_delegate_mask(u);
-        if (m != 0) {
-                _cleanup_free_ char *s = NULL;
-                (void) cg_mask_to_string(m, &s);
-                fprintf(f, "%s\tCGroup delegate mask: %s\n", prefix, strnull(s));
-        }
-
-        if (!sd_id128_is_null(u->invocation_id))
-                fprintf(f, "%s\tInvocation ID: " SD_ID128_FORMAT_STR "\n",
-                        prefix, SD_ID128_FORMAT_VAL(u->invocation_id));
-
-        STRV_FOREACH(j, u->documentation)
-                fprintf(f, "%s\tDocumentation: %s\n", prefix, *j);
-
-        following = unit_following(u);
-        if (following)
-                fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
-
-        r = unit_following_set(u, &following_set);
-        if (r >= 0) {
-                Unit *other;
-
-                SET_FOREACH(other, following_set)
-                        fprintf(f, "%s\tFollowing Set Member: %s\n", prefix, other->id);
-        }
-
-        if (u->fragment_path)
-                fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
-
-        if (u->source_path)
-                fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path);
-
-        STRV_FOREACH(j, u->dropin_paths)
-                fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j);
-
-        if (u->failure_action != EMERGENCY_ACTION_NONE)
-                fprintf(f, "%s\tFailure Action: %s\n", prefix, emergency_action_to_string(u->failure_action));
-        if (u->failure_action_exit_status >= 0)
-                fprintf(f, "%s\tFailure Action Exit Status: %i\n", prefix, u->failure_action_exit_status);
-        if (u->success_action != EMERGENCY_ACTION_NONE)
-                fprintf(f, "%s\tSuccess Action: %s\n", prefix, emergency_action_to_string(u->success_action));
-        if (u->success_action_exit_status >= 0)
-                fprintf(f, "%s\tSuccess Action Exit Status: %i\n", prefix, u->success_action_exit_status);
-
-        if (u->job_timeout != USEC_INFINITY)
-                fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
-
-        if (u->job_timeout_action != EMERGENCY_ACTION_NONE)
-                fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action));
-
-        if (u->job_timeout_reboot_arg)
-                fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg);
-
-        condition_dump_list(u->conditions, f, prefix, condition_type_to_string);
-        condition_dump_list(u->asserts, f, prefix, assert_type_to_string);
-
-        if (dual_timestamp_is_set(&u->condition_timestamp))
-                fprintf(f,
-                        "%s\tCondition Timestamp: %s\n"
-                        "%s\tCondition Result: %s\n",
-                        prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->condition_timestamp.realtime)),
-                        prefix, yes_no(u->condition_result));
-
-        if (dual_timestamp_is_set(&u->assert_timestamp))
-                fprintf(f,
-                        "%s\tAssert Timestamp: %s\n"
-                        "%s\tAssert Result: %s\n",
-                        prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->assert_timestamp.realtime)),
-                        prefix, yes_no(u->assert_result));
-
-        for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
-                UnitDependencyInfo di;
-                Unit *other;
-
-                HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d]) {
-                        bool space = false;
-
-                        fprintf(f, "%s\t%s: %s (", prefix, unit_dependency_to_string(d), other->id);
-
-                        print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
-                        print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
-
-                        fputs(")\n", f);
-                }
-        }
-
-        if (!hashmap_isempty(u->requires_mounts_for)) {
-                UnitDependencyInfo di;
-                const char *path;
-
-                HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) {
-                        bool space = false;
-
-                        fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path);
-
-                        print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
-                        print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
-
-                        fputs(")\n", f);
-                }
-        }
-
-        if (u->load_state == UNIT_LOADED) {
-
-                fprintf(f,
-                        "%s\tStopWhenUnneeded: %s\n"
-                        "%s\tRefuseManualStart: %s\n"
-                        "%s\tRefuseManualStop: %s\n"
-                        "%s\tDefaultDependencies: %s\n"
-                        "%s\tOnFailureJobMode: %s\n"
-                        "%s\tIgnoreOnIsolate: %s\n",
-                        prefix, yes_no(u->stop_when_unneeded),
-                        prefix, yes_no(u->refuse_manual_start),
-                        prefix, yes_no(u->refuse_manual_stop),
-                        prefix, yes_no(u->default_dependencies),
-                        prefix, job_mode_to_string(u->on_failure_job_mode),
-                        prefix, yes_no(u->ignore_on_isolate));
-
-                if (UNIT_VTABLE(u)->dump)
-                        UNIT_VTABLE(u)->dump(u, f, prefix2);
-
-        } else if (u->load_state == UNIT_MERGED)
-                fprintf(f,
-                        "%s\tMerged into: %s\n",
-                        prefix, u->merged_into->id);
-        else if (u->load_state == UNIT_ERROR)
-                fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror_safe(u->load_error));
-
-        for (const char *n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track))
-                fprintf(f, "%s\tBus Ref: %s\n", prefix, n);
-
-        if (u->job)
-                job_dump(u->job, f, prefix2);
-
-        if (u->nop_job)
-                job_dump(u->nop_job, f, prefix2);
-}
-
 /* Common implementation for multiple backends */
 int unit_load_fragment_and_dropin(Unit *u, bool fragment_required) {
         int r;
@@ -2655,9 +2390,13 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
 
         /* Make sure the cgroup and state files are always removed when we become inactive */
         if (UNIT_IS_INACTIVE_OR_FAILED(ns)) {
+                SET_FLAG(u->markers,
+                         (1u << UNIT_MARKER_NEEDS_RELOAD)|(1u << UNIT_MARKER_NEEDS_RESTART),
+                         false);
                 unit_prune_cgroup(u);
                 unit_unlink_state_files(u);
-        }
+        } else if (ns != os && ns == UNIT_RELOADING)
+                SET_FLAG(u->markers, 1u << UNIT_MARKER_NEEDS_RELOAD, false);
 
         unit_update_on_console(u);
 
@@ -3241,7 +2980,7 @@ char *unit_dbus_path_invocation_id(Unit *u) {
         return unit_dbus_path_from_name(u->invocation_id_string);
 }
 
-static int unit_set_invocation_id(Unit *u, sd_id128_t id) {
+int unit_set_invocation_id(Unit *u, sd_id128_t id) {
         int r;
 
         assert(u);
@@ -3526,539 +3265,6 @@ bool unit_can_serialize(Unit *u) {
         return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item;
 }
 
-static int serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) {
-        _cleanup_free_ char *s = NULL;
-        int r;
-
-        assert(f);
-        assert(key);
-
-        if (mask == 0)
-                return 0;
-
-        r = cg_mask_to_string(mask, &s);
-        if (r < 0)
-                return log_error_errno(r, "Failed to format cgroup mask: %m");
-
-        return serialize_item(f, key, s);
-}
-
-static const char *const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
-        [CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes",
-        [CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets",
-        [CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes",
-        [CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets",
-};
-
-static const char *const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
-        [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base",
-        [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base",
-        [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base",
-        [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-base",
-};
-
-static const char *const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
-        [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last",
-        [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last",
-        [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last",
-        [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last",
-};
-
-int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
-        int r;
-
-        assert(u);
-        assert(f);
-        assert(fds);
-
-        if (unit_can_serialize(u)) {
-                r = UNIT_VTABLE(u)->serialize(u, f, fds);
-                if (r < 0)
-                        return r;
-        }
-
-        (void) serialize_dual_timestamp(f, "state-change-timestamp", &u->state_change_timestamp);
-
-        (void) serialize_dual_timestamp(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
-        (void) serialize_dual_timestamp(f, "active-enter-timestamp", &u->active_enter_timestamp);
-        (void) serialize_dual_timestamp(f, "active-exit-timestamp", &u->active_exit_timestamp);
-        (void) serialize_dual_timestamp(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
-
-        (void) serialize_dual_timestamp(f, "condition-timestamp", &u->condition_timestamp);
-        (void) serialize_dual_timestamp(f, "assert-timestamp", &u->assert_timestamp);
-
-        if (dual_timestamp_is_set(&u->condition_timestamp))
-                (void) serialize_bool(f, "condition-result", u->condition_result);
-
-        if (dual_timestamp_is_set(&u->assert_timestamp))
-                (void) serialize_bool(f, "assert-result", u->assert_result);
-
-        (void) serialize_bool(f, "transient", u->transient);
-        (void) serialize_bool(f, "in-audit", u->in_audit);
-
-        (void) serialize_bool(f, "exported-invocation-id", u->exported_invocation_id);
-        (void) serialize_bool(f, "exported-log-level-max", u->exported_log_level_max);
-        (void) serialize_bool(f, "exported-log-extra-fields", u->exported_log_extra_fields);
-        (void) serialize_bool(f, "exported-log-rate-limit-interval", u->exported_log_ratelimit_interval);
-        (void) serialize_bool(f, "exported-log-rate-limit-burst", u->exported_log_ratelimit_burst);
-
-        (void) serialize_item_format(f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base);
-        if (u->cpu_usage_last != NSEC_INFINITY)
-                (void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last);
-
-        if (u->managed_oom_kill_last > 0)
-                (void) serialize_item_format(f, "managed-oom-kill-last", "%" PRIu64, u->managed_oom_kill_last);
-
-        if (u->oom_kill_last > 0)
-                (void) serialize_item_format(f, "oom-kill-last", "%" PRIu64, u->oom_kill_last);
-
-        for (CGroupIOAccountingMetric im = 0; im < _CGROUP_IO_ACCOUNTING_METRIC_MAX; im++) {
-                (void) serialize_item_format(f, io_accounting_metric_field_base[im], "%" PRIu64, u->io_accounting_base[im]);
-
-                if (u->io_accounting_last[im] != UINT64_MAX)
-                        (void) serialize_item_format(f, io_accounting_metric_field_last[im], "%" PRIu64, u->io_accounting_last[im]);
-        }
-
-        if (u->cgroup_path)
-                (void) serialize_item(f, "cgroup", u->cgroup_path);
-
-        (void) serialize_bool(f, "cgroup-realized", u->cgroup_realized);
-        (void) serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask);
-        (void) serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask);
-        (void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", u->cgroup_invalidated_mask);
-
-        if (uid_is_valid(u->ref_uid))
-                (void) serialize_item_format(f, "ref-uid", UID_FMT, u->ref_uid);
-        if (gid_is_valid(u->ref_gid))
-                (void) serialize_item_format(f, "ref-gid", GID_FMT, u->ref_gid);
-
-        if (!sd_id128_is_null(u->invocation_id))
-                (void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id));
-
-        (void) serialize_item_format(f, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u)));
-
-        bus_track_serialize(u->bus_track, f, "ref");
-
-        for (CGroupIPAccountingMetric m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
-                uint64_t v;
-
-                r = unit_get_ip_accounting(u, m, &v);
-                if (r >= 0)
-                        (void) serialize_item_format(f, ip_accounting_metric_field[m], "%" PRIu64, v);
-        }
-
-        if (serialize_jobs) {
-                if (u->job) {
-                        fputs("job\n", f);
-                        job_serialize(u->job, f);
-                }
-
-                if (u->nop_job) {
-                        fputs("job\n", f);
-                        job_serialize(u->nop_job, f);
-                }
-        }
-
-        /* End marker */
-        fputc('\n', f);
-        return 0;
-}
-
-static int unit_deserialize_job(Unit *u, FILE *f) {
-        _cleanup_(job_freep) Job *j = NULL;
-        int r;
-
-        assert(u);
-        assert(f);
-
-        j = job_new_raw(u);
-        if (!j)
-                return log_oom();
-
-        r = job_deserialize(j, f);
-        if (r < 0)
-                return r;
-
-        r = job_install_deserialized(j);
-        if (r < 0)
-                return r;
-
-        TAKE_PTR(j);
-        return 0;
-}
-
-int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
-        int r;
-
-        assert(u);
-        assert(f);
-        assert(fds);
-
-        for (;;) {
-                _cleanup_free_ char *line = NULL;
-                char *l, *v;
-                ssize_t m;
-                size_t k;
-
-                r = read_line(f, LONG_LINE_MAX, &line);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to read serialization line: %m");
-                if (r == 0) /* eof */
-                        break;
-
-                l = strstrip(line);
-                if (isempty(l)) /* End marker */
-                        break;
-
-                k = strcspn(l, "=");
-
-                if (l[k] == '=') {
-                        l[k] = 0;
-                        v = l+k+1;
-                } else
-                        v = l+k;
-
-                if (streq(l, "job")) {
-                        if (v[0] == '\0') {
-                                /* New-style serialized job */
-                                r = unit_deserialize_job(u, f);
-                                if (r < 0)
-                                        return r;
-                        } else  /* Legacy for pre-44 */
-                                log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v);
-                        continue;
-                } else if (streq(l, "state-change-timestamp")) {
-                        (void) deserialize_dual_timestamp(v, &u->state_change_timestamp);
-                        continue;
-                } else if (streq(l, "inactive-exit-timestamp")) {
-                        (void) deserialize_dual_timestamp(v, &u->inactive_exit_timestamp);
-                        continue;
-                } else if (streq(l, "active-enter-timestamp")) {
-                        (void) deserialize_dual_timestamp(v, &u->active_enter_timestamp);
-                        continue;
-                } else if (streq(l, "active-exit-timestamp")) {
-                        (void) deserialize_dual_timestamp(v, &u->active_exit_timestamp);
-                        continue;
-                } else if (streq(l, "inactive-enter-timestamp")) {
-                        (void) deserialize_dual_timestamp(v, &u->inactive_enter_timestamp);
-                        continue;
-                } else if (streq(l, "condition-timestamp")) {
-                        (void) deserialize_dual_timestamp(v, &u->condition_timestamp);
-                        continue;
-                } else if (streq(l, "assert-timestamp")) {
-                        (void) deserialize_dual_timestamp(v, &u->assert_timestamp);
-                        continue;
-                } else if (streq(l, "condition-result")) {
-
-                        r = parse_boolean(v);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse condition result value %s, ignoring.", v);
-                        else
-                                u->condition_result = r;
-
-                        continue;
-
-                } else if (streq(l, "assert-result")) {
-
-                        r = parse_boolean(v);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse assert result value %s, ignoring.", v);
-                        else
-                                u->assert_result = r;
-
-                        continue;
-
-                } else if (streq(l, "transient")) {
-
-                        r = parse_boolean(v);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse transient bool %s, ignoring.", v);
-                        else
-                                u->transient = r;
-
-                        continue;
-
-                } else if (streq(l, "in-audit")) {
-
-                        r = parse_boolean(v);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse in-audit bool %s, ignoring.", v);
-                        else
-                                u->in_audit = r;
-
-                        continue;
-
-                } else if (streq(l, "exported-invocation-id")) {
-
-                        r = parse_boolean(v);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse exported invocation ID bool %s, ignoring.", v);
-                        else
-                                u->exported_invocation_id = r;
-
-                        continue;
-
-                } else if (streq(l, "exported-log-level-max")) {
-
-                        r = parse_boolean(v);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse exported log level max bool %s, ignoring.", v);
-                        else
-                                u->exported_log_level_max = r;
-
-                        continue;
-
-                } else if (streq(l, "exported-log-extra-fields")) {
-
-                        r = parse_boolean(v);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse exported log extra fields bool %s, ignoring.", v);
-                        else
-                                u->exported_log_extra_fields = r;
-
-                        continue;
-
-                } else if (streq(l, "exported-log-rate-limit-interval")) {
-
-                        r = parse_boolean(v);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse exported log rate limit interval %s, ignoring.", v);
-                        else
-                                u->exported_log_ratelimit_interval = r;
-
-                        continue;
-
-                } else if (streq(l, "exported-log-rate-limit-burst")) {
-
-                        r = parse_boolean(v);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse exported log rate limit burst %s, ignoring.", v);
-                        else
-                                u->exported_log_ratelimit_burst = r;
-
-                        continue;
-
-                } else if (STR_IN_SET(l, "cpu-usage-base", "cpuacct-usage-base")) {
-
-                        r = safe_atou64(v, &u->cpu_usage_base);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse CPU usage base %s, ignoring.", v);
-
-                        continue;
-
-                } else if (streq(l, "cpu-usage-last")) {
-
-                        r = safe_atou64(v, &u->cpu_usage_last);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to read CPU usage last %s, ignoring.", v);
-
-                        continue;
-
-                } else if (streq(l, "managed-oom-kill-last")) {
-
-                        r = safe_atou64(v, &u->managed_oom_kill_last);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to read managed OOM kill last %s, ignoring.", v);
-
-                        continue;
-
-                } else if (streq(l, "oom-kill-last")) {
-
-                        r = safe_atou64(v, &u->oom_kill_last);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to read OOM kill last %s, ignoring.", v);
-
-                        continue;
-
-                } else if (streq(l, "cgroup")) {
-
-                        r = unit_set_cgroup_path(u, v);
-                        if (r < 0)
-                                log_unit_debug_errno(u, r, "Failed to set cgroup path %s, ignoring: %m", v);
-
-                        (void) unit_watch_cgroup(u);
-                        (void) unit_watch_cgroup_memory(u);
-
-                        continue;
-                } else if (streq(l, "cgroup-realized")) {
-                        int b;
-
-                        b = parse_boolean(v);
-                        if (b < 0)
-                                log_unit_debug(u, "Failed to parse cgroup-realized bool %s, ignoring.", v);
-                        else
-                                u->cgroup_realized = b;
-
-                        continue;
-
-                } else if (streq(l, "cgroup-realized-mask")) {
-
-                        r = cg_mask_from_string(v, &u->cgroup_realized_mask);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse cgroup-realized-mask %s, ignoring.", v);
-                        continue;
-
-                } else if (streq(l, "cgroup-enabled-mask")) {
-
-                        r = cg_mask_from_string(v, &u->cgroup_enabled_mask);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse cgroup-enabled-mask %s, ignoring.", v);
-                        continue;
-
-                } else if (streq(l, "cgroup-invalidated-mask")) {
-
-                        r = cg_mask_from_string(v, &u->cgroup_invalidated_mask);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse cgroup-invalidated-mask %s, ignoring.", v);
-                        continue;
-
-                } else if (streq(l, "ref-uid")) {
-                        uid_t uid;
-
-                        r = parse_uid(v, &uid);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse referenced UID %s, ignoring.", v);
-                        else
-                                unit_ref_uid_gid(u, uid, GID_INVALID);
-
-                        continue;
-
-                } else if (streq(l, "ref-gid")) {
-                        gid_t gid;
-
-                        r = parse_gid(v, &gid);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse referenced GID %s, ignoring.", v);
-                        else
-                                unit_ref_uid_gid(u, UID_INVALID, gid);
-
-                        continue;
-
-                } else if (streq(l, "ref")) {
-
-                        r = strv_extend(&u->deserialized_refs, v);
-                        if (r < 0)
-                                return log_oom();
-
-                        continue;
-                } else if (streq(l, "invocation-id")) {
-                        sd_id128_t id;
-
-                        r = sd_id128_from_string(v, &id);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse invocation id %s, ignoring.", v);
-                        else {
-                                r = unit_set_invocation_id(u, id);
-                                if (r < 0)
-                                        log_unit_warning_errno(u, r, "Failed to set invocation ID for unit: %m");
-                        }
-
-                        continue;
-                } else if (streq(l, "freezer-state")) {
-                        FreezerState s;
-
-                        s = freezer_state_from_string(v);
-                        if (s < 0)
-                                log_unit_debug(u, "Failed to deserialize freezer-state '%s', ignoring.", v);
-                        else
-                                u->freezer_state = s;
-
-                        continue;
-                }
-
-                /* Check if this is an IP accounting metric serialization field */
-                m = string_table_lookup(ip_accounting_metric_field, ELEMENTSOF(ip_accounting_metric_field), l);
-                if (m >= 0) {
-                        uint64_t c;
-
-                        r = safe_atou64(v, &c);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse IP accounting value %s, ignoring.", v);
-                        else
-                                u->ip_accounting_extra[m] = c;
-                        continue;
-                }
-
-                m = string_table_lookup(io_accounting_metric_field_base, ELEMENTSOF(io_accounting_metric_field_base), l);
-                if (m >= 0) {
-                        uint64_t c;
-
-                        r = safe_atou64(v, &c);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse IO accounting base value %s, ignoring.", v);
-                        else
-                                u->io_accounting_base[m] = c;
-                        continue;
-                }
-
-                m = string_table_lookup(io_accounting_metric_field_last, ELEMENTSOF(io_accounting_metric_field_last), l);
-                if (m >= 0) {
-                        uint64_t c;
-
-                        r = safe_atou64(v, &c);
-                        if (r < 0)
-                                log_unit_debug(u, "Failed to parse IO accounting last value %s, ignoring.", v);
-                        else
-                                u->io_accounting_last[m] = c;
-                        continue;
-                }
-
-                if (unit_can_serialize(u)) {
-                        r = exec_runtime_deserialize_compat(u, l, v, fds);
-                        if (r < 0) {
-                                log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
-                                continue;
-                        }
-
-                        /* Returns positive if key was handled by the call */
-                        if (r > 0)
-                                continue;
-
-                        r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
-                        if (r < 0)
-                                log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
-                }
-        }
-
-        /* Versions before 228 did not carry a state change timestamp. In this case, take the current time. This is
-         * useful, so that timeouts based on this timestamp don't trigger too early, and is in-line with the logic from
-         * before 228 where the base for timeouts was not persistent across reboots. */
-
-        if (!dual_timestamp_is_set(&u->state_change_timestamp))
-                dual_timestamp_get(&u->state_change_timestamp);
-
-        /* Let's make sure that everything that is deserialized also gets any potential new cgroup settings applied
-         * after we are done. For that we invalidate anything already realized, so that we can realize it again. */
-        unit_invalidate_cgroup(u, _CGROUP_MASK_ALL);
-        unit_invalidate_cgroup_bpf(u);
-
-        return 0;
-}
-
-int unit_deserialize_skip(FILE *f) {
-        int r;
-        assert(f);
-
-        /* Skip serialized data for this unit. We don't know what it is. */
-
-        for (;;) {
-                _cleanup_free_ char *line = NULL;
-                char *l;
-
-                r = read_line(f, LONG_LINE_MAX, &line);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to read serialization line: %m");
-                if (r == 0)
-                        return 0;
-
-                l = strstrip(line);
-
-                /* End marker */
-                if (isempty(l))
-                        return 1;
-        }
-}
-
 int unit_add_node_dependency(Unit *u, const char *what, UnitDependency dep, UnitDependencyMask mask) {
         _cleanup_free_ char *e = NULL;
         Unit *device;
index 1b3b1463697bebb2ab2181fd7b7571e139276804..7c13e5087889d79a70fdbc25f2663b664621254e 100644 (file)
@@ -5,6 +5,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+#include "sd-id128.h"
+
 #include "bpf-program.h"
 #include "condition.h"
 #include "emergency-action.h"
@@ -118,9 +120,6 @@ typedef struct Unit {
         UnitLoadState load_state;
         Unit *merged_into;
 
-        FreezerState freezer_state;
-        sd_bus_message *pending_freezer_message;
-
         char *id;   /* The one special name that we use for identification */
         char *instance;
 
@@ -148,6 +147,16 @@ typedef struct Unit {
         /* If this is a transient unit we are currently writing, this is where we are writing it to */
         FILE *transient_file;
 
+        /* Freezer state */
+        sd_bus_message *pending_freezer_message;
+        FreezerState freezer_state;
+
+        /* Job timeout and action to take */
+        EmergencyAction job_timeout_action;
+        usec_t job_timeout;
+        usec_t job_running_timeout;
+        char *job_timeout_reboot_arg;
+
         /* If there is something to do with this unit, then this is the installed job for it */
         Job *job;
 
@@ -162,13 +171,6 @@ typedef struct Unit {
         sd_bus_track *bus_track;
         char **deserialized_refs;
 
-        /* Job timeout and action to take */
-        usec_t job_timeout;
-        usec_t job_running_timeout;
-        bool job_running_timeout_set:1;
-        EmergencyAction job_timeout_action;
-        char *job_timeout_reboot_arg;
-
         /* References to this */
         LIST_HEAD(UnitRef, refs_by_target);
 
@@ -240,6 +242,9 @@ typedef struct Unit {
         RateLimit start_ratelimit;
         EmergencyAction start_limit_action;
 
+        /* The unit has been marked for reload, restart, etc. Stored as 1u << marker1 | 1u << marker2. */
+        unsigned markers;
+
         /* What to do on failure or success */
         EmergencyAction success_action, failure_action;
         int success_action_exit_status, failure_action_exit_status;
@@ -357,6 +362,8 @@ typedef struct Unit {
 
         bool sent_dbus_new_signal:1;
 
+        bool job_running_timeout_set:1;
+
         bool in_audit:1;
         bool on_console:1;
 
@@ -721,8 +728,6 @@ int unit_freezer_state_kernel(Unit *u, FreezerState *ret);
 
 const char* unit_sub_state_to_string(Unit *u);
 
-void unit_dump(Unit *u, FILE *f, const char *prefix);
-
 bool unit_can_reload(Unit *u) _pure_;
 bool unit_can_start(Unit *u) _pure_;
 bool unit_can_stop(Unit *u) _pure_;
@@ -764,10 +769,6 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
 
 bool unit_can_serialize(Unit *u) _pure_;
 
-int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
-int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
-int unit_deserialize_skip(FILE *f);
-
 int unit_add_node_dependency(Unit *u, const char *what, UnitDependency d, UnitDependencyMask mask);
 int unit_add_blockdev_dependency(Unit *u, const char *what, UnitDependencyMask mask);
 
@@ -847,6 +848,7 @@ void unit_unref_uid_gid(Unit *u, bool destroy_now);
 
 void unit_notify_user_lookup(Unit *u, uid_t uid, gid_t gid);
 
+int unit_set_invocation_id(Unit *u, sd_id128_t id);
 int unit_acquire_invocation_id(Unit *u);
 
 bool unit_shall_confirm_spawn(Unit *u);
index f358a8699e8de7dc8005ef4df2886943900d55d9..894d681260f3c233d011577cff02353191f20f5e 100644 (file)
@@ -5587,17 +5587,26 @@ int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
 }
 
 int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
-        const char *s;
+        char type;
+        const char *contents, *s;
         int r;
 
         assert(m);
         assert(l);
 
-        r = sd_bus_message_enter_container(m, 'a', "s");
+        r = sd_bus_message_peek_type(m, &type, &contents);
+        if (r < 0)
+                return r;
+
+        if (type != SD_BUS_TYPE_ARRAY || !STR_IN_SET(contents, "s", "o", "g"))
+                return -ENXIO;
+
+        r = sd_bus_message_enter_container(m, 'a', NULL);
         if (r <= 0)
                 return r;
 
-        while ((r = sd_bus_message_read_basic(m, 's', &s)) > 0) {
+        /* sd_bus_message_read_basic() does content validation for us. */
+        while ((r = sd_bus_message_read_basic(m, *contents, &s)) > 0) {
                 r = strv_extend(l, s);
                 if (r < 0)
                         return r;
index 80d2a5d98b5846600209ffb49dd26d5c668ccc28..5ef3f30c70dced1e0165f2b22b3b75637c076684 100644 (file)
@@ -297,8 +297,7 @@ static int client(struct context *c) {
         assert_se(r >= 0);
         assert_se(streq(s, "<<<hallo>>>"));
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
         assert_se(r < 0);
@@ -306,6 +305,12 @@ static int client(struct context *c) {
 
         sd_bus_error_free(&error);
 
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, NULL); /* NULL and "" are equivalent */
+        assert_se(r < 0);
+        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
+
+        sd_bus_error_free(&error);
+
         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
         assert_se(r < 0);
         assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
@@ -319,8 +324,7 @@ static int client(struct context *c) {
         assert_se(r >= 0);
         assert_se(streq(s, "<<<hallo>>>"));
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
         r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
         assert_se(r >= 0);
@@ -332,8 +336,7 @@ static int client(struct context *c) {
         assert_se(r >= 0);
         assert_se(streq(s, "test"));
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
         r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
         assert_se(r >= 0);
@@ -352,8 +355,16 @@ static int client(struct context *c) {
         assert_se(r >= 0);
         fputs(s, stdout);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, NULL); /* NULL and "" are equivalent */
+        assert_se(r >= 0);
+
+        r = sd_bus_message_read(reply, "s", &s);
+        assert_se(r >= 0);
+        fputs(s, stdout);
+
+        reply = sd_bus_message_unref(reply);
 
         r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
         assert_se(r >= 0);
@@ -362,66 +373,60 @@ static int client(struct context *c) {
         assert_se(r >= 0);
         log_info("read %s", s);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, NULL);
         assert_se(r >= 0);
 
         r = sd_bus_message_read(reply, "s", &s);
         assert_se(r >= 0);
         fputs(s, stdout);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, NULL);
         assert_se(r >= 0);
 
         r = sd_bus_message_read(reply, "s", &s);
         assert_se(r >= 0);
         fputs(s, stdout);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, NULL);
         assert_se(r >= 0);
 
         r = sd_bus_message_read(reply, "s", &s);
         assert_se(r >= 0);
         fputs(s, stdout);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", NULL);
         assert_se(r >= 0);
 
         sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
         assert_se(r < 0);
         assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
         sd_bus_error_free(&error);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, NULL);
         assert_se(r < 0);
         assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
         sd_bus_error_free(&error);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, NULL);
         assert_se(r >= 0);
 
         sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, NULL);
         assert_se(r >= 0);
 
         r = sd_bus_process(bus, &reply);
@@ -430,10 +435,9 @@ static int client(struct context *c) {
         assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
         sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, NULL);
         assert_se(r >= 0);
 
         r = sd_bus_process(bus, &reply);
@@ -442,10 +446,9 @@ static int client(struct context *c) {
         assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
         sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, NULL);
         assert_se(r >= 0);
 
         r = sd_bus_process(bus, &reply);
@@ -454,10 +457,9 @@ static int client(struct context *c) {
         assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
         sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, NULL);
         assert_se(r >= 0);
 
         r = sd_bus_process(bus, &reply);
@@ -466,10 +468,9 @@ static int client(struct context *c) {
         assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
         sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, NULL);
         assert_se(r >= 0);
 
         r = sd_bus_process(bus, &reply);
@@ -478,10 +479,9 @@ static int client(struct context *c) {
         assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
         sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, NULL);
         assert_se(r >= 0);
 
         r = sd_bus_process(bus, &reply);
@@ -490,10 +490,9 @@ static int client(struct context *c) {
         assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
         sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
 
-        sd_bus_message_unref(reply);
-        reply = NULL;
+        reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, NULL);
         assert_se(r >= 0);
 
         sd_bus_flush(bus);
similarity index 97%
rename from src/core/macros.systemd.in
rename to src/rpm/macros.systemd.in
index 1c40328db0f26ab34852be409651887c3c1fdea2..24996de10ab46710ddc670ef6832a70267721e26 100644 (file)
@@ -82,7 +82,9 @@ fi \
 %{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# systemd_postun_with_restart}} \
 if [ $1 -ge 1 ] && [ -x @bindir@/systemctl ]; then \
         # Package upgrade, not uninstall \
-        @bindir@/systemctl try-restart %{?*} || : \
+        for unit in %{?*}; do \
+                @bindir@/systemctl set-property $unit Markers=+needs-restart || : \
+        done \
 fi \
 %{nil}
 
diff --git a/src/rpm/meson.build b/src/rpm/meson.build
new file mode 100644 (file)
index 0000000..d299b18
--- /dev/null
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+configure_file(
+        input : 'macros.systemd.in',
+        output : 'macros.systemd',
+        configuration : substs,
+        install_dir : rpmmacrosdir == 'no' ? '' : rpmmacrosdir)
+
+# Those doesn't get installed anywhere, one of them needs to included in the
+# rpm spec file definition.
+configure_file(
+        input : 'triggers.systemd.in',
+        output : 'triggers.systemd',
+        configuration : substs)
+configure_file(
+        input : 'triggers.systemd.sh.in',
+        output : 'triggers.systemd.sh',
+        configuration : substs)
similarity index 73%
rename from src/core/triggers.systemd.in
rename to src/rpm/triggers.systemd.in
index 2d25db3696d54008af5f2677b1b62526d094787d..3a89f9169d7afb568c37cde1b8a0ec0a122f677d 100644 (file)
@@ -6,14 +6,13 @@
 
 # The contents of this are an example to be copied into systemd.spec.
 #
-# Minimum rpm version supported: 4.13.0
+# Minimum rpm version supported: 4.14.0
 
 %transfiletriggerin -P 900900 -p <lua> -- @systemunitdir@ /etc/systemd/system
 -- This script will run after any package is initially installed or
 -- upgraded. We care about the case where a package is initially
 -- installed, because other cases are covered by the *un scriptlets,
 -- so sometimes we will reload needlessly.
-
 if posix.access("/run/systemd/system") then
     pid = posix.fork()
     if pid == 0 then
@@ -21,33 +20,22 @@ if posix.access("/run/systemd/system") then
     elseif pid > 0 then
         posix.wait(pid)
     end
+
+    pid = posix.fork()
+    if pid == 0 then
+        assert(posix.exec("%{_bindir}/systemctl", "reload-or-restart", "--marked"))
+    elseif pid > 0 then
+        posix.wait(pid)
+    end
 end
 
-%transfiletriggerun -p <lua> -- @systemunitdir@ /etc/systemd/system
+%transfiletriggerpostun -P 1000100 -p <lua> -- @systemunitdir@ /etc/systemd/system
 -- On removal, we need to run daemon-reload after any units have been
--- removed. %transfiletriggerpostun would be ideal, but it does not get
--- executed for some reason.
+-- removed.
 -- On upgrade, we need to run daemon-reload after any new unit files
 -- have been installed, but before %postun scripts in packages get
--- executed. %transfiletriggerun gets the right list of files
--- but it is invoked too early (before changes happen).
--- %filetriggerpostun happens at the right time, but it fires for
--- every package.
--- To execute the reload at the right time, we create a state
--- file in %transfiletriggerun and execute the daemon-reload in
--- the first %filetriggerpostun.
-
+-- executed.
 if posix.access("/run/systemd/system") then
-    posix.mkdir("%{_localstatedir}/lib")
-    posix.mkdir("%{_localstatedir}/lib/rpm-state")
-    posix.mkdir("%{_localstatedir}/lib/rpm-state/systemd")
-    io.open("%{_localstatedir}/lib/rpm-state/systemd/needs-reload", "w")
-end
-
-%filetriggerpostun -P 1000100 -p <lua> -- @systemunitdir@ /etc/systemd/system
-if posix.access("%{_localstatedir}/lib/rpm-state/systemd/needs-reload") then
-    posix.unlink("%{_localstatedir}/lib/rpm-state/systemd/needs-reload")
-    posix.rmdir("%{_localstatedir}/lib/rpm-state/systemd")
     pid = posix.fork()
     if pid == 0 then
         assert(posix.exec("%{_bindir}/systemctl", "daemon-reload"))
@@ -56,33 +44,31 @@ if posix.access("%{_localstatedir}/lib/rpm-state/systemd/needs-reload") then
     end
 end
 
-%transfiletriggerin -P 100700 -p <lua> -- @sysusersdir@
--- This script will process files installed in @sysusersdir@ to create
--- specified users automatically. The priority is set such that it
--- will run before the tmpfiles file trigger.
+%transfiletriggerpostun -P 10000 -p <lua> -- @systemunitdir@ /etc/systemd/system
+-- We restart remaining services that should be restarted here.
 if posix.access("/run/systemd/system") then
     pid = posix.fork()
     if pid == 0 then
-        assert(posix.exec("%{_bindir}/systemd-sysusers"))
+        assert(posix.exec("%{_bindir}/systemctl", "reload-or-restart", "--marked"))
     elseif pid > 0 then
         posix.wait(pid)
     end
 end
 
-%transfiletriggerin -P 100500 -p <lua> -- @tmpfilesdir@
--- This script will process files installed in @tmpfilesdir@ to create
--- tmpfiles automatically. The priority is set such that it will run
--- after the sysusers file trigger, but before any other triggers.
+%transfiletriggerin -P 100700 -p <lua> -- @sysusersdir@
+-- This script will process files installed in @sysusersdir@ to create
+-- specified users automatically. The priority is set such that it
+-- will run before the tmpfiles file trigger.
 if posix.access("/run/systemd/system") then
     pid = posix.fork()
     if pid == 0 then
-        assert(posix.exec("%{_bindir}/systemd-tmpfiles", "--create"))
+        assert(posix.exec("%{_bindir}/systemd-sysusers"))
     elseif pid > 0 then
         posix.wait(pid)
     end
 end
 
-%transfiletriggerin -p <lua> -- @udevhwdbdir@
+%transfiletriggerin -P 1000700 udev -p <lua> -- @udevhwdbdir@
 -- This script will automatically invoke hwdb update if files have been
 -- installed or updated in @udevhwdbdir@.
 if posix.access("/run/systemd/system") then
@@ -94,7 +80,7 @@ if posix.access("/run/systemd/system") then
     end
 end
 
-%transfiletriggerin -p <lua> -- @catalogdir@
+%transfiletriggerin -P 1000700 -p <lua> -- @catalogdir@
 -- This script will automatically invoke journal catalog update if files
 -- have been installed or updated in @catalogdir@.
 if posix.access("/run/systemd/system") then
@@ -106,37 +92,50 @@ if posix.access("/run/systemd/system") then
     end
 end
 
-%transfiletriggerin -p <lua> -- @udevrulesdir@
--- This script will automatically update udev with new rules if files
--- have been installed or updated in @udevrulesdir@.
+%transfiletriggerin -P 1000700 -p <lua> -- @binfmtdir@
+-- This script will automatically apply binfmt rules if files have been
+-- installed or updated in @binfmtdir@.
 if posix.access("/run/systemd/system") then
     pid = posix.fork()
     if pid == 0 then
-        assert(posix.exec("%{_bindir}/udevadm", "control", "--reload"))
+        assert(posix.exec("@rootlibexecdir@/systemd-binfmt"))
     elseif pid > 0 then
         posix.wait(pid)
     end
 end
 
-%transfiletriggerin -p <lua> -- @sysctldir@
--- This script will automatically apply sysctl rules if files have been
--- installed or updated in @sysctldir@.
+%transfiletriggerin -P 1000600 -p <lua> -- @tmpfilesdir@
+-- This script will process files installed in @tmpfilesdir@ to create
+-- tmpfiles automatically. The priority is set such that it will run
+-- after the sysusers file trigger, but before any other triggers.
 if posix.access("/run/systemd/system") then
     pid = posix.fork()
     if pid == 0 then
-        assert(posix.exec("@rootlibexecdir@/systemd-sysctl"))
+        assert(posix.exec("%{_bindir}/systemd-tmpfiles", "--create"))
     elseif pid > 0 then
         posix.wait(pid)
     end
 end
 
-%transfiletriggerin -p <lua> -- @binfmtdir@
--- This script will automatically apply binfmt rules if files have been
--- installed or updated in @binfmtdir@.
+%transfiletriggerin -P 1000600 udev -p <lua> -- @udevrulesdir@
+-- This script will automatically update udev with new rules if files
+-- have been installed or updated in @udevrulesdir@.
 if posix.access("/run/systemd/system") then
     pid = posix.fork()
     if pid == 0 then
-        assert(posix.exec("@rootlibexecdir@/systemd-binfmt"))
+        assert(posix.exec("%{_bindir}/udevadm", "control", "--reload"))
+    elseif pid > 0 then
+        posix.wait(pid)
+    end
+end
+
+%transfiletriggerin -P 1000500 -p <lua> -- @sysctldir@
+-- This script will automatically apply sysctl rules if files have been
+-- installed or updated in @sysctldir@.
+if posix.access("/run/systemd/system") then
+    pid = posix.fork()
+    if pid == 0 then
+        assert(posix.exec("@rootlibexecdir@/systemd-sysctl"))
     elseif pid > 0 then
         posix.wait(pid)
     end
diff --git a/src/rpm/triggers.systemd.sh.in b/src/rpm/triggers.systemd.sh.in
new file mode 100644 (file)
index 0000000..0080040
--- /dev/null
@@ -0,0 +1,89 @@
+#  -*- Mode: rpm-spec; indent-tabs-mode: nil -*- */
+#  SPDX-License-Identifier: LGPL-2.1-or-later
+#
+#  This file is part of systemd.
+#
+#  Copyright 2018 Neal Gompa
+
+# The contents of this are an example to be copied into systemd.spec.
+#
+# Minimum rpm version supported: 4.14.0
+
+%transfiletriggerin -P 900900 -- @systemunitdir@ /etc/systemd/system
+# This script will run after any package is initially installed or
+# upgraded. We care about the case where a package is initially
+# installed, because other cases are covered by the *un scriptlets,
+# so sometimes we will reload needlessly.
+if test -d "/run/systemd/system"; then
+  %{_bindir}/systemctl daemon-reload || :
+  %{_bindir}/systemctl reload-or-restart --marked || :
+fi
+
+%transfiletriggerpostun -P 1000100 -- @systemunitdir@ /etc/systemd/system
+# On removal, we need to run daemon-reload after any units have been
+# removed.
+# On upgrade, we need to run daemon-reload after any new unit files
+# have been installed, but before %postun scripts in packages get
+# executed.
+if test -d "/run/systemd/system"; then
+  %{_bindir}/systemctl daemon-reload || :
+fi
+
+%transfiletriggerpostun -P 10000 -- @systemunitdir@ /etc/systemd/system
+# We restart remaining services that should be restarted here.
+if test -d "/run/systemd/system"; then
+  %{_bindir}/systemctl reload-or-restart --marked || :
+fi
+
+%transfiletriggerin -P 1000700 -- @sysusersdir@
+# This script will process files installed in @sysusersdir@ to create
+# specified users automatically. The priority is set such that it
+# will run before the tmpfiles file trigger.
+if test -d "/run/systemd/system"; then
+  %{_bindir}/systemd-sysusers || :
+fi
+
+%transfiletriggerin -P 1000700 udev -- @udevhwdbdir@
+# This script will automatically invoke hwdb update if files have been
+# installed or updated in @udevhwdbdir@.
+if test -d "/run/systemd/system"; then
+  %{_bindir}/systemd-hwdb update || :
+fi
+
+%transfiletriggerin -P 1000700 -- @catalogdir@
+# This script will automatically invoke journal catalog update if files
+# have been installed or updated in @catalogdir@.
+if test -d "/run/systemd/system"; then
+  %{_bindir}/journalctl --update-catalog || :
+fi
+
+%transfiletriggerin -P 1000700 -- @binfmtdir@
+# This script will automatically apply binfmt rules if files have been
+# installed or updated in @binfmtdir@.
+if test -d "/run/systemd/system"; then
+  # systemd-binfmt might fail if binfmt_misc kernel module is not loaded
+  # during install
+  @rootlibexecdir@/systemd-binfmt || :
+fi
+
+%transfiletriggerin -P 1000600 -- @tmpfilesdir@
+# This script will process files installed in @tmpfilesdir@ to create
+# tmpfiles automatically. The priority is set such that it will run
+# after the sysusers file trigger, but before any other triggers.
+if test -d "/run/systemd/system"; then
+  %{_bindir}/systemd-tmpfiles --create || :
+fi
+
+%transfiletriggerin -P 1000600 udev -- @udevrulesdir@
+# This script will automatically update udev with new rules if files
+# have been installed or updated in @udevrulesdir@.
+if test -e /run/udev/control; then
+  %{_bindir}/udevadm control --reload || :
+fi
+
+%transfiletriggerin -P 1000500 -- @sysctldir@
+# This script will automatically apply sysctl rules if files have been
+# installed or updated in @sysctldir@.
+if test -d "/run/systemd/system"; then
+  @rootlibexecdir@/systemd-sysctl || :
+fi
index 5bbaa07dd1c75632007bfb2a2cdd1110652e73da..2ce507aa1ce67a9a794cec5b8b783cffd708bedf 100644 (file)
@@ -2192,7 +2192,8 @@ static int bus_append_unit_property(sd_bus_message *m, const char *field, const
 
         if (unit_dependency_from_string(field) >= 0 ||
             STR_IN_SET(field, "Documentation",
-                              "RequiresMountsFor"))
+                              "RequiresMountsFor",
+                              "Markers"))
                 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
 
         t = condition_type_from_string(field);
index 3d99b0deb60f2b6411bc1654ed32cfa3010e9fdd..d83736e94aa22dd4112280e1b81c46227c22c7ea 100644 (file)
@@ -14,7 +14,7 @@ static int check_unit_generic(int code, const UnitActiveState good_states[], int
         UnitActiveState active_state;
         sd_bus *bus;
         char **name;
-        int r, i;
+        int r;
         bool found = false;
 
         r = acquire_bus(BUS_MANAGER, &bus);
@@ -33,7 +33,7 @@ static int check_unit_generic(int code, const UnitActiveState good_states[], int
                 if (!arg_quiet)
                         puts(unit_active_state_to_string(active_state));
 
-                for (i = 0; i < nb_states; ++i)
+                for (int i = 0; i < nb_states; ++i)
                         if (good_states[i] == active_state)
                                 found = true;
         }
index babd5902c9855330e8107042ca9a65bb7c604088..de1d016bb3b3ebbadcc4e1990cebdf231bfe35af 100644 (file)
@@ -9,7 +9,7 @@
 
 static int show_installation_targets_client_side(const char *name) {
         UnitFileChange *changes = NULL;
-        size_t n_changes = 0, i;
+        size_t n_changes = 0;
         UnitFileFlags flags;
         char **p;
         int r;
@@ -22,7 +22,7 @@ static int show_installation_targets_client_side(const char *name) {
         if (r < 0)
                 return log_error_errno(r, "Failed to get file links for %s: %m", name);
 
-        for (i = 0; i < n_changes; i++)
+        for (size_t i = 0; i < n_changes; i++)
                 if (changes[i].type == UNIT_FILE_UNLINK)
                         printf("  %s\n", changes[i].path);
 
index fbb81d90fa2fa3196a6e0053c2277ae395f7c494..5d19f338d87dedc4b96ad57295e2ac2b4d1ee77f 100644 (file)
@@ -12,11 +12,10 @@ static int list_dependencies_print(const char *name, int level, unsigned branche
         _cleanup_free_ char *n = NULL;
         size_t max_len = MAX(columns(),20u);
         size_t len = 0;
-        int i;
 
         if (!arg_plain) {
 
-                for (i = level - 1; i >= 0; i--) {
+                for (int i = level - 1; i >= 0; i--) {
                         len += 2;
                         if (len > max_len - 3 && !arg_full) {
                                 printf("%s...\n",max_len % 2 ? "" : " ");
index 8b028c013aef23591a940c33baec72c6da4966c3..27eecb548ca9f8f9b349cf66a29a1e91eb27746a 100644 (file)
@@ -58,7 +58,6 @@ struct job_info {
 
 static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
         _cleanup_(table_unrefp) Table *table = NULL;
-        const struct job_info *j;
         const char *on, *off;
         int r;
 
@@ -86,7 +85,7 @@ static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n
 
         (void) table_set_empty_string(table, "-");
 
-        for (j = jobs; j < jobs + n; j++) {
+        for (const struct job_info *j = jobs; j < jobs + n; j++) {
                 if (streq(j->state, "running"))
                         on = ansi_highlight();
                 else
index 48d0e8bde477673b53b4be38ccbaa05b5bceebe3..63adcec5f34fb4f06cae6346d12ba9c523dc3059 100644 (file)
@@ -33,12 +33,10 @@ void machine_info_clear(struct machine_info *info) {
 }
 
 static void free_machines_list(struct machine_info *machine_infos, int n) {
-        int i;
-
         if (!machine_infos)
                 return;
 
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
                 machine_info_clear(&machine_infos[i]);
 
         free(machine_infos);
@@ -150,7 +148,6 @@ static int get_machine_list(
 
 static int output_machines_list(struct machine_info *machine_infos, unsigned n) {
         _cleanup_(table_unrefp) Table *table = NULL;
-        struct machine_info *m;
         bool state_missing = false;
         int r;
 
@@ -172,7 +169,7 @@ static int output_machines_list(struct machine_info *machine_infos, unsigned n)
 
         (void) table_set_empty_string(table, "-");
 
-        for (m = machine_infos; m < machine_infos + n; m++) {
+        for (struct machine_info *m = machine_infos; m < machine_infos + n; m++) {
                 _cleanup_free_ char *mname = NULL;
                 const char *on_state = "", *on_failed = "";
                 bool circle = false;
index e1bf8766205b1fa4710079d037a299aa0c7f2b19..6da2914eff1b0a355f60f66adecb884faaa5157b 100644 (file)
@@ -136,7 +136,6 @@ static int output_unit_file_list(const UnitFileList *units, unsigned c) {
 int list_unit_files(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_free_ UnitFileList *units = NULL;
-        UnitFileList *unit;
         size_t size = 0;
         unsigned c = 0;
         const char *state;
@@ -265,7 +264,7 @@ int list_unit_files(int argc, char *argv[], void *userdata) {
                 return r;
 
         if (install_client_side())
-                for (unit = units; unit < units + c; unit++)
+                for (UnitFileList *unit = units; unit < units + c; unit++)
                         free(unit->path);
 
         if (c == 0)
index 7f0e79eedd6c34242c5d38d777c9299652d9875f..a413ef6d5b22bbbd7af19d8d870eae125caa62bc 100644 (file)
@@ -351,7 +351,6 @@ static int socket_info_compare(const struct socket_info *a, const struct socket_
 
 static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
         _cleanup_(table_unrefp) Table *table = NULL;
-        struct socket_info *s;
         const char *on, *off;
         int r;
 
@@ -373,7 +372,7 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
         (void) table_set_empty_string(table, "-");
 
         if (cs) {
-                for (s = socket_infos; s < socket_infos + cs; s++) {
+                for (struct socket_info *s = socket_infos; s < socket_infos + cs; s++) {
                         _cleanup_free_ char *j = NULL;
                         const char *path;
 
@@ -432,8 +431,6 @@ int list_sockets(int argc, char *argv[], void *userdata) {
         _cleanup_strv_free_ char **sockets_with_suffix = NULL;
         _cleanup_free_ UnitInfo *unit_infos = NULL;
         _cleanup_free_ struct socket_info *socket_infos = NULL;
-        const UnitInfo *u;
-        struct socket_info *s;
         unsigned cs = 0;
         size_t size = 0;
         int r, n;
@@ -454,9 +451,9 @@ int list_sockets(int argc, char *argv[], void *userdata) {
                 if (n < 0)
                         return n;
 
-                for (u = unit_infos; u < unit_infos + n; u++) {
+                for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) {
                         _cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
-                        int i, c;
+                        int c;
 
                         if (!endswith(u->id, ".socket"))
                                 continue;
@@ -476,7 +473,7 @@ int list_sockets(int argc, char *argv[], void *userdata) {
                                 goto cleanup;
                         }
 
-                        for (i = 0; i < c; i++)
+                        for (int i = 0; i < c; i++)
                                 socket_infos[cs + i] = (struct socket_info) {
                                         .machine = u->machine,
                                         .id = u->id,
@@ -499,7 +496,7 @@ int list_sockets(int argc, char *argv[], void *userdata) {
 
  cleanup:
         assert(cs == 0 || socket_infos);
-        for (s = socket_infos; s < socket_infos + cs; s++) {
+        for (struct socket_info *s = socket_infos; s < socket_infos + cs; s++) {
                 free(s->type);
                 free(s->path);
                 if (s->own_triggered)
@@ -604,7 +601,6 @@ static int timer_info_compare(const struct timer_info *a, const struct timer_inf
 
 static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
         _cleanup_(table_unrefp) Table *table = NULL;
-        struct timer_info *t;
         const char *on, *off;
         int r;
 
@@ -620,34 +616,34 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
 
         (void) table_set_empty_string(table, "-");
 
-        if (n > 0) {
-                for (t = timer_infos; t < timer_infos + n; t++) {
-                        _cleanup_free_ char *j = NULL, *activates = NULL;
-                        const char *unit;
-
-                        if (t->machine) {
-                                j = strjoin(t->machine, ":", t->id);
-                                if (!j)
-                                        return log_oom();
-                                unit = j;
-                        } else
-                                unit = t->id;
+        for (struct timer_info *t = timer_infos; t < timer_infos + n; t++) {
+                _cleanup_free_ char *j = NULL, *activates = NULL;
+                const char *unit;
 
-                        activates = strv_join(t->triggered, ", ");
-                        if (!activates)
+                if (t->machine) {
+                        j = strjoin(t->machine, ":", t->id);
+                        if (!j)
                                 return log_oom();
+                        unit = j;
+                } else
+                        unit = t->id;
 
-                        r = table_add_many(table,
-                                           TABLE_TIMESTAMP, t->next_elapse,
-                                           TABLE_TIMESTAMP_RELATIVE, t->next_elapse,
-                                           TABLE_TIMESTAMP, t->last_trigger,
-                                           TABLE_TIMESTAMP_RELATIVE, t->last_trigger,
-                                           TABLE_STRING, unit,
-                                           TABLE_STRING, activates);
-                        if (r < 0)
-                                return table_log_add_error(r);
-                }
+                activates = strv_join(t->triggered, ", ");
+                if (!activates)
+                        return log_oom();
 
+                r = table_add_many(table,
+                                   TABLE_TIMESTAMP, t->next_elapse,
+                                   TABLE_TIMESTAMP_RELATIVE, t->next_elapse,
+                                   TABLE_TIMESTAMP, t->last_trigger,
+                                   TABLE_TIMESTAMP_RELATIVE, t->last_trigger,
+                                   TABLE_STRING, unit,
+                                   TABLE_STRING, activates);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
+
+        if (n > 0) {
                 on = ansi_highlight();
                 off = ansi_normal();
         } else {
@@ -699,8 +695,6 @@ int list_timers(int argc, char *argv[], void *userdata) {
         _cleanup_strv_free_ char **timers_with_suffix = NULL;
         _cleanup_free_ struct timer_info *timer_infos = NULL;
         _cleanup_free_ UnitInfo *unit_infos = NULL;
-        struct timer_info *t;
-        const UnitInfo *u;
         size_t size = 0;
         int n, c = 0;
         dual_timestamp nw;
@@ -724,7 +718,7 @@ int list_timers(int argc, char *argv[], void *userdata) {
 
                 dual_timestamp_get(&nw);
 
-                for (u = unit_infos; u < unit_infos + n; u++) {
+                for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) {
                         _cleanup_strv_free_ char **triggered = NULL;
                         dual_timestamp next = DUAL_TIMESTAMP_NULL;
                         usec_t m, last = 0;
@@ -764,7 +758,7 @@ int list_timers(int argc, char *argv[], void *userdata) {
         output_timers_list(timer_infos, c);
 
  cleanup:
-        for (t = timer_infos; t < timer_infos + c; t++)
+        for (struct timer_info *t = timer_infos; t < timer_infos + c; t++)
                 strv_free(t->triggered);
 
         return r;
index 9b04b698be1160de91eb1d7fefbc5361bbbb5d0d..57e708095da849d3241b26e244f3358d2a202c8f 100644 (file)
@@ -1103,7 +1103,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
 
                 } else if (endswith(name, "ExitStatus") && streq(contents, "aiai")) {
                         const int32_t *status, *signal;
-                        size_t n_status, n_signal, i;
+                        size_t n_status, n_signal;
 
                         r = sd_bus_message_enter_container(m, 'r', "aiai");
                         if (r < 0)
@@ -1132,7 +1132,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                                         fputc('=', stdout);
                                 }
 
-                                for (i = 0; i < n_status; i++) {
+                                for (size_t i = 0; i < n_status; i++) {
                                         if (first)
                                                 first = false;
                                         else
@@ -1141,7 +1141,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                                         printf("%"PRIi32, status[i]);
                                 }
 
-                                for (i = 0; i < n_signal; i++) {
+                                for (size_t i = 0; i < n_signal; i++) {
                                         const char *str;
 
                                         str = signal_to_string((int) signal[i]);
@@ -1933,7 +1933,6 @@ static int show_all(
 
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_free_ UnitInfo *unit_infos = NULL;
-        const UnitInfo *u;
         unsigned c;
         int r, ret = 0;
 
@@ -1947,7 +1946,7 @@ static int show_all(
 
         typesafe_qsort(unit_infos, c, unit_info_compare);
 
-        for (u = unit_infos; u < unit_infos + c; u++) {
+        for (const UnitInfo *u = unit_infos; u < unit_infos + c; u++) {
                 _cleanup_free_ char *p = NULL;
 
                 p = unit_dbus_path_from_name(u->id);
index b398e77eb281f0f65dcb4da46a6134c19fccdcdf..c40e807212d9d48bddd41ee929bc74e410307069 100644 (file)
@@ -36,9 +36,7 @@ static const struct {
 };
 
 static const char *verb_to_method(const char *verb) {
-       size_t i;
-
-       for (i = 0; i < ELEMENTSOF(unit_actions); i++)
+       for (size_t i = 0; i < ELEMENTSOF(unit_actions); i++)
                 if (streq_ptr(unit_actions[i].verb, verb))
                         return unit_actions[i].method;
 
@@ -46,9 +44,7 @@ static const char *verb_to_method(const char *verb) {
 }
 
 static const char *verb_to_job_type(const char *verb) {
-       size_t i;
-
-       for (i = 0; i < ELEMENTSOF(unit_actions); i++)
+       for (size_t i = 0; i < ELEMENTSOF(unit_actions); i++)
                 if (streq_ptr(unit_actions[i].verb, verb))
                         return unit_actions[i].job_type;
 
@@ -180,6 +176,43 @@ fail:
         return r;
 }
 
+static int enqueue_marked_jobs(
+                sd_bus *bus,
+                BusWaitForJobs *w) {
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        int r;
+
+        log_debug("%s dbus call org.freedesktop.systemd1.Manager EnqueueMarkedJobs()",
+                  arg_dry_run ? "Would execute" : "Executing");
+
+        if (arg_dry_run)
+                return 0;
+
+        r = bus_call_method(bus, bus_systemd_mgr, "EnqueueMarkedJobs", &error, &reply, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to start jobs: %s", bus_error_message(&error, r));
+
+        _cleanup_strv_free_ char **paths = NULL;
+        r = sd_bus_message_read_strv(reply, &paths);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        if (w) {
+                char **path;
+
+                STRV_FOREACH(path, paths) {
+                        log_debug("Adding %s to the set", *path);
+                        r = bus_wait_for_jobs_add(w, *path);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to watch job %s: %m", *path);
+                }
+        }
+
+        return 0;
+}
+
 const struct action_metadata action_table[_ACTION_MAX] = {
         [ACTION_HALT]                   = { SPECIAL_HALT_TARGET,                   "halt",                   "replace-irreversibly" },
         [ACTION_POWEROFF]               = { SPECIAL_POWEROFF_TARGET,               "poweroff",               "replace-irreversibly" },
@@ -200,9 +233,7 @@ const struct action_metadata action_table[_ACTION_MAX] = {
 };
 
 enum action verb_to_action(const char *verb) {
-        enum action i;
-
-        for (i = 0; i < _ACTION_MAX; i++)
+        for (enum action i = 0; i < _ACTION_MAX; i++)
                 if (streq_ptr(action_table[i].verb, verb))
                         return i;
 
@@ -271,7 +302,7 @@ int start_unit(int argc, char *argv[], void *userdata) {
                                 job_type = "start";
                                 mode = "isolate";
                                 suffix = ".target";
-                        } else {
+                        } else if (!arg_marked) {
                                 /* A command in style of "systemctl start <unit1> <unit2> …", "sysemctl stop <unit1> <unit2> …" and so on */
                                 method = verb_to_method(argv[0]);
                                 job_type = verb_to_job_type(argv[0]);
@@ -295,7 +326,7 @@ int start_unit(int argc, char *argv[], void *userdata) {
                 names = strv_new(one_name);
                 if (!names)
                         return log_oom();
-        } else {
+        } else if (!arg_marked) {
                 bool expanded;
 
                 r = expand_unit_names(bus, strv_skip(argv, 1), suffix, &names, &expanded);
@@ -328,19 +359,23 @@ int start_unit(int argc, char *argv[], void *userdata) {
                         return log_error_errno(r, "Failed to allocate unit watch context: %m");
         }
 
-        STRV_FOREACH(name, names) {
-                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        if (arg_marked)
+                ret = enqueue_marked_jobs(bus, w);
 
-                r = start_unit_one(bus, method, job_type, *name, mode, &error, w, wu);
-                if (ret == EXIT_SUCCESS && r < 0)
-                        ret = translate_bus_error_to_exit_status(r, &error);
+        else
+                STRV_FOREACH(name, names) {
+                        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
 
-                if (r >= 0 && streq(method, "StopUnit")) {
-                        r = strv_push(&stopped_units, *name);
-                        if (r < 0)
-                                return log_oom();
+                        r = start_unit_one(bus, method, job_type, *name, mode, &error, w, wu);
+                        if (ret == EXIT_SUCCESS && r < 0)
+                                ret = translate_bus_error_to_exit_status(r, &error);
+
+                        if (r >= 0 && streq(method, "StopUnit")) {
+                                r = strv_push(&stopped_units, *name);
+                                if (r < 0)
+                                        return log_oom();
+                        }
                 }
-        }
 
         if (!arg_no_block) {
                 const char* extra_args[4];
index 89c342a0b10c0349a447b79f0bafaf3ad1a5cdd2..d1490c906d080a0f79023cd4ebfeb3c3344e682f 100644 (file)
@@ -62,9 +62,7 @@ int acquire_bus(BusFocus focus, sd_bus **ret) {
 }
 
 void release_busses(void) {
-        BusFocus w;
-
-        for (w = 0; w < _BUS_FOCUS_MAX; w++)
+        for (BusFocus w = 0; w < _BUS_FOCUS_MAX; w++)
                 buses[w] = sd_bus_flush_close_unref(buses[w]);
 }
 
@@ -237,7 +235,7 @@ int get_unit_list(
 int expand_unit_names(sd_bus *bus, char **names, const char* suffix, char ***ret, bool *ret_expanded) {
         _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
         char **name;
-        int r, i;
+        int r;
 
         assert(bus);
         assert(ret);
@@ -272,7 +270,7 @@ int expand_unit_names(sd_bus *bus, char **names, const char* suffix, char ***ret
                 n = strv_length(mangled);
                 allocated = n + 1;
 
-                for (i = 0; i < r; i++) {
+                for (int i = 0; i < r; i++) {
                         if (!GREEDY_REALLOC(mangled, allocated, n+2))
                                 return log_oom();
 
index 08a54a469e70c53ea41fa7828403d5c93295bde7..b82e541d7a6a03d8b78b76648c6b1bcd96a40853 100644 (file)
@@ -109,6 +109,7 @@ char **arg_clean_what = NULL;
 TimestampStyle arg_timestamp_style = TIMESTAMP_PRETTY;
 bool arg_read_only = false;
 bool arg_mkdir = false;
+bool arg_marked = false;
 
 STATIC_DESTRUCTOR_REGISTER(arg_wall, strv_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
@@ -296,6 +297,7 @@ static int systemctl_help(void) {
                "                         'us+utc': 'Day YYYY-MM-DD HH:MM:SS.UUUUUU UTC\n"
                "     --read-only         Create read-only bind mount\n"
                "     --mkdir             Create directory before mounting, if missing\n"
+               "     --marked            Restart/reload previously marked units\n"
                "\nSee the %2$s for details.\n",
                program_invocation_short_name,
                link,
@@ -414,6 +416,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_TIMESTAMP_STYLE,
                 ARG_READ_ONLY,
                 ARG_MKDIR,
+                ARG_MARKED,
         };
 
         static const struct option options[] = {
@@ -472,6 +475,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "timestamp",           required_argument, NULL, ARG_TIMESTAMP_STYLE     },
                 { "read-only",           no_argument,       NULL, ARG_READ_ONLY           },
                 { "mkdir",               no_argument,       NULL, ARG_MKDIR               },
+                { "marked",              no_argument,       NULL, ARG_MARKED              },
                 {}
         };
 
@@ -882,6 +886,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_mkdir = true;
                         break;
 
+                case ARG_MARKED:
+                        arg_marked = true;
+                        break;
+
                 case '.':
                         /* Output an error mimicking getopt, and print a hint afterwards */
                         log_error("%s: invalid option -- '.'", program_invocation_name);
@@ -905,6 +913,27 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "--wait may not be combined with --no-block.");
 
+        bool do_reload_or_restart = streq_ptr(argv[optind], "reload-or-restart");
+        if (arg_marked) {
+                if (!do_reload_or_restart)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "--marked may only be used with 'reload-or-restart'.");
+                if (optind + 1 < argc)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "No additional arguments allowed with 'reload-or-restart --marked'.");
+                if (arg_wait)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "--marked --wait is not supported.");
+                if (arg_show_transaction)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "--marked --show-transaction is not supported.");
+
+        } else if (do_reload_or_restart) {
+                if (optind + 1 >= argc)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "List of units to restart/reload is required.");
+        }
+
         return 1;
 }
 
@@ -982,7 +1011,7 @@ static int systemctl_main(int argc, char *argv[]) {
                 { "reload",                2,        VERB_ANY, VERB_ONLINE_ONLY, start_unit              },
                 { "restart",               2,        VERB_ANY, VERB_ONLINE_ONLY, start_unit              },
                 { "try-restart",           2,        VERB_ANY, VERB_ONLINE_ONLY, start_unit              },
-                { "reload-or-restart",     2,        VERB_ANY, VERB_ONLINE_ONLY, start_unit              },
+                { "reload-or-restart",     VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, start_unit              },
                 { "reload-or-try-restart", 2,        VERB_ANY, VERB_ONLINE_ONLY, start_unit              }, /* For compatibility with old systemctl <= 228 */
                 { "try-reload-or-restart", 2,        VERB_ANY, VERB_ONLINE_ONLY, start_unit              },
                 { "force-reload",          2,        VERB_ANY, VERB_ONLINE_ONLY, start_unit              }, /* For compatibility with SysV */
index 0ebe4580c6027b7c11122f48bcab6c4ebfa2fc0f..3c5a4023a9f827367402e63e8eacddac0b2c9b31 100644 (file)
@@ -93,5 +93,6 @@ extern char **arg_clean_what;
 extern TimestampStyle arg_timestamp_style;
 extern bool arg_read_only;
 extern bool arg_mkdir;
+extern bool arg_marked;
 
 int systemctl_dispatch_parse_argv(int argc, char *argv[]);
index b6fd22904fa17d8c686cb84f89cbe8d5064b560e..b29c0d78440f0572c459870e4b9a2acb3ea639d6 100644 (file)
@@ -12,7 +12,7 @@
 #include "rm-rf.h"
 #include "service.h"
 #include "tests.h"
-#include "unit.h"
+#include "unit-serialize.h"
 #include "virt.h"
 
 int main(int argc, char *argv[]) {
index 1bd1dbddf526b28a483e7ea1a54294c038191b37..21a8ea3fa6f004209932d7c696ca3922c6bb2662 100644 (file)
@@ -6,7 +6,7 @@
 static void test_udev_builtin_cmd_to_ptr(void) {
         log_info("/* %s */", __func__);
 
-        /* Those could have been static_assert()s, but ({}) is not allowed there. */
+        /* Those could have been static asserts, but ({}) is not allowed there. */
 #if HAVE_BLKID
         assert_se(UDEV_BUILTIN_CMD_TO_PTR(UDEV_BUILTIN_BLKID));
         assert_se(PTR_TO_UDEV_BUILTIN_CMD(UDEV_BUILTIN_CMD_TO_PTR(UDEV_BUILTIN_BLKID)) == UDEV_BUILTIN_BLKID);