chiark / gitweb /
Report about syntax errors with metadata
[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                 if (sched_getparam(0, &p) >= 0)
166                         n = p.sched_priority;
167                 else
168                         n = 0;
169         }
170
171         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
172                 return -ENOMEM;
173
174         return 0;
175 }
176
177 int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) {
178         ExecContext *c = data;
179         dbus_bool_t b;
180         DBusMessageIter sub;
181
182         assert(i);
183         assert(property);
184         assert(c);
185
186         if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
187                 return -ENOMEM;
188
189         if (c->cpuset)
190                 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
191         else
192                 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, 0);
193
194         if (!b)
195                 return -ENOMEM;
196
197         if (!dbus_message_iter_close_container(i, &sub))
198                 return -ENOMEM;
199
200         return 0;
201 }
202
203 int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) {
204         ExecContext *c = data;
205         uint64_t u;
206
207         assert(i);
208         assert(property);
209         assert(c);
210
211         if (c->timer_slack_nsec != (nsec_t) -1)
212                 u = (uint64_t) c->timer_slack_nsec;
213         else
214                 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
215
216         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
217                 return -ENOMEM;
218
219         return 0;
220 }
221
222 int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) {
223         ExecContext *c = data;
224         uint64_t normal, inverted;
225
226         assert(i);
227         assert(property);
228         assert(c);
229
230         /* We store this negated internally, to match the kernel, but
231          * we expose it normalized. */
232
233         normal = *(uint64_t*) data;
234         inverted = ~normal;
235
236         return bus_property_append_uint64(i, property, &inverted);
237 }
238
239 int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) {
240         ExecContext *c = data;
241         char *t = NULL;
242         const char *s;
243         dbus_bool_t b;
244
245         assert(i);
246         assert(property);
247         assert(c);
248
249         if (c->capabilities)
250                 s = t = cap_to_text(c->capabilities, NULL);
251         else
252                 s = "";
253
254         if (!s)
255                 return -ENOMEM;
256
257         b = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &s);
258
259         if (t)
260                 cap_free(t);
261
262         if (!b)
263                 return -ENOMEM;
264
265         return 0;
266 }
267
268 int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) {
269         ExecContext *c = data;
270         int r;
271         uint64_t u;
272
273         assert(i);
274         assert(property);
275         assert(c);
276
277         assert_se((r = rlimit_from_string(property)) >= 0);
278
279         if (c->rlimit[r])
280                 u = (uint64_t) c->rlimit[r]->rlim_max;
281         else {
282                 struct rlimit rl = {};
283
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 };