systemctl: allow multiple arguments to --type

This mirrors --property, and is generally useful.

New functionality is used in bash completion.

In case of zsh completion, new functionality is less useful
because of caching. Nevertheless, zsh completion for restart
is made to behave more-or-less the same as bash completion.
At least sockets can be restarted.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2013-04-10 22:40:58 -04:00
parent 296f3c53cb
commit 20b3f379cf
4 changed files with 80 additions and 58 deletions

View file

@ -92,21 +92,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<term><option>--type=</option></term> <term><option>--type=</option></term>
<listitem> <listitem>
<para>The argument should be a unit type name such as <para>The argument should be a comma separated list of unit
<option>service</option> and <option>socket</option>, or a types such as <option>service</option> and
unit load state such as <option>loaded</option> and <option>socket</option>, or unit load states such as
<option>masked</option>. <option>loaded</option> and <option>masked</option>
</para> (types and states can be mixed).</para>
<para>If the argument is a unit type, when listing units, <para>If one of the arguments is a unit type, when listing
limit display to certain unit types. If not specified units units, limit display to certain unit types. Otherwise units
of all types will be shown.</para> of all types will be shown.</para>
<para>If the argument is a unit load state, when listing <para>If one of the arguments is a unit load state, when
units, limit display to certain unit types. If not specified listing units, limit display to certain unit
units of in all load states will be shown.</para> types. Otherwise units of in all load states will be
shown.</para>
<para>As a special case, if the argument is <para>As a special case, if one of the arguments is
<option>help</option>, a list of allowed values will be <option>help</option>, a list of allowed values will be
printed and the program will exit.</para> printed and the program will exit.</para>
</listitem> </listitem>

View file

@ -45,7 +45,7 @@ __get_all_units () { __systemctl $1 list-units --all \
| { while read -r a b; do echo " $a"; done; }; } | { while read -r a b; do echo " $a"; done; }; }
__get_active_units () { __systemctl $1 list-units \ __get_active_units () { __systemctl $1 list-units \
| { while read -r a b; do echo " $a"; done; }; } | { while read -r a b; do echo " $a"; done; }; }
__get_inactive_units () { __systemctl $1 list-units --all \ __get_startable_units () { __systemctl $1 list-units --all -t service,timer,socket,mount,automount,path,snapshot,swap \
| { while read -r a b c d; do [[ $c == "inactive" || $c == "failed " ]] && echo " $a"; done; }; } | { while read -r a b c d; do [[ $c == "inactive" || $c == "failed " ]] && echo " $a"; done; }; }
__get_failed_units () { __systemctl $1 list-units \ __get_failed_units () { __systemctl $1 list-units \
| { while read -r a b c d; do [[ $c == "failed" ]] && echo " $a"; done; }; } | { while read -r a b c d; do [[ $c == "failed" ]] && echo " $a"; done; }; }
@ -156,10 +156,7 @@ _systemctl () {
elif __contains_word "$verb" ${VERBS[STARTABLE_UNITS]}; then elif __contains_word "$verb" ${VERBS[STARTABLE_UNITS]}; then
comps=$( __filter_units_by_property $mode CanStart yes \ comps=$( __filter_units_by_property $mode CanStart yes \
$( __get_inactive_units $mode \ $( __get_startable_units $mode))
| while read -r line; do \
[[ "$line" =~ \.(device|snapshot)$ ]] || echo " $line"; \
done ))
elif __contains_word "$verb" ${VERBS[RESTARTABLE_UNITS]}; then elif __contains_word "$verb" ${VERBS[RESTARTABLE_UNITS]}; then
comps=$( __filter_units_by_property $mode CanStart yes \ comps=$( __filter_units_by_property $mode CanStart yes \

View file

@ -536,7 +536,7 @@ for fun in restart reload-or-restart ; do
_systemctl_all_units _systemctl_all_units
compadd "$@" - $( _filter_units_by_property CanStart yes \ compadd "$@" - $( _filter_units_by_property CanStart yes \
${_sys_all_units[*]} | while read line; do \ ${_sys_all_units[*]} | while read line; do \
[[ "$line" =~ \.(device|snapshot|socket|timer)$ ]] || echo " $line"; \ [[ "$line" =~ \.device$ ]] || echo " $line"; \
done ) done )
} }
done done

View file

@ -68,9 +68,9 @@
#include "socket-util.h" #include "socket-util.h"
#include "fileio.h" #include "fileio.h"
static const char *arg_type = NULL; static char **arg_types = NULL;
static const char *arg_load_state = NULL; static char **arg_load_states = NULL;
static char **arg_property = NULL; static char **arg_properties = NULL;
static bool arg_all = false; static bool arg_all = false;
static const char *arg_job_mode = "replace"; static const char *arg_job_mode = "replace";
static UnitFileScope arg_scope = UNIT_FILE_SYSTEM; static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
@ -295,9 +295,9 @@ static bool output_show_unit(const struct unit_info *u) {
if (arg_failed) if (arg_failed)
return streq(u->active_state, "failed"); return streq(u->active_state, "failed");
return (!arg_type || ((dot = strrchr(u->id, '.')) && return (!arg_types || ((dot = strrchr(u->id, '.')) &&
streq(dot+1, arg_type))) && strv_find(arg_types, dot+1))) &&
(!arg_load_state || streq(u->load_state, arg_load_state)) && (!arg_load_states || strv_find(arg_load_states, u->load_state)) &&
(arg_all || !(streq(u->active_state, "inactive") (arg_all || !(streq(u->active_state, "inactive")
|| u->following[0]) || u->job_id > 0); || u->following[0]) || u->job_id > 0);
} }
@ -524,7 +524,7 @@ static int compare_unit_file_list(const void *a, const void *b) {
static bool output_show_unit_file(const UnitFileList *u) { static bool output_show_unit_file(const UnitFileList *u) {
const char *dot; const char *dot;
return !arg_type || ((dot = strrchr(u->path, '.')) && streq(dot+1, arg_type)); return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1));
} }
static void output_unit_file_list(const UnitFileList *units, unsigned c) { static void output_unit_file_list(const UnitFileList *units, unsigned c) {
@ -2946,7 +2946,7 @@ static int print_property(const char *name, DBusMessageIter *iter) {
/* This is a low-level property printer, see /* This is a low-level property printer, see
* print_status_info() for the nicer output */ * print_status_info() for the nicer output */
if (arg_property && !strv_find(arg_property, name)) if (arg_properties && !strv_find(arg_properties, name))
return 0; return 0;
switch (dbus_message_iter_get_arg_type(iter)) { switch (dbus_message_iter_get_arg_type(iter)) {
@ -4504,45 +4504,67 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
puts(SYSTEMD_FEATURES); puts(SYSTEMD_FEATURES);
return 0; return 0;
case 't': case 't': {
if (streq(optarg, "help")) {
help_types();
return 0;
}
if (unit_type_from_string(optarg) >= 0) {
arg_type = optarg;
break;
}
if (unit_load_state_from_string(optarg) >= 0) {
arg_load_state = optarg;
break;
}
log_error("Unkown unit type or load state '%s'.",
optarg);
log_info("Use -t help to see a list of allowed values.");
return -EINVAL;
case 'p': {
char *word, *state; char *word, *state;
size_t size; size_t size;
FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
char _cleanup_free_ *type;
type = strndup(word, size);
if (!type)
return -ENOMEM;
if (streq(type, "help")) {
help_types();
return 0;
}
if (unit_type_from_string(type) >= 0) {
if (strv_push(&arg_types, type))
return log_oom();
type = NULL;
continue;
}
if (unit_load_state_from_string(optarg) >= 0) {
if (strv_push(&arg_load_states, type))
return log_oom();
type = NULL;
continue;
}
log_error("Unkown unit type or load state '%s'.", type);
log_info("Use -t help to see a list of allowed values.");
return -EINVAL;
}
break;
}
case 'p': {
/* Make sure that if the empty property list /* Make sure that if the empty property list
was specified, we won't show any properties. */ was specified, we won't show any properties. */
const char *source = isempty(optarg) ? " " : optarg; if (isempty(optarg) && !arg_properties) {
arg_properties = strv_new(NULL, NULL);
if (!arg_properties)
return log_oom();
} else {
char *word, *state;
size_t size;
FOREACH_WORD_SEPARATOR(word, size, source, ",", state) { FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
char _cleanup_free_ *prop; char *prop;
char **tmp;
prop = strndup(word, size); prop = strndup(word, size);
if (!prop) if (!prop)
return -ENOMEM; return log_oom();
tmp = strv_append(arg_property, prop); if (strv_push(&arg_properties, prop)) {
if (!tmp) free(prop);
return -ENOMEM; return log_oom();
}
strv_free(arg_property); }
arg_property = tmp;
} }
/* If the user asked for a particular /* If the user asked for a particular
@ -5725,7 +5747,9 @@ finish:
dbus_shutdown(); dbus_shutdown();
strv_free(arg_property); strv_free(arg_types);
strv_free(arg_load_states);
strv_free(arg_properties);
pager_close(); pager_close();
ask_password_agent_close(); ask_password_agent_close();