mirror of
https://github.com/systemd/systemd.git
synced 2024-10-26 17:27:41 +03:00
sysupdated: Plumb through optional features
This adds APIs to enumerate/inspect/enable/disable optional features.
This commit is contained in:
parent
0cd1a58921
commit
e55e7a5a61
@ -122,9 +122,18 @@ node /org/freedesktop/sysupdate1/target/host {
|
||||
out s new_version,
|
||||
out t job_id,
|
||||
out o job_path);
|
||||
Vacuum(out u count);
|
||||
Vacuum(out u instances,
|
||||
out u disabled_transfers);
|
||||
GetAppStream(out as appstream);
|
||||
GetVersion(out s version);
|
||||
ListFeatures(in t flags,
|
||||
out as features);
|
||||
DescribeFeature(in s feature,
|
||||
in t flags,
|
||||
out s json);
|
||||
SetFeatureEnabled(in s feature,
|
||||
in i enabled,
|
||||
in t flags);
|
||||
properties:
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s Class = '...';
|
||||
@ -159,6 +168,12 @@ node /org/freedesktop/sysupdate1/target/host {
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="GetVersion()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ListFeatures()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="DescribeFeature()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="SetFeatureEnabled()"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Class"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Name"/>
|
||||
@ -273,6 +288,68 @@ node /org/freedesktop/sysupdate1/target/host {
|
||||
<varname>IMAGE_VERSION</varname> in <filename>/etc/os-release</filename>. If the target has no current
|
||||
version, the function will return an empty string.</para>
|
||||
|
||||
<para><function>ListFeatures()</function> returns a list of this target's optional features, by ID.
|
||||
The <varname>flags</varname> argument is added for future extensibility, and must be set to 0.
|
||||
If the target has no optional features, the method returns an empty array.</para>
|
||||
|
||||
<para><function>DescribeFeature()</function> returns all known information about a given optional feature.
|
||||
The <varname>feature</varname> argument is used to pass the ID of the feature to be described.
|
||||
The <varname>flags</varname> argument is added for future extensibility, and must be set to 0.
|
||||
The returned JSON object contains several known keys. More keys may be added in the future.
|
||||
The currently known keys are as follows:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><literal>name</literal></term>
|
||||
<listitem><para>A string containing the feature's name.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>description</literal></term>
|
||||
<listitem><para>An optional string that contains a user-presentable description that identifies
|
||||
this feature</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>enabled</literal></term>
|
||||
<listitem><para>A boolean indicating whether this feature is enabled.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>documentationUrl</literal></term>
|
||||
<listitem><para>An optional string that contains a user-presentable HTTP/HTTPS URL to documentation
|
||||
about this feature.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>appstreamUrl</literal></term>
|
||||
<listitem><para>An optional string that contains an HTTP/HTTPS URL to an
|
||||
<ulink url="https://wwww.freedesktop.org/software/appstream/docs/chap-CatalogData.html">appstream
|
||||
catalog</ulink> XML file containing metadata about this feature.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>transfers</literal></term>
|
||||
<listitem><para>An optional array of strings that list which transfer definitions belong to this
|
||||
feature.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para><function>SetFeatureEnabled()</function> writes an appropriate drop-in file to enable or disable
|
||||
the specified optional feature.
|
||||
If <varname>enable</varname> is zero, the feature is disabled. When greater than zero, the feature is
|
||||
enabled. When less than zero, the feature is reset to the distribution's default.
|
||||
The <varname>flags</varname> argument is added for future extensibility, and must be set to 0.
|
||||
The feature does not have to exist; this allows for graceful handling of masked features, and for
|
||||
preemptive decisions to be made about features that are planned to appear in future releases of the OS.
|
||||
The drop-in will have a filename of <literal>50-systemd-sysupdate-enabled.conf</literal>.
|
||||
This method only changes configuration files; to actually apply the changes, clients will need to
|
||||
call <function>Update()</function>.
|
||||
Depending on the exact needs of the client, it can choose to update the system to the latest available
|
||||
version, or it can extend the newest existing installation in-place (by passing in the version returned
|
||||
by <varname>GetVersion()</varname>).
|
||||
For now, this method only works with the <literal>host</literal> target.</para>
|
||||
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
@ -327,8 +404,13 @@ node /org/freedesktop/sysupdate1/target/host {
|
||||
<interfacename>org.freedesktop.sysupdate1.vacuum</interfacename>. By default, this action requires
|
||||
administrator authentication.</para>
|
||||
|
||||
<para><function>GetAppStream()</function> and <function>GetVersion()</function> are unauthenticated and
|
||||
may be called by anybody.</para>
|
||||
<para><function>SetFeatureEnabled()</function> uses the polkit action
|
||||
<interfacename>org.freedesktop.sysupdate1.manage-features</interfacename>. By default, this action
|
||||
requires administrator authentication.</para>
|
||||
|
||||
<para><function>GetAppStream()</function>, <function>GetVersion()</function>,
|
||||
<function>ListFeatures()</function>, and <function>DescribeFeature()</function>
|
||||
are unauthenticated and may be called by anybody.</para>
|
||||
|
||||
<para>All methods called on this interface expose additional variables to the polkit rules.
|
||||
<literal>class</literal> contains the class of the Target being acted upon, and <literal>name</literal>
|
||||
@ -409,9 +491,9 @@ node /org/freedesktop/sysupdate1/job/_1 {
|
||||
|
||||
<para>The <varname>Id</varname> property exposes the numeric job ID of the job object.</para>
|
||||
|
||||
<para>The <varname>Type</varname> property exposes the type of operation (one of: <literal>list</literal>,
|
||||
<literal>describe</literal>, <literal>check-new</literal>, <literal>update</literal>, or <literal>vacuum</literal>).
|
||||
</para>
|
||||
<para>The <varname>Type</varname> property exposes the type of operation (one of:
|
||||
<literal>list</literal>, <literal>describe</literal>, <literal>check-new</literal>,
|
||||
<literal>update</literal>, <literal>vacuum</literal>, or <literal>describe-feature</literal>).</para>
|
||||
|
||||
<para>The <varname>Offline</varname> property exposes whether the job is permitted to access
|
||||
the network or not.</para>
|
||||
@ -481,6 +563,9 @@ node /org/freedesktop/sysupdate1/job/_1 {
|
||||
<function>Vacuum()</function>,
|
||||
<function>GetAppStream()</function>,
|
||||
<function>GetVersion()</function>,
|
||||
<function>ListFeatures()</function>,
|
||||
<function>DescribeFeature()</function>,
|
||||
<function>SetFeatureEnabled()</function>,
|
||||
<varname>Class</varname>,
|
||||
<varname>Name</varname>, and
|
||||
<varname>Path</varname> were added in version 257.</para>
|
||||
|
@ -78,6 +78,18 @@
|
||||
send_interface="org.freedesktop.sysupdate1.Target"
|
||||
send_member="GetVersion"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.sysupdate1"
|
||||
send_interface="org.freedesktop.sysupdate1.Target"
|
||||
send_member="ListFeatures"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.sysupdate1"
|
||||
send_interface="org.freedesktop.sysupdate1.Target"
|
||||
send_member="DescribeFeature"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.sysupdate1"
|
||||
send_interface="org.freedesktop.sysupdate1.Target"
|
||||
send_member="SetFeatureEnabled"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.sysupdate1"
|
||||
send_interface="org.freedesktop.sysupdate1.Job"
|
||||
send_member="Cancel"/>
|
||||
|
@ -71,4 +71,14 @@
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<action id="org.freedesktop.sysupdate1.manage-features">
|
||||
<description gettext-domain="systemd">Manage optional features</description>
|
||||
<message gettext-domain="systemd">Authentication is required to manage optional features</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
</policyconfig>
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "bus-util.h"
|
||||
#include "common-signal.h"
|
||||
#include "discover-image.h"
|
||||
#include "dropin.h"
|
||||
#include "env-util.h"
|
||||
#include "escape.h"
|
||||
#include "event-util.h"
|
||||
@ -31,6 +32,8 @@
|
||||
#include "string-table.h"
|
||||
#include "sysupdate-util.h"
|
||||
|
||||
#define FEATURES_DROPIN_NAME "systemd-sysupdate-enabled"
|
||||
|
||||
typedef struct Manager {
|
||||
sd_event *event;
|
||||
sd_bus *bus;
|
||||
@ -85,6 +88,7 @@ typedef enum JobType {
|
||||
JOB_CHECK_NEW,
|
||||
JOB_UPDATE,
|
||||
JOB_VACUUM,
|
||||
JOB_DESCRIBE_FEATURE,
|
||||
_JOB_TYPE_MAX,
|
||||
_JOB_TYPE_INVALID = -EINVAL,
|
||||
} JobType;
|
||||
@ -104,6 +108,7 @@ struct Job {
|
||||
JobType type;
|
||||
bool offline;
|
||||
char *version; /* Passed into sysupdate for JOB_DESCRIBE and JOB_UPDATE */
|
||||
char *feature; /* Passed into sysupdate for JOB_DESCRIBE_FEATURE */
|
||||
|
||||
unsigned progress_percent;
|
||||
|
||||
@ -131,11 +136,12 @@ static const char* const target_class_table[_TARGET_CLASS_MAX] = {
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(target_class, TargetClass);
|
||||
|
||||
static const char* const job_type_table[_JOB_TYPE_MAX] = {
|
||||
[JOB_LIST] = "list",
|
||||
[JOB_DESCRIBE] = "describe",
|
||||
[JOB_CHECK_NEW] = "check-new",
|
||||
[JOB_UPDATE] = "update",
|
||||
[JOB_VACUUM] = "vacuum",
|
||||
[JOB_LIST] = "list",
|
||||
[JOB_DESCRIBE] = "describe",
|
||||
[JOB_CHECK_NEW] = "check-new",
|
||||
[JOB_UPDATE] = "update",
|
||||
[JOB_VACUUM] = "vacuum",
|
||||
[JOB_DESCRIBE_FEATURE] = "describe-feature",
|
||||
};
|
||||
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(job_type, JobType);
|
||||
@ -149,6 +155,7 @@ static Job *job_free(Job *j) {
|
||||
|
||||
free(j->object_path);
|
||||
free(j->version);
|
||||
free(j->feature);
|
||||
|
||||
sd_json_variant_unref(j->json);
|
||||
|
||||
@ -440,8 +447,8 @@ static int job_start(Job *j) {
|
||||
NULL, /* maybe --verify=no */
|
||||
NULL, /* maybe --component=, --root=, or --image= */
|
||||
NULL, /* maybe --offline */
|
||||
NULL, /* list, check-new, update, vacuum */
|
||||
NULL, /* maybe version (for list, update) */
|
||||
NULL, /* list, check-new, update, vacuum, features */
|
||||
NULL, /* maybe version (for list, update), maybe feature (features) */
|
||||
NULL
|
||||
};
|
||||
size_t k = 2;
|
||||
@ -493,6 +500,12 @@ static int job_start(Job *j) {
|
||||
cmd[k++] = "vacuum";
|
||||
break;
|
||||
|
||||
case JOB_DESCRIBE_FEATURE:
|
||||
cmd[k++] = "features";
|
||||
assert(!isempty(j->feature));
|
||||
cmd[k++] = j->feature;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
@ -573,20 +586,26 @@ static int job_method_cancel(sd_bus_message *msg, void *userdata, sd_bus_error *
|
||||
action = "org.freedesktop.sysupdate1.vacuum";
|
||||
break;
|
||||
|
||||
case JOB_DESCRIBE_FEATURE:
|
||||
action = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
r = bus_verify_polkit_async(
|
||||
msg,
|
||||
action,
|
||||
/* details= */ NULL,
|
||||
&j->manager->polkit_registry,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return 1; /* Will call us back */
|
||||
if (action) {
|
||||
r = bus_verify_polkit_async(
|
||||
msg,
|
||||
action,
|
||||
/* details= */ NULL,
|
||||
&j->manager->polkit_registry,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return 1; /* Will call us back */
|
||||
}
|
||||
|
||||
r = job_cancel(j);
|
||||
if (r < 0)
|
||||
@ -918,6 +937,8 @@ static int target_method_describe_finish(
|
||||
_cleanup_free_ char *text = NULL;
|
||||
int r;
|
||||
|
||||
/* NOTE: This is also reused by target_method_describe_feature */
|
||||
|
||||
assert(json);
|
||||
|
||||
r = sd_json_variant_format(json, 0, &text);
|
||||
@ -1132,7 +1153,7 @@ static int target_method_vacuum_finish(
|
||||
sd_bus_error *error) {
|
||||
|
||||
sd_json_variant *v;
|
||||
uint64_t instances;
|
||||
uint64_t instances, disabled;
|
||||
|
||||
assert(json);
|
||||
|
||||
@ -1144,7 +1165,15 @@ static int target_method_vacuum_finish(
|
||||
instances = sd_json_variant_unsigned(v);
|
||||
assert(instances <= UINT32_MAX);
|
||||
|
||||
return sd_bus_reply_method_return(msg, "u", (uint32_t) instances);
|
||||
v = sd_json_variant_by_key(json, "disabledTransfers");
|
||||
if (!v)
|
||||
return log_sysupdate_bad_json(SYNTHETIC_ERRNO(EPROTO), "vacuum", "Missing key 'disabledTransfers'");
|
||||
if (!sd_json_variant_is_unsigned(v))
|
||||
return log_sysupdate_bad_json(SYNTHETIC_ERRNO(EPROTO), "vacuum", "Key 'disabledTransfers' should be an unsigned int");
|
||||
disabled = sd_json_variant_unsigned(v);
|
||||
assert(disabled <= UINT32_MAX);
|
||||
|
||||
return sd_bus_reply_method_return(msg, "uu", (uint32_t) instances, (uint32_t) disabled);
|
||||
}
|
||||
|
||||
static int target_method_vacuum(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||
@ -1247,6 +1276,167 @@ static int target_method_get_appstream(sd_bus_message *msg, void *userdata, sd_b
|
||||
return sd_bus_send(NULL, reply, NULL);
|
||||
}
|
||||
|
||||
static int target_method_list_features(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *json = NULL;
|
||||
_cleanup_strv_free_ char **features = NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
Target *t = ASSERT_PTR(userdata);
|
||||
sd_json_variant *v;
|
||||
uint64_t flags;
|
||||
int r;
|
||||
|
||||
assert(msg);
|
||||
|
||||
r = sd_bus_message_read(msg, "t", &flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (flags != 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be 0");
|
||||
|
||||
r = sysupdate_run_simple(&json, t, "features", NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
v = sd_json_variant_by_key(json, "features");
|
||||
if (!v)
|
||||
return -EINVAL;
|
||||
r = sd_json_variant_strv(v, &features);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_new_method_return(msg, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append_strv(reply, features);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send(NULL, reply, NULL);
|
||||
}
|
||||
|
||||
static int target_method_describe_feature(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||
Target *t = ASSERT_PTR(userdata);
|
||||
_cleanup_(job_freep) Job *j = NULL;
|
||||
const char *feature;
|
||||
uint64_t flags;
|
||||
int r;
|
||||
|
||||
assert(msg);
|
||||
|
||||
r = sd_bus_message_read(msg, "st", &feature, &flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (isempty(feature))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Feature must be specified");
|
||||
|
||||
if (flags != 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be 0");
|
||||
|
||||
r = job_new(JOB_DESCRIBE_FEATURE, t, msg, target_method_describe_finish, &j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
j->feature = strdup(feature);
|
||||
if (!j->feature)
|
||||
return log_oom();
|
||||
|
||||
r = job_start(j);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to start job: %m");
|
||||
TAKE_PTR(j); /* Avoid job from being killed & freed */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool feature_name_is_valid(const char *name) {
|
||||
if (isempty(name))
|
||||
return false;
|
||||
|
||||
if (!ascii_is_valid(name))
|
||||
return false;
|
||||
|
||||
if (!filename_is_valid(strjoina(name, ".feature.d")))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int target_method_set_feature_enabled(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_free_ char *feature_ext = NULL;
|
||||
Target *t = ASSERT_PTR(userdata);
|
||||
const char *feature;
|
||||
uint64_t flags;
|
||||
int32_t enabled;
|
||||
int r;
|
||||
|
||||
assert(msg);
|
||||
|
||||
if (t->class != TARGET_HOST)
|
||||
return sd_bus_reply_method_errorf(msg,
|
||||
SD_BUS_ERROR_NOT_SUPPORTED,
|
||||
"For now, features can only be managed on the host system.");
|
||||
|
||||
r = sd_bus_message_read(msg, "sit", &feature, &enabled, &flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!feature_name_is_valid(feature))
|
||||
return sd_bus_reply_method_errorf(msg,
|
||||
SD_BUS_ERROR_INVALID_ARGS,
|
||||
"The specified feature is invalid");
|
||||
if (flags != 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be 0");
|
||||
|
||||
if (!endswith(feature, ".feature")) {
|
||||
feature_ext = strjoin(feature, ".feature");
|
||||
if (!feature_ext)
|
||||
return -ENOMEM;
|
||||
feature = feature_ext;
|
||||
}
|
||||
|
||||
const char *details[] = {
|
||||
"class", target_class_to_string(t->class),
|
||||
"name", t->name,
|
||||
"feature", feature,
|
||||
"enabled", enabled >= 0 ? true_false(enabled) : "unset",
|
||||
NULL
|
||||
};
|
||||
|
||||
r = bus_verify_polkit_async(
|
||||
msg,
|
||||
"org.freedesktop.sysupdate1.manage-features",
|
||||
details,
|
||||
&t->manager->polkit_registry,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return 1; /* Will call us back */
|
||||
|
||||
/* We assume that no sysadmin will name their config 50-systemd-sysupdate-enabled.conf */
|
||||
if (enabled < 0) { /* Reset -> delete the drop-in file */
|
||||
_cleanup_free_ char *path = NULL;
|
||||
|
||||
r = drop_in_file(SYSCONF_DIR "/sysupdate.d", feature, 50, FEATURES_DROPIN_NAME, NULL, &path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (unlink(path) < 0)
|
||||
return -errno;
|
||||
} else { /* otherwise, create the drop-in with the right settings */
|
||||
r = write_drop_in_format(SYSCONF_DIR "/sysupdate.d", feature, 50, FEATURES_DROPIN_NAME,
|
||||
"# Generated via org.freedesktop.sysupdate1 D-Bus interface\n\n"
|
||||
"[Feature]\n"
|
||||
"Enabled=%s\n",
|
||||
yes_no(enabled));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_reply_method_return(msg, NULL);
|
||||
}
|
||||
|
||||
static int target_list_components(Target *t, char ***ret_components, bool *ret_have_default) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *json = NULL;
|
||||
_cleanup_strv_free_ char **components = NULL;
|
||||
@ -1397,7 +1587,7 @@ static const sd_bus_vtable target_vtable[] = {
|
||||
|
||||
SD_BUS_METHOD_WITH_ARGS("Vacuum",
|
||||
SD_BUS_NO_ARGS,
|
||||
SD_BUS_RESULT("u", count),
|
||||
SD_BUS_RESULT("u", instances, "u", disabled_transfers),
|
||||
target_method_vacuum,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
@ -1413,6 +1603,24 @@ static const sd_bus_vtable target_vtable[] = {
|
||||
target_method_get_version,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_METHOD_WITH_ARGS("ListFeatures",
|
||||
SD_BUS_ARGS("t", flags),
|
||||
SD_BUS_RESULT("as", features),
|
||||
target_method_list_features,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_METHOD_WITH_ARGS("DescribeFeature",
|
||||
SD_BUS_ARGS("s", feature, "t", flags),
|
||||
SD_BUS_RESULT("s", json),
|
||||
target_method_describe_feature,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_METHOD_WITH_ARGS("SetFeatureEnabled",
|
||||
SD_BUS_ARGS("s", feature, "i", enabled, "t", flags),
|
||||
SD_BUS_NO_RESULT,
|
||||
target_method_set_feature_enabled,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
|
@ -1166,17 +1166,25 @@ static int verb_vacuum(int argc, char **argv, void *userdata) {
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
uint32_t count;
|
||||
uint32_t count, disabled;
|
||||
|
||||
r = sd_bus_call_method(bus, bus_sysupdate_mgr->destination, target_paths[i], SYSUPDATE_TARGET_INTERFACE, "Vacuum", &error, &reply, NULL);
|
||||
if (r < 0)
|
||||
return log_bus_error(r, &error, targets[i], "call Vacuum");
|
||||
|
||||
r = sd_bus_message_read(reply, "u", &count);
|
||||
r = sd_bus_message_read(reply, "uu", &count, &disabled);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
log_info("Deleted %u instance(s) of %s.\n", count, targets[i]);
|
||||
if (count > 0 && disabled > 0)
|
||||
log_info("Deleted %u instance(s) and %u disabled transfer(s) of %s.",
|
||||
count, disabled, targets[i]);
|
||||
else if (count > 0)
|
||||
log_info("Deleted %u instance(s) of %s.", count, targets[i]);
|
||||
else if (disabled > 0)
|
||||
log_info("Deleted %u disabled transfer(s) of %s.", disabled, targets[i]);
|
||||
else
|
||||
log_info("Found nothing to delete for %s.", targets[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user