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 Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser 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"
29 #include "selinux-access.h"
30 #include "cgroup-util.h"
32 #include "path-util.h"
35 const char bus_unit_interface
[] _introspect_("Unit") = BUS_UNIT_INTERFACE
;
37 #define INVALIDATING_PROPERTIES \
41 "InactiveExitTimestamp\0" \
42 "ActiveEnterTimestamp\0" \
43 "ActiveExitTimestamp\0" \
44 "InactiveEnterTimestamp\0" \
48 static int bus_unit_append_names(DBusMessageIter
*i
, const char *property
, void *data
) {
54 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_ARRAY
, "s", &sub
))
57 SET_FOREACH(t
, u
->names
, j
)
58 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &t
))
61 if (!dbus_message_iter_close_container(i
, &sub
))
67 static int bus_unit_append_following(DBusMessageIter
*i
, const char *property
, void *data
) {
75 f
= unit_following(u
);
78 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &d
))
84 static int bus_unit_append_slice(DBusMessageIter
*i
, const char *property
, void *data
) {
92 d
= strempty(unit_slice_name(u
));
94 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &d
))
100 static int bus_unit_append_dependencies(DBusMessageIter
*i
, const char *property
, void *data
) {
106 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_ARRAY
, "s", &sub
))
110 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &u
->id
))
113 if (!dbus_message_iter_close_container(i
, &sub
))
119 static int bus_unit_append_description(DBusMessageIter
*i
, const char *property
, void *data
) {
127 d
= unit_description(u
);
129 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &d
))
135 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state
, unit_load_state
, UnitLoadState
);
137 static int bus_unit_append_active_state(DBusMessageIter
*i
, const char *property
, void *data
) {
145 state
= unit_active_state_to_string(unit_active_state(u
));
147 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &state
))
153 static int bus_unit_append_sub_state(DBusMessageIter
*i
, const char *property
, void *data
) {
161 state
= unit_sub_state_to_string(u
);
163 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &state
))
169 static int bus_unit_append_file_state(DBusMessageIter
*i
, const char *property
, void *data
) {
177 state
= strempty(unit_file_state_to_string(unit_get_unit_file_state(u
)));
179 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &state
))
185 static int bus_unit_append_can_start(DBusMessageIter
*i
, const char *property
, void *data
) {
193 b
= unit_can_start(u
) &&
194 !u
->refuse_manual_start
;
196 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
202 static int bus_unit_append_can_stop(DBusMessageIter
*i
, const char *property
, void *data
) {
210 /* On the lower levels we assume that every unit we can start
211 * we can also stop */
213 b
= unit_can_start(u
) &&
214 !u
->refuse_manual_stop
;
216 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
222 static int bus_unit_append_can_reload(DBusMessageIter
*i
, const char *property
, void *data
) {
230 b
= unit_can_reload(u
);
232 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
238 static int bus_unit_append_can_isolate(DBusMessageIter
*i
, const char *property
, void *data
) {
246 b
= unit_can_isolate(u
) &&
247 !u
->refuse_manual_start
;
249 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
255 static int bus_unit_append_job(DBusMessageIter
*i
, const char *property
, void *data
) {
258 _cleanup_free_
char *p
= NULL
;
264 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_STRUCT
, NULL
, &sub
))
269 p
= job_dbus_path(u
->job
);
273 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_UINT32
, &u
->job
->id
) ||
274 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_OBJECT_PATH
, &p
))
279 /* No job, so let's fill in some placeholder
280 * data. Since we need to fill in a valid path we
281 * simple point to ourselves. */
283 p
= unit_dbus_path(u
);
287 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_UINT32
, &id
) ||
288 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_OBJECT_PATH
, &p
))
292 if (!dbus_message_iter_close_container(i
, &sub
))
298 static int bus_unit_append_need_daemon_reload(DBusMessageIter
*i
, const char *property
, void *data
) {
306 b
= unit_need_daemon_reload(u
);
308 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
314 static int bus_unit_append_load_error(DBusMessageIter
*i
, const char *property
, void *data
) {
316 const char *name
, *message
;
323 if (u
->load_error
!= 0) {
324 name
= bus_errno_to_dbus(u
->load_error
);
325 message
= strempty(strerror(-u
->load_error
));
329 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_STRUCT
, NULL
, &sub
) ||
330 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &name
) ||
331 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &message
) ||
332 !dbus_message_iter_close_container(i
, &sub
))
338 static DBusHandlerResult
bus_unit_message_dispatch(Unit
*u
, DBusConnection
*connection
, DBusMessage
*message
) {
339 _cleanup_dbus_message_unref_ DBusMessage
*reply
= NULL
;
341 JobType job_type
= _JOB_TYPE_INVALID
;
342 bool reload_if_possible
= false;
345 dbus_error_init(&error
);
347 if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Start"))
348 job_type
= JOB_START
;
349 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Stop"))
351 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Reload"))
352 job_type
= JOB_RELOAD
;
353 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Restart"))
354 job_type
= JOB_RESTART
;
355 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "TryRestart"))
356 job_type
= JOB_TRY_RESTART
;
357 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "ReloadOrRestart")) {
358 reload_if_possible
= true;
359 job_type
= JOB_RESTART
;
360 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "ReloadOrTryRestart")) {
361 reload_if_possible
= true;
362 job_type
= JOB_TRY_RESTART
;
363 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Kill")) {
368 if (!dbus_message_get_args(
371 DBUS_TYPE_STRING
, &swho
,
372 DBUS_TYPE_INT32
, &signo
,
374 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
379 who
= kill_who_from_string(swho
);
381 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
384 if (signo
<= 0 || signo
>= _NSIG
)
385 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
387 SELINUX_UNIT_ACCESS_CHECK(u
, connection
, message
, "stop");
389 r
= unit_kill(u
, who
, signo
, &error
);
391 return bus_send_error_reply(connection
, message
, &error
, r
);
393 reply
= dbus_message_new_method_return(message
);
397 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "ResetFailed")) {
399 SELINUX_UNIT_ACCESS_CHECK(u
, connection
, message
, "reload");
401 unit_reset_failed(u
);
403 reply
= dbus_message_new_method_return(message
);
407 } else if (UNIT_VTABLE(u
)->bus_message_handler
)
408 return UNIT_VTABLE(u
)->bus_message_handler(u
, connection
, message
);
410 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
412 if (job_type
!= _JOB_TYPE_INVALID
) {
416 if (!dbus_message_get_args(
419 DBUS_TYPE_STRING
, &smode
,
421 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
423 mode
= job_mode_from_string(smode
);
425 dbus_set_error(&error
, BUS_ERROR_INVALID_JOB_MODE
, "Job mode %s is invalid.", smode
);
426 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
429 return bus_unit_queue_job(connection
, message
, u
, job_type
, mode
, reload_if_possible
);
433 if (!bus_maybe_send_reply(connection
, message
, reply
))
436 return DBUS_HANDLER_RESULT_HANDLED
;
439 dbus_error_free(&error
);
440 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
443 static DBusHandlerResult
bus_unit_message_handler(DBusConnection
*connection
, DBusMessage
*message
, void *data
) {
447 _cleanup_dbus_message_unref_ DBusMessage
*reply
= NULL
;
454 dbus_error_init(&error
);
456 if (streq(dbus_message_get_path(message
), "/org/freedesktop/systemd1/unit")) {
457 /* Be nice to gdbus and return introspection data for our mid-level paths */
459 SELINUX_ACCESS_CHECK(connection
, message
, "status");
461 if (dbus_message_is_method_call(message
, "org.freedesktop.DBus.Introspectable", "Introspect")) {
462 char *introspection
= NULL
;
468 reply
= dbus_message_new_method_return(message
);
472 /* We roll our own introspection code here, instead of
473 * relying on bus_default_message_handler() because we
474 * need to generate our introspection string
477 f
= open_memstream(&introspection
, &size
);
481 fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
484 fputs(BUS_INTROSPECTABLE_INTERFACE
, f
);
485 fputs(BUS_PEER_INTERFACE
, f
);
487 HASHMAP_FOREACH_KEY(u
, k
, m
->units
, i
) {
493 p
= bus_path_escape(k
);
500 fprintf(f
, "<node name=\"%s\"/>", p
);
504 fputs("</node>\n", f
);
517 if (!dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &introspection
, DBUS_TYPE_INVALID
)) {
524 if (!bus_maybe_send_reply(connection
, message
, reply
))
527 return DBUS_HANDLER_RESULT_HANDLED
;
530 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
533 r
= manager_load_unit_from_dbus_path(m
, dbus_message_get_path(message
), &error
, &u
);
537 return bus_send_error_reply(connection
, message
, &error
, r
);
539 return bus_unit_message_dispatch(u
, connection
, message
);
542 dbus_error_free(&error
);
544 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
547 const DBusObjectPathVTable bus_unit_vtable
= {
548 .message_function
= bus_unit_message_handler
551 void bus_unit_send_change_signal(Unit
*u
) {
552 _cleanup_free_
char *p
= NULL
;
553 _cleanup_dbus_message_unref_ DBusMessage
*m
= NULL
;
557 if (u
->in_dbus_queue
) {
558 LIST_REMOVE(Unit
, dbus_queue
, u
->manager
->dbus_unit_queue
, u
);
559 u
->in_dbus_queue
= false;
565 if (!bus_has_subscriber(u
->manager
)) {
566 u
->sent_dbus_new_signal
= true;
570 p
= unit_dbus_path(u
);
574 if (u
->sent_dbus_new_signal
) {
575 /* Send a properties changed signal. First for the
576 * specific type, then for the generic unit. The
577 * clients may rely on this order to get atomic
578 * behavior if needed. */
580 if (UNIT_VTABLE(u
)->bus_invalidating_properties
) {
582 m
= bus_properties_changed_new(p
,
583 UNIT_VTABLE(u
)->bus_interface
,
584 UNIT_VTABLE(u
)->bus_invalidating_properties
);
588 if (bus_broadcast(u
->manager
, m
) < 0)
591 dbus_message_unref(m
);
594 m
= bus_properties_changed_new(p
, "org.freedesktop.systemd1.Unit",
595 INVALIDATING_PROPERTIES
);
600 /* Send a new signal */
602 m
= dbus_message_new_signal("/org/freedesktop/systemd1",
603 "org.freedesktop.systemd1.Manager",
608 if (!dbus_message_append_args(m
,
609 DBUS_TYPE_STRING
, &u
->id
,
610 DBUS_TYPE_OBJECT_PATH
, &p
,
615 if (bus_broadcast(u
->manager
, m
) < 0)
618 u
->sent_dbus_new_signal
= true;
626 void bus_unit_send_removed_signal(Unit
*u
) {
627 _cleanup_free_
char *p
= NULL
;
628 _cleanup_dbus_message_unref_ DBusMessage
*m
= NULL
;
632 if (!bus_has_subscriber(u
->manager
))
635 if (!u
->sent_dbus_new_signal
)
636 bus_unit_send_change_signal(u
);
641 p
= unit_dbus_path(u
);
645 m
= dbus_message_new_signal("/org/freedesktop/systemd1",
646 "org.freedesktop.systemd1.Manager",
651 if (!dbus_message_append_args(m
,
652 DBUS_TYPE_STRING
, &u
->id
,
653 DBUS_TYPE_OBJECT_PATH
, &p
,
657 if (bus_broadcast(u
->manager
, m
) < 0)
666 DBusHandlerResult
bus_unit_queue_job(
667 DBusConnection
*connection
,
668 DBusMessage
*message
,
672 bool reload_if_possible
) {
674 _cleanup_dbus_message_unref_ DBusMessage
*reply
= NULL
;
675 _cleanup_free_
char *path
= NULL
;
684 assert(type
>= 0 && type
< _JOB_TYPE_MAX
);
685 assert(mode
>= 0 && mode
< _JOB_MODE_MAX
);
687 dbus_error_init(&error
);
689 if (reload_if_possible
&& unit_can_reload(u
)) {
690 if (type
== JOB_RESTART
)
691 type
= JOB_RELOAD_OR_START
;
692 else if (type
== JOB_TRY_RESTART
)
696 SELINUX_UNIT_ACCESS_CHECK(u
, connection
, message
,
697 (type
== JOB_START
|| type
== JOB_RESTART
|| type
== JOB_TRY_RESTART
) ? "start" :
698 type
== JOB_STOP
? "stop" : "reload");
700 if (type
== JOB_STOP
&& u
->load_state
== UNIT_ERROR
&& unit_active_state(u
) == UNIT_INACTIVE
) {
701 dbus_set_error(&error
, BUS_ERROR_NO_SUCH_UNIT
, "Unit %s not loaded.", u
->id
);
702 return bus_send_error_reply(connection
, message
, &error
, -EPERM
);
705 if ((type
== JOB_START
&& u
->refuse_manual_start
) ||
706 (type
== JOB_STOP
&& u
->refuse_manual_stop
) ||
707 ((type
== JOB_RESTART
|| type
== JOB_TRY_RESTART
) && (u
->refuse_manual_start
|| u
->refuse_manual_stop
))) {
708 dbus_set_error(&error
, BUS_ERROR_ONLY_BY_DEPENDENCY
,
709 "Operation refused, unit %s may be requested by dependency only.", u
->id
);
710 return bus_send_error_reply(connection
, message
, &error
, -EPERM
);
713 r
= manager_add_job(u
->manager
, type
, u
, mode
, true, &error
, &j
);
715 return bus_send_error_reply(connection
, message
, &error
, r
);
717 cl
= job_bus_client_new(connection
, bus_message_get_sender_with_fallback(message
));
721 LIST_PREPEND(JobBusClient
, client
, j
->bus_client_list
, cl
);
723 reply
= dbus_message_new_method_return(message
);
727 path
= job_dbus_path(j
);
731 if (!dbus_message_append_args(
733 DBUS_TYPE_OBJECT_PATH
, &path
,
737 if (!bus_maybe_send_reply(connection
, message
, reply
))
740 return DBUS_HANDLER_RESULT_HANDLED
;
743 dbus_error_free(&error
);
745 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
748 const BusProperty bus_unit_properties
[] = {
749 { "Id", bus_property_append_string
, "s", offsetof(Unit
, id
), true },
750 { "Names", bus_unit_append_names
, "as", 0 },
751 { "Following", bus_unit_append_following
, "s", 0 },
752 { "Slice", bus_unit_append_slice
, "s", 0 },
753 { "Requires", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_REQUIRES
]), true },
754 { "RequiresOverridable", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_REQUIRES_OVERRIDABLE
]), true },
755 { "Requisite", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_REQUISITE
]), true },
756 { "RequisiteOverridable", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_REQUISITE_OVERRIDABLE
]), true },
757 { "Wants", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_WANTS
]), true },
758 { "BindsTo", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_BINDS_TO
]), true },
759 { "PartOf", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_PART_OF
]), true },
760 { "RequiredBy", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY
]), true },
761 { "RequiredByOverridable",bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY_OVERRIDABLE
]), true },
762 { "WantedBy", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_WANTED_BY
]), true },
763 { "BoundBy", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_BOUND_BY
]), true },
764 { "ConsistsOf", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_CONSISTS_OF
]), true },
765 { "Conflicts", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_CONFLICTS
]), true },
766 { "ConflictedBy", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_CONFLICTED_BY
]), true },
767 { "Before", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_BEFORE
]), true },
768 { "After", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_AFTER
]), true },
769 { "OnFailure", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_ON_FAILURE
]), true },
770 { "Triggers", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_TRIGGERS
]), true },
771 { "TriggeredBy", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_TRIGGERED_BY
]), true },
772 { "PropagatesReloadTo", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_PROPAGATES_RELOAD_TO
]), true },
773 { "ReloadPropagatedFrom", bus_unit_append_dependencies
, "as", offsetof(Unit
, dependencies
[UNIT_RELOAD_PROPAGATED_FROM
]), true },
774 { "RequiresMountsFor", bus_property_append_strv
, "as", offsetof(Unit
, requires_mounts_for
), true },
775 { "Documentation", bus_property_append_strv
, "as", offsetof(Unit
, documentation
), true },
776 { "Description", bus_unit_append_description
, "s", 0 },
777 { "LoadState", bus_unit_append_load_state
, "s", offsetof(Unit
, load_state
) },
778 { "ActiveState", bus_unit_append_active_state
, "s", 0 },
779 { "SubState", bus_unit_append_sub_state
, "s", 0 },
780 { "FragmentPath", bus_property_append_string
, "s", offsetof(Unit
, fragment_path
), true },
781 { "SourcePath", bus_property_append_string
, "s", offsetof(Unit
, source_path
), true },
782 { "DropInPaths", bus_property_append_strv
, "as", offsetof(Unit
, dropin_paths
), true },
783 { "UnitFileState", bus_unit_append_file_state
, "s", 0 },
784 { "InactiveExitTimestamp",bus_property_append_usec
, "t", offsetof(Unit
, inactive_exit_timestamp
.realtime
) },
785 { "InactiveExitTimestampMonotonic", bus_property_append_usec
, "t", offsetof(Unit
, inactive_exit_timestamp
.monotonic
) },
786 { "ActiveEnterTimestamp", bus_property_append_usec
, "t", offsetof(Unit
, active_enter_timestamp
.realtime
) },
787 { "ActiveEnterTimestampMonotonic", bus_property_append_usec
, "t", offsetof(Unit
, active_enter_timestamp
.monotonic
) },
788 { "ActiveExitTimestamp", bus_property_append_usec
, "t", offsetof(Unit
, active_exit_timestamp
.realtime
) },
789 { "ActiveExitTimestampMonotonic", bus_property_append_usec
, "t", offsetof(Unit
, active_exit_timestamp
.monotonic
) },
790 { "InactiveEnterTimestamp", bus_property_append_usec
, "t", offsetof(Unit
, inactive_enter_timestamp
.realtime
) },
791 { "InactiveEnterTimestampMonotonic",bus_property_append_usec
, "t", offsetof(Unit
, inactive_enter_timestamp
.monotonic
) },
792 { "CanStart", bus_unit_append_can_start
, "b", 0 },
793 { "CanStop", bus_unit_append_can_stop
, "b", 0 },
794 { "CanReload", bus_unit_append_can_reload
, "b", 0 },
795 { "CanIsolate", bus_unit_append_can_isolate
, "b", 0 },
796 { "Job", bus_unit_append_job
, "(uo)", 0 },
797 { "StopWhenUnneeded", bus_property_append_bool
, "b", offsetof(Unit
, stop_when_unneeded
) },
798 { "RefuseManualStart", bus_property_append_bool
, "b", offsetof(Unit
, refuse_manual_start
) },
799 { "RefuseManualStop", bus_property_append_bool
, "b", offsetof(Unit
, refuse_manual_stop
) },
800 { "AllowIsolate", bus_property_append_bool
, "b", offsetof(Unit
, allow_isolate
) },
801 { "DefaultDependencies", bus_property_append_bool
, "b", offsetof(Unit
, default_dependencies
) },
802 { "OnFailureIsolate", bus_property_append_bool
, "b", offsetof(Unit
, on_failure_isolate
) },
803 { "IgnoreOnIsolate", bus_property_append_bool
, "b", offsetof(Unit
, ignore_on_isolate
) },
804 { "IgnoreOnSnapshot", bus_property_append_bool
, "b", offsetof(Unit
, ignore_on_snapshot
) },
805 { "NeedDaemonReload", bus_unit_append_need_daemon_reload
, "b", 0 },
806 { "JobTimeoutUSec", bus_property_append_usec
, "t", offsetof(Unit
, job_timeout
) },
807 { "ConditionTimestamp", bus_property_append_usec
, "t", offsetof(Unit
, condition_timestamp
.realtime
) },
808 { "ConditionTimestampMonotonic", bus_property_append_usec
, "t", offsetof(Unit
, condition_timestamp
.monotonic
) },
809 { "ConditionResult", bus_property_append_bool
, "b", offsetof(Unit
, condition_result
) },
810 { "LoadError", bus_unit_append_load_error
, "(ss)", 0 },
811 { "ControlGroup", bus_property_append_string
, "s", offsetof(Unit
, cgroup_path
), true },