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