chiark / gitweb /
0a53207e590ca114a1a61f000f63ca8ca2d0b21d
[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 #include "fileio.h"
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                 }
87         }
88
89         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
90                 return -ENOMEM;
91
92         return 0;
93 }
94
95 int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) {
96         ExecContext *c = data;
97         int32_t n;
98
99         assert(i);
100         assert(property);
101         assert(c);
102
103         if (c->nice_set)
104                 n = c->nice;
105         else
106                 n = getpriority(PRIO_PROCESS, 0);
107
108         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
109                 return -ENOMEM;
110
111         return 0;
112 }
113
114 int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) {
115         ExecContext *c = data;
116         int32_t n;
117
118         assert(i);
119         assert(property);
120         assert(c);
121
122         if (c->ioprio_set)
123                 n = c->ioprio;
124         else
125                 n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
126
127         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
128                 return -ENOMEM;
129
130         return 0;
131 }
132
133 int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) {
134         ExecContext *c = data;
135         int32_t n;
136
137         assert(i);
138         assert(property);
139         assert(c);
140
141         if (c->cpu_sched_set)
142                 n = c->cpu_sched_policy;
143         else
144                 n = sched_getscheduler(0);
145
146         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
147                 return -ENOMEM;
148
149         return 0;
150 }
151
152 int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) {
153         ExecContext *c = data;
154         int32_t n;
155
156         assert(i);
157         assert(property);
158         assert(c);
159
160         if (c->cpu_sched_set)
161                 n = c->cpu_sched_priority;
162         else {
163                 struct sched_param p;
164
165                 zero(p);
166                 if (sched_getparam(0, &p) >= 0)
167                         n = p.sched_priority;
168                 else
169                         n = 0;
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         { "UtmpIdentifier",           bus_property_append_string,            "s", offsetof(ExecContext, utmp_id),                true },
435         { "ControlGroupModify",       bus_property_append_bool,              "b", offsetof(ExecContext, control_group_modify)         },
436         { "ControlGroupPersistent",   bus_property_append_tristate_false,    "b", offsetof(ExecContext, control_group_persistent)     },
437         { "IgnoreSIGPIPE",            bus_property_append_bool,              "b", offsetof(ExecContext, ignore_sigpipe)               },
438         { "NoNewPrivileges",          bus_property_append_bool,              "b", offsetof(ExecContext, no_new_privileges)            },
439         { "SystemCallFilter",         bus_execute_append_syscall_filter,    "au", 0                                                   },
440         { NULL, }
441 };