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/>.
25 #include "path-util.h"
26 #include "dbus-unit.h"
27 #include "dbus-execute.h"
28 #include "dbus-kill.h"
29 #include "dbus-cgroup.h"
30 #include "dbus-common.h"
31 #include "selinux-access.h"
32 #include "dbus-service.h"
34 #define BUS_SERVICE_INTERFACE \
35 " <interface name=\"org.freedesktop.systemd1.Service\">\n" \
36 " <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
37 " <property name=\"Restart\" type=\"s\" access=\"read\"/>\n" \
38 " <property name=\"PIDFile\" type=\"s\" access=\"read\"/>\n" \
39 " <property name=\"NotifyAccess\" type=\"s\" access=\"read\"/>\n" \
40 " <property name=\"RestartUSec\" type=\"t\" access=\"read\"/>\n" \
41 " <property name=\"TimeoutStartUSec\" type=\"t\" access=\"read\"/>\n" \
42 " <property name=\"TimeoutStopUSec\" type=\"t\" access=\"read\"/>\n" \
43 " <property name=\"WatchdogUSec\" type=\"t\" access=\"read\"/>\n" \
44 " <property name=\"WatchdogTimestamp\" type=\"t\" access=\"read\"/>\n" \
45 " <property name=\"WatchdogTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
46 " <property name=\"StartLimitInterval\" type=\"t\" access=\"read\"/>\n" \
47 " <property name=\"StartLimitBurst\" type=\"u\" access=\"read\"/>\n" \
48 " <property name=\"StartLimitAction\" type=\"s\" access=\"readwrite\"/>\n" \
49 BUS_EXEC_COMMAND_INTERFACE("ExecStartPre") \
50 BUS_EXEC_COMMAND_INTERFACE("ExecStart") \
51 BUS_EXEC_COMMAND_INTERFACE("ExecStartPost") \
52 BUS_EXEC_COMMAND_INTERFACE("ExecReload") \
53 BUS_EXEC_COMMAND_INTERFACE("ExecStop") \
54 BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \
55 BUS_EXEC_CONTEXT_INTERFACE \
56 BUS_KILL_CONTEXT_INTERFACE \
57 BUS_CGROUP_CONTEXT_INTERFACE \
58 " <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>\n" \
59 " <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>\n" \
60 " <property name=\"RemainAfterExit\" type=\"b\" access=\"read\"/>\n" \
61 BUS_EXEC_STATUS_INTERFACE("ExecMain") \
62 " <property name=\"MainPID\" type=\"u\" access=\"read\"/>\n" \
63 " <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
64 " <property name=\"BusName\" type=\"s\" access=\"read\"/>\n" \
65 " <property name=\"StatusText\" type=\"s\" access=\"read\"/>\n" \
66 " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \
69 #define INTROSPECTION \
70 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
73 BUS_SERVICE_INTERFACE \
74 BUS_PROPERTIES_INTERFACE \
76 BUS_INTROSPECTABLE_INTERFACE \
79 #define INTERFACES_LIST \
80 BUS_UNIT_INTERFACES_LIST \
81 "org.freedesktop.systemd1.Service\0"
83 const char bus_service_interface
[] _introspect_("Service") = BUS_SERVICE_INTERFACE
;
85 const char bus_service_invalidating_properties
[] =
94 "WatchdogTimestampMonotonic\0"
100 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type
, service_type
, ServiceType
);
101 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart
, service_restart
, ServiceRestart
);
102 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_notify_access
, notify_access
, NotifyAccess
);
103 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_service_result
, service_result
, ServiceResult
);
104 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_start_limit_action
, start_limit_action
, StartLimitAction
);
105 static DEFINE_BUS_PROPERTY_SET_ENUM(bus_service_set_start_limit_action
, start_limit_action
, StartLimitAction
);
107 static const BusProperty bus_exec_main_status_properties
[] = {
108 { "ExecMainStartTimestamp", bus_property_append_usec
, "t", offsetof(ExecStatus
, start_timestamp
.realtime
) },
109 { "ExecMainStartTimestampMonotonic",bus_property_append_usec
, "t", offsetof(ExecStatus
, start_timestamp
.monotonic
) },
110 { "ExecMainExitTimestamp", bus_property_append_usec
, "t", offsetof(ExecStatus
, exit_timestamp
.realtime
) },
111 { "ExecMainExitTimestampMonotonic", bus_property_append_usec
, "t", offsetof(ExecStatus
, exit_timestamp
.monotonic
) },
112 { "ExecMainPID", bus_property_append_pid
, "u", offsetof(ExecStatus
, pid
) },
113 { "ExecMainCode", bus_property_append_int
, "i", offsetof(ExecStatus
, code
) },
114 { "ExecMainStatus", bus_property_append_int
, "i", offsetof(ExecStatus
, status
) },
118 static const BusProperty bus_service_properties
[] = {
119 { "Type", bus_service_append_type
, "s", offsetof(Service
, type
) },
120 { "Restart", bus_service_append_restart
, "s", offsetof(Service
, restart
) },
121 { "PIDFile", bus_property_append_string
, "s", offsetof(Service
, pid_file
), true },
122 { "NotifyAccess", bus_service_append_notify_access
, "s", offsetof(Service
, notify_access
) },
123 { "RestartUSec", bus_property_append_usec
, "t", offsetof(Service
, restart_usec
) },
124 { "TimeoutStartUSec", bus_property_append_usec
, "t", offsetof(Service
, timeout_start_usec
) },
125 { "TimeoutStopUSec", bus_property_append_usec
, "t", offsetof(Service
, timeout_stop_usec
) },
126 { "WatchdogUSec", bus_property_append_usec
, "t", offsetof(Service
, watchdog_usec
) },
127 { "WatchdogTimestamp", bus_property_append_usec
, "t", offsetof(Service
, watchdog_timestamp
.realtime
) },
128 { "WatchdogTimestampMonotonic",bus_property_append_usec
, "t", offsetof(Service
, watchdog_timestamp
.monotonic
) },
129 { "StartLimitInterval", bus_property_append_usec
, "t", offsetof(Service
, start_limit
.interval
) },
130 { "StartLimitBurst", bus_property_append_uint32
, "u", offsetof(Service
, start_limit
.burst
) },
131 { "StartLimitAction", bus_service_append_start_limit_action
,"s", offsetof(Service
, start_limit_action
), false, bus_service_set_start_limit_action
},
132 BUS_EXEC_COMMAND_PROPERTY("ExecStartPre", offsetof(Service
, exec_command
[SERVICE_EXEC_START_PRE
]), true ),
133 BUS_EXEC_COMMAND_PROPERTY("ExecStart", offsetof(Service
, exec_command
[SERVICE_EXEC_START
]), true ),
134 BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Service
, exec_command
[SERVICE_EXEC_START_POST
]), true ),
135 BUS_EXEC_COMMAND_PROPERTY("ExecReload", offsetof(Service
, exec_command
[SERVICE_EXEC_RELOAD
]), true ),
136 BUS_EXEC_COMMAND_PROPERTY("ExecStop", offsetof(Service
, exec_command
[SERVICE_EXEC_STOP
]), true ),
137 BUS_EXEC_COMMAND_PROPERTY("ExecStopPost", offsetof(Service
, exec_command
[SERVICE_EXEC_STOP_POST
]), true ),
138 { "PermissionsStartOnly", bus_property_append_bool
, "b", offsetof(Service
, permissions_start_only
) },
139 { "RootDirectoryStartOnly", bus_property_append_bool
, "b", offsetof(Service
, root_directory_start_only
) },
140 { "RemainAfterExit", bus_property_append_bool
, "b", offsetof(Service
, remain_after_exit
) },
141 { "GuessMainPID", bus_property_append_bool
, "b", offsetof(Service
, guess_main_pid
) },
142 { "MainPID", bus_property_append_pid
, "u", offsetof(Service
, main_pid
) },
143 { "ControlPID", bus_property_append_pid
, "u", offsetof(Service
, control_pid
) },
144 { "BusName", bus_property_append_string
, "s", offsetof(Service
, bus_name
), true },
145 { "StatusText", bus_property_append_string
, "s", offsetof(Service
, status_text
), true },
146 { "Result", bus_service_append_service_result
,"s", offsetof(Service
, result
) },
150 DBusHandlerResult
bus_service_message_handler(Unit
*u
, DBusConnection
*connection
, DBusMessage
*message
) {
151 Service
*s
= SERVICE(u
);
153 const BusBoundProperties bps
[] = {
154 { "org.freedesktop.systemd1.Unit", bus_unit_properties
, u
},
155 { "org.freedesktop.systemd1.Service", bus_service_properties
, s
},
156 { "org.freedesktop.systemd1.Service", bus_exec_context_properties
, &s
->exec_context
},
157 { "org.freedesktop.systemd1.Service", bus_kill_context_properties
, &s
->kill_context
},
158 { "org.freedesktop.systemd1.Service", bus_cgroup_context_properties
, &s
->cgroup_context
},
159 { "org.freedesktop.systemd1.Service", bus_exec_main_status_properties
, &s
->main_exec_status
},
163 SELINUX_UNIT_ACCESS_CHECK(u
, connection
, message
, "status");
165 return bus_default_message_handler(connection
, message
, INTROSPECTION
, INTERFACES_LIST
, bps
);
168 static int bus_service_set_transient_properties(
172 UnitSetPropertiesMode mode
,
181 if (streq(name
, "ExecStart")) {
185 if (dbus_message_iter_get_arg_type(i
) != DBUS_TYPE_ARRAY
||
186 dbus_message_iter_get_element_type(i
) != DBUS_TYPE_STRUCT
)
189 dbus_message_iter_recurse(i
, &sub
);
190 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
191 _cleanup_strv_free_
char **argv
= NULL
;
192 DBusMessageIter sub2
;
196 dbus_message_iter_recurse(&sub
, &sub2
);
198 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &path
, true) < 0)
201 if (!path_is_absolute(path
)) {
202 dbus_set_error(error
, DBUS_ERROR_INVALID_ARGS
, "Path %s is not absolute.", path
);
206 r
= bus_parse_strv_iter(&sub2
, &argv
);
210 dbus_message_iter_next(&sub2
);
212 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_BOOLEAN
, &ignore
, false) < 0)
215 if (mode
!= UNIT_CHECK
) {
218 c
= new0(ExecCommand
, 1);
222 c
->path
= strdup(path
);
233 path_kill_slashes(c
->path
);
234 exec_command_append_list(&s
->exec_command
[SERVICE_EXEC_START
], c
);
238 dbus_message_iter_next(&sub
);
241 if (mode
!= UNIT_CHECK
) {
242 _cleanup_free_
char *buf
= NULL
;
243 _cleanup_fclose_
FILE *f
= NULL
;
248 exec_command_free_list(s
->exec_command
[SERVICE_EXEC_START
]);
249 s
->exec_command
[SERVICE_EXEC_START
] = NULL
;
252 f
= open_memstream(&buf
, &size
);
256 fputs("ExecStart=\n", f
);
258 LIST_FOREACH(command
, c
, s
->exec_command
[SERVICE_EXEC_START
]) {
260 fputs("ExecStart=", f
);
268 STRV_FOREACH(a
, c
->argv
) {
277 unit_write_drop_in_private_section(UNIT(s
), mode
, "exec-start", buf
);
286 int bus_service_set_property(
290 UnitSetPropertiesMode mode
,
293 Service
*s
= SERVICE(u
);
300 r
= bus_cgroup_set_property(u
, &s
->cgroup_context
, name
, i
, mode
, error
);
304 if (u
->transient
&& u
->load_state
== UNIT_STUB
) {
305 /* This is a transient unit, let's load a little more */
307 r
= bus_service_set_transient_properties(s
, name
, i
, mode
, error
);
315 int bus_service_commit_properties(Unit
*u
) {
318 unit_realize_cgroup(u
);