1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
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 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <dbus/dbus.h>
24 #include <sys/prctl.h>
26 #include "dbus-execute.h"
30 #include "dbus-common.h"
32 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_kill_mode
, kill_mode
, KillMode
);
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
);
37 int bus_execute_append_env_files(DBusMessageIter
*i
, const char *property
, void *data
) {
38 char **env_files
= data
, **j
;
39 DBusMessageIter sub
, sub2
;
44 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_ARRAY
, "(sb)", &sub
))
47 STRV_FOREACH(j
, env_files
) {
48 dbus_bool_t b
= false;
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
))
63 if (!dbus_message_iter_close_container(i
, &sub
))
69 int bus_execute_append_oom_score_adjust(DBusMessageIter
*i
, const char *property
, void *data
) {
70 ExecContext
*c
= data
;
77 if (c
->oom_score_adjust_set
)
78 n
= c
->oom_score_adjust
;
83 if (read_one_line_file("/proc/self/oom_score_adj", &t
) >= 0) {
86 } else if (read_one_line_file("/proc/self/oom_adj", &t
) >= 0) {
90 if (n
== OOM_ADJUST_MAX
)
91 n
= OOM_SCORE_ADJ_MAX
;
93 n
= (n
* OOM_SCORE_ADJ_MAX
) / -OOM_DISABLE
;
97 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_INT32
, &n
))
103 int bus_execute_append_nice(DBusMessageIter
*i
, const char *property
, void *data
) {
104 ExecContext
*c
= data
;
114 n
= getpriority(PRIO_PROCESS
, 0);
116 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_INT32
, &n
))
122 int bus_execute_append_ioprio(DBusMessageIter
*i
, const char *property
, void *data
) {
123 ExecContext
*c
= data
;
133 n
= ioprio_get(IOPRIO_WHO_PROCESS
, 0);
135 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_INT32
, &n
))
141 int bus_execute_append_cpu_sched_policy(DBusMessageIter
*i
, const char *property
, void *data
) {
142 ExecContext
*c
= data
;
149 if (c
->cpu_sched_set
)
150 n
= c
->cpu_sched_policy
;
152 n
= sched_getscheduler(0);
154 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_INT32
, &n
))
160 int bus_execute_append_cpu_sched_priority(DBusMessageIter
*i
, const char *property
, void *data
) {
161 ExecContext
*c
= data
;
168 if (c
->cpu_sched_set
)
169 n
= c
->cpu_sched_priority
;
171 struct sched_param p
;
175 if (sched_getparam(0, &p
) >= 0)
176 n
= p
.sched_priority
;
179 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_INT32
, &n
))
185 int bus_execute_append_affinity(DBusMessageIter
*i
, const char *property
, void *data
) {
186 ExecContext
*c
= data
;
194 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_ARRAY
, "y", &sub
))
198 b
= dbus_message_iter_append_fixed_array(&sub
, DBUS_TYPE_BYTE
, &c
->cpuset
, CPU_ALLOC_SIZE(c
->cpuset_ncpus
));
200 b
= dbus_message_iter_append_fixed_array(&sub
, DBUS_TYPE_BYTE
, &c
->cpuset
, 0);
205 if (!dbus_message_iter_close_container(i
, &sub
))
211 int bus_execute_append_timer_slack_nsec(DBusMessageIter
*i
, const char *property
, void *data
) {
212 ExecContext
*c
= data
;
219 if (c
->timer_slack_nsec_set
)
220 u
= (uint64_t) c
->timer_slack_nsec
;
222 u
= (uint64_t) prctl(PR_GET_TIMERSLACK
);
224 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_UINT64
, &u
))
230 int bus_execute_append_capability_bs(DBusMessageIter
*i
, const char *property
, void *data
) {
231 ExecContext
*c
= data
;
232 uint64_t normal
, inverted
;
238 /* We store this negated internally, to match the kernel, but
239 * we expose it normalized. */
241 normal
= *(uint64_t*) data
;
244 return bus_property_append_uint64(i
, property
, &inverted
);
247 int bus_execute_append_capabilities(DBusMessageIter
*i
, const char *property
, void *data
) {
248 ExecContext
*c
= data
;
258 s
= t
= cap_to_text(c
->capabilities
, NULL
);
265 b
= dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &s
);
276 int bus_execute_append_rlimits(DBusMessageIter
*i
, const char *property
, void *data
) {
277 ExecContext
*c
= data
;
285 assert_se((r
= rlimit_from_string(property
)) >= 0);
288 u
= (uint64_t) c
->rlimit
[r
]->rlim_max
;
295 u
= (uint64_t) rl
.rlim_max
;
298 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_UINT64
, &u
))
304 int bus_execute_append_command(DBusMessageIter
*i
, const char *property
, void *data
) {
305 ExecCommand
*c
= data
;
306 DBusMessageIter sub
, sub2
, sub3
;
311 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_ARRAY
, "(sasbttttuii)", &sub
))
314 LIST_FOREACH(command
, c
, c
) {
317 int32_t code
, status
;
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
))
328 STRV_FOREACH(l
, c
->argv
)
329 if (!dbus_message_iter_append_basic(&sub3
, DBUS_TYPE_STRING
, l
))
332 pid
= (uint32_t) c
->exec_status
.pid
;
333 code
= (int32_t) c
->exec_status
.code
;
334 status
= (int32_t) c
->exec_status
.status
;
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
))
349 if (!dbus_message_iter_close_container(&sub
, &sub2
))
353 if (!dbus_message_iter_close_container(i
, &sub
))
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
) },