docbook-xsl (optional, required for documentation)
xsltproc (optional, required for documentation)
python-lxml (optional, required to build the indices)
- python, meson, ninja
+ python >= 3.4, meson >= 0.44, ninja
gcc, awk, sed, grep, m4, and similar tools
During runtime, you need the following additional
For more information on this issue consult
https://www.freedesktop.org/wiki/Software/systemd/separate-usr-is-broken
- To run systemd under valgrind, compile with VALGRIND defined
- (e.g. CPPFLAGS='... -DVALGRIND=1' meson <options>) and have valgrind
- development headers installed (i.e. valgrind-devel or
- equivalent). Otherwise, false positives will be triggered by code which
- violates some rules but is actually safe. Note that valgrind generates
- nice output only on exit(), hence on shutdown we don't execve()
- systemd-shutdown.
+ To run systemd under valgrind, compile with meson option
+ -Dvalgrind=true and have valgrind development headers installed
+ (i.e. valgrind-devel or equivalent). Otherwise, false positives will be
+ triggered by code which violates some rules but is actually safe. Note
+ that valgrind generates nice output only on exit(), hence on shutdown
+ we don't execve() systemd-shutdown.
STABLE BRANCHES AND BACKPORTS
<listitem><para>Controls where to store cores. One of <literal>none</literal>,
<literal>external</literal>, and <literal>journal</literal>. When
- <literal>none</literal>, the core dumps will be logged (including the backtrace if
+ <literal>none</literal>, the core dumps may be logged (including the backtrace if
possible), but not stored permanently. When <literal>external</literal> (the
default), cores will be stored in <filename>/var/lib/systemd/coredump/</filename>.
When <literal>journal</literal>, cores will be stored in the journal and rotated
<listitem><para>The maximum size in bytes of a core
which will be processed. Core dumps exceeding this size
- will be logged, but the backtrace will not be generated
- and the core will not be stored.</para></listitem>
+ may be stored, but the backtrace will not be generated.
+ </para>
+
+ <para>Setting <varname>Storage=none</varname> and <varname>ProcessSizeMax=0</varname>
+ disables all coredump handling except for a log entry.</para>
+ </listitem>
</varlistentry>
<varlistentry>
core dumps and files can be set in files <filename>/etc/systemd/coredump.conf</filename> and snippets mentioned
above. In addition the storage time of core dump files is restricted by <command>systemd-tmpfiles</command>,
corresponding settings are by default in <filename>/usr/lib/tmpfiles.d/systemd.conf</filename>.</para>
+
+ <refsect2>
+ <title>Disabling coredump processing</title>
+
+ <para>To disable potentially resource-intensive processing by <command>systemd-coredump</command>,
+ set <programlisting>Storage=none
+ProcessSizeMax=0</programlisting> in
+ <citerefentry><refentrytitle>coredump.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ </para>
+ </refsect2>
</refsect1>
<refsect1>
acquiring one.</para></listitem>
</varlistentry>
+ <xi:include href="standard-options.xml" xpointer="no-pager" />
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
doing so.</para>
</refsect1>
+ <xi:include href="less-variables.xml" />
+
<refsect1>
<title>See Also</title>
<para>
instead.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--hostname=</option></term>
+
+ <listitem><para>Controls the hostname to set within the container, if different from the machine name. Expects
+ a valid hostname as argument. If this option is used, the kernel hostname of the container will be set to this
+ value, otherwise it will be initialized to the machine name as controlled by the <option>--machine=</option>
+ option described above. The machine name is used for various aspect of identification of the container from the
+ outside, the kernel hostname configurable with this option is useful for the container to identify itself from
+ the inside. It is usually a good idea to keep both forms of identification synchronized, in order to avoid
+ confusion. It is hence recommended to avoid usage of this option, and use <option>--machine=</option>
+ exclusively. Note that regardless whether the container's hostname is initialized from the name set with
+ <option>--hostname=</option> or the one set with <option>--machine=</option>, the container can later override
+ its kernel hostname freely on its own as well.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--uuid=</option></term>
above).</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--no-new-privileges=</option></term>
+
+ <listitem><para>Takes a boolean argument. Specifies the value of the <constant>PR_SET_NO_NEW_PRIVS</constant>
+ flag for the container payload. Defaults to off. When turned on the payload code of the container cannot
+ acquire new privileges, i.e. the "setuid" file bit as well as file system capabilities will not have an effect
+ anymore. See <citerefentry
+ project='man-pages'><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details
+ about this flag. </para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--system-call-filter=</option></term>
<listitem><para>Alter the system call filter applied to containers. Takes a space-separated list of system call
names or group names (the latter prefixed with <literal>@</literal>, as listed by the
- <command>syscall-filter</command> command of <citerefentry
- project='man-pages'><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>). Passed
+ <command>syscall-filter</command> command of
+ <citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>). Passed
system calls will be permitted. The list may optionally be prefixed by <literal>~</literal>, in which case all
listed system calls are prohibited. If this command line option is used multiple times the configured lists are
combined. If both a positive and a negative list (that is one system call list without and one with the
capabilities are passed using the <command>--capabilities=</command>.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--rlimit=</option></term>
+
+ <listitem><para>Sets the specified POSIX resource limit for the container payload. Expects an assignment of the
+ form
+ <literal><replaceable>LIMIT</replaceable>=<replaceable>SOFT</replaceable>:<replaceable>HARD</replaceable></literal>
+ or <literal><replaceable>LIMIT</replaceable>=<replaceable>VALUE</replaceable></literal>, where
+ <replaceable>LIMIT</replaceable> should refer to a resource limit type, such as
+ <constant>RLIMIT_NOFILE</constant> or <constant>RLIMIT_NICE</constant>. The <replaceable>SOFT</replaceable> and
+ <replaceable>HARD</replaceable> fields should refer to the numeric soft and hard resource limit values. If the
+ second form is used, <replaceable>VALUE</replaceable> may specifiy a value that is used both as soft and hard
+ limit. In place of a numeric value the special string <literal>infinity</literal> may be used to turn off
+ resource limiting for the specific type of resource. This command line option may be used multiple times to
+ control limits on multiple limit types. If used multiple times for the same limit type, the last last use
+ wins. For details about resource limits see <citerefentry
+ project='man-pages'><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry>. By default
+ resource limits for the container's init process (PID 1) are set to the same values the Linux kernel originally
+ passed to the host init system. Note that some resource limits are enforced on resources counted per user, in
+ particular <constant>RLIMIT_NPROC</constant>. This means that unless user namespacing is deployed
+ (i.e. <option>--private-users=</option> is used, see above), any limits set will be applied to the resource
+ usage of the same user on all local containers as well as the host. This means particular care needs to be
+ taken with these limits as they might be triggered by possibly less trusted code. Example:
+ <literal>--rlimit=RLIMIT_NOFILE=8192:16384</literal>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--oom-score-adjust=</option></term>
+
+ <listitem><para>Changes the OOM ("Out Of Memory") score adjustment value for the container payload. This controls
+ <filename>/proc/self/oom_score_adj</filename> which influences the preference with which this container is
+ terminated when memory becomes scarce. For details see <citerefentry
+ project='man-pages'><refentrytitle>proc</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Takes an
+ integer in the range -1000…1000.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--cpu-affinity=</option></term>
+
+ <listitem><para>Controls the CPU affinity of the container payload. Takes a comma separated list of CPU numbers
+ or number ranges (the latter's start and end value separated by dashes). See <citerefentry
+ project='man-pages'><refentrytitle>sched_setaffinity</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
+ details.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--kill-signal=</option></term>
- <listitem><para>Specify the process signal to send to the
- container's PID 1 when nspawn itself receives SIGTERM, in
- order to trigger an orderly shutdown of the
- container. Defaults to SIGRTMIN+3 if <option>--boot</option>
- is used (on systemd-compatible init systems SIGRTMIN+3
- triggers an orderly shutdown). For a list of valid signals, see
- <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para></listitem>
+ <listitem><para>Specify the process signal to send to the container's PID 1 when nspawn itself receives
+ <constant>SIGTERM</constant>, in order to trigger an orderly shutdown of the container. Defaults to
+ <constant>SIGRTMIN+3</constant> if <option>--boot</option> is used (on systemd-compatible init systems
+ <constant>SIGRTMIN+3</constant> triggers an orderly shutdown). If <option>--boot</option> is not used and this
+ option is not specified the container's processes are terminated abrubtly via <constant>SIGKILL</constant>. For
+ a list of valid signals, see <citerefentry
+ project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
all cases.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>NoNewPrivileges=</varname></term>
+
+ <listitem><para>Takes a boolean argument that controls the <constant>PR_SET_NO_NEW_PRIVS</constant> flag for
+ the container payload. This is equivalent to the
+ <option>--no-new-privileges=</option> command line switch. See
+ <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
+ details.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>KillSignal=</varname></term>
details.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>LimitCPU=</varname></term>
+ <term><varname>LimitFSIZE=</varname></term>
+ <term><varname>LimitDATA=</varname></term>
+ <term><varname>LimitSTACK=</varname></term>
+ <term><varname>LimitCORE=</varname></term>
+ <term><varname>LimitRSS=</varname></term>
+ <term><varname>LimitNOFILE=</varname></term>
+ <term><varname>LimitAS=</varname></term>
+ <term><varname>LimitNPROC=</varname></term>
+ <term><varname>LimitMEMLOCK=</varname></term>
+ <term><varname>LimitLOCKS=</varname></term>
+ <term><varname>LimitSIGPENDING=</varname></term>
+ <term><varname>LimitMSGQUEUE=</varname></term>
+ <term><varname>LimitNICE=</varname></term>
+ <term><varname>LimitRTPRIO=</varname></term>
+ <term><varname>LimitRTTIME=</varname></term>
+
+ <listitem><para>Configures various types of resource limits applied to containers. This is equivalent to the
+ <option>--rlimit=</option> command line switch, and takes the same arguments. See
+ <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
+ details.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>OOMScoreAdjust=</varname></term>
+
+ <listitem><para>Configures the OOM score adjustment value. This is equivalent to the
+ <option>--oom-score-adjust=</option> command line switch, and takes the same argument. See
+ <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
+ details.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>CPUAffinity=</varname></term>
+
+ <listitem><para>Configures the CPU affinity. This is equivalent to the <option>--cpu-affinity=</option> command
+ line switch, and takes the same argument. See
+ <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
+ details.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>Hostname=</varname></term>
+
+ <listitem><para>Configures the kernel hostname set for the container. This is equivalent to the
+ <option>--hostname=</option> command line switch, and takes the same argument. See
+ <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
+ details.</para></listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
passed to the service manager from a specific service are passed back to the service's main process on the next
service restart. Any file descriptors passed to the service manager are automatically closed when
<constant>POLLHUP</constant> or <constant>POLLERR</constant> is seen on them, or when the service is fully
- stopped and no job is queued or being executed for it.</para></listitem>
+ stopped and no job is queued or being executed for it. If this option is used, <varname>NotifyAccess=</varname>
+ (see above) should be set to open access to the notification socket provided by systemd. If
+ <varname>NotifyAccess=</varname> is not set, it will be implicitly set to
+ <option>main</option>.</para></listitem>
</varlistentry>
<varlistentry>
'sysconfdir=/etc',
'localstatedir=/var',
],
- meson_version : '>= 0.41',
+ meson_version : '>= 0.44',
)
libsystemd_version = '0.22.0'
fuzzing_engine = meson.get_compiler('cpp').find_library('FuzzingEngine')
endif
-foreach arg : ['-Wextra',
- '-Werror=undef',
- '-Wlogical-op',
- '-Wmissing-include-dirs',
- '-Wold-style-definition',
- '-Wpointer-arith',
- '-Winit-self',
- '-Wdeclaration-after-statement',
- '-Wfloat-equal',
- '-Wsuggest-attribute=noreturn',
- '-Werror=missing-prototypes',
- '-Werror=implicit-function-declaration',
- '-Werror=missing-declarations',
- '-Werror=return-type',
- '-Werror=incompatible-pointer-types',
- '-Werror=format=2',
- '-Wstrict-prototypes',
- '-Wredundant-decls',
- '-Wmissing-noreturn',
- '-Wimplicit-fallthrough=5',
- '-Wshadow',
- '-Wendif-labels',
- '-Wstrict-aliasing=2',
- '-Wwrite-strings',
- '-Werror=overflow',
- '-Wdate-time',
- '-Wnested-externs',
- '-ffast-math',
- '-fno-common',
- '-fdiagnostics-show-option',
- '-fno-strict-aliasing',
- '-fvisibility=hidden',
- '-fstack-protector',
- '-fstack-protector-strong',
- '--param=ssp-buffer-size=4',
- ]
- if cc.has_argument(arg)
- add_project_arguments(arg, language : 'c')
- endif
-endforeach
+possible_cc_flags = [
+ '-Wextra',
+ '-Werror=undef',
+ '-Wlogical-op',
+ '-Wmissing-include-dirs',
+ '-Wold-style-definition',
+ '-Wpointer-arith',
+ '-Winit-self',
+ '-Wdeclaration-after-statement',
+ '-Wfloat-equal',
+ '-Wsuggest-attribute=noreturn',
+ '-Werror=missing-prototypes',
+ '-Werror=implicit-function-declaration',
+ '-Werror=missing-declarations',
+ '-Werror=return-type',
+ '-Werror=incompatible-pointer-types',
+ '-Werror=format=2',
+ '-Wstrict-prototypes',
+ '-Wredundant-decls',
+ '-Wmissing-noreturn',
+ '-Wimplicit-fallthrough=5',
+ '-Wshadow',
+ '-Wendif-labels',
+ '-Wstrict-aliasing=2',
+ '-Wwrite-strings',
+ '-Werror=overflow',
+ '-Wdate-time',
+ '-Wnested-externs',
+ '-ffast-math',
+ '-fno-common',
+ '-fdiagnostics-show-option',
+ '-fno-strict-aliasing',
+ '-fvisibility=hidden',
+ '-fstack-protector',
+ '-fstack-protector-strong',
+ '--param=ssp-buffer-size=4',
+]
+
+# --as-needed and --no-undefined are provided by meson by default,
+# run mesonconf to see what is enabled
+possible_link_flags = [
+ '-Wl,-z,relro',
+ '-Wl,-z,now',
+]
# the oss-fuzz fuzzers are not built with -fPIE, so don't
# enable it when we are linking against them
if not fuzzer_build
- if cc.has_argument('-fPIE')
- add_project_arguments('-fPIE', language : 'c')
- endif
+ possible_cc_flags += '-fPIE'
+ possible_link_flags += '-pie'
+endif
+
+if cc.get_id() == 'clang'
+ possible_cc_flags += [
+ '-Wno-typedef-redefinition',
+ '-Wno-gnu-variable-sized-type-not-at-end',
+ ]
+endif
+
+if get_option('buildtype') != 'debug'
+ possible_cc_flags += [
+ '-ffunction-sections',
+ '-fdata-sections',
+ ]
+
+ possible_link_flags += '-Wl,--gc-sections'
endif
+add_project_arguments(cc.get_supported_arguments(possible_cc_flags), language : 'c')
+
# "negative" arguments: gcc on purpose does not return an error for "-Wno-"
# arguments, just emits a warnings. So test for the "positive" version instead.
foreach arg : ['unused-parameter',
add_project_arguments('-Werror=shadow', language : 'c')
endif
-if cc.get_id() == 'clang'
- foreach arg : ['-Wno-typedef-redefinition',
- '-Wno-gnu-variable-sized-type-not-at-end',
- ]
- if cc.has_argument(arg)
- add_project_arguments(arg, language : 'c')
- endif
- endforeach
-endif
-
link_test_c = files('tools/meson-link-test.c')
-# --as-needed and --no-undefined are provided by meson by default,
-# run mesonconf to see what is enabled
-foreach arg : ['-Wl,-z,relro',
- '-Wl,-z,now',
- '-pie',
- ]
-
+foreach arg : possible_link_flags
have = run_command(check_compilation_sh,
cc.cmd_array(), '-x', 'c', arg,
'-include', link_test_c).returncode() == 0
message('Linking with @0@ supported: @1@'.format(arg, have ? 'yes' : 'no'))
- if have and (arg != '-pie' or not fuzzer_build)
+ if have
add_project_link_arguments(arg, language : 'c')
endif
endforeach
-if get_option('buildtype') != 'debug'
- foreach arg : ['-ffunction-sections',
- '-fdata-sections']
- if cc.has_argument(arg)
- add_project_arguments(arg, language : 'c')
- endif
- endforeach
-
- foreach arg : ['-Wl,--gc-sections']
- have = run_command(check_compilation_sh,
- cc.cmd_array(), '-x', 'c', arg,
- '-include', link_test_c).returncode() == 0
- message('Linking with @0@ supported: @1@'.format(arg, have ? 'yes' : 'no'))
- if have
- add_project_link_arguments(arg, language : 'c')
- endif
- endforeach
-endif
-
cpp = ' '.join(cc.cmd_array()) + ' -E'
#####################################################################
if getent_result.returncode() == 0
name = getent_result.stdout().split(':')[0]
if name != nobody_user
- message('WARNING:\n' +
- ' The local user with the UID 65534 does not match the configured user name "@0@" of the nobody user (its name is @1@).\n'.format(nobody_user, name) +
- ' Your build will result in an user table setup that is incompatible with the local system.')
+ warning('\n' +
+ 'The local user with the UID 65534 does not match the configured user name "@0@" of the nobody user (its name is @1@).\n'.format(nobody_user, name) +
+ 'Your build will result in an user table setup that is incompatible with the local system.')
endif
endif
id_result = run_command('id', '-u', nobody_user)
if id_result.returncode() == 0
id = id_result.stdout().to_int()
if id != 65534
- message('WARNING:\n' +
- ' The local user with the configured user name "@0@" of the nobody user does not have UID 65534 (it has @1@).\n'.format(nobody_user, id) +
- ' Your build will result in an user table setup that is incompatible with the local system.')
+ warning('\n' +
+ 'The local user with the configured user name "@0@" of the nobody user does not have UID 65534 (it has @1@).\n'.format(nobody_user, id) +
+ 'Your build will result in an user table setup that is incompatible with the local system.')
endif
endif
if getent_result.returncode() == 0
name = getent_result.stdout().split(':')[0]
if name != nobody_group
- message('WARNING:\n' +
- ' The local group with the GID 65534 does not match the configured group name "@0@" of the nobody group (its name is @1@).\n'.format(nobody_group, name) +
- ' Your build will result in an group table setup that is incompatible with the local system.')
+ warning('\n' +
+ 'The local group with the GID 65534 does not match the configured group name "@0@" of the nobody group (its name is @1@).\n'.format(nobody_group, name) +
+ 'Your build will result in an group table setup that is incompatible with the local system.')
endif
endif
id_result = run_command('id', '-g', nobody_group)
if id_result.returncode() == 0
id = id_result.stdout().to_int()
if id != 65534
- message('WARNING:\n' +
- ' The local group with the configured group name "@0@" of the nobody group does not have UID 65534 (it has @1@).\n'.format(nobody_group, id) +
- ' Your build will result in an group table setup that is incompatible with the local system.')
+ warning('\n' +
+ 'The local group with the configured group name "@0@" of the nobody group does not have UID 65534 (it has @1@).\n'.format(nobody_group, id) +
+ 'Your build will result in an group table setup that is incompatible with the local system.')
endif
endif
if nobody_user != nobody_group and not (nobody_user == 'nobody' and nobody_group == 'nogroup')
- message('WARNING:\n' +
- ' The configured user name "@0@" and group name "@0@" of the nobody user/group are not equivalent.\n'.format(nobody_user, nobody_group) +
- ' Please re-check that both "nobody-user" and "nobody-group" options are correctly set.')
+ warning('\n' +
+ 'The configured user name "@0@" and group name "@0@" of the nobody user/group are not equivalent.\n'.format(nobody_user, nobody_group) +
+ 'Please re-check that both "nobody-user" and "nobody-group" options are correctly set.')
endif
conf.set_quoted('NOBODY_USER_NAME', nobody_user)
substs.set('SUSHELL', get_option('debug-shell'))
substs.set('DEBUGTTY', get_option('debug-tty'))
-debug = get_option('debug')
enable_debug_hashmap = false
enable_debug_mmap_cache = false
-if debug != ''
- foreach name : debug.split(',')
- if name == 'hashmap'
- enable_debug_hashmap = true
- elif name == 'mmap-cache'
- enable_debug_mmap_cache = true
- else
- message('unknown debug option "@0@", ignoring'.format(name))
- endif
- endforeach
-endif
+foreach name : get_option('debug')
+ if name == 'hashmap'
+ enable_debug_hashmap = true
+ elif name == 'mmap-cache'
+ enable_debug_mmap_cache = true
+ else
+ message('unknown debug option "@0@", ignoring'.format(name))
+ endif
+endforeach
conf.set10('ENABLE_DEBUG_HASHMAP', enable_debug_hashmap)
conf.set10('ENABLE_DEBUG_MMAP_CACHE', enable_debug_mmap_cache)
+conf.set10('VALGRIND', get_option('valgrind'))
+
#####################################################################
threads = dependency('threads')
['gshadow'],
['debug hashmap'],
['debug mmap cache'],
+ ['valgrind', conf.get('VALGRIND') == 1],
]
if tuple.length() >= 2
message('\n '.join(status))
if rootprefixdir != rootprefix_default
- message('WARNING:\n' +
- ' Note that the installation prefix was changed to "@0@".\n'.format(rootprefixdir) +
- ' systemd used fixed names for unit file directories and other paths, so anything\n' +
- ' except the default ("@0@") is strongly discouraged.'.format(rootprefix_default))
+ warning('\n' +
+ 'Note that the installation prefix was changed to "@0@".\n'.format(rootprefixdir) +
+ 'systemd used fixed names for unit file directories and other paths, so anything\n' +
+ 'except the default ("@0@") is strongly discouraged.'.format(rootprefix_default))
endif
description : 'path to debug shell binary')
option('debug-tty', type : 'string', value : '/dev/tty9',
description : 'specify the tty device for debug shell')
-option('debug', type : 'string',
- description : 'enable extra debugging (hashmap,mmap-cache)')
+option('debug', type : 'array', choices : ['hashmap', 'mmap-cache'], value : [],
+ description : 'enable extra debugging')
option('memory-accounting-default', type : 'boolean',
description : 'enable MemoryAccounting= by default')
+option('valgrind', type : 'boolean', value : false,
+ description : 'do extra operations to avoid valgrind warnings')
option('utmp', type : 'boolean',
description : 'support for utmp/wtmp log handling')
# by-label/by-uuid links (filesystem metadata)
ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}"
-ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}"
+ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}"
# by-id (World Wide Name)
ENV{DEVTYPE}=="disk", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-id/wwn-$env{ID_WWN_WITH_EXTENSION}"
local i verb comps
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
local OPTS='-h --help --version --adjust-system-clock --no-pager
- --no-ask-password -H --host -M --machine'
+ --no-ask-password -H --host -M --machine --monitor
+ -p --property -a --all --value'
if __contains_word "$prev" $OPTS; then
case $prev in
local -A VERBS=(
[BOOLEAN]='set-local-rtc set-ntp'
- [STANDALONE]='status list-timezones'
+ [STANDALONE]='status list-timezones timesync-status show-timesync'
[TIMEZONES]='set-timezone'
[TIME]='set-time'
)
#include <stdlib.h>
#include "alloc-util.h"
+#include "all-units.h"
#include "analyze-verify.h"
#include "bus-error.h"
#include "bus-util.h"
d = opendir("/proc/self/fd");
if (!d) {
- int fd;
struct rlimit rl;
+ int fd, max_fd;
- /* When /proc isn't available (for example in chroots)
- * the fallback is brute forcing through the fd
+ /* When /proc isn't available (for example in chroots) the fallback is brute forcing through the fd
* table */
assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
- for (fd = 3; fd < (int) rl.rlim_max; fd ++) {
+
+ if (rl.rlim_max == 0)
+ return -EINVAL;
+
+ /* Let's take special care if the resource limit is set to unlimited, or actually larger than the range
+ * of 'int'. Let's avoid implicit overflows. */
+ max_fd = (rl.rlim_max == RLIM_INFINITY || rl.rlim_max > INT_MAX) ? INT_MAX : (int) (rl.rlim_max - 1);
+
+ for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
int q;
if (fd_in_set(fd, except, n_except))
return r;
}
+void unlink_tempfilep(char (*p)[]) {
+ /* If the file is created with mkstemp(), it will (almost always)
+ * change the suffix. Treat this as a sign that the file was
+ * successfully created. We ignore both the rare case where the
+ * original suffix is used and unlink failures. */
+ if (!endswith(*p, ".XXXXXX"))
+ (void) unlink(*p);
+}
+
int unlinkat_deallocate(int fd, const char *name, int flags) {
_cleanup_close_ int truncate_fd = -1;
struct stat st;
int access_fd(int fd, int mode);
+void unlink_tempfilep(char (*p)[]);
int unlinkat_deallocate(int fd, const char *name, int flags);
int fsync_directory_of_file(int fd);
},
};
-#ifdef VALGRIND
+#if VALGRIND
__attribute__((destructor)) static void cleanup_pools(void) {
_cleanup_free_ char *t = NULL;
int r;
mp->freelist = p;
}
-#ifdef VALGRIND
+#if VALGRIND
void mempool_drop(struct mempool *mp) {
struct pool *p = mp->first_pool;
}
-#ifdef VALGRIND
+#if VALGRIND
void mempool_drop(struct mempool *mp);
#endif
*ret = d;
return 0;
}
+
+int parse_oom_score_adjust(const char *s, int *ret) {
+ int r, v;
+
+ assert(s);
+ assert(ret);
+
+ r = safe_atoi(s, &v);
+ if (r < 0)
+ return r;
+
+ if (v < OOM_SCORE_ADJ_MIN || v > OOM_SCORE_ADJ_MAX)
+ return -ERANGE;
+
+ *ret = v;
+ return 0;
+}
int parse_nice(const char *p, int *ret);
int parse_ip_port(const char *s, uint16_t *ret);
+
+int parse_oom_score_adjust(const char *s, int *ret);
return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
path_kill_slashes(p);
- if (suppress_root && path_equal(p, "/"))
+ if (suppress_root && empty_or_root(p))
p = mfree(p);
free(*arg);
*arg = p;
+
return 0;
}
_exit(EXIT_FAILURE);
}
+int set_oom_score_adjust(int value) {
+ char t[DECIMAL_STR_MAX(int)];
+
+ sprintf(t, "%i", value);
+
+ return write_string_file("/proc/self/oom_score_adj", t,
+ WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid, const char *path, ...);
+int set_oom_score_adjust(int value);
+
#if SIZEOF_PID_T == 4
/* The highest possibly (theoretic) pid_t value on this architecture. */
#define PID_T_MAX ((pid_t) INT32_MAX)
if (getrlimit(resource, &highest) < 0)
return -errno;
+ /* If the hard limit is unbounded anyway, then the EPERM had other reasons, let's propagate the original EPERM
+ * then */
+ if (highest.rlim_max == RLIM_INFINITY)
+ return -EPERM;
+
fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
return 0;
}
+int setrlimit_closest_all(const struct rlimit *const *rlim, int *which_failed) {
+ int i, r;
+
+ assert(rlim);
+
+ /* On failure returns the limit's index that failed in *which_failed, but only if non-NULL */
+
+ for (i = 0; i < _RLIMIT_MAX; i++) {
+ if (!rlim[i])
+ continue;
+
+ r = setrlimit_closest(i, rlim[i]);
+ if (r < 0) {
+ if (which_failed)
+ *which_failed = i;
+
+ return r;
+ }
+ }
+
+ if (which_failed)
+ *which_failed = -1;
+
+ return 0;
+}
+
static int rlimit_parse_u64(const char *val, rlim_t *ret) {
uint64_t u;
int r;
}
static const char* const rlimit_table[_RLIMIT_MAX] = {
- [RLIMIT_CPU] = "LimitCPU",
- [RLIMIT_FSIZE] = "LimitFSIZE",
- [RLIMIT_DATA] = "LimitDATA",
- [RLIMIT_STACK] = "LimitSTACK",
- [RLIMIT_CORE] = "LimitCORE",
- [RLIMIT_RSS] = "LimitRSS",
- [RLIMIT_NOFILE] = "LimitNOFILE",
- [RLIMIT_AS] = "LimitAS",
- [RLIMIT_NPROC] = "LimitNPROC",
- [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
- [RLIMIT_LOCKS] = "LimitLOCKS",
- [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
- [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
- [RLIMIT_NICE] = "LimitNICE",
- [RLIMIT_RTPRIO] = "LimitRTPRIO",
- [RLIMIT_RTTIME] = "LimitRTTIME"
+ [RLIMIT_AS] = "AS",
+ [RLIMIT_CORE] = "CORE",
+ [RLIMIT_CPU] = "CPU",
+ [RLIMIT_DATA] = "DATA",
+ [RLIMIT_FSIZE] = "FSIZE",
+ [RLIMIT_LOCKS] = "LOCKS",
+ [RLIMIT_MEMLOCK] = "MEMLOCK",
+ [RLIMIT_MSGQUEUE] = "MSGQUEUE",
+ [RLIMIT_NICE] = "NICE",
+ [RLIMIT_NOFILE] = "NOFILE",
+ [RLIMIT_NPROC] = "NPROC",
+ [RLIMIT_RSS] = "RSS",
+ [RLIMIT_RTPRIO] = "RTPRIO",
+ [RLIMIT_RTTIME] = "RTTIME",
+ [RLIMIT_SIGPENDING] = "SIGPENDING",
+ [RLIMIT_STACK] = "STACK",
};
DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
+
+int rlimit_from_string_harder(const char *s) {
+ const char *suffix;
+
+ /* The official prefix */
+ suffix = startswith(s, "RLIMIT_");
+ if (suffix)
+ return rlimit_from_string(suffix);
+
+ /* Our own unit file setting prefix */
+ suffix = startswith(s, "Limit");
+ if (suffix)
+ return rlimit_from_string(suffix);
+
+ return rlimit_from_string(s);
+}
+
+void rlimit_free_all(struct rlimit **rl) {
+ int i;
+
+ if (!rl)
+ return;
+
+ for (i = 0; i < _RLIMIT_MAX; i++)
+ rl[i] = mfree(rl[i]);
+}
const char *rlimit_to_string(int i) _const_;
int rlimit_from_string(const char *s) _pure_;
+int rlimit_from_string_harder(const char *s) _pure_;
int setrlimit_closest(int resource, const struct rlimit *rlim);
+int setrlimit_closest_all(const struct rlimit * const *rlim, int *which_failed);
int rlimit_parse_one(int resource, const char *val, rlim_t *ret);
int rlimit_parse(int resource, const char *val, struct rlimit *ret);
int rlimit_format(const struct rlimit *rl, char **ret);
+void rlimit_free_all(struct rlimit **rl);
+
#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
--- /dev/null
+#pragma once
+
+#include "unit.h"
+
+#include "automount.h"
+#include "device.h"
+#include "path.h"
+#include "scope.h"
+#include "service.h"
+#include "slice.h"
+#include "socket.h"
+#include "swap.h"
+#include "target.h"
+#include "timer.h"
const char* automount_result_to_string(AutomountResult i) _const_;
AutomountResult automount_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(AUTOMOUNT, Automount);
_CGROUP_IP_ACCOUNTING_METRIC_INVALID = -1,
} CGroupIPAccountingMetric;
-#include "unit.h"
+typedef struct Unit Unit;
+typedef struct Manager Manager;
void cgroup_context_init(CGroupContext *c);
void cgroup_context_done(CGroupContext *c);
#include "sd-bus.h"
+#include "unit.h"
#include "cgroup.h"
extern const sd_bus_vtable bus_cgroup_vtable[];
static BUS_DEFINE_PROPERTY_GET(property_get_ioprio, "i", ExecContext, exec_context_get_effective_ioprio);
static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_class, "i", ExecContext, exec_context_get_effective_ioprio, IOPRIO_PRIO_CLASS);
static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_priority, "i", ExecContext, exec_context_get_effective_ioprio, IOPRIO_PRIO_DATA);
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_string, "s", NULL);
+static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_level, "i", int, LOG_PRI);
+static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_facility, "i", int, LOG_FAC);
static int property_get_environment_files(
sd_bus *bus,
return sd_bus_message_append(reply, "t", u);
}
-static int property_get_empty_string(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- return sd_bus_message_append(reply, "s", NULL);
-}
-
static int property_get_syscall_filter(
sd_bus *bus,
const char *path,
return sd_bus_message_append(reply, "s", wd);
}
-static int property_get_syslog_level(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- int *s = userdata;
-
- assert(bus);
- assert(reply);
- assert(s);
-
- return sd_bus_message_append(reply, "i", LOG_PRI(*s));
-}
-
-static int property_get_syslog_facility(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- int *s = userdata;
-
- assert(bus);
- assert(reply);
- assert(s);
-
- return sd_bus_message_append(reply, "i", LOG_FAC(*s));
-}
-
static int property_get_stdio_fdname(
sd_bus *bus,
const char *path,
UnitWriteFlags flags,
sd_bus_error *error) {
- const char *soft = NULL;
- int r, ri;
+ const char *suffix;
+ int r;
assert(u);
assert(c);
return r;
STRV_FOREACH(p, l) {
- if (!path_is_normalized(*p) || path_is_absolute(*p))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path is not valid: %s", name, *p);
+ if (!path_is_normalized(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path is not normalized: %s", name, *p);
+
+ if (path_is_absolute(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path is absolute: %s", name, *p);
+
+ if (path_startswith(*p, "private"))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path can't be 'private': %s", name, *p);
}
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
}
return 1;
- }
- ri = rlimit_from_string(name);
- if (ri < 0) {
- soft = endswith(name, "Soft");
- if (soft) {
- const char *n;
+ } else if ((suffix = startswith(name, "Limit"))) {
+ const char *soft = NULL;
+ int ri;
- n = strndupa(name, soft - name);
- ri = rlimit_from_string(n);
- if (ri >= 0)
- name = n;
+ ri = rlimit_from_string(suffix);
+ if (ri < 0) {
+ soft = endswith(suffix, "Soft");
+ if (soft) {
+ const char *n;
+ n = strndupa(suffix, soft - suffix);
+ ri = rlimit_from_string(n);
+ if (ri >= 0)
+ name = strjoina("Limit", n);
+ }
}
- }
- if (ri >= 0) {
- uint64_t rl;
- rlim_t x;
-
- r = sd_bus_message_read(message, "t", &rl);
- if (r < 0)
- return r;
-
- if (rl == (uint64_t) -1)
- x = RLIM_INFINITY;
- else {
- x = (rlim_t) rl;
-
- if ((uint64_t) x != rl)
- return -ERANGE;
- }
+ if (ri >= 0) {
+ uint64_t rl;
+ rlim_t x;
- if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- _cleanup_free_ char *f = NULL;
- struct rlimit nl;
-
- if (c->rlimit[ri]) {
- nl = *c->rlimit[ri];
-
- if (soft)
- nl.rlim_cur = x;
- else
- nl.rlim_max = x;
- } else
- /* When the resource limit is not initialized yet, then assign the value to both fields */
- nl = (struct rlimit) {
- .rlim_cur = x,
- .rlim_max = x,
- };
-
- r = rlimit_format(&nl, &f);
+ r = sd_bus_message_read(message, "t", &rl);
if (r < 0)
return r;
- if (c->rlimit[ri])
- *c->rlimit[ri] = nl;
+ if (rl == (uint64_t) -1)
+ x = RLIM_INFINITY;
else {
- c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
- if (!c->rlimit[ri])
- return -ENOMEM;
+ x = (rlim_t) rl;
+
+ if ((uint64_t) x != rl)
+ return -ERANGE;
}
- unit_write_settingf(u, flags, name, "%s=%s", name, f);
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ _cleanup_free_ char *f = NULL;
+ struct rlimit nl;
+
+ if (c->rlimit[ri]) {
+ nl = *c->rlimit[ri];
+
+ if (soft)
+ nl.rlim_cur = x;
+ else
+ nl.rlim_max = x;
+ } else
+ /* When the resource limit is not initialized yet, then assign the value to both fields */
+ nl = (struct rlimit) {
+ .rlim_cur = x,
+ .rlim_max = x,
+ };
+
+ r = rlimit_format(&nl, &f);
+ if (r < 0)
+ return r;
+
+ if (c->rlimit[ri])
+ *c->rlimit[ri] = nl;
+ else {
+ c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
+ if (!c->rlimit[ri])
+ return -ENOMEM;
+ }
+
+ unit_write_settingf(u, flags, name, "%s=%s", name, f);
+ }
+
+ return 1;
}
- return 1;
}
return 0;
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_log_target, "s", log_target_to_string(log_get_target()));
static BUS_DEFINE_PROPERTY_GET2(property_get_system_state, "s", Manager, manager_state, manager_state_to_string);
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_timer_slack_nsec, "t", (uint64_t) prctl(PR_GET_TIMERSLACK));
+static BUS_DEFINE_PROPERTY_GET_REF(property_get_hashmap_size, "u", Hashmap *, hashmap_size);
+static BUS_DEFINE_PROPERTY_GET_REF(property_get_set_size, "u", Set *, set_size);
static int property_get_virtualization(
sd_bus *bus,
return r;
}
-static int property_get_hashmap_size(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Hashmap **h = userdata;
-
- assert(bus);
- assert(reply);
- assert(h);
-
- return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(*h));
-}
-
-static int property_get_set_size(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Set **s = userdata;
-
- assert(bus);
- assert(reply);
- assert(s);
-
- return sd_bus_message_append(reply, "u", (uint32_t) set_size(*s));
-}
-
static int property_get_progress(
sd_bus *bus,
const char *path,
#include "sd-bus.h"
-#include "unit.h"
+#include "scope.h"
extern const sd_bus_vtable bus_scope_vtable[];
#include "user-util.h"
#include "web-util.h"
+static bool unit_can_start_refuse_manual(Unit *u) {
+ return unit_can_start(u) && !u->refuse_manual_start;
+}
+
+static bool unit_can_stop_refuse_manual(Unit *u) {
+ return unit_can_stop(u) && !u->refuse_manual_stop;
+}
+
+static bool unit_can_isolate_refuse_manual(Unit *u) {
+ return unit_can_isolate(u) && !u->refuse_manual_start;
+}
+
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_collect_mode, collect_mode, CollectMode);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
static BUS_DEFINE_PROPERTY_GET(property_get_sub_state, "s", Unit, unit_sub_state_to_string);
static BUS_DEFINE_PROPERTY_GET2(property_get_unit_file_state, "s", Unit, unit_get_unit_file_state, unit_file_state_to_string);
static BUS_DEFINE_PROPERTY_GET(property_get_can_reload, "b", Unit, unit_can_reload);
+static BUS_DEFINE_PROPERTY_GET(property_get_can_start, "b", Unit, unit_can_start_refuse_manual);
+static BUS_DEFINE_PROPERTY_GET(property_get_can_stop, "b", Unit, unit_can_stop_refuse_manual);
+static BUS_DEFINE_PROPERTY_GET(property_get_can_isolate, "b", Unit, unit_can_isolate_refuse_manual);
static BUS_DEFINE_PROPERTY_GET(property_get_need_daemon_reload, "b", Unit, unit_need_daemon_reload);
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_strv, "as", 0);
static int property_get_names(
sd_bus *bus,
void *userdata,
sd_bus_error *error) {
- Unit *u = userdata;
+ Set **s = userdata;
Iterator i;
const char *t;
int r;
assert(bus);
assert(reply);
- assert(u);
+ assert(s);
r = sd_bus_message_open_container(reply, 'a', "s");
if (r < 0)
return r;
- SET_FOREACH(t, u->names, i) {
+ SET_FOREACH(t, *s, i) {
r = sd_bus_message_append(reply, "s", t);
if (r < 0)
return r;
return sd_bus_message_close_container(reply);
}
-static int property_get_obsolete_dependencies(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- /* For dependency types we don't support anymore always return an empty array */
- return sd_bus_message_append(reply, "as", 0);
-}
-
static int property_get_requires_mounts_for(
sd_bus *bus,
const char *path,
r > 0 ? "enabled" : "disabled");
}
-static int property_get_can_start(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
-}
-
-static int property_get_can_stop(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "b", unit_can_stop(u) && !u->refuse_manual_stop);
-}
-
-static int property_get_can_isolate(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
-}
-
static int property_get_job(
sd_bus *bus,
const char *path,
sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
- Unit *u = userdata;
+ Job **j = userdata;
assert(bus);
assert(reply);
- assert(u);
+ assert(j);
- if (!u->job)
+ if (!*j)
return sd_bus_message_append(reply, "(uo)", 0, "/");
- p = job_dbus_path(u->job);
+ p = job_dbus_path(*j);
if (!p)
return -ENOMEM;
- return sd_bus_message_append(reply, "(uo)", u->job->id, p);
+ return sd_bus_message_append(reply, "(uo)", (*j)->id, p);
}
static int property_get_conditions(
sd_bus_error *error) {
_cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
- Unit *u = userdata;
+ int *n = userdata;
assert(bus);
assert(reply);
- assert(u);
+ assert(n);
- if (u->load_error != 0)
- sd_bus_error_set_errno(&e, u->load_error);
+ if (*n != 0)
+ sd_bus_error_set_errno(&e, *n);
return sd_bus_message_append(reply, "(ss)", e.name, e.message);
}
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Names", "as", property_get_names, offsetof(Unit, names), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Job", "(uo)", property_get_job, offsetof(Unit, job), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0),
SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
- SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, offsetof(Unit, load_error), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Perpetual", "b", bus_property_get_bool, offsetof(Unit, perpetual), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("StartLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("Ref", NULL, NULL, bus_unit_method_ref, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Unref", NULL, NULL, bus_unit_method_unref, SD_BUS_VTABLE_UNPRIVILEGED),
- /* Obsolete properties or obsolete alias names */
- SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
+ /* For dependency types we don't support anymore always return an empty array */
+ SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
+ /* Obsolete alias names */
SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_VTABLE_END
#include "mkdir.h"
#include "process-util.h"
#include "selinux-access.h"
+#include "service.h"
#include "special.h"
#include "string-util.h"
#include "strv.h"
Copyright 2010 Lennart Poettering
***/
+#include "unit.h"
+
typedef struct Device Device;
typedef enum DeviceFound {
int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now);
bool device_shall_be_bound_by(Unit *device, Unit *u);
+
+DEFINE_CAST(DEVICE, Device);
#include "io-util.h"
#include "parse-util.h"
#include "random-util.h"
+#include "socket-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "user-util.h"
#include "selinux-util.h"
#include "signal-util.h"
#include "smack-util.h"
+#include "socket-util.h"
#include "special.h"
#include "stat-util.h"
#include "string-table.h"
#endif
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
- int i, r, ngids = 0;
+ int r, ngids = 0;
size_t n_fds;
ExecDirectoryType dt;
int secure_bits;
}
if (context->oom_score_adjust_set) {
- char t[DECIMAL_STR_MAX(context->oom_score_adjust)];
-
- /* When we can't make this change due to EPERM, then
- * let's silently skip over it. User namespaces
- * prohibit write access to this file, and we
- * shouldn't trip up over that. */
-
- sprintf(t, "%i", context->oom_score_adjust);
- r = write_string_file("/proc/self/oom_score_adj", t, 0);
+ /* When we can't make this change due to EPERM, then let's silently skip over it. User namespaces
+ * prohibit write access to this file, and we shouldn't trip up over that. */
+ r = set_oom_score_adjust(context->oom_score_adjust);
if (IN_SET(r, -EPERM, -EACCES))
log_unit_debug_errno(unit, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m");
else if (r < 0) {
if (needs_sandboxing) {
uint64_t bset;
+ int which_failed;
- for (i = 0; i < _RLIMIT_MAX; i++) {
-
- if (!context->rlimit[i])
- continue;
-
- r = setrlimit_closest(i, context->rlimit[i]);
- if (r < 0) {
- *exit_status = EXIT_LIMITS;
- return log_unit_error_errno(unit, r, "Failed to adjust resource limit %s: %m", rlimit_to_string(i));
- }
+ r = setrlimit_closest_all((const struct rlimit* const *) context->rlimit, &which_failed);
+ if (r < 0) {
+ *exit_status = EXIT_LIMITS;
+ return log_unit_error_errno(unit, r, "Failed to adjust resource limit RLIMIT_%s: %m", rlimit_to_string(which_failed));
}
/* Set the RTPRIO resource limit to 0, but only if nothing else was explicitly requested. */
c->pass_environment = strv_free(c->pass_environment);
c->unset_environment = strv_free(c->unset_environment);
- for (l = 0; l < ELEMENTSOF(c->rlimit); l++)
- c->rlimit[l] = mfree(c->rlimit[l]);
+ rlimit_free_all(c->rlimit);
for (l = 0; l < 3; l++) {
c->stdio_fdname[l] = mfree(c->stdio_fdname[l]);
for (i = 0; i < RLIM_NLIMITS; i++)
if (c->rlimit[i]) {
- fprintf(f, "%s%s: " RLIM_FMT "\n",
+ fprintf(f, "Limit%s%s: " RLIM_FMT "\n",
prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
- fprintf(f, "%s%sSoft: " RLIM_FMT "\n",
+ fprintf(f, "Limit%s%sSoft: " RLIM_FMT "\n",
prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur);
}
#include "conf-parser.h"
#include "load-fragment.h"
#include "missing.h"
+
+#include "all-units.h"
%}
struct ConfigPerfItem;
%null_strings
$1.RestrictRealtime, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.LockPersonality, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
-$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.LimitCPU, config_parse_rlimit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
+$1.LimitFSIZE, config_parse_rlimit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
+$1.LimitDATA, config_parse_rlimit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
+$1.LimitSTACK, config_parse_rlimit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
+$1.LimitCORE, config_parse_rlimit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
+$1.LimitRSS, config_parse_rlimit, RLIMIT_RSS, offsetof($1, exec_context.rlimit)
+$1.LimitNOFILE, config_parse_rlimit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit)
+$1.LimitAS, config_parse_rlimit, RLIMIT_AS, offsetof($1, exec_context.rlimit)
+$1.LimitNPROC, config_parse_rlimit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit)
+$1.LimitMEMLOCK, config_parse_rlimit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit)
+$1.LimitLOCKS, config_parse_rlimit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit)
+$1.LimitSIGPENDING, config_parse_rlimit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit)
+$1.LimitMSGQUEUE, config_parse_rlimit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
+$1.LimitNICE, config_parse_rlimit, RLIMIT_NICE, offsetof($1, exec_context.rlimit)
+$1.LimitRTPRIO, config_parse_rlimit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit)
+$1.LimitRTTIME, config_parse_rlimit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_paths)
$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths)
$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths)
#include "af-list.h"
#include "alloc-util.h"
+#include "all-units.h"
#include "bus-error.h"
#include "bus-internal.h"
#include "bus-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
-#include "rlimit-util.h"
#if HAVE_SECCOMP
#include "seccomp-util.h"
#endif
#include "strv.h"
#include "unit-name.h"
#include "unit-printf.h"
-#include "unit.h"
#include "user-util.h"
#include "utf8.h"
#include "web-util.h"
p->type = SOCKET_SOCKET;
r = unit_full_printf(UNIT(s), rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
return 0;
}
return 0;
}
-int config_parse_exec_oom_score_adjust(const char* unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_exec_oom_score_adjust(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
ExecContext *c = data;
int oa, r;
assert(rvalue);
assert(data);
- r = safe_atoi(rvalue, &oa);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
+ if (isempty(rvalue)) {
+ c->oom_score_adjust_set = false;
return 0;
}
- if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue);
+ r = parse_oom_score_adjust(rvalue, &oa);
+ if (r == -ERANGE) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
return 0;
}
} else
n = NULL;
- free(s->bind_to_device);
- s->bind_to_device = n;
+ free_and_replace(s->bind_to_device, n);
return 0;
}
return 0;
}
-int config_parse_limit(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- struct rlimit **rl = data, d = {};
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = rlimit_parse(ltype, rvalue, &d);
- if (r == -EILSEQ) {
- log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
- return 0;
- }
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
- return 0;
- }
-
- if (rl[ltype])
- *rl[ltype] = d;
- else {
- rl[ltype] = newdup(struct rlimit, &d, 1);
- if (!rl[ltype])
- return log_oom();
- }
-
- return 0;
-}
-
#if HAVE_SYSV_COMPAT
int config_parse_sysv_priority(const char *unit,
const char *filename,
continue;
}
- if (!path_is_normalized(k) || path_is_absolute(k)) {
+ if (!path_is_normalized(k)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "%s= path is not normalized, ignoring assignment: %s", lvalue, rvalue);
+ continue;
+ }
+
+ if (path_is_absolute(k)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "%s= path is absolute, ignoring assignment: %s", lvalue, rvalue);
+ continue;
+ }
+
+ if (path_startswith(k, "private")) {
log_syntax(unit, LOG_ERR, filename, line, 0,
- "%s= path is not valid, ignoring assignment: %s", lvalue, rvalue);
+ "%s= path can't be 'private', ingoring assignment: %s", lvalue, rvalue);
continue;
}
{ config_parse_log_level, "LEVEL" },
{ config_parse_exec_secure_bits, "SECUREBITS" },
{ config_parse_capability_set, "BOUNDINGSET" },
- { config_parse_limit, "LIMIT" },
+ { config_parse_rlimit, "LIMIT" },
{ config_parse_unit_deps, "UNIT [...]" },
{ config_parse_exec, "PATH [ARGUMENT [...]]" },
{ config_parse_service_type, "SERVICETYPE" },
int config_parse_exec_cpu_affinity(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_capability_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
#include "def.h"
#include "emergency-action.h"
#include "env-util.h"
+#include "exit-status.h"
#include "fd-util.h"
#include "fdset.h"
#include "fileio.h"
{ "Manager", "DefaultStartLimitIntervalSec",config_parse_sec, 0, &arg_default_start_limit_interval },
{ "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
{ "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment },
- { "Manager", "DefaultLimitCPU", config_parse_limit, RLIMIT_CPU, arg_default_rlimit },
- { "Manager", "DefaultLimitFSIZE", config_parse_limit, RLIMIT_FSIZE, arg_default_rlimit },
- { "Manager", "DefaultLimitDATA", config_parse_limit, RLIMIT_DATA, arg_default_rlimit },
- { "Manager", "DefaultLimitSTACK", config_parse_limit, RLIMIT_STACK, arg_default_rlimit },
- { "Manager", "DefaultLimitCORE", config_parse_limit, RLIMIT_CORE, arg_default_rlimit },
- { "Manager", "DefaultLimitRSS", config_parse_limit, RLIMIT_RSS, arg_default_rlimit },
- { "Manager", "DefaultLimitNOFILE", config_parse_limit, RLIMIT_NOFILE, arg_default_rlimit },
- { "Manager", "DefaultLimitAS", config_parse_limit, RLIMIT_AS, arg_default_rlimit },
- { "Manager", "DefaultLimitNPROC", config_parse_limit, RLIMIT_NPROC, arg_default_rlimit },
- { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, RLIMIT_MEMLOCK, arg_default_rlimit },
- { "Manager", "DefaultLimitLOCKS", config_parse_limit, RLIMIT_LOCKS, arg_default_rlimit },
- { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, RLIMIT_SIGPENDING, arg_default_rlimit },
- { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, RLIMIT_MSGQUEUE, arg_default_rlimit },
- { "Manager", "DefaultLimitNICE", config_parse_limit, RLIMIT_NICE, arg_default_rlimit },
- { "Manager", "DefaultLimitRTPRIO", config_parse_limit, RLIMIT_RTPRIO, arg_default_rlimit },
- { "Manager", "DefaultLimitRTTIME", config_parse_limit, RLIMIT_RTTIME, arg_default_rlimit },
+ { "Manager", "DefaultLimitCPU", config_parse_rlimit, RLIMIT_CPU, arg_default_rlimit },
+ { "Manager", "DefaultLimitFSIZE", config_parse_rlimit, RLIMIT_FSIZE, arg_default_rlimit },
+ { "Manager", "DefaultLimitDATA", config_parse_rlimit, RLIMIT_DATA, arg_default_rlimit },
+ { "Manager", "DefaultLimitSTACK", config_parse_rlimit, RLIMIT_STACK, arg_default_rlimit },
+ { "Manager", "DefaultLimitCORE", config_parse_rlimit, RLIMIT_CORE, arg_default_rlimit },
+ { "Manager", "DefaultLimitRSS", config_parse_rlimit, RLIMIT_RSS, arg_default_rlimit },
+ { "Manager", "DefaultLimitNOFILE", config_parse_rlimit, RLIMIT_NOFILE, arg_default_rlimit },
+ { "Manager", "DefaultLimitAS", config_parse_rlimit, RLIMIT_AS, arg_default_rlimit },
+ { "Manager", "DefaultLimitNPROC", config_parse_rlimit, RLIMIT_NPROC, arg_default_rlimit },
+ { "Manager", "DefaultLimitMEMLOCK", config_parse_rlimit, RLIMIT_MEMLOCK, arg_default_rlimit },
+ { "Manager", "DefaultLimitLOCKS", config_parse_rlimit, RLIMIT_LOCKS, arg_default_rlimit },
+ { "Manager", "DefaultLimitSIGPENDING", config_parse_rlimit, RLIMIT_SIGPENDING, arg_default_rlimit },
+ { "Manager", "DefaultLimitMSGQUEUE", config_parse_rlimit, RLIMIT_MSGQUEUE, arg_default_rlimit },
+ { "Manager", "DefaultLimitNICE", config_parse_rlimit, RLIMIT_NICE, arg_default_rlimit },
+ { "Manager", "DefaultLimitRTPRIO", config_parse_rlimit, RLIMIT_RTPRIO, arg_default_rlimit },
+ { "Manager", "DefaultLimitRTTIME", config_parse_rlimit, RLIMIT_RTTIME, arg_default_rlimit },
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
{ "Manager", "DefaultIOAccounting", config_parse_bool, 0, &arg_default_io_accounting },
{ "Manager", "DefaultIPAccounting", config_parse_bool, 0, &arg_default_ip_accounting },
#include "sd-path.h"
#include "alloc-util.h"
+#include "all-units.h"
#include "audit-fd.h"
#include "boot-timestamps.h"
#include "bus-common-errors.h"
#include "path-util.h"
#include "process-util.h"
#include "ratelimit.h"
+#include "rlimit-util.h"
#include "rm-rf.h"
#include "signal-util.h"
+#include "socket-util.h"
#include "special.h"
#include "stat-util.h"
#include "string-table.h"
Manager* manager_free(Manager *m) {
UnitType c;
- int i;
ExecDirectoryType dt;
if (!m)
free(m->switch_root);
free(m->switch_root_init);
- for (i = 0; i < _RLIMIT_MAX; i++)
- m->rlimit[i] = mfree(m->rlimit[i]);
+ rlimit_free_all(m->rlimit);
assert(hashmap_isempty(m->units_requiring_mounts_for));
hashmap_free(m->units_requiring_mounts_for);
#include "ratelimit.h"
struct libmnt_monitor;
+typedef struct Unit Unit;
/* Enforce upper limit how many names we allow */
#define MANAGER_MAX_NAMES 131072 /* 128K */
#include "alloc-util.h"
#include "dbus-mount.h"
+#include "device.h"
#include "escape.h"
#include "exit-status.h"
#include "format-util.h"
#include "kill.h"
#include "dynamic-user.h"
+#include "unit.h"
typedef enum MountExecCommand {
MOUNT_EXEC_MOUNT,
const char* mount_result_to_string(MountResult i) _const_;
MountResult mount_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(MOUNT, Mount);
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
+ <annotate key="org.freedesktop.policykit.imply">org.freedesktop.systemd1.reload-daemon org.freedesktop.systemd1.manage-units</annotate>
</action>
<action id="org.freedesktop.systemd1.set-environment">
const char* path_result_to_string(PathResult i) _const_;
PathResult path_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(PATH, Path);
const char* scope_result_to_string(ScopeResult i) _const_;
ScopeResult scope_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(SCOPE, Scope);
if (r < 0)
return r;
- if (s->type == SERVICE_NOTIFY && s->notify_access == NOTIFY_NONE)
- s->notify_access = NOTIFY_MAIN;
-
- if (s->watchdog_usec > 0 && s->notify_access == NOTIFY_NONE)
+ /* If the service needs the notify socket, let's enable it automatically. */
+ if (s->notify_access == NOTIFY_NONE &&
+ (s->type == SERVICE_NOTIFY || s->watchdog_usec > 0 || s->n_fd_store_max > 0))
s->notify_access = NOTIFY_MAIN;
r = service_add_default_dependencies(s);
#include "kill.h"
#include "path.h"
#include "ratelimit.h"
+#include "socket.h"
+#include "unit.h"
typedef enum ServiceRestart {
SERVICE_RESTART_NO,
const char* service_result_to_string(ServiceResult i) _const_;
ServiceResult service_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(SERVICE, Service);
Copyright 2013 Lennart Poettering
***/
+#include "unit.h"
+
typedef struct Slice Slice;
struct Slice {
};
extern const UnitVTable slice_vtable;
+
+DEFINE_CAST(SLICE, Slice);
#include "mount.h"
#include "service.h"
#include "socket-util.h"
+#include "unit.h"
typedef enum SocketExecCommand {
SOCKET_EXEC_START_PRE,
const char* socket_port_type_to_string(SocketPort *p) _pure_;
SocketType socket_port_type_from_string(const char *p) _pure_;
+
+DEFINE_CAST(SOCKET, Socket);
#include "alloc-util.h"
#include "dbus-swap.h"
+#include "device.h"
#include "escape.h"
#include "exit-status.h"
#include "fd-util.h"
***/
#include "libudev.h"
+#include "unit.h"
typedef struct Swap Swap;
const char* swap_result_to_string(SwapResult i) _const_;
SwapResult swap_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(SWAP, Swap);
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include "unit.h"
+
/***
This file is part of systemd.
};
extern const UnitVTable target_vtable;
+
+DEFINE_CAST(TARGET, Target);
typedef struct Timer Timer;
#include "calendarspec.h"
+#include "unit.h"
typedef enum TimerBase {
TIMER_ACTIVE,
const char* timer_result_to_string(TimerResult i) _const_;
TimerResult timer_result_from_string(const char *s) _pure_;
+
+DEFINE_CAST(TIMER, Timer);
#include "sd-messages.h"
#include "alloc-util.h"
+#include "all-units.h"
#include "bus-common-errors.h"
#include "bus-util.h"
#include "cgroup-util.h"
#include <stdlib.h>
#include <unistd.h>
-typedef struct Unit Unit;
-typedef struct UnitVTable UnitVTable;
-typedef struct UnitRef UnitRef;
-typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
-
#include "bpf-program.h"
#include "condition.h"
#include "emergency-action.h"
#include "unit-name.h"
#include "cgroup.h"
+typedef struct UnitRef UnitRef;
+
typedef enum KillOperation {
KILL_TERMINATE,
KILL_TERMINATE_AND_LOG,
UNIT_CGROUP_BPF_INVALIDATED = -1,
} UnitCGroupBPFState;
-struct Unit {
+typedef struct Unit {
Manager *manager;
UnitType type;
/* When writing transient unit files, stores which section we stored last. If < 0, we didn't write any yet. If
* == 0 we are in the [Unit] section, if > 0 we are in the unit type-specific section. */
int last_section_private:2;
-};
+} Unit;
-struct UnitStatusMessageFormats {
+typedef struct UnitStatusMessageFormats {
const char *starting_stopping[2];
const char *finished_start_job[_JOB_RESULT_MAX];
const char *finished_stop_job[_JOB_RESULT_MAX];
-};
+} UnitStatusMessageFormats;
/* Flags used when writing drop-in files or transient unit files */
typedef enum UnitWriteFlags {
/* Returns true if neither persistent, nor runtime storage is requested, i.e. this is a check invocation only */
#define UNIT_WRITE_FLAGS_NOOP(flags) (((flags) & (UNIT_RUNTIME|UNIT_PERSISTENT)) == 0)
-#include "automount.h"
-#include "device.h"
-#include "path.h"
-#include "scope.h"
-#include "slice.h"
-#include "socket.h"
-#include "swap.h"
-#include "target.h"
-#include "timer.h"
-
-struct UnitVTable {
+#include "kill.h"
+
+typedef struct UnitVTable {
/* How much memory does an object of this unit type need */
size_t object_size;
/* True if queued jobs of this type should be GC'ed if no other job needs them anymore */
bool gc_jobs:1;
-};
+} UnitVTable;
extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
#define UNIT_TRIGGER(u) ((Unit*) hashmap_first_key((u)->dependencies[UNIT_TRIGGERS]))
-DEFINE_CAST(SERVICE, Service);
-DEFINE_CAST(SOCKET, Socket);
-DEFINE_CAST(TARGET, Target);
-DEFINE_CAST(DEVICE, Device);
-DEFINE_CAST(MOUNT, Mount);
-DEFINE_CAST(AUTOMOUNT, Automount);
-DEFINE_CAST(SWAP, Swap);
-DEFINE_CAST(TIMER, Timer);
-DEFINE_CAST(PATH, Path);
-DEFINE_CAST(SLICE, Slice);
-DEFINE_CAST(SCOPE, Scope);
-
Unit *unit_new(Manager *m, size_t size);
void unit_free(Unit *u);
DEFINE_TRIVIAL_CLEANUP_FUNC(Unit *, unit_free);
}
static inline uint64_t storage_size_max(void) {
- return arg_storage == COREDUMP_STORAGE_EXTERNAL ? arg_external_size_max : arg_journal_size_max;
+ if (arg_storage == COREDUMP_STORAGE_EXTERNAL)
+ return arg_external_size_max;
+ if (arg_storage == COREDUMP_STORAGE_JOURNAL)
+ return arg_journal_size_max;
+ assert(arg_storage == COREDUMP_STORAGE_NONE);
+ return 0;
}
static int fix_acl(int fd, uid_t uid) {
_cleanup_free_ char *fn = NULL, *tmp = NULL;
_cleanup_close_ int fd = -1;
- uint64_t rlimit, max_size;
+ uint64_t rlimit, process_limit, max_size;
struct stat st;
uid_t uid;
int r;
return -EBADSLT;
}
+ process_limit = MAX(arg_process_size_max, storage_size_max());
+ if (process_limit == 0) {
+ log_debug("Limits for coredump processing and storage are both 0, not dumping core.");
+ return -EBADSLT;
+ }
+
/* Never store more than the process configured, or than we actually shall keep or process */
- max_size = MIN(rlimit, MAX(arg_process_size_max, storage_size_max()));
+ max_size = MIN(rlimit, process_limit);
r = make_filename(context, &fn);
if (r < 0)
Context *c = userdata;
const char *name;
int interactive;
- char *h;
int r;
assert(m);
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- h = strdup(name);
- if (!h)
- return -ENOMEM;
-
- free(c->data[PROP_HOSTNAME]);
- c->data[PROP_HOSTNAME] = h;
+ r = free_and_strdup(&c->data[PROP_HOSTNAME], name);
+ if (r < 0)
+ return r;
r = context_update_kernel_hostname(c);
if (r < 0) {
if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
return sd_bus_reply_method_return(m, NULL);
+ if (!isempty(name) && !hostname_is_valid(name, false))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
+
r = bus_verify_polkit_async(
m,
CAP_SYS_ADMIN,
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- if (isempty(name))
- c->data[PROP_STATIC_HOSTNAME] = mfree(c->data[PROP_STATIC_HOSTNAME]);
- else {
- char *h;
-
- if (!hostname_is_valid(name, false))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
-
- h = strdup(name);
- if (!h)
- return -ENOMEM;
-
- free(c->data[PROP_STATIC_HOSTNAME]);
- c->data[PROP_STATIC_HOSTNAME] = h;
- }
+ r = free_and_strdup(&c->data[PROP_STATIC_HOSTNAME], name);
+ if (r < 0)
+ return r;
r = context_update_kernel_hostname(c);
if (r < 0) {
if (streq_ptr(name, c->data[prop]))
return sd_bus_reply_method_return(m, NULL);
+ if (!isempty(name)) {
+ /* The icon name might ultimately be used as file
+ * name, so better be safe than sorry */
+
+ if (prop == PROP_ICON_NAME && !filename_is_valid(name))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
+ if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
+ if (prop == PROP_CHASSIS && !valid_chassis(name))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
+ if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
+ if (prop == PROP_LOCATION && string_has_cc(name, NULL))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
+ }
+
/* Since the pretty hostname should always be changed at the
* same time as the static one, use the same policy action for
* both... */
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- if (isempty(name))
- c->data[prop] = mfree(c->data[prop]);
- else {
- char *h;
-
- /* The icon name might ultimately be used as file
- * name, so better be safe than sorry */
-
- if (prop == PROP_ICON_NAME && !filename_is_valid(name))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
- if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
- if (prop == PROP_CHASSIS && !valid_chassis(name))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
- if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
- if (prop == PROP_LOCATION && string_has_cc(name, NULL))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
-
- h = strdup(name);
- if (!h)
- return -ENOMEM;
-
- free(c->data[prop]);
- c->data[prop] = h;
- }
+ r = free_and_strdup(&c->data[prop], name);
+ if (r < 0)
+ return r;
r = context_write_data_machine_info(c);
if (r < 0) {
* then masks off the part it's not allowed to read. Because the
* string is aligned, the masked-off tail is in the same word as the
* rest of the string. Every machine with memory protection I've seen
- * does it on word boundaries, so is OK with this. But VALGRIND will
+ * does it on word boundaries, so is OK with this. But valgrind will
* still catch it and complain. The masking trick does make the hash
* noticeably faster for short strings (like English words).
*/
-#if !defined(VALGRIND) && !defined(__SANITIZE_ADDRESS__)
+#if !VALGRIND && !defined(__SANITIZE_ADDRESS__)
switch(length)
{
* then masks off the part it's not allowed to read. Because the
* string is aligned, the masked-off tail is in the same word as the
* rest of the string. Every machine with memory protection I've seen
- * does it on word boundaries, so is OK with this. But VALGRIND will
+ * does it on word boundaries, so is OK with this. But valgrind will
* still catch it and complain. The masking trick does make the hash
* noticeably faster for short strings (like English words).
*/
-#if !defined(VALGRIND) && !defined(__SANITIZE_ADDRESS__)
+#if !VALGRIND && !defined(__SANITIZE_ADDRESS__)
switch(length)
{
* then shifts out the part it's not allowed to read. Because the
* string is aligned, the illegal read is in the same word as the
* rest of the string. Every machine with memory protection I've seen
- * does it on word boundaries, so is OK with this. But VALGRIND will
+ * does it on word boundaries, so is OK with this. But valgrind will
* still catch it and complain. The masking trick does make the hash
* noticeably faster for short strings (like English words).
*/
-#if !defined(VALGRIND) && !defined(__SANITIZE_ADDRESS__)
+#if !VALGRIND && !defined(__SANITIZE_ADDRESS__)
switch(length)
{
#include "alloc-util.h"
#include "catalog.h"
#include "fd-util.h"
+#include "fs-util.h"
#include "fileio.h"
#include "log.h"
#include "macro.h"
NULL
};
-static Hashmap * test_import(const char* contents, ssize_t size, int code) {
- int r;
- char name[] = "/tmp/test-catalog.XXXXXX";
+static Hashmap* test_import(const char* contents, ssize_t size, int code) {
+ _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-catalog.XXXXXX";
_cleanup_close_ int fd;
Hashmap *h;
assert_se(fd >= 0);
assert_se(write(fd, contents, size) == size);
- r = catalog_import_file(h, name);
- assert_se(r == code);
-
- unlink(name);
+ assert_se(catalog_import_file(h, name) == code);
return h;
}
}
}
-static const char* database = NULL;
-
-static void test_catalog_update(void) {
- static char name[] = "/tmp/test-catalog.XXXXXX";
+static void test_catalog_update(const char *database) {
int r;
- r = mkostemp_safe(name);
- assert_se(r >= 0);
-
- database = name;
-
/* Test what happens if there are no files. */
r = catalog_update(database, NULL, NULL);
assert_se(r == 0);
}
int main(int argc, char *argv[]) {
+ _cleanup_(unlink_tempfilep) char database[] = "/tmp/test-catalog.XXXXXX";
_cleanup_free_ char *text = NULL;
int r;
test_catalog_import_merge();
test_catalog_import_merge_no_body();
- test_catalog_update();
+ assert_se(mkostemp_safe(database) >= 0);
+
+ test_catalog_update(database);
r = catalog_list(stdout, database, true);
assert_se(r >= 0);
assert_se(catalog_get(database, SD_MESSAGE_COREDUMP, &text) >= 0);
printf(">>>%s<<<\n", text);
- if (database)
- unlink(database);
-
return 0;
}
#include "compress.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "macro.h"
#include "path-util.h"
#include "random-util.h"
const char *srcfile) {
_cleanup_close_ int src = -1, dst = -1, dst2 = -1;
- char pattern[] = "/tmp/systemd-test.compressed.XXXXXX",
- pattern2[] = "/tmp/systemd-test.compressed.XXXXXX";
+ _cleanup_(unlink_tempfilep) char
+ pattern[] = "/tmp/systemd-test.compressed.XXXXXX",
+ pattern2[] = "/tmp/systemd-test.compressed.XXXXXX";
int r;
_cleanup_free_ char *cmd = NULL, *cmd2 = NULL;
struct stat st = {};
assert_se(lseek(dst2, 0, SEEK_SET) == 0);
r = decompress(dst, dst2, st.st_size - 1);
assert_se(r == -EFBIG);
-
- assert_se(unlink(pattern) == 0);
- assert_se(unlink(pattern2) == 0);
}
#endif
test_discover_message(e);
test_addr_acq(e);
-#ifdef VALGRIND
+#if VALGRIND
/* Make sure the async_close thread has finished.
* valgrind would report some of the phread_* structures
* as not cleaned up properly. */
#include "bus-util.h"
#include "fd-util.h"
#include "format-util.h"
+#include "pager.h"
#include "process-util.h"
#include "signal-util.h"
#include "strv.h"
static const char* arg_who = NULL;
static const char* arg_why = "Unknown reason";
static const char* arg_mode = NULL;
+static bool arg_no_pager = false;
static enum {
ACTION_INHIBIT,
unsigned n = 0;
int r;
+ (void) pager_open(arg_no_pager, false);
+
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"Execute a process while inhibiting shutdown/sleep/idle.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
+ " --no-pager Do not pipe output into a pager\n"
" --what=WHAT Operations to inhibit, colon separated list of:\n"
" shutdown, sleep, idle, handle-power-key,\n"
" handle-suspend-key, handle-hibernate-key,\n"
ARG_WHY,
ARG_MODE,
ARG_LIST,
+ ARG_NO_PAGER,
};
static const struct option options[] = {
{ "why", required_argument, NULL, ARG_WHY },
{ "mode", required_argument, NULL, ARG_MODE },
{ "list", no_argument, NULL, ARG_LIST },
+ { "no-pager", no_argument, NULL, ARG_NO_PAGER },
{}
};
arg_action = ACTION_LIST;
break;
+ case ARG_NO_PAGER:
+ arg_no_pager = true;
+ break;
+
case '?':
return -EINVAL;
if (arg_action == ACTION_LIST) {
r = print_inhibitors(bus, &error);
+ pager_close();
if (r < 0) {
log_error("Failed to list inhibitors: %s", bus_error_message(&error, -r));
return EXIT_FAILURE;
}
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction);
-
-static int property_get_docked(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Manager *m = userdata;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- return sd_bus_message_append(reply, "b", manager_is_docked_or_external_displays(m));
-}
-
-static int property_get_current_sessions(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Manager *m = userdata;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->sessions));
-}
-
-static int property_get_current_inhibitors(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Manager *m = userdata;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->inhibitors));
-}
-
-static int property_get_compat_user_tasks_max(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(reply);
-
- return sd_bus_message_append(reply, "t", CGROUP_LIMIT_MAX);
-}
+static BUS_DEFINE_PROPERTY_GET(property_get_docked, "b", Manager, manager_is_docked_or_external_displays);
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_compat_user_tasks_max, "t", CGROUP_LIMIT_MAX);
+static BUS_DEFINE_PROPERTY_GET_REF(property_get_hashmap_size, "t", Hashmap *, (uint64_t) hashmap_size);
static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(Manager, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RuntimeDirectorySize", "t", bus_property_get_size, offsetof(Manager, runtime_dir_size), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("InhibitorsMax", "t", NULL, offsetof(Manager, inhibitors_max), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("NCurrentInhibitors", "t", property_get_current_inhibitors, 0, 0),
+ SD_BUS_PROPERTY("NCurrentInhibitors", "t", property_get_hashmap_size, offsetof(Manager, inhibitors), 0),
SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_current_sessions, 0, 0),
+ SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_hashmap_size, offsetof(Manager, sessions), 0),
SD_BUS_PROPERTY("UserTasksMax", "t", property_get_compat_user_tasks_max, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED),
#include "user-util.h"
#include "util.h"
+static BUS_DEFINE_PROPERTY_GET(property_get_can_multi_session, "b", Seat, seat_can_multi_session);
+static BUS_DEFINE_PROPERTY_GET(property_get_can_tty, "b", Seat, seat_can_tty);
+static BUS_DEFINE_PROPERTY_GET(property_get_can_graphical, "b", Seat, seat_can_graphical);
+
static int property_get_active_session(
sd_bus *bus,
const char *path,
return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p);
}
-static int property_get_can_multi_session(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Seat *s = userdata;
-
- assert(bus);
- assert(reply);
- assert(s);
-
- return sd_bus_message_append(reply, "b", seat_can_multi_session(s));
-}
-
-static int property_get_can_tty(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Seat *s = userdata;
-
- assert(bus);
- assert(reply);
- assert(s);
-
- return sd_bus_message_append(reply, "b", seat_can_tty(s));
-}
-
-static int property_get_can_graphical(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Seat *s = userdata;
-
- assert(bus);
- assert(reply);
- assert(s);
-
- return sd_bus_message_append(reply, "b", seat_can_graphical(s));
-}
-
static int property_get_sessions(
sd_bus *bus,
const char *path,
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, session_type, SessionType);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, session_class, SessionClass);
-
-static int property_get_active(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Session *s = userdata;
-
- assert(bus);
- assert(reply);
- assert(s);
-
- return sd_bus_message_append(reply, "b", session_is_active(s));
-}
-
-static int property_get_state(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Session *s = userdata;
-
- assert(bus);
- assert(reply);
- assert(s);
-
- return sd_bus_message_append(reply, "s", session_state_to_string(session_get_state(s)));
-}
+static BUS_DEFINE_PROPERTY_GET(property_get_active, "b", Session, session_is_active);
+static BUS_DEFINE_PROPERTY_GET2(property_get_state, "s", Session, session_get_state, session_state_to_string);
static int property_get_idle_hint(
sd_bus *bus,
#include "strv.h"
#include "user-util.h"
+static BUS_DEFINE_PROPERTY_GET2(property_get_state, "s", User, user_get_state, user_state_to_string);
+
static int property_get_display(
sd_bus *bus,
const char *path,
return sd_bus_message_append(reply, "(so)", u->display ? u->display->id : "", p);
}
-static int property_get_state(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- User *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- return sd_bus_message_append(reply, "s", user_state_to_string(user_get_state(u)));
-}
-
static int property_get_sessions(
sd_bus *bus,
const char *path,
#include "terminal-util.h"
#include "user-util.h"
-static int property_get_state(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Machine *m = userdata;
- const char *state;
- int r;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- state = machine_state_to_string(machine_get_state(m));
-
- r = sd_bus_message_append_basic(reply, 's', state);
- if (r < 0)
- return r;
-
- return 1;
-}
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
+static BUS_DEFINE_PROPERTY_GET2(property_get_state, "s", Machine, machine_get_state, machine_state_to_string);
static int property_get_netif(
sd_bus *bus,
return sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
}
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
-
int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Machine *m = userdata;
int r;
#include "unit-name.h"
#include "user-util.h"
-static int property_get_pool_path(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- return sd_bus_message_append(reply, "s", "/var/lib/machines");
-}
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_pool_path, "s", "/var/lib/machines");
static int property_get_pool_usage(
sd_bus *bus,
%struct-type
%includes
%%
-Exec.Boot, config_parse_boot, 0, 0
-Exec.ProcessTwo, config_parse_pid2, 0, 0
-Exec.Parameters, config_parse_strv, 0, offsetof(Settings, parameters)
-Exec.Environment, config_parse_strv, 0, offsetof(Settings, environment)
-Exec.User, config_parse_string, 0, offsetof(Settings, user)
-Exec.Capability, config_parse_capability, 0, offsetof(Settings, capability)
-Exec.DropCapability, config_parse_capability, 0, offsetof(Settings, drop_capability)
-Exec.KillSignal, config_parse_signal, 0, offsetof(Settings, kill_signal)
-Exec.Personality, config_parse_personality, 0, offsetof(Settings, personality)
-Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id)
-Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings, working_directory)
-Exec.PivotRoot, config_parse_pivot_root, 0, 0
-Exec.PrivateUsers, config_parse_private_users, 0, 0
-Exec.NotifyReady, config_parse_bool, 0, offsetof(Settings, notify_ready)
-Exec.SystemCallFilter, config_parse_syscall_filter,0, 0,
-Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
-Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
-Files.Bind, config_parse_bind, 0, 0
-Files.BindReadOnly, config_parse_bind, 1, 0
-Files.TemporaryFileSystem, config_parse_tmpfs, 0, 0
-Files.Overlay, config_parse_overlay, 0, 0
-Files.OverlayReadOnly, config_parse_overlay, 1, 0
-Files.PrivateUsersChown, config_parse_tristate, 0, offsetof(Settings, userns_chown)
-Network.Private, config_parse_tristate, 0, offsetof(Settings, private_network)
-Network.Interface, config_parse_strv, 0, offsetof(Settings, network_interfaces)
-Network.MACVLAN, config_parse_strv, 0, offsetof(Settings, network_macvlan)
-Network.IPVLAN, config_parse_strv, 0, offsetof(Settings, network_ipvlan)
-Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth)
-Network.VirtualEthernetExtra, config_parse_veth_extra, 0, 0
-Network.Bridge, config_parse_ifname, 0, offsetof(Settings, network_bridge)
-Network.Zone, config_parse_network_zone, 0, 0
-Network.Port, config_parse_expose_port, 0, 0
+Exec.Boot, config_parse_boot, 0, 0
+Exec.ProcessTwo, config_parse_pid2, 0, 0
+Exec.Parameters, config_parse_strv, 0, offsetof(Settings, parameters)
+Exec.Environment, config_parse_strv, 0, offsetof(Settings, environment)
+Exec.User, config_parse_string, 0, offsetof(Settings, user)
+Exec.Capability, config_parse_capability, 0, offsetof(Settings, capability)
+Exec.DropCapability, config_parse_capability, 0, offsetof(Settings, drop_capability)
+Exec.KillSignal, config_parse_signal, 0, offsetof(Settings, kill_signal)
+Exec.Personality, config_parse_personality, 0, offsetof(Settings, personality)
+Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id)
+Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings, working_directory)
+Exec.PivotRoot, config_parse_pivot_root, 0, 0
+Exec.PrivateUsers, config_parse_private_users, 0, 0
+Exec.NotifyReady, config_parse_bool, 0, offsetof(Settings, notify_ready)
+Exec.SystemCallFilter, config_parse_syscall_filter, 0, 0,
+Exec.LimitCPU, config_parse_rlimit, RLIMIT_CPU, offsetof(Settings, rlimit)
+Exec.LimitFSIZE, config_parse_rlimit, RLIMIT_FSIZE, offsetof(Settings, rlimit)
+Exec.LimitDATA, config_parse_rlimit, RLIMIT_DATA, offsetof(Settings, rlimit)
+Exec.LimitSTACK, config_parse_rlimit, RLIMIT_STACK, offsetof(Settings, rlimit)
+Exec.LimitCORE, config_parse_rlimit, RLIMIT_CORE, offsetof(Settings, rlimit)
+Exec.LimitRSS, config_parse_rlimit, RLIMIT_RSS, offsetof(Settings, rlimit)
+Exec.LimitNOFILE, config_parse_rlimit, RLIMIT_NOFILE, offsetof(Settings, rlimit)
+Exec.LimitAS, config_parse_rlimit, RLIMIT_AS, offsetof(Settings, rlimit)
+Exec.LimitNPROC, config_parse_rlimit, RLIMIT_NPROC, offsetof(Settings, rlimit)
+Exec.LimitMEMLOCK, config_parse_rlimit, RLIMIT_MEMLOCK, offsetof(Settings, rlimit)
+Exec.LimitLOCKS, config_parse_rlimit, RLIMIT_LOCKS, offsetof(Settings, rlimit)
+Exec.LimitSIGPENDING, config_parse_rlimit, RLIMIT_SIGPENDING, offsetof(Settings, rlimit)
+Exec.LimitMSGQUEUE, config_parse_rlimit, RLIMIT_MSGQUEUE, offsetof(Settings, rlimit)
+Exec.LimitNICE, config_parse_rlimit, RLIMIT_NICE, offsetof(Settings, rlimit)
+Exec.LimitRTPRIO, config_parse_rlimit, RLIMIT_RTPRIO, offsetof(Settings, rlimit)
+Exec.LimitRTTIME, config_parse_rlimit, RLIMIT_RTTIME, offsetof(Settings, rlimit)
+Exec.Hostname, config_parse_hostname, 0, offsetof(Settings, hostname)
+Exec.NoNewPrivileges, config_parse_tristate, 0, offsetof(Settings, no_new_privileges)
+Exec.OOMScoreAdjust, config_parse_oom_score_adjust, 0, 0
+Exec.CPUAffinity, config_parse_cpu_affinity, 0, 0
+Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
+Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
+Files.Bind, config_parse_bind, 0, 0
+Files.BindReadOnly, config_parse_bind, 1, 0
+Files.TemporaryFileSystem, config_parse_tmpfs, 0, 0
+Files.Overlay, config_parse_overlay, 0, 0
+Files.OverlayReadOnly, config_parse_overlay, 1, 0
+Files.PrivateUsersChown, config_parse_tristate, 0, offsetof(Settings, userns_chown)
+Network.Private, config_parse_tristate, 0, offsetof(Settings, private_network)
+Network.Interface, config_parse_strv, 0, offsetof(Settings, network_interfaces)
+Network.MACVLAN, config_parse_strv, 0, offsetof(Settings, network_macvlan)
+Network.IPVLAN, config_parse_strv, 0, offsetof(Settings, network_ipvlan)
+Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth)
+Network.VirtualEthernetExtra, config_parse_veth_extra, 0, 0
+Network.Bridge, config_parse_ifname, 0, offsetof(Settings, network_bridge)
+Network.Zone, config_parse_network_zone, 0, 0
+Network.Port, config_parse_expose_port, 0, 0
#include "alloc-util.h"
#include "cap-list.h"
#include "conf-parser.h"
+#include "cpu-set-util.h"
+#include "hostname-util.h"
#include "nspawn-network.h"
#include "nspawn-settings.h"
#include "parse-util.h"
#include "process-util.h"
+#include "rlimit-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
s->userns_mode = _USER_NAMESPACE_MODE_INVALID;
s->uid_shift = UID_INVALID;
s->uid_range = UID_INVALID;
+ s->no_new_privileges = -1;
s->read_only = -1;
s->volatile_mode = _VOLATILE_MODE_INVALID;
free(s->working_directory);
strv_free(s->syscall_whitelist);
strv_free(s->syscall_blacklist);
+ rlimit_free_all(s->rlimit);
+ free(s->hostname);
+ s->cpuset = cpu_set_mfree(s->cpuset);
strv_free(s->network_interfaces);
strv_free(s->network_macvlan);
return 0;
}
+
+int config_parse_hostname(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ char **s = data;
+
+ assert(rvalue);
+ assert(s);
+
+ if (!hostname_is_valid(rvalue, false)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid hostname, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
+ return log_oom();
+
+ return 0;
+}
+
+int config_parse_oom_score_adjust(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Settings *settings = data;
+ int oa, r;
+
+ assert(rvalue);
+ assert(settings);
+
+ if (isempty(rvalue)) {
+ settings->oom_score_adjust_set = false;
+ return 0;
+ }
+
+ r = parse_oom_score_adjust(rvalue, &oa);
+ if (r == -ERANGE) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ settings->oom_score_adjust = oa;
+ settings->oom_score_adjust_set = true;
+
+ return 0;
+}
+
+int config_parse_cpu_affinity(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
+ Settings *settings = data;
+ int ncpus;
+
+ assert(rvalue);
+ assert(settings);
+
+ ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
+ if (ncpus < 0)
+ return ncpus;
+
+ if (ncpus == 0) {
+ /* An empty assignment resets the CPU list */
+ settings->cpuset = cpu_set_mfree(settings->cpuset);
+ settings->cpuset_ncpus = 0;
+ return 0;
+ }
+
+ if (!settings->cpuset) {
+ settings->cpuset = TAKE_PTR(cpuset);
+ settings->cpuset_ncpus = (unsigned) ncpus;
+ return 0;
+ }
+
+ if (settings->cpuset_ncpus < (unsigned) ncpus) {
+ CPU_OR_S(CPU_ALLOC_SIZE(settings->cpuset_ncpus), cpuset, settings->cpuset, cpuset);
+ CPU_FREE(settings->cpuset);
+ settings->cpuset = TAKE_PTR(cpuset);
+ settings->cpuset_ncpus = (unsigned) ncpus;
+ return 0;
+ }
+
+ CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus), settings->cpuset, settings->cpuset, cpuset);
+
+ return 0;
+}
Copyright 2015 Lennart Poettering
***/
+#include <sched.h>
#include <stdio.h>
#include "sd-id128.h"
} UserNamespaceMode;
typedef enum SettingsMask {
- SETTING_START_MODE = 1 << 0,
- SETTING_ENVIRONMENT = 1 << 1,
- SETTING_USER = 1 << 2,
- SETTING_CAPABILITY = 1 << 3,
- SETTING_KILL_SIGNAL = 1 << 4,
- SETTING_PERSONALITY = 1 << 5,
- SETTING_MACHINE_ID = 1 << 6,
- SETTING_NETWORK = 1 << 7,
- SETTING_EXPOSE_PORTS = 1 << 8,
- SETTING_READ_ONLY = 1 << 9,
- SETTING_VOLATILE_MODE = 1 << 10,
- SETTING_CUSTOM_MOUNTS = 1 << 11,
- SETTING_WORKING_DIRECTORY = 1 << 12,
- SETTING_USERNS = 1 << 13,
- SETTING_NOTIFY_READY = 1 << 14,
- SETTING_PIVOT_ROOT = 1 << 15,
- SETTING_SYSCALL_FILTER = 1 << 16,
- _SETTINGS_MASK_ALL = (1 << 17) -1
+ SETTING_START_MODE = UINT64_C(1) << 0,
+ SETTING_ENVIRONMENT = UINT64_C(1) << 1,
+ SETTING_USER = UINT64_C(1) << 2,
+ SETTING_CAPABILITY = UINT64_C(1) << 3,
+ SETTING_KILL_SIGNAL = UINT64_C(1) << 4,
+ SETTING_PERSONALITY = UINT64_C(1) << 5,
+ SETTING_MACHINE_ID = UINT64_C(1) << 6,
+ SETTING_NETWORK = UINT64_C(1) << 7,
+ SETTING_EXPOSE_PORTS = UINT64_C(1) << 8,
+ SETTING_READ_ONLY = UINT64_C(1) << 9,
+ SETTING_VOLATILE_MODE = UINT64_C(1) << 10,
+ SETTING_CUSTOM_MOUNTS = UINT64_C(1) << 11,
+ SETTING_WORKING_DIRECTORY = UINT64_C(1) << 12,
+ SETTING_USERNS = UINT64_C(1) << 13,
+ SETTING_NOTIFY_READY = UINT64_C(1) << 14,
+ SETTING_PIVOT_ROOT = UINT64_C(1) << 15,
+ SETTING_SYSCALL_FILTER = UINT64_C(1) << 16,
+ SETTING_HOSTNAME = UINT64_C(1) << 17,
+ SETTING_NO_NEW_PRIVILEGES = UINT64_C(1) << 18,
+ SETTING_OOM_SCORE_ADJUST = UINT64_C(1) << 19,
+ SETTING_CPU_AFFINITY = UINT64_C(1) << 20,
+ SETTING_RLIMIT_FIRST = UINT64_C(1) << 21, /* we define one bit per resource limit here */
+ SETTING_RLIMIT_LAST = UINT64_C(1) << (21 + _RLIMIT_MAX - 1),
+ _SETTINGS_MASK_ALL = (UINT64_C(1) << (21 + _RLIMIT_MAX)) - 1
} SettingsMask;
typedef struct Settings {
bool notify_ready;
char **syscall_whitelist;
char **syscall_blacklist;
+ struct rlimit *rlimit[_RLIMIT_MAX];
+ char *hostname;
+ int no_new_privileges;
+ int oom_score_adjust;
+ bool oom_score_adjust_set;
+ cpu_set_t *cpuset;
+ unsigned cpuset_ncpus;
/* [Image] */
int read_only;
int config_parse_pid2(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_private_users(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_syscall_filter(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_hostname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_oom_score_adjust(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_cpu_affinity(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
#include "capability-util.h"
#include "cgroup-util.h"
#include "copy.h"
+#include "cpu-set-util.h"
#include "dev-setup.h"
#include "dissect-image.h"
#include "env-util.h"
#include "nspawn-settings.h"
#include "nspawn-setuid.h"
#include "nspawn-stub-pid1.h"
+#include "pager.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "ptyfwd.h"
#include "random-util.h"
#include "raw-clone.h"
+#include "rlimit-util.h"
#include "rm-rf.h"
#include "selinux-util.h"
#include "signal-util.h"
static char *arg_pivot_root_old = NULL;
static char *arg_user = NULL;
static sd_id128_t arg_uuid = {};
-static char *arg_machine = NULL;
+static char *arg_machine = NULL; /* The name used by the host to refer to this */
+static char *arg_hostname = NULL; /* The name the payload sees by default */
static const char *arg_selinux_context = NULL;
static const char *arg_selinux_apifs_context = NULL;
static const char *arg_slice = NULL;
static size_t arg_root_hash_size = 0;
static char **arg_syscall_whitelist = NULL;
static char **arg_syscall_blacklist = NULL;
+static struct rlimit *arg_rlimit[_RLIMIT_MAX] = {};
+static bool arg_no_new_privileges = false;
+static int arg_oom_score_adjust = 0;
+static bool arg_oom_score_adjust_set = false;
+static cpu_set_t *arg_cpuset = NULL;
+static unsigned arg_cpuset_ncpus = 0;
static void help(void) {
+
+ (void) pager_open(false, false);
+
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
"Spawn a minimal namespace container for debugging, testing and building.\n\n"
" -h --help Show this help\n"
" Pivot root to given directory in the container\n"
" -u --user=USER Run the command under specified user or uid\n"
" -M --machine=NAME Set the machine name for the container\n"
+ " --hostname=NAME Override the hostname for the container\n"
" --uuid=UUID Set a specific machine UUID for the container\n"
" -S --slice=SLICE Place the container in the specified slice\n"
" --property=NAME=VALUE Set scope unit property\n"
" --drop-capability=CAP Drop the specified capability from the default set\n"
" --system-call-filter=LIST|~LIST\n"
" Permit/prohibit specific system calls\n"
+ " --rlimit=NAME=LIMIT Set a resource limit for the payload\n"
+ " --oom-score-adjust=VALUE\n"
+ " Adjust the OOM score value for the payload\n"
+ " --cpu-affinity=CPUS Adjust the CPU affinity of the container\n"
" --kill-signal=SIGNAL Select signal to use for shutting down PID 1\n"
" --link-journal=MODE Link up guest journal, one of no, auto, guest, \n"
" host, try-guest, try-host\n"
ARG_NOTIFY_READY,
ARG_ROOT_HASH,
ARG_SYSTEM_CALL_FILTER,
+ ARG_RLIMIT,
+ ARG_HOSTNAME,
+ ARG_NO_NEW_PRIVILEGES,
+ ARG_OOM_SCORE_ADJUST,
+ ARG_CPU_AFFINITY,
};
static const struct option options[] = {
{ "read-only", no_argument, NULL, ARG_READ_ONLY },
{ "capability", required_argument, NULL, ARG_CAPABILITY },
{ "drop-capability", required_argument, NULL, ARG_DROP_CAPABILITY },
+ { "no-new-privileges", required_argument, NULL, ARG_NO_NEW_PRIVILEGES },
{ "link-journal", required_argument, NULL, ARG_LINK_JOURNAL },
{ "bind", required_argument, NULL, ARG_BIND },
{ "bind-ro", required_argument, NULL, ARG_BIND_RO },
{ "overlay", required_argument, NULL, ARG_OVERLAY },
{ "overlay-ro", required_argument, NULL, ARG_OVERLAY_RO },
{ "machine", required_argument, NULL, 'M' },
+ { "hostname", required_argument, NULL, ARG_HOSTNAME },
{ "slice", required_argument, NULL, 'S' },
{ "setenv", required_argument, NULL, 'E' },
{ "selinux-context", required_argument, NULL, 'Z' },
{ "notify-ready", required_argument, NULL, ARG_NOTIFY_READY },
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
{ "system-call-filter", required_argument, NULL, ARG_SYSTEM_CALL_FILTER },
+ { "rlimit", required_argument, NULL, ARG_RLIMIT },
+ { "oom-score-adjust", required_argument, NULL, ARG_OOM_SCORE_ADJUST },
+ { "cpu-affinity", required_argument, NULL, ARG_CPU_AFFINITY },
{}
};
}
break;
+ case ARG_HOSTNAME:
+ if (isempty(optarg))
+ arg_hostname = mfree(arg_hostname);
+ else {
+ if (!hostname_is_valid(optarg, false)) {
+ log_error("Invalid hostname: %s", optarg);
+ return -EINVAL;
+ }
+
+ r = free_and_strdup(&arg_hostname, optarg);
+ if (r < 0)
+ return log_oom();
+ }
+
+ arg_settings_mask |= SETTING_HOSTNAME;
+ break;
+
case 'Z':
arg_selinux_context = optarg;
break;
break;
}
+ case ARG_NO_NEW_PRIVILEGES:
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --no-new-privileges= argument: %s", optarg);
+
+ arg_no_new_privileges = r;
+ arg_settings_mask |= SETTING_NO_NEW_PRIVILEGES;
+ break;
+
case 'j':
arg_link_journal = LINK_GUEST;
arg_link_journal_try = true;
break;
}
+ case ARG_RLIMIT: {
+ const char *eq;
+ char *name;
+ int rl;
+
+ eq = strchr(optarg, '=');
+ if (!eq) {
+ log_error("--rlimit= expects an '=' assignment.");
+ return -EINVAL;
+ }
+
+ name = strndup(optarg, eq - optarg);
+ if (!name)
+ return log_oom();
+
+ rl = rlimit_from_string_harder(name);
+ if (rl < 0) {
+ log_error("Unknown resource limit: %s", name);
+ return -EINVAL;
+ }
+
+ if (!arg_rlimit[rl]) {
+ arg_rlimit[rl] = new0(struct rlimit, 1);
+ if (!arg_rlimit[rl])
+ return log_oom();
+ }
+
+ r = rlimit_parse(rl, eq + 1, arg_rlimit[rl]);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse resource limit: %s", eq + 1);
+
+ arg_settings_mask |= SETTING_RLIMIT_FIRST << rl;
+ break;
+ }
+
+ case ARG_OOM_SCORE_ADJUST:
+ r = parse_oom_score_adjust(optarg, &arg_oom_score_adjust);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --oom-score-adjust= parameter: %s", optarg);
+
+ arg_oom_score_adjust_set = true;
+ arg_settings_mask |= SETTING_OOM_SCORE_ADJUST;
+ break;
+
+ case ARG_CPU_AFFINITY: {
+ _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
+
+ r = parse_cpu_set(optarg, &cpuset);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse CPU affinity mask: %s", optarg);
+
+ if (arg_cpuset)
+ CPU_FREE(arg_cpuset);
+
+ arg_cpuset = TAKE_PTR(cpuset);
+ arg_cpuset_ncpus = r;
+ arg_settings_mask |= SETTING_CPU_AFFINITY;
+ break;
+ }
+
case '?':
return -EINVAL;
}
static int setup_hostname(void) {
+ int r;
if ((arg_clone_ns_flags & CLONE_NEWUTS) == 0)
return 0;
- if (sethostname_idempotent(arg_machine) < 0)
- return -errno;
+ r = sethostname_idempotent(arg_hostname ?: arg_machine);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set hostname: %m");
return 0;
}
NULL
};
const char *exec_target;
-
_cleanup_strv_free_ char **env_use = NULL;
int r;
rtnl_socket = safe_close(rtnl_socket);
}
+ if (arg_oom_score_adjust_set) {
+ r = set_oom_score_adjust(arg_oom_score_adjust);
+ if (r < 0)
+ return log_error_errno(r, "Failed to adjust OOM score: %m");
+ }
+
+ if (arg_cpuset)
+ if (sched_setaffinity(0, CPU_ALLOC_SIZE(arg_cpuset_ncpus), arg_cpuset) < 0)
+ return log_error_errno(errno, "Failed to set CPU affinity: %m");
+
r = drop_capabilities();
if (r < 0)
return log_error_errno(r, "drop_capabilities() failed: %m");
- setup_hostname();
+ (void) setup_hostname();
if (arg_personality != PERSONALITY_INVALID) {
r = safe_personality(arg_personality);
if (r < 0)
return r;
+ if (arg_no_new_privileges)
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0)
+ return log_error_errno(errno, "Failed to disable new privileges: %m");
+
/* LXC sets container=lxc, so follow the scheme here */
envp[n_env++] = strjoina("container=", arg_container_service_name);
FDSet *fds,
int netns_fd) {
+ _cleanup_close_ int fd = -1;
+ int r, which_failed;
pid_t pid;
ssize_t l;
- int r;
- _cleanup_close_ int fd = -1;
assert(barrier);
assert(directory);
if (fd < 0)
return fd;
+ r = setrlimit_closest_all((const struct rlimit *const*) arg_rlimit, &which_failed);
+ if (r < 0)
+ return log_error_errno(r, "Failed to apply resource limit RLIMIT_%s: %m", rlimit_to_string(which_failed));
+
pid = raw_clone(SIGCHLD|CLONE_NEWNS|
arg_clone_ns_flags |
(arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER : 0));
return 0;
}
-static int load_settings(void) {
- _cleanup_(settings_freep) Settings *settings = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *p = NULL;
- const char *fn, *i;
- int r;
-
- /* If all settings are masked, there's no point in looking for
- * the settings file */
- if ((arg_settings_mask & _SETTINGS_MASK_ALL) == _SETTINGS_MASK_ALL)
- return 0;
+static int merge_settings(Settings *settings, const char *path) {
+ int rl;
- fn = strjoina(arg_machine, ".nspawn");
+ assert(settings);
+ assert(path);
- /* We first look in the admin's directories in /etc and /run */
- FOREACH_STRING(i, "/etc/systemd/nspawn", "/run/systemd/nspawn") {
- _cleanup_free_ char *j = NULL;
-
- j = strjoin(i, "/", fn);
- if (!j)
- return log_oom();
-
- f = fopen(j, "re");
- if (f) {
- p = TAKE_PTR(j);
-
- /* By default, we trust configuration from /etc and /run */
- if (arg_settings_trusted < 0)
- arg_settings_trusted = true;
-
- break;
- }
-
- if (errno != ENOENT)
- return log_error_errno(errno, "Failed to open %s: %m", j);
- }
-
- if (!f) {
- /* After that, let's look for a file next to the
- * actual image we shall boot. */
-
- if (arg_image) {
- p = file_in_same_dir(arg_image, fn);
- if (!p)
- return log_oom();
- } else if (arg_directory) {
- p = file_in_same_dir(arg_directory, fn);
- if (!p)
- return log_oom();
- }
-
- if (p) {
- f = fopen(p, "re");
- if (!f && errno != ENOENT)
- return log_error_errno(errno, "Failed to open %s: %m", p);
-
- /* By default, we do not trust configuration from /var/lib/machines */
- if (arg_settings_trusted < 0)
- arg_settings_trusted = false;
- }
- }
-
- if (!f)
- return 0;
-
- log_debug("Settings are trusted: %s", yes_no(arg_settings_trusted));
-
- r = settings_load(f, p, &settings);
- if (r < 0)
- return r;
-
- /* Copy over bits from the settings, unless they have been
- * explicitly masked by command line switches. */
+ /* Copy over bits from the settings, unless they have been explicitly masked by command line switches. Note
+ * that this steals the fields of the Settings* structure, and hence modifies it. */
if ((arg_settings_mask & SETTING_START_MODE) == 0 &&
settings->start_mode >= 0) {
if (!arg_settings_trusted && plus != 0) {
if (settings->capability != 0)
- log_warning("Ignoring Capability= setting, file %s is not trusted.", p);
+ log_warning("Ignoring Capability= setting, file %s is not trusted.", path);
} else
arg_caps_retain |= plus;
!sd_id128_is_null(settings->machine_id)) {
if (!arg_settings_trusted)
- log_warning("Ignoring MachineID= setting, file %s is not trusted.", p);
+ log_warning("Ignoring MachineID= setting, file %s is not trusted.", path);
else
arg_uuid = settings->machine_id;
}
settings->n_custom_mounts > 0) {
if (!arg_settings_trusted)
- log_warning("Ignoring TemporaryFileSystem=, Bind= and BindReadOnly= settings, file %s is not trusted.", p);
+ log_warning("Ignoring TemporaryFileSystem=, Bind= and BindReadOnly= settings, file %s is not trusted.", path);
else {
custom_mount_free_all(arg_custom_mounts, arg_n_custom_mounts);
arg_custom_mounts = TAKE_PTR(settings->custom_mounts);
settings->network_veth_extra)) {
if (!arg_settings_trusted)
- log_warning("Ignoring network settings, file %s is not trusted.", p);
+ log_warning("Ignoring network settings, file %s is not trusted.", path);
else {
arg_network_veth = settings_network_veth(settings);
arg_private_network = settings_private_network(settings);
settings->expose_ports) {
if (!arg_settings_trusted)
- log_warning("Ignoring Port= setting, file %s is not trusted.", p);
+ log_warning("Ignoring Port= setting, file %s is not trusted.", path);
else {
expose_port_free_all(arg_expose_ports);
arg_expose_ports = TAKE_PTR(settings->expose_ports);
settings->userns_mode != _USER_NAMESPACE_MODE_INVALID) {
if (!arg_settings_trusted)
- log_warning("Ignoring PrivateUsers= and PrivateUsersChown= settings, file %s is not trusted.", p);
+ log_warning("Ignoring PrivateUsers= and PrivateUsersChown= settings, file %s is not trusted.", path);
else {
arg_userns_mode = settings->userns_mode;
arg_uid_shift = settings->uid_shift;
if ((arg_settings_mask & SETTING_SYSCALL_FILTER) == 0) {
if (!arg_settings_trusted && !strv_isempty(arg_syscall_whitelist))
- log_warning("Ignoring SystemCallFilter= settings, file %s is not trusted.", p);
+ log_warning("Ignoring SystemCallFilter= settings, file %s is not trusted.", path);
else {
strv_free_and_replace(arg_syscall_whitelist, settings->syscall_whitelist);
strv_free_and_replace(arg_syscall_blacklist, settings->syscall_blacklist);
}
}
+ for (rl = 0; rl < _RLIMIT_MAX; rl ++) {
+ if ((arg_settings_mask & (SETTING_RLIMIT_FIRST << rl)))
+ continue;
+
+ if (!settings->rlimit[rl])
+ continue;
+
+ if (!arg_settings_trusted) {
+ log_warning("Ignoring Limit%s= setting, file '%s' is not trusted.", rlimit_to_string(rl), path);
+ continue;
+ }
+
+ free_and_replace(arg_rlimit[rl], settings->rlimit[rl]);
+ }
+
+ if ((arg_settings_mask & SETTING_HOSTNAME) == 0 &&
+ settings->hostname)
+ free_and_replace(arg_hostname, settings->hostname);
+
+ if ((arg_settings_mask & SETTING_NO_NEW_PRIVILEGES) == 0 &&
+ settings->no_new_privileges >= 0)
+ arg_no_new_privileges = settings->no_new_privileges;
+
+ if ((arg_settings_mask & SETTING_OOM_SCORE_ADJUST) == 0 &&
+ settings->oom_score_adjust_set) {
+
+ if (!arg_settings_trusted)
+ log_warning("Ignoring OOMScoreAdjust= setting, file '%s' is not trusted.", path);
+ else {
+ arg_oom_score_adjust = settings->oom_score_adjust;
+ arg_oom_score_adjust_set = true;
+ }
+ }
+
+ if ((arg_settings_mask & SETTING_CPU_AFFINITY) == 0 &&
+ settings->cpuset) {
+
+ if (!arg_settings_trusted)
+ log_warning("Ignoring CPUAffinity= setting, file '%s' is not trusted.", path);
+ else {
+ if (arg_cpuset)
+ CPU_FREE(arg_cpuset);
+ arg_cpuset = TAKE_PTR(settings->cpuset);
+ arg_cpuset_ncpus = settings->cpuset_ncpus;
+ }
+ }
+
return 0;
}
+static int load_settings(void) {
+ _cleanup_(settings_freep) Settings *settings = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *p = NULL;
+ const char *fn, *i;
+ int r;
+
+ /* If all settings are masked, there's no point in looking for
+ * the settings file */
+ if ((arg_settings_mask & _SETTINGS_MASK_ALL) == _SETTINGS_MASK_ALL)
+ return 0;
+
+ fn = strjoina(arg_machine, ".nspawn");
+
+ /* We first look in the admin's directories in /etc and /run */
+ FOREACH_STRING(i, "/etc/systemd/nspawn", "/run/systemd/nspawn") {
+ _cleanup_free_ char *j = NULL;
+
+ j = strjoin(i, "/", fn);
+ if (!j)
+ return log_oom();
+
+ f = fopen(j, "re");
+ if (f) {
+ p = TAKE_PTR(j);
+
+ /* By default, we trust configuration from /etc and /run */
+ if (arg_settings_trusted < 0)
+ arg_settings_trusted = true;
+
+ break;
+ }
+
+ if (errno != ENOENT)
+ return log_error_errno(errno, "Failed to open %s: %m", j);
+ }
+
+ if (!f) {
+ /* After that, let's look for a file next to the
+ * actual image we shall boot. */
+
+ if (arg_image) {
+ p = file_in_same_dir(arg_image, fn);
+ if (!p)
+ return log_oom();
+ } else if (arg_directory) {
+ p = file_in_same_dir(arg_directory, fn);
+ if (!p)
+ return log_oom();
+ }
+
+ if (p) {
+ f = fopen(p, "re");
+ if (!f && errno != ENOENT)
+ return log_error_errno(errno, "Failed to open %s: %m", p);
+
+ /* By default, we do not trust configuration from /var/lib/machines */
+ if (arg_settings_trusted < 0)
+ arg_settings_trusted = false;
+ }
+ }
+
+ if (!f)
+ return 0;
+
+ log_debug("Settings are trusted: %s", yes_no(arg_settings_trusted));
+
+ r = settings_load(f, p, &settings);
+ if (r < 0)
+ return r;
+
+ return merge_settings(settings, p);
+}
+
static int run(int master,
const char* console,
DissectedImage *dissected_image,
"STATUS=Container running.\n"
"X_NSPAWN_LEADER_PID=" PID_FMT, *pid);
if (!arg_notify_ready)
- sd_notify(false, "READY=1\n");
+ (void) sd_notify(false, "READY=1\n");
if (arg_kill_signal > 0) {
/* Try to kill the init system on SIGINT or SIGTERM */
- sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, PID_TO_PTR(*pid));
- sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, PID_TO_PTR(*pid));
+ (void) sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, PID_TO_PTR(*pid));
+ (void) sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, PID_TO_PTR(*pid));
} else {
/* Immediately exit */
- sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
- sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
+ (void) sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
+ (void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
}
/* Exit when the child exits */
- sd_event_add_signal(event, NULL, SIGCHLD, on_sigchld, PID_TO_PTR(*pid));
+ (void) sd_event_add_signal(event, NULL, SIGCHLD, on_sigchld, PID_TO_PTR(*pid));
if (arg_expose_ports) {
r = expose_port_watch_rtnl(event, rtnl_socket_pair[0], on_address_change, exposed, &rtnl);
return 1; /* loop again */
}
+static int initialize_rlimits(void) {
+
+ /* The default resource limits the kernel passes to PID 1, as per kernel 4.16. Let's pass our container payload
+ * the same values as the kernel originally passed to PID 1, in order to minimize differences between host and
+ * container execution environments. */
+
+ static const struct rlimit kernel_defaults[_RLIMIT_MAX] = {
+ [RLIMIT_AS] = { RLIM_INFINITY, RLIM_INFINITY },
+ [RLIMIT_CORE] = { 0, RLIM_INFINITY },
+ [RLIMIT_CPU] = { RLIM_INFINITY, RLIM_INFINITY },
+ [RLIMIT_DATA] = { RLIM_INFINITY, RLIM_INFINITY },
+ [RLIMIT_FSIZE] = { RLIM_INFINITY, RLIM_INFINITY },
+ [RLIMIT_LOCKS] = { RLIM_INFINITY, RLIM_INFINITY },
+ [RLIMIT_MEMLOCK] = { 65536, 65536 },
+ [RLIMIT_MSGQUEUE] = { 819200, 819200 },
+ [RLIMIT_NICE] = { 0, 0 },
+ [RLIMIT_NOFILE] = { 1024, 4096 },
+ [RLIMIT_RSS] = { RLIM_INFINITY, RLIM_INFINITY },
+ [RLIMIT_RTPRIO] = { 0, 0 },
+ [RLIMIT_RTTIME] = { RLIM_INFINITY, RLIM_INFINITY },
+ [RLIMIT_STACK] = { 8388608, RLIM_INFINITY },
+
+ /* The kernel scales the default for RLIMIT_NPROC and RLIMIT_SIGPENDING based on the system's amount of
+ * RAM. To provide best compatibility we'll read these limits off PID 1 instead of hardcoding them
+ * here. This is safe as we know that PID 1 doesn't change these two limits and thus the original
+ * kernel's initialization should still be valid during runtime — at least if PID 1 is systemd. Note
+ * that PID 1 changes a number of other resource limits during early initialization which is why we
+ * don't read the other limits from PID 1 but prefer the static table above. */
+ };
+
+ int rl;
+
+ for (rl = 0; rl < _RLIMIT_MAX; rl++) {
+
+ /* Let's only fill in what the user hasn't explicitly configured anyway */
+ if ((arg_settings_mask & (SETTING_RLIMIT_FIRST << rl)) == 0) {
+ const struct rlimit *v;
+ struct rlimit buffer;
+
+ if (IN_SET(rl, RLIMIT_NPROC, RLIMIT_SIGPENDING)) {
+ /* For these two let's read the limits off PID 1. See above for an explanation. */
+
+ if (prlimit(1, rl, NULL, &buffer) < 0)
+ return log_error_errno(errno, "Failed to read resource limit RLIMIT_%s of PID 1: %m", rlimit_to_string(rl));
+
+ v = &buffer;
+ } else
+ v = kernel_defaults + rl;
+
+ arg_rlimit[rl] = newdup(struct rlimit, v, 1);
+ if (!arg_rlimit[rl])
+ return log_oom();
+ }
+
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *k = NULL;
+
+ (void) rlimit_format(arg_rlimit[rl], &k);
+ log_debug("Setting RLIMIT_%s to %s.", rlimit_to_string(rl), k);
+ }
+ }
+
+ return 0;
+}
+
int main(int argc, char *argv[]) {
_cleanup_free_ char *console = NULL;
if (r < 0)
goto finish;
+ r = initialize_rlimits();
+ if (r < 0)
+ goto finish;
+
r = determine_names();
if (r < 0)
goto finish;
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1) >= 0);
- if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) {
+ if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) < 0) {
r = log_error_errno(errno, "Failed to become subreaper: %m");
goto finish;
}
if (pid > 0)
(void) wait_for_terminate(pid, NULL);
+ pager_close();
+
if (remove_directory && arg_directory) {
int k;
free(arg_template);
free(arg_image);
free(arg_machine);
+ free(arg_hostname);
free(arg_user);
free(arg_pivot_root_new);
free(arg_pivot_root_old);
custom_mount_free_all(arg_custom_mounts, arg_n_custom_mounts);
expose_port_free_all(arg_expose_ports);
free(arg_root_hash);
+ rlimit_free_all(arg_rlimit);
+ arg_cpuset = cpu_set_mfree(arg_cpuset);
return r < 0 ? EXIT_FAILURE : ret;
}
(uint64_t) m->n_dnssec_verdict[DNSSEC_INDETERMINATE]);
}
-static int bus_property_get_dnssec_supported(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Manager *m = userdata;
-
- assert(reply);
- assert(m);
-
- return sd_bus_message_append(reply, "b", manager_dnssec_supported(m));
-}
-
-static int bus_property_get_dnssec_mode(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Manager *m = userdata;
-
- assert(reply);
- assert(m);
-
- return sd_bus_message_append(reply, "s", dnssec_mode_to_string(manager_get_dnssec_mode(m)));
-}
-
static int bus_property_get_ntas(
sd_bus *bus,
const char *path,
}
static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_dns_stub_listener_mode, dns_stub_listener_mode, DnsStubListenerMode);
+static BUS_DEFINE_PROPERTY_GET(bus_property_get_dnssec_supported, "b", Manager, manager_dnssec_supported);
+static BUS_DEFINE_PROPERTY_GET2(bus_property_get_dnssec_mode, "s", Manager, manager_get_dnssec_mode, dnssec_mode_to_string);
static int bus_method_reset_statistics(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
#include "resolved-resolv-conf.h"
#include "strv.h"
-static int property_get_dnssec_mode(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Link *l = userdata;
-
- assert(reply);
- assert(l);
-
- return sd_bus_message_append(reply, "s", dnssec_mode_to_string(link_get_dnssec_mode(l)));
-}
+static BUS_DEFINE_PROPERTY_GET(property_get_dnssec_supported, "b", Link, link_dnssec_supported);
+static BUS_DEFINE_PROPERTY_GET2(property_get_dnssec_mode, "s", Link, link_get_dnssec_mode, dnssec_mode_to_string);
static int property_get_dns(
sd_bus *bus,
return sd_bus_message_close_container(reply);
}
-static int property_get_dnssec_supported(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Link *l = userdata;
-
- assert(reply);
- assert(l);
-
- return sd_bus_message_append(reply, "b", link_dnssec_supported(l));
-}
-
static int verify_unmanaged_link(Link *l, sd_bus_error *error) {
assert(l);
}
static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
- int r, rl;
+ const char *suffix;
+ int r;
if (STR_IN_SET(field,
"User", "Group",
return bus_append_byte_array(m, field, decoded, sz);
}
- rl = rlimit_from_string(field);
- if (rl >= 0) {
- const char *sn;
- struct rlimit l;
+ if ((suffix = startswith(field, "Limit"))) {
+ int rl;
- r = rlimit_parse(rl, eq, &l);
- if (r < 0)
- return log_error_errno(r, "Failed to parse resource limit: %s", eq);
+ rl = rlimit_from_string(suffix);
+ if (rl >= 0) {
+ const char *sn;
+ struct rlimit l;
- r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
- if (r < 0)
- return bus_log_create_error(r);
+ r = rlimit_parse(rl, eq, &l);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse resource limit: %s", eq);
- sn = strjoina(field, "Soft");
- r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
- if (r < 0)
- return bus_log_create_error(r);
+ r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
+ if (r < 0)
+ return bus_log_create_error(r);
- return 1;
+ sn = strjoina(field, "Soft");
+ r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+ }
}
if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) {
void *userdata,
sd_bus_error *error) {
+ const char *is_soft;
struct rlimit *rl;
uint64_t u;
rlim_t x;
- const char *is_soft;
assert(bus);
assert(reply);
assert(userdata);
is_soft = endswith(property, "Soft");
+
rl = *(struct rlimit**) userdata;
if (rl)
x = is_soft ? rl->rlim_cur : rl->rlim_max;
else {
struct rlimit buf = {};
+ const char *s, *p;
int z;
- const char *s;
+ /* Chop off "Soft" suffix */
s = is_soft ? strndupa(property, is_soft - property) : property;
- z = rlimit_from_string(strstr(s, "Limit"));
+ /* Skip over any prefix, such as "Default" */
+ assert_se(p = strstr(s, "Limit"));
+
+ z = rlimit_from_string(p + 5);
assert(z >= 0);
- getrlimit(z, &buf);
+ (void) getrlimit(z, &buf);
x = is_soft ? buf.rlim_cur : buf.rlim_max;
}
- /* rlim_t might have different sizes, let's map
- * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
- * all archs */
+ /* rlim_t might have different sizes, let's map RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on all
+ * archs */
u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
return sd_bus_message_append(reply, "t", u);
}
#define ident(x) (x)
-#define BUS_DEFINE_PROPERTY_GET(function, bus_type, data_type, get1) \
+#define BUS_DEFINE_PROPERTY_GET(function, bus_type, data_type, get1) \
BUS_DEFINE_PROPERTY_GET2(function, bus_type, data_type, get1, ident)
+#define ref(x) (*(x))
+#define BUS_DEFINE_PROPERTY_GET_REF(function, bus_type, data_type, get) \
+ BUS_DEFINE_PROPERTY_GET2(function, bus_type, data_type, ref, get)
+
#define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type) \
- int function(sd_bus *bus, \
- const char *path, \
- const char *interface, \
- const char *property, \
- sd_bus_message *reply, \
- void *userdata, \
- sd_bus_error *error) { \
- \
- const char *value; \
- type *field = userdata; \
- int r; \
- \
- assert(bus); \
- assert(reply); \
- assert(field); \
- \
- value = strempty(name##_to_string(*field)); \
- \
- r = sd_bus_message_append_basic(reply, 's', value); \
- if (r < 0) \
- return r; \
- \
- return 1; \
- }
+ BUS_DEFINE_PROPERTY_GET_REF(function, "s", type, name##_to_string)
#define BUS_PROPERTY_DUAL_TIMESTAMP(name, offset, flags) \
SD_BUS_PROPERTY(name, "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, realtime), (flags)), \
#include "syslog-util.h"
#include "time-util.h"
#include "utf8.h"
+#include "rlimit-util.h"
int config_item_table_lookup(
const void *table,
void *data,
void *userdata) {
- char **s = data, *n;
+ char **s = data;
assert(filename);
assert(lvalue);
return 0;
}
- if (isempty(rvalue))
- n = NULL;
- else {
- n = strdup(rvalue);
- if (!n)
- return log_oom();
- }
-
- free(*s);
- *s = n;
+ if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
+ return log_oom();
return 0;
}
return 0;
}
+
+int config_parse_rlimit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ struct rlimit **rl = data, d = {};
+ int r;
+
+ assert(rvalue);
+ assert(rl);
+
+ r = rlimit_parse(ltype, rvalue, &d);
+ if (r == -EILSEQ) {
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (rl[ltype])
+ *rl[ltype] = d;
+ else {
+ rl[ltype] = newdup(struct rlimit, &d, 1);
+ if (!rl[ltype])
+ return log_oom();
+ }
+
+ return 0;
+}
int config_parse_ip_port(GENERIC_PARSER_ARGS);
int config_parse_join_controllers(GENERIC_PARSER_ARGS);
int config_parse_mtu(GENERIC_PARSER_ARGS);
+int config_parse_rlimit(GENERIC_PARSER_ARGS);
typedef enum Disabled {
DISABLED_CONFIGURATION,
static int cat_config(void) {
_cleanup_strv_free_ char **files = NULL;
- _cleanup_free_ char *replace_file = NULL;
int r;
r = conf_files_list_with_replacement(arg_root, CONF_PATHS_STRV("sysusers.d"), arg_replace, &files, NULL);
#include "conf-parser.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "log.h"
#include "macro.h"
#include "string-util.h"
};
static void test_config_parse(unsigned i, const char *s) {
- char name[] = "/tmp/test-conf-parser.XXXXXX";
+ _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-conf-parser.XXXXXX";
int fd, r;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *setting1 = NULL;
#if HAVE_SECCOMP
#include "seccomp-util.h"
#endif
+#include "service.h"
#include "stat-util.h"
#include "test-helper.h"
#include "tests.h"
#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "io-util.h"
#include "parse-util.h"
#include "process-util.h"
#include "util.h"
static void test_parse_env_file(void) {
- char t[] = "/tmp/test-fileio-in-XXXXXX",
+ _cleanup_(unlink_tempfilep) char
+ t[] = "/tmp/test-fileio-in-XXXXXX",
p[] = "/tmp/test-fileio-out-XXXXXX";
int fd, r;
FILE *f;
r = load_env_file(NULL, p, NULL, &b);
assert_se(r >= 0);
-
- unlink(t);
- unlink(p);
}
static void test_parse_multiline_env_file(void) {
- char t[] = "/tmp/test-fileio-in-XXXXXX",
+ _cleanup_(unlink_tempfilep) char
+ t[] = "/tmp/test-fileio-in-XXXXXX",
p[] = "/tmp/test-fileio-out-XXXXXX";
int fd, r;
FILE *f;
r = load_env_file(NULL, p, NULL, &b);
assert_se(r >= 0);
-
- unlink(t);
- unlink(p);
}
static void test_merge_env_file(void) {
- char t[] = "/tmp/test-fileio-XXXXXX";
+ _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX";
int fd, r;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_strv_free_ char **a = NULL;
}
static void test_merge_env_file_invalid(void) {
- char t[] = "/tmp/test-fileio-XXXXXX";
+ _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX";
int fd, r;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_strv_free_ char **a = NULL;
}
static void test_executable_is_script(void) {
- char t[] = "/tmp/test-executable-XXXXXX";
+ _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX";
int fd, r;
- FILE *f;
+ _cleanup_fclose_ FILE *f = NULL;
char *command;
fd = mkostemp_safe(t);
assert_se(startswith(command, "/"));
free(command);
}
-
- fclose(f);
- unlink(t);
}
static void test_status_field(void) {
}
static void test_write_string_stream(void) {
- char fn[] = "/tmp/test-write_string_stream-XXXXXX";
- FILE *f = NULL;
+ _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-write_string_stream-XXXXXX";
+ _cleanup_fclose_ FILE *f = NULL;
int fd;
char buf[64];
assert_se(fgets(buf, sizeof(buf), f));
printf(">%s<", buf);
assert_se(streq(buf, "boohoo"));
- f = safe_fclose(f);
-
- unlink(fn);
}
static void test_write_string_file(void) {
- char fn[] = "/tmp/test-write_string_file-XXXXXX";
+ _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-write_string_file-XXXXXX";
char buf[64] = {};
_cleanup_close_ int fd;
assert_se(read(fd, buf, sizeof(buf)) == 7);
assert_se(streq(buf, "boohoo\n"));
-
- unlink(fn);
}
static void test_write_string_file_no_create(void) {
- char fn[] = "/tmp/test-write_string_file_no_create-XXXXXX";
+ _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-write_string_file_no_create-XXXXXX";
_cleanup_close_ int fd;
char buf[64] = {0};
assert_se(read(fd, buf, sizeof(buf)) == STRLEN("boohoo\n"));
assert_se(streq(buf, "boohoo\n"));
-
- unlink(fn);
}
static void test_write_string_file_verify(void) {
}
static void test_load_env_file_pairs(void) {
- char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX";
- int fd;
- int r;
+ _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX";
+ int fd, r;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_strv_free_ char **l = NULL;
char **k, **v;
if (streq(*k, "SUPPORT_URL")) assert_se(streq(*v, "https://bbs.archlinux.org/"));
if (streq(*k, "BUG_REPORT_URL")) assert_se(streq(*v, "https://bugs.archlinux.org/"));
}
-
- unlink(fn);
}
static void test_search_and_fopen(void) {
const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL};
+
char name[] = "/tmp/test-search_and_fopen.XXXXXX";
- int fd = -1;
- int r;
+ int fd, r;
FILE *f;
fd = mkostemp_safe(name);
static void test_search_and_fopen_nulstr(void) {
const char dirs[] = "/tmp/foo/bar\0/tmp\0";
- char name[] = "/tmp/test-search_and_fopen.XXXXXX";
- int fd = -1;
- int r;
+
+ _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-search_and_fopen.XXXXXX";
+ int fd, r;
FILE *f;
fd = mkostemp_safe(name);
}
static void test_writing_tmpfile(void) {
- char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX";
+ _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX";
_cleanup_free_ char *contents = NULL;
size_t size;
- int r;
_cleanup_close_ int fd = -1;
struct iovec iov[3];
+ int r;
iov[0] = IOVEC_MAKE_STRING("abc\n");
iov[1] = IOVEC_MAKE_STRING(ALPHANUMERICAL "\n");
assert_se(r == 0);
printf("contents: %s", contents);
assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n"));
-
- unlink(name);
}
static void test_tempfn(void) {
}
static void test_read_line2(void) {
- char name[] = "/tmp/test-fileio.XXXXXX";
+ _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-fileio.XXXXXX";
int fd;
_cleanup_fclose_ FILE *f = NULL;
#include <sys/types.h>
#include "alloc-util.h"
+#include "all-units.h"
#include "fd-util.h"
#include "fs-util.h"
#include "macro.h"
.rlim_cur = 10,
.rlim_max = 5,
};
+ int i;
log_parse_environment();
log_open();
new.rlim_max = old.rlim_max;
assert_se(setrlimit(RLIMIT_NOFILE, &new) >= 0);
- assert_se(rlimit_from_string("LimitNOFILE") == RLIMIT_NOFILE);
+ assert_se(rlimit_from_string("NOFILE") == RLIMIT_NOFILE);
+ assert_se(rlimit_from_string("LimitNOFILE") == -1);
+ assert_se(rlimit_from_string("RLIMIT_NOFILE") == -1);
+ assert_se(rlimit_from_string("xxxNOFILE") == -1);
assert_se(rlimit_from_string("DefaultLimitNOFILE") == -1);
- assert_se(streq_ptr(rlimit_to_string(RLIMIT_NOFILE), "LimitNOFILE"));
+ assert_se(rlimit_from_string_harder("NOFILE") == RLIMIT_NOFILE);
+ assert_se(rlimit_from_string_harder("LimitNOFILE") == RLIMIT_NOFILE);
+ assert_se(rlimit_from_string_harder("RLIMIT_NOFILE") == RLIMIT_NOFILE);
+ assert_se(rlimit_from_string_harder("xxxNOFILE") == -1);
+ assert_se(rlimit_from_string_harder("DefaultLimitNOFILE") == -1);
+
+ for (i = 0; i < _RLIMIT_MAX; i++) {
+ _cleanup_free_ char *prefixed = NULL;
+ const char *p;
+
+ assert_se(p = rlimit_to_string(i));
+ log_info("%i = %s", i, p);
+
+ assert_se(rlimit_from_string(p) == i);
+ assert_se(rlimit_from_string_harder(p) == i);
+
+ assert_se(prefixed = strjoin("Limit", p));
+
+ assert_se(rlimit_from_string(prefixed) < 0);
+ assert_se(rlimit_from_string_harder(prefixed) == i);
+
+ prefixed = mfree(prefixed);
+ assert_se(prefixed = strjoin("RLIMIT_", p));
+
+ assert_se(rlimit_from_string(prefixed) < 0);
+ assert_se(rlimit_from_string_harder(prefixed) == i);
+ }
+
+ assert_se(streq_ptr(rlimit_to_string(RLIMIT_NOFILE), "NOFILE"));
assert_se(rlimit_to_string(-1) == NULL);
assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0);
#include <sched.h>
+#include "all-units.h"
#include "macro.h"
#include "manager.h"
#include "rm-rf.h"
#include <unistd.h>
#include "alloc-util.h"
+#include "all-units.h"
#include "capability-util.h"
+#include "conf-parser.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "hashmap.h"
#include "hostname-util.h"
#include "install-printf.h"
_cleanup_strv_free_ char **data = NULL;
int r;
- char name[] = "/tmp/test-load-env-file.XXXXXX";
+ _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
_cleanup_close_ int fd;
fd = mkostemp_safe(name);
assert_se(streq(data[4], "h=h"));
assert_se(streq(data[5], "i=i"));
assert_se(data[6] == NULL);
- unlink(name);
}
static void test_load_env_file_2(void) {
_cleanup_strv_free_ char **data = NULL;
int r;
- char name[] = "/tmp/test-load-env-file.XXXXXX";
+ _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
_cleanup_close_ int fd;
fd = mkostemp_safe(name);
assert_se(r == 0);
assert_se(streq(data[0], "a=a"));
assert_se(data[1] == NULL);
- unlink(name);
}
static void test_load_env_file_3(void) {
_cleanup_strv_free_ char **data = NULL;
int r;
- char name[] = "/tmp/test-load-env-file.XXXXXX";
+ _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
_cleanup_close_ int fd;
fd = mkostemp_safe(name);
r = load_env_file(NULL, name, NULL, &data);
assert_se(r == 0);
assert_se(data == NULL);
- unlink(name);
}
static void test_load_env_file_4(void) {
_cleanup_strv_free_ char **data = NULL;
- char name[] = "/tmp/test-load-env-file.XXXXXX";
+ _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
_cleanup_close_ int fd;
int r;
assert_se(streq(data[1], "MODULE_0=coretemp"));
assert_se(streq(data[2], "MODULE_1=f71882fg"));
assert_se(data[3] == NULL);
- unlink(name);
}
static void test_load_env_file_5(void) {
_cleanup_strv_free_ char **data = NULL;
int r;
- char name[] = "/tmp/test-load-env-file.XXXXXX";
+ _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
_cleanup_close_ int fd;
fd = mkostemp_safe(name);
assert_se(streq(data[0], "a="));
assert_se(streq(data[1], "b="));
assert_se(data[2] == NULL);
- unlink(name);
}
static void test_install_printf(void) {
static void test_config_parse_rlimit(void) {
struct rlimit * rl[_RLIMIT_MAX] = {};
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0);
assert_se(rl[RLIMIT_NOFILE]);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0);
assert_se(rl[RLIMIT_NOFILE]);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0);
assert_se(rl[RLIMIT_NOFILE]);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0);
assert_se(rl[RLIMIT_NOFILE]);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
rl[RLIMIT_NOFILE]->rlim_max = 20;
/* Invalid values don't change rl */
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0);
assert_se(rl[RLIMIT_NOFILE]);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0);
assert_se(rl[RLIMIT_NOFILE]);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0);
assert_se(rl[RLIMIT_NOFILE]);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0);
assert_se(rl[RLIMIT_NOFILE]);
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
assert_se(rl[RLIMIT_CPU]);
assert_se(rl[RLIMIT_CPU]->rlim_cur == 56);
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0);
assert_se(rl[RLIMIT_CPU]);
assert_se(rl[RLIMIT_CPU]->rlim_cur == 57);
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0);
assert_se(rl[RLIMIT_CPU]);
assert_se(rl[RLIMIT_CPU]->rlim_cur == 40);
assert_se(rl[RLIMIT_CPU]->rlim_max == 60);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
assert_se(rl[RLIMIT_CPU]);
assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY);
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0);
assert_se(rl[RLIMIT_CPU]);
assert_se(rl[RLIMIT_CPU]->rlim_cur == 2);
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0);
assert_se(rl[RLIMIT_RTTIME]);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0);
assert_se(rl[RLIMIT_RTTIME]);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
assert_se(rl[RLIMIT_RTTIME]);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0);
assert_se(rl[RLIMIT_RTTIME]);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
assert_se(rl[RLIMIT_RTTIME]);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0);
assert_se(rl[RLIMIT_RTTIME]);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
- assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
+ assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
assert_se(rl[RLIMIT_RTTIME]);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC);
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
#include <string.h>
#include "alloc-util.h"
+#include "all-units.h"
#include "glob-util.h"
#include "hostname-util.h"
#include "macro.h"
#include "log.h"
#include "manager.h"
#include "rm-rf.h"
+#include "service.h"
#include "test-helper.h"
#include "tests.h"
<action id="org.freedesktop.timedate1.set-local-rtc">
<description gettext-domain="systemd">Set RTC to local timezone or UTC</description>
- <message gettext-domain="systemd">Authentication is required to control whether
- the RTC stores the local or UTC time.</message>
+ <message gettext-domain="systemd">Authentication is required to control whether the RTC stores the local or UTC time.</message>
<defaults>
<allow_any>auth_admin_keep</allow_any>
<allow_inactive>auth_admin_keep</allow_inactive>
<action id="org.freedesktop.timedate1.set-ntp">
<description gettext-domain="systemd">Turn network time synchronization on or off</description>
- <message gettext-domain="systemd">Authentication is required to control whether
- network time synchronization shall be enabled.</message>
+ <message gettext-domain="systemd">Authentication is required to control whether network time synchronization shall be enabled.</message>
<defaults>
<allow_any>auth_admin_keep</allow_any>
<allow_inactive>auth_admin_keep</allow_inactive>
return 0;
}
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_time, "t", now(CLOCK_REALTIME));
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_ntp_sync, "b", ntp_synced());
+
static int property_get_rtc_time(
sd_bus *bus,
const char *path,
return sd_bus_message_append(reply, "t", t);
}
-static int property_get_time(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- return sd_bus_message_append(reply, "t", now(CLOCK_REALTIME));
-}
-
-static int property_get_ntp_sync(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- return sd_bus_message_append(reply, "b", ntp_synced());
-}
-
static int property_get_can_ntp(
sd_bus *bus,
const char *path,
if (!timezone_is_valid(z, LOG_DEBUG))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid time zone '%s'", z);
- r = free_and_strdup(&c->zone, z);
- if (r < 0)
- return r;
- if (r == 0)
+ if (streq_ptr(z, c->zone))
return sd_bus_reply_method_return(m, NULL);
r = bus_verify_polkit_async(
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+ r = free_and_strdup(&c->zone, z);
+ if (r < 0)
+ return r;
+
/* 1. Write new configuration file */
r = context_write_data_timezone(c);
if (r < 0) {
assert(bus);
assert(reply);
- return sd_bus_message_append(reply, "s", *s ? (*s)->string : "");
+ return sd_bus_message_append(reply, "s", *s ? (*s)->string : NULL);
}
static int property_get_current_server_address(
return 0;
}
+static int patch_var_run(const char *fname, unsigned line, char **path) {
+ const char *k;
+ char *n;
+
+ assert(path);
+ assert(*path);
+
+ /* Optionally rewrites lines referencing /var/run/, to use /run/ instead. Why bother? tmpfiles merges lines in
+ * some cases and detects conflicts in others. If files/directories are specified through two equivalent lines
+ * this is problematic as neither case will be detected. Ideally we'd detect these cases by resolving symlinks
+ * early, but that's precisely not what we can do here as this code very likely is running very early on, at a
+ * time where the paths in question are not available yet, or even more importantly, our own tmpfiles rules
+ * might create the paths that are intermediary to the listed paths. We can't really cover the generic case,
+ * but the least we can do is cover the specific case of /var/run vs. /run, as /var/run is a legacy name for
+ * /run only, and we explicitly document that and require that on systemd systems the former is a symlink to
+ * the latter. Moreover files below this path are by far the primary usecase for tmpfiles.d/. */
+
+ k = path_startswith(*path, "/var/run/");
+ if (isempty(k)) /* Don't complain about other paths than /var/run, and not about /var/run itself either. */
+ return 0;
+
+ n = strjoin("/run/", k);
+ if (!n)
+ return log_oom();
+
+ /* Also log about this briefly. We do so at LOG_NOTICE level, as we fixed up the situation automatically, hence
+ * there's no immediate need for action by the user. However, in the interest of making things less confusing
+ * to the user, let's still inform the user that these snippets should really be updated. */
+
+ log_notice("[%s:%u] Line references path below legacy directory /var/run/, updating %s → %s; please update the tmpfiles.d/ drop-in file accordingly.", fname, line, *path, n);
+
+ free(*path);
+ *path = n;
+
+ return 0;
+}
+
static int parse_line(const char *fname, unsigned line, const char *buffer, bool *invalid_config) {
_cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s", fname, line, path);
}
+ r = patch_var_run(fname, line, &i.path);
+ if (r < 0)
+ return r;
+
switch (i.type) {
case CREATE_DIRECTORY:
d /var/lib/systemd 0755 root root -
d /var/lib/systemd/coredump 0755 root root 3d
+
+d /var/lib/private 0700 root root -
+d /var/log/private 0700 root root -
+d /var/cache/private 0700 root root -