chiark / gitweb /
util: introduce a proper nsec_t and make use of it where appropriate
[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
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 != (nsec_t) -1)
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 };