]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-execute.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.git] / src / core / dbus-execute.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <errno.h>
23 #include <dbus/dbus.h>
24 #include <sys/prctl.h>
25
26 #include "dbus-execute.h"
27 #include "missing.h"
28 #include "ioprio.h"
29 #include "strv.h"
30 #include "dbus-common.h"
31
32 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_kill_mode, kill_mode, KillMode);
33
34 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
35 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
36
37 int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data) {
38 char **env_files = data, **j;
39 DBusMessageIter sub, sub2;
40
41 assert(i);
42 assert(property);
43
44 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sb)", &sub))
45 return -ENOMEM;
46
47 STRV_FOREACH(j, env_files) {
48 dbus_bool_t b = false;
49 char *fn = *j;
50
51 if (fn[0] == '-') {
52 b = true;
53 fn++;
54 }
55
56 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
57 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &fn) ||
58 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
59 !dbus_message_iter_close_container(&sub, &sub2))
60 return -ENOMEM;
61 }
62
63 if (!dbus_message_iter_close_container(i, &sub))
64 return -ENOMEM;
65
66 return 0;
67 }
68
69 int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) {
70 ExecContext *c = data;
71 int32_t n;
72
73 assert(i);
74 assert(property);
75 assert(c);
76
77 if (c->oom_score_adjust_set)
78 n = c->oom_score_adjust;
79 else {
80 char *t;
81
82 n = 0;
83 if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) {
84 safe_atoi(t, &n);
85 free(t);
86 } else if (read_one_line_file("/proc/self/oom_adj", &t) >= 0) {
87 safe_atoi(t, &n);
88 free(t);
89
90 if (n == OOM_ADJUST_MAX)
91 n = OOM_SCORE_ADJ_MAX;
92 else
93 n = (n * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
94 }
95 }
96
97 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
98 return -ENOMEM;
99
100 return 0;
101 }
102
103 int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) {
104 ExecContext *c = data;
105 int32_t n;
106
107 assert(i);
108 assert(property);
109 assert(c);
110
111 if (c->nice_set)
112 n = c->nice;
113 else
114 n = getpriority(PRIO_PROCESS, 0);
115
116 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
117 return -ENOMEM;
118
119 return 0;
120 }
121
122 int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) {
123 ExecContext *c = data;
124 int32_t n;
125
126 assert(i);
127 assert(property);
128 assert(c);
129
130 if (c->ioprio_set)
131 n = c->ioprio;
132 else
133 n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
134
135 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
136 return -ENOMEM;
137
138 return 0;
139 }
140
141 int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) {
142 ExecContext *c = data;
143 int32_t n;
144
145 assert(i);
146 assert(property);
147 assert(c);
148
149 if (c->cpu_sched_set)
150 n = c->cpu_sched_policy;
151 else
152 n = sched_getscheduler(0);
153
154 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
155 return -ENOMEM;
156
157 return 0;
158 }
159
160 int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) {
161 ExecContext *c = data;
162 int32_t n;
163
164 assert(i);
165 assert(property);
166 assert(c);
167
168 if (c->cpu_sched_set)
169 n = c->cpu_sched_priority;
170 else {
171 struct sched_param p;
172 n = 0;
173
174 zero(p);
175 if (sched_getparam(0, &p) >= 0)
176 n = p.sched_priority;
177 }
178
179 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
180 return -ENOMEM;
181
182 return 0;
183 }
184
185 int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) {
186 ExecContext *c = data;
187 dbus_bool_t b;
188 DBusMessageIter sub;
189
190 assert(i);
191 assert(property);
192 assert(c);
193
194 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
195 return -ENOMEM;
196
197 if (c->cpuset)
198 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
199 else
200 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, 0);
201
202 if (!b)
203 return -ENOMEM;
204
205 if (!dbus_message_iter_close_container(i, &sub))
206 return -ENOMEM;
207
208 return 0;
209 }
210
211 int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) {
212 ExecContext *c = data;
213 uint64_t u;
214
215 assert(i);
216 assert(property);
217 assert(c);
218
219 if (c->timer_slack_nsec_set)
220 u = (uint64_t) c->timer_slack_nsec;
221 else
222 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
223
224 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
225 return -ENOMEM;
226
227 return 0;
228 }
229
230 int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) {
231 ExecContext *c = data;
232 uint64_t normal, inverted;
233
234 assert(i);
235 assert(property);
236 assert(c);
237
238 /* We store this negated internally, to match the kernel, but
239 * we expose it normalized. */
240
241 normal = *(uint64_t*) data;
242 inverted = ~normal;
243
244 return bus_property_append_uint64(i, property, &inverted);
245 }
246
247 int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) {
248 ExecContext *c = data;
249 char *t = NULL;
250 const char *s;
251 dbus_bool_t b;
252
253 assert(i);
254 assert(property);
255 assert(c);
256
257 if (c->capabilities)
258 s = t = cap_to_text(c->capabilities, NULL);
259 else
260 s = "";
261
262 if (!s)
263 return -ENOMEM;
264
265 b = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &s);
266
267 if (t)
268 cap_free(t);
269
270 if (!b)
271 return -ENOMEM;
272
273 return 0;
274 }
275
276 int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) {
277 ExecContext *c = data;
278 int r;
279 uint64_t u;
280
281 assert(i);
282 assert(property);
283 assert(c);
284
285 assert_se((r = rlimit_from_string(property)) >= 0);
286
287 if (c->rlimit[r])
288 u = (uint64_t) c->rlimit[r]->rlim_max;
289 else {
290 struct rlimit rl;
291
292 zero(rl);
293 getrlimit(r, &rl);
294
295 u = (uint64_t) rl.rlim_max;
296 }
297
298 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
299 return -ENOMEM;
300
301 return 0;
302 }
303
304 int bus_execute_append_command(DBusMessageIter *i, const char *property, void *data) {
305 ExecCommand *c = data;
306 DBusMessageIter sub, sub2, sub3;
307
308 assert(i);
309 assert(property);
310
311 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sasbttttuii)", &sub))
312 return -ENOMEM;
313
314 LIST_FOREACH(command, c, c) {
315 char **l;
316 uint32_t pid;
317 int32_t code, status;
318 dbus_bool_t b;
319
320 if (!c->path)
321 continue;
322
323 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
324 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &c->path) ||
325 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_ARRAY, "s", &sub3))
326 return -ENOMEM;
327
328 STRV_FOREACH(l, c->argv)
329 if (!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, l))
330 return -ENOMEM;
331
332 pid = (uint32_t) c->exec_status.pid;
333 code = (int32_t) c->exec_status.code;
334 status = (int32_t) c->exec_status.status;
335
336 b = !!c->ignore;
337
338 if (!dbus_message_iter_close_container(&sub2, &sub3) ||
339 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
340 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.realtime) ||
341 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.monotonic) ||
342 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.realtime) ||
343 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.monotonic) ||
344 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid) ||
345 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &code) ||
346 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &status))
347 return -ENOMEM;
348
349 if (!dbus_message_iter_close_container(&sub, &sub2))
350 return -ENOMEM;
351 }
352
353 if (!dbus_message_iter_close_container(i, &sub))
354 return -ENOMEM;
355
356 return 0;
357 }
358
359 const BusProperty bus_exec_context_properties[] = {
360 { "Environment", bus_property_append_strv, "as", offsetof(ExecContext, environment), true },
361 { "EnvironmentFiles", bus_execute_append_env_files, "a(sb)", offsetof(ExecContext, environment_files), true },
362 { "UMask", bus_property_append_mode, "u", offsetof(ExecContext, umask) },
363 { "LimitCPU", bus_execute_append_rlimits, "t", 0 },
364 { "LimitFSIZE", bus_execute_append_rlimits, "t", 0 },
365 { "LimitDATA", bus_execute_append_rlimits, "t", 0 },
366 { "LimitSTACK", bus_execute_append_rlimits, "t", 0 },
367 { "LimitCORE", bus_execute_append_rlimits, "t", 0 },
368 { "LimitRSS", bus_execute_append_rlimits, "t", 0 },
369 { "LimitNOFILE", bus_execute_append_rlimits, "t", 0 },
370 { "LimitAS", bus_execute_append_rlimits, "t", 0 },
371 { "LimitNPROC", bus_execute_append_rlimits, "t", 0 },
372 { "LimitMEMLOCK", bus_execute_append_rlimits, "t", 0 },
373 { "LimitLOCKS", bus_execute_append_rlimits, "t", 0 },
374 { "LimitSIGPENDING", bus_execute_append_rlimits, "t", 0 },
375 { "LimitMSGQUEUE", bus_execute_append_rlimits, "t", 0 },
376 { "LimitNICE", bus_execute_append_rlimits, "t", 0 },
377 { "LimitRTPRIO", bus_execute_append_rlimits, "t", 0 },
378 { "LimitRTTIME", bus_execute_append_rlimits, "t", 0 },
379 { "WorkingDirectory", bus_property_append_string, "s", offsetof(ExecContext, working_directory), true },
380 { "RootDirectory", bus_property_append_string, "s", offsetof(ExecContext, root_directory), true },
381 { "OOMScoreAdjust", bus_execute_append_oom_score_adjust, "i", 0 },
382 { "Nice", bus_execute_append_nice, "i", 0 },
383 { "IOScheduling", bus_execute_append_ioprio, "i", 0 },
384 { "CPUSchedulingPolicy", bus_execute_append_cpu_sched_policy, "i", 0 },
385 { "CPUSchedulingPriority", bus_execute_append_cpu_sched_priority, "i", 0 },
386 { "CPUAffinity", bus_execute_append_affinity, "ay", 0 },
387 { "TimerSlackNSec", bus_execute_append_timer_slack_nsec, "t", 0 },
388 { "CPUSchedulingResetOnFork", bus_property_append_bool, "b", offsetof(ExecContext, cpu_sched_reset_on_fork) },
389 { "NonBlocking", bus_property_append_bool, "b", offsetof(ExecContext, non_blocking) },
390 { "StandardInput", bus_execute_append_input, "s", offsetof(ExecContext, std_input) },
391 { "StandardOutput", bus_execute_append_output, "s", offsetof(ExecContext, std_output) },
392 { "StandardError", bus_execute_append_output, "s", offsetof(ExecContext, std_error) },
393 { "TTYPath", bus_property_append_string, "s", offsetof(ExecContext, tty_path), true },
394 { "TTYReset", bus_property_append_bool, "b", offsetof(ExecContext, tty_reset) },
395 { "TTYVHangup", bus_property_append_bool, "b", offsetof(ExecContext, tty_vhangup) },
396 { "TTYVTDisallocate", bus_property_append_bool, "b", offsetof(ExecContext, tty_vt_disallocate) },
397 { "SyslogPriority", bus_property_append_int, "i", offsetof(ExecContext, syslog_priority) },
398 { "SyslogIdentifier", bus_property_append_string, "s", offsetof(ExecContext, syslog_identifier), true },
399 { "SyslogLevelPrefix", bus_property_append_bool, "b", offsetof(ExecContext, syslog_level_prefix) },
400 { "Capabilities", bus_execute_append_capabilities, "s", 0 },
401 { "SecureBits", bus_property_append_int, "i", offsetof(ExecContext, secure_bits) },
402 { "CapabilityBoundingSet", bus_execute_append_capability_bs, "t", offsetof(ExecContext, capability_bounding_set_drop) },
403 { "User", bus_property_append_string, "s", offsetof(ExecContext, user), true },
404 { "Group", bus_property_append_string, "s", offsetof(ExecContext, group), true },
405 { "SupplementaryGroups", bus_property_append_strv, "as", offsetof(ExecContext, supplementary_groups), true },
406 { "TCPWrapName", bus_property_append_string, "s", offsetof(ExecContext, tcpwrap_name), true },
407 { "PAMName", bus_property_append_string, "s", offsetof(ExecContext, pam_name), true },
408 { "ReadWriteDirectories", bus_property_append_strv, "as", offsetof(ExecContext, read_write_dirs), true },
409 { "ReadOnlyDirectories", bus_property_append_strv, "as", offsetof(ExecContext, read_only_dirs), true },
410 { "InaccessibleDirectories", bus_property_append_strv, "as", offsetof(ExecContext, inaccessible_dirs), true },
411 { "MountFlags", bus_property_append_ul, "t", offsetof(ExecContext, mount_flags) },
412 { "PrivateTmp", bus_property_append_bool, "b", offsetof(ExecContext, private_tmp) },
413 { "PrivateNetwork", bus_property_append_bool, "b", offsetof(ExecContext, private_network) },
414 { "SameProcessGroup", bus_property_append_bool, "b", offsetof(ExecContext, same_pgrp) },
415 { "KillMode", bus_execute_append_kill_mode, "s", offsetof(ExecContext, kill_mode) },
416 { "KillSignal", bus_property_append_int, "i", offsetof(ExecContext, kill_signal) },
417 { "UtmpIdentifier", bus_property_append_string, "s", offsetof(ExecContext, utmp_id), true },
418 { "ControlGroupModify", bus_property_append_bool, "b", offsetof(ExecContext, control_group_modify) },
419 { "ControlGroupPersistent", bus_property_append_tristate_false, "b", offsetof(ExecContext, control_group_persistent) },
420 { "IgnoreSIGPIPE", bus_property_append_bool, "b", offsetof(ExecContext, ignore_sigpipe ) },
421 { NULL, }
422 };