mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
systemctl: allow globbing in commands which take multiple unit names
This commit is contained in:
@@ -580,15 +580,24 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>start <replaceable>NAME</replaceable>...</command></term>
|
||||
<term><command>start <replaceable>PATTERN</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Start (activate) one or more units specified on the
|
||||
command line.</para>
|
||||
|
||||
<para>Note that glob patterns operate on a list of currently
|
||||
loaded units. Units which are not active and are not in a
|
||||
failed state usually are not loaded, and would not be
|
||||
matched by any pattern. In addition, in case of
|
||||
instantiated units, systemd is often unaware of the
|
||||
instance name until the instance has been started. Therefore
|
||||
using glob patterns with <command>start</command>
|
||||
has limited usefulness.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>stop <replaceable>NAME</replaceable>...</command></term>
|
||||
<term><command>stop <replaceable>PATTERN</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Stop (deactivate) one or more units specified on the
|
||||
@@ -596,7 +605,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>reload <replaceable>NAME</replaceable>...</command></term>
|
||||
<term><command>reload <replaceable>PATTERN</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Asks all units listed on the command line to reload
|
||||
@@ -617,7 +626,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>restart <replaceable>NAME</replaceable>...</command></term>
|
||||
<term><command>restart <replaceable>PATTERN</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Restart one or more units specified on the command
|
||||
@@ -626,7 +635,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>try-restart <replaceable>NAME</replaceable>...</command></term>
|
||||
<term><command>try-restart <replaceable>PATTERN</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Restart one or more units specified on the command
|
||||
@@ -637,7 +646,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>reload-or-restart <replaceable>NAME</replaceable>...</command></term>
|
||||
<term><command>reload-or-restart <replaceable>PATTERN</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Reload one or more units if they support it. If not,
|
||||
@@ -646,7 +655,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>reload-or-try-restart <replaceable>NAME</replaceable>...</command></term>
|
||||
<term><command>reload-or-try-restart <replaceable>PATTERN</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Reload one or more units if they support it. If not,
|
||||
@@ -676,7 +685,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>kill <replaceable>NAME</replaceable>...</command></term>
|
||||
<term><command>kill <replaceable>PATTERN</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Send a signal to one or more processes of the
|
||||
@@ -687,7 +696,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>is-active <replaceable>NAME</replaceable>...</command></term>
|
||||
<term><command>is-active <replaceable>PATTERN</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Check whether any of the specified units are active
|
||||
@@ -698,7 +707,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>is-failed <replaceable>NAME</replaceable>...</command></term>
|
||||
<term><command>is-failed <replaceable>PATTERN</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Check whether any of the specified units are in a "failed" state.
|
||||
@@ -709,7 +718,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>status</command> <optional><replaceable>NAME</replaceable>...|<replaceable>PID</replaceable>...]</optional></term>
|
||||
<term><command>status</command> <optional><replaceable>PATTERN</replaceable>...|<replaceable>PID</replaceable>...]</optional></term>
|
||||
|
||||
<listitem>
|
||||
<para>Show terse runtime status information about one or
|
||||
@@ -735,7 +744,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>show</command> <optional><replaceable>NAME</replaceable>...|<replaceable>JOB</replaceable>...</optional></term>
|
||||
<term><command>show</command> <optional><replaceable>PATTERN</replaceable>...|<replaceable>JOB</replaceable>...</optional></term>
|
||||
|
||||
<listitem>
|
||||
<para>Show properties of one or more units, jobs, or the
|
||||
@@ -752,7 +761,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>cat <replaceable>NAME</replaceable>...</command></term>
|
||||
<term><command>cat <replaceable>PATTERN</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Show backing files of one or more units. Prints the
|
||||
@@ -788,7 +797,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>help <replaceable>NAME</replaceable>...|<replaceable>PID</replaceable>...</command></term>
|
||||
<term><command>help <replaceable>PATTERN</replaceable>...|<replaceable>PID</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Show manual pages for one or more units, if
|
||||
@@ -798,7 +807,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>reset-failed [<replaceable>NAME</replaceable>...]</command></term>
|
||||
<term><command>reset-failed [<replaceable>PATTERN</replaceable>...]</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Reset the <literal>failed</literal> state of the
|
||||
@@ -1137,7 +1146,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>delete <replaceable>NAME</replaceable>...</command></term>
|
||||
<term><command>delete <replaceable>PATTERN</replaceable>...</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Remove a snapshot previously created with
|
||||
@@ -1383,23 +1392,55 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
<refsect2>
|
||||
<title>Parameter Syntax</title>
|
||||
|
||||
<para>For unit commands, the specified
|
||||
<replaceable>NAME</replaceable> should be the full name of the
|
||||
unit, or an abbreviated name which is automatically extended with
|
||||
the <literal>.service</literal> suffix.
|
||||
<programlisting># systemctl start foo.service</programlisting> is equivalent to:
|
||||
<programlisting># systemctl start foo</programlisting>
|
||||
Note that (absolute) paths to device nodes are automatically converted to device unit names, and other (absolute) paths to mount unit names.
|
||||
<programlisting># systemctl status /dev/sda
|
||||
# systemctl status /home</programlisting> is equivalent to:
|
||||
<programlisting># systemctl status dev-sda.device
|
||||
# systemctl status home.mount</programlisting></para>
|
||||
<para>Unit ommands listed above take either a single unit name
|
||||
(designated as <replaceable>NAME</replaceable>), or multiple
|
||||
unit specifications (designated as
|
||||
<replaceable>PATTERN</replaceable>...). In the first case, the
|
||||
unit name with or without a suffix must be given. If the suffix
|
||||
is not specified, systemctl will append a suitable suffix,
|
||||
<literal>.service</literal> by default, and a type-specific
|
||||
suffix in case of commands which operate only on specific unit
|
||||
types. For example,
|
||||
<programlisting># systemctl start sshd</programlisting> and
|
||||
<programlisting># systemctl start sshd.service</programlisting>
|
||||
are equivalent, as are
|
||||
<programlisting># systemctl isolate snapshot-11</programlisting>
|
||||
and
|
||||
<programlisting># systemctl isolate snapshot-11.snapshot</programlisting>
|
||||
Note that (absolute) paths to device nodes are automatically
|
||||
converted to device unit names, and other (absolute) paths to
|
||||
mount unit names.
|
||||
<programlisting># systemctl status /dev/sda
|
||||
# systemctl status /home</programlisting>
|
||||
are equivalent to:
|
||||
<programlisting># systemctl status dev-sda.device
|
||||
# systemctl status home.mount</programlisting>
|
||||
In the second case, shell-style globs will be matched against
|
||||
currently loaded units, and literal unit names, with or without
|
||||
a suffix, will be treated as in the first case. This means that
|
||||
literal unit names always refer to exactly one unit, but globs
|
||||
may match zero units and this is not considered an error.</para>
|
||||
|
||||
<para>For unit file commands, the
|
||||
specified <replaceable>NAME</replaceable> should be the full name
|
||||
of the unit file, or the absolute path to the unit file.
|
||||
<programlisting># systemctl link /path/to/foo.service</programlisting>
|
||||
</para>
|
||||
<para>Glob patterns use
|
||||
<citerefentry><refentrytitle>fnmatch</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
so normal shell-style globbing rules are used, and
|
||||
<literal>*</literal>, <literal>?</literal>,
|
||||
<literal>[]</literal> may be used. See
|
||||
<citerefentry><refentrytitle>glob</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
for more details. The patterns are matched against the names of
|
||||
currently loaded units, and patterns which don't match anything
|
||||
are silently skipped. For example:
|
||||
<programlisting># systemctl stop sshd@*.service</programlisting>
|
||||
will stop all <filename>sshd@.service</filename> instances.
|
||||
</para>
|
||||
|
||||
<para>For unit file commands, the specified
|
||||
<replaceable>NAME</replaceable> should be the full name of the
|
||||
unit file, or the absolute path to the unit file:
|
||||
<programlisting># systemctl enable foo.service</programlisting>
|
||||
or
|
||||
<programlisting># systemctl link /path/to/foo.service</programlisting>
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
</refsect1>
|
||||
@@ -1441,6 +1482,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
|
||||
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>wall</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.preset</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>glob</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@@ -268,7 +268,7 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
|
||||
memcpy(e, w, l);
|
||||
e[l] = 0;
|
||||
|
||||
n = unit_name_mangle(e);
|
||||
n = unit_name_mangle(e, false);
|
||||
if (!n) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
|
||||
@@ -991,7 +991,7 @@ static int add_units(sd_journal *j) {
|
||||
assert(j);
|
||||
|
||||
STRV_FOREACH(i, arg_system_units) {
|
||||
u = unit_name_mangle(*i);
|
||||
u = unit_name_mangle(*i, false);
|
||||
if (!u)
|
||||
return log_oom();
|
||||
r = add_matches_for_unit(j, u);
|
||||
@@ -1003,7 +1003,7 @@ static int add_units(sd_journal *j) {
|
||||
}
|
||||
|
||||
STRV_FOREACH(i, arg_user_units) {
|
||||
u = unit_name_mangle(*i);
|
||||
u = unit_name_mangle(*i, false);
|
||||
if (!u)
|
||||
return log_oom();
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bu
|
||||
if (!isempty(arg_slice)) {
|
||||
_cleanup_free_ char *slice;
|
||||
|
||||
slice = unit_name_mangle_with_suffix(arg_slice, ".slice");
|
||||
slice = unit_name_mangle_with_suffix(arg_slice, false, ".slice");
|
||||
if (!slice)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -255,7 +255,7 @@ static int start_transient_service(
|
||||
int r;
|
||||
|
||||
if (arg_unit)
|
||||
name = unit_name_mangle_with_suffix(arg_unit, ".service");
|
||||
name = unit_name_mangle_with_suffix(arg_unit, false, ".service");
|
||||
else
|
||||
asprintf(&name, "run-%lu.service", (unsigned long) getpid());
|
||||
if (!name)
|
||||
@@ -342,7 +342,7 @@ static int start_transient_scope(
|
||||
assert(bus);
|
||||
|
||||
if (arg_unit)
|
||||
name = unit_name_mangle_with_suffix(arg_unit, ".scope");
|
||||
name = unit_name_mangle_with_suffix(arg_unit, false, ".scope");
|
||||
else
|
||||
asprintf(&name, "run-%lu.scope", (unsigned long) getpid());
|
||||
if (!name)
|
||||
|
||||
@@ -481,15 +481,18 @@ int unit_name_from_dbus_path(const char *path, char **name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *unit_name_mangle(const char *name) {
|
||||
|
||||
/**
|
||||
* Try to turn a string that might not be a unit name into a
|
||||
* sensible unit name.
|
||||
*/
|
||||
char *unit_name_mangle(const char *name, bool allow_globs) {
|
||||
char *r, *t;
|
||||
const char *f;
|
||||
const char* valid_chars = allow_globs ? "@" VALID_CHARS "[]!-*?" : "@" VALID_CHARS;
|
||||
|
||||
assert(name);
|
||||
|
||||
/* Try to turn a string that might not be a unit name into a
|
||||
* sensible unit name. */
|
||||
|
||||
if (is_device_path(name))
|
||||
return unit_name_from_path(name, ".device");
|
||||
|
||||
@@ -506,7 +509,7 @@ char *unit_name_mangle(const char *name) {
|
||||
for (f = name, t = r; *f; f++) {
|
||||
if (*f == '/')
|
||||
*(t++) = '-';
|
||||
else if (!strchr("@" VALID_CHARS, *f))
|
||||
else if (!strchr(valid_chars, *f))
|
||||
t = do_escape_char(*f, t);
|
||||
else
|
||||
*(t++) = *f;
|
||||
@@ -520,7 +523,12 @@ char *unit_name_mangle(const char *name) {
|
||||
return r;
|
||||
}
|
||||
|
||||
char *unit_name_mangle_with_suffix(const char *name, const char *suffix) {
|
||||
|
||||
/**
|
||||
* Similar to unit_name_mangle(), but is called when we know
|
||||
* that this is about a specific unit type.
|
||||
*/
|
||||
char *unit_name_mangle_with_suffix(const char *name, bool allow_globs, const char *suffix) {
|
||||
char *r, *t;
|
||||
const char *f;
|
||||
|
||||
@@ -528,9 +536,6 @@ char *unit_name_mangle_with_suffix(const char *name, const char *suffix) {
|
||||
assert(suffix);
|
||||
assert(suffix[0] == '.');
|
||||
|
||||
/* Similar to unit_name_mangle(), but is called when we know
|
||||
* that this is about snapshot units. */
|
||||
|
||||
r = new(char, strlen(name) * 4 + strlen(suffix) + 1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
@@ -98,7 +98,7 @@ char *unit_name_to_path(const char *name);
|
||||
char *unit_dbus_path_from_name(const char *name);
|
||||
int unit_name_from_dbus_path(const char *path, char **name);
|
||||
|
||||
char *unit_name_mangle(const char *name);
|
||||
char *unit_name_mangle_with_suffix(const char *name, const char *suffix);
|
||||
char *unit_name_mangle(const char *name, bool allow_globs);
|
||||
char *unit_name_mangle_with_suffix(const char *name, bool allow_globs, const char *suffix);
|
||||
|
||||
int build_subslice(const char *slice, const char*name, char **subslice);
|
||||
|
||||
@@ -47,9 +47,10 @@
|
||||
|
||||
/* What is interpreted as whitespace? */
|
||||
#define WHITESPACE " \t\n\r"
|
||||
#define NEWLINE "\n\r"
|
||||
#define QUOTES "\"\'"
|
||||
#define COMMENTS "#;"
|
||||
#define NEWLINE "\n\r"
|
||||
#define QUOTES "\"\'"
|
||||
#define COMMENTS "#;"
|
||||
#define GLOB_CHARS "*?["
|
||||
|
||||
#define FORMAT_BYTES_MAX 8
|
||||
|
||||
@@ -627,6 +628,13 @@ bool path_is_safe(const char *p) _pure_;
|
||||
bool string_is_safe(const char *p) _pure_;
|
||||
bool string_has_cc(const char *p) _pure_;
|
||||
|
||||
/**
|
||||
* Check if a string contains any glob patterns.
|
||||
*/
|
||||
_pure_ static inline bool string_is_glob(const char *p) {
|
||||
return !!strpbrk(p, GLOB_CHARS);
|
||||
}
|
||||
|
||||
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
||||
int (*compar) (const void *, const void *, void *),
|
||||
void *arg);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -92,8 +92,8 @@ static void test_replacements(void) {
|
||||
#define expect(pattern) \
|
||||
{ \
|
||||
_cleanup_free_ char *k, *t; \
|
||||
assert_se(t = unit_name_mangle(pattern)); \
|
||||
assert_se(k = unit_name_mangle(t)); \
|
||||
assert_se(t = unit_name_mangle(pattern, false)); \
|
||||
assert_se(k = unit_name_mangle(t, false)); \
|
||||
puts(t); \
|
||||
assert_se(streq(t, k)); \
|
||||
}
|
||||
|
||||
@@ -961,7 +961,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
|
||||
int has_glob;
|
||||
|
||||
has_split = (strchr(value, '|') != NULL);
|
||||
has_glob = (strchr(value, '*') != NULL || strchr(value, '?') != NULL || strchr(value, '[') != NULL);
|
||||
has_glob = string_is_glob(value);
|
||||
if (has_split && has_glob) {
|
||||
glob = GL_SPLIT_GLOB;
|
||||
} else if (has_split) {
|
||||
|
||||
Reference in New Issue
Block a user