1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "dbus-unit.h"
27 #include "bus-errors.h"
28 #include "dbus-common.h"
30 const char bus_unit_interface
[] _introspect_("Unit") = BUS_UNIT_INTERFACE
;
32 #define INVALIDATING_PROPERTIES \
36 "InactiveExitTimestamp\0" \
37 "ActiveEnterTimestamp\0" \
38 "ActiveExitTimestamp\0" \
39 "InactiveEnterTimestamp\0" \
43 static int bus_unit_append_names(DBusMessageIter
*i
, const char *property
, void *data
) {
49 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_ARRAY
, "s", &sub
))
52 SET_FOREACH(t
, u
->names
, j
)
53 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &t
))
56 if (!dbus_message_iter_close_container(i
, &sub
))
62 static int bus_unit_append_following(DBusMessageIter
*i
, const char *property
, void *data
) {
70 f
= unit_following(u
);
73 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &d
))
79 static int bus_unit_append_dependencies(DBusMessageIter
*i
, const char *property
, void *data
) {
85 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_ARRAY
, "s", &sub
))
89 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &u
->id
))
92 if (!dbus_message_iter_close_container(i
, &sub
))
98 static int bus_unit_append_description(DBusMessageIter
*i
, const char *property
, void *data
) {
106 d
= unit_description(u
);
108 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &d
))
114 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state
, unit_load_state
, UnitLoadState
);
116 static int bus_unit_append_active_state(DBusMessageIter
*i
, const char *property
, void *data
) {
124 state
= unit_active_state_to_string(unit_active_state(u
));
126 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &state
))
132 static int bus_unit_append_sub_state(DBusMessageIter
*i
, const char *property
, void *data
) {
140 state
= unit_sub_state_to_string(u
);
142 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &state
))
148 static int bus_unit_append_file_state(DBusMessageIter
*i
, const char *property
, void *data
) {
156 state
= strempty(unit_file_state_to_string(unit_get_unit_file_state(u
)));
158 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &state
))
164 static int bus_unit_append_can_start(DBusMessageIter
*i
, const char *property
, void *data
) {
172 b
= unit_can_start(u
) &&
173 !u
->refuse_manual_start
;
175 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
181 static int bus_unit_append_can_stop(DBusMessageIter
*i
, const char *property
, void *data
) {
189 /* On the lower levels we assume that every unit we can start
190 * we can also stop */
192 b
= unit_can_start(u
) &&
193 !u
->refuse_manual_stop
;
195 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
201 static int bus_unit_append_can_reload(DBusMessageIter
*i
, const char *property
, void *data
) {
209 b
= unit_can_reload(u
);
211 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
217 static int bus_unit_append_can_isolate(DBusMessageIter
*i
, const char *property
, void *data
) {
225 b
= unit_can_isolate(u
) &&
226 !u
->refuse_manual_start
;
228 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
234 static int bus_unit_append_job(DBusMessageIter
*i
, const char *property
, void *data
) {
243 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_STRUCT
, NULL
, &sub
))
248 if (!(p
= job_dbus_path(u
->job
)))
251 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_UINT32
, &u
->job
->id
) ||
252 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_OBJECT_PATH
, &p
)) {
259 /* No job, so let's fill in some placeholder
260 * data. Since we need to fill in a valid path we
261 * simple point to ourselves. */
263 if (!(p
= unit_dbus_path(u
)))
266 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_UINT32
, &id
) ||
267 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_OBJECT_PATH
, &p
)) {
275 if (!dbus_message_iter_close_container(i
, &sub
))
281 static int bus_unit_append_default_cgroup(DBusMessageIter
*i
, const char *property
, void *data
) {
291 if ((cgb
= unit_get_default_cgroup(u
))) {
292 if (!(t
= cgroup_bonding_to_string(cgb
)))
297 success
= dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &t
);
302 return success
? 0 : -ENOMEM
;
305 static int bus_unit_append_cgroups(DBusMessageIter
*i
, const char *property
, void *data
) {
310 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_ARRAY
, "s", &sub
))
313 LIST_FOREACH(by_unit
, cgb
, u
->cgroup_bondings
) {
317 if (!(t
= cgroup_bonding_to_string(cgb
)))
320 success
= dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &t
);
327 if (!dbus_message_iter_close_container(i
, &sub
))
333 static int bus_unit_append_cgroup_attrs(DBusMessageIter
*i
, const char *property
, void *data
) {
336 DBusMessageIter sub
, sub2
;
338 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_ARRAY
, "(sss)", &sub
))
341 LIST_FOREACH(by_unit
, a
, u
->cgroup_attributes
) {
346 a
->map_callback(a
->controller
, a
->name
, a
->value
, &v
);
349 dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
) &&
350 dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &a
->controller
) &&
351 dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &a
->name
) &&
352 dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, v
? &v
: &a
->value
) &&
353 dbus_message_iter_close_container(&sub
, &sub2
);
361 if (!dbus_message_iter_close_container(i
, &sub
))
367 static int bus_unit_append_need_daemon_reload(DBusMessageIter
*i
, const char *property
, void *data
) {
375 b
= unit_need_daemon_reload(u
);
377 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
383 static int bus_unit_append_load_error(DBusMessageIter
*i
, const char *property
, void *data
) {
385 const char *name
, *message
;
392 if (u
->load_error
!= 0) {
393 name
= bus_errno_to_dbus(u
->load_error
);
394 message
= strempty(strerror(-u
->load_error
));
398 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_STRUCT
, NULL
, &sub
) ||
399 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &name
) ||
400 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &message
) ||
401 !dbus_message_iter_close_container(i
, &sub
))
407 static DBusHandlerResult
bus_unit_message_dispatch(Unit
*u
, DBusConnection
*connection
, DBusMessage
*message
) {
408 DBusMessage
*reply
= NULL
;
409 Manager
*m
= u
->manager
;
411 JobType job_type
= _JOB_TYPE_INVALID
;
413 bool reload_if_possible
= false;
415 dbus_error_init(&error
);
417 if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Start"))
418 job_type
= JOB_START
;
419 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Stop"))
421 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Reload"))
422 job_type
= JOB_RELOAD
;
423 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Restart"))
424 job_type
= JOB_RESTART
;
425 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "TryRestart"))
426 job_type
= JOB_TRY_RESTART
;
427 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "ReloadOrRestart")) {
428 reload_if_possible
= true;
429 job_type
= JOB_RESTART
;
430 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "ReloadOrTryRestart")) {
431 reload_if_possible
= true;
432 job_type
= JOB_TRY_RESTART
;
433 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Kill")) {
434 const char *swho
, *smode
;
440 if (!dbus_message_get_args(
443 DBUS_TYPE_STRING
, &swho
,
444 DBUS_TYPE_STRING
, &smode
,
445 DBUS_TYPE_INT32
, &signo
,
447 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
452 who
= kill_who_from_string(swho
);
454 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
458 mode
= KILL_CONTROL_GROUP
;
460 mode
= kill_mode_from_string(smode
);
462 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
465 if (signo
<= 0 || signo
>= _NSIG
)
466 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
468 if ((r
= unit_kill(u
, who
, mode
, signo
, &error
)) < 0)
469 return bus_send_error_reply(connection
, message
, &error
, r
);
471 if (!(reply
= dbus_message_new_method_return(message
)))
474 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "ResetFailed")) {
476 unit_reset_failed(u
);
478 if (!(reply
= dbus_message_new_method_return(message
)))
481 } else if (UNIT_VTABLE(u
)->bus_message_handler
)
482 return UNIT_VTABLE(u
)->bus_message_handler(u
, connection
, message
);
484 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
486 if (job_type
!= _JOB_TYPE_INVALID
) {
492 if ((job_type
== JOB_START
&& u
->refuse_manual_start
) ||
493 (job_type
== JOB_STOP
&& u
->refuse_manual_stop
) ||
494 ((job_type
== JOB_RESTART
|| job_type
== JOB_TRY_RESTART
) &&
495 (u
->refuse_manual_start
|| u
->refuse_manual_stop
))) {
496 dbus_set_error(&error
, BUS_ERROR_ONLY_BY_DEPENDENCY
, "Operation refused, may be requested by dependency only.");
497 return bus_send_error_reply(connection
, message
, &error
, -EPERM
);
500 if (!dbus_message_get_args(
503 DBUS_TYPE_STRING
, &smode
,
505 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
507 if (reload_if_possible
&& unit_can_reload(u
)) {
508 if (job_type
== JOB_RESTART
)
509 job_type
= JOB_RELOAD_OR_START
;
510 else if (job_type
== JOB_TRY_RESTART
)
511 job_type
= JOB_RELOAD
;
514 if ((mode
= job_mode_from_string(smode
)) == _JOB_MODE_INVALID
) {
515 dbus_set_error(&error
, BUS_ERROR_INVALID_JOB_MODE
, "Job mode %s is invalid.", smode
);
516 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
519 if ((r
= manager_add_job(m
, job_type
, u
, mode
, true, &error
, &j
)) < 0)
520 return bus_send_error_reply(connection
, message
, &error
, r
);
522 if (!(reply
= dbus_message_new_method_return(message
)))
525 if (!(path
= job_dbus_path(j
)))
528 if (!dbus_message_append_args(
530 DBUS_TYPE_OBJECT_PATH
, &path
,
536 if (!dbus_connection_send(connection
, reply
, NULL
))
539 dbus_message_unref(reply
);
544 return DBUS_HANDLER_RESULT_HANDLED
;
550 dbus_message_unref(reply
);
552 dbus_error_free(&error
);
554 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
557 static DBusHandlerResult
bus_unit_message_handler(DBusConnection
*connection
, DBusMessage
*message
, void *data
) {
567 if (streq(dbus_message_get_path(message
), "/org/freedesktop/systemd1/unit")) {
568 /* Be nice to gdbus and return introspection data for our mid-level paths */
570 if (dbus_message_is_method_call(message
, "org.freedesktop.DBus.Introspectable", "Introspect")) {
571 char *introspection
= NULL
;
577 if (!(reply
= dbus_message_new_method_return(message
)))
580 /* We roll our own introspection code here, instead of
581 * relying on bus_default_message_handler() because we
582 * need to generate our introspection string
585 if (!(f
= open_memstream(&introspection
, &size
)))
588 fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
591 fputs(BUS_INTROSPECTABLE_INTERFACE
, f
);
592 fputs(BUS_PEER_INTERFACE
, f
);
594 HASHMAP_FOREACH_KEY(u
, k
, m
->units
, i
) {
600 if (!(p
= bus_path_escape(k
))) {
606 fprintf(f
, "<node name=\"%s\"/>", p
);
610 fputs("</node>\n", f
);
623 if (!dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &introspection
, DBUS_TYPE_INVALID
)) {
630 if (!dbus_connection_send(connection
, reply
, NULL
))
633 dbus_message_unref(reply
);
635 return DBUS_HANDLER_RESULT_HANDLED
;
638 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
641 if ((r
= manager_get_unit_from_dbus_path(m
, dbus_message_get_path(message
), &u
)) < 0) {
644 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
650 dbus_set_error_const(&e
, DBUS_ERROR_UNKNOWN_OBJECT
, "Unknown unit");
651 return bus_send_error_reply(connection
, message
, &e
, r
);
654 return bus_send_error_reply(connection
, message
, NULL
, r
);
657 return bus_unit_message_dispatch(u
, connection
, message
);
661 dbus_message_unref(reply
);
663 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
666 const DBusObjectPathVTable bus_unit_vtable
= {
667 .message_function
= bus_unit_message_handler
670 void bus_unit_send_change_signal(Unit
*u
) {
672 DBusMessage
*m
= NULL
;
676 if (u
->in_dbus_queue
) {
677 LIST_REMOVE(Unit
, dbus_queue
, u
->manager
->dbus_unit_queue
, u
);
678 u
->in_dbus_queue
= false;
684 if (!bus_has_subscriber(u
->manager
)) {
685 u
->sent_dbus_new_signal
= true;
689 if (!(p
= unit_dbus_path(u
)))
692 if (u
->sent_dbus_new_signal
) {
693 /* Send a properties changed signal. First for the
694 * specific type, then for the generic unit. The
695 * clients may rely on this order to get atomic
696 * behaviour if needed. */
698 if (UNIT_VTABLE(u
)->bus_invalidating_properties
) {
700 if (!(m
= bus_properties_changed_new(p
,
701 UNIT_VTABLE(u
)->bus_interface
,
702 UNIT_VTABLE(u
)->bus_invalidating_properties
)))
705 if (bus_broadcast(u
->manager
, m
) < 0)
708 dbus_message_unref(m
);
711 if (!(m
= bus_properties_changed_new(p
, "org.freedesktop.systemd1.Unit", INVALIDATING_PROPERTIES
)))
715 /* Send a new signal */
717 if (!(m
= dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitNew")))
720 if (!dbus_message_append_args(m
,
721 DBUS_TYPE_STRING
, &u
->id
,
722 DBUS_TYPE_OBJECT_PATH
, &p
,
727 if (bus_broadcast(u
->manager
, m
) < 0)
731 dbus_message_unref(m
);
733 u
->sent_dbus_new_signal
= true;
741 dbus_message_unref(m
);
743 log_error("Failed to allocate unit change/new signal.");
746 void bus_unit_send_removed_signal(Unit
*u
) {
748 DBusMessage
*m
= NULL
;
752 if (!bus_has_subscriber(u
->manager
))
755 if (!u
->sent_dbus_new_signal
)
756 bus_unit_send_change_signal(u
);
761 if (!(p
= unit_dbus_path(u
)))
764 if (!(m
= dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitRemoved")))
767 if (!dbus_message_append_args(m
,
768 DBUS_TYPE_STRING
, &u
->id
,
769 DBUS_TYPE_OBJECT_PATH
, &p
,
773 if (bus_broadcast(u
->manager
, m
) < 0)
777 dbus_message_unref(m
);
785 dbus_message_unref(m
);
787 log_error("Failed to allocate unit remove signal.");
790 const BusProperty bus_unit_properties
[] = {
791 { "Id", bus_property_append_string
, "s", offsetof(Unit
, id
), true },
792 { "Names", bus_unit_append_names
, "as", 0 },
793 { "Following", bus_unit_append_following
, "s", 0 },
794 { "Requires", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_REQUIRES
]), true },
795 { "RequiresOverridable", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_REQUIRES_OVERRIDABLE
]), true },
796 { "Requisite", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_REQUISITE
]), true },
797 { "RequisiteOverridable", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_REQUISITE_OVERRIDABLE
]), true },
798 { "Wants", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_WANTS
]), true },
799 { "BindTo", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_BIND_TO
]), true },
800 { "RequiredBy", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY
]), true },
801 { "RequiredByOverridable",bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY_OVERRIDABLE
]), true },
802 { "WantedBy", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_WANTED_BY
]), true },
803 { "BoundBy", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_BOUND_BY
]), true },
804 { "Conflicts", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_CONFLICTS
]), true },
805 { "ConflictedBy", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_CONFLICTED_BY
]), true },
806 { "Before", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_BEFORE
]), true },
807 { "After", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_AFTER
]), true },
808 { "OnFailure", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_ON_FAILURE
]), true },
809 { "Triggers", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_TRIGGERS
]), true },
810 { "TriggeredBy", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_TRIGGERED_BY
]), true },
811 { "PropagateReloadTo", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_PROPAGATE_RELOAD_TO
]), true },
812 { "PropagateReloadFrom", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_PROPAGATE_RELOAD_FROM
]), true },
813 { "Description", bus_unit_append_description
, "s", 0 },
814 { "LoadState", bus_unit_append_load_state
, "s", offsetof(Unit
, load_state
) },
815 { "ActiveState", bus_unit_append_active_state
, "s", 0 },
816 { "SubState", bus_unit_append_sub_state
, "s", 0 },
817 { "FragmentPath", bus_property_append_string
, "s", offsetof(Unit
, fragment_path
), true },
818 { "UnitFileState", bus_unit_append_file_state
, "s", 0 },
819 { "InactiveExitTimestamp",bus_property_append_usec
, "t", offsetof(Unit
, inactive_exit_timestamp
.realtime
) },
820 { "InactiveExitTimestampMonotonic", bus_property_append_usec
, "t", offsetof(Unit
, inactive_exit_timestamp
.monotonic
) },
821 { "ActiveEnterTimestamp", bus_property_append_usec
, "t", offsetof(Unit
, active_enter_timestamp
.realtime
) },
822 { "ActiveEnterTimestampMonotonic", bus_property_append_usec
, "t", offsetof(Unit
, active_enter_timestamp
.monotonic
) },
823 { "ActiveExitTimestamp", bus_property_append_usec
, "t", offsetof(Unit
, active_exit_timestamp
.realtime
) },
824 { "ActiveExitTimestampMonotonic", bus_property_append_usec
, "t", offsetof(Unit
, active_exit_timestamp
.monotonic
) },
825 { "InactiveEnterTimestamp", bus_property_append_usec
, "t", offsetof(Unit
, inactive_enter_timestamp
.realtime
) },
826 { "InactiveEnterTimestampMonotonic",bus_property_append_usec
, "t", offsetof(Unit
, inactive_enter_timestamp
.monotonic
) },
827 { "CanStart", bus_unit_append_can_start
, "b", 0 },
828 { "CanStop", bus_unit_append_can_stop
, "b", 0 },
829 { "CanReload", bus_unit_append_can_reload
, "b", 0 },
830 { "CanIsolate", bus_unit_append_can_isolate
, "b", 0 },
831 { "Job", bus_unit_append_job
, "(uo)", 0 },
832 { "StopWhenUnneeded", bus_property_append_bool
, "b", offsetof(Unit
, stop_when_unneeded
) },
833 { "RefuseManualStart", bus_property_append_bool
, "b", offsetof(Unit
, refuse_manual_start
) },
834 { "RefuseManualStop", bus_property_append_bool
, "b", offsetof(Unit
, refuse_manual_stop
) },
835 { "AllowIsolate", bus_property_append_bool
, "b", offsetof(Unit
, allow_isolate
) },
836 { "DefaultDependencies", bus_property_append_bool
, "b", offsetof(Unit
, default_dependencies
) },
837 { "OnFailureIsolate", bus_property_append_bool
, "b", offsetof(Unit
, on_failure_isolate
) },
838 { "IgnoreOnIsolate", bus_property_append_bool
, "b", offsetof(Unit
, ignore_on_isolate
) },
839 { "IgnoreOnSnapshot", bus_property_append_bool
, "b", offsetof(Unit
, ignore_on_snapshot
) },
840 { "DefaultControlGroup", bus_unit_append_default_cgroup
, "s", 0 },
841 { "ControlGroup", bus_unit_append_cgroups
, "as", 0 },
842 { "ControlGroupAttributes", bus_unit_append_cgroup_attrs
,"a(sss)", 0 },
843 { "NeedDaemonReload", bus_unit_append_need_daemon_reload
, "b", 0 },
844 { "JobTimeoutUSec", bus_property_append_usec
, "t", offsetof(Unit
, job_timeout
) },
845 { "ConditionTimestamp", bus_property_append_usec
, "t", offsetof(Unit
, condition_timestamp
.realtime
) },
846 { "ConditionTimestampMonotonic", bus_property_append_usec
, "t", offsetof(Unit
, condition_timestamp
.monotonic
) },
847 { "ConditionResult", bus_property_append_bool
, "b", offsetof(Unit
, condition_result
) },
848 { "LoadError", bus_unit_append_load_error
, "(ss)", 0 },