sensor:modalias:acpi:KIOX000A*:dmi:bvnLENOVO:bvr1HCN4?WW:*:svnLENOVO:pn80SG:*
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
-# IdeaPad Miix 320
+# IdeaPad Miix 320, different batches use a different sensor
sensor:modalias:acpi:*BOSC0200*:dmi:*:svnLENOVO*:pn80XF:*
+sensor:modalias:acpi:SMO8840*:dmi:*:svnLENOVO:pn80XF:pvrLenovoMIIX320*
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
#########################################
</listitem>
</varlistentry>
- <varlistentry>
- <term><option>--no-ask-password</option></term>
-
- <listitem><para>Do not query the user for authentication for
- privileged operations.</para></listitem>
- </varlistentry>
-
<varlistentry>
<term><option>--kill-who=</option></term>
<xi:include href="standard-options.xml" xpointer="no-pager" />
<xi:include href="standard-options.xml" xpointer="no-legend" />
+ <xi:include href="standard-options.xml" xpointer="no-ask-password" />
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
<refsect1>
<title>See Also</title>
<para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
based on the <varname>$DISPLAY</varname> variable.</para>
</refsect1>
+ <refsect1>
+ <title>Session limits</title>
+
+ <para>PAM modules earlier in the stack, that is those that come before <command>pam_systemd.so</command>,
+ can set session scope limits using the PAM context objects. The data for these objects is provided as NUL-terminated C strings
+ and maps directly to the respective unit resource control directives. Note that these limits apply to individual sessions of the user,
+ they do not apply to all user processes as a combined whole. In particular, the per-user <command>user@.service</command> unit instance,
+ which runs the <command>systemd --user</command> manager process and its children, and is tracked outside of any session, being shared
+ by all the user's sessions, is not covered by these limits.
+ </para>
+
+ <para> See
+ <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information about the resources.
+ Also, see <citerefentry><refentrytitle>pam_set_data</refentrytitle><manvolnum>3</manvolnum></citerefentry> for additional information about how to set
+ the context objects.
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><varname>systemd.memory_max</varname></term>
+
+ <listitem><para>Sets unit <varname>MemoryMax=</varname>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>systemd.tasks_max</varname></term>
+
+ <listitem><para>Sets unit <varname>TasksMax=</varname>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>systemd.cpu_weight</varname></term>
+
+ <listitem><para>Sets unit <varname>CPUWeight=</varname>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>systemd.io_weight</varname></term>
+
+ <listitem><para>Sets unit <varname>IOWeight=</varname>.</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>Example data as can be provided from an another PAM module:
+ <programlisting>
+pam_set_data(handle, "systemd.memory_max", (void *)"200M", cleanup);
+pam_set_data(handle, "systemd.tasks_max", (void *)"50", cleanup);
+pam_set_data(handle, "systemd.cpu_weight", (void *)"100", cleanup);
+pam_set_data(handle, "systemd.io_weight", (void *)"340", cleanup);
+ </programlisting>
+ </para>
+
+ </refsect1>
+
<refsect1>
<title>Example</title>
<refsynopsisdiv>
<cmdsynopsis>
- <command>systemd-path <arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="opt" rep="repeat">NAME</arg></command>
+ <command>systemd-path</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="opt" rep="repeat">NAME</arg>
</cmdsynopsis>
</refsynopsisdiv>
<varlistentry>
<term><option>--suffix=</option></term>
- <listitem><para>The printed paths are suffixed by the
- specified string.</para></listitem>
+ <listitem><para>Printed paths are suffixed by the specified string.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<title>Description</title>
<para><filename>systemd-time-wait-sync</filename> is a system service that delays the start of units that depend on
- <filename>time-sync.target</filename> until <filename>systemd-timesyncd.service</filename> or something else has
- set the system time and marked it as synchronized. Reaching this state generally requires synchronization with an
- external source, such as an NTP server.</para>
+ <filename>time-sync.target</filename> until the system time has been synchronized with an accurate time source by
+ <filename>systemd-timesyncd.service</filename>.</para>
- <para>When this unit is not enabled the <filename>time-sync.target</filename> synchronization point may be reached
- as soon as the system time is advanced by <filename>systemd-timesyncd.service</filename> to the time stored at the
- last shutdown. That time may not meet the expectations of dependent services that require an accurate
- clock.</para>
+ <para><filename>systemd-timesyncd.service</filename> notifies on successful synchronization.
+ <filename>systemd-time-wait-sync</filename> also tries to detect when the kernel marks the time as synchronized,
+ but this detection is not reliable and is intended only as a fallback for other servies that can be used to
+ synchronize time (e.g., ntpd, chronyd).</para>
</refsect1>
<refsect1>
- <title>Notes</title>
+ <title>Files</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>/run/systemd/timesync/synchronized</filename></term>
+
+ <listitem>
+ <para>The presence of this file indicates to this service that the system clock has been synchronized.</para>
+ </listitem>
+
+ </varlistentry>
+ </variablelist>
- <para>This service works correctly with a time synchronization service like
- <filename>systemd-timesyncd.service</filename> that uses the same protocol as NTP to set the time from a
- synchronized source. When used with time synchronization services that follow a different protocol the event of
- setting synchronized time may not be detected in which case this service will not complete.</para>
</refsect1>
<refsect1>
<term><filename>/var/lib/systemd/timesync/clock</filename></term>
<listitem>
- <para>This file contains the timestamp of the last successful
+ <para>The modification time of this file indicates the timestamp of the last successful
synchronization.</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><filename>/run/systemd/timesync/synchronized</filename></term>
+
+ <listitem>
+ <para>A file that is touched on each successful synchronization, to assist
+ <filename>systemd-time-wait-sync</filename> and other applications to detecting synchronization
+ events.</para>
+ </listitem>
+
+ </varlistentry>
</variablelist>
</refsect1>
<citerefentry><refentrytitle>timesyncd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-time-wait-sync.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>timedatectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>localtime</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>hwclock</refentrytitle><manvolnum>8</manvolnum></citerefentry>
<varname>ExecStop=</varname> line set. (Services lacking both <varname>ExecStart=</varname> and
<varname>ExecStop=</varname> are not valid.)</para>
- <para>For each of the specified commands, the first argument must be an absolute path to an
- executable. Optionally, this filename may be prefixed with a number of special characters:</para>
+ <para>For each of the specified commands, the first argument must be either an absolute path to an executable
+ or a simple file name without any slashes. Optionally, this filename may be prefixed with a number of special
+ characters:</para>
<table>
<title>Special executable prefixes</title>
<literal>&</literal>, and <emphasis>other elements of shell
syntax are not supported</emphasis>.</para>
- <para>The command to execute must be an absolute path name. It may
- contain spaces, but control characters are not allowed.</para>
+ <para>The command to execute may contain spaces, but control characters are not allowed.</para>
- <para>The command line accepts <literal>%</literal> specifiers as
- described in
+ <para>The command line accepts <literal>%</literal> specifiers as described in
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
<para>Basic environment variable substitution is supported. Use
For this type of expansion, quotes are respected when splitting
into words, and afterwards removed.</para>
+ <para>If the command is not a full (absolute) path, it will be resolved to a full path using a
+ fixed search path determinted at compilation time. Searched directories include
+ <filename>/usr/local/bin/</filename>, <filename>/usr/bin/</filename>, <filename>/bin/</filename>
+ on systems using split <filename>/usr/bin/</filename> and <filename>/bin/</filename>
+ directories, and their <filename>sbin/</filename> counterparts on systems using split
+ <filename>bin/</filename> and <filename>sbin/</filename>. It is thus safe to use just the
+ executable name in case of executables located in any of the "standard" directories, and an
+ absolute path must be used in other cases. Using an absolute path is recommended to avoid
+ ambiguity. Hint: this search path may be queried using
+ <command>systemd-path search-binaries-default</command>.</para>
+
<para>Example:</para>
<programlisting>Environment="ONE=one" 'TWO=two two'
-ExecStart=/bin/echo $ONE $TWO ${TWO}</programlisting>
+ExecStart=echo $ONE $TWO ${TWO}</programlisting>
<para>This will execute <command>/bin/echo</command> with four
arguments: <literal>one</literal>, <literal>two</literal>,
<programlisting>Environment=ONE='one' "TWO='two two' too" THREE=
ExecStart=/bin/echo ${ONE} ${TWO} ${THREE}
ExecStart=/bin/echo $ONE $TWO $THREE</programlisting>
- <para>This results in <filename>echo</filename> being
+ <para>This results in <filename>/bin/echo</filename> being
called twice, the first time with arguments
<literal>'one'</literal>,
<literal>'two two' too</literal>, <literal></literal>,
<para>Note that shell command lines are not directly supported. If
shell command lines are to be used, they need to be passed
explicitly to a shell implementation of some kind. Example:</para>
- <programlisting>ExecStart=/bin/sh -c 'dmesg | tac'</programlisting>
+ <programlisting>ExecStart=sh -c 'dmesg | tac'</programlisting>
<para>Example:</para>
- <programlisting>ExecStart=/bin/echo one ; /bin/echo "two two"</programlisting>
+ <programlisting>ExecStart=echo one ; echo "two two"</programlisting>
- <para>This will execute <command>/bin/echo</command> two times,
+ <para>This will execute <command>echo</command> two times,
each time with one argument: <literal>one</literal> and
<literal>two two</literal>, respectively. Because two commands are
specified, <varname>Type=oneshot</varname> must be used.</para>
<para>Example:</para>
- <programlisting>ExecStart=/bin/echo / >/dev/null & \; \
-/bin/ls</programlisting>
+ <programlisting>ExecStart=echo / >/dev/null & \; \
+ls</programlisting>
- <para>This will execute <command>/bin/echo</command>
+ <para>This will execute <command>echo</command>
with five arguments: <literal>/</literal>,
<literal>>/dev/null</literal>,
<literal>&</literal>, <literal>;</literal>, and
- <literal>/bin/ls</literal>.</para>
+ <literal>ls</literal>.</para>
<table>
<title>C escapes supported in command lines and environment variables</title>
}
int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators) {
- _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
_cleanup_free_ char *var = NULL;
Manager *m = NULL;
FILE *serial = NULL;
continue;
}
- k = manager_load_unit(m, NULL, prepared, &err, &units[count]);
- if (k < 0) {
- log_error_errno(k, "Failed to load %s: %m", *filename);
- if (r == 0)
- r = k;
- } else
+ k = manager_load_startable_unit_or_warn(m, NULL, prepared, &units[count]);
+ if (k < 0 && r == 0)
+ r = k;
+ else
count++;
}
struct stat st;
int flags;
- /* Checks whether the specified file descriptor refers to a pipe, and if so if is has O_NONBLOCK set. */
+ /* Checks whether the specified file descriptor refers to a pipe, and if so if O_NONBLOCK is set. */
if (fstat(fd, &st) < 0)
return -errno;
#if HAVE_SPLIT_BIN
# define PATH_SBIN_BIN(x) x "sbin:" x "bin"
+# define PATH_SBIN_BIN_NULSTR(x) x "sbin\0" x "bin\0"
#else
# define PATH_SBIN_BIN(x) x "bin"
+# define PATH_SBIN_BIN_NULSTR(x) x "bin\0"
#endif
#define DEFAULT_PATH_NORMAL PATH_SBIN_BIN("/usr/local/") ":" PATH_SBIN_BIN("/usr/")
+#define DEFAULT_PATH_NORMAL_NULSTR PATH_SBIN_BIN_NULSTR("/usr/local/") PATH_SBIN_BIN_NULSTR("/usr/")
#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":" PATH_SBIN_BIN("/")
+#define DEFAULT_PATH_SPLIT_USR_NULSTR DEFAULT_PATH_NORMAL_NULSTR PATH_SBIN_BIN_NULSTR("/")
#if HAVE_SPLIT_USR
# define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR
+# define DEFAULT_PATH_NULSTR DEFAULT_PATH_SPLIT_USR_NULSTR
#else
# define DEFAULT_PATH DEFAULT_PATH_NORMAL
+# define DEFAULT_PATH_NULSTR DEFAULT_PATH_NORMAL_NULSTR
#endif
bool is_path(const char *p) _pure_;
assert(suffix);
assert(ret);
- if (isempty(suffix))
- return -EINVAL;
if (suffix[0] != '.')
return -EINVAL;
}
if (!string_is_safe(path)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
- "Executable path contains special characters%s: %s",
- ignore ? ", ignoring" : "", rvalue);
- return ignore ? 0 : -ENOEXEC;
- }
- if (!path_is_absolute(path)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Executable path is not absolute%s: %s",
- ignore ? ", ignoring" : "", rvalue);
+ "Executable name contains special characters%s: %s",
+ ignore ? ", ignoring" : "", path);
return ignore ? 0 : -ENOEXEC;
}
if (endswith(path, "/")) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"Executable path specifies a directory%s: %s",
- ignore ? ", ignoring" : "", rvalue);
+ ignore ? ", ignoring" : "", path);
return ignore ? 0 : -ENOEXEC;
}
+ if (!path_is_absolute(path)) {
+ const char *prefix;
+ bool found = false;
+
+ if (!filename_is_valid(path)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Neither a valid executable name nor an absolute path%s: %s",
+ ignore ? ", ignoring" : "", path);
+ return ignore ? 0 : -ENOEXEC;
+ }
+
+ /* Resolve a single-component name to a full path */
+ NULSTR_FOREACH(prefix, DEFAULT_PATH_NULSTR) {
+ _cleanup_free_ char *fullpath = NULL;
+
+ fullpath = strjoin(prefix, "/", path);
+ if (!fullpath)
+ return log_oom();
+
+ if (access(fullpath, F_OK) >= 0) {
+ free_and_replace(path, fullpath);
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Executable \"%s\" not found in path \"%s\"%s",
+ path, DEFAULT_PATH, ignore ? ", ignoring" : "");
+ return ignore ? 0 : -ENOEXEC;
+ }
+ }
+
if (!separate_argv0) {
char *w = NULL;
log_debug("Activating default unit: %s", arg_default_unit);
- r = manager_load_unit(m, arg_default_unit, NULL, &error, &target);
- if (r < 0)
- log_error("Failed to load default target: %s", bus_error_message(&error, r));
- else if (IN_SET(target->load_state, UNIT_ERROR, UNIT_NOT_FOUND))
- log_error_errno(target->load_error, "Failed to load default target: %m");
- else if (target->load_state == UNIT_MASKED)
- log_error("Default target masked.");
-
- if (!target || target->load_state != UNIT_LOADED) {
- log_info("Trying to load rescue target...");
+ r = manager_load_startable_unit_or_warn(m, arg_default_unit, NULL, &target);
+ if (r < 0) {
+ log_info("Falling back to rescue target: " SPECIAL_RESCUE_TARGET);
- r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &error, &target);
+ r = manager_load_startable_unit_or_warn(m, SPECIAL_RESCUE_TARGET, NULL, &target);
if (r < 0) {
- *ret_error_message = "Failed to load rescue target";
- return log_emergency_errno(r, "Failed to load rescue target: %s", bus_error_message(&error, r));
- } else if (IN_SET(target->load_state, UNIT_ERROR, UNIT_NOT_FOUND)) {
- *ret_error_message = "Failed to load rescue target";
- return log_emergency_errno(target->load_error, "Failed to load rescue target: %m");
- } else if (target->load_state == UNIT_MASKED) {
- *ret_error_message = "Rescue target masked";
- log_emergency("Rescue target masked.");
- return -ERFKILL;
+ *ret_error_message = r == -ERFKILL ? "Rescue target masked"
+ : "Failed to load rescue target";
+ return r;
}
}
manager_dispatch_load_queue(m);
*_ret = unit_follow_merge(*_ret);
+ return 0;
+}
+
+int manager_load_startable_unit_or_warn(
+ Manager *m,
+ const char *name,
+ const char *path,
+ Unit **ret) {
+
+ /* Load a unit, make sure it loaded fully and is not masked. */
+
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ Unit *unit;
+ int r;
+
+ r = manager_load_unit(m, name, path, &error, &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load %s %s: %s",
+ name ? "unit" : "file", name ?: path,
+ bus_error_message(&error, r));
+ else if (IN_SET(unit->load_state, UNIT_ERROR, UNIT_NOT_FOUND))
+ return log_error_errno(unit->load_error, "Failed to load %s %s: %m",
+ name ? "unit" : "file", name ?: path);
+ else if (unit->load_state == UNIT_MASKED) {
+ log_error("%s %s is masked.",
+ name ? "Unit" : "File", name ?: path);
+ return -ERFKILL;
+ }
+ *ret = unit;
return 0;
}
int manager_load_unit_prepare(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret);
int manager_load_unit(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret);
+int manager_load_startable_unit_or_warn(Manager *m, const char *name, const char *path, Unit **ret);
int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u);
int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret);
if (IN_SET(type,
SD_PATH_SEARCH_BINARIES,
+ SD_PATH_SEARCH_BINARIES_DEFAULT,
SD_PATH_SEARCH_LIBRARY_PRIVATE,
SD_PATH_SEARCH_LIBRARY_ARCH,
SD_PATH_SEARCH_SHARED,
false,
"/etc",
NULL);
- }
+
+ case SD_PATH_SEARCH_BINARIES_DEFAULT: {
+ char **t;
+
+ t = strv_split_nulstr(DEFAULT_PATH_NULSTR);
+ if (!t)
+ return -ENOMEM;
+
+ *list = t;
+ return 0;
+ }}
return -EOPNOTSUPP;
}
if (!IN_SET(type,
SD_PATH_SEARCH_BINARIES,
+ SD_PATH_SEARCH_BINARIES_DEFAULT,
SD_PATH_SEARCH_LIBRARY_PRIVATE,
SD_PATH_SEARCH_LIBRARY_ARCH,
SD_PATH_SEARCH_SHARED,
}
}
- r = sd_bus_message_enter_container(message, 'a', "(sv)");
- if (r < 0)
- return r;
-
if (t == _SESSION_TYPE_INVALID) {
if (!isempty(display))
t = SESSION_X11;
goto fail;
}
- r = session_start(session);
+ r = sd_bus_message_enter_container(message, 'a', "(sv)");
+ if (r < 0)
+ return r;
+
+ r = session_start(session, message);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_message_exit_container(message);
if (r < 0)
goto fail;
const char *description,
const char *after,
const char *after2,
- uint64_t tasks_max,
+ sd_bus_message *more_properties,
sd_bus_error *error,
char **job) {
if (r < 0)
return r;
- r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
+ /* disable TasksMax= for the session scope, rely on the slice setting for it */
+ r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", (uint64_t)-1);
if (r < 0)
- return r;
+ return bus_log_create_error(r);
+
+ if (more_properties) {
+ /* If TasksMax also appears here, it will overwrite the default value set above */
+ r = sd_bus_message_copy(m, more_properties, true);
+ if (r < 0)
+ return r;
+ }
r = sd_bus_message_close_container(m);
if (r < 0)
return 0;
}
-static int session_start_scope(Session *s) {
+static int session_start_scope(Session *s, sd_bus_message *properties) {
int r;
assert(s);
description,
"systemd-logind.service",
"systemd-user-sessions.service",
- (uint64_t) -1, /* disable TasksMax= for the scope, rely on the slice setting for it */
+ properties,
&error,
&job);
if (r < 0) {
return 0;
}
-int session_start(Session *s) {
+int session_start(Session *s, sd_bus_message *properties) {
int r;
assert(s);
return r;
/* Create cgroup */
- r = session_start_scope(s);
+ r = session_start_scope(s, properties);
if (r < 0)
return r;
int session_get_locked_hint(Session *s);
void session_set_locked_hint(Session *s, bool b);
int session_create_fifo(Session *s);
-int session_start(Session *s);
+int session_start(Session *s, sd_bus_message *properties);
int session_stop(Session *s, bool force);
int session_finalize(Session *s);
int session_release(Session *s);
user_start(user);
HASHMAP_FOREACH(session, m->sessions, i)
- session_start(session);
+ session_start(session, NULL);
HASHMAP_FOREACH(inhibitor, m->inhibitors, i)
inhibitor_start(inhibitor);
int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_;
int manager_start_slice(Manager *manager, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job);
-int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job);
+int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_message *more_properties, sd_bus_error *error, char **job);
int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error);
#include "terminal-util.h"
#include "util.h"
#include "path-util.h"
+#include "cgroup-util.h"
static int parse_argv(
pam_handle_t *handle,
return r;
}
+static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
+ uint64_t val;
+ int r;
+
+ if (isempty(limit))
+ return 0;
+
+ if (streq(limit, "infinity")) {
+ r = sd_bus_message_append(m, "(sv)", "MemoryMax", "t", (uint64_t)-1);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return r;
+ }
+ } else {
+ r = parse_percent(limit);
+ if (r >= 0) {
+ r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U));
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return r;
+ }
+ } else {
+ r = parse_size(limit, 1024, &val);
+ if (r >= 0) {
+ r = sd_bus_message_append(m, "(sv)", "MemoryMax", "t", val);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return r;
+ }
+ } else
+ pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.limit: %s, ignoring.", limit);
+ }
+ }
+
+ return 0;
+}
+
+static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, const char *limit)
+{
+ uint64_t val;
+ int r;
+
+ /* No need to parse "infinity" here, it will be set unconditionally later in manager_start_scope() */
+ if (isempty(limit) || streq(limit, "infinity"))
+ return 0;
+
+ r = safe_atou64(limit, &val);
+ if (r >= 0) {
+ r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", val);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return r;
+ }
+ } else
+ pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.limit: %s, ignoring.", limit);
+
+ return 0;
+}
+
+static int append_session_cg_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit, const char *field) {
+ uint64_t val;
+ int r;
+
+ if (!isempty(limit)) {
+ r = cg_weight_parse(limit, &val);
+ if (r >= 0) {
+ r = sd_bus_message_append(m, "(sv)", field, "t", val);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return r;
+ }
+ } else if (streq(field, "CPUWeight"))
+ pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight: %s, ignoring.", limit);
+ else
+ pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight: %s, ignoring.", limit);
+ }
+
+ return 0;
+}
+
_public_ PAM_EXTERN int pam_sm_open_session(
pam_handle_t *handle,
int flags,
int argc, const char **argv) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
const char
*username, *id, *object_path, *runtime_path,
*service = NULL,
*remote_user = NULL, *remote_host = NULL,
*seat = NULL,
*type = NULL, *class = NULL,
- *class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL;
+ *class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL,
+ *memory_max = NULL, *tasks_max = NULL, *cpu_weight = NULL, *io_weight = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int session_fd = -1, existing, r;
bool debug = false, remote;
remote = !isempty(remote_host) && !is_localhost(remote_host);
+ (void) pam_get_data(handle, "systemd.memory_max", (const void **)&memory_max);
+ (void) pam_get_data(handle, "systemd.tasks_max", (const void **)&tasks_max);
+ (void) pam_get_data(handle, "systemd.cpu_weight", (const void **)&cpu_weight);
+ (void) pam_get_data(handle, "systemd.io_weight", (const void **)&io_weight);
+
/* Talk to logind over the message bus */
r = sd_bus_open_system(&bus);
return PAM_SESSION_ERR;
}
- if (debug)
+ if (debug) {
pam_syslog(handle, LOG_DEBUG, "Asking logind to create session: "
"uid="UID_FMT" pid="PID_FMT" service=%s type=%s class=%s desktop=%s seat=%s vtnr=%"PRIu32" tty=%s display=%s remote=%s remote_user=%s remote_host=%s",
pw->pw_uid, getpid_cached(),
type, class, strempty(desktop),
strempty(seat), vtnr, strempty(tty), strempty(display),
yes_no(remote), strempty(remote_user), strempty(remote_host));
+ pam_syslog(handle, LOG_DEBUG, "Session limits: "
+ "memory_max=%s tasks_max=%s cpu_weight=%s io_weight=%s",
+ strna(memory_max), strna(tasks_max), strna(cpu_weight), strna(io_weight));
+ }
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "CreateSession");
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to create CreateSession method call: %s", strerror(-r));
+ return PAM_SESSION_ERR;
+ }
+
+ r = sd_bus_message_append(m, "uusssssussbss",
+ (uint32_t) pw->pw_uid,
+ (uint32_t) getpid_cached(),
+ service,
+ type,
+ class,
+ desktop,
+ seat,
+ vtnr,
+ tty,
+ display,
+ remote,
+ remote_user,
+ remote_host);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return PAM_SESSION_ERR;
+ }
+
+ r = sd_bus_message_open_container(m, 'a', "(sv)");
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to open message container: %s", strerror(-r));
+ return PAM_SYSTEM_ERR;
+ }
+
+ r = append_session_memory_max(handle, m, memory_max);
+ if (r < 0)
+ return PAM_SESSION_ERR;
+
+ r = append_session_tasks_max(handle, m, tasks_max);
+ if (r < 0)
+ return PAM_SESSION_ERR;
+
+ r = append_session_cg_weight(handle, m, cpu_weight, "CPUWeight");
+ if (r < 0)
+ return PAM_SESSION_ERR;
+
+ r = append_session_cg_weight(handle, m, io_weight, "IOWeight");
+ if (r < 0)
+ return PAM_SESSION_ERR;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to close message container: %s", strerror(-r));
+ return PAM_SYSTEM_ERR;
+ }
- r = sd_bus_call_method(bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "CreateSession",
- &error,
- &reply,
- "uusssssussbssa(sv)",
- (uint32_t) pw->pw_uid,
- (uint32_t) getpid_cached(),
- service,
- type,
- class,
- desktop,
- seat,
- vtnr,
- tty,
- display,
- remote,
- remote_user,
- remote_host,
- 0);
+ r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) {
pam_syslog(handle, LOG_DEBUG, "Cannot create session: %s", bus_error_message(&error, r));
uint64_t limit;
int r;
+ polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
+
if (STR_IN_SET(argv[argc-1], "-", "none", "infinity"))
limit = (uint64_t) -1;
else {
r = parse_size(argv[argc-1], 1024, &limit);
if (r < 0)
- return log_error("Failed to parse size: %s", argv[argc-1]);
+ return log_error_errno(r, "Failed to parse size: %s", argv[argc-1]);
}
if (argc > 2)
NULL,
"t", limit);
- if (r < 0) {
- log_error("Could not set limit: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not set limit: %s", bus_error_message(&error, r));
return 0;
}
unsigned c = 0;
int r;
+ polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
+
r = sd_bus_message_new_method_call(
bus,
&m,
goto finish;
}
- sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
+ (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
r = machinectl_main(argc, argv, bus);
#include "signal-util.h"
#include "special.h"
-Manager *manager_new(void) {
- Manager *m;
+static Manager* manager_unref(Manager *m);
+DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref);
+
+static int manager_new(Manager **ret) {
+ _cleanup_(manager_unrefp) Manager *m = NULL;
int r;
+ assert(ret);
+
m = new0(Manager, 1);
if (!m)
- return NULL;
+ return -ENOMEM;
m->machines = hashmap_new(&string_hash_ops);
m->machine_units = hashmap_new(&string_hash_ops);
m->machine_leaders = hashmap_new(NULL);
- if (!m->machines || !m->machine_units || !m->machine_leaders) {
- manager_free(m);
- return NULL;
- }
+ if (!m->machines || !m->machine_units || !m->machine_leaders)
+ return -ENOMEM;
r = sd_event_default(&m->event);
- if (r < 0) {
- manager_free(m);
- return NULL;
- }
+ if (r < 0)
+ return r;
+
+ r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
+ if (r < 0)
+ return r;
+
+ r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
+ if (r < 0)
+ return r;
- sd_event_set_watchdog(m->event, true);
+ (void) sd_event_set_watchdog(m->event, true);
- return m;
+ *ret = TAKE_PTR(m);
+ return 0;
}
-void manager_free(Manager *m) {
+static Manager* manager_unref(Manager *m) {
Machine *machine;
assert(m);
sd_bus_unref(m->bus);
sd_event_unref(m->event);
- free(m);
+ return mfree(m);
}
static int manager_add_host_machine(Manager *m) {
return 0;
}
-int manager_enumerate_machines(Manager *m) {
+static int manager_enumerate_machines(Manager *m) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
int r = 0;
return 0;
}
-void manager_gc(Manager *m, bool drop_not_started) {
+static void manager_gc(Manager *m, bool drop_not_started) {
Machine *machine;
assert(m);
}
}
-int manager_startup(Manager *m) {
+static int manager_startup(Manager *m) {
Machine *machine;
Iterator i;
int r;
return hashmap_isempty(m->machines);
}
-int manager_run(Manager *m) {
+static int manager_run(Manager *m) {
assert(m);
return bus_event_loop_with_idle(
}
int main(int argc, char *argv[]) {
- Manager *m = NULL;
+ _cleanup_(manager_unrefp) Manager *m = NULL;
int r;
log_set_target(LOG_TARGET_AUTO);
goto finish;
}
- /* Always create the directories people can create inotify
- * watches in. Note that some applications might check for the
- * existence of /run/systemd/machines/ to determine whether
- * machined is available, so please always make sure this
- * check stays in. */
- mkdir_label("/run/systemd/machines", 0755);
+ /* Always create the directories people can create inotify watches in. Note that some applications might check
+ * for the existence of /run/systemd/machines/ to determine whether machined is available, so please always
+ * make sure this check stays in. */
+ (void) mkdir_label("/run/systemd/machines", 0755);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, -1) >= 0);
- m = manager_new();
- if (!m) {
- r = log_oom();
+ r = manager_new(&m);
+ if (r < 0) {
+ log_error_errno(r, "Failed to allocate manager object: %m");
goto finish;
}
log_debug("systemd-machined stopped as pid "PID_FMT, getpid_cached());
finish:
- manager_free(m);
-
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
unsigned n_operations;
};
-Manager *manager_new(void);
-void manager_free(Manager *m);
-
int manager_add_machine(Manager *m, const char *name, Machine **_machine);
-int manager_enumerate_machines(Manager *m);
-
-int manager_startup(Manager *m);
-int manager_run(Manager *m);
-
-void manager_gc(Manager *m, bool drop_not_started);
-
int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine);
extern const sd_bus_vtable manager_vtable[];
link_set_dhcp_routes(link);
+ if (link->dhcp4_messages == 0) {
+ link->dhcp4_configured = true;
+ link_check_ready(link);
+ }
+
return 1;
}
goto dhcp4_address_fail;
}
- r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
+ r = sd_dhcp_client_new(&link->dhcp_client, link->network ? link->network->dhcp_anonymize : 0);
if (r < 0)
return log_link_error_errno(link, r, "Failed to create DHCPv4 client: %m");
if (m->bus)
return 0;
- r = bus_open_system_watch_bind(&m->bus);
+ r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-network");
if (r < 0)
return log_error_errno(r, "Failed to connect to bus: %m");
sd_bus_unref(m->bus);
sd_bus_slot_unref(m->prepare_for_sleep_slot);
sd_bus_slot_unref(m->connected_slot);
- sd_event_source_unref(m->bus_retry_event_source);
free(m->dynamic_timezone);
free(m->dynamic_hostname);
sd_netlink *genl;
sd_event *event;
sd_resolve *resolve;
- sd_event_source *bus_retry_event_source;
sd_bus *bus;
sd_bus_slot *prepare_for_sleep_slot;
sd_bus_slot *connected_slot;
[SD_PATH_USER_TEMPLATES] = "user-templates",
[SD_PATH_USER_DESKTOP] = "user-desktop",
[SD_PATH_SEARCH_BINARIES] = "search-binaries",
+ [SD_PATH_SEARCH_BINARIES_DEFAULT] = "search-binaries-default",
[SD_PATH_SEARCH_LIBRARY_PRIVATE] = "search-library-private",
[SD_PATH_SEARCH_LIBRARY_ARCH] = "search-library-arch",
[SD_PATH_SEARCH_SHARED] = "search-shared",
if (m->bus)
return 0;
- r = bus_open_system_watch_bind(&m->bus);
+ r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-resolve");
if (r < 0)
return log_error_errno(r, "Failed to connect to system bus: %m");
manager_dns_stub_stop(m);
sd_bus_slot_unref(m->prepare_for_sleep_slot);
- sd_event_source_unref(m->bus_retry_event_source);
sd_bus_unref(m->bus);
sd_event_source_unref(m->sigusr1_event_source);
/* dbus */
sd_bus *bus;
- sd_event_source *bus_retry_event_source;
/* The hostname we publish on LLMNR and mDNS */
char *full_hostname;
return r;
}
-int bus_open_system_watch_bind(sd_bus **ret) {
+int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) {
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
const char *e;
int r;
if (r < 0)
return r;
+ if (description) {
+ r = sd_bus_set_description(bus, description);
+ if (r < 0)
+ return r;
+ }
+
e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
if (!e)
e = DEFAULT_SYSTEM_BUS_ADDRESS;
int bus_track_add_name_many(sd_bus_track *t, char **l);
-int bus_open_system_watch_bind(sd_bus **ret);
+int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description);
+static inline int bus_open_system_watch_bind(sd_bus **ret) {
+ return bus_open_system_watch_bind_with_description(ret, NULL);
+}
int polkit_agent_open(void);
void polkit_agent_close(void);
-static inline void polkit_agent_open_if_enabled(
+static inline int polkit_agent_open_if_enabled(
BusTransport transport,
bool ask_password) {
/* Open the polkit agent as a child process if necessary */
if (transport != BUS_TRANSPORT_LOCAL)
- return;
+ return 0;
if (!ask_password)
- return;
+ return 0;
- polkit_agent_open();
+ return polkit_agent_open();
}
/* Search paths */
SD_PATH_SEARCH_BINARIES,
+ SD_PATH_SEARCH_BINARIES_DEFAULT,
SD_PATH_SEARCH_LIBRARY_PRIVATE,
SD_PATH_SEARCH_LIBRARY_ARCH,
SD_PATH_SEARCH_SHARED,
libseccomp,
libselinux,
libmount,
- libblkid]],
+ libblkid],
+ '', 'timeout=360'],
[['src/test/test-siphash24.c'],
[],
assert_se(manager_startup(m, serial, fdset) >= 0);
/* Load units and verify hierarchy. */
- assert_se(manager_load_unit(m, "parent.slice", NULL, NULL, &parent) >= 0);
- assert_se(manager_load_unit(m, "son.service", NULL, NULL, &son) >= 0);
- assert_se(manager_load_unit(m, "daughter.service", NULL, NULL, &daughter) >= 0);
- assert_se(manager_load_unit(m, "grandchild.service", NULL, NULL, &grandchild) >= 0);
- assert_se(manager_load_unit(m, "parent-deep.slice", NULL, NULL, &parent_deep) >= 0);
- assert_se(parent->load_state == UNIT_LOADED);
- assert_se(son->load_state == UNIT_LOADED);
- assert_se(daughter->load_state == UNIT_LOADED);
- assert_se(grandchild->load_state == UNIT_LOADED);
- assert_se(parent_deep->load_state == UNIT_LOADED);
+ assert_se(manager_load_startable_unit_or_warn(m, "parent.slice", NULL, &parent) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "son.service", NULL, &son) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "daughter.service", NULL, &daughter) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "grandchild.service", NULL, &grandchild) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "parent-deep.slice", NULL, &parent_deep) >= 0);
assert_se(UNIT_DEREF(son->slice) == parent);
assert_se(UNIT_DEREF(daughter->slice) == parent);
assert_se(UNIT_DEREF(parent_deep->slice) == parent);
assert_se(manager_startup(m, serial, fdset) >= 0);
printf("Load1:\n");
- assert_se(manager_load_unit(m, "a.service", NULL, NULL, &a) >= 0);
- assert_se(manager_load_unit(m, "b.service", NULL, NULL, &b) >= 0);
- assert_se(manager_load_unit(m, "c.service", NULL, NULL, &c) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "a.service", NULL, &a) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "b.service", NULL, &b) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "c.service", NULL, &c) >= 0);
manager_dump_units(m, stdout, "\t");
printf("Test1: (Trivial)\n");
printf("Load2:\n");
manager_clear_jobs(m);
- assert_se(manager_load_unit(m, "d.service", NULL, NULL, &d) >= 0);
- assert_se(manager_load_unit(m, "e.service", NULL, NULL, &e) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "d.service", NULL, &d) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "e.service", NULL, &e) >= 0);
manager_dump_units(m, stdout, "\t");
printf("Test2: (Cyclic Order, Unfixable)\n");
manager_dump_jobs(m, stdout, "\t");
printf("Load3:\n");
- assert_se(manager_load_unit(m, "g.service", NULL, NULL, &g) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "g.service", NULL, &g) >= 0);
manager_dump_units(m, stdout, "\t");
printf("Test5: (Colliding transaction, fail)\n");
manager_dump_jobs(m, stdout, "\t");
printf("Load4:\n");
- assert_se(manager_load_unit(m, "h.service", NULL, NULL, &h) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "h.service", NULL, &h) >= 0);
manager_dump_units(m, stdout, "\t");
printf("Test10: (Unmergeable job type of auxiliary job, fail)\n");
assert_se(unit_name);
- assert_se(manager_load_unit(m, unit_name, NULL, NULL, &unit) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
check(m, unit, status_expected, code_expected);
}
test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
}
+static void test_exec_basic(Manager *m) {
+ test(m, "exec-basic.service", 0, CLD_EXITED);
+}
+
static void test_exec_ambientcapabilities(Manager *m) {
int r;
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
static const test_function_t user_tests[] = {
+ test_exec_basic,
test_exec_ambientcapabilities,
test_exec_bindpaths,
test_exec_capabilityboundingset,
assert_se(m);
- assert_se(manager_load_unit(m, "path-exists.path", NULL, NULL, &unit) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "path-exists.path", NULL, &unit) >= 0);
assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
assert_se(touch(test_path) >= 0);
Unit *unit = NULL;
assert_se(m);
- assert_se(manager_load_unit(m, "path-existsglob.path", NULL, NULL, &unit) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "path-existsglob.path", NULL, &unit) >= 0);
assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
assert_se(touch(test_path) >= 0);
assert_se(touch(test_path) >= 0);
- assert_se(manager_load_unit(m, "path-changed.path", NULL, NULL, &unit) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "path-changed.path", NULL, &unit) >= 0);
assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
f = fopen(test_path, "w");
assert_se(touch(test_path) >= 0);
- assert_se(manager_load_unit(m, "path-modified.path", NULL, NULL, &unit) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "path-modified.path", NULL, &unit) >= 0);
assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
f = fopen(test_path, "w");
assert_se(m);
- assert_se(manager_load_unit(m, "path-unit.path", NULL, NULL, &unit) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "path-unit.path", NULL, &unit) >= 0);
assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
assert_se(touch(test_path) >= 0);
assert_se(access(test_path, F_OK) < 0);
- assert_se(manager_load_unit(m, "path-directorynotempty.path", NULL, NULL, &unit) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "path-directorynotempty.path", NULL, &unit) >= 0);
assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
/* MakeDirectory default to no */
assert_se(access(test_path, F_OK) < 0);
- assert_se(manager_load_unit(m, "path-makedirectory.path", NULL, NULL, &unit) >= 0);
+ assert_se(manager_load_startable_unit_or_warn(m, "path-makedirectory.path", NULL, &unit) >= 0);
assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
/* Check if the directory has been created */
assert_se(manager_startup(m, serial, fdset) >= 0);
/* load idle ok */
- assert_se(manager_load_unit(m, "sched_idle_ok.service", NULL, NULL, &idle_ok) >= 0);
- assert_se(idle_ok->load_state == UNIT_LOADED);
+ assert_se(manager_load_startable_unit_or_warn(m, "sched_idle_ok.service", NULL, &idle_ok) >= 0);
ser = SERVICE(idle_ok);
assert_se(ser->exec_context.cpu_sched_policy == SCHED_OTHER);
assert_se(ser->exec_context.cpu_sched_priority == 0);
/*
* load idle bad. This should print a warning but we have no way to look at it.
*/
- assert_se(manager_load_unit(m, "sched_idle_bad.service", NULL, NULL, &idle_bad) >= 0);
- assert_se(idle_bad->load_state == UNIT_LOADED);
+ assert_se(manager_load_startable_unit_or_warn(m, "sched_idle_bad.service", NULL, &idle_bad) >= 0);
ser = SERVICE(idle_ok);
assert_se(ser->exec_context.cpu_sched_policy == SCHED_OTHER);
assert_se(ser->exec_context.cpu_sched_priority == 0);
* load rr ok.
* Test that the default priority is moving from 0 to 1.
*/
- assert_se(manager_load_unit(m, "sched_rr_ok.service", NULL, NULL, &rr_ok) >= 0);
- assert_se(rr_ok->load_state == UNIT_LOADED);
+ assert_se(manager_load_startable_unit_or_warn(m, "sched_rr_ok.service", NULL, &rr_ok) >= 0);
ser = SERVICE(rr_ok);
assert_se(ser->exec_context.cpu_sched_policy == SCHED_RR);
assert_se(ser->exec_context.cpu_sched_priority == 1);
* load rr bad.
* Test that the value of 0 and 100 is ignored.
*/
- assert_se(manager_load_unit(m, "sched_rr_bad.service", NULL, NULL, &rr_bad) >= 0);
- assert_se(rr_bad->load_state == UNIT_LOADED);
+ assert_se(manager_load_startable_unit_or_warn(m, "sched_rr_bad.service", NULL, &rr_bad) >= 0);
ser = SERVICE(rr_bad);
assert_se(ser->exec_context.cpu_sched_policy == SCHED_RR);
assert_se(ser->exec_context.cpu_sched_priority == 1);
* load rr change.
* Test that anything between 1 and 99 can be set.
*/
- assert_se(manager_load_unit(m, "sched_rr_change.service", NULL, NULL, &rr_sched) >= 0);
- assert_se(rr_sched->load_state == UNIT_LOADED);
+ assert_se(manager_load_startable_unit_or_warn(m, "sched_rr_change.service", NULL, &rr_sched) >= 0);
ser = SERVICE(rr_sched);
assert_se(ser->exec_context.cpu_sched_policy == SCHED_RR);
assert_se(ser->exec_context.cpu_sched_priority == 99);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/inotify.h>
#include <sys/timerfd.h>
#include <sys/timex.h>
#include <unistd.h>
#include "sd-event.h"
#include "fd-util.h"
+#include "fs-util.h"
#include "missing.h"
#include "signal-util.h"
#include "time-util.h"
typedef struct ClockState {
- int fd; /* non-negative is descriptor from timerfd_create */
- int adjtime_state; /* return value from last adjtimex(2) call */
- sd_event_source *event_source; /* non-null is the active io event source */
+ int timerfd_fd; /* non-negative is descriptor from timerfd_create */
+ int adjtime_state; /* return value from last adjtimex(2) call */
+ sd_event_source *timerfd_event_source; /* non-null is the active io event source */
+ int inotify_fd;
+ sd_event_source *inotify_event_source;
+ int run_systemd_wd;
+ int run_systemd_timesync_wd;
+ bool has_watchfile;
} ClockState;
+static void clock_state_release_timerfd(ClockState *sp) {
+ sp->timerfd_event_source = sd_event_source_unref(sp->timerfd_event_source);
+ sp->timerfd_fd = safe_close(sp->timerfd_fd);
+}
+
static void clock_state_release(ClockState *sp) {
- sp->event_source = sd_event_source_unref(sp->event_source);
- sp->fd = safe_close(sp->fd);
+ clock_state_release_timerfd(sp);
+ sp->inotify_event_source = sd_event_source_unref(sp->inotify_event_source);
+ sp->inotify_fd = safe_close(sp->inotify_fd);
}
static int clock_state_update(ClockState *sp, sd_event *event);
-static int io_handler(sd_event_source * s,
- int fd,
- uint32_t revents,
- void *userdata) {
+static int update_notify_run_systemd_timesync(ClockState *sp) {
+ sp->run_systemd_timesync_wd = inotify_add_watch(sp->inotify_fd, "/run/systemd/timesync", IN_CREATE|IN_DELETE_SELF);
+ return sp->run_systemd_timesync_wd;
+}
+
+static int timerfd_handler(sd_event_source *s,
+ int fd,
+ uint32_t revents,
+ void *userdata) {
ClockState *sp = userdata;
return clock_state_update(sp, sd_event_source_get_event(s));
}
+static void process_inotify_event(sd_event *event, ClockState *sp, struct inotify_event *e) {
+ if (e->wd == sp->run_systemd_wd) {
+ /* Only thing we care about is seeing if we can start watching /run/systemd/timesync. */
+ if (sp->run_systemd_timesync_wd < 0)
+ update_notify_run_systemd_timesync(sp);
+ } else if (e->wd == sp->run_systemd_timesync_wd) {
+ if (e->mask & IN_DELETE_SELF) {
+ /* Somebody removed /run/systemd/timesync. */
+ (void) inotify_rm_watch(sp->inotify_fd, sp->run_systemd_timesync_wd);
+ sp->run_systemd_timesync_wd = -1;
+ } else
+ /* Somebody might have created /run/systemd/timesync/synchronized. */
+ clock_state_update(sp, event);
+ }
+}
+
+static int inotify_handler(sd_event_source *s,
+ int fd,
+ uint32_t revents,
+ void *userdata) {
+ sd_event *event = sd_event_source_get_event(s);
+ ClockState *sp = userdata;
+ union inotify_event_buffer buffer;
+ struct inotify_event *e;
+ ssize_t l;
+
+ l = read(fd, &buffer, sizeof(buffer));
+ if (l < 0) {
+ if (IN_SET(errno, EAGAIN, EINTR))
+ return 0;
+
+ return log_warning_errno(errno, "Lost access to inotify: %m");
+ }
+ FOREACH_INOTIFY_EVENT(e, buffer, l)
+ process_inotify_event(event, sp, e);
+
+ return 0;
+}
+
static int clock_state_update(ClockState *sp,
sd_event *event) {
static const struct itimerspec its = {
usec_t t;
const char * ts;
- clock_state_release(sp);
+ clock_state_release_timerfd(sp);
/* The kernel supports cancelling timers whenever its realtime clock is "set" (which can happen in a variety of
- * ways, generally adjustments of at least 500 ms). The way this module works is we set up a timer that will
+ * ways, generally adjustments of at least 500 ms). The way this module works is we set up a timerfd that will
* wake when the clock is set, and when that happens we read the clock synchronization state from the return
* value of adjtimex(2), which supports the NTP time adjustment protocol.
*
* The kernel determines whether the clock is synchronized using driver-specific tests, based on time
- * information passed by an application, generally through adjtimex(2). If the application asserts the clock
- * is synchronized, but does not also do something that "sets the clock", the timer will not be cancelled and
- * synchronization will not be detected. Should this behavior be observed with a time synchronization provider
- * this code might be reworked to do a periodic check as well.
+ * information passed by an application, generally through adjtimex(2). If the application asserts the clock is
+ * synchronized, but does not also do something that "sets the clock", the timer will not be cancelled and
+ * synchronization will not be detected.
*
* Similarly, this service will never complete if the application sets the time without also providing
- * information that adjtimex(2) can use to determine that the clock is synchronized.
+ * information that adjtimex(2) can use to determine that the clock is synchronized. This generally doesn't
+ * happen, but can if the system has a hardware clock that is accurate enough that the adjustment is too small
+ * to be a "set".
+ *
+ * Both these failure-to-detect situations are covered by having the presence/creation of
+ * /run/systemd/timesync/synchronized, which is considered sufficient to indicate a synchronized clock even if
+ * the kernel has not been updated.
*
- * Well-behaved implementations including systemd-timesyncd should not produce either situation. For timesyncd
- * the initial setting of the time uses settimeofday(2), which sets the clock but does not mark it
- * synchronized. When an NTP source is selected it sets the clock again with clock_adjtime(2) which does mark
- * it synchronized. */
+ * For timesyncd the initial setting of the time uses settimeofday(2), which sets the clock but does not mark
+ * it synchronized. When an NTP source is selected it sets the clock again with clock_adjtime(2) which marks it
+ * synchronized and also touches /run/systemd/timesync/synchronized which covers the case when the clock wasn't
+ * "set". */
r = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC);
if (r < 0) {
log_error_errno(errno, "Failed to create timerfd: %m");
goto finish;
}
- sp->fd = r;
+ sp->timerfd_fd = r;
- r = timerfd_settime(sp->fd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &its, NULL);
+ r = timerfd_settime(sp->timerfd_fd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &its, NULL);
if (r < 0) {
log_error_errno(errno, "Failed to set timerfd conditions: %m");
goto finish;
strcpy(buf, "unrepresentable");
log_info("adjtime state %d status %x time %s", sp->adjtime_state, tx.status, ts);
- if (sp->adjtime_state == TIME_ERROR) {
- /* Not synchronized. Do a one-shot wait on the descriptor and inform the caller we need to keep
+ sp->has_watchfile = access("/run/systemd/timesync/synchronized", F_OK) >= 0;
+ if (sp->has_watchfile)
+ /* Presence of watch file overrides adjtime_state */
+ r = 0;
+ else if (sp->adjtime_state == TIME_ERROR) {
+ /* Not synchronized. Do a one-shot wait on the descriptor and inform the caller we need to keep
* running. */
- r = sd_event_add_io(event, &sp->event_source, sp->fd,
- EPOLLIN, io_handler, sp);
+ r = sd_event_add_io(event, &sp->timerfd_event_source, sp->timerfd_fd,
+ EPOLLIN, timerfd_handler, sp);
if (r < 0) {
log_error_errno(r, "Failed to create time change monitor source: %m");
goto finish;
}
r = 1;
- } else {
+ } else
/* Synchronized; we can exit. */
- (void) sd_event_exit(event, 0);
r = 0;
- }
finish:
- if (r < 0)
+ if (r <= 0)
(void) sd_event_exit(event, r);
return r;
}
int r;
_cleanup_(sd_event_unrefp) sd_event *event;
ClockState state = {
- .fd = -1,
+ .timerfd_fd = -1,
+ .inotify_fd = -1,
+ .run_systemd_wd = -1,
+ .run_systemd_timesync_wd = -1,
};
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
goto finish;
}
+ r = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+ if (r < 0) {
+ log_error_errno(errno, "Failed to create inotify descriptor: %m");
+ goto finish;
+ }
+ state.inotify_fd = r;
+
+ r = sd_event_add_io(event, &state.inotify_event_source, state.inotify_fd,
+ EPOLLIN, inotify_handler, &state);
+ if (r < 0) {
+ log_error_errno(r, "Failed to create notify event source: %m");
+ goto finish;
+ }
+
+ r = inotify_add_watch(state.inotify_fd, "/run/systemd/", IN_CREATE);
+ if (r < 0) {
+ log_error_errno(errno, "Failed to watch /run/systemd/: %m");
+ goto finish;
+ }
+ state.run_systemd_wd = r;
+
+ (void) update_notify_run_systemd_timesync(&state);
+
r = clock_state_update(&state, event);
if (r > 0) {
r = sd_event_loop(event);
if (r < 0)
log_error_errno(r, "Failed in event loop: %m");
- else if (state.adjtime_state == TIME_ERROR) {
- log_error("Event loop terminated without synchronizing");
- r = -ECANCELED;
- }
}
+ if (state.has_watchfile)
+ log_debug("Exit enabled by: /run/systemd/timesync/synchonized");
+
+ if (state.adjtime_state == TIME_ERROR)
+ log_info("Exit without adjtimex synchronized.");
+
finish:
clock_state_release(&state);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
/* If touch fails, there isn't much we can do. Maybe it'll work next time. */
(void) touch("/var/lib/systemd/timesync/clock");
+ (void) touch("/run/systemd/timesync/synchronized");
m->drift_ppm = tmx.freq / 65536;
return r;
}
+static bool manager_is_connected(Manager *m) {
+ /* Return true when the manager is sending a request, resolving a server name, or
+ * in a poll interval. */
+ return m->server_socket >= 0 || m->resolve_query || m->event_timer;
+}
+
static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
Manager *m = userdata;
bool changed, connected, online;
online = network_is_online();
/* check if the client is currently connected */
- connected = m->server_socket >= 0 || m->resolve_query || m->exhausted_servers;
+ connected = manager_is_connected(m);
if (connected && !online) {
log_info("No network connectivity, watching for changes.");
manager_disconnect(m);
- } else if (!connected && online && changed) {
+ } else if ((!connected || changed) && online) {
log_info("Network configuration changed, trying to establish connection.");
if (m->current_server_address)
sockets.target
son.service
sysinit.target
+ test-execute/exec-basic.service
test-execute/exec-ambientcapabilities-merge-nfsnobody.service
test-execute/exec-ambientcapabilities-merge-nobody.service
test-execute/exec-ambientcapabilities-merge.service
--- /dev/null
+[Unit]
+Description=Test for basic execution
+
+[Service]
+ExecStart=touch /tmp/a ; /bin/touch /tmp/b ; touch /tmp/c
+ExecStart=test -f /tmp/a
+ExecStart=!test -f /tmp/b
+ExecStart=!!test -f /tmp/c
+ExecStart=+test -f /tmp/c
+ExecStartPost=rm /tmp/a /tmp/b /tmp/c
+
+PrivateTmp=true
+Type=oneshot
[Service]
Type=oneshot
# Create a file in /tmp/test-exec-bindpaths
-ExecStart=/bin/sh -c 'touch /tmp/test-exec-bindpaths/thisisasimpletest'
+ExecStart=touch /tmp/test-exec-bindpaths/thisisasimpletest
# Then, the file can be access through /tmp
-ExecStart=/bin/sh -c 'test -f /tmp/thisisasimpletest'
+ExecStart=test -f /tmp/thisisasimpletest
# Also, through /tmp/test-exec-bindreadonlypaths
-ExecStart=/bin/sh -c 'test -f /tmp/test-exec-bindreadonlypaths/thisisasimpletest'
+ExecStart=test -f /tmp/test-exec-bindreadonlypaths/thisisasimpletest
# The file cannot modify through /tmp/test-exec-bindreadonlypaths
ExecStart=/bin/sh -x -c '! touch /tmp/test-exec-bindreadonlypaths/thisisasimpletest'
# Cleanup
-ExecStart=/bin/sh -c 'rm /tmp/thisisasimpletest'
+ExecStart=rm /tmp/thisisasimpletest
BindPaths=/tmp:/tmp/test-exec-bindpaths
BindReadOnlyPaths=/tmp:/tmp/test-exec-bindreadonlypaths
Description=Test DynamicUser= migrate StateDirectory= (preparation)
[Service]
-ExecStart=/bin/sh -c 'test -w /var/lib/test-dynamicuser-migrate'
-ExecStart=/bin/sh -c 'test -w /var/lib/test-dynamicuser-migrate2/hoge'
-ExecStart=/bin/sh -c 'test ! -L /var/lib/test-dynamicuser-migrate'
-ExecStart=/bin/sh -c 'test ! -L /var/lib/test-dynamicuser-migrate2/hoge'
-ExecStart=/bin/sh -c 'test -d /var/lib/test-dynamicuser-migrate'
-ExecStart=/bin/sh -c 'test -d /var/lib/test-dynamicuser-migrate2/hoge'
-ExecStart=/bin/sh -c 'touch /var/lib/test-dynamicuser-migrate/yay'
-ExecStart=/bin/sh -c 'touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay'
+ExecStart=test -w /var/lib/test-dynamicuser-migrate
+ExecStart=test -w /var/lib/test-dynamicuser-migrate2/hoge
+ExecStart=test ! -L /var/lib/test-dynamicuser-migrate
+ExecStart=test ! -L /var/lib/test-dynamicuser-migrate2/hoge
+ExecStart=test -d /var/lib/test-dynamicuser-migrate
+ExecStart=test -d /var/lib/test-dynamicuser-migrate2/hoge
+ExecStart=touch /var/lib/test-dynamicuser-migrate/yay
+ExecStart=touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay
Type=oneshot
DynamicUser=no
Description=Test DynamicUser= migrate StateDirectory= (preparation)
[Service]
-ExecStart=/bin/sh -c 'test -w /var/lib/test-dynamicuser-migrate'
-ExecStart=/bin/sh -c 'test -w /var/lib/test-dynamicuser-migrate2/hoge'
-ExecStart=/bin/sh -c 'test -L /var/lib/test-dynamicuser-migrate'
-ExecStart=/bin/sh -c 'test -L /var/lib/test-dynamicuser-migrate2/hoge'
-ExecStart=/bin/sh -c 'test -d /var/lib/test-dynamicuser-migrate'
-ExecStart=/bin/sh -c 'test -d /var/lib/test-dynamicuser-migrate2/hoge'
-ExecStart=/bin/sh -c 'test -f /var/lib/test-dynamicuser-migrate/yay'
-ExecStart=/bin/sh -c 'test -f /var/lib/test-dynamicuser-migrate2/hoge/yayyay'
-ExecStart=/bin/sh -c 'test -d /var/lib/private/test-dynamicuser-migrate'
-ExecStart=/bin/sh -c 'test -d /var/lib/private/test-dynamicuser-migrate2/hoge'
-ExecStart=/bin/sh -c 'test -f /var/lib/private/test-dynamicuser-migrate/yay'
-ExecStart=/bin/sh -c 'test -f /var/lib/private/test-dynamicuser-migrate2/hoge/yayyay'
-ExecStart=/bin/sh -c 'touch /var/lib/test-dynamicuser-migrate/yay'
-ExecStart=/bin/sh -c 'touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay'
-ExecStart=/bin/sh -c 'touch /var/lib/private/test-dynamicuser-migrate/yay'
-ExecStart=/bin/sh -c 'touch /var/lib/private/test-dynamicuser-migrate2/hoge/yayyay'
+ExecStart=test -w /var/lib/test-dynamicuser-migrate
+ExecStart=test -w /var/lib/test-dynamicuser-migrate2/hoge
+ExecStart=test -L /var/lib/test-dynamicuser-migrate
+ExecStart=test -L /var/lib/test-dynamicuser-migrate2/hoge
+ExecStart=test -d /var/lib/test-dynamicuser-migrate
+ExecStart=test -d /var/lib/test-dynamicuser-migrate2/hoge
+ExecStart=test -f /var/lib/test-dynamicuser-migrate/yay
+ExecStart=test -f /var/lib/test-dynamicuser-migrate2/hoge/yayyay
+ExecStart=test -d /var/lib/private/test-dynamicuser-migrate
+ExecStart=test -d /var/lib/private/test-dynamicuser-migrate2/hoge
+ExecStart=test -f /var/lib/private/test-dynamicuser-migrate/yay
+ExecStart=test -f /var/lib/private/test-dynamicuser-migrate2/hoge/yayyay
+ExecStart=touch /var/lib/test-dynamicuser-migrate/yay
+ExecStart=touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay
+ExecStart=touch /var/lib/private/test-dynamicuser-migrate/yay
+ExecStart=touch /var/lib/private/test-dynamicuser-migrate2/hoge/yayyay
Type=oneshot
DynamicUser=yes
Description=Test DynamicUser= with StateDirectory=
[Service]
-ExecStart=/bin/sh -c 'test -w /var/lib/waldo'
-ExecStart=/bin/sh -c 'test -w /var/lib/quux/pief'
-ExecStart=/bin/sh -c 'touch /var/lib/waldo/yay'
-ExecStart=/bin/sh -c 'touch /var/lib/quux/pief/yayyay'
-ExecStart=/bin/sh -c 'test -f /var/lib/waldo/yay'
-ExecStart=/bin/sh -c 'test -f /var/lib/quux/pief/yayyay'
-ExecStart=/bin/sh -c 'test -f /var/lib/private/waldo/yay'
-ExecStart=/bin/sh -c 'test -f /var/lib/private/quux/pief/yayyay'
+ExecStart=test -w /var/lib/waldo
+ExecStart=test -w /var/lib/quux/pief
+ExecStart=touch /var/lib/waldo/yay
+ExecStart=touch /var/lib/quux/pief/yayyay
+ExecStart=test -f /var/lib/waldo/yay
+ExecStart=test -f /var/lib/quux/pief/yayyay
+ExecStart=test -f /var/lib/private/waldo/yay
+ExecStart=test -f /var/lib/private/quux/pief/yayyay
# Make sure that /var/lib/private/waldo is really the only writable directory besides the obvious candidates
-ExecStart=/bin/sh -x -c 'test $$(find / -type d -writable 2> /dev/null | egrep -v -e \'^(/var/tmp$$|/tmp$$|/proc/|/dev/mqueue$$|/dev/shm$$|/sys/fs/bpf$$)\' | sort -u | tr -d '\\\\n') = /var/lib/private/quux/pief/var/lib/private/waldo'
+ExecStart=sh -x -c 'test $$(find / \( -path /var/tmp -o -path /tmp -o -path /proc -o -path /dev/mqueue -o -path /dev/shm -o -path /sys/fs/bpf \) -prune -o -type d -writable -print 2>/dev/null | sort -u | tr -d '\\\\n') = /var/lib/private/quux/pief/var/lib/private/waldo'
Type=oneshot
DynamicUser=yes
[Service]
RestrictNamespaces=~mnt
-ExecStart=/bin/sh -x -c 'unshare -m'
+ExecStart=unshare -m
Type=oneshot
[Service]
RestrictNamespaces=mnt
-ExecStart=/bin/sh -x -c 'unshare -m'
+ExecStart=unshare -m
Type=oneshot
[Service]
RestrictNamespaces=no
-ExecStart=/bin/sh -x -c 'unshare -m -u -i -n -p -f'
+ExecStart=unshare -m -u -i -n -p -f
Type=oneshot
[Service]
RestrictNamespaces=yes
-ExecStart=/bin/sh -x -c 'unshare -m'
+ExecStart=unshare -m
Type=oneshot
[Service]
Type=oneshot
-ExecStart=/usr/bin/test %n = exec-specifier.service
-ExecStart=/usr/bin/test %N = exec-specifier
-ExecStart=/usr/bin/test %p = exec-specifier
-ExecStart=/usr/bin/test %P = exec/specifier
-ExecStart=/usr/bin/test %i = ""
-ExecStart=/usr/bin/test %I = ""
-ExecStart=/usr/bin/test %f = /exec/specifier
-ExecStart=/usr/bin/test %t = /run
-ExecStart=/usr/bin/test %S = /var/lib
-ExecStart=/usr/bin/test %C = /var/cache
-ExecStart=/usr/bin/test %L = /var/log
-ExecStart=/bin/sh -c 'test %u = $$(id -un 0)'
-ExecStart=/usr/bin/test %U = 0
-ExecStart=/bin/sh -c 'test %h = $$(getent passwd 0 | cut -d: -f 6)
-ExecStart=/bin/sh -c 'test %s = $$(getent passwd 0 | cut -d: -f 7)
-ExecStart=/bin/sh -c 'test %m = $$(cat /etc/machine-id)'
-ExecStart=/bin/sh -c 'test %b = $$(cat /proc/sys/kernel/random/boot_id | sed -e 's/-//g')'
-ExecStart=/bin/sh -c 'test %H = $$(hostname)'
-ExecStart=/bin/sh -c 'test %v = $$(uname -r)'
+ExecStart=test %n = exec-specifier.service
+ExecStart=test %N = exec-specifier
+ExecStart=test %p = exec-specifier
+ExecStart=test %P = exec/specifier
+ExecStart=test %i = ""
+ExecStart=test %I = ""
+ExecStart=test %f = /exec/specifier
+ExecStart=test %t = /run
+ExecStart=test %S = /var/lib
+ExecStart=test %C = /var/cache
+ExecStart=test %L = /var/log
+ExecStart=sh -c 'test %u = $$(id -un 0)'
+ExecStart=test %U = 0
+ExecStart=sh -c 'test %h = $$(getent passwd 0 | cut -d: -f 6)'
+ExecStart=sh -c 'test %s = $$(getent passwd 0 | cut -d: -f 7)'
+ExecStart=sh -c 'test %m = $$(cat /etc/machine-id)'
+ExecStart=sh -c 'test %b = $$(cat /proc/sys/kernel/random/boot_id | sed -e 's/-//g')'
+ExecStart=sh -c 'test %H = $$(hostname)'
+ExecStart=sh -c 'test %v = $$(uname -r)'
[Service]
Type=oneshot
-ExecStart=/usr/bin/test %n = exec-specifier@foo-bar.service
-ExecStart=/usr/bin/test %N = exec-specifier@foo-bar
-ExecStart=/usr/bin/test %p = exec-specifier
-ExecStart=/usr/bin/test %P = exec/specifier
-ExecStart=/usr/bin/test %i = foo-bar
-ExecStart=/usr/bin/test %I = foo/bar
-ExecStart=/usr/bin/test %f = /foo/bar
-ExecStart=/usr/bin/test %t = /run
-ExecStart=/usr/bin/test %S = /var/lib
-ExecStart=/usr/bin/test %C = /var/cache
-ExecStart=/usr/bin/test %L = /var/log
-ExecStart=/bin/sh -c 'test %u = $$(id -un 0)'
-ExecStart=/usr/bin/test %U = 0
-ExecStart=/bin/sh -c 'test %h = $$(getent passwd 0 | cut -d: -f 6)
-ExecStart=/bin/sh -c 'test %s = $$(getent passwd 0 | cut -d: -f 7)
-ExecStart=/bin/sh -c 'test %m = $$(cat /etc/machine-id)'
-ExecStart=/bin/sh -c 'test %b = $$(cat /proc/sys/kernel/random/boot_id | sed -e 's/-//g')'
-ExecStart=/bin/sh -c 'test %H = $$(hostname)'
-ExecStart=/bin/sh -c 'test %v = $$(uname -r)'
+ExecStart=test %n = exec-specifier@foo-bar.service
+ExecStart=test %N = exec-specifier@foo-bar
+ExecStart=test %p = exec-specifier
+ExecStart=test %P = exec/specifier
+ExecStart=test %i = foo-bar
+ExecStart=test %I = foo/bar
+ExecStart=test %f = /foo/bar
+ExecStart=test %t = /run
+ExecStart=test %S = /var/lib
+ExecStart=test %C = /var/cache
+ExecStart=test %L = /var/log
+ExecStart=sh -c 'test %u = $$(id -un 0)'
+ExecStart=test %U = 0
+ExecStart=sh -c 'test %h = $$(getent passwd 0 | cut -d: -f 6)'
+ExecStart=sh -c 'test %s = $$(getent passwd 0 | cut -d: -f 7)'
+ExecStart=sh -c 'test %m = $$(cat /etc/machine-id)'
+ExecStart=sh -c 'test %b = $$(cat /proc/sys/kernel/random/boot_id | sed -e 's/-//g')'
+ExecStart=sh -c 'test %H = $$(hostname)'
+ExecStart=sh -c 'test %v = $$(uname -r)'
Type=oneshot
# Check directories exist
-ExecStart=/bin/sh -c 'test -d /var/test-exec-temporaryfilesystem/rw && test -d /var/test-exec-temporaryfilesystem/ro'
+ExecStart=test -d /var/test-exec-temporaryfilesystem/rw -a -d /var/test-exec-temporaryfilesystem/ro
# Check TemporaryFileSystem= are empty
-ExecStart=/bin/sh -c 'for i in $$(ls -A /var); do test $$i = test-exec-temporaryfilesystem || false; done'
+ExecStart=sh -c 'for i in $$(ls -A /var); do test $$i = test-exec-temporaryfilesystem || false; done'
# Create a file in /var
-ExecStart=/bin/sh -c 'touch /var/hoge'
+ExecStart=touch /var/hoge
# Create a file in /var/test-exec-temporaryfilesystem/rw
-ExecStart=/bin/sh -c 'touch /var/test-exec-temporaryfilesystem/rw/thisisasimpletest-temporaryfilesystem'
+ExecStart=touch /var/test-exec-temporaryfilesystem/rw/thisisasimpletest-temporaryfilesystem
# Then, the file can be access through /tmp
-ExecStart=/bin/sh -c 'test -f /tmp/thisisasimpletest-temporaryfilesystem'
+ExecStart=test -f /tmp/thisisasimpletest-temporaryfilesystem
# Also, through /var/test-exec-temporaryfilesystem/ro
-ExecStart=/bin/sh -c 'test -f /var/test-exec-temporaryfilesystem/ro/thisisasimpletest-temporaryfilesystem'
+ExecStart=test -f /var/test-exec-temporaryfilesystem/ro/thisisasimpletest-temporaryfilesystem
# The file cannot modify through /var/test-exec-temporaryfilesystem/ro
-ExecStart=/bin/sh -c '! touch /var/test-exec-temporaryfilesystem/ro/thisisasimpletest-temporaryfilesystem'
+ExecStart=sh -c '! touch /var/test-exec-temporaryfilesystem/ro/thisisasimpletest-temporaryfilesystem'
# Cleanup
-ExecStart=/bin/sh -c 'rm /tmp/thisisasimpletest-temporaryfilesystem'
+ExecStart=rm /tmp/thisisasimpletest-temporaryfilesystem
TemporaryFileSystem=/var
BindPaths=/tmp:/var/test-exec-temporaryfilesystem/rw
tmpfiles = [['home.conf', ''],
['journal-nocow.conf', ''],
['systemd-nologin.conf', ''],
- ['systemd-nspawn.conf', ''],
+ ['systemd-nspawn.conf', 'ENABLE_MACHINED'],
['tmp.conf', ''],
['x11.conf', ''],
['legacy.conf', 'HAVE_SYSV_COMPAT'],
['sysinit.target', ''],
['syslog.socket', ''],
['system-update.target', ''],
+ ['system-update-cleanup.service', ''],
['systemd-ask-password-console.path', '',
'sysinit.target.wants/'],
['systemd-ask-password-wall.path', '',
['quotaon.service', 'ENABLE_QUOTACHECK'],
['rc-local.service', 'HAVE_SYSV_COMPAT'],
['rescue.service', ''],
- ['system-update-cleanup.service', ''],
['systemd-ask-password-console.service', ''],
['systemd-ask-password-wall.service', ''],
['systemd-backlight@.service', 'ENABLE_BACKLIGHT'],
'dbus-org.freedesktop.timedate1.service'],
['systemd-timesyncd.service', 'ENABLE_TIMESYNCD',
join_paths(pkgsysconfdir, 'system/sysinit.target.wants/')],
- ['systemd-time-wait-sync.service', '',
- join_paths(pkgsysconfdir, 'system/sysinit.target.wants/')],
+ ['systemd-time-wait-sync.service', 'ENABLE_TIMESYNCD'],
['systemd-tmpfiles-clean.service', 'ENABLE_TMPFILES'],
['systemd-tmpfiles-setup-dev.service', 'ENABLE_TMPFILES',
'sysinit.target.wants/'],
]
m4_units = [
+ ['console-getty.service', ''],
+ ['container-getty@.service', ''],
['getty@.service', '',
'autovt@.service ' +
join_paths(pkgsysconfdir, 'system/getty.target.wants/getty@tty1.service')],
['serial-getty@.service', ''],
]
-m4_in_units = [
- ['console-getty.service', ''],
- ['container-getty@.service', ''],
-]
-
-foreach tuple : m4_in_units
- file = tuple[0]
-
- gen = configure_file(
- input : file + '.m4.in',
- output : file + '.m4',
- configuration : substs)
-
- m4_units += [[file, tuple.get(1, ''), tuple.get(2, ''), gen]]
-endforeach
-
foreach tuple : in_units
file = tuple[0]
RestrictRealtime=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
+RuntimeDirectory=systemd/timesync
SystemCallFilter=~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @reboot @swap
SystemCallArchitectures=native
LockPersonality=yes