From 90ccc3fca7e53a60a9e67b9d5812e1d4a27fc07d Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 12 Apr 2012 13:34:18 +0200 Subject: move more main systemd parts to core/ --- src/core/load-fragment-gperf.gperf.m4 | 231 ++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 src/core/load-fragment-gperf.gperf.m4 (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 new file mode 100644 index 0000000000..c65db30fff --- /dev/null +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -0,0 +1,231 @@ +%{ +#include +#include "conf-parser.h" +#include "load-fragment.h" +#include "missing.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name load_fragment_gperf_hash +%define lookup-function-name load_fragment_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +m4_dnl Define the context options only once +m4_define(`EXEC_CONTEXT_CONFIG_ITEMS', +`$1.WorkingDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.working_directory) +$1.RootDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.root_directory) +$1.User, config_parse_unit_string_printf, 0, offsetof($1, exec_context.user) +$1.Group, config_parse_unit_string_printf, 0, offsetof($1, exec_context.group) +$1.SupplementaryGroups, config_parse_strv, 0, offsetof($1, exec_context.supplementary_groups) +$1.Nice, config_parse_exec_nice, 0, offsetof($1, exec_context) +$1.OOMScoreAdjust, config_parse_exec_oom_score_adjust, 0, offsetof($1, exec_context) +$1.IOSchedulingClass, config_parse_exec_io_class, 0, offsetof($1, exec_context) +$1.IOSchedulingPriority, config_parse_exec_io_priority, 0, offsetof($1, exec_context) +$1.CPUSchedulingPolicy, config_parse_exec_cpu_sched_policy, 0, offsetof($1, exec_context) +$1.CPUSchedulingPriority, config_parse_exec_cpu_sched_prio, 0, offsetof($1, exec_context) +$1.CPUSchedulingResetOnFork, config_parse_bool, 0, offsetof($1, exec_context.cpu_sched_reset_on_fork) +$1.CPUAffinity, config_parse_exec_cpu_affinity, 0, offsetof($1, exec_context) +$1.UMask, config_parse_mode, 0, offsetof($1, exec_context.umask) +$1.Environment, config_parse_unit_strv_printf, 0, offsetof($1, exec_context.environment) +$1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files) +$1.StandardInput, config_parse_input, 0, offsetof($1, exec_context.std_input) +$1.StandardOutput, config_parse_output, 0, offsetof($1, exec_context.std_output) +$1.StandardError, config_parse_output, 0, offsetof($1, exec_context.std_error) +$1.TTYPath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.tty_path) +$1.TTYReset, config_parse_bool, 0, offsetof($1, exec_context.tty_reset) +$1.TTYVHangup, config_parse_bool, 0, offsetof($1, exec_context.tty_vhangup) +$1.TTYVTDisallocate, config_parse_bool, 0, offsetof($1, exec_context.tty_vt_disallocate) +$1.SyslogIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.syslog_identifier) +$1.SyslogFacility, config_parse_facility, 0, offsetof($1, exec_context.syslog_priority) +$1.SyslogLevel, config_parse_level, 0, offsetof($1, exec_context.syslog_priority) +$1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix) +$1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context) +$1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context) +$1.CapabilityBoundingSet, config_parse_exec_bounding_set, 0, offsetof($1, exec_context) +$1.TimerSlackNSec, config_parse_exec_timer_slack_nsec, 0, offsetof($1, exec_context) +$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) +$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) +$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) +$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) +$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) +$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) +$1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit) +$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) +$1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit) +$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) +$1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit) +$1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit) +$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) +$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) +$1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) +$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) +$1.ControlGroup, config_parse_unit_cgroup, 0, 0 +$1.ControlGroupAttribute, config_parse_unit_cgroup_attr, 0, 0 +$1.CPUShares, config_parse_unit_cpu_shares, 0, 0 +$1.MemoryLimit, config_parse_unit_memory_limit, 0, 0 +$1.MemorySoftLimit, config_parse_unit_memory_limit, 0, 0 +$1.DeviceAllow, config_parse_unit_device_allow, 0, 0 +$1.DeviceDeny, config_parse_unit_device_allow, 0, 0 +$1.BlockIOWeight, config_parse_unit_blkio_weight, 0, 0 +$1.BlockIOReadBandwidth, config_parse_unit_blkio_bandwidth, 0, 0 +$1.BlockIOWriteBandwidth, config_parse_unit_blkio_bandwidth, 0, 0 +$1.ReadWriteDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.read_write_dirs) +$1.ReadOnlyDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.read_only_dirs) +$1.InaccessibleDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs) +$1.PrivateTmp, config_parse_bool, 0, offsetof($1, exec_context.private_tmp) +$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network) +$1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context) +$1.TCPWrapName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.tcpwrap_name) +$1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name) +$1.KillMode, config_parse_kill_mode, 0, offsetof($1, exec_context.kill_mode) +$1.KillSignal, config_parse_kill_signal, 0, offsetof($1, exec_context.kill_signal) +$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, exec_context.send_sigkill) +$1.IgnoreSIGPIPE, config_parse_bool, 0, offsetof($1, exec_context.ignore_sigpipe) +$1.UtmpIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.utmp_id) +$1.ControlGroupModify, config_parse_bool, 0, offsetof($1, exec_context.control_group_modify) +$1.ControlGroupPersistent, config_parse_tristate, 0, offsetof($1, exec_context.control_group_persistent)' +)m4_dnl +Unit.Names, config_parse_unit_names, 0, 0 +Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description) +Unit.Requires, config_parse_unit_deps, UNIT_REQUIRES, 0 +Unit.RequiresOverridable, config_parse_unit_deps, UNIT_REQUIRES_OVERRIDABLE, 0 +Unit.Requisite, config_parse_unit_deps, UNIT_REQUISITE, 0 +Unit.RequisiteOverridable, config_parse_unit_deps, UNIT_REQUISITE_OVERRIDABLE, 0 +Unit.Wants, config_parse_unit_deps, UNIT_WANTS, 0 +Unit.BindTo, config_parse_unit_deps, UNIT_BIND_TO, 0 +Unit.Conflicts, config_parse_unit_deps, UNIT_CONFLICTS, 0 +Unit.Before, config_parse_unit_deps, UNIT_BEFORE, 0 +Unit.After, config_parse_unit_deps, UNIT_AFTER, 0 +Unit.OnFailure, config_parse_unit_deps, UNIT_ON_FAILURE, 0 +Unit.PropagateReloadTo, config_parse_unit_deps, UNIT_PROPAGATE_RELOAD_TO, 0 +Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_PROPAGATE_RELOAD_FROM, 0 +Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded) +Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start) +Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Unit, refuse_manual_stop) +Unit.AllowIsolate, config_parse_bool, 0, offsetof(Unit, allow_isolate) +Unit.DefaultDependencies, config_parse_bool, 0, offsetof(Unit, default_dependencies) +Unit.OnFailureIsolate, config_parse_bool, 0, offsetof(Unit, on_failure_isolate) +Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Unit, ignore_on_isolate) +Unit.IgnoreOnSnapshot, config_parse_bool, 0, offsetof(Unit, ignore_on_snapshot) +Unit.JobTimeoutSec, config_parse_usec, 0, offsetof(Unit, job_timeout) +Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, 0 +Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, 0 +Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, 0 +Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,0 +Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, 0 +Unit.ConditionPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, 0 +Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, 0 +Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, 0 +Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, 0 +Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0 +Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, 0 +Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 0 +Unit.ConditionNull, config_parse_unit_condition_null, 0, 0 +m4_dnl +Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file) +Service.ExecStartPre, config_parse_exec, SERVICE_EXEC_START_PRE, offsetof(Service, exec_command) +Service.ExecStart, config_parse_exec, SERVICE_EXEC_START, offsetof(Service, exec_command) +Service.ExecStartPost, config_parse_exec, SERVICE_EXEC_START_POST, offsetof(Service, exec_command) +Service.ExecReload, config_parse_exec, SERVICE_EXEC_RELOAD, offsetof(Service, exec_command) +Service.ExecStop, config_parse_exec, SERVICE_EXEC_STOP, offsetof(Service, exec_command) +Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command) +Service.RestartSec, config_parse_usec, 0, offsetof(Service, restart_usec) +Service.TimeoutSec, config_parse_usec, 0, offsetof(Service, timeout_usec) +Service.WatchdogSec, config_parse_usec, 0, offsetof(Service, watchdog_usec) +Service.StartLimitInterval, config_parse_usec, 0, offsetof(Service, start_limit.interval) +Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst) +Service.StartLimitAction, config_parse_start_limit_action, 0, offsetof(Service, start_limit_action) +Service.Type, config_parse_service_type, 0, offsetof(Service, type) +Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart) +Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only) +Service.RootDirectoryStartOnly, config_parse_bool, 0, offsetof(Service, root_directory_start_only) +Service.RemainAfterExit, config_parse_bool, 0, offsetof(Service, remain_after_exit) +Service.GuessMainPID, config_parse_bool, 0, offsetof(Service, guess_main_pid) +m4_ifdef(`HAVE_SYSV_COMPAT', +`Service.SysVStartPriority, config_parse_sysv_priority, 0, offsetof(Service, sysv_start_priority)', +`Service.SysVStartPriority, config_parse_warn_compat, 0, 0') +Service.NonBlocking, config_parse_bool, 0, offsetof(Service, exec_context.non_blocking) +Service.BusName, config_parse_unit_string_printf, 0, offsetof(Service, bus_name) +Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access) +Service.Sockets, config_parse_service_sockets, 0, 0 +Service.FsckPassNo, config_parse_fsck_passno, 0, offsetof(Service, fsck_passno) +EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl +m4_dnl +Socket.ListenStream, config_parse_socket_listen, 0, 0 +Socket.ListenDatagram, config_parse_socket_listen, 0, 0 +Socket.ListenSequentialPacket, config_parse_socket_listen, 0, 0 +Socket.ListenFIFO, config_parse_socket_listen, 0, 0 +Socket.ListenNetlink, config_parse_socket_listen, 0, 0 +Socket.ListenSpecial, config_parse_socket_listen, 0, 0 +Socket.ListenMessageQueue, config_parse_socket_listen, 0, 0 +Socket.BindIPv6Only, config_parse_socket_bind, 0, 0, +Socket.Backlog, config_parse_unsigned, 0, offsetof(Socket, backlog) +Socket.BindToDevice, config_parse_socket_bindtodevice, 0, 0 +Socket.ExecStartPre, config_parse_exec, SOCKET_EXEC_START_PRE, offsetof(Socket, exec_command) +Socket.ExecStartPost, config_parse_exec, SOCKET_EXEC_START_POST, offsetof(Socket, exec_command) +Socket.ExecStopPre, config_parse_exec, SOCKET_EXEC_STOP_PRE, offsetof(Socket, exec_command) +Socket.ExecStopPost, config_parse_exec, SOCKET_EXEC_STOP_POST, offsetof(Socket, exec_command) +Socket.TimeoutSec, config_parse_usec, 0, offsetof(Socket, timeout_usec) +Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode) +Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode) +Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept) +Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections) +Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive) +Socket.Priority, config_parse_int, 0, offsetof(Socket, priority) +Socket.ReceiveBuffer, config_parse_bytes_size, 0, offsetof(Socket, receive_buffer) +Socket.SendBuffer, config_parse_bytes_size, 0, offsetof(Socket, send_buffer) +Socket.IPTOS, config_parse_ip_tos, 0, offsetof(Socket, ip_tos) +Socket.IPTTL, config_parse_int, 0, offsetof(Socket, ip_ttl) +Socket.Mark, config_parse_int, 0, offsetof(Socket, mark) +Socket.PipeSize, config_parse_bytes_size, 0, offsetof(Socket, pipe_size) +Socket.FreeBind, config_parse_bool, 0, offsetof(Socket, free_bind) +Socket.Transparent, config_parse_bool, 0, offsetof(Socket, transparent) +Socket.Broadcast, config_parse_bool, 0, offsetof(Socket, broadcast) +Socket.PassCredentials, config_parse_bool, 0, offsetof(Socket, pass_cred) +Socket.PassSecurity, config_parse_bool, 0, offsetof(Socket, pass_sec) +Socket.TCPCongestion, config_parse_string, 0, offsetof(Socket, tcp_congestion) +Socket.MessageQueueMaxMessages, config_parse_long, 0, offsetof(Socket, mq_maxmsg) +Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize) +Socket.Service, config_parse_socket_service, 0, 0 +EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl +m4_dnl +Mount.What, config_parse_string, 0, offsetof(Mount, parameters_fragment.what) +Mount.Where, config_parse_path, 0, offsetof(Mount, where) +Mount.Options, config_parse_string, 0, offsetof(Mount, parameters_fragment.options) +Mount.Type, config_parse_string, 0, offsetof(Mount, parameters_fragment.fstype) +Mount.TimeoutSec, config_parse_usec, 0, offsetof(Mount, timeout_usec) +Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode) +EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl +m4_dnl +Automount.Where, config_parse_path, 0, offsetof(Automount, where) +Automount.DirectoryMode, config_parse_mode, 0, offsetof(Automount, directory_mode) +m4_dnl +Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what) +Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority) +Swap.TimeoutSec, config_parse_usec, 0, offsetof(Swap, timeout_usec) +EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl +m4_dnl +Timer.OnActiveSec, config_parse_timer, 0, 0 +Timer.OnBootSec, config_parse_timer, 0, 0 +Timer.OnStartupSec, config_parse_timer, 0, 0 +Timer.OnUnitActiveSec, config_parse_timer, 0, 0 +Timer.OnUnitInactiveSec, config_parse_timer, 0, 0 +Timer.Unit, config_parse_timer_unit, 0, 0 +m4_dnl +Path.PathExists, config_parse_path_spec, 0, 0 +Path.PathExistsGlob, config_parse_path_spec, 0, 0 +Path.PathChanged, config_parse_path_spec, 0, 0 +Path.PathModified, config_parse_path_spec, 0, 0 +Path.DirectoryNotEmpty, config_parse_path_spec, 0, 0 +Path.Unit, config_parse_path_unit, 0, 0 +Path.MakeDirectory, config_parse_bool, 0, offsetof(Path, make_directory) +Path.DirectoryMode, config_parse_mode, 0, offsetof(Path, directory_mode) +m4_dnl The [Install] section is ignored here. +Install.Alias, NULL, 0, 0 +Install.WantedBy, NULL, 0, 0 +Install.Also, NULL, 0, 0 -- cgit v1.2.3-54-g00ecf From 7c8fa05c4d5d01748ff2a04edb882afb3119b7d7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 29 Apr 2012 14:26:07 +0200 Subject: unit: add new dependency type RequiresMountsFor= RequiresMountsFor= is a shortcut for adding requires and after dependencies to all mount units neeed for the specified paths. This solves a couple of issues regarding dep loop cycles for encrypted swap. --- Makefile.am | 1 + man/systemd.unit.xml | 12 ++++++ src/core/dbus-unit.c | 1 + src/core/dbus-unit.h | 1 + src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/load-fragment.c | 30 +++++++++++++++ src/core/load-fragment.h | 1 + src/core/manager.h | 3 ++ src/core/mount.c | 19 ++++++++++ src/core/unit.c | 62 +++++++++++++++++++++++++++++++ src/core/unit.h | 8 ++++ units/systemd-random-seed-load.service.in | 4 +- units/systemd-random-seed-save.service.in | 1 + 13 files changed, 142 insertions(+), 2 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/Makefile.am b/Makefile.am index 41fd773795..e1501aecf0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2889,6 +2889,7 @@ SED_PROCESS = \ -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' \ + -e 's,@RANDOM_SEED\@,$(localstatedir)/lib/random-seed,g' \ -e 's,@prefix\@,$(prefix),g' \ -e 's,@exec_prefix\@,$(exec_prefix),g' \ -e 's,@libdir\@,$(libdir),g' \ diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 12416fa317..c81c7a30b0 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -525,6 +525,18 @@ settings. + + RequiresMountsFor= + + Takes a space + separated list of paths. Automatically + adds dependencies of type + Requires= and + After= for all + mount units required to access the + specified path. + + OnFailureIsolate= diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 0484d75829..b8d661698b 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -810,6 +810,7 @@ const BusProperty bus_unit_properties[] = { { "TriggeredBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), true }, { "PropagateReloadTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PROPAGATE_RELOAD_TO]), true }, { "PropagateReloadFrom", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PROPAGATE_RELOAD_FROM]), true }, + { "RequiresMountsFor", bus_property_append_strv, "as", offsetof(Unit, requires_mounts_for), true }, { "Description", bus_unit_append_description, "s", 0 }, { "LoadState", bus_unit_append_load_state, "s", offsetof(Unit, load_state) }, { "ActiveState", bus_unit_append_active_state, "s", 0 }, diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index e6d549c0fb..d22802d274 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -85,6 +85,7 @@ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index c65db30fff..d929273877 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -104,6 +104,7 @@ Unit.After, config_parse_unit_deps, UNIT_AFTER, Unit.OnFailure, config_parse_unit_deps, UNIT_ON_FAILURE, 0 Unit.PropagateReloadTo, config_parse_unit_deps, UNIT_PROPAGATE_RELOAD_TO, 0 Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_PROPAGATE_RELOAD_FROM, 0 +Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, offsetof(Unit, requires_mounts_for) Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded) Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start) Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Unit, refuse_manual_stop) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 1665be82a0..d24919f998 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2032,6 +2032,35 @@ int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const return 0; } +int config_parse_unit_requires_mounts_for( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Unit *u = userdata; + int r; + bool empty_before; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + empty_before = !u->requires_mounts_for; + + r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata); + + /* Make it easy to find units with requires_mounts set */ + if (empty_before && u->requires_mounts_for) + LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u); + + return r; +} #define FOLLOW_MAX 8 @@ -2394,6 +2423,7 @@ void unit_dump_config_items(FILE *f) { { config_parse_socket_bindtodevice, "NETWORKINTERFACE" }, { config_parse_usec, "SECONDS" }, { config_parse_path_strv, "PATH [...]" }, + { config_parse_unit_requires_mounts_for, "PATH [...]" }, { config_parse_exec_mount_flags, "MOUNTFLAG [...]" }, { config_parse_unit_string_printf, "STRING" }, { config_parse_timer, "TIMER" }, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 03e13a9c8c..ccc436420e 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -83,6 +83,7 @@ int config_parse_unit_memory_limit(const char *filename, unsigned line, const ch int config_parse_unit_device_allow(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_requires_mounts_for(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* gperf prototypes */ const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length); diff --git a/src/core/manager.h b/src/core/manager.h index 154c1faeb7..6d1f5d86c2 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -104,6 +104,9 @@ struct Manager { * type we maintain a per type linked list */ LIST_HEAD(Unit, units_by_type[_UNIT_TYPE_MAX]); + /* To optimize iteration of units that have requires_mounts_for set */ + LIST_HEAD(Unit, has_requires_mounts_for); + /* Units that need to be loaded */ LIST_HEAD(Unit, load_queue); /* this is actually more a stack than a queue, but uh. */ diff --git a/src/core/mount.c b/src/core/mount.c index 3357b7df5b..5f50d9557a 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -263,6 +263,21 @@ static int mount_add_socket_links(Mount *m) { return 0; } +static int mount_add_requires_mounts_links(Mount *m) { + Unit *other; + int r; + + assert(m); + + LIST_FOREACH(has_requires_mounts_for, other, UNIT(m)->manager->has_requires_mounts_for) { + r = unit_add_one_mount_link(other, m); + if (r < 0) + return r; + } + + return 0; +} + static char* mount_test_option(const char *haystack, const char *needle) { struct mntent me; @@ -614,6 +629,10 @@ static int mount_load(Unit *u) { if ((r = mount_add_path_links(m)) < 0) return r; + r = mount_add_requires_mounts_links(m); + if (r < 0) + return r; + if ((r = mount_add_automount_links(m)) < 0) return r; diff --git a/src/core/unit.c b/src/core/unit.c index 491ba3f33f..fea75e88fe 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -370,6 +370,11 @@ void unit_free(Unit *u) { for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) bidi_set_free(u, u->dependencies[d]); + if (u->requires_mounts_for) { + LIST_REMOVE(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u); + strv_free(u->requires_mounts_for); + } + if (u->type != _UNIT_TYPE_INVALID) LIST_REMOVE(Unit, units_by_type, u->manager->units_by_type[u->type], u); @@ -691,6 +696,18 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->id); } + if (!strv_isempty(u->requires_mounts_for)) { + char **j; + + fprintf(f, + "%s\tRequiresMountsFor:", prefix); + + STRV_FOREACH(j, u->requires_mounts_for) + fprintf(f, " %s", *j); + + fputs("\n", f); + } + if (u->load_state == UNIT_LOADED) { CGroupBonding *b; CGroupAttribute *a; @@ -869,6 +886,12 @@ int unit_load(Unit *u) { if ((r = unit_add_default_dependencies(u)) < 0) goto fail; + if (u->load_state == UNIT_LOADED) { + r = unit_add_mount_links(u); + if (r < 0) + return r; + } + if (u->on_failure_isolate && set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) { @@ -2685,6 +2708,45 @@ void unit_ref_unset(UnitRef *ref) { ref->unit = NULL; } +int unit_add_one_mount_link(Unit *u, Mount *m) { + char **i; + + assert(u); + assert(m); + + if (u->load_state != UNIT_LOADED || + UNIT(m)->load_state != UNIT_LOADED) + return 0; + + STRV_FOREACH(i, u->requires_mounts_for) { + + if (UNIT(m) == u) + continue; + + if (!path_startswith(*i, m->where)) + continue; + + return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true); + } + + return 0; +} + +int unit_add_mount_links(Unit *u) { + Unit *other; + int r; + + assert(u); + + LIST_FOREACH(units_by_type, other, u->manager->units_by_type[UNIT_MOUNT]) { + r = unit_add_one_mount_link(u, MOUNT(other)); + if (r < 0) + return r; + } + + return 0; +} + static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { [UNIT_STUB] = "stub", [UNIT_LOADED] = "loaded", diff --git a/src/core/unit.h b/src/core/unit.h index c2bae0a45c..33920892fd 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -153,6 +153,8 @@ struct Unit { Set *names; Set *dependencies[_UNIT_DEPENDENCY_MAX]; + char **requires_mounts_for; + char *description; char *fragment_path; /* if loaded from a config file this is the primary path to it */ @@ -186,6 +188,9 @@ struct Unit { /* Per type list */ LIST_FIELDS(Unit, units_by_type); + /* All units which have requires_mounts_for set */ + LIST_FIELDS(Unit, has_requires_mounts_for); + /* Load queue */ LIST_FIELDS(Unit, load_queue); @@ -554,6 +559,9 @@ void unit_ref_unset(UnitRef *ref); #define UNIT_DEREF(ref) ((ref).unit) +int unit_add_one_mount_link(Unit *u, Mount *m); +int unit_add_mount_links(Unit *u); + const char *unit_load_state_to_string(UnitLoadState i); UnitLoadState unit_load_state_from_string(const char *s); diff --git a/units/systemd-random-seed-load.service.in b/units/systemd-random-seed-load.service.in index 6360436021..82f49c762b 100644 --- a/units/systemd-random-seed-load.service.in +++ b/units/systemd-random-seed-load.service.in @@ -8,10 +8,10 @@ [Unit] Description=Load Random Seed DefaultDependencies=no -Wants=local-fs.target Conflicts=shutdown.target -After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target +After=systemd-readahead-collect.service systemd-readahead-replay.service Before=sysinit.target shutdown.target +RequiresMountsFor=@RANDOM_SEED@ [Service] Type=oneshot diff --git a/units/systemd-random-seed-save.service.in b/units/systemd-random-seed-save.service.in index 219731bae5..0ebd07d868 100644 --- a/units/systemd-random-seed-save.service.in +++ b/units/systemd-random-seed-save.service.in @@ -11,6 +11,7 @@ DefaultDependencies=no After=systemd-random-seed-load.service Before=shutdown.target Conflicts=systemd-random-seed-load.service +RequiresMountsFor=@RANDOM_SEED@ [Service] Type=oneshot -- cgit v1.2.3-54-g00ecf From 49dbfa7b2b0bf3906704dac1eaeb4eba91056a19 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 21 May 2012 15:12:18 +0200 Subject: units: introduce new Documentation= field and make use of it everywhere This should help making the boot process a bit easier to explore and understand for the administrator. The simple idea is that "systemctl status" now shows a link to documentation alongside the other status and decriptionary information of a service. This patch adds the necessary fields to all our shipped units if we have proper documentation for them. --- man/systemd.special.xml | 65 ++++++++++++++++++++++++++ man/systemd.unit.xml | 17 +++++++ src/core/dbus-unit.c | 1 + src/core/dbus-unit.h | 1 + src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/load-fragment.c | 37 +++++++++++++++ src/core/load-fragment.h | 1 + src/core/unit.c | 8 ++-- src/core/unit.h | 1 + src/shared/util.c | 21 +++++++++ src/shared/util.h | 2 + src/systemctl/systemctl.c | 38 +++++++++++++++ units/basic.target | 3 +- units/bluetooth.target | 3 +- units/cryptsetup.target | 3 +- units/dev-hugepages.mount | 1 + units/dev-mqueue.mount | 1 + units/emergency.service.in | 2 - units/emergency.target | 3 +- units/final.target | 3 +- units/getty.target | 1 + units/getty@.service.m4 | 1 + units/graphical.target | 3 +- units/halt.target | 3 +- units/hibernate.target | 3 +- units/http-daemon.target | 3 +- units/kexec.target | 3 +- units/local-fs-pre.target | 3 +- units/local-fs.target | 3 +- units/mail-transfer-agent.target | 3 +- units/multi-user.target | 3 +- units/network.target | 3 +- units/nss-lookup.target | 3 +- units/nss-user-lookup.target | 3 +- units/poweroff.target | 3 +- units/printer.target | 3 +- units/proc-sys-fs-binfmt_misc.mount | 1 + units/reboot.target | 3 +- units/remote-fs-pre.target | 3 +- units/remote-fs.target | 3 +- units/rescue.service.m4.in | 2 - units/rescue.target | 3 +- units/rpcbind.target | 3 +- units/serial-getty@.service.m4 | 1 + units/shutdown.target | 3 +- units/sigpwr.target | 3 +- units/sleep.target | 3 +- units/smartcard.target | 3 +- units/sockets.target | 3 +- units/sound.target | 3 +- units/suspend.target | 3 +- units/swap.target | 3 +- units/sysinit.target | 3 +- units/syslog.socket | 4 +- units/syslog.target | 4 +- units/systemd-ask-password-console.path | 1 + units/systemd-ask-password-console.service.in | 1 + units/systemd-ask-password-plymouth.path | 1 + units/systemd-ask-password-plymouth.service.in | 1 + units/systemd-ask-password-wall.path | 1 + units/systemd-ask-password-wall.service.in | 1 + units/systemd-binfmt.service.in | 2 + units/systemd-hostnamed.service.in | 5 +- units/systemd-initctl.service.in | 2 - units/systemd-initctl.socket | 2 - units/systemd-journald.service.in | 3 +- units/systemd-journald.socket | 3 +- units/systemd-localed.service.in | 5 +- units/systemd-logind.service.in | 4 +- units/systemd-modules-load.service.in | 1 + units/systemd-shutdownd.service.in | 2 - units/systemd-shutdownd.socket | 2 - units/systemd-sysctl.service.in | 1 + units/systemd-timedated-ntp.target | 1 + units/systemd-timedated.service.in | 4 +- units/systemd-tmpfiles-clean.service.in | 1 + units/systemd-tmpfiles-clean.timer | 1 + units/systemd-tmpfiles-setup.service.in | 1 + units/systemd-udev-control.socket | 9 ++++ units/systemd-udev-kernel.socket | 9 ++++ units/systemd-udev-settle.service.in | 9 ++++ units/systemd-udev-trigger.service.in | 9 ++++ units/systemd-udev.service.in | 9 ++++ units/systemd-update-utmp-runlevel.service.in | 1 + units/systemd-update-utmp-shutdown.service.in | 1 + units/systemd-vconsole-setup.service.in | 1 + units/time-sync.target | 3 +- units/umount.target | 3 +- units/user/default.target | 3 +- units/user/exit.service.in | 3 +- units/user/exit.target | 3 +- 91 files changed, 312 insertions(+), 107 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 984e998aba..96befd5f5d 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -49,7 +49,9 @@ basic.target, + bluetooth.target, ctrl-alt-del.target, + cryptsetup.target, dbus.service, dbus.socket, default.target, @@ -57,6 +59,7 @@ emergency.target, exit.service, final.service, + getty.target, graphical.target, hibernate.target, http-daemon.target, @@ -69,7 +72,9 @@ multi-user.target, network.target, nss-lookup.target, + nss-user-lookup.target, poweroff.target, + printer.target, reboot.target, remote-fs.target, remote-fs-pre.target, @@ -82,7 +87,9 @@ shutdown.target, sigpwr.target, sleep.target, + smartcard.target, sockets.target, + sound.target, suspend.target, swap.target, sysinit.target, @@ -127,6 +134,16 @@ this unit. + + bluetooth.target + + This target is started + automatically as soon as a + bluetooth controller is + plugged in or becomes + available at boot. + + ctrl-alt-del.target @@ -139,6 +156,15 @@ reboot.target. + + cryptsetup.target + + A target that pulls in + setup services for all + encrypted block + devices. + + dbus.service @@ -226,6 +252,15 @@ + + getty.target + + A special target unit + that pulls in all local TTY + getty instances. + + + graphical.target @@ -442,6 +477,16 @@ unit, for compatibility with SysV. + + printer.target + + This target is started + automatically as soon as a + printer is plugged in or + becomes available at + boot. + + reboot.target @@ -615,6 +660,16 @@ logic. + + smartcard.target + + This target is started + automatically as soon as a + smartcard controller is + plugged in or becomes + available at boot. + + sockets.target @@ -629,6 +684,16 @@ during installation. + + sound.target + + This target is started + automatically as soon as a + sound card is plugged in or + becomes available at + boot. + + suspend.target diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index c81c7a30b0..dbc5fedea9 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -294,6 +294,23 @@ name. + + Documentation= + A space separated list + of URIs referencing documentation for + this unit or its + configuration. Accepted are only URIs + of the types + http://, + https://, + file:, + info:, + man:. For more + information about the syntax of these + URIs see + uri7. + + Requires= diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 834fbd7693..812f1b9f16 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -808,6 +808,7 @@ const BusProperty bus_unit_properties[] = { { "PropagateReloadTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PROPAGATE_RELOAD_TO]), true }, { "PropagateReloadFrom", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PROPAGATE_RELOAD_FROM]), true }, { "RequiresMountsFor", bus_property_append_strv, "as", offsetof(Unit, requires_mounts_for), true }, + { "Documentation", bus_property_append_strv, "as", offsetof(Unit, documentation), true }, { "Description", bus_unit_append_description, "s", 0 }, { "LoadState", bus_unit_append_load_state, "s", offsetof(Unit, load_state) }, { "ActiveState", bus_unit_append_active_state, "s", 0 }, diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index d22802d274..9680b56f06 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -87,6 +87,7 @@ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index d929273877..f0e25c0c5d 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -92,6 +92,7 @@ $1.ControlGroupPersistent, config_parse_tristate, 0, )m4_dnl Unit.Names, config_parse_unit_names, 0, 0 Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description) +Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation) Unit.Requires, config_parse_unit_deps, UNIT_REQUIRES, 0 Unit.RequiresOverridable, config_parse_unit_deps, UNIT_REQUIRES_OVERRIDABLE, 0 Unit.Requisite, config_parse_unit_deps, UNIT_REQUISITE, 0 diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index c2efec6657..3bc053341c 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2063,6 +2063,43 @@ int config_parse_unit_requires_mounts_for( return r; } +int config_parse_documentation( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Unit *u = userdata; + int r; + char **a, **b; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(u); + + r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata); + if (r < 0) + return r; + + for (a = b = u->documentation; a && *a; a++) { + + if (is_valid_documentation_url(*a)) + *(b++) = *a; + else { + log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a); + free(*a); + } + } + *b = NULL; + + return r; +} + #define FOLLOW_MAX 8 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index ccc436420e..3b2ed096b5 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -36,6 +36,7 @@ int config_parse_unit_names(const char *filename, unsigned line, const char *sec int config_parse_unit_string_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_strv_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_path_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_documentation(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_socket_listen(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_socket_bind(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_nice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/core/unit.c b/src/core/unit.c index 200d196878..1f1a5314f7 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -397,6 +397,7 @@ void unit_free(Unit *u) { cgroup_attribute_free_list(u->cgroup_attributes); free(u->description); + strv_free(u->documentation); free(u->fragment_path); free(u->instance); @@ -624,7 +625,7 @@ const char *unit_description(Unit *u) { } void unit_dump(Unit *u, FILE *f, const char *prefix) { - char *t; + char *t, **j; UnitDependency d; Iterator i; char *p2; @@ -672,6 +673,9 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { SET_FOREACH(t, u->names, i) fprintf(f, "%s\tName: %s\n", prefix, t); + STRV_FOREACH(j, u->documentation) + fprintf(f, "%s\tDocumentation: %s\n", prefix, *j); + if ((following = unit_following(u))) fprintf(f, "%s\tFollowing: %s\n", prefix, following->id); @@ -698,8 +702,6 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { } if (!strv_isempty(u->requires_mounts_for)) { - char **j; - fprintf(f, "%s\tRequiresMountsFor:", prefix); diff --git a/src/core/unit.h b/src/core/unit.h index e8e6b09866..87dc88c961 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -157,6 +157,7 @@ struct Unit { char **requires_mounts_for; char *description; + char **documentation; char *fragment_path; /* if loaded from a config file this is the primary path to it */ usec_t fragment_mtime; diff --git a/src/shared/util.c b/src/shared/util.c index 0b81e1c4f9..ae0ce320ad 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -5610,3 +5610,24 @@ int can_sleep(const char *type) { free(p); return found; } + +bool is_valid_documentation_url(const char *url) { + assert(url); + + if (startswith(url, "http://") && url[7]) + return true; + + if (startswith(url, "https://") && url[8]) + return true; + + if (startswith(url, "file:") && url[5]) + return true; + + if (startswith(url, "info:") && url[5]) + return true; + + if (startswith(url, "man:") && url[4]) + return true; + + return false; +} diff --git a/src/shared/util.h b/src/shared/util.h index f1bcb8a101..3dce047b40 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -508,4 +508,6 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value); int can_sleep(const char *type); +bool is_valid_documentation_url(const char *url); + #endif diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 92c79d038f..0d2044f874 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2158,6 +2158,8 @@ typedef struct UnitStatusInfo { const char *description; const char *following; + char **documentation; + const char *path; const char *default_control_group; @@ -2303,6 +2305,19 @@ static void print_status_info(UnitStatusInfo *i) { if (i->what) printf("\t What: %s\n", i->what); + if (!strv_isempty(i->documentation)) { + char **t; + bool first = true; + + STRV_FOREACH(t, i->documentation) { + if (first) { + printf("\t Docs: %s\n", *t); + first = false; + } else + printf("\t %s\n", *t); + } + } + if (i->accept) printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections); @@ -2607,6 +2622,27 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn LIST_PREPEND(ExecStatusInfo, exec, i->exec, info); + dbus_message_iter_next(&sub); + } + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING && + streq(name, "Documentation")) { + + DBusMessageIter sub; + + dbus_message_iter_recurse(iter, &sub); + while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) { + const char *s; + char **l; + + dbus_message_iter_get_basic(&sub, &s); + + l = strv_append(i->documentation, s); + if (!l) + return -ENOMEM; + + strv_free(i->documentation); + i->documentation = l; + dbus_message_iter_next(&sub); } } @@ -2932,6 +2968,8 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo if (!show_properties) print_status_info(&info); + strv_free(info.documentation); + if (!streq_ptr(info.active_state, "active") && !streq_ptr(info.active_state, "reloading") && streq(verb, "status")) diff --git a/units/basic.target b/units/basic.target index c3c7ced7c6..f9d03fa16f 100644 --- a/units/basic.target +++ b/units/basic.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Basic System +Documentation=man:systemd.special(7) Requires=sysinit.target sockets.target After=sysinit.target sockets.target RefuseManualStart=yes diff --git a/units/bluetooth.target b/units/bluetooth.target index 6b9b5b5442..dd4ae14cfb 100644 --- a/units/bluetooth.target +++ b/units/bluetooth.target @@ -5,8 +5,7 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Bluetooth +Documentation=man:systemd.special(7) StopWhenUnneeded=yes diff --git a/units/cryptsetup.target b/units/cryptsetup.target index af38e5d673..25d3e33f6a 100644 --- a/units/cryptsetup.target +++ b/units/cryptsetup.target @@ -5,7 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Encrypted Volumes +Documentation=man:systemd.special(7) diff --git a/units/dev-hugepages.mount b/units/dev-hugepages.mount index fcc50736e0..9381167c83 100644 --- a/units/dev-hugepages.mount +++ b/units/dev-hugepages.mount @@ -7,6 +7,7 @@ [Unit] Description=Huge Pages File System +Documentation=https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt DefaultDependencies=no Before=sysinit.target ConditionPathExists=/sys/kernel/mm/hugepages diff --git a/units/dev-mqueue.mount b/units/dev-mqueue.mount index a55ac935c4..5786bb1519 100644 --- a/units/dev-mqueue.mount +++ b/units/dev-mqueue.mount @@ -7,6 +7,7 @@ [Unit] Description=POSIX Message Queue File System +Documentation=man:mq_overview(7) DefaultDependencies=no Before=sysinit.target ConditionPathExists=/proc/sys/fs/mqueue diff --git a/units/emergency.service.in b/units/emergency.service.in index 75007563d7..87864f1c53 100644 --- a/units/emergency.service.in +++ b/units/emergency.service.in @@ -5,8 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Emergency Shell DefaultDependencies=no diff --git a/units/emergency.target b/units/emergency.target index 791dbe595c..0760d66f95 100644 --- a/units/emergency.target +++ b/units/emergency.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Emergency Mode +Documentation=man:systemd.special(7) Requires=emergency.service After=emergency.service AllowIsolate=yes diff --git a/units/final.target b/units/final.target index d516f38e9e..42819105c8 100644 --- a/units/final.target +++ b/units/final.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Final Step +Documentation=man:systemd.special(7) DefaultDependencies=no RefuseManualStart=yes After=shutdown.target umount.target diff --git a/units/getty.target b/units/getty.target index f1c926c72d..d53da35f9c 100644 --- a/units/getty.target +++ b/units/getty.target @@ -7,3 +7,4 @@ [Unit] Description=Login Prompts +Documentation=man:systemd.special(7) diff --git a/units/getty@.service.m4 b/units/getty@.service.m4 index 431a3dd722..6d458360a4 100644 --- a/units/getty@.service.m4 +++ b/units/getty@.service.m4 @@ -7,6 +7,7 @@ [Unit] Description=Getty on %I +Documentation=man:agetty(8) After=systemd-user-sessions.service plymouth-quit-wait.service m4_ifdef(`TARGET_FEDORA', After=rc-local.service diff --git a/units/graphical.target b/units/graphical.target index 2e82d6f898..7c6ebd4789 100644 --- a/units/graphical.target +++ b/units/graphical.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Graphical Interface +Documentation=man:systemd.special(7) Requires=multi-user.target After=multi-user.target Conflicts=rescue.target diff --git a/units/halt.target b/units/halt.target index dc908805db..41266b96f0 100644 --- a/units/halt.target +++ b/units/halt.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Halt +Documentation=man:systemd.special(7) DefaultDependencies=no Requires=halt.service After=halt.service diff --git a/units/hibernate.target b/units/hibernate.target index 05238a7cbf..23a9f99984 100644 --- a/units/hibernate.target +++ b/units/hibernate.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Hibernate +Documentation=man:systemd.special(7) DefaultDependencies=no BindTo=hibernate.service After=hibernate.service diff --git a/units/http-daemon.target b/units/http-daemon.target index 1de1ec4018..21ce997c1a 100644 --- a/units/http-daemon.target +++ b/units/http-daemon.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - # This exists mostly for compatibility with SysV/LSB units, and # implementations lacking socket/bus activation. [Unit] Description=Web Server +Documentation=man:systemd.special(7) diff --git a/units/kexec.target b/units/kexec.target index 4941f51c91..be8eafcf1f 100644 --- a/units/kexec.target +++ b/units/kexec.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Reboot via kexec +Documentation=man:systemd.special(7) DefaultDependencies=no Requires=kexec.service After=kexec.service diff --git a/units/local-fs-pre.target b/units/local-fs-pre.target index a928c1d79e..f8760ec9df 100644 --- a/units/local-fs-pre.target +++ b/units/local-fs-pre.target @@ -5,7 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Local File Systems (Pre) +Documentation=man:systemd.special(7) diff --git a/units/local-fs.target b/units/local-fs.target index 2aa51fca8c..dd92b17b6a 100644 --- a/units/local-fs.target +++ b/units/local-fs.target @@ -5,9 +5,8 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Local File Systems +Documentation=man:systemd.special(7) OnFailure=emergency.target OnFailureIsolate=yes diff --git a/units/mail-transfer-agent.target b/units/mail-transfer-agent.target index 94d134e345..d2f24d15b9 100644 --- a/units/mail-transfer-agent.target +++ b/units/mail-transfer-agent.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - # This exists mostly for compatibility with SysV/LSB units, and # implementations lacking socket/bus activation. [Unit] Description=Mail Transfer Agent +Documentation=man:systemd.special(7) diff --git a/units/multi-user.target b/units/multi-user.target index fe19cbcd0b..6e3f0b4f7a 100644 --- a/units/multi-user.target +++ b/units/multi-user.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Multi-User +Documentation=man:systemd.special(7) Requires=basic.target Conflicts=rescue.service rescue.target After=basic.target rescue.service rescue.target diff --git a/units/network.target b/units/network.target index da800da5b0..5406f4e5d9 100644 --- a/units/network.target +++ b/units/network.target @@ -5,7 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Network +Documentation=man:systemd.special(7) diff --git a/units/nss-lookup.target b/units/nss-lookup.target index c2d605c8a1..eea905a715 100644 --- a/units/nss-lookup.target +++ b/units/nss-lookup.target @@ -5,11 +5,10 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - # This exists mostly for compatibility with SysV/LSB units, and # implementations lacking socket/bus activation. [Unit] Description=Host and Network Name Lookups +Documentation=man:systemd.special(7) After=network.target diff --git a/units/nss-user-lookup.target b/units/nss-user-lookup.target index 0053f0608c..3e0fced101 100644 --- a/units/nss-user-lookup.target +++ b/units/nss-user-lookup.target @@ -5,11 +5,10 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - # This exists mostly for implementations lacking socket/bus # activation. [Unit] Description=User and Group Name Lookups +Documentation=man:systemd.special(7) After=network.target diff --git a/units/poweroff.target b/units/poweroff.target index b81d6ee0d4..bb60c33dd9 100644 --- a/units/poweroff.target +++ b/units/poweroff.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Power-Off +Documentation=man:systemd.special(7) DefaultDependencies=no Requires=poweroff.service After=poweroff.service diff --git a/units/printer.target b/units/printer.target index b8582da7ad..a6b86caa8d 100644 --- a/units/printer.target +++ b/units/printer.target @@ -5,8 +5,7 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Printer +Documentation=man:systemd.special(7) StopWhenUnneeded=yes diff --git a/units/proc-sys-fs-binfmt_misc.mount b/units/proc-sys-fs-binfmt_misc.mount index ff958ca01b..c64c84951e 100644 --- a/units/proc-sys-fs-binfmt_misc.mount +++ b/units/proc-sys-fs-binfmt_misc.mount @@ -7,6 +7,7 @@ [Unit] Description=Arbitrary Executable File Formats File System +Documentation=https://www.kernel.org/doc/Documentation/binfmt_misc.txt DefaultDependencies=no [Mount] diff --git a/units/reboot.target b/units/reboot.target index 6d02417eb5..9faeb1800f 100644 --- a/units/reboot.target +++ b/units/reboot.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Reboot +Documentation=man:systemd.special(7) DefaultDependencies=no Requires=reboot.service After=reboot.service diff --git a/units/remote-fs-pre.target b/units/remote-fs-pre.target index 8f688ad7af..2169533bd3 100644 --- a/units/remote-fs-pre.target +++ b/units/remote-fs-pre.target @@ -5,8 +5,7 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Remote File Systems (Pre) +Documentation=man:systemd.special(7) After=network.target nss-lookup.target diff --git a/units/remote-fs.target b/units/remote-fs.target index 87455a4a99..9e68878ad8 100644 --- a/units/remote-fs.target +++ b/units/remote-fs.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Remote File Systems +Documentation=man:systemd.special(7) [Install] WantedBy=multi-user.target diff --git a/units/rescue.service.m4.in b/units/rescue.service.m4.in index 3adfcf45bd..75b9fde278 100644 --- a/units/rescue.service.m4.in +++ b/units/rescue.service.m4.in @@ -5,8 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Rescue Shell DefaultDependencies=no diff --git a/units/rescue.target b/units/rescue.target index 85099a1ee0..c17a4e12d0 100644 --- a/units/rescue.target +++ b/units/rescue.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Rescue Mode +Documentation=man:systemd.special(7) Requires=basic.target rescue.service After=basic.target rescue.service AllowIsolate=yes diff --git a/units/rpcbind.target b/units/rpcbind.target index 5a286ebe6a..eb06a6db26 100644 --- a/units/rpcbind.target +++ b/units/rpcbind.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - # This exists mostly for compatibility with SysV/LSB units, and # implementations lacking socket/bus activation. [Unit] Description=RPC Port Mapper +Documentation=man:systemd.special(7) diff --git a/units/serial-getty@.service.m4 b/units/serial-getty@.service.m4 index 366b2d0710..d61f93cec3 100644 --- a/units/serial-getty@.service.m4 +++ b/units/serial-getty@.service.m4 @@ -7,6 +7,7 @@ [Unit] Description=Serial Getty on %I +Documentation=man:agetty(8) BindTo=dev-%i.device After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service m4_ifdef(`TARGET_FEDORA', diff --git a/units/shutdown.target b/units/shutdown.target index 1bbef68280..73e302b8b2 100644 --- a/units/shutdown.target +++ b/units/shutdown.target @@ -5,9 +5,8 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Shutdown +Documentation=man:systemd.special(7) DefaultDependencies=no RefuseManualStart=yes diff --git a/units/sigpwr.target b/units/sigpwr.target index 18a9683fb8..a52e7cffc9 100644 --- a/units/sigpwr.target +++ b/units/sigpwr.target @@ -5,7 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Power Failure +Documentation=man:systemd.special(7) diff --git a/units/sleep.target b/units/sleep.target index 9f4b247eb5..d7ebd289c8 100644 --- a/units/sleep.target +++ b/units/sleep.target @@ -5,9 +5,8 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Sleep +Documentation=man:systemd.special(7) DefaultDependencies=no RefuseManualStart=yes diff --git a/units/smartcard.target b/units/smartcard.target index 3e554a0303..5fefe84703 100644 --- a/units/smartcard.target +++ b/units/smartcard.target @@ -5,8 +5,7 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Smart Card +Documentation=man:systemd.special(7) StopWhenUnneeded=yes diff --git a/units/sockets.target b/units/sockets.target index ab1b786870..26ab065d02 100644 --- a/units/sockets.target +++ b/units/sockets.target @@ -5,7 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Sockets +Documentation=man:systemd.special(7) diff --git a/units/sound.target b/units/sound.target index 6a17360c10..6699adeceb 100644 --- a/units/sound.target +++ b/units/sound.target @@ -5,8 +5,7 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Sound Card +Documentation=man:systemd.special(7) StopWhenUnneeded=yes diff --git a/units/suspend.target b/units/suspend.target index 3ddb44975d..eaf79bed11 100644 --- a/units/suspend.target +++ b/units/suspend.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Suspend +Documentation=man:systemd.special(7) DefaultDependencies=no BindTo=suspend.service After=suspend.service diff --git a/units/swap.target b/units/swap.target index 4e165424b2..23a7d0dc9c 100644 --- a/units/swap.target +++ b/units/swap.target @@ -5,7 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Swap +Documentation=man:systemd.special(7) diff --git a/units/sysinit.target b/units/sysinit.target index 5bc568ff22..8f4fb8f5c1 100644 --- a/units/sysinit.target +++ b/units/sysinit.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=System Initialization +Documentation=man:systemd.special(7) Conflicts=emergency.service emergency.target Wants=local-fs.target swap.target After=local-fs.target swap.target emergency.service emergency.target diff --git a/units/syslog.socket b/units/syslog.socket index f644f6e38b..a228e5b09d 100644 --- a/units/syslog.socket +++ b/units/syslog.socket @@ -5,10 +5,10 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Syslog Socket +Documentation=man:systemd.special(7) +Documentation=http://www.freedesktop.org/wiki/Software/systemd/syslog DefaultDependencies=no Before=sockets.target syslog.target Conflicts=shutdown.target diff --git a/units/syslog.target b/units/syslog.target index 92d2576e95..87ac886df3 100644 --- a/units/syslog.target +++ b/units/syslog.target @@ -5,13 +5,13 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - # This exists mostly for compatibility with SysV/LSB units, and # implementations lacking socket/bus activation. [Unit] Description=Syslog +Documentation=man:systemd.special(7) +Documentation=http://www.freedesktop.org/wiki/Software/systemd/syslog # Avoid that we conflict with shutdown.target, so that we can stay # until the very end and do not cancel shutdown.target if we should diff --git a/units/systemd-ask-password-console.path b/units/systemd-ask-password-console.path index dc8ab32bcb..a0a3631b2f 100644 --- a/units/systemd-ask-password-console.path +++ b/units/systemd-ask-password-console.path @@ -7,6 +7,7 @@ [Unit] Description=Dispatch Password Requests to Console Directory Watch +Documentation=http://www.freedesktop.org/wiki/Software/systemd/PasswordAgents DefaultDependencies=no Conflicts=shutdown.target After=plymouth-start.service diff --git a/units/systemd-ask-password-console.service.in b/units/systemd-ask-password-console.service.in index 55e3d8648e..85e739fd80 100644 --- a/units/systemd-ask-password-console.service.in +++ b/units/systemd-ask-password-console.service.in @@ -7,6 +7,7 @@ [Unit] Description=Dispatch Password Requests to Console +Documentation=http://www.freedesktop.org/wiki/Software/systemd/PasswordAgents DefaultDependencies=no Conflicts=shutdown.target After=plymouth-start.service diff --git a/units/systemd-ask-password-plymouth.path b/units/systemd-ask-password-plymouth.path index b938ae57cf..9320b4a4df 100644 --- a/units/systemd-ask-password-plymouth.path +++ b/units/systemd-ask-password-plymouth.path @@ -7,6 +7,7 @@ [Unit] Description=Forward Password Requests to Plymouth Directory Watch +Documentation=http://www.freedesktop.org/wiki/Software/systemd/PasswordAgents DefaultDependencies=no Conflicts=shutdown.target After=plymouth-start.service diff --git a/units/systemd-ask-password-plymouth.service.in b/units/systemd-ask-password-plymouth.service.in index fcc2853642..ea80bbd931 100644 --- a/units/systemd-ask-password-plymouth.service.in +++ b/units/systemd-ask-password-plymouth.service.in @@ -7,6 +7,7 @@ [Unit] Description=Forward Password Requests to Plymouth +Documentation=http://www.freedesktop.org/wiki/Software/systemd/PasswordAgents DefaultDependencies=no Conflicts=shutdown.target After=plymouth-start.service diff --git a/units/systemd-ask-password-wall.path b/units/systemd-ask-password-wall.path index 73e13616b6..3890a7412d 100644 --- a/units/systemd-ask-password-wall.path +++ b/units/systemd-ask-password-wall.path @@ -7,6 +7,7 @@ [Unit] Description=Forward Password Requests to Wall Directory Watch +Documentation=http://www.freedesktop.org/wiki/Software/systemd/PasswordAgents DefaultDependencies=no Conflicts=shutdown.target Before=basic.target shutdown.target diff --git a/units/systemd-ask-password-wall.service.in b/units/systemd-ask-password-wall.service.in index 1db408e55b..9305fca6f7 100644 --- a/units/systemd-ask-password-wall.service.in +++ b/units/systemd-ask-password-wall.service.in @@ -7,6 +7,7 @@ [Unit] Description=Forward Password Requests to Wall +Documentation=http://www.freedesktop.org/wiki/Software/systemd/PasswordAgents After=systemd-user-sessions.service [Service] diff --git a/units/systemd-binfmt.service.in b/units/systemd-binfmt.service.in index 8d288066dc..a7cda979d4 100644 --- a/units/systemd-binfmt.service.in +++ b/units/systemd-binfmt.service.in @@ -7,6 +7,8 @@ [Unit] Description=Set Up Additional Binary Formats +Documentation=man:binfmt.d(5) +Documentation=https://www.kernel.org/doc/Documentation/binfmt_misc.txt DefaultDependencies=no Conflicts=shutdown.target After=systemd-readahead-collect.service systemd-readahead-replay.service proc-sys-fs-binfmt_misc.automount diff --git a/units/systemd-hostnamed.service.in b/units/systemd-hostnamed.service.in index a9a99136c0..d7fd1940f3 100644 --- a/units/systemd-hostnamed.service.in +++ b/units/systemd-hostnamed.service.in @@ -5,10 +5,11 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Hostname Service +Documentation=man:hostname(5) +Documentation=man:machine-info(5) +Documentation=http://www.freedesktop.org/wiki/Software/systemd/hostnamed [Service] ExecStart=@rootlibexecdir@/systemd-hostnamed diff --git a/units/systemd-initctl.service.in b/units/systemd-initctl.service.in index bcadcc8d1a..11e2286035 100644 --- a/units/systemd-initctl.service.in +++ b/units/systemd-initctl.service.in @@ -5,8 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=/dev/initctl Compatibility Daemon DefaultDependencies=no diff --git a/units/systemd-initctl.socket b/units/systemd-initctl.socket index 66597ee107..abafc525d7 100644 --- a/units/systemd-initctl.socket +++ b/units/systemd-initctl.socket @@ -5,8 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=/dev/initctl Compatibility Named Pipe DefaultDependencies=no diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in index a3c22c8ffa..da07cb9ce6 100644 --- a/units/systemd-journald.service.in +++ b/units/systemd-journald.service.in @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Journal Service +Documentation=man:journald.conf(5) DefaultDependencies=no Requires=systemd-journald.socket After=systemd-journald.socket diff --git a/units/systemd-journald.socket b/units/systemd-journald.socket index d613e2288f..0454e3e340 100644 --- a/units/systemd-journald.socket +++ b/units/systemd-journald.socket @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Journal Socket +Documentation=man:journald.conf(5) DefaultDependencies=no Before=sockets.target syslog.target diff --git a/units/systemd-localed.service.in b/units/systemd-localed.service.in index 763d2900fc..f973fa4585 100644 --- a/units/systemd-localed.service.in +++ b/units/systemd-localed.service.in @@ -5,10 +5,11 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Locale Service +Documentation=http://www.freedesktop.org/wiki/Software/systemd/localed +Documentation=man:locale.conf(5) +Documentation=man:vconsole.conf(5) [Service] ExecStart=@rootlibexecdir@/systemd-localed diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in index f244761606..d890713fdd 100644 --- a/units/systemd-logind.service.in +++ b/units/systemd-logind.service.in @@ -5,10 +5,10 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Login Service +Documentation=http://www.freedesktop.org/wiki/Software/systemd/multiseat +Documentation=man:logind.conf(5) After=nss-user-lookup.target [Service] diff --git a/units/systemd-modules-load.service.in b/units/systemd-modules-load.service.in index 243afadc83..8f25091986 100644 --- a/units/systemd-modules-load.service.in +++ b/units/systemd-modules-load.service.in @@ -7,6 +7,7 @@ [Unit] Description=Load Kernel Modules +Documentation=man:modules-load.d(5) DefaultDependencies=no Conflicts=shutdown.target After=systemd-readahead-collect.service systemd-readahead-replay.service diff --git a/units/systemd-shutdownd.service.in b/units/systemd-shutdownd.service.in index ec88b23fde..b9e271f0f6 100644 --- a/units/systemd-shutdownd.service.in +++ b/units/systemd-shutdownd.service.in @@ -5,8 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Delayed Shutdown Service DefaultDependencies=no diff --git a/units/systemd-shutdownd.socket b/units/systemd-shutdownd.socket index c97e01a337..ed6225a098 100644 --- a/units/systemd-shutdownd.socket +++ b/units/systemd-shutdownd.socket @@ -5,8 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Delayed Shutdown Socket DefaultDependencies=no diff --git a/units/systemd-sysctl.service.in b/units/systemd-sysctl.service.in index d38f026142..d8849e7929 100644 --- a/units/systemd-sysctl.service.in +++ b/units/systemd-sysctl.service.in @@ -7,6 +7,7 @@ [Unit] Description=Apply Kernel Variables +Documentation=man:sysctl.d(5) DefaultDependencies=no Conflicts=shutdown.target After=systemd-readahead-collect.service systemd-readahead-replay.service diff --git a/units/systemd-timedated-ntp.target b/units/systemd-timedated-ntp.target index 128424857d..0837004128 100644 --- a/units/systemd-timedated-ntp.target +++ b/units/systemd-timedated-ntp.target @@ -12,6 +12,7 @@ [Unit] Description=Network Time Protocol +Documentation=http://www.freedesktop.org/wiki/Software/systemd/timedated [Install] WantedBy=multi-user.target diff --git a/units/systemd-timedated.service.in b/units/systemd-timedated.service.in index 01222833d1..fbdf9e1746 100644 --- a/units/systemd-timedated.service.in +++ b/units/systemd-timedated.service.in @@ -5,10 +5,10 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Time & Date Service +Documentation=http://www.freedesktop.org/wiki/Software/systemd/timedated +Documentation=man:timezone(5) [Service] ExecStart=@rootlibexecdir@/systemd-timedated diff --git a/units/systemd-tmpfiles-clean.service.in b/units/systemd-tmpfiles-clean.service.in index 0a8707e138..a288232e12 100644 --- a/units/systemd-tmpfiles-clean.service.in +++ b/units/systemd-tmpfiles-clean.service.in @@ -7,6 +7,7 @@ [Unit] Description=Cleanup of Temporary Directories +Documentation=man:tmpfiles.d(5) DefaultDependencies=no Wants=local-fs.target After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target diff --git a/units/systemd-tmpfiles-clean.timer b/units/systemd-tmpfiles-clean.timer index c9f89e803d..fac4ee3da8 100644 --- a/units/systemd-tmpfiles-clean.timer +++ b/units/systemd-tmpfiles-clean.timer @@ -7,6 +7,7 @@ [Unit] Description=Daily Cleanup of Temporary Directories +Documentation=man:tmpfiles.d(5) [Timer] OnBootSec=15min diff --git a/units/systemd-tmpfiles-setup.service.in b/units/systemd-tmpfiles-setup.service.in index 58c3415b1e..dbd6bfb6d5 100644 --- a/units/systemd-tmpfiles-setup.service.in +++ b/units/systemd-tmpfiles-setup.service.in @@ -7,6 +7,7 @@ [Unit] Description=Recreate Volatile Files and Directories +Documentation=man:tmpfiles.d(5) DefaultDependencies=no Wants=local-fs.target After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target diff --git a/units/systemd-udev-control.socket b/units/systemd-udev-control.socket index 1cf0683911..dc5e1da174 100644 --- a/units/systemd-udev-control.socket +++ b/units/systemd-udev-control.socket @@ -1,5 +1,14 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + [Unit] Description=udev Control Socket +Documentation=man:udev(7) +Documentation=man:udevd(8) DefaultDependencies=no ConditionCapability=CAP_MKNOD diff --git a/units/systemd-udev-kernel.socket b/units/systemd-udev-kernel.socket index 8f2690f3fe..3270fe8ced 100644 --- a/units/systemd-udev-kernel.socket +++ b/units/systemd-udev-kernel.socket @@ -1,5 +1,14 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + [Unit] Description=udev Kernel Socket +Documentation=man:udev(7) +Documentation=man:udevd(8) DefaultDependencies=no ConditionCapability=CAP_MKNOD diff --git a/units/systemd-udev-settle.service.in b/units/systemd-udev-settle.service.in index e8c9223162..b782d73ad0 100644 --- a/units/systemd-udev-settle.service.in +++ b/units/systemd-udev-settle.service.in @@ -1,3 +1,10 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + # This service is usually not enabled by default. If enabled, it # acts as a barrier for basic.target -- so all later services will # wait for udev completely finishing its coldplug run. @@ -10,6 +17,8 @@ [Unit] Description=udev Wait for Complete Device Initialization +Documentation=man:udev(7) +Documentation=man:udevd(8) DefaultDependencies=no Wants=systemd-udev.service After=udev-trigger.service diff --git a/units/systemd-udev-trigger.service.in b/units/systemd-udev-trigger.service.in index 523dd47abc..61d188e489 100644 --- a/units/systemd-udev-trigger.service.in +++ b/units/systemd-udev-trigger.service.in @@ -1,5 +1,14 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + [Unit] Description=udev Coldplug all Devices +Documentation=man:udev(7) +Documentation=man:udevd(8) Wants=systemd-udev.service After=systemd-udev-kernel.socket systemd-udev-control.socket DefaultDependencies=no diff --git a/units/systemd-udev.service.in b/units/systemd-udev.service.in index 8a1793339b..7bd8e3c210 100644 --- a/units/systemd-udev.service.in +++ b/units/systemd-udev.service.in @@ -1,5 +1,14 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + [Unit] Description=udev Kernel Device Manager +Documentation=man:udev(7) +Documentation=man:udevd(8) Wants=systemd-udev-control.socket systemd-udev-kernel.socket After=systemd-udev-control.socket systemd-udev-kernel.socket Before=basic.target diff --git a/units/systemd-update-utmp-runlevel.service.in b/units/systemd-update-utmp-runlevel.service.in index 2a0751e896..6666dbd790 100644 --- a/units/systemd-update-utmp-runlevel.service.in +++ b/units/systemd-update-utmp-runlevel.service.in @@ -7,6 +7,7 @@ [Unit] Description=Update UTMP about System Runlevel Changes +Documentation=man:utmp(5) DefaultDependencies=no After=local-fs.target sysinit.target auditd.service runlevel1.target runlevel2.target runlevel3.target runlevel4.target runlevel5.target systemd-tmpfiles-setup.service Before=poweroff.service reboot.service halt.service diff --git a/units/systemd-update-utmp-shutdown.service.in b/units/systemd-update-utmp-shutdown.service.in index e86c770548..5b726c3688 100644 --- a/units/systemd-update-utmp-shutdown.service.in +++ b/units/systemd-update-utmp-shutdown.service.in @@ -7,6 +7,7 @@ [Unit] Description=Update UTMP about System Shutdown +Documentation=man:utmp(5) DefaultDependencies=no After=local-fs.target sysinit.target auditd.service systemd-update-utmp-runlevel.service Before=poweroff.service reboot.service halt.service diff --git a/units/systemd-vconsole-setup.service.in b/units/systemd-vconsole-setup.service.in index 1420ce8f62..51fc0b5124 100644 --- a/units/systemd-vconsole-setup.service.in +++ b/units/systemd-vconsole-setup.service.in @@ -7,6 +7,7 @@ [Unit] Description=Setup Virtual Console +Documentation=man:vconsole.conf(5) DefaultDependencies=no Conflicts=shutdown.target After=systemd-readahead-collect.service systemd-readahead-replay.service diff --git a/units/time-sync.target b/units/time-sync.target index 36b9e7aeea..ec00ecbbf4 100644 --- a/units/time-sync.target +++ b/units/time-sync.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - # This exists mostly for compatibility with SysV/LSB units, and # implementations lacking socket/bus activation. [Unit] Description=System Time Synchronized +Documentation=man:systemd.special(7) diff --git a/units/umount.target b/units/umount.target index c583062911..39668d85d2 100644 --- a/units/umount.target +++ b/units/umount.target @@ -5,9 +5,8 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Unmount All Filesystems +Documentation=man:systemd.special(7) DefaultDependencies=no RefuseManualStart=yes diff --git a/units/user/default.target b/units/user/default.target index 4f9379ea5e..56cf4dcb9c 100644 --- a/units/user/default.target +++ b/units/user/default.target @@ -5,7 +5,6 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Default +Documentation=man:systemd.special(7) diff --git a/units/user/exit.service.in b/units/user/exit.service.in index c785fbd64a..a114f6c1be 100644 --- a/units/user/exit.service.in +++ b/units/user/exit.service.in @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Exit the Session +Documentation=man:systemd.special(7) DefaultDependencies=no Requires=shutdown.target After=shutdown.target diff --git a/units/user/exit.target b/units/user/exit.target index ffc8fad019..539e03a9aa 100644 --- a/units/user/exit.target +++ b/units/user/exit.target @@ -5,10 +5,9 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See systemd.special(7) for details - [Unit] Description=Exit the Session +Documentation=man:systemd.special(7) DefaultDependencies=no Requires=exit.service After=exit.service -- cgit v1.2.3-54-g00ecf From 78d54bd42b87818f5d0ef862d247f9db4844fadd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 21 May 2012 15:27:26 +0200 Subject: unit: introduce RequiredBy= setting in [Install], to complement WantedBy= --- man/systemd.unit.xml | 2 ++ src/core/load-fragment-gperf.gperf.m4 | 1 + src/shared/install.c | 57 ++++++++++++++++++++++++++++++++--- 3 files changed, 55 insertions(+), 5 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index dbc5fedea9..c0da6523c4 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -951,9 +951,11 @@ WantedBy= + RequiredBy= Installs a symlink in the .wants/ + resp. .requires/ subdirectory for a unit. This has the effect that when the listed unit name is activated the unit listing it is diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index f0e25c0c5d..5be4daddee 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -230,4 +230,5 @@ Path.DirectoryMode, config_parse_mode, 0, m4_dnl The [Install] section is ignored here. Install.Alias, NULL, 0, 0 Install.WantedBy, NULL, 0, 0 +Install.RequiredBy, NULL, 0, 0 Install.Also, NULL, 0, 0 diff --git a/src/shared/install.c b/src/shared/install.c index 560bb24a93..d6644e580f 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -43,6 +43,7 @@ typedef struct { char **aliases; char **wanted_by; + char **required_by; } InstallInfo; typedef struct { @@ -883,6 +884,7 @@ static void install_info_free(InstallInfo *i) { free(i->path); strv_free(i->aliases); strv_free(i->wanted_by); + strv_free(i->required_by); free(i); } @@ -1021,9 +1023,10 @@ static int unit_file_load( bool allow_symlink) { const ConfigTableItem items[] = { - { "Install", "Alias", config_parse_strv, 0, &info->aliases }, - { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by }, - { "Install", "Also", config_parse_also, 0, c }, + { "Install", "Alias", config_parse_strv, 0, &info->aliases }, + { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by }, + { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by }, + { "Install", "Also", config_parse_also, 0, c }, { NULL, NULL, NULL, 0, NULL } }; @@ -1050,7 +1053,10 @@ static int unit_file_load( if (r < 0) return r; - return strv_length(info->aliases) + strv_length(info->wanted_by); + return + strv_length(info->aliases) + + strv_length(info->wanted_by) + + strv_length(info->required_by); } static int unit_file_search( @@ -1121,7 +1127,10 @@ static int unit_file_can_install( r = unit_file_search(&c, i, paths, root_dir, allow_symlink); if (r >= 0) - r = strv_length(i->aliases) + strv_length(i->wanted_by); + r = + strv_length(i->aliases) + + strv_length(i->wanted_by) + + strv_length(i->required_by); install_context_done(&c); @@ -1241,6 +1250,40 @@ static int install_info_symlink_wants( return r; } +static int install_info_symlink_requires( + InstallInfo *i, + const char *config_path, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + char **s; + int r = 0, q; + + assert(i); + assert(config_path); + + STRV_FOREACH(s, i->required_by) { + char *path; + + if (!unit_name_is_valid_no_type(*s, true)) { + r = -EINVAL; + continue; + } + + if (asprintf(&path, "%s/%s.requires/%s", config_path, *s, i->name) < 0) + return -ENOMEM; + + q = create_symlink(i->path, path, force, changes, n_changes); + free(path); + + if (r == 0) + r = q; + } + + return r; +} + static int install_info_symlink_link( InstallInfo *i, LookupPaths *paths, @@ -1290,6 +1333,10 @@ static int install_info_apply( if (r == 0) r = q; + q = install_info_symlink_requires(i, config_path, force, changes, n_changes); + if (r == 0) + r = q; + q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes); if (r == 0) r = q; -- cgit v1.2.3-54-g00ecf From 36140842612803d71fe771ce03f3dee7732284f0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 21 May 2012 17:24:26 +0200 Subject: service: make the fsck pass no configurable --- man/systemd.service.xml | 9 +++++++++ src/core/load-fragment-gperf.gperf.m4 | 1 + 2 files changed, 10 insertions(+) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 11f98c34d6..d5633dc329 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -835,6 +835,15 @@ . + + FsckPassNo= + + If this is an file + system checking service specify the + pass number. This should not be used + for normal services. + + diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 5be4daddee..681f2e9ae0 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -200,6 +200,7 @@ Mount.What, config_parse_string, 0, Mount.Where, config_parse_path, 0, offsetof(Mount, where) Mount.Options, config_parse_string, 0, offsetof(Mount, parameters_fragment.options) Mount.Type, config_parse_string, 0, offsetof(Mount, parameters_fragment.fstype) +Mount.FsckPassNo, config_parse_int, 0, offsetof(Mount, parameters_fragment.passno) Mount.TimeoutSec, config_parse_usec, 0, offsetof(Mount, timeout_usec) Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode) EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl -- cgit v1.2.3-54-g00ecf From 1b64d026af01277e332d10d9e67e2eed5a4ded28 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 22 May 2012 23:08:24 +0200 Subject: units: remove service sysv_path variable and replace it by generic unit_path UnitPath= is also writable via native units and may be used by generators to clarify from which file a unit is generated. This patch also hooks up the cryptsetup and fstab generators to set UnitPath= accordingly. --- man/systemd.unit.xml | 13 ++++++++ src/core/dbus-service.c | 4 +-- src/core/dbus-unit.c | 1 + src/core/dbus-unit.h | 1 + src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/load-fragment.c | 7 +++++ src/core/service.c | 59 +++++++++++------------------------ src/core/service.h | 4 +-- src/core/socket.c | 4 +-- src/core/unit.c | 19 ++++++++--- src/core/unit.h | 5 ++- src/cryptsetup/cryptsetup-generator.c | 7 ++--- src/fstab-generator/fstab-generator.c | 3 ++ src/systemctl/systemctl.c | 49 ++++++++++------------------- 14 files changed, 85 insertions(+), 92 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index c0da6523c4..123965bd44 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -897,6 +897,19 @@ instances. + + + SourcePath= + A path to a + configuration file this unit has been + generated from. This is primarily + useful for implementation of generator + tools that convert configuration from + an external configuration file format + into native unit files. Thus + functionality should not be used in + normal units. + Unit file may include a [Install] section, which diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index e0e5ffcbfd..4c6d5f0648 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -29,8 +29,7 @@ #ifdef HAVE_SYSV_COMPAT #define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT \ " \n" \ - " \n" \ - " \n" + " \n" #else #define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT "" #endif @@ -148,7 +147,6 @@ static const BusProperty bus_service_properties[] = { #ifdef HAVE_SYSV_COMPAT { "SysVRunLevels", bus_property_append_string, "s", offsetof(Service, sysv_runlevels), true }, { "SysVStartPriority", bus_property_append_int, "i", offsetof(Service, sysv_start_priority) }, - { "SysVPath", bus_property_append_string, "s", offsetof(Service, sysv_path), true }, #endif { "FsckPassNo", bus_property_append_int, "i", offsetof(Service, fsck_passno) }, { "Result", bus_service_append_service_result,"s", offsetof(Service, result) }, diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 812f1b9f16..f85f3f898a 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -814,6 +814,7 @@ const BusProperty bus_unit_properties[] = { { "ActiveState", bus_unit_append_active_state, "s", 0 }, { "SubState", bus_unit_append_sub_state, "s", 0 }, { "FragmentPath", bus_property_append_string, "s", offsetof(Unit, fragment_path), true }, + { "SourcePath", bus_property_append_string, "s", offsetof(Unit, source_path), true }, { "UnitFileState", bus_unit_append_file_state, "s", 0 }, { "InactiveExitTimestamp",bus_property_append_usec, "t", offsetof(Unit, inactive_exit_timestamp.realtime) }, { "InactiveExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, inactive_exit_timestamp.monotonic) }, diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index 9680b56f06..ae94ca2c2b 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -87,6 +87,7 @@ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 681f2e9ae0..901c20e78e 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -93,6 +93,7 @@ $1.ControlGroupPersistent, config_parse_tristate, 0, Unit.Names, config_parse_unit_names, 0, 0 Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description) Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation) +Unit.SourcePath, config_parse_path, 0, offsetof(Unit, source_path) Unit.Requires, config_parse_unit_deps, UNIT_REQUIRES, 0 Unit.RequiresOverridable, config_parse_unit_deps, UNIT_REQUIRES_OVERRIDABLE, 0 Unit.Requisite, config_parse_unit_deps, UNIT_REQUISITE, 0 diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 3bc053341c..d2267722dd 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2320,6 +2320,13 @@ static int load_from_path(Unit *u, const char *path) { u->fragment_mtime = timespec_load(&st.st_mtim); + if (u->source_path) { + if (stat(u->source_path, &st) >= 0) + u->source_mtime = timespec_load(&st.st_mtim); + else + u->source_mtime = 0; + } + r = 0; finish: diff --git a/src/core/service.c b/src/core/service.c index 5d82e9b545..940d664701 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -264,9 +264,6 @@ static void service_done(Unit *u) { s->pid_file = NULL; #ifdef HAVE_SYSV_COMPAT - free(s->sysv_path); - s->sysv_path = NULL; - free(s->sysv_runlevels); s->sysv_runlevels = NULL; #endif @@ -504,17 +501,21 @@ static int sysv_exec_commands(Service *s) { ExecCommand *c; assert(s); - assert(s->sysv_path); + assert(s->is_sysv); + assert(UNIT(s)->source_path); - if (!(c = exec_command_new(s->sysv_path, "start"))) + c = exec_command_new(UNIT(s)->source_path, "start"); + if (!c) return -ENOMEM; exec_command_append_list(s->exec_command+SERVICE_EXEC_START, c); - if (!(c = exec_command_new(s->sysv_path, "stop"))) + c = exec_command_new(UNIT(s)->source_path, "stop"); + if (!c) return -ENOMEM; exec_command_append_list(s->exec_command+SERVICE_EXEC_STOP, c); - if (!(c = exec_command_new(s->sysv_path, "reload"))) + c = exec_command_new(UNIT(s)->source_path, "reload"); + if (!c) return -ENOMEM; exec_command_append_list(s->exec_command+SERVICE_EXEC_RELOAD, c); @@ -540,7 +541,8 @@ static int service_load_sysv_path(Service *s, const char *path) { u = UNIT(s); - if (!(f = fopen(path, "re"))) { + f = fopen(path, "re"); + if (!f) { r = errno == ENOENT ? 0 : -errno; goto finish; } @@ -551,13 +553,13 @@ static int service_load_sysv_path(Service *s, const char *path) { goto finish; } - free(s->sysv_path); - if (!(s->sysv_path = strdup(path))) { + free(u->source_path); + u->source_path = strdup(path); + if (!u->source_path) { r = -ENOMEM; goto finish; } - - s->sysv_mtime = timespec_load(&st.st_mtim); + u->source_mtime = timespec_load(&st.st_mtim); if (null_or_empty(&st)) { u->load_state = UNIT_MASKED; @@ -565,6 +567,8 @@ static int service_load_sysv_path(Service *s, const char *path) { goto finish; } + s->is_sysv = true; + while (!feof(f)) { char l[LINE_MAX], *t; @@ -1337,12 +1341,10 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) { } #ifdef HAVE_SYSV_COMPAT - if (s->sysv_path) + if (s->is_sysv) fprintf(f, - "%sSysV Init Script Path: %s\n" "%sSysV Init Script has LSB Header: %s\n" "%sSysVEnabled: %s\n", - prefix, s->sysv_path, prefix, yes_no(s->sysv_has_lsb), prefix, yes_no(s->sysv_enabled)); @@ -2716,7 +2718,7 @@ static bool service_check_gc(Unit *u) { return true; #ifdef HAVE_SYSV_COMPAT - if (s->sysv_path) + if (s->is_sysv) return true; #endif @@ -3626,29 +3628,6 @@ static void service_reset_failed(Unit *u) { s->reload_result = SERVICE_SUCCESS; } -static bool service_need_daemon_reload(Unit *u) { - Service *s = SERVICE(u); - - assert(s); - -#ifdef HAVE_SYSV_COMPAT - if (s->sysv_path) { - struct stat st; - - zero(st); - if (stat(s->sysv_path, &st) < 0) - /* What, cannot access this anymore? */ - return true; - - if (s->sysv_mtime > 0 && - timespec_load(&st.st_mtim) != s->sysv_mtime) - return true; - } -#endif - - return false; -} - static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) { Service *s = SERVICE(u); int r = 0; @@ -3826,8 +3805,6 @@ const UnitVTable service_vtable = { .reset_failed = service_reset_failed, - .need_daemon_reload = service_need_daemon_reload, - .cgroup_notify_empty = service_cgroup_notify_event, .notify_message = service_notify_message, diff --git a/src/core/service.h b/src/core/service.h index 819672f617..f4ccc2b5a0 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -165,14 +165,13 @@ struct Service { bool forbid_restart:1; bool got_socket_fd:1; #ifdef HAVE_SYSV_COMPAT + bool is_sysv:1; bool sysv_has_lsb:1; bool sysv_enabled:1; int sysv_start_priority_from_rcnd; int sysv_start_priority; - char *sysv_path; char *sysv_runlevels; - usec_t sysv_mtime; #endif char *bus_name; @@ -182,7 +181,6 @@ struct Service { RateLimit start_limit; StartLimitAction start_limit_action; - UnitRef accept_socket; Watch timer_watch; diff --git a/src/core/socket.c b/src/core/socket.c index 2be1647be9..df47578a49 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -165,7 +165,7 @@ static int socket_instantiate_service(Socket *s) { return r; #ifdef HAVE_SYSV_COMPAT - if (SERVICE(u)->sysv_path) { + if (SERVICE(u)->is_sysv) { log_error("Using SysV services for socket activation is not supported. Refusing."); return -ENOENT; } @@ -1575,7 +1575,7 @@ static int socket_start(Unit *u) { } #ifdef HAVE_SYSV_COMPAT - if (service->sysv_path) { + if (service->is_sysv) { log_error("Using SysV services for socket activation is not supported. Refusing."); return -ENOENT; } diff --git a/src/core/unit.c b/src/core/unit.c index 1f1a5314f7..f53bdd5a91 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -399,6 +399,7 @@ void unit_free(Unit *u) { free(u->description); strv_free(u->documentation); free(u->fragment_path); + free(u->source_path); free(u->instance); set_free_free(u->names); @@ -682,6 +683,9 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { if (u->fragment_path) fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path); + if (u->source_path) + fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path); + if (u->job_timeout > 0) fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout)); @@ -2575,11 +2579,11 @@ void unit_status_printf(Unit *u, const char *status, const char *format, ...) { } bool unit_need_daemon_reload(Unit *u) { + struct stat st; + assert(u); if (u->fragment_path) { - struct stat st; - zero(st); if (stat(u->fragment_path, &st) < 0) /* What, cannot access this anymore? */ @@ -2590,8 +2594,15 @@ bool unit_need_daemon_reload(Unit *u) { return true; } - if (UNIT_VTABLE(u)->need_daemon_reload) - return UNIT_VTABLE(u)->need_daemon_reload(u); + if (u->source_path) { + zero(st); + if (stat(u->source_path, &st) < 0) + return true; + + if (u->source_mtime > 0 && + timespec_load(&st.st_mtim) != u->source_mtime) + return true; + } return false; } diff --git a/src/core/unit.h b/src/core/unit.h index 87dc88c961..cfb38d0aae 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -160,7 +160,9 @@ struct Unit { char **documentation; char *fragment_path; /* if loaded from a config file this is the primary path to it */ + char *source_path; /* if converted, the source file */ usec_t fragment_mtime; + usec_t source_mtime; /* If there is something to do with this unit, then this is the installed job for it */ Job *job; @@ -353,9 +355,6 @@ struct UnitVTable { void (*sigchld_event)(Unit *u, pid_t pid, int code, int status); void (*timer_event)(Unit *u, uint64_t n_elapsed, Watch *w); - /* Check whether unit needs a daemon reload */ - bool (*need_daemon_reload)(Unit *u); - /* Reset failed state if we are in failed state */ void (*reset_failed)(Unit *u); diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index 7eb122d276..51706b7a86 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -115,6 +115,7 @@ static int create_disk( "# Automatically generated by systemd-cryptsetup-generator\n\n" "[Unit]\n" "Description=Cryptography Setup for %%I\n" + "SourcePath=/etc/crypttab\n" "Conflicts=umount.target\n" "DefaultDependencies=no\n" "BindTo=%s dev-mapper-%%i.device\n" @@ -129,11 +130,9 @@ static int create_disk( if (password && (streq(password, "/dev/urandom") || streq(password, "/dev/random") || streq(password, "/dev/hw_random"))) - fprintf(f, - "After=systemd-random-seed-load.service\n"); + fputs("After=systemd-random-seed-load.service\n", f); else - fprintf(f, - "Before=local-fs.target\n"); + fputs("Before=local-fs.target\n", f); fprintf(f, "\n[Service]\n" diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 86cbc45b78..8a519fcfd9 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -117,6 +117,7 @@ static int add_swap(const char *what, struct mntent *me) { fputs("# Automatically generated by systemd-fstab-generator\n\n" "[Unit]\n" + "SourcePath=/etc/fstab\n" "DefaultDependencies=no\n" "Conflicts=" SPECIAL_UMOUNT_TARGET "\n" "Before=" SPECIAL_UMOUNT_TARGET "\n", f); @@ -274,6 +275,7 @@ static int add_mount(const char *what, const char *where, struct mntent *me) { fputs("# Automatically generated by systemd-fstab-generator\n\n" "[Unit]\n" + "SourcePath=/etc/fstab\n" "DefaultDependencies=no\n", f); if (!path_equal(where, "/")) @@ -386,6 +388,7 @@ static int add_mount(const char *what, const char *where, struct mntent *me) { fprintf(f, "# Automatically generated by systemd-fstab-generator\n\n" "[Unit]\n" + "SourcePath=/etc/fstab\n" "DefaultDependencies=no\n" "Conflicts=" SPECIAL_UMOUNT_TARGET "\n" "Before=" SPECIAL_UMOUNT_TARGET " %s\n" diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index b4253a45b1..03c2fd2d62 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2160,7 +2160,8 @@ typedef struct UnitStatusInfo { char **documentation; - const char *path; + const char *fragment_path; + const char *source_path; const char *default_control_group; const char *load_error; @@ -2179,9 +2180,6 @@ typedef struct UnitStatusInfo { pid_t control_pid; const char *status_text; bool running:1; -#ifdef HAVE_SYSV_COMPAT - bool is_sysv:1; -#endif usec_t start_timestamp; usec_t exit_timestamp; @@ -2214,6 +2212,7 @@ static void print_status_info(UnitStatusInfo *i) { usec_t timestamp; char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1; char since2[FORMAT_TIMESTAMP_MAX], *s2; + const char *path; assert(i); @@ -2236,12 +2235,14 @@ static void print_status_info(UnitStatusInfo *i) { } else on = off = ""; + path = i->source_path ? i->source_path : i->fragment_path; + if (i->load_error) printf("\t Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error); - else if (i->path && i->unit_file_state) - printf("\t Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, i->path, i->unit_file_state); - else if (i->path) - printf("\t Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, i->path); + else if (path && i->unit_file_state) + printf("\t Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state); + else if (path) + printf("\t Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path); else printf("\t Loaded: %s%s%s\n", on, strna(i->load_state), off); @@ -2333,13 +2334,7 @@ static void print_status_info(UnitStatusInfo *i) { printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t)); free(t); -#ifdef HAVE_SYSV_COMPAT - if (i->is_sysv) - good = is_clean_exit_lsb(p->code, p->status); - else -#endif - good = is_clean_exit(p->code, p->status); - + good = is_clean_exit_lsb(p->code, p->status); if (!good) { on = ansi_highlight_red(true); off = ansi_highlight_red(false); @@ -2353,11 +2348,8 @@ static void print_status_info(UnitStatusInfo *i) { printf("status=%i", p->status); -#ifdef HAVE_SYSV_COMPAT - if ((c = exit_status_to_string(p->status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD))) -#else - if ((c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD))) -#endif + c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD); + if (c) printf("/%s", c); } else @@ -2396,11 +2388,8 @@ static void print_status_info(UnitStatusInfo *i) { printf("status=%i", i->exit_status); -#ifdef HAVE_SYSV_COMPAT - if ((c = exit_status_to_string(i->exit_status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD))) -#else - if ((c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD))) -#endif + c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD); + if (c) printf("/%s", c); } else @@ -2492,13 +2481,9 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn else if (streq(name, "Description")) i->description = s; else if (streq(name, "FragmentPath")) - i->path = s; -#ifdef HAVE_SYSV_COMPAT - else if (streq(name, "SysVPath")) { - i->is_sysv = true; - i->path = s; - } -#endif + i->fragment_path = s; + else if (streq(name, "SourcePath")) + i->source_path = s; else if (streq(name, "DefaultControlGroup")) i->default_control_group = s; else if (streq(name, "StatusText")) -- cgit v1.2.3-54-g00ecf From 66b1a24790ccc3c60509e6f94890ed8c20a2fe9e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2012 04:11:29 +0200 Subject: man: properly document FsckPassNo= for mount units --- man/systemd.mount.xml | 13 +++++++++++++ man/systemd.service.xml | 9 --------- src/core/load-fragment-gperf.gperf.m4 | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml index ddaa3ce744..a1cc9dbf8d 100644 --- a/man/systemd.mount.xml +++ b/man/systemd.mount.xml @@ -257,6 +257,18 @@ value. Defaults to "yes". + + + FsckPassNo= + + The pass number for + the file system checking service for + this mount. See + systemd.service5 + for more information on this setting. + + + @@ -267,6 +279,7 @@ systemctl8, systemd.unit5, systemd.exec5, + systemd.service5, systemd.device5, mount8 diff --git a/man/systemd.service.xml b/man/systemd.service.xml index d5633dc329..11f98c34d6 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -835,15 +835,6 @@ . - - FsckPassNo= - - If this is an file - system checking service specify the - pass number. This should not be used - for normal services. - - diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 901c20e78e..ea502bd288 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -201,7 +201,7 @@ Mount.What, config_parse_string, 0, Mount.Where, config_parse_path, 0, offsetof(Mount, where) Mount.Options, config_parse_string, 0, offsetof(Mount, parameters_fragment.options) Mount.Type, config_parse_string, 0, offsetof(Mount, parameters_fragment.fstype) -Mount.FsckPassNo, config_parse_int, 0, offsetof(Mount, parameters_fragment.passno) +Mount.FsckPassNo, config_parse_fsck_passno, 0, offsetof(Mount, parameters_fragment.passno) Mount.TimeoutSec, config_parse_usec, 0, offsetof(Mount, timeout_usec) Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode) EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl -- cgit v1.2.3-54-g00ecf From ec8927ca5940e809f0b72f530582c76f1db4f065 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 24 May 2012 04:00:56 +0200 Subject: main: add configuration option to alter capability bounding set for PID 1 This also ensures that caps dropped from the bounding set are also dropped from the inheritable set, to be extra-secure. Usually that should change very little though as the inheritable set is empty for all our uses anyway. --- TODO | 18 ++----- man/systemd.conf.xml | 45 ++++++++++++++++-- man/systemd.exec.xml | 16 +++---- src/core/execute.c | 64 +------------------------ src/core/load-fragment-gperf.gperf.m4 | 2 +- src/core/load-fragment.c | 13 ++--- src/core/load-fragment.h | 2 +- src/core/main.c | 11 +++++ src/core/system.conf | 17 +++++++ src/nspawn/nspawn.c | 70 +++++++++++---------------- src/shared/capability.c | 89 ++++++++++++++++++++++++++++++++++- src/shared/capability.h | 5 ++ 12 files changed, 211 insertions(+), 141 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/TODO b/TODO index 6553cb0bc4..6d5eb73262 100644 --- a/TODO +++ b/TODO @@ -23,7 +23,9 @@ Bugfixes: Features: -* For Type=idle don't get confused by ExecStartPre= getting the effect of the idle hup but delaying jobs going away +* make use of /sys/power/wake_lock in inhibitors + +* introduce "systemctl help" which invokes man for the man pages listed in Documentation= * drop accountsservice's StandardOutput=syslog and Type=dbus fields @@ -140,8 +142,6 @@ Features: * There's currently no way to cancel fsck (used to be possible via C-c or c on the console) -* keep an eye on https://bugzilla.gnome.org/show_bug.cgi?id=670100 - * journal: sanely deal with entries which are larger than the individual file size, but where the componets would fit * add command to systemctl to plot dependency graph as tree (see rhbz 795365) @@ -152,9 +152,6 @@ Features: * default unix qlen is too small (10). bump sysctl? add sockopt? -* support units generated by a generator and placed in /run/systemd/system/; the directory is - currently ignored because it is empty before the generatores are executed - * Possibly, detect whether SysV init scripts can do reloading by looking for "echo Usage:" lines * figure out whether we should leave dbus around during shutdown @@ -213,8 +210,6 @@ Features: * when an instanced service exits, remove its parent cgroup too if possible. -* as Tom Gundersen pointed out there's a always a dep loop if people use crypto file systems with random keys - * automatically escape unit names passed on the service (i.e. think "systemctl start serial-getty.service@serial/by-path/jshdfjsdfhkjh" being automatically escaped as necessary. * if we can not get user quota for tmpfs, mount a separate tmpfs instance @@ -361,10 +356,6 @@ External: - allow disabling of UID passing for AUTH EXTERNAL - always pass cred data along each message -* systemd --user - PR_SET_CHILD_REAPER patch: https://lkml.org/lkml/2011/7/28/426 - (patch in linux-next, on the way to the next kernel) - * fix alsa mixer restore to not print error when no config is stored * gnome-shell python script/glxinfo/is-accelerated must die @@ -379,9 +370,6 @@ External: we are in 11-minutes-mode. When we trust the system time to NTP we also want the RTC to sync up. -* patch kernel for cpu feature modalias for autoloading aes/kvm/... - (patches in linux-next, on the way to the next kernel) - * kernel: add device_type = "fb", "fbcon" to class "graphics" Regularly: diff --git a/man/systemd.conf.xml b/man/systemd.conf.xml index 7dfaa18c18..2659f9ab7b 100644 --- a/man/systemd.conf.xml +++ b/man/systemd.conf.xml @@ -183,6 +183,38 @@ available. + + CapabilityBoundingSet= + + Controls which + capabilities to include in the + capability bounding set for PID 1 and + its children. See + capabilities7 + for details. Takes a whitespace + separated list of capability names as + read by + cap_from_name3. + Capabilities listed will be included + in the bounding set, all others are + removed. If the list of capabilities + is prefixed with ~ all but the listed + capabilities will be included, the + effect of the assignment + inverted. Note that this option also + effects the respective capabilities in + the effective, permitted and + inheritable capability sets. The + capability bounding set may also be + individually configured for units + using the + CapabilityBoundingSet= + directive for units, but note that + capabilities dropped for PID 1 cannot + be regained in individual units, they + are lost for good. + + DefaultLimitCPU= DefaultLimitFSIZE= @@ -200,14 +232,21 @@ DefaultLimitNICE= DefaultLimitRTPRIO= DefaultLimitRTTIME= + These settings control - various default resource limits for units. See + various default resource limits for + units. See setrlimit2 for details. Use the string infinity to configure no limit on a specific - resource. They can be overriden in units files - using corresponding LimitXXXX parameter. + resource. These settings may be + overriden in individual units + using the corresponding LimitXXX= + directives. Note that these resource + limits are only defaults for units, + they are not applied to PID 1 + itself. diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 219733be37..0dc2ed48b5 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -678,17 +678,17 @@ is prefixed with ~ all but the listed capabilities will be included, the effect of the assignment - inverted. Note that this option does - not actually set or unset any - capabilities in the effective, - permitted or inherited capability - sets. That's what - Capabilities= is - for. If this option is not used the + inverted. Note that this option also + effects the respective capabilities in + the effective, permitted and + inheritable capability sets, on top of + what Capabilities= + does. If this option is not used the capability bounding set is not modified on process execution, hence no limits on the capabilities of the - process are enforced. + process are + enforced. diff --git a/src/core/execute.c b/src/core/execute.c index bb841b7fcf..9c2006ebc7 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -870,68 +870,6 @@ fail: } #endif -static int do_capability_bounding_set_drop(uint64_t drop) { - unsigned long i; - cap_t old_cap = NULL, new_cap = NULL; - cap_flag_value_t fv; - int r; - - /* If we are run as PID 1 we will lack CAP_SETPCAP by default - * in the effective set (yes, the kernel drops that when - * executing init!), so get it back temporarily so that we can - * call PR_CAPBSET_DROP. */ - - old_cap = cap_get_proc(); - if (!old_cap) - return -errno; - - if (cap_get_flag(old_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) { - r = -errno; - goto finish; - } - - if (fv != CAP_SET) { - static const cap_value_t v = CAP_SETPCAP; - - new_cap = cap_dup(old_cap); - if (!new_cap) { - r = -errno; - goto finish; - } - - if (cap_set_flag(new_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) { - r = -errno; - goto finish; - } - - if (cap_set_proc(new_cap) < 0) { - r = -errno; - goto finish; - } - } - - for (i = 0; i <= cap_last_cap(); i++) - if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { - if (prctl(PR_CAPBSET_DROP, i) < 0) { - r = -errno; - goto finish; - } - } - - r = 0; - -finish: - if (new_cap) - cap_free(new_cap); - - if (old_cap) { - cap_set_proc(old_cap); - cap_free(old_cap); - } - - return r; -} - static void rename_process_from_path(const char *path) { char process_name[11]; const char *p; @@ -1398,7 +1336,7 @@ int exec_spawn(ExecCommand *command, } if (context->capability_bounding_set_drop) { - err = do_capability_bounding_set_drop(context->capability_bounding_set_drop); + err = capability_bounding_set_drop(context->capability_bounding_set_drop, false); if (err < 0) { r = EXIT_CAPABILITIES; goto fail_child; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index ea502bd288..6f2a0d63ef 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -46,7 +46,7 @@ $1.SyslogLevel, config_parse_level, 0, $1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix) $1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context) $1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context) -$1.CapabilityBoundingSet, config_parse_exec_bounding_set, 0, offsetof($1, exec_context) +$1.CapabilityBoundingSet, config_parse_bounding_set, 0, offsetof($1, exec_context.capability_bounding_set_drop) $1.TimerSlackNSec, config_parse_exec_timer_slack_nsec, 0, offsetof($1, exec_context) $1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) $1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index d2267722dd..ff6e13e599 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -931,7 +931,7 @@ int config_parse_exec_secure_bits( return 0; } -int config_parse_exec_bounding_set( +int config_parse_bounding_set( const char *filename, unsigned line, const char *section, @@ -941,7 +941,7 @@ int config_parse_exec_bounding_set( void *data, void *userdata) { - ExecContext *c = data; + uint64_t *capability_bounding_set_drop = data; char *w; size_t l; char *state; @@ -968,7 +968,8 @@ int config_parse_exec_bounding_set( int r; cap_value_t cap; - if (!(t = strndup(w, l))) + t = strndup(w, l); + if (!t) return -ENOMEM; r = cap_from_name(t, &cap); @@ -983,9 +984,9 @@ int config_parse_exec_bounding_set( } if (invert) - c->capability_bounding_set_drop |= sum; + *capability_bounding_set_drop |= sum; else - c->capability_bounding_set_drop |= ~sum; + *capability_bounding_set_drop |= ~sum; return 0; } @@ -2447,7 +2448,7 @@ void unit_dump_config_items(FILE *f) { { config_parse_level, "LEVEL" }, { config_parse_exec_capabilities, "CAPABILITIES" }, { config_parse_exec_secure_bits, "SECUREBITS" }, - { config_parse_exec_bounding_set, "BOUNDINGSET" }, + { config_parse_bounding_set, "BOUNDINGSET" }, { config_parse_exec_timer_slack_nsec, "TIMERSLACK" }, { config_parse_limit, "LIMIT" }, { config_parse_unit_cgroup, "CGROUP [...]" }, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 3b2ed096b5..6b382494aa 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -56,7 +56,7 @@ int config_parse_exec_cpu_sched_prio(const char *filename, unsigned line, const int config_parse_exec_cpu_affinity(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_capabilities(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_secure_bits(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_bounding_set(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_bounding_set(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_timer_slack_nsec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_cgroup(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/core/main.c b/src/core/main.c index 4d9a2d453e..9248c388a4 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -50,6 +50,7 @@ #include "watchdog.h" #include "path-util.h" #include "switch-root.h" +#include "capability.h" #include "mount-setup.h" #include "loopback-setup.h" @@ -88,6 +89,7 @@ static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT; static usec_t arg_runtime_watchdog = 0; static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE; static struct rlimit *arg_default_rlimit[RLIMIT_NLIMITS] = {}; +static uint64_t arg_capability_bounding_set_drop = 0; static FILE* serialization = NULL; @@ -678,6 +680,7 @@ static int parse_config_file(void) { { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, { "Manager", "RuntimeWatchdogSec", config_parse_usec, 0, &arg_runtime_watchdog }, { "Manager", "ShutdownWatchdogSec", config_parse_usec, 0, &arg_shutdown_watchdog }, + { "Manager", "CapabilityBoundingSet", config_parse_bounding_set, 0, &arg_capability_bounding_set_drop }, { "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU]}, { "Manager", "DefaultLimitFSIZE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE]}, { "Manager", "DefaultLimitDATA", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_DATA]}, @@ -1484,6 +1487,14 @@ int main(int argc, char *argv[]) { if (arg_running_as == MANAGER_SYSTEM && arg_runtime_watchdog > 0) watchdog_set_timeout(&arg_runtime_watchdog); + if (arg_capability_bounding_set_drop) { + r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true); + if (r < 0) { + log_error("Failed to drop capability bounding set: %s", strerror(-r)); + goto finish; + } + } + r = manager_new(arg_running_as, &m); if (r < 0) { log_error("Failed to allocate manager object: %s", strerror(-r)); diff --git a/src/core/system.conf b/src/core/system.conf index 2b14d3e31e..7b9171b803 100644 --- a/src/core/system.conf +++ b/src/core/system.conf @@ -24,3 +24,20 @@ #JoinControllers=cpu,cpuacct #RuntimeWatchdogSec=0 #ShutdownWatchdogSec=10min +#CapabilityBoundingSet= +#DefaultLimitCPU= +#DefaultLimitFSIZE= +#DefaultLimitDATA= +#DefaultLimitSTACK= +#DefaultLimitCORE= +#DefaultLimitRSS= +#DefaultLimitNOFILE= +#DefaultLimitAS= +#DefaultLimitNPROC= +#DefaultLimitMEMLOCK= +#DefaultLimitLOCKS= +#DefaultLimitSIGPENDING= +#DefaultLimitMSGQUEUE= +#DefaultLimitNICE= +#DefaultLimitRTPRIO= +#DefaultLimitRTTIME= diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 31e8b015df..8a5eb34c7f 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -544,49 +544,31 @@ static int setup_hostname(void) { } static int drop_capabilities(void) { - static const unsigned long retain[] = { - CAP_CHOWN, - CAP_DAC_OVERRIDE, - CAP_DAC_READ_SEARCH, - CAP_FOWNER, - CAP_FSETID, - CAP_IPC_OWNER, - CAP_KILL, - CAP_LEASE, - CAP_LINUX_IMMUTABLE, - CAP_NET_BIND_SERVICE, - CAP_NET_BROADCAST, - CAP_NET_RAW, - CAP_SETGID, - CAP_SETFCAP, - CAP_SETPCAP, - CAP_SETUID, - CAP_SYS_ADMIN, - CAP_SYS_CHROOT, - CAP_SYS_NICE, - CAP_SYS_PTRACE, - CAP_SYS_TTY_CONFIG - }; - - unsigned long l; - - for (l = 0; l <= cap_last_cap(); l++) { - unsigned i; - - for (i = 0; i < ELEMENTSOF(retain); i++) - if (retain[i] == l) - break; - - if (i < ELEMENTSOF(retain)) - continue; - if (prctl(PR_CAPBSET_DROP, l) < 0) { - log_error("PR_CAPBSET_DROP failed: %m"); - return -errno; - } - } - - return 0; + static const uint64_t retain = + (1ULL << CAP_CHOWN) | + (1ULL << CAP_DAC_OVERRIDE) | + (1ULL << CAP_DAC_READ_SEARCH) | + (1ULL << CAP_FOWNER) | + (1ULL << CAP_FSETID) | + (1ULL << CAP_IPC_OWNER) | + (1ULL << CAP_KILL) | + (1ULL << CAP_LEASE) | + (1ULL << CAP_LINUX_IMMUTABLE) | + (1ULL << CAP_NET_BIND_SERVICE) | + (1ULL << CAP_NET_BROADCAST) | + (1ULL << CAP_NET_RAW) | + (1ULL << CAP_SETGID) | + (1ULL << CAP_SETFCAP) | + (1ULL << CAP_SETPCAP) | + (1ULL << CAP_SETUID) | + (1ULL << CAP_SYS_ADMIN) | + (1ULL << CAP_SYS_CHROOT) | + (1ULL << CAP_SYS_NICE) | + (1ULL << CAP_SYS_PTRACE) | + (1ULL << CAP_SYS_TTY_CONFIG); + + return capability_bounding_set_drop(~retain, false); } static int is_os_tree(const char *path) { @@ -1041,8 +1023,10 @@ int main(int argc, char *argv[]) { loopback_setup(); - if (drop_capabilities() < 0) + if (drop_capabilities() < 0) { + log_error("drop_capabilities() failed: %m"); goto child_fail; + } if (arg_user) { diff --git a/src/shared/capability.c b/src/shared/capability.c index b2cd9ed75e..08b7a209da 100644 --- a/src/shared/capability.c +++ b/src/shared/capability.c @@ -40,7 +40,8 @@ int have_effective_cap(int value) { cap_flag_value_t fv; int r; - if (!(cap = cap_get_proc())) + cap = cap_get_proc(); + if (!cap) return -errno; if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0) @@ -84,3 +85,89 @@ unsigned long cap_last_cap(void) { return p; } + +int capability_bounding_set_drop(uint64_t drop, bool right_now) { + unsigned long i; + cap_t after_cap = NULL, temp_cap = NULL; + cap_flag_value_t fv; + int r; + + /* If we are run as PID 1 we will lack CAP_SETPCAP by default + * in the effective set (yes, the kernel drops that when + * executing init!), so get it back temporarily so that we can + * call PR_CAPBSET_DROP. */ + + after_cap = cap_get_proc(); + if (!after_cap) + return -errno; + + if (cap_get_flag(after_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) { + cap_free(after_cap); + return -errno; + } + + if (fv != CAP_SET) { + static const cap_value_t v = CAP_SETPCAP; + + temp_cap = cap_dup(after_cap); + if (!temp_cap) { + r = -errno; + goto finish; + } + + if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) { + r = -errno; + goto finish; + } + + if (cap_set_proc(temp_cap) < 0) { + r = -errno; + goto finish; + } + } + + for (i = 0; i <= cap_last_cap(); i++) { + + if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { + cap_value_t v; + + /* Drop it from the bounding set */ + if (prctl(PR_CAPBSET_DROP, i) < 0) { + r = -errno; + goto finish; + } + v = i; + + /* Also drop it from the inheritable set, so + * that anything we exec() loses the + * capability for good. */ + if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) { + r = -errno; + goto finish; + } + + /* If we shall apply this right now drop it + * also from our own capability sets. */ + if (right_now) { + if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 || + cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) { + r = -errno; + goto finish; + } + } + } + } + + r = 0; + +finish: + if (temp_cap) + cap_free(temp_cap); + + if (after_cap) { + cap_set_proc(after_cap); + cap_free(after_cap); + } + + return r; +} diff --git a/src/shared/capability.h b/src/shared/capability.h index 9f9c49cf5b..0cc5dd08aa 100644 --- a/src/shared/capability.h +++ b/src/shared/capability.h @@ -22,6 +22,11 @@ along with systemd; If not, see . ***/ +#include +#include + unsigned long cap_last_cap(void); int have_effective_cap(int value); +int capability_bounding_set_drop(uint64_t caps, bool right_now); + #endif -- cgit v1.2.3-54-g00ecf From d88a251b125f6e9178b9ca9ea47ab7da3234cb58 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 31 May 2012 04:27:03 +0200 Subject: util: introduce a proper nsec_t and make use of it where appropriate --- man/systemd.exec.xml | 11 +++--- src/core/dbus-execute.c | 2 +- src/core/execute.c | 5 +-- src/core/execute.h | 3 +- src/core/load-fragment-gperf.gperf.m4 | 2 +- src/core/load-fragment.c | 30 +--------------- src/core/load-fragment.h | 1 - src/shared/conf-parser.c | 25 +++++++++++++ src/shared/conf-parser.h | 1 + src/shared/util.c | 67 ++++++++++++++++++++++++++++++++++- src/shared/util.h | 8 +++++ 11 files changed, 113 insertions(+), 42 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 0dc2ed48b5..01b638f5ac 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -581,16 +581,17 @@ TimerSlackNSec= Sets the timer slack in nanoseconds for the executed - processes. The timer slack controls the - accuracy of wake-ups triggered by + processes. The timer slack controls + the accuracy of wake-ups triggered by timers. See prctl2 for more information. Note that in contrast to most other time span definitions this parameter takes an - integer value in nano-seconds and does - not understand any other - units. + integer value in nano-seconds if no + unit is specified. The usual time + units are understood + too. diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index ef55ef12b9..f1a9da0c57 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -216,7 +216,7 @@ int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property assert(property); assert(c); - if (c->timer_slack_nsec_set) + if (c->timer_slack_nsec != (nsec_t) -1) u = (uint64_t) c->timer_slack_nsec; else u = (uint64_t) prctl(PR_GET_TIMERSLACK); diff --git a/src/core/execute.c b/src/core/execute.c index 9c2006ebc7..3ef4eafa7f 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1183,7 +1183,7 @@ int exec_spawn(ExecCommand *command, goto fail_child; } - if (context->timer_slack_nsec_set) + if (context->timer_slack_nsec != (nsec_t) -1) if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) { err = -errno; r = EXIT_TIMERSLACK; @@ -1494,6 +1494,7 @@ void exec_context_init(ExecContext *c) { c->send_sigkill = true; c->control_group_persistent = -1; c->ignore_sigpipe = true; + c->timer_slack_nsec = (nsec_t) -1; } void exec_context_done(ExecContext *c) { @@ -1739,7 +1740,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { fputs("\n", f); } - if (c->timer_slack_nsec_set) + if (c->timer_slack_nsec != (nsec_t) -1) fprintf(f, "%sTimerSlackNSec: %lu\n", prefix, c->timer_slack_nsec); fprintf(f, diff --git a/src/core/execute.h b/src/core/execute.h index 03c63d465a..6c68169a84 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -118,7 +118,7 @@ struct ExecContext { ExecOutput std_output; ExecOutput std_error; - unsigned long timer_slack_nsec; + nsec_t timer_slack_nsec; char *tcpwrap_name; @@ -178,7 +178,6 @@ struct ExecContext { bool nice_set:1; bool ioprio_set:1; bool cpu_sched_set:1; - bool timer_slack_nsec_set:1; }; int exec_spawn(ExecCommand *command, diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 6f2a0d63ef..0e21e8165f 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -47,7 +47,7 @@ $1.SyslogLevelPrefix, config_parse_bool, 0, $1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context) $1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context) $1.CapabilityBoundingSet, config_parse_bounding_set, 0, offsetof($1, exec_context.capability_bounding_set_drop) -$1.TimerSlackNSec, config_parse_exec_timer_slack_nsec, 0, offsetof($1, exec_context) +$1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec) $1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) $1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) $1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index ff6e13e599..2db1290db8 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -991,34 +991,6 @@ int config_parse_bounding_set( return 0; } -int config_parse_exec_timer_slack_nsec( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = data; - unsigned long u; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (safe_atolu(rvalue, &u) < 0) { - log_error("[%s:%u] Failed to parse time slack value, ignoring: %s", filename, line, rvalue); - return 0; - } - - c->timer_slack_nsec = u; - - return 0; -} - int config_parse_limit( const char *filename, unsigned line, @@ -2449,7 +2421,6 @@ void unit_dump_config_items(FILE *f) { { config_parse_exec_capabilities, "CAPABILITIES" }, { config_parse_exec_secure_bits, "SECUREBITS" }, { config_parse_bounding_set, "BOUNDINGSET" }, - { config_parse_exec_timer_slack_nsec, "TIMERSLACK" }, { config_parse_limit, "LIMIT" }, { config_parse_unit_cgroup, "CGROUP [...]" }, { config_parse_unit_deps, "UNIT [...]" }, @@ -2468,6 +2439,7 @@ void unit_dump_config_items(FILE *f) { { config_parse_socket_bind, "SOCKETBIND" }, { config_parse_socket_bindtodevice, "NETWORKINTERFACE" }, { config_parse_usec, "SECONDS" }, + { config_parse_nsec, "NANOSECONDS" }, { config_parse_path_strv, "PATH [...]" }, { config_parse_unit_requires_mounts_for, "PATH [...]" }, { config_parse_exec_mount_flags, "MOUNTFLAG [...]" }, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 6b382494aa..b412d3b2ea 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -57,7 +57,6 @@ int config_parse_exec_cpu_affinity(const char *filename, unsigned line, const ch int config_parse_exec_capabilities(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_secure_bits(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_bounding_set(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_timer_slack_nsec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_cgroup(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_sysv_priority(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 65035e4c6a..724bcf00c9 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -817,6 +817,31 @@ int config_parse_usec( return 0; } +int config_parse_nsec( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + nsec_t *nsec = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (parse_nsec(rvalue, nsec) < 0) { + log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue); + return 0; + } + + return 0; +} + int config_parse_mode( const char *filename, unsigned line, diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index d37029f083..9e5f81d56b 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -102,6 +102,7 @@ int config_parse_path(const char *filename, unsigned line, const char *section, int config_parse_strv(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_path_strv(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_usec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_nsec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); #define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \ diff --git a/src/shared/util.c b/src/shared/util.c index 70b159f8c3..9db2a6b2a2 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -2707,7 +2707,7 @@ int parse_usec(const char *t, usec_t *usec) { { "m", USEC_PER_MINUTE }, { "usec", 1ULL }, { "us", 1ULL }, - { "", USEC_PER_SEC }, + { "", USEC_PER_SEC }, /* default is sec */ }; const char *p; @@ -2753,6 +2753,71 @@ int parse_usec(const char *t, usec_t *usec) { return 0; } +int parse_nsec(const char *t, nsec_t *nsec) { + static const struct { + const char *suffix; + nsec_t nsec; + } table[] = { + { "sec", NSEC_PER_SEC }, + { "s", NSEC_PER_SEC }, + { "min", NSEC_PER_MINUTE }, + { "hr", NSEC_PER_HOUR }, + { "h", NSEC_PER_HOUR }, + { "d", NSEC_PER_DAY }, + { "w", NSEC_PER_WEEK }, + { "msec", NSEC_PER_MSEC }, + { "ms", NSEC_PER_MSEC }, + { "m", NSEC_PER_MINUTE }, + { "usec", NSEC_PER_USEC }, + { "us", NSEC_PER_USEC }, + { "nsec", 1ULL }, + { "ns", 1ULL }, + { "", 1ULL }, /* default is nsec */ + }; + + const char *p; + nsec_t r = 0; + + assert(t); + assert(nsec); + + p = t; + do { + long long l; + char *e; + unsigned i; + + errno = 0; + l = strtoll(p, &e, 10); + + if (errno != 0) + return -errno; + + if (l < 0) + return -ERANGE; + + if (e == p) + return -EINVAL; + + e += strspn(e, WHITESPACE); + + for (i = 0; i < ELEMENTSOF(table); i++) + if (startswith(e, table[i].suffix)) { + r += (nsec_t) l * table[i].nsec; + p = e + strlen(table[i].suffix); + break; + } + + if (i >= ELEMENTSOF(table)) + return -EINVAL; + + } while (*p != 0); + + *nsec = r; + + return 0; +} + int parse_bytes(const char *t, off_t *bytes) { static const struct { const char *suffix; diff --git a/src/shared/util.h b/src/shared/util.h index 35ff2e3547..18b2930e18 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -39,6 +39,7 @@ #include "macro.h" typedef uint64_t usec_t; +typedef unsigned long nsec_t; typedef struct dual_timestamp { usec_t realtime; @@ -53,11 +54,17 @@ typedef struct dual_timestamp { #define NSEC_PER_USEC 1000ULL #define USEC_PER_MINUTE (60ULL*USEC_PER_SEC) +#define NSEC_PER_MINUTE (60ULL*NSEC_PER_SEC) #define USEC_PER_HOUR (60ULL*USEC_PER_MINUTE) +#define NSEC_PER_HOUR (60ULL*NSEC_PER_MINUTE) #define USEC_PER_DAY (24ULL*USEC_PER_HOUR) +#define NSEC_PER_DAY (24ULL*NSEC_PER_HOUR) #define USEC_PER_WEEK (7ULL*USEC_PER_DAY) +#define NSEC_PER_WEEK (7ULL*NSEC_PER_DAY) #define USEC_PER_MONTH (2629800ULL*USEC_PER_SEC) +#define NSEC_PER_MONTH (2629800ULL*NSEC_PER_SEC) #define USEC_PER_YEAR (31557600ULL*USEC_PER_SEC) +#define NSEC_PER_YEAR (31557600ULL*NSEC_PER_SEC) /* What is interpreted as whitespace? */ #define WHITESPACE " \t\n\r" @@ -139,6 +146,7 @@ void close_many(const int fds[], unsigned n_fd); int parse_boolean(const char *v); int parse_usec(const char *t, usec_t *usec); +int parse_nsec(const char *t, nsec_t *nsec); int parse_bytes(const char *t, off_t *bytes); int parse_pid(const char *s, pid_t* ret_pid); int parse_uid(const char *s, uid_t* ret_uid); -- cgit v1.2.3-54-g00ecf From 98709151f3e782eb508ba15e2a12c0b46003f061 Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Thu, 14 Jun 2012 17:07:07 +0200 Subject: service: timeout for oneshot services Add possibility to specify timeout for oneshot services. [ https://bugzilla.redhat.com/show_bug.cgi?id=761656 Added minor fixups. -- michich ] --- man/systemd.service.xml | 4 +++- src/core/load-fragment-gperf.gperf.m4 | 2 +- src/core/load-fragment.c | 26 ++++++++++++++++++++++++++ src/core/load-fragment.h | 1 + src/core/service.c | 8 ++++++-- src/core/service.h | 1 + 6 files changed, 38 insertions(+), 4 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 12d0b8a12b..233807d2b3 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -470,7 +470,9 @@ time span value such as "5min 20s". Pass 0 to disable the timeout logic. Defaults to - 90s. + 90s, except when Type=oneshot is + used in which case the timeout + is disabled by default. diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 0e21e8165f..d51c7ac5e2 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -138,7 +138,7 @@ Service.ExecReload, config_parse_exec, SERVICE_EXE Service.ExecStop, config_parse_exec, SERVICE_EXEC_STOP, offsetof(Service, exec_command) Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command) Service.RestartSec, config_parse_usec, 0, offsetof(Service, restart_usec) -Service.TimeoutSec, config_parse_usec, 0, offsetof(Service, timeout_usec) +Service.TimeoutSec, config_parse_service_timeout, 0, offsetof(Service, timeout_usec) Service.WatchdogSec, config_parse_usec, 0, offsetof(Service, watchdog_usec) Service.StartLimitInterval, config_parse_usec, 0, offsetof(Service, start_limit.interval) Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 5494d7bce4..22da6c1197 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1398,6 +1398,32 @@ int config_parse_service_sockets( return 0; } +int config_parse_service_timeout( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Service *s = userdata; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(s); + + r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata); + + if (!r) + s->timeout_defined = true; + + return r; +} + int config_parse_unit_env_file( const char *filename, unsigned line, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index aa48ebdd3c..9a3465a166 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -42,6 +42,7 @@ int config_parse_socket_bind(const char *filename, unsigned line, const char *se int config_parse_exec_nice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_oom_score_adjust(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_service_timeout(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_service_type(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_service_restart(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_socket_bindtodevice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/core/service.c b/src/core/service.c index 936fee2636..8941271679 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1249,6 +1249,10 @@ static int service_load(Unit *u) { if (s->type == _SERVICE_TYPE_INVALID) s->type = s->bus_name ? SERVICE_DBUS : SERVICE_SIMPLE; + /* Oneshot services have disabled timeout by default */ + if (s->type == SERVICE_ONESHOT && !s->timeout_defined) + s->timeout_usec = 0; + service_fix_output(s); if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0) @@ -2157,7 +2161,7 @@ static void service_enter_start(Service *s) { r = service_spawn(s, c, - s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY, + s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY || s->type == SERVICE_ONESHOT, true, true, true, @@ -2372,7 +2376,7 @@ static void service_run_next_main(Service *s) { r = service_spawn(s, s->main_command, - false, + true, true, true, true, diff --git a/src/core/service.h b/src/core/service.h index f4ccc2b5a0..4a7287d827 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -164,6 +164,7 @@ struct Service { bool bus_name_good:1; bool forbid_restart:1; bool got_socket_fd:1; + bool timeout_defined:1; #ifdef HAVE_SYSV_COMPAT bool is_sysv:1; bool sysv_has_lsb:1; -- cgit v1.2.3-54-g00ecf From 8ff290af3b7db00eef76bdec61fee4aca7d84d0b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Jun 2012 16:24:57 +0200 Subject: unit: drop the Names= option Names= is a source of errors, simply because alias names specified like this only become relevant after a unit has been loaded but cannot be used to load a unit. Let's get rid of the confusion and drop this field. To establish alias names peope should use symlinks, which have the the benefit of being useful as key to load a unit, even though they are not taken into account if unit names are listed but they haven't been explicitly referenced before. --- TODO | 2 -- man/systemd.unit.xml | 54 +---------------------------------- src/core/load-fragment-gperf.gperf.m4 | 1 - src/core/load-fragment.c | 44 ---------------------------- src/core/load-fragment.h | 1 - 5 files changed, 1 insertion(+), 101 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/TODO b/TODO index 7fb3747db2..8778707169 100644 --- a/TODO +++ b/TODO @@ -399,5 +399,3 @@ Regularly: Scheduled for removal (or fixing): * xxxOverridable dependencies - -* Names= unit option diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 123965bd44..93fb37b72b 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -869,35 +869,6 @@ symlinks. - - Names= - - Additional names for - this unit. The names listed here must - have the same suffix (i.e. type) as - the unit file name. This option may be - specified more than once, in which - case all listed names are used. Note - that this option is different from the - Alias= option from - the [Install] section mentioned - below. See below for details. Note - that in almost all cases this option - is not what you want. A symlink alias - in the file system is generally - preferable since it can be used as - lookup key. If a unit with a symlinked - alias name is not loaded and needs to - be it is easily found via the - symlink. However, if a unit with an - alias name configured with this - setting is not loaded it will not be - discovered. This settings' only use is - in conjunction with service - instances. - - - SourcePath= A path to a @@ -936,30 +907,7 @@ time, systemctl enable will create symlinks from these names - to the unit file name. Note that this - is different from the - Names= option from - the [Unit] section mentioned above: - The names from - Names= apply - unconditionally if the unit is - loaded. The names from - Alias= apply only - if the unit has actually been - installed with the - systemctl enable - command. Also, if systemd searches for a - unit, it will discover symlinked alias - names as configured with - Alias=, but not - names configured with - Names= only. It is - a common pattern to list a name in - both options. In this case, a unit - will be active under all names if - installed, but also if not installed - but requested explicitly under its - main name. + to the unit file name. diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index d51c7ac5e2..f5e9b70672 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -90,7 +90,6 @@ $1.UtmpIdentifier, config_parse_unit_string_printf, 0, $1.ControlGroupModify, config_parse_bool, 0, offsetof($1, exec_context.control_group_modify) $1.ControlGroupPersistent, config_parse_tristate, 0, offsetof($1, exec_context.control_group_persistent)' )m4_dnl -Unit.Names, config_parse_unit_names, 0, 0 Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description) Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation) Unit.SourcePath, config_parse_path, 0, offsetof(Unit, source_path) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 22da6c1197..1ca0dece67 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -105,49 +105,6 @@ int config_parse_unit_deps( return 0; } -int config_parse_unit_names( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Unit *u = userdata; - char *w; - size_t l; - char *state; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - char *t, *k; - int r; - - t = strndup(w, l); - if (!t) - return -ENOMEM; - - k = unit_name_printf(u, t); - free(t); - if (!k) - return -ENOMEM; - - r = unit_merge_by_name(u, k); - if (r < 0) - log_error("Failed to add name %s, ignoring: %s", k, strerror(-r)); - - free(k); - } - - return 0; -} - int config_parse_unit_string_printf( const char *filename, unsigned line, @@ -2395,7 +2352,6 @@ void unit_dump_config_items(FILE *f) { { config_parse_limit, "LIMIT" }, { config_parse_unit_cgroup, "CGROUP [...]" }, { config_parse_unit_deps, "UNIT [...]" }, - { config_parse_unit_names, "UNIT [...]" }, { config_parse_exec, "PATH [ARGUMENT [...]]" }, { config_parse_service_type, "SERVICETYPE" }, { config_parse_service_restart, "SERVICERESTART" }, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 9a3465a166..501ea4ad47 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -32,7 +32,6 @@ void unit_dump_config_items(FILE *f); int config_parse_warn_compat(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_deps(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_names(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_string_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_strv_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_path_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -- cgit v1.2.3-54-g00ecf From 7f2cddae09fd2579ae24434df577bb5e5a157d86 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 13 Jul 2012 23:34:40 +0200 Subject: unit: rename BindTo= to BindsTo= all other dependencies are in 3rd person. Change BindTo= accordingly to BindsTo=. Of course, the dependency is widely used, hence we parse the old name too for compatibility. --- TODO | 4 ---- man/systemd.unit.xml | 6 +++--- src/core/dbus-unit.c | 6 +++--- src/core/dbus-unit.h | 6 +++--- src/core/load-fragment-gperf.gperf.m4 | 9 ++++++--- src/core/service.c | 2 +- src/core/target.c | 2 +- src/core/transaction.c | 4 ++-- src/core/unit.c | 20 ++++++++++---------- src/core/unit.h | 8 ++++---- src/cryptsetup/cryptsetup-generator.c | 2 +- units/hibernate.target | 2 +- units/serial-getty@.service.m4 | 2 +- units/suspend.target | 2 +- units/systemd-fsck@.service.in | 2 +- 15 files changed, 38 insertions(+), 39 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/TODO b/TODO index 3bf6ef8dff..61c0b57126 100644 --- a/TODO +++ b/TODO @@ -40,12 +40,8 @@ Features: * seccomp filters for services -* replace BindTo= by BindsTo=, but keep old name for compat - * switch-root: sockets need relabelling -* switch-root: handle journald restart - * segfault in journalctl during /var migration * systemd-analyze post-boot is broken for initrd diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 93fb37b72b..3fd76f3020 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -410,7 +410,7 @@ - BindTo= + BindsTo= Configures requirement dependencies, very similar in style to @@ -527,8 +527,8 @@ - PropagateReloadTo= - PropagateReloadFrom= + PropagatesReloadTo= + ReloadPropagatedFrom= Lists one or more units where reload requests on the diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index f85f3f898a..21145873ea 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -793,7 +793,7 @@ const BusProperty bus_unit_properties[] = { { "Requisite", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUISITE]), true }, { "RequisiteOverridable", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), true }, { "Wants", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_WANTS]), true }, - { "BindTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_BIND_TO]), true }, + { "BindsTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_BINDS_TO]), true }, { "RequiredBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), true }, { "RequiredByOverridable",bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), true }, { "WantedBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_WANTED_BY]), true }, @@ -805,8 +805,8 @@ const BusProperty bus_unit_properties[] = { { "OnFailure", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_ON_FAILURE]), true }, { "Triggers", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_TRIGGERS]), true }, { "TriggeredBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), true }, - { "PropagateReloadTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PROPAGATE_RELOAD_TO]), true }, - { "PropagateReloadFrom", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PROPAGATE_RELOAD_FROM]), true }, + { "PropagatesReloadTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), true }, + { "ReloadPropagatedFrom", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), true }, { "RequiresMountsFor", bus_property_append_strv, "as", offsetof(Unit, requires_mounts_for), true }, { "Documentation", bus_property_append_strv, "as", offsetof(Unit, documentation), true }, { "Description", bus_unit_append_description, "s", 0 }, diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index ae94ca2c2b..d5902ee22a 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -71,7 +71,7 @@ " \n" \ " \n" \ " \n" \ - " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -83,8 +83,8 @@ " \n" \ " \n" \ " \n" \ - " \n" \ - " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index f5e9b70672..192c2b2780 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -98,13 +98,16 @@ Unit.RequiresOverridable, config_parse_unit_deps, UNIT_REQUIR Unit.Requisite, config_parse_unit_deps, UNIT_REQUISITE, 0 Unit.RequisiteOverridable, config_parse_unit_deps, UNIT_REQUISITE_OVERRIDABLE, 0 Unit.Wants, config_parse_unit_deps, UNIT_WANTS, 0 -Unit.BindTo, config_parse_unit_deps, UNIT_BIND_TO, 0 +Unit.BindsTo, config_parse_unit_deps, UNIT_BINDS_TO, 0 +Unit.BindTo, config_parse_unit_deps, UNIT_BINDS_TO, 0 Unit.Conflicts, config_parse_unit_deps, UNIT_CONFLICTS, 0 Unit.Before, config_parse_unit_deps, UNIT_BEFORE, 0 Unit.After, config_parse_unit_deps, UNIT_AFTER, 0 Unit.OnFailure, config_parse_unit_deps, UNIT_ON_FAILURE, 0 -Unit.PropagateReloadTo, config_parse_unit_deps, UNIT_PROPAGATE_RELOAD_TO, 0 -Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_PROPAGATE_RELOAD_FROM, 0 +Unit.PropagatesReloadTo, config_parse_unit_deps, UNIT_PROPAGATES_RELOAD_TO, 0 +Unit.PropagateReloadTo, config_parse_unit_deps, UNIT_PROPAGATES_RELOAD_TO, 0 +Unit.ReloadPropagatedFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0 +Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0 Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, offsetof(Unit, requires_mounts_for) Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded) Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start) diff --git a/src/core/service.c b/src/core/service.c index 2be6ee5d99..0a6658809e 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -2464,7 +2464,7 @@ static int service_start(Unit *u) { return 0; /* A service that will be restarted must be stopped first to - * trigger BindTo and/or OnFailure dependencies. If a user + * trigger BindsTo and/or OnFailure dependencies. If a user * does not want to wait for the holdoff time to elapse, the * service should be manually restarted, not started. */ if (s->state == SERVICE_AUTO_RESTART) { diff --git a/src/core/target.c b/src/core/target.c index 092b2065f2..55f9fc6fc4 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -59,7 +59,7 @@ static int target_add_default_dependencies(Target *t) { UNIT_REQUISITE, UNIT_REQUISITE_OVERRIDABLE, UNIT_WANTS, - UNIT_BIND_TO + UNIT_BINDS_TO }; Iterator i; diff --git a/src/core/transaction.c b/src/core/transaction.c index 44fdc06580..a1cf706934 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -893,7 +893,7 @@ int transaction_add_job_and_dependencies( } } - SET_FOREACH(dep, ret->unit->dependencies[UNIT_BIND_TO], i) { + SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) { r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e); if (r < 0) { if (r != -EBADR) @@ -998,7 +998,7 @@ int transaction_add_job_and_dependencies( if (type == JOB_RELOAD) { - SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATE_RELOAD_TO], i) { + SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) { r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e); if (r < 0) { log_warning("Cannot add dependency reload job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); diff --git a/src/core/unit.c b/src/core/unit.c index 516f4fad8b..6914ccdb99 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1144,7 +1144,7 @@ static void retroactively_start_dependencies(Unit *u) { !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); - SET_FOREACH(other, u->dependencies[UNIT_BIND_TO], i) + SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) if (!set_get(u->dependencies[UNIT_AFTER], other) && !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); @@ -1209,7 +1209,7 @@ static void check_unneeded_dependencies(Unit *u) { SET_FOREACH(other, u->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) unit_check_unneeded(other); - SET_FOREACH(other, u->dependencies[UNIT_BIND_TO], i) + SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) unit_check_unneeded(other); } @@ -1595,11 +1595,11 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen [UNIT_WANTS] = UNIT_WANTED_BY, [UNIT_REQUISITE] = UNIT_REQUIRED_BY, [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE, - [UNIT_BIND_TO] = UNIT_BOUND_BY, + [UNIT_BINDS_TO] = UNIT_BOUND_BY, [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID, [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID, [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID, - [UNIT_BOUND_BY] = UNIT_BIND_TO, + [UNIT_BOUND_BY] = UNIT_BINDS_TO, [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY, [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS, [UNIT_BEFORE] = UNIT_AFTER, @@ -1609,8 +1609,8 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen [UNIT_REFERENCED_BY] = UNIT_REFERENCES, [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY, [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS, - [UNIT_PROPAGATE_RELOAD_TO] = UNIT_PROPAGATE_RELOAD_FROM, - [UNIT_PROPAGATE_RELOAD_FROM] = UNIT_PROPAGATE_RELOAD_TO + [UNIT_PROPAGATES_RELOAD_TO] = UNIT_RELOAD_PROPAGATED_FROM, + [UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO }; int r, q = 0, v = 0, w = 0; @@ -2519,7 +2519,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) { if (r < 0) return r; - if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_BIND_TO, device, true)) < 0) + if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_BINDS_TO, device, true)) < 0) return r; if (wants) @@ -2765,7 +2765,7 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable", [UNIT_REQUIRED_BY] = "RequiredBy", [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable", - [UNIT_BIND_TO] = "BindTo", + [UNIT_BINDS_TO] = "BindsTo", [UNIT_WANTED_BY] = "WantedBy", [UNIT_CONFLICTS] = "Conflicts", [UNIT_CONFLICTED_BY] = "ConflictedBy", @@ -2777,8 +2777,8 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_ON_FAILURE] = "OnFailure", [UNIT_TRIGGERS] = "Triggers", [UNIT_TRIGGERED_BY] = "TriggeredBy", - [UNIT_PROPAGATE_RELOAD_TO] = "PropagateReloadTo", - [UNIT_PROPAGATE_RELOAD_FROM] = "PropagateReloadFrom" + [UNIT_PROPAGATES_RELOAD_TO] = "PropagatesReloadTo", + [UNIT_RELOAD_PROPAGATED_FROM] = "ReloadPropagatedFrom" }; DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency); diff --git a/src/core/unit.h b/src/core/unit.h index 0e1e72ebf0..9d75e02532 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -76,13 +76,13 @@ enum UnitDependency { UNIT_REQUISITE, UNIT_REQUISITE_OVERRIDABLE, UNIT_WANTS, - UNIT_BIND_TO, + UNIT_BINDS_TO, /* Inverse of the above */ UNIT_REQUIRED_BY, /* inverse of 'requires' and 'requisite' is 'required_by' */ UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' and 'requisite_overridable' is 'soft_required_by' */ UNIT_WANTED_BY, /* inverse of 'wants' */ - UNIT_BOUND_BY, /* inverse of 'bind_to' */ + UNIT_BOUND_BY, /* inverse of 'binds_to' */ /* Negative dependencies */ UNIT_CONFLICTS, /* inverse of 'conflicts' is 'conflicted_by' */ @@ -100,8 +100,8 @@ enum UnitDependency { UNIT_TRIGGERED_BY, /* Propagate reloads */ - UNIT_PROPAGATE_RELOAD_TO, - UNIT_PROPAGATE_RELOAD_FROM, + UNIT_PROPAGATES_RELOAD_TO, + UNIT_RELOAD_PROPAGATED_FROM, /* Reference information for GC logic */ UNIT_REFERENCES, /* Inverse of 'references' is 'referenced_by' */ diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index 7801de64b5..d0984242c8 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -124,7 +124,7 @@ static int create_disk( "SourcePath=/etc/crypttab\n" "Conflicts=umount.target\n" "DefaultDependencies=no\n" - "BindTo=%s dev-mapper-%%i.device\n" + "BindsTo=%s dev-mapper-%%i.device\n" "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n" "Before=umount.target\n", d, d); diff --git a/units/hibernate.target b/units/hibernate.target index c56460237d..143eb59230 100644 --- a/units/hibernate.target +++ b/units/hibernate.target @@ -9,5 +9,5 @@ Description=Hibernate Documentation=man:systemd.special(7) DefaultDependencies=no -BindTo=systemd-hibernate.service +BindsTo=systemd-hibernate.service After=systemd-hibernate.service diff --git a/units/serial-getty@.service.m4 b/units/serial-getty@.service.m4 index fa386ea0d4..d6a7669045 100644 --- a/units/serial-getty@.service.m4 +++ b/units/serial-getty@.service.m4 @@ -8,7 +8,7 @@ [Unit] Description=Serial Getty on %I Documentation=man:agetty(8) man:systemd-getty-generator(8) -BindTo=dev-%i.device +BindsTo=dev-%i.device After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service m4_ifdef(`TARGET_FEDORA', After=rc-local.service diff --git a/units/suspend.target b/units/suspend.target index 83f69f1b54..f50cb2264f 100644 --- a/units/suspend.target +++ b/units/suspend.target @@ -9,5 +9,5 @@ Description=Suspend Documentation=man:systemd.special(7) DefaultDependencies=no -BindTo=systemd-suspend.service +BindsTo=systemd-suspend.service After=systemd-suspend.service diff --git a/units/systemd-fsck@.service.in b/units/systemd-fsck@.service.in index 1cade4e602..b3c71eb250 100644 --- a/units/systemd-fsck@.service.in +++ b/units/systemd-fsck@.service.in @@ -9,7 +9,7 @@ Description=File System Check on %f Documentation=man:systemd-fsck@.service(8) DefaultDependencies=no -BindTo=%i.device +BindsTo=%i.device After=systemd-readahead-collect.service systemd-readahead-replay.service %i.device Before=shutdown.target -- cgit v1.2.3-54-g00ecf From 8351ceaea9480d9c2979aa2ff0f4982cfdfef58d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 Jul 2012 04:17:53 +0200 Subject: execute: support syscall filtering using seccomp filters --- Makefile.am | 26 +++++++++-- TODO | 9 ++-- man/systemd.exec.xml | 48 ++++++++++++++++++++ src/core/.gitignore | 4 ++ src/core/dbus-execute.c | 31 ++++++++++++- src/core/dbus-execute.h | 5 ++- src/core/execute.c | 70 +++++++++++++++++++++++++++++ src/core/execute.h | 4 ++ src/core/load-fragment-gperf.gperf.m4 | 2 + src/core/load-fragment.c | 85 ++++++++++++++++++++++++++++++++++- src/core/load-fragment.h | 1 + src/core/syscall-list.c | 55 +++++++++++++++++++++++ src/core/syscall-list.h | 30 +++++++++++++ src/shared/dbus-common.c | 23 ++++++++++ src/shared/exit-status.c | 6 +++ src/shared/exit-status.h | 5 ++- src/shared/linux/seccomp-bpf.h | 76 +++++++++++++++++++++++++++++++ src/shared/linux/seccomp.h | 47 +++++++++++++++++++ src/shared/missing.h | 4 ++ 19 files changed, 517 insertions(+), 14 deletions(-) create mode 100644 src/core/syscall-list.c create mode 100644 src/core/syscall-list.h create mode 100644 src/shared/linux/seccomp-bpf.h create mode 100644 src/shared/linux/seccomp.h (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/Makefile.am b/Makefile.am index cf911a0fe4..b16c01ae67 100644 --- a/Makefile.am +++ b/Makefile.am @@ -961,11 +961,15 @@ libsystemd_core_la_SOURCES = \ src/core/switch-root.h \ src/core/switch-root.c \ src/core/killall.h \ - src/core/killall.c + src/core/killall.c \ + src/core/syscall-list.c \ + src/core/syscall-list.h nodist_libsystemd_core_la_SOURCES = \ src/core/load-fragment-gperf.c \ - src/core/load-fragment-gperf-nulstr.c + src/core/load-fragment-gperf-nulstr.c \ + src/core/syscall-from-name.h \ + src/core/syscall-to-name.h libsystemd_core_la_CFLAGS = \ $(AM_CFLAGS) \ @@ -998,7 +1002,23 @@ EXTRA_DIST += \ CLEANFILES += \ src/core/load-fragment-gperf.gperf \ src/core/load-fragment-gperf.c \ - src/core/load-fragment-gperf-nulstr.c + src/core/load-fragment-gperf-nulstr.c \ + src/core/syscall-list.txt \ + src/core/syscall-from-name.gperf \ + src/core/syscall-from-name.h \ + src/core/syscall-to-name.h + +src/core/syscall-list.txt: Makefile + $(AM_V_GEN)cpp -dM -include sys/syscall.h < /dev/null | $(AWK) '/^#define[ \t]+__NR_[^ ]+[ \t]+[0-9]/ { sub(/__NR_/, "", $$2); print $$2; }' > $@ || rm $@ + +src/core/syscall-from-name.gperf: src/core/syscall-list.txt Makefile + $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct syscall_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, __NR_%s\n", $$1, $$1 }' < $< > $@ + +src/core/syscall-from-name.h: src/core/syscall-from-name.gperf Makefile + $(AM_V_GEN)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_syscall -H hash_syscall_name -p -C < $< > $@ + +src/core/syscall-to-name.h: src/core/syscall-list.txt Makefile + $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char* const syscall_names[] = { "} { printf "[__NR_%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' < $< > $@ # ------------------------------------------------------------------------------ systemd_SOURCES = \ diff --git a/TODO b/TODO index 0a923ce30d..c0381b88aa 100644 --- a/TODO +++ b/TODO @@ -33,12 +33,13 @@ Bugfixes: Jul 09 18:22:37 mop [21866]: Process 21865 (systemd) dumped core. Features: + +* use cpp -dM for key mapping too? + * change mount access mode of 0700 or so for debugfs? * logind: wakelock/opportunistic suspend support -* seccomp filters for services - * switch-root: sockets need relabelling * segfault in journalctl during /var migration @@ -60,8 +61,6 @@ Features: * load-fragment: when loading a unit file via a chain of symlinks verify that it isn't masked via any of the names traversed. -* journald: _BOOT_ID triggers too many collisions. - * journald: we currently rotate only after MaxUse+MaxFilesize has been reached. * nspawn: bind mount /var/log/journal from the host @@ -236,8 +235,6 @@ Features: * write RPM spec macros for presets -* journal: extend hash tables as we go - * journal: API for looking for retrieving "all values of this field" * journal: deal nicely with byte-by-byte copied files, especially regards header diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index c04db12e3b..6e55d8dfcf 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1091,6 +1091,54 @@ shell pipelines. + + NoNewPrivileges= + + Takes a boolean + argument. If true ensures that the + service process and all its children + can never gain new privileges. This + option is more powerful than the respective + secure bits flags (see above), as it + also prohibits UID changes of any + kind. This is the simplest, most + effective way to ensure that a process + and its children can never elevate + privileges again. + + + + SystemCallFilter= + + Takes a space + separated list of system call + names. If this setting is used all + system calls executed by the unit + process except for the listed ones + will result in immediate process + termination with the SIGSYS signal + (whitelisting). If the first character + of the list is ~ + the effect is inverted: only the + listed system calls will result in + immediate process termination + (blacklisting). If this option is used + NoNewPrivileges=yes + is implied. This feature makes use of + the Secure Computing Mode 2 interfaces + of the kernel ('seccomp filtering') + and is useful for enforcing a minimal + sandboxing environment. Note that the + execve, + rt_sigreturn, + sigreturn, + exit_group, + exit system calls + are implicitly whitelisted and don't + need to be listed + explicitly. + + diff --git a/src/core/.gitignore b/src/core/.gitignore index f293bbdc93..a763f72507 100644 --- a/src/core/.gitignore +++ b/src/core/.gitignore @@ -1,2 +1,6 @@ +/syscall-from-name.gperf +/syscall-from-name.h +/syscall-list.txt +/syscall-to-name.h /macros.systemd /systemd.pc diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 9322cdfd86..a00ad50795 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -28,6 +28,7 @@ #include "ioprio.h" #include "strv.h" #include "dbus-common.h" +#include "syscall-list.h" DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_kill_mode, kill_mode, KillMode); @@ -348,6 +349,32 @@ int bus_execute_append_command(DBusMessageIter *i, const char *property, void *d return 0; } +int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data) { + ExecContext *c = data; + dbus_bool_t b; + DBusMessageIter sub; + + assert(i); + assert(property); + assert(c); + + if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "u", &sub)) + return -ENOMEM; + + if (c->syscall_filter) + b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_UINT32, &c->syscall_filter, (syscall_max() + 31) >> 4); + else + b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_UINT32, &c->syscall_filter, 0); + + if (!b) + return -ENOMEM; + + if (!dbus_message_iter_close_container(i, &sub)) + return -ENOMEM; + + return 0; +} + const BusProperty bus_exec_context_properties[] = { { "Environment", bus_property_append_strv, "as", offsetof(ExecContext, environment), true }, { "EnvironmentFiles", bus_execute_append_env_files, "a(sb)", offsetof(ExecContext, environment_files), true }, @@ -409,6 +436,8 @@ const BusProperty bus_exec_context_properties[] = { { "UtmpIdentifier", bus_property_append_string, "s", offsetof(ExecContext, utmp_id), true }, { "ControlGroupModify", bus_property_append_bool, "b", offsetof(ExecContext, control_group_modify) }, { "ControlGroupPersistent", bus_property_append_tristate_false, "b", offsetof(ExecContext, control_group_persistent) }, - { "IgnoreSIGPIPE", bus_property_append_bool, "b", offsetof(ExecContext, ignore_sigpipe ) }, + { "IgnoreSIGPIPE", bus_property_append_bool, "b", offsetof(ExecContext, ignore_sigpipe) }, + { "NoNewPrivileges", bus_property_append_bool, "b", offsetof(ExecContext, no_new_privileges) }, + { "SystemCallFilter", bus_execute_append_syscall_filter, "au", 0 }, { NULL, } }; diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h index b8bbe1c9f2..dc267e6ccc 100644 --- a/src/core/dbus-execute.h +++ b/src/core/dbus-execute.h @@ -96,7 +96,9 @@ " \n" \ " \n" \ " \n" \ - " \n" + " \n" \ + " \n" \ + " \n" #define BUS_EXEC_COMMAND_INTERFACE(name) \ " \n" @@ -121,5 +123,6 @@ int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *d int bus_execute_append_command(DBusMessageIter *u, const char *property, void *data); int bus_execute_append_kill_mode(DBusMessageIter *i, const char *property, void *data); int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data); #endif diff --git a/src/core/execute.c b/src/core/execute.c index daba1a3846..7a72aa486c 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -38,6 +38,7 @@ #include #include #include +#include #ifdef HAVE_PAM #include @@ -60,6 +61,7 @@ #include "def.h" #include "loopback-setup.h" #include "path-util.h" +#include "syscall-list.h" #define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC) @@ -924,6 +926,59 @@ static void rename_process_from_path(const char *path) { rename_process(process_name); } +static int apply_seccomp(uint32_t *syscall_filter) { + static const struct sock_filter header[] = { + VALIDATE_ARCHITECTURE, + EXAMINE_SYSCALL + }; + static const struct sock_filter footer[] = { + _KILL_PROCESS + }; + + int i; + unsigned n; + struct sock_filter *f; + struct sock_fprog prog; + + assert(syscall_filter); + + /* First: count the syscalls to check for */ + for (i = 0, n = 0; i < syscall_max(); i++) + if (syscall_filter[i >> 4] & (1 << (i & 31))) + n++; + + /* Second: build the filter program from a header the syscall + * matches and the footer */ + f = alloca(sizeof(struct sock_filter) * (ELEMENTSOF(header) + 2*n + ELEMENTSOF(footer))); + memcpy(f, header, sizeof(header)); + + for (i = 0, n = 0; i < syscall_max(); i++) + if (syscall_filter[i >> 4] & (1 << (i & 31))) { + struct sock_filter item[] = { + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, i, 0, 1), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) + }; + + assert_cc(ELEMENTSOF(item) == 2); + + f[ELEMENTSOF(header) + 2*n] = item[0]; + f[ELEMENTSOF(header) + 2*n+1] = item[1]; + + n++; + } + + memcpy(f + (ELEMENTSOF(header) + 2*n), footer, sizeof(footer)); + + /* Third: install the filter */ + zero(prog); + prog.len = ELEMENTSOF(header) + ELEMENTSOF(footer) + 2*n; + prog.filter = f; + if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) + return -errno; + + return 0; +} + int exec_spawn(ExecCommand *command, char **argv, const ExecContext *context, @@ -1355,6 +1410,21 @@ int exec_spawn(ExecCommand *command, r = EXIT_CAPABILITIES; goto fail_child; } + + if (context->no_new_privileges) + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { + err = -errno; + r = EXIT_NO_NEW_PRIVILEGES; + goto fail_child; + } + + if (context->syscall_filter) { + err = apply_seccomp(context->syscall_filter); + if (err < 0) { + r = EXIT_SECCOMP; + goto fail_child; + } + } } if (!(our_env = new0(char*, 7))) { diff --git a/src/core/execute.h b/src/core/execute.h index 2083c2971b..187165cdc2 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -164,6 +164,8 @@ struct ExecContext { bool private_tmp; bool private_network; + bool no_new_privileges; + bool control_group_modify; int control_group_persistent; @@ -174,6 +176,8 @@ struct ExecContext { * don't enter a trigger loop. */ bool same_pgrp; + uint32_t *syscall_filter; + bool oom_score_adjust_set:1; bool nice_set:1; bool ioprio_set:1; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 192c2b2780..140cb9c0a3 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -48,6 +48,8 @@ $1.Capabilities, config_parse_exec_capabilities, 0, $1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context) $1.CapabilityBoundingSet, config_parse_bounding_set, 0, offsetof($1, exec_context.capability_bounding_set_drop) $1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec) +$1.NoNewPrivileges config_parse_bool, 0, offsetof($1, exec_context.no_new_privileges) +$1.SystemCallFilter, config_parse_syscall_filter, 0, offsetof($1, exec_context) $1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) $1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) $1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 748ab55d54..7fcd63a17a 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -45,6 +45,7 @@ #include "bus-errors.h" #include "utf8.h" #include "path-util.h" +#include "syscall-list.h" #ifndef HAVE_SYSV_COMPAT int config_parse_warn_compat( @@ -879,7 +880,7 @@ int config_parse_bounding_set( if (r < 0) { log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue); - return 0; + continue; } sum |= ((uint64_t) 1ULL) << (uint64_t) cap; @@ -2001,6 +2002,88 @@ int config_parse_documentation( return r; } +static void syscall_set(uint32_t *p, int nr) { + p[nr >> 4] |= 1 << (nr & 31); +} + +static void syscall_unset(uint32_t *p, int nr) { + p[nr >> 4] &= ~(1 << (nr & 31)); +} + +int config_parse_syscall_filter( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + Unit *u = userdata; + bool invert; + char *w; + size_t l; + char *state; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(u); + + if (rvalue[0] == '~') { + invert = true; + rvalue++; + } + + if (!c->syscall_filter) { + size_t n; + + n = (syscall_max() + 31) >> 4; + c->syscall_filter = new(uint32_t, n); + if (!c->syscall_filter) + return -ENOMEM; + + memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t)); + + /* Add these by default */ + syscall_set(c->syscall_filter, __NR_execve); + syscall_set(c->syscall_filter, __NR_rt_sigreturn); +#ifdef __NR_sigreturn + syscall_set(c->syscall_filter, __NR_sigreturn); +#endif + syscall_set(c->syscall_filter, __NR_exit_group); + syscall_set(c->syscall_filter, __NR_exit); + } + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + int id; + char *t; + + t = strndup(w, l); + if (!t) + return -ENOMEM; + + id = syscall_from_name(t); + free(t); + + if (id < 0) { + log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue); + continue; + } + + if (invert) + syscall_unset(c->syscall_filter, id); + else + syscall_set(c->syscall_filter, id); + } + + c->no_new_privileges = true; + + return 0; +} + #define FOLLOW_MAX 8 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 501ea4ad47..543e32968f 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -82,6 +82,7 @@ int config_parse_unit_device_allow(const char *filename, unsigned line, const ch int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_requires_mounts_for(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_syscall_filter(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* gperf prototypes */ const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length); diff --git a/src/core/syscall-list.c b/src/core/syscall-list.c new file mode 100644 index 0000000000..05fad3e158 --- /dev/null +++ b/src/core/syscall-list.c @@ -0,0 +1,55 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" + +#include "syscall-list.h" + +const struct syscall_name *lookup_syscall(register const char *str, register unsigned int len); + +#include "syscall-to-name.h" +#include "syscall-from-name.h" + +const char *syscall_to_name(int id) { + if (id < 0 || id >= (int) ELEMENTSOF(syscall_names)) + return NULL; + + return syscall_names[id]; +} + +int syscall_from_name(const char *name) { + const struct syscall_name *sc; + + assert(name); + + sc = lookup_syscall(name, strlen(name)); + if (!sc) + return -1; + + return sc->id; +} + +int syscall_max(void) { + return ELEMENTSOF(syscall_names); +} diff --git a/src/core/syscall-list.h b/src/core/syscall-list.h new file mode 100644 index 0000000000..0fc6859605 --- /dev/null +++ b/src/core/syscall-list.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosyscalllisthfoo +#define foosyscalllisthfoo + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +const char *syscall_to_name(int id); +int syscall_from_name(const char *name); + +int syscall_max(void); + +#endif diff --git a/src/shared/dbus-common.c b/src/shared/dbus-common.c index 3f5ce97680..7d57680cfc 100644 --- a/src/shared/dbus-common.c +++ b/src/shared/dbus-common.c @@ -1082,6 +1082,29 @@ int generic_print_property(const char *name, DBusMessageIter *iter, bool all) { puts(""); } + return 1; + + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_UINT32) { + DBusMessageIter sub; + + dbus_message_iter_recurse(iter, &sub); + if (all || + dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + printf("%s=", name); + + while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + uint32_t u; + + assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32); + dbus_message_iter_get_basic(&sub, &u); + printf("%08x", u); + + dbus_message_iter_next(&sub); + } + + puts(""); + } + return 1; } diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c index b07a66a3e2..0dc82b2e13 100644 --- a/src/shared/exit-status.c +++ b/src/shared/exit-status.c @@ -122,6 +122,12 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { case EXIT_NAMESPACE: return "NAMESPACE"; + + case EXIT_NO_NEW_PRIVILEGES: + return "NO_NEW_PRIVILEGES"; + + case EXIT_SECCOMP: + return "SECCOMP"; } } diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h index 349e24fbf2..813f1ce1b4 100644 --- a/src/shared/exit-status.h +++ b/src/shared/exit-status.h @@ -66,8 +66,9 @@ typedef enum ExitStatus { EXIT_TCPWRAP, EXIT_PAM, EXIT_NETWORK, - EXIT_NAMESPACE - + EXIT_NAMESPACE, + EXIT_NO_NEW_PRIVILEGES, + EXIT_SECCOMP } ExitStatus; typedef enum ExitStatusLevel { diff --git a/src/shared/linux/seccomp-bpf.h b/src/shared/linux/seccomp-bpf.h new file mode 100644 index 0000000000..1e3d136739 --- /dev/null +++ b/src/shared/linux/seccomp-bpf.h @@ -0,0 +1,76 @@ +/* + * seccomp example for x86 (32-bit and 64-bit) with BPF macros + * + * Copyright (c) 2012 The Chromium OS Authors + * Authors: + * Will Drewry + * Kees Cook + * + * The code may be used by anyone for any purpose, and can serve as a + * starting point for developing applications using mode 2 seccomp. + */ +#ifndef _SECCOMP_BPF_H_ +#define _SECCOMP_BPF_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#ifndef SECCOMP_MODE_FILTER +# define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ +# define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ +# define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ +# define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ +struct seccomp_data { + int nr; + __u32 arch; + __u64 instruction_pointer; + __u64 args[6]; +}; +#endif +#ifndef SYS_SECCOMP +# define SYS_SECCOMP 1 +#endif + +#define syscall_nr (offsetof(struct seccomp_data, nr)) +#define arch_nr (offsetof(struct seccomp_data, arch)) + +#if defined(__i386__) +# define REG_SYSCALL REG_EAX +# define ARCH_NR AUDIT_ARCH_I386 +#elif defined(__x86_64__) +# define REG_SYSCALL REG_RAX +# define ARCH_NR AUDIT_ARCH_X86_64 +#else +# warning "Platform does not support seccomp filter yet" +# define REG_SYSCALL 0 +# define ARCH_NR 0 +#endif + +#define VALIDATE_ARCHITECTURE \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) + +#define EXAMINE_SYSCALL \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr) + +#define ALLOW_SYSCALL(name) \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##name, 0, 1), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) + +#define _KILL_PROCESS \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) + +#endif /* _SECCOMP_BPF_H_ */ diff --git a/src/shared/linux/seccomp.h b/src/shared/linux/seccomp.h new file mode 100644 index 0000000000..9c03683fa0 --- /dev/null +++ b/src/shared/linux/seccomp.h @@ -0,0 +1,47 @@ +#ifndef _LINUX_SECCOMP_H +#define _LINUX_SECCOMP_H + + +#include + + +/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, ) */ +#define SECCOMP_MODE_DISABLED 0 /* seccomp is not in use. */ +#define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */ +#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ + +/* + * All BPF programs must return a 32-bit value. + * The bottom 16-bits are for optional return data. + * The upper 16-bits are ordered from least permissive values to most. + * + * The ordering ensures that a min_t() over composed return values always + * selects the least permissive choice. + */ +#define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ +#define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ +#define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ +#define SECCOMP_RET_TRACE 0x7ff00000U /* pass to a tracer or disallow */ +#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ + +/* Masks for the return value sections. */ +#define SECCOMP_RET_ACTION 0x7fff0000U +#define SECCOMP_RET_DATA 0x0000ffffU + +/** + * struct seccomp_data - the format the BPF program executes over. + * @nr: the system call number + * @arch: indicates system call convention as an AUDIT_ARCH_* value + * as defined in . + * @instruction_pointer: at the time of the system call. + * @args: up to 6 system call arguments always stored as 64-bit values + * regardless of the architecture. + */ +struct seccomp_data { + int nr; + __u32 arch; + __u64 instruction_pointer; + __u64 args[6]; +}; + +#endif /* _LINUX_SECCOMP_H */ diff --git a/src/shared/missing.h b/src/shared/missing.h index 0cf7949d2c..d918c4e9a7 100644 --- a/src/shared/missing.h +++ b/src/shared/missing.h @@ -188,4 +188,8 @@ static inline pid_t gettid(void) { #define MS_STRICTATIME (1<<24) #endif +#ifndef PR_SET_NO_NEW_PRIVS +#define PR_SET_NO_NEW_PRIVS 38 +#endif + #endif -- cgit v1.2.3-54-g00ecf From 4819ff0358b6317c195fd4b1768e03d09c871070 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 19 Jul 2012 23:47:10 +0200 Subject: unit: split off KillContext from ExecContext containing only kill definitions --- Makefile.am | 5 + man/systemd.exec.xml | 3 +- man/systemd.kill.xml | 170 ++++++++++++++++++++++++++++++++++ man/systemd.mount.xml | 55 ++++------- man/systemd.service.xml | 100 +++++--------------- man/systemd.socket.xml | 54 ++++------- man/systemd.swap.xml | 58 +++++------- src/core/dbus-execute.c | 4 - src/core/dbus-execute.h | 1 - src/core/dbus-kill.c | 35 +++++++ src/core/dbus-kill.h | 39 ++++++++ src/core/dbus-mount.c | 3 + src/core/dbus-service.c | 4 + src/core/dbus-socket.c | 3 + src/core/dbus-swap.c | 3 + src/core/execute.c | 34 +------ src/core/execute.h | 27 ------ src/core/kill.c | 63 +++++++++++++ src/core/kill.h | 58 ++++++++++++ src/core/load-fragment-gperf.gperf.m4 | 12 ++- src/core/mount.c | 17 ++-- src/core/mount.h | 2 + src/core/service.c | 19 ++-- src/core/service.h | 3 + src/core/socket.c | 14 +-- src/core/socket.h | 1 + src/core/swap.c | 14 +-- src/core/swap.h | 1 + 28 files changed, 519 insertions(+), 283 deletions(-) create mode 100644 man/systemd.kill.xml create mode 100644 src/core/dbus-kill.c create mode 100644 src/core/dbus-kill.h create mode 100644 src/core/kill.c create mode 100644 src/core/kill.h (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/Makefile.am b/Makefile.am index b15b9f54c1..655d9bf6b3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -455,6 +455,7 @@ MANPAGES = \ man/systemd.device.5 \ man/systemd.snapshot.5 \ man/systemd.exec.5 \ + man/systemd.kill.5 \ man/systemd.special.7 \ man/systemd.journal-fields.7 \ man/kernel-command-line.7 \ @@ -904,6 +905,8 @@ libsystemd_core_la_SOURCES = \ src/core/load-dropin.h \ src/core/execute.c \ src/core/execute.h \ + src/core/kill.c \ + src/core/kill.h \ src/core/dbus.c \ src/core/dbus.h \ src/core/dbus-manager.c \ @@ -932,6 +935,8 @@ libsystemd_core_la_SOURCES = \ src/core/dbus-device.h \ src/core/dbus-execute.c \ src/core/dbus-execute.h \ + src/core/dbus-kill.c \ + src/core/dbus-kill.h \ src/core/dbus-path.c \ src/core/dbus-path.h \ src/core/cgroup.c \ diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 6e55d8dfcf..e1193d2d55 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1152,7 +1152,8 @@ systemd.service5, systemd.socket5, systemd.swap5, - systemd.mount5 + systemd.mount5, + systemd.kill5 diff --git a/man/systemd.kill.xml b/man/systemd.kill.xml new file mode 100644 index 0000000000..3300534040 --- /dev/null +++ b/man/systemd.kill.xml @@ -0,0 +1,170 @@ + + + + + + + + + systemd.kill + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd.kill + 5 + + + + systemd.kill + Kill environment configuration + + + + systemd.service, + systemd.socket, + systemd.mount, + systemd.swap + + + + Description + + Unit configuration files for services, sockets, + mount points and swap devices share a subset of + configuration options which define the process killing + parameters of spawned processes. + + This man page lists the configuration options + shared by these four unit types. See + systemd.unit5 + for the common options of all unit configuration + files, and + systemd.service5, + systemd.socket5, + systemd.swap5 + and + systemd.mount5 + for more information on the specific unit + configuration files. The execution specific + configuration options are configured in the [Service], + [Socket], [Mount] resp. [Swap] section, depending on the unit + type. + + + + Options + + + + + KillMode= + Specifies how + processes of this service shall be + killed. One of + , + , + . + + If set to + all + remaining processes in the control + group of this unit will be terminated + on unit stop (for services: after the + stop command is executed, as + configured with + ExecStop=). If set + to only the + main process itself is killed. If set + to no process is + killed. In this case only the stop + command will be executed on unit + stop, but no process be killed + otherwise. Processes remaining alive + after stop are left in their control + group and the control group continues + to exist after stop unless it is + empty. Defaults to + . + + Processes will first be + terminated via SIGTERM (unless the + signal to send is changed via + KillSignal=). If + then after a delay (configured via the + TimeoutSec= option) + processes still remain, the + termination request is repeated with + the SIGKILL signal (unless this is + disabled via the + SendSIGKILL= + option). See + kill2 + for more + information. + + + + KillSignal= + Specifies which signal + to use when killing a + service. Defaults to SIGTERM. + + + + + SendSIGKILL= + Specifies whether to + send SIGKILL to remaining processes + after a timeout, if the normal + shutdown procedure left processes of + the service around. Takes a boolean + value. Defaults to "yes". + + + + + + + See Also + + systemd1, + systemctl8, + journalctl8, + systemd.unit5, + systemd.service5, + systemd.socket5, + systemd.swap5, + systemd.mount5, + systemd.exec5 + + + + diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml index 105afb41ea..bcaae33418 100644 --- a/man/systemd.mount.xml +++ b/man/systemd.mount.xml @@ -72,7 +72,10 @@ systemd.exec5, which define the execution environment the mount8 - binary is executed in. + binary is executed in, and in + systemd.kill5 + which define the way the processes are + terminated. Mount units must be named after the mount point directories they control. Example: the mount point @@ -147,7 +150,9 @@ supervises. A number of options that may be used in this section are shared with other unit types. These options are documented in - systemd.exec5. The + systemd.exec5 + and + systemd.kill5. The options specific to the [Mount] section of mount units are the following: @@ -220,50 +225,21 @@ will be terminated forcibly via SIGTERM, and after another delay of this time with SIGKILL. (See - below.) + in + systemd.kill5.) Takes a unit-less value in seconds, or a time span value such as "5min 20s". Pass 0 to disable the timeout logic. Defaults to 90s. - - - KillMode= - Specifies how - processes of this mount shall be - killed. One of - , - , - . - - This option is mostly equivalent - to the - option of service files. See - systemd.service5 - for details. - - - - KillSignal= - Specifies which signal - to use when killing a process of this - mount. Defaults to SIGTERM. - - - - - SendSIGKILL= - Specifies whether to - send SIGKILL to remaining processes - after a timeout, if the normal - shutdown procedure left processes of - the mount around. Takes a boolean - value. Defaults to "yes". - - - + + Check + systemd.exec5 + and + systemd.kill5 + for more settings. @@ -295,6 +271,7 @@ systemctl8, systemd.unit5, systemd.exec5, + systemd.kill5, systemd.service5, systemd.device5, mount8, diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 38a4035f67..f43201dc7e 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -72,7 +72,10 @@ Additional options are listed in systemd.exec5, which define the execution environment the commands - are executed in. + are executed in, and in + systemd.kill5 + which define the way the processes of the service are + terminated. Unless DefaultDependencies= is set to , service units will @@ -112,7 +115,9 @@ supervises. A number of options that may be used in this section are shared with other unit types. These options are documented in - systemd.exec5. The + systemd.exec5 + and + systemd.kill5. The options specific to the [Service] section of service units are the following: @@ -417,12 +422,13 @@ configured in this option are run are terminated according to the KillMode= setting - (see below). If this option is not - specified the process is terminated - right-away when service stop is - requested. Specifier and environment - variable substitution is supported - (including + (see + systemd.kill5). If + this option is not specified the + process is terminated right-away when + service stop is requested. Specifier + and environment variable substitution + is supported (including $MAINPID, see above). @@ -471,7 +477,7 @@ another delay of this time with SIGKILL. (See KillMode= - below.) Takes a unit-less value in seconds, or a + in systemd.kill5) Takes a unit-less value in seconds, or a time span value such as "5min 20s". Pass 0 to disable the timeout logic. Defaults to @@ -598,72 +604,6 @@ false. - - KillMode= - Specifies how - processes of this service shall be - killed. One of - , - , - . - - If set to - all - remaining processes in the control - group of this service will be - terminated on service stop, after the - stop command (as configured with - ExecStop=) is - executed. If set to - only the main - process itself is killed. If set to - no process is - killed. In this case only the stop - command will be executed on service - stop, but no process be killed - otherwise. Processes remaining alive - after stop are left in their control - group and the control group continues - to exist after stop unless it is - empty. Defaults to - . - - Processes will first be - terminated via SIGTERM (unless the - signal to send is changed via - KillSignal=). If - then after a delay (configured via the - TimeoutSec= option) - processes still remain, the - termination request is repeated with - the SIGKILL signal (unless this is - disabled via the - SendSIGKILL= - option). See - kill2 - for more - information. - - - - KillSignal= - Specifies which signal - to use when killing a - service. Defaults to SIGTERM. - - - - - SendSIGKILL= - Specifies whether to - send SIGKILL to remaining processes - after a timeout, if the normal - shutdown procedure left processes of - the service around. Takes a boolean - value. Defaults to "yes". - - - NonBlocking= Set O_NONBLOCK flag @@ -818,6 +758,13 @@ + + Check + systemd.exec5 + and + systemd.kill5 + for more settings. + @@ -888,7 +835,8 @@ systemd1, systemctl8, systemd.unit5, - systemd.exec5 + systemd.exec5, + systemd.kill5 diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 5ca1c7a7c1..8a12e25cf4 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -76,7 +76,10 @@ , and commands are executed - in. + in, and in + systemd.kill5 + which define the way the processes are + terminated. For each socket file a matching service file (see @@ -134,7 +137,9 @@ supervises. A number of options that may be used in this section are shared with other unit types. These options are documented in - systemd.exec5. The + systemd.exec5 + and + systemd.kill5. The options specific to the [Socket] section of socket units are the following: @@ -603,7 +608,7 @@ will be terminated forcibly via SIGTERM, and after another delay of this time with SIGKILL. (See - below.) + in systemd.kill5.) Takes a unit-less value in seconds, or a time span value such as "5min 20s". Pass 0 to disable the timeout @@ -611,41 +616,6 @@ 90s. - - KillMode= - Specifies how - processes of this socket unit shall be - killed. One of - , - , - . - - This option is mostly equivalent - to the - option of service files. See - systemd.service5 - for details. - - - - KillSignal= - Specifies which signal - to use when killing a process of this - socket. Defaults to SIGTERM. - - - - - SendSIGKILL= - Specifies whether to - send SIGKILL to remaining processes - after a timeout, if the normal - shutdown procedure left processes of - the socket around. Takes a boolean - value. Defaults to "yes". - - - Service= Specifies the service @@ -658,6 +628,13 @@ + + Check + systemd.exec5 + and + systemd.kill5 + for more settings. + @@ -667,6 +644,7 @@ systemctl8, systemd.unit5, systemd.exec5, + systemd.kill5, systemd.service5 diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml index aaf77f8396..5eb008dfcf 100644 --- a/man/systemd.swap.xml +++ b/man/systemd.swap.xml @@ -68,6 +68,15 @@ specific configuration options are configured in the [Swap] section. + Additional options are listed in + systemd.exec5, + which define the execution environment the + swapon8 + binary is executed in, and in + systemd.kill5 + which define the way the processes are + terminated. + Swap units must be named after the devices (resp. files) they control. Example: the swap device /dev/sda5 must be configured in a @@ -121,7 +130,9 @@ supervises. A number of options that may be used in this section are shared with other unit types. These options are documented in - systemd.exec5. The + systemd.exec5 + and + systemd.kill5. The options specific to the [Swap] section of swap units are the following: @@ -167,49 +178,21 @@ will be terminated forcibly via SIGTERM, and after another delay of this time with SIGKILL. (See - below.) + in + systemd.kill5.) Takes a unit-less value in seconds, or a time span value such as "5min 20s". Pass 0 to disable the timeout logic. Defaults to 90s. - - - KillMode= - Specifies how - processes of this swap shall be - killed. One of - , - , - . - - This option is mostly equivalent - to the - option of service files. See - systemd.service5 - for details. - - - - KillSignal= - Specifies which signal - to use when killing a process of this - swap. Defaults to SIGTERM. - - - - - SendSIGKILL= - Specifies whether to - send SIGKILL to remaining processes - after a timeout, if the normal - shutdown procedure left processes of - the swap around. Takes a boolean - value. Defaults to "yes". - - + + Check + systemd.exec5 + and + systemd.kill5 + for more settings. @@ -219,6 +202,7 @@ systemctl8, systemd.unit5, systemd.exec5, + systemd.kill5, systemd.device5, systemd.mount5, swapon8, diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index a00ad50795..e815cb58e4 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -30,8 +30,6 @@ #include "dbus-common.h" #include "syscall-list.h" -DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_kill_mode, kill_mode, KillMode); - DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput); DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput); @@ -431,8 +429,6 @@ const BusProperty bus_exec_context_properties[] = { { "PrivateTmp", bus_property_append_bool, "b", offsetof(ExecContext, private_tmp) }, { "PrivateNetwork", bus_property_append_bool, "b", offsetof(ExecContext, private_network) }, { "SameProcessGroup", bus_property_append_bool, "b", offsetof(ExecContext, same_pgrp) }, - { "KillMode", bus_execute_append_kill_mode, "s", offsetof(ExecContext, kill_mode) }, - { "KillSignal", bus_property_append_int, "i", offsetof(ExecContext, kill_signal) }, { "UtmpIdentifier", bus_property_append_string, "s", offsetof(ExecContext, utmp_id), true }, { "ControlGroupModify", bus_property_append_bool, "b", offsetof(ExecContext, control_group_modify) }, { "ControlGroupPersistent", bus_property_append_tristate_false, "b", offsetof(ExecContext, control_group_persistent) }, diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h index feb883335f..eaa1b73e69 100644 --- a/src/core/dbus-execute.h +++ b/src/core/dbus-execute.h @@ -120,6 +120,5 @@ int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, vo int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data); int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data); int bus_execute_append_command(DBusMessageIter *u, const char *property, void *data); -int bus_execute_append_kill_mode(DBusMessageIter *i, const char *property, void *data); int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data); int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data); diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c new file mode 100644 index 0000000000..165f63074b --- /dev/null +++ b/src/core/dbus-kill.c @@ -0,0 +1,35 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "dbus-kill.h" +#include "dbus-common.h" + +DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_kill_append_mode, kill_mode, KillMode); + +const BusProperty bus_kill_context_properties[] = { + { "KillMode", bus_kill_append_mode, "s", offsetof(KillContext, kill_mode) }, + { "KillSignal", bus_property_append_int, "i", offsetof(KillContext, kill_signal) }, + { "SendSIGKILL", bus_property_append_bool, "b", offsetof(KillContext, send_sigkill) }, + { NULL, } +}; diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h new file mode 100644 index 0000000000..238fbd36d6 --- /dev/null +++ b/src/core/dbus-kill.h @@ -0,0 +1,39 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "manager.h" +#include "dbus-common.h" + +#define BUS_KILL_CONTEXT_INTERFACE \ + " \n" \ + " \n" \ + " \n" + +#define BUS_KILL_COMMAND_INTERFACE(name) \ + " \n" + +extern const BusProperty bus_kill_context_properties[]; + +int bus_kill_append_mode(DBusMessageIter *i, const char *property, void *data); diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c index 26b04abe5d..93bfa4c35d 100644 --- a/src/core/dbus-mount.c +++ b/src/core/dbus-mount.c @@ -23,6 +23,7 @@ #include "dbus-unit.h" #include "dbus-mount.h" +#include "dbus-kill.h" #include "dbus-execute.h" #include "dbus-common.h" @@ -37,6 +38,7 @@ BUS_EXEC_COMMAND_INTERFACE("ExecUnmount") \ BUS_EXEC_COMMAND_INTERFACE("ExecRemount") \ BUS_EXEC_CONTEXT_INTERFACE \ + BUS_KILL_CONTEXT_INTERFACE \ " \n" \ " \n" \ " \n" \ @@ -155,6 +157,7 @@ DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMess { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, { "org.freedesktop.systemd1.Mount", bus_mount_properties, m }, { "org.freedesktop.systemd1.Mount", bus_exec_context_properties, &m->exec_context }, + { "org.freedesktop.systemd1.Mount", bus_kill_context_properties, &m->kill_context }, { NULL, } }; diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index 6568cd5ce0..c0fac16d2b 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -23,6 +23,7 @@ #include "dbus-unit.h" #include "dbus-execute.h" +#include "dbus-kill.h" #include "dbus-service.h" #include "dbus-common.h" @@ -47,6 +48,7 @@ BUS_EXEC_COMMAND_INTERFACE("ExecStop") \ BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \ BUS_EXEC_CONTEXT_INTERFACE \ + BUS_KILL_CONTEXT_INTERFACE \ " \n" \ " \n" \ " \n" \ @@ -140,10 +142,12 @@ static const BusProperty bus_service_properties[] = { DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connection, DBusMessage *message) { Service *s = SERVICE(u); + const BusBoundProperties bps[] = { { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, { "org.freedesktop.systemd1.Service", bus_service_properties, s }, { "org.freedesktop.systemd1.Service", bus_exec_context_properties, &s->exec_context }, + { "org.freedesktop.systemd1.Service", bus_kill_context_properties, &s->kill_context }, { "org.freedesktop.systemd1.Service", bus_exec_main_status_properties, &s->main_exec_status }, { NULL, } }; diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 80d19dd1bd..b2045225d7 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -24,6 +24,7 @@ #include "dbus-unit.h" #include "dbus-socket.h" #include "dbus-execute.h" +#include "dbus-kill.h" #include "dbus-common.h" #define BUS_SOCKET_INTERFACE \ @@ -36,6 +37,7 @@ BUS_EXEC_COMMAND_INTERFACE("ExecStopPre") \ BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \ BUS_EXEC_CONTEXT_INTERFACE \ + BUS_KILL_CONTEXT_INTERFACE \ " \n" \ " \n" \ " \n" \ @@ -132,6 +134,7 @@ DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMes { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, { "org.freedesktop.systemd1.Socket", bus_socket_properties, s }, { "org.freedesktop.systemd1.Socket", bus_exec_context_properties, &s->exec_context }, + { "org.freedesktop.systemd1.Socket", bus_kill_context_properties, &s->kill_context }, { NULL, } }; diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c index 3ede0e606e..cad6ec1aaa 100644 --- a/src/core/dbus-swap.c +++ b/src/core/dbus-swap.c @@ -25,6 +25,7 @@ #include "dbus-unit.h" #include "dbus-swap.h" #include "dbus-execute.h" +#include "dbus-kill.h" #include "dbus-common.h" #define BUS_SWAP_INTERFACE \ @@ -35,6 +36,7 @@ BUS_EXEC_COMMAND_INTERFACE("ExecActivate") \ BUS_EXEC_COMMAND_INTERFACE("ExecDeactivate") \ BUS_EXEC_CONTEXT_INTERFACE \ + BUS_KILL_CONTEXT_INTERFACE \ " \n" \ " \n" \ " \n" @@ -102,6 +104,7 @@ DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessa { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, { "org.freedesktop.systemd1.Swap", bus_swap_properties, s }, { "org.freedesktop.systemd1.Swap", bus_exec_context_properties, &s->exec_context }, + { "org.freedesktop.systemd1.Swap", bus_kill_context_properties, &s->kill_context }, { NULL, } }; diff --git a/src/core/execute.c b/src/core/execute.c index db4a8ae51c..fc0edc6cfd 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1541,8 +1541,6 @@ void exec_context_init(ExecContext *c) { c->syslog_priority = LOG_DAEMON|LOG_INFO; c->syslog_level_prefix = true; c->mount_flags = MS_SHARED; - c->kill_signal = SIGTERM; - c->send_sigkill = true; c->control_group_persistent = -1; c->ignore_sigpipe = true; c->timer_slack_nsec = (nsec_t) -1; @@ -1735,7 +1733,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { "%sPrivateTmp: %s\n" "%sControlGroupModify: %s\n" "%sControlGroupPersistent: %s\n" - "%sPrivateNetwork: %s\n", + "%sPrivateNetwork: %s\n" + "%sIgnoreSIGPIPE: %s\n", prefix, c->umask, prefix, c->working_directory ? c->working_directory : "/", prefix, c->root_directory ? c->root_directory : "/", @@ -1743,7 +1742,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { prefix, yes_no(c->private_tmp), prefix, yes_no(c->control_group_modify), prefix, yes_no(c->control_group_persistent), - prefix, yes_no(c->private_network)); + prefix, yes_no(c->private_network), + prefix, yes_no(c->ignore_sigpipe)); STRV_FOREACH(e, c->environment) fprintf(f, "%sEnvironment: %s\n", prefix, *e); @@ -1894,16 +1894,6 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { fputs("\n", f); } - fprintf(f, - "%sKillMode: %s\n" - "%sKillSignal: SIG%s\n" - "%sSendSIGKILL: %s\n" - "%sIgnoreSIGPIPE: %s\n", - prefix, kill_mode_to_string(c->kill_mode), - prefix, signal_to_string(c->kill_signal), - prefix, yes_no(c->send_sigkill), - prefix, yes_no(c->ignore_sigpipe)); - if (c->utmp_id) fprintf(f, "%sUtmpIdentifier: %s\n", @@ -2111,19 +2101,3 @@ static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput); - -static const char* const kill_mode_table[_KILL_MODE_MAX] = { - [KILL_CONTROL_GROUP] = "control-group", - [KILL_PROCESS] = "process", - [KILL_NONE] = "none" -}; - -DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode); - -static const char* const kill_who_table[_KILL_WHO_MAX] = { - [KILL_MAIN] = "main", - [KILL_CONTROL] = "control", - [KILL_ALL] = "all" -}; - -DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho); diff --git a/src/core/execute.h b/src/core/execute.h index 09f246e161..2bcd2e1e6c 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -39,22 +39,6 @@ struct CGroupAttribute; #include "list.h" #include "util.h" -typedef enum KillMode { - KILL_CONTROL_GROUP = 0, - KILL_PROCESS, - KILL_NONE, - _KILL_MODE_MAX, - _KILL_MODE_INVALID = -1 -} KillMode; - -typedef enum KillWho { - KILL_MAIN, - KILL_CONTROL, - KILL_ALL, - _KILL_WHO_MAX, - _KILL_WHO_INVALID = -1 -} KillWho; - typedef enum ExecInput { EXEC_INPUT_NULL, EXEC_INPUT_TTY, @@ -146,11 +130,6 @@ struct ExecContext { uint64_t capability_bounding_set_drop; - /* Not relevant for spawning processes, just for killing */ - KillMode kill_mode; - int kill_signal; - bool send_sigkill; - cap_t capabilities; int secure_bits; @@ -228,9 +207,3 @@ ExecOutput exec_output_from_string(const char *s); const char* exec_input_to_string(ExecInput i); ExecInput exec_input_from_string(const char *s); - -const char *kill_mode_to_string(KillMode k); -KillMode kill_mode_from_string(const char *s); - -const char *kill_who_to_string(KillWho k); -KillWho kill_who_from_string(const char *s); diff --git a/src/core/kill.c b/src/core/kill.c new file mode 100644 index 0000000000..0775653f73 --- /dev/null +++ b/src/core/kill.c @@ -0,0 +1,63 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "kill.h" +#include "util.h" + +void kill_context_init(KillContext *c) { + assert(c); + + c->kill_signal = SIGTERM; + c->send_sigkill = true; +} + +void kill_context_dump(KillContext *c, FILE *f, const char *prefix) { + assert(c); + + if (!prefix) + prefix = ""; + + fprintf(f, + "%sKillMode: %s\n" + "%sKillSignal: SIG%s\n" + "%sSendSIGKILL: %s\n", + prefix, kill_mode_to_string(c->kill_mode), + prefix, signal_to_string(c->kill_signal), + prefix, yes_no(c->send_sigkill)); +} + +static const char* const kill_mode_table[_KILL_MODE_MAX] = { + [KILL_CONTROL_GROUP] = "control-group", + [KILL_PROCESS] = "process", + [KILL_NONE] = "none" +}; + +DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode); + +static const char* const kill_who_table[_KILL_WHO_MAX] = { + [KILL_MAIN] = "main", + [KILL_CONTROL] = "control", + [KILL_ALL] = "all" +}; + +DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho); diff --git a/src/core/kill.h b/src/core/kill.h new file mode 100644 index 0000000000..4f88239271 --- /dev/null +++ b/src/core/kill.h @@ -0,0 +1,58 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct KillContext KillContext; + +#include +#include + +typedef enum KillMode { + KILL_CONTROL_GROUP = 0, + KILL_PROCESS, + KILL_NONE, + _KILL_MODE_MAX, + _KILL_MODE_INVALID = -1 +} KillMode; + +struct KillContext { + KillMode kill_mode; + int kill_signal; + bool send_sigkill; +}; + +typedef enum KillWho { + KILL_MAIN, + KILL_CONTROL, + KILL_ALL, + _KILL_WHO_MAX, + _KILL_WHO_INVALID = -1 +} KillWho; + +void kill_context_init(KillContext *c); +void kill_context_dump(KillContext *c, FILE *f, const char *prefix); + +const char *kill_mode_to_string(KillMode k); +KillMode kill_mode_from_string(const char *s); + +const char *kill_who_to_string(KillWho k); +KillWho kill_who_from_string(const char *s); diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 140cb9c0a3..d6a4711a32 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -84,14 +84,16 @@ $1.PrivateNetwork, config_parse_bool, 0, $1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context) $1.TCPWrapName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.tcpwrap_name) $1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name) -$1.KillMode, config_parse_kill_mode, 0, offsetof($1, exec_context.kill_mode) -$1.KillSignal, config_parse_kill_signal, 0, offsetof($1, exec_context.kill_signal) -$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, exec_context.send_sigkill) $1.IgnoreSIGPIPE, config_parse_bool, 0, offsetof($1, exec_context.ignore_sigpipe) $1.UtmpIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.utmp_id) $1.ControlGroupModify, config_parse_bool, 0, offsetof($1, exec_context.control_group_modify) $1.ControlGroupPersistent, config_parse_tristate, 0, offsetof($1, exec_context.control_group_persistent)' )m4_dnl +m4_define(`KILL_CONTEXT_CONFIG_ITEMS', +`$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, kill_context.send_sigkill) +$1.KillMode, config_parse_kill_mode, 0, offsetof($1, kill_context.kill_mode) +$1.KillSignal, config_parse_kill_signal, 0, offsetof($1, kill_context.kill_signal)' +)m4_dnl Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description) Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation) Unit.SourcePath, config_parse_path, 0, offsetof(Unit, source_path) @@ -162,6 +164,7 @@ Service.NotifyAccess, config_parse_notify_access, 0, Service.Sockets, config_parse_service_sockets, 0, 0 Service.FsckPassNo, config_parse_fsck_passno, 0, offsetof(Service, fsck_passno) EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl +KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl m4_dnl Socket.ListenStream, config_parse_socket_listen, 0, 0 Socket.ListenDatagram, config_parse_socket_listen, 0, 0 @@ -200,6 +203,7 @@ Socket.MessageQueueMaxMessages, config_parse_long, 0, Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize) Socket.Service, config_parse_socket_service, 0, 0 EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl +KILL_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl m4_dnl Mount.What, config_parse_string, 0, offsetof(Mount, parameters_fragment.what) Mount.Where, config_parse_path, 0, offsetof(Mount, where) @@ -209,6 +213,7 @@ Mount.FsckPassNo, config_parse_fsck_passno, 0, Mount.TimeoutSec, config_parse_usec, 0, offsetof(Mount, timeout_usec) Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode) EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl +KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl m4_dnl Automount.Where, config_parse_path, 0, offsetof(Automount, where) Automount.DirectoryMode, config_parse_mode, 0, offsetof(Automount, directory_mode) @@ -217,6 +222,7 @@ Swap.What, config_parse_path, 0, Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority) Swap.TimeoutSec, config_parse_usec, 0, offsetof(Swap, timeout_usec) EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl +KILL_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl m4_dnl Timer.OnActiveSec, config_parse_timer, 0, 0 Timer.OnBootSec, config_parse_timer, 0, 0 diff --git a/src/core/mount.c b/src/core/mount.c index a88b255875..82c64ff79b 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -79,6 +79,8 @@ static void mount_init(Unit *u) { m->exec_context.std_error = u->manager->default_std_error; } + kill_context_init(&m->kill_context); + /* We need to make sure that /bin/mount is always called in * the same process group as us, so that the autofs kernel * side doesn't send us another mount request while we are @@ -529,7 +531,7 @@ static int mount_verify(Mount *m) { return -EBADMSG; } - if (m->exec_context.pam_name && m->exec_context.kill_mode != KILL_CONTROL_GROUP) { + if (m->exec_context.pam_name && m->kill_context.kill_mode != KILL_CONTROL_GROUP) { log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(m)->id); return -EINVAL; } @@ -783,6 +785,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) { prefix, (unsigned long) m->control_pid); exec_context_dump(&m->exec_context, f, prefix); + kill_context_dump(&m->kill_context, f, prefix); } static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { @@ -855,10 +858,10 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) { if (f != MOUNT_SUCCESS) m->result = f; - if (m->exec_context.kill_mode != KILL_NONE) { + if (m->kill_context.kill_mode != KILL_NONE) { int sig = (state == MOUNT_MOUNTING_SIGTERM || state == MOUNT_UNMOUNTING_SIGTERM || - state == MOUNT_REMOUNTING_SIGTERM) ? m->exec_context.kill_signal : SIGKILL; + state == MOUNT_REMOUNTING_SIGTERM) ? m->kill_context.kill_signal : SIGKILL; if (m->control_pid > 0) { if (kill_and_sigcont(m->control_pid, sig) < 0 && errno != ESRCH) @@ -868,7 +871,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) { wait_for_exit = true; } - if (m->exec_context.kill_mode == KILL_CONTROL_GROUP) { + if (m->kill_context.kill_mode == KILL_CONTROL_GROUP) { if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) { r = -ENOMEM; @@ -1327,7 +1330,7 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) { break; case MOUNT_MOUNTING_SIGTERM: - if (m->exec_context.send_sigkill) { + if (m->kill_context.send_sigkill) { log_warning("%s mounting timed out. Killing.", u->id); mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); } else { @@ -1341,7 +1344,7 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) { break; case MOUNT_REMOUNTING_SIGTERM: - if (m->exec_context.send_sigkill) { + if (m->kill_context.send_sigkill) { log_warning("%s remounting timed out. Killing.", u->id); mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); } else { @@ -1355,7 +1358,7 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) { break; case MOUNT_UNMOUNTING_SIGTERM: - if (m->exec_context.send_sigkill) { + if (m->kill_context.send_sigkill) { log_warning("%s unmounting timed out. Killing.", u->id); mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); } else { diff --git a/src/core/mount.h b/src/core/mount.h index 9583eebe3a..67d6132a5d 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -24,6 +24,7 @@ typedef struct Mount Mount; #include "unit.h" +#include "kill.h" typedef enum MountState { MOUNT_DEAD, @@ -95,6 +96,7 @@ struct Mount { ExecCommand exec_command[_MOUNT_EXEC_COMMAND_MAX]; ExecContext exec_context; + KillContext kill_context; MountState state, deserialized_state; diff --git a/src/core/service.c b/src/core/service.c index 5dc06b36cc..567e9a4eb3 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -153,6 +153,7 @@ static void service_init(Unit *u) { for (i = 0; i < RLIMIT_NLIMITS; i++) if (UNIT(s)->manager->rlimit[i]) s->exec_context.rlimit[i] = newdup(struct rlimit, UNIT(s)->manager->rlimit[i], 1); + kill_context_init(&s->kill_context); RATELIMIT_INIT(s->start_limit, 10*USEC_PER_SEC, 5); @@ -928,7 +929,7 @@ static int service_load_sysv_path(Service *s, const char *path) { s->guess_main_pid = false; s->restart = SERVICE_RESTART_NO; s->exec_context.ignore_sigpipe = false; - s->exec_context.kill_mode = KILL_PROCESS; + s->kill_context.kill_mode = KILL_PROCESS; /* We use the long description only if * no short description is set. */ @@ -1164,7 +1165,7 @@ static int service_verify(Service *s) { if (s->bus_name && s->type != SERVICE_DBUS) log_warning("%s has a D-Bus service name specified, but is not of type dbus. Ignoring.", UNIT(s)->id); - if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) { + if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) { log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id); return -EINVAL; } @@ -1351,6 +1352,7 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) { prefix, s->bus_name, prefix, yes_no(s->bus_name_good)); + kill_context_dump(&s->kill_context, f, prefix); exec_context_dump(&s->exec_context, f, prefix); for (c = 0; c < _SERVICE_EXEC_COMMAND_MAX; c++) { @@ -1967,8 +1969,8 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f if (f != SERVICE_SUCCESS) s->result = f; - if (s->exec_context.kill_mode != KILL_NONE) { - int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL; + if (s->kill_context.kill_mode != KILL_NONE) { + int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? s->kill_context.kill_signal : SIGKILL; if (s->main_pid > 0) { if (kill_and_sigcont(s->main_pid, sig) < 0 && errno != ESRCH) @@ -1984,9 +1986,10 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f wait_for_exit = true; } - if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) { + if (s->kill_context.kill_mode == KILL_CONTROL_GROUP) { - if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) { + pid_set = set_new(trivial_hash_func, trivial_compare_func); + if (!pid_set) { r = -ENOMEM; goto fail; } @@ -3144,7 +3147,7 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) { break; case SERVICE_STOP_SIGTERM: - if (s->exec_context.send_sigkill) { + if (s->kill_context.send_sigkill) { log_warning("%s stopping timed out. Killing.", u->id); service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT); } else { @@ -3169,7 +3172,7 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) { break; case SERVICE_FINAL_SIGTERM: - if (s->exec_context.send_sigkill) { + if (s->kill_context.send_sigkill) { log_warning("%s stopping timed out (2). Killing.", u->id); service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT); } else { diff --git a/src/core/service.h b/src/core/service.h index 5ad09d0acc..cc63347c76 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -27,6 +27,7 @@ typedef struct Service Service; #include "path.h" #include "ratelimit.h" #include "service.h" +#include "kill.h" typedef enum ServiceState { SERVICE_DEAD, @@ -126,7 +127,9 @@ struct Service { Watch watchdog_watch; ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX]; + ExecContext exec_context; + KillContext kill_context; ServiceState state, deserialized_state; diff --git a/src/core/socket.c b/src/core/socket.c index 8153a8e762..6d417878b5 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -83,6 +83,7 @@ static void socket_init(Unit *u) { exec_context_init(&s->exec_context); s->exec_context.std_output = u->manager->default_std_output; s->exec_context.std_error = u->manager->default_std_error; + kill_context_init(&s->kill_context); s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; } @@ -223,7 +224,7 @@ static int socket_verify(Socket *s) { return -EINVAL; } - if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) { + if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) { log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id); return -EINVAL; } @@ -526,6 +527,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { } exec_context_dump(&s->exec_context, f, prefix); + kill_context_dump(&s->kill_context, f, prefix); for (c = 0; c < _SOCKET_EXEC_COMMAND_MAX; c++) { if (!s->exec_command[c]) @@ -1226,8 +1228,8 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) { if (f != SOCKET_SUCCESS) s->result = f; - if (s->exec_context.kill_mode != KILL_NONE) { - int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL; + if (s->kill_context.kill_mode != KILL_NONE) { + int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? s->kill_context.kill_signal : SIGKILL; if (s->control_pid > 0) { if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH) @@ -1237,7 +1239,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) { wait_for_exit = true; } - if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) { + if (s->kill_context.kill_mode == KILL_CONTROL_GROUP) { if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) { r = -ENOMEM; @@ -1983,7 +1985,7 @@ static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) { break; case SOCKET_STOP_PRE_SIGTERM: - if (s->exec_context.send_sigkill) { + if (s->kill_context.send_sigkill) { log_warning("%s stopping timed out. Killing.", u->id); socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_FAILURE_TIMEOUT); } else { @@ -2003,7 +2005,7 @@ static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) { break; case SOCKET_FINAL_SIGTERM: - if (s->exec_context.send_sigkill) { + if (s->kill_context.send_sigkill) { log_warning("%s stopping timed out (2). Killing.", u->id); socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_FAILURE_TIMEOUT); } else { diff --git a/src/core/socket.h b/src/core/socket.h index 508f00eb34..a06b3eae94 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -101,6 +101,7 @@ struct Socket { ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX]; ExecContext exec_context; + KillContext kill_context; /* For Accept=no sockets refers to the one service we'll activate. For Accept=yes sockets is either NULL, or filled diff --git a/src/core/swap.c b/src/core/swap.c index ed61ba3c81..03993b1e60 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -86,6 +86,7 @@ static void swap_init(Unit *u) { exec_context_init(&s->exec_context); s->exec_context.std_output = u->manager->default_std_output; s->exec_context.std_error = u->manager->default_std_error; + kill_context_init(&s->kill_context); s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1; @@ -235,7 +236,7 @@ static int swap_verify(Swap *s) { return -EINVAL; } - if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) { + if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) { log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id); return -EINVAL; } @@ -569,6 +570,7 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) { prefix, (unsigned long) s->control_pid); exec_context_dump(&s->exec_context, f, prefix); + kill_context_dump(&s->kill_context, f, prefix); } static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { @@ -641,9 +643,9 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) { if (f != SWAP_SUCCESS) s->result = f; - if (s->exec_context.kill_mode != KILL_NONE) { + if (s->kill_context.kill_mode != KILL_NONE) { int sig = (state == SWAP_ACTIVATING_SIGTERM || - state == SWAP_DEACTIVATING_SIGTERM) ? s->exec_context.kill_signal : SIGKILL; + state == SWAP_DEACTIVATING_SIGTERM) ? s->kill_context.kill_signal : SIGKILL; if (s->control_pid > 0) { if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH) @@ -653,7 +655,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) { wait_for_exit = true; } - if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) { + if (s->kill_context.kill_mode == KILL_CONTROL_GROUP) { if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) { r = -ENOMEM; @@ -993,7 +995,7 @@ static void swap_timer_event(Unit *u, uint64_t elapsed, Watch *w) { break; case SWAP_ACTIVATING_SIGTERM: - if (s->exec_context.send_sigkill) { + if (s->kill_context.send_sigkill) { log_warning("%s activation timed out. Killing.", u->id); swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT); } else { @@ -1003,7 +1005,7 @@ static void swap_timer_event(Unit *u, uint64_t elapsed, Watch *w) { break; case SWAP_DEACTIVATING_SIGTERM: - if (s->exec_context.send_sigkill) { + if (s->kill_context.send_sigkill) { log_warning("%s deactivation timed out. Killing.", u->id); swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT); } else { diff --git a/src/core/swap.h b/src/core/swap.h index d8888e1768..35d47fd46f 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -87,6 +87,7 @@ struct Swap { ExecCommand exec_command[_SWAP_EXEC_COMMAND_MAX]; ExecContext exec_context; + KillContext kill_context; SwapState state, deserialized_state; -- cgit v1.2.3-54-g00ecf From 85e9a1010d16064ce435b84f02dc585bc645aade Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Fri, 20 Jul 2012 15:55:01 +0200 Subject: systemd: added new dependency PartOf This should address TODO item "new dependency type to "group" services in a target". Semantic of new dependency is as follows. Once configured it creates dependency which will cause that all dependent units get stopped if unit they all depend on is stopped or restarted. Usual use case would be configuring PartOf=some.target in template unit file and WantedBy=some.target in [Install] section and enabling desired number of instances. In this case starting one instance won't pull in target but stopping or starting target(in case of WantedBy is properly configured) will cause stop/start of all instances. --- man/systemd.unit.xml | 15 +++++++++++++++ src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/transaction.c | 12 ++++++++++++ src/core/unit.c | 3 ++- src/core/unit.h | 2 ++ 5 files changed, 32 insertions(+), 1 deletion(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 286862006a..bdd8f7d701 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -441,6 +441,21 @@ systemd. + + PartOf= + + Configures dependency + on other unit. When systemd stops or + restarts unit listed here, stop or + restart is propagated to dependent + units. Note that this is one way + dependency and changes to dependent + units does not affect listed unit. If + something else is desired, please + use some other type of dependency. + + + Conflicts= diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index d6a4711a32..2b1cfa073c 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -112,6 +112,7 @@ Unit.PropagatesReloadTo, config_parse_unit_deps, UNIT_PROPAG Unit.PropagateReloadTo, config_parse_unit_deps, UNIT_PROPAGATES_RELOAD_TO, 0 Unit.ReloadPropagatedFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0 Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0 +Unit.PartOf, config_parse_unit_deps, UNIT_PART_OF, 0 Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, offsetof(Unit, requires_mounts_for) Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded) Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start) diff --git a/src/core/transaction.c b/src/core/transaction.c index a1cf706934..1f8d803aeb 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -994,6 +994,18 @@ int transaction_add_job_and_dependencies( dbus_error_free(e); } } + + SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) { + r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) + goto fail; + + if (e) + dbus_error_free(e); + } + } + } if (type == JOB_RELOAD) { diff --git a/src/core/unit.c b/src/core/unit.c index 7b2f597589..be75cd792d 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1610,7 +1610,8 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY, [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS, [UNIT_PROPAGATES_RELOAD_TO] = UNIT_RELOAD_PROPAGATED_FROM, - [UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO + [UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO, + [UNIT_PART_OF] = UNIT_CONSISTS_OF }; int r, q = 0, v = 0, w = 0; diff --git a/src/core/unit.h b/src/core/unit.h index 2102b7a570..89bd61c2d8 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -75,12 +75,14 @@ enum UnitDependency { UNIT_REQUISITE_OVERRIDABLE, UNIT_WANTS, UNIT_BINDS_TO, + UNIT_PART_OF, /* Inverse of the above */ UNIT_REQUIRED_BY, /* inverse of 'requires' and 'requisite' is 'required_by' */ UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' and 'requisite_overridable' is 'soft_required_by' */ UNIT_WANTED_BY, /* inverse of 'wants' */ UNIT_BOUND_BY, /* inverse of 'binds_to' */ + UNIT_CONSISTS_OF, /* inverse of 'part_of' */ /* Negative dependencies */ UNIT_CONFLICTS, /* inverse of 'conflicts' is 'conflicted_by' */ -- cgit v1.2.3-54-g00ecf From d568a3350ee8a45877eef87cd026a954124e2cf8 Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Tue, 7 Aug 2012 14:41:48 +0200 Subject: systemd: introduced new timeout types Makes possible to specify separate timeout for start and stop of the service. [ Improved the manpage. Coding style fix. -- michich ] --- man/systemd.service.xml | 46 ++++++++++++++++++++++++++--------- src/core/dbus-service.c | 4 ++- src/core/load-fragment-gperf.gperf.m4 | 4 ++- src/core/load-fragment.c | 12 ++++++--- src/core/service.c | 35 +++++++++++++++----------- src/core/service.h | 5 ++-- 6 files changed, 73 insertions(+), 33 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.service.xml b/man/systemd.service.xml index f43201dc7e..1946d85f48 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -463,27 +463,49 @@ - TimeoutSec= + TimeoutStartSec= Configures the time to - wait for start-up and stop. If a + wait for start-up. If a daemon service does not signal start-up completion within the - configured time the service will be + configured time, the service will be considered failed and be shut down - again. If a service is asked to stop - but does not terminate in the - specified time it will be terminated + again. + Takes a unit-less value in seconds, or a + time span value such as "5min + 20s". Pass 0 to disable the timeout + logic. Defaults to 90s, except when + Type=oneshot is + used in which case the timeout + is disabled by default. + + + + + TimeoutStopSec= + Configures the time to + wait for stop. If a service is asked + to stop but does not terminate in the + specified time, it will be terminated forcibly via SIGTERM, and after another delay of this time with - SIGKILL. (See + SIGKILL (See KillMode= - in systemd.kill5) Takes a unit-less value in seconds, or a + in systemd.kill5). + Takes a unit-less value in seconds, or a time span value such as "5min 20s". Pass 0 to disable the timeout - logic. Defaults to - 90s, except when Type=oneshot is - used in which case the timeout - is disabled by default. + logic. Defaults to 90s. + + + + + TimeoutSec= + A shorthand for configuring + both TimeoutStartSec= + and TimeoutStopSec= + to the specified value. + diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index c0fac16d2b..129e131a65 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -115,7 +115,9 @@ static const BusProperty bus_service_properties[] = { { "PIDFile", bus_property_append_string, "s", offsetof(Service, pid_file), true }, { "NotifyAccess", bus_service_append_notify_access, "s", offsetof(Service, notify_access) }, { "RestartUSec", bus_property_append_usec, "t", offsetof(Service, restart_usec) }, - { "TimeoutUSec", bus_property_append_usec, "t", offsetof(Service, timeout_usec) }, + { "TimeoutUSec", bus_property_append_usec, "t", offsetof(Service, timeout_start_usec) }, + { "TimeoutStartUSec", bus_property_append_usec, "t", offsetof(Service, timeout_start_usec) }, + { "TimeoutStopUSec", bus_property_append_usec, "t", offsetof(Service, timeout_stop_usec) }, { "WatchdogUSec", bus_property_append_usec, "t", offsetof(Service, watchdog_usec) }, { "WatchdogTimestamp", bus_property_append_usec, "t", offsetof(Service, watchdog_timestamp.realtime) }, { "WatchdogTimestampMonotonic",bus_property_append_usec, "t", offsetof(Service, watchdog_timestamp.monotonic) }, diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 2b1cfa073c..e738213e27 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -145,7 +145,9 @@ Service.ExecReload, config_parse_exec, SERVICE_EXE Service.ExecStop, config_parse_exec, SERVICE_EXEC_STOP, offsetof(Service, exec_command) Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command) Service.RestartSec, config_parse_usec, 0, offsetof(Service, restart_usec) -Service.TimeoutSec, config_parse_service_timeout, 0, offsetof(Service, timeout_usec) +Service.TimeoutSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec) +Service.TimeoutStartSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec) +Service.TimeoutStopSec, config_parse_service_timeout, 0, offsetof(Service, timeout_stop_usec) Service.WatchdogSec, config_parse_usec, 0, offsetof(Service, watchdog_usec) Service.StartLimitInterval, config_parse_usec, 0, offsetof(Service, start_limit.interval) Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index bbd82b9d24..10681307cf 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1376,10 +1376,16 @@ int config_parse_service_timeout( r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata); - if (!r) - s->timeout_defined = true; + if (r) + return r; - return r; + if (streq(lvalue, "TimeoutSec")) { + s->start_timeout_defined = true; + s->timeout_stop_usec = s->timeout_start_usec; + } else if (streq(lvalue, "TimeoutStartSec")) + s->start_timeout_defined = true; + + return 0; } int config_parse_unit_env_file( diff --git a/src/core/service.c b/src/core/service.c index 1c127bdbcb..e74da54eac 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -134,7 +134,8 @@ static void service_init(Unit *u) { assert(u); assert(u->load_state == UNIT_STUB); - s->timeout_usec = DEFAULT_TIMEOUT_USEC; + s->timeout_start_usec = DEFAULT_TIMEOUT_USEC; + s->timeout_stop_usec = DEFAULT_TIMEOUT_USEC; s->restart_usec = DEFAULT_RESTART_USEC; s->type = _SERVICE_TYPE_INVALID; @@ -914,9 +915,13 @@ static int service_load_sysv_path(Service *s, const char *path) { UNIT(s)->default_dependencies = false; /* Don't timeout special services during boot (like fsck) */ - s->timeout_usec = 0; - } else - s->timeout_usec = DEFAULT_SYSV_TIMEOUT_USEC; + s->timeout_start_usec = 0; + s->timeout_stop_usec = 0; + } else { + s->timeout_start_usec = DEFAULT_SYSV_TIMEOUT_USEC; + s->timeout_stop_usec = DEFAULT_SYSV_TIMEOUT_USEC; + } + /* Special setting for all SysV services */ s->type = SERVICE_FORKING; @@ -1241,9 +1246,9 @@ static int service_load(Unit *u) { if (s->type == _SERVICE_TYPE_INVALID) s->type = s->bus_name ? SERVICE_DBUS : SERVICE_SIMPLE; - /* Oneshot services have disabled timeout by default */ - if (s->type == SERVICE_ONESHOT && !s->timeout_defined) - s->timeout_usec = 0; + /* Oneshot services have disabled start timeout by default */ + if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined) + s->timeout_start_usec = 0; service_fix_output(s); @@ -1603,11 +1608,10 @@ static int service_coldplug(Unit *u) { s->deserialized_state == SERVICE_FINAL_SIGTERM || s->deserialized_state == SERVICE_FINAL_SIGKILL || s->deserialized_state == SERVICE_AUTO_RESTART) { - - if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_usec > 0) { + if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_start_usec > 0) { usec_t k; - k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_usec; + k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_start_usec; if ((r = unit_watch_timer(UNIT(s), k, &s->timer_watch)) < 0) return r; @@ -1753,8 +1757,9 @@ static int service_spawn( } } - if (timeout && s->timeout_usec) { - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) + if (timeout && s->timeout_start_usec) { + r = unit_watch_timer(UNIT(s), s->timeout_start_usec, &s->timer_watch); + if (r < 0) goto fail; } else unit_unwatch_timer(UNIT(s), &s->timer_watch); @@ -2011,9 +2016,11 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f } if (wait_for_exit) { - if (s->timeout_usec > 0) - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) + if (s->timeout_stop_usec > 0) { + r = unit_watch_timer(UNIT(s), s->timeout_stop_usec, &s->timer_watch); + if (r < 0) goto fail; + } service_set_state(s, state); } else if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL) diff --git a/src/core/service.h b/src/core/service.h index cc63347c76..c78de79a09 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -120,7 +120,8 @@ struct Service { char *pid_file; usec_t restart_usec; - usec_t timeout_usec; + usec_t timeout_start_usec; + usec_t timeout_stop_usec; dual_timestamp watchdog_timestamp; usec_t watchdog_usec; @@ -166,7 +167,7 @@ struct Service { bool bus_name_good:1; bool forbid_restart:1; bool got_socket_fd:1; - bool timeout_defined:1; + bool start_timeout_defined:1; #ifdef HAVE_SYSV_COMPAT bool is_sysv:1; bool sysv_has_lsb:1; -- cgit v1.2.3-54-g00ecf From 96342de68d0d6de71a062d984dafd2a0905ed9fe Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Mon, 13 Aug 2012 13:58:01 +0200 Subject: service: add options RestartPreventExitStatus and SuccessExitStatus In some cases, like wrong configuration, restarting after error does not help, so administrator can specify statuses by RestartPreventExitStatus which will not cause restart of a service. Sometimes you have non-standart exit status, so this can be specified by SuccessfulExitStatus. --- man/systemd.service.xml | 14 +++++++ src/core/load-fragment-gperf.gperf.m4 | 2 + src/core/mount.c | 2 +- src/core/service.c | 20 +++++++++- src/core/service.h | 3 ++ src/core/socket.c | 2 +- src/core/swap.c | 2 +- src/remount-fs/remount-fs.c | 2 +- src/shared/conf-parser.c | 70 +++++++++++++++++++++++++++++++++++ src/shared/conf-parser.h | 1 + src/shared/exit-status.c | 16 +++++--- src/shared/exit-status.h | 11 ++++-- src/shared/hashmap.c | 15 ++++++++ src/shared/hashmap.h | 1 + src/shared/set.c | 4 ++ src/shared/set.h | 1 + src/shared/util.c | 2 +- src/systemctl/systemctl.c | 2 +- 18 files changed, 154 insertions(+), 16 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 1946d85f48..c4bd65e349 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -579,6 +579,20 @@ hit a timeout. + + RestartPreventExitStatus= + Specify exit status list, which + will prevent service from restart. Codes are + separated by whitespace (e.g. "1 6 SIGKILL"). + + + + SuccessExitStatus= + Specify exit status list, which + will be considered as successful exit. Codes are + separated by whitespace (e.g. "1 6 SIGKILL"). + + PermissionsStartOnly= Takes a boolean diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index e738213e27..84eea1c465 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -158,6 +158,8 @@ Service.PermissionsStartOnly, config_parse_bool, 0, Service.RootDirectoryStartOnly, config_parse_bool, 0, offsetof(Service, root_directory_start_only) Service.RemainAfterExit, config_parse_bool, 0, offsetof(Service, remain_after_exit) Service.GuessMainPID, config_parse_bool, 0, offsetof(Service, guess_main_pid) +Service.RestartPreventExitStatus, config_parse_set_status, 0, offsetof(Service, restart_ignore_status) +Service.SuccessExitStatus, config_parse_set_status, 0, offsetof(Service, success_status) m4_ifdef(`HAVE_SYSV_COMPAT', `Service.SysVStartPriority, config_parse_sysv_priority, 0, offsetof(Service, sysv_start_priority)', `Service.SysVStartPriority, config_parse_warn_compat, 0, 0') diff --git a/src/core/mount.c b/src/core/mount.c index 83e51a7aba..fc981c74f4 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1225,7 +1225,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { m->control_pid = 0; - if (is_clean_exit(code, status)) + if (is_clean_exit(code, status, NULL)) f = MOUNT_SUCCESS; else if (code == CLD_EXITED) f = MOUNT_FAILURE_EXIT_CODE; diff --git a/src/core/service.c b/src/core/service.c index e74da54eac..f540752b61 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -294,6 +294,16 @@ static void service_done(Unit *u) { s->control_command = NULL; s->main_command = NULL; + set_free(s->restart_ignore_status.code); + s->restart_ignore_status.code = NULL; + set_free(s->restart_ignore_status.signal); + s->restart_ignore_status.signal = NULL; + + set_free(s->success_status.code); + s->success_status.code = NULL; + set_free(s->success_status.signal); + s->success_status.signal = NULL; + /* This will leak a process, but at least no memory or any of * our resources */ service_unwatch_main_pid(s); @@ -1902,7 +1912,12 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) (s->restart == SERVICE_RESTART_ON_SUCCESS && s->result == SERVICE_SUCCESS) || (s->restart == SERVICE_RESTART_ON_FAILURE && s->result != SERVICE_SUCCESS) || (s->restart == SERVICE_RESTART_ON_ABORT && (s->result == SERVICE_FAILURE_SIGNAL || - s->result == SERVICE_FAILURE_CORE_DUMP)))) { + s->result == SERVICE_FAILURE_CORE_DUMP))) && + (s->result != SERVICE_FAILURE_EXIT_CODE || + !set_contains(s->restart_ignore_status.code, INT_TO_PTR(s->main_exec_status.status))) && + (s->result != SERVICE_FAILURE_SIGNAL || + !set_contains(s->restart_ignore_status.signal, INT_TO_PTR(s->main_exec_status.status))) + ) { r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch); if (r < 0) @@ -2874,7 +2889,8 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { assert(s); assert(pid >= 0); - if (UNIT(s)->fragment_path ? is_clean_exit(code, status) : is_clean_exit_lsb(code, status)) + if (UNIT(s)->fragment_path ? is_clean_exit(code, status, &s->success_status) : + is_clean_exit_lsb(code, status, &s->success_status)) f = SERVICE_SUCCESS; else if (code == CLD_EXITED) f = SERVICE_FAILURE_EXIT_CODE; diff --git a/src/core/service.h b/src/core/service.h index c78de79a09..2a4dc30d0b 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -28,6 +28,7 @@ typedef struct Service Service; #include "ratelimit.h" #include "service.h" #include "kill.h" +#include "exit-status.h" typedef enum ServiceState { SERVICE_DEAD, @@ -115,6 +116,8 @@ struct Service { ServiceType type; ServiceRestart restart; + ExitStatusSet restart_ignore_status; + ExitStatusSet success_status; /* If set we'll read the main daemon PID from this file */ char *pid_file; diff --git a/src/core/socket.c b/src/core/socket.c index 837b166e3b..cbbfb0cd3a 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1884,7 +1884,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) { s->control_pid = 0; - if (is_clean_exit(code, status)) + if (is_clean_exit(code, status, NULL)) f = SOCKET_SUCCESS; else if (code == CLD_EXITED) f = SOCKET_FAILURE_EXIT_CODE; diff --git a/src/core/swap.c b/src/core/swap.c index 458e00efe5..cd4d9ab3d7 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -917,7 +917,7 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) { s->control_pid = 0; - if (is_clean_exit(code, status)) + if (is_clean_exit(code, status, NULL)) f = SWAP_SUCCESS; else if (code == CLD_EXITED) f = SWAP_FAILURE_EXIT_CODE; diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c index 636c46f0f3..b49d095cbb 100644 --- a/src/remount-fs/remount-fs.c +++ b/src/remount-fs/remount-fs.c @@ -145,7 +145,7 @@ int main(int argc, char *argv[]) { s = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)); if (s) { - if (!is_clean_exit(si.si_code, si.si_status)) { + if (!is_clean_exit(si.si_code, si.si_status, NULL)) { if (si.si_code == CLD_EXITED) log_error("/bin/mount for %s exited with exit status %i.", s, si.si_status); else diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 1eccec5989..595bb51a27 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -32,6 +32,8 @@ #include "log.h" #include "utf8.h" #include "path-util.h" +#include "set.h" +#include "exit-status.h" int config_item_table_lookup( void *table, @@ -933,3 +935,71 @@ int config_parse_level( *o = (*o & LOG_FACMASK) | x; return 0; } + +int config_parse_set_status( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char *w; + size_t l; + char *state; + int r; + ExitStatusSet *status_set = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + FOREACH_WORD(w, l, rvalue, state) { + int val; + char *temp = strndup(w, l); + if (!temp) + return log_oom(); + + r = safe_atoi(temp, &val); + if (r < 0) { + val = signal_from_string_try_harder(temp); + free(temp); + if (val > 0) { + if (!status_set->signal) { + status_set->signal = set_new(trivial_hash_func, trivial_compare_func); + if (!status_set->signal) + return log_oom(); + } + r = set_put(status_set->signal, INT_TO_PTR(val)); + if (r < 0) { + log_error("[%s:%u] Unable to store: %s", filename, line, w); + return r; + } + } else { + log_error("[%s:%u] Failed to parse value: %s", filename, line, w); + return r; + } + } else { + free(temp); + if(val < 0 || val > 255) + log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename, line, val); + else { + if (!status_set->code) { + status_set->code = set_new(trivial_hash_func, trivial_compare_func); + if (!status_set->code) + return log_oom(); + } + r = set_put(status_set->code, INT_TO_PTR(val)); + if (r < 0) { + log_error("[%s:%u] Unable to store: %s", filename, line, w); + return r; + } + } + } + + } + return 0; +} diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 4f94b3b907..56ffc2f8a8 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -105,6 +105,7 @@ int config_parse_nsec(const char *filename, unsigned line, const char *section, int config_parse_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_facility(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_level(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_set_status(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); #define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \ int function( \ diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c index 0dc82b2e13..45131f2b2a 100644 --- a/src/shared/exit-status.c +++ b/src/shared/exit-status.c @@ -23,6 +23,8 @@ #include #include "exit-status.h" +#include "set.h" +#include "macro.h" const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { @@ -158,10 +160,12 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { } -bool is_clean_exit(int code, int status) { +bool is_clean_exit(int code, int status, ExitStatusSet *success_status) { if (code == CLD_EXITED) - return status == 0; + return status == 0 || + (success_status && + set_contains(success_status->code, INT_TO_PTR(status))); /* If a daemon does not implement handlers for some of the * signals that's not considered an unclean shutdown */ @@ -170,14 +174,16 @@ bool is_clean_exit(int code, int status) { status == SIGHUP || status == SIGINT || status == SIGTERM || - status == SIGPIPE; + status == SIGPIPE || + (success_status && + set_contains(success_status->signal, INT_TO_PTR(status))); return false; } -bool is_clean_exit_lsb(int code, int status) { +bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status) { - if (is_clean_exit(code, status)) + if (is_clean_exit(code, status, success_status)) return true; return diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h index 3f42c15e3b..d3b548fc96 100644 --- a/src/shared/exit-status.h +++ b/src/shared/exit-status.h @@ -22,7 +22,7 @@ ***/ #include - +#include "set.h" typedef enum ExitStatus { /* EXIT_SUCCESS defined by libc */ /* EXIT_FAILURE defined by libc */ @@ -77,7 +77,12 @@ typedef enum ExitStatusLevel { EXIT_STATUS_FULL = EXIT_STATUS_LSB } ExitStatusLevel; +typedef struct ExitStatusSet { + Set *code; + Set *signal; +} ExitStatusSet; + const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level); -bool is_clean_exit(int code, int status); -bool is_clean_exit_lsb(int code, int status); +bool is_clean_exit(int code, int status, ExitStatusSet *success_status); +bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status); diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c index e2395d4d42..be37a3659d 100644 --- a/src/shared/hashmap.c +++ b/src/shared/hashmap.c @@ -378,6 +378,21 @@ void* hashmap_get(Hashmap *h, const void *key) { return e->value; } +bool hashmap_contains(Hashmap *h, const void *key) { + unsigned hash; + struct hashmap_entry *e; + + if (!h) + return false; + + hash = h->hash_func(key) % NBUCKETS; + + if (!(e = hash_scan(h, hash, key))) + return false; + + return true; +} + void* hashmap_remove(Hashmap *h, const void *key) { struct hashmap_entry *e; unsigned hash; diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h index ee810f5ae1..504f0b7637 100644 --- a/src/shared/hashmap.h +++ b/src/shared/hashmap.h @@ -53,6 +53,7 @@ int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t int hashmap_put(Hashmap *h, const void *key, void *value); int hashmap_replace(Hashmap *h, const void *key, void *value); void* hashmap_get(Hashmap *h, const void *key); +bool hashmap_contains(Hashmap *h, const void *key); void* hashmap_remove(Hashmap *h, const void *key); void* hashmap_remove_value(Hashmap *h, const void *key, void *value); int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value); diff --git a/src/shared/set.c b/src/shared/set.c index f5c7c37cab..4d56c4f505 100644 --- a/src/shared/set.c +++ b/src/shared/set.c @@ -57,6 +57,10 @@ void *set_get(Set *s, void *value) { return hashmap_get(MAKE_HASHMAP(s), value); } +bool set_contains(Set *s, void *value) { + return hashmap_contains(MAKE_HASHMAP(s), value); +} + void *set_remove(Set *s, void *value) { return hashmap_remove(MAKE_HASHMAP(s), value); } diff --git a/src/shared/set.h b/src/shared/set.h index c7b6231eed..a6c1d76b0e 100644 --- a/src/shared/set.h +++ b/src/shared/set.h @@ -40,6 +40,7 @@ int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_ int set_put(Set *s, void *value); int set_replace(Set *s, void *value); void *set_get(Set *s, void *value); +bool set_contains(Set *s, void *value); void *set_remove(Set *s, void *value); int set_remove_and_put(Set *s, void *old_value, void *new_value); diff --git a/src/shared/util.c b/src/shared/util.c index e615195af5..cbf44ebdfd 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -4357,7 +4357,7 @@ void execute_directory(const char *directory, DIR *d, char *argv[]) { } if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) { - if (!is_clean_exit(si.si_code, si.si_status)) { + if (!is_clean_exit(si.si_code, si.si_status, NULL)) { if (si.si_code == CLD_EXITED) log_error("%s exited with exit status %i.", path, si.si_status); else diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 13e0f91096..2481849232 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2148,7 +2148,7 @@ static void print_status_info(UnitStatusInfo *i) { printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t)); free(t); - good = is_clean_exit_lsb(p->code, p->status); + good = is_clean_exit_lsb(p->code, p->status, NULL); if (!good) { on = ansi_highlight_red(true); off = ansi_highlight_red(false); -- cgit v1.2.3-54-g00ecf From c0d6e764d107a81a6439c41edbe92790623ed7de Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Aug 2012 01:51:53 +0200 Subject: unit: add new ConditionHost= condition type --- TODO | 4 +- man/systemd.unit.xml | 112 +++++++++++++++++++++++----------- src/core/condition.c | 31 ++++++++++ src/core/condition.h | 1 + src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/load-fragment.c | 11 ++-- 6 files changed, 120 insertions(+), 40 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/TODO b/TODO index 7f53535401..28141ec68c 100644 --- a/TODO +++ b/TODO @@ -49,6 +49,8 @@ Bugfixes: Features: +* There's something wrong with escaping unit names: http://lists.freedesktop.org/archives/systemd-devel/2012-August/006292.html + * cleanup ellipsation for log output in journalctl and systemctl status: have a sane way to disable ellipsation, and disable it by default when invoked in less/more * enforce limits on fds openened by socket units @@ -59,8 +61,6 @@ Features: * testing tool for socket activation: some binary that listens on a socket and passes it on using the usual socket activation protocol to some server. -* ConditionHost= for filtering services for clusters - * journald: add symlinks and device names to kernel messages * maybe make systemd-detect-virt suid? or use fscaps? diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index da2dba52b3..bf22ca9bd0 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -586,7 +586,7 @@ RequiresMountsFor= Takes a space - separated list of paths. Automatically + separated list of absolute paths. Automatically adds dependencies of type Requires= and After= for all @@ -760,65 +760,86 @@ ConditionVirtualization= ConditionSecurity= ConditionCapability= + ConditionHost= ConditionNull= Before starting a unit verify that the specified condition is - true. With + true. If it is not true the starting + of the unit will be skipped, however + all ordering dependencies of it are + still respected. A failing condition + will not result in the unit being + moved into a failure state. The + condition is checked at the time the + queued start job is to be + executed. + + With ConditionPathExists= - a file existence condition can be + a file existence condition is checked before a unit is started. If the specified absolute path name does - not exist, startup of a unit will not - actually happen, however the unit is - still useful for ordering purposes in - this case. The condition is checked at - the time the queued start job is to be - executed. If the absolute path name - passed to + not exist the condition will + fail. If the absolute path name passed + to ConditionPathExists= is prefixed with an exclamation mark - (!), the test is negated, and the unit + ('!'), the test is negated, and the unit is only started if the path does not - exist. - ConditionPathExistsGlob= - works in a similar way, but checks for - the existence of at least one file or - directory matching the specified - globbing - pattern. ConditionPathIsDirectory= + exist. + + ConditionPathExistsGlob= + is similar to + ConditionPathExists=, + but checks for the existence of at + least one file or directory matching + the specified globbing pattern. + + ConditionPathIsDirectory= is similar to ConditionPathExists= but verifies whether a certain path exists and is a - directory. ConditionPathIsSymbolicLink= + directory. + + ConditionPathIsSymbolicLink= is similar to ConditionPathExists= but verifies whether a certain path exists and is a symbolic - link. ConditionPathIsMountPoint= + link. + + ConditionPathIsMountPoint= is similar to ConditionPathExists= but verifies whether a certain path exists and is a mount - point. ConditionPathIsReadWrite= + point. + + ConditionPathIsReadWrite= is similar to ConditionPathExists= but verifies whether the underlying - file system is read and writable + file system is readable and writable (i.e. not mounted - read-only). ConditionFileIsExecutable= + read-only). + + ConditionFileIsExecutable= is similar to ConditionPathExists= but verifies whether a certain path exists, is a regular file and marked - executable. - ConditionDirectoryNotEmpty= + executable. + + ConditionDirectoryNotEmpty= is similar to ConditionPathExists= but verifies whether a certain path exists and is a non-empty - directory. Similarly + directory. + + Similarly, ConditionKernelCommandLine= may be used to check whether a specific kernel command line option is @@ -826,14 +847,16 @@ exclamation mark unset). The argument must either be a single word, or an assignment (i.e. two words, separated - by the equality sign). In the former + '='). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case the exact assignment is looked for with right and left hand side - matching. ConditionVirtualization= + matching. + + ConditionVirtualization= may be used to check whether the system is executed in a virtualized environment and optionally test @@ -843,7 +866,7 @@ any virtualized environment, or one of vm and container to test - against a specific type of + against a generic type of virtualization solution, or one of qemu, kvm, @@ -862,15 +885,18 @@ virtualization technologies are nested only the innermost is considered. The test may be negated by prepending an - exclamation mark. - ConditionSecurity= + exclamation mark. + + ConditionSecurity= may be used to check whether the given security module is enabled on the system. Currently the only recognized value is selinux. The test may be negated by prepending an exclamation - mark. ConditionCapability= + mark. + + ConditionCapability= may be used to check whether the given capability exists in the capability bounding set of the service manager @@ -881,14 +907,32 @@ for details). Pass a capability name such as CAP_MKNOD, possibly prefixed with an exclamation - mark to negate the check. Finally, + mark to negate the check. + + ConditionHost= + may be used to match against the + host name or machine ID of the + host. This either takes a host name + string (optionally with shell style + globs) which is tested against the + locally set host name as returned by + gethostname2, + or a machine ID formatted as string + (see + machine-id5). + The test may be negated by prepending + an exclamation mark. + + Finally, ConditionNull= may be used to add a constant condition check value to the unit. It takes a boolean argument. If set to false the condition will always fail, otherwise - succeed. If multiple conditions are + succeed. + + If multiple conditions are specified the unit will be executed if all of them apply (i.e. a logical AND is applied). Condition checks can be diff --git a/src/core/condition.c b/src/core/condition.c index e4080d569d..e5cda21c37 100644 --- a/src/core/condition.c +++ b/src/core/condition.c @@ -25,11 +25,13 @@ #include #include #include +#include #ifdef HAVE_SELINUX #include #endif +#include #include "util.h" #include "condition.h" #include "virt.h" @@ -194,6 +196,31 @@ static bool test_capability(const char *parameter) { return !!(capabilities & (1ULL << value)); } +static bool test_host(const char *parameter) { + sd_id128_t x, y; + char *h; + int r; + bool b; + + if (sd_id128_from_string(parameter, &x) >= 0) { + + r = sd_id128_get_machine(&y); + if (r < 0) + return false; + + return sd_id128_equal(x, y); + } + + h = gethostname_malloc(); + if (!h) + return false; + + b = fnmatch(parameter, h, FNM_CASEFOLD) == 0; + free(h); + + return b; +} + bool condition_test(Condition *c) { assert(c); @@ -255,6 +282,9 @@ bool condition_test(Condition *c) { case CONDITION_CAPABILITY: return test_capability(c->parameter) == !c->negate; + case CONDITION_HOST: + return test_host(c->parameter) == !c->negate; + case CONDITION_NULL: return !c->negate; @@ -323,6 +353,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine", [CONDITION_VIRTUALIZATION] = "ConditionVirtualization", [CONDITION_SECURITY] = "ConditionSecurity", + [CONDITION_HOST] = "ConditionHost", [CONDITION_NULL] = "ConditionNull" }; diff --git a/src/core/condition.h b/src/core/condition.h index 3dca432f77..55b331edd7 100644 --- a/src/core/condition.h +++ b/src/core/condition.h @@ -38,6 +38,7 @@ typedef enum ConditionType { CONDITION_VIRTUALIZATION, CONDITION_SECURITY, CONDITION_CAPABILITY, + CONDITION_HOST, CONDITION_NULL, _CONDITION_TYPE_MAX, _CONDITION_TYPE_INVALID = -1 diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 84eea1c465..8187cd48c6 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -135,6 +135,7 @@ Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_K Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0 Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, 0 Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 0 +Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, 0 Unit.ConditionNull, config_parse_unit_condition_null, 0, 0 m4_dnl Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 10681307cf..9438aa312b 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1516,14 +1516,17 @@ int config_parse_unit_condition_string( assert(rvalue); assert(data); - if ((trigger = rvalue[0] == '|')) + trigger = rvalue[0] == '|'; + if (trigger) rvalue++; - if ((negate = rvalue[0] == '!')) + negate = rvalue[0] == '!'; + if (negate) rvalue++; - if (!(c = condition_new(cond, rvalue, trigger, negate))) - return -ENOMEM; + c = condition_new(cond, rvalue, trigger, negate); + if (!c) + return log_oom(); LIST_PREPEND(Condition, conditions, u->conditions, c); return 0; -- cgit v1.2.3-54-g00ecf From 0eb59ccfe619cbc4b42ef8ff02b52971994dfe05 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 29 Oct 2012 15:30:05 -0700 Subject: SMACK: Add configuration options. (v3) This adds SMACK label configuration options to socket units. SMACK labels should be applied to most objects on disk well before execution time, but two items remain that are generated dynamically at run time that require SMACK labels to be set in order to enforce MAC on all objects. Files on disk can be labelled using package management. For device nodes, simple udev rules are sufficient to add SMACK labels at boot/insertion time. Sockets can be created at run time and systemd does just that for several services. In order to protect FIFO's and UNIX domain sockets, we must instruct systemd to apply SMACK labels at runtime. This patch adds the following options: Smack - applicable to FIFO's. SmackIpIn/SmackIpOut - applicable to sockets. No external dependencies are required to support SMACK, as setting the labels is done using fsetxattr(). The labels can be set on a kernel that does not have SMACK enabled either, so there is no need to #ifdef any of this code out. For more information about SMACK, please see Documentation/Smack.txt in the kernel source code. v3 of this patch changes the config options to be CamelCased. --- man/systemd.socket.xml | 20 ++++++++++++++++++++ src/core/dbus-socket.c | 6 ++++++ src/core/load-fragment-gperf.gperf.m4 | 3 +++ src/core/socket.c | 32 ++++++++++++++++++++++++++++++++ src/core/socket.h | 4 ++++ 5 files changed, 65 insertions(+) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 9db39b1de9..ae8497e8ab 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -484,6 +484,26 @@ for details. + + SmackLabel= + SmackLabelIPIn= + SmackLabelIPOut= + Takes a string + value. Controls the extended + attributes + security.SMACK64, + security.SMACK64IPIN + and + security.SMACK64IPOUT, + respectively, i.e. the security label + of the FIFO, or the security label for + the incoming or outgoing connections + of the socket, respectively. See + Smack.txt + for details. + + PipeSize= Takes an integer diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index c57cce19fb..095a031612 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -63,6 +63,9 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ #define INTROSPECTION \ @@ -126,6 +129,9 @@ static const BusProperty bus_socket_properties[] = { { "MessageQueueMaxMessages", bus_property_append_long, "x", offsetof(Socket, mq_maxmsg) }, { "MessageQueueMessageSize", bus_property_append_long, "x", offsetof(Socket, mq_msgsize) }, { "Result", bus_socket_append_socket_result, "s", offsetof(Socket, result) }, + { "SmackLabel", bus_property_append_string, "s", offsetof(Socket, smack), true }, + { "SmackLabelIPIn", bus_property_append_string, "s", offsetof(Socket, smack_ip_in), true }, + { "SmackLabelIPOut",bus_property_append_string, "s", offsetof(Socket, smack_ip_out), true }, { NULL, } }; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 8187cd48c6..0c5ccebd73 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -208,6 +208,9 @@ Socket.TCPCongestion, config_parse_string, 0, Socket.MessageQueueMaxMessages, config_parse_long, 0, offsetof(Socket, mq_maxmsg) Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize) Socket.Service, config_parse_socket_service, 0, 0 +Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack) +Socket.SmackLabelIPIn, config_parse_string, 0, offsetof(Socket, smack_ip_in) +Socket.SmackLabelIPOut, config_parse_string, 0, offsetof(Socket, smack_ip_out) EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl KILL_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl m4_dnl diff --git a/src/core/socket.c b/src/core/socket.c index 71cdf2dfc8..c0959815c1 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "unit.h" #include "socket.h" @@ -131,6 +132,10 @@ static void socket_done(Unit *u) { free(s->bind_to_device); s->bind_to_device = NULL; + free(s->smack); + free(s->smack_ip_in); + free(s->smack_ip_out); + unit_unwatch_timer(u, &s->timer_watch); } @@ -508,6 +513,21 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sMessageQueueMessageSize: %li\n", prefix, s->mq_msgsize); + if (s->smack) + fprintf(f, + "%sSmackLabel: %s\n", + prefix, s->smack); + + if (s->smack_ip_in) + fprintf(f, + "%sSmackLabelIPIn: %s\n", + prefix, s->smack_ip_in); + + if (s->smack_ip_out) + fprintf(f, + "%sSmackLabelIPOut: %s\n", + prefix, s->smack_ip_out); + LIST_FOREACH(port, p, s->ports) { if (p->type == SOCKET_SOCKET) { @@ -747,6 +767,14 @@ static void socket_apply_socket_options(Socket *s, int fd) { if (s->tcp_congestion) if (setsockopt(fd, SOL_TCP, TCP_CONGESTION, s->tcp_congestion, strlen(s->tcp_congestion)+1) < 0) log_warning("TCP_CONGESTION failed: %m"); + + if (s->smack_ip_in) + if (fsetxattr(fd, "security.SMACK64IPIN", s->smack_ip_in, strlen(s->smack_ip_in), 0) < 0) + log_error("fsetxattr(\"security.SMACK64IPIN\"): %m"); + + if (s->smack_ip_out) + if (fsetxattr(fd, "security.SMACK64IPOUT", s->smack_ip_out, strlen(s->smack_ip_out), 0) < 0) + log_error("fsetxattr(\"security.SMACK64IPOUT\"): %m"); } static void socket_apply_fifo_options(Socket *s, int fd) { @@ -756,6 +784,10 @@ static void socket_apply_fifo_options(Socket *s, int fd) { if (s->pipe_size > 0) if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0) log_warning("F_SETPIPE_SZ: %m"); + + if (s->smack) + if (fsetxattr(fd, "security.SMACK64", s->smack, strlen(s->smack), 0) < 0) + log_error("fsetxattr(\"security.SMACK64\"): %m"); } static int fifo_address_create( diff --git a/src/core/socket.h b/src/core/socket.h index a06b3eae94..f099520dce 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -144,6 +144,10 @@ struct Socket { /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */ SocketAddressBindIPv6Only bind_ipv6_only; + + char *smack; + char *smack_ip_in; + char *smack_ip_out; }; /* Called from the service code when collecting fds */ -- cgit v1.2.3-54-g00ecf From aea54018a5e66a41318afb6c6be745b6aef48d9e Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Mon, 5 Nov 2012 12:50:19 -0500 Subject: Implement SocketUser= and SocketGroup= for [Socket] Since we already allow defining the mode of AF_UNIX sockets and FIFO, it makes sense to also allow specific user/group ownership of the socket file for restricting access. --- man/systemd.socket.xml | 24 +++++++++++++ src/core/dbus-socket.c | 4 +++ src/core/load-fragment-gperf.gperf.m4 | 2 ++ src/core/socket.c | 67 +++++++++++++++++++++++++++++++++-- src/core/socket.h | 2 ++ src/shared/socket-label.c | 1 + 6 files changed, 97 insertions(+), 3 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 4b1fcc8b0c..dc0d78f0a2 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -357,6 +357,30 @@ 0666. + + SocketUser= + If listening on a file system + socket or FIFO, this option specifies the + user owner of the created socket. When + defining this, keep in mind that name + switch services for user name lookups may + not be available. It is advisable to use a + numeric UID for this + setting. + + + + SocketGroup= + If listening on a file system + socket or FIFO, this option specifies the + group owner of the created socket. When + defining this, keep in mind that name + switch services for group name lookups may + not be available. It is advisable to use a + numeric GID for this + setting. + + Accept= Takes a boolean diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 095a031612..887c80eb89 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -43,6 +43,8 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -109,6 +111,8 @@ static const BusProperty bus_socket_properties[] = { { "BindToDevice", bus_property_append_string, "s", offsetof(Socket, bind_to_device), true }, { "DirectoryMode", bus_property_append_mode, "u", offsetof(Socket, directory_mode) }, { "SocketMode", bus_property_append_mode, "u", offsetof(Socket, socket_mode) }, + { "SocketUser", bus_property_append_string, "s", offsetof(Socket, socket_user), true }, + { "SocketGroup", bus_property_append_string, "s", offsetof(Socket, socket_group), true }, { "Accept", bus_property_append_bool, "b", offsetof(Socket, accept) }, { "KeepAlive", bus_property_append_bool, "b", offsetof(Socket, keep_alive) }, { "Priority", bus_property_append_int, "i", offsetof(Socket, priority) }, diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 0c5ccebd73..b48e9e9f56 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -189,6 +189,8 @@ Socket.ExecStopPost, config_parse_exec, SOCKET_EXEC Socket.TimeoutSec, config_parse_usec, 0, offsetof(Socket, timeout_usec) Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode) Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode) +Socket.SocketUser, config_parse_string, 0, offsetof(Socket, socket_user) +Socket.SocketGroup, config_parse_string, 0, offsetof(Socket, socket_group) Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept) Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections) Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive) diff --git a/src/core/socket.c b/src/core/socket.c index c0959815c1..f3f09cac43 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -136,6 +136,12 @@ static void socket_done(Unit *u) { free(s->smack_ip_in); free(s->smack_ip_out); + free(s->socket_user); + s->socket_user = NULL; + + free(s->socket_group); + s->socket_group = NULL; + unit_unwatch_timer(u, &s->timer_watch); } @@ -449,6 +455,16 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(s->pass_sec), prefix, strna(s->tcp_congestion)); + if (s->socket_user) + fprintf(f, + "SocketUser: %s\n", + s->socket_user); + + if (s->socket_group) + fprintf(f, + "SocketGroup: %s\n", + s->socket_group); + if (s->control_pid > 0) fprintf(f, "%sControl PID: %lu\n", @@ -692,6 +708,9 @@ static void socket_close_fds(Socket *s) { } static void socket_apply_socket_options(Socket *s, int fd) { + uid_t uid = 0; + gid_t gid = 0; + assert(s); assert(fd >= 0); @@ -775,6 +794,21 @@ static void socket_apply_socket_options(Socket *s, int fd) { if (s->smack_ip_out) if (fsetxattr(fd, "security.SMACK64IPOUT", s->smack_ip_out, strlen(s->smack_ip_out), 0) < 0) log_error("fsetxattr(\"security.SMACK64IPOUT\"): %m"); + + if (s->socket_user && + get_user_creds((const char **)&s->socket_user, &uid, + NULL, NULL, NULL) < 0) { + log_warning("failed to lookup user: %s", s->socket_user); + } + + if (s->socket_group && + get_group_creds((const char **)&s->socket_group, &gid) < 0) { + log_warning("failed to lookup group: %s", s->socket_group); + } + + if ((uid != 0 || gid != 0) && fchown(fd, uid, gid) < 0) { + log_warning("failed to change ownership of socket"); + } } static void socket_apply_fifo_options(Socket *s, int fd) { @@ -794,11 +828,15 @@ static int fifo_address_create( const char *path, mode_t directory_mode, mode_t socket_mode, + const char *socket_user, + const char *socket_group, int *_fd) { int fd = -1, r = 0; struct stat st; mode_t old_mask; + uid_t uid = 0; + gid_t gid = 0; assert(path); assert(_fd); @@ -823,7 +861,8 @@ static int fifo_address_create( goto fail; } - if ((fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) { + fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW); + if (fd < 0) { r = -errno; goto fail; } @@ -835,15 +874,35 @@ static int fifo_address_create( goto fail; } + if (socket_user && + get_user_creds(&socket_user, &uid, NULL, NULL, NULL) < 0) { + r = -errno; + log_error("failed to lookup user: %s", socket_user); + goto fail; + } + + if (socket_group && + get_group_creds(&socket_group, &gid) < 0) { + r = -errno; + log_error("failed to lookup group: %s", socket_group); + goto fail; + } + if (!S_ISFIFO(st.st_mode) || (st.st_mode & 0777) != (socket_mode & ~old_mask) || - st.st_uid != getuid() || - st.st_gid != getgid()) { + st.st_uid != uid || + st.st_gid != gid) { r = -EEXIST; goto fail; } + if ((uid != 0 || gid != 0) && fchown(fd, uid, gid) < 0) { + r = -errno; + log_error("failed to changed ownership of FIFO: %s", path); + goto fail; + } + *_fd = fd; return 0; @@ -1013,6 +1072,8 @@ static int socket_open_fds(Socket *s) { p->path, s->directory_mode, s->socket_mode, + s->socket_user, + s->socket_group, &p->fd)) < 0) goto rollback; diff --git a/src/core/socket.h b/src/core/socket.h index f099520dce..a273ac2740 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -118,6 +118,8 @@ struct Socket { mode_t directory_mode; mode_t socket_mode; + char *socket_user; + char *socket_group; SocketResult result; diff --git a/src/shared/socket-label.c b/src/shared/socket-label.c index ff212de825..d105a66fe8 100644 --- a/src/shared/socket-label.c +++ b/src/shared/socket-label.c @@ -52,6 +52,7 @@ int socket_address_listen( int *ret) { int r, fd, one; + assert(a); assert(ret); -- cgit v1.2.3-54-g00ecf From e4f44e734c4f397ee5e7ba3270e014a8ae0043dd Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Tue, 6 Nov 2012 09:54:17 -0500 Subject: Revert "Implement SocketUser= and SocketGroup= for [Socket]" This was never intended to be pushed. This reverts commit aea54018a5e66a41318afb6c6be745b6aef48d9e. --- man/systemd.socket.xml | 24 ------------- src/core/dbus-socket.c | 4 --- src/core/load-fragment-gperf.gperf.m4 | 2 -- src/core/socket.c | 67 ++--------------------------------- src/core/socket.h | 2 -- src/shared/socket-label.c | 1 - 6 files changed, 3 insertions(+), 97 deletions(-) (limited to 'src/core/load-fragment-gperf.gperf.m4') diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index dc0d78f0a2..4b1fcc8b0c 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -357,30 +357,6 @@ 0666. - - SocketUser= - If listening on a file system - socket or FIFO, this option specifies the - user owner of the created socket. When - defining this, keep in mind that name - switch services for user name lookups may - not be available. It is advisable to use a - numeric UID for this - setting. - - - - SocketGroup= - If listening on a file system - socket or FIFO, this option specifies the - group owner of the created socket. When - defining this, keep in mind that name - switch services for group name lookups may - not be available. It is advisable to use a - numeric GID for this - setting. - - Accept= Takes a boolean diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 887c80eb89..095a031612 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -43,8 +43,6 @@ " \n" \ " \n" \ " \n" \ - " \n" \ - " \n" \ " \n" \ " \n" \ " \n" \ @@ -111,8 +109,6 @@ static const BusProperty bus_socket_properties[] = { { "BindToDevice", bus_property_append_string, "s", offsetof(Socket, bind_to_device), true }, { "DirectoryMode", bus_property_append_mode, "u", offsetof(Socket, directory_mode) }, { "SocketMode", bus_property_append_mode, "u", offsetof(Socket, socket_mode) }, - { "SocketUser", bus_property_append_string, "s", offsetof(Socket, socket_user), true }, - { "SocketGroup", bus_property_append_string, "s", offsetof(Socket, socket_group), true }, { "Accept", bus_property_append_bool, "b", offsetof(Socket, accept) }, { "KeepAlive", bus_property_append_bool, "b", offsetof(Socket, keep_alive) }, { "Priority", bus_property_append_int, "i", offsetof(Socket, priority) }, diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index b48e9e9f56..0c5ccebd73 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -189,8 +189,6 @@ Socket.ExecStopPost, config_parse_exec, SOCKET_EXEC Socket.TimeoutSec, config_parse_usec, 0, offsetof(Socket, timeout_usec) Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode) Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode) -Socket.SocketUser, config_parse_string, 0, offsetof(Socket, socket_user) -Socket.SocketGroup, config_parse_string, 0, offsetof(Socket, socket_group) Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept) Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections) Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive) diff --git a/src/core/socket.c b/src/core/socket.c index f3f09cac43..c0959815c1 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -136,12 +136,6 @@ static void socket_done(Unit *u) { free(s->smack_ip_in); free(s->smack_ip_out); - free(s->socket_user); - s->socket_user = NULL; - - free(s->socket_group); - s->socket_group = NULL; - unit_unwatch_timer(u, &s->timer_watch); } @@ -455,16 +449,6 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(s->pass_sec), prefix, strna(s->tcp_congestion)); - if (s->socket_user) - fprintf(f, - "SocketUser: %s\n", - s->socket_user); - - if (s->socket_group) - fprintf(f, - "SocketGroup: %s\n", - s->socket_group); - if (s->control_pid > 0) fprintf(f, "%sControl PID: %lu\n", @@ -708,9 +692,6 @@ static void socket_close_fds(Socket *s) { } static void socket_apply_socket_options(Socket *s, int fd) { - uid_t uid = 0; - gid_t gid = 0; - assert(s); assert(fd >= 0); @@ -794,21 +775,6 @@ static void socket_apply_socket_options(Socket *s, int fd) { if (s->smack_ip_out) if (fsetxattr(fd, "security.SMACK64IPOUT", s->smack_ip_out, strlen(s->smack_ip_out), 0) < 0) log_error("fsetxattr(\"security.SMACK64IPOUT\"): %m"); - - if (s->socket_user && - get_user_creds((const char **)&s->socket_user, &uid, - NULL, NULL, NULL) < 0) { - log_warning("failed to lookup user: %s", s->socket_user); - } - - if (s->socket_group && - get_group_creds((const char **)&s->socket_group, &gid) < 0) { - log_warning("failed to lookup group: %s", s->socket_group); - } - - if ((uid != 0 || gid != 0) && fchown(fd, uid, gid) < 0) { - log_warning("failed to change ownership of socket"); - } } static void socket_apply_fifo_options(Socket *s, int fd) { @@ -828,15 +794,11 @@ static int fifo_address_create( const char *path, mode_t directory_mode, mode_t socket_mode, - const char *socket_user, - const char *socket_group, int *_fd) { int fd = -1, r = 0; struct stat st; mode_t old_mask; - uid_t uid = 0; - gid_t gid = 0; assert(path); assert(_fd); @@ -861,8 +823,7 @@ static int fifo_address_create( goto fail; } - fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW); - if (fd < 0) { + if ((fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) { r = -errno; goto fail; } @@ -874,35 +835,15 @@ static int fifo_address_create( goto fail; } - if (socket_user && - get_user_creds(&socket_user, &uid, NULL, NULL, NULL) < 0) { - r = -errno; - log_error("failed to lookup user: %s", socket_user); - goto fail; - } - - if (socket_group && - get_group_creds(&socket_group, &gid) < 0) { - r = -errno; - log_error("failed to lookup group: %s", socket_group); - goto fail; - } - if (!S_ISFIFO(st.st_mode) || (st.st_mode & 0777) != (socket_mode & ~old_mask) || - st.st_uid != uid || - st.st_gid != gid) { + st.st_uid != getuid() || + st.st_gid != getgid()) { r = -EEXIST; goto fail; } - if ((uid != 0 || gid != 0) && fchown(fd, uid, gid) < 0) { - r = -errno; - log_error("failed to changed ownership of FIFO: %s", path); - goto fail; - } - *_fd = fd; return 0; @@ -1072,8 +1013,6 @@ static int socket_open_fds(Socket *s) { p->path, s->directory_mode, s->socket_mode, - s->socket_user, - s->socket_group, &p->fd)) < 0) goto rollback; diff --git a/src/core/socket.h b/src/core/socket.h index a273ac2740..f099520dce 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -118,8 +118,6 @@ struct Socket { mode_t directory_mode; mode_t socket_mode; - char *socket_user; - char *socket_group; SocketResult result; diff --git a/src/shared/socket-label.c b/src/shared/socket-label.c index d105a66fe8..ff212de825 100644 --- a/src/shared/socket-label.c +++ b/src/shared/socket-label.c @@ -52,7 +52,6 @@ int socket_address_listen( int *ret) { int r, fd, one; - assert(a); assert(ret); -- cgit v1.2.3-54-g00ecf