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